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