Skip to content

Commit 92af9f7

Browse files
committed
script: (optimization) introduce sighash midstate caching
1 parent 8f3ddb0 commit 92af9f7

File tree

2 files changed

+62
-3
lines changed

2 files changed

+62
-3
lines changed

src/script/interpreter.cpp

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,8 +1564,35 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons
15641564
return true;
15651565
}
15661566

1567+
int SigHashCache::CacheIndex(int32_t hash_type) const noexcept
1568+
{
1569+
// Note that we do not distinguish between BASE and WITNESS_V0 to determine the cache index,
1570+
// because no input can simultaneously use both.
1571+
return 3 * !!(hash_type & SIGHASH_ANYONECANPAY) +
1572+
2 * ((hash_type & 0x1f) == SIGHASH_SINGLE) +
1573+
1 * ((hash_type & 0x1f) == SIGHASH_NONE);
1574+
}
1575+
1576+
bool SigHashCache::Load(int32_t hash_type, const CScript& script_code, HashWriter& writer) const noexcept
1577+
{
1578+
auto& entry = m_cache_entries[CacheIndex(hash_type)];
1579+
if (entry.has_value()) {
1580+
if (script_code == entry->first) {
1581+
writer = HashWriter(entry->second);
1582+
return true;
1583+
}
1584+
}
1585+
return false;
1586+
}
1587+
1588+
void SigHashCache::Store(int32_t hash_type, const CScript& script_code, const HashWriter& writer) noexcept
1589+
{
1590+
auto& entry = m_cache_entries[CacheIndex(hash_type)];
1591+
entry.emplace(script_code, writer);
1592+
}
1593+
15671594
template <class T>
1568-
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int32_t nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
1595+
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int32_t nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache, SigHashCache* sighash_cache)
15691596
{
15701597
assert(nIn < txTo.vin.size());
15711598

@@ -1581,6 +1608,13 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
15811608

15821609
HashWriter ss{};
15831610

1611+
// Try to compute using cached SHA256 midstate.
1612+
if (sighash_cache && sighash_cache->Load(nHashType, scriptCode, ss)) {
1613+
// Add sighash type and hash.
1614+
ss << nHashType;
1615+
return ss.GetHash();
1616+
}
1617+
15841618
if (sigversion == SigVersion::WITNESS_V0) {
15851619
uint256 hashPrevouts;
15861620
uint256 hashSequence;
@@ -1627,6 +1661,11 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
16271661
ss << txTmp;
16281662
}
16291663

1664+
// If a cache object was provided, store the midstate there.
1665+
if (sighash_cache != nullptr) {
1666+
sighash_cache->Store(nHashType, scriptCode, ss);
1667+
}
1668+
16301669
// Add sighash type and hash.
16311670
ss << nHashType;
16321671
return ss.GetHash();
@@ -1661,7 +1700,7 @@ bool GenericTransactionSignatureChecker<T>::CheckECDSASignature(const std::vecto
16611700
// Witness sighashes need the amount.
16621701
if (sigversion == SigVersion::WITNESS_V0 && amount < 0) return HandleMissingData(m_mdb);
16631702

1664-
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata);
1703+
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, sigversion, this->txdata, &m_sighash_cache);
16651704

16661705
if (!VerifyECDSASignature(vchSig, pubkey, sighash))
16671706
return false;

src/script/interpreter.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,27 @@ extern const HashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre
239239
extern const HashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it.
240240
extern const HashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
241241

242+
/** Data structure to cache SHA256 midstates for the ECDSA sighash calculations
243+
* (bare, P2SH, P2WPKH, P2WSH). */
244+
class SigHashCache
245+
{
246+
/** For each sighash mode (ALL, SINGLE, NONE, ALL|ANYONE, SINGLE|ANYONE, NONE|ANYONE),
247+
* optionally store a scriptCode which the hash is for, plus a midstate for the SHA256
248+
* computation just before adding the hash_type itself. */
249+
std::optional<std::pair<CScript, HashWriter>> m_cache_entries[6];
250+
251+
/** Given a hash_type, find which of the 6 cache entries is to be used. */
252+
int CacheIndex(int32_t hash_type) const noexcept;
253+
254+
public:
255+
/** Load into writer the SHA256 midstate if found in this cache. */
256+
[[nodiscard]] bool Load(int32_t hash_type, const CScript& script_code, HashWriter& writer) const noexcept;
257+
/** Store into this cache object the provided SHA256 midstate. */
258+
void Store(int32_t hash_type, const CScript& script_code, const HashWriter& writer) noexcept;
259+
};
260+
242261
template <class T>
243-
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int32_t nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
262+
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int32_t nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr, SigHashCache* sighash_cache = nullptr);
244263

245264
class BaseSignatureChecker
246265
{
@@ -289,6 +308,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker
289308
unsigned int nIn;
290309
const CAmount amount;
291310
const PrecomputedTransactionData* txdata;
311+
mutable SigHashCache m_sighash_cache;
292312

293313
protected:
294314
virtual bool VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;

0 commit comments

Comments
 (0)