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