mirror of
https://github.com/wownero/wownero.git
synced 2026-10-17 07:31:35 +02:00
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)
This commit is contained in:
@@ -32,9 +32,13 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <sodium/crypto_verify_32.h>
|
||||
#include <sodium/crypto_shorthash_siphash24.h>
|
||||
|
||||
#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<unsigned char*>(&h), static_cast<const unsigned char*>(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<crypto::type> { \
|
||||
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)); \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -32,5 +32,15 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -789,7 +789,7 @@ inline std::ostream &operator <<(std::ostream &o, const rct::key &v) {
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<rct::key> { std::size_t operator()(const rct::key &k) const { return reinterpret_cast<const std::size_t&>(k); } };
|
||||
template<> struct hash<rct::key> { std::size_t operator()(const rct::key &k) const { return ::crypto::siphash_to_size_t(&k, sizeof(k)); } };
|
||||
}
|
||||
|
||||
BLOB_SERIALIZER(rct::key);
|
||||
|
||||
Reference in New Issue
Block a user