Repository navigation
Introduce per-txin sighash midstate cache for legacy/p2sh/segwitv0 scripts - #32473
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code Coverage & BenchmarksFor details see: https://corecheck.dev/bitcoin/bitcoin/pulls/32473. ReviewsSee 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. ConflictsReviewers, 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. |
darosior
left a comment
There was a problem hiding this comment.
Neat. Concept ACK.
I'm open to discussing alternatives, however.
I think enabling it by consensus is unnecessarily risky. I would rather take some slightly more complicate logic, for instance by having CScriptCheck own the sighash cache:
Click to see diff
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index ffac2acb948..fe24dae6c54 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1700,7 +1700,7 @@ bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vecto
// Witness sighashes need the amount.
if (sigversion == SigVersion::WITNESS_V0 && amount < 0) return HandleMissingData(m_mdb);
- uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata, &m_sighash_cache);
+ uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata, m_sighash_cache);
if (!VerifyECDSASignature(vchSig, pubkey, sighash))
return false;
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 2108e3992fc..6c84c6dd74c 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -308,15 +308,15 @@ private:
unsigned int nIn;
const CAmount amount;
const PrecomputedTransactionData* txdata;
- mutable SigHashCache m_sighash_cache;
+ mutable SigHashCache* m_sighash_cache;
protected:
virtual bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
virtual bool VerifySchnorrSignature(std::span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const;
public:
- GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, MissingDataBehavior mdb) : txTo(txToIn), m_mdb(mdb), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
- GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn, MissingDataBehavior mdb) : txTo(txToIn), m_mdb(mdb), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
+ GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, MissingDataBehavior mdb, SigHashCache* sighash_cache = nullptr) : txTo(txToIn), m_mdb(mdb), nIn(nInIn), amount(amountIn), txdata(nullptr), m_sighash_cache(sighash_cache) {}
+ GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn, MissingDataBehavior mdb, SigHashCache* sighash_cache = nullptr) : txTo(txToIn), m_mdb(mdb), nIn(nInIn), amount(amountIn), txdata(&txdataIn), m_sighash_cache(sighash_cache) {}
bool CheckECDSASignature(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
bool CheckSchnorrSignature(std::span<const unsigned char> sig, std::span<const unsigned char> pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override;
bool CheckLockTime(const CScriptNum& nLockTime) const override;
diff --git a/src/script/sigcache.h b/src/script/sigcache.h
index ca4b44910e6..89aa5e85ad8 100644
--- a/src/script/sigcache.h
+++ b/src/script/sigcache.h
@@ -67,7 +67,7 @@ private:
SignatureCache& m_signature_cache;
public:
- CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, SignatureCache& signature_cache, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn, MissingDataBehavior::ASSERT_FAIL), store(storeIn), m_signature_cache(signature_cache) {}
+ CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, bool storeIn, SignatureCache& signature_cache, PrecomputedTransactionData& txdataIn, SigHashCache* sighash_cache = nullptr) : TransactionSignatureChecker(txToIn, nInIn, amountIn, txdataIn, MissingDataBehavior::ASSERT_FAIL, sighash_cache), store(storeIn), m_signature_cache(signature_cache) {}
bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const override;
bool VerifySchnorrSignature(std::span<const unsigned char> sig, const XOnlyPubKey& pubkey, const uint256& sighash) const override;
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
index af36a956931..d2f97f47461 100644
--- a/src/test/txvalidationcache_tests.cpp
+++ b/src/test/txvalidationcache_tests.cpp
@@ -24,7 +24,8 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
ValidationCache& validation_cache,
- std::vector<CScriptCheck>* pvChecks) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ std::vector<CScriptCheck>* pvChecks,
+ bool cache_sighash = false) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
BOOST_AUTO_TEST_SUITE(txvalidationcache_tests)
diff --git a/src/validation.cpp b/src/validation.cpp
index 5ad2ebdcd7e..58bdc8baaf3 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -142,7 +142,8 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
ValidationCache& validation_cache,
- std::vector<CScriptCheck>* pvChecks = nullptr)
+ std::vector<CScriptCheck>* pvChecks = nullptr,
+ bool cache_sighash = false)
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool CheckFinalTxAtTip(const CBlockIndex& active_chain_tip, const CTransaction& tx)
@@ -1237,13 +1238,13 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
// Check input scripts and signatures.
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
- if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, ws.m_precomputed_txdata, GetValidationCache())) {
+ if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, ws.m_precomputed_txdata, GetValidationCache(), /* pvChecks= */ nullptr, /* cache_sighash= */ true)) {
// SCRIPT_VERIFY_CLEANSTACK requires SCRIPT_VERIFY_WITNESS, so we
// need to turn both off, and compare against just turning off CLEANSTACK
// to see if the failure is specifically due to witness validation.
TxValidationState state_dummy; // Want reported failures to be from first CheckInputScripts
- if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, ws.m_precomputed_txdata, GetValidationCache()) &&
- !CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, ws.m_precomputed_txdata, GetValidationCache())) {
+ if (!tx.HasWitness() && CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~(SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_CLEANSTACK), true, false, ws.m_precomputed_txdata, GetValidationCache(), /* pvChecks= */ nullptr, /* cache_sighash= */ true) &&
+ !CheckInputScripts(tx, state_dummy, m_view, scriptVerifyFlags & ~SCRIPT_VERIFY_CLEANSTACK, true, false, ws.m_precomputed_txdata, GetValidationCache(), /* pvChecks= */ nullptr, /* cache_sighash= */ true)) {
// Only the witness is missing, so the transaction itself may be fine.
state.Invalid(TxValidationResult::TX_WITNESS_STRIPPED,
state.GetRejectReason(), state.GetDebugMessage());
@@ -2119,7 +2120,7 @@ std::optional<std::pair<ScriptError, std::string>> CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
const CScriptWitness *witness = &ptxTo->vin[nIn].scriptWitness;
ScriptError error{SCRIPT_ERR_UNKNOWN_ERROR};
- if (VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *m_signature_cache, *txdata), &error)) {
+ if (VerifyScript(scriptSig, m_tx_out.scriptPubKey, witness, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, m_tx_out.nValue, cacheStore, *m_signature_cache, *txdata, m_sighash_cache.get()), &error)) {
return std::nullopt;
} else {
auto debug_str = strprintf("input %i of %s (wtxid %s), spending %s:%i", nIn, ptxTo->GetHash().ToString(), ptxTo->GetWitnessHash().ToString(), ptxTo->vin[nIn].prevout.hash.ToString(), ptxTo->vin[nIn].prevout.n);
@@ -2166,7 +2167,8 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState& state,
const CCoinsViewCache& inputs, unsigned int flags, bool cacheSigStore,
bool cacheFullScriptStore, PrecomputedTransactionData& txdata,
ValidationCache& validation_cache,
- std::vector<CScriptCheck>* pvChecks)
+ std::vector<CScriptCheck>* pvChecks,
+ bool cache_sighash)
{
if (tx.IsCoinBase()) return true;
diff --git a/src/validation.h b/src/validation.h
index 7411ab400c2..842e3f0d28a 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -338,10 +338,11 @@ private:
bool cacheStore;
PrecomputedTransactionData *txdata;
SignatureCache* m_signature_cache;
+ std::unique_ptr<SigHashCache> m_sighash_cache;
public:
- CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, SignatureCache& signature_cache, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn) :
- m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn), m_signature_cache(&signature_cache) { }
+ CScriptCheck(const CTxOut& outIn, const CTransaction& txToIn, SignatureCache& signature_cache, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn, PrecomputedTransactionData* txdataIn, bool cache_sighash = false) :
+ m_tx_out(outIn), ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn), txdata(txdataIn), m_signature_cache(&signature_cache), m_sighash_cache(cache_sighash ? std::make_unique<SigHashCache>() : nullptr) { }
CScriptCheck(const CScriptCheck&) = delete;
CScriptCheck& operator=(const CScriptCheck&) = delete;|
@darosior just noting the tests are specifically written to not worry about standardness, so at least these would have to be augmented to cover the cases this PR is ostensibly supporting |
|
@instagibbs Yes and no, depending on the meaning of standardness I guess. The worrisome transactions are non-standard (in the sense that they are not relayed/accepted), but are standard in the |
26fced4 to
dac139b
Compare
|
Hmm, not relevant to what's being addressed here, but couldn't the per-tx Edit: Given their size I guess that's not nearly as interesting. |
dac139b to
e1f8349
Compare
|
@darosior I did it slightly differently, but added a commit that makes the use of the sighash cache optional. I avoided using default values as they can result in unexpected/missed call sites. |
e1f8349 to
0b646fa
Compare
|
🚧 At least one of the CI tasks failed. HintsTry to run the tests locally, according to the documentation. However, a CI failure may still
Leave a comment here, if you need help tracking down a confusing failure. |
0079e81 to
fb7e9de
Compare
Github-Pull: bitcoin#32473 Rebased-From: b221aa8
Github-Pull: bitcoin#32473 Rebased-From: 8395027
…e for legacy/p2sh/segwitv0 scripts 8395027 qa: unit test sighash caching (Antoine Poinsot) b221aa8 qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot) 92af9f7 script: (optimization) introduce sighash midstate caching (Pieter Wuille) 8f3ddb0 script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille) 9014d40 tests: add sighash caching tests to feature_taproot (Pieter Wuille) Pull request description: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used. The PR implements two different approaches: * The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly). * The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it. Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR). ACKs for top commit: achow101: ACK 8395027 dergoegge: Code review ACK 8395027 darosior: re-ACK 8395027 Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
…e for legacy/p2sh/segwitv0 scripts 8395027 qa: unit test sighash caching (Antoine Poinsot) b221aa8 qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot) 92af9f7 script: (optimization) introduce sighash midstate caching (Pieter Wuille) 8f3ddb0 script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille) 9014d40 tests: add sighash caching tests to feature_taproot (Pieter Wuille) Pull request description: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used. The PR implements two different approaches: * The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly). * The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it. Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR). ACKs for top commit: achow101: ACK 8395027 dergoegge: Code review ACK 8395027 darosior: re-ACK 8395027 Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
…e for legacy/p2sh/segwitv0 scripts 8395027 qa: unit test sighash caching (Antoine Poinsot) b221aa8 qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot) 92af9f7 script: (optimization) introduce sighash midstate caching (Pieter Wuille) 8f3ddb0 script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille) 9014d40 tests: add sighash caching tests to feature_taproot (Pieter Wuille) Pull request description: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used. The PR implements two different approaches: * The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly). * The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it. Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR). ACKs for top commit: achow101: ACK 8395027 dergoegge: Code review ACK 8395027 darosior: re-ACK 8395027 Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
…e for legacy/p2sh/segwitv0 scripts 8395027 qa: unit test sighash caching (Antoine Poinsot) b221aa8 qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot) 92af9f7 script: (optimization) introduce sighash midstate caching (Pieter Wuille) 8f3ddb0 script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille) 9014d40 tests: add sighash caching tests to feature_taproot (Pieter Wuille) Pull request description: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used. The PR implements two different approaches: * The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly). * The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it. Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR). ACKs for top commit: achow101: ACK 8395027 dergoegge: Code review ACK 8395027 darosior: re-ACK 8395027 Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
…e for legacy/p2sh/segwitv0 scripts 8395027 qa: unit test sighash caching (Antoine Poinsot) b221aa8 qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot) 92af9f7 script: (optimization) introduce sighash midstate caching (Pieter Wuille) 8f3ddb0 script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille) 9014d40 tests: add sighash caching tests to feature_taproot (Pieter Wuille) Pull request description: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used. The PR implements two different approaches: * The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly). * The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it. Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR). ACKs for top commit: achow101: ACK 8395027 dergoegge: Code review ACK 8395027 darosior: re-ACK 8395027 Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
…e for legacy/p2sh/segwitv0 scripts 8395027 qa: unit test sighash caching (Antoine Poinsot) b221aa8 qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot) 92af9f7 script: (optimization) introduce sighash midstate caching (Pieter Wuille) 8f3ddb0 script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille) 9014d40 tests: add sighash caching tests to feature_taproot (Pieter Wuille) Pull request description: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used. The PR implements two different approaches: * The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly). * The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it. Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR). ACKs for top commit: achow101: ACK 8395027 dergoegge: Code review ACK 8395027 darosior: re-ACK 8395027 Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
…e for legacy/p2sh/segwitv0 scripts 8395027 qa: unit test sighash caching (Antoine Poinsot) b221aa8 qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot) 92af9f7 script: (optimization) introduce sighash midstate caching (Pieter Wuille) 8f3ddb0 script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille) 9014d40 tests: add sighash caching tests to feature_taproot (Pieter Wuille) Pull request description: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used. The PR implements two different approaches: * The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly). * The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it. Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR). ACKs for top commit: achow101: ACK 8395027 dergoegge: Code review ACK 8395027 darosior: re-ACK 8395027 Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
…e for legacy/p2sh/segwitv0 scripts 8395027 qa: unit test sighash caching (Antoine Poinsot) b221aa8 qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot) 92af9f7 script: (optimization) introduce sighash midstate caching (Pieter Wuille) 8f3ddb0 script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille) 9014d40 tests: add sighash caching tests to feature_taproot (Pieter Wuille) Pull request description: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used. The PR implements two different approaches: * The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly). * The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it. Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR). ACKs for top commit: achow101: ACK 8395027 dergoegge: Code review ACK 8395027 darosior: re-ACK 8395027 Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
… for legacy/p2sh/segwitv0 scripts eb64d24 Merge bitcoin/bitcoin#32473: Introduce per-txin sighash midstate cache for legacy/p2sh/segwitv0 scripts (merge-script) Pull request description: Backport of bitcoin/bitcoin#32473 Additional cache index bit added for sighash combination with `SIGHASH_RANGEPROOF`
…h/segwitv0 scripts eb64d24 Merge bitcoin/bitcoin#32473: Introduce per-txin sighash midstate cache for legacy/p2sh/segwitv0 scripts (merge-script) Pull request description: Backport of bitcoin/bitcoin#32473 Additional cache index bit added for sighash combination with `SIGHASH_RANGEPROOF` ACKs for top commit: delta1: ACK eb64d24 Tree-SHA512: 94014e726ff16473809672f3e01a8e4d11c4abd38b3ae3ae64b8b9ae61be2e3c246157dca5a3a3afc4b85cc8ec69e23181af8f11c36e0b43cfac2dcb3e2e8d70
Github-Pull: bitcoin#32473 Rebased-From: 2dd75a6
Github-Pull: bitcoin#32473 Rebased-From: 21c913b
Github-Pull: bitcoin#32473 Rebased-From: 793934b
Github-Pull: bitcoin#32473 Rebased-From: 3318cdc
Github-Pull: bitcoin#32473 Rebased-From: c084d94
Summary: This is a partial backport of [[bitcoin/bitcoin#32473 | core#32473]] bitcoin/bitcoin@8f3ddb0 Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Differential Revision: https://reviews.bitcoinabc.org/D18848
Summary: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare) and P2SH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 12 sighash modes a (scriptCode, midstate) tuple, which gives a midstate CSHA256 object right before the appending of the sighash type itself (to permit all 256, rather than just the 12 ones that match the modes). The midstate is only reused if the scriptCode matches. This works because - within a single input - only the sighash type and the scriptCode affect the actual sighash used. This concludes backport of [[bitcoin/bitcoin#32473 | core#32473]] bitcoin/bitcoin@92af9f7 bitcoin/bitcoin@b221aa8 bitcoin/bitcoin@8395027 Depends on D18848 Test Plan: `ninja all check-all bitcoin-fuzzers` Reviewers: #bitcoin_abc, Fabien Reviewed By: #bitcoin_abc, Fabien Subscribers: Fabien Differential Revision: https://reviews.bitcoinabc.org/D18849
…e for legacy/p2sh/segwitv0 scripts c32ada9 qa: unit test sighash caching (Antoine Poinsot) 26f3783 qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot) c01fc2f script: (optimization) introduce sighash midstate caching (Pieter Wuille) 7ad58bd script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille) 1208aa1 tests: add sighash caching tests to feature_taproot (Pieter Wuille) Pull request description: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used. The PR implements two different approaches: * The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly). * The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it. Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR). ACKs for top commit: achow101: ACK c32ada9 dergoegge: Code review ACK c32ada9 darosior: re-ACK c32ada9 Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
…e for legacy/p2sh/segwitv0 scripts c084d94 qa: unit test sighash caching (Antoine Poinsot) 3318cdc qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot) 793934b script: (optimization) introduce sighash midstate caching (Pieter Wuille) 21c913b script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille) 2dd75a6 tests: add sighash caching tests to feature_taproot (Pieter Wuille) Pull request description: This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks. The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used. The PR implements two different approaches: * The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly). * The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it. Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR). ACKs for top commit: achow101: ACK c084d94 dergoegge: Code review ACK c084d94 darosior: re-ACK c084d94 Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
…e for legacy/p2sh/segwitv0 scripts
83950275eddacac56c58a7a3648ed435a5593328 qa: unit test sighash caching (Antoine Poinsot)
b221aa80a081579b8d3b460e3403f7ac0daa7139 qa: simple differential fuzzing for sighash with/without caching (Antoine Poinsot)
92af9f74d74e76681f7d98f293eab226972137b4 script: (optimization) introduce sighash midstate caching (Pieter Wuille)
8f3ddb0bccebc930836b4a6745a7cf29b41eb302 script: (refactor) prepare for introducing sighash midstate cache (Pieter Wuille)
9014d4016ad9351cb59b587541895e55f5d589cc tests: add sighash caching tests to feature_taproot (Pieter Wuille)
Pull request description:
This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks.
The cache works by remembering for each of the 6 sighash modes a `(scriptCode, midstate)` tuple, which gives a midstate `CSHA256` object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if the `scriptCode` matches. This works because - within a single input - only the sighash type and the `scriptCode` affect the actual sighash used.
The PR implements two different approaches:
* The initial commits introduce the caching effect always, for both consensus and relay relation validation. Despite being primarily intended for improving the situation for standard transactions only, I chose this approach as the code paths are already largely common between the two, and this approach I believe involves fewer code changes than a more targetted approach, and furthermore, it should not hurt (it may even help common multisig cases slightly).
* The final commit changes the behavior to only using the cache for non-consensus script validation. I'm open to feedback about whether adding this commit is worth it.
Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and `OP_CODESEPARATOR`s in all script types (including P2TR, which isn't modified by this PR).
ACKs for top commit:
achow101:
ACK 83950275eddacac56c58a7a3648ed435a5593328
dergoegge:
Code review ACK 83950275eddacac56c58a7a3648ed435a5593328
darosior:
re-ACK 83950275eddacac56c58a7a3648ed435a5593328
Tree-SHA512: 65ae8635429a4d563b19969bac8128038ac2cbe01d9c9946abd4cac3c0780974d1e8b9aae9bb83f414e5d247a59f4a18fef5b37d93ad59ed41b6f11c3fe05af4
…PROOF keying Backport of bitcoin/bitcoin#32473 as integrated on elements-23.x (eb64d24), reapplied against master's tree. The SIGHASH_RANGEPROOF (0x40) bit changes the sighash preimage: segwit v0 appends hashRangeproofs, and the legacy serializer appends each output's rangeproof and surjectionproof. It is therefore part of the cache key, and the table has 16 entries rather than upstream's 6. Dropping that term is a consensus split with deployed elements-23.x in both directions. Upstream added SigHashCache as a pure addition, so a merge of this file will auto-merge without prompting for the Elements adaptation. Hence the explicit markers.
…h/segwitv0 scripts ec89c80 Add test that sighash midstate cache treats the SIGHASH_RANGEPROOF bit as part of its key (Tom Trevethan) 1484750 tests: add sighash caching tests to feature_taproot (Pieter Wuille) 903be1e ELEMENTS: backport per-txin sighash midstate cache with SIGHASH_RANGEPROOF keying (Tom Trevethan) Pull request description: Merge of bitcoin/bitcoin#32473 with additional cache index bit added for sighash combination with SIGHASH_RANGEPROOF. ACKs for top commit: delta1: ACK 9631bd3; tested locally Tree-SHA512: 71263dd590b419aba19a3a5f9b492e5616fc074e951348f164c13833797ad9a5486c9eb808e474a939a4b8b30e258409dfcb9475e46e7ceff6befc58f5516699
This introduces a per-txin cache for sighash midstate computation to the script interpreter for legacy (bare), P2SH, P2WSH, and (as collateral effect, but not actually useful) P2WPKH. This reduces the impact of certain types of quadratic hashing attacks that use standard transactions. It is not known to improve the situation for attacks involving non-standard transaction attacks.
The cache works by remembering for each of the 6 sighash modes a
(scriptCode, midstate)tuple, which gives a midstateCSHA256object right before the appending of the sighash type itself (to permit all 256, rather than just the 6 ones that match the modes). The midstate is only reused if thescriptCodematches. This works because - within a single input - only the sighash type and thescriptCodeaffect the actual sighash used.The PR implements two different approaches:
Functional tests are included that construct contrived cases with many sighash types (standard and non-standard ones) and
OP_CODESEPARATORs in all script types (including P2TR, which isn't modified by this PR).