Skip to content

Commit 1112433

Browse files
martinusl0rinc
authored andcommitted
SaltedOutpointHasher uses rapidhash
SipHashUint256Extra is rather slow. For the purpose of generating a hash from a COutPoint and some seed that is only used inside a hashmap, it is sufficient to use a non-cryptographic hash. rapidhash [1] is a well tested and very fast hash function. This implementation strips down this hash function, originally implemented for a memory buffer, to be used with the COutPoint + 2*64bit seed as the input. [1] https://github.com/Nicoshev/rapidhash
1 parent 1d281da commit 1112433

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

src/crypto/siphash.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,53 @@ uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint3
172172
SIPROUND;
173173
return v0 ^ v1 ^ v2 ^ v3;
174174
}
175+
176+
177+
uint64_t ModifiedRapidHash(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra)
178+
{
179+
auto const rapid_mum = [](uint64_t* a, uint64_t* b) {
180+
#if defined(__SIZEOF_INT128__)
181+
__uint128_t r = *a;
182+
r *= *b;
183+
*a = (uint64_t)r;
184+
*b = (uint64_t)(r >> 64);
185+
#elif defined(_MSC_VER) && (defined(_WIN64) || defined(_M_HYBRID_CHPE_ARM64))
186+
#if defined(_M_X64)
187+
*a = _umul128(*a, *b, b);
188+
#else
189+
uint64_t c = __umulh(*a, *b);
190+
*a = *a * *b;
191+
*b = c;
192+
#endif
193+
#else
194+
uint64_t ha = *a >> 32, hb = *b >> 32, la = (uint32_t)*a, lb = (uint32_t)*b, hi, lo;
195+
uint64_t rh = ha * hb, rm0 = ha * lb, rm1 = hb * la, rl = la * lb, t = rl + (rm0 << 32), c = t < rl;
196+
lo = t + (rm1 << 32);
197+
c += lo < t;
198+
hi = rh + (rm0 >> 32) + (rm1 >> 32) + c;
199+
*a = lo;
200+
*b = hi;
201+
#endif
202+
};
203+
204+
auto const rapid_mix = [&rapid_mum](uint64_t a, uint64_t b) -> uint64_t {
205+
rapid_mum(&a, &b);
206+
return a ^ b;
207+
};
208+
209+
// This effectifely behaves like rapidhash with that input:
210+
// seed: k0, data: [val, k1, extra]
211+
// So it hashes 32+8+4 = 44 bytes, plus uses the 8 byte as seed.
212+
213+
// Default secret parameters.
214+
static constexpr uint64_t secret[3] = {0x2d358dccaa6c78a5ull, 0x8bb84b93962eacc9ull, 0x4b33a62ed433d4a3ull};
215+
216+
// no need to mix the seed itself, as it is purely random.
217+
uint64_t seed = k0;
218+
seed = rapid_mix(val.GetUint64(0) ^ secret[2], val.GetUint64(1) ^ seed ^ secret[1]);
219+
seed = rapid_mix(val.GetUint64(2) ^ secret[2], val.GetUint64(3) ^ seed);
220+
uint64_t a = k1 ^ secret[1];
221+
uint64_t b = extra ^ seed;
222+
rapid_mum(&a, &b);
223+
return rapid_mix(a ^ secret[0], b ^ secret[1]);
224+
}

src/crypto/siphash.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,6 @@ class CSipHasher
4444
*/
4545
uint64_t SipHashUint256(uint64_t k0, uint64_t k1, const uint256& val);
4646
uint64_t SipHashUint256Extra(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra);
47+
uint64_t ModifiedRapidHash(uint64_t k0, uint64_t k1, const uint256& val, uint32_t extra);
4748

4849
#endif // BITCOIN_CRYPTO_SIPHASH_H

src/util/hasher.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class SaltedOutpointHasher
4747
* @see https://gcc.gnu.org/onlinedocs/gcc-13.2.0/libstdc++/manual/manual/unordered_associative.html
4848
*/
4949
size_t operator()(const COutPoint& id) const noexcept {
50-
return SipHashUint256Extra(k0, k1, id.hash, id.n);
50+
return ModifiedRapidHash(k0, k1, id.hash, id.n);
5151
}
5252
};
5353

0 commit comments

Comments
 (0)