Skip to content

Commit 4b24186

Browse files
committed
test: add test for decoding PSBT with MuSig2 PSBT key types (BIP 373)
1 parent 8ba245c commit 4b24186

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

test/functional/rpc_psbt.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,12 @@
2929
PSBT_IN_SHA256,
3030
PSBT_IN_HASH160,
3131
PSBT_IN_HASH256,
32+
PSBT_IN_MUSIG2_PARTIAL_SIG,
33+
PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS,
34+
PSBT_IN_MUSIG2_PUB_NONCE,
3235
PSBT_IN_NON_WITNESS_UTXO,
3336
PSBT_IN_WITNESS_UTXO,
37+
PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS,
3438
PSBT_OUT_TAP_TREE,
3539
)
3640
from test_framework.script import CScript, OP_TRUE
@@ -199,6 +203,75 @@ def test_input_confs_control(self):
199203

200204
wallet.unloadwallet()
201205

206+
def test_decodepsbt_musig2_input_output_types(self):
207+
self.log.info("Test decoding PSBT with MuSig2 per-input and per-output types")
208+
# create 2-of-2 musig2 using fake aggregate key, leaf hash, pubnonce, and partial sig
209+
# TODO: actually implement MuSig2 aggregation (for decoding only it doesn't matter though)
210+
_, in_pubkey1 = generate_keypair()
211+
_, in_pubkey2 = generate_keypair()
212+
_, in_fake_agg_pubkey = generate_keypair()
213+
fake_leaf_hash = randbytes(32)
214+
fake_pubnonce = randbytes(66)
215+
fake_partialsig = randbytes(32)
216+
tx = CTransaction()
217+
tx.vin = [CTxIn(outpoint=COutPoint(hash=int('ee' * 32, 16), n=0), scriptSig=b"")]
218+
tx.vout = [CTxOut(nValue=0, scriptPubKey=b"")]
219+
psbt = PSBT()
220+
psbt.g = PSBTMap({PSBT_GLOBAL_UNSIGNED_TX: tx.serialize()})
221+
participant1_keydata = in_pubkey1 + in_fake_agg_pubkey + fake_leaf_hash
222+
psbt.i = [PSBTMap({
223+
bytes([PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS]) + in_fake_agg_pubkey: [in_pubkey1, in_pubkey2],
224+
bytes([PSBT_IN_MUSIG2_PUB_NONCE]) + participant1_keydata: fake_pubnonce,
225+
bytes([PSBT_IN_MUSIG2_PARTIAL_SIG]) + participant1_keydata: fake_partialsig,
226+
})]
227+
_, out_pubkey1 = generate_keypair()
228+
_, out_pubkey2 = generate_keypair()
229+
_, out_fake_agg_pubkey = generate_keypair()
230+
psbt.o = [PSBTMap({
231+
bytes([PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS]) + out_fake_agg_pubkey: [out_pubkey1, out_pubkey2],
232+
})]
233+
res = self.nodes[0].decodepsbt(psbt.to_base64())
234+
assert_equal(len(res["inputs"]), 1)
235+
res_input = res["inputs"][0]
236+
assert_equal(len(res["outputs"]), 1)
237+
res_output = res["outputs"][0]
238+
239+
assert "musig2_participant_pubkeys" in res_input
240+
in_participant_pks = res_input["musig2_participant_pubkeys"][0]
241+
assert "aggregate_pubkey" in in_participant_pks
242+
assert_equal(in_participant_pks["aggregate_pubkey"], in_fake_agg_pubkey.hex())
243+
assert "participant_pubkeys" in in_participant_pks
244+
assert_equal(in_participant_pks["participant_pubkeys"], [in_pubkey1.hex(), in_pubkey2.hex()])
245+
246+
assert "musig2_pubnonces" in res_input
247+
in_pubnonce = res_input["musig2_pubnonces"][0]
248+
assert "participant_pubkey" in in_pubnonce
249+
assert_equal(in_pubnonce["participant_pubkey"], in_pubkey1.hex())
250+
assert "aggregate_pubkey" in in_pubnonce
251+
assert_equal(in_pubnonce["aggregate_pubkey"], in_fake_agg_pubkey.hex())
252+
assert "leaf_hash" in in_pubnonce
253+
assert_equal(in_pubnonce["leaf_hash"], fake_leaf_hash.hex())
254+
assert "pubnonce" in in_pubnonce
255+
assert_equal(in_pubnonce["pubnonce"], fake_pubnonce.hex())
256+
257+
assert "musig2_partial_sigs" in res_input
258+
in_partialsig = res_input["musig2_partial_sigs"][0]
259+
assert "participant_pubkey" in in_partialsig
260+
assert_equal(in_partialsig["participant_pubkey"], in_pubkey1.hex())
261+
assert "aggregate_pubkey" in in_partialsig
262+
assert_equal(in_partialsig["aggregate_pubkey"], in_fake_agg_pubkey.hex())
263+
assert "leaf_hash" in in_partialsig
264+
assert_equal(in_partialsig["leaf_hash"], fake_leaf_hash.hex())
265+
assert "partial_sig" in in_partialsig
266+
assert_equal(in_partialsig["partial_sig"], fake_partialsig.hex())
267+
268+
assert "musig2_participant_pubkeys" in res_output
269+
out_participant_pks = res_output["musig2_participant_pubkeys"][0]
270+
assert "aggregate_pubkey" in out_participant_pks
271+
assert_equal(out_participant_pks["aggregate_pubkey"], out_fake_agg_pubkey.hex())
272+
assert "participant_pubkeys" in out_participant_pks
273+
assert_equal(out_participant_pks["participant_pubkeys"], [out_pubkey1.hex(), out_pubkey2.hex()])
274+
202275
def assert_change_type(self, psbtx, expected_type):
203276
"""Assert that the given PSBT has a change output with the given type."""
204277

@@ -959,6 +1032,8 @@ def test_psbt_input_keys(psbt_input, keys):
9591032
assert hash.hex() in res_input[preimage_key]
9601033
assert_equal(res_input[preimage_key][hash.hex()], preimage.hex())
9611034

1035+
self.test_decodepsbt_musig2_input_output_types()
1036+
9621037
self.log.info("Test that combining PSBTs with different transactions fails")
9631038
tx = CTransaction()
9641039
tx.vin = [CTxIn(outpoint=COutPoint(hash=int('aa' * 32, 16), n=0), scriptSig=b"")]

0 commit comments

Comments
 (0)