chiark / gitweb /
ec-field-test.c: Make the field-element type use internal format.
[secnet.git] / sha3.c
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
57 static 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
67 static void step(sha3_ctx *ctx) { keccak1600_p(&ctx->s, &ctx->s, 24); }
68
69 static 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
83 static 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
93 enum {
94   OP_CSHAKE = 0x04,
95   OP_SHA3 = 0x06,
96   OP_SHAKE = 0x1f
97 };
98
99 enum { 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
112 static 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
118 void sha3_224_init(sha3_ctx *ctx) { init_sha3(ctx, 224); }
119 void sha3_256_init(sha3_ctx *ctx) { init_sha3(ctx, 256); }
120 void sha3_384_init(sha3_ctx *ctx) { init_sha3(ctx, 384); }
121 void 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
135 void 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
170 void 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
185 static 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
198 static 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
201 static void bytepad_before(shake_ctx *ctx)
202   { leftenc_sz(ctx, ctx->h.r); }
203
204 static 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
233 static 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
250 void 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
255 void 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
270 void shake128_init(shake_ctx *ctx) { init_shake(ctx, 128, 0, 0, 0, 0); }
271 void 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
285 void 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
298 void 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
318 void 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
360 void 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 -------------------------------------------------*/