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