shared: expose siphash24() related functionality in nm-hash-utils.h

CSiphash is a first class citizen, it's fine to use everwhere where we
need it.

NMHash wraps CSiphash and provides three things:

1) Convenience macros that make hashing nicer to use.

2) it uses a randomly generated, per-run hash seed, that can be combined
   with a guint static seed.

3) it's a general API for hashing data. It nowhere promises that it
   actually uses siphash24, although currently it does everywhere.
   NMHash is not (officially) siphash24.

Add API nm_hash_siphash42_init() and nm_hash_siphash42() to "nm-hash-utils.h",
that exposes (2) for use with regular CSiphash. You of course no longer
get the convenice macros (1) but you get plain siphash24 (which
NMHash does not give (3)).

While at it, also add a nm_hash_complete_u64(). Usually, for hasing we
want guint types. But we don't need to hide the fact, that the
underlying value is first uint64. Expose it.
This commit is contained in:
Thomas Haller 2018-12-12 12:11:53 +01:00
parent 3e0177f7d5
commit db791db4e1
2 changed files with 59 additions and 9 deletions

View file

@ -122,17 +122,17 @@ nm_hash_static (guint static_seed)
}
void
nm_hash_init (NMHashState *state, guint static_seed)
nm_hash_siphash42_init (CSipHash *h, guint static_seed)
{
const guint8 *g;
guint seed[HASH_KEY_SIZE_GUINT];
nm_assert (state);
nm_assert (h);
g = _get_hash_key ();
memcpy (seed, g, HASH_KEY_SIZE);
seed[0] ^= static_seed;
c_siphash_init (&state->_state, (const guint8 *) seed);
c_siphash_init (h, (const guint8 *) seed);
}
guint

View file

@ -25,6 +25,39 @@
#include "c-siphash/src/c-siphash.h"
#include "nm-macros-internal.h"
/*****************************************************************************/
void nm_hash_siphash42_init (CSipHash *h, guint static_seed);
/* Siphash24 of binary buffer @arr and @len, using the randomized seed from
* other NMHash functions.
*
* Note, that this is guaranteed to use siphash42 under the hood (contrary to
* all other NMHash API, which leave this undefined). That matters at the point,
* where the caller needs to be sure that a reasonably strong hasing algorithm
* is used. (Yes, NMHash is all about siphash24, but otherwise that is not promised
* anywhere).
*
* Another difference is, that this returns guint64 (not guint like other NMHash functions).
*
* Another difference is, that this may also return zero (not like nm_hash_complete()).
*
* Then, why not use c_siphash_hash() directly? Because this also uses the randomized,
* per-run hash-seed like nm_hash_init(). So, you get siphash24 with a random
* seed (which is cached for the current run of the program).
*/
static inline guint64
nm_hash_siphash42 (guint static_seed, const void *ptr, gsize n)
{
CSipHash h;
nm_hash_siphash42_init (&h, static_seed);
c_siphash_append (&h, ptr, n);
return c_siphash_finalize (&h);
}
/*****************************************************************************/
struct _NMHashState {
CSipHash _state;
};
@ -33,16 +66,33 @@ typedef struct _NMHashState NMHashState;
guint nm_hash_static (guint static_seed);
void nm_hash_init (NMHashState *state, guint static_seed);
static inline void
nm_hash_init (NMHashState *state, guint static_seed)
{
nm_assert (state);
nm_hash_siphash42_init (&state->_state, static_seed);
}
static inline guint64
nm_hash_complete_u64 (NMHashState *state)
{
nm_assert (state);
/* this returns the native u64 hash value. Note that this differs
* from nm_hash_complete() in two ways:
*
* - the type, guint64 vs. guint.
* - nm_hash_complete() never returns zero. */
return c_siphash_finalize (&state->_state);
}
static inline guint
nm_hash_complete (NMHashState *state)
{
guint64 h;
nm_assert (state);
h = c_siphash_finalize (&state->_state);
h = nm_hash_complete_u64 (state);
/* we don't ever want to return a zero hash.
*
@ -218,8 +268,8 @@ guint nm_str_hash (gconstpointer str);
({ \
NMHashState _h; \
\
nm_hash_init (&_h, static_seed); \
nm_hash_update_val (&_h, val); \
nm_hash_init (&_h, (static_seed)); \
nm_hash_update_val (&_h, (val)); \
nm_hash_complete (&_h); \
})