Skip to content

Commit 9e8bd21

Browse files
author
MarcoFalke
committed
Merge #13204: Faster sigcache nonce
152e8ba Use salted hasher instead of nonce in sigcache (Jeremy Rubin) 5495fa5 Add Hash Padding Microbenchmarks (Jeremy Rubin) Pull request description: This PR replaces nonces in two places with pre-salted hashers. The nonce is chosen to be 64 bytes long so that it forces the SHA256 hasher to process the chunk. This leaves the next 64 (or 56 depending if final chunk) open for data. In the case of the script execution cache, this does not make a big performance improvement because the nonce was already properly padded to fit into one buffer, but does make the code a little simpler. In the case of the sig cache, this should reduce the hashing overhead slightly because we are less likely to need an additional processing step. I haven't benchmarked this, but back of the envelope it should reduce the hashing by one buffer for all combinations except compressed public keys with compact signatures. ACKs for top commit: ryanofsky: Code review ACK 152e8ba. No code changes, just rebase since last review and expanded commit message Tree-SHA512: b133e902fd595cfe3b54ad8814b823f4d132cb2c358c89158842ae27daee56ab5f70cde2585078deb46f77a6e7b35b4cc6bba47b65302b7befc2cff254bad93d
2 parents 45a1489 + 152e8ba commit 9e8bd21

File tree

4 files changed

+71
-12
lines changed

4 files changed

+71
-12
lines changed

src/Makefile.bench.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ bench_bench_bitcoin_SOURCES = \
2929
bench/crypto_hash.cpp \
3030
bench/ccoins_caching.cpp \
3131
bench/gcs_filter.cpp \
32+
bench/hashpadding.cpp \
3233
bench/merkle_root.cpp \
3334
bench/mempool_eviction.cpp \
3435
bench/mempool_stress.cpp \

src/bench/hashpadding.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2015-2018 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <bench/bench.h>
6+
#include <hash.h>
7+
#include <random.h>
8+
#include <uint256.h>
9+
10+
11+
static void PrePadded(benchmark::State& state)
12+
{
13+
14+
CSHA256 hasher;
15+
16+
// Setup the salted hasher
17+
uint256 nonce = GetRandHash();
18+
hasher.Write(nonce.begin(), 32);
19+
hasher.Write(nonce.begin(), 32);
20+
uint256 data = GetRandHash();
21+
while (state.KeepRunning()) {
22+
unsigned char out[32];
23+
CSHA256 h = hasher;
24+
h.Write(data.begin(), 32);
25+
h.Finalize(out);
26+
}
27+
}
28+
29+
BENCHMARK(PrePadded, 10000);
30+
31+
static void RegularPadded(benchmark::State& state)
32+
{
33+
CSHA256 hasher;
34+
35+
// Setup the salted hasher
36+
uint256 nonce = GetRandHash();
37+
uint256 data = GetRandHash();
38+
while (state.KeepRunning()) {
39+
unsigned char out[32];
40+
CSHA256 h = hasher;
41+
h.Write(nonce.begin(), 32);
42+
h.Write(data.begin(), 32);
43+
h.Finalize(out);
44+
}
45+
}
46+
47+
BENCHMARK(RegularPadded, 10000);

src/script/sigcache.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,27 @@ class CSignatureCache
2323
{
2424
private:
2525
//! Entries are SHA256(nonce || signature hash || public key || signature):
26-
uint256 nonce;
26+
CSHA256 m_salted_hasher;
2727
typedef CuckooCache::cache<uint256, SignatureCacheHasher> map_type;
2828
map_type setValid;
2929
boost::shared_mutex cs_sigcache;
3030

3131
public:
3232
CSignatureCache()
3333
{
34-
GetRandBytes(nonce.begin(), 32);
34+
uint256 nonce = GetRandHash();
35+
// We want the nonce to be 64 bytes long to force the hasher to process
36+
// this chunk, which makes later hash computations more efficient. We
37+
// just write our 32-byte entropy twice to fill the 64 bytes.
38+
m_salted_hasher.Write(nonce.begin(), 32);
39+
m_salted_hasher.Write(nonce.begin(), 32);
3540
}
3641

3742
void
3843
ComputeEntry(uint256& entry, const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubkey)
3944
{
40-
CSHA256().Write(nonce.begin(), 32).Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());
45+
CSHA256 hasher = m_salted_hasher;
46+
hasher.Write(hash.begin(), 32).Write(&pubkey[0], pubkey.size()).Write(&vchSig[0], vchSig.size()).Finalize(entry.begin());
4147
}
4248

