Skip to content

Commit 9ca52a4

Browse files
committed
optimization: migrate SipHashUint256 to PresaltedSipHasher
Replaces standalone `SipHashUint256` with an `operator()` overload in `PresaltedSipHasher`. Updates all hasher classes (`SaltedUint256Hasher`, `SaltedTxidHasher`, `SaltedWtxidHasher`) to use `PresaltedSipHasher` internally, enabling the same constant-state caching optimization while keeping behavior unchanged. Benchmark was also adjusted to cache the salting part.
1 parent ec11b9f commit 9ca52a4

File tree

8 files changed

+45
-55
lines changed

8 files changed

+45
-55
lines changed

src/bench/crypto_hash.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,13 +193,11 @@ static void SHA512(benchmark::Bench& bench)
193193
static void SipHash_32b(benchmark::Bench& bench)
194194
{
195195
FastRandomContext rng{/*fDeterministic=*/true};
196-
auto k0{rng.rand64()}, k1{rng.rand64()};
196+
PresaltedSipHasher presalted_sip_hasher(rng.rand64(), rng.rand64());
197197
auto val{rng.rand256()};
198198
auto i{0U};
199199
bench.run([&] {
200-
ankerl::nanobench::doNotOptimizeAway(SipHashUint256(k0, k1, val));
201-
++k0;
202-
++k1;
200+
ankerl::nanobench::doNotOptimizeAway(presalted_sip_hasher(val));
203201
++i;
204202
val.data()[i % uint256::size()] ^= i & 0xFF;
205203
});

src/blockencodings.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const {
4242

4343
uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const Wtxid& wtxid) const {
4444
static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids calculation assumes 6-byte shorttxids");
45-
return SipHashUint256(shorttxidk0, shorttxidk1, wtxid.ToUint256()) & 0xffffffffffffL;
45+
PresaltedSipHasher hasher(shorttxidk0, shorttxidk1); // TODO extract
46+
return hasher(wtxid.ToUint256()) & 0xffffffffffffL;
4647
}
4748

4849
/* Reconstructing a compact block is in the hot-path for block relay,

src/crypto/siphash.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,11 @@ uint64_t CSipHasher::Finalize() const
9696
return v0 ^ v1 ^ v2 ^ v3;
9797
}
9898

99-
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
99+
uint64_t PresaltedSipHasher::operator()(const uint256& val) const noexcept
100100
{
101-
/* Specialized implementation for efficiency */
101+
uint64_t v0 = v[0], v1 = v[1], v2 = v[2], v3 = v[3];
102102
uint64_t d = val.GetUint64(0);
103-
104-
// TODO moved in followup commit
105-
uint64_t v0 = CSipHasher::C0 ^ k0;
106-
uint64_t v1 = CSipHasher::C1 ^ k1;
107-
uint64_t v2 = CSipHasher::C2 ^ k0;
108-
uint64_t v3 = CSipHasher::C3 ^ k1 ^ d;
103+
v3 ^= d;
109104

110105
SIPROUND;
111106
SIPROUND;

src/crypto/siphash.h

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,15 @@ class CSipHasher
3737
uint64_t Finalize() const;
3838
};
3939

40-
/** Optimized SipHash-2-4 implementation for uint256.
40+
/**
41+
* Optimized SipHash-2-4 implementation for uint256.
4142
*
42-
* It is identical to:
43-
* SipHasher(k0, k1)
44-
* .Write(val.GetUint64(0))
45-
* .Write(val.GetUint64(1))
46-
* .Write(val.GetUint64(2))
47-
* .Write(val.GetUint64(3))
48-
* .Finalize()
43+
* This class caches the initial SipHash v[0..3] state derived from (k0, k1)
44+
* and implements a specialized hashing path for uint256 values, with or
45+
* without an extra 32-bit word. The internal state is immutable, so
46+
* PresaltedSipHasher instances can be reused for multiple hashes with the
47+
* same key.
4948
*/
50-
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
51-
5249
class PresaltedSipHasher
5350
{
5451
uint64_t v[4];
@@ -61,6 +58,7 @@ class PresaltedSipHasher
6158
v[3] = CSipHasher::C3 ^ k1;
6259
}
6360

61+
uint64_t operator()(const uint256& val) const noexcept;
6462
uint64_t operator()(const uint256& val, uint32_t extra) const noexcept;
6563
};
6664

src/test/fuzz/integer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ FUZZ_TARGET(integer, .init = initialize_integer)
118118
}
119119
(void)MillisToTimeval(i64);
120120
(void)SighashToStr(uch);
121-
(void)SipHashUint256(u64, u64, u256);
121+
(void)PresaltedSipHasher(u64, u64)(u256);
122122
(void)PresaltedSipHasher(u64, u64)(u256, u32);
123123
(void)ToLower(ch);
124124
(void)ToUpper(ch);

src/test/hash_tests.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(siphash)
104104
hasher.Write(0x2F2E2D2C2B2A2928ULL);
105105
BOOST_CHECK_EQUAL(hasher.Finalize(), 0xe612a3cb9ecba951ull);
106106

