1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 #include <inttypes.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 #include <isc/endian.h>
17 #include <isc/siphash.h>
18 #include <isc/util.h>
19
20 /*
21 * The implementation is based on SipHash reference C implementation by
22 *
23 * Copyright (c) 2012-2016 Jean-Philippe Aumasson
24 * <jeanphilippe.aumasson@gmail.com> Copyright (c) 2012-2014 Daniel J. Bernstein
25 * <djb@cr.yp.to>
26 *
27 * To the extent possible under law, the author(s) have dedicated all copyright
28 * and related and neighboring rights to this software to the public domain
29 * worldwide. This software is distributed without any warranty. You should
30 * have received a copy of the CC0 Public Domain Dedication along with this
31 * software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
32 */
33
34 #define cROUNDS 2
35 #define dROUNDS 4
36
37 #define ROTATE64(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
38
39 #define HALF_ROUND64(a, b, c, d, s, t) \
40 a += b; \
41 c += d; \
42 b = ROTATE64(b, s) ^ a; \
43 d = ROTATE64(d, t) ^ c; \
44 a = ROTATE64(a, 32);
45
46 #define FULL_ROUND64(v0, v1, v2, v3) \
47 HALF_ROUND64(v0, v1, v2, v3, 13, 16); \
48 HALF_ROUND64(v2, v1, v0, v3, 17, 21);
49
50 #define SIPROUND FULL_ROUND64
51
52 #define ROTATE32(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b))))
53
54 #define HALF_ROUND32(a, b, c, d, s, t) \
55 a += b; \
56 c += d; \
57 b = ROTATE32(b, s) ^ a; \
58 d = ROTATE32(d, t) ^ c; \
59 a = ROTATE32(a, 16);
60
61 #define FULL_ROUND32(v0, v1, v2, v3) \
62 HALF_ROUND32(v0, v1, v2, v3, 5, 8); \
63 HALF_ROUND32(v2, v1, v0, v3, 13, 7);
64
65 #define HALFSIPROUND FULL_ROUND32
66
67 #define U32TO8_LE(p, v) \
68 (p)[0] = (uint8_t)((v)); \
69 (p)[1] = (uint8_t)((v) >> 8); \
70 (p)[2] = (uint8_t)((v) >> 16); \
71 (p)[3] = (uint8_t)((v) >> 24);
72
73 #define U8TO32_LE(p) \
74 (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \
75 ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24))
76
77 #define U64TO8_LE(p, v) \
78 U32TO8_LE((p), (uint32_t)((v))); \
79 U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
80
81 #define U8TO64_LE(p) \
82 (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
83 ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
84 ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
85 ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
86
87 void
isc_siphash24(const uint8_t * k,const uint8_t * in,const size_t inlen,uint8_t * out)88 isc_siphash24(const uint8_t *k, const uint8_t *in, const size_t inlen,
89 uint8_t *out) {
90 REQUIRE(k != NULL);
91 REQUIRE(out != NULL);
92
93 uint64_t k0 = U8TO64_LE(k);
94 uint64_t k1 = U8TO64_LE(k + 8);
95
96 uint64_t v0 = UINT64_C(0x736f6d6570736575) ^ k0;
97 uint64_t v1 = UINT64_C(0x646f72616e646f6d) ^ k1;
98 uint64_t v2 = UINT64_C(0x6c7967656e657261) ^ k0;
99 uint64_t v3 = UINT64_C(0x7465646279746573) ^ k1;
100
101 uint64_t b = ((uint64_t)inlen) << 56;
102
103 const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t));
104 const size_t left = inlen & 7;
105
106 for (; in != end; in += 8) {
107 uint64_t m = U8TO64_LE(in);
108
109 v3 ^= m;
110
111 for (size_t i = 0; i < cROUNDS; ++i) {
112 SIPROUND(v0, v1, v2, v3);
113 }
114
115 v0 ^= m;
116 }
117
118 switch (left) {
119 case 7:
120 b |= ((uint64_t)in[6]) << 48;
121 /* FALLTHROUGH */
122 case 6:
123 b |= ((uint64_t)in[5]) << 40;
124 /* FALLTHROUGH */
125 case 5:
126 b |= ((uint64_t)in[4]) << 32;
127 /* FALLTHROUGH */
128 case 4:
129 b |= ((uint64_t)in[3]) << 24;
130 /* FALLTHROUGH */
131 case 3:
132 b |= ((uint64_t)in[2]) << 16;
133 /* FALLTHROUGH */
134 case 2:
135 b |= ((uint64_t)in[1]) << 8;
136 /* FALLTHROUGH */
137 case 1:
138 b |= ((uint64_t)in[0]);
139 /* FALLTHROUGH */
140 case 0:
141 break;
142 default:
143 INSIST(0);
144 ISC_UNREACHABLE();
145 }
146
147 v3 ^= b;
148
149 for (size_t i = 0; i < cROUNDS; ++i) {
150 SIPROUND(v0, v1, v2, v3);
151 }
152
153 v0 ^= b;
154
155 v2 ^= 0xff;
156
157 for (size_t i = 0; i < dROUNDS; ++i) {
158 SIPROUND(v0, v1, v2, v3);
159 }
160
161 b = v0 ^ v1 ^ v2 ^ v3;
162
163 U64TO8_LE(out, b);
164 }
165
166 void
isc_halfsiphash24(const uint8_t * k,const uint8_t * in,const size_t inlen,uint8_t * out)167 isc_halfsiphash24(const uint8_t *k, const uint8_t *in, const size_t inlen,
168 uint8_t *out) {
169 REQUIRE(k != NULL);
170 REQUIRE(out != NULL);
171
172 uint32_t k0 = U8TO32_LE(k);
173 uint32_t k1 = U8TO32_LE(k + 4);
174
175 uint32_t v0 = UINT32_C(0x00000000) ^ k0;
176 uint32_t v1 = UINT32_C(0x00000000) ^ k1;
177 uint32_t v2 = UINT32_C(0x6c796765) ^ k0;
178 uint32_t v3 = UINT32_C(0x74656462) ^ k1;
179
180 uint32_t b = ((uint32_t)inlen) << 24;
181
182 const uint8_t *end = in + inlen - (inlen % sizeof(uint32_t));
183 const int left = inlen & 3;
184
185 for (; in != end; in += 4) {
186 uint32_t m = U8TO32_LE(in);
187 v3 ^= m;
188
189 for (size_t i = 0; i < cROUNDS; ++i) {
190 HALFSIPROUND(v0, v1, v2, v3);
191 }
192
193 v0 ^= m;
194 }
195
196 switch (left) {
197 case 3:
198 b |= ((uint32_t)in[2]) << 16;
199 /* FALLTHROUGH */
200 case 2:
201 b |= ((uint32_t)in[1]) << 8;
202 /* FALLTHROUGH */
203 case 1:
204 b |= ((uint32_t)in[0]);
205 /* FALLTHROUGH */
206 case 0:
207 break;
208 default:
209 INSIST(0);
210 ISC_UNREACHABLE();
211 }
212
213 v3 ^= b;
214
215 for (size_t i = 0; i < cROUNDS; ++i) {
216 HALFSIPROUND(v0, v1, v2, v3);
217 }
218
219 v0 ^= b;
220
221 v2 ^= 0xff;
222
223 for (size_t i = 0; i < dROUNDS; ++i) {
224 HALFSIPROUND(v0, v1, v2, v3);
225 }
226
227 b = v1 ^ v3;
228 U32TO8_LE(out, b);
229 }
230