/* $NetSBD$ */ /* SIP Hash */ /*- * Copyright (c) 2012 Taylor R. Campbell * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Jean-Philippe Aumasson and Daniel J. Bernstein, `SipHash: a fast * short-input PRF', Cryptology ePrint Archive Report 2012/351, 2012, * presented at the DIAC workshop. * * http://eprint.iacr.org/2012/351 */ #include #if defined(_KERNEL) || defined(_STANDALONE) _KERNEL_RCSID(0, "$NetBSD$"); #else __RCSID("$NetBSD$"); #ifdef __weak_alias __weak_alias(siphash,_siphash); __weak_alias(siphash_2_4,_siphash_2_4); __weak_alias(siphash_4_8,_siphash_4_8); #endif #include "namespace.h" #endif #include #include #include #include "siphash.h" struct state { uint64_t v[4]; }; static inline void rotate64(uint64_t *p, unsigned int n) { *p = ((*p << n) | (*p >> (64 - n))); } static inline void sipround(struct state *s) { s->v[0] += s->v[1]; rotate64(&s->v[1], 13); s->v[1] ^= s->v[0]; rotate64(&s->v[0], 32); s->v[2] += s->v[3]; rotate64(&s->v[3], 16); s->v[3] ^= s->v[2]; s->v[0] += s->v[3]; rotate64(&s->v[3], 21); s->v[3] ^= s->v[0]; s->v[2] += s->v[1]; rotate64(&s->v[1], 17); s->v[1] ^= s->v[2]; rotate64(&s->v[2], 32); } static inline void sipcompress(unsigned int rounds, uint64_t m, struct state *s) { s->v[3] ^= m; while (0 < rounds--) sipround(s); s->v[0] ^= m; } static inline uint64_t sipfinalize(unsigned int rounds, struct state *s) { s->v[2] ^= UINT64_C(0xff); while (0 < rounds--) sipround(s); return (s->v[0] ^ s->v[1] ^ s->v[2] ^ s->v[3]); } inline uint64_t siphash(unsigned int compress_rounds, unsigned int finalize_rounds, const uint8_t key[16], const uint8_t *message, size_t length) { uint64_t k[2]; struct state s; size_t words, remainder, i; uint8_t buffer[8]; /* `somepseudorandomlygeneratedbytes' */ static const uint64_t h[] = { UINT64_C(0x736f6d6570736575), UINT64_C(0x646f72616e646f6d), UINT64_C(0x6c7967656e657261), UINT64_C(0x7465646279746573), }; k[0] = le64dec(&key[0]); k[1] = le64dec(&key[8]); s.v[0] = (k[0] ^ h[0]); s.v[1] = (k[1] ^ h[1]); s.v[2] = (k[0] ^ h[2]); s.v[3] = (k[1] ^ h[3]); remainder = (length & 7); words = (((length + 1) >> 3) - (remainder != 0)); while (0 < words--) { sipcompress(compress_rounds, le64dec(message), &s); message += 8; } for (i = 0; (i < remainder); i++) buffer[i] = message[i]; for (i = remainder; (i < 7); i++) buffer[i] = 0; buffer[7] = (length & 0xff); sipcompress(compress_rounds, le64dec(buffer), &s); return sipfinalize(finalize_rounds, &s); } uint64_t siphash_2_4(const uint8_t key[16], const uint8_t *message, size_t length) { return siphash(2, 4, key, message, length); } uint64_t siphash_4_8(const uint8_t key[16], const uint8_t *message, size_t length) { return siphash(4, 8, key, message, length); }