]> git.ipfire.org Git - thirdparty/gnulib.git/commitdiff
crypto/sha3: New module.
authorCollin Funk <collin.funk1@gmail.com>
Sun, 31 Aug 2025 21:21:02 +0000 (14:21 -0700)
committerCollin Funk <collin.funk1@gmail.com>
Sun, 31 Aug 2025 21:54:38 +0000 (14:54 -0700)
* 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
lib/sha3-stream.c [new file with mode: 0644]
lib/sha3.h
modules/crypto/sha3 [new file with mode: 0644]

index 924d67e13587c563d73527ffa65316a1f466c9f2..d202892dd1d36598ef037bd38f501628f6f86c7d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2025-08-31  Collin Funk  <collin.funk1@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 (file)
index 0000000..708dafa
--- /dev/null
@@ -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);
+}
index c299c6fab7882e63225d2636f95907671d1e6548..8e0a7a7fdf8e84f006ff26e3bc29db8ab7088fc6 100644 (file)
@@ -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 (file)
index 0000000..f2b8787
--- /dev/null
@@ -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