mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-20 15:19:07 +01:00
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.
This commit is contained in:
@@ -193,13 +193,11 @@ static void SHA512(benchmark::Bench& bench)
|
||||
static void SipHash_32b(benchmark::Bench& bench)
|
||||
{
|
||||
FastRandomContext rng{/*fDeterministic=*/true};
|
||||
auto k0{rng.rand64()}, k1{rng.rand64()};
|
||||
PresaltedSipHasher presalted_sip_hasher(rng.rand64(), rng.rand64());
|
||||
auto val{rng.rand256()};
|
||||
auto i{0U};
|
||||
bench.run([&] {
|
||||
ankerl::nanobench::doNotOptimizeAway(SipHashUint256(k0, k1, val));
|
||||
++k0;
|
||||
++k1;
|
||||
ankerl::nanobench::doNotOptimizeAway(presalted_sip_hasher(val));
|
||||
++i;
|
||||
val.data()[i % uint256::size()] ^= i & 0xFF;
|
||||
});
|
||||
|
||||
@@ -42,7 +42,8 @@ void CBlockHeaderAndShortTxIDs::FillShortTxIDSelector() const {
|
||||
|
||||
uint64_t CBlockHeaderAndShortTxIDs::GetShortID(const Wtxid& wtxid) const {
|
||||
static_assert(SHORTTXIDS_LENGTH == 6, "shorttxids calculation assumes 6-byte shorttxids");
|
||||
return SipHashUint256(shorttxidk0, shorttxidk1, wtxid.ToUint256()) & 0xffffffffffffL;
|
||||
PresaltedSipHasher hasher(shorttxidk0, shorttxidk1); // TODO extract
|
||||
return hasher(wtxid.ToUint256()) & 0xffffffffffffL;
|
||||
}
|
||||
|
||||
/* Reconstructing a compact block is in the hot-path for block relay,
|
||||
|
||||
@@ -96,16 +96,11 @@ uint64_t CSipHasher::Finalize() const
|
||||
return v0 ^ v1 ^ v2 ^ v3;
|
||||
}
|
||||
|
||||
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val)
|
||||
uint64_t PresaltedSipHasher::operator()(const uint256& val) 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 followup 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;
|
||||
|
||||
@@ -37,18 +37,15 @@ public:
|
||||
uint64_t Finalize() const;
|
||||
};
|
||||
|
||||
/** Optimized SipHash-2-4 implementation for uint256.
|
||||
/**
|
||||
* Optimized SipHash-2-4 implementation for uint256.
|
||||
*
|
||||
* It is identical to:
|
||||
* SipHasher(k0, k1)
|
||||
* .Write(val.GetUint64(0))
|
||||
* .Write(val.GetUint64(1))
|
||||
* .Write(val.GetUint64(2))
|
||||
* .Write(val.GetUint64(3))
|
||||
* .Finalize()
|
||||
* This class caches the initial SipHash v[0..3] state derived from (k0, k1)
|
||||
* and implements a specialized hashing path for uint256 values, with or
|
||||
* without an extra 32-bit word. The internal state is immutable, so
|
||||
* PresaltedSipHasher instances can be reused for multiple hashes with the
|
||||
* same key.
|
||||
*/
|
||||
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
|
||||
|
||||
class PresaltedSipHasher
|
||||
{
|
||||
uint64_t v[4];
|
||||
@@ -61,6 +58,7 @@ public:
|
||||
v[3] = CSipHasher::C3 ^ k1;
|
||||
}
|
||||
|
||||
uint64_t operator()(const uint256& val) const noexcept;
|
||||
uint64_t operator()(const uint256& val, uint32_t extra) const noexcept;
|
||||
};
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ FUZZ_TARGET(integer, .init = initialize_integer)
|
||||
}
|
||||
(void)MillisToTimeval(i64);
|
||||
(void)SighashToStr(uch);
|
||||
(void)SipHashUint256(u64, u64, u256);
|
||||
(void)PresaltedSipHasher(u64, u64)(u256);
|
||||
(void)PresaltedSipHasher(u64, u64)(u256, u32);
|
||||
(void)ToLower(ch);
|
||||
(void)ToUpper(ch);
|
||||
|
||||
@@ -104,7 +104,7 @@ BOOST_AUTO_TEST_CASE(siphash)
|
||||
hasher.Write(0x2F2E2D2C2B2A2928ULL);
|
||||
BOOST_CHECK_EQUAL(hasher.Finalize(), 0xe612a3cb9ecba951ull);
|
||||
|
||||
BOOST_CHECK_EQUAL(SipHashUint256(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL, uint256{"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"}), 0x7127512f72f27cceull);
|
||||
BOOST_CHECK_EQUAL(PresaltedSipHasher(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL)(uint256{"1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"}), 0x7127512f72f27cceull);
|
||||
|
||||
// Check test vectors from spec, one byte at a time
|
||||
CSipHasher hasher2(0x0706050403020100ULL, 0x0F0E0D0C0B0A0908ULL);
|
||||
@@ -128,9 +128,9 @@ BOOST_AUTO_TEST_CASE(siphash)
|
||||
// and the test would be affected by default tx version bumps if not fixed.
|
||||
tx.version = 1;
|
||||
ss << TX_WITH_WITNESS(tx);
|
||||
BOOST_CHECK_EQUAL(SipHashUint256(1, 2, ss.GetHash()), 0x79751e980c2a0a35ULL);
|
||||
BOOST_CHECK_EQUAL(PresaltedSipHasher(1, 2)(ss.GetHash()), 0x79751e980c2a0a35ULL);
|
||||
|
||||
// Check consistency between CSipHasher and SipHashUint256 and PresaltedSipHasher.
|
||||
// Check consistency between CSipHasher and PresaltedSipHasher.
|
||||
FastRandomContext ctx;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
uint64_t k0 = ctx.rand64();
|
||||
@@ -139,7 +139,7 @@ BOOST_AUTO_TEST_CASE(siphash)
|
||||
|
||||
CSipHasher sip256(k0, k1);
|
||||
sip256.Write(x);
|
||||
BOOST_CHECK_EQUAL(SipHashUint256(k0, k1, x), sip256.Finalize()); // TODO modified in follow-up commit
|
||||
BOOST_CHECK_EQUAL(PresaltedSipHasher(k0, k1)(x), sip256.Finalize());
|
||||
|
||||
CSipHasher sip288 = sip256;
|
||||
uint32_t n = ctx.rand32();
|
||||
|
||||
@@ -7,17 +7,20 @@
|
||||
#include <span.h>
|
||||
#include <util/hasher.h>
|
||||
|
||||
SaltedUint256Hasher::SaltedUint256Hasher() :
|
||||
k0{FastRandomContext().rand64()},
|
||||
k1{FastRandomContext().rand64()} {}
|
||||
SaltedUint256Hasher::SaltedUint256Hasher() : m_hasher{
|
||||
FastRandomContext().rand64(),
|
||||
FastRandomContext().rand64()}
|
||||
{}
|
||||
|
||||
SaltedTxidHasher::SaltedTxidHasher() :
|
||||
k0{FastRandomContext().rand64()},
|
||||
k1{FastRandomContext().rand64()} {}
|
||||
SaltedTxidHasher::SaltedTxidHasher() : m_hasher{
|
||||
FastRandomContext().rand64(),
|
||||
FastRandomContext().rand64()}
|
||||
{}
|
||||
|
||||
SaltedWtxidHasher::SaltedWtxidHasher() :
|
||||
k0{FastRandomContext().rand64()},
|
||||
k1{FastRandomContext().rand64()} {}
|
||||
SaltedWtxidHasher::SaltedWtxidHasher() : m_hasher{
|
||||
FastRandomContext().rand64(),
|
||||
FastRandomContext().rand64()}
|
||||
{}
|
||||
|
||||
SaltedOutpointHasher::SaltedOutpointHasher(bool deterministic) : m_hasher{
|
||||
deterministic ? 0x8e819f2607a18de6 : FastRandomContext().rand64(),
|
||||
|
||||
@@ -17,47 +17,43 @@
|
||||
|
||||
class SaltedUint256Hasher
|
||||
{
|
||||
private:
|
||||
/** Salt */
|
||||
const uint64_t k0, k1;
|
||||
const PresaltedSipHasher m_hasher;
|
||||
|
||||
public:
|
||||
SaltedUint256Hasher();
|
||||
|
||||
size_t operator()(const uint256& hash) const {
|
||||
return SipHashUint256(k0, k1, hash);
|
||||
size_t operator()(const uint256& hash) const
|
||||
{
|
||||
return m_hasher(hash);
|
||||
}
|
||||
};
|
||||
|
||||
class SaltedTxidHasher
|
||||
{
|
||||
private:
|
||||
/** Salt */
|
||||
const uint64_t k0, k1;
|
||||
const PresaltedSipHasher m_hasher;
|
||||
|
||||
public:
|
||||
SaltedTxidHasher();
|
||||
|
||||
size_t operator()(const Txid& txid) const {
|
||||
return SipHashUint256(k0, k1, txid.ToUint256());
|
||||
size_t operator()(const Txid& txid) const
|
||||
{
|
||||
return m_hasher(txid.ToUint256());
|
||||
}
|
||||
};
|
||||
|
||||
class SaltedWtxidHasher
|
||||
{
|
||||
private:
|
||||
/** Salt */
|
||||
const uint64_t k0, k1;
|
||||
const PresaltedSipHasher m_hasher;
|
||||
|
||||
public:
|
||||
SaltedWtxidHasher();
|
||||
|
||||
size_t operator()(const Wtxid& wtxid) const {
|
||||
return SipHashUint256(k0, k1, wtxid.ToUint256());
|
||||
size_t operator()(const Wtxid& wtxid) const
|
||||
{
|
||||
return m_hasher(wtxid.ToUint256());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class SaltedOutpointHasher
|
||||
{
|
||||
const PresaltedSipHasher m_hasher;
|
||||
@@ -80,8 +76,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct FilterHeaderHasher
|
||||
{
|
||||
struct FilterHeaderHasher {
|
||||
size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user