@@ -103,6 +103,9 @@ class PartiallySignedInput:
103
103
PSBT_IN_TAP_BIP32_DERIVATION = 0x16
104
104
PSBT_IN_TAP_INTERNAL_KEY = 0x17
105
105
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
106
109
107
110
def __init__ (self , version : int ) -> None :
108
111
self .non_witness_utxo : Optional [CTransaction ] = None
@@ -125,6 +128,9 @@ def __init__(self, version: int) -> None:
125
128
self .tap_bip32_paths : Dict [bytes , Tuple [Set [bytes ], KeyOriginInfo ]] = {}
126
129
self .tap_internal_key = b""
127
130
self .tap_merkle_root = b""
131
+ self .musig2_participant_pubkeys = {}
132
+ self .musig2_pub_nonce = {}
133
+ self .musig2_partial_sig = {}
128
134
self .unknown : Dict [bytes , bytes ] = {}
129
135
130
136
self .version : int = version
@@ -153,6 +159,9 @@ def set_null(self) -> None:
153
159
self .sequence = None
154
160
self .time_locktime = None
155
161
self .height_locktime = None
162
+ self .musig2_participant_pubkeys .clear ()
163
+ self .musig2_pub_nonce .clear ()
164
+ self .musig2_partial_sig .clear ()
156
165
self .unknown .clear ()
157
166
158
167
def deserialize (self , f : Readable ) -> None :
@@ -351,6 +360,18 @@ def deserialize(self, f: Readable) -> None:
351
360
self .tap_merkle_root = deser_string (f )
352
361
if len (self .tap_merkle_root ) != 32 :
353
362
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 )
354
375
else :
355
376
if key in self .unknown :
356
377
raise PSBTSerializationError ("Duplicate key, key for unknown value already provided" )
@@ -441,6 +462,18 @@ def serialize(self) -> bytes:
441
462
witstack = self .final_script_witness .serialize ()
442
463
r += ser_string (witstack )
443
464
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
+
444
477
if self .version >= 2 :
445
478
if len (self .prev_txid ) != 0 :
446
479
r += ser_string (ser_compact_size (PartiallySignedInput .PSBT_IN_PREVIOUS_TXID ))
@@ -483,6 +516,7 @@ class PartiallySignedOutput:
483
516
PSBT_OUT_TAP_INTERNAL_KEY = 0x05
484
517
PSBT_OUT_TAP_TREE = 0x06
485
518
PSBT_OUT_TAP_BIP32_DERIVATION = 0x07
519
+ PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS = 0x08
486
520
487
521
def __init__ (self , version : int ) -> None :
488
522
self .redeem_script = b""
@@ -493,6 +527,7 @@ def __init__(self, version: int) -> None:
493
527
self .tap_internal_key = b""
494
528
self .tap_tree = b""
495
529
self .tap_bip32_paths : Dict [bytes , Tuple [Set [bytes ], KeyOriginInfo ]] = {}
530
+ self .musig2_participant_pubkeys = {}
496
531
self .unknown : Dict [bytes , bytes ] = {}
497
532
498
533
self .version : int = version
@@ -509,6 +544,7 @@ def set_null(self) -> None:
509
544
self .tap_bip32_paths .clear ()
510
545
self .amount = None
511
546
self .script = b""
547
+ self .musig2_participant_pubkeys = {}
512
548
self .unknown .clear ()
513
549
514
550
def deserialize (self , f : Readable ) -> None :
@@ -589,6 +625,10 @@ def deserialize(self, f: Readable) -> None:
589
625
for i in range (0 , num_hashes ):
590
626
leaf_hashes .add (vs .read (32 ))
591
627
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 )
592
632
else :
593
633
if key in self .unknown :
594
634
raise PSBTSerializationError ("Duplicate key, key for unknown value already provided" )
@@ -646,6 +686,10 @@ def serialize(self) -> bytes:
646
686
value += origin .serialize ()
647
687
r += ser_string (value )
648
688
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
+
649
693
for key , value in sorted (self .unknown .items ()):
650
694
r += ser_string (key )
651
695
r += ser_string (value )
0 commit comments