VirtualBox

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

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

IPRT/sha3: Some VS2019 performance tweaks. bugref:9734

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