@@ -14,6 +14,9 @@ package psbt
1414import (
1515 "bytes"
1616 "fmt"
17+ "github.com/btcsuite/btcd/btcec/v2"
18+ "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
19+ "github.com/btcsuite/btcd/chaincfg/chainhash"
1720
1821 "github.com/btcsuite/btcd/btcec/v2/schnorr"
1922 "github.com/btcsuite/btcd/txscript"
@@ -47,11 +50,19 @@ func isFinalizableWitnessInput(pInput *PInput) bool {
4750
4851 case txscript .IsPayToTaproot (pkScript ):
4952 if pInput .TaprootKeySpendSig == nil &&
50- pInput .TaprootScriptSpendSig == nil {
53+ pInput .TaprootScriptSpendSig == nil &&
54+ pInput .MuSig2PartialSigs == nil {
5155
5256 return false
5357 }
5458
59+ // For each participant, we need a corresponding
60+ // MuSig2 partial signature.
61+ if len (pInput .MuSig2PartialSigs ) > 0 {
62+ return len (pInput .MuSig2PartialSigs ) ==
63+ len (pInput .MuSig2PubNonces )
64+ }
65+
5566 // For each of the script spend signatures we need a
5667 // corresponding tap script leaf with the control block.
5768 for _ , sig := range pInput .TaprootScriptSpendSig {
@@ -577,6 +588,91 @@ func finalizeTaprootInput(p *Packet, inIndex int) error {
577588
578589 serializedWitness , err = writeWitness (witnessStack ... )
579590
591+ // MuSig2 spend path.
592+ case len (pInput .MuSig2PartialSigs ) > 0 :
593+ if len (pInput .MuSig2PubNonces ) !=
594+ len (pInput .MuSig2PartialSigs ) {
595+
596+ return fmt .Errorf ("number of MuSig2 pub nonces " +
597+ "does not match number of partial signatures" )
598+ }
599+
600+ // We'll need to combine MuSig2 partial signatures into a single
601+ // one, which requires the message that was signed over.
602+ firstSig := pInput .MuSig2PartialSigs [0 ]
603+
604+ // We don't (yet) support signing over a tap leaf hash.
605+ // TODO(guggero): Add support for signing over a tap leaf hash.
606+ if len (firstSig .TapLeafHash ) > 0 {
607+ return fmt .Errorf ("combining partial MuSig2 " +
608+ "signatures for a tap leaf is not supported" )
609+ }
610+
611+ prevOutFetcher := PrevOutputFetcher (p )
612+ sigHashes := txscript .NewTxSigHashes (
613+ p .UnsignedTx , prevOutFetcher ,
614+ )
615+ sigHash , err := txscript .CalcTaprootSignatureHash (
616+ sigHashes , pInput .SighashType , p .UnsignedTx ,
617+ inIndex , prevOutFetcher ,
618+ )
619+ if err != nil {
620+ return fmt .Errorf ("error calculating signature hash: " +
621+ "%w" , err )
622+ }
623+
624+ var sigHashMsg [32 ]byte
625+ copy (sigHashMsg [:], sigHash )
626+
627+ var (
628+ pubNonces = make (
629+ [][musig2 .PubNonceSize ]byte ,
630+ len (pInput .MuSig2PubNonces ),
631+ )
632+ keys = make (
633+ []* btcec.PublicKey , len (pInput .MuSig2PubNonces ),
634+ )
635+ partialSigs = make (
636+ []* musig2.PartialSignature ,
637+ len (pInput .MuSig2PartialSigs ),
638+ )
639+ )
640+ for i , pubNonce := range pInput .MuSig2PubNonces {
641+ copy (pubNonces [i ][:], pubNonce .PubNonce [:])
642+ keys [i ] = pubNonce .PubKey
643+
644+ partialSigs [i ] = & pInput .MuSig2PartialSigs [i ].PartialSig
645+ }
646+ aggregateNonce , err := musig2 .AggregateNonces (pubNonces )
647+ if err != nil {
648+ return fmt .Errorf ("error aggregating pub nonces: %w" ,
649+ err )
650+ }
651+
652+ aggKey , _ , _ , err := musig2 .AggregateKeys (
653+ keys , true , musig2 .WithBIP86KeyTweak (),
654+ )
655+ if err != nil {
656+ return fmt .Errorf ("error aggregating keys: %w" , err )
657+ }
658+
659+ combinedNonce , err := computeSigningNonce (
660+ aggregateNonce , aggKey .FinalKey , sigHashMsg ,
661+ )
662+ if err != nil {
663+ return fmt .Errorf ("error computing signing nonce: %w" ,
664+ err )
665+ }
666+
667+ combineOpt := musig2 .WithBip86TweakedCombine (
668+ sigHashMsg , keys , true ,
669+ )
670+ schnorrSig := musig2 .CombineSigs (
671+ combinedNonce , partialSigs , combineOpt ,
672+ )
673+
674+ serializedWitness , err = writeWitness (schnorrSig .Serialize ())
675+
580676 default :
581677 return ErrInvalidPsbtFormat
582678 }
@@ -595,3 +691,57 @@ func finalizeTaprootInput(p *Packet, inIndex int) error {
595691 p .Inputs [inIndex ] = * newInput
596692 return nil
597693}
694+
695+ // computeSigningNonce calculates the final nonce used for signing. This will
696+ // be the R value used in the final signature.
697+ func computeSigningNonce (combinedNonce [musig2 .PubNonceSize ]byte ,
698+ combinedKey * btcec.PublicKey , msg [32 ]byte ) (* btcec.PublicKey , error ) {
699+
700+ // Next we'll compute the value b, that blinds our second public
701+ // nonce:
702+ // * b = h(tag=NonceBlindTag, combinedNonce || combinedKey || m).
703+ var (
704+ nonceMsgBuf bytes.Buffer
705+ nonceBlinder btcec.ModNScalar
706+ )
707+ nonceMsgBuf .Write (combinedNonce [:])
708+ nonceMsgBuf .Write (schnorr .SerializePubKey (combinedKey ))
709+ nonceMsgBuf .Write (msg [:])
710+ nonceBlindHash := chainhash .TaggedHash (
711+ musig2 .NonceBlindTag , nonceMsgBuf .Bytes (),
712+ )
713+ nonceBlinder .SetByteSlice (nonceBlindHash [:])
714+
715+ // Next, we'll parse the public nonces into R1 and R2.
716+ r1J , err := btcec .ParseJacobian (
717+ combinedNonce [:btcec .PubKeyBytesLenCompressed ],
718+ )
719+ if err != nil {
720+ return nil , err
721+ }
722+ r2J , err := btcec .ParseJacobian (
723+ combinedNonce [btcec .PubKeyBytesLenCompressed :],
724+ )
725+ if err != nil {
726+ return nil , err
727+ }
728+
729+ // With our nonce blinding value, we'll now combine both the public
730+ // nonces, using the blinding factor to tweak the second nonce:
731+ // * R = R_1 + b*R_2
732+ var nonce btcec.JacobianPoint
733+ btcec .ScalarMultNonConst (& nonceBlinder , & r2J , & r2J )
734+ btcec .AddNonConst (& r1J , & r2J , & nonce )
735+
736+ // If the combined nonce is the point at infinity, we'll use the
737+ // generator point instead.
738+ var infinityPoint btcec.JacobianPoint
739+ if nonce == infinityPoint {
740+ G := btcec .Generator ()
741+ G .AsJacobian (& nonce )
742+ }
743+
744+ nonce .ToAffine ()
745+
746+ return btcec .NewPublicKey (& nonce .X , & nonce .Y ), nil
747+ }
0 commit comments