Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
SHA3HashAlgorithm.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* SHA3HashAlgorithm.cc (C) 2000-2024 */
9/* */
10/* Calcule de fonction de hashage SHA-3. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/Array.h"
15#include "arcane/utils/FatalErrorException.h"
16#include "arcane/utils/SHA3HashAlgorithm.h"
17
18#include <cstring>
19
20// L'algorithme est decrit ici;
21// https://en.wikipedia.org/wiki/SHA-3
22
23// L'implémentation est issue du dépot suivant:
24// https : //github.com/rhash/RHash
25
26/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak).
27 * based on the
28 * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011
29 * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche
30 *
31 * Copyright (c) 2013, Aleksey Kravchenko <rhash.admin@gmail.com>
32 *
33 * Permission to use, copy, modify, and/or distribute this software for any
34 * purpose with or without fee is hereby granted.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
37 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
38 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
39 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
40 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
41 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
42 * PERFORMANCE OF THIS SOFTWARE.
43 */
44
45/*---------------------------------------------------------------------------*/
46/*---------------------------------------------------------------------------*/
47
48namespace Arcane
49{
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
54} // namespace Arcane
55
56namespace Arcane::SHA3Algorithm
57{
58
59namespace
60{
61 // constants
62 constexpr int sha3_max_permutation_size = 25;
63 constexpr int sha3_max_rate_in_qwords = 24;
64
65 constexpr int NumberOfRounds = 24;
66
67 //! SHA3 (Keccak) constants for 24 rounds
68 constexpr uint64_t keccak_round_constants[NumberOfRounds] = {
69 0x0000000000000001, 0x0000000000008082, 0x800000000000808A, 0x8000000080008000,
70 0x000000000000808B, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009,
71 0x000000000000008A, 0x0000000000000088, 0x0000000080008009, 0x000000008000000A,
72 0x000000008000808B, 0x800000000000008B, 0x8000000000008089, 0x8000000000008003,
73 0x8000000000008002, 0x8000000000000080, 0x000000000000800A, 0x800000008000000A,
74 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008
75 };
76
77 // ROTL/ROTR rotate a 64-bit word left by n bits
78 static uint64_t _rotateLeft(uint64_t qword, int n)
79 {
80 return ((qword) << (n) ^ ((qword) >> (64 - (n))));
81 }
82} // namespace
83
84class SHA3
85{
86
87 //! Algorithm context.
88 struct sha3_ctx
89 {
90 /* 1600 bits algorithm hashing state */
91 uint64_t hash[sha3_max_permutation_size];
92 /* 1536-bit buffer for leftovers */
93 uint64_t message[sha3_max_rate_in_qwords];
94 /* count of bytes in the message[] buffer */
95 unsigned int rest;
96 /* size of a message block processed at once */
97 unsigned int block_size;
98 };
99 sha3_ctx m_context;
100
101 public:
102
103 void keccak_init(unsigned int bits);
104 void sha3_224_init();
105 void sha3_256_init();
106 void sha3_384_init();
107 void sha3_512_init();
108
109 static void keccak_theta(uint64_t* A);
110 static void keccak_pi(uint64_t* A);
111 static void keccak_chi(uint64_t* A);
112 static void sha3_permutation(uint64_t* state);
113 static void sha3_process_block(uint64_t hash[25], const uint64_t* block, size_t block_size);
115 void sha3_final(ByteArray& output_hash);
116};
117
118// Valide pour little-endian
119//@{
120#define le2me_64(x) (x)
121#define me64_to_le_str(to, from, length) std::memcpy((to), (from), (length))
122//@}
123
124#define IS_ALIGNED_64(p) (0 == (7 & (uintptr_t)(p)))
125
126/*---------------------------------------------------------------------------*/
127/*---------------------------------------------------------------------------*/
128
129//! Initializing a sha3 context for given number of output bits
131keccak_init(unsigned int bits)
132{
133 /* NB: The Keccak capacity parameter = bits * 2 */
134 unsigned rate = 1600 - bits * 2;
135
136 std::memset(&m_context, 0, sizeof(sha3_ctx));
137 m_context.block_size = rate / 8;
138 bool is_ok = (rate <= 1600 && (rate % 64) == 0);
139 if (!is_ok)
140 ARCANE_FATAL("Bad value for rate '{0}'", rate);
141 // La taille de bloc est au maximum de 144 pour SHA3-224
142 // Au dela, la fonction 'sha3_process_block' ne fonctionne pas
143 if (m_context.block_size > 144)
144 ARCANE_FATAL("Block size is too big (v={0}) max_allowed=144", m_context.block_size);
145}
146
147/*---------------------------------------------------------------------------*/
148/*---------------------------------------------------------------------------*/
149/*!
150 * \brief Initialize context before calculating hash.
151 */
154{
155 keccak_init(224);
156}
157
158/*---------------------------------------------------------------------------*/
159/*---------------------------------------------------------------------------*/
160/*!
161 * \brief Initialize context before calculating hash.
162 */
165{
166 keccak_init(256);
167}
168
169/*---------------------------------------------------------------------------*/
170/*---------------------------------------------------------------------------*/
171/*!
172 * \brief Initialize context before calculating hash.
173 */
176{
177 keccak_init(384);
178}
179
180/*---------------------------------------------------------------------------*/
181/*---------------------------------------------------------------------------*/
182/*!
183 * \brief Initialize context before calculating hash.
184 */
187{
188 keccak_init(512);
189}
190
191#define XORED_A(i) A[(i)] ^ A[(i) + 5] ^ A[(i) + 10] ^ A[(i) + 15] ^ A[(i) + 20]
192#define THETA_STEP(i) \
193 A[(i)] ^= D[(i)]; \
194 A[(i) + 5] ^= D[(i)]; \
195 A[(i) + 10] ^= D[(i)]; \
196 A[(i) + 15] ^= D[(i)]; \
197 A[(i) + 20] ^= D[(i)]
198
199/*---------------------------------------------------------------------------*/
200/*---------------------------------------------------------------------------*/
201
202//! Keccak theta() transformation
204keccak_theta(uint64_t* A)
205{
206 uint64_t D[5];
207 D[0] = _rotateLeft(XORED_A(1), 1) ^ XORED_A(4);
208 D[1] = _rotateLeft(XORED_A(2), 1) ^ XORED_A(0);
209 D[2] = _rotateLeft(XORED_A(3), 1) ^ XORED_A(1);
210 D[3] = _rotateLeft(XORED_A(4), 1) ^ XORED_A(2);
211 D[4] = _rotateLeft(XORED_A(0), 1) ^ XORED_A(3);
212 THETA_STEP(0);
213 THETA_STEP(1);
214 THETA_STEP(2);
215 THETA_STEP(3);
216 THETA_STEP(4);
217}
218
219/*---------------------------------------------------------------------------*/
220/*---------------------------------------------------------------------------*/
221
222//! Keccak pi() transformation
224keccak_pi(uint64_t* A)
225{
226 uint64_t A1;
227 A1 = A[1];
228 A[1] = A[6];
229 A[6] = A[9];
230 A[9] = A[22];
231 A[22] = A[14];
232 A[14] = A[20];
233 A[20] = A[2];
234 A[2] = A[12];
235 A[12] = A[13];
236 A[13] = A[19];
237 A[19] = A[23];
238 A[23] = A[15];
239 A[15] = A[4];
240 A[4] = A[24];
241 A[24] = A[21];
242 A[21] = A[8];
243 A[8] = A[16];
244 A[16] = A[5];
245 A[5] = A[3];
246 A[3] = A[18];
247 A[18] = A[17];
248 A[17] = A[11];
249 A[11] = A[7];
250 A[7] = A[10];
251 A[10] = A1;
252 // note: A[ 0] is left as is
253}
254
255/*---------------------------------------------------------------------------*/
256/*---------------------------------------------------------------------------*/
257
258#define CHI_STEP(i) \
259 A0 = A[0 + (i)]; \
260 A1 = A[1 + (i)]; \
261 A[0 + (i)] ^= ~A1 & A[2 + (i)]; \
262 A[1 + (i)] ^= ~A[2 + (i)] & A[3 + (i)]; \
263 A[2 + (i)] ^= ~A[3 + (i)] & A[4 + (i)]; \
264 A[3 + (i)] ^= ~A[4 + (i)] & A0; \
265 A[4 + (i)] ^= ~A0 & A1
266
267/*---------------------------------------------------------------------------*/
268/*---------------------------------------------------------------------------*/
269
270//! Keccak chi() transformation
272keccak_chi(uint64_t* A)
273{
274 uint64_t A0, A1;
275 CHI_STEP(0);
276 CHI_STEP(5);
277 CHI_STEP(10);
278 CHI_STEP(15);
279 CHI_STEP(20);
280}
281
282/*---------------------------------------------------------------------------*/
283/*---------------------------------------------------------------------------*/
284
285void SHA3::
286sha3_permutation(uint64_t* state)
287{
288 int round;
289 for (round = 0; round < NumberOfRounds; round++) {
290 keccak_theta(state);
291
292 /* apply Keccak rho() transformation */
293 state[1] = _rotateLeft(state[1], 1);
294 state[2] = _rotateLeft(state[2], 62);
295 state[3] = _rotateLeft(state[3], 28);
296 state[4] = _rotateLeft(state[4], 27);
297 state[5] = _rotateLeft(state[5], 36);
298 state[6] = _rotateLeft(state[6], 44);
299 state[7] = _rotateLeft(state[7], 6);
300 state[8] = _rotateLeft(state[8], 55);
301 state[9] = _rotateLeft(state[9], 20);
302 state[10] = _rotateLeft(state[10], 3);
303 state[11] = _rotateLeft(state[11], 10);
304 state[12] = _rotateLeft(state[12], 43);
305 state[13] = _rotateLeft(state[13], 25);
306 state[14] = _rotateLeft(state[14], 39);
307 state[15] = _rotateLeft(state[15], 41);
308 state[16] = _rotateLeft(state[16], 45);
309 state[17] = _rotateLeft(state[17], 15);
310 state[18] = _rotateLeft(state[18], 21);
311 state[19] = _rotateLeft(state[19], 8);
312 state[20] = _rotateLeft(state[20], 18);
313 state[21] = _rotateLeft(state[21], 2);
314 state[22] = _rotateLeft(state[22], 61);
315 state[23] = _rotateLeft(state[23], 56);
316 state[24] = _rotateLeft(state[24], 14);
317
318 keccak_pi(state);
319 keccak_chi(state);
320
321 // apply iota(state, round)
322 *state ^= keccak_round_constants[round];
323 }
324}
325
326/*---------------------------------------------------------------------------*/
327/*---------------------------------------------------------------------------*/
328/*!
329 * \brief The core transformation. Process the specified block of data.
330 *
331 * @param hash the algorithm state
332 * @param block the message block to process
333 * @param block_size the size of the processed block in bytes
334 */
336sha3_process_block(uint64_t hash[25], const uint64_t* block, size_t block_size)
337{
338 // La taille de bloc est au maximum de 144 pour SHA3-224
339 // Cela est testé dans keccak_init().
340
341 // expanded loop
342 hash[0] ^= le2me_64(block[0]);
343 hash[1] ^= le2me_64(block[1]);
344 hash[2] ^= le2me_64(block[2]);
345 hash[3] ^= le2me_64(block[3]);
346 hash[4] ^= le2me_64(block[4]);
347 hash[5] ^= le2me_64(block[5]);
348 hash[6] ^= le2me_64(block[6]);
349 hash[7] ^= le2me_64(block[7]);
350 hash[8] ^= le2me_64(block[8]);
351 // if not sha3-512
352 if (block_size > 72) {
353 hash[9] ^= le2me_64(block[9]);
354 hash[10] ^= le2me_64(block[10]);
355 hash[11] ^= le2me_64(block[11]);
356 hash[12] ^= le2me_64(block[12]);
357 // if not sha3-384
358 if (block_size > 104) {
359 hash[13] ^= le2me_64(block[13]);
360 hash[14] ^= le2me_64(block[14]);
361 hash[15] ^= le2me_64(block[15]);
362 hash[16] ^= le2me_64(block[16]);
363 // if not sha3-256
364 if (block_size > 136) {
365 hash[17] ^= le2me_64(block[17]);
366 }
367 }
368 }
369 // make a permutation of the hash
370 sha3_permutation(hash);
371}
372
373#define SHA3_FINALIZED 0x80000000
374
375/*---------------------------------------------------------------------------*/
376/*---------------------------------------------------------------------------*/
377/*!
378 * \brief Calculate message hash.
379 *
380 * Can be called repeatedly with chunks of the message to be hashed.
381 *
382 * @param ctx the algorithm context containing current hashing state
383 * @param bytes message chunk
384 */
387{
388 sha3_ctx* ctx = &m_context;
389 const unsigned char* msg = reinterpret_cast<const unsigned char*>(bytes.data());
390 size_t size = bytes.size();
391
392 const size_t index = (size_t)ctx->rest;
393 const size_t block_size = (size_t)ctx->block_size;
394
395 if (ctx->rest & SHA3_FINALIZED)
396 return; /* too late for additional input */
397 ctx->rest = (unsigned)((ctx->rest + size) % block_size);
398
399 /* fill partial block */
400 if (index) {
401 size_t left = block_size - index;
402 std::memcpy((char*)ctx->message + index, msg, (size < left ? size : left));
403 if (size < left)
404 return;
405
406 /* process partial block */
407 sha3_process_block(ctx->hash, ctx->message, block_size);
408 msg += left;
409 size -= left;
410 }
411 while (size >= block_size) {
412 uint64_t* aligned_message_block;
413 if (IS_ALIGNED_64(msg)) {
414 /* the most common case is processing of an already aligned message
415 without copying it */
416 aligned_message_block = (uint64_t*)msg;
417 }
418 else {
419 std::memcpy(ctx->message, msg, block_size);
420 aligned_message_block = ctx->message;
421 }
422
423 sha3_process_block(ctx->hash, aligned_message_block, block_size);
424 msg += block_size;
425 size -= block_size;
426 }
427 if (size) {
428 std::memcpy(ctx->message, msg, size); /* save leftovers */
429 }
430}
431
432/*---------------------------------------------------------------------------*/
433/*---------------------------------------------------------------------------*/
434/*!
435 * \brief Store calculated hash into the given array.
436 *
437 * @param output_hash calculated hash in binary form
438 */
440sha3_final(ByteArray& output_hash)
441{
442 sha3_ctx* ctx = &m_context;
443 size_t digest_length = 100 - ctx->block_size / 2;
444 const size_t block_size = ctx->block_size;
445 output_hash.resize(digest_length);
446 auto* result = reinterpret_cast<unsigned char*>(output_hash.data());
447
448 if (!(ctx->rest & SHA3_FINALIZED)) {
449 // clear the rest of the data queue
450 std::memset((char*)ctx->message + ctx->rest, 0, block_size - ctx->rest);
451 ((char*)ctx->message)[ctx->rest] |= 0x06;
452 ((char*)ctx->message)[block_size - 1] |= (char)0x80;
453
454 // process final block
455 sha3_process_block(ctx->hash, ctx->message, block_size);
456 ctx->rest = SHA3_FINALIZED; // mark context as finalized
457 }
458
459 if (block_size <= digest_length)
460 ARCANE_FATAL("Bad value: block_size={0} digest_length={1}", block_size, digest_length);
461
462 if (result)
463 me64_to_le_str(result, ctx->hash, digest_length);
464}
465
466/*---------------------------------------------------------------------------*/
467/*---------------------------------------------------------------------------*/
468
469} // namespace Arcane::SHA3Algorithm
470
471/*---------------------------------------------------------------------------*/
472/*---------------------------------------------------------------------------*/
473
474namespace Arcane
475{
476
477/*---------------------------------------------------------------------------*/
478/*---------------------------------------------------------------------------*/
479
480void SHA3HashAlgorithm::
481_computeHash64(Span<const std::byte> input, ByteArray& output)
482{
483 using namespace SHA3Algorithm;
484
485 SHA3 sha3;
486 this->_initialize(sha3);
487 sha3.sha3_update(input);
488 sha3.sha3_final(output);
489}
490
491/*---------------------------------------------------------------------------*/
492/*---------------------------------------------------------------------------*/
493
496{
497 Span<const Byte> input64(input);
498 return _computeHash64(asBytes(input64), output);
499}
500
501/*---------------------------------------------------------------------------*/
502/*---------------------------------------------------------------------------*/
503
506{
507 Span<const std::byte> bytes(asBytes(input));
508 return _computeHash64(bytes, output);
509}
510
511/*---------------------------------------------------------------------------*/
512/*---------------------------------------------------------------------------*/
513
516{
517 return _computeHash64(input, output);
518}
519
520/*---------------------------------------------------------------------------*/
521/*---------------------------------------------------------------------------*/
522
523void SHA3_256HashAlgorithm::
524_initialize(SHA3Algorithm::SHA3& sha3)
525{
526 sha3.sha3_256_init();
527}
528
529/*---------------------------------------------------------------------------*/
530/*---------------------------------------------------------------------------*/
531
532void SHA3_224HashAlgorithm::
533_initialize(SHA3Algorithm::SHA3& sha3)
534{
535 sha3.sha3_224_init();
536}
537
538/*---------------------------------------------------------------------------*/
539/*---------------------------------------------------------------------------*/
540
541void SHA3_384HashAlgorithm::
542_initialize(SHA3Algorithm::SHA3& sha3)
543{
544 sha3.sha3_384_init();
545}
546
547/*---------------------------------------------------------------------------*/
548/*---------------------------------------------------------------------------*/
549
550void SHA3_512HashAlgorithm::
551_initialize(SHA3Algorithm::SHA3& sha3)
552{
553 sha3.sha3_512_init();
554}
555
556/*---------------------------------------------------------------------------*/
557/*---------------------------------------------------------------------------*/
558
559} // namespace Arcane
560
561/*---------------------------------------------------------------------------*/
562/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
void sha3_512_init()
Initialize context before calculating hash.
static void keccak_pi(uint64_t *A)
Keccak pi() transformation.
void sha3_224_init()
Initialize context before calculating hash.
static void sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size)
The core transformation. Process the specified block of data.
static void keccak_theta(uint64_t *A)
Keccak theta() transformation.
void sha3_384_init()
Initialize context before calculating hash.
void sha3_256_init()
Initialize context before calculating hash.
void sha3_final(ByteArray &output_hash)
Store calculated hash into the given array.
void keccak_init(unsigned int bits)
Initializing a sha3 context for given number of output bits.
static void keccak_chi(uint64_t *A)
Keccak chi() transformation.
void sha3_update(Span< const std::byte > bytes)
Calculate message hash.
void computeHash64(Span< const Byte > input, ByteArray &output) final
Calcule la valeur du hash pour le tableau input.
void computeHash(ByteConstArrayView input, ByteArray &output) final
Calcule la valeur du hash pour le tableau input.
Classe de base des vecteurs 1D de données.
const T * data() const
Accès à la racine du tableau hors toute protection.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
Vue constante d'un tableau de type T.
constexpr __host__ __device__ SizeType size() const noexcept
Retourne la taille du tableau.
Definition Span.h:209
constexpr __host__ __device__ pointer data() const noexcept
Pointeur sur le début de la vue.
Definition Span.h:419
Vue d'un tableau d'éléments de type T.
Definition Span.h:510
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-