Implements un/serialization of MuSig2 PSBT fields and prepares PSBT to be able to sign for MuSig2 inputs.
Split from #29675
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/31247.
See the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.
Reviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
717@@ -672,6 +718,80 @@ struct PSBTInput
718 UnserializeFromVector(s, m_tap_merkle_root);
719 break;
720 }
721+ case PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS:
722+ {
723+ if (!key_lookup.emplace(key).second) {
724+ throw std::ios_base::failure("Duplicate Key, input participant pubkeys for an aggregate key already provided");
725+ } else if (key.size() != 34) {
726+ throw std::ios_base::failure("Input musig2 participants pubkeys aggregate key is more than 33 bytes");
error message nit:
0 throw std::ios_base::failure("Input musig2 participants pubkeys aggregate key is not 34 bytes");
(assuming we are refering to the complete size of the key here, including the compact-size type prefix; we seem to do so on other key types like PSBT_IN_TAP_SCRIPT_SIG)
Code-review ACK 8da5ab60b58b808d693d251c8605d53ae54ba617
I’ve prepared a branch for adding the MuSig2 key types to the test framework and adding a functional test that verifies the decodepsbt
results on these, feel free to either pull in or ignore (will just open a separate PR after this one is merged then): https://github.com/theStack/bitcoin/tree/202411-test-add_musig2_decodepsbt_test
1371+ musig_keys.push_back(musig_part);
1372+ }
1373+ in.pushKV("musig2_participant_pubkeys", musig_keys);
1374+ }
1375+ if (!input.m_musig2_pubnonces.empty()) {
1376+ UniValue musig_pubnonces(UniValue::UniValue::VARR);
0 UniValue musig_pubnonces(UniValue::VARR);
1386+ }
1387+ }
1388+ in.pushKV("musig2_pubnonces", musig_pubnonces);
1389+ }
1390+ if (!input.m_musig2_partial_sigs.empty()) {
1391+ UniValue musig_partial_sigs(UniValue::UniValue::VARR);
0 UniValue musig_partial_sigs(UniValue::VARR);
926@@ -927,6 +927,37 @@ const RPCResult decodepsbt_inputs{
927 }},
928 {RPCResult::Type::STR_HEX, "taproot_internal_key", /*optional=*/ true, "The hex-encoded Taproot x-only internal key"},
929 {RPCResult::Type::STR_HEX, "taproot_merkle_root", /*optional=*/ true, "The hex-encoded Taproot merkle root"},
930+ {RPCResult::Type::ARR, "musig2_participant_pubkeys", /*optional*/true, "",
/*optional=*/ true
like above
utACK 8da5ab60b58b808d693d251c8605d53ae54ba617
Would have been nice to have tests here but fine for me to keep it for a follow-up since this is part of a larger project anyway.
re-ACK ea53b468e2650dc6e5d6d996cc899846a5ffe901
Just addressed minor review comments.
re-ACK ea53b468e2650dc6e5d6d996cc899846a5ffe901
Verified that all review comments have been adressed since my previous ACK.
Would have been nice to have tests here but fine for me to keep it for a follow-up
#29675 introduces wallet_musig.py
which uses PSBT internally. IIUC all new fields are needed for MuSig2 to work at all, so they’re tested implicitly. Additionally the test inspects musig2_participant_pubkeys
and musig2_partial_sigs
, though not musig2_pubnonces
.
That said, I think it would be better if this PR introduced at least some basic test coverage for e.g. the new errors that are introduced, and a simple round trip. This could be combined with generating test vectors for BIP 373.
Test vectors should probably include some PSBTv2 examples, which would have to go in a followup after #21283.
733+ std::vector<unsigned char> val;
734+ s >> val;
735+ SpanReader s_val{val};
736+ while (!s_val.empty()) {
737+ std::array<unsigned char, 33> part_key_bytes;
738+ s_val >> AsWritableBytes(Span{part_key_bytes});
s_val
has less than 33 bytes remaining, this throws?