Hi,

Pádraig and I both wanted to add SHA-3 to cksum before the next
coreutils release. These two patches add the sha3-buffer module and
tests to Gnulib. They use the u64 module so that projects that care
about platforms without 64-bit integers can use them like Emacs. I can
have a look at adding it there later.

Tested on x86_64 and MIPS64 (big endian) with both 64-bit integers and
32-bit integers.

The module currently does not have OpenSSL support since it cannot be
done in the same way as the other Gnulib crypto modules. SHA-3 was
created after OpenSSL deprecated the <CIPHER>_Init, <CIPHER>_Update,
<CIPHER>_Final functions if my memory serves me correctly. So the SHA-3
versions of those do not exist. We would have to use the EVP interface
instead [1]. I'll have a look at it adding that later, but figured it
would make reviewing the patch harder.

Anyways, will push this patch later to give some time for review. I'll
have to write the the crypto/sha3-stream module but that is fairly
simple.

Collin

[1] https://docs.openssl.org/master/man3/EVP_DigestInit/#examples

>From d500646bbe6eaa8d97a16d7ac2c5155bebcb0c35 Mon Sep 17 00:00:00 2001
Message-ID: <d500646bbe6eaa8d97a16d7ac2c5155bebcb0c35.1756601977.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Sat, 30 Aug 2025 11:17:42 -0700
Subject: [PATCH 1/2] crypto/sha3-buffer: New module.

* lib/u64.h (u64getlo, u64not): New functions.
* lib/sha3.c: New file.
* lib/sha3.h: Likewise.
* modules/crypto/sha3-buffer: Likewise.
---
 ChangeLog                  |   8 +
 lib/sha3.c                 | 317 +++++++++++++++++++++++++++++++++++++
 lib/sha3.h                 | 101 ++++++++++++
 lib/u64.h                  |  19 +++
 modules/crypto/sha3-buffer |  30 ++++
 5 files changed, 475 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 33d9975bbe..e608a58978 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2025-08-30  Collin Funk  <[email protected]>
+
+	crypto/sha3-buffer: New module.
+	* lib/u64.h (u64getlo, u64not): New functions.
+	* lib/sha3.c: New file.
+	* lib/sha3.h: Likewise.
+	* modules/crypto/sha3-buffer: Likewise.
+
 2024-08-25  Bruno Haible  <[email protected]>
 
 	nstrftime tests: Test in the UTF-8 environment on native Windows.
diff --git a/lib/sha3.c b/lib/sha3.c
new file mode 100644
index 0000000000..65150b4a32
--- /dev/null
+++ b/lib/sha3.c
@@ -0,0 +1,317 @@
+/* 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 <[email protected]>, 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 += 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 += 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 <[email protected]>, 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 6ea08969c2..35dbb944ec 100644
--- a/lib/u64.h
+++ b/lib/u64.h
@@ -45,7 +45,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))
@@ -94,6 +96,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)
@@ -104,6 +113,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..ea0f228dc8
--- /dev/null
+++ b/modules/crypto/sha3-buffer
@@ -0,0 +1,30 @@
+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"
+
+Link:
+
+License:
+LGPLv2+
+
+Maintainer:
+all
-- 
2.51.0

>From fbb23f6a7584933fb89fda5fc06e10cf0a6b96f7 Mon Sep 17 00:00:00 2001
Message-ID: <fbb23f6a7584933fb89fda5fc06e10cf0a6b96f7.1756601977.git.collin.fu...@gmail.com>
In-Reply-To: <d500646bbe6eaa8d97a16d7ac2c5155bebcb0c35.1756601977.git.collin.fu...@gmail.com>
References: <d500646bbe6eaa8d97a16d7ac2c5155bebcb0c35.1756601977.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Sat, 30 Aug 2025 17:41:30 -0700
Subject: [PATCH 2/2] 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 e608a58978..0eef5a44fc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,16 @@
 2025-08-30  Collin Funk  <[email protected]>
 
+	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.
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 <[email protected]>, 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 <[email protected]>, 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 <[email protected]>, 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 <[email protected]>, 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

Reply via email to