Skip to content

Commit

Permalink
optimization: refactor: Introduce Uint256ExtraSipHasher to cache SipH…
Browse files Browse the repository at this point in the history
…ash constant state

Previously, only k0 and k1 were stored, causing the constant xor operations to be recomputed in every call to `SipHashUint256Extra`.
This commit adds a dedicated `Uint256ExtraSipHasher` class that caches the initial state (v0-v3) and to perform the `SipHash` computation on a `uint256` (with an extra parameter), hiding the constant computation details from higher-level code and improving efficiency.

> cmake -B build -DBUILD_BENCH=ON -DCMAKE_BUILD_TYPE=Release && cmake --build build -j$(nproc) && build/src/bench/bench_bitcoin -filter='SaltedOutpointHasherBench' -min-time=10000

> C++ compiler .......................... AppleClang 16.0.0.16000026

|               ns/op |                op/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|               57.27 |       17,462,299.19 |    0.1% |     11.02 | `SaltedOutpointHasherBench_create_set`
|               11.24 |       88,997,888.48 |    0.3% |     11.04 | `SaltedOutpointHasherBench_hash`
|               13.91 |       71,902,014.20 |    0.2% |     11.01 | `SaltedOutpointHasherBench_match`
|               13.29 |       75,230,390.31 |    0.1% |     11.00 | `SaltedOutpointHasherBench_mismatch`

> C++ compiler .......................... GNU 13.3.0

?

compared to master:
SaltedOutpointHasherBenchmark_create_set - 17,462,299.19/17,065,922.04 - 2.3% faster
SaltedOutpointHasherBenchmark_hash - 88,997,888.48/83,576,684.83 - 6.4% faster
SaltedOutpointHasherBenchmark_match - 71,902,014.20/68,985,850.12 - 4.2% faster
SaltedOutpointHasherBenchmark_mismatch - 75,230,390.31/71,942,033.47 - 4.5% faster
  • Loading branch information
l0rinc committed Feb 1, 2025
1 parent ca78bca commit a8df73e
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 21 deletions.
13 changes: 4 additions & 9 deletions src/crypto/siphash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,12 @@ uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
return v0 ^ v1 ^ v2 ^ v3;
}

uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
/* Specialized implementation for efficiency */
uint64_t Uint256ExtraSipHasher::operator()(const uint256& val, uint32_t extra) const noexcept
{
/* Specialized implementation for efficiency */
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
uint64_t d = val.GetUint64(0);

// TODO moved in next commit
uint64_t v0 = CSipHasher::C0 ^ k0;
uint64_t v1 = CSipHasher::C1 ^ k1;
uint64_t v2 = CSipHasher::C2 ^ k0;
uint64_t v3 = CSipHasher::C3 ^ k1 ^ d;

v3 ^= d;
SIPROUND;
SIPROUND;
v0 ^= d;
Expand Down
15 changes: 14 additions & 1 deletion src/crypto/siphash.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,19 @@ class CSipHasher
* .Finalize()
*/
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra);

class Uint256ExtraSipHasher {
uint64_t v[4];

public:
Uint256ExtraSipHasher(const uint64_t k0, const uint64_t k1) noexcept {
v[0] = CSipHasher::C0 ^ k0;
v[1] = CSipHasher::C1 ^ k1;
v[2] = CSipHasher::C2 ^ k0;
v[3] = CSipHasher::C3 ^ k1;
}

uint64_t operator()(const uint256& val, uint32_t extra) const noexcept;
};

#endif // BITCOIN_CRYPTO_SIPHASH_H
2 changes: 1 addition & 1 deletion src/test/fuzz/integer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ FUZZ_TARGET(integer, .init = initialize_integer)
(void)MillisToTimeval(i64);
(void)SighashToStr(uch);
(void)SipHashUint256(u64, u64, u256);
(void)SipHashUint256Extra(u64, u64, u256, u32);
(void)Uint256ExtraSipHasher(u64, u64)(u256, u32);
(void)ToLower(ch);
(void)ToUpper(ch);
{
Expand Down
4 changes: 2 additions & 2 deletions src/test/hash_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ BOOST_AUTO_TEST_CASE(siphash)
ss << TX_WITH_WITNESS(tx);
BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL);

// Check consistency between CSipHasher and SipHashUint256[Extra].
// Check consistency between CSipHasher and SipHashUint256 and Uint256ExtraSipHasher.
FastRandomContext ctx;
for (int i = 0; i < 16; ++i) {
uint64_t k0 = ctx.rand64();
Expand All @@ -144,7 +144,7 @@ BOOST_AUTO_TEST_CASE(siphash)
CSipHasher sip288 = sip256;
sip288.Write(nb);
BOOST_CHECK_EQUAL(SipHashUint256(k0, k1, x), sip256.Finalize());
BOOST_CHECK_EQUAL(SipHashUint256Extra(k0, k1, x, n), sip288.Finalize()); // TODO modified in follow-up commit
BOOST_CHECK_EQUAL(Uint256ExtraSipHasher(k0, k1)(x, n), sip288.Finalize());
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/util/hasher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ SaltedTxidHasher::SaltedTxidHasher() :
k0{FastRandomContext().rand64()},
k1{FastRandomContext().rand64()} {}

SaltedOutpointHasher::SaltedOutpointHasher(bool deterministic) :
k0{deterministic ? 0x8e819f2607a18de6 : FastRandomContext().rand64()},
k1{deterministic ? 0xf4020d2e3983b0eb : FastRandomContext().rand64()}
SaltedOutpointHasher::SaltedOutpointHasher(bool deterministic) : hasher{
deterministic ? 0x8e819f2607a18de6 : FastRandomContext().rand64(),
deterministic ? 0xf4020d2e3983b0eb : FastRandomContext().rand64()}
{}

SaltedSipHasher::SaltedSipHasher() :
Expand Down
8 changes: 3 additions & 5 deletions src/util/hasher.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,10 @@ class SaltedTxidHasher

class SaltedOutpointHasher
{
private:
/** Salt */
const uint64_t k0, k1;
const Uint256ExtraSipHasher hasher;

public:
SaltedOutpointHasher(bool deterministic = false);
explicit SaltedOutpointHasher(bool deterministic = false);

/**
* Having the hash noexcept allows libstdc++'s unordered_map to recalculate
Expand All @@ -47,7 +45,7 @@ class SaltedOutpointHasher
* @see https://gcc.gnu.org/onlinedocs/gcc-13.2.0/libstdc++/manual/manual/unordered_associative.html
*/
size_t operator()(const COutPoint& id) const noexcept {
return SipHashUint256Extra(k0, k1, id.hash, id.n);
return hasher(id.hash, id.n);
}
};

Expand Down

0 comments on commit a8df73e

Please sign in to comment.