diff options
Diffstat (limited to 'lib/isc/siphash.c')
-rw-r--r-- | lib/isc/siphash.c | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/lib/isc/siphash.c b/lib/isc/siphash.c new file mode 100644 index 0000000..a6e60cf --- /dev/null +++ b/lib/isc/siphash.c @@ -0,0 +1,235 @@ +/* + * 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/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 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 U8TO32_LE(p) \ + (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 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)) + +void +isc_siphash24(const uint8_t *k, const uint8_t *in, const size_t inlen, + uint8_t *out) { + REQUIRE(k != NULL); + REQUIRE(out != NULL); + REQUIRE(inlen == 0 || in != NULL); + + uint64_t k0 = U8TO64_LE(k); + uint64_t k1 = 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; + + const uint8_t *end = (in == NULL) + ? NULL + : in + inlen - (inlen % sizeof(uint64_t)); + const size_t left = inlen & 7; + + for (; in != end; in += 8) { + uint64_t m = 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 |= ((uint64_t)in[6]) << 48; + FALLTHROUGH; + case 6: + b |= ((uint64_t)in[5]) << 40; + FALLTHROUGH; + case 5: + b |= ((uint64_t)in[4]) << 32; + FALLTHROUGH; + case 4: + b |= ((uint64_t)in[3]) << 24; + FALLTHROUGH; + case 3: + b |= ((uint64_t)in[2]) << 16; + FALLTHROUGH; + case 2: + b |= ((uint64_t)in[1]) << 8; + FALLTHROUGH; + case 1: + b |= ((uint64_t)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; + + U64TO8_LE(out, b); +} + +void +isc_halfsiphash24(const uint8_t *k, const uint8_t *in, const size_t inlen, + uint8_t *out) { + REQUIRE(k != NULL); + REQUIRE(out != NULL); + REQUIRE(inlen == 0 || in != NULL); + + uint32_t k0 = U8TO32_LE(k); + uint32_t k1 = 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; + + const uint8_t *end = (in == NULL) + ? NULL + : in + inlen - (inlen % sizeof(uint32_t)); + const int left = inlen & 3; + + for (; in != end; in += 4) { + uint32_t m = 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 |= ((uint32_t)in[2]) << 16; + FALLTHROUGH; + case 2: + b |= ((uint32_t)in[1]) << 8; + FALLTHROUGH; + case 1: + b |= ((uint32_t)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; + U32TO8_LE(out, b); +} |