@@ -154,15 +154,15 @@ func TestSignerMulti(t *testing.T) {
154154 }
155155
156156 // INFO: Build MultiSig 4 of 4.
157- leafTapScript , err := utils .NewTaprootMultiSigLeafTapScript (tapScriptPrivateKey1 , tapScriptPrivateKey2 ,
158- tapScriptPrivateKey3 , tapScriptPrivateKey4 )
157+ leafTapScript , err := utils .NewTaprootMultiSigLeafTapScript (tapScriptPrivateKey1 . PubKey () , tapScriptPrivateKey2 . PubKey () ,
158+ tapScriptPrivateKey3 . PubKey () , tapScriptPrivateKey4 . PubKey () )
159159 require .NoErrorf (t , err , "leaf tapScript building" )
160160
161161 leafTapScriptUnspendable , err := utils .NewUnspendableScript ([]byte ("really_unspendable_!" )... )
162162 require .NoErrorf (t , err , "leaf tapScript unspendable building" )
163163
164164 // INFO: Generate Taproot address.
165- taprootAddress , err := utils .NewTaprootAddressFromScripts (chainParams , masterPrivateKey , leafTapScript , leafTapScriptUnspendable )
165+ taprootAddress , err := utils .NewTaprootAddressFromScripts (chainParams , masterPrivateKey . PubKey () , leafTapScript , leafTapScriptUnspendable )
166166 require .NoErrorf (t , err , "taproot address generation" )
167167
168168 // INFO: Generate TapScript tree.
@@ -257,6 +257,127 @@ func TestSignerMulti(t *testing.T) {
257257 }
258258}
259259
260+ func TestSignerMultiAppend (t * testing.T ) {
261+ chainParams := & chaincfg .MainNetParams
262+ s := signer .NewSigner (chainParams )
263+
264+ var (
265+ masterPrivateKey ,
266+ tapScriptPrivateKey1 , tapScriptPrivateKey2 ,
267+ tapScriptPrivateKey3 , tapScriptPrivateKey4 ,
268+ invalidPrivateKey1 , invalidPrivateKey2 * btcec.PrivateKey
269+ err error
270+ )
271+ for _ , privateKeyP := range []* * btcec.PrivateKey {
272+ & masterPrivateKey , & tapScriptPrivateKey1 , & tapScriptPrivateKey2 ,
273+ & tapScriptPrivateKey3 , & tapScriptPrivateKey4 , & invalidPrivateKey1 , & invalidPrivateKey2 ,
274+ } {
275+ * privateKeyP , err = btcec .NewPrivateKey ()
276+ require .NoError (t , err )
277+ }
278+
279+ // INFO: Build MultiSig 4 of 4.
280+ leafTapScript , err := utils .NewTaprootMultiSigLeafTapScript (tapScriptPrivateKey1 .PubKey (), tapScriptPrivateKey2 .PubKey (),
281+ tapScriptPrivateKey3 .PubKey (), tapScriptPrivateKey4 .PubKey ())
282+ require .NoErrorf (t , err , "leaf tapScript building" )
283+
284+ leafTapScriptUnspendable , err := utils .NewUnspendableScript ([]byte ("really_unspendable_!" )... )
285+ require .NoErrorf (t , err , "leaf tapScript unspendable building" )
286+
287+ // INFO: Generate Taproot address.
288+ taprootAddress , err := utils .NewTaprootAddressFromScripts (chainParams , masterPrivateKey .PubKey (), leafTapScript , leafTapScriptUnspendable )
289+ require .NoErrorf (t , err , "taproot address generation" )
290+
291+ // INFO: Generate TapScript tree.
292+ tapScriptTree , err := utils .NewTapScriptTreeFromRawScripts (leafTapScript , leafTapScriptUnspendable )
293+ require .NoErrorf (t , err , "tapScript tree generation" )
294+
295+ invalidTapScriptTree , err := utils .NewTapScriptTreeFromRawScripts (leafTapScript )
296+ require .NoErrorf (t , err , "tapScript tree invalid generation" )
297+
298+ masterPublicKeyXOnly := masterPrivateKey .PubKey ().SerializeCompressed ()[1 :]
299+
300+ tests := []struct {
301+ name string
302+ tapScriptPrivateKeys []* btcec.PrivateKey
303+ tapScriptTree * txscript.IndexedTapScriptTree
304+ err error
305+ }{
306+ {
307+ name : "valid 4 of 4 signature" ,
308+ tapScriptPrivateKeys : []* btcec.PrivateKey {tapScriptPrivateKey4 , tapScriptPrivateKey3 , tapScriptPrivateKey2 , tapScriptPrivateKey1 },
309+ tapScriptTree : tapScriptTree ,
310+ },
311+ {
312+ name : "not enough signatures (3 of 4 private keys for leaf signatures)" ,
313+ tapScriptPrivateKeys : []* btcec.PrivateKey {tapScriptPrivateKey3 , tapScriptPrivateKey2 , tapScriptPrivateKey1 },
314+ tapScriptTree : tapScriptTree ,
315+ err : txscript.Error {ErrorCode : txscript .ErrInvalidStackOperation , Description : "index 0 is invalid for stack size 0" },
316+ },
317+ {
318+ name : "private keys invalid order" ,
319+ tapScriptPrivateKeys : []* btcec.PrivateKey {tapScriptPrivateKey1 , tapScriptPrivateKey2 , tapScriptPrivateKey3 , tapScriptPrivateKey4 },
320+ tapScriptTree : tapScriptTree ,
321+ err : txscript.Error {ErrorCode : txscript .ErrNullFail , Description : "signature not empty on failed checksig" },
322+ },
323+ {
324+ name : "invalid leaf keys" ,
325+ tapScriptPrivateKeys : []* btcec.PrivateKey {invalidPrivateKey1 , tapScriptPrivateKey3 , tapScriptPrivateKey2 , invalidPrivateKey2 },
326+ tapScriptTree : tapScriptTree ,
327+ err : txscript.Error {ErrorCode : txscript .ErrNullFail , Description : "signature not empty on failed checksig" },
328+ },
329+ {
330+ name : "unable to unlock by script spend path without correct script tree" ,
331+ tapScriptPrivateKeys : []* btcec.PrivateKey {tapScriptPrivateKey4 , tapScriptPrivateKey3 , tapScriptPrivateKey2 , tapScriptPrivateKey1 },
332+ err : txscript.Error {ErrorCode : txscript .ErrTaprootMerkleProofInvalid },
333+ },
334+ {
335+ name : "unable to unlock by script spend path with incorrect script tree" ,
336+ tapScriptPrivateKeys : []* btcec.PrivateKey {tapScriptPrivateKey4 , tapScriptPrivateKey3 , tapScriptPrivateKey2 , tapScriptPrivateKey1 },
337+ tapScriptTree : invalidTapScriptTree ,
338+ err : txscript.Error {ErrorCode : txscript .ErrTaprootMerkleProofInvalid },
339+ },
340+ }
341+ for _ , test := range tests {
342+ t .Run (test .name , func (t * testing.T ) {
343+ var signedPSBTs [2 ][]byte
344+ t .Run ("group signature" , func (t * testing.T ) {
345+ packetBytes := prepareTxPacketBytes (t , taprootAddress , masterPublicKeyXOnly , leafTapScript , test .tapScriptTree )
346+
347+ signedPSBTs [0 ], err = s .SignTaprootMulti (signer.SignTaprootMultiParams {
348+ SerializedPSBT : packetBytes ,
349+ Inputs : []int {0 },
350+ TapScriptPrivateKeys : test .tapScriptPrivateKeys ,
351+ })
352+ require .NoError (t , err )
353+
354+ err = prepareMultiSigEngine (t , signedPSBTs [0 ]).Execute ()
355+ require .ErrorIs (t , err , test .err )
356+ })
357+
358+ t .Run ("append signature" , func (t * testing.T ) {
359+ packetBytes := prepareTxPacketBytes (t , taprootAddress , masterPublicKeyXOnly , leafTapScript , test .tapScriptTree )
360+
361+ signParams := signer.SignTaprootMultiAppendParams {
362+ SerializedPSBT : packetBytes ,
363+ Inputs : []int {0 },
364+ }
365+ for _ , tapScriptPrivateKey := range test .tapScriptPrivateKeys {
366+ signParams .TapScriptPrivateKey = tapScriptPrivateKey
367+ signParams .SerializedPSBT , err = s .SignTaprootMultiAppend (signParams )
368+ require .NoError (t , err )
369+ }
370+
371+ signedPSBTs [1 ] = signParams .SerializedPSBT
372+ err = prepareMultiSigEngine (t , signedPSBTs [1 ]).Execute ()
373+ require .ErrorIs (t , err , test .err )
374+ })
375+
376+ require .EqualValues (t , signedPSBTs [0 ], signedPSBTs [1 ])
377+ })
378+ }
379+ }
380+
260381func mustHex (s string ) []byte {
261382 b , _ := hex .DecodeString (s )
262383
0 commit comments