libxcks  0.1.0.1
keccak.cpp
Go to the documentation of this file.
1 /*
2  * libxcks
3  * Copyright (C) 2022 Julien Couot
4  *
5  * This program is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13  * License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
24 //---------------------------------------------------------------------------
25 #include <cstring>
26 #include <cassert>
27 
28 #include "keccak.hpp"
29 //---------------------------------------------------------------------------
30 
32 using namespace std;
33 //---------------------------------------------------------------------------
34 
35 
36 namespace libxcks
37 {
38 //###########################################################################
39 // Implementation of AbstractKeccakImpl
40 //###########################################################################
41 
45 AbstractKeccakImpl::AbstractKeccakImpl(const unsigned size,
46  const bool isSHA3Hash) :
47  capacityWords((2 * size) / sizeof(uint64_t)), useSHA3Hash(isSHA3Hash)
48 {
49  reset();
50 }
51 //---------------------------------------------------------------------------
52 
53 /*
54  * Resets the Keccak hash to initial value.
55  */
57 {
58  saved = UINT64_C(0);
59  memset(state, 0, SHA3_KECCAK_SPONGE_WORDS * sizeof(uint64_t));
60  byteIndex = 0;
61  wordIndex = 0;
62 }
63 //---------------------------------------------------------------------------
64 
65 
66 /*
67  * Updates the Keccak hash with specified array of bytes.
68  */
69 void AbstractKeccakImpl::update(const uint8_t* buf, size_t len)
70 {
71  // 0...7 -- how much is needed to have a word
72  size_t old_tail = (8 - byteIndex) & 7;
73 
74  size_t words;
75  unsigned tail;
76  size_t i;
77 
78  assert(byteIndex < 8);
79  assert(wordIndex < sizeof(state) / sizeof(state[0]));
80 
81  if (len < old_tail) // have no complete word or haven't started the word yet
82  {
83  // Endian-independent code follows:
84  while (len--)
85  saved |= (uint64_t) (*(buf++)) << ((byteIndex++) * 8);
86  assert(byteIndex < 8);
87  return;
88  }
89 
90  if (old_tail) // will have one word to process
91  {
92  // Endian-independent code follows:
93  len -= old_tail;
94  while (old_tail--)
95  saved |= (uint64_t) (*(buf++)) << ((byteIndex++) * 8);
96 
97  // Now ready to add saved to the sponge
98  state[wordIndex] ^= saved;
99  assert(byteIndex == 8);
100  byteIndex = 0;
101  saved = 0;
103  {
104  transform();
105  wordIndex = 0;
106  }
107  }
108 
109  // Now work in full words directly from input
110  assert(byteIndex == 0);
111 
112  words = len / sizeof(uint64_t);
113  tail = len - words * sizeof(uint64_t);
114 
115  for (i = 0; i < words; i++, buf += sizeof(uint64_t))
116  {
117  const uint64_t t = (uint64_t) (buf[0]) |
118  ((uint64_t) (buf[1]) << 8 * 1) |
119  ((uint64_t) (buf[2]) << 8 * 2) |
120  ((uint64_t) (buf[3]) << 8 * 3) |
121  ((uint64_t) (buf[4]) << 8 * 4) |
122  ((uint64_t) (buf[5]) << 8 * 5) |
123  ((uint64_t) (buf[6]) << 8 * 6) |
124  ((uint64_t) (buf[7]) << 8 * 7);
125  #if defined(__x86_64__ ) || defined(__i386__)
126  assert(memcmp(&t, buf, 8) == 0);
127  #endif
128  state[wordIndex] ^= t;
130  {
131  transform();
132  wordIndex = 0;
133  }
134  }
135 
136  // Finally, save the partial word
137  assert(byteIndex == 0 && tail < 8);
138  while (tail--)
139  saved |= (uint64_t) (*(buf++)) << ((byteIndex++) * 8);
140  assert(byteIndex < 8);
141 }
142 //---------------------------------------------------------------------------
143 
144 
145 /*
146  * Process a full block.
147  */
148 void AbstractKeccakImpl::transform()
149 {
150  static constexpr int KECCAK_ROUNDS = 24;
151  static const uint64_t keccakf_rndc[KECCAK_ROUNDS] = {
152  UINT64_C(0x0000000000000001), UINT64_C(0x0000000000008082),
153  UINT64_C(0x800000000000808a), UINT64_C(0x8000000080008000),
154  UINT64_C(0x000000000000808b), UINT64_C(0x0000000080000001),
155  UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008009),
156  UINT64_C(0x000000000000008a), UINT64_C(0x0000000000000088),
157  UINT64_C(0x0000000080008009), UINT64_C(0x000000008000000a),
158  UINT64_C(0x000000008000808b), UINT64_C(0x800000000000008b),
159  UINT64_C(0x8000000000008089), UINT64_C(0x8000000000008003),
160  UINT64_C(0x8000000000008002), UINT64_C(0x8000000000000080),
161  UINT64_C(0x000000000000800a), UINT64_C(0x800000008000000a),
162  UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008080),
163  UINT64_C(0x0000000080000001), UINT64_C(0x8000000080008008)
164  };
165 
166  static const unsigned keccakf_rotc[KECCAK_ROUNDS] = {
167  1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62,
168  18, 39, 61, 20, 44 };
169 
170  static const unsigned keccakf_piln[KECCAK_ROUNDS] = {
171  10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20,
172  14, 22, 9, 6, 1 };
173 
174  int i, j, round;
175  uint64_t t, bc[5];
176 
177  for (round = 0; round < KECCAK_ROUNDS; round++)
178  {
179  // Theta
180  for (i = 0; i < 5; i++)
181  bc[i] = state[i] ^ state[i + 5] ^ state[i + 10] ^ state[i + 15] ^ state[i + 20];
182 
183  for (i = 0; i < 5; i++)
184  {
185  t = bc[(i + 4) % 5] ^ rol(bc[(i + 1) % 5], 1);
186  for (j = 0; j < 25; j += 5)
187  state[j + i] ^= t;
188  }
189 
190  // Rho Pi
191  t = state[1];
192  for (i = 0; i < 24; i++)
193  {
194  j = keccakf_piln[i];
195  bc[0] = state[j];
196  state[j] = rol(t, keccakf_rotc[i]);
197  t = bc[0];
198  }
199 
200  // Chi
201  for (j = 0; j < 25; j += 5)
202  {
203  for (i = 0; i < 5; i++)
204  bc[i] = state[j + i];
205  for (i = 0; i < 5; i++)
206  state[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5];
207  }
208 
209  // Iota
210  state[0] ^= keccakf_rndc[round];
211  }
212 }
213 //---------------------------------------------------------------------------
214 
215 
216 /*
217  * Process the remaining bytes in the internal buffer and the usual
218  * prolog according to the standard.
219  */
221 {
222  /* Append 2-bit suffix 01, per SHA-3 spec. Instead of 1 for padding we
223  * use 1<<2 below. The 0x02 below corresponds to the suffix 01.
224  * Overall, we feed 0, then 1, and finally 1 to start padding. Without
225  * M || 01, we would simply use 1 to start padding. */
226 
227  uint64_t t;
228 
229  if (!useSHA3Hash)
230  // Keccak version
231  t = (uint64_t)(((uint64_t) 1) << (byteIndex * 8));
232  else // SHA3 version
233  t = (uint64_t)(((uint64_t)(0x02 | (1 << 2))) << ((byteIndex) * 8));
234 
235  state[wordIndex] ^= saved ^ t;
236  state[SHA3_KECCAK_SPONGE_WORDS - capacityWords - 1] ^= UINT64_C(0x8000000000000000);
237  transform();
238 
239  /* Return first bytes of the ctx->s. This conversion is not needed for
240  * little-endian platforms e.g. wrap with #if !defined(__BYTE_ORDER__)
241  * || !defined(__ORDER_LITTLE_ENDIAN__) || __BYTE_ORDER__!=__ORDER_LITTLE_ENDIAN__
242  * ... the conversion below ...
243  * #endif */
244  #if (LIBXCKS_BYTE_ORDER != LIBXCKS_LITTLE_ENDIAN)
245  for (unsigned i = 0; i < SHA3_KECCAK_SPONGE_WORDS; i++)
246  swapOnBE(state[i]);
247  #endif
248 }
249 //---------------------------------------------------------------------------
250 
251 
252 
253 //###########################################################################
254 // Implementation of SHA3-224
255 //###########################################################################
256 
257 /*
258  * Returns the SHA3-224 hash value in the first 28 bytes of the given address.
259  */
260 uint8_t* SHA3_224::getValue(uint8_t* buffer) const
261 {
262  SHA3_224 sha3_224(*this);
263  sha3_224.finish();
264 
265  memcpy(buffer, sha3_224.state, getSize());
266 
267  return buffer;
268 }
269 //---------------------------------------------------------------------------
270 
271 
272 /*
273  * Returns the alternative names of the SHA3-224 hash algorithm.
274  */
276 {
277  return ArrayString{ "SHA-3-224" };
278 }
279 //---------------------------------------------------------------------------
280 
281 
282 
283 //###########################################################################
284 // Implementation of SHA3-256
285 //###########################################################################
286 
287 /*
288  * Returns the SHA3-256 hash value in the first 32 bytes of the given address.
289  */
290 uint8_t* SHA3_256::getValue(uint8_t* buffer) const
291 {
292  SHA3_256 sha3_256(*this);
293  sha3_256.finish();
294 
295  memcpy(buffer, sha3_256.state, getSize());
296 
297  return buffer;
298 }
299 //---------------------------------------------------------------------------
300 
301 
302 /*
303  * Returns the alternative names of the SHA3-256 hash algorithm.
304  */
306 {
307  return ArrayString{ "SHA-3-256" };
308 }
309 //---------------------------------------------------------------------------
310 
311 
312 
313 //###########################################################################
314 // Implementation of SHA3-384
315 //###########################################################################
316 
317 /*
318  * Returns the SHA3-384 hash value in the first 48 bytes of the given address.
319  */
320 uint8_t* SHA3_384::getValue(uint8_t* buffer) const
321 {
322  SHA3_384 sha3_384(*this);
323  sha3_384.finish();
324 
325  memcpy(buffer, sha3_384.state, getSize());
326 
327  return buffer;
328 }
329 //---------------------------------------------------------------------------
330 
331 
332 /*
333  * Returns the alternative names of the SHA3-384 hash algorithm.
334  */
336 {
337  return ArrayString{ "SHA-3-384" };
338 }
339 //---------------------------------------------------------------------------
340 
341 
342 
343 //###########################################################################
344 // Implementation of SHA3-512
345 //###########################################################################
346 
347 /*
348  * Returns the SHA3-512 hash value in the first 64 bytes of the given address.
349  */
350 uint8_t* SHA3_512::getValue(uint8_t* buffer) const
351 {
352  SHA3_512 sha3_512(*this);
353  sha3_512.finish();
354 
355  memcpy(buffer, sha3_512.state, getSize());
356 
357  return buffer;
358 }
359 //---------------------------------------------------------------------------
360 
361 
362 /*
363  * Returns the alternative names of the SHA3-512 hash algorithm.
364  */
366 {
367  return ArrayString{ "SHA-3-512" };
368 }
369 //---------------------------------------------------------------------------
370 
371 
372 #if 0
373 //###########################################################################
374 // Implementation of Keccak-224
375 //###########################################################################
376 
377 /*
378  * Returns the Keccak-224 hash value in the first 28 bytes of the given address.
379  */
380 uint8_t* Keccak224::getValue(uint8_t* buffer) const
381 {
382  Keccak224 keccak224(*this);
383  keccak224.finish();
384 
385  memcpy(buffer, keccak224.state, getSize());
386 
387  return buffer;
388 }
389 //---------------------------------------------------------------------------
390 
391 
392 /*
393  * Returns the alternative names of the Keccak-224 hash algorithm.
394  */
395 ArrayString Keccak224::getAlternativeNames()
396 {
397  return ArrayString{ "Keccak-224" };
398 }
399 //---------------------------------------------------------------------------
400 
401 
402 
403 //###########################################################################
404 // Implementation of Keccak-256
405 //###########################################################################
406 
407 /*
408  * Returns the Keccak-256 hash value in the first 32 bytes of the given address.
409  */
410 uint8_t* Keccak256::getValue(uint8_t* buffer) const
411 {
412  Keccak256 keccak256(*this);
413  keccak256.finish();
414 
415  memcpy(buffer, keccak256.state, getSize());
416 
417  return buffer;
418 }
419 //---------------------------------------------------------------------------
420 
421 
422 /*
423  * Returns the alternative names of the Keccak-256 hash algorithm.
424  */
425 ArrayString Keccak256::getAlternativeNames()
426 {
427  return ArrayString{ "Keccak-256" };
428 }
429 //---------------------------------------------------------------------------
430 
431 
432 
433 //###########################################################################
434 // Implementation of Keccak-384
435 //###########################################################################
436 
437 /*
438  * Returns the Keccak-384 hash value in the first 48 bytes of the given address.
439  */
440 uint8_t* Keccak384::getValue(uint8_t* buffer) const
441 {
442  Keccak384 keccak384(*this);
443  keccak384.finish();
444 
445  memcpy(buffer, keccak384.state, getSize());
446 
447  return buffer;
448 }
449 //---------------------------------------------------------------------------
450 
451 
452 /*
453  * Returns the alternative names of the Keccak-384 hash algorithm.
454  */
455 ArrayString Keccak384::getAlternativeNames()
456 {
457  return ArrayString{ "Keccak-384" };
458 }
459 //---------------------------------------------------------------------------
460 
461 
462 
463 //###########################################################################
464 // Implementation of Keccak-512
465 //###########################################################################
466 
467 /*
468  * Returns the Keccak-512 hash value in the first 64 bytes of the given address.
469  */
470 uint8_t* Keccak512::getValue(uint8_t* buffer) const
471 {
472  Keccak512 keccak512(*this);
473  keccak512.finish();
474 
475  memcpy(buffer, keccak512.state, getSize());
476 
477  return buffer;
478 }
479 //---------------------------------------------------------------------------
480 
481 
482 /*
483  * Returns the alternative names of the Keccak-512 hash algorithm.
484  */
485 ArrayString Keccak512::getAlternativeNames()
486 {
487  return ArrayString{ "Keccak-512" };
488 }
489 //---------------------------------------------------------------------------
490 #endif
491 } // namespace libxcks
492 //---------------------------------------------------------------------------
void update(const uint8_t *buf, size_t len) override final
Updates the Keccak hash with specified array of bytes.
Definition: keccak.cpp:69
const bool useSHA3Hash
true if result is SHA3 hash, false if "original" Keccak hash.
Definition: keccak.hpp:54
unsigned byteIndex
0..7–the next byte after the set one (starts from 0; 0–none are buffered).
Definition: keccak.hpp:51
unsigned wordIndex
0..24–the next word to integrate input (starts from 0).
Definition: keccak.hpp:52
void reset() override final
Resets the Keccak hash to initial value.
Definition: keccak.cpp:56
uint64_t state[SHA3_KECCAK_SPONGE_WORDS]
Keccak's state in 'words'.
Definition: keccak.hpp:50
void finish()
Process the remaining bytes in the internal buffer and the usual prolog according to the standard.
Definition: keccak.cpp:220
static constexpr unsigned SHA3_KECCAK_SPONGE_WORDS
'Words' here refers to uint64_t
Definition: keccak.hpp:47
uint64_t saved
The portion of the input message that we didn't consume yet.
Definition: keccak.hpp:49
const unsigned capacityWords
The double size of the hash output in words (e.g. 16 for Keccak 512).
Definition: keccak.hpp:53
static uint32_t swapOnBE(const uint32_t value)
Swaps bytes on big endian architectures.
Definition: checksumex.hpp:120
Computes the SHA3-224 hash from a byte stream.
Definition: keccak.hpp:135
size_t getSize() const override final
Returns the minimal size to allocate in memory to store the hash with the getValue(buffer) method.
Definition: keccak.hpp:159
uint8_t * getValue(uint8_t *buffer) const override
Returns the SHA3-224 hash value in the first 28 bytes of the given address.
Definition: keccak.cpp:260
static ArrayString getAlternativeNames()
Returns the alternative names of the SHA3-224 hash algorithm.
Definition: keccak.cpp:275
Computes the SHA3-256 hash from a byte stream.
Definition: keccak.hpp:264
static ArrayString getAlternativeNames()
Returns the alternative names of the SHA3-256 hash algorithm.
Definition: keccak.cpp:305
size_t getSize() const override final
Returns the minimal size to allocate in memory to store the hash with the getValue(buffer) method.
Definition: keccak.hpp:288
uint8_t * getValue(uint8_t *buffer) const override
Returns the SHA3-256 hash value in the first 32 bytes of the given address.
Definition: keccak.cpp:290
Computes the SHA3-384 hash from a byte stream.
Definition: keccak.hpp:393
size_t getSize() const override final
Returns the minimal size to allocate in memory to store the hash with the getValue(buffer) method.
Definition: keccak.hpp:417
uint8_t * getValue(uint8_t *buffer) const override final
Returns the SHA3-384 hash value in the first 48 bytes of the given address.
Definition: keccak.cpp:320
static ArrayString getAlternativeNames()
Returns the alternative names of the SHA3-384 hash algorithm.
Definition: keccak.cpp:335
Computes the SHA3-512 hash from a byte stream.
Definition: keccak.hpp:522
static ArrayString getAlternativeNames()
Returns the alternative names of the SHA3-512 hash algorithm.
Definition: keccak.cpp:365
uint8_t * getValue(uint8_t *buffer) const override final
Returns the SHA3-512 hash value in the first 64 bytes of the given address.
Definition: keccak.cpp:350
size_t getSize() const override final
Returns the minimal size to allocate in memory to store the hash with the getValue(buffer) method.
Definition: keccak.hpp:546
Compute Keccak and SHA3 hashes.
std::vector< std::string > ArrayString
Array of strings.
Definition: types.hpp:44