4349
bool

src/validation.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,14 +1481,21 @@ int GetSpendHeight(const CCoinsViewCache& inputs)
14811481
}
14821482

14831483

1484-
static CuckooCache::cache<uint256, SignatureCacheHasher> scriptExecutionCache;
1485-
static uint256 scriptExecutionCacheNonce(GetRandHash());
1484+
static CuckooCache::cache<uint256, SignatureCacheHasher> g_scriptExecutionCache;
1485+
static CSHA256 g_scriptExecutionCacheHasher;
14861486

14871487
void InitScriptExecutionCache() {
1488+
// Setup the salted hasher
1489+
uint256 nonce = GetRandHash();
1490+
// We want the nonce to be 64 bytes long to force the hasher to process
1491+
// this chunk, which makes later hash computations more efficient. We
1492+
// just write our 32-byte entropy twice to fill the 64 bytes.
1493+
g_scriptExecutionCacheHasher.Write(nonce.begin(), 32);
1494+
g_scriptExecutionCacheHasher.Write(nonce.begin(), 32);
14881495
// nMaxCacheSize is unsigned. If -maxsigcachesize is set to zero,
14891496
// setup_bytes creates the minimum possible cache (2 elements).
14901497
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);
1491-
size_t nElems = scriptExecutionCache.setup_bytes(nMaxCacheSize);
1498+
size_t nElems = g_scriptExecutionCache.setup_bytes(nMaxCacheSize);
14921499
LogPrintf("Using %zu MiB out of %zu/2 requested for script execution cache, able to store %zu elements\n",
14931500
(nElems*sizeof(uint256)) >>20, (nMaxCacheSize*2)>>20, nElems);
14941501
}
@@ -1526,12 +1533,10 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
15261533
// properly commits to the scriptPubKey in the inputs view of that
15271534
// transaction).
15281535
uint256 hashCacheEntry;
1529-
// We only use the first 19 bytes of nonce to avoid a second SHA
1530-
// round - giving us 19 + 32 + 4 = 55 bytes (+ 8 + 1 = 64)
1531-
static_assert(55 - sizeof(flags) - 32 >= 128/8, "Want at least 128 bits of nonce for script execution cache");
1532-
CSHA256().Write(scriptExecutionCacheNonce.begin(), 55 - sizeof(flags) - 32).Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
1536+
CSHA256 hasher = g_scriptExecutionCacheHasher;
1537+
hasher.Write(tx.GetWitnessHash().begin(), 32).Write((unsigned char*)&flags, sizeof(flags)).Finalize(hashCacheEntry.begin());
15331538
AssertLockHeld(cs_main); //TODO: Remove this requirement by making CuckooCache not require external locks
1534-
if (scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
1539+
if (g_scriptExecutionCache.contains(hashCacheEntry, !cacheFullScriptStore)) {
15351540
return true;
15361541
}
15371542

@@ -1586,7 +1591,7 @@ bool CheckInputScripts(const CTransaction& tx, TxValidationState &state, const C
15861591
if (cacheFullScriptStore && !pvChecks) {
15871592
// We executed all of the provided scripts, and were told to
15881593
// cache the result. Do so now.
1589-
scriptExecutionCache.insert(hashCacheEntry);
1594+
g_scriptExecutionCache.insert(hashCacheEntry);
15901595
}
15911596

15921597
return true;

0 commit comments

Comments
 (0)