]> git.ipfire.org Git - thirdparty/nettle.git/commitdiff
New files slh-dsa-128s.c and slh-dsa-128f.c.
authorNiels Möller <nisse@lysator.liu.se>
Tue, 9 Sep 2025 18:29:52 +0000 (20:29 +0200)
committerNiels Möller <nisse@lysator.liu.se>
Tue, 9 Sep 2025 18:29:52 +0000 (20:29 +0200)
Move params structs and parse_digest functions, since they are the
same for shake and sha2.

ChangeLog
Makefile.in
slh-dsa-128f.c [new file with mode: 0644]
slh-dsa-128s.c [new file with mode: 0644]
slh-dsa-internal.h
slh-dsa-shake-128f.c
slh-dsa-shake-128s.c
slh-dsa.c

index b7a7f193eb0cfca87460ae6e2d21af2b7b87cbb4..30cbaccc716fc74c93c1f69ccfe36ee7ad1f17c8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2025-09-09  Niels Möller  <nisse@lysator.liu.se>
+
+       * slh-dsa-internal.h (slh_parse_digest_func): New typedef.
+       (struct slh_dsa_params): New function pointer parse_digest.
+
+       * slh-dsa.c (_slh_dsa_sign): Delete tree_idx and leaf_idx
+       arguments. Instead, call params->parse_digest to get them from the
+       digest. Introduce c99 mid-block declarations, for convenience.
+       (_slh_dsa_verify): Likewise.
+
+       * slh-dsa-128s.c: New file.
+       (_slh_dsa_128s_params): Params struct moved here.
+       (parse_digest): Corresponding function to extract tree and leaf
+       indices from digest.
+       * slh-dsa-shake-128s.c (_slh_dsa_128s_params, parse_digest): ...
+       old location.
+
+       * slh-dsa-128f.c: New file.
+       (_slh_dsa_128f_params): Params struct moved here.
+       (parse_digest): Corresponding function to extract tree and leaf
+       indices from digest.
+       * slh-dsa-shake-128f.c (_slh_dsa_128f_params, parse_digest): ...
+       old location.
+
+       * Makefile.in (nettle_SOURCES): Add slh-dsa-128s.c slh-dsa-128f.c.
+
 2025-09-08  Niels Möller  <nisse@lysator.liu.se>
 
        * slh-dsa-shake-128s.c (_slh_dsa_128s_params): Renamed, from...
index 88ecf211d4dd0405812814fec19f644cd31c9752..e3396e336013e3b909b26a0d5e0dc1340c1e4a5d 100644 (file)
@@ -177,7 +177,8 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt-table.c \
                 xts.c xts-aes128.c xts-aes256.c \
                 drbg-ctr-aes256.c \
                 slh-fors.c slh-merkle.c slh-shake.c slh-wots.c slh-xmss.c \
-                slh-dsa.c slh-dsa-shake-128s.c slh-dsa-shake-128f.c
+                slh-dsa.c slh-dsa-128s.c slh-dsa-128f.c \
+                slh-dsa-shake-128s.c slh-dsa-shake-128f.c
 
 hogweed_SOURCES = sexp.c sexp-format.c \
                  sexp-transport.c sexp-transport-format.c \
