OpenVPN
siphash_reference.c
Go to the documentation of this file.
1/*
2 * SipHash reference C implementation
3 *
4 * Copyright 2012-2024 JP Aumasson
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 *
24 */
25
26/* Note: the reference implementation is also available under CC0 license
27 * (dual licensed) we included the MIT license here since it is shorter */
28
29#include "siphash.h"
30#include <assert.h>
31#include <stddef.h>
32#include <stdint.h>
33
34/* default: SipHash-2-4 */
35#ifndef cROUNDS
36#define cROUNDS 2
37#endif
38#ifndef dROUNDS
39#define dROUNDS 4
40#endif
41
42#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
43
44#define U32TO8_LE(p, v) \
45 (p)[0] = (uint8_t)((v)); \
46 (p)[1] = (uint8_t)((v) >> 8); \
47 (p)[2] = (uint8_t)((v) >> 16); \
48 (p)[3] = (uint8_t)((v) >> 24);
49
50#define U64TO8_LE(p, v) \
51 U32TO8_LE((p), (uint32_t)((v))); \
52 U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
53
54#define U8TO64_LE(p) \
55 (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) \
56 | ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) \
57 | ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) \
58 | ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
59
60#define SIPROUND \
61 do \
62 { \
63 v0 += v1; \
64 v1 = ROTL(v1, 13); \
65 v1 ^= v0; \
66 v0 = ROTL(v0, 32); \
67 v2 += v3; \
68 v3 = ROTL(v3, 16); \
69 v3 ^= v2; \
70 v0 += v3; \
71 v3 = ROTL(v3, 21); \
72 v3 ^= v0; \
73 v2 += v1; \
74 v1 = ROTL(v1, 17); \
75 v1 ^= v2; \
76 v2 = ROTL(v2, 32); \
77 } while (0)
78
79#ifdef DEBUG_SIPHASH
80#include <stdio.h>
81
82#define TRACE \
83 do \
84 { \
85 printf("(%3zu) v0 %016" PRIx64 "\n", inlen, v0); \
86 printf("(%3zu) v1 %016" PRIx64 "\n", inlen, v1); \
87 printf("(%3zu) v2 %016" PRIx64 "\n", inlen, v2); \
88 printf("(%3zu) v3 %016" PRIx64 "\n", inlen, v3); \
89 } while (0)
90#else /* ifdef DEBUG_SIPHASH */
91#define TRACE
92#endif
93
94/*
95 * Computes a SipHash value
96 * in: pointer to input data (read-only)
97 * inlen: input data length in bytes (any size_t value)
98 * k: pointer to the key data (read-only), must be 16 bytes
99 * out: pointer to output data (write-only), outlen bytes must be allocated
100 * outlen: length of the output in bytes, must be 8 or 16
101 */
102void
103siphash_reference(const void *in, const size_t inlen, const void *k, uint8_t *out,
104 const size_t outlen)
105{
106 const unsigned char *ni = (const unsigned char *)in;
107 const unsigned char *kk = (const unsigned char *)k;
108
109 assert((outlen == 8) || (outlen == 16));
110 uint64_t v0 = UINT64_C(0x736f6d6570736575);
111 uint64_t v1 = UINT64_C(0x646f72616e646f6d);
112 uint64_t v2 = UINT64_C(0x6c7967656e657261);
113 uint64_t v3 = UINT64_C(0x7465646279746573);
114 uint64_t k0 = U8TO64_LE(kk);
115 uint64_t k1 = U8TO64_LE(kk + 8);
116 int i;
117 const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t));
118 const int left = inlen & 7;
119 uint64_t b = ((uint64_t)inlen) << 56;
120 v3 ^= k1;
121 v2 ^= k0;
122 v1 ^= k1;
123 v0 ^= k0;
124
125 if (outlen == 16)
126 {
127 v1 ^= 0xee;
128 }
129
130 for (; ni != end; ni += 8)
131 {
132 uint64_t m = U8TO64_LE(ni);
133 v3 ^= m;
134
135 TRACE;
136 for (i = 0; i < cROUNDS; ++i)
137 {
138 SIPROUND;
139 }
140
141 v0 ^= m;
142 }
143
144 switch (left)
145 {
146 case 7:
147 b |= ((uint64_t)ni[6]) << 48;
148
149 /* FALLTHRU */
150 case 6:
151 b |= ((uint64_t)ni[5]) << 40;
152
153 /* FALLTHRU */
154 case 5:
155 b |= ((uint64_t)ni[4]) << 32;
156
157 /* FALLTHRU */
158 case 4:
159 b |= ((uint64_t)ni[3]) << 24;
160
161 /* FALLTHRU */
162 case 3:
163 b |= ((uint64_t)ni[2]) << 16;
164
165 /* FALLTHRU */
166 case 2:
167 b |= ((uint64_t)ni[1]) << 8;
168
169 /* FALLTHRU */
170 case 1:
171 b |= ((uint64_t)ni[0]);
172 break;
173
174 case 0:
175 break;
176 }
177
178 v3 ^= b;
179
180 TRACE;
181 for (i = 0; i < cROUNDS; ++i)
182 {
183 SIPROUND;
184 }
185
186 v0 ^= b;
187
188 if (outlen == 16)
189 {
190 v2 ^= 0xee;
191 }
192 else
193 {
194 v2 ^= 0xff;
195 }
196
197 TRACE;
198 for (i = 0; i < dROUNDS; ++i)
199 {
200 SIPROUND;
201 }
202
203 b = v0 ^ v1 ^ v2 ^ v3;
204 U64TO8_LE(out, b);
205
206 if (outlen == 8)
207 {
208 return;
209 }
210
211 v1 ^= 0xdd;
212
213 TRACE;
214 for (i = 0; i < dROUNDS; ++i)
215 {
216 SIPROUND;
217 }
218
219 b = v0 ^ v1 ^ v2 ^ v3;
220 U64TO8_LE(out + 8, b);
221}
void siphash_reference(const void *in, const size_t inlen, const void *k, uint8_t *out, const size_t outlen)
Calculates SIPHASH using the reference implementation.
#define dROUNDS
#define U8TO64_LE(p)
#define U64TO8_LE(p, v)
#define cROUNDS
#define TRACE
#define SIPROUND