123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- /* <MIT License>
- Copyright (c) 2013-2014 Marek Majkowski <marek@popcount.org>
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- </MIT License>
- Original location:
- https://github.com/majek/csiphash/
- Solution inspired by code from:
- Samuel Neves (supercop/crypto_auth/siphash24/little)
- djb (supercop/crypto_auth/siphash24/little2)
- Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c)
- */
- #include "torint.h"
- #include "siphash.h"
- /* for tor_assert */
- #include "util.h"
- /* for memcpy */
- #include <string.h>
- #if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
- __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- # define _le64toh(x) ((uint64_t)(x))
- #elif defined(_WIN32)
- /* Windows is always little endian, unless you're on xbox360
- http://msdn.microsoft.com/en-us/library/b0084kay(v=vs.80).aspx */
- # define _le64toh(x) ((uint64_t)(x))
- #elif defined(__APPLE__)
- # include <libkern/OSByteOrder.h>
- # define _le64toh(x) OSSwapLittleToHostInt64(x)
- #elif defined(sun) || defined(__sun)
- # include <sys/byteorder.h>
- # define _le64toh(x) LE_64(x)
- #else
- /* See: http://sourceforge.net/p/predef/wiki/Endianness/ */
- # if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
- # include <sys/endian.h>
- # else
- # include <endian.h>
- # endif
- # if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
- __BYTE_ORDER == __LITTLE_ENDIAN
- # define _le64toh(x) ((uint64_t)(x))
- # else
- # if defined(__OpenBSD__)
- # define _le64toh(x) letoh64(x)
- # else
- # define _le64toh(x) le64toh(x)
- # endif
- # endif
- #endif
- #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; \
- a = ROTATE(a, 32);
- #define DOUBLE_ROUND(v0,v1,v2,v3) \
- HALF_ROUND(v0,v1,v2,v3,13,16); \
- HALF_ROUND(v2,v1,v0,v3,17,21); \
- HALF_ROUND(v0,v1,v2,v3,13,16); \
- HALF_ROUND(v2,v1,v0,v3,17,21);
- #if 0
- /* This does not seem to save very much runtime in the fast case, and it's
- * potentially a big loss in the slow case where we're misaligned and we cross
- * a cache line. */
- #if (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
- defined(__x86_64) || defined(__x86_64__) || \
- defined(_M_AMD64) || defined(_M_X64) || defined(__INTEL__))
- # define UNALIGNED_OK 1
- #endif
- #endif
- uint64_t siphash24(const void *src, unsigned long src_sz, const struct sipkey *key) {
- uint64_t k0 = key->k0;
- uint64_t k1 = key->k1;
- uint64_t b = (uint64_t)src_sz << 56;
- #ifdef UNALIGNED_OK
- const uint64_t *in = (uint64_t*)src;
- #else
- /* On platforms where alignment matters, if 'in' is a pointer to a
- * datatype that must be aligned, the compiler is allowed to
- * generate code that assumes that it is aligned as such.
- */
- const uint8_t *in = (uint8_t *)src;
- #endif
- uint64_t t;
- uint8_t *pt, *m;
- uint64_t v0 = k0 ^ 0x736f6d6570736575ULL;
- uint64_t v1 = k1 ^ 0x646f72616e646f6dULL;
- uint64_t v2 = k0 ^ 0x6c7967656e657261ULL;
- uint64_t v3 = k1 ^ 0x7465646279746573ULL;
- while (src_sz >= 8) {
- #ifdef UNALIGNED_OK
- uint64_t mi = _le64toh(*in);
- in += 1;
- #else
- uint64_t mi;
- memcpy(&mi, in, 8);
- mi = _le64toh(mi);
- in += 8;
- #endif
- src_sz -= 8;
- v3 ^= mi;
- DOUBLE_ROUND(v0,v1,v2,v3);
- v0 ^= mi;
- }
- t = 0; pt = (uint8_t*)&t; m = (uint8_t*)in;
- switch (src_sz) {
- case 7: pt[6] = m[6];
- case 6: pt[5] = m[5];
- case 5: pt[4] = m[4];
- #ifdef UNALIGNED_OK
- case 4: *((uint32_t*)&pt[0]) = *((uint32_t*)&m[0]); break;
- #else
- case 4: pt[3] = m[3];
- #endif
- case 3: pt[2] = m[2];
- case 2: pt[1] = m[1];
- case 1: pt[0] = m[0];
- }
- b |= _le64toh(t);
- v3 ^= b;
- DOUBLE_ROUND(v0,v1,v2,v3);
- v0 ^= b; v2 ^= 0xff;
- DOUBLE_ROUND(v0,v1,v2,v3);
- DOUBLE_ROUND(v0,v1,v2,v3);
- return (v0 ^ v1) ^ (v2 ^ v3);
- }
- static int the_siphash_key_is_set = 0;
- static struct sipkey the_siphash_key;
- uint64_t siphash24g(const void *src, unsigned long src_sz) {
- tor_assert(the_siphash_key_is_set);
- return siphash24(src, src_sz, &the_siphash_key);
- }
- void siphash_set_global_key(const struct sipkey *key)
- {
- tor_assert(! the_siphash_key_is_set);
- the_siphash_key.k0 = key->k0;
- the_siphash_key.k1 = key->k1;
- the_siphash_key_is_set = 1;
- }
|