Collin Funk <[email protected]> writes:

> 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.

Here is a patch implementing the crypto/sha3-stream module.

The second is needed to allow lib/u64.h to be included twice as is done
in coreutils src/cksum.c (once in sha512.h and once in sha3.h).

Tested using a local patch to cksum compared to openssl on a various
files.

Collin

>From c00faa784608f77cdd46ea08fa180eab017a4405 Mon Sep 17 00:00:00 2001
Message-ID: <c00faa784608f77cdd46ea08fa180eab017a4405.1756619842.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Sat, 30 Aug 2025 21:52:15 -0700
Subject: [PATCH 1/2] 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 0eef5a44fc..4507c51298 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2025-08-30  Collin Funk  <[email protected]>
 
+	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..c569c36b68
--- /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 and finishing operations are INIT_CTX and FINISH_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 % 128 == 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..23bb8f8f7e 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 SHA5-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 a99da69b2c6b618cd9a873605cab459cffae8ae7 Mon Sep 17 00:00:00 2001
Message-ID: <a99da69b2c6b618cd9a873605cab459cffae8ae7.1756619842.git.collin.fu...@gmail.com>
In-Reply-To: <c00faa784608f77cdd46ea08fa180eab017a4405.1756619842.git.collin.fu...@gmail.com>
References: <c00faa784608f77cdd46ea08fa180eab017a4405.1756619842.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Sat, 30 Aug 2025 22:53:13 -0700
Subject: [PATCH 2/2] u64: Allow the header to be included twice.

* lib/u64.h: Add include gaurd.
---
 ChangeLog | 3 +++
 lib/u64.h | 5 +++++
 2 files changed, 8 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 4507c51298..441aa663c6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2025-08-30  Collin Funk  <[email protected]>
 
+	u64: Allow the header to be included twice.
+	* lib/u64.h: Add include gaurd.
+
 	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 35dbb944ec..d6bbee0f85 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."
@@ -228,3 +231,5 @@ u64rol (u64 x, int n)
 #endif
 
 _GL_INLINE_HEADER_END
+
+#endif
-- 
2.51.0

Reply via email to