From 0191dd59a86319bb6c303b582ca366212a146336 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Fri, 14 Jun 2024 11:06:45 +0200 Subject: [PATCH] psbt: add new MuSig2 fields to inputs and outputs --- btcutil/psbt/partial_input.go | 87 ++++++++++++++++++++++++++++++++++ btcutil/psbt/partial_output.go | 30 ++++++++++++ btcutil/psbt/types.go | 24 ++++++++++ 3 files changed, 141 insertions(+) diff --git a/btcutil/psbt/partial_input.go b/btcutil/psbt/partial_input.go index 73595d2513..8d4cccb84e 100644 --- a/btcutil/psbt/partial_input.go +++ b/btcutil/psbt/partial_input.go @@ -28,6 +28,9 @@ type PInput struct { TaprootBip32Derivation []*TaprootBip32Derivation TaprootInternalKey []byte TaprootMerkleRoot []byte + MuSig2Participants []*MuSig2Participants + MuSig2PubNonces []*MuSig2PubNonce + MuSig2PartialSigs []*MuSig2PartialSig Unknowns []*Unknown } @@ -363,6 +366,60 @@ func (pi *PInput) deserialize(r io.Reader) error { pi.TaprootMerkleRoot = value + case MuSig2ParticipantsInputType: + participants, err := ReadMuSig2Participants( + keyData, value, + ) + if err != nil { + return err + } + + // Duplicate keys are not allowed. + newKey := participants.KeyData() + for _, x := range pi.MuSig2Participants { + if bytes.Equal(x.KeyData(), newKey) { + return ErrDuplicateKey + } + } + + pi.MuSig2Participants = append( + pi.MuSig2Participants, participants, + ) + + case MuSig2PubNoncesInputType: + nonce, err := ReadMuSig2PubNonce(keyData, value) + if err != nil { + return err + } + + // Duplicate keys are not allowed. + newKey := nonce.KeyData() + for _, x := range pi.MuSig2PubNonces { + if bytes.Equal(x.KeyData(), newKey) { + return ErrDuplicateKey + } + } + + pi.MuSig2PubNonces = append(pi.MuSig2PubNonces, nonce) + + case MuSig2PartialSigsInputType: + partialSig, err := ReadMuSig2PartialSig(keyData, value) + if err != nil { + return err + } + + // Duplicate keys are not allowed. + newKey := partialSig.KeyData() + for _, x := range pi.MuSig2PartialSigs { + if bytes.Equal(x.KeyData(), newKey) { + return ErrDuplicateKey + } + } + + pi.MuSig2PartialSigs = append( + pi.MuSig2PartialSigs, partialSig, + ) + default: // A fall through case for any proprietary types. keyCodeAndData := append( @@ -572,6 +629,36 @@ func (pi *PInput) serialize(w io.Writer) error { return err } } + + for _, participants := range pi.MuSig2Participants { + err := SerializeMuSig2Participants( + w, uint8(MuSig2ParticipantsInputType), + participants, + ) + if err != nil { + return err + } + } + + for _, nonce := range pi.MuSig2PubNonces { + err := SerializeMuSig2PubNonce( + w, uint8(MuSig2PubNoncesInputType), + nonce, + ) + if err != nil { + return err + } + } + + for _, sig := range pi.MuSig2PartialSigs { + err := SerializeMuSig2PartialSig( + w, uint8(MuSig2PartialSigsInputType), + sig, + ) + if err != nil { + return err + } + } } if pi.FinalScriptSig != nil { diff --git a/btcutil/psbt/partial_output.go b/btcutil/psbt/partial_output.go index 86e476457d..d73265bff9 100644 --- a/btcutil/psbt/partial_output.go +++ b/btcutil/psbt/partial_output.go @@ -17,6 +17,7 @@ type POutput struct { TaprootInternalKey []byte TaprootTapTree []byte TaprootBip32Derivation []*TaprootBip32Derivation + MuSig2Participants []*MuSig2Participants Unknowns []*Unknown } @@ -144,6 +145,26 @@ func (po *POutput) deserialize(r io.Reader) error { po.TaprootBip32Derivation, taprootDerivation, ) + case MuSig2ParticipantsOutputType: + participants, err := ReadMuSig2Participants( + keyData, value, + ) + if err != nil { + return err + } + + // Duplicate keys are not allowed. + newKey := participants.AggregateKey + for _, x := range po.MuSig2Participants { + if x.AggregateKey.IsEqual(newKey) { + return ErrDuplicateKey + } + } + + po.MuSig2Participants = append( + po.MuSig2Participants, participants, + ) + default: // A fall through case for any proprietary types. keyCodeAndData := append( @@ -246,6 +267,15 @@ func (po *POutput) serialize(w io.Writer) error { } } + for _, participants := range po.MuSig2Participants { + err := SerializeMuSig2Participants( + w, uint8(MuSig2ParticipantsOutputType), participants, + ) + if err != nil { + return err + } + } + // Unknown is a special case; we don't have a key type, only a key and // a value field for _, kv := range po.Unknowns { diff --git a/btcutil/psbt/types.go b/btcutil/psbt/types.go index e833e1af35..37b8e36191 100644 --- a/btcutil/psbt/types.go +++ b/btcutil/psbt/types.go @@ -151,6 +151,24 @@ const ( // 32-byte hash denoting the root hash of a merkle tree of scripts. TaprootMerkleRootType InputType = 0x18 + // MuSig2ParticipantsInputType is a type that carries the participant + // public keys and aggregated key for a MuSig2 signing session + // ({0x1a}|{aggregate_key}). The value is a list of 33-byte compressed + // public keys in the order required for aggregation. + MuSig2ParticipantsInputType InputType = 0x1a + + // MuSig2PubNoncesInputType is a type that carries the public nonces + // provided by participants in a MuSig2 signing session + // ({0x1b}|{participant_key}|{aggregate_key}[|{tapleaf_hash}]). The + // value is the 66-byte public nonces provided by the participant. + MuSig2PubNoncesInputType InputType = 0x1b + + // MuSig2PartialSigsInputType is a type that carries the partial + // signatures provided by participants in a MuSig2 signing session + // ({0x1c}|{participant_key}|{aggregate_key}[|{tapleaf_hash}]). The + // value is the 32-byte partial signature provided by the participant. + MuSig2PartialSigsInputType InputType = 0x1c + // ProprietaryInputType is a custom type for use by devs. // // The key ({0xFC}||{subtype}|{key data}), is a Variable length @@ -200,4 +218,10 @@ const ( // followed by said number of 32-byte leaf hashes. The rest of the value // is then identical to the Bip32DerivationInputType value. TaprootBip32DerivationOutputType OutputType = 7 + + // MuSig2ParticipantsOutputType is a type that carries the participant + // public keys and aggregated key for a MuSig2 signing session + // ({0x08}|{aggregate_key}). The value is a list of 33-byte compressed + // public keys in the order required for aggregation. + MuSig2ParticipantsOutputType OutputType = 0x08 )