diff --git a/loopin.go b/loopin.go index 3863444..c3c002f 100644 --- a/loopin.go +++ b/loopin.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/mempool" @@ -19,6 +20,7 @@ import ( "github.com/lightninglabs/loop/swap" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lnwallet/chainfee" @@ -248,9 +250,17 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig, }, } + // TODO - add nonce to server reponse and add to session + session, err := swap.NewMusig2Session( + globalCtx, cfg.lnd, keyDesc, swapResp.receiverKey, + ) + if err != nil { + return nil, err + } + swapKit := newSwapKit( swapHash, swap.TypeIn, - cfg, &contract.SwapContract, + cfg, &contract.SwapContract, session, ) swapKit.lastUpdateTime = initiationTime @@ -349,16 +359,34 @@ func awaitProbe(ctx context.Context, lnd lndclient.LndServices, // resumeLoopInSwap returns a swap object representing a pending swap that has // been restored from the database. -func resumeLoopInSwap(_ context.Context, cfg *swapConfig, +func resumeLoopInSwap(ctx context.Context, cfg *swapConfig, pend *loopdb.LoopIn) (*loopInSwap, error) { hash := lntypes.Hash(sha256.Sum256(pend.Contract.Preimage[:])) log.Infof("Resuming loop in swap %v", hash) + pubkey, err := btcec.ParsePubKey(pend.Contract.SenderKey[:]) + if err != nil { + return nil, err + } + + keyDesc := &keychain.KeyDescriptor{ + PubKey: pubkey, + // TODO - NB! get locator for key, otherwise we won't resume + // session with the right key. + KeyLocator: keychain.KeyLocator{}, + } + session, err := swap.NewMusig2Session( + ctx, cfg.lnd, keyDesc, pend.Contract.ReceiverKey, + ) + if err != nil { + return nil, err + } + swapKit := newSwapKit( hash, swap.TypeIn, cfg, - &pend.Contract.SwapContract, + &pend.Contract.SwapContract, session, ) swap := &loopInSwap{ diff --git a/loopout.go b/loopout.go index d348b7b..f4c32dc 100644 --- a/loopout.go +++ b/loopout.go @@ -10,6 +10,8 @@ import ( "sync" "time" + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/wire" @@ -20,6 +22,7 @@ import ( "github.com/lightninglabs/loop/sweep" "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/channeldb" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnrpc" "github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/zpay32" @@ -153,6 +156,22 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig, confs = loopdb.DefaultLoopOutHtlcConfirmations } + // Create a musig session using the key and nonce shared from the + // server. + var serverNonce [musig2.PubNonceSize]byte + copy(serverNonce[:], swapResp.nonce[:]) + + opt := lndclient.MusigNonceOpt([][musig2.PubNonceSize]byte{ + serverNonce, + }) + + session, err := swap.NewMusig2Session( + globalCtx, cfg.lnd, keyDesc, swapResp.senderKey, opt, + ) + if err != nil { + return nil, err + } + // Instantiate a struct that contains all required data to start the // swap. initiationTime := time.Now() @@ -184,7 +203,7 @@ func newLoopOutSwap(globalCtx context.Context, cfg *swapConfig, swapKit := newSwapKit( swapHash, swap.TypeOut, - cfg, &contract.SwapContract, + cfg, &contract.SwapContract, session, ) swapKit.lastUpdateTime = initiationTime @@ -238,9 +257,27 @@ func resumeLoopOutSwap(reqContext context.Context, cfg *swapConfig, log.Infof("Resuming loop out swap %v", hash) + pubkey, err := btcec.ParsePubKey(pend.Contract.ReceiverKey[:]) + if err != nil { + return nil, err + } + + keyDesc := &keychain.KeyDescriptor{ + PubKey: pubkey, + // TODO - get key locator or we will resume with the wrong + // key!! + KeyLocator: keychain.KeyLocator{}, + } + session, err := swap.NewMusig2Session( + reqContext, cfg.lnd, keyDesc, pend.Contract.SenderKey, + ) + if err != nil { + return nil, err + } + swapKit := newSwapKit( hash, swap.TypeOut, cfg, - &pend.Contract.SwapContract, + &pend.Contract.SwapContract, session, ) // Create the htlc. diff --git a/swap.go b/swap.go index 193bdde..eb40597 100644 --- a/swap.go +++ b/swap.go @@ -28,10 +28,13 @@ type swapKit struct { swapType swap.Type swapConfig + + musig2Session *lndclient.MuSig2Session } func newSwapKit(hash lntypes.Hash, swapType swap.Type, cfg *swapConfig, - contract *loopdb.SwapContract) *swapKit { + contract *loopdb.SwapContract, + session *lndclient.MuSig2Session) *swapKit { log := &swap.PrefixLog{ Hash: hash, @@ -39,12 +42,13 @@ func newSwapKit(hash lntypes.Hash, swapType swap.Type, cfg *swapConfig, } return &swapKit{ - swapConfig: *cfg, - hash: hash, - log: log, - state: loopdb.StateInitiated, - contract: contract, - swapType: swapType, + swapConfig: *cfg, + hash: hash, + log: log, + state: loopdb.StateInitiated, + contract: contract, + swapType: swapType, + musig2Session: session, } } diff --git a/swap/musig2.go b/swap/musig2.go new file mode 100644 index 0000000..a46e1c2 --- /dev/null +++ b/swap/musig2.go @@ -0,0 +1,29 @@ +package swap + +import ( + "context" + + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/btcec/v2/schnorr" + "github.com/lightninglabs/lndclient" + "github.com/lightningnetwork/lnd/keychain" +) + +// NewMuSig2Session creates a new musig session. +func NewMusig2Session(ctx context.Context, lnd *lndclient.LndServices, + ourKey *keychain.KeyDescriptor, theirKey [33]byte, + opts ...lndclient.MuSigSessionOpts) (*lndclient.MuSig2Session, error) { + + theirPubkey, err := btcec.ParsePubKey(theirKey[:]) + if err != nil { + return nil, err + } + + signers := make([][32]byte, 2) + copy(signers[0][:], schnorr.SerializePubKey(ourKey.PubKey)) + copy(signers[1][:], schnorr.SerializePubKey(theirPubkey)) + + return lnd.Signer.NewMuSig2Session( + ctx, &ourKey.KeyLocator, signers, opts..., + ) +}