VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use