@@ -4,38 +4,145 @@ import (
44 "testing"
55
66 "github.com/btcsuite/btcd/btcec/v2"
7+ "github.com/btcsuite/btcd/btcec/v2/schnorr"
78 "github.com/lightninglabs/loop/test"
89 "github.com/lightningnetwork/lnd/input"
910 "github.com/stretchr/testify/require"
1011)
1112
13+ // rawKeys returns serialized private keys for the given test seeds.
14+ func rawKeys (seeds ... int32 ) [][32 ]byte {
15+ keys := make ([][32 ]byte , len (seeds ))
16+ for i , seed := range seeds {
17+ privKey , _ := test .CreateKey (seed )
18+ copy (keys [i ][:], privKey .Serialize ())
19+ }
20+
21+ return keys
22+ }
23+
24+ // signerPubKeys returns signer public keys derived from the given seeds in the
25+ // format expected by the given MuSig2 version.
26+ func signerPubKeys (t * testing.T , version input.MuSig2Version ,
27+ seeds ... int32 ) []* btcec.PublicKey {
28+
29+ t .Helper ()
30+
31+ pubKeys := make ([]* btcec.PublicKey , len (seeds ))
32+ for i , seed := range seeds {
33+ _ , pubKey := test .CreateKey (seed )
34+
35+ if version == input .MuSig2Version040 {
36+ var err error
37+ pubKey , err = schnorr .ParsePubKey (
38+ schnorr .SerializePubKey (pubKey ),
39+ )
40+ require .NoError (t , err )
41+ }
42+
43+ pubKeys [i ] = pubKey
44+ }
45+
46+ return pubKeys
47+ }
48+
49+ // hasOddY returns true if the compressed serialization of the public key uses
50+ // the odd-Y prefix.
51+ func hasOddY (pubKey * btcec.PublicKey ) bool {
52+ return pubKey .SerializeCompressed ()[0 ] == 0x03
53+ }
54+
1255// TestMuSig2SignRejectsSingleSigner ensures the helper fails fast with a clear
1356// error instead of entering an invalid one-party MuSig2 flow.
1457func TestMuSig2SignRejectsSingleSigner (t * testing.T ) {
15- privKey , pubKey := test .CreateKey (1 )
16-
1758 _ , err := MuSig2Sign (
1859 input .MuSig2Version100RC2 ,
19- []* btcec.PrivateKey {privKey },
20- []* btcec.PublicKey {pubKey },
60+ rawKeys (1 ),
2161 & input.MuSig2Tweaks {},
2262 [32 ]byte {},
2363 )
2464 require .ErrorContains (t , err , "need at least two signing keys" )
2565}
2666
27- // TestMuSig2SignRejectsMismatchedKeyCounts ensures we fail before creating any
28- // MuSig2 sessions when the signer sets are inconsistent.
29- func TestMuSig2SignRejectsMismatchedKeyCounts (t * testing.T ) {
30- privKey , pubKey1 := test .CreateKey (1 )
31- _ , pubKey2 := test .CreateKey (2 )
67+ // TestMuSig2SignSupportsVersions verifies the helper works with the supported
68+ // MuSig2 versions used in Loop.
69+ func TestMuSig2SignSupportsVersions (t * testing.T ) {
70+ t .Parallel ()
3271
33- _ , err := MuSig2Sign (
34- input .MuSig2Version100RC2 ,
35- []* btcec.PrivateKey {privKey },
36- []* btcec.PublicKey {pubKey1 , pubKey2 },
37- & input.MuSig2Tweaks {},
38- [32 ]byte {},
39- )
40- require .ErrorContains (t , err , "must match number of public keys" )
72+ tweaks := & input.MuSig2Tweaks {}
73+ msg := [32 ]byte {1 }
74+
75+ testCases := []struct {
76+ name string
77+ version input.MuSig2Version
78+ seeds []int32
79+ oddYSigner int32
80+ }{
81+ {
82+ name : testVersionName (input .MuSig2Version040 ),
83+ version : input .MuSig2Version040 ,
84+ seeds : []int32 {1 , 2 },
85+ },
86+ {
87+ name : testVersionName (input .MuSig2Version100RC2 ),
88+ version : input .MuSig2Version100RC2 ,
89+ seeds : []int32 {1 , 2 },
90+ },
91+ {
92+ name : testVersionName (input .MuSig2Version040 ) +
93+ " odd Y" ,
94+ version : input .MuSig2Version040 ,
95+ seeds : []int32 {5 , 1 },
96+ oddYSigner : 5 ,
97+ },
98+ }
99+
100+ for _ , testCase := range testCases {
101+ t .Run (testCase .name , func (t * testing.T ) {
102+ t .Parallel ()
103+
104+ if testCase .oddYSigner != 0 {
105+ _ , oddYKey := test .CreateKey (
106+ testCase .oddYSigner ,
107+ )
108+ require .True (t , hasOddY (oddYKey ))
109+ }
110+
111+ keys := rawKeys (testCase .seeds ... )
112+ pubKeys := signerPubKeys (
113+ t , testCase .version , testCase .seeds ... ,
114+ )
115+
116+ sigBytes , err := MuSig2Sign (
117+ testCase .version , keys , tweaks , msg ,
118+ )
119+ require .NoError (t , err )
120+ require .Len (t , sigBytes , 64 )
121+
122+ sig , err := schnorr .ParseSignature (sigBytes )
123+ require .NoError (t , err )
124+
125+ combinedKey , err := input .MuSig2CombineKeys (
126+ testCase .version , pubKeys , true , tweaks ,
127+ )
128+ require .NoError (t , err )
129+ require .True (
130+ t , sig .Verify (msg [:], combinedKey .FinalKey ),
131+ )
132+ })
133+ }
134+ }
135+
136+ // testVersionName returns a stable subtest name for a MuSig2 version.
137+ func testVersionName (version input.MuSig2Version ) string {
138+ switch version {
139+ case input .MuSig2Version040 :
140+ return "MuSig2 0.4"
141+
142+ case input .MuSig2Version100RC2 :
143+ return "MuSig2 1.0RC2"
144+
145+ default :
146+ return "unknown"
147+ }
41148}
0 commit comments