Skip to content

Commit

Permalink
swap: pass in MuSig2 version when creating taproot HTLCs
Browse files Browse the repository at this point in the history
This commit adds the MuSig2 version as an input parameter when creating
Taproot htlcs. This will allow us to create both old and new MuSig2
Taproot HTLCs correctly.
  • Loading branch information
bhandras committed Feb 6, 2023
1 parent 476f472 commit e8cfe4c
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 26 deletions.
2 changes: 2 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/swap"
"github.com/lightninglabs/loop/test"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -285,6 +286,7 @@ func testLoopOutResume(t *testing.T, confs uint32, expired, preimageRevealed,

case swap.HtlcV3:
htlc, err = swap.NewHtlcV3(
input.MuSig2Version040,
pendingSwap.Contract.CltvExpiry, senderKey,
receiverKey, senderKey, receiverKey, hash,
&chaincfg.TestNet3Params,
Expand Down
2 changes: 2 additions & 0 deletions loopin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/lightninglabs/loop/swap"
"github.com/lightninglabs/loop/test"
"github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/input"
invpkg "github.com/lightningnetwork/lnd/invoices"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -459,6 +460,7 @@ func testLoopInResume(t *testing.T, state loopdb.SwapState, expired bool,

case swap.HtlcV3:
htlc, err = swap.NewHtlcV3(
input.MuSig2Version040,
contract.CltvExpiry, contract.SenderKey,
contract.ReceiverKey, contract.SenderKey,
contract.ReceiverKey, testPreimage.Hash(),
Expand Down
2 changes: 2 additions & 0 deletions swap.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/loop/loopdb"
"github.com/lightninglabs/loop/swap"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/lntypes"
)

Expand Down Expand Up @@ -82,6 +83,7 @@ func GetHtlc(hash lntypes.Hash, contract *loopdb.SwapContract,

case swap.HtlcV3:
return swap.NewHtlcV3(
input.MuSig2Version040,
contract.CltvExpiry, contract.SenderKey,
contract.ReceiverKey, contract.SenderKey,
contract.ReceiverKey, hash,
Expand Down
69 changes: 46 additions & 23 deletions swap/htlc.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ var (
// QuoteHtlcP2TR is a template script just used for sweep fee
// estimation.
QuoteHtlcP2TR, _ = NewHtlcV3(
^int32(0), dummyPubKey, dummyPubKey, dummyPubKey, dummyPubKey,
quoteHash, &chaincfg.MainNetParams,
input.MuSig2Version100RC2, ^int32(0), dummyPubKey, dummyPubKey,
dummyPubKey, dummyPubKey, quoteHash, &chaincfg.MainNetParams,
)

// ErrInvalidScriptVersion is returned when an unknown htlc version
Expand Down Expand Up @@ -188,13 +188,13 @@ func NewHtlcV2(cltvExpiry int32, senderKey, receiverKey [33]byte,

// NewHtlcV3 returns a new V3 HTLC (P2TR) instance. Internal pubkey generated
// by both participants must be provided.
func NewHtlcV3(cltvExpiry int32, senderInternalKey, receiverInternalKey,
senderKey, receiverKey [33]byte, hash lntypes.Hash,
chainParams *chaincfg.Params) (*Htlc, error) {
func NewHtlcV3(muSig2Version input.MuSig2Version, cltvExpiry int32,
senderInternalKey, receiverInternalKey, senderKey, receiverKey [33]byte,
hash lntypes.Hash, chainParams *chaincfg.Params) (*Htlc, error) {

htlc, err := newHTLCScriptV3(
cltvExpiry, senderInternalKey, receiverInternalKey,
senderKey, receiverKey, hash,
muSig2Version, cltvExpiry, senderInternalKey,
receiverInternalKey, senderKey, receiverKey, hash,
)

if err != nil {
Expand Down Expand Up @@ -504,17 +504,37 @@ type HtlcScriptV3 struct {
RootHash chainhash.Hash
}

// parsePubKey will parse a serialized public key into a btcec.PublicKey
// depending on the passed MuSig2 version.
func parsePubKey(muSig2Version input.MuSig2Version, key [33]byte) (
*btcec.PublicKey, error) {

// Make sure that we have the correct public keys depending on the
// MuSig2 version.
switch muSig2Version {
case input.MuSig2Version100RC2:
return btcec.ParsePubKey(key[:])

case input.MuSig2Version040:
return schnorr.ParsePubKey(key[1:])

default:
return nil, fmt.Errorf("unsupported MuSig2 version: %v",
muSig2Version)
}
}

// newHTLCScriptV3 constructs a HtlcScipt with the HTLC V3 taproot script.
func newHTLCScriptV3(cltvExpiry int32, senderInternalKey, receiverInternalKey,
senderHtlcKey, receiverHtlcKey [33]byte,
swapHash lntypes.Hash) (*HtlcScriptV3, error) {
func newHTLCScriptV3(muSig2Version input.MuSig2Version, cltvExpiry int32,
senderInternalKey, receiverInternalKey, senderHtlcKey,
receiverHtlcKey [33]byte, swapHash lntypes.Hash) (*HtlcScriptV3, error) {

senderPubKey, err := schnorr.ParsePubKey(senderHtlcKey[1:])
senderPubKey, err := parsePubKey(muSig2Version, senderHtlcKey)
if err != nil {
return nil, err
}

receiverPubKey, err := schnorr.ParsePubKey(receiverHtlcKey[1:])
receiverPubKey, err := parsePubKey(muSig2Version, receiverHtlcKey)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -548,38 +568,41 @@ func newHTLCScriptV3(cltvExpiry int32, senderInternalKey, receiverInternalKey,
// Parse the pub keys used in the internal aggregate key. They are
// optional and may just be the same keys that are used for the script
// paths.
senderInternalPubKey, err := schnorr.ParsePubKey(senderInternalKey[1:])
senderInternalPubKey, err := parsePubKey(
muSig2Version, senderInternalKey,
)
if err != nil {
return nil, err
}

receiverInternalPubKey, err := schnorr.ParsePubKey(
receiverInternalKey[1:],
receiverInternalPubKey, err := parsePubKey(
muSig2Version, receiverInternalKey,
)
if err != nil {
return nil, err
}

var aggregateKey *musig2.AggregateKey
// Calculate the internal aggregate key.
aggregateKey, _, _, err := musig2.AggregateKeys(
aggregateKey, err = input.MuSig2CombineKeys(
muSig2Version,
[]*btcec.PublicKey{
senderInternalPubKey, receiverInternalPubKey,
}, true,
},
true,
&input.MuSig2Tweaks{
TaprootTweak: rootHash[:],
},
)
if err != nil {
return nil, err
}

// Calculate top level taproot key.
taprootKey := txscript.ComputeTaprootOutputKey(
aggregateKey.PreTweakedKey, rootHash[:],
)

return &HtlcScriptV3{
timeoutScript: timeoutPathScript,
successScript: successPathScript,
InternalPubKey: aggregateKey.PreTweakedKey,
TaprootKey: taprootKey,
TaprootKey: aggregateKey.FinalKey,
RootHash: rootHash,
}, nil
}
Expand Down
19 changes: 16 additions & 3 deletions swap/htlc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,19 @@ func TestHtlcV2(t *testing.T) {

// TestHtlcV3 tests the HTLC V3 script success and timeout spend cases.
func TestHtlcV3(t *testing.T) {
versions := map[string]input.MuSig2Version{
"MuSig2 0.4": input.MuSig2Version040,
"MuSig2 1.0RC2": input.MuSig2Version100RC2,
}

for name, version := range versions {
t.Run(name, func(t *testing.T) {
testHtlcV3(t, version)
})
}
}

func testHtlcV3(t *testing.T, muSig2Version input.MuSig2Version) {
var (
receiverKey [33]byte
senderKey [33]byte
Expand All @@ -355,8 +368,8 @@ func TestHtlcV3(t *testing.T) {
copy(senderKey[:], senderPubKey.SerializeCompressed())

htlc, err := NewHtlcV3(
cltvExpiry, senderKey, receiverKey, senderKey, receiverKey,
hashedPreimage, &chaincfg.MainNetParams,
muSig2Version, cltvExpiry, senderKey, receiverKey, senderKey,
receiverKey, hashedPreimage, &chaincfg.MainNetParams,
)
require.NoError(t, err)

Expand Down Expand Up @@ -538,7 +551,7 @@ func TestHtlcV3(t *testing.T) {
)

htlc, err := NewHtlcV3(
cltvExpiry, senderKey,
muSig2Version, cltvExpiry, senderKey,
receiverKey, bogusKeyBytes, receiverKey,
hashedPreimage, &chaincfg.MainNetParams,
)
Expand Down

0 comments on commit e8cfe4c

Please sign in to comment.