107-
BOOST_CHECK_EQUAL(SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, uint256{"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"}), 0x7127512f72f27cceull);
107+
BOOST_CHECK_EQUAL(PresaltedSipHasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL)(uint256{"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"}), 0x7127512f72f27cceull);
108108

109109
// Check test vectors from spec, one byte at a time
110110
CSipHasher hasher2(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL);
@@ -128,9 +128,9 @@ BOOST_AUTO_TEST_CASE(siphash)
128128
// and the test would be affected by default tx version bumps if not fixed.
129129
tx.version = 1;
130130
ss << TX_WITH_WITNESS(tx);
131-
BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL);
131+
BOOST_CHECK_EQUAL(PresaltedSipHasher(1, 2)(ss.GetHash()), 0x79751e980c2a0a35ULL);
132132

133-
// Check consistency between CSipHasher and SipHashUint256 and PresaltedSipHasher.
133+
// Check consistency between CSipHasher and PresaltedSipHasher.
134134
FastRandomContext ctx;
135135
for (int i = 0; i < 16; ++i) {
136136
uint64_t k0 = ctx.rand64();
@@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(siphash)
139139

140140
CSipHasher sip256(k0, k1);
141141
sip256.Write(x);
142-
BOOST_CHECK_EQUAL(SipHashUint256(k0, k1, x), sip256.Finalize()); // TODO modified in follow-up commit
142+
BOOST_CHECK_EQUAL(PresaltedSipHasher(k0, k1)(x), sip256.Finalize());
143143

144144
CSipHasher sip288 = sip256;
145145
uint32_t n = ctx.rand32();

src/util/hasher.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,20 @@
77
#include <span.h>
88
#include <util/hasher.h>
99

10-
SaltedUint256Hasher::SaltedUint256Hasher() :
11-
k0{FastRandomContext().rand64()},
12-
k1{FastRandomContext().rand64()} {}
10+
SaltedUint256Hasher::SaltedUint256Hasher() : m_hasher{
11+
FastRandomContext().rand64(),
12+
FastRandomContext().rand64()}
13+
{}
1314

14-
SaltedTxidHasher::SaltedTxidHasher() :
15-
k0{FastRandomContext().rand64()},
16-
k1{FastRandomContext().rand64()} {}
15+
SaltedTxidHasher::SaltedTxidHasher() : m_hasher{
16+
FastRandomContext().rand64(),
17+
FastRandomContext().rand64()}
18+
{}
1719

18-
SaltedWtxidHasher::SaltedWtxidHasher() :
19-
k0{FastRandomContext().rand64()},
20-
k1{FastRandomContext().rand64()} {}
20+
SaltedWtxidHasher::SaltedWtxidHasher() : m_hasher{
21+
FastRandomContext().rand64(),
22+
FastRandomContext().rand64()}
23+
{}
2124

2225
SaltedOutpointHasher::SaltedOutpointHasher(bool deterministic) : m_hasher{
2326
deterministic ? 0x8e819f2607a18de6 : FastRandomContext().rand64(),

src/util/hasher.h

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,47 +17,43 @@
1717

1818
class SaltedUint256Hasher
1919
{
20-
private:
21-
/** Salt */
22-
const uint64_t k0, k1;
20+
const PresaltedSipHasher m_hasher;
2321

2422
public:
2523
SaltedUint256Hasher();
2624

27-
size_t operator()(const uint256& hash) const {
28-
return SipHashUint256(k0, k1, hash);
25+
size_t operator()(const uint256& hash) const
26+
{
27+
return m_hasher(hash);
2928
}
3029
};
3130

3231
class SaltedTxidHasher
3332
{
34-
private:
35-
/** Salt */
36-
const uint64_t k0, k1;
33+
const PresaltedSipHasher m_hasher;
3734

3835
public:
3936
SaltedTxidHasher();
4037

41-
size_t operator()(const Txid& txid) const {
42-
return SipHashUint256(k0, k1, txid.ToUint256());
38+
size_t operator()(const Txid& txid) const
39+
{
40+
return m_hasher(txid.ToUint256());
4341
}
4442
};
4543

4644
class SaltedWtxidHasher
4745
{
48-
private:
49-
/** Salt */
50-
const uint64_t k0, k1;
46+
const PresaltedSipHasher m_hasher;
5147

5248
public:
5349
SaltedWtxidHasher();
5450

55-
size_t operator()(const Wtxid& wtxid) const {
56-
return SipHashUint256(k0, k1, wtxid.ToUint256());
51+
size_t operator()(const Wtxid& wtxid) const
52+
{
53+
return m_hasher(wtxid.ToUint256());
5754
}
5855
};
5956

60-
6157
class SaltedOutpointHasher
6258
{
6359
const PresaltedSipHasher m_hasher;
@@ -80,8 +76,7 @@ class SaltedOutpointHasher
8076
}
8177
};
8278

83-
struct FilterHeaderHasher
84-
{
79+
struct FilterHeaderHasher {
8580
size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
8681
};
8782

0 commit comments

Comments
 (0)