VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/checksum/alt-sha3.cpp@ 85624

Last change on this file since 85624 was 85624, checked in by vboxsync, 4 years ago

IPRT: Tweaking some performance out of the alternative SHA-3 implementation on gcc 10.2.1. bugref:9734

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.3 KB
Line 
1/* $Id: alt-sha3.cpp 85624 2020-08-05 20:50:16Z vboxsync $ */
2/** @file
3 * IPRT - SHA-3 hash functions, Alternative Implementation.
4 */
5
6/*
7 * Copyright (C) 2009-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Defined Constants And Macros *
30*********************************************************************************************************************************/
31/** Number of rounds [3.4]. */
32#define RTSHA3_ROUNDS 24
33
34/** @def RTSHA3_FULL_UNROLL
35 * Do full loop unrolling unless we're using VS2019 as it seems to degrate
36 * performances there for some reason. With gcc 10.2.1 on a recent Intel system
37 * (10890XE), this results SHA3-512 throughput (tstRTDigest-2) increasing from
38 * 83532 KiB/s to 194942 KiB/s against a text size jump from 5913 to 6929 bytes.
39 *
40 * For comparison, openssl 1.1.1g assembly code (AMD64) achives 264915 KiB/s,
41 * which is only 36% more. Performance is more or less exactly the same as
42 * KECCAK_2X without ROL optimizations (they improve it to 203493 KiB/s).
43 */
44#if !defined(_MSC_VER) || defined(DOXYGEN_RUNNING)
45# define RTSHA3_FULL_UNROLL
46#endif
47
48
49/*********************************************************************************************************************************
50* Header Files *
51*********************************************************************************************************************************/
52#include "internal/iprt.h"
53#include <iprt/assert.h>
54#include <iprt/assertcompile.h>
55#include <iprt/asm.h>
56#include <iprt/string.h>
57
58
59/*********************************************************************************************************************************
60* Structures and Typedefs *
61*********************************************************************************************************************************/
62typedef struct RTSHA3ALTPRIVATECTX
63{
64 /** The KECCAK state (W=1600). */
65 union
66 {
67 uint64_t au64[/*1600/64 =*/ 25];
68 uint8_t ab[/*1600/8 =*/ 200];
69 };
70
71 /** Current input position. */
72 uint8_t offInput;
73 /** The number of bytes to xor into the state before doing KECCAK. */
74 uint8_t cbInput;
75 /** The digest size in bytes. */
76 uint8_t cbDigest;
77 /** Padding the size up to 208 bytes. */
78 uint8_t abPadding[4];
79 /** Set if we've finalized the digest. */
80 bool fFinal;
81} RTSHA3ALTPRIVATECTX;
82
83#define RT_SHA3_PRIVATE_ALT_CONTEXT
84#include <iprt/sha.h>
85
86
87
88static void rtSha3Keccak(RTSHA3ALTPRIVATECTX *pState)
89{
90#ifdef RT_BIG_ENDIAN
91 /* This sucks a performance wise on big endian systems, sorry. We just
92 needed something simple that works on AMD64 and x86. */
93 for (size_t i = 0; i < RT_ELEMENTS(pState->aState); i++)
94 pState->au64[i] = RT_LE2H_U64(pState->au64[i]);
95#endif
96
97 /*
98 * Rounds: Rnd(A,idxRound) = Iota(Chi(Pi(Rho(Theta(A)))), idxRount) [3.3]
99 */
100 for (uint32_t idxRound = 0; idxRound < RTSHA3_ROUNDS; idxRound++)
101 {
102 /*
103 * 3.2.1 Theta
104 */
105 {
106 /* Step 1: */
107 const uint64_t au64C[5] =
108 {
109 pState->au64[0] ^ pState->au64[5] ^ pState->au64[10] ^ pState->au64[15] ^ pState->au64[20],
110 pState->au64[1] ^ pState->au64[6] ^ pState->au64[11] ^ pState->au64[16] ^ pState->au64[21],
111 pState->au64[2] ^ pState->au64[7] ^ pState->au64[12] ^ pState->au64[17] ^ pState->au64[22],
112 pState->au64[3] ^ pState->au64[8] ^ pState->au64[13] ^ pState->au64[18] ^ pState->au64[23],
113 pState->au64[4] ^ pState->au64[9] ^ pState->au64[14] ^ pState->au64[19] ^ pState->au64[24],
114 };
115
116 /* Step 2 & 3: */
117#ifndef RTSHA3_FULL_UNROLL
118 for (size_t i = 0; i < RT_ELEMENTS(au64C); i++)
119 {
120 uint64_t const u64D = au64C[(i + 4) % RT_ELEMENTS(au64C)]
121 ^ ASMRotateLeftU64(au64C[(i + 1) % RT_ELEMENTS(au64C)], 1);
122 pState->au64[ 0 + i] ^= u64D;
123 pState->au64[ 5 + i] ^= u64D;
124 pState->au64[10 + i] ^= u64D;
125 pState->au64[15 + i] ^= u64D;
126 pState->au64[20 + i] ^= u64D;
127 }
128#else /* RTSHA3_FULL_UNROLL */
129# define THETA_STEP_2_3(a_i, a_idxCLeft, a_idxCRight) do { \
130 uint64_t const u64D = au64C[a_idxCLeft] ^ ASMRotateLeftU64(au64C[a_idxCRight], 1); \
131 pState->au64[ 0 + a_i] ^= u64D; \
132 pState->au64[ 5 + a_i] ^= u64D; \
133 pState->au64[10 + a_i] ^= u64D; \
134 pState->au64[15 + a_i] ^= u64D; \
135 pState->au64[20 + a_i] ^= u64D; \
136 } while (0)
137 THETA_STEP_2_3(0, 4, 1);
138 THETA_STEP_2_3(1, 0, 2);
139 THETA_STEP_2_3(2, 1, 3);
140 THETA_STEP_2_3(3, 2, 4);
141 THETA_STEP_2_3(4, 3, 0);
142#endif /* RTSHA3_FULL_UNROLL */
143 }
144
145 /*
146 * 3.2.2 Rho + 3.2.3 Pi
147 */
148 {
149#ifndef RTSHA3_FULL_UNROLL
150 static uint8_t const s_aidxState[] = {10,7,11,17,18, 3, 5,16, 8,21, 24, 4,15,23,19, 13,12, 2,20,14, 22, 9, 6, 1};
151 static uint8_t const s_acRotate[] = { 1,3, 6,10,15, 21,28,36,45,55, 2,14,27,41,56, 8,25,43,62,18, 39,61,20,44};
152 AssertCompile(RT_ELEMENTS(s_aidxState) == 24); AssertCompile(RT_ELEMENTS(s_acRotate) == 24);
153 uint64_t u64 = pState->au64[1 /*s_aidxState[RT_ELEMENTS(s_aidxState) - 1]*/];
154# if !defined(_MSC_VER) /* This is slower with VS2019 but slightly faster with g++ (10.2.1). */
155 for (size_t i = 0; i <= 23 - 1; i++) /*i=t*/
156 {
157 uint64_t const u64Result = ASMRotateLeftU64(u64, s_acRotate[i]);
158 size_t const idxState = s_aidxState[i];
159 u64 = pState->au64[idxState];
160 pState->au64[idxState] = u64Result;
161 }
162 pState->au64[1 /*s_aidxState[23]*/] = ASMRotateLeftU64(u64, 44 /*s_acRotate[23]*/);
163# else
164 for (size_t i = 0; i <= 23; i++) /*i=t*/
165 {
166 uint64_t const u64Result = ASMRotateLeftU64(u64, s_acRotate[i]);
167 size_t const idxState = s_aidxState[i];
168 u64 = pState->au64[idxState];
169 pState->au64[idxState] = u64Result;
170 }
171# endif
172#else /* RTSHA3_FULL_UNROLL */
173# define RHO_AND_PI(a_idxState, a_cRotate) do { \
174 uint64_t const u64Result = ASMRotateLeftU64(u64, a_cRotate); \
175 u64 = pState->au64[a_idxState]; \
176 pState->au64[a_idxState] = u64Result; \
177 } while (0)
178
179 uint64_t u64 = pState->au64[1 /*s_aidxState[RT_ELEMENTS(s_aidxState) - 1]*/];
180 RHO_AND_PI(10, 1);
181 RHO_AND_PI( 7, 3);
182 RHO_AND_PI(11, 6);
183 RHO_AND_PI(17, 10);
184 RHO_AND_PI(18, 15);
185 RHO_AND_PI( 3, 21);
186 RHO_AND_PI( 5, 28);
187 RHO_AND_PI(16, 36);
188 RHO_AND_PI( 8, 45);
189 RHO_AND_PI(21, 55);
190 RHO_AND_PI(24, 2);
191 RHO_AND_PI( 4, 14);
192 RHO_AND_PI(15, 27);
193 RHO_AND_PI(23, 41);
194 RHO_AND_PI(19, 56);
195 RHO_AND_PI(13, 8);
196 RHO_AND_PI(12, 25);
197 RHO_AND_PI( 2, 43);
198 RHO_AND_PI(20, 62);
199 RHO_AND_PI(14, 18);
200 RHO_AND_PI(22, 39);
201 RHO_AND_PI( 9, 61);
202 RHO_AND_PI( 6, 20);
203 pState->au64[1 /*s_aidxState[23]*/] = ASMRotateLeftU64(u64, 44 /*s_acRotate[23]*/);
204
205#endif /* RTSHA3_FULL_UNROLL */
206 }
207
208 /*
209 * 3.2.4 Chi & 3.2.5 Iota.
210 */
211 /* Iota values xor constants (indexed by round). */
212 static uint64_t const s_au64RC[] =
213 {
214 UINT64_C(0x0000000000000001), UINT64_C(0x0000000000008082), UINT64_C(0x800000000000808a), UINT64_C(0x8000000080008000),
215 UINT64_C(0x000000000000808b), UINT64_C(0x0000000080000001), UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008009),
216 UINT64_C(0x000000000000008a), UINT64_C(0x0000000000000088), UINT64_C(0x0000000080008009), UINT64_C(0x000000008000000a),
217 UINT64_C(0x000000008000808b), UINT64_C(0x800000000000008b), UINT64_C(0x8000000000008089), UINT64_C(0x8000000000008003),
218 UINT64_C(0x8000000000008002), UINT64_C(0x8000000000000080), UINT64_C(0x000000000000800a), UINT64_C(0x800000008000000a),
219 UINT64_C(0x8000000080008081), UINT64_C(0x8000000000008080), UINT64_C(0x0000000080000001), UINT64_C(0x8000000080008008),
220 };
221 AssertCompile(RT_ELEMENTS(s_au64RC) == RTSHA3_ROUNDS);
222#ifndef RTSHA3_FULL_UNROLL
223 /* Chi */
224 for (size_t i = 0; i < 25; i += 5)
225 {
226# ifndef _MSC_VER /* This is typically slower with VS2019 - go figure. Makes not difference with g++. */
227 uint64_t const u0 = pState->au64[i + 0];
228 uint64_t const u1 = pState->au64[i + 1];
229 uint64_t const u2 = pState->au64[i + 2];
230 pState->au64[i + 0] = u0 ^ (~u1 & u2);
231 uint64_t const u3 = pState->au64[i + 3];
232 pState->au64[i + 1] = u1 ^ (~u2 & u3);
233 uint64_t const u4 = pState->au64[i + 4];
234 pState->au64[i + 2] = u2 ^ (~u3 & u4);
235 pState->au64[i + 3] = u3 ^ (~u4 & u0);
236 pState->au64[i + 4] = u4 ^ (~u0 & u1);
237# else
238 uint64_t const au64Tmp[] = { pState->au64[i + 0], pState->au64[i + 1], pState->au64[i + 2],
239 pState->au64[i + 3], pState->au64[i + 4] };
240 pState->au64[i + 0] ^= ~au64Tmp[1] & au64Tmp[2];
241 pState->au64[i + 1] ^= ~au64Tmp[2] & au64Tmp[3];
242 pState->au64[i + 2] ^= ~au64Tmp[3] & au64Tmp[4];
243 pState->au64[i + 3] ^= ~au64Tmp[4] & au64Tmp[0];
244 pState->au64[i + 4] ^= ~au64Tmp[0] & au64Tmp[1];
245# endif
246 }
247
248 /* Iota. */
249 pState->au64[0] ^= s_au64RC[idxRound];
250
251#else /* RTSHA3_FULL_UNROLL */
252# define CHI_AND_IOTA(a_i, a_IotaExpr) do { \
253 uint64_t const u0 = pState->au64[a_i + 0]; \
254 uint64_t const u1 = pState->au64[a_i + 1]; \
255 uint64_t const u2 = pState->au64[a_i + 2]; \
256 pState->au64[a_i + 0] = u0 ^ (~u1 & u2) a_IotaExpr; \
257 uint64_t const u3 = pState->au64[a_i + 3]; \
258 pState->au64[a_i + 1] = u1 ^ (~u2 & u3); \
259 uint64_t const u4 = pState->au64[a_i + 4]; \
260 pState->au64[a_i + 2] = u2 ^ (~u3 & u4); \
261 pState->au64[a_i + 3] = u3 ^ (~u4 & u0); \
262 pState->au64[a_i + 4] = u4 ^ (~u0 & u1); \
263 } while (0)
264 CHI_AND_IOTA( 0, ^ s_au64RC[idxRound]);
265 CHI_AND_IOTA( 5, RT_NOTHING);
266 CHI_AND_IOTA(10, RT_NOTHING);
267 CHI_AND_IOTA(15, RT_NOTHING);
268 CHI_AND_IOTA(20, RT_NOTHING);
269#endif /* RTSHA3_FULL_UNROLL */
270 }
271
272#ifdef RT_BIG_ENDIAN
273 for (size_t i = 0; i < RT_ELEMENTS(pState->au64State); i++)
274 pState->au64State[i] = RT_H2LE_U64(pState->au64State[i]);
275#endif
276}
277
278
279static int rtSha3Init(RTSHA3ALTPRIVATECTX *pCtx, unsigned cBitsDigest)
280{
281 RT_ZERO(pCtx->au64);
282 pCtx->offInput = 0;
283 pCtx->cbInput = (uint8_t)(sizeof(pCtx->ab) - (2 * cBitsDigest / 8));
284 pCtx->cbDigest = cBitsDigest / 8;
285 pCtx->fFinal = false;
286 return VINF_SUCCESS;
287}
288
289
290static int rtSha3Update(RTSHA3ALTPRIVATECTX *pCtx, uint8_t const *pbData, size_t cbData)
291{
292 Assert(!pCtx->fFinal);
293 size_t const cbInput = pCtx->cbInput;
294 size_t offState = pCtx->offInput;
295 Assert(!(cbInput & 7));
296#if 1
297 if ( ((uintptr_t)pbData & 7) == 0
298 && (offState & 7) == 0
299 && (cbData & 7) == 0)
300 {
301 uint64_t const cQwordsInput = cbInput / sizeof(uint64_t);
302 uint64_t const *pu64Data = (uint64_t const *)pbData;
303 size_t cQwordsData = cbData / sizeof(uint64_t);
304 size_t offData = 0;
305 offState /= sizeof(uint64_t);
306
307 /*
308 * Any catching up to do?
309 */
310 if (offState == 0 || cQwordsData >= cQwordsInput - offState)
311 {
312 if (offState > 0)
313 {
314 while (offState < cQwordsInput)
315 pCtx->au64[offState++] ^= pu64Data[offData++];
316 rtSha3Keccak(pCtx);
317 offState = 0;
318 }
319 if (offData < cQwordsData)
320 {
321 /*
322 * Do full chunks.
323 */
324# if 1
325 switch (cQwordsInput)
326 {
327 case 18: /* ( 200 - (2 * 224/8) = 0x90 (144) ) / 8 = 0x12 (18) */
328 {
329 size_t cFullChunks = (cQwordsData - offData) / 18;
330 while (cFullChunks-- > 0)
331 {
332 pCtx->au64[ 0] ^= pu64Data[offData + 0];
333 pCtx->au64[ 1] ^= pu64Data[offData + 1];
334 pCtx->au64[ 2] ^= pu64Data[offData + 2];
335 pCtx->au64[ 3] ^= pu64Data[offData + 3];
336 pCtx->au64[ 4] ^= pu64Data[offData + 4];
337 pCtx->au64[ 5] ^= pu64Data[offData + 5];
338 pCtx->au64[ 6] ^= pu64Data[offData + 6];
339 pCtx->au64[ 7] ^= pu64Data[offData + 7];
340 pCtx->au64[ 8] ^= pu64Data[offData + 8];
341 pCtx->au64[ 9] ^= pu64Data[offData + 9];
342 pCtx->au64[10] ^= pu64Data[offData + 10];
343 pCtx->au64[11] ^= pu64Data[offData + 11];
344 pCtx->au64[12] ^= pu64Data[offData + 12];
345 pCtx->au64[13] ^= pu64Data[offData + 13];
346 pCtx->au64[14] ^= pu64Data[offData + 14];
347 pCtx->au64[15] ^= pu64Data[offData + 15];
348 pCtx->au64[16] ^= pu64Data[offData + 16];
349 pCtx->au64[17] ^= pu64Data[offData + 17];
350 offData += 18;
351 rtSha3Keccak(pCtx);
352 }
353 break;
354 }
355
356 case 17: /* ( 200 - (2 * 256/8) = 0x88 (136) ) / 8 = 0x11 (17) */
357 {
358 size_t cFullChunks = (cQwordsData - offData) / 17;
359 while (cFullChunks-- > 0)
360 {
361 pCtx->au64[ 0] ^= pu64Data[offData + 0];
362 pCtx->au64[ 1] ^= pu64Data[offData + 1];
363 pCtx->au64[ 2] ^= pu64Data[offData + 2];
364 pCtx->au64[ 3] ^= pu64Data[offData + 3];
365 pCtx->au64[ 4] ^= pu64Data[offData + 4];
366 pCtx->au64[ 5] ^= pu64Data[offData + 5];
367 pCtx->au64[ 6] ^= pu64Data[offData + 6];
368 pCtx->au64[ 7] ^= pu64Data[offData + 7];
369 pCtx->au64[ 8] ^= pu64Data[offData + 8];
370 pCtx->au64[ 9] ^= pu64Data[offData + 9];
371 pCtx->au64[10] ^= pu64Data[offData + 10];
372 pCtx->au64[11] ^= pu64Data[offData + 11];
373 pCtx->au64[12] ^= pu64Data[offData + 12];
374 pCtx->au64[13] ^= pu64Data[offData + 13];
375 pCtx->au64[14] ^= pu64Data[offData + 14];
376 pCtx->au64[15] ^= pu64Data[offData + 15];
377 pCtx->au64[16] ^= pu64Data[offData + 16];
378 offData += 17;
379 rtSha3Keccak(pCtx);
380 }
381 break;
382 }
383
384 case 13: /* ( 200 - (2 * 384/8) = 0x68 (104) ) / 8 = 0x0d (13) */
385 {
386 size_t cFullChunks = (cQwordsData - offData) / 13;
387 while (cFullChunks-- > 0)
388 {
389 pCtx->au64[ 0] ^= pu64Data[offData + 0];
390 pCtx->au64[ 1] ^= pu64Data[offData + 1];
391 pCtx->au64[ 2] ^= pu64Data[offData + 2];
392 pCtx->au64[ 3] ^= pu64Data[offData + 3];
393 pCtx->au64[ 4] ^= pu64Data[offData + 4];
394 pCtx->au64[ 5] ^= pu64Data[offData + 5];
395 pCtx->au64[ 6] ^= pu64Data[offData + 6];
396 pCtx->au64[ 7] ^= pu64Data[offData + 7];
397 pCtx->au64[ 8] ^= pu64Data[offData + 8];
398 pCtx->au64[ 9] ^= pu64Data[offData + 9];
399 pCtx->au64[10] ^= pu64Data[offData + 10];
400 pCtx->au64[11] ^= pu64Data[offData + 11];
401 pCtx->au64[12] ^= pu64Data[offData + 12];
402 offData += 13;
403 rtSha3Keccak(pCtx);
404 }
405 break;
406 }
407
408 case 9: /* ( 200 - (2 * 512/8) = 0x48 (72) ) / 8 = 0x09 (9) */
409 {
410 size_t cFullChunks = (cQwordsData - offData) / 9;
411 while (cFullChunks-- > 0)
412 {
413 pCtx->au64[ 0] ^= pu64Data[offData + 0];
414 pCtx->au64[ 1] ^= pu64Data[offData + 1];
415 pCtx->au64[ 2] ^= pu64Data[offData + 2];
416 pCtx->au64[ 3] ^= pu64Data[offData + 3];
417 pCtx->au64[ 4] ^= pu64Data[offData + 4];
418 pCtx->au64[ 5] ^= pu64Data[offData + 5];
419 pCtx->au64[ 6] ^= pu64Data[offData + 6];
420 pCtx->au64[ 7] ^= pu64Data[offData + 7];
421 pCtx->au64[ 8] ^= pu64Data[offData + 8];
422 offData += 9;
423 rtSha3Keccak(pCtx);
424 }
425 break;
426 }
427
428 default:
429 {
430 AssertFailed();
431# endif
432 size_t cFullChunks = (cQwordsData - offData) / cQwordsInput;
433 while (cFullChunks-- > 0)
434 {
435 offState = cQwordsInput;
436 while (offState-- > 0)
437 pCtx->au64[offState] ^= pu64Data[offData + offState];
438 offData += cQwordsInput;
439 rtSha3Keccak(pCtx);
440 }
441# if 1
442 break;
443 }
444 }
445# endif
446 offState = 0;
447
448 /*
449 * Partial last chunk?
450 */
451 if (offData < cQwordsData)
452 {
453 Assert(cQwordsData - offData < cQwordsInput);
454 while (offData < cQwordsData)
455 pCtx->au64[offState++] ^= pu64Data[offData++];
456 offState *= sizeof(uint64_t);
457 }
458 }
459 }
460 else
461 {
462 while (offData < cQwordsData)
463 pCtx->au64[offState++] ^= pu64Data[offData++];
464 offState *= sizeof(uint64_t);
465 }
466 Assert(offData == cQwordsData);
467 }
468 else
469#endif
470 {
471 /*
472 * Misaligned input/state, so just do simpe byte by byte processing.
473 */
474 for (size_t offData = 0; offData < cbData; offData++)
475 {
476 pCtx->ab[offState] ^= pbData[offData];
477 offState++;
478 if (offState < cbInput)
479 { /* likely */ }
480 else
481 {
482 rtSha3Keccak(pCtx);
483 offState = 0;
484 }
485 }
486 }
487 pCtx->offInput = (uint8_t)offState;
488 return VINF_SUCCESS;
489}
490
491
492static void rtSha3FinalInternal(RTSHA3ALTPRIVATECTX *pCtx)
493{
494 Assert(!pCtx->fFinal);
495
496 pCtx->ab[pCtx->offInput] ^= 0x06;
497 pCtx->ab[pCtx->cbInput - 1] ^= 0x80;
498 rtSha3Keccak(pCtx);
499}
500
501
502static int rtSha3Final(RTSHA3ALTPRIVATECTX *pCtx, uint8_t *pbDigest)
503{
504 Assert(!pCtx->fFinal);
505
506 rtSha3FinalInternal(pCtx);
507
508 memcpy(pbDigest, pCtx->ab, pCtx->cbDigest);
509
510 /* Wipe non-hash state. */
511 RT_BZERO(&pCtx->ab[pCtx->cbDigest], sizeof(pCtx->ab) - pCtx->cbDigest);
512 pCtx->fFinal = true;
513 return VINF_SUCCESS;
514}
515
516
517static int rtSha3(const void *pvData, size_t cbData, unsigned cBitsDigest, uint8_t *pabHash)
518{
519 RTSHA3ALTPRIVATECTX Ctx;
520 rtSha3Init(&Ctx, cBitsDigest);
521 rtSha3Update(&Ctx, (uint8_t const *)pvData, cbData);
522 rtSha3Final(&Ctx, pabHash);
523 return VINF_SUCCESS;
524}
525
526
527static bool rtSha3Check(const void *pvData, size_t cbData, unsigned cBitsDigest, const uint8_t *pabHash)
528{
529 RTSHA3ALTPRIVATECTX Ctx;
530 rtSha3Init(&Ctx, cBitsDigest);
531 rtSha3Update(&Ctx, (uint8_t const *)pvData, cbData);
532 rtSha3FinalInternal(&Ctx);
533 bool fRet = memcmp(pabHash, &Ctx.ab, cBitsDigest / 8) == 0;
534 RT_ZERO(Ctx);
535 return fRet;
536}
537
538
539/** Macro for declaring the interface for a SHA3 variation.
540 * @internal */
541#define RTSHA3_DEFINE_VARIANT(a_cBits) \
542AssertCompile((a_cBits / 8) == RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)); \
543AssertCompile(sizeof(RT_CONCAT3(RTSHA3T,a_cBits,CONTEXT)) >= sizeof(RTSHA3ALTPRIVATECTX)); \
544\
545RTDECL(int) RT_CONCAT(RTSha3t,a_cBits)(const void *pvBuf, size_t cbBuf, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
546{ \
547 return rtSha3(pvBuf, cbBuf, a_cBits, pabHash); \
548} \
549RT_EXPORT_SYMBOL(RT_CONCAT(RTSha3t,a_cBits)); \
550\
551\
552RTDECL(bool) RT_CONCAT3(RTSha3t,a_cBits,Check)(const void *pvBuf, size_t cbBuf, \
553 uint8_t const pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
554{ \
555 return rtSha3Check(pvBuf, cbBuf, a_cBits, pabHash); \
556} \
557RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Check)); \
558\
559\
560RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Init)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx) \
561{ \
562 AssertCompile(sizeof(pCtx->Sha3.a64Padding) >= sizeof(pCtx->Sha3.AltPrivate)); \
563 AssertCompile(sizeof(pCtx->Sha3.a64Padding) == sizeof(pCtx->Sha3.abPadding)); \
564 return rtSha3Init(&pCtx->Sha3.AltPrivate, a_cBits); \
565} \
566RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Init)); \
567\
568\
569RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Update)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx, const void *pvBuf, size_t cbBuf) \
570{ \
571 Assert(pCtx->Sha3.AltPrivate.cbDigest == (a_cBits) / 8); \
572 return rtSha3Update(&pCtx->Sha3.AltPrivate, (uint8_t const *)pvBuf, cbBuf); \
573} \
574RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Update)); \
575\
576\
577RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Final)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx, \
578 uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
579{ \
580 Assert(pCtx->Sha3.AltPrivate.cbDigest == (a_cBits) / 8); \
581 return rtSha3Final(&pCtx->Sha3.AltPrivate, pabHash); \
582} \
583RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Final)); \
584\
585\
586RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Cleanup)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx) \
587{ \
588 if (pCtx) \
589 { \
590 Assert(pCtx->Sha3.AltPrivate.cbDigest == (a_cBits) / 8); \
591 RT_ZERO(*pCtx); \
592 } \
593 return VINF_SUCCESS; \
594} \
595RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Cleanup)); \
596\
597\
598RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,Clone)(RT_CONCAT3(PRTSHA3T,a_cBits,CONTEXT) pCtx, \
599 RT_CONCAT3(RTSHA3T,a_cBits,CONTEXT) const *pCtxSrc) \
600{ \
601 memcpy(pCtx, pCtxSrc, sizeof(*pCtx)); \
602 return VINF_SUCCESS; \
603} \
604RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,Clone)); \
605\
606\
607RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,ToString)(uint8_t const pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)], \
608 char *pszDigest, size_t cchDigest) \
609{ \
610 return RTStrPrintHexBytes(pszDigest, cchDigest, pabHash, (a_cBits) / 8, 0 /*fFlags*/); \
611} \
612RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,ToString)); \
613\
614\
615RTDECL(int) RT_CONCAT3(RTSha3t,a_cBits,FromString)(char const *pszDigest, uint8_t pabHash[RT_CONCAT3(RTSHA3_,a_cBits,_HASH_SIZE)]) \
616{ \
617 return RTStrConvertHexBytes(RTStrStripL(pszDigest), &pabHash[0], (a_cBits) / 8, 0 /*fFlags*/); \
618} \
619RT_EXPORT_SYMBOL(RT_CONCAT3(RTSha3t,a_cBits,FromString))
620
621
622RTSHA3_DEFINE_VARIANT(224);
623RTSHA3_DEFINE_VARIANT(256);
624RTSHA3_DEFINE_VARIANT(384);
625RTSHA3_DEFINE_VARIANT(512);
626
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette