Bruno Haible <br...@clisp.org> writes: > Thanks for testing. Now I'm convinced of the absence of a fatal typo > somewhere. > [...] > I see. Indeed, some Gnulib modules make fewer assumptions than others / > strive for greater portability than others. Well spotted!
Thanks for the review, all. I pushed the attached v2 patches. The only change outside of some comment/typo fixes is fixing two -Wpointer-arith warnings I saw when building coreutils. I always fix those anyways, even though I have personally not used a compiler that does not support the GNU C extension allowing addition to void pointers [1]. Bruno, I am curious, do you know of any compilers where that is not the case? I'll add the test case Pádraig recommended in a seperate commit later. And clean up my local coreutils patch before sending. Collin [1] https://gcc.gnu.org/onlinedocs/gcc/Pointer-Arith.html#Arithmetic-on-void--and-Function-Pointers
>From 4cdf7734fbdb040557f253ceb885c8aa1dbf225b Mon Sep 17 00:00:00 2001 Message-ID: <4cdf7734fbdb040557f253ceb885c8aa1dbf225b.1756677369.git.collin.fu...@gmail.com> From: Collin Funk <collin.fu...@gmail.com> Date: Sun, 31 Aug 2025 11:43:37 -0700 Subject: [PATCH v2 1/4] crypto/sha3-buffer: New module. * lib/u64.h (u64getlo, u64not): New functions. * lib/sha3.c: New file, based on lib/sha512.c. * lib/sha3.h: New file, based on lib/sha512.h. * modules/crypto/sha3-buffer: New file. --- ChangeLog | 8 + lib/sha3.c | 316 +++++++++++++++++++++++++++++++++++++ lib/sha3.h | 101 ++++++++++++ lib/u64.h | 19 +++ modules/crypto/sha3-buffer | 28 ++++ 5 files changed, 472 insertions(+) create mode 100644 lib/sha3.c create mode 100644 lib/sha3.h create mode 100644 modules/crypto/sha3-buffer diff --git a/ChangeLog b/ChangeLog index 70dc193626..24093d2d63 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2025-08-31 Collin Funk <collin.fu...@gmail.com> + + crypto/sha3-buffer: New module. + * lib/u64.h (u64getlo, u64not): New functions. + * lib/sha3.c: New file, based on lib/sha512.c. + * lib/sha3.h: New file, based on lib/sha512.h. + * modules/crypto/sha3-buffer: New file. + 2025-08-31 Paul Eggert <egg...@cs.ucla.edu> u64: avoid theoretical problem with >64-bit int diff --git a/lib/sha3.c b/lib/sha3.c new file mode 100644 index 0000000000..f4e56ab3a1 --- /dev/null +++ b/lib/sha3.c @@ -0,0 +1,316 @@ +/* sha3.c - Functions to calculate SHA-3 hashes as specified by FIPS-202. + Copyright (C) 2025 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Collin Funk <collin.fu...@gmail.com>, 2025. */ + +#include <config.h> + +/* Specification. */ +#include "sha3.h" + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include <byteswap.h> +#ifdef WORDS_BIGENDIAN +# define SWAP(n) u64bswap (n) +#else +# define SWAP(n) (n) +#endif + +static const u64 rc[] = { + u64init (0x00000000, 0x00000001), u64init (0x00000000, 0x00008082), + u64init (0x80000000, 0x0000808A), u64init (0x80000000, 0x80008000), + u64init (0x00000000, 0x0000808B), u64init (0x00000000, 0x80000001), + u64init (0x80000000, 0x80008081), u64init (0x80000000, 0x00008009), + u64init (0x00000000, 0x0000008A), u64init (0x00000000, 0x00000088), + u64init (0x00000000, 0x80008009), u64init (0x00000000, 0x8000000A), + u64init (0x00000000, 0x8000808B), u64init (0x80000000, 0x0000008B), + u64init (0x80000000, 0x00008089), u64init (0x80000000, 0x00008003), + u64init (0x80000000, 0x00008002), u64init (0x80000000, 0x00000080), + u64init (0x00000000, 0x0000800A), u64init (0x80000000, 0x8000000A), + u64init (0x80000000, 0x80008081), u64init (0x80000000, 0x00008080), + u64init (0x00000000, 0x80000001), u64init (0x80000000, 0x80008008) +}; + +#define DEFINE_SHA3_INIT_CTX(SIZE) \ + void \ + sha3_##SIZE##_init_ctx (struct sha3_ctx *ctx) \ + { \ + memset (&ctx->state, '\0', sizeof ctx->state); \ + ctx->buflen = 0; \ + ctx->digestlen = SHA3_##SIZE##_DIGEST_SIZE; \ + ctx->blocklen = SHA3_##SIZE##_BLOCK_SIZE; \ + } + +DEFINE_SHA3_INIT_CTX (224) +DEFINE_SHA3_INIT_CTX (256) +DEFINE_SHA3_INIT_CTX (384) +DEFINE_SHA3_INIT_CTX (512) + +/* Copy the value from V into the memory location pointed to by *CP, + If your architecture allows unaligned access, this is equivalent to + * (__typeof__ (v) *) cp = v */ +static void +set_uint64 (char *cp, u64 v) +{ + memcpy (cp, &v, sizeof v); +} + +void * +sha3_read_ctx (const struct sha3_ctx *ctx, void *resbuf) +{ + char *r = resbuf; + int i; + size_t words = ctx->digestlen / sizeof *ctx->state; + size_t bytes = ctx->digestlen % sizeof *ctx->state; + + for (i = 0; i < words; ++i, r += sizeof *ctx->state) + set_uint64 (r, SWAP (ctx->state[i])); + if (bytes) + { + u64 word = ctx->state[i]; + do + { + *r++ = u64getlo (word) & 0xFF; + word = u64shr (word, 8); + } + while (--bytes); + } + return resbuf; +} + +static void +sha3_conclude_ctx (struct sha3_ctx *ctx) +{ + ctx->buffer[ctx->buflen++] = 0x06; + memset (ctx->buffer + ctx->buflen, '\0', ctx->blocklen - ctx->buflen); + ctx->buffer[ctx->blocklen - 1] |= 0x80; + sha3_process_block (ctx->buffer, ctx->blocklen, ctx); +} + +void * +sha3_finish_ctx (struct sha3_ctx *ctx, void *resbuf) +{ + sha3_conclude_ctx (ctx); + return sha3_read_ctx (ctx, resbuf); +} + +#define DEFINE_SHA3_BUFFER(SIZE) \ + void * \ + sha3_##SIZE##_buffer (const char *buffer, size_t len, void *resblock) \ + { \ + struct sha3_ctx ctx; \ + sha3_##SIZE##_init_ctx (&ctx); \ + sha3_process_bytes (buffer, len, &ctx); \ + return sha3_finish_ctx (&ctx, resblock); \ + } + +DEFINE_SHA3_BUFFER (224) +DEFINE_SHA3_BUFFER (256) +DEFINE_SHA3_BUFFER (384) +DEFINE_SHA3_BUFFER (512) + +void +sha3_process_bytes (const void *buffer, size_t len, struct sha3_ctx *ctx) +{ + if (0 < ctx->buflen) + { + size_t left = ctx->blocklen - ctx->buflen; + if (len < left) + { + /* Not enough to fill a full block. */ + memcpy (ctx->buffer + ctx->buflen, buffer, len); + ctx->buflen += len; + return; + } + /* Process the block that already had bytes buffered. */ + memcpy (ctx->buffer + ctx->buflen, buffer, left); + buffer = (char *) buffer + left; + len -= left; + sha3_process_block (ctx->buffer, ctx->blocklen, ctx); + } + /* Process as many complete blocks as possible. */ + if (0 < len) + { + size_t full_blocks = (len / ctx->blocklen) * ctx->blocklen; + sha3_process_block (buffer, full_blocks, ctx); + buffer = (char *) buffer + full_blocks; + len -= full_blocks; + memcpy (ctx->buffer, buffer, len); + ctx->buflen = len; + } +} + +void +sha3_process_block (const void *buffer, size_t len, struct sha3_ctx *ctx) +{ + u64 *a = ctx->state; + const u64 *words = buffer; + size_t nwords = len / sizeof *words; + const u64 *endp = words + nwords; + u64 c[5]; + u64 d[5]; + u64 t1; + u64 t2; + + while (words < endp) + { + for (size_t i = 0; i < ctx->blocklen / sizeof *ctx->state; ++i, ++words) + ctx->state[i] = u64xor (ctx->state[i], SWAP (*words)); + for (int i = 0; i < 24; ++i) + { + /* Theta step 1. */ + c[0] = u64xor (u64xor (u64xor (u64xor (a[0], a[5]), a[10]), + a[15]), a[20]); + c[1] = u64xor (u64xor (u64xor (u64xor (a[1], a[6]), a[11]), + a[16]), a[21]); + c[2] = u64xor (u64xor (u64xor (u64xor (a[2], a[7]), a[12]), + a[17]), a[22]); + c[3] = u64xor (u64xor (u64xor (u64xor (a[3], a[8]), a[13]), + a[18]), a[23]); + c[4] = u64xor (u64xor (u64xor (u64xor (a[4], a[9]), a[14]), + a[19]), a[24]); + + /* Theta step 2. */ + d[0] = u64xor (c[4], u64rol (c[1], 1)); + d[1] = u64xor (c[0], u64rol (c[2], 1)); + d[2] = u64xor (c[1], u64rol (c[3], 1)); + d[3] = u64xor (c[2], u64rol (c[4], 1)); + d[4] = u64xor (c[3], u64rol (c[0], 1)); + + /* Theta step 3. */ + a[0] = u64xor (a[0], d[0]); + a[5] = u64xor (a[5], d[0]); + a[10] = u64xor (a[10], d[0]); + a[15] = u64xor (a[15], d[0]); + a[20] = u64xor (a[20], d[0]); + a[1] = u64xor (a[1], d[1]); + a[6] = u64xor (a[6], d[1]); + a[11] = u64xor (a[11], d[1]); + a[16] = u64xor (a[16], d[1]); + a[21] = u64xor (a[21], d[1]); + a[2] = u64xor (a[2], d[2]); + a[7] = u64xor (a[7], d[2]); + a[12] = u64xor (a[12], d[2]); + a[17] = u64xor (a[17], d[2]); + a[22] = u64xor (a[22], d[2]); + a[3] = u64xor (a[3], d[3]); + a[8] = u64xor (a[8], d[3]); + a[13] = u64xor (a[13], d[3]); + a[18] = u64xor (a[18], d[3]); + a[23] = u64xor (a[23], d[3]); + a[4] = u64xor (a[4], d[4]); + a[9] = u64xor (a[9], d[4]); + a[14] = u64xor (a[14], d[4]); + a[19] = u64xor (a[19], d[4]); + a[24] = u64xor (a[24], d[4]); + + /* Rho and Pi. */ + t1 = a[1]; + t2 = u64rol (t1, 1); + t1 = a[10]; + a[10] = t2; + t2 = u64rol (t1, 3); + t1 = a[7]; + a[7] = t2; + t2 = u64rol (t1, 6); + t1 = a[11]; + a[11] = t2; + t2 = u64rol (t1, 10); + t1 = a[17]; + a[17] = t2; + t2 = u64rol (t1, 15); + t1 = a[18]; + a[18] = t2; + t2 = u64rol (t1, 21); + t1 = a[3]; + a[3] = t2; + t2 = u64rol (t1, 28); + t1 = a[5]; + a[5] = t2; + t2 = u64rol (t1, 36); + t1 = a[16]; + a[16] = t2; + t2 = u64rol (t1, 45); + t1 = a[8]; + a[8] = t2; + t2 = u64rol (t1, 55); + t1 = a[21]; + a[21] = t2; + t2 = u64rol (t1, 2); + t1 = a[24]; + a[24] = t2; + t2 = u64rol (t1, 14); + t1 = a[4]; + a[4] = t2; + t2 = u64rol (t1, 27); + t1 = a[15]; + a[15] = t2; + t2 = u64rol (t1, 41); + t1 = a[23]; + a[23] = t2; + t2 = u64rol (t1, 56); + t1 = a[19]; + a[19] = t2; + t2 = u64rol (t1, 8); + t1 = a[13]; + a[13] = t2; + t2 = u64rol (t1, 25); + t1 = a[12]; + a[12] = t2; + t2 = u64rol (t1, 43); + t1 = a[2]; + a[2] = t2; + t2 = u64rol (t1, 62); + t1 = a[20]; + a[20] = t2; + t2 = u64rol (t1, 18); + t1 = a[14]; + a[14] = t2; + t2 = u64rol (t1, 39); + t1 = a[22]; + a[22] = t2; + t2 = u64rol (t1, 61); + t1 = a[9]; + a[9] = t2; + t2 = u64rol (t1, 20); + t1 = a[6]; + a[6] = t2; + t2 = u64rol (t1, 44); + t1 = a[1]; + a[1] = t2; + + /* Chi. */ + for (int j = 0; j < 25; j += 5) + { + t1 = a[j]; + t2 = a[j + 1]; + a[j] = u64xor (a[j], u64and (u64not (a[j + 1]), a[j + 2])); + a[j + 1] = u64xor (a[j + 1], u64and (u64not (a[j + 2]), + a[j + 3])); + a[j + 2] = u64xor (a[j + 2], u64and (u64not (a[j + 3]), + a[j + 4])); + a[j + 3] = u64xor (a[j + 3], u64and (u64not (a[j + 4]), t1)); + a[j + 4] = u64xor (a[j + 4], u64and (u64not (t1), t2)); + } + + /* Iota. */ + a[0] = u64xor (a[0], rc[i]); + } + } +} diff --git a/lib/sha3.h b/lib/sha3.h new file mode 100644 index 0000000000..c299c6fab7 --- /dev/null +++ b/lib/sha3.h @@ -0,0 +1,101 @@ +/* sha3.h - Functions to calculate SHA-3 hashes as specified by FIPS-202. + Copyright (C) 2025 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Collin Funk <collin.fu...@gmail.com>, 2025. */ + +#ifndef SHA3_H +# define SHA3_H 1 + +# include <stdio.h> +# include <stdint.h> + +# include "u64.h" + +# ifdef __cplusplus +extern "C" { +# endif + +/* Digest sizes in bytes. */ +enum { SHA3_224_DIGEST_SIZE = 224 / 8 }; +enum { SHA3_256_DIGEST_SIZE = 256 / 8 }; +enum { SHA3_384_DIGEST_SIZE = 384 / 8 }; +enum { SHA3_512_DIGEST_SIZE = 512 / 8 }; + +/* Block sizes in bytes. */ +enum { SHA3_224_BLOCK_SIZE = 1152 / 8 }; +enum { SHA3_256_BLOCK_SIZE = 1088 / 8 }; +enum { SHA3_384_BLOCK_SIZE = 832 / 8 }; +enum { SHA3_512_BLOCK_SIZE = 576 / 8 }; + +/* Structure to save state of computation between the single steps. */ +struct sha3_ctx +{ + u64 state[25]; + uint8_t buffer[144]; /* Up to BLOCKLEN in use. */ + size_t buflen; /* ≥ 0, ≤ BLOCKLEN */ + size_t digestlen; /* One of SHA3_{224,256,384,512}_DIGEST_SIZE. */ + size_t blocklen; /* One of SHA3_{224,256,384,512}_BLOCK_SIZE. */ +}; + +/* Initialize structure containing state of computation. */ +extern void sha3_224_init_ctx (struct sha3_ctx *ctx); +extern void sha3_256_init_ctx (struct sha3_ctx *ctx); +extern void sha3_384_init_ctx (struct sha3_ctx *ctx); +extern void sha3_512_init_ctx (struct sha3_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of the BLOCKLEN member of CTX!!! */ +extern void sha3_process_block (const void *buffer, size_t len, + struct sha3_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of the BLOCKLEN member of CTX. */ +extern void sha3_process_bytes (const void *buffer, size_t len, + struct sha3_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX in RESBUF. + The result is always in little endian byte order, so that a byte-wise output + yields to the wanted ASCII representation of the message digest. */ +extern void *sha3_finish_ctx (struct sha3_ctx *ctx, void *restrict resbuf); + +/* Put result from CTX in RESBUF. The result is always in little endian byte + order, so that a byte-wise output yields to the wanted ASCII representation + of the message digest. */ +extern void *sha3_read_ctx (const struct sha3_ctx *ctx, + void *restrict resbuf); + +/* Compute a SHA-3 message digest for LEN bytes beginning at BUFFER. + The result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *sha3_224_buffer (const char *buffer, size_t len, + void *restrict resblock); +extern void *sha3_256_buffer (const char *buffer, size_t len, + void *restrict resblock); +extern void *sha3_384_buffer (const char *buffer, size_t len, + void *restrict resblock); +extern void *sha3_512_buffer (const char *buffer, size_t len, + void *restrict resblock); + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/lib/u64.h b/lib/u64.h index 01135057c2..a344bc7bd5 100644 --- a/lib/u64.h +++ b/lib/u64.h @@ -46,7 +46,9 @@ typedef uint64_t u64; # define u64hilo(hi, lo) ((u64) (((u64) (hi) << 32) + (lo))) # define u64init(hi, lo) u64hilo (hi, lo) # define u64lo(x) ((u64) (x)) +# define u64getlo(x) ((uint32_t) ((x) & UINT32_MAX)) # define u64size(x) u64lo (x) +# define u64not(x) (~(x)) # define u64lt(x, y) ((x) < (y)) # define u64and(x, y) ((x) & (y)) # define u64or(x, y) ((x) | (y)) @@ -95,6 +97,13 @@ u64lo (unsigned int lo) return r; } +/* Return the low 32 bits of the u64 value X. */ +_GL_U64_INLINE unsigned int +u64getlo (u64 x) +{ + return x.lo & _GL_U64_MASK32; +} + /* Return a u64 value representing SIZE, where 0 <= SIZE < 2**64. */ _GL_U64_INLINE u64 u64size (size_t size) @@ -105,6 +114,16 @@ u64size (size_t size) return r; } +/* Return the bitwise NOT of X. */ +_GL_U64_INLINE u64 +u64not (u64 x) +{ + u64 r; + r.hi = ~x.hi; + r.lo = ~x.lo; + return r; +} + /* Return X < Y. */ _GL_U64_INLINE bool u64lt (u64 x, u64 y) diff --git a/modules/crypto/sha3-buffer b/modules/crypto/sha3-buffer new file mode 100644 index 0000000000..375e7ba6a2 --- /dev/null +++ b/modules/crypto/sha3-buffer @@ -0,0 +1,28 @@ +Description: +Compute SHA-3 checksums. + +Files: +lib/sha3.h +lib/sha3.c + +Depends-on: +byteswap +c99 +stdint-h +u64 + +configure.ac: +AC_REQUIRE([AC_C_RESTRICT]) +AC_REQUIRE([gl_BIGENDIAN]) + +Makefile.am: +lib_SOURCES += sha3.c + +Include: +"sha3.h" + +License: +LGPLv2+ + +Maintainer: +all -- 2.51.0
>From ec500f501da4eab0eecb862ad734d9276c600654 Mon Sep 17 00:00:00 2001 Message-ID: <ec500f501da4eab0eecb862ad734d9276c600654.1756677369.git.collin.fu...@gmail.com> In-Reply-To: <4cdf7734fbdb040557f253ceb885c8aa1dbf225b.1756677369.git.collin.fu...@gmail.com> References: <4cdf7734fbdb040557f253ceb885c8aa1dbf225b.1756677369.git.collin.fu...@gmail.com> From: Collin Funk <collin.fu...@gmail.com> Date: Sun, 31 Aug 2025 12:51:14 -0700 Subject: [PATCH v2 2/4] crypto/sha3-buffer: Add tests. * modules/crypto/sha3-buffer-tests: New file. * tests/test-sha3-224-buffer.c: Likewise. * tests/test-sha3-256-buffer.c: Likewise. * tests/test-sha3-384-buffer.c: Likewise. * tests/test-sha3-512-buffer.c: Likewise. * tests/bench-sha3-224.c: Likewise. * tests/bench-sha3-256.c: Likewise. * tests/bench-sha3-384.c: Likewise. * tests/bench-sha3-512.c: Likewise. --- ChangeLog | 11 ++++ modules/crypto/sha3-buffer-tests | 30 +++++++++ tests/bench-sha3-224.c | 24 +++++++ tests/bench-sha3-256.c | 24 +++++++ tests/bench-sha3-384.c | 24 +++++++ tests/bench-sha3-512.c | 24 +++++++ tests/test-sha3-224-buffer.c | 93 +++++++++++++++++++++++++++ tests/test-sha3-256-buffer.c | 94 +++++++++++++++++++++++++++ tests/test-sha3-384-buffer.c | 99 +++++++++++++++++++++++++++++ tests/test-sha3-512-buffer.c | 105 +++++++++++++++++++++++++++++++ 10 files changed, 528 insertions(+) create mode 100644 modules/crypto/sha3-buffer-tests create mode 100644 tests/bench-sha3-224.c create mode 100644 tests/bench-sha3-256.c create mode 100644 tests/bench-sha3-384.c create mode 100644 tests/bench-sha3-512.c create mode 100644 tests/test-sha3-224-buffer.c create mode 100644 tests/test-sha3-256-buffer.c create mode 100644 tests/test-sha3-384-buffer.c create mode 100644 tests/test-sha3-512-buffer.c diff --git a/ChangeLog b/ChangeLog index 24093d2d63..924d67e135 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2025-08-31 Collin Funk <collin.fu...@gmail.com> + crypto/sha3-buffer: Add tests. + * modules/crypto/sha3-buffer-tests: New file. + * tests/test-sha3-224-buffer.c: Likewise. + * tests/test-sha3-256-buffer.c: Likewise. + * tests/test-sha3-384-buffer.c: Likewise. + * tests/test-sha3-512-buffer.c: Likewise. + * tests/bench-sha3-224.c: Likewise. + * tests/bench-sha3-256.c: Likewise. + * tests/bench-sha3-384.c: Likewise. + * tests/bench-sha3-512.c: Likewise. + crypto/sha3-buffer: New module. * lib/u64.h (u64getlo, u64not): New functions. * lib/sha3.c: New file, based on lib/sha512.c. diff --git a/modules/crypto/sha3-buffer-tests b/modules/crypto/sha3-buffer-tests new file mode 100644 index 0000000000..0f9e57318a --- /dev/null +++ b/modules/crypto/sha3-buffer-tests @@ -0,0 +1,30 @@ +Files: +tests/test-sha3-224-buffer.c +tests/test-sha3-256-buffer.c +tests/test-sha3-384-buffer.c +tests/test-sha3-512-buffer.c +tests/bench-sha3-224.c +tests/bench-sha3-256.c +tests/bench-sha3-384.c +tests/bench-sha3-512.c +tests/bench-digest.h +tests/bench.h + +Depends-on: +c99 +getrusage +gettimeofday + +configure.ac: + +Makefile.am: +TESTS += test-sha3-224-buffer test-sha3-256-buffer +TESTS += test-sha3-384-buffer test-sha3-512-buffer +check_PROGRAMS += test-sha3-224-buffer test-sha3-256-buffer +check_PROGRAMS += test-sha3-384-buffer test-sha3-512-buffer +noinst_PROGRAMS += bench-sha3-224 bench-sha3-256 +noinst_PROGRAMS += bench-sha3-384 bench-sha3-512 +bench_sha3_224_CPPFLAGS = $(AM_CPPFLAGS) -DNDEBUG +bench_sha3_256_CPPFLAGS = $(AM_CPPFLAGS) -DNDEBUG +bench_sha3_384_CPPFLAGS = $(AM_CPPFLAGS) -DNDEBUG +bench_sha3_512_CPPFLAGS = $(AM_CPPFLAGS) -DNDEBUG diff --git a/tests/bench-sha3-224.c b/tests/bench-sha3-224.c new file mode 100644 index 0000000000..db90e654fe --- /dev/null +++ b/tests/bench-sha3-224.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Benchmark program for the sha3_224_buffer function. */ + +#include <config.h> + +#include "sha3.h" + +#define FUNC sha3_224_buffer +#include "bench-digest.h" diff --git a/tests/bench-sha3-256.c b/tests/bench-sha3-256.c new file mode 100644 index 0000000000..24583c02b1 --- /dev/null +++ b/tests/bench-sha3-256.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Benchmark program for the sha3_256_buffer function. */ + +#include <config.h> + +#include "sha3.h" + +#define FUNC sha3_256_buffer +#include "bench-digest.h" diff --git a/tests/bench-sha3-384.c b/tests/bench-sha3-384.c new file mode 100644 index 0000000000..09834adeaa --- /dev/null +++ b/tests/bench-sha3-384.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Benchmark program for the sha3_384_buffer function. */ + +#include <config.h> + +#include "sha3.h" + +#define FUNC sha3_384_buffer +#include "bench-digest.h" diff --git a/tests/bench-sha3-512.c b/tests/bench-sha3-512.c new file mode 100644 index 0000000000..8479ffc5ad --- /dev/null +++ b/tests/bench-sha3-512.c @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Benchmark program for the sha3_512_buffer function. */ + +#include <config.h> + +#include "sha3.h" + +#define FUNC sha3_512_buffer +#include "bench-digest.h" diff --git a/tests/test-sha3-224-buffer.c b/tests/test-sha3-224-buffer.c new file mode 100644 index 0000000000..0fe5f329d8 --- /dev/null +++ b/tests/test-sha3-224-buffer.c @@ -0,0 +1,93 @@ +/* Test of the sha3_224_buffer() function. + Copyright (C) 2025 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Collin Funk <collin.fu...@gmail.com>, 2025. */ + +#include <config.h> + +/* Specification. */ +#include "sha3.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +struct test_case { + char const *message; + char const *digest; +}; + +static const struct test_case test_cases[] = { + { "", "\x6b\x4e\x03\x42\x36\x67\xdb\xb7\x3b\x6e\x15\x45\x4f\x0e\xb1\xab\xd4" + "\x59\x7f\x9a\x1b\x07\x8e\x3f\x5b\x5a\x6b\xc7" }, + { "abc", "\xe6\x42\x82\x4c\x3f\x8c\xf2\x4a\xd0\x92\x34\xee\x7d\x3c\x76\x6f" + "\xc9\xa3\xa5\x16\x8d\x0c\x94\xad\x73\xb4\x6f\xdf" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "\x8a\x24\x10\x8b\x15\x4a\xda\x21\xc9\xfd\x55\x74\x49\x44\x79\xba\x5c\x7e" + "\x7a\xb7\x6e\xf2\x64\xea\xd0\xfc\xce\x33" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopj" + "klmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "\x54\x3e\x68\x68\xe1\x66\x6c\x1a\x64\x36\x30\xdf\x77\x36\x7a\xe5\xa6\x2a" + "\x85\x07\x0a\x51\xc1\x4c\xbf\x66\x5c\xbc" }, +}; + +static int +check (char const *message, size_t len, char const *expect) +{ + char buf[SHA3_224_DIGEST_SIZE]; + if (memcmp (sha3_224_buffer (message, len, buf), + expect, SHA3_224_DIGEST_SIZE) != 0) + { + size_t i; + printf ("expected:\n"); + for (i = 0; i < SHA3_224_DIGEST_SIZE; i++) + printf ("%02x ", expect[i] & 0xFFu); + printf ("\ncomputed:\n"); + for (i = 0; i < SHA3_224_DIGEST_SIZE; i++) + printf ("%02x ", buf[i] & 0xFFu); + printf ("\n"); + return 1; + } + return 0; +} + +int +main (void) +{ + /* Check the test vectors. */ + for (size_t i = 0; i < sizeof test_cases / sizeof *test_cases; ++i) + { + char const *message = test_cases[i].message; + char const *digest = test_cases[i].digest; + if (check (message, strlen (message), digest) != 0) + return 1; + } + + /* Check that a large buffer works. */ + char *large = malloc (1000000); + if (large != NULL) + { + memset (large, 'a', 1000000); + char const *expect = ("\xd6\x93\x35\xb9\x33\x25\x19\x2e\x51\x6a\x91\x2e" + "\x6d\x19\xa1\x5c\xb5\x1c\x6e\xd5\xc1\x52\x43\xe7" + "\xa7\xfd\x65\x3c"); + if (check (large, 1000000, expect) != 0) + return 1; + free (large); + } + + return 0; +} diff --git a/tests/test-sha3-256-buffer.c b/tests/test-sha3-256-buffer.c new file mode 100644 index 0000000000..8d47874adc --- /dev/null +++ b/tests/test-sha3-256-buffer.c @@ -0,0 +1,94 @@ +/* Test of the sha3_256_buffer() function. + Copyright (C) 2025 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Collin Funk <collin.fu...@gmail.com>, 2025. */ + +#include <config.h> + +/* Specification. */ +#include "sha3.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +struct test_case { + char const *message; + char const *digest; +}; + +static const struct test_case test_cases[] = { + { "", "\xa7\xff\xc6\xf8\xbf\x1e\xd7\x66\x51\xc1\x47\x56\xa0\x61\xd6\x62\xf5" + "\x80\xff\x4d\xe4\x3b\x49\xfa\x82\xd8\x0a\x4b\x80\xf8\x43\x4a" }, + { "abc", + "\x3a\x98\x5d\xa7\x4f\xe2\x25\xb2\x04\x5c\x17\x2d\x6b\xd3\x90\xbd\x85\x5f" + "\x08\x6e\x3e\x9d\x52\x5b\x46\xbf\xe2\x45\x11\x43\x15\x32" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "\x41\xc0\xdb\xa2\xa9\xd6\x24\x08\x49\x10\x03\x76\xa8\x23\x5e\x2c\x82\xe1" + "\xb9\x99\x8a\x99\x9e\x21\xdb\x32\xdd\x97\x49\x6d\x33\x76" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopj" + "klmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "\x91\x6f\x60\x61\xfe\x87\x97\x41\xca\x64\x69\xb4\x39\x71\xdf\xdb\x28\xb1" + "\xa3\x2d\xc3\x6c\xb3\x25\x4e\x81\x2b\xe2\x7a\xad\x1d\x18" }, +}; + +static int +check (char const *message, size_t len, char const *expect) +{ + char buf[SHA3_256_DIGEST_SIZE]; + if (memcmp (sha3_256_buffer (message, len, buf), + expect, SHA3_256_DIGEST_SIZE) != 0) + { + size_t i; + printf ("expected:\n"); + for (i = 0; i < SHA3_256_DIGEST_SIZE; i++) + printf ("%02x ", expect[i] & 0xFFu); + printf ("\ncomputed:\n"); + for (i = 0; i < SHA3_256_DIGEST_SIZE; i++) + printf ("%02x ", buf[i] & 0xFFu); + printf ("\n"); + return 1; + } + return 0; +} + +int +main (void) +{ + /* Check the test vectors. */ + for (size_t i = 0; i < sizeof test_cases / sizeof *test_cases; ++i) + { + char const *message = test_cases[i].message; + char const *digest = test_cases[i].digest; + if (check (message, strlen (message), digest) != 0) + return 1; + } + + /* Check that a large buffer works. */ + char *large = malloc (1000000); + if (large != NULL) + { + memset (large, 'a', 1000000); + char const *expect = ("\x5c\x88\x75\xae\x47\x4a\x36\x34\xba\x4f\xd5\x5e" + "\xc8\x5b\xff\xd6\x61\xf3\x2a\xca\x75\xc6\xd6\x99" + "\xd0\xcd\xcb\x6c\x11\x58\x91\xc1"); + if (check (large, 1000000, expect) != 0) + return 1; + free (large); + } + + return 0; +} diff --git a/tests/test-sha3-384-buffer.c b/tests/test-sha3-384-buffer.c new file mode 100644 index 0000000000..c85408ed4a --- /dev/null +++ b/tests/test-sha3-384-buffer.c @@ -0,0 +1,99 @@ +/* Test of the sha3_384_buffer() function. + Copyright (C) 2025 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Collin Funk <collin.fu...@gmail.com>, 2025. */ + +#include <config.h> + +/* Specification. */ +#include "sha3.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +struct test_case { + char const *message; + char const *digest; +}; + +static const struct test_case test_cases[] = { + { "", "\x0c\x63\xa7\x5b\x84\x5e\x4f\x7d\x01\x10\x7d\x85\x2e\x4c\x24\x85\xc5" + "\x1a\x50\xaa\xaa\x94\xfc\x61\x99\x5e\x71\xbb\xee\x98\x3a\x2a\xc3\x71" + "\x38\x31\x26\x4a\xdb\x47\xfb\x6b\xd1\xe0\x58\xd5\xf0\x04" }, + { "abc", + "\xec\x01\x49\x82\x88\x51\x6f\xc9\x26\x45\x9f\x58\xe2\xc6\xad\x8d\xf9\xb4" + "\x73\xcb\x0f\xc0\x8c\x25\x96\xda\x7c\xf0\xe4\x9b\xe4\xb2\x98\xd8\x8c\xea" + "\x92\x7a\xc7\xf5\x39\xf1\xed\xf2\x28\x37\x6d\x25" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "\x99\x1c\x66\x57\x55\xeb\x3a\x4b\x6b\xbd\xfb\x75\xc7\x8a\x49\x2e\x8c\x56" + "\xa2\x2c\x5c\x4d\x7e\x42\x9b\xfd\xbc\x32\xb9\xd4\xad\x5a\xa0\x4a\x1f\x07" + "\x6e\x62\xfe\xa1\x9e\xef\x51\xac\xd0\x65\x7c\x22" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopj" + "klmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "\x79\x40\x7d\x3b\x59\x16\xb5\x9c\x3e\x30\xb0\x98\x22\x97\x47\x91\xc3\x13" + "\xfb\x9e\xcc\x84\x9e\x40\x6f\x23\x59\x2d\x04\xf6\x25\xdc\x8c\x70\x9b\x98" + "\xb4\x3b\x38\x52\xb3\x37\x21\x61\x79\xaa\x7f\xc7" } +}; + +static int +check (char const *message, size_t len, char const *expect) +{ + char buf[SHA3_384_DIGEST_SIZE]; + if (memcmp (sha3_384_buffer (message, len, buf), + expect, SHA3_384_DIGEST_SIZE) != 0) + { + size_t i; + printf ("expected:\n"); + for (i = 0; i < SHA3_384_DIGEST_SIZE; i++) + printf ("%02x ", expect[i] & 0xFFu); + printf ("\ncomputed:\n"); + for (i = 0; i < SHA3_384_DIGEST_SIZE; i++) + printf ("%02x ", buf[i] & 0xFFu); + printf ("\n"); + return 1; + } + return 0; +} + +int +main (void) +{ + /* Check the test vectors. */ + for (size_t i = 0; i < sizeof test_cases / sizeof *test_cases; ++i) + { + char const *message = test_cases[i].message; + char const *digest = test_cases[i].digest; + if (check (message, strlen (message), digest) != 0) + return 1; + } + + /* Check that a large buffer works. */ + char *large = malloc (1000000); + if (large != NULL) + { + memset (large, 'a', 1000000); + char const *expect = ("\xee\xe9\xe2\x4d\x78\xc1\x85\x53\x37\x98\x34\x51" + "\xdf\x97\xc8\xad\x9e\xed\xf2\x56\xc6\x33\x4f\x8e" + "\x94\x8d\x25\x2d\x5e\x0e\x76\x84\x7a\xa0\x77\x4d" + "\xdb\x90\xa8\x42\x19\x0d\x2c\x55\x8b\x4b\x83\x40"); + if (check (large, 1000000, expect) != 0) + return 1; + free (large); + } + + return 0; +} diff --git a/tests/test-sha3-512-buffer.c b/tests/test-sha3-512-buffer.c new file mode 100644 index 0000000000..535dfde168 --- /dev/null +++ b/tests/test-sha3-512-buffer.c @@ -0,0 +1,105 @@ +/* Test of the sha3_512_buffer() function. + Copyright (C) 2025 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Collin Funk <collin.fu...@gmail.com>, 2025. */ + +#include <config.h> + +/* Specification. */ +#include "sha3.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +struct test_case { + char const *message; + char const *digest; +}; + +static const struct test_case test_cases[] = { + { "", "\xa6\x9f\x73\xcc\xa2\x3a\x9a\xc5\xc8\xb5\x67\xdc\x18\x5a\x75\x6e\x97" + "\xc9\x82\x16\x4f\xe2\x58\x59\xe0\xd1\xdc\xc1\x47\x5c\x80\xa6\x15\xb2" + "\x12\x3a\xf1\xf5\xf9\x4c\x11\xe3\xe9\x40\x2c\x3a\xc5\x58\xf5\x00\x19" + "\x9d\x95\xb6\xd3\xe3\x01\x75\x85\x86\x28\x1d\xcd\x26" }, + { "abc", + "\xb7\x51\x85\x0b\x1a\x57\x16\x8a\x56\x93\xcd\x92\x4b\x6b\x09\x6e\x08\xf6" + "\x21\x82\x74\x44\xf7\x0d\x88\x4f\x5d\x02\x40\xd2\x71\x2e\x10\xe1\x16\xe9" + "\x19\x2a\xf3\xc9\x1a\x7e\xc5\x76\x47\xe3\x93\x40\x57\x34\x0b\x4c\xf4\x08" + "\xd5\xa5\x65\x92\xf8\x27\x4e\xec\x53\xf0" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "\x04\xa3\x71\xe8\x4e\xcf\xb5\xb8\xb7\x7c\xb4\x86\x10\xfc\xa8\x18\x2d\xd4" + "\x57\xce\x6f\x32\x6a\x0f\xd3\xd7\xec\x2f\x1e\x91\x63\x6d\xee\x69\x1f\xbe" + "\x0c\x98\x53\x02\xba\x1b\x0d\x8d\xc7\x8c\x08\x63\x46\xb5\x33\xb4\x9c\x03" + "\x0d\x99\xa2\x7d\xaf\x11\x39\xd6\xe7\x5e" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopj" + "klmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + "\xaf\xeb\xb2\xef\x54\x2e\x65\x79\xc5\x0c\xad\x06\xd2\xe5\x78\xf9\xf8\xdd" + "\x68\x81\xd7\xdc\x82\x4d\x26\x36\x0f\xee\xbf\x18\xa4\xfa\x73\xe3\x26\x11" + "\x22\x94\x8e\xfc\xfd\x49\x2e\x74\xe8\x2e\x21\x89\xed\x0f\xb4\x40\xd1\x87" + "\xf3\x82\x27\x0c\xb4\x55\xf2\x1d\xd1\x85" } +}; + +static int +check (char const *message, size_t len, char const *expect) +{ + char buf[SHA3_512_DIGEST_SIZE]; + if (memcmp (sha3_512_buffer (message, len, buf), + expect, SHA3_512_DIGEST_SIZE) != 0) + { + size_t i; + printf ("expected:\n"); + for (i = 0; i < SHA3_512_DIGEST_SIZE; i++) + printf ("%02x ", expect[i] & 0xFFu); + printf ("\ncomputed:\n"); + for (i = 0; i < SHA3_512_DIGEST_SIZE; i++) + printf ("%02x ", buf[i] & 0xFFu); + printf ("\n"); + return 1; + } + return 0; +} + +int +main (void) +{ + /* Check the test vectors. */ + for (size_t i = 0; i < sizeof test_cases / sizeof *test_cases; ++i) + { + char const *message = test_cases[i].message; + char const *digest = test_cases[i].digest; + if (check (message, strlen (message), digest) != 0) + return 1; + } + + /* Check that a large buffer works. */ + char *large = malloc (1000000); + if (large != NULL) + { + memset (large, 'a', 1000000); + char const *expect = ("\x3c\x3a\x87\x6d\xa1\x40\x34\xab\x60\x62\x7c\x07" + "\x7b\xb9\x8f\x7e\x12\x0a\x2a\x53\x70\x21\x2d\xff" + "\xb3\x38\x5a\x18\xd4\xf3\x88\x59\xed\x31\x1d\x0a" + "\x9d\x51\x41\xce\x9c\xc5\xc6\x6e\xe6\x89\xb2\x66" + "\xa8\xaa\x18\xac\xe8\x28\x2a\x0e\x0d\xb5\x96\xc9" + "\x0b\x0a\x7b\x87"); + if (check (large, 1000000, expect) != 0) + return 1; + free (large); + } + + return 0; +} -- 2.51.0
>From 3a3a63530b1b6931be7dba66371aed3ffd9cb1db Mon Sep 17 00:00:00 2001 Message-ID: <3a3a63530b1b6931be7dba66371aed3ffd9cb1db.1756677369.git.collin.fu...@gmail.com> In-Reply-To: <4cdf7734fbdb040557f253ceb885c8aa1dbf225b.1756677369.git.collin.fu...@gmail.com> References: <4cdf7734fbdb040557f253ceb885c8aa1dbf225b.1756677369.git.collin.fu...@gmail.com> From: Collin Funk <collin.fu...@gmail.com> Date: Sun, 31 Aug 2025 14:21:02 -0700 Subject: [PATCH v2 3/4] crypto/sha3: New module. * modules/crypto/sha3: New file. * lib/sha3-stream.c: New file, based on sha512-stream.c. * lib/sha3.h (sha3_224_stream, sha3_256_stream, sha3_384_stream) (sha3_512_stream): New declarations. --- ChangeLog | 6 ++ lib/sha3-stream.c | 145 ++++++++++++++++++++++++++++++++++++++++++++ lib/sha3.h | 10 +++ modules/crypto/sha3 | 23 +++++++ 4 files changed, 184 insertions(+) create mode 100644 lib/sha3-stream.c create mode 100644 modules/crypto/sha3 diff --git a/ChangeLog b/ChangeLog index 924d67e135..d202892dd1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2025-08-31 Collin Funk <collin.fu...@gmail.com> + crypto/sha3: New module. + * modules/crypto/sha3: New file. + * lib/sha3-stream.c: New file, based on sha512-stream.c. + * lib/sha3.h (sha3_224_stream, sha3_256_stream, sha3_384_stream) + (sha3_512_stream): New declarations. + crypto/sha3-buffer: Add tests. * modules/crypto/sha3-buffer-tests: New file. * tests/test-sha3-224-buffer.c: Likewise. diff --git a/lib/sha3-stream.c b/lib/sha3-stream.c new file mode 100644 index 0000000000..708dafa7dc --- /dev/null +++ b/lib/sha3-stream.c @@ -0,0 +1,145 @@ +/* sha3-stream.c - Functions to compute the SHA-3 message digest of files as + specified by FIPS-202. + + Copyright (C) 2025 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include "sha3.h" + +#include <stdlib.h> + +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif + +#include "af_alg.h" + +#define BLOCKSIZE 31824 +#if (BLOCKSIZE % 144 != 0 && BLOCKSIZE % 136 != 0 && BLOCKSIZE % 104 != 0 \ + && BLOCKSIZE % 72 != 0) +# error "invalid BLOCKSIZE" +#endif + +/* Compute message digest for bytes read from STREAM using algorithm ALG. + Write the message digest into RESBLOCK, which contains HASHLEN bytes. + The initial operation is INIT_CTX. Return zero if and only if + successful. */ +static int +sha3_xxx_stream (FILE *stream, char const *alg, void *resblock, + ssize_t hashlen, void (*init_ctx) (struct sha3_ctx *)) +{ + switch (afalg_stream (stream, alg, resblock, hashlen)) + { + case 0: return 0; + case -EIO: return 1; + } + + char *buffer = malloc (BLOCKSIZE + 72); + if (!buffer) + return 1; + + struct sha3_ctx ctx; + init_ctx (&ctx); + size_t sum; + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + /* Either process a partial fread() from this loop, + or the fread() in afalg_stream may have gotten EOF. + We need to avoid a subsequent fread() as EOF may + not be sticky. For details of such systems, see: + https://sourceware.org/PR1190 */ + if (feof (stream)) + goto process_partial_block; + + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + { + free (buffer); + return 1; + } + goto process_partial_block; + } + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % ctx.blocklen == 0 + */ + sha3_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha3_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha3_finish_ctx (&ctx, resblock); + free (buffer); + return 0; +} + +int +sha3_224_stream (FILE *stream, void *resblock) +{ + return sha3_xxx_stream (stream, "sha3-224", resblock, SHA3_224_DIGEST_SIZE, + sha3_224_init_ctx); +} + +int +sha3_256_stream (FILE *stream, void *resblock) +{ + return sha3_xxx_stream (stream, "sha3-256", resblock, SHA3_256_DIGEST_SIZE, + sha3_256_init_ctx); +} + +int +sha3_384_stream (FILE *stream, void *resblock) +{ + return sha3_xxx_stream (stream, "sha3-384", resblock, SHA3_384_DIGEST_SIZE, + sha3_384_init_ctx); +} + +int +sha3_512_stream (FILE *stream, void *resblock) +{ + return sha3_xxx_stream (stream, "sha3-512", resblock, SHA3_512_DIGEST_SIZE, + sha3_512_init_ctx); +} diff --git a/lib/sha3.h b/lib/sha3.h index c299c6fab7..8e0a7a7fdf 100644 --- a/lib/sha3.h +++ b/lib/sha3.h @@ -94,6 +94,16 @@ extern void *sha3_384_buffer (const char *buffer, size_t len, extern void *sha3_512_buffer (const char *buffer, size_t len, void *restrict resblock); +/* Compute SHA-3 message digest for bytes read from STREAM. STREAM is an open + file stream. Regular files are handled more efficiently. The contents of + STREAM from its current position to its end will be read. The case that the + last operation on STREAM was an 'ungetc' is not supported. The resulting + message digest number will be written into RESBLOCK. */ +extern int sha3_224_stream (FILE *stream, void *resblock); +extern int sha3_256_stream (FILE *stream, void *resblock); +extern int sha3_384_stream (FILE *stream, void *resblock); +extern int sha3_512_stream (FILE *stream, void *resblock); + # ifdef __cplusplus } # endif diff --git a/modules/crypto/sha3 b/modules/crypto/sha3 new file mode 100644 index 0000000000..f2b878794a --- /dev/null +++ b/modules/crypto/sha3 @@ -0,0 +1,23 @@ +Description: +Compute SHA-3 checksums. + +Files: +lib/sha3-stream.c + +Depends-on: +crypto/af_alg +crypto/sha3-buffer + +configure.ac: + +Makefile.am: +lib_SOURCES += sha3-stream.c + +Include: +"sha3.h" + +License: +LGPLv2+ + +Maintainer: +all -- 2.51.0
>From 6c5936dddf2b9685675624313065f2379305598a Mon Sep 17 00:00:00 2001 Message-ID: <6c5936dddf2b9685675624313065f2379305598a.1756677369.git.collin.fu...@gmail.com> In-Reply-To: <4cdf7734fbdb040557f253ceb885c8aa1dbf225b.1756677369.git.collin.fu...@gmail.com> References: <4cdf7734fbdb040557f253ceb885c8aa1dbf225b.1756677369.git.collin.fu...@gmail.com> From: Collin Funk <collin.fu...@gmail.com> Date: Sun, 31 Aug 2025 14:54:56 -0700 Subject: [PATCH v2 4/4] u64: Allow the header to be included twice. * lib/u64.h: Add include guard. --- ChangeLog | 3 +++ lib/u64.h | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index d202892dd1..46e8238da1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2025-08-31 Collin Funk <collin.fu...@gmail.com> + u64: Allow the header to be included twice. + * lib/u64.h: Add include guard. + crypto/sha3: New module. * modules/crypto/sha3: New file. * lib/sha3-stream.c: New file, based on sha512-stream.c. diff --git a/lib/u64.h b/lib/u64.h index a344bc7bd5..b47d65e503 100644 --- a/lib/u64.h +++ b/lib/u64.h @@ -17,6 +17,9 @@ /* Written by Paul Eggert. */ +#ifndef U64_H +#define U64_H 1 + /* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */ #if !_GL_CONFIG_H_INCLUDED #error "Please include config.h first." @@ -229,3 +232,5 @@ u64rol (u64 x, int n) #endif _GL_INLINE_HEADER_END + +#endif -- 2.51.0