keccak.c
Go to the documentation of this file.
1 /**
2  * @file keccak.c
3  * @brief Keccak sponge function
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2025 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneCRYPTO Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.5.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL CRYPTO_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/crypto.h"
36 #include "xof/keccak.h"
37 
38 //Check crypto library configuration
39 #if (KECCAK_SUPPORT == ENABLED)
40 
41 //Keccak round constants
42 static const keccak_lane_t rc[KECCAK_NR] =
43 {
44  (keccak_lane_t) 0x0000000000000001,
45  (keccak_lane_t) 0x0000000000008082,
46  (keccak_lane_t) 0x800000000000808A,
47  (keccak_lane_t) 0x8000000080008000,
48  (keccak_lane_t) 0x000000000000808B,
49  (keccak_lane_t) 0x0000000080000001,
50  (keccak_lane_t) 0x8000000080008081,
51  (keccak_lane_t) 0x8000000000008009,
52  (keccak_lane_t) 0x000000000000008A,
53  (keccak_lane_t) 0x0000000000000088,
54  (keccak_lane_t) 0x0000000080008009,
55  (keccak_lane_t) 0x000000008000000A,
56  (keccak_lane_t) 0x000000008000808B,
57  (keccak_lane_t) 0x800000000000008B,
58  (keccak_lane_t) 0x8000000000008089,
59  (keccak_lane_t) 0x8000000000008003,
60  (keccak_lane_t) 0x8000000000008002,
61  (keccak_lane_t) 0x8000000000000080,
62 #if (KECCAK_L >= 4)
63  (keccak_lane_t) 0x000000000000800A,
64  (keccak_lane_t) 0x800000008000000A,
65 #endif
66 #if (KECCAK_L >= 5)
67  (keccak_lane_t) 0x8000000080008081,
68  (keccak_lane_t) 0x8000000000008080,
69 #endif
70 #if (KECCAK_L >= 6)
71  (keccak_lane_t) 0x0000000080000001,
72  (keccak_lane_t) 0x8000000080008008
73 #endif
74 };
75 
76 
77 /**
78  * @brief Apply theta transformation
79  * @param[in,out] a State array
80  **/
81 
82 static void theta(keccak_lane_t a[5][5])
83 {
84  keccak_lane_t c[5];
85  keccak_lane_t d[5];
86 
87  //The effect of the theta transformation is to XOR each bit in the state
88  //with the parities of two columns in the array
89  c[0] = a[0][0] ^ a[1][0] ^ a[2][0] ^ a[3][0] ^ a[4][0];
90  c[1] = a[0][1] ^ a[1][1] ^ a[2][1] ^ a[3][1] ^ a[4][1];
91  c[2] = a[0][2] ^ a[1][2] ^ a[2][2] ^ a[3][2] ^ a[4][2];
92  c[3] = a[0][3] ^ a[1][3] ^ a[2][3] ^ a[3][3] ^ a[4][3];
93  c[4] = a[0][4] ^ a[1][4] ^ a[2][4] ^ a[3][4] ^ a[4][4];
94 
95  d[0] = c[4] ^ KECCAK_ROL(c[1], 1);
96  d[1] = c[0] ^ KECCAK_ROL(c[2], 1);
97  d[2] = c[1] ^ KECCAK_ROL(c[3], 1);
98  d[3] = c[2] ^ KECCAK_ROL(c[4], 1);
99  d[4] = c[3] ^ KECCAK_ROL(c[0], 1);
100 
101  a[0][0] ^= d[0];
102  a[1][0] ^= d[0];
103  a[2][0] ^= d[0];
104  a[3][0] ^= d[0];
105  a[4][0] ^= d[0];
106 
107  a[0][1] ^= d[1];
108  a[1][1] ^= d[1];
109  a[2][1] ^= d[1];
110  a[3][1] ^= d[1];
111  a[4][1] ^= d[1];
112 
113  a[0][2] ^= d[2];
114  a[1][2] ^= d[2];
115  a[2][2] ^= d[2];
116  a[3][2] ^= d[2];
117  a[4][2] ^= d[2];
118 
119  a[0][3] ^= d[3];
120  a[1][3] ^= d[3];
121  a[2][3] ^= d[3];
122  a[3][3] ^= d[3];
123  a[4][3] ^= d[3];
124 
125  a[0][4] ^= d[4];
126  a[1][4] ^= d[4];
127  a[2][4] ^= d[4];
128  a[3][4] ^= d[4];
129  a[4][4] ^= d[4];
130 }
131 
132 
133 /**
134  * @brief Apply rho transformation
135  * @param[in,out] a State array
136  **/
137 
138 static void rho(keccak_lane_t a[5][5])
139 {
140  //The effect of the rho transformation is to rotate the bits of each lane by
141  //an offset, which depends on the fixed x and y coordinates of the lane
142  a[0][1] = KECCAK_ROL(a[0][1], 1);
143  a[0][2] = KECCAK_ROL(a[0][2], 190);
144  a[0][3] = KECCAK_ROL(a[0][3], 28);
145  a[0][4] = KECCAK_ROL(a[0][4], 91);
146 
147  a[1][0] = KECCAK_ROL(a[1][0], 36);
148  a[1][1] = KECCAK_ROL(a[1][1], 300);
149  a[1][2] = KECCAK_ROL(a[1][2], 6);
150  a[1][3] = KECCAK_ROL(a[1][3], 55);
151  a[1][4] = KECCAK_ROL(a[1][4], 276);
152 
153  a[2][0] = KECCAK_ROL(a[2][0], 3);
154  a[2][1] = KECCAK_ROL(a[2][1], 10);
155  a[2][2] = KECCAK_ROL(a[2][2], 171);
156  a[2][3] = KECCAK_ROL(a[2][3], 153);
157  a[2][4] = KECCAK_ROL(a[2][4], 231);
158 
159  a[3][0] = KECCAK_ROL(a[3][0], 105);
160  a[3][1] = KECCAK_ROL(a[3][1], 45);
161  a[3][2] = KECCAK_ROL(a[3][2], 15);
162  a[3][3] = KECCAK_ROL(a[3][3], 21);
163  a[3][4] = KECCAK_ROL(a[3][4], 136);
164 
165  a[4][0] = KECCAK_ROL(a[4][0], 210);
166  a[4][1] = KECCAK_ROL(a[4][1], 66);
167  a[4][2] = KECCAK_ROL(a[4][2], 253);
168  a[4][3] = KECCAK_ROL(a[4][3], 120);
169  a[4][4] = KECCAK_ROL(a[4][4], 78);
170 }
171 
172 
173 /**
174  * @brief Apply pi transformation
175  * @param[in,out] a State array
176  **/
177 
178 static void pi(keccak_lane_t a[5][5])
179 {
180  keccak_lane_t temp;
181 
182  //The effect of the pi transformation is to rearrange the positions of
183  //the lanes
184  temp = a[0][1];
185  a[0][1] = a[1][1];
186  a[1][1] = a[1][4];
187  a[1][4] = a[4][2];
188  a[4][2] = a[2][4];
189  a[2][4] = a[4][0];
190  a[4][0] = a[0][2];
191  a[0][2] = a[2][2];
192  a[2][2] = a[2][3];
193  a[2][3] = a[3][4];
194  a[3][4] = a[4][3];
195  a[4][3] = a[3][0];
196  a[3][0] = a[0][4];
197  a[0][4] = a[4][4];
198  a[4][4] = a[4][1];
199  a[4][1] = a[1][3];
200  a[1][3] = a[3][1];
201  a[3][1] = a[1][0];
202  a[1][0] = a[0][3];
203  a[0][3] = a[3][3];
204  a[3][3] = a[3][2];
205  a[3][2] = a[2][1];
206  a[2][1] = a[1][2];
207  a[1][2] = a[2][0];
208  a[2][0] = temp;
209 }
210 
211 
212 /**
213  * @brief Apply chi transformation
214  * @param[in,out] a State array
215  **/
216 
217 static void chi(keccak_lane_t a[5][5])
218 {
219  keccak_lane_t temp1;
220  keccak_lane_t temp2;
221 
222  //The effect of the chi transformation is to XOR each bit with a non
223  //linear function of two other bits in its row
224  temp1 = a[0][0];
225  temp2 = a[0][1];
226  a[0][0] ^= ~a[0][1] & a[0][2];
227  a[0][1] ^= ~a[0][2] & a[0][3];
228  a[0][2] ^= ~a[0][3] & a[0][4];
229  a[0][3] ^= ~a[0][4] & temp1;
230  a[0][4] ^= ~temp1 & temp2;
231 
232  temp1 = a[1][0];
233  temp2 = a[1][1];
234  a[1][0] ^= ~a[1][1] & a[1][2];
235  a[1][1] ^= ~a[1][2] & a[1][3];
236  a[1][2] ^= ~a[1][3] & a[1][4];
237  a[1][3] ^= ~a[1][4] & temp1;
238  a[1][4] ^= ~temp1 & temp2;
239 
240  temp1 = a[2][0];
241  temp2 = a[2][1];
242  a[2][0] ^= ~a[2][1] & a[2][2];
243  a[2][1] ^= ~a[2][2] & a[2][3];
244  a[2][2] ^= ~a[2][3] & a[2][4];
245  a[2][3] ^= ~a[2][4] & temp1;
246  a[2][4] ^= ~temp1 & temp2;
247 
248  temp1 = a[3][0];
249  temp2 = a[3][1];
250  a[3][0] ^= ~a[3][1] & a[3][2];
251  a[3][1] ^= ~a[3][2] & a[3][3];
252  a[3][2] ^= ~a[3][3] & a[3][4];
253  a[3][3] ^= ~a[3][4] & temp1;
254  a[3][4] ^= ~temp1 & temp2;
255 
256  temp1 = a[4][0];
257  temp2 = a[4][1];
258  a[4][0] ^= ~a[4][1] & a[4][2];
259  a[4][1] ^= ~a[4][2] & a[4][3];
260  a[4][2] ^= ~a[4][3] & a[4][4];
261  a[4][3] ^= ~a[4][4] & temp1;
262  a[4][4] ^= ~temp1 & temp2;
263 }
264 
265 
266 /**
267  * @brief Apply iota transformation
268  * @param[in,out] a State array
269  * @param[index] round Round index
270  **/
271 
272 static void iota(keccak_lane_t a[5][5], uint_t index)
273 {
274  //The iota transformation is parameterized by the round index
275  a[0][0] ^= rc[index];
276 }
277 
278 
279 /**
280  * @brief Initialize Keccak context
281  * @param[in] context Pointer to the Keccak context to initialize
282  * @param[in] capacity Capacity of the sponge function
283  **/
284 
286 {
287  uint_t rate;
288 
289  //Make sure the Keccak context is valid
290  if(context == NULL)
292 
293  //Clear Keccak context
294  osMemset(context, 0, sizeof(KeccakContext));
295 
296  //The capacity cannot exceed the width of a Keccak-p permutation
297  if(capacity >= KECCAK_B_BITS)
299 
300  //The rate depends on the capacity of the sponge function
301  rate = KECCAK_B_BITS - capacity;
302 
303  //The rate must be multiple of the lane size
304  if((rate % KECCAK_W_BITS) != 0)
306 
307  //Save the block size, in bytes
308  context->blockSize = rate / 8;
309 
310  //Successful initialization
311  return NO_ERROR;
312 }
313 
314 
315 /**
316  * @brief Absorb data
317  * @param[in] context Pointer to the Keccak context
318  * @param[in] input Pointer to the buffer being hashed
319  * @param[in] length Length of the buffer
320  **/
321 
322 __weak_func void keccakAbsorb(KeccakContext *context, const void *input,
323  size_t length)
324 {
325  uint_t i;
326  size_t n;
327  keccak_lane_t *a;
328 
329  //Point to the state array
330  a = (keccak_lane_t *) context->a;
331 
332  //Absorbing phase
333  while(length > 0)
334  {
335  //Limit the number of bytes to process at a time
336  n = MIN(length, context->blockSize - context->length);
337 
338  //Copy the data to the buffer
339  osMemcpy(context->buffer + context->length, input, n);
340  //Adjust the length of the buffer
341  context->length += n;
342 
343  //Advance the data pointer
344  input = (uint8_t *) input + n;
345  //Remaining bytes to process
346  length -= n;
347 
348  //Absorb the message block by block
349  if(context->length == context->blockSize)
350  {
351  //Absorb the current block
352  for(i = 0; i < context->blockSize / KECCAK_W_BYTES; i++)
353  {
354  a[i] ^= KECCAK_LOAD_LANE(context->buffer + i * KECCAK_W_BYTES);
355  }
356 
357  //Apply block permutation function
358  keccakPermutBlock(context);
359 
360  //The input buffer is empty
361  context->length = 0;
362  }
363  }
364 }
365 
366 
367 /**
368  * @brief Finish absorbing phase
369  * @param[in] context Pointer to the Keccak context
370  * @param[in] pad Padding byte used for domain separation
371  **/
372 
373 void keccakFinal(KeccakContext *context, uint8_t pad)
374 {
375  uint_t i;
376  size_t q;
377  keccak_lane_t *a;
378 
379  //Point to the state array
380  a = (keccak_lane_t *) context->a;
381 
382  //Compute the number of padding bytes
383  q = context->blockSize - context->length;
384 
385  //Append padding
386  osMemset(context->buffer + context->length, 0, q);
387  context->buffer[context->length] |= pad;
388  context->buffer[context->blockSize - 1] |= 0x80;
389 
390  //Absorb the final block
391  for(i = 0; i < context->blockSize / KECCAK_W_BYTES; i++)
392  {
393  a[i] ^= KECCAK_LOAD_LANE(context->buffer + i * KECCAK_W_BYTES);
394  }
395 
396  //Apply block permutation function
397  keccakPermutBlock(context);
398 
399  //Convert lanes to little-endian byte order
400  for(i = 0; i < context->blockSize / KECCAK_W_BYTES; i++)
401  {
402  KECCAK_STORE_LANE(a[i], context->buffer + i * KECCAK_W_BYTES);
403  }
404 
405  //Number of bytes available in the output buffer
406  context->length = context->blockSize;
407 }
408 
409 
410 /**
411  * @brief Extract data from the squeezing phase
412  * @param[in] context Pointer to the Keccak context
413  * @param[out] output Output string
414  * @param[in] length Desired output length, in bytes
415  **/
416 
417 void keccakSqueeze(KeccakContext *context, uint8_t *output, size_t length)
418 {
419  uint_t i;
420  size_t n;
421  keccak_lane_t *a;
422 
423  //Point to the state array
424  a = (keccak_lane_t *) context->a;
425 
426  //An arbitrary number of output bits can be squeezed out of the state
427  while(length > 0)
428  {
429  //Check whether more data is required
430  if(context->length == 0)
431  {
432  //Apply block permutation function
433  keccakPermutBlock(context);
434 
435  //Convert lanes to little-endian byte order
436  for(i = 0; i < context->blockSize / KECCAK_W_BYTES; i++)
437  {
438  KECCAK_STORE_LANE(a[i], context->buffer + i * KECCAK_W_BYTES);
439  }
440 
441  //Number of bytes available in the output buffer
442  context->length = context->blockSize;
443  }
444 
445  //Compute the number of bytes to process at a time
446  n = MIN(length, context->length);
447 
448  //Copy the output string
449  if(output != NULL)
450  {
451  osMemcpy(output, context->buffer + context->blockSize -
452  context->length, n);
453  }
454 
455  //Number of bytes available in the output buffer
456  context->length -= n;
457 
458  //Advance the data pointer
459  output = (uint8_t *) output + n;
460  //Number of bytes that remains to be written
461  length -= n;
462  }
463 }
464 
465 
466 /**
467  * @brief Block permutation
468  * @param[in] context Pointer to the Keccak context
469  **/
470 
471 __weak_func void keccakPermutBlock(KeccakContext *context)
472 {
473  uint_t i;
474 
475  //Each round consists of a sequence of five transformations, which are
476  //called the step mappings
477  for(i = 0; i < KECCAK_NR; i++)
478  {
479  //Apply theta step mapping
480  theta(context->a);
481  //Apply rho step mapping
482  rho(context->a);
483  //Apply pi step mapping
484  pi(context->a);
485  //Apply chi step mapping
486  chi(context->a);
487  //Apply iota step mapping
488  iota(context->a, i);
489  }
490 }
491 
492 #endif
#define KECCAK_ROL(a, n)
Definition: keccak.h:74
keccak_lane_t a[5][5]
Definition: keccak.h:117
__weak_func void keccakPermutBlock(KeccakContext *context)
Block permutation.
Definition: keccak.c:471
uint8_t a
Definition: ndp.h:411
#define KECCAK_W_BYTES
Definition: keccak.h:86
Keccak context.
Definition: keccak.h:116
void keccakFinal(KeccakContext *context, uint8_t pad)
Finish absorbing phase.
Definition: keccak.c:373
uint8_t buffer[24 *KECCAK_W_BYTES]
Definition: keccak.h:118
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define osMemcpy(dest, src, length)
Definition: os_port.h:144
error_t
Error codes.
Definition: error.h:43
General definitions for cryptographic algorithms.
#define KECCAK_B_BITS
Definition: keccak.h:89
uint8_t length
Definition: tcp.h:375
__weak_func void keccakAbsorb(KeccakContext *context, const void *input, size_t length)
Absorb data.
Definition: keccak.c:322
#define MIN(a, b)
Definition: os_port.h:63
#define KECCAK_LOAD_LANE(p)
Definition: keccak.h:76
void keccakSqueeze(KeccakContext *context, uint8_t *output, size_t length)
Extract data from the squeezing phase.
Definition: keccak.c:417
#define KECCAK_NR
Definition: keccak.h:94
#define keccak_lane_t
Definition: keccak.h:72
Keccak sponge function.
uint8_t n
uint_t blockSize
Definition: keccak.h:119
size_t length
Definition: keccak.h:120
#define KECCAK_W_BITS
Definition: keccak.h:84
#define KECCAK_STORE_LANE(a, p)
Definition: keccak.h:78
error_t keccakInit(KeccakContext *context, uint_t capacity)
Initialize Keccak context.
Definition: keccak.c:285
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
@ NO_ERROR
Success.
Definition: error.h:44
uint8_t c
Definition: ndp.h:514