diff --git a/slh-dsa-128f.c b/slh-dsa-128f.c
new file mode 100644 (file)
index 0000000..47b87fe
--- /dev/null
@@ -0,0 +1,83 @@
+/* slh-dsa-128f.c
+
+   SLH-DSA (FIPS 205) signatures.
+
+   Copyright (C) 2025 Niels Möller
+
+   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 "slh-dsa.h"
+#include "slh-dsa-internal.h"
+
+#define SLH_DSA_D 22
+#define XMSS_H 3
+
+/* Use k Merkle trees, each of size 2^a. Signs messages of size
+   k * a = 198 bits or 25 octets (with 2 left-over bits). */
+#define FORS_A 6
+#define FORS_K 33
+#define FORS_MSG_SIZE 25
+
+static void
+parse_digest (const uint8_t *digest, uint64_t *tree_idx, unsigned *leaf_idx)
+{
+  uint64_t x;
+  unsigned i;
+
+  /* Split digest as
+     +----+------+-----+
+     | md | tree | leaf|
+     +----+------+-----+
+       25       8     1
+
+   The first 25 octets are the digest signed with fors (and not
+   processed by this function), the next 8 octets represent 63 bits
+   selecting the tree, the last octet represent 3 bits selecting
+   the key in that tree.
+
+   Left over high bits are discarded.
+  */
+  x = digest[0] & 0x7f; /* Discard high-most bit of 64 */
+  for (i = 1; i < 8; i++)
+    x = (x << 8) + digest[i];
+  *tree_idx = x;
+  /* Discard 5 high-most bits */
+  *leaf_idx = digest[8] & 7;
+}
+
+const struct slh_dsa_params
+_slh_dsa_128f_params =
+  {
+    parse_digest,
+    { SLH_DSA_D, XMSS_H, XMSS_SIGNATURE_SIZE (XMSS_H) },
+    { FORS_A, FORS_K, FORS_MSG_SIZE, FORS_SIGNATURE_SIZE (FORS_A, FORS_K) },
+  };
diff --git a/slh-dsa-128s.c b/slh-dsa-128s.c
new file mode 100644 (file)
index 0000000..cc764f7
--- /dev/null
@@ -0,0 +1,83 @@
+/* slh-dsa-128s.c
+
+   SLH-DSA (FIPS 205) signatures.
+
+   Copyright (C) 2025 Niels Möller
+
+   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 "slh-dsa.h"
+#include "slh-dsa-internal.h"
+
+#define SLH_DSA_D 7
+#define XMSS_H 9
+
+/* Use k Merkle trees, each of size 2^a. Signs messages of size
+   k * a = 168 bits or 21 octets. */
+#define FORS_A 12
+#define FORS_K 14
+#define FORS_MSG_SIZE 21
+
+static void
+parse_digest (const uint8_t *digest, uint64_t *tree_idx, unsigned *leaf_idx)
+{
+  uint64_t x;
+  unsigned i;
+
+  /* Split digest as
+     +----+------+-----+
+     | md | tree | leaf|
+     +----+------+-----+
+       21       7     2
+
+   The first 21 octets are the digest signed with fors (and skipped by
+   this function), the next 7 octets represent 54 bits selecting the
+   tree, the last 2 octets represent 9 bits selecting the key in that
+   tree.
+
+   Left over high bits are discarded.
+  */
+  x = digest[0] & 0x3f; /* Discard 2 high-most bits of 56 */
+  for (i = 1; i < 7; i++)
+    x = (x << 8) + digest[i];
+  *tree_idx = x;
+  /* Discard 7 high-most bits of 16 */
+  *leaf_idx = ((digest[7] & 1) << 8) + digest[8];
+}
+
+const struct slh_dsa_params
+_slh_dsa_128s_params =
+  {
+    parse_digest,
+    { SLH_DSA_D, XMSS_H, XMSS_SIGNATURE_SIZE (XMSS_H) },
+    { FORS_A, FORS_K, FORS_MSG_SIZE, FORS_SIGNATURE_SIZE (FORS_A, FORS_K) },
+  };
index 516e068e95f99e928a0e9e2bbcc002c01a4aa0f2..9b413197271f07108c5fdb1abe7d3b028adbe9e2 100644 (file)
@@ -111,8 +111,11 @@ struct slh_fors_params
   unsigned short signature_size;
 };
 
+typedef void slh_parse_digest_func (const uint8_t *digest, uint64_t *tree_idx, unsigned *leaf_idx);
+
 struct slh_dsa_params
 {
+  slh_parse_digest_func *parse_digest;
   struct slh_xmss_params xmss;
   struct slh_fors_params fors;
 };
