Blame lib/isc/siphash.c

Packit Service ae04f2
/*
Packit Service ae04f2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
Packit Service ae04f2
 *
Packit Service ae04f2
 * This Source Code Form is subject to the terms of the Mozilla Public
Packit Service ae04f2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit Service ae04f2
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
Packit Service ae04f2
 *
Packit Service ae04f2
 * See the COPYRIGHT file distributed with this work for additional
Packit Service ae04f2
 * information regarding copyright ownership.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
   siphash() function is SipHash reference C implementation
Packit Service ae04f2
Packit Service ae04f2
   Copyright (c) 2012-2016 Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
Packit Service ae04f2
   Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
Packit Service ae04f2
Packit Service ae04f2
   To the extent possible under law, the author(s) have dedicated all copyright
Packit Service ae04f2
   and related and neighboring rights to this software to the public domain
Packit Service ae04f2
   worldwide. This software is distributed without any warranty.
Packit Service ae04f2
Packit Service ae04f2
   You should have received a copy of the CC0 Public Domain Dedication along
Packit Service ae04f2
   with this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
/*! \file isc/siphash.c */
Packit Service ae04f2
Packit Service ae04f2
#include <config.h>
Packit Service ae04f2
Packit Service ae04f2
#include <inttypes.h>
Packit Service ae04f2
#include <unistd.h>
Packit Service ae04f2
#include <string.h>
Packit Service ae04f2
Packit Service ae04f2
#include <isc/endian.h>
Packit Service ae04f2
#include <isc/util.h>
Packit Service ae04f2
#include <isc/siphash.h>
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * The implementation is based on SipHash reference C implementation by
Packit Service ae04f2
 *
Packit Service ae04f2
 * Copyright (c) 2012-2016 Jean-Philippe Aumasson <jeanphilippe.aumasson@gmail.com>
Packit Service ae04f2
 * Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
Packit Service ae04f2
 *
Packit Service ae04f2
 * To the extent possible under law, the author(s) have dedicated all copyright
Packit Service ae04f2
 * and related and neighboring rights to this software to the public domain
Packit Service ae04f2
 * worldwide. This software is distributed without any warranty.  You should
Packit Service ae04f2
 * have received a copy of the CC0 Public Domain Dedication along with this
Packit Service ae04f2
 * software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
#define cROUNDS 2
Packit Service ae04f2
#define dROUNDS 4
Packit Service ae04f2
Packit Service ae04f2
#define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) )
Packit Service ae04f2
Packit Service ae04f2
#define HALF_ROUND(a, b, c, d, s, t)			\
Packit Service ae04f2
	a += b; c += d;					\
Packit Service ae04f2
	b = ROTATE(b, s) ^ a;				\
Packit Service ae04f2
	d = ROTATE(d, t) ^ c;				\
Packit Service ae04f2
	a = ROTATE(a, 32);
Packit Service ae04f2
Packit Service ae04f2
#define FULL_ROUND(v0, v1, v2, v3)			\
Packit Service ae04f2
	HALF_ROUND(v0, v1, v2, v3, 13, 16);		\
Packit Service ae04f2
	HALF_ROUND(v2, v1, v0, v3, 17, 21);
Packit Service ae04f2
Packit Service ae04f2
#define DOUBLE_ROUND(v0, v1, v2, v3)			\
Packit Service ae04f2
	FULL_ROUND(v0, v1, v2, v3)			\
Packit Service ae04f2
	FULL_ROUND(v0, v1, v2, v3)
Packit Service ae04f2
Packit Service ae04f2
#define SIPROUND FULL_ROUND
Packit Service ae04f2
Packit Service ae04f2
#define U32TO8_LE(p, v)					\
Packit Service ae04f2
	(p)[0] = (uint8_t)((v));			\
Packit Service ae04f2
	(p)[1] = (uint8_t)((v) >> 8);			\
Packit Service ae04f2
	(p)[2] = (uint8_t)((v) >> 16);			\
Packit Service ae04f2
	(p)[3] = (uint8_t)((v) >> 24);
Packit Service ae04f2
Packit Service ae04f2
#define U64TO8_LE(p, v)					\
Packit Service ae04f2
	U32TO8_LE((p), (uint32_t)((v)));		\
Packit Service ae04f2
	U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
