3 * The SipHash-2-4 message authentication code
5 * (c) 2024 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
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.
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.
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,
28 #ifndef MLIB_SIPHASH_H
29 #define MLIB_SIPHASH_H
35 /*----- Header files ------------------------------------------------------*/
43 /*----- Constants and data structures -------------------------------------*/
45 #define SIPHASH_KEYSZ 16 /* size of a SipHash key in bytes */
46 #define SIPHASH_BLKSZ 8 /* size of SipHash blocks */
48 struct siphash_key { kludge64 k0, k1; }; /* a prepared SipHash key */
50 struct siphash { /* a SipHash context */
52 octet buf[SIPHASH_BLKSZ]; unsigned n, msz;
55 /*----- Implementation macros ---------------------------------------------*/
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 */
63 /* --- @SIPHASH__ROUND@ --- *
65 * Arguments: @kludge64 &a, &b, &c, &d@ = four state variables (updated)
69 * Use: Does one round of SipHash. Not really intended for user
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); \
84 /* --- @SIPHASH_INIT@ --- *
86 * Arguments: @kludge64 &a, &b, &c, &d@ = four state variables (output)
87 * @const struct siphash_key *k@ = prepared key
91 * Use: Initialize a SipHash state.
94 #define SIPHASH_INIT(a, b, c, d, k) do { \
96 _a0 = SIPHASH__A0, _b0 = SIPHASH__B0, \
97 _c0 = SIPHASH__C0, _d0 = SIPHASH__D0; \
98 const struct siphash_key *_k = (k); \
100 XOR64((a), _a0, _k->k0); XOR64((b), _b0, _k->k1); \
101 XOR64((c), _c0, _k->k0); XOR64((d), _d0, _k->k1); \
104 /* --- @SIPHASH_WORD@ --- *
106 * Arguments: @kludge64 &a, &b, &c, &d@ = four state variables (updated)
107 * @kludge64 m@ = message word (multiply evaluated)
111 * Use: Update a SipHash state with a single message word.
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)); \
120 /* --- @SIPHASH_FINAL@ --- *
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)
131 * Use: Completes a SipHash operation, storing the final result in
135 #define SIPHASH_FINAL(a, b, c, d, z_out, p, n, msz) do { \
136 const unsigned char *_p = (const unsigned char *)(p); \
139 /* Prepare the final message word. \
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. \
145 SET64(_t, 0, 0); SETBYTE64(_t, (msz), 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); \
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); \
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); \
169 /* --- @SIPHASH@ --- *
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
178 * Use: Hash a message using under the key @k@, leaving the result in
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; \
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; \
191 SIPHASH_FINAL(_a, _b, _c, _d, (z_out), _q, _sz, _sz0); \
194 /*----- Functions provided ------------------------------------------------*/
196 /* --- @siphash_setkey@ --- *
198 * Arguments: @struct siphash_key *k@ = prepared key structure to fill in
199 * @const octet *p@ = pointer to key data (@SIPHASH_KEYSZ = 16@
204 * Use: Prepare a SipHash key.
207 extern void siphash_setkey(struct siphash_key */*k*/, const octet */*p*/);
209 /* --- @siphash_init@ --- *
211 * Arguments: @struct siphash *s@ = hashing state to initialize
212 * @const struct siphash_key *k@ = prepared key structure
216 * Use: Initialize a state for hashing a message in multiple pieces.
219 extern void siphash_init(struct siphash */*s*/,
220 const struct siphash_key */*k*/);
222 /* --- @siphash_hash@ --- *
224 * Arguments: @struct siphash *s@ = hashing state
225 * @const void *p, size_t sz@ = input message buffer
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.
234 extern void siphash_hash(struct siphash */*s*/,
235 const void */*p*/, size_t /*sz*/);
237 /* --- @siphash_done@ --- *
239 * Arguments: @struct siphash *s@ = hashing state (clobbered)
241 * Returns: The completed hash.
243 * Use: Complete the hashing operation tracked by the state,
244 * returning the resulting 64-bit hash.
247 extern kludge64 siphash_done(struct siphash */*s*/);
249 /* --- @siphash@ --- *
251 * Arguments: @const struct siphash_key *k@ = prepared key
252 * @const void *p, size_t sz@ = input message buffer
254 * Returns: The completed hash.
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@
262 extern kludge64 siphash(const struct siphash_key */*k*/,
263 const void */*p*/, size_t /*sz*/);
265 /*----- That's all, folks -------------------------------------------------*/