@@ -218,13 +221,10 @@ _slh_dsa_digest (const uint8_t *randomizer, const uint8_t *pub,
 void
 _slh_dsa_sign (const struct slh_dsa_params *params,
               const uint8_t *pub, const uint8_t *priv,
-              const uint8_t *digest,
-              uint64_t tree_idx, unsigned leaf_idx,
-              uint8_t *signature);
+              const uint8_t *digest, uint8_t *signature);
 int
 _slh_dsa_verify (const struct slh_dsa_params *params, const uint8_t *pub,
-                const uint8_t *digest, uint64_t tree_idx, unsigned leaf_idx,
-                const uint8_t *signature);
+                const uint8_t *digest, const uint8_t *signature);
 
 
 #endif /* NETTLE_SLH_DSA_INTERNAL_H_INCLUDED */
index 100c04a24f030c12b6cd8a6fc97f90a60fa35912..7ddcf1cab3c6ecae2ee3c3e5b251de1fe45a8a25 100644 (file)
 
 #define SLH_DSA_M 34
 
-#define SLH_DSA_D 22
 #define XMSS_H 3
 
-/* Use k Merkle trees, each of size 2^a. Signs messages of size
-   k * a = 198 bits or 25 octets (with 2 left-over bits). */
-#define FORS_A 6
-#define FORS_K 33
-#define FORS_MSG_SIZE 25
-
-const struct slh_dsa_params
-_slh_dsa_128f_params =
-  {
-    { SLH_DSA_D, XMSS_H, XMSS_SIGNATURE_SIZE (XMSS_H) },
-    { FORS_A, FORS_K, FORS_MSG_SIZE, FORS_SIGNATURE_SIZE (FORS_A, FORS_K) },
-  };
-
 void
 slh_dsa_shake_128f_root (const uint8_t *public_seed, const uint8_t *private_seed,
                         uint8_t *root)
@@ -73,33 +59,6 @@ slh_dsa_shake_128f_generate_keypair (uint8_t *pub, uint8_t *priv,
   slh_dsa_shake_128f_root (pub, priv, pub + SLH_DSA_128_SEED_SIZE);
 }
 
