@@@ fltfmt mess
[mLib] / hash / siphash.h
1 /* -*-c-*-
2 *
3 * The SipHash-2-4 message authentication code
4 *
5 * (c) 2024 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the mLib utilities library.
11 *
12 * mLib is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU Library General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
16 *
17 * mLib is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
20 * License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib. If not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25 * USA.
26 */
27
28 #ifndef MLIB_SIPHASH_H
29 #define MLIB_SIPHASH_H
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 /*----- Header files ------------------------------------------------------*/
36
37 #include <string.h>
38
39 #ifndef MLIB_BITS_H
40 # include "bits.h"
41 #endif
42
43 /*----- Constants and data structures -------------------------------------*/
44
45 #define SIPHASH_KEYSZ 16 /* size of a SipHash key in bytes */
46 #define SIPHASH_BLKSZ 8 /* size of SipHash blocks */
47
48 struct siphash_key { kludge64 k0, k1; }; /* a prepared SipHash key */
49
50 struct siphash { /* a SipHash context */
51 kludge64 a, b, c, d;
52 octet buf[SIPHASH_BLKSZ]; unsigned n, msz;
53 };
54
55 /*----- Implementation macros ---------------------------------------------*/
56
57 /* The initial state, not intended for user consumption. */
58 #define SIPHASH__A0 X64(736f6d65, 70736575) /* some pseu */
59 #define SIPHASH__B0 X64(646f7261, 6e646f6d) /* dora ndom */
60 #define SIPHASH__C0 X64(6c796765, 6e657261) /* lyge nera */
61 #define SIPHASH__D0 X64(74656462, 79746573) /* tedb ytes */
62
63 /* --- @SIPHASH__ROUND@ --- *
64 *
65 * Arguments: @kludge64 &a, &b, &c, &d@ = four state variables (updated)
66 *
67 * Returns: ---
68 *
69 * Use: Does one round of SipHash. Not really intended for user
70 * consumption.
71 */
72
73 #define SIPHASH__ROUND(a, b, c, d) do { \
74 ADD64((a), (a), (b)); ADD64((c), (c), (d)); \
75 ROL64_((b), (b), 13); ROL64_((d), (d), 16); \
76 XOR64((b), (b), (a)); XOR64((d), (d), (c)); \
77 ROL64_((a), (a), 32); \
78 ADD64((c), (c), (b)); ADD64((a), (a), (d)); \
79 ROL64_((b), (b), 17); ROL64_((d), (d), 21); \
80 XOR64((b), (b), (c)); XOR64((d), (d), (a)); \
81 ROL64_((c), (c), 32); \
82 } while (0)
83
84 /* --- @SIPHASH_INIT@ --- *
85 *
86 * Arguments: @kludge64 &a, &b, &c, &d@ = four state variables (output)
87 * @const struct siphash_key *k@ = prepared key
88 *
89 * Returns: ---
90 *
91 * Use: Initialize a SipHash state.
92 */
93
94 #define SIPHASH_INIT(a, b, c, d, k) do { \
95 kludge64 \
96 _a0 = SIPHASH__A0, _b0 = SIPHASH__B0, \
97 _c0 = SIPHASH__C0, _d0 = SIPHASH__D0; \
98 const struct siphash_key *_k = (k); \
99 \
100 XOR64((a), _a0, _k->k0); XOR64((b), _b0, _k->k1); \
101 XOR64((c), _c0, _k->k0); XOR64((d), _d0, _k->k1); \
102 } while (0)
103
104 /* --- @SIPHASH_WORD@ --- *
105 *
106 * Arguments: @kludge64 &a, &b, &c, &d@ = four state variables (updated)
107 * @kludge64 m@ = message word (multiply evaluated)
108 *
109 * Returns: ---
110 *
111 * Use: Update a SipHash state with a single message word.
112 */
113
114 #define SIPHASH_WORD(a, b, c, d, m) do { \
115 XOR64((d), (d), (m)); \
116 SIPHASH__ROUND(a, b, c, d); SIPHASH__ROUND(a, b, c, d); \
117 XOR64((a), (a), (m)); \
118 } while (0)
119
120 /* --- @SIPHASH_FINAL@ --- *
121 *
122 * Arguments: @kludge64 &a, &b, &c, &d@ = four state variables (updated)
123 * @kludge64 &z_out@ = hash result (output)
124 * @const void *p@ = pointer to message tail
125 * @unsigned n@ = length of message tail in bytes (must be less
126 * than @SIPHASH_BLKSZ@)
127 * @size_t msz@ = overall message size (at least mod 256)
128 *
129 * Returns: ---
130 *
131 * Use: Completes a SipHash operation, storing the final result in
132 * @z@.
133 */
134
135 #define SIPHASH_FINAL(a, b, c, d, z_out, p, n, msz) do { \
136 const unsigned char *_p = (const unsigned char *)(p); \
137 kludge64 _t, _u; \
138 \
139 /* Prepare the final message word. \
140 * \
141 * This is kind of annoying. Overrunning the input buffer could be \
142 * disastrous. This fiddly switch seems faster than building the \
143 * value in a byte buffer and then loading it. \
144 */ \
145 SET64(_t, 0, 0); SETBYTE64(_t, (msz), 7); \
146 switch (n) { \
147 /* case 7: */ \
148 default: SETBYTE64(_t, _p[6], 6); \
149 case 6: SETBYTE64(_t, _p[5], 5); \
150 case 5: SETBYTE64(_t, _p[4], 4); \
151 case 4: SETBYTE64(_t, _p[3], 3); \
152 case 3: SETBYTE64(_t, _p[2], 2); \
153 case 2: SETBYTE64(_t, _p[1], 1); \
154 case 1: SETBYTE64(_t, _p[0], 0); \
155 case 0: break; \
156 } \
157 \
158 /* Finish the hashing job. */ \
159 SIPHASH_WORD(a, b, c, d, _t); \
160 SET64(_t, 0, 0xff); XOR64((c), (c), _t); \
161 SIPHASH__ROUND(a, b, c, d); SIPHASH__ROUND(a, b, c, d); \
162 SIPHASH__ROUND(a, b, c, d); SIPHASH__ROUND(a, b, c, d); \
163 \
164 /* Combine the hash-state words into a single result. */ \
165 XOR64(_t, (a), (b)); XOR64(_u, (c), (d)); XOR64((z_out), _t, _u); \
166 SET64((a), 0, 0); SET64((b), 0, 0); SET64((c), 0, 0); SET64((d), 0, 0); \
167 } while (0)
168
169 /* --- @SIPHASH@ --- *
170 *
171 * Arguments: @const struct siphash_key *k@ = prepared key
172 * @kludge64 &z_out@ = hash result (output)
173 * @const void *p@ = pointer to message
174 * @size_t sz@ = message size in bytes
175 *
176 * Returns: ---
177 *
178 * Use: Hash a message using under the key @k@, leaving the result in
179 * @z@.
180 */
181
182 #define SIPHASH(k, z_out, p, sz) do { \
183 kludge64 _a, _b, _c, _d, _m; \
184 const octet *_q = (p); size_t _sz0 = (sz), _sz = _sz0; \
185 \
186 SIPHASH_INIT(_a, _b, _c, _d, (k)); \
187 while (_sz >= SIPHASH_BLKSZ) { \
188 LOAD64_L_(_m, _q); SIPHASH_WORD(_a, _b, _c, _d, _m); \
189 _q += SIPHASH_BLKSZ; _sz -= SIPHASH_BLKSZ; \
190 } \
191 SIPHASH_FINAL(_a, _b, _c, _d, (z_out), _q, _sz, _sz0); \
192 } while (0)
193
194 /*----- Functions provided ------------------------------------------------*/
195
196 /* --- @siphash_setkey@ --- *
197 *
198 * Arguments: @struct siphash_key *k@ = prepared key structure to fill in
199 * @const octet *p@ = pointer to key data (@SIPHASH_KEYSZ = 16@
200 * bytes)
201 *
202 * Returns: ---
203 *
204 * Use: Prepare a SipHash key.
205 */
206
207 extern void siphash_setkey(struct siphash_key */*k*/, const octet */*p*/);
208
209 /* --- @siphash_init@ --- *
210 *
211 * Arguments: @struct siphash *s@ = hashing state to initialize
212 * @const struct siphash_key *k@ = prepared key structure
213 *
214 * Returns: ---
215 *
216 * Use: Initialize a state for hashing a message in multiple pieces.
217 */
218
219 extern void siphash_init(struct siphash */*s*/,
220 const struct siphash_key */*k*/);
221
222 /* --- @siphash_hash@ --- *
223 *
224 * Arguments: @struct siphash *s@ = hashing state
225 * @const void *p, size_t sz@ = input message buffer
226 *
227 * Returns: ---
228 *
229 * Use: Update the hashing state by processing the provided input
230 * message chunk. The address and size do not need to be
231 * aligned in any particular way.
232 */
233
234 extern void siphash_hash(struct siphash */*s*/,
235 const void */*p*/, size_t /*sz*/);
236
237 /* --- @siphash_done@ --- *
238 *
239 * Arguments: @struct siphash *s@ = hashing state (clobbered)
240 *
241 * Returns: The completed hash.
242 *
243 * Use: Complete the hashing operation tracked by the state,
244 * returning the resulting 64-bit hash.
245 */
246
247 extern kludge64 siphash_done(struct siphash */*s*/);
248
249 /* --- @siphash@ --- *
250 *
251 * Arguments: @const struct siphash_key *k@ = prepared key
252 * @const void *p, size_t sz@ = input message buffer
253 *
254 * Returns: The completed hash.
255 *
256 * Use: Hash the message data in a single input buffer under the
257 * control of the supplied key, returning the resulting hash.
258 * This is simpler and faster than the @init@/@hash@/@done@
259 * interface.
260 */
261
262 extern kludge64 siphash(const struct siphash_key */*k*/,
263 const void */*p*/, size_t /*sz*/);
264
265 /*----- That's all, folks -------------------------------------------------*/
266
267 #ifdef __cplusplus
268 }
269 #endif
270
271 #endif