psbt: Refactor duplicate key lookup and size checks
What changed, and why it matters
This commit is a code cleanup in Bitcoin Core's Partially Signed Bitcoin Transaction (PSBT) handling. It moves duplicate-key detection and fixed-size checks into shared helpers so the same logic is not repeated dozens of times. The behavior is intended to stay the same; only error messages change in a few test cases. There is no indication this fixes a security bug.
No security action required. Treat as normal code-quality review; verify that the centralized duplicate check covers all previously checked cases, which the diff appears to confirm.
Security signals we found
Refactoring only: duplicate detection and size validation logic preserved
Error message strings changed; no test vectors removed
No new parsing paths or trust boundaries introduced
No vendor disclosure of security relevance in commit message or diff
Evidence from the diff
The patch refactors PSBT deserialization in src/psbt.h. A single key_lookup.emplace(key) duplicate check is hoisted before the switch statements for PSBTInput, PSBTOutput, and PartiallySignedTransaction, replacing per-case duplicate checks. Fixed-size key checks are consolidated into a new ExpectedKeySize() helper. A few remaining per-case size checks (e.g., MuSig2 pubnonce/partial sig variable sizes, Taproot leaf script minimum size) are left inline. Test expectations in rpc_psbt.json are updated only because error message strings changed. No logic relaxation or tightening is visible in the diff.
Changed components
src/psbt.htest/functional/data/rpc_psbt.jsonInspect captured patch +53 / −175
diff --git a/src/psbt.h b/src/psbt.h
index 6348bd15..719d68d9 100644
--- a/src/psbt.h
+++ b/src/psbt.h
@@ -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;
diff --git a/test/functional/data/rpc_psbt.json b/test/functional/data/rpc_psbt.json
index 9e8131db..fd46312a 100644
--- a/test/functional/data/rpc_psbt.json
+++ b/test/functional/data/rpc_psbt.json
@@ -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==",
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.