From 9610becebd5495228cf6d60e0f80f1c322da40ff Mon Sep 17 00:00:00 2001 From: Andras Banki-Horvath Date: Wed, 11 May 2022 16:37:50 +0200 Subject: [PATCH] multi: add the aggregate internal pubkey to the v3 htlc --- client.go | 6 ++-- client_test.go | 2 +- loopd/view.go | 4 +-- loopin_test.go | 2 +- swap.go | 2 +- swap/htlc.go | 91 +++++++++++++++++++---------------------------- swap/htlc_test.go | 30 +++------------- 7 files changed, 50 insertions(+), 87 deletions(-) diff --git a/client.go b/client.go index 4037cc2..b6bed80 100644 --- a/client.go +++ b/client.go @@ -195,7 +195,7 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) { htlc, err := swap.NewHtlc( GetHtlcScriptVersion(swp.Contract.ProtocolVersion), swp.Contract.CltvExpiry, swp.Contract.SenderKey, - swp.Contract.ReceiverKey, nil, swp.Hash, swap.HtlcP2WSH, + swp.Contract.ReceiverKey, swp.Hash, swap.HtlcP2WSH, s.lndServices.ChainParams, ) if err != nil { @@ -216,7 +216,7 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) { htlcNP2WSH, err := swap.NewHtlc( GetHtlcScriptVersion(swp.Contract.ProtocolVersion), swp.Contract.CltvExpiry, swp.Contract.SenderKey, - swp.Contract.ReceiverKey, nil, swp.Hash, swap.HtlcNP2WSH, + swp.Contract.ReceiverKey, swp.Hash, swap.HtlcNP2WSH, s.lndServices.ChainParams, ) if err != nil { @@ -226,7 +226,7 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) { htlcP2WSH, err := swap.NewHtlc( GetHtlcScriptVersion(swp.Contract.ProtocolVersion), swp.Contract.CltvExpiry, swp.Contract.SenderKey, - swp.Contract.ReceiverKey, nil, swp.Hash, swap.HtlcP2WSH, + swp.Contract.ReceiverKey, swp.Hash, swap.HtlcP2WSH, s.lndServices.ChainParams, ) if err != nil { diff --git a/client_test.go b/client_test.go index 426ee6c..6a315bc 100644 --- a/client_test.go +++ b/client_test.go @@ -284,7 +284,7 @@ func testResume(t *testing.T, confs uint32, expired, preimageRevealed, scriptVersion := GetHtlcScriptVersion(protocolVersion) htlc, err := swap.NewHtlc( scriptVersion, pendingSwap.Contract.CltvExpiry, senderKey, - receiverKey, nil, hash, swap.HtlcP2WSH, &chaincfg.TestNet3Params, + receiverKey, hash, swap.HtlcP2WSH, &chaincfg.TestNet3Params, ) require.NoError(t, err) require.Equal(t, htlc.PkScript, confIntent.PkScript) diff --git a/loopd/view.go b/loopd/view.go index a3d40ee..c13c8ba 100644 --- a/loopd/view.go +++ b/loopd/view.go @@ -54,7 +54,7 @@ func viewOut(swapClient *loop.Client, chainParams *chaincfg.Params) error { s.Contract.CltvExpiry, s.Contract.SenderKey, s.Contract.ReceiverKey, - nil, s.Hash, swap.HtlcP2WSH, chainParams, + s.Hash, swap.HtlcP2WSH, chainParams, ) if err != nil { return err @@ -106,7 +106,7 @@ func viewIn(swapClient *loop.Client, chainParams *chaincfg.Params) error { s.Contract.CltvExpiry, s.Contract.SenderKey, s.Contract.ReceiverKey, - nil, s.Hash, swap.HtlcNP2WSH, chainParams, + s.Hash, swap.HtlcNP2WSH, chainParams, ) if err != nil { return err diff --git a/loopin_test.go b/loopin_test.go index 8bfe401..bdf47da 100644 --- a/loopin_test.go +++ b/loopin_test.go @@ -399,7 +399,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool, htlc, err := swap.NewHtlc( scriptVersion, contract.CltvExpiry, contract.SenderKey, - contract.ReceiverKey, nil, testPreimage.Hash(), swap.HtlcNP2WSH, + contract.ReceiverKey, testPreimage.Hash(), swap.HtlcNP2WSH, cfg.lnd.ChainParams, ) if err != nil { diff --git a/swap.go b/swap.go index 3f778c2..193bdde 100644 --- a/swap.go +++ b/swap.go @@ -72,7 +72,7 @@ func (s *swapKit) getHtlc(outputType swap.HtlcOutputType) (*swap.Htlc, error) { return swap.NewHtlc( GetHtlcScriptVersion(s.contract.ProtocolVersion), s.contract.CltvExpiry, s.contract.SenderKey, - s.contract.ReceiverKey, nil, s.hash, outputType, + s.contract.ReceiverKey, s.hash, outputType, s.swapConfig.lnd.ChainParams, ) } diff --git a/swap/htlc.go b/swap/htlc.go index 2c20e91..5be9e35 100644 --- a/swap/htlc.go +++ b/swap/htlc.go @@ -6,10 +6,12 @@ import ( "errors" "fmt" - btcec "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" + "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" secp "github.com/decred/dcrd/dcrec/secp256k1/v4" @@ -106,7 +108,7 @@ var ( // script size. QuoteHtlc, _ = NewHtlc( HtlcV2, - ^int32(0), quoteKey, quoteKey, nil, quoteHash, HtlcP2WSH, + ^int32(0), quoteKey, quoteKey, quoteHash, HtlcP2WSH, &chaincfg.MainNetParams, ) @@ -119,17 +121,6 @@ var ( // selected for a v1 or v2 script. ErrInvalidOutputSelected = fmt.Errorf("taproot output selected for " + "non taproot htlc") - - // ErrSharedKeyNotNeeded is returned when a shared key is provided for - // either the v1 or v2 script. Shared key is only necessary for the v3 - // script. - ErrSharedKeyNotNeeded = fmt.Errorf("shared key not supported for " + - "script version") - - // ErrSharedKeyRequired is returned when a script version requires a - // shared key. - ErrSharedKeyRequired = fmt.Errorf("shared key required for script " + - "version") ) // String returns the string value of HtlcOutputType. @@ -152,9 +143,8 @@ func (h HtlcOutputType) String() string { // NewHtlc returns a new instance. For v3 scripts, an internal pubkey generated // by both participants must be provided. func NewHtlc(version ScriptVersion, cltvExpiry int32, - senderKey, receiverKey [33]byte, sharedKey *btcec.PublicKey, - hash lntypes.Hash, outputType HtlcOutputType, - chainParams *chaincfg.Params) (*Htlc, error) { + senderKey, receiverKey [33]byte, hash lntypes.Hash, + outputType HtlcOutputType, chainParams *chaincfg.Params) (*Htlc, error) { var ( err error @@ -163,28 +153,18 @@ func NewHtlc(version ScriptVersion, cltvExpiry int32, switch version { case HtlcV1: - if sharedKey != nil { - return nil, ErrSharedKeyNotNeeded - } htlc, err = newHTLCScriptV1( cltvExpiry, senderKey, receiverKey, hash, ) case HtlcV2: - if sharedKey != nil { - return nil, ErrSharedKeyNotNeeded - } htlc, err = newHTLCScriptV2( cltvExpiry, senderKey, receiverKey, hash, ) case HtlcV3: - if sharedKey == nil { - return nil, ErrSharedKeyRequired - } htlc, err = newHTLCScriptV3( - cltvExpiry, senderKey, receiverKey, - sharedKey, hash, + cltvExpiry, senderKey, receiverKey, hash, ) default: @@ -646,49 +626,51 @@ func (h *HtlcScriptV2) lockingConditions(htlcOutputType HtlcOutputType, // HtlcScriptV3 encapsulates the htlc v3 script. type HtlcScriptV3 struct { - // The final locking script for the timeout path which is available to - // the sender after the set blockheight. + // TimeoutScript is the final locking script for the timeout path which + // is available to the sender after the set blockheight. TimeoutScript []byte - // The final locking script for the success path in which the receiver - // reveals the preimage. + // SuccessScript is the final locking script for the success path in + // which the receiver reveals the preimage. SuccessScript []byte - // The public key for the keyspend path which bypasses the above two - // locking scripts. + // InternalPubKey is the public key for the keyspend path which bypasses + // the above two locking scripts. InternalPubKey *btcec.PublicKey - // The taproot public key which is created with the above 3 inputs. + // TaprootKey is the taproot public key which is created with the above + // 3 inputs. TaprootKey *btcec.PublicKey + + // RootHash is the root hash of the taptree. + RootHash chainhash.Hash } // newHTLCScriptV3 constructs a HtlcScipt with the HTLC V3 taproot script. -func newHTLCScriptV3(cltvExpiry int32, senderHtlcKey, - receiverHtlcKey [33]byte, sharedKey *btcec.PublicKey, +func newHTLCScriptV3(cltvExpiry int32, senderHtlcKey, receiverHtlcKey [33]byte, swapHash lntypes.Hash) (*HtlcScriptV3, error) { - receiverPubKey, err := btcec.ParsePubKey( - receiverHtlcKey[:], - ) + senderPubKey, err := schnorr.ParsePubKey(senderHtlcKey[1:]) if err != nil { return nil, err } - senderPubKey, err := btcec.ParsePubKey( - senderHtlcKey[:], - ) + receiverPubKey, err := schnorr.ParsePubKey(receiverHtlcKey[1:]) if err != nil { return nil, err } - var schnorrSenderKey, schnorrReceiverKey [32]byte - copy(schnorrSenderKey[:], schnorr.SerializePubKey(senderPubKey)) - copy(schnorrReceiverKey[:], schnorr.SerializePubKey(receiverPubKey)) + aggregateKey, _, _, err := musig2.AggregateKeys( + []*btcec.PublicKey{senderPubKey, receiverPubKey}, true, + ) + if err != nil { + return nil, err + } // Create our success path script, we'll use this separately // to generate the success path leaf. successPathScript, err := GenSuccessPathScript( - schnorrReceiverKey, swapHash, + receiverPubKey, swapHash, ) if err != nil { return nil, err @@ -697,7 +679,7 @@ func newHTLCScriptV3(cltvExpiry int32, senderHtlcKey, // Create our timeout path leaf, we'll use this separately // to generate the timeout path leaf. timeoutPathScript, err := GenTimeoutPathScript( - schnorrSenderKey, int64(cltvExpiry), + senderPubKey, int64(cltvExpiry), ) if err != nil { return nil, err @@ -713,14 +695,15 @@ func newHTLCScriptV3(cltvExpiry int32, senderHtlcKey, // Calculate top level taproot key. taprootKey := txscript.ComputeTaprootOutputKey( - sharedKey, rootHash[:], + aggregateKey.PreTweakedKey, rootHash[:], ) return &HtlcScriptV3{ TimeoutScript: timeoutPathScript, SuccessScript: successPathScript, - InternalPubKey: sharedKey, + InternalPubKey: aggregateKey.PreTweakedKey, TaprootKey: taprootKey, + RootHash: rootHash, }, nil } @@ -728,11 +711,11 @@ func newHTLCScriptV3(cltvExpiry int32, senderHtlcKey, // Largest possible bytesize of the script is 32 + 1 + 2 + 1 = 36. // // OP_CHECKSIGVERIFY OP_CHECKLOCKTIMEVERIFY -func GenTimeoutPathScript( - senderHtlcKey [32]byte, cltvExpiry int64) ([]byte, error) { +func GenTimeoutPathScript(senderHtlcKey *btcec.PublicKey, cltvExpiry int64) ( + []byte, error) { builder := txscript.NewScriptBuilder() - builder.AddData(senderHtlcKey[:]) + builder.AddData(schnorr.SerializePubKey(senderHtlcKey)) builder.AddOp(txscript.OP_CHECKSIGVERIFY) builder.AddInt64(cltvExpiry) builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY) @@ -746,12 +729,12 @@ func GenTimeoutPathScript( // OP_SIZE 32 OP_EQUALVERIFY // OP_HASH160 OP_EQUALVERIFY // 1 OP_CHECKSEQUENCEVERIFY -func GenSuccessPathScript(receiverHtlcKey [32]byte, +func GenSuccessPathScript(receiverHtlcKey *btcec.PublicKey, swapHash lntypes.Hash) ([]byte, error) { builder := txscript.NewScriptBuilder() - builder.AddData(receiverHtlcKey[:]) + builder.AddData(schnorr.SerializePubKey(receiverHtlcKey)) builder.AddOp(txscript.OP_CHECKSIGVERIFY) builder.AddOp(txscript.OP_SIZE) builder.AddInt64(32) diff --git a/swap/htlc_test.go b/swap/htlc_test.go index 742f677..0bf9b9e 100644 --- a/swap/htlc_test.go +++ b/swap/htlc_test.go @@ -3,12 +3,10 @@ package swap import ( "bytes" "crypto/sha256" - "encoding/hex" "fmt" "testing" "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" @@ -137,7 +135,7 @@ func TestHtlcV2(t *testing.T) { // Create the htlc. htlc, err := NewHtlc( - HtlcV2, testCltvExpiry, senderKey, receiverKey, nil, hash, + HtlcV2, testCltvExpiry, senderKey, receiverKey, hash, HtlcP2WSH, &chaincfg.MainNetParams, ) require.NoError(t, err) @@ -285,7 +283,7 @@ func TestHtlcV2(t *testing.T) { // Create the htlc with the bogus key. htlc, err = NewHtlc( HtlcV2, testCltvExpiry, - bogusKey, receiverKey, nil, hash, + bogusKey, receiverKey, hash, HtlcP2WSH, &chaincfg.MainNetParams, ) require.NoError(t, err) @@ -352,17 +350,8 @@ func TestHtlcV3(t *testing.T) { copy(receiverKey[:], receiverPubKey.SerializeCompressed()) copy(senderKey[:], senderPubKey.SerializeCompressed()) - randomSharedKey, err := hex.DecodeString( - "03fcb7d1b502bd59f4dbc6cf503e5c280189e0e6dd2d10c4c14d97ed8611" + - "a99178", - ) - require.NoError(t, err) - - randomSharedPubKey, err := btcec.ParsePubKey(randomSharedKey) - require.NoError(t, err) - htlc, err := NewHtlc( - HtlcV3, cltvExpiry, senderKey, receiverKey, randomSharedPubKey, + HtlcV3, cltvExpiry, senderKey, receiverKey, hashedPreimage, HtlcP2TR, &chaincfg.MainNetParams, ) require.NoError(t, err) @@ -544,18 +533,9 @@ func TestHtlcV3(t *testing.T) { bogusKey.SerializeCompressed(), ) - var shnorrSenderKey [32]byte - copy( - shnorrSenderKey[:], - schnorr.SerializePubKey( - senderPubKey, - ), - ) - htlc, err := NewHtlc( HtlcV3, cltvExpiry, bogusKeyBytes, - receiverKey, randomSharedPubKey, - hashedPreimage, HtlcP2TR, + receiverKey, hashedPreimage, HtlcP2TR, &chaincfg.MainNetParams, ) require.NoError(t, err) @@ -576,7 +556,7 @@ func TestHtlcV3(t *testing.T) { ) timeoutScript, err := GenTimeoutPathScript( - shnorrSenderKey, int64(cltvExpiry), + senderPubKey, int64(cltvExpiry), ) require.NoError(t, err)