diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 8cd2f7998d..02c4d1ac32 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -2629,7 +2629,7 @@ static bool HandleMissingData(MissingDataBehavior mdb) } template -bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb) +bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb) { uint8_t ext_flag, key_version; switch (sigversion) { @@ -2717,13 +2717,20 @@ bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata // Data about the output (if only one). if (output_type == SIGHASH_SINGLE) { if (in_pos >= tx_to.vout.size()) return false; - CHashWriter sha_single_output(SER_GETHASH, 0); - sha_single_output << tx_to.vout[in_pos]; - ss << sha_single_output.GetSHA256(); + if (!execdata.m_output_hash) { + CHashWriter sha_single_output(SER_GETHASH, 0); + sha_single_output << tx_to.vout[in_pos]; + execdata.m_output_hash = sha_single_output.GetSHA256(); + } + ss << execdata.m_output_hash.value(); - CHashWriter sha_single_output_witness(SER_GETHASH, 0); - sha_single_output_witness << tx_to.witness.vtxoutwit[in_pos]; - ss << sha_single_output_witness.GetSHA256(); + // ELEMENTS + if (!execdata.m_output_witness_hash) { + CHashWriter sha_single_output_witness(SER_GETHASH, 0); + sha_single_output_witness << tx_to.witness.vtxoutwit[in_pos]; + execdata.m_output_witness_hash = sha_single_output_witness.GetSHA256(); + } + ss << execdata.m_output_witness_hash.value(); } // Additional data for BIP 342 signatures @@ -2883,7 +2890,7 @@ bool GenericTransactionSignatureChecker::CheckECDSASignature(const std::vecto } template -bool GenericTransactionSignatureChecker::CheckSchnorrSignature(Span sig, Span pubkey_in, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror) const +bool GenericTransactionSignatureChecker::CheckSchnorrSignature(Span sig, Span pubkey_in, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const { assert(sigversion == SigVersion::TAPROOT || sigversion == SigVersion::TAPSCRIPT); // Schnorr signatures have 32-byte public keys. The caller is responsible for enforcing this. diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 1e2996db48..268276f989 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -244,6 +245,13 @@ struct ScriptExecutionData bool m_validation_weight_left_init = false; //! How much validation weight is left (decremented for every successful non-empty signature check). int64_t m_validation_weight_left; + + //! The hash of the corresponding output + std::optional m_output_hash; + + // ELEMENTS + //! The hash of the corresponding output witness + std::optional m_output_witness_hash; }; /** Signature hash sizes */ @@ -273,7 +281,7 @@ public: return false; } - virtual bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const + virtual bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const { return false; } @@ -331,7 +339,7 @@ enum class MissingDataBehavior }; template -bool SignatureHashSchnorr(uint256& hash_out, const ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb); +bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, const T& tx_to, uint32_t in_pos, uint8_t hash_type, SigVersion sigversion, const PrecomputedTransactionData& cache, MissingDataBehavior mdb); template class GenericTransactionSignatureChecker : public BaseSignatureChecker @@ -351,7 +359,7 @@ public: GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, MissingDataBehavior mdb) : txTo(txToIn), m_mdb(mdb), nIn(nInIn), amount(amountIn), txdata(nullptr) {} GenericTransactionSignatureChecker(const T* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, const PrecomputedTransactionData& txdataIn, MissingDataBehavior mdb) : txTo(txToIn), m_mdb(mdb), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} bool CheckECDSASignature(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override; - bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override; + bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override; bool CheckLockTime(const CScriptNum& nLockTime) const override; bool CheckSequence(const CScriptNum& nSequence) const override; const std::vector* GetTxvIn() const override; @@ -379,7 +387,7 @@ public: return m_checker.CheckECDSASignature(scriptSig, vchPubKey, scriptCode, sigversion, flags); } - bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override + bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override { return m_checker.CheckSchnorrSignature(sig, pubkey, sigversion, execdata, serror); } diff --git a/src/script/sign.cpp b/src/script/sign.cpp index d85817e208..cc8a9f0d83 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -566,7 +566,7 @@ class DummySignatureChecker final : public BaseSignatureChecker public: DummySignatureChecker() {} bool CheckECDSASignature(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override { return true; } - bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror) const override { return true; } + bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror) const override { return true; } }; const DummySignatureChecker DUMMY_CHECKER; diff --git a/src/test/fuzz/signature_checker.cpp b/src/test/fuzz/signature_checker.cpp index 0f06259563..4fbe43fa51 100644 --- a/src/test/fuzz/signature_checker.cpp +++ b/src/test/fuzz/signature_checker.cpp @@ -34,7 +34,7 @@ public: return m_fuzzed_data_provider.ConsumeBool(); } - bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override + bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override { return m_fuzzed_data_provider.ConsumeBool(); } diff --git a/src/test/fuzz/witness_program.cpp b/src/test/fuzz/witness_program.cpp index 5f45b8f49d..04b0c96fda 100644 --- a/src/test/fuzz/witness_program.cpp +++ b/src/test/fuzz/witness_program.cpp @@ -15,7 +15,7 @@ class DummySigChecker : public MutableTransactionSignatureChecker { bool CheckECDSASignature(const std::vector& vchSig, const std::vector& vchPubKey, const CScript& scriptCode, SigVersion sigversion, unsigned int flags) const override { return !vchSig.empty() && vchSig[0] > 0x80; } - bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, const ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override { return !sig.empty() && sig[0] > 0x80; } + bool CheckSchnorrSignature(Span sig, Span pubkey, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror = nullptr) const override { return !sig.empty() && sig[0] > 0x80; } public: DummySigChecker(const CMutableTransaction* txToIn, unsigned int nInIn, const CConfidentialValue& amountIn, const PrecomputedTransactionData& txdataIn, MissingDataBehavior mdb) : MutableTransactionSignatureChecker{txToIn, nInIn, amountIn, txdataIn, mdb} {} @@ -142,4 +142,3 @@ FUZZ_TARGET_INIT(witness_program, initialize_witness_program) return; } } -