diff --git a/CHANGELOG.md b/CHANGELOG.md index e602d5d..ff9dcbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- `wpMur3HasherIO` to setup the hash IO struct -- `wpX64Mur3Hasher128` implementation for the x64 128-bit variant of the MurmurHash3 algorithm - `wpMiscUtilsRotl64` utility +- `wpMur3HasherIO` to setup the MurmurHash3 IO struct +- `wpX64Mur3Hasher128` implementation for the x64 128-bit variant of the MurmurHash3 algorithm +- `wpSip24Hasher128IO`, `wpSip48Hasher128IO`, `wpSip24Hasher64IO` and `wpSip48Hasher64IO` to setup the siphash IO structs for the different variants +- `wpSipHasher128` and `wpSipHasher64` implementation for the 128 and 64 variants of siphash ## [2.4.0] - 2026-08-30 diff --git a/src/base/hash/hasher/siphash.c b/src/base/hash/hasher/siphash.c new file mode 100644 index 0000000..cf0d600 --- /dev/null +++ b/src/base/hash/hasher/siphash.c @@ -0,0 +1,177 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +#include "siphash.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/assert/assert.h" +#include "../../../common/misc/misc_utils.h" +#include + +wp_intern inline void _siphash(WpStream *bytes, const WpSipHasherParams *params, u8 *out, u64 outlen); +wp_intern inline void _validate128IO(const WpSipHasher128IO *io); +wp_intern inline void _validate64IO(const WpSipHasher64IO *io); +wp_intern inline b8 _checkRounds(const WpSipHasherParams *params); + +#define _u32To8LE(p, v) \ + (p)[0] = (u8)((v)); \ + (p)[1] = (u8)((v) >> 8); \ + (p)[2] = (u8)((v) >> 16); \ + (p)[3] = (u8)((v) >> 24); + +#define _u64To8LE(p, v) \ + _u32To8LE((p), (u32)((v))); \ + _u32To8LE((p) + 4, (u32)((v) >> 32)); + +#define _u8To64LE(p) \ + (((u64)((p)[0])) | ((u64)((p)[1]) << 8) | \ + ((u64)((p)[2]) << 16) | ((u64)((p)[3]) << 24) | \ + ((u64)((p)[4]) << 32) | ((u64)((p)[5]) << 40) | \ + ((u64)((p)[6]) << 48) | ((u64)((p)[7]) << 56)) + +#define _sipRound \ + do { \ + v0 += v1; \ + v1 = wpMiscUtilsRotl64(v1, 13); \ + v1 ^= v0; \ + v0 = wpMiscUtilsRotl64(v0, 32); \ + v2 += v3; \ + v3 = wpMiscUtilsRotl64(v3, 16); \ + v3 ^= v2; \ + v0 += v3; \ + v3 = wpMiscUtilsRotl64(v3, 21); \ + v3 ^= v0; \ + v2 += v1; \ + v1 = wpMiscUtilsRotl64(v1, 17); \ + v1 ^= v2; \ + v2 = wpMiscUtilsRotl64(v2, 32); \ + } while (0) + +void wpSipHasher128(WpStream *bytes, void *hasher_io) { + WpSipHasher128IO *io = (WpSipHasher128IO *)hasher_io; + _validate128IO(io); + _siphash(bytes, &io->params, (u8 *)&io->hash, sizeof(u64) * 2); +} + +void wpSipHasher64(WpStream *bytes, void *hasher_io) { + WpSipHasher64IO *io = (WpSipHasher64IO *)hasher_io; + _validate64IO(io); + _siphash(bytes, &io->params, (u8 *)&io->hash, sizeof(u64)); +} + +wp_intern inline void _siphash(WpStream *bytes, const WpSipHasherParams *params, u8 *out, + u64 outlen) { + const u8 *kk = (const u8 *)¶ms->key; + u64 inlen = bytes->count * bytes->item_size; + + wpRuntimeAssert((outlen == 8) || (outlen == 16), "outlen should be 8 or 16"); + + u64 v0 = UINT64_C(0x736f6d6570736575); + u64 v1 = UINT64_C(0x646f72616e646f6d); + u64 v2 = UINT64_C(0x6c7967656e657261); + u64 v3 = UINT64_C(0x7465646279746573); + u64 k0 = _u8To64LE(kk); + u64 k1 = _u8To64LE(kk + 8); + u64 m; + u64 i; + const i32 left = inlen & 7; + u64 b = ((u64)inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + if (outlen == 16) { + v1 ^= 0xee; + } + + u8 *data; + while (wpStreamHasCount(bytes, sizeof(u64))) { + data = wpStreamConsumeCount(u8, bytes, sizeof(u64)); + m = _u8To64LE(data); + v3 ^= m; + + for (i = 0; i < params->compression; ++i) { + _sipRound; + } + + v0 ^= m; + } + + data = wpStreamConsume(u8, bytes); + switch (left) { + case 7: + b |= ((u64)data[6]) << 48; + /* FALLTHRU */ + case 6: + b |= ((u64)data[5]) << 40; + /* FALLTHRU */ + case 5: + b |= ((u64)data[4]) << 32; + /* FALLTHRU */ + case 4: + b |= ((u64)data[3]) << 24; + /* FALLTHRU */ + case 3: + b |= ((u64)data[2]) << 16; + /* FALLTHRU */ + case 2: + b |= ((u64)data[1]) << 8; + /* FALLTHRU */ + case 1: + b |= ((u64)data[0]); + break; + case 0: + break; + } + + v3 ^= b; + + for (i = 0; i < params->compression; ++i) { + _sipRound; + } + + v0 ^= b; + + if (outlen == 16) { + v2 ^= 0xee; + } else { + v2 ^= 0xff; + } + + for (i = 0; i < params->finalisation; ++i) { + _sipRound; + } + + b = v0 ^ v1 ^ v2 ^ v3; + _u64To8LE(out, b); + + if (outlen == 8) { + return; + } + + v1 ^= 0xdd; + + for (i = 0; i < params->finalisation; ++i) { + _sipRound; + } + + b = v0 ^ v1 ^ v2 ^ v3; + _u64To8LE(out + 8, b); +} + +wp_intern inline void _validate128IO(const WpSipHasher128IO *io) { + b8 magic_match = io->params.magic == WP_SIP_HASHER_128_MAGIC; + b8 rounds = _checkRounds(&io->params); + wpRuntimeAssert(magic_match && rounds, "Invalid Siphash 128 IO"); +} + +wp_intern inline void _validate64IO(const WpSipHasher64IO *io) { + b8 magic_match = io->params.magic == WP_SIP_HASHER_64_MAGIC; + b8 rounds = _checkRounds(&io->params); + wpRuntimeAssert(magic_match && rounds, "Invalid Siphash 64 IO"); +} + +wp_intern inline b8 _checkRounds(const WpSipHasherParams *params) { + b8 rounds24 = params->compression == 2 && params->finalisation == 4; + b8 rounds48 = params->compression == 4 && params->finalisation == 8; + return rounds24 || rounds48; +} diff --git a/src/base/hash/hasher/siphash.h b/src/base/hash/hasher/siphash.h new file mode 100644 index 0000000..7112af6 --- /dev/null +++ b/src/base/hash/hasher/siphash.h @@ -0,0 +1,103 @@ +// vim:fileencoding=utf-8:foldmethod=marker + +/** + * Implementations of the SipHash-2-4-128, SipHash4-8-128, SipHash-2-4-64 and SipHash4-8-64 + * algorithms based on https://github.com/veorq/SipHash/blob/master/siphash.c + */ + +#ifndef SIPHASH_H +#define SIPHASH_H + +#include "../../stream/stream.h" +#include "../../../common/aliases/aliases.h" +#include "../../../common/platform/platform.h" + +#ifdef WP_PLATFORM_CPP +BEGIN_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#define WP_SIP_HASHER_128_MAGIC ((u64)0x5750534950313238) +#define WP_SIP_HASHER_64_MAGIC ((u64)0x57505349503634) + +typedef struct { + u64 lo; + u64 hi; +} WpSipHasherKey; + +typedef struct { + WpSipHasherKey key; + u64 magic; + u64 compression; + u64 finalisation; +} WpSipHasherParams; + +typedef struct { + WpSipHasherParams params; + u64 hash[2]; +} WpSipHasher128IO; + +typedef struct { + WpSipHasherParams params; + u64 hash; +} WpSipHasher64IO; + +#ifdef WP_PLATFORM_CPP +#define wpSip24Hasher128IO(KEY) (WpSipHasher128IO{ \ + WpSipHasherParams{KEY, WP_SIP_HASHER_128_MAGIC, 2, 4}, \ + {}, \ +}) +#define wpSip48Hasher128IO(KEY) (WpSipHasher128IO{ \ + WpSipHasherParams{KEY, WP_SIP_HASHER_128_MAGIC, 4, 8}, \ + {}, \ +}) +#define wpSip24Hasher64IO(KEY) (WpSipHasher64IO{ \ + WpSipHasherParams{KEY, WP_SIP_HASHER_64_MAGIC, 2, 4}, \ + 0, \ +}) +#define wpSip48Hasher64IO(KEY) (WpSipHasher64IO{ \ + WpSipHasherParams{KEY, WP_SIP_HASHER_64_MAGIC, 4, 8}, \ + 0, \ +}) +#else +#define wpSip24Hasher128IO(KEY) ((WpSipHasher128IO){ \ + .params = (WpSipHasherParams){ \ + .key = KEY, \ + .magic = WP_SIP_HASHER_128_MAGIC, \ + .compression = 2, \ + .finalisation = 4, \ + } \ +}) +#define wpSip48Hasher128IO(KEY) ((WpSipHasher128IO){ \ + .params = (WpSipHasherParams){ \ + .key = KEY, \ + .magic = WP_SIP_HASHER_128_MAGIC, \ + .compression = 4, \ + .finalisation = 8, \ + } \ +}) +#define wpSip24Hasher64IO(KEY) ((WpSipHasher64IO){ \ + .params = (WpSipHasherParams){ \ + .key = KEY, \ + .magic = WP_SIP_HASHER_64_MAGIC, \ + .compression = 2, \ + .finalisation = 4, \ + } \ +}) +#define wpSip48Hasher64IO(KEY) ((WpSipHasher64IO){ \ + .params = (WpSipHasherParams){ \ + .key = KEY, \ + .magic = WP_SIP_HASHER_64_MAGIC, \ + .compression = 4, \ + .finalisation = 8, \ + } \ +}) +#endif + +void wpSipHasher128(WpU8Stream *bytes, void *hasher_io); +void wpSipHasher64(WpU8Stream *bytes, void *hasher_io); + +#ifdef WP_PLATFORM_CPP +END_C_LINKAGE +#endif // !WP_PLATFORM_CPP + +#endif // !SIPHASH_H diff --git a/src/base/wapp_base.c b/src/base/wapp_base.c index 57a90d2..059be82 100644 --- a/src/base/wapp_base.c +++ b/src/base/wapp_base.c @@ -7,6 +7,7 @@ #include "array/array.c" #include "dbl_list/dbl_list.c" #include "hash/hasher/murmur3.c" +#include "hash/hasher/siphash.c" #include "queue/queue.c" #include "stream/stream.c" #include "mem/allocator/mem_allocator.c" diff --git a/src/base/wapp_base.h b/src/base/wapp_base.h index 1fdc9e6..894349d 100644 --- a/src/base/wapp_base.h +++ b/src/base/wapp_base.h @@ -7,6 +7,7 @@ #include "dbl_list/dbl_list.h" #include "hash/hasher/hasher.h" #include "hash/hasher/murmur3.h" +#include "hash/hasher/siphash.h" #include "queue/queue.h" #include "stream/stream.h" #include "mem/allocator/mem_allocator.h" diff --git a/tests/hasher/siphash.c b/tests/hasher/siphash.c new file mode 100644 index 0000000..c6d16e2 --- /dev/null +++ b/tests/hasher/siphash.c @@ -0,0 +1,185 @@ +/* + SipHash reference C implementation + + Copyright (c) 2012-2022 Jean-Philippe Aumasson + + Copyright (c) 2012-2014 Daniel J. Bernstein + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . + */ + +#include "siphash.h" +#include +#include +#include + +/* default: SipHash-2-4 */ +#ifndef cROUNDS +#define cROUNDS 2 +#endif +#ifndef dROUNDS +#define dROUNDS 4 +#endif + +#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) + +#define U32TO8_LE(p, v) \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); + +#define U64TO8_LE(p, v) \ + U32TO8_LE((p), (uint32_t)((v))); \ + U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); + +#define U8TO64_LE(p) \ + (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ + ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ + ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ + ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) + +#define SIPROUND \ + do { \ + v0 += v1; \ + v1 = ROTL(v1, 13); \ + v1 ^= v0; \ + v0 = ROTL(v0, 32); \ + v2 += v3; \ + v3 = ROTL(v3, 16); \ + v3 ^= v2; \ + v0 += v3; \ + v3 = ROTL(v3, 21); \ + v3 ^= v0; \ + v2 += v1; \ + v1 = ROTL(v1, 17); \ + v1 ^= v2; \ + v2 = ROTL(v2, 32); \ + } while (0) + +#ifdef DEBUG_SIPHASH +#include + +#define TRACE \ + do { \ + printf("(%3zu) v0 %016" PRIx64 "\n", inlen, v0); \ + printf("(%3zu) v1 %016" PRIx64 "\n", inlen, v1); \ + printf("(%3zu) v2 %016" PRIx64 "\n", inlen, v2); \ + printf("(%3zu) v3 %016" PRIx64 "\n", inlen, v3); \ + } while (0) +#else +#define TRACE +#endif + +/* + Computes a SipHash value + *in: pointer to input data (read-only) + inlen: input data length in bytes (any size_t value) + *k: pointer to the key data (read-only), must be 16 bytes + *out: pointer to output data (write-only), outlen bytes must be allocated + outlen: length of the output in bytes, must be 8 or 16 +*/ +int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out, + const size_t outlen) { + + const unsigned char *ni = (const unsigned char *)in; + const unsigned char *kk = (const unsigned char *)k; + + assert((outlen == 8) || (outlen == 16)); + uint64_t v0 = UINT64_C(0x736f6d6570736575); + uint64_t v1 = UINT64_C(0x646f72616e646f6d); + uint64_t v2 = UINT64_C(0x6c7967656e657261); + uint64_t v3 = UINT64_C(0x7465646279746573); + uint64_t k0 = U8TO64_LE(kk); + uint64_t k1 = U8TO64_LE(kk + 8); + uint64_t m; + int i; + const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t)); + const int left = inlen & 7; + uint64_t b = ((uint64_t)inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + if (outlen == 16) + v1 ^= 0xee; + + for (; ni != end; ni += 8) { + m = U8TO64_LE(ni); + v3 ^= m; + + TRACE; + for (i = 0; i < cROUNDS; ++i) + SIPROUND; + + v0 ^= m; + } + + switch (left) { + case 7: + b |= ((uint64_t)ni[6]) << 48; + /* FALLTHRU */ + case 6: + b |= ((uint64_t)ni[5]) << 40; + /* FALLTHRU */ + case 5: + b |= ((uint64_t)ni[4]) << 32; + /* FALLTHRU */ + case 4: + b |= ((uint64_t)ni[3]) << 24; + /* FALLTHRU */ + case 3: + b |= ((uint64_t)ni[2]) << 16; + /* FALLTHRU */ + case 2: + b |= ((uint64_t)ni[1]) << 8; + /* FALLTHRU */ + case 1: + b |= ((uint64_t)ni[0]); + break; + case 0: + break; + } + + v3 ^= b; + + TRACE; + for (i = 0; i < cROUNDS; ++i) + SIPROUND; + + v0 ^= b; + + if (outlen == 16) + v2 ^= 0xee; + else + v2 ^= 0xff; + + TRACE; + for (i = 0; i < dROUNDS; ++i) + SIPROUND; + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out, b); + + if (outlen == 8) + return 0; + + v1 ^= 0xdd; + + TRACE; + for (i = 0; i < dROUNDS; ++i) + SIPROUND; + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out + 8, b); + + return 0; +} diff --git a/tests/hasher/siphash.cc b/tests/hasher/siphash.cc new file mode 100644 index 0000000..c6d16e2 --- /dev/null +++ b/tests/hasher/siphash.cc @@ -0,0 +1,185 @@ +/* + SipHash reference C implementation + + Copyright (c) 2012-2022 Jean-Philippe Aumasson + + Copyright (c) 2012-2014 Daniel J. Bernstein + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . + */ + +#include "siphash.h" +#include +#include +#include + +/* default: SipHash-2-4 */ +#ifndef cROUNDS +#define cROUNDS 2 +#endif +#ifndef dROUNDS +#define dROUNDS 4 +#endif + +#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) + +#define U32TO8_LE(p, v) \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); + +#define U64TO8_LE(p, v) \ + U32TO8_LE((p), (uint32_t)((v))); \ + U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); + +#define U8TO64_LE(p) \ + (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ + ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ + ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ + ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) + +#define SIPROUND \ + do { \ + v0 += v1; \ + v1 = ROTL(v1, 13); \ + v1 ^= v0; \ + v0 = ROTL(v0, 32); \ + v2 += v3; \ + v3 = ROTL(v3, 16); \ + v3 ^= v2; \ + v0 += v3; \ + v3 = ROTL(v3, 21); \ + v3 ^= v0; \ + v2 += v1; \ + v1 = ROTL(v1, 17); \ + v1 ^= v2; \ + v2 = ROTL(v2, 32); \ + } while (0) + +#ifdef DEBUG_SIPHASH +#include + +#define TRACE \ + do { \ + printf("(%3zu) v0 %016" PRIx64 "\n", inlen, v0); \ + printf("(%3zu) v1 %016" PRIx64 "\n", inlen, v1); \ + printf("(%3zu) v2 %016" PRIx64 "\n", inlen, v2); \ + printf("(%3zu) v3 %016" PRIx64 "\n", inlen, v3); \ + } while (0) +#else +#define TRACE +#endif + +/* + Computes a SipHash value + *in: pointer to input data (read-only) + inlen: input data length in bytes (any size_t value) + *k: pointer to the key data (read-only), must be 16 bytes + *out: pointer to output data (write-only), outlen bytes must be allocated + outlen: length of the output in bytes, must be 8 or 16 +*/ +int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out, + const size_t outlen) { + + const unsigned char *ni = (const unsigned char *)in; + const unsigned char *kk = (const unsigned char *)k; + + assert((outlen == 8) || (outlen == 16)); + uint64_t v0 = UINT64_C(0x736f6d6570736575); + uint64_t v1 = UINT64_C(0x646f72616e646f6d); + uint64_t v2 = UINT64_C(0x6c7967656e657261); + uint64_t v3 = UINT64_C(0x7465646279746573); + uint64_t k0 = U8TO64_LE(kk); + uint64_t k1 = U8TO64_LE(kk + 8); + uint64_t m; + int i; + const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t)); + const int left = inlen & 7; + uint64_t b = ((uint64_t)inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + if (outlen == 16) + v1 ^= 0xee; + + for (; ni != end; ni += 8) { + m = U8TO64_LE(ni); + v3 ^= m; + + TRACE; + for (i = 0; i < cROUNDS; ++i) + SIPROUND; + + v0 ^= m; + } + + switch (left) { + case 7: + b |= ((uint64_t)ni[6]) << 48; + /* FALLTHRU */ + case 6: + b |= ((uint64_t)ni[5]) << 40; + /* FALLTHRU */ + case 5: + b |= ((uint64_t)ni[4]) << 32; + /* FALLTHRU */ + case 4: + b |= ((uint64_t)ni[3]) << 24; + /* FALLTHRU */ + case 3: + b |= ((uint64_t)ni[2]) << 16; + /* FALLTHRU */ + case 2: + b |= ((uint64_t)ni[1]) << 8; + /* FALLTHRU */ + case 1: + b |= ((uint64_t)ni[0]); + break; + case 0: + break; + } + + v3 ^= b; + + TRACE; + for (i = 0; i < cROUNDS; ++i) + SIPROUND; + + v0 ^= b; + + if (outlen == 16) + v2 ^= 0xee; + else + v2 ^= 0xff; + + TRACE; + for (i = 0; i < dROUNDS; ++i) + SIPROUND; + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out, b); + + if (outlen == 8) + return 0; + + v1 ^= 0xdd; + + TRACE; + for (i = 0; i < dROUNDS; ++i) + SIPROUND; + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out + 8, b); + + return 0; +} diff --git a/tests/hasher/siphash.h b/tests/hasher/siphash.h new file mode 100644 index 0000000..3fbd378 --- /dev/null +++ b/tests/hasher/siphash.h @@ -0,0 +1,22 @@ +/* + SipHash reference C implementation + + Copyright (c) 2012-2021 Jean-Philippe Aumasson + + Copyright (c) 2012-2014 Daniel J. Bernstein + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . + */ + +#include +#include + +int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out, + const size_t outlen); diff --git a/tests/hasher/test_hasher.c b/tests/hasher/test_hasher.c index 646021d..76c9555 100644 --- a/tests/hasher/test_hasher.c +++ b/tests/hasher/test_hasher.c @@ -2,6 +2,7 @@ #include "test_hasher.h" #include "MurmurHash3.h" +#include "siphash.h" #include "wapp.h" WpTestFuncResult test_murmur3(void) { @@ -39,3 +40,83 @@ WpTestFuncResult test_murmur3(void) { return wpTesterResult(result); } + +WpTestFuncResult test_siphash_128(void) { + b8 result = true; + + WpStr8 str = wpStr8Lit("Hello world"); + WpI32Array arr = wpArray(i32, 1, 2, 3, 4, 5); + u64 num = 287324; + + WpSipHasherKey key = { .lo = 238742, .hi = 671734 }; + WpSipHasher128IO io = wpSip24Hasher128IO(key); + + WpU8Stream str_bytes = wpStream(u8, str.buf, str.size); + WpU8Stream arr_bytes = wpStream(u8, (u8 *)arr, wpArrayCount(arr) * wpArrayItemSize(arr)); + WpU8Stream num_bytes = wpStream(u8, (u8 *)&num, sizeof(u64)); + + u64 hash[2] = {0}; + + // Sring hash + wpSipHasher128(&str_bytes, (void *)&io); + siphash(str_bytes.data, str_bytes.count * str_bytes.item_size, (void *)&io.params.key, + (u8 *)hash, sizeof(u64) * 2); + + result = result && io.hash[0] == hash[0] && io.hash[1] == hash[1]; + + // Array hash + wpSipHasher128(&arr_bytes, (void *)&io); + siphash(arr_bytes.data, arr_bytes.count * arr_bytes.item_size, (void *)&io.params.key, + (u8 *)hash, sizeof(u64) * 2); + + result = result && io.hash[0] == hash[0] && io.hash[1] == hash[1]; + + // Number hash + wpSipHasher128(&num_bytes, (void *)&io); + siphash(num_bytes.data, num_bytes.count * num_bytes.item_size, (void *)&io.params.key, + (u8 *)hash, sizeof(u64) * 2); + + result = result && io.hash[0] == hash[0] && io.hash[1] == hash[1]; + + return wpTesterResult(result); +} + +WpTestFuncResult test_siphash_64(void) { + b8 result = true; + + WpStr8 str = wpStr8Lit("Hello world"); + WpI32Array arr = wpArray(i32, 1, 2, 3, 4, 5); + u64 num = 287324; + + WpSipHasherKey key = { .lo = 238742, .hi = 671734 }; + WpSipHasher64IO io = wpSip24Hasher64IO(key); + + WpU8Stream str_bytes = wpStream(u8, str.buf, str.size); + WpU8Stream arr_bytes = wpStream(u8, (u8 *)arr, wpArrayCount(arr) * wpArrayItemSize(arr)); + WpU8Stream num_bytes = wpStream(u8, (u8 *)&num, sizeof(u64)); + + u64 hash = {0}; + + // Sring hash + wpSipHasher64(&str_bytes, (void *)&io); + siphash(str_bytes.data, str_bytes.count * str_bytes.item_size, (void *)&io.params.key, + (u8 *)&hash, sizeof(u64)); + + result = result && io.hash == hash; + + // Array hash + wpSipHasher64(&arr_bytes, (void *)&io); + siphash(arr_bytes.data, arr_bytes.count * arr_bytes.item_size, (void *)&io.params.key, + (u8 *)&hash, sizeof(u64)); + + result = result && io.hash == hash; + + // Number hash + wpSipHasher64(&num_bytes, (void *)&io); + siphash(num_bytes.data, num_bytes.count * num_bytes.item_size, (void *)&io.params.key, + (u8 *)&hash, sizeof(u64)); + + result = result && io.hash == hash; + + return wpTesterResult(result); +} diff --git a/tests/hasher/test_hasher.cc b/tests/hasher/test_hasher.cc index 646021d..b24a950 100644 --- a/tests/hasher/test_hasher.cc +++ b/tests/hasher/test_hasher.cc @@ -2,6 +2,7 @@ #include "test_hasher.h" #include "MurmurHash3.h" +#include "siphash.h" #include "wapp.h" WpTestFuncResult test_murmur3(void) { @@ -39,3 +40,83 @@ WpTestFuncResult test_murmur3(void) { return wpTesterResult(result); } + +WpTestFuncResult test_siphash_128(void) { + b8 result = true; + + WpStr8 str = wpStr8Lit("Hello world"); + WpI32Array arr = wpArray(i32, 1, 2, 3, 4, 5); + u64 num = 287324; + + WpSipHasherKey key = { 238742, 671734 }; + WpSipHasher128IO io = wpSip24Hasher128IO(key); + + WpU8Stream str_bytes = wpStream(u8, str.buf, str.size); + WpU8Stream arr_bytes = wpStream(u8, (u8 *)arr, wpArrayCount(arr) * wpArrayItemSize(arr)); + WpU8Stream num_bytes = wpStream(u8, (u8 *)&num, sizeof(u64)); + + u64 hash[2] = {0}; + + // Sring hash + wpSipHasher128(&str_bytes, (void *)&io); + siphash((void *)str_bytes.data, str_bytes.count * str_bytes.item_size, (void *)&io.params.key, + (u8 *)hash, sizeof(u64) * 2); + + result = result && io.hash[0] == hash[0] && io.hash[1] == hash[1]; + + // Array hash + wpSipHasher128(&arr_bytes, (void *)&io); + siphash((void *)arr_bytes.data, arr_bytes.count * arr_bytes.item_size, (void *)&io.params.key, + (u8 *)hash, sizeof(u64) * 2); + + result = result && io.hash[0] == hash[0] && io.hash[1] == hash[1]; + + // Number hash + wpSipHasher128(&num_bytes, (void *)&io); + siphash((void *)num_bytes.data, num_bytes.count * num_bytes.item_size, (void *)&io.params.key, + (u8 *)hash, sizeof(u64) * 2); + + result = result && io.hash[0] == hash[0] && io.hash[1] == hash[1]; + + return wpTesterResult(result); +} + +WpTestFuncResult test_siphash_64(void) { + b8 result = true; + + WpStr8 str = wpStr8Lit("Hello world"); + WpI32Array arr = wpArray(i32, 1, 2, 3, 4, 5); + u64 num = 287324; + + WpSipHasherKey key = { 238742, 671734 }; + WpSipHasher64IO io = wpSip24Hasher64IO(key); + + WpU8Stream str_bytes = wpStream(u8, str.buf, str.size); + WpU8Stream arr_bytes = wpStream(u8, (u8 *)arr, wpArrayCount(arr) * wpArrayItemSize(arr)); + WpU8Stream num_bytes = wpStream(u8, (u8 *)&num, sizeof(u64)); + + u64 hash = {0}; + + // Sring hash + wpSipHasher64(&str_bytes, (void *)&io); + siphash((void *)str_bytes.data, str_bytes.count * str_bytes.item_size, (void *)&io.params.key, + (u8 *)&hash, sizeof(u64)); + + result = result && io.hash == hash; + + // Array hash + wpSipHasher64(&arr_bytes, (void *)&io); + siphash((void *)arr_bytes.data, arr_bytes.count * arr_bytes.item_size, (void *)&io.params.key, + (u8 *)&hash, sizeof(u64)); + + result = result && io.hash == hash; + + // Number hash + wpSipHasher64(&num_bytes, (void *)&io); + siphash((void *)num_bytes.data, num_bytes.count * num_bytes.item_size, (void *)&io.params.key, + (u8 *)&hash, sizeof(u64)); + + result = result && io.hash == hash; + + return wpTesterResult(result); +} diff --git a/tests/hasher/test_hasher.h b/tests/hasher/test_hasher.h index 209d4f8..b738fb9 100644 --- a/tests/hasher/test_hasher.h +++ b/tests/hasher/test_hasher.h @@ -8,4 +8,8 @@ // Test Murmur3 hash implementation against the reference implementation WpTestFuncResult test_murmur3(void); +// Test Sip hash implementation against the reference implementation +WpTestFuncResult test_siphash_128(void); +WpTestFuncResult test_siphash_64(void); + #endif // !TEST_HASHER_H diff --git a/tests/wapptest.c b/tests/wapptest.c index c376ddb..1e86f3d 100644 --- a/tests/wapptest.c +++ b/tests/wapptest.c @@ -103,6 +103,8 @@ int main(void) { test_wapp_file_rename, test_wapp_file_remove, test_murmur3, + test_siphash_128, + test_siphash_64, test_commander_cmd_success, test_commander_cmd_failure, test_commander_cmd_out_buf_success, diff --git a/tests/wapptest.cc b/tests/wapptest.cc index c376ddb..1e86f3d 100644 --- a/tests/wapptest.cc +++ b/tests/wapptest.cc @@ -103,6 +103,8 @@ int main(void) { test_wapp_file_rename, test_wapp_file_remove, test_murmur3, + test_siphash_128, + test_siphash_64, test_commander_cmd_success, test_commander_cmd_failure, test_commander_cmd_out_buf_success,