Skip to content

Commit 9610bec

Browse files
committed
multi: add the aggregate internal pubkey to the v3 htlc
1 parent 638973d commit 9610bec

File tree

7 files changed

+50
-87
lines changed

7 files changed

+50
-87
lines changed

client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) {
195195
htlc, err := swap.NewHtlc(
196196
GetHtlcScriptVersion(swp.Contract.ProtocolVersion),
197197
swp.Contract.CltvExpiry, swp.Contract.SenderKey,
198-
swp.Contract.ReceiverKey, nil, swp.Hash, swap.HtlcP2WSH,
198+
swp.Contract.ReceiverKey, swp.Hash, swap.HtlcP2WSH,
199199
s.lndServices.ChainParams,
200200
)
201201
if err != nil {
@@ -216,7 +216,7 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) {
216216
htlcNP2WSH, err := swap.NewHtlc(
217217
GetHtlcScriptVersion(swp.Contract.ProtocolVersion),
218218
swp.Contract.CltvExpiry, swp.Contract.SenderKey,
219-
swp.Contract.ReceiverKey, nil, swp.Hash, swap.HtlcNP2WSH,
219+
swp.Contract.ReceiverKey, swp.Hash, swap.HtlcNP2WSH,
220220
s.lndServices.ChainParams,
221221
)
222222
if err != nil {
@@ -226,7 +226,7 @@ func (s *Client) FetchSwaps() ([]*SwapInfo, error) {
226226
htlcP2WSH, err := swap.NewHtlc(
227227
GetHtlcScriptVersion(swp.Contract.ProtocolVersion),
228228
swp.Contract.CltvExpiry, swp.Contract.SenderKey,
229-
swp.Contract.ReceiverKey, nil, swp.Hash, swap.HtlcP2WSH,
229+
swp.Contract.ReceiverKey, swp.Hash, swap.HtlcP2WSH,
230230
s.lndServices.ChainParams,
231231
)
232232
if err != nil {

client_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ func testResume(t *testing.T, confs uint32, expired, preimageRevealed,
284284
scriptVersion := GetHtlcScriptVersion(protocolVersion)
285285
htlc, err := swap.NewHtlc(
286286
scriptVersion, pendingSwap.Contract.CltvExpiry, senderKey,
287-
receiverKey, nil, hash, swap.HtlcP2WSH, &chaincfg.TestNet3Params,
287+
receiverKey, hash, swap.HtlcP2WSH, &chaincfg.TestNet3Params,
288288
)
289289
require.NoError(t, err)
290290
require.Equal(t, htlc.PkScript, confIntent.PkScript)

loopd/view.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ func viewOut(swapClient *loop.Client, chainParams *chaincfg.Params) error {
5454
s.Contract.CltvExpiry,
5555
s.Contract.SenderKey,
5656
s.Contract.ReceiverKey,
57-
nil, s.Hash, swap.HtlcP2WSH, chainParams,
57+
s.Hash, swap.HtlcP2WSH, chainParams,
5858
)
5959
if err != nil {
6060
return err
@@ -106,7 +106,7 @@ func viewIn(swapClient *loop.Client, chainParams *chaincfg.Params) error {
106106
s.Contract.CltvExpiry,
107107
s.Contract.SenderKey,
108108
s.Contract.ReceiverKey,
109-
nil, s.Hash, swap.HtlcNP2WSH, chainParams,
109+
s.Hash, swap.HtlcNP2WSH, chainParams,
110110
)
111111
if err != nil {
112112
return err

loopin_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool,
399399

400400
htlc, err := swap.NewHtlc(
401401
scriptVersion, contract.CltvExpiry, contract.SenderKey,
402-
contract.ReceiverKey, nil, testPreimage.Hash(), swap.HtlcNP2WSH,
402+
contract.ReceiverKey, testPreimage.Hash(), swap.HtlcNP2WSH,
403403
cfg.lnd.ChainParams,
404404
)
405405
if err != nil {

swap.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (s *swapKit) getHtlc(outputType swap.HtlcOutputType) (*swap.Htlc, error) {
7272
return swap.NewHtlc(
7373
GetHtlcScriptVersion(s.contract.ProtocolVersion),
7474
s.contract.CltvExpiry, s.contract.SenderKey,
75-
s.contract.ReceiverKey, nil, s.hash, outputType,
75+
s.contract.ReceiverKey, s.hash, outputType,
7676
s.swapConfig.lnd.ChainParams,
7777
)
7878
}

swap/htlc.go

Lines changed: 37 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ import (
66
"errors"
77
"fmt"
88

9-
btcec "github.com/btcsuite/btcd/btcec/v2"
9+
"github.com/btcsuite/btcd/btcec/v2"
1010
"github.com/btcsuite/btcd/btcec/v2/schnorr"
11+
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
1112
"github.com/btcsuite/btcd/btcutil"
1213
"github.com/btcsuite/btcd/chaincfg"
14+
"github.com/btcsuite/btcd/chaincfg/chainhash"
1315
"github.com/btcsuite/btcd/txscript"
1416
"github.com/btcsuite/btcd/wire"
1517
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
@@ -106,7 +108,7 @@ var (
106108
// script size.
107109
QuoteHtlc, _ = NewHtlc(
108110
HtlcV2,
109-
^int32(0), quoteKey, quoteKey, nil, quoteHash, HtlcP2WSH,
111+
^int32(0), quoteKey, quoteKey, quoteHash, HtlcP2WSH,
110112
&chaincfg.MainNetParams,
111113
)
112114

@@ -119,17 +121,6 @@ var (
119121
// selected for a v1 or v2 script.
120122
ErrInvalidOutputSelected = fmt.Errorf("taproot output selected for " +
121123
"non taproot htlc")
122-
123-
// ErrSharedKeyNotNeeded is returned when a shared key is provided for
124-
// either the v1 or v2 script. Shared key is only necessary for the v3
125-
// script.
126-
ErrSharedKeyNotNeeded = fmt.Errorf("shared key not supported for " +
127-
"script version")
128-
129-
// ErrSharedKeyRequired is returned when a script version requires a
130-
// shared key.
131-
ErrSharedKeyRequired = fmt.Errorf("shared key required for script " +
132-
"version")
133124
)
134125

135126
// String returns the string value of HtlcOutputType.
@@ -152,9 +143,8 @@ func (h HtlcOutputType) String() string {
152143
// NewHtlc returns a new instance. For v3 scripts, an internal pubkey generated
153144
// by both participants must be provided.
154145
func NewHtlc(version ScriptVersion, cltvExpiry int32,
155-
senderKey, receiverKey [33]byte, sharedKey *btcec.PublicKey,
156-
hash lntypes.Hash, outputType HtlcOutputType,
157-
chainParams *chaincfg.Params) (*Htlc, error) {
146+
senderKey, receiverKey [33]byte, hash lntypes.Hash,
147+
outputType HtlcOutputType, chainParams *chaincfg.Params) (*Htlc, error) {
158148

159149
var (
160150
err error
@@ -163,28 +153,18 @@ func NewHtlc(version ScriptVersion, cltvExpiry int32,
163153

164154
switch version {
165155
case HtlcV1:
166-
if sharedKey != nil {
167-
return nil, ErrSharedKeyNotNeeded
168-
}
169156
htlc, err = newHTLCScriptV1(
170157
cltvExpiry, senderKey, receiverKey, hash,
171158
)
172159

173160
case HtlcV2:
174-
if sharedKey != nil {
175-
return nil, ErrSharedKeyNotNeeded
176-
}
177161
htlc, err = newHTLCScriptV2(
178162
cltvExpiry, senderKey, receiverKey, hash,
179163
)
180164

181165
case HtlcV3:
182-
if sharedKey == nil {
183-
return nil, ErrSharedKeyRequired
184-
}
185166
htlc, err = newHTLCScriptV3(
186-
cltvExpiry, senderKey, receiverKey,
187-
sharedKey, hash,
167+
cltvExpiry, senderKey, receiverKey, hash,
188168
)
189169

190170
default:
@@ -646,49 +626,51 @@ func (h *HtlcScriptV2) lockingConditions(htlcOutputType HtlcOutputType,
646626

647627
// HtlcScriptV3 encapsulates the htlc v3 script.
648628
type HtlcScriptV3 struct {
649-
// The final locking script for the timeout path which is available to
650-
// the sender after the set blockheight.
629+
// TimeoutScript is the final locking script for the timeout path which
630+
// is available to the sender after the set blockheight.
651631
TimeoutScript []byte
652632

653-
// The final locking script for the success path in which the receiver
654-
// reveals the preimage.
633+
// SuccessScript is the final locking script for the success path in
634+
// which the receiver reveals the preimage.
655635
SuccessScript []byte
656636

657-
// The public key for the keyspend path which bypasses the above two
658-
// locking scripts.
637+
// InternalPubKey is the public key for the keyspend path which bypasses
638+
// the above two locking scripts.
659639
InternalPubKey *btcec.PublicKey
660640

661-
// The taproot public key which is created with the above 3 inputs.
641+
// TaprootKey is the taproot public key which is created with the above
642+
// 3 inputs.
662643
TaprootKey *btcec.PublicKey
644+
645+
// RootHash is the root hash of the taptree.
646+
RootHash chainhash.Hash
663647
}
664648

665649
// newHTLCScriptV3 constructs a HtlcScipt with the HTLC V3 taproot script.
666-
func newHTLCScriptV3(cltvExpiry int32, senderHtlcKey,
667-
receiverHtlcKey [33]byte, sharedKey *btcec.PublicKey,
650+
func newHTLCScriptV3(cltvExpiry int32, senderHtlcKey, receiverHtlcKey [33]byte,
668651
swapHash lntypes.Hash) (*HtlcScriptV3, error) {
669652

670-
receiverPubKey, err := btcec.ParsePubKey(
671-
receiverHtlcKey[:],
672-
)
653+
senderPubKey, err := schnorr.ParsePubKey(senderHtlcKey[1:])
673654
if err != nil {
674655
return nil, err
675656
}
676657

677-
senderPubKey, err := btcec.ParsePubKey(
678-
senderHtlcKey[:],
679-
)
658+
receiverPubKey, err := schnorr.ParsePubKey(receiverHtlcKey[1:])
680659
if err != nil {
681660
return nil, err
682661
}
683662

684-
var schnorrSenderKey, schnorrReceiverKey [32]byte
685-
copy(schnorrSenderKey[:], schnorr.SerializePubKey(senderPubKey))
686-
copy(schnorrReceiverKey[:], schnorr.SerializePubKey(receiverPubKey))
663+
aggregateKey, _, _, err := musig2.AggregateKeys(
664+
[]*btcec.PublicKey{senderPubKey, receiverPubKey}, true,
665+
)
666+
if err != nil {
667+
return nil, err
668+
}
687669

688670
// Create our success path script, we'll use this separately
689671
// to generate the success path leaf.
690672
successPathScript, err := GenSuccessPathScript(
691-
schnorrReceiverKey, swapHash,
673+
receiverPubKey, swapHash,
692674
)
693675
if err != nil {
694676
return nil, err
@@ -697,7 +679,7 @@ func newHTLCScriptV3(cltvExpiry int32, senderHtlcKey,
697679
// Create our timeout path leaf, we'll use this separately
698680
// to generate the timeout path leaf.
699681
timeoutPathScript, err := GenTimeoutPathScript(
700-
schnorrSenderKey, int64(cltvExpiry),
682+
senderPubKey, int64(cltvExpiry),
701683
)
702684
if err != nil {
703685
return nil, err
@@ -713,26 +695,27 @@ func newHTLCScriptV3(cltvExpiry int32, senderHtlcKey,
713695

714696
// Calculate top level taproot key.
715697
taprootKey := txscript.ComputeTaprootOutputKey(
716-
sharedKey, rootHash[:],
698+
aggregateKey.PreTweakedKey, rootHash[:],
717699
)
718700

719701
return &HtlcScriptV3{
720702
TimeoutScript: timeoutPathScript,
721703
SuccessScript: successPathScript,
722-
InternalPubKey: sharedKey,
704+
InternalPubKey: aggregateKey.PreTweakedKey,
723705
TaprootKey: taprootKey,
706+
RootHash: rootHash,
724707
}, nil
725708
}
726709

727710
// GenTimeoutPathScript constructs an HtlcScript for the timeout payment path.
728711
// Largest possible bytesize of the script is 32 + 1 + 2 + 1 = 36.
729712
//
730713
// <senderHtlcKey> OP_CHECKSIGVERIFY <cltvExpiry> OP_CHECKLOCKTIMEVERIFY
731-
func GenTimeoutPathScript(
732-
senderHtlcKey [32]byte, cltvExpiry int64) ([]byte, error) {
714+
func GenTimeoutPathScript(senderHtlcKey *btcec.PublicKey, cltvExpiry int64) (
715+
[]byte, error) {
733716

734717
builder := txscript.NewScriptBuilder()
735-
builder.AddData(senderHtlcKey[:])
718+
builder.AddData(schnorr.SerializePubKey(senderHtlcKey))
736719
builder.AddOp(txscript.OP_CHECKSIGVERIFY)
737720
builder.AddInt64(cltvExpiry)
738721
builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
@@ -746,12 +729,12 @@ func GenTimeoutPathScript(
746729
// OP_SIZE 32 OP_EQUALVERIFY
747730
// OP_HASH160 <ripemd160h(swapHash)> OP_EQUALVERIFY
748731
// 1 OP_CHECKSEQUENCEVERIFY
749-
func GenSuccessPathScript(receiverHtlcKey [32]byte,
732+
func GenSuccessPathScript(receiverHtlcKey *btcec.PublicKey,
750733
swapHash lntypes.Hash) ([]byte, error) {
751734

752735
builder := txscript.NewScriptBuilder()
753736

754-
builder.AddData(receiverHtlcKey[:])
737+
builder.AddData(schnorr.SerializePubKey(receiverHtlcKey))
755738
builder.AddOp(txscript.OP_CHECKSIGVERIFY)
756739
builder.AddOp(txscript.OP_SIZE)
757740
builder.AddInt64(32)

swap/htlc_test.go

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ package swap
33
import (
44
"bytes"
55
"crypto/sha256"
6-
"encoding/hex"
76
"fmt"
87
"testing"
98

109
"github.com/btcsuite/btcd/btcec/v2"
11-
"github.com/btcsuite/btcd/btcec/v2/schnorr"
1210
"github.com/btcsuite/btcd/btcutil"
1311
"github.com/btcsuite/btcd/chaincfg"
1412
"github.com/btcsuite/btcd/chaincfg/chainhash"
@@ -137,7 +135,7 @@ func TestHtlcV2(t *testing.T) {
137135

138136
// Create the htlc.
139137
htlc, err := NewHtlc(
140-
HtlcV2, testCltvExpiry, senderKey, receiverKey, nil, hash,
138+
HtlcV2, testCltvExpiry, senderKey, receiverKey, hash,
141139
HtlcP2WSH, &chaincfg.MainNetParams,
142140
)
143141
require.NoError(t, err)
@@ -285,7 +283,7 @@ func TestHtlcV2(t *testing.T) {
285283
// Create the htlc with the bogus key.
286284
htlc, err = NewHtlc(
287285
HtlcV2, testCltvExpiry,
288-
bogusKey, receiverKey, nil, hash,
286+
bogusKey, receiverKey, hash,
289287
HtlcP2WSH, &chaincfg.MainNetParams,
290288
)
291289
require.NoError(t, err)
@@ -352,17 +350,8 @@ func TestHtlcV3(t *testing.T) {
352350
copy(receiverKey[:], receiverPubKey.SerializeCompressed())
353351
copy(senderKey[:], senderPubKey.SerializeCompressed())
354352

355-
randomSharedKey, err := hex.DecodeString(
356-
"03fcb7d1b502bd59f4dbc6cf503e5c280189e0e6dd2d10c4c14d97ed8611" +
357-
"a99178",
358-
)
359-
require.NoError(t, err)
360-
361-
randomSharedPubKey, err := btcec.ParsePubKey(randomSharedKey)
362-
require.NoError(t, err)
363-
364353
htlc, err := NewHtlc(
365-
HtlcV3, cltvExpiry, senderKey, receiverKey, randomSharedPubKey,
354+
HtlcV3, cltvExpiry, senderKey, receiverKey,
366355
hashedPreimage, HtlcP2TR, &chaincfg.MainNetParams,
367356
)
368357
require.NoError(t, err)
@@ -544,18 +533,9 @@ func TestHtlcV3(t *testing.T) {
544533
bogusKey.SerializeCompressed(),
545534
)
546535

547-
var shnorrSenderKey [32]byte
548-
copy(
549-
shnorrSenderKey[:],
550-
schnorr.SerializePubKey(
551-
senderPubKey,
552-
),
553-
)
554-
555536
htlc, err := NewHtlc(
556537
HtlcV3, cltvExpiry, bogusKeyBytes,
557-
receiverKey, randomSharedPubKey,
558-
hashedPreimage, HtlcP2TR,
538+
receiverKey, hashedPreimage, HtlcP2TR,
559539
&chaincfg.MainNetParams,
560540
)
561541
require.NoError(t, err)
@@ -576,7 +556,7 @@ func TestHtlcV3(t *testing.T) {
576556
)
577557

578558
timeoutScript, err := GenTimeoutPathScript(
579-
shnorrSenderKey, int64(cltvExpiry),
559+
senderPubKey, int64(cltvExpiry),
580560
)
581561
require.NoError(t, err)
582562

0 commit comments

Comments
 (0)