From d33ed2d88d41aae20ad2733e19f8bf41a06693a1 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <dueno@redhat.com>
Date: Sun, 24 Mar 2024 09:14:40 +0900
Subject: [PATCH 3/3] sha3-shake: Generalize sha3_shake*_output

Signed-off-by: Daiki Ueno <dueno@redhat.com>
---
 Makefile.in     |   2 +-
 sha3-internal.h |   7 +++
 sha3-shake.c    | 111 ++++++++++++++++++++++++++++++++++++++++++++++++
 shake256.c      |  63 ++-------------------------
 4 files changed, 122 insertions(+), 61 deletions(-)
 create mode 100644 sha3-shake.c

diff --git a/Makefile.in b/Makefile.in
index f027e762..6953a528 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -151,7 +151,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c aes-decrypt-table.c \
 		 sha3.c sha3-permute.c \
 		 sha3-224.c sha3-224-meta.c sha3-256.c sha3-256-meta.c \
 		 sha3-384.c sha3-384-meta.c sha3-512.c sha3-512-meta.c \
-		 shake256.c \
+		 sha3-shake.c shake256.c \
 		 sm3.c sm3-meta.c \
 		 serpent-set-key.c serpent-encrypt.c serpent-decrypt.c \
 		 serpent-meta.c \
diff --git a/sha3-internal.h b/sha3-internal.h
index 9b01231a..f1e5c55b 100644
--- a/sha3-internal.h
+++ b/sha3-internal.h
@@ -56,5 +56,12 @@ _nettle_sha3_pad (struct sha3_state *state,
 #define _sha3_pad_shake(state, block_size, block, pos) \
   _nettle_sha3_pad (state, block_size, block, pos, SHA3_SHAKE_MAGIC)
 
+unsigned
+_nettle_sha3_shake_output (struct sha3_state *state,
+			   size_t block_size,
+			   uint8_t *block,
+			   unsigned index,
+			   size_t length,
+			   uint8_t *digest);
 
 #endif
diff --git a/sha3-shake.c b/sha3-shake.c
new file mode 100644
index 00000000..eb6df3bb
--- /dev/null
+++ b/sha3-shake.c
@@ -0,0 +1,111 @@
+/* sha3-shake.c
+
+   Support function for SHA3 SHAKE XOF.
+
+   Copyright (C) 2024 Red Hat, Inc.
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle 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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <limits.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "sha3.h"
+#include "sha3-internal.h"
+
+#include "nettle-write.h"
+
+#define INDEX_HIGH_BIT (~((UINT_MAX) >> 1))
+
+unsigned
+_nettle_sha3_shake_output (struct sha3_state *state,
+			   size_t block_size,
+			   uint8_t *block,
+			   unsigned index,
+			   size_t length,
+			   uint8_t *digest)
+{
+  unsigned left;
+
+  /* We use the leftmost bit as a flag to indicate SHAKE is initialized.  */
+  if (index & INDEX_HIGH_BIT)
+    index = ~index;
+  else
+    {
+      /* This is the first call of _shake_output.  */
+      _sha3_pad_shake (state, block_size, block, index);
+      /* Point at the end of block to trigger fill in of the buffer.  */
+      index = 0;
+    }
+
+  assert (index < block_size);
+
+  if (index == 0)
+    {
+      /* Fill in the buffer.  */
+      _nettle_write_le64 (block_size, block, state->a);
+      sha3_permute (state);
+    }
+
+  /* Write remaining data from the buffer.  */
+  left = block_size - index;
+  if (length <= left)
+    {
+      memcpy (digest, block + index, length);
+      return ~((index + length) % block_size);
+    }
+  else
+    {
+      memcpy (digest, block + index, left);
+      length -= left;
+      digest += left;
+    }
+
+  /* Write full blocks.  */
+  while (length >= block_size)
+    {
+      _nettle_write_le64 (block_size, digest, state->a);
+      sha3_permute (state);
+      length -= block_size;
+      digest += block_size;
+    }
+
+  if (length > 0)
+    {
+      /* Fill in the buffer.  */
+      _nettle_write_le64 (block_size, block, state->a);
+      sha3_permute (state);
+      memcpy (digest, block, length);
+    }
+  return ~length;
+}
diff --git a/shake256.c b/shake256.c
index 879c0935..9656b4ce 100644
--- a/shake256.c
+++ b/shake256.c
@@ -36,18 +36,12 @@
 # include "config.h"
 #endif
 
-#include <assert.h>
-#include <limits.h>
 #include <stddef.h>
 #include <string.h>
 
 #include "sha3.h"
 #include "sha3-internal.h"
 
-#include "nettle-write.h"
-
-#define INDEX_HIGH_BIT (~((UINT_MAX) >> 1))
-
 void
 sha3_shake256_init (struct sha3_shake256_ctx *ctx)
 {
@@ -69,60 +63,9 @@ sha3_shake256_output (struct sha3_shake256_ctx *ctx,
 		      size_t length,
 		      uint8_t *digest)
 {
-  unsigned index, left;
-
-  /* We use the leftmost bit as a flag to indicate SHAKE is initialized.  */
-  if (ctx->index & INDEX_HIGH_BIT)
-    index = ~ctx->index;
-  else
-    {
-      /* This is the first call of _shake_output.  */
-      _sha3_pad_shake (&ctx->state, sizeof (ctx->block), ctx->block, ctx->index);
-      /* Point at the end of block to trigger fill in of the buffer.  */
-      index = 0;
-    }
-
-  assert (index < sizeof (ctx->block));
-
-  if (index == 0)
-    {
-      /* Fill in the buffer.  */
-      _nettle_write_le64 (sizeof (ctx->block), ctx->block, ctx->state.a);
-      sha3_permute (&ctx->state);
-    }
-
-  /* Write remaining data from the buffer.  */
-  left = sizeof (ctx->block) - index;
-  if (length <= left)
-    {
-      memcpy (digest, ctx->block + index, length);
-      ctx->index = ~((index + length) % sizeof (ctx->block));
-      return;
-    }
-  else
-    {
-      memcpy (digest, ctx->block + index, left);
-      length -= left;
-      digest += left;
-    }
-
-  /* Write full blocks.  */
-  while (length >= sizeof (ctx->block))
-    {
-      _nettle_write_le64 (sizeof (ctx->block), digest, ctx->state.a);
-      sha3_permute (&ctx->state);
-      length -= sizeof (ctx->block);
-      digest += sizeof (ctx->block);
-    }
-
-  if (length > 0)
-    {
-      /* Fill in the buffer.  */
-      _nettle_write_le64 (sizeof (ctx->block), ctx->block, ctx->state.a);
-      sha3_permute (&ctx->state);
-      memcpy (digest, ctx->block, length);
-    }
-  ctx->index = ~length;
+  ctx->index = _nettle_sha3_shake_output (&ctx->state,
+					  SHA3_256_BLOCK_SIZE, ctx->block,
+					  ctx->index, length, digest);
 }
 
 void
-- 
2.44.0

