Use salted hasher instead of nonce in sigcache

Use salted hasher instead of nonce in Script Execution Cache

Don't read more than 32 bytes from GetRand

Apply g_* naming convention to scriptExecutionCache in validation.cpp

Fully apply g_* naming convention to scriptCacheHasher

Write same uint256 nonce twice for cache hash rather than calling getrand twice

Use salted hasher instead of nonce in sigcache

Use salted hasher instead of nonce in Script Execution Cache

Don't read more than 32 bytes from GetRand

Apply g_* naming convention to scriptExecutionCache in validation.cpp

Fully apply g_* naming convention to scriptCacheHasher

Write same uint256 nonce twice for cache hash rather than calling getrand twice
This commit is contained in:
Jeremy Rubin 2018-05-09 11:05:46 -07:00
parent 5495fa5850
commit 152e8baf08
2 changed files with 23 additions and 12 deletions

View File

@ -23,7 +23,7 @@ class CSignatureCache
{ {
private: private:
//! Entries are SHA256(nonce || signature hash || public key || signature): //! Entries are SHA256(nonce || signature hash || public key || signature):
uint256 nonce; CSHA256 m_salted_hasher;
typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type; typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;
map_type setValid; map_type setValid;
boost::shared_mutex cs_sigcache; boost::shared_mutex cs_sigcache;
@ -31,13 +31,19 @@ private:
public: public:
CSignatureCache() CSignatureCache()
{ {
GetRandBytes(nonce.begin(), 32); uint256 nonce = GetRandHash();
// We want the nonce to be 64 bytes long to force the hasher to process
// this chunk, which makes later hash computations more efficient. We
// just write our 32-byte entropy twice to fill the 64 bytes.
m_salted_hasher.Write(nonce.begin(), 32);
m_salted_hasher.Write(nonce.begin(), 32);
} }
void void
ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey) ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey)
{ {
CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin()); CSHA256 hasher = m_salted_hasher;
hasher.Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());
} }
bool bool

View File

@ -1481,14 +1481,21 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
} }
static CuckooCache::cache<uint256, SignatureCacheHasher> scriptExecutionCache; static CuckooCache::cache<uint256, SignatureCacheHasher> g_scriptExecutionCache;
static uint256 scriptExecutionCacheNonce(GetRandHash()); static CSHA256 g_scriptExecutionCacheHasher;
void InitScriptExecutionCache() { void InitScriptExecutionCache() {
// Setup the salted hasher
uint256 nonce = GetRandHash();
// We want the nonce to be 64 bytes long to force the hasher to process
// this chunk, which makes later hash computations more efficient. We
// just write our 32-byte entropy twice to fill the 64 bytes.
g_scriptExecutionCacheHasher.Write(nonce.begin(), 32);
g_scriptExecutionCacheHasher.Write(nonce.begin(), 32);
// nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero, // nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
// setup_bytes creates the minimum possible cache (2 elements). // setup_bytes creates the minimum possible cache (2 elements).
size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20); size_t nMaxCacheSize = std::min(std::max((int64_t)0, gArgs.GetArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_SIZE) / 2), MAX_MAX_SIG_CACHE_SIZE) * ((size_t) 1 << 20);
size_t nElems = scriptExecutionCache.setup_bytes(nMaxCacheSize); size_t nElems = g_scriptExecutionCache.setup_bytes(nMaxCacheSize);
LogPrintf("Using %zu MiB out of %zu/2 requested for script execution cache, able to store %zu elements\n", LogPrintf("Using %zu MiB out of %zu/2 requested for script execution cache, able to store %zu elements\n",
(nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems); (nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems);
} }
@ -1526,12 +1533,10 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
// properly commits to the scriptPubKey in the inputs view of that // properly commits to the scriptPubKey in the inputs view of that
// transaction). // transaction).
uint256 hashCacheEntry; uint256 hashCacheEntry;
// We only use the first 19 bytes of nonce to avoid a second SHA CSHA256 hasher = g_scriptExecutionCacheHasher;
// round - giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64) hasher.Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
static_assert(55 - sizeof(flags) - 32 >= 128/8, "Want at least 128 bits of nonce for script execution cache");
CSHA256().Write(scriptExecutionCacheNonce.begin(), 55 - sizeof(flags) - 32).Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks
if (scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) { if (g_scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
return true; return true;
} }
@ -1586,7 +1591,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
if (cacheFullScriptStore && !pvChecks) { if (cacheFullScriptStore && !pvChecks) {
// We executed all of the provided scripts, and were told to // We executed all of the provided scripts, and were told to
// cache the result. Do so now. // cache the result. Do so now.
scriptExecutionCache.insert(hashCacheEntry); g_scriptExecutionCache.insert(hashCacheEntry);
} }
return true; return true;