mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
Merge branch '4306-add-incremental-isc_siphash' into 'main'
Implement incremental version of SipHash 2-4 and HalfSipHash 2-4 Closes #4306 See merge request isc-projects/bind9!8288
This commit is contained in:
commit
8805d989ec
8 changed files with 500 additions and 283 deletions
3
CHANGES
3
CHANGES
|
|
@ -1,3 +1,6 @@
|
|||
6247. [func] Implement incremental hashing in both isc_siphash
|
||||
and isc_hash units. [GL #4306]
|
||||
|
||||
6246. [placeholder]
|
||||
|
||||
6245. [placeholder]
|
||||
|
|
|
|||
|
|
@ -182,7 +182,6 @@ libisc_la_SOURCES = \
|
|||
safe.c \
|
||||
serial.c \
|
||||
signal.c \
|
||||
siphash.c \
|
||||
sockaddr.c \
|
||||
stats.c \
|
||||
stdio.c \
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
#include <isc/ascii.h>
|
||||
#include <isc/entropy.h>
|
||||
#include <isc/hash.h> /* IWYU pragma: keep */
|
||||
#include <isc/once.h>
|
||||
#include <isc/random.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/siphash.h>
|
||||
|
|
@ -27,34 +26,24 @@
|
|||
#include <isc/util.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <isc/assertions.h>
|
||||
#include <isc/lang.h>
|
||||
#include <isc/siphash.h>
|
||||
#include <isc/types.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* <jeanphilippe.aumasson@gmail.com> Copyright (c) 2012-2014 Daniel J. Bernstein
|
||||
* <djb@cr.yp.to>
|
||||
*
|
||||
* 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 <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
/*! \file isc/siphash.h */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <isc/ascii.h>
|
||||
#include <isc/endian.h>
|
||||
#include <isc/lang.h>
|
||||
#include <isc/types.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#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
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
/*! \file */
|
||||
|
||||
#include <isc/hash.h>
|
||||
#include <isc/iterated_hash.h>
|
||||
#include <isc/md.h>
|
||||
#include <isc/mem.h>
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <isc/ascii.h>
|
||||
#include <isc/endian.h>
|
||||
#include <isc/siphash.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
/*
|
||||
* The implementation is based on SipHash reference C implementation by
|
||||
*
|
||||
* Copyright (c) 2012-2016 Jean-Philippe Aumasson
|
||||
* <jeanphilippe.aumasson@gmail.com> Copyright (c) 2012-2014 Daniel J. Bernstein
|
||||
* <djb@cr.yp.to>
|
||||
*
|
||||
* 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 <http://creativecommons.org/publicdomain/zero/1.0/>.
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
@ -24,8 +24,6 @@
|
|||
|
||||
#include <isc/siphash.h>
|
||||
|
||||
#include "siphash.c"
|
||||
|
||||
#include <tests/isc.h>
|
||||
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in a new issue