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
219void KeccakP1600OnWords(UInt64 *state, unsigned int nrRounds)
220{
221 for (unsigned int i = (24 - nrRounds); i < 24; i++) KeccakP1600Round(state, i);
222}
223
224void KeccakP1600_Permute_24rounds(void *state)
225{
226#ifndef POCO_ARCH_LITTLE_ENDIAN
227 UInt64 stateAsWords[1600 / 64];
228#endif
229#ifdef POCO_ARCH_LITTLE_ENDIAN
230 KeccakP1600OnWords((UInt64*)state, 24);
231#else
232 fromBytesToWords(stateAsWords, (const unsigned char *)state);
233 KeccakP1600OnWords(stateAsWords, 24);
234 fromWordsToBytes((unsigned char *)state, stateAsWords);
235#endif
236}
237
238void KeccakP1600_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length)
239{
240 assert(offset < 200);
241 assert(offset + length <= 200);
242 memcpy(data, (unsigned char*)state + offset, length);
243}
244#else
245void toBitInterleaving(UInt32 low, UInt32 high, UInt32 *even, UInt32 *odd)
246{
247 unsigned int i;
248
249 *even = 0;
250 *odd = 0;
251 for (i = 0; i<64; i++) {
252 unsigned int inBit;
253 if (i < 32)
254 inBit = (low >> i) & 1;
255 else
256 inBit = (high >> (i - 32)) & 1;
257 if ((i % 2) == 0)
258 *even |= inBit << (i / 2);
259 else
260 *odd |= inBit << ((i - 1) / 2);
261 }
262}
263
264void fromBitInterleaving(UInt32 even, UInt32 odd, UInt32 *low, UInt32 *high)
265{
266 unsigned int i;
267
268 *low = 0;
269 *high = 0;
270 for (i = 0; i<64; i++) {
271 unsigned int inBit;
272 if ((i % 2) == 0)
273 inBit = (even >> (i / 2)) & 1;
274 else
275 inBit = (odd >> ((i - 1) / 2)) & 1;
276 if (i < 32)
277 *low |= inBit << i;
278 else
279 *high |= inBit << (i - 32);
280 }
281}
282
283void KeccakP1600_AddBytesInLane(void *state, unsigned int lanePosition, const unsigned char *data, unsigned int offset, unsigned int length)
284{
285 if ((lanePosition < 25) && (offset < 8) && (offset + length <= 8)) {
286 UInt8 laneAsBytes[8];
287 UInt32 low, high;
288 UInt32 lane[2];
289 UInt32 *stateAsHalfLanes;
290
291 memset(laneAsBytes, 0, 8);
292 memcpy(laneAsBytes + offset, data, length);
293 low = laneAsBytes[0]
294 | ((UInt32)(laneAsBytes[1]) << 8)
295 | ((UInt32)(laneAsBytes[2]) << 16)
296 | ((UInt32)(laneAsBytes[3]) << 24);
297 high = laneAsBytes[4]
298 | ((UInt32)(laneAsBytes[5]) << 8)
299 | ((UInt32)(laneAsBytes[6]) << 16)
300 | ((UInt32)(laneAsBytes[7]) << 24);
301 toBitInterleaving(low, high, lane, lane + 1);
302 stateAsHalfLanes = (UInt32*)state;
303 stateAsHalfLanes[lanePosition * 2 + 0] ^= lane[0];
304 stateAsHalfLanes[lanePosition * 2 + 1] ^= lane[1];
305 }
306}
307
308void KeccakP1600_AddBytes(void *state, const unsigned char *data, unsigned int offset, unsigned int length)
309{
310 unsigned int lanePosition = offset / 8;
311 unsigned int offsetInLane = offset % 8;
312
313 assert(offset < 200);
314 assert(offset + length <= 200);
315 while (length > 0) {
316 unsigned int bytesInLane = 8 - offsetInLane;
317 if (bytesInLane > length)
318 bytesInLane = length;
319 KeccakP1600_AddBytesInLane(state, lanePosition, data, offsetInLane, bytesInLane);
320 length -= bytesInLane;
321 lanePosition++;
322 offsetInLane = 0;
323 data += bytesInLane;
324 }
325}
326
327void KeccakP1600_AddByte(void *state, unsigned char byte, unsigned int offset)
328{
329 unsigned char data[1];
330 assert(offset < 200);
331 data[0] = byte;
332 KeccakP1600_AddBytes(state, data, offset, 1);
333}
334
335#define ROL32(a, offset) ((offset != 0) ? ((((UInt32)a) << offset) ^ (((UInt32)a) >> (32-offset))) : a)
336#define index(x, y,z) ((((x)%5)+5*((y)%5))*2 + z)
337void ROL64(UInt32 inEven, UInt32 inOdd, UInt32 *outEven, UInt32 *outOdd, unsigned int offset)
338{
339 if ((offset % 2) == 0) {
340 *outEven = ROL32(inEven, offset / 2);
341 *outOdd = ROL32(inOdd, offset / 2);
342 }
343 else {
344 *outEven = ROL32(inOdd, (offset + 1) / 2);
345 *outOdd = ROL32(inEven, (offset - 1) / 2);
346 }
347}
348
349static void theta(UInt32 *A)
350{
351 unsigned int x, y, z;
352 UInt32 C[5][2], D[5][2];
353 for (x = 0; x<5; x++) {
354 for (z = 0; z<2; z++) {
355 C[x][z] = 0;
356 for (y = 0; y<5; y++)
357 C[x][z] ^= A[index(x, y, z)];
358 }
359 }
360 for (x = 0; x<5; x++) {
361 ROL64(C[(x + 1) % 5][0], C[(x + 1) % 5][1], &(D[x][0]), &(D[x][1]), 1);
362 for (z = 0; z<2; z++)
363 D[x][z] ^= C[(x + 4) % 5][z];
364 }
365 for (x = 0; x<5; x++)
366 for (y = 0; y<5; y++)
367 for (z = 0; z<2; z++)
368 A[index(x, y, z)] ^= D[x][z];
369}
370
371static void rho(UInt32 *A)
372{
373 unsigned int x, y;
374 for (x = 0; x<5; x++) for (y = 0; y<5; y++)
375 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]);
376}
377
378static void pi(UInt32 *A)
379{
380 unsigned int x, y, z;
381 UInt32 tempA[50];
382 for (x = 0; x<5; x++) for (y = 0; y<5; y++) for (z = 0; z<2; z++)
383 tempA[index(x, y, z)] = A[index(x, y, z)];
384 for (x = 0; x<5; x++) for (y = 0; y<5; y++) for (z = 0; z<2; z++)
385 A[index(0 * x + 1 * y, 2 * x + 3 * y, z)] = tempA[index(x, y, z)];
386}
387
388static void chi(UInt32 *A)
389{
390 unsigned int x, y, z;
391 UInt32 C[5][2];
392 for (y = 0; y<5; y++) {
393 for (x = 0; x<5; x++)
394 for (z = 0; z<2; z++)
395 C[x][z] = A[index(x, y, z)] ^ ((~A[index(x + 1, y, z)]) & A[index(x + 2, y, z)]);
396 for (x = 0; x<5; x++)
397 for (z = 0; z<2; z++)
398 A[index(x, y, z)] = C[x][z];
399 }
400}
401
402static void iota(UInt32 *A, unsigned int indexRound)
403{
404 A[index(0, 0, 0)] ^= KeccakRoundConstants[indexRound][0];
405 A[index(0, 0, 1)] ^= KeccakRoundConstants[indexRound][1];
406}
407
408void KeccakP1600_PermutationOnWords(UInt32 *state, unsigned int nrRounds)
409{
410 for (unsigned int i = (24 - nrRounds); i < 24; i++)
411 {
412 theta(state);
413 rho(state);
414 pi(state);
415 chi(state);
416 iota(state, i);
417 }
418}
419
420void KeccakP1600_ExtractBytesInLane(const void *state, unsigned int lanePosition, unsigned char *data, unsigned int offset, unsigned int length)
421{
422 if ((lanePosition < 25) && (offset < 8) && (offset + length <= 8)) {
423 UInt32 *stateAsHalfLanes = (UInt32*)state;
424 UInt32 lane[2];
425 UInt8 laneAsBytes[8];
426 fromBitInterleaving(stateAsHalfLanes[lanePosition * 2], stateAsHalfLanes[lanePosition * 2 + 1], lane, lane + 1);
427 laneAsBytes[0] = lane[0] & 0xFF;
428 laneAsBytes[1] = (lane[0] >> 8) & 0xFF;
429 laneAsBytes[2] = (lane[0] >> 16) & 0xFF;
430 laneAsBytes[3] = (lane[0] >> 24) & 0xFF;
431 laneAsBytes[4] = lane[1] & 0xFF;
432 laneAsBytes[5] = (lane[1] >> 8) & 0xFF;
433 laneAsBytes[6] = (lane[1] >> 16) & 0xFF;
434 laneAsBytes[7] = (lane[1] >> 24) & 0xFF;
435 memcpy(data, laneAsBytes + offset, length);
436 }
437}
438
439void KeccakP1600_ExtractBytes(const void *state, unsigned char *data, unsigned int offset, unsigned int length)
440{
441 unsigned int lanePosition = offset / 8;
442 unsigned int offsetInLane = offset % 8;
443
444 assert(offset < 200);
445 assert(offset + length <= 200);
446 while (length > 0) {
447 unsigned int bytesInLane = 8 - offsetInLane;
448 if (bytesInLane > length)
449 bytesInLane = length;
450 KeccakP1600_ExtractBytesInLane(state, lanePosition, data, offsetInLane, bytesInLane);
451 length -= bytesInLane;
452 lanePosition++;
453 offsetInLane = 0;
454 data += bytesInLane;
455 }
456}
457
458void KeccakP1600_Permute_24rounds(void *state)
459{
460 UInt32 *stateAsHalfLanes = (UInt32*)state;
461 {
462 UInt8 stateAsBytes[1600 / 8];
463 KeccakP1600_ExtractBytes(state, stateAsBytes, 0, 1600 / 8);
464 }
465 KeccakP1600_PermutationOnWords(stateAsHalfLanes, 24);
466 {
467 UInt8 stateAsBytes[1600 / 8];
468 KeccakP1600_ExtractBytes(state, stateAsBytes, 0, 1600 / 8);
469 }
470}
471#endif
472
473void SHA3Engine::updateImpl(const void* buffer_, std::size_t count)
474{
475 if (_context == NULL || buffer_ == NULL || count == 0) return;
476 HASHCONTEXT* pContext = (HASHCONTEXT*)_context;
477 size_t j;
478 unsigned int partialBlock;
479 unsigned int rateInBytes = (&pContext->sponge)->rate / 8;
480 if ((&pContext->sponge)->squeezing) return;
481 size_t i = 0;
482 const unsigned char *curData = (const unsigned char *)buffer_;
483 while (i < count) {
484 if (((&pContext->sponge)->byteIOIndex == 0) && (count >= (i + rateInBytes))) {
485 for (j = count - i; j >= rateInBytes; j -= rateInBytes) {
486 KeccakP1600_AddBytes((&pContext->sponge)->state, curData, 0, rateInBytes);
487 KeccakP1600_Permute_24rounds((&pContext->sponge)->state);
488 curData += rateInBytes;
489 }
490 i = count - j;
491 }
492 else {
493 partialBlock = (unsigned int)(count - i);
494 if (partialBlock + (&pContext->sponge)->byteIOIndex > rateInBytes)
495 partialBlock = rateInBytes - (&pContext->sponge)->byteIOIndex;
496 i += partialBlock;
497
498 KeccakP1600_AddBytes((&pContext->sponge)->state, curData, (&pContext->sponge)->byteIOIndex, partialBlock);
499 curData += partialBlock;
500 (&pContext->sponge)->byteIOIndex += partialBlock;
501 if ((&pContext->sponge)->byteIOIndex == rateInBytes) {
502 KeccakP1600_Permute_24rounds((&pContext->sponge)->state);
503 (&pContext->sponge)->byteIOIndex = 0;
504 }
505 }
506 }
507}
508
509std::size_t SHA3Engine::digestLength() const
510{
511 return (size_t)((int)_algorithm / 8);
512}
513
514int KeccakWidth1600_SpongeInitialize(KeccakWidth1600_SpongeInstance *instance, unsigned int rate, unsigned int capacity)
515{
516 if (rate + capacity != 1600) return 1;
517 if ((rate <= 0) || (rate > 1600) || ((rate % 8) != 0)) return 1;
518 memset(instance->state, 0, 1600 / 8);
519 instance->rate = rate;
520 instance->byteIOIndex = 0;
521 instance->squeezing = 0;
522 return 0;
523}
524
525void SHA3Engine::reset()
526{
527 if (_context != NULL) free(_context);
528 _context = calloc(1, sizeof(HASHCONTEXT));
529 HASHCONTEXT* pContext = (HASHCONTEXT*)_context;
530 switch (_algorithm)
531 {
532 case SHA3_224:
533 KeccakWidth1600_SpongeInitialize(&pContext->sponge, 1152, 448);
534 pContext->fixedOutputLength = 224;
535 pContext->delimitedSuffix = 0x06;
536 break;
537 case SHA3_256:
538 KeccakWidth1600_SpongeInitialize(&pContext->sponge, 1088, 512);
539 pContext->fixedOutputLength = 256;
540 pContext->delimitedSuffix = 0x06;
541 break;
542 case SHA3_384:
543 KeccakWidth1600_SpongeInitialize(&pContext->sponge, 832, 768);
544 pContext->fixedOutputLength = 384;
545 pContext->delimitedSuffix = 0x06;
546 break;
547 default:
548 case SHA3_512:
549 KeccakWidth1600_SpongeInitialize(&pContext->sponge, 576, 1024);
550 pContext->fixedOutputLength = 512;
551 pContext->delimitedSuffix = 0x06;
552 break;
553 }
554}
555
556int KeccakWidth1600_SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance *instance, unsigned char delimitedData)
557{
558 unsigned int rateInBytes = instance->rate / 8;
559
560 if (delimitedData == 0)
561 return 1;
562 if (instance->squeezing)
563 return 1; /* Too late for additional input */
564
565 /* Last few bits, whose delimiter coincides with first bit of padding */
566 KeccakP1600_AddByte(instance->state, delimitedData, instance->byteIOIndex);
567 /* If the first bit of padding is at position rate-1, we need a whole new block for the second bit of padding */
568 if ((delimitedData >= 0x80) && (instance->byteIOIndex == (rateInBytes - 1)))
569 KeccakP1600_Permute_24rounds(instance->state);
570 /* Second bit of padding */
571 KeccakP1600_AddByte(instance->state, 0x80, rateInBytes - 1);
572 KeccakP1600_Permute_24rounds(instance->state);
573 instance->byteIOIndex = 0;
574 instance->squeezing = 1;
575 return 0;
576}
577
578int SpongeAbsorbLastFewBits(KeccakWidth1600_SpongeInstance *instance, unsigned char delimitedData)
579{
580 unsigned int rateInBytes = instance->rate / 8;
581 if (delimitedData == 0) return 1;
582 if (instance->squeezing) return 1; /* Too late for additional input */
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 KeccakWidth1600_SpongeSqueeze(KeccakWidth1600_SpongeInstance *instance, unsigned char *data, size_t dataByteLen)
597{
598 size_t i, j;
599 unsigned int partialBlock;
600 unsigned int rateInBytes = instance->rate / 8;
601 unsigned char *curData;
602
603 if (!instance->squeezing)
604 SpongeAbsorbLastFewBits(instance, 0x01);
605
606 i = 0;
607 curData = data;
608 while (i < dataByteLen) {
609 if ((instance->byteIOIndex == rateInBytes) && (dataByteLen >= (i + rateInBytes))) {
610 for (j = dataByteLen - i; j >= rateInBytes; j -= rateInBytes) {
611 KeccakP1600_Permute_24rounds(instance->state);
612 KeccakP1600_ExtractBytes(instance->state, curData, 0, rateInBytes);
613 curData += rateInBytes;
614 }
615 i = dataByteLen - j;
616 }
617 else {
618 /* normal lane: using the message queue */
619 if (instance->byteIOIndex == rateInBytes) {
620 KeccakP1600_Permute_24rounds(instance->state);
621 instance->byteIOIndex = 0;
622 }
623 partialBlock = (unsigned int)(dataByteLen - i);
624 if (partialBlock + instance->byteIOIndex > rateInBytes)
625 partialBlock = rateInBytes - instance->byteIOIndex;
626 i += partialBlock;
627
628 KeccakP1600_ExtractBytes(instance->state, curData, instance->byteIOIndex, partialBlock);
629 curData += partialBlock;
630 instance->byteIOIndex += partialBlock;
631 }
632 }
633 return 0;
634}
635
636const DigestEngine::Digest& SHA3Engine::digest()
637{
638 _digest.clear();
639 HASHCONTEXT* pContext = (HASHCONTEXT*)_context;
640 unsigned char hash[64];
641 memset(hash, 0, 64);
642 if (KeccakWidth1600_SpongeAbsorbLastFewBits(&pContext->sponge, pContext->delimitedSuffix) == 0)
643 KeccakWidth1600_SpongeSqueeze(&pContext->sponge, hash, pContext->fixedOutputLength / 8);
644 _digest.insert(_digest.begin(), hash, hash + digestLength());
645 reset();
646 return _digest;
647}
648
649} // namespace Poco
650