loopin: generate and send internal key for MuSig2 swaps

This commit changes how we create loopin swaps if the client activates
the experimental MuSig2 features. When creating a new loopin swap the
client will create (and store) a new key that will be used as the
sender's internal key when constructing the HTLC. The client will send
the public part to the server and will also receive (and store) the
server's (receiver) internal public key.
pull/547/head
Andras Banki-Horvath 1 year ago
parent da4bcbea10
commit 90ae922adf
No known key found for this signature in database
GPG Key ID: 80E5375C094198D8

@ -9,6 +9,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/mempool" "github.com/btcsuite/btcd/mempool"
@ -19,6 +20,7 @@ import (
"github.com/lightninglabs/loop/swap" "github.com/lightninglabs/loop/swap"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
invpkg "github.com/lightningnetwork/lnd/invoices" invpkg "github.com/lightningnetwork/lnd/invoices"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc" "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc" "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntypes" "github.com/lightningnetwork/lnd/lntypes"
@ -189,6 +191,23 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
return nil, err return nil, err
} }
// Default the HTLC internal key to our sender key.
senderInternalPubKey := senderKey
// If this is a MuSig2 swap then we'll generate a brand new key pair
// and will use that as the internal key for the HTLC.
if loopdb.CurrentProtocolVersion() >= loopdb.ProtocolVersionMuSig2 {
secret, err := sharedSecretFromHash(
globalCtx, cfg.lnd.Signer, swapHash,
)
if err != nil {
return nil, err
}
_, pubKey := btcec.PrivKeyFromBytes(secret[:])
copy(senderInternalPubKey[:], pubKey.SerializeCompressed())
}
// Create a cancellable context that is used for monitoring the probe. // Create a cancellable context that is used for monitoring the probe.
probeWaitCtx, probeWaitCancel := context.WithCancel(globalCtx) probeWaitCtx, probeWaitCancel := context.WithCancel(globalCtx)
@ -204,8 +223,8 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
// htlc. // htlc.
log.Infof("Initiating swap request at height %v", currentHeight) log.Infof("Initiating swap request at height %v", currentHeight)
swapResp, err := cfg.server.NewLoopInSwap(globalCtx, swapHash, swapResp, err := cfg.server.NewLoopInSwap(globalCtx, swapHash,
request.Amount, senderKey, swapInvoice, probeInvoice, request.Amount, senderKey, senderInternalPubKey, swapInvoice,
request.LastHop, request.Initiator, probeInvoice, request.LastHop, request.Initiator,
) )
probeWaitCancel() probeWaitCancel()
if err != nil { if err != nil {
@ -254,6 +273,13 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
}, },
} }
// For MuSig2 swaps we store the proper internal keys that we generated
// and received from the server.
if loopdb.CurrentProtocolVersion() >= loopdb.ProtocolVersionMuSig2 {
contract.HtlcKeys.SenderInternalPubKey = senderInternalPubKey
contract.HtlcKeys.ReceiverInternalPubKey = swapResp.receiverInternalKey
}
swapKit := newSwapKit( swapKit := newSwapKit(
swapHash, swap.TypeIn, swapHash, swap.TypeIn,
cfg, &contract.SwapContract, cfg, &contract.SwapContract,
@ -1031,3 +1057,18 @@ func (s *loopInSwap) setState(state loopdb.SwapState) {
s.lastUpdateTime = time.Now() s.lastUpdateTime = time.Now()
s.state = state s.state = state
} }
// sharedSecretFromHash derives the shared secret from the swap hash using the
// swap.KeyFamily family and zero as index.
func sharedSecretFromHash(ctx context.Context, signer lndclient.SignerClient,
hash lntypes.Hash) ([32]byte, error) {
_, hashPubKey := btcec.PrivKeyFromBytes(hash[:])
return signer.DeriveSharedKey(
ctx, hashPubKey, &keychain.KeyLocator{
Family: keychain.KeyFamily(swap.KeyFamily),
Index: 0,
},
)
}

@ -151,17 +151,22 @@ func getInvoice(hash lntypes.Hash, amt btcutil.Amount, memo string) (string, err
} }
func (s *serverMock) NewLoopInSwap(_ context.Context, swapHash lntypes.Hash, func (s *serverMock) NewLoopInSwap(_ context.Context, swapHash lntypes.Hash,
amount btcutil.Amount, _ [33]byte, swapInvoice, _ string, amount btcutil.Amount, _, _ [33]byte, swapInvoice, _ string,
_ *route.Vertex, _ string) (*newLoopInResponse, error) { _ *route.Vertex, _ string) (*newLoopInResponse, error) {
_, receiverKey := test.CreateKey(101) _, receiverKey := test.CreateKey(101)
_, receiverInternalKey := test.CreateKey(102)
if amount != s.expectedSwapAmt { if amount != s.expectedSwapAmt {
return nil, errors.New("unexpected test swap amount") return nil, errors.New("unexpected test swap amount")
} }
var receiverKeyArray [33]byte var receiverKeyArray, receiverInternalKeyArray [33]byte
copy(receiverKeyArray[:], receiverKey.SerializeCompressed()) copy(receiverKeyArray[:], receiverKey.SerializeCompressed())
copy(
receiverInternalKeyArray[:],
receiverInternalKey.SerializeCompressed(),
)
s.swapInvoice = swapInvoice s.swapInvoice = swapInvoice
s.swapHash = swapHash s.swapHash = swapHash
@ -175,8 +180,9 @@ func (s *serverMock) NewLoopInSwap(_ context.Context, swapHash lntypes.Hash,
<-s.lnd.FailInvoiceChannel <-s.lnd.FailInvoiceChannel
resp := &newLoopInResponse{ resp := &newLoopInResponse{
expiry: s.height + testChargeOnChainCltvDelta, expiry: s.height + testChargeOnChainCltvDelta,
receiverKey: receiverKeyArray, receiverKey: receiverKeyArray,
receiverInternalKey: receiverInternalKeyArray,
} }
return resp, nil return resp, nil

@ -94,10 +94,10 @@ type swapServerClient interface {
preimage lntypes.Preimage) error preimage lntypes.Preimage) error
NewLoopInSwap(ctx context.Context, NewLoopInSwap(ctx context.Context,
swapHash lntypes.Hash, amount btcutil.Amount, swapHash lntypes.Hash, amount btcutil.Amount, senderScriptKey,
senderKey [33]byte, swapInvoice, probeInvoice string, senderInternalKey [33]byte, swapInvoice, probeInvoice string,
lastHop *route.Vertex, initiator string) (*newLoopInResponse, lastHop *route.Vertex, initiator string) (
error) *newLoopInResponse, error)
// SubscribeLoopOutUpdates subscribes to loop out server state. // SubscribeLoopOutUpdates subscribes to loop out server state.
SubscribeLoopOutUpdates(ctx context.Context, SubscribeLoopOutUpdates(ctx context.Context,
@ -419,9 +419,9 @@ func (s *grpcSwapServerClient) PushLoopOutPreimage(ctx context.Context,
} }
func (s *grpcSwapServerClient) NewLoopInSwap(ctx context.Context, func (s *grpcSwapServerClient) NewLoopInSwap(ctx context.Context,
swapHash lntypes.Hash, amount btcutil.Amount, senderKey [33]byte, swapHash lntypes.Hash, amount btcutil.Amount, senderScriptKey,
swapInvoice, probeInvoice string, lastHop *route.Vertex, senderInternalKey [33]byte, swapInvoice, probeInvoice string,
initiator string) (*newLoopInResponse, error) { lastHop *route.Vertex, initiator string) (*newLoopInResponse, error) {
rpcCtx, rpcCancel := context.WithTimeout(ctx, globalCallTimeout) rpcCtx, rpcCancel := context.WithTimeout(ctx, globalCallTimeout)
defer rpcCancel() defer rpcCancel()
@ -429,7 +429,7 @@ func (s *grpcSwapServerClient) NewLoopInSwap(ctx context.Context,
req := &looprpc.ServerLoopInRequest{ req := &looprpc.ServerLoopInRequest{
SwapHash: swapHash[:], SwapHash: swapHash[:],
Amt: uint64(amount), Amt: uint64(amount),
SenderKey: senderKey[:], SenderKey: senderScriptKey[:],
SwapInvoice: swapInvoice, SwapInvoice: swapInvoice,
ProtocolVersion: loopdb.CurrentRPCProtocolVersion(), ProtocolVersion: loopdb.CurrentRPCProtocolVersion(),
ProbeInvoice: probeInvoice, ProbeInvoice: probeInvoice,
@ -439,13 +439,19 @@ func (s *grpcSwapServerClient) NewLoopInSwap(ctx context.Context,
req.LastHop = lastHop[:] req.LastHop = lastHop[:]
} }
// Set the client's internal key if this is a MuSig2 swap.
if loopdb.CurrentProtocolVersion() >= loopdb.ProtocolVersionMuSig2 {
req.SenderInternalPubkey = senderInternalKey[:]
}
swapResp, err := s.server.NewLoopInSwap(rpcCtx, req) swapResp, err := s.server.NewLoopInSwap(rpcCtx, req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var receiverKey [33]byte var receiverKey, receiverInternalKey [33]byte
copy(receiverKey[:], swapResp.ReceiverKey) copy(receiverKey[:], swapResp.ReceiverKey)
copy(receiverInternalKey[:], swapResp.ReceiverInternalPubkey)
// Validate receiver key. // Validate receiver key.
_, err = btcec.ParsePubKey(receiverKey[:]) _, err = btcec.ParsePubKey(receiverKey[:])
@ -454,9 +460,10 @@ func (s *grpcSwapServerClient) NewLoopInSwap(ctx context.Context,
} }
return &newLoopInResponse{ return &newLoopInResponse{
receiverKey: receiverKey, receiverKey: receiverKey,
expiry: swapResp.Expiry, receiverInternalKey: receiverInternalKey,
serverMessage: swapResp.ServerMessage, expiry: swapResp.Expiry,
serverMessage: swapResp.ServerMessage,
}, nil }, nil
} }
@ -873,7 +880,8 @@ type newLoopOutResponse struct {
} }
type newLoopInResponse struct { type newLoopInResponse struct {
receiverKey [33]byte receiverKey [33]byte
expiry int32 receiverInternalKey [33]byte
serverMessage string expiry int32
serverMessage string
} }

Loading…
Cancel
Save