1//
2// SHA3Engine.cpp
3//
4// Library: Foundation
5// Package: Crypt
6// Module: SHA3Engine
7//
8// Code of class SHA3Engine.
9//
10/// This class implements the SHA-3 message digest algorithm.
11/// (FIPS 202, see http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf)
12//
13// Based on the Keccak Code Package (public domain)
14// https://github.com/gvanas/KeccakCodePackage
15//
16// Copyright (c) 2017, Applied Informatics Software Engineering GmbH
17// and Contributors.
18//
19// SPDX-License-Identifier: BSL-1.0
20//
21
22#include "Poco/SHA3Engine.h"
23#include <string.h>
24#include <assert.h>
25
26namespace Poco {
27
28#ifdef _MSC_VER
29#pragma intrinsic(memcpy)
30#endif
31
32 #if defined(__GNUC__)
33#define ALIGN(x) __attribute__ ((aligned(x)))
34#elif defined(_MSC_VER)
35#define ALIGN(x) __declspec(align(x))
36#elif defined(__ARMCC_VERSION)
37#define ALIGN(x) __align(x)
38#else
39#define ALIGN(x)
40#endif
41
42#ifdef POCO_PTR_IS_64_BIT
43static const UInt64 KeccakRoundConstants[24] =
44{
45 0x0000000000000001,
46 0x0000000000008082,
47 0x800000000000808a,
48 0x8000000080008000,
49 0x000000000000808b,
50 0x0000000080000001,
51 0x8000000080008081,
52 0x8000000000008009,
53 0x000000000000008a,
54 0x0000000000000088,
55 0x0000000080008009,
56 0x000000008000000a,
57 0x000000008000808b,
58 0x800000000000008b,
59 0x8000000000008089,
60 0x8000000000008003,
61 0x8000000000008002,
62 0x8000000000000080,
63 0x000000000000800a,
64 0x800000008000000a,
65 0x8000000080008081,
66 0x8000000000008080,
67 0x0000000080000001,
68 0x8000000080008008,
69};
70static const unsigned int KeccakRhoOffsets[25] =
71{
72 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14
73};
74#define KeccakP1600_stateAlignment 8
75#else
76static const UInt32 KeccakRoundConstants[24][2] =
77{
78 0x00000001, 0x00000000,
79 0x00000000, 0x00000089,
80 0x00000000, 0x8000008B,
81 0x00000000, 0x80008080,
82 0x00000001, 0x0000008B,
83 0x00000001, 0x00008000,
84 0x00000001, 0x80008088,
85 0x00000001, 0x80000082,
86 0x00000000, 0x0000000B,
87 0x00000000, 0x0000000A,
88 0x00000001, 0x00008082,
89 0x00000000, 0x00008003,
90 0x00000001, 0x0000808B,
91 0x00000001, 0x8000000B,
92 0x00000001, 0x8000008A,
93 0x00000001, 0x80000081,
94 0x00000000, 0x80000081,
95 0x00000000, 0x80000008,
96 0x00000000, 0x00000083,
97 0x00000000, 0x80008003,
98 0x00000001, 0x80008088,
99 0x00000000, 0x80000088,
100 0x00000001, 0x00008000,
101 0x00000000, 0x80008082
102};
103
104static const unsigned int KeccakRhoOffsets[25] =
105{
106 0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39, 41, 45, 15, 21, 8, 18, 2, 61, 56, 14
107};
108#define KeccakP1600_stateAlignment 4
109#endif
110
111ALIGN(KeccakP1600_stateAlignment) typedef struct KeccakWidth1600_SpongeInstanceStruct
112{
113 unsigned char state[200];
114 unsigned int rate;
115 unsigned int byteIOIndex;
116 int squeezing;
117} KeccakWidth1600_SpongeInstance;
118
119typedef struct
120{
121 KeccakWidth1600_SpongeInstance sponge;
122 unsigned int fixedOutputLength;
123 unsigned char delimitedSuffix;
124} HASHCONTEXT;
125
126SHA3Engine::SHA3Engine(ALGORITHM algorithm): _context(NULL),
127 _algorithm(algorithm)
128{
129 _digest.reserve(digestLength());
130 reset();
131}
132
133SHA3Engine::~SHA3Engine()
134{
135 reset();
136 free(_context);
137}
138
139#ifdef POCO_PTR_IS_64_BIT
140void KeccakP1600_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length)
141{
142 assert(offset < 200);
143 assert(offset + length <= 200);
144 for (unsigned int i = 0; i<length; i++) ((unsigned char *)state)[offset + i] ^= data[i];
145}
146
147void KeccakP1600_AddByte(void *state, unsigned char byte, unsigned int offset)
148{
149 assert(offset < 200);
150 ((unsigned char *)state)[offset] ^= byte;
151}
152
153#define ROL64(a, offset) ((offset != 0) ? ((((UInt64)a) << offset) ^ (((UInt64)a) >> (64-offset))) : a)
154#define index(x, y) (((x)%5)+5*((y)%5))
155
156static void theta(UInt64 *A)
157{
158 unsigned int x, y;
159 UInt64 C[5], D[5];
160
161 for (x = 0; x<5; x++) {
162 C[x] = 0;
163 for (y = 0; y<5; y++)
164 C[x] ^= A[index(x, y)];
165 }
166 for (x = 0; x<5; x++)
167 D[x] = ROL64(C[(x + 1) % 5], 1) ^ C[(x + 4) % 5];
168 for (x = 0; x<5; x++)
169 for (y = 0; y<5; y++)
170 A[index(x, y)] ^= D[x];
171}
172
173static void rho(UInt64 *A)
174{
175 unsigned int x, y;
176
177 for (x = 0; x<5; x++) for (y = 0; y<5; y++)
178 A[index(x, y)] = ROL64(A[index(x, y)], KeccakRhoOffsets[index(x, y)]);
179}
180
181static void pi(UInt64 *A)
182{
183 unsigned int x, y;
184 UInt64 tempA[25];
185
186 for (x = 0; x<5; x++) for (y = 0; y<5; y++)
187 tempA[index(x, y)] = A[index(x, y)];
188 for (x = 0; x<5; x++) for (y = 0; y<5; y++)
189 A[index(0 * x + 1 * y, 2 * x + 3 * y)] = tempA[index(x, y)];
190}
191
192static void chi(UInt64 *A)
193{
194 unsigned int x, y;
195 UInt64 C[5];
196
197 for (y = 0; y<5; y++) {
198 for (x = 0; x<5; x++)
199 C[x] = A[index(x, y)] ^ ((~A[index(x + 1, y)]) & A[index(x + 2, y)]);
200 for (x = 0; x<5; x++)
201 A[index(x, y)] = C[x];
202 }
203}
204
205static void iota(UInt64 *A, unsigned int indexRound)
206{
207 A[index(0, 0)] ^= KeccakRoundConstants[indexRound];
208}
209
210void KeccakP1600Round(UInt64 *state, unsigned int indexRound)
211{
212 theta(state);
213 rho(state);
214 pi(state);
215 chi(state);
216 iota(state, indexRound);
217}
218
219static void fromBytesToWords(UInt64 *stateAsWords, const unsigned char *state)
220{
221 unsigned int i, j;
222 for (i = 0; i < 25; i++) {
223 stateAsWords[i] = 0;
224 for (j = 0; j < (64 / 8); j++)
225 stateAsWords[i] |= (UInt64)(state[i*(64 / 8) + j]) << (8 * j);
226 }
227}
228
229void KeccakP1600OnWords(UInt64 *state, unsigned int nrRounds)
230{
231 for (unsigned int i = (24 - nrRounds); i < 24; i++) KeccakP1600Round(state, i);
232}
233
234static void fromWordsToBytes(unsigned char *state, const UInt64 *stateAsWords)
235{
236 unsigned int i, j;
237 for (i = 0; i < 25; i++)
238 for (j = 0; j < (64 / 8); j++)
239 state[i*(64 / 8) + j] = (unsigned char)((stateAsWords[i] >> (8 * j)) & 0xFF);
240}
241
242void KeccakP1600_Permute_24rounds(void *state)
243{
244#ifndef POCO_ARCH_LITTLE_ENDIAN
245 UInt64 stateAsWords[1600 / 64];
246#endif
247#ifdef POCO_ARCH_LITTLE_ENDIAN
248 KeccakP1600OnWords((UInt64*)state, 24);
249#else
250 fromBytesToWords(stateAsWords, (const unsigned char *)state);
251 KeccakP1600OnWords(stateAsWords, 24);
252 fromWordsToBytes((unsigned char *)state, stateAsWords);
253#endif
254}
255
256void KeccakP1600_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length)
257{
258 assert(offset < 200);
259 assert(offset + length <= 200);
260 memcpy(data, (unsigned char*)state + offset, length);
261}
262#else
263void toBitInterleaving(UInt32 low, UInt32 high, UInt32 *even, UInt32 *odd)
264{
265 unsigned int i;
266
267 *even = 0;
268 *odd = 0;
269 for (i = 0; i<64; i++) {
270 unsigned int inBit;
271 if (i < 32)
272 inBit = (low >> i) & 1;
273 else
274 inBit = (high >> (i - 32)) & 1;
275 if ((i % 2) == 0)
276 *even |= inBit << (i / 2);
277 else
278 *odd |= inBit << ((i - 1) / 2);
279 }
280}
281
282void fromBitInterleaving(UInt32 even, UInt32 odd, UInt32 *low, UInt32 *high)
283{
284 unsigned int i;
285
286 *low = 0;
287 *high = 0;
288 for (i = 0; i<64; i++) {
289 unsigned int inBit;
290 if ((i % 2) == 0)
291 inBit = (even >> (i / 2)) & 1;
292 else
293 inBit = (odd >> ((i - 1) / 2)) & 1;
294 if (i < 32)
295 *low |= inBit << i;
296 else
297 *high |= inBit << (i - 32);
298 }
299}
300
301void KeccakP1600_AddBytesInLane(void *state, unsigned int lanePosition, const unsigned char *data, unsigned int offset, unsigned int length)
302{
303 if ((lanePosition < 25) && (offset < 8) && (offset + length <= 8)) {
304 UInt8 laneAsBytes[8];
305 UInt32 low, high;
306 UInt32 lane[2];
307 UInt32 *stateAsHalfLanes;
308
309 memset(laneAsBytes, 0, 8);
310 memcpy(laneAsBytes + offset, data, length);
311 low = laneAsBytes[0]
312 | ((UInt32)(laneAsBytes[1]) << 8)
313 | ((UInt32)(laneAsBytes[2]) << 16)
314 | ((UInt32)(laneAsBytes[3]) << 24);
315 high = laneAsBytes[4]
316 | ((UInt32)(laneAsBytes[5]) << 8)
317 | ((UInt32)(laneAsBytes[6]) << 16)
318 | ((UInt32)(laneAsBytes[7]) << 24);
319 toBitInterleaving(low, high, lane, lane + 1);
320 stateAsHalfLanes = (UInt32*)state;
321 stateAsHalfLanes[lanePosition * 2 + 0] ^= lane[0];
322 stateAsHalfLanes[lanePosition * 2 + 1] ^= lane[1];
323 }
324}
325
326void KeccakP1600_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length)
327{
328 unsigned int lanePosition = offset / 8;
329 unsigned int offsetInLane = offset % 8;
330
331 assert(offset < 200);
332 assert(offset + length <= 200);
333 while (length > 0) {
334 unsigned int bytesInLane = 8 - offsetInLane;
335 if (bytesInLane > length)
336 bytesInLane = length;
337 KeccakP1600_AddBytesInLane(state, lanePosition, data, offsetInLane, bytesInLane);
338 length -= bytesInLane;
339 lanePosition++;
340 offsetInLane = 0;
341 data += bytesInLane;
342 }
343}
344
345void KeccakP1600_AddByte(void *state, unsigned char byte, unsigned int offset)
346{
347 unsigned char data[1];
348 assert(offset < 200);
349 data[0] = byte;
350 KeccakP1600_AddBytes(state, data, offset, 1);
351}
352
353#define ROL32(a, offset) ((offset != 0) ? ((((UInt32)a) << offset) ^ (((UInt32)a) >> (32-offset))) : a)
354#define index(x, y,z) ((((x)%5)+5*((y)%5))*2 + z)
355void ROL64(UInt32 inEven, UInt32 inOdd, UInt32 *outEven, UInt32 *outOdd, unsigned int offset)
356{
357 if ((offset % 2) == 0) {
358 *outEven = ROL32(inEven, offset / 2);
359 *outOdd = ROL32(inOdd, offset / 2);
360 }
361 else {
362 *outEven = ROL32(inOdd, (offset + 1) / 2);
363 *outOdd = ROL32(inEven, (offset - 1) / 2);
364 }
365}
366
367static void theta(UInt32 *A)
368{
369 unsigned int x, y, z;
370 UInt32 C[5][2], D[5][2];
371 for (x = 0; x<5; x++) {
372 for (z = 0; z<2; z++) {
373 C[x][z] = 0;
374 for (y = 0; y<5; y++)
375 C[x][z] ^= A[index(x, y, z)];
376 }
377 }
378 for (x = 0; x<5; x++) {
379 ROL64(C[(x + 1) % 5][0], C[(x + 1) % 5][1], &(D[x][0]), &(D[x][1]), 1);
380 for (z = 0; z<2; z++)
381 D[x][z] ^= C[(x + 4) % 5][z];
382 }
383 for (x = 0; x<5; x++)
384 for (y = 0; y<5; y++)
385 for (z = 0; z<2; z++)
386 A[index(x, y, z)] ^= D[x][z];
387}
388
389static void rho(UInt32 *A)
390{
391 unsigned int x, y;
392 for (x = 0; x<5; x++) for (y = 0; y<5; y++)
393 ROL64(A[index(x, y, 0)], A[index(x, y, 1)], &(A[index(x, y, 0)]), &(A[index(x, y, 1)]), KeccakRhoOffsets[5 * y + x]);
394}
395
396static void pi(UInt32 *A)
397{
398 unsigned int x, y, z;
399 UInt32 tempA[50];
400 for (x = 0; x<5; x++) for (y = 0; y<5; y++) for (z = 0; z<2; z++)
401 tempA[index(x, y, z)] = A[index(x, y, z)];
402 for (x = 0; x<5; x++) for (y = 0; y<5; y++) for (z = 0; z<2; z++)
403 A[index(0 * x + 1 * y, 2 * x + 3 * y, z)] = tempA[index(x, y, z)];
404}
405
406static void chi(UInt32 *A)
407{
408 unsigned int x, y, z;
409 UInt32 C[5][2];
410 for (y = 0; y<5; y++) {
411 for (x = 0; x<5; x++)
412 for (z = 0; z<2; z++)
413 C[x][z] = A[index(x, y, z)] ^ ((~A[index(x + 1, y, z)]) & A[index(x + 2, y, z)]);
414 for (x = 0; x<5; x++)
415 for (z = 0; z<2; z++)
416 A[index(x, y, z)] = C[x][z];
417 }
418}
419
420static void iota(UInt32 *A, unsigned int indexRound)
421{
422 A[index(0, 0, 0)] ^= KeccakRoundConstants[indexRound][0];
423 A[index(0, 0, 1)] ^= KeccakRoundConstants[indexRound][1];
424}
425
426void KeccakP1600_PermutationOnWords(UInt32 *state, unsigned int nrRounds)
427{
428 for (unsigned int i = (24 - nrRounds); i < 24; i++)
429 {
430 theta(state);
431 rho(state);
432 pi(state);
433 chi(state);
434 iota(state, i);
435 }
436}
437
438void KeccakP1600_ExtractBytesInLane(const void *state, unsigned int lanePosition, unsigned char *data, unsigned int offset, unsigned int length)
439{
440 if ((lanePosition < 25) && (offset < 8) && (offset + length <= 8)) {
441 UInt32 *stateAsHalfLanes = (UInt32*)state;
442 UInt32 lane[2];
443 UInt8 laneAsBytes[8];
444 fromBitInterleaving(stateAsHalfLanes[lanePosition * 2], stateAsHalfLanes[lanePosition * 2 + 1], lane, lane + 1);
445 laneAsBytes[0] = lane[0] & 0xFF;
446 laneAsBytes[1] = (lane[0] >> 8) & 0xFF;
447 laneAsBytes[2] = (lane[0] >> 16) & 0xFF;
448 laneAsBytes[3] = (lane[0] >> 24) & 0xFF;
449 laneAsBytes[4] = lane[1] & 0xFF;
450 laneAsBytes[5] = (lane[1] >> 8) & 0xFF;
451 laneAsBytes[6] = (lane[1] >> 16) & 0xFF;
452 laneAsBytes[7] = (lane[1] >> 24) & 0xFF;
453 memcpy(data, laneAsBytes + offset, length);
454 }
455}
456
457void KeccakP1600_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length)
458{
459 unsigned int lanePosition = offset / 8;
460 unsigned int offsetInLane = offset % 8;
461
462 assert(offset < 200);
463 assert(offset + length <= 200);
464 while (length > 0) {
465 unsigned int bytesInLane = 8 - offsetInLane;
466 if (bytesInLane > length)
467 bytesInLane = length;
468 KeccakP1600_ExtractBytesInLane(state, lanePosition, data, offsetInLane, bytesInLane);
469 length -= bytesInLane;
470 lanePosition++;
471 offsetInLane = 0;
472 data += bytesInLane;
473 }
474}
475
476void KeccakP1600_Permute_24rounds(void *state)
477{
478 UInt32 *stateAsHalfLanes = (UInt32*)state;
479 {
480 UInt8 stateAsBytes[1600 / 8];
481 KeccakP1600_ExtractBytes(state, stateAsBytes, 0, 1600 / 8);
482 }
483 KeccakP1600_PermutationOnWords(stateAsHalfLanes, 24);
484 {
485 UInt8 stateAsBytes[1600 / 8];
486 KeccakP1600_ExtractBytes(state, stateAsBytes, 0, 1600 / 8);
487 }
488}
489#endif
490
491void SHA3Engine::updateImpl(const void* buffer_, std::size_t count)
492{
493 if (_context == NULL || buffer_ == NULL || count == 0) return;
494 HASHCONTEXT* pContext = (HASHCONTEXT*)_context;
495 size_t j;
496 unsigned int partialBlock;
497 unsigned int rateInBytes = (&pContext->sponge)->rate / 8;
498 if ((&pContext->sponge)->squeezing) return;
499 size_t i = 0;
500 const unsigned char *curData = (const unsigned char *)buffer_;
501 while (i < count) {
502 if (((&pContext->sponge)->byteIOIndex == 0) && (count >= (i + rateInBytes))) {
503 for (j = count - i; j >= rateInBytes; j -= rateInBytes) {
504 KeccakP1600_AddBytes((&pContext->sponge)->state, curData, 0, rateInBytes);
505 KeccakP1600_Permute_24rounds((&pContext->sponge)->state);
506 curData += rateInBytes;
507 }
508 i = count - j;
509 }
510 else {
511 partialBlock = (unsigned int)(count - i);
512 if (partialBlock + (&pContext->sponge)->byteIOIndex > rateInBytes)
513 partialBlock = rateInBytes - (&pContext->sponge)->byteIOIndex;
514 i += partialBlock;
515
516 KeccakP1600_AddBytes((&pContext->sponge)->state, curData, (&pContext->sponge)->byteIOIndex, partialBlock);
517 curData += partialBlock;
518 (&pContext->sponge)->byteIOIndex += partialBlock;
519 if ((&pContext->sponge)->byteIOIndex == rateInBytes) {
520 KeccakP1600_Permute_24rounds((&pContext->sponge)->state);
521 (&pContext->sponge)->byteIOIndex = 0;
522 }
523 }
524 }
525}
526
527std::size_t SHA3Engine::digestLength() const
528{
529 return (size_t)((int)_algorithm / 8);
530}
531
532int KeccakWidth1600_SpongeInitialize(KeccakWidth1600_SpongeInstance *instance, unsigned int rate, unsigned int capacity)
533{
534 if (rate + capacity != 1600) return 1;
535 if ((rate <= 0) || (rate > 1600) || ((rate % 8) != 0)) return 1;
536 memset(instance->state, 0, 1600 / 8);
537 instance->rate = rate;
538 instance->byteIOIndex = 0;
539 instance->squeezing = 0;
540 return 0;
541}
542
543void SHA3Engine::reset()
544{
545 if (_context != NULL) free(_context);
546 _context = calloc(1, sizeof(HASHCONTEXT));
547 HASHCONTEXT* pContext = (HASHCONTEXT*)_context;
548 switch (_algorithm)
549 {
550 case SHA3_224:
551 KeccakWidth1600_SpongeInitialize(&pContext->sponge, 1152, 448);
552 pContext->fixedOutputLength = 224;
553 pContext->delimitedSuffix = 0x06;
554 break;
555 case SHA3_256:
556 KeccakWidth1600_SpongeInitialize(&pContext->sponge, 1088, 512);
557 pContext->fixedOutputLength = 256;
558 pContext->delimitedSuffix = 0x06;
559 break;
560 case SHA3_384:
561 KeccakWidth1600_SpongeInitialize(&pContext->sponge, 832, 768);
562 pContext->fixedOutputLength = 384;
563 pContext->delimitedSuffix = 0x06;
564 break;
565 default:
566 case SHA3_512:
567 KeccakWidth1600_SpongeInitialize(&pContext->sponge, 576, 1024);
568 pContext->fixedOutputLength = 512;
569 pContext->delimitedSuffix = 0x06;
570 break;
571 }
572}
573
574int KeccakWidth1600_SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance *instance, unsigned char delimitedData)
575{
576 unsigned int rateInBytes = instance->rate / 8;
577
578 if (delimitedData == 0)
579 return 1;
580 if (instance->squeezing)
581 return 1; /* Too late for additional input */
582
583 /* Last few bits, whose delimiter coincides with first bit of padding */
584 KeccakP1600_AddByte(instance->state, delimitedData, instance->byteIOIndex);
585 /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */
586 if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes - 1)))
587 KeccakP1600_Permute_24rounds(instance->state);
588 /* Second bit of padding */
589 KeccakP1600_AddByte(instance->state, 0x80, rateInBytes - 1);
590 KeccakP1600_Permute_24rounds(instance->state);
591 instance->byteIOIndex = 0;
592 instance->squeezing = 1;
593 return 0;
594}
595
596int SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance *instance, unsigned char delimitedData)
597{
598 unsigned int rateInBytes = instance->rate / 8;
599 if (delimitedData == 0) return 1;
600 if (instance->squeezing) return 1; /* Too late for additional input */
601 /* Last few bits, whose delimiter coincides with first bit of padding */
602 KeccakP1600_AddByte(instance->state, delimitedData, instance->byteIOIndex);
603 /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */
604 if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes - 1)))
605 KeccakP1600_Permute_24rounds(instance->state);
606 /* Second bit of padding */
607 KeccakP1600_AddByte(instance->state, 0x80, rateInBytes - 1);
608 KeccakP1600_Permute_24rounds(instance->state);
609 instance->byteIOIndex = 0;
610 instance->squeezing = 1;
611 return 0;
612}
613
614int KeccakWidth1600_SpongeSqueeze(KeccakWidth1600_SpongeInstance *instance, unsigned char *data, size_t dataByteLen)
615{
616 size_t i, j;
617 unsigned int partialBlock;
618 unsigned int rateInBytes = instance->rate / 8;
619 unsigned char *curData;
620
621 if (!instance->squeezing)
622 SpongeAbsorbLastFewBits(instance, 0x01);
623
624 i = 0;
625 curData = data;
626 while (i < dataByteLen) {
627 if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) {
628 for (j = dataByteLen - i; j >= rateInBytes; j -= rateInBytes) {
629 KeccakP1600_Permute_24rounds(instance->state);
630 KeccakP1600_ExtractBytes(instance->state, curData, 0, rateInBytes);
631 curData += rateInBytes;
632 }
633 i = dataByteLen - j;
634 }
635 else {
636 /* normal lane: using the message queue */
637 if (instance->byteIOIndex == rateInBytes) {
638 KeccakP1600_Permute_24rounds(instance->state);
639 instance->byteIOIndex = 0;
640 }
641 partialBlock = (unsigned int)(dataByteLen - i);
642 if (partialBlock + instance->byteIOIndex > rateInBytes)
643 partialBlock = rateInBytes - instance->byteIOIndex;
644 i += partialBlock;
645
646 KeccakP1600_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock);
647 curData += partialBlock;
648 instance->byteIOIndex += partialBlock;
649 }
650 }
651 return 0;
652}
653
654const DigestEngine::Digest& SHA3Engine::digest()
655{
656 _digest.clear();
657 HASHCONTEXT* pContext = (HASHCONTEXT*)_context;
658 unsigned char hash[64];
659 memset(hash, 0, 64);
660 if (KeccakWidth1600_SpongeAbsorbLastFewBits(&pContext->sponge, pContext->delimitedSuffix) == 0)
661 KeccakWidth1600_SpongeSqueeze(&pContext->sponge, hash, pContext->fixedOutputLength / 8);
662 _digest.insert(_digest.begin(), hash, hash + digestLength());
663 reset();
664 return _digest;
665}
666
667} // namespace Poco
668