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"
"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"
invpkg "github.com/lightningnetwork/lnd/invoices"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lntypes"
@ -189,6 +191,23 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
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.
probeWaitCtx, probeWaitCancel := context.WithCancel(globalCtx)
@ -204,8 +223,8 @@ func newLoopInSwap(globalCtx context.Context, cfg *swapConfig,
// htlc.
log.Infof("Initiating swap request at height %v", currentHeight)
swapResp, err := cfg.server.NewLoopInSwap(globalCtx, swapHash,
request.Amount, senderKey, swapInvoice, probeInvoice,
request.LastHop, request.Initiator,
request.Amount, senderKey, senderInternalPubKey, swapInvoice,
probeInvoice, request.LastHop, request.Initiator,
)
probeWaitCancel()
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(
swapHash, swap.TypeIn,
cfg, &contract.SwapContract,
@ -1031,3 +1057,18 @@ func (s *loopInSwap) setState(state loopdb.SwapState) {
s.lastUpdateTime = time.Now()
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,
amount btcutil.Amount, _ [33]byte, swapInvoice, _ string,
amount btcutil.Amount, _, _ [33]byte, swapInvoice, _ string,
_ *route.Vertex, _ string) (*newLoopInResponse, error) {
_, receiverKey := test.CreateKey(101)
_, receiverInternalKey := test.CreateKey(102)
if amount != s.expectedSwapAmt {
return nil, errors.New("unexpected test swap amount")
}
var receiverKeyArray [33]byte
var receiverKeyArray, receiverInternalKeyArray [33]byte
copy(receiverKeyArray[:], receiverKey.SerializeCompressed())
copy(
receiverInternalKeyArray[:],
receiverInternalKey.SerializeCompressed(),
)
s.swapInvoice = swapInvoice
s.swapHash = swapHash
@ -175,8 +180,9 @@ func (s *serverMock) NewLoopInSwap(_ context.Context, swapHash lntypes.Hash,
<-s.lnd.FailInvoiceChannel
resp := &newLoopInResponse{
expiry: s.height + testChargeOnChainCltvDelta,
receiverKey: receiverKeyArray,
expiry: s.height + testChargeOnChainCltvDelta,
receiverKey: receiverKeyArray,
receiverInternalKey: receiverInternalKeyArray,
}
return resp, nil

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

Loading…
Cancel
Save