Line data Source code
1 : /* <MIT License>
2 : Copyright (c) 2013-2014 Marek Majkowski <marek@popcount.org>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : </MIT License>
22 :
23 : Original location:
24 : https://github.com/majek/csiphash/
25 :
26 : Solution inspired by code from:
27 : Samuel Neves (supercop/crypto_auth/siphash24/little)
28 : djb (supercop/crypto_auth/siphash24/little2)
29 : Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c)
30 : */
31 :
32 : #include "lib/cc/torint.h"
33 : #include "lib/err/torerr.h"
34 :
35 : #include "ext/siphash.h"
36 : #include <string.h>
37 : #include <stdlib.h>
38 : #include "ext/byteorder.h"
39 :
40 : #define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) )
41 :
42 : #define HALF_ROUND(a,b,c,d,s,t) \
43 : a += b; c += d; \
44 : b = ROTATE(b, s) ^ a; \
45 : d = ROTATE(d, t) ^ c; \
46 : a = ROTATE(a, 32);
47 :
48 : #define DOUBLE_ROUND(v0,v1,v2,v3) \
49 : HALF_ROUND(v0,v1,v2,v3,13,16); \
50 : HALF_ROUND(v2,v1,v0,v3,17,21); \
51 : HALF_ROUND(v0,v1,v2,v3,13,16); \
52 : HALF_ROUND(v2,v1,v0,v3,17,21);
53 :
54 : #if 0
55 : /* This does not seem to save very much runtime in the fast case, and it's
56 : * potentially a big loss in the slow case where we're misaligned and we cross
57 : * a cache line. */
58 : #if (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
59 : defined(__x86_64) || defined(__x86_64__) || \
60 : defined(_M_AMD64) || defined(_M_X64) || defined(__INTEL__))
61 : # define UNALIGNED_OK 1
62 : #endif
63 : #endif
64 :
65 865118 : uint64_t siphash24(const void *src, unsigned long src_sz, const struct sipkey *key) {
66 865118 : const uint8_t *m = src;
67 865118 : uint64_t k0 = key->k0;
68 865118 : uint64_t k1 = key->k1;
69 865118 : uint64_t last7 = (uint64_t)(src_sz & 0xff) << 56;
70 865118 : size_t i, blocks;
71 :
72 865118 : uint64_t v0 = k0 ^ 0x736f6d6570736575ULL;
73 865118 : uint64_t v1 = k1 ^ 0x646f72616e646f6dULL;
74 865118 : uint64_t v2 = k0 ^ 0x6c7967656e657261ULL;
75 865118 : uint64_t v3 = k1 ^ 0x7465646279746573ULL;
76 :
77 3292039 : for (i = 0, blocks = (src_sz & ~7); i < blocks; i+= 8) {
78 : #ifdef UNALIGNED_OK
79 : uint64_t mi = _le64toh(*(m + i));
80 : #else
81 2426921 : uint64_t mi;
82 2426921 : memcpy(&mi, m + i, 8);
83 2426921 : mi = _le64toh(mi);
84 : #endif
85 2426921 : v3 ^= mi;
86 2426921 : DOUBLE_ROUND(v0,v1,v2,v3);
87 2426921 : v0 ^= mi;
88 : }
89 :
90 : #ifdef __COVERITY__
91 : {
92 : uint64_t mi = 0;
93 : memcpy(&mi, m+i, (src_sz-blocks));
94 : last7 = _le64toh(mi) | (uint64_t)(src_sz & 0xff) << 56;
95 : }
96 : #else
97 865118 : switch (src_sz - blocks) {
98 1460 : case 7: last7 |= (uint64_t)m[i + 6] << 48; FALLTHROUGH;
99 9093 : case 6: last7 |= (uint64_t)m[i + 5] << 40; FALLTHROUGH;
100 15272 : case 5: last7 |= (uint64_t)m[i + 4] << 32; FALLTHROUGH;
101 155275 : case 4: last7 |= (uint64_t)m[i + 3] << 24; FALLTHROUGH;
102 179501 : case 3: last7 |= (uint64_t)m[i + 2] << 16; FALLTHROUGH;
103 183173 : case 2: last7 |= (uint64_t)m[i + 1] << 8; FALLTHROUGH;
104 183526 : case 1: last7 |= (uint64_t)m[i + 0] ; FALLTHROUGH;
105 865118 : case 0:
106 865118 : default:;
107 : }
108 : #endif
109 865118 : v3 ^= last7;
110 865118 : DOUBLE_ROUND(v0,v1,v2,v3);
111 865118 : v0 ^= last7;
112 865118 : v2 ^= 0xff;
113 865118 : DOUBLE_ROUND(v0,v1,v2,v3);
114 865118 : DOUBLE_ROUND(v0,v1,v2,v3);
115 865118 : return v0 ^ v1 ^ v2 ^ v3;
116 : }
117 :
118 :
119 : static int the_siphash_key_is_set = 0;
120 : static struct sipkey the_siphash_key;
121 :
122 800882 : uint64_t siphash24g(const void *src, unsigned long src_sz) {
123 800882 : raw_assert(the_siphash_key_is_set);
124 800882 : return siphash24(src, src_sz, &the_siphash_key);
125 : }
126 :
127 10870 : void siphash_set_global_key(const struct sipkey *key)
128 : {
129 10870 : raw_assert(! the_siphash_key_is_set);
130 10870 : the_siphash_key.k0 = key->k0;
131 10870 : the_siphash_key.k1 = key->k1;
132 10870 : the_siphash_key_is_set = 1;
133 10870 : }
134 :
135 5544 : void siphash_unset_global_key(void)
136 : {
137 5544 : the_siphash_key_is_set = 0;
138 5544 : memset(&the_siphash_key, 0, sizeof(the_siphash_key));
139 5544 : }
|