Skip to content

Commit

Permalink
Merge pull request #7994 from Roasbeef/remote-signer-musig2-nonces
Browse files Browse the repository at this point in the history
multi: add ability to specify local nonces for musig2 signer rpc, add itest for remote signer taproot chans
  • Loading branch information
Roasbeef authored Sep 18, 2023
2 parents 2359481 + 6c3a55d commit 7412482
Show file tree
Hide file tree
Showing 13 changed files with 300 additions and 160 deletions.
7 changes: 7 additions & 0 deletions docs/release-notes/release-notes-0.17.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,13 @@ None
* Add [`--unused`](https://github.com/lightningnetwork/lnd/pull/6387) to
`lncli newaddr` command.

* [The `MuSig2SessionRequest` proto message now contains a field to allow a
caller to specify a custom signing
nonce](https://github.com/lightningnetwork/lnd/pull/7994). This can be useful
for protocol where an external nonces must be pre-generated before the full
session can be completed.


## Code Health
* Updated [our fork for serializing protobuf as JSON to be based on the
latest version of `google.golang.org/protobuf` instead of the deprecated
Expand Down
26 changes: 17 additions & 9 deletions input/musig2.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ type MuSig2Signer interface {
// already known, they can be submitted as well to reduce the number of
// method calls necessary later on.
//
// The set of sessionOpts are _optional_ and allow a caller to modify
// the generated sessions. As an example the local nonce might already
// be generated ahead of time.
// The localNonces field is optional. If it is set, then the specified
// nonces will be used instead of generating from scratch. This is
// useful in instances where the nonces are generated ahead of time
// before the set of signers is known.
MuSig2CreateSession(MuSig2Version, keychain.KeyLocator,
[]*btcec.PublicKey, *MuSig2Tweaks, [][musig2.PubNonceSize]byte,
...musig2.SessionOption) (*MuSig2SessionInfo, error)
*musig2.Nonces) (*MuSig2SessionInfo, error)

// MuSig2RegisterNonces registers one or more public nonces of other
// signing participants for a session identified by its ID. This method
Expand Down Expand Up @@ -379,18 +380,18 @@ func combineKeysV040(allSignerPubKeys []*btcec.PublicKey, sortKeys bool,
// MuSig2CreateContext creates a new MuSig2 signing context.
func MuSig2CreateContext(bipVersion MuSig2Version, privKey *btcec.PrivateKey,
allSignerPubKeys []*btcec.PublicKey, tweaks *MuSig2Tweaks,
sessionOpts ...musig2.SessionOption,
localNonces *musig2.Nonces,
) (MuSig2Context, MuSig2Session, error) {

switch bipVersion {
case MuSig2Version040:
return createContextV040(
privKey, allSignerPubKeys, tweaks, sessionOpts...,
privKey, allSignerPubKeys, tweaks, localNonces,
)

case MuSig2Version100RC2:
return createContextV100RC2(
privKey, allSignerPubKeys, tweaks, sessionOpts...,
privKey, allSignerPubKeys, tweaks, localNonces,
)

default:
Expand All @@ -403,7 +404,7 @@ func MuSig2CreateContext(bipVersion MuSig2Version, privKey *btcec.PrivateKey,
// BIP draft version 1.0.0rc2.
func createContextV100RC2(privKey *btcec.PrivateKey,
allSignerPubKeys []*btcec.PublicKey, tweaks *MuSig2Tweaks,
sessionOpts ...musig2.SessionOption,
localNonces *musig2.Nonces,
) (*musig2.Context, *musig2.Session, error) {

// The context keeps track of all signing keys and our local key.
Expand All @@ -419,6 +420,13 @@ func createContextV100RC2(privKey *btcec.PrivateKey,
"context: %v", err)
}

var sessionOpts []musig2.SessionOption
if localNonces != nil {
sessionOpts = append(
sessionOpts, musig2.WithPreGeneratedNonce(localNonces),
)
}

muSigSession, err := muSigContext.NewSession(sessionOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating MuSig2 signing "+
Expand All @@ -432,7 +440,7 @@ func createContextV100RC2(privKey *btcec.PrivateKey,
// draft version 0.4.0.
func createContextV040(privKey *btcec.PrivateKey,
allSignerPubKeys []*btcec.PublicKey, tweaks *MuSig2Tweaks,
_ ...musig2.SessionOption,
_ *musig2.Nonces,
) (*musig2v040.Context, *musig2v040.Session, error) {

// The context keeps track of all signing keys and our local key.
Expand Down
4 changes: 2 additions & 2 deletions input/musig2_session_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func NewMusigSessionManager(keyFetcher PrivKeyFetcher) *MusigSessionManager {
func (m *MusigSessionManager) MuSig2CreateSession(bipVersion MuSig2Version,
keyLoc keychain.KeyLocator, allSignerPubKeys []*btcec.PublicKey,
tweaks *MuSig2Tweaks, otherSignerNonces [][musig2.PubNonceSize]byte,
sessionOpts ...musig2.SessionOption) (*MuSig2SessionInfo, error) {
localNonces *musig2.Nonces) (*MuSig2SessionInfo, error) {

// We need to derive the private key for signing. In the remote signing
// setup, this whole RPC call will be forwarded to the signing
Expand All @@ -78,7 +78,7 @@ func (m *MusigSessionManager) MuSig2CreateSession(bipVersion MuSig2Version,
// Create a signing context and session with the given private key and
// list of all known signer public keys.
musigContext, musigSession, err := MuSig2CreateContext(
bipVersion, privKey, allSignerPubKeys, tweaks, sessionOpts...,
bipVersion, privKey, allSignerPubKeys, tweaks, localNonces,
)
if err != nil {
return nil, fmt.Errorf("error creating signing context: %w",
Expand Down
23 changes: 19 additions & 4 deletions itest/lnd_payment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,19 +233,34 @@ func testAsyncPayments(ht *lntest.HarnessTest) {
ht.EnsureConnected(alice, bob)
ht.FundCoins(btcutil.SatoshiPerBitcoin, alice)

runAsyncPayments(ht, alice, bob)
runAsyncPayments(ht, alice, bob, nil)
}

// runAsyncPayments tests the performance of the async payments.
func runAsyncPayments(ht *lntest.HarnessTest, alice, bob *node.HarnessNode) {
func runAsyncPayments(ht *lntest.HarnessTest, alice, bob *node.HarnessNode,
commitType *lnrpc.CommitmentType) {

const paymentAmt = 100

channelCapacity := btcutil.Amount(paymentAmt * 2000)

chanArgs := lntest.OpenChannelParams{
Amt: channelCapacity,
}

if commitType != nil {
chanArgs.CommitmentType = *commitType

if *commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT {
chanArgs.Private = true
}
}

// First establish a channel with a capacity equals to the overall
// amount of payments, between Alice and Bob, at the end of the test
// Alice should send all money from her side to Bob.
channelCapacity := btcutil.Amount(paymentAmt * 2000)
chanPoint := ht.OpenChannel(
alice, bob, lntest.OpenChannelParams{Amt: channelCapacity},
alice, bob, chanArgs,
)

info := ht.QueryChannelByChanPoint(alice, chanPoint)
Expand Down
28 changes: 24 additions & 4 deletions itest/lnd_remote_signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func testRemoteSigner(ht *lntest.HarnessTest) {
name string
randomSeed bool
sendCoins bool
commitType lnrpc.CommitmentType
fn func(tt *lntest.HarnessTest,
wo, carol *node.HarnessNode)
}
Expand Down Expand Up @@ -94,8 +95,19 @@ func testRemoteSigner(ht *lntest.HarnessTest) {
name: "async payments",
sendCoins: true,
fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
runAsyncPayments(tt, wo, carol)
runAsyncPayments(tt, wo, carol, nil)
},
}, {
name: "async payments taproot",
sendCoins: true,
fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
commitType := lnrpc.CommitmentType_SIMPLE_TAPROOT

runAsyncPayments(
tt, wo, carol, &commitType,
)
},
commitType: lnrpc.CommitmentType_SIMPLE_TAPROOT,
}, {
name: "shared key",
fn: func(tt *lntest.HarnessTest, wo, carol *node.HarnessNode) {
Expand Down Expand Up @@ -199,11 +211,18 @@ func testRemoteSigner(ht *lntest.HarnessTest) {
require.NoError(st, err)
}

var commitArgs []string
if subTest.commitType == lnrpc.CommitmentType_SIMPLE_TAPROOT {
commitArgs = lntest.NodeArgsForCommitType(
subTest.commitType,
)
}

// WatchOnly is the node that has a watch-only wallet and uses
// the Signer node for any operation that requires access to
// private keys.
watchOnly := st.NewNodeRemoteSigner(
"WatchOnly", []string{
"WatchOnly", append([]string{
"--remotesigner.enable",
fmt.Sprintf(
"--remotesigner.rpchost=localhost:%d",
Expand All @@ -217,7 +236,8 @@ func testRemoteSigner(ht *lntest.HarnessTest) {
"--remotesigner.macaroonpath=%s",
signer.Cfg.AdminMacPath,
),
}, password, &lnrpc.WatchOnly{
}, commitArgs...),
password, &lnrpc.WatchOnly{
MasterKeyBirthdayTimestamp: 0,
MasterKeyFingerprint: nil,
Accounts: watchOnlyAccounts,
Expand All @@ -235,7 +255,7 @@ func testRemoteSigner(ht *lntest.HarnessTest) {
)
}

carol := st.NewNode("carol", nil)
carol := st.NewNode("carol", commitArgs)
st.EnsureConnected(watchOnly, carol)

return signer, watchOnly, carol
Expand Down
Loading

0 comments on commit 7412482

Please sign in to comment.