psbt: Refactor duplicate key lookup and size checks

Every key has a duplicate key lookup check, and many keys have fixed
size checks. These can be refactored to reduce code duplication.

Co-Authored-By: David Gumberg <davidzgumberg@gmail.com>
This commit is contained in:
Ava Chow
2026-03-18 10:30:26 -07:00
parent 88384180d3
commit 1e2d146b47
2 changed files with 53 additions and 175 deletions

View File

@@ -158,9 +158,6 @@ void DeserializeHDKeypaths(Stream& s, const std::vector<unsigned char>& key, std
if (!pubkey.IsFullyValid()) {
throw std::ios_base::failure("Invalid pubkey");
}
if (hd_keypaths.contains(pubkey)) {
throw std::ios_base::failure("Duplicate Key, pubkey derivation path already provided");
}
KeyOriginInfo keypath;
DeserializeHDKeypath(s, keypath);
@@ -257,6 +254,12 @@ void DeserializeMuSig2ParticipantDataIdentifier(Stream& skey, CPubKey& agg_pub,
}
}
static inline void ExpectedKeySize(const std::string& key_name, const std::vector<unsigned char>& key, uint64_t expected_size) {
if (key.size() != expected_size) {
throw std::ios_base::failure(tfm::format("Size of key was not %d for the type %s", expected_size, key_name));
}
}
/** A structure for PSBTs which contain per-input information */
struct PSBTInput
{
@@ -494,6 +497,11 @@ struct PSBTInput
break;
}
// Duplicate keys are not permitted
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure(tfm::format("Duplicate Key, input key \"%s\" already provided", HexStr(key)));
}
// "skey" is used so that "key" is unchanged after reading keytype below
SpanReader skey{key};
// keytype is of the format compact size uint at the beginning of "key"
@@ -504,21 +512,13 @@ struct PSBTInput
switch(type) {
case PSBT_IN_NON_WITNESS_UTXO:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input non-witness utxo already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Non-witness utxo key is more than one byte type");
}
ExpectedKeySize("Input Non-witness UTXO", key, 1);
// Set the stream to unserialize with witness since this is always a valid network transaction
UnserializeFromVector(s, TX_WITH_WITNESS(non_witness_utxo));
break;
}
case PSBT_IN_WITNESS_UTXO:
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input witness utxo already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Witness utxo key is more than one byte type");
}
ExpectedKeySize("Input Witness UTXO", key, 1);
UnserializeFromVector(s, witness_utxo);
break;
case PSBT_IN_PARTIAL_SIG:
@@ -532,9 +532,6 @@ struct PSBTInput
if (!pubkey.IsFullyValid()) {
throw std::ios_base::failure("Invalid pubkey");
}
if (partial_sigs.contains(pubkey.GetID())) {
throw std::ios_base::failure("Duplicate Key, input partial signature for pubkey already provided");
}
// Read in the signature from value
std::vector<unsigned char> sig;
@@ -550,32 +547,20 @@ struct PSBTInput
break;
}
case PSBT_IN_SIGHASH:
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input sighash type already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Sighash type key is more than one byte type");
}
ExpectedKeySize("Input Sighash Type", key, 1);
int sighash;
UnserializeFromVector(s, sighash);
sighash_type = sighash;
break;
case PSBT_IN_REDEEMSCRIPT:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input redeemScript already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Input redeemScript key is more than one byte type");
}
ExpectedKeySize("Input redeemScript", key, 1);
s >> redeem_script;
break;
}
case PSBT_IN_WITNESSSCRIPT:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input witnessScript already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Input witnessScript key is more than one byte type");
}
ExpectedKeySize("Input witnessScript", key, 1);
s >> witness_script;
break;
}
@@ -586,36 +571,22 @@ struct PSBTInput
}
case PSBT_IN_SCRIPTSIG:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input final scriptSig already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Final scriptSig key is more than one byte type");
}
ExpectedKeySize("Input Final scriptSig", key, 1);
s >> final_script_sig;
break;
}
case PSBT_IN_SCRIPTWITNESS:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input final scriptWitness already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Final scriptWitness key is more than one byte type");
}
ExpectedKeySize("Input Final scriptWitness", key, 1);
UnserializeFromVector(s, final_script_witness.stack);
break;
}
case PSBT_IN_RIPEMD160:
{
// Make sure that the key is the size of a ripemd160 hash + 1
if (key.size() != CRIPEMD160::OUTPUT_SIZE + 1) {
throw std::ios_base::failure("Size of key was not the expected size for the type ripemd160 preimage");
}
ExpectedKeySize("Input RIPEMD160 Preimage", key, CRIPEMD160::OUTPUT_SIZE + 1);
// Read in the hash from key
std::vector<unsigned char> hash_vec(key.begin() + 1, key.end());
uint160 hash(hash_vec);
if (ripemd160_preimages.contains(hash)) {
throw std::ios_base::failure("Duplicate Key, input ripemd160 preimage already provided");
}
// Read in the preimage from value
std::vector<unsigned char> preimage;
@@ -627,16 +598,10 @@ struct PSBTInput
}
case PSBT_IN_SHA256:
{
// Make sure that the key is the size of a sha256 hash + 1
if (key.size() != CSHA256::OUTPUT_SIZE + 1) {
throw std::ios_base::failure("Size of key was not the expected size for the type sha256 preimage");
}
ExpectedKeySize("Input SHA256 Preimage", key, CSHA256::OUTPUT_SIZE + 1);
// Read in the hash from key
std::vector<unsigned char> hash_vec(key.begin() + 1, key.end());
uint256 hash(hash_vec);
if (sha256_preimages.contains(hash)) {
throw std::ios_base::failure("Duplicate Key, input sha256 preimage already provided");
}
// Read in the preimage from value
std::vector<unsigned char> preimage;
@@ -648,16 +613,10 @@ struct PSBTInput
}
case PSBT_IN_HASH160:
{
// Make sure that the key is the size of a hash160 hash + 1
if (key.size() != CHash160::OUTPUT_SIZE + 1) {
throw std::ios_base::failure("Size of key was not the expected size for the type hash160 preimage");
}
ExpectedKeySize("Input Hash160 Preimage", key, CHash160::OUTPUT_SIZE + 1);
// Read in the hash from key
std::vector<unsigned char> hash_vec(key.begin() + 1, key.end());
uint160 hash(hash_vec);
if (hash160_preimages.contains(hash)) {
throw std::ios_base::failure("Duplicate Key, input hash160 preimage already provided");
}
// Read in the preimage from value
std::vector<unsigned char> preimage;
@@ -669,16 +628,10 @@ struct PSBTInput
}
case PSBT_IN_HASH256:
{
// Make sure that the key is the size of a hash256 hash + 1
if (key.size() != CHash256::OUTPUT_SIZE + 1) {
throw std::ios_base::failure("Size of key was not the expected size for the type hash256 preimage");
}
ExpectedKeySize("Input Hash256 Preimage", key, CHash256::OUTPUT_SIZE + 1);
// Read in the hash from key
std::vector<unsigned char> hash_vec(key.begin() + 1, key.end());
uint256 hash(hash_vec);
if (hash256_preimages.contains(hash)) {
throw std::ios_base::failure("Duplicate Key, input hash256 preimage already provided");
}
// Read in the preimage from value
std::vector<unsigned char> preimage;
@@ -690,11 +643,7 @@ struct PSBTInput
}
case PSBT_IN_TAP_KEY_SIG:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input Taproot key signature already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Input Taproot key signature key is more than one byte type");
}
ExpectedKeySize("Input Taproot Key Path Signature", key, 1);
s >> m_tap_key_sig;
if (m_tap_key_sig.size() < 64) {
throw std::ios_base::failure("Input Taproot key path signature is shorter than 64 bytes");
@@ -705,11 +654,7 @@ struct PSBTInput
}
case PSBT_IN_TAP_SCRIPT_SIG:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input Taproot script signature already provided");
} else if (key.size() != 65) {
throw std::ios_base::failure("Input Taproot script signature key is not 65 bytes");
}
ExpectedKeySize("Input Taproot Script Path Signature", key, 65);
SpanReader s_key{std::span{key}.subspan(1)};
XOnlyPubKey xonly;
uint256 hash;
@@ -727,10 +672,8 @@ struct PSBTInput
}
case PSBT_IN_TAP_LEAF_SCRIPT:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input Taproot leaf script already provided");
} else if (key.size() < 34) {
throw std::ios_base::failure("Taproot leaf script key is not at least 34 bytes");
if (key.size() < 34) {
throw std::ios_base::failure("Input Taproot leaf script key is not at least 34 bytes");
} else if ((key.size() - 2) % 32 != 0) {
throw std::ios_base::failure("Input Taproot leaf script key's control block size is not valid");
}
@@ -747,11 +690,7 @@ struct PSBTInput
}
case PSBT_IN_TAP_BIP32_DERIVATION:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input Taproot BIP32 keypath already provided");
} else if (key.size() != 33) {
throw std::ios_base::failure("Input Taproot BIP32 keypath key is not at 33 bytes");
}
ExpectedKeySize("Input Taproot BIP32 Keypath", key, 33);
SpanReader s_key{std::span{key}.subspan(1)};
XOnlyPubKey xonly;
s_key >> xonly;
@@ -770,39 +709,25 @@ struct PSBTInput
}
case PSBT_IN_TAP_INTERNAL_KEY:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input Taproot internal key already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Input Taproot internal key key is more than one byte type");
}
ExpectedKeySize("Input Taproot Internal Key", key, 1);
UnserializeFromVector(s, m_tap_internal_key);
break;
}
case PSBT_IN_TAP_MERKLE_ROOT:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input Taproot merkle root already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Input Taproot merkle root key is more than one byte type");
}
ExpectedKeySize("Input Taproot Merkle Root", key, 1);
UnserializeFromVector(s, m_tap_merkle_root);
break;
}
case PSBT_IN_MUSIG2_PARTICIPANT_PUBKEYS:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input participant pubkeys for an aggregate key already provided");
} else if (key.size() != CPubKey::COMPRESSED_SIZE + 1) {
throw std::ios_base::failure("Input musig2 participants pubkeys aggregate key is not 34 bytes");
}
ExpectedKeySize("Input MuSig2 Participants Pubkeys", key, CPubKey::COMPRESSED_SIZE + 1);
DeserializeMuSig2ParticipantPubkeys(s, skey, m_musig2_participants, std::string{"Input"});
break;
}
case PSBT_IN_MUSIG2_PUB_NONCE:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input musig2 pubnonce already provided");
} else if (key.size() != 2 * CPubKey::COMPRESSED_SIZE + 1 && key.size() != 2 * CPubKey::COMPRESSED_SIZE + CSHA256::OUTPUT_SIZE + 1) {
if (key.size() != 2 * CPubKey::COMPRESSED_SIZE + 1 && key.size() != 2 * CPubKey::COMPRESSED_SIZE + CSHA256::OUTPUT_SIZE + 1) {
throw std::ios_base::failure("Input musig2 pubnonce key is not expected size of 67 or 99 bytes");
}
CPubKey agg_pub, part_pub;
@@ -820,9 +745,7 @@ struct PSBTInput
}
case PSBT_IN_MUSIG2_PARTIAL_SIG:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, input musig2 partial sig already provided");
} else if (key.size() != 2 * CPubKey::COMPRESSED_SIZE + 1 && key.size() != 2 * CPubKey::COMPRESSED_SIZE + CSHA256::OUTPUT_SIZE + 1) {
if (key.size() != 2 * CPubKey::COMPRESSED_SIZE + 1 && key.size() != 2 * CPubKey::COMPRESSED_SIZE + CSHA256::OUTPUT_SIZE + 1) {
throw std::ios_base::failure("Input musig2 partial sig key is not expected size of 67 or 99 bytes");
}
CPubKey agg_pub, part_pub;
@@ -842,18 +765,12 @@ struct PSBTInput
this_prop.subtype = ReadCompactSize(skey);
this_prop.key = key;
if (m_proprietary.contains(this_prop)) {
throw std::ios_base::failure("Duplicate Key, proprietary key already found");
}
s >> this_prop.value;
m_proprietary.insert(this_prop);
break;
}
// Unknown stuff
default:
if (unknown.contains(key)) {
throw std::ios_base::failure("Duplicate Key, key for unknown value already provided");
}
// Read in the value
std::vector<unsigned char> val_bytes;
s >> val_bytes;
@@ -986,6 +903,11 @@ struct PSBTOutput
break;
}
// Duplicate keys are not permitted
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure(tfm::format("Duplicate Key, output key \"%s\" already provided", HexStr(key)));
}
// "skey" is used so that "key" is unchanged after reading keytype below
SpanReader skey{key};
// keytype is of the format compact size uint at the beginning of "key"
@@ -996,21 +918,13 @@ struct PSBTOutput
switch(type) {
case PSBT_OUT_REDEEMSCRIPT:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, output redeemScript already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Output redeemScript key is more than one byte type");
}
ExpectedKeySize("Output redeemScript", key, 1);
s >> redeem_script;
break;
}
case PSBT_OUT_WITNESSSCRIPT:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, output witnessScript already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Output witnessScript key is more than one byte type");
}
ExpectedKeySize("Output witnessScript", key, 1);
s >> witness_script;
break;
}
@@ -1021,21 +935,13 @@ struct PSBTOutput
}
case PSBT_OUT_TAP_INTERNAL_KEY:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, output Taproot internal key already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Output Taproot internal key key is more than one byte type");
}
ExpectedKeySize("Output Taproot Internal Key", key, 1);
UnserializeFromVector(s, m_tap_internal_key);
break;
}
case PSBT_OUT_TAP_TREE:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, output Taproot tree already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Output Taproot tree key is more than one byte type");
}
ExpectedKeySize("Output Taproot Tree Key", key, 1);
std::vector<unsigned char> tree_v;
s >> tree_v;
SpanReader s_tree{tree_v};
@@ -1066,11 +972,7 @@ struct PSBTOutput
}
case PSBT_OUT_TAP_BIP32_DERIVATION:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, output Taproot BIP32 keypath already provided");
} else if (key.size() != 33) {
throw std::ios_base::failure("Output Taproot BIP32 keypath key is not at 33 bytes");
}
ExpectedKeySize("Output Taproot BIP32 Keypath", key, 33);
XOnlyPubKey xonly(uint256(std::span<uint8_t>(key).last(32)));
std::set<uint256> leaf_hashes;
uint64_t value_len = ReadCompactSize(s);
@@ -1087,11 +989,7 @@ struct PSBTOutput
}
case PSBT_OUT_MUSIG2_PARTICIPANT_PUBKEYS:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, output participant pubkeys for an aggregate key already provided");
} else if (key.size() != CPubKey::COMPRESSED_SIZE + 1) {
throw std::ios_base::failure("Output musig2 participants pubkeys aggregate key is not 34 bytes");
}
ExpectedKeySize("Output MuSig2 Participants Pubkeys", key, CPubKey::COMPRESSED_SIZE + 1);
DeserializeMuSig2ParticipantPubkeys(s, skey, m_musig2_participants, std::string{"Output"});
break;
}
@@ -1102,18 +1000,12 @@ struct PSBTOutput
this_prop.subtype = ReadCompactSize(skey);
this_prop.key = key;
if (m_proprietary.contains(this_prop)) {
throw std::ios_base::failure("Duplicate Key, proprietary key already found");
}
s >> this_prop.value;
m_proprietary.insert(this_prop);
break;
}
// Unknown stuff
default: {
if (unknown.contains(key)) {
throw std::ios_base::failure("Duplicate Key, key for unknown value already provided");
}
// Read in the value
std::vector<unsigned char> val_bytes;
s >> val_bytes;
@@ -1252,6 +1144,11 @@ struct PartiallySignedTransaction
break;
}
// Duplicate keys are not permitted
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure(tfm::format("Duplicate Key, global key \"%s\" already provided", HexStr(key)));
}
// "skey" is used so that "key" is unchanged after reading keytype below
SpanReader skey{key};
// keytype is of the format compact size uint at the beginning of "key"
@@ -1262,11 +1159,7 @@ struct PartiallySignedTransaction
switch(type) {
case PSBT_GLOBAL_UNSIGNED_TX:
{
if (!key_lookup.emplace(key).second) {
throw std::ios_base::failure("Duplicate Key, unsigned tx already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Global unsigned tx key is more than one byte type");
}
ExpectedKeySize("Global Unsigned TX", key, 1);
CMutableTransaction mtx;
// Set the stream to serialize with non-witness since this should always be non-witness
UnserializeFromVector(s, TX_NO_WITNESS(mtx));
@@ -1281,18 +1174,13 @@ struct PartiallySignedTransaction
}
case PSBT_GLOBAL_XPUB:
{
if (key.size() != BIP32_EXTKEY_WITH_VERSION_SIZE + 1) {
throw std::ios_base::failure("Size of key was not the expected size for the type global xpub");
}
ExpectedKeySize("Global XPUB", key, BIP32_EXTKEY_WITH_VERSION_SIZE + 1);
// Read in the xpub from key
CExtPubKey xpub;
xpub.DecodeWithVersion(&key.data()[1]);
if (!xpub.pubkey.IsFullyValid()) {
throw std::ios_base::failure("Invalid pubkey");
}
if (global_xpubs.contains(xpub)) {
throw std::ios_base::failure("Duplicate key, global xpub already provided");
}
global_xpubs.insert(xpub);
// Read in the keypath from stream
KeyOriginInfo keypath;
@@ -1311,11 +1199,7 @@ struct PartiallySignedTransaction
}
case PSBT_GLOBAL_VERSION:
{
if (m_version) {
throw std::ios_base::failure("Duplicate Key, version already provided");
} else if (key.size() != 1) {
throw std::ios_base::failure("Global version key is more than one byte type");
}
ExpectedKeySize("Global PSBT Version", key, 1);
uint32_t v;
UnserializeFromVector(s, v);
m_version = v;
@@ -1331,18 +1215,12 @@ struct PartiallySignedTransaction
this_prop.subtype = ReadCompactSize(skey);
this_prop.key = key;
if (m_proprietary.contains(this_prop)) {
throw std::ios_base::failure("Duplicate Key, proprietary key already found");
}
s >> this_prop.value;
m_proprietary.insert(this_prop);
break;
}
// Unknown stuff
default: {
if (unknown.contains(key)) {
throw std::ios_base::failure("Duplicate Key, key for unknown value already provided");
}
// Read in the value
std::vector<unsigned char> val_bytes;
s >> val_bytes;

View File

@@ -53,7 +53,7 @@
],
[
"cHNidP8BAFICAAAAAVaG3/QAFl9OBApYVfZYCTRyybz4EIsnKl0x8YH3tP+xAQAAAAD9////ARjd9QUAAAAAFgAUyRI+BujX8JZsXRzQ+TMALU63V80AAAAAAAEBKwDh9QUAAAAAIlEgC1jjN6pNOFKowpOHxCQI2M++OmE6Xjl+Cp8BpftxB9QhFgtY4zeqTThSqMKTh8QkCNjPvjphOl45fgqfAaX7cQfUBQAmgN1uIRY0a5lZM1cQfJ00Weneuo0+r0TmY2yFx/hT65C6UujNAAUAWAsIhyEWT6/WX4FpGG/Cv9siM8d+Yw0QvigKJMcWXAmidhF3XCwFAMMkmoIhFvkwigGSWMMQSTRPhfidUim1MchFg2+ZsIYB8RO84Db5BQB91lWSIRoLWOM3qk04UqjCk4fEJAjYz746YTpeOX4KnwGl+3EH1GMCNGuZWTNXEHydNFnp3rqNPq9E5mNshcf4U+uQulLozQACT6/WX4FpGG/Cv9siM8d+Yw0QvigKJMcWXAmidhF3XCwC+TCKAZJYwxBJNE+F+J1SKbUxyEWDb5mwhgHxE7zgNvkAAA==",
"Input musig2 participants pubkeys aggregate key is not 34 bytes"
"Size of key was not 34 for the type Input MuSig2 Participants Pubkeys"
],
[
"cHNidP8BADMAAZJuAQAAAAAAAAAAAABMHQD/AAAAAAAAAAAA//////9BAB4AjIwAAAD5////AAAA/NwAAQErYQIAAAAAAAAiUSBw/G0rYgJicCsrtgAA2P//+HN0AAIA+f//7gAF++8AACIaCAEAAP8AcHNidP8BABMAAiEeAAEXDD4AAAEBAACCpP73IUL8j3+PjNNzYnT/AAAAAAAAlpb/AAAAAAAAAAYEAisAAAA=",
@@ -77,7 +77,7 @@
],
[
"cHNidP8BAH0CAAAAASWJ53Z5WLoVT5AYzM8N7ephR7tgzRoZS241kKmWVpDWAAAAAAD9////AoCWmAAAAAAAIlEgKWfS0CCpeV2nK1G+Tz/KJbsOV+kcWz56gav6cjKjSUIPwJJ8AAAAABYAFDScXTMCeMMAKmT1l9KwGqPcG9kDAAAAAAABAH0CAAAAAZqLSlB5a5YAmQ9/4R36ALxw79KWBIr8hnGa8PsfqRk3AAAAAAD9////AolcK30AAAAAFgAUz9mLoQJ+pO1L0q4bNIthVqAVA3UA4fUFAAAAACJRINCyJsZZnyc4dN+P5oSrbDAoCBvuiiy+0xoTb1hl9s+k4QAAAAEBH4lcK30AAAAAFgAUz9mLoQJ+pO1L0q4bNIthVqAVA3UiBgKmZlDwi/+k8InrIu3NvnYWZF/2zRgKNkhNS8gQVFlbexi//0SjVAAAgAEAAIAAAACAAQAAAIoCAAAAAQUgC1jjN6pNOFKowpOHxCQI2M++OmE6Xjl+Cp8BpftxB9QhBwtY4zeqTThSqMKTh8QkCNjPvjphOl45fgqfAaX7cQfUBQAmgN1uIQc0a5lZM1cQfJ00Weneuo0+r0TmY2yFx/hT65C6UujNAAUAWAsIhyEHT6/WX4FpGG/Cv9siM8d+Yw0QvigKJMcWXAmidhF3XCwFAMMkmoIhB/kwigGSWMMQSTRPhfidUim1MchFg2+ZsIYB8RO84Db5BQB91lWSIQgLWOM3qk04UqjCk4fEJAjYz746YTpeOX4KnwGl+3EH1GMCNGuZWTNXEHydNFnp3rqNPq9E5mNshcf4U+uQulLozQACT6/WX4FpGG/Cv9siM8d+Yw0QvigKJMcWXAmidhF3XCwC+TCKAZJYwxBJNE+F+J1SKbUxyEWDb5mwhgHxE7zgNvkAIgIDvkrlPTfMB19Asw1tpHKdQK3uuYNTOvFhYZK8dtWyYSoYv/9Eo1QAAIABAACAAAAAgAEAAACNAgAAAA==",
"Output musig2 participants pubkeys aggregate key is not 34 bytes"
"Size of key was not 34 for the type Output MuSig2 Participants Pubkeys"
],
[
"cHNidP8BAH0CAAAAASWJ53Z5WLoVT5AYzM8N7ephR7tgzRoZS241kKmWVpDWAAAAAAD9////AoCWmAAAAAAAIlEgKWfS0CCpeV2nK1G+Tz/KJbsOV+kcWz56gav6cjKjSUIPwJJ8AAAAABYAFDScXTMCeMMAKmT1l9KwGqPcG9kDAAAAAAABAH0CAAAAAZqLSlB5a5YAmQ9/4R36ALxw79KWBIr8hnGa8PsfqRk3AAAAAAD9////AolcK30AAAAAFgAUz9mLoQJ+pO1L0q4bNIthVqAVA3UA4fUFAAAAACJRINCyJsZZnyc4dN+P5oSrbDAoCBvuiiy+0xoTb1hl9s+k4QAAAAEBH4lcK30AAAAAFgAUz9mLoQJ+pO1L0q4bNIthVqAVA3UiBgKmZlDwi/+k8InrIu3NvnYWZF/2zRgKNkhNS8gQVFlbexi//0SjVAAAgAEAAIAAAACAAQAAAIoCAAAAAQUgC1jjN6pNOFKowpOHxCQI2M++OmE6Xjl+Cp8BpftxB9QhBwtY4zeqTThSqMKTh8QkCNjPvjphOl45fgqfAaX7cQfUBQAmgN1uIQc0a5lZM1cQfJ00Weneuo0+r0TmY2yFx/hT65C6UujNAAUAWAsIhyEHT6/WX4FpGG/Cv9siM8d+Yw0QvigKJMcWXAmidhF3XCwFAMMkmoIhB/kwigGSWMMQSTRPhfidUim1MchFg2+ZsIYB8RO84Db5BQB91lWSIggDC1jjN6pNOFKowpOHxCQI2M++OmE6Xjl+Cp8BpftxB9RiNGuZWTNXEHydNFnp3rqNPq9E5mNshcf4U+uQulLozQACT6/WX4FpGG/Cv9siM8d+Yw0QvigKJMcWXAmidhF3XCwC+TCKAZJYwxBJNE+F+J1SKbUxyEWDb5mwhgHxE7zgNvkAIgIDvkrlPTfMB19Asw1tpHKdQK3uuYNTOvFhYZK8dtWyYSoYv/9Eo1QAAIABAACAAAAAgAEAAACNAgAAAA==",