-static void
-parse_digest (const uint8_t *digest, uint64_t *tree_idx, unsigned *leaf_idx)
-{
-  uint64_t x;
-  unsigned i;
-
-  /* Split digest as
-     +----+------+-----+
-     | md | tree | leaf|
-     +----+------+-----+
-       25       8     1
-
-   The first 25 octets are the digest signed with fors (and not
-   processed by this function), the next 8 octets represent 63 bits
-   selecting the tree, the last octet represent 3 bits selecting
-   the key in that tree.
-
-   Left over high bits are discarded.
-  */
-  x = digest[0] & 0x7f; /* Discard high-most bit of 64 */
-  for (i = 1; i < 8; i++)
-    x = (x << 8) + digest[i];
-  *tree_idx = x;
-  /* Discard 5 high-most bits */
-  *leaf_idx = digest[8] & 7;
-}
-
 /* Only the "pure" and deterministic variant. */
 void
 slh_dsa_shake_128f_sign (const uint8_t *pub, const uint8_t *priv,
@@ -107,14 +66,10 @@ slh_dsa_shake_128f_sign (const uint8_t *pub, const uint8_t *priv,
                         uint8_t *signature)
 {
   uint8_t digest[SLH_DSA_M];
-  uint64_t tree_idx;
-  unsigned leaf_idx;
 
   _slh_dsa_randomizer (pub, priv + _SLH_DSA_128_SIZE, length, msg, signature);
   _slh_dsa_digest (signature, pub, length, msg, SLH_DSA_M, digest);
-  parse_digest (digest + FORS_MSG_SIZE, &tree_idx, &leaf_idx);
-
-  _slh_dsa_sign (&_slh_dsa_128f_params, pub, priv, digest, tree_idx, leaf_idx,
+  _slh_dsa_sign (&_slh_dsa_128f_params, pub, priv, digest,
                 signature + _SLH_DSA_128_SIZE);
 }
 
@@ -124,11 +79,8 @@ slh_dsa_shake_128f_verify (const uint8_t *pub,
                           const uint8_t *signature)
 {
   uint8_t digest[SLH_DSA_M];
-  uint64_t tree_idx;
-  unsigned leaf_idx;
 
   _slh_dsa_digest (signature, pub, length, msg, SLH_DSA_M,digest);
-  parse_digest (digest + FORS_MSG_SIZE, &tree_idx, &leaf_idx);
-  return _slh_dsa_verify (&_slh_dsa_128f_params, pub, digest, tree_idx, leaf_idx,
+  return _slh_dsa_verify (&_slh_dsa_128f_params, pub, digest,
                          signature + _SLH_DSA_128_SIZE);
 }
index 9fdea1414918ddeb108874756cc1289ca3e65548..8fa48839b97991190626c96c6070127ec09bfc01 100644 (file)
 
 #define SLH_DSA_M 30
 
-#define SLH_DSA_D 7
 #define XMSS_H 9
 
-/* Use k Merkle trees, each of size 2^a. Signs messages of size
-   k * a = 168 bits or 21 octets. */
-#define FORS_A 12
-#define FORS_K 14
-#define FORS_MSG_SIZE 21
-
-const struct slh_dsa_params
-_slh_dsa_128s_params =
-  {
-    { SLH_DSA_D, XMSS_H, XMSS_SIGNATURE_SIZE (XMSS_H) },
-    { FORS_A, FORS_K, FORS_MSG_SIZE, FORS_SIGNATURE_SIZE (FORS_A, FORS_K) },
-  };
-
 void
 slh_dsa_shake_128s_root (const uint8_t *public_seed, const uint8_t *private_seed,
                         uint8_t *root)
@@ -73,33 +59,6 @@ slh_dsa_shake_128s_generate_keypair (uint8_t *pub, uint8_t *priv,
   slh_dsa_shake_128s_root (pub, priv, pub + SLH_DSA_128_SEED_SIZE);
 }
 
-static void
-parse_digest (const uint8_t *digest, uint64_t *tree_idx, unsigned *leaf_idx)
-{
-  uint64_t x;
-  unsigned i;
-
-  /* Split digest as
-     +----+------+-----+
-     | md | tree | leaf|
-     +----+------+-----+
-       21       7     2
-
-   The first 21 octets are the digest signed with fors (and not
-   processed by this function), the next 7 octets represent 54 bits
-   selecting the tree, the last 2 octets represent 9 bits selecting
-   the key in that tree.
-
-   Left over high bits are discarded.
-  */
-  x = digest[0] & 0x3f; /* Discard 2 high-most bits of 56 */
-  for (i = 1; i < 7; i++)
-    x = (x << 8) + digest[i];
-  *tree_idx = x;
-  /* Discard 7 high-most bits of 16 */
-  *leaf_idx = ((digest[7] & 1) << 8) + digest[8];
-}
-
 /* Only the "pure" and deterministic variant. */
 void
 slh_dsa_shake_128s_sign (const uint8_t *pub, const uint8_t *priv,
@@ -107,14 +66,10 @@ slh_dsa_shake_128s_sign (const uint8_t *pub, const uint8_t *priv,
                         uint8_t *signature)
 {
   uint8_t digest[SLH_DSA_M];
-  uint64_t tree_idx;
-  unsigned leaf_idx;
 
   _slh_dsa_randomizer (pub, priv + _SLH_DSA_128_SIZE, length, msg, signature);
   _slh_dsa_digest (signature, pub, length, msg, SLH_DSA_M, digest);
-  parse_digest (digest + FORS_MSG_SIZE, &tree_idx, &leaf_idx);
-
-  _slh_dsa_sign (&_slh_dsa_128s_params, pub, priv, digest, tree_idx, leaf_idx,
+  _slh_dsa_sign (&_slh_dsa_128s_params, pub, priv, digest,
                 signature + _SLH_DSA_128_SIZE);
 }
 
@@ -124,11 +79,8 @@ slh_dsa_shake_128s_verify (const uint8_t *pub,
                           const uint8_t *signature)
 {
   uint8_t digest[SLH_DSA_M];
-  uint64_t tree_idx;
-  unsigned leaf_idx;
 
   _slh_dsa_digest (signature, pub, length, msg, SLH_DSA_M,digest);
-  parse_digest (digest + FORS_MSG_SIZE, &tree_idx, &leaf_idx);
-  return _slh_dsa_verify (&_slh_dsa_128s_params, pub, digest, tree_idx, leaf_idx,
+  return _slh_dsa_verify (&_slh_dsa_128s_params, pub, digest,
                          signature + _SLH_DSA_128_SIZE);
 }
index d5b0afab7f29486733b2847d47b306ae50bf4302..cec779d3c471f6b7d7462bbc8aec9054ea9ac1f2 100644 (file)
--- a/slh-dsa.c
+++ b/slh-dsa.c
@@ -79,19 +79,21 @@ _slh_dsa_digest (const uint8_t *randomizer, const uint8_t *pub,
 void
 _slh_dsa_sign (const struct slh_dsa_params *params,
               const uint8_t *pub, const uint8_t *priv,
-              const uint8_t *digest,
-              uint64_t tree_idx, unsigned leaf_idx,
-              uint8_t *signature)
+              const uint8_t *digest, uint8_t *signature)
 {
-  uint8_t root[_SLH_DSA_128_SIZE];
-  int i;
+  uint64_t tree_idx;
+  unsigned leaf_idx;
+
+  params->parse_digest (digest + params->fors.msg_size, &tree_idx, &leaf_idx);
 
   struct sha3_ctx tree_ctx;
-  struct slh_merkle_ctx_secret merkle_ctx =
+  const struct slh_merkle_ctx_secret merkle_ctx =
     {
       { &tree_ctx, leaf_idx },
       priv,
     };
+  uint8_t root[_SLH_DSA_128_SIZE];
+
   _slh_shake_init (&tree_ctx, pub, 0, tree_idx);
 
   _fors_sign (&merkle_ctx, &params->fors, digest, signature, root);
@@ -99,7 +101,7 @@ _slh_dsa_sign (const struct slh_dsa_params *params,
 
   _xmss_sign (&merkle_ctx, params->xmss.h, leaf_idx, root, signature, root);
 
-  for (i = 1; i < params->xmss.d; i++)
+  for (unsigned i = 1; i < params->xmss.d; i++)
     {
       signature += params->xmss.signature_size;
 
@@ -115,16 +117,19 @@ _slh_dsa_sign (const struct slh_dsa_params *params,
 
 int
 _slh_dsa_verify (const struct slh_dsa_params *params, const uint8_t *pub,
-                const uint8_t *digest, uint64_t tree_idx, unsigned leaf_idx,
-                const uint8_t *signature)
+                const uint8_t *digest, const uint8_t *signature)
 {
-  uint8_t root[_SLH_DSA_128_SIZE];
-  int i;
+  uint64_t tree_idx;
+  unsigned leaf_idx;
+
+  params->parse_digest (digest + params->fors.msg_size, &tree_idx, &leaf_idx);
 
   struct sha3_ctx tree_ctx;
-  struct slh_merkle_ctx_public merkle_ctx =
+  const struct slh_merkle_ctx_public merkle_ctx =
     { &tree_ctx, leaf_idx };
 
+  uint8_t root[_SLH_DSA_128_SIZE];
+
   _slh_shake_init (&tree_ctx, pub, 0, tree_idx);
 
   _fors_verify (&merkle_ctx, &params->fors, digest, signature, root);
@@ -132,7 +137,7 @@ _slh_dsa_verify (const struct slh_dsa_params *params, const uint8_t *pub,
 
   _xmss_verify (&merkle_ctx, params->xmss.h, leaf_idx, root, signature, root);
 
-  for (i = 1; i < params->xmss.d; i++)
+  for (unsigned i = 1; i < params->xmss.d; i++)
     {
       signature += params->xmss.signature_size;