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 */
102int
103siphash(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 uint64_t m;
117 int i;
118 const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t));
119 const int left = inlen & 7;
120 uint64_t b = ((uint64_t)inlen) << 56;
121 v3 ^= k1;
122 v2 ^= k0;
123 v1 ^= k1;
124 v0 ^= k0;
125
126 if (outlen == 16)
127 {
128 v1 ^= 0xee;
129 }
130
131 for (; ni != end; ni += 8)
132 {
133 m = U8TO64_LE(ni);
134 v3 ^= m;
135
136 TRACE;
137 for (i = 0; i < cROUNDS; ++i)
138 {
139 SIPROUND;
140 }
141
142 v0 ^= m;
143 }
144
145 switch (left)
146 {
147 case 7:
148 b |= ((uint64_t)ni[6]) << 48;
149
150 /* FALLTHRU */
151 case 6:
152 b |= ((uint64_t)ni[5]) << 40;
153
154 /* FALLTHRU */
155 case 5:
156 b |= ((uint64_t)ni[4]) << 32;
157
158 /* FALLTHRU */
159 case 4:
160 b |= ((uint64_t)ni[3]) << 24;
161
162 /* FALLTHRU */
163 case 3:
164 b |= ((uint64_t)ni[2]) << 16;
165
166 /* FALLTHRU */
167 case 2:
168 b |= ((uint64_t)ni[1]) << 8;
169
170 /* FALLTHRU */
171 case 1:
172 b |= ((uint64_t)ni[0]);
173 break;
174
175 case 0:
176 break;
177 }
178
179 v3 ^= b;
180
181 TRACE;
182 for (i = 0; i < cROUNDS; ++i)
183 {
184 SIPROUND;
185 }
186
187 v0 ^= b;
188
189 if (outlen == 16)
190 {
191 v2 ^= 0xee;
192 }
193 else
194 {
195 v2 ^= 0xff;
196 }
197
198 TRACE;
199 for (i = 0; i < dROUNDS; ++i)
200 {
201 SIPROUND;
202 }
203
204 b = v0 ^ v1 ^ v2 ^ v3;
205 U64TO8_LE(out, b);
206
207 if (outlen == 8)
208 {
209 return 0;
210 }
211
212 v1 ^= 0xdd;
213
214 TRACE;
215 for (i = 0; i < dROUNDS; ++i)
216 {
217 SIPROUND;
218 }
219
220 b = v0 ^ v1 ^ v2 ^ v3;
221 U64TO8_LE(out + 8, b);
222
223 return 0;
224}
#define dROUNDS
#define U8TO64_LE(p)
#define U64TO8_LE(p, v)
int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out, const size_t outlen)
#define cROUNDS
#define TRACE
#define SIPROUND