From ad119391ebd70b53fa9a83b0d132dc86e17d7081 Mon Sep 17 00:00:00 2001 From: SChernykh <15806605+SChernykh@users.noreply.github.com> Date: Thu, 23 Jul 2026 19:54:33 +0200 Subject: [PATCH] Optimize hashing of generic types Use a proper hash function instead of f(x)=x to achieve better distribution of hash values (cherry picked from commit 5eeff1d9c15dfdce6ade9bed455e8fdaab777b31) --- src/crypto/generic-ops.h | 25 ++++++++++++++++++------- src/crypto/random.c | 3 +++ src/crypto/random.h | 10 ++++++++++ src/ringct/rctTypes.h | 2 +- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/crypto/generic-ops.h b/src/crypto/generic-ops.h index 3ff3619fe..8d103aa18 100644 --- a/src/crypto/generic-ops.h +++ b/src/crypto/generic-ops.h @@ -32,9 +32,13 @@ #include #include +#include #include #include #include +#include + +#include "random.h" #define CRYPTO_MAKE_COMPARABLE(type) \ namespace crypto { \ @@ -57,22 +61,29 @@ namespace crypto { \ } \ } +namespace crypto { + inline std::size_t siphash_to_size_t(const void *data, std::size_t length) { + static_assert(sizeof(crypto_siphash_key) == crypto_shorthash_siphash24_KEYBYTES, + "crypto_siphash_key size must match the SipHash-2-4 key length"); + static_assert(sizeof(std::uint64_t) == crypto_shorthash_siphash24_BYTES, + "std::uint64_t size must match the SipHash-2-4 digest length"); + std::uint64_t h; + crypto_shorthash_siphash24(reinterpret_cast(&h), static_cast(data), length, crypto_siphash_key); + return h; + } +} + #define CRYPTO_DEFINE_HASH_FUNCTIONS(type) \ namespace crypto { \ - static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \ inline std::size_t hash_value(const type &_v) { \ - std::size_t h; \ - memcpy(&h, std::addressof(_v), sizeof(h)); \ - return h; \ + return siphash_to_size_t(std::addressof(_v), sizeof(_v)); \ } \ } \ namespace std { \ template<> \ struct hash { \ std::size_t operator()(const crypto::type &_v) const { \ - std::size_t h; \ - memcpy(&h, std::addressof(_v), sizeof(h)); \ - return h; \ + return ::crypto::siphash_to_size_t(std::addressof(_v), sizeof(_v)); \ } \ }; \ } diff --git a/src/crypto/random.c b/src/crypto/random.c index cfb637fb4..0f6f16130 100644 --- a/src/crypto/random.c +++ b/src/crypto/random.c @@ -96,6 +96,7 @@ static void generate_system_random_bytes(size_t n, void *result) { #endif static union hash_state state; +unsigned char crypto_siphash_key[16]; #if !defined(NDEBUG) static volatile int curstate; /* To catch thread safety problems. */ @@ -107,10 +108,12 @@ FINALIZER(deinit_random) { curstate = 0; #endif memset(&state, 0, sizeof(union hash_state)); + memset(crypto_siphash_key, 0, sizeof(crypto_siphash_key)); } INITIALIZER(init_random) { generate_system_random_bytes(32, &state); + generate_system_random_bytes(sizeof(crypto_siphash_key), crypto_siphash_key); REGISTER_FINALIZER(deinit_random); #if !defined(NDEBUG) assert(curstate == 0); diff --git a/src/crypto/random.h b/src/crypto/random.h index d50f29430..935f76353 100644 --- a/src/crypto/random.h +++ b/src/crypto/random.h @@ -32,5 +32,15 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + void generate_random_bytes_not_thread_safe(size_t n, void *result); void add_extra_entropy_not_thread_safe(const void *ptr, size_t bytes); + +extern unsigned char crypto_siphash_key[16]; + +#ifdef __cplusplus +} +#endif diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 2ece24d9e..94fe48aa4 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -789,7 +789,7 @@ inline std::ostream &operator <<(std::ostream &o, const rct::key &v) { namespace std { - template<> struct hash { std::size_t operator()(const rct::key &k) const { return reinterpret_cast(k); } }; + template<> struct hash { std::size_t operator()(const rct::key &k) const { return ::crypto::siphash_to_size_t(&k, sizeof(k)); } }; } BLOB_SERIALIZER(rct::key);