Files
wizapp-stdlib/src/base/hash/hasher/siphash.c
T
Abdelrahman Said c215486442
Release / release (push) Successful in 3s
Restructure hasher implementation
2026-09-23 00:02:37 +01:00

191 lines
6.4 KiB
C

// vim:fileencoding=utf-8:foldmethod=marker
#include "siphash.h"
#include "hasher.h"
#include "../../../common/aliases/aliases.h"
#include "../../../common/assert/assert.h"
#include "../../../common/misc/misc_utils.h"
#include "../../../prng/xorshift/xorshift.h"
wp_intern inline void siphash(WpStream *bytes, const WpHasherCtx *ctx, u8 *out, u64 outlen);
wp_intern inline void validateSipHasherCtx(const WpHasherCtx *ctx);
wp_intern inline b8 checkRounds(const WpHasherCtx *ctx);
#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)
WpHasher wpSip24Hasher(void) {
WpXor256State state = wpPrngXorshiftInit();
WpU128 key = { .value = { wpPrngXorshift256(&state), wpPrngXorshift256(&state) } };
return wpSip24HasherWithKey(key);
}
WpHasher wpSip48Hasher(void) {
WpXor256State state = wpPrngXorshiftInit();
WpU128 key = { .value = { wpPrngXorshift256(&state), wpPrngXorshift256(&state) } };
return wpSip48HasherWithKey(key);
}
WpHasher wpSip24HasherWithKey(WpU128 key) {
return (WpHasher){
.func = wpSipGetHash128,
.ctx = (WpHasherCtx){
.type = WP_HASHER_CTX_SIPHASH,
.siphash = (WpSiphashCtx){ .key = key, .compression = 2, .finalisation = 4 },
},
};
}
WpHasher wpSip48HasherWithKey(WpU128 key) {
return (WpHasher){
.func = wpSipGetHash128,
.ctx = (WpHasherCtx){
.type = WP_HASHER_CTX_SIPHASH,
.siphash = (WpSiphashCtx){ .key = key, .compression = 4, .finalisation = 8 },
},
};
}
WpU128 wpSipGetHash128(WpStream *bytes, WpHasherCtx ctx) {
validateSipHasherCtx(&ctx);
WpU128 output = {0};
siphash(bytes, &ctx, (u8 *)&output.value, sizeof(u64) * 2);
return output;
}
/**
* Implementation of the 128-variant of the siphash algorithm
*/
wp_intern inline void siphash(WpStream *bytes, const WpHasherCtx *ctx, u8 *out, u64 outlen) {
const u8 *kk = (const u8 *)&ctx->siphash.key;
u64 inlen = bytes->count * bytes->item_size;
wpRuntimeAssert(outlen == 16, "outlen should be 16");
u64 v0 = wpU64Const(0x736f6d6570736575);
u64 v1 = wpU64Const(0x646f72616e646f6d);
u64 v2 = wpU64Const(0x6c7967656e657261);
u64 v3 = wpU64Const(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;
v1 ^= 0xee;
u8 *data;
while (wpStreamHasCount(bytes, sizeof(u64))) {
data = wpStreamConsumeCount(u8, bytes, sizeof(u64));
m = _u8To64LE(data);
v3 ^= m;
for (i = 0; i < ctx->siphash.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 < ctx->siphash.compression; ++i) {
_sipRound;
}
v0 ^= b;
v2 ^= 0xee;
for (i = 0; i < ctx->siphash.finalisation; ++i) {
_sipRound;
}
b = v0 ^ v1 ^ v2 ^ v3;
_u64To8LE(out, b);
v1 ^= 0xdd;
for (i = 0; i < ctx->siphash.finalisation; ++i) {
_sipRound;
}
b = v0 ^ v1 ^ v2 ^ v3;
_u64To8LE(out + 8, b);
}
wp_intern inline void validateSipHasherCtx(const WpHasherCtx *ctx) {
b8 magic_match = ctx->type == WP_HASHER_CTX_SIPHASH;
b8 rounds = checkRounds(ctx);
wpRuntimeAssert(magic_match && rounds, "Invalid Siphash context");
}
wp_intern inline b8 checkRounds(const WpHasherCtx *ctx) {
b8 rounds24 = ctx->siphash.compression == 2 && ctx->siphash.finalisation == 4;
b8 rounds48 = ctx->siphash.compression == 4 && ctx->siphash.finalisation == 8;
return rounds24 || rounds48;
}