mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 01:43:16 +01:00
input+lnwallet: move some MuSig2 calls to input pkg
As a preparation for making it possible to version switch calls to the MuSig2 API, we move some of the calls to the input package where in a future commit we'll call the corresponding code in the correct package.
This commit is contained in:
parent
4f5ede84c6
commit
13789f5d95
@ -145,6 +145,26 @@ func (t *MuSig2Tweaks) ToContextOptions() []musig2.ContextOption {
|
||||
return tweakOpts
|
||||
}
|
||||
|
||||
// MuSig2ParsePubKeys parses a list of raw public keys as the signing keys of a
|
||||
// MuSig2 signing session.
|
||||
func MuSig2ParsePubKeys(rawPubKeys [][]byte) ([]*btcec.PublicKey, error) {
|
||||
allSignerPubKeys := make([]*btcec.PublicKey, len(rawPubKeys))
|
||||
if len(rawPubKeys) < 2 {
|
||||
return nil, fmt.Errorf("need at least two signing public keys")
|
||||
}
|
||||
|
||||
for idx, pubKeyBytes := range rawPubKeys {
|
||||
pubKey, err := schnorr.ParsePubKey(pubKeyBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing signer public "+
|
||||
"key %d: %v", idx, err)
|
||||
}
|
||||
allSignerPubKeys[idx] = pubKey
|
||||
}
|
||||
|
||||
return allSignerPubKeys, nil
|
||||
}
|
||||
|
||||
// MuSig2CombineKeys combines the given set of public keys into a single
|
||||
// combined MuSig2 combined public key, applying the given tweaks.
|
||||
func MuSig2CombineKeys(allSignerPubKeys []*btcec.PublicKey,
|
||||
@ -173,6 +193,64 @@ func MuSig2CombineKeys(allSignerPubKeys []*btcec.PublicKey,
|
||||
return combinedKey, err
|
||||
}
|
||||
|
||||
// MuSig2CreateContext creates a new MuSig2 signing context.
|
||||
func MuSig2CreateContext(privKey *btcec.PrivateKey,
|
||||
allSignerPubKeys []*btcec.PublicKey,
|
||||
tweaks *MuSig2Tweaks) (*musig2.Context, *musig2.Session, error) {
|
||||
|
||||
// The context keeps track of all signing keys and our local key.
|
||||
allOpts := append(
|
||||
[]musig2.ContextOption{
|
||||
musig2.WithKnownSigners(allSignerPubKeys),
|
||||
},
|
||||
tweaks.ToContextOptions()...,
|
||||
)
|
||||
muSigContext, err := musig2.NewContext(privKey, true, allOpts...)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating MuSig2 signing "+
|
||||
"context: %v", err)
|
||||
}
|
||||
|
||||
muSigSession, err := muSigContext.NewSession()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("error creating MuSig2 signing "+
|
||||
"session: %v", err)
|
||||
}
|
||||
|
||||
return muSigContext, muSigSession, nil
|
||||
}
|
||||
|
||||
// MuSig2Sign calls the Sign() method on the given versioned signing session and
|
||||
// returns the result in the most recent version of the MuSig2 API.
|
||||
func MuSig2Sign(session *musig2.Session, msg [32]byte,
|
||||
withSortedKeys bool) (*musig2.PartialSignature, error) {
|
||||
|
||||
var opts []musig2.SignOption
|
||||
if withSortedKeys {
|
||||
opts = append(opts, musig2.WithSortedKeys())
|
||||
}
|
||||
partialSig, err := session.Sign(msg, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error signing with local key: %v", err)
|
||||
}
|
||||
|
||||
return partialSig, nil
|
||||
}
|
||||
|
||||
// MuSig2CombineSig calls the CombineSig() method on the given versioned signing
|
||||
// session and returns the result in the most recent version of the MuSig2 API.
|
||||
func MuSig2CombineSig(session *musig2.Session,
|
||||
otherPartialSig *musig2.PartialSignature) (bool, error) {
|
||||
|
||||
haveAllSigs, err := session.CombineSig(otherPartialSig)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error combining partial signature: "+
|
||||
"%v", err)
|
||||
}
|
||||
|
||||
return haveAllSigs, nil
|
||||
}
|
||||
|
||||
// NewMuSig2SessionID returns the unique ID of a MuSig2 session by using the
|
||||
// combined key and the local public nonces and hashing that data.
|
||||
func NewMuSig2SessionID(combinedKey *btcec.PublicKey,
|
||||
|
122
input/musig2_test.go
Normal file
122
input/musig2_test.go
Normal file
@ -0,0 +1,122 @@
|
||||
package input
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var (
|
||||
hexDecode = func(keyStr string) []byte {
|
||||
keyBytes, _ := hex.DecodeString(keyStr)
|
||||
return keyBytes
|
||||
}
|
||||
dummyPubKey1, _ = btcec.ParsePubKey(hexDecode(
|
||||
"02ec95e4e8ad994861b95fc5986eedaac24739e5ea3d0634db4c8ccd44cd" +
|
||||
"a126ea",
|
||||
))
|
||||
dummyPubKey2, _ = btcec.ParsePubKey(hexDecode(
|
||||
"0356167ba3e54ac542e86e906d4186aba9ca0b9df45001c62b753d33fe06" +
|
||||
"f5b4e8",
|
||||
))
|
||||
dummyPubKey3, _ = btcec.ParsePubKey(hexDecode(
|
||||
"02a9b0e1777e35d4620061a9fb0e614bf0254a50dea4f872babf6d44bf4d" +
|
||||
"8ee7c6",
|
||||
))
|
||||
|
||||
testVector040Key1, _ = schnorr.ParsePubKey(hexDecode(
|
||||
"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE0" +
|
||||
"36F9",
|
||||
))
|
||||
testVector040Key2, _ = schnorr.ParsePubKey(hexDecode(
|
||||
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502B" +
|
||||
"A659",
|
||||
))
|
||||
testVector040Key3, _ = schnorr.ParsePubKey(hexDecode(
|
||||
"3590A94E768F8E1815C2F24B4D80A8E3149316C3518CE7B7AD338368D038" +
|
||||
"CA66",
|
||||
))
|
||||
|
||||
bip86Tweak = &MuSig2Tweaks{TaprootBIP0086Tweak: true}
|
||||
)
|
||||
|
||||
func TestMuSig2CombineKeys(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
keys []*btcec.PublicKey
|
||||
tweak *MuSig2Tweaks
|
||||
expectedErr string
|
||||
expectedFinalKey string
|
||||
expectedPreTweakKey string
|
||||
}{{
|
||||
name: "v0.4.0 two dummy keys BIP86",
|
||||
keys: []*btcec.PublicKey{dummyPubKey1, dummyPubKey2},
|
||||
tweak: bip86Tweak,
|
||||
expectedFinalKey: "03b54fb320a8fc3589e86a1559c6aaa774fbab4e4d" +
|
||||
"9fbf31e2fd836b661ac6a132",
|
||||
expectedPreTweakKey: "0279c76a15dcf6786058a571e4022b78633e1bf" +
|
||||
"8a7a4ca440bcbbeeaea772228a2",
|
||||
}, {
|
||||
name: "v0.4.0 three dummy keys BIP86",
|
||||
keys: []*btcec.PublicKey{
|
||||
dummyPubKey1, dummyPubKey2, dummyPubKey3,
|
||||
},
|
||||
tweak: bip86Tweak,
|
||||
expectedFinalKey: "03fa8195d584b195476f20e2fe978fd7312f4b08f2" +
|
||||
"777f080bcdfc9350603cd6e7",
|
||||
expectedPreTweakKey: "03e615b8aad4ed10544537bc48b1d6600e15773" +
|
||||
"476a675c6cbba6808f21b1988e5",
|
||||
}, {
|
||||
name: "v0.4.0 three test vector keys BIP86",
|
||||
keys: []*btcec.PublicKey{
|
||||
testVector040Key1, testVector040Key2, testVector040Key3,
|
||||
},
|
||||
tweak: bip86Tweak,
|
||||
expectedFinalKey: "025b257b4e785d61157ef5303051f45184bd5cb47b" +
|
||||
"c4b4069ed4dd4536459cb83b",
|
||||
expectedPreTweakKey: "02d70cd69a2647f7390973df48cbfa2ccc407b8" +
|
||||
"b2d60b08c5f1641185c7998a290",
|
||||
}, {
|
||||
name: "v0.4.0 three test vector keys BIP86 reverse order",
|
||||
keys: []*btcec.PublicKey{
|
||||
testVector040Key3, testVector040Key2, testVector040Key1,
|
||||
},
|
||||
tweak: bip86Tweak,
|
||||
expectedFinalKey: "025b257b4e785d61157ef5303051f45184bd5cb47b" +
|
||||
"c4b4069ed4dd4536459cb83b",
|
||||
expectedPreTweakKey: "02d70cd69a2647f7390973df48cbfa2ccc407b8" +
|
||||
"b2d60b08c5f1641185c7998a290",
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(tt *testing.T) {
|
||||
tt.Parallel()
|
||||
|
||||
res, err := MuSig2CombineKeys(tc.keys, tc.tweak)
|
||||
|
||||
if tc.expectedErr != "" {
|
||||
require.ErrorContains(tt, err, tc.expectedErr)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(tt, err)
|
||||
|
||||
finalKey := res.FinalKey.SerializeCompressed()
|
||||
preTweakKey := res.PreTweakedKey.SerializeCompressed()
|
||||
require.Equal(
|
||||
tt, tc.expectedFinalKey,
|
||||
hex.EncodeToString(finalKey),
|
||||
)
|
||||
require.Equal(
|
||||
tt, tc.expectedPreTweakKey,
|
||||
hex.EncodeToString(preTweakKey),
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
@ -826,18 +826,10 @@ func (s *Server) MuSig2CombineKeys(_ context.Context,
|
||||
|
||||
// Parse the public keys of all signing participants. This must also
|
||||
// include our own, local key.
|
||||
allSignerPubKeys := make([]*btcec.PublicKey, len(in.AllSignerPubkeys))
|
||||
if len(in.AllSignerPubkeys) < 2 {
|
||||
return nil, fmt.Errorf("need at least two signing public keys")
|
||||
}
|
||||
|
||||
for idx, pubKeyBytes := range in.AllSignerPubkeys {
|
||||
pubKey, err := schnorr.ParsePubKey(pubKeyBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing signer public "+
|
||||
"key %d: %v", idx, err)
|
||||
}
|
||||
allSignerPubKeys[idx] = pubKey
|
||||
allSignerPubKeys, err := input.MuSig2ParsePubKeys(in.AllSignerPubkeys)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing all signer public "+
|
||||
"keys: %w", err)
|
||||
}
|
||||
|
||||
// Are there any tweaks to apply to the combined public key?
|
||||
@ -887,18 +879,10 @@ func (s *Server) MuSig2CreateSession(_ context.Context,
|
||||
|
||||
// Parse the public keys of all signing participants. This must also
|
||||
// include our own, local key.
|
||||
allSignerPubKeys := make([]*btcec.PublicKey, len(in.AllSignerPubkeys))
|
||||
if len(in.AllSignerPubkeys) < 2 {
|
||||
return nil, fmt.Errorf("need at least two signing public keys")
|
||||
}
|
||||
|
||||
for idx, pubKeyBytes := range in.AllSignerPubkeys {
|
||||
pubKey, err := schnorr.ParsePubKey(pubKeyBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing signer public "+
|
||||
"key %d: %v", idx, err)
|
||||
}
|
||||
allSignerPubKeys[idx] = pubKey
|
||||
allSignerPubKeys, err := input.MuSig2ParsePubKeys(in.AllSignerPubkeys)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing all signer public "+
|
||||
"keys: %w", err)
|
||||
}
|
||||
|
||||
// We participate a nonce ourselves, so we can't have more nonces than
|
||||
|
@ -503,24 +503,14 @@ func (b *BtcWallet) MuSig2CreateSession(keyLoc keychain.KeyLocator,
|
||||
return nil, fmt.Errorf("error deriving private key: %v", err)
|
||||
}
|
||||
|
||||
// The context keeps track of all signing keys and our local key.
|
||||
allOpts := append(
|
||||
[]musig2.ContextOption{
|
||||
musig2.WithKnownSigners(allSignerPubKeys),
|
||||
},
|
||||
tweaks.ToContextOptions()...,
|
||||
// Create a signing context with the given private key and list of all
|
||||
// known signer public keys.
|
||||
muSigContext, muSigSession, err := input.MuSig2CreateContext(
|
||||
privKey, allSignerPubKeys, tweaks,
|
||||
)
|
||||
muSigContext, err := musig2.NewContext(privKey, true, allOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating MuSig2 signing "+
|
||||
"context: %v", err)
|
||||
}
|
||||
|
||||
// The session keeps track of the own and other nonces.
|
||||
muSigSession, err := muSigContext.NewSession()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating MuSig2 signing "+
|
||||
"session: %v", err)
|
||||
return nil, fmt.Errorf("error creating signing context: %v",
|
||||
err)
|
||||
}
|
||||
|
||||
// Add all nonces we might've learned so far.
|
||||
@ -652,7 +642,7 @@ func (b *BtcWallet) MuSig2Sign(sessionID input.MuSig2SessionID,
|
||||
}
|
||||
|
||||
// Create our own partial signature with the local signing key.
|
||||
partialSig, err := session.session.Sign(msg, musig2.WithSortedKeys())
|
||||
partialSig, err := input.MuSig2Sign(session.session, msg, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error signing with local key: %v", err)
|
||||
}
|
||||
@ -698,8 +688,8 @@ func (b *BtcWallet) MuSig2CombineSig(sessionID input.MuSig2SessionID,
|
||||
err error
|
||||
)
|
||||
for _, otherPartialSig := range partialSigs {
|
||||
session.HaveAllSigs, err = session.session.CombineSig(
|
||||
otherPartialSig,
|
||||
session.HaveAllSigs, err = input.MuSig2CombineSig(
|
||||
session.session, otherPartialSig,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error combining "+
|
||||
|
Loading…
Reference in New Issue
Block a user