Skip to content

Commit

Permalink
psbt: add new MuSig2 fields to inputs and outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
guggero committed Jun 15, 2024
1 parent d526f14 commit 0191dd5
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 0 deletions.
87 changes: 87 additions & 0 deletions btcutil/psbt/partial_input.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ type PInput struct {
TaprootBip32Derivation []*TaprootBip32Derivation
TaprootInternalKey []byte
TaprootMerkleRoot []byte
MuSig2Participants []*MuSig2Participants
MuSig2PubNonces []*MuSig2PubNonce
MuSig2PartialSigs []*MuSig2PartialSig
Unknowns []*Unknown
}

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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 {
Expand Down
30 changes: 30 additions & 0 deletions btcutil/psbt/partial_output.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type POutput struct {
TaprootInternalKey []byte
TaprootTapTree []byte
TaprootBip32Derivation []*TaprootBip32Derivation
MuSig2Participants []*MuSig2Participants
Unknowns []*Unknown
}

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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 {
Expand Down
24 changes: 24 additions & 0 deletions btcutil/psbt/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}|<prefix>|{subtype}|{key data}), is a Variable length
Expand Down Expand Up @@ -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
)

0 comments on commit 0191dd5

Please sign in to comment.