Packit Service ae04f2
Packit Service ae04f2
#define U8TO64_LE(p)							\
Packit Service ae04f2
	(((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) |		\
Packit Service ae04f2
	 ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) |	\
Packit Service ae04f2
	 ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) |	\
Packit Service ae04f2
	 ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
Packit Service ae04f2
Packit Service ae04f2
void
Packit Service ae04f2
isc_siphash24(const uint8_t *k,
Packit Service ae04f2
	      const uint8_t *in, const size_t inlen,
Packit Service ae04f2
	      uint8_t *out)
Packit Service ae04f2
{
Packit Service ae04f2
	REQUIRE(k != NULL);
Packit Service ae04f2
	REQUIRE(out != NULL);
Packit Service ae04f2
Packit Service ae04f2
	uint64_t k0 = U8TO64_LE(k);
Packit Service ae04f2
	uint64_t k1 = U8TO64_LE(k + 8);
Packit Service ae04f2
Packit Service ae04f2
	uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
Packit Service ae04f2
	uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
Packit Service ae04f2
	uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
Packit Service ae04f2
	uint64_t v3 = 0x7465646279746573ULL ^ k1;
Packit Service ae04f2
Packit Service ae04f2
	uint64_t b = ((uint64_t)inlen) << 56;
Packit Service ae04f2
Packit Service ae04f2
	const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t));
Packit Service ae04f2
	const size_t left = inlen & 7;
Packit Service ae04f2
Packit Service ae04f2
	for (; in != end; in += 8) {
Packit Service ae04f2
		uint64_t m = U8TO64_LE(in);
Packit Service ae04f2
Packit Service ae04f2
		v3 ^= m;
Packit Service ae04f2
Packit Service ae04f2
		for (size_t i = 0; i < cROUNDS; ++i) {
Packit Service ae04f2
			SIPROUND(v0, v1, v2, v3);
Packit Service ae04f2
		}
Packit Service ae04f2
Packit Service ae04f2
		v0 ^= m;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	switch (left) {
Packit Service ae04f2
	case 7:
Packit Service ae04f2
		b |= ((uint64_t)in[6]) << 48;
Packit Service ae04f2
		/* FALLTHROUGH */
Packit Service ae04f2
	case 6:
Packit Service ae04f2
		b |= ((uint64_t)in[5]) << 40;
Packit Service ae04f2
		/* FALLTHROUGH */
Packit Service ae04f2
	case 5:
Packit Service ae04f2
		b |= ((uint64_t)in[4]) << 32;
Packit Service ae04f2
		/* FALLTHROUGH */
Packit Service ae04f2
	case 4:
Packit Service ae04f2
		b |= ((uint64_t)in[3]) << 24;
Packit Service ae04f2
		/* FALLTHROUGH */
Packit Service ae04f2
	case 3:
Packit Service ae04f2
		b |= ((uint64_t)in[2]) << 16;
Packit Service ae04f2
		/* FALLTHROUGH */
Packit Service ae04f2
	case 2:
Packit Service ae04f2
		b |= ((uint64_t)in[1]) << 8;
Packit Service ae04f2
		/* FALLTHROUGH */
Packit Service ae04f2
	case 1:
Packit Service ae04f2
		b |= ((uint64_t)in[0]);
Packit Service ae04f2
		/* FALLTHROUGH */
Packit Service ae04f2
	case 0:
Packit Service ae04f2
		break;
Packit Service ae04f2
	default:
Packit Service ae04f2
		INSIST(0);
Packit Service ae04f2
		ISC_UNREACHABLE();
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	v3 ^= b;
Packit Service ae04f2
Packit Service ae04f2
	for (size_t i = 0; i < cROUNDS; ++i) {
Packit Service ae04f2
		SIPROUND(v0, v1, v2, v3);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	v0 ^= b;
Packit Service ae04f2
Packit Service ae04f2
	v2 ^= 0xff;
Packit Service ae04f2
Packit Service ae04f2
	for (size_t i = 0; i < dROUNDS; ++i) {
Packit Service ae04f2
		SIPROUND(v0, v1, v2, v3);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	b = v0 ^ v1 ^ v2 ^ v3;
Packit Service ae04f2
Packit Service ae04f2
	U64TO8_LE(out, b);
Packit Service ae04f2
}