diff --git a/changelog.d/verif-sighash-corpus.md b/changelog.d/verif-sighash-corpus.md new file mode 100644 index 0000000000..0e6304e123 --- /dev/null +++ b/changelog.d/verif-sighash-corpus.md @@ -0,0 +1,3 @@ +Added + +- **The script corpus pins executed `OP_VERIF` / `OP_VERNOTIF` and ECDSA hashtypes `0x00`, `0x80`, and `0x85`.** DERSIG still accepts those hashtypes. STRICTENC rejects them. Rewriting the type byte rejects the signature. diff --git a/crates/rbitcoin-consensus/src/script/mod.rs b/crates/rbitcoin-consensus/src/script/mod.rs index b62b0d7b84..b4f03c936c 100644 --- a/crates/rbitcoin-consensus/src/script/mod.rs +++ b/crates/rbitcoin-consensus/src/script/mod.rs @@ -879,6 +879,22 @@ pub(crate) mod crypto { assert!(!is_valid_signature_encoding(&sm)); assert!(is_valid_signature_encoding(&valid_der_sig())); + // BIP66 does not range-check the hashtype byte. STRICTENC does, + // via `is_defined_hashtype`. `0x00`, `0x04`, `0x80`, and `0x85` + // stay valid DER. + for ht in [0x00u8, 0x04, 0x80, 0x85] { + let mut sig = valid_der_sig(); + let last = sig.len() - 1; + sig[last] = ht; + assert!( + is_valid_signature_encoding(&sig), + "BIP66 keeps hashtype {ht:#x}" + ); + assert!( + !is_defined_hashtype(&sig), + "STRICTENC rejects hashtype {ht:#x}" + ); + } // A one-byte zero integer is minimal. `len > 1` must not become `>=`. assert!(is_valid_signature_encoding(&[ 0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01, 0x01 diff --git a/crates/rbitcoin-consensus/tests/fixtures/script_corpus/INDEX.md b/crates/rbitcoin-consensus/tests/fixtures/script_corpus/INDEX.md index afad2d5623..e6460b6eac 100644 --- a/crates/rbitcoin-consensus/tests/fixtures/script_corpus/INDEX.md +++ b/crates/rbitcoin-consensus/tests/fixtures/script_corpus/INDEX.md @@ -81,6 +81,12 @@ through `VerifyScript`. Legacy rows are bare scripts with no flags. | `vernotif-unexec-legacy` | OP_VERNOTIF rejects even inside an unexecuted IF, in every signature version. | | `vernotif-unexec-v0` | OP_VERNOTIF rejects even inside an unexecuted IF, in every signature version. | | `vernotif-unexec-tapscript` | OP_VERNOTIF rejects even inside an unexecuted IF, in every signature version. | +| `verif-exec-legacy` | OP_VERIF in the taken IF branch rejects, in every signature version. | +| `verif-exec-v0` | OP_VERIF in the taken IF branch rejects, in every signature version. | +| `verif-exec-tapscript` | OP_VERIF in the taken IF branch rejects, in every signature version. | +| `vernotif-exec-legacy` | OP_VERNOTIF in the taken IF branch rejects, in every signature version. | +| `vernotif-exec-v0` | OP_VERNOTIF in the taken IF branch rejects, in every signature version. | +| `vernotif-exec-tapscript` | OP_VERNOTIF in the taken IF branch rejects, in every signature version. | | `stack-1000-legacy` | Legacy main stack of 1,000 accepts. Cleanstack is off. | | `stack-1001-legacy` | Legacy main stack of 1,001 rejects. | | `stack-alt-1000-legacy` | Legacy main stack plus altstack of 1,000 accepts: 201 items moved aside, then 799 more. | @@ -297,7 +303,7 @@ Core `script_tests.json` already has both an accept and a reject for NOP, VERIFY An optional `spend` object sets `version`, `locktime`, `sequence`, and `n_outputs` on the spending transaction only. A missing object is version 1, locktime 0, sequence `0xffffffff`, and one output. `version` is the consensus i32 bit pattern. -Unknown hashtype bytes are a STRICTENC check. DERSIG checks the DER encoding and still accepts hashtype `0x04`. LOW_S stays off. +Unknown hashtype bytes are a STRICTENC check. DERSIG checks the DER encoding and still accepts hashtype `0x00`, `0x04`, `0x80`, and `0x85`. The signature is over that raw byte, so rewriting it to a standard type rejects. LOW_S stays off. FindAndDelete is observed with an empty signature. Its needle is the single byte `OP_0`. A verifying signature is not placed in `scriptPubKey`, because this credit template would make that signature commit to a txid that already contains it. A `0x00` buried in a push is the off-boundary case. A signature longer than `scriptCode` is the no-op already covered by `sighash-all-legacy`. @@ -338,6 +344,24 @@ Tapscript validation weight: one non-empty CHECKSIGADD against a 1-byte pubkey a | `sighash-type04-strictenc-legacy` | STRICTENC rejects hashtype 0x04. LOW_S stays off. | | `sighash-type04-dersig-v0` | Witness v0 DERSIG alone accepts hashtype 0x04. | | `sighash-type04-strictenc-v0` | Witness v0 STRICTENC rejects hashtype 0x04. | +| `sighash-type00-dersig-legacy` | DERSIG accepts hashtype 0x00. The digest uses that raw byte, not SIGHASH_ALL. | +| `sighash-type00-strictenc-legacy` | STRICTENC rejects hashtype 0x00. | +| `sighash-type00-as-01-legacy` | The 0x00 signature with its type byte rewritten to 0x01 rejects. | +| `sighash-type00-dersig-v0` | Witness v0 DERSIG accepts hashtype 0x00. | +| `sighash-type00-strictenc-v0` | Witness v0 STRICTENC rejects hashtype 0x00. | +| `sighash-type00-as-01-v0` | Witness v0 rejects the 0x00 signature rewritten to 0x01. | +| `sighash-type80-dersig-legacy` | DERSIG accepts hashtype 0x80 (ANYONECANPAY with base 0). | +| `sighash-type80-strictenc-legacy` | STRICTENC rejects hashtype 0x80. | +| `sighash-type80-as-81-legacy` | The 0x80 signature rewritten to 0x81 rejects. | +| `sighash-type80-dersig-v0` | Witness v0 DERSIG accepts hashtype 0x80. | +| `sighash-type80-strictenc-v0` | Witness v0 STRICTENC rejects hashtype 0x80. | +| `sighash-type80-as-81-v0` | Witness v0 rejects the 0x80 signature rewritten to 0x81. | +| `sighash-type85-dersig-legacy` | DERSIG accepts hashtype 0x85 (ANYONECANPAY with base 5). | +| `sighash-type85-strictenc-legacy` | STRICTENC rejects hashtype 0x85. | +| `sighash-type85-as-81-legacy` | The 0x85 signature rewritten to 0x81 rejects. | +| `sighash-type85-dersig-v0` | Witness v0 DERSIG accepts hashtype 0x85. | +| `sighash-type85-strictenc-v0` | Witness v0 STRICTENC rejects hashtype 0x85. | +| `sighash-type85-as-81-v0` | Witness v0 rejects the 0x85 signature rewritten to 0x81. | | `dersig-off-nondet-legacy` | With DERSIG and LOW_S off, a non-minimal S that the lax parser accepts still verifies. | | `dersig-on-nondet-legacy` | DERSIG rejects that non-minimal S. LOW_S stays off. | | `dersig-off-nondet-v0` | Witness v0 with DERSIG off accepts the same non-minimal S. | diff --git a/crates/rbitcoin-consensus/tests/fixtures/script_corpus/script_tests.json b/crates/rbitcoin-consensus/tests/fixtures/script_corpus/script_tests.json index f14959b213..a490ca6f9c 100644 --- a/crates/rbitcoin-consensus/tests/fixtures/script_corpus/script_tests.json +++ b/crates/rbitcoin-consensus/tests/fixtures/script_corpus/script_tests.json @@ -692,6 +692,78 @@ "ERR" ] }, + { + "id": "verif-exec-legacy", + "row": [ + "", + "0x516365675168", + "NONE", + "ERR" + ] + }, + { + "id": "verif-exec-v0", + "row": [ + [ + "516365675168", + 0.0 + ], + "", + "0x0020e06680f1661ad5b946977b6213d642e746144e4443619c0348079c83fd1bccbb", + "P2SH,WITNESS", + "ERR" + ] + }, + { + "id": "verif-exec-tapscript", + "row": [ + [ + "#SCRIPT# 0x516365675168", + "#CONTROLBLOCK#", + 0.0 + ], + "", + "0x51 0x20 #TAPROOTOUTPUT#", + "P2SH,WITNESS,TAPROOT", + "ERR" + ] + }, + { + "id": "vernotif-exec-legacy", + "row": [ + "", + "0x516366675168", + "NONE", + "ERR" + ] + }, + { + "id": "vernotif-exec-v0", + "row": [ + [ + "516366675168", + 0.0 + ], + "", + "0x00201ed8d3cebff162c775e607217c2c3679321e4b2df8bf70aeb71a2e5fd0a7dfe7", + "P2SH,WITNESS", + "ERR" + ] + }, + { + "id": "vernotif-exec-tapscript", + "row": [ + [ + "#SCRIPT# 0x516366675168", + "#CONTROLBLOCK#", + 0.0 + ], + "", + "0x51 0x20 #TAPROOTOUTPUT#", + "P2SH,WITNESS,TAPROOT", + "ERR" + ] + }, { "id": "stack-1000-legacy", "row": [ @@ -9506,6 +9578,213 @@ "ERR" ] }, + { + "id": "sighash-type00-dersig-legacy", + "row": [ + "0x483045022100a4c88cbf157bcb0c2a083675614690ce35d6a9577b7e28bc0f5831e182e1a9f00220109b1f54ade4786d10aa7d787609d9ba92a56f4b55c85c640dbce00cfedf2cd300", + "0x21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + "DERSIG", + "OK" + ] + }, + { + "id": "sighash-type00-strictenc-legacy", + "row": [ + "0x483045022100a4c88cbf157bcb0c2a083675614690ce35d6a9577b7e28bc0f5831e182e1a9f00220109b1f54ade4786d10aa7d787609d9ba92a56f4b55c85c640dbce00cfedf2cd300", + "0x21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + "STRICTENC", + "ERR" + ] + }, + { + "id": "sighash-type00-as-01-legacy", + "row": [ + "0x483045022100a4c88cbf157bcb0c2a083675614690ce35d6a9577b7e28bc0f5831e182e1a9f00220109b1f54ade4786d10aa7d787609d9ba92a56f4b55c85c640dbce00cfedf2cd301", + "0x21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + "DERSIG", + "ERR" + ] + }, + { + "id": "sighash-type00-dersig-v0", + "row": [ + [ + "3045022100970bf0ef00ef0c9c70871a2722fc659c726f8eef60ab2bd91f3d4146f8e0ed4f022017706ddd9d97351e5b9c02b76dd2587764fd692df8a57e2e510bde5856351fd600", + "21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + 0.0 + ], + "", + "0x00208f30ec1925eaa1916f4d67a9742d938c247d220c796bef6550111eaa90327245", + "P2SH,WITNESS,DERSIG", + "OK" + ] + }, + { + "id": "sighash-type00-strictenc-v0", + "row": [ + [ + "3045022100970bf0ef00ef0c9c70871a2722fc659c726f8eef60ab2bd91f3d4146f8e0ed4f022017706ddd9d97351e5b9c02b76dd2587764fd692df8a57e2e510bde5856351fd600", + "21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + 0.0 + ], + "", + "0x00208f30ec1925eaa1916f4d67a9742d938c247d220c796bef6550111eaa90327245", + "P2SH,WITNESS,STRICTENC", + "ERR" + ] + }, + { + "id": "sighash-type00-as-01-v0", + "row": [ + [ + "3045022100970bf0ef00ef0c9c70871a2722fc659c726f8eef60ab2bd91f3d4146f8e0ed4f022017706ddd9d97351e5b9c02b76dd2587764fd692df8a57e2e510bde5856351fd601", + "21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + 0.0 + ], + "", + "0x00208f30ec1925eaa1916f4d67a9742d938c247d220c796bef6550111eaa90327245", + "P2SH,WITNESS,DERSIG", + "ERR" + ] + }, + { + "id": "sighash-type80-dersig-legacy", + "row": [ + "0x483045022100fdcc007649c5545067c1e1caaeb229deb358ccd1a4c912b3c90d63919ffa2f6902205741a9a1b8dd4ebd9d9f656285f773fb0276567c475f62a1c4a9a37f4f37319a80", + "0x21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + "DERSIG", + "OK" + ] + }, + { + "id": "sighash-type80-strictenc-legacy", + "row": [ + "0x483045022100fdcc007649c5545067c1e1caaeb229deb358ccd1a4c912b3c90d63919ffa2f6902205741a9a1b8dd4ebd9d9f656285f773fb0276567c475f62a1c4a9a37f4f37319a80", + "0x21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + "STRICTENC", + "ERR" + ] + }, + { + "id": "sighash-type80-as-81-legacy", + "row": [ + "0x483045022100fdcc007649c5545067c1e1caaeb229deb358ccd1a4c912b3c90d63919ffa2f6902205741a9a1b8dd4ebd9d9f656285f773fb0276567c475f62a1c4a9a37f4f37319a81", + "0x21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + "DERSIG", + "ERR" + ] + }, + { + "id": "sighash-type80-dersig-v0", + "row": [ + [ + "3045022100a29b93bdbe099c4bcd88071d890be29b1c2f1a5c43ee2adeda66e6960e08cc2602200c4ece9d140cf6fe3d61e9ba03c4f7d2a9a31cc6e1982ce07e14ecac8b0cf37980", + "21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + 0.0 + ], + "", + "0x00208f30ec1925eaa1916f4d67a9742d938c247d220c796bef6550111eaa90327245", + "P2SH,WITNESS,DERSIG", + "OK" + ] + }, + { + "id": "sighash-type80-strictenc-v0", + "row": [ + [ + "3045022100a29b93bdbe099c4bcd88071d890be29b1c2f1a5c43ee2adeda66e6960e08cc2602200c4ece9d140cf6fe3d61e9ba03c4f7d2a9a31cc6e1982ce07e14ecac8b0cf37980", + "21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + 0.0 + ], + "", + "0x00208f30ec1925eaa1916f4d67a9742d938c247d220c796bef6550111eaa90327245", + "P2SH,WITNESS,STRICTENC", + "ERR" + ] + }, + { + "id": "sighash-type80-as-81-v0", + "row": [ + [ + "3045022100a29b93bdbe099c4bcd88071d890be29b1c2f1a5c43ee2adeda66e6960e08cc2602200c4ece9d140cf6fe3d61e9ba03c4f7d2a9a31cc6e1982ce07e14ecac8b0cf37981", + "21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + 0.0 + ], + "", + "0x00208f30ec1925eaa1916f4d67a9742d938c247d220c796bef6550111eaa90327245", + "P2SH,WITNESS,DERSIG", + "ERR" + ] + }, + { + "id": "sighash-type85-dersig-legacy", + "row": [ + "0x4730440220480d07c26876b82c87089d7450fb055416c603fb747c41f5c0ea598521cd11fd02201127b240fb977b1c15c5b98e7786aaea96bc4e44e166d4e4cc80eb7496dafd9085", + "0x21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + "DERSIG", + "OK" + ] + }, + { + "id": "sighash-type85-strictenc-legacy", + "row": [ + "0x4730440220480d07c26876b82c87089d7450fb055416c603fb747c41f5c0ea598521cd11fd02201127b240fb977b1c15c5b98e7786aaea96bc4e44e166d4e4cc80eb7496dafd9085", + "0x21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + "STRICTENC", + "ERR" + ] + }, + { + "id": "sighash-type85-as-81-legacy", + "row": [ + "0x4730440220480d07c26876b82c87089d7450fb055416c603fb747c41f5c0ea598521cd11fd02201127b240fb977b1c15c5b98e7786aaea96bc4e44e166d4e4cc80eb7496dafd9081", + "0x21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + "DERSIG", + "ERR" + ] + }, + { + "id": "sighash-type85-dersig-v0", + "row": [ + [ + "304502210090ac2a7e4b7ee1d1c6c89916029d1a98e7f5633e2fe426a0e8a45396482c95e1022044ee303bf6b4e069776d34c3da602364acbae6ce9f38ed3bc4693ef60ffe5e9c85", + "21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + 0.0 + ], + "", + "0x00208f30ec1925eaa1916f4d67a9742d938c247d220c796bef6550111eaa90327245", + "P2SH,WITNESS,DERSIG", + "OK" + ] + }, + { + "id": "sighash-type85-strictenc-v0", + "row": [ + [ + "304502210090ac2a7e4b7ee1d1c6c89916029d1a98e7f5633e2fe426a0e8a45396482c95e1022044ee303bf6b4e069776d34c3da602364acbae6ce9f38ed3bc4693ef60ffe5e9c85", + "21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + 0.0 + ], + "", + "0x00208f30ec1925eaa1916f4d67a9742d938c247d220c796bef6550111eaa90327245", + "P2SH,WITNESS,STRICTENC", + "ERR" + ] + }, + { + "id": "sighash-type85-as-81-v0", + "row": [ + [ + "304502210090ac2a7e4b7ee1d1c6c89916029d1a98e7f5633e2fe426a0e8a45396482c95e1022044ee303bf6b4e069776d34c3da602364acbae6ce9f38ed3bc4693ef60ffe5e9c81", + "21034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aaac", + 0.0 + ], + "", + "0x00208f30ec1925eaa1916f4d67a9742d938c247d220c796bef6550111eaa90327245", + "P2SH,WITNESS,DERSIG", + "ERR" + ] + }, { "id": "dersig-off-nondet-legacy", "row": [