ec-field-test.c: Make the field-element type use internal format.
[secnet] / sha3.c
CommitLineData
a1a6042e
MW
1/* -*-c-*-
2 *
3 * The SHA3 algorithm family
4 *
5 * (c) 2017 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of secnet.
11 * See README for full list of copyright holders.
12 *
13 * secnet is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version d of the License, or
16 * (at your option) any later version.
17 *
18 * secnet is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * version 3 along with secnet; if not, see
25 * https://www.gnu.org/licenses/gpl.html.
26 *
27 * This file was originally part of Catacomb, but has been automatically
28 * modified for incorporation into secnet: see `import-catacomb-crypto'
29 * for details.
30 *
31 * Catacomb is free software; you can redistribute it and/or modify
32 * it under the terms of the GNU Library General Public License as
33 * published by the Free Software Foundation; either version 2 of the
34 * License, or (at your option) any later version.
35 *
36 * Catacomb is distributed in the hope that it will be useful,
37 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39 * GNU Library General Public License for more details.
40 *
41 * You should have received a copy of the GNU Library General Public
42 * License along with Catacomb; if not, write to the Free
43 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
44 * MA 02111-1307, USA.
45 */
46
47/*----- Header files ------------------------------------------------------*/
48
49#include <assert.h>
50#include <stdarg.h>
51#include <string.h>
52
53#include "sha3.h"
54
55/*----- General utilities -------------------------------------------------*/
56
57static void absorb(sha3_ctx *ctx, const octet *p, unsigned r)
58{
59 kludge64 t[25];
60 unsigned i;
61
62/* memdump("absorb", p, 8*r, 0); */
63 for (i = 0; i < r; i++) { LOAD64_L_(t[i], p); p += 8; }
64 keccak1600_mix(&ctx->s, t, r);
65}
66
67static void step(sha3_ctx *ctx) { keccak1600_p(&ctx->s, &ctx->s, 24); }
68
69static void pad(sha3_ctx *ctx, unsigned lo, unsigned hi)
70{
71 size_t spare = ctx->r - ctx->n;
72
73 if (spare == 1)
74 ctx->buf[ctx->n] = lo | hi;
75 else {
76 ctx->buf[ctx->n] = lo;
77 ctx->buf[ctx->r - 1] = hi;
78 memset(ctx->buf + ctx->n + 1, 0, spare - 2);
79 }
80 absorb(ctx, ctx->buf, ctx->r/8);
81}
82
83static void squeeze(sha3_ctx *ctx, octet *p, unsigned r)
84{
85 kludge64 t[25];
86 unsigned i;
87
88 keccak1600_extract(&ctx->s, t, r);
89 for (i = 0; i < r; i++) { STORE64_L_(p, t[i]); p += 8; }
90/* memdump("squeeze", p - 8*r, 8*r, 0); */
91}
92
93enum {
94 OP_CSHAKE = 0x04,
95 OP_SHA3 = 0x06,
96 OP_SHAKE = 0x1f
97};
98
99enum { ST_ABSORB, ST_SQUEEZE, ST_DEAD };
100
101/*----- The SHA3 algorithms -----------------------------------------------*/
102
103/* --- @sha3_{224,256,384,512}_init@ --- *
104 *
105 * Arguments: @sha3_ctx *ctx@ = pointer to context block to initialize
106 *
107 * Returns: ---
108 *
109 * Use: Initializes a SHA3 hashing context for use.
110 */
111
112static void init_sha3(sha3_ctx *ctx, unsigned w)
113{
114 keccak1600_init(&ctx->s);
115 ctx->w = w/8; ctx->r = (1600 - 2*w)/8; ctx->n = 0;
116}
117
118void sha3_224_init(sha3_ctx *ctx) { init_sha3(ctx, 224); }
119void sha3_256_init(sha3_ctx *ctx) { init_sha3(ctx, 256); }
120void sha3_384_init(sha3_ctx *ctx) { init_sha3(ctx, 384); }
121void sha3_512_init(sha3_ctx *ctx) { init_sha3(ctx, 512); }
122
123/* --- @sha3_hash@ --- *
124 *
125 * Arguments: @sha3_ctx *ctx@ = pointer to context bock
126 * @const void *p@ = pointer to data to hash
127 * @size_t sz@ = size of buffer to hash
128 *
129 * Returns: ---
130 *
131 * Use: Hashes a buffer of data. The buffer may be of any size and
132 * alignment.
133 */
134
135void sha3_hash(sha3_ctx *ctx, const void *p, size_t sz)
136{
137 const octet *q = p;
138 size_t spare = ctx->r - ctx->n;
139
140 if (sz < spare) {
141 memcpy(ctx->buf + ctx->n, q, sz);
142 ctx->n += sz;
143 return;
144 }
145 if (ctx->n) {
146 memcpy(ctx->buf + ctx->n, q, spare);
147 absorb(ctx, ctx->buf, ctx->r/8);
148 step(ctx);
149 q += spare; sz -= spare;
150 }
151 while (sz >= ctx->r) {
152 absorb(ctx, q, ctx->r/8);
153 step(ctx);
154 q += ctx->r; sz -= ctx->r;
155 }
156 if (sz) memcpy(ctx->buf, q, sz);
157 ctx->n = sz;
158}
159
160/* --- @sha3_done@ --- *
161 *
162 * Arguments: @sha3_ctx *ctx@ = pointer to context block
163 * @void *hash@ = pointer to output buffer
164 *
165 * Returns: ---
166 *
167 * Use: Returns the hash of the data read so far.
168 */
169
170void sha3_done(sha3_ctx *ctx, void *hash)
171{
172 pad(ctx, OP_SHA3, 0x80);
173 step(ctx);
174
175 if (ctx->w%8 == 0)
176 squeeze(ctx, hash, ctx->w/8);
177 else {
178 squeeze(ctx, ctx->buf, (ctx->w + 7)/8);
179 memcpy(hash, ctx->buf, ctx->w);
180 }
181}
182
183/*----- The cSHAKE XOF algorithm ------------------------------------------*/
184
185static void leftenc_sz(shake_ctx *ctx, size_t n)
186{
187 kludge64 t;
188 octet b[9];
189 unsigned i;
190
191 SET64(t, ((n&~(size_t)MASK32) >> 16) >> 16, n&MASK32);
192 STORE64_B_(b + 1, t);
193 for (i = 1; i < 8 && !b[i]; i++);
194 i--; b[i] = 8 - i;
195 shake_hash(ctx, b + i, 9 - i);
196}
197
a1a6042e
MW
198static void stringenc(shake_ctx *ctx, const void *p, size_t sz)
199 { leftenc_sz(ctx, 8*sz); if (sz) shake_hash(ctx, p, sz); }
200
201static void bytepad_before(shake_ctx *ctx)
202 { leftenc_sz(ctx, ctx->h.r); }
203
204static void bytepad_after(shake_ctx *ctx)
205{
206 unsigned pad;
207
208 if (ctx->h.n%8) {
209 pad = 8 - ctx->h.n%8;
210 memset(ctx->h.buf + ctx->h.n, 0, pad);
211 ctx->h.n += pad;
212 }
213 if (ctx->h.n) {
214 absorb(&ctx->h, ctx->h.buf, ctx->h.n/8);
215 step(&ctx->h); ctx->h.n = 0;
216 }
217}
218
219/* --- @cshake{128,256}_init@ --- *
220 *
221 * Arguments: @shake_ctx *ctx@ = pointer to context to initialize
222 * @const void *func@ = NIST-allocated function name
223 * @size_t fsz@ = length of function name
224 * @const void *perso@ = user personalization string
225 * @size_t psz@ = length of personalization string
226 *
227 * Returns: ---
228 *
229 * Use: Initializes a cSHAKE context. The context is initially in
230 * the `absorbing' state: feed it data with @shake_hash@.
231 */
232
233static void init_shake(shake_ctx *ctx, unsigned c0,
234 const void *func, size_t fsz,
235 const void *perso, size_t psz)
236{
237 keccak1600_init(&ctx->h.s); ctx->st = ST_ABSORB;
238 ctx->h.r = (1600 - 2*c0)/8; ctx->h.w = 0; ctx->h.n = 0;
239 if (!fsz && !psz)
240 ctx->op = OP_SHAKE;
241 else {
242 bytepad_before(ctx);
243 stringenc(ctx, func, fsz);
244 stringenc(ctx, perso, psz);
245 bytepad_after(ctx);
246 ctx->op = OP_CSHAKE;
247 }
248}
249
250void cshake128_init(shake_ctx *ctx,
251 const void *func, size_t fsz,
252 const void *perso, size_t psz)
253 { init_shake(ctx, 128, func, fsz, perso, psz); }
254
255void cshake256_init(shake_ctx *ctx,
256 const void *func, size_t fsz,
257 const void *perso, size_t psz)
258 { init_shake(ctx, 256, func, fsz, perso, psz); }
259
260/* --- @shake{128,256}_init@ --- *
261 *
262 * Arguments: @sha3_ctx *ctx@ = pointer to context to initialize
263 *
264 * Returns: ---
265 *
266 * Use: Initializes a SHAKE context. The context is initially in
267 * the `absorbing' state: feed it data with @shake_hash@.
268 */
269
270void shake128_init(shake_ctx *ctx) { init_shake(ctx, 128, 0, 0, 0, 0); }
271void shake256_init(shake_ctx *ctx) { init_shake(ctx, 256, 0, 0, 0, 0); }
272
273/* --- @shake_hash@ --- *
274 *
275 * Arguments: @shake_ctx *ctx@ = context to update
276 * @const void *p@ = input buffer
277 * @size_t sz@ = size of input
278 *
279 * Returns: ---
280 *
281 * Use: Feeds input data into a SHAKE context. The context must be
282 * in `absorbing' state.
283 */
284
285void shake_hash(shake_ctx *ctx, const void *p, size_t sz)
286 { assert(ctx->st == ST_ABSORB); sha3_hash(&ctx->h, p, sz); }
287
288/* --- @shake_xof@ --- *
289 *
290 * Arguments: @shake_ctx *ctx@ = context to update
291 *
292 * Returns: ---
293 *
294 * Use: Switches the context into `squeezing' state. Use @shake_get@
295 * or @shake_mask@ to extract data.
296 */
297
298void shake_xof(shake_ctx *ctx)
299{
300 assert(ctx->st == ST_ABSORB);
301 pad(&ctx->h, ctx->op, 0x80);
302 ctx->st = ST_SQUEEZE;
303 ctx->h.n = ctx->h.r;
304}
305
306/* --- @shake_get@ --- *
307 *
308 * Arguments: @shake_ctx *ctx@ = context to update
309 * @void *p@ = output buffer
310 * @size_t sz@ = size of output
311 *
312 * Returns: ---
313 *
314 * Use: Extracts output from a SHAKE context. The context must be
315 * in `squeezing' state.
316 */
317
318void shake_get(shake_ctx *ctx, void *p, size_t sz)
319{
320 octet *q = p;
321 size_t left = ctx->h.r - ctx->h.n;
322
323 assert(ctx->st == ST_SQUEEZE);
324 if (left >= sz) {
325 memcpy(q, ctx->h.buf + ctx->h.n, sz);
326 ctx->h.n += sz;
327 return;
328 }
329 if (left) {
330 memcpy(q, ctx->h.buf + ctx->h.n, left);
331 q += left; sz -= left;
332 }
333 while (sz >= ctx->h.r) {
334 step(&ctx->h);
335 squeeze(&ctx->h, q, ctx->h.r/8);
336 q += ctx->h.r; sz -= ctx->h.r;
337 }
338 if (!sz)
339 ctx->h.n = ctx->h.r;
340 else {
341 step(&ctx->h);
342 squeeze(&ctx->h, ctx->h.buf, ctx->h.r/8);
343 memcpy(q, ctx->h.buf, sz);
344 ctx->h.n = sz;
345 }
346}
347
348/* --- @shake_done@ --- *
349 *
350 * Arguments: @shake_ctx *ctx@ = context to update
351 * @void *h@ = where to write the hash
352 * @size_t hsz@ = size of the hash to make
353 *
354 * Returns: ---
355 *
356 * Use: Switches the context into `squeezing' state. Use @shake_get@
357 * or @shake_mask@ to extract data.
358 */
359
360void shake_done(shake_ctx *ctx, void *h, size_t hsz)
361 { shake_xof(ctx); shake_get(ctx, h, hsz); ctx->st = ST_DEAD; }
362
363/*----- That's all, folks -------------------------------------------------*/