#include <unistd.h>
#include <string.h>
-#include <openssl/opensslv.h>
-
#include <isc/endian.h>
#include <isc/util.h>
#include <isc/siphash.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 ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) )
-#define HALF_ROUND(a, b, c, d, s, t) \
- a += b; c += d; \
- b = ROTATE(b, s) ^ a; \
- d = ROTATE(d, t) ^ c; \
+#define HALF_ROUND(a, b, c, d, s, t) \
+ a += b; c += d; \
+ b = ROTATE(b, s) ^ a; \
+ d = ROTATE(d, t) ^ c; \
a = ROTATE(a, 32);
-#define FULL_ROUND(v0, v1, v2, v3) \
- HALF_ROUND(v0, v1, v2, v3, 13, 16); \
+#define FULL_ROUND(v0, v1, v2, v3) \
+ HALF_ROUND(v0, v1, v2, v3, 13, 16); \
HALF_ROUND(v2, v1, v0, v3, 17, 21);
-#define DOUBLE_ROUND(v0, v1, v2, v3) \
+#define DOUBLE_ROUND(v0, v1, v2, v3) \
FULL_ROUND(v0, v1, v2, v3) \
FULL_ROUND(v0, v1, v2, v3)
#define SIPROUND FULL_ROUND
+#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))
+
void
-isc_siphash24(const uint8_t *k, const uint8_t *in, size_t inlen, uint8_t *out)
+isc_siphash24(const uint8_t *k,
+ const uint8_t *in, const size_t inlen,
+ uint8_t *out)
{
- const uint64_t *key = (const uint64_t *)k;
- uint64_t k0 = le64toh(key[0]);
- uint64_t k1 = le64toh(key[1]);
+ REQUIRE(k != NULL);
+ REQUIRE(out != NULL);
+
+ uint64_t k0 = U8TO64_LE(k);
+ uint64_t k1 = U8TO64_LE(k + 8);
uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
uint64_t v3 = 0x7465646279746573ULL ^ k1;
- size_t left = inlen;
-
uint64_t b = ((uint64_t)inlen) << 56;
- const uint64_t *inbuf = (const uint64_t *)in;
- while (left >= 8) {
- uint64_t m = le64toh(*inbuf);
+ const uint8_t *end = 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;
- SIPROUND(v0, v1, v2, v3);
- SIPROUND(v0, v1, v2, v3);
+ for (size_t i = 0; i < cROUNDS; ++i) {
+ SIPROUND(v0, v1, v2, v3);
+ }
v0 ^= m;
-
- inbuf++; left -= 8;
}
- const uint8_t *end = in + (inlen - left);
-
switch (left) {
case 7:
- b |= ((uint64_t)end[6]) << 48;
+ b |= ((uint64_t)in[6]) << 48;
/* FALLTHROUGH */
case 6:
- b |= ((uint64_t)end[5]) << 40;
+ b |= ((uint64_t)in[5]) << 40;
/* FALLTHROUGH */
case 5:
- b |= ((uint64_t)end[4]) << 32;
+ b |= ((uint64_t)in[4]) << 32;
/* FALLTHROUGH */
case 4:
- b |= ((uint64_t)end[3]) << 24;
+ b |= ((uint64_t)in[3]) << 24;
/* FALLTHROUGH */
case 3:
- b |= ((uint64_t)end[2]) << 16;
+ b |= ((uint64_t)in[2]) << 16;
/* FALLTHROUGH */
case 2:
- b |= ((uint64_t)end[1]) << 8;
+ b |= ((uint64_t)in[1]) << 8;
/* FALLTHROUGH */
case 1:
- b |= ((uint64_t)end[0]);
+ b |= ((uint64_t)in[0]);
/* FALLTHROUGH */
case 0:
break;
v3 ^= b;
- SIPROUND(v0, v1, v2, v3);
- SIPROUND(v0, v1, v2, v3);
+ for (size_t i = 0; i < cROUNDS; ++i) {
+ SIPROUND(v0, v1, v2, v3);
+ }
v0 ^= b;
v2 ^= 0xff;
- SIPROUND(v0, v1, v2, v3);
- SIPROUND(v0, v1, v2, v3);
- SIPROUND(v0, v1, v2, v3);
- SIPROUND(v0, v1, v2, v3);
+ for (size_t i = 0; i < dROUNDS; ++i) {
+ SIPROUND(v0, v1, v2, v3);
+ }
b = v0 ^ v1 ^ v2 ^ v3;
- uint64_t *outbuf = (uint64_t *)out;
- *outbuf = htole64(b);
+ U64TO8_LE(out, b);
}
#include <stddef.h>
#include <setjmp.h>
+#include <sched.h>
#include <stdlib.h>
#define UNIT_TESTING
#include <isc/siphash.h>
+void
+native_isc_siphash24(const uint8_t *,
+ const uint8_t *, const size_t,
+ uint8_t *);
+
+#if HAVE_OPENSSL_SIPHASH
+
+void
+openssl_isc_siphash24(const uint8_t *,
+ const uint8_t *, const size_t,
+ uint8_t *);
+
+#undef HAVE_OPENSSL_SIPHASH
+#define isc_siphash24 native_isc_siphash24
#include "../siphash.c"
+#undef isc_siphash24
+
+#define HAVE_OPENSSL_SIPHASH 1
+#define isc_siphash24 openssl_isc_siphash24
+#include "../siphash.c"
+#undef isc_siphash24
+
+#else
+
+#define isc_siphash24 native_isc_siphash24
+#include "../siphash.c"
+#undef isc_siphash24
+
+#endif
const uint8_t vectors[64][8] = {
{ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, },
{ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, },
};
+#if HAVE_OPENSSL_SIPHASH
+static void
+openssl_isc_siphash24_test(void **state) {
+ UNUSED(state);
+
+ uint8_t in[64], out[8], key[16];
+ for (int i = 0; i < 16; i++) {
+ key[i] = i;
+ }
+
+ for (int i = 0; i < 64; i++) {
+ in[i] = i;
+ openssl_isc_siphash24(key, in, i, out);
+ assert_memory_equal(out, vectors[i], 8);
+ }
+}
+#endif
+
static void
-isc_siphash24_test(void **state) {
+native_isc_siphash24_test(void **state) {
UNUSED(state);
uint8_t in[64], out[8], key[16];
for (int i = 0; i < 64; i++) {
in[i] = i;
- isc_siphash24(key, in, i, out);
+ native_isc_siphash24(key, in, i, out);
assert_memory_equal(out, vectors[i], 8);
}
}
int main(void) {
const struct CMUnitTest tests[] = {
- cmocka_unit_test(isc_siphash24_test),
+#if HAVE_OPENSSL_SIPHASH
+ cmocka_unit_test(openssl_isc_siphash24_test),
+#endif
+ cmocka_unit_test(native_isc_siphash24_test),
};
return (cmocka_run_group_tests(tests, NULL, NULL));