Repository navigation
BIP174's invalid-witnessScript vector pushes a key that is not a point #408
Description
Activity
The pull request, opened as bitcoin/bips#2238.
Title: BIP-174: test data: a public key in the witnessScript case
Body:
The "PSBT with invalid output witnessScript typed key" case tests one
condition: aPSBT_OUT_WITNESS_SCRIPTkey longer than the one octet the
type is. Its last record, key length included, is21 010025512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d 06 d57f8a8751aeRead as a stream, the witnessScript is
OP_1 <03b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d06d57f8a87> OP_1 OP_CHECKMULTISIGand
x**3 + 7is not a square mod p for that x: the pushed key is not a
point of secp256k1.An implementation that checks the pushed key but not the key length
refuses the case for the wrong reason and the missing check goes
undetected.65f0b3dd62ecc55e43436173c5f84e893809d0fa replaced
2bwith06to make
the value length consistent: with2bit is 43 where 7 octets remain, and
a reader that takes the whole key-value pair before judging the key hits a
short read. That octet is the 29th of the pushed key.The case commits to the key with
2b. sha256 of that script is
876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a65, the
P2WSH the output's redeemScript pushes, and hash160 of that redeemScript
is b921b1ba6f722e4bfa83b6557a3139986a42ec83, the P2SH scriptPubKey of the
unsigned transaction's second output. The script as it reads today hashes
to bcea4f011e49b37595c2c24fd4b39077670a5d3a32dd47ed928d4e0dfbb21dc8, which
nothing in the case commits to. Another point in its place would mean
recomputing both hashes and the unsigned transaction; keeping it means
moving the value length off it.The record below does that, carrying the extra octet in the key and the
whole script in the value, as the "invalid output redeemScript typed key"
case does.02 0100 25 512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d2bd57f8a8751aeSame length as now, same failure, and the first 222 of the 264 octets
unchanged.bitcoin/bitcoin's
test/functional/data/rpc_psbt.jsoncarries the
pre-65f0b3dd octets, byte for byte: that copy has the key and the short
read. The encoding above serves both.The diff.
diff --git a/bip-0174.mediawiki b/bip-0174.mediawiki index 454a1db..640a207 100644 --- a/bip-0174.mediawiki +++ b/bip-0174.mediawiki @@ -679,8 +679,8 @@ The following are invalid PSBTs: ** Base64 String: <pre>cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A</pre> * Case: PSBT with invalid output witnessScript typed key -** Bytes in Hex: <pre>70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c00010016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a6521010025512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d06d57f8a8751ae00</pre> -** Base64 String: <pre>cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnQbVf4qHUa4A</pre> +** Bytes in Hex: <pre>70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c00010016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a6502010025512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d2bd57f8a8751ae00</pre> +** Base64 String: <pre>cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plAgEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A</pre> * Case: PSBT with unsigned tx serialized with witness serialization format ** Bytes in Hex: <pre>70736274ff01007802000000000101268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc78700b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab300000000000000</pre>
btclib already tests this vector, unmodified, as part of
test_invalid_psbt_bip174(case 18, "PSBT with invalid output witness
script typed key"). It raisesBTClibValueError: invalid witness script key length: 33, matching the vendorederror message:deserialize_bytes
checks the record's key length before the value is ever read, and nothing
in btclib's psbt code validates a pubkey pushed inside a script. The
vector cannot fail on "invalid public key" today, regardless of what
bitcoin/bips#2238 does upstream.tests/psbt/_data/bip174_test_vectors.jsonis pinned to bitcoin/bips
commit8c369ac8e6, documented intests/_data/README.md;
.github/workflows/vendored-vectors.yml's monthly
check_vendored_vectors.pyreports when that pin falls behind the tip of
bip-0174.mediawiki. Once bitcoin/bips#2238, or any other fix, merges and
moves the tip, that check opens "Vendored vectors behind upstream" and
the vector is refreshed then.Nothing to change in btclib until upstream moves.
BIP174's "PSBT with invalid output witness script typed key" pushes a key
that is not a point of secp256k1. The vector is vendored in
tests/psbt/_data/bip174_test_vectors.json,invalid psbts, and the copyis faithful: bip-0174.mediawiki has the same octets. btclib refuses the
vector for the defect it declares, so the script is never parsed.
The bytes
Its last record, key length included, is
Read as a stream, the witnessScript is
and
x**3 + 7is not a square mod p for that x.The sibling "PSBT with invalid output redeem script typed key" carries the
same script with
2bin place of06, and that key is a point. It is theonly well-formed key in the file — 33 octets, prefix 02 or 03 — that is
not one; the two the file declares invalid, in the input and output BIP32
derivations, are 32 octets, invalid by length.
The risk
The case tests one condition: a
PSBT_OUT_WITNESS_SCRIPTkey longer thanthe one octet the type is. An implementation that checks the pushed key
but not the key length refuses the vector for the wrong reason and the
missing check goes undetected.
Provenance
bitcoin/bips 6107b014 added the case with
2b. 65f0b3dd62ec, "BIP-174:test data: fix value length", replaced it with
06: with2bthe valuelength is 43 where 7 octets remain, so a reader that takes the whole
key-value pair before judging the key hits a short read. That octet is the
29th of the pushed key.
bitcoin/bitcoin's
test/functional/data/rpc_psbt.jsoncarries thepre-65f0b3dd octets, byte for byte.
The fix
The key is not free. sha256 of the script with
2bis876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a65, the
P2WSH the output's redeemScript pushes, and hash160 of that redeemScript
is b921b1ba6f722e4bfa83b6557a3139986a42ec83, the P2SH script_pub_key of
the unsigned transaction's second output. The script as it reads today
hashes to bcea4f011e49b37595c2c24fd4b39077670a5d3a32dd47ed928d4e0dfbb21dc8,
which nothing in the vector commits to. Another point in its place would
mean recomputing both hashes and the unsigned transaction: the octet to
keep is
2b, and what moves is the value length sitting on it.Upstream, mangling the record as the redeemScript case is mangled: the
extra octet in the key, the whole script in the value.
The first 222 of the 264 octets are unchanged; the last record reads
Same failure. btclib refuses it with
invalid witness script key length: 2against the current: 33, the vendorederror messageis the prefixboth share, and
tests/psbtpasses with the vector replaced.bitcoin/bips#2238 carries it: its text is in the comment below, its diff
in the one after.