From 4dd49ac528e3bb3c40a7c9ff4472a59a9ee9f5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Fri, 8 Sep 2023 17:22:05 +0200 Subject: [PATCH 1/3] Implement incremental version of SipHash 2-4 and HalfSipHash 2-4 When inserting items into hashtables (hashmaps), we might have a fragmented key (as an example we might want to hash DNS name + class + type). We either need to construct continuous key in the memory and then hash it en bloc, or incremental hashing is required. This incremental version of SipHash 2-4 algorithm is the first building block. As SipHash 2-4 is often used in the hot paths, I've turned the implementation into header-only version in the process. --- lib/isc/Makefile.am | 1 - lib/isc/include/isc/siphash.h | 407 +++++++++++++++++++++++++++++++++- lib/isc/siphash.c | 229 ------------------- tests/isc/siphash_test.c | 28 ++- 4 files changed, 424 insertions(+), 241 deletions(-) delete mode 100644 lib/isc/siphash.c diff --git a/lib/isc/Makefile.am b/lib/isc/Makefile.am index 0f692d32c6..1aa7849c43 100644 --- a/lib/isc/Makefile.am +++ b/lib/isc/Makefile.am @@ -182,7 +182,6 @@ libisc_la_SOURCES = \ safe.c \ serial.c \ signal.c \ - siphash.c \ sockaddr.c \ stats.c \ stdio.c \ diff --git a/lib/isc/include/isc/siphash.h b/lib/isc/include/isc/siphash.h index 905711f7cb..1cb3582f01 100644 --- a/lib/isc/include/isc/siphash.h +++ b/lib/isc/include/isc/siphash.h @@ -11,12 +11,29 @@ * information regarding copyright ownership. */ +/* + * The implementation is based on SipHash reference C implementation by + * + * Copyright (c) 2012-2016 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 . + */ + /*! \file isc/siphash.h */ #pragma once +#include +#include #include #include +#include #define ISC_SIPHASH24_KEY_LENGTH 128 / 8 #define ISC_SIPHASH24_TAG_LENGTH 64 / 8 @@ -24,13 +41,393 @@ #define ISC_HALFSIPHASH24_KEY_LENGTH 64 / 8 #define ISC_HALFSIPHASH24_TAG_LENGTH 32 / 8 +#define cROUNDS 2 +#define dROUNDS 4 + +#define ROTATE64(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) + +#define HALF_ROUND64(a, b, c, d, s, t) \ + a += b; \ + c += d; \ + b = ROTATE64(b, s) ^ a; \ + d = ROTATE64(d, t) ^ c; \ + a = ROTATE64(a, 32); + +#define FULL_ROUND64(v0, v1, v2, v3) \ + HALF_ROUND64(v0, v1, v2, v3, 13, 16); \ + HALF_ROUND64(v2, v1, v0, v3, 17, 21); + +#define SIPROUND FULL_ROUND64 + +#define ROTATE32(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b)))) + +#define HALF_ROUND32(a, b, c, d, s, t) \ + a += b; \ + c += d; \ + b = ROTATE32(b, s) ^ a; \ + d = ROTATE32(d, t) ^ c; \ + a = ROTATE32(a, 16); + +#define FULL_ROUND32(v0, v1, v2, v3) \ + HALF_ROUND32(v0, v1, v2, v3, 5, 8); \ + HALF_ROUND32(v2, v1, v0, v3, 13, 7); + +#define HALFSIPROUND FULL_ROUND32 + +#define U8TO32_ONE(case_sensitive, byte) \ + (uint32_t)(case_sensitive ? byte : isc__ascii_tolower1(byte)) + +#define U8TO64_ONE(case_sensitive, byte) \ + (uint64_t)(case_sensitive ? byte : isc__ascii_tolower1(byte)) + ISC_LANG_BEGINDECLS -void +typedef struct isc_siphash24 { + uint64_t k0; + uint64_t k1; + + uint64_t v0; + uint64_t v1; + uint64_t v2; + uint64_t v3; + + uint64_t b; + + size_t inlen; +} isc_siphash24_t; + +typedef struct isc_halfsiphash24 { + uint32_t k0; + uint32_t k1; + + uint32_t v0; + uint32_t v1; + uint32_t v2; + uint32_t v3; + + uint32_t b; + + size_t inlen; +} isc_halfsiphash24_t; + +static inline void +isc_siphash24_init(isc_siphash24_t *state, const uint8_t *k) { + REQUIRE(k != NULL); + + uint64_t k0 = ISC_U8TO64_LE(k); + uint64_t k1 = ISC_U8TO64_LE(k + 8); + + *state = (isc_siphash24_t){ + .k0 = k0, + .k1 = k1, + .v0 = UINT64_C(0x736f6d6570736575) ^ k0, + .v1 = UINT64_C(0x646f72616e646f6d) ^ k1, + .v2 = UINT64_C(0x6c7967656e657261) ^ k0, + .v3 = UINT64_C(0x7465646279746573) ^ k1, + }; +} + +static inline void +isc_siphash24_one(isc_siphash24_t *restrict state, const uint64_t m) { + state->v3 ^= m; + + for (size_t i = 0; i < cROUNDS; ++i) { + SIPROUND(state->v0, state->v1, state->v2, state->v3); + } + + state->v0 ^= m; +} + +static inline void +isc_siphash24_hash(isc_siphash24_t *restrict state, const uint8_t *in, + const size_t inlen, const bool case_sensitive) { + REQUIRE(inlen == 0 || in != NULL); + + if (in == NULL || inlen == 0) { + return; + } + + size_t len = inlen; + const int right = state->inlen & 7; + + switch (right) { + case 0: + break; + case 1: + state->b |= U8TO64_ONE(case_sensitive, in[0]) << 8; + state->inlen++; + ++in; + + if (--len == 0) { + return; + } + FALLTHROUGH; + case 2: + state->b |= U8TO64_ONE(case_sensitive, in[0]) << 16; + state->inlen++; + ++in; + + if (--len == 0) { + return; + } + FALLTHROUGH; + case 3: + state->b |= U8TO64_ONE(case_sensitive, in[0]) << 24; + state->inlen++; + ++in; + + if (--len == 0) { + return; + } + FALLTHROUGH; + case 4: + state->b |= U8TO64_ONE(case_sensitive, in[0]) << 32; + state->inlen++; + ++in; + + if (--len == 0) { + return; + } + FALLTHROUGH; + case 5: + state->b |= U8TO64_ONE(case_sensitive, in[0]) << 40; + state->inlen++; + ++in; + + if (--len == 0) { + return; + } + FALLTHROUGH; + case 6: + state->b |= U8TO64_ONE(case_sensitive, in[0]) << 48; + state->inlen++; + ++in; + + if (--len == 0) { + return; + } + FALLTHROUGH; + case 7: + state->b |= U8TO64_ONE(case_sensitive, in[0]) << 56; + state->inlen++; + ++in; + + isc_siphash24_one(state, state->b); + state->b = 0; /* consumed */ + + if (--len == 0) { + return; + } + break; + default: + UNREACHABLE(); + } + + const uint8_t *end = in + len - (len % sizeof(uint64_t)); + const size_t left = len & 7; + + for (; in != end; in += 8) { + uint64_t m = case_sensitive + ? ISC_U8TO64_LE(in) + : isc_ascii_tolower8(ISC_U8TO64_LE(in)); + + isc_siphash24_one(state, m); + } + + INSIST(state->b == 0); + switch (left) { + case 7: + state->b |= U8TO64_ONE(case_sensitive, in[6]) << 48; + FALLTHROUGH; + case 6: + state->b |= U8TO64_ONE(case_sensitive, in[5]) << 40; + FALLTHROUGH; + case 5: + state->b |= U8TO64_ONE(case_sensitive, in[4]) << 32; + FALLTHROUGH; + case 4: + state->b |= U8TO64_ONE(case_sensitive, in[3]) << 24; + FALLTHROUGH; + case 3: + state->b |= U8TO64_ONE(case_sensitive, in[2]) << 16; + FALLTHROUGH; + case 2: + state->b |= U8TO64_ONE(case_sensitive, in[1]) << 8; + FALLTHROUGH; + case 1: + state->b |= U8TO64_ONE(case_sensitive, in[0]); + FALLTHROUGH; + case 0: + break; + default: + UNREACHABLE(); + } + + state->inlen += len; +} + +static inline void +isc_siphash24_finalize(isc_siphash24_t *restrict state, uint8_t *out) { + REQUIRE(out != NULL); + + uint64_t b = ((uint64_t)state->inlen) << 56 | state->b; + + isc_siphash24_one(state, b); + + state->v2 ^= 0xff; + + for (size_t i = 0; i < dROUNDS; ++i) { + SIPROUND(state->v0, state->v1, state->v2, state->v3); + } + + b = state->v0 ^ state->v1 ^ state->v2 ^ state->v3; + + ISC_U64TO8_LE(out, b); +} + +static inline void isc_siphash24(const uint8_t *key, const uint8_t *in, const size_t inlen, - bool case_sensitive, uint8_t *out); -void -isc_halfsiphash24(const uint8_t *key, const uint8_t *in, const size_t inlen, - bool case_sensitive, uint8_t *out); + bool case_sensitive, uint8_t *out) { + isc_siphash24_t state; + isc_siphash24_init(&state, key); + isc_siphash24_hash(&state, in, inlen, case_sensitive); + isc_siphash24_finalize(&state, out); +} + +static inline void +isc_halfsiphash24_init(isc_halfsiphash24_t *restrict state, const uint8_t *k) { + REQUIRE(k != NULL); + + uint32_t k0 = ISC_U8TO32_LE(k); + uint32_t k1 = ISC_U8TO32_LE(k + 4); + + *state = (isc_halfsiphash24_t){ + .k0 = k0, + .k1 = k1, + .v0 = UINT32_C(0x00000000) ^ k0, + .v1 = UINT32_C(0x00000000) ^ k1, + .v2 = UINT32_C(0x6c796765) ^ k0, + .v3 = UINT32_C(0x74656462) ^ k1, + }; +} + +static inline void +isc_halfsiphash24_one(isc_halfsiphash24_t *restrict state, const uint32_t m) { + state->v3 ^= m; + + for (size_t i = 0; i < cROUNDS; ++i) { + HALFSIPROUND(state->v0, state->v1, state->v2, state->v3); + } + + state->v0 ^= m; +} + +static inline void +isc_halfsiphash24_hash(isc_halfsiphash24_t *restrict state, const uint8_t *in, + const size_t inlen, const bool case_sensitive) { + REQUIRE(inlen == 0 || in != NULL); + + if (in == NULL || inlen == 0) { + return; + } + + size_t len = inlen; + const int right = state->inlen & 3; + + switch (right) { + case 0: + break; + case 1: + state->b |= U8TO32_ONE(case_sensitive, in[0]) << 8; + state->inlen++; + ++in; + + if (--len == 0) { + return; + } + FALLTHROUGH; + case 2: + state->b |= U8TO32_ONE(case_sensitive, in[0]) << 16; + state->inlen++; + ++in; + + if (--len == 0) { + return; + } + FALLTHROUGH; + case 3: + state->b |= U8TO32_ONE(case_sensitive, in[0]) << 24; + state->inlen++; + ++in; + + isc_halfsiphash24_one(state, state->b); + state->b = 0; /* consumed */ + + if (--len == 0) { + return; + } + break; + default: + UNREACHABLE(); + } + + const uint8_t *end = in + len - (len % sizeof(uint32_t)); + const int left = len & 3; + + for (; in != end; in += 4) { + uint32_t m = case_sensitive + ? ISC_U8TO32_LE(in) + : isc_ascii_tolower4(ISC_U8TO32_LE(in)); + + isc_halfsiphash24_one(state, m); + } + + INSIST(state->b == 0); + switch (left) { + case 3: + state->b |= U8TO32_ONE(case_sensitive, in[2]) << 16; + FALLTHROUGH; + case 2: + state->b |= U8TO32_ONE(case_sensitive, in[1]) << 8; + FALLTHROUGH; + case 1: + state->b |= U8TO32_ONE(case_sensitive, in[0]); + FALLTHROUGH; + case 0: + break; + default: + UNREACHABLE(); + } + + state->inlen += len; +} + +static inline void +isc_halfsiphash24_finalize(isc_halfsiphash24_t *restrict state, uint8_t *out) { + REQUIRE(out != NULL); + + uint32_t b = ((uint32_t)state->inlen) << 24 | state->b; + + isc_halfsiphash24_one(state, b); + + state->v2 ^= 0xff; + + for (size_t i = 0; i < dROUNDS; ++i) { + HALFSIPROUND(state->v0, state->v1, state->v2, state->v3); + } + + b = state->v1 ^ state->v3; + ISC_U32TO8_LE(out, b); +} + +static inline void +isc_halfsiphash24(const uint8_t *k, const uint8_t *in, const size_t inlen, + bool case_sensitive, uint8_t *out) { + isc_halfsiphash24_t state; + + isc_halfsiphash24_init(&state, k); + isc_halfsiphash24_hash(&state, in, inlen, case_sensitive); + isc_halfsiphash24_finalize(&state, out); +} ISC_LANG_ENDDECLS diff --git a/lib/isc/siphash.c b/lib/isc/siphash.c deleted file mode 100644 index ce24a6229f..0000000000 --- a/lib/isc/siphash.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright (C) Internet Systems Consortium, Inc. ("ISC") - * - * SPDX-License-Identifier: MPL-2.0 - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, you can obtain one at https://mozilla.org/MPL/2.0/. - * - * See the COPYRIGHT file distributed with this work for additional - * information regarding copyright ownership. - */ - -#include -#include -#include - -#include -#include -#include -#include - -/* - * The implementation is based on SipHash reference C implementation by - * - * Copyright (c) 2012-2016 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 . - */ - -#define cROUNDS 2 -#define dROUNDS 4 - -#define ROTATE64(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) - -#define HALF_ROUND64(a, b, c, d, s, t) \ - a += b; \ - c += d; \ - b = ROTATE64(b, s) ^ a; \ - d = ROTATE64(d, t) ^ c; \ - a = ROTATE64(a, 32); - -#define FULL_ROUND64(v0, v1, v2, v3) \ - HALF_ROUND64(v0, v1, v2, v3, 13, 16); \ - HALF_ROUND64(v2, v1, v0, v3, 17, 21); - -#define SIPROUND FULL_ROUND64 - -#define ROTATE32(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b)))) - -#define HALF_ROUND32(a, b, c, d, s, t) \ - a += b; \ - c += d; \ - b = ROTATE32(b, s) ^ a; \ - d = ROTATE32(d, t) ^ c; \ - a = ROTATE32(a, 16); - -#define FULL_ROUND32(v0, v1, v2, v3) \ - HALF_ROUND32(v0, v1, v2, v3, 5, 8); \ - HALF_ROUND32(v2, v1, v0, v3, 13, 7); - -#define HALFSIPROUND FULL_ROUND32 - -#define U8TO32_ONE(case_sensitive, byte) \ - (uint32_t)(case_sensitive ? byte : isc__ascii_tolower1(byte)) - -#define U8TO64_ONE(case_sensitive, byte) \ - (uint64_t)(case_sensitive ? byte : isc__ascii_tolower1(byte)) - -void -isc_siphash24(const uint8_t *k, const uint8_t *in, const size_t inlen, - bool case_sensitive, uint8_t *out) { - REQUIRE(k != NULL); - REQUIRE(out != NULL); - REQUIRE(inlen == 0 || in != NULL); - - uint64_t k0 = ISC_U8TO64_LE(k); - uint64_t k1 = ISC_U8TO64_LE(k + 8); - - uint64_t v0 = UINT64_C(0x736f6d6570736575) ^ k0; - uint64_t v1 = UINT64_C(0x646f72616e646f6d) ^ k1; - uint64_t v2 = UINT64_C(0x6c7967656e657261) ^ k0; - uint64_t v3 = UINT64_C(0x7465646279746573) ^ k1; - - uint64_t b = ((uint64_t)inlen) << 56; - - if (in != NULL && inlen != 0) { - const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); - const size_t left = inlen & 7; - - for (; in != end; in += 8) { - uint64_t m = - case_sensitive - ? ISC_U8TO64_LE(in) - : isc_ascii_tolower8(ISC_U8TO64_LE(in)); - - v3 ^= m; - - for (size_t i = 0; i < cROUNDS; ++i) { - SIPROUND(v0, v1, v2, v3); - } - - v0 ^= m; - } - - switch (left) { - case 7: - b |= U8TO64_ONE(case_sensitive, in[6]) << 48; - FALLTHROUGH; - case 6: - b |= U8TO64_ONE(case_sensitive, in[5]) << 40; - FALLTHROUGH; - case 5: - b |= U8TO64_ONE(case_sensitive, in[4]) << 32; - FALLTHROUGH; - case 4: - b |= U8TO64_ONE(case_sensitive, in[3]) << 24; - FALLTHROUGH; - case 3: - b |= U8TO64_ONE(case_sensitive, in[2]) << 16; - FALLTHROUGH; - case 2: - b |= U8TO64_ONE(case_sensitive, in[1]) << 8; - FALLTHROUGH; - case 1: - b |= U8TO64_ONE(case_sensitive, in[0]); - FALLTHROUGH; - case 0: - break; - default: - UNREACHABLE(); - } - } - - v3 ^= b; - - for (size_t i = 0; i < cROUNDS; ++i) { - SIPROUND(v0, v1, v2, v3); - } - - v0 ^= b; - - v2 ^= 0xff; - - for (size_t i = 0; i < dROUNDS; ++i) { - SIPROUND(v0, v1, v2, v3); - } - - b = v0 ^ v1 ^ v2 ^ v3; - - ISC_U64TO8_LE(out, b); -} - -void -isc_halfsiphash24(const uint8_t *k, const uint8_t *in, const size_t inlen, - bool case_sensitive, uint8_t *out) { - REQUIRE(k != NULL); - REQUIRE(out != NULL); - REQUIRE(inlen == 0 || in != NULL); - - uint32_t k0 = ISC_U8TO32_LE(k); - uint32_t k1 = ISC_U8TO32_LE(k + 4); - - uint32_t v0 = UINT32_C(0x00000000) ^ k0; - uint32_t v1 = UINT32_C(0x00000000) ^ k1; - uint32_t v2 = UINT32_C(0x6c796765) ^ k0; - uint32_t v3 = UINT32_C(0x74656462) ^ k1; - - uint32_t b = ((uint32_t)inlen) << 24; - - if (in != NULL && inlen != 0) { - const uint8_t *end = in + inlen - (inlen % sizeof(uint32_t)); - const int left = inlen & 3; - - for (; in != end; in += 4) { - uint32_t m = - case_sensitive - ? ISC_U8TO32_LE(in) - : isc_ascii_tolower4(ISC_U8TO32_LE(in)); - - v3 ^= m; - - for (size_t i = 0; i < cROUNDS; ++i) { - HALFSIPROUND(v0, v1, v2, v3); - } - - v0 ^= m; - } - - switch (left) { - case 3: - b |= U8TO32_ONE(case_sensitive, in[2]) << 16; - FALLTHROUGH; - case 2: - b |= U8TO32_ONE(case_sensitive, in[1]) << 8; - FALLTHROUGH; - case 1: - b |= U8TO32_ONE(case_sensitive, in[0]); - FALLTHROUGH; - case 0: - break; - default: - UNREACHABLE(); - } - } - - v3 ^= b; - - for (size_t i = 0; i < cROUNDS; ++i) { - HALFSIPROUND(v0, v1, v2, v3); - } - - v0 ^= b; - - v2 ^= 0xff; - - for (size_t i = 0; i < dROUNDS; ++i) { - HALFSIPROUND(v0, v1, v2, v3); - } - - b = v1 ^ v3; - ISC_U32TO8_LE(out, b); -} diff --git a/tests/isc/siphash_test.c b/tests/isc/siphash_test.c index 6fca930306..6970ca98a7 100644 --- a/tests/isc/siphash_test.c +++ b/tests/isc/siphash_test.c @@ -24,8 +24,6 @@ #include -#include "siphash.c" - #include const uint8_t vectors_sip64[64][8] = { @@ -131,8 +129,6 @@ const uint8_t vectors_hsip32[64][4] = { }; ISC_RUN_TEST_IMPL(isc_siphash24) { - UNUSED(state); - uint8_t in[64], out[8], key[16]; for (size_t i = 0; i < ARRAY_SIZE(key); i++) { key[i] = i; @@ -143,11 +139,20 @@ ISC_RUN_TEST_IMPL(isc_siphash24) { isc_siphash24(key, in, i, true, out); assert_memory_equal(out, vectors_sip64[i], 8); } + + for (size_t i = 0; i < ARRAY_SIZE(in); i++) { + for (size_t j = 0; j < i; j++) { + isc_siphash24_t s; + isc_siphash24_init(&s, key); + isc_siphash24_hash(&s, in, j, true); + isc_siphash24_hash(&s, in + j, i - j, true); + isc_siphash24_finalize(&s, out); + assert_memory_equal(out, vectors_sip64[i], 8); + } + } } ISC_RUN_TEST_IMPL(isc_halfsiphash24) { - UNUSED(state); - uint8_t in[64], out[4], key[16]; for (size_t i = 0; i < ARRAY_SIZE(key); i++) { key[i] = i; @@ -158,6 +163,17 @@ ISC_RUN_TEST_IMPL(isc_halfsiphash24) { isc_halfsiphash24(key, in, i, true, out); assert_memory_equal(out, vectors_hsip32[i], 4); } + + for (size_t i = 0; i < ARRAY_SIZE(in); i++) { + for (size_t j = 0; j < i; j++) { + isc_halfsiphash24_t s; + isc_halfsiphash24_init(&s, key); + isc_halfsiphash24_hash(&s, in, j, true); + isc_halfsiphash24_hash(&s, in + j, i - j, true); + isc_halfsiphash24_finalize(&s, out); + assert_memory_equal(out, vectors_hsip32[i], 4); + } + } } ISC_TEST_LIST_START From 6ac286d4a36e8aa8be94aac8d67cc5035b12f0e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Fri, 8 Sep 2023 17:48:45 +0200 Subject: [PATCH 2/3] Implement incremental version of isc_hash32 and isc_hash64 Add support for incremental hashing to the isc_hash unit, both 32-bit and 64-bit incremental hashing is now supported. This is commit second in series adding incremental hashing to libisc. --- lib/isc/hash.c | 77 ++++++++++++++++++-------------------- lib/isc/include/isc/hash.h | 36 +++++++++++++++++- lib/isc/lib.c | 2 + 3 files changed, 73 insertions(+), 42 deletions(-) diff --git a/lib/isc/hash.c b/lib/isc/hash.c index 1a28a216a7..2783a37e41 100644 --- a/lib/isc/hash.c +++ b/lib/isc/hash.c @@ -18,7 +18,6 @@ #include #include #include /* IWYU pragma: keep */ -#include #include #include #include @@ -27,34 +26,24 @@ #include static uint8_t isc_hash_key[16]; -static uint8_t isc_hash32_key[8]; -static bool hash_initialized = false; -static isc_once_t isc_hash_once = ISC_ONCE_INIT; -static void -isc_hash_initialize(void) { +void +isc__hash_initialize(void) { /* * Set a constant key to help in problem reproduction should * fuzzing find a crash or a hang. */ - uint64_t key[2] = { 0, 1 }; + uint8_t key[16] = { 1 }; #if !FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION isc_entropy_get(key, sizeof(key)); #endif /* if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ + STATIC_ASSERT(sizeof(key) >= sizeof(isc_hash_key), + "sizeof(key) < sizeof(isc_hash_key)"); memmove(isc_hash_key, key, sizeof(isc_hash_key)); -#if !FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - isc_entropy_get(key, sizeof(key)); -#endif /* if FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */ - memmove(isc_hash32_key, key, sizeof(isc_hash32_key)); - hash_initialized = true; } const void * isc_hash_get_initializer(void) { - if (!hash_initialized) { - isc_once_do(&isc_hash_once, isc_hash_initialize); - } - return (isc_hash_key); } @@ -62,41 +51,49 @@ void isc_hash_set_initializer(const void *initializer) { REQUIRE(initializer != NULL); - /* - * Ensure that isc_hash_initialize() is not called after - * isc_hash_set_initializer() is called. - */ - if (!hash_initialized) { - isc_once_do(&isc_hash_once, isc_hash_initialize); - } - memmove(isc_hash_key, initializer, sizeof(isc_hash_key)); } -uint64_t -isc_hash64(const void *data, const size_t length, const bool case_sensitive) { - uint64_t hval; +void +isc_hash32_init(isc_hash32_t *restrict state) { + isc_halfsiphash24_init(state, isc_hash_key); +} +void +isc_hash32_hash(isc_hash32_t *restrict state, const void *data, + const size_t length, const bool case_sensitive) { REQUIRE(length == 0 || data != NULL); - isc_once_do(&isc_hash_once, isc_hash_initialize); - - isc_siphash24(isc_hash_key, data, length, case_sensitive, - (uint8_t *)&hval); - - return (hval); + isc_halfsiphash24_hash(state, data, length, case_sensitive); } uint32_t -isc_hash32(const void *data, const size_t length, const bool case_sensitive) { +isc_hash32_finalize(isc_hash32_t *restrict state) { uint32_t hval; - REQUIRE(length == 0 || data != NULL); - - isc_once_do(&isc_hash_once, isc_hash_initialize); - - isc_halfsiphash24(isc_hash_key, data, length, case_sensitive, - (uint8_t *)&hval); + isc_halfsiphash24_finalize(state, (uint8_t *)&hval); + + return (hval); +} + +void +isc_hash64_init(isc_hash64_t *restrict state) { + isc_siphash24_init(state, isc_hash_key); +} + +void +isc_hash64_hash(isc_hash64_t *restrict state, const void *data, + const size_t length, const bool case_sensitive) { + REQUIRE(length == 0 || data != NULL); + + isc_siphash24_hash(state, data, length, case_sensitive); +} + +uint64_t +isc_hash64_finalize(isc_hash64_t *restrict state) { + uint64_t hval; + + isc_siphash24_finalize(state, (uint8_t *)&hval); return (hval); } diff --git a/lib/isc/include/isc/hash.h b/lib/isc/include/isc/hash.h index c3926157d0..bac9d9f7b8 100644 --- a/lib/isc/include/isc/hash.h +++ b/lib/isc/include/isc/hash.h @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -26,11 +27,17 @@ #define ISC_HASH_MIN_BITS 2U #define ISC_HASH_MAX_BITS 32U +typedef struct isc_halfsiphash24 isc_hash32_t; +typedef struct isc_siphash24 isc_hash64_t; + /*** *** Functions ***/ ISC_LANG_BEGINDECLS +void +isc__hash_initialize(void); + const void * isc_hash_get_initializer(void); @@ -39,10 +46,35 @@ isc_hash_set_initializer(const void *initializer); #define isc_hash_function isc_hash64 +void +isc_hash32_init(isc_hash32_t *restrict state); +void +isc_hash32_hash(isc_hash32_t *restrict state, const void *data, + const size_t length, const bool case_sensitive); uint32_t -isc_hash32(const void *data, const size_t length, const bool case_sensitive); +isc_hash32_finalize(isc_hash32_t *restrict state); +static inline uint32_t +isc_hash32(const void *data, const size_t length, const bool case_sensitive) { + isc_hash32_t state; + isc_hash32_init(&state); + isc_hash32_hash(&state, data, length, case_sensitive); + return (isc_hash32_finalize(&state)); +} + +void +isc_hash64_init(isc_hash64_t *restrict state); +void +isc_hash64_hash(isc_hash64_t *restrict state, const void *data, + const size_t length, const bool case_sensitive); uint64_t -isc_hash64(const void *data, const size_t length, const bool case_sensitive); +isc_hash64_finalize(isc_hash64_t *restrict state); +static inline uint64_t +isc_hash64(const void *data, const size_t length, const bool case_sensitive) { + isc_hash64_t state; + isc_hash64_init(&state); + isc_hash64_hash(&state, data, length, case_sensitive); + return (isc_hash64_finalize(&state)); +} /*!< * \brief Calculate a hash over data. * diff --git a/lib/isc/lib.c b/lib/isc/lib.c index aba5dc1db8..4fd65e6020 100644 --- a/lib/isc/lib.c +++ b/lib/isc/lib.c @@ -13,6 +13,7 @@ /*! \file */ +#include #include #include #include @@ -50,6 +51,7 @@ isc__initialize(void) { isc__uv_initialize(); isc__xml_initialize(); isc__md_initialize(); + isc__hash_initialize(); isc__iterated_hash_initialize(); (void)isc_os_ncpus(); rcu_register_thread(); From 0f3155e0ef157cdb191d1bad29c6a326a7dc36f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Fri, 8 Sep 2023 17:56:23 +0200 Subject: [PATCH 3/3] Add CHANGES note for [GL #4306] --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index be320c0f61..66981c5292 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +6247. [func] Implement incremental hashing in both isc_siphash + and isc_hash units. [GL #4306] + 6246. [placeholder] 6245. [placeholder]