@@ -103,6 +103,9 @@ class PartiallySignedInput:
103103 PSBT_IN_TAP_BIP32_DERIVATION = 0x16
104104 PSBT_IN_TAP_INTERNAL_KEY = 0x17
105105 PSBT_IN_TAP_MERKLE_ROOT = 0x18
106+ PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS = 0x1a
107+ PSBT_IN_MUSIG2_PUB_NONCE = 0x1b
108+ PSBT_IN_MUSIG2_PARTIAL_SIG = 0x1c
106109
107110 def __init__ (self , version : int ) -> None :
108111 self .non_witness_utxo : Optional [CTransaction ] = None
@@ -125,6 +128,9 @@ def __init__(self, version: int) -> None:
125128 self .tap_bip32_paths : Dict [bytes , Tuple [Set [bytes ], KeyOriginInfo ]] = {}
126129 self .tap_internal_key = b""
127130 self .tap_merkle_root = b""
131+ self .musig2_participant_pubkeys = {}
132+ self .musig2_pub_nonce = {}
133+ self .musig2_partial_sig = {}
128134 self .unknown : Dict [bytes , bytes ] = {}
129135
130136 self .version : int = version
@@ -153,6 +159,9 @@ def set_null(self) -> None:
153159 self .sequence = None
154160 self .time_locktime = None
155161 self .height_locktime = None
162+ self .musig2_participant_pubkeys .clear ()
163+ self .musig2_pub_nonce .clear ()
164+ self .musig2_partial_sig .clear ()
156165 self .unknown .clear ()
157166
158167 def deserialize (self , f : Readable ) -> None :
@@ -351,6 +360,18 @@ def deserialize(self, f: Readable) -> None:
351360 self .tap_merkle_root = deser_string (f )
352361 if len (self .tap_merkle_root ) != 32 :
353362 raise PSBTSerializationError ("Input Taproot merkle root is not 32 bytes" )
363+ elif key_type == PartiallySignedInput .PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS :
364+ if key in key_lookup :
365+ raise PSBTSerializationError ("Duplicate key, input MuSig2 Participant Public Keys already provided" )
366+ self .musig2_participant_pubkeys = deser_string (f )
367+ elif key_type == PartiallySignedInput .PSBT_IN_MUSIG2_PUB_NONCE :
368+ if key in key_lookup :
369+ raise PSBTSerializationError ("Duplicate key, input MuSig2 Public Nonce already provided" )
370+ self .musig2_pub_nonce = deser_string (f )
371+ elif key_type == PartiallySignedInput .PSBT_IN_MUSIG2_PARTIAL_SIG :
372+ if key in key_lookup :
373+ raise PSBTSerializationError ("Duplicate key, input MuSig2 Participant Partial Signature already provided" )
374+ self .musig2_partial_sig = deser_string (f )
354375 else :
355376 if key in self .unknown :
356377 raise PSBTSerializationError ("Duplicate key, key for unknown value already provided" )
@@ -441,6 +462,18 @@ def serialize(self) -> bytes:
441462 witstack = self .final_script_witness .serialize ()
442463 r += ser_string (witstack )
443464
465+ if len (self .musig2_participant_pubkeys ) != 0 :
466+ r += ser_string (ser_compact_size (PartiallySignedInput .PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS ))
467+ r += ser_string (self .musig2_participant_pubkeys )
468+
469+ if len (self .musig2_pub_nonce ) != 0 :
470+ r += ser_string (ser_compact_size (PartiallySignedInput .PSBT_IN_MUSIG2_PUB_NONCE ))
471+ r += ser_string (self .musig2_pub_nonce )
472+
473+ if len (self .musig2_partial_sig ) != 0 :
474+ r += ser_string (ser_compact_size (PartiallySignedInput .PSBT_IN_MUSIG2_PARTIAL_SIG ))
475+ r += ser_string (self .musig2_partial_sig )
476+
444477 if self .version >= 2 :
445478 if len (self .prev_txid ) != 0 :
446479 r += ser_string (ser_compact_size (PartiallySignedInput .PSBT_IN_PREVIOUS_TXID ))
@@ -483,6 +516,7 @@ class PartiallySignedOutput:
483516 PSBT_OUT_TAP_INTERNAL_KEY = 0x05
484517 PSBT_OUT_TAP_TREE = 0x06
485518 PSBT_OUT_TAP_BIP32_DERIVATION = 0x07
519+ PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS = 0x08
486520
487521 def __init__ (self , version : int ) -> None :
488522 self .redeem_script = b""
@@ -493,6 +527,7 @@ def __init__(self, version: int) -> None:
493527 self .tap_internal_key = b""
494528 self .tap_tree = b""
495529 self .tap_bip32_paths : Dict [bytes , Tuple [Set [bytes ], KeyOriginInfo ]] = {}
530+ self .musig2_participant_pubkeys = {}
496531 self .unknown : Dict [bytes , bytes ] = {}
497532
498533 self .version : int = version
@@ -509,6 +544,7 @@ def set_null(self) -> None:
509544 self .tap_bip32_paths .clear ()
510545 self .amount = None
511546 self .script = b""
547+ self .musig2_participant_pubkeys = {}
512548 self .unknown .clear ()
513549
514550 def deserialize (self , f : Readable ) -> None :
@@ -589,6 +625,10 @@ def deserialize(self, f: Readable) -> None:
589625 for i in range (0 , num_hashes ):
590626 leaf_hashes .add (vs .read (32 ))
591627 self .tap_bip32_paths [xonly ] = (leaf_hashes , KeyOriginInfo .deserialize (vs .read ()))
628+ elif key_type == PartiallySignedOutput .PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS :
629+ if key in key_lookup :
630+ raise PSBTSerializationError ("Duplicate key, output MuSig2 Participant Public Keys already provided" )
631+ self .musig2_participant_pubkeys = deser_string (f )
592632 else :
593633 if key in self .unknown :
594634 raise PSBTSerializationError ("Duplicate key, key for unknown value already provided" )
@@ -646,6 +686,10 @@ def serialize(self) -> bytes:
646686 value += origin .serialize ()
647687 r += ser_string (value )
648688
689+ if len (self .musig2_participant_pubkeys ) != 0 :
690+ r += ser_string (ser_compact_size (PartiallySignedOutput .PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS ))
691+ r += ser_string (self .musig2_participant_pubkeys )
692+
649693 for key , value in sorted (self .unknown .items ()):
650694 r += ser_string (key )
651695 r += ser_string (value )
0 commit comments