]> git.ipfire.org Git - thirdparty/nettle.git/commitdiff
Return success/failure from slh-dsa signing functions. master
authorNiels Möller <nisse@lysator.liu.se>
Wed, 1 Jul 2026 06:29:04 +0000 (08:29 +0200)
committerNiels Möller <nisse@lysator.liu.se>
Wed, 1 Jul 2026 06:29:04 +0000 (08:29 +0200)
ChangeLog
examples/hogweed-benchmark.c
nettle.texinfo
slh-dsa-internal.h
slh-dsa-sha2-128f.c
slh-dsa-sha2-128s.c
slh-dsa-shake-128f.c
slh-dsa-shake-128s.c
slh-dsa.c
slh-dsa.h
testsuite/slh-dsa-test.c

index 6346a8726722ec936d87406ad8b21105212585db..beecc55b08f454f78e195d9f1687031c219a2e7b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2026-06-30  Niels Möller  <nisse@lysator.liu.se>
+
+       * slh-dsa.c (_slh_dsa_sign): Change return type from void to int.
+       After checking expected root hash with memeql_sec, return result
+       rather than asserting that it is true.
+       * slh-dsa-sha2-128f.c (slh_dsa_sha2_128f_sign): Add return value,
+       return success/failure from _slh_dsa_sign, and on failure, clear
+       output signature to all zeros.
+       * slh-dsa-sha2-128s.c (slh_dsa_sha2_128s_sign): Likewise.
+       * slh-dsa-shake-128f.c (slh_dsa_shake_128f_sign): Likewise.
+       * slh-dsa-shake-128s.c (slh_dsa_shake_128s_sign): Likewise.
+       * testsuite/slh-dsa-test.c (test_slh_dsa): Check that signing
+       function returns failure, if public or private key is corrupted.
+       * nettle.texinfo (SLH-DSA): Update documentation.
+
 2026-06-05  Niels Möller  <nisse@lysator.liu.se>
 
        * ml-kem-internal.c (compress, reduce, mod_sub, mod_add): Use
 2026-06-05  Niels Möller  <nisse@lysator.liu.se>
 
        * ml-kem-internal.c (compress, reduce, mod_sub, mod_add): Use
index 58547d5388d309a5264cb92028ea8c187b4a1fa1..246efd7a62aab9e2185a420ec85e265632014e55 100644 (file)
@@ -901,7 +901,7 @@ struct slh_dsa_ctx
   uint8_t key[SLH_DSA_128_KEY_SIZE];
   uint8_t msg[10];
   uint8_t *sig;
   uint8_t key[SLH_DSA_128_KEY_SIZE];
   uint8_t msg[10];
   uint8_t *sig;
-  void (*sign)(const uint8_t *pub, const uint8_t *priv,
+  int (*sign)(const uint8_t *pub, const uint8_t *priv,
               size_t length, const uint8_t *msg,
               uint8_t *signature);
   int (*verify)(const uint8_t *pub,
               size_t length, const uint8_t *msg,
               uint8_t *signature);
   int (*verify)(const uint8_t *pub,
@@ -985,7 +985,8 @@ static void
 bench_slh_dsa_sign (void *p)
 {
   struct slh_dsa_ctx *ctx = p;
 bench_slh_dsa_sign (void *p)
 {
   struct slh_dsa_ctx *ctx = p;
-  ctx->sign (ctx->pub, ctx->key, sizeof (ctx->msg), ctx->msg, ctx->sig);
+  int res = ctx->sign (ctx->pub, ctx->key, sizeof (ctx->msg), ctx->msg, ctx->sig);
+  assert (res);
 }
 
 static void
 }
 
 static void
index 3802b3b333f4e948b6c12e9d7ab422d74d41ca74..3047b8368989051a541956f8622dda7edb38f0bf 100644 (file)
@@ -5837,6 +5837,18 @@ traversal of all leaves of the corresponding Merkle trees, and this is
 several orders of magnitude slower than signing using elliptic curves or
 RSA.
 
 several orders of magnitude slower than signing using elliptic curves or
 RSA.
 
+The signing operation can recompute the top-level Merkle tree root
+almost for free. Nettle's SLH-DSA signing functions do that, and compare
+the resulting root hash to the provided public key. If the root hash is
+not as expected, the signing operation fails, and the returned signature
+is cleared to all zeros before return. This check is intended to detect
+invalid inputs, accidental corruption, and some types of software or
+hardware bugs that could affect the computation, but it is not a solid
+defense against deliberate fault injection attacks. Checking the return
+value from these signing functions is not strictly required; it's the
+application's choice if it prefers to handle this error, or pass on an
+invalid all-zero signature.
+
 Nettle currently implements the four SLH-DSA variants designed for
 ``128-bit security'': There's the choice of either SHA256 (in the SHA2
 family) or SHAKE256 (in the SHA3 family) as the underlying hash
 Nettle currently implements the four SLH-DSA variants designed for
 ``128-bit security'': There's the choice of either SHA256 (in the SHA2
 family) or SHAKE256 (in the SHA3 family) as the underlying hash
@@ -5893,13 +5905,14 @@ typically called with @var{root} = @var{public_seed} +
 @code{SLH_DSA_128_SEED_SIZE}.
 @end deftypefun
 
 @code{SLH_DSA_128_SEED_SIZE}.
 @end deftypefun
 
-@deftypefun void slh_dsa_shake_128s_sign (const uint8_t *@var{pub}, const uint8_t *@var{priv}, size_t @var{length}, const uint8_t *@var{msg}, uint8_t *@var{signature})
-@deftypefunx void slh_dsa_shake_128f_sign (const uint8_t *@var{pub}, const uint8_t *@var{priv}, size_t @var{length}, const uint8_t *@var{msg}, uint8_t *@var{signature})
-@deftypefunx void slh_dsa_sha2_128s_sign (const uint8_t *@var{pub}, const uint8_t *@var{priv}, size_t @var{length}, const uint8_t *@var{msg}, uint8_t *@var{signature})
-@deftypefunx void slh_dsa_sha2_128f_sign (const uint8_t *@var{pub}, const uint8_t *@var{priv}, size_t @var{length}, const uint8_t *@var{msg}, uint8_t *@var{signature})
+@deftypefun int slh_dsa_shake_128s_sign (const uint8_t *@var{pub}, const uint8_t *@var{priv}, size_t @var{length}, const uint8_t *@var{msg}, uint8_t *@var{signature})
+@deftypefunx int slh_dsa_shake_128f_sign (const uint8_t *@var{pub}, const uint8_t *@var{priv}, size_t @var{length}, const uint8_t *@var{msg}, uint8_t *@var{signature})
+@deftypefunx int slh_dsa_sha2_128s_sign (const uint8_t *@var{pub}, const uint8_t *@var{priv}, size_t @var{length}, const uint8_t *@var{msg}, uint8_t *@var{signature})
+@deftypefunx int slh_dsa_sha2_128f_sign (const uint8_t *@var{pub}, const uint8_t *@var{priv}, size_t @var{length}, const uint8_t *@var{msg}, uint8_t *@var{signature})
 Signs a message using the provided key pair. The size of the resulting
 signature is @code{SLH_DSA_128S_SIGNATURE_SIZE} or
 Signs a message using the provided key pair. The size of the resulting
 signature is @code{SLH_DSA_128S_SIGNATURE_SIZE} or
-@code{SLH_DSA_128F_SIGNATURE_SIZE} for respective functions.
+@code{SLH_DSA_128F_SIGNATURE_SIZE} for respective functions. Returns 1
+on success, 0 on failure (see above on what failure means).
 @end deftypefun
 
 @deftypefun int slh_dsa_shake_128s_verify (const uint8_t *@var{pub}, size_t @var{length}, const uint8_t *@var{msg}, const uint8_t *@var{signature})
 @end deftypefun
 
 @deftypefun int slh_dsa_shake_128s_verify (const uint8_t *@var{pub}, size_t @var{length}, const uint8_t *@var{msg}, const uint8_t *@var{signature})
index 209e58fead61c7fc7101f1d56a125002d8db45db..4db2ddcdfee5543e906b36aeef7c2cef02ccde13 100644 (file)
@@ -282,7 +282,7 @@ _slh_dsa_pure_rdigest (const struct slh_hash *hash,
                       size_t length, const uint8_t *msg,
                       uint8_t *randomizer, size_t digest_size, uint8_t *digest);
 
                       size_t length, const uint8_t *msg,
                       uint8_t *randomizer, size_t digest_size, uint8_t *digest);
 
-void
+int
 _slh_dsa_sign (const struct slh_dsa_params *params,
               const struct slh_hash *hash,
               const uint8_t *pub, const uint8_t *priv,
 _slh_dsa_sign (const struct slh_dsa_params *params,
               const struct slh_hash *hash,
               const uint8_t *pub, const uint8_t *priv,
index a121bba5e76dc47fe9f28d78ac4f53dea961862e..62c181ee7b3ce3bdfad0eb8cae808abc1f178930 100644 (file)
@@ -35,6 +35,8 @@
 # include "config.h"
 #endif
 
 # include "config.h"
 #endif
 
+#include <string.h>
+
 #include "slh-dsa.h"
 #include "slh-dsa-internal.h"
 
 #include "slh-dsa.h"
 #include "slh-dsa-internal.h"
 
@@ -65,19 +67,25 @@ slh_dsa_sha2_128f_generate_keypair (uint8_t *pub, uint8_t *priv,
 }
 
 /* Only the "pure" and deterministic variant. */
 }
 
 /* Only the "pure" and deterministic variant. */
-void
+int
 slh_dsa_sha2_128f_sign (const uint8_t *pub, const uint8_t *priv,
                         size_t length, const uint8_t *msg,
                         uint8_t *signature)
 {
   struct sha256_ctx tree_ctx, scratch_ctx;
   uint8_t digest[SLH_DSA_M];
 slh_dsa_sha2_128f_sign (const uint8_t *pub, const uint8_t *priv,
                         size_t length, const uint8_t *msg,
                         uint8_t *signature)
 {
   struct sha256_ctx tree_ctx, scratch_ctx;
   uint8_t digest[SLH_DSA_M];
+  int res;
+
   _slh_dsa_pure_rdigest (&_slh_hash_sha256,
                         pub, priv + _SLH_DSA_128_SIZE, length, msg,
                         signature, sizeof (digest), digest);
   _slh_dsa_pure_rdigest (&_slh_hash_sha256,
                         pub, priv + _SLH_DSA_128_SIZE, length, msg,
                         signature, sizeof (digest), digest);
-  _slh_dsa_sign (&_slh_dsa_128f_params, &_slh_hash_sha256,
-                pub, priv, digest, signature + _SLH_DSA_128_SIZE,
-                &tree_ctx, &scratch_ctx);
+  res = _slh_dsa_sign (&_slh_dsa_128f_params, &_slh_hash_sha256,
+                      pub, priv, digest, signature + _SLH_DSA_128_SIZE,
+                      &tree_ctx, &scratch_ctx);
+  if (!res)
+    memset (signature, 0, SLH_DSA_128F_SIGNATURE_SIZE);
+
+  return res;
 }
 
 int
 }
 
 int
index 7dafd17f65eabc470f350deef2fe40a47fedc50f..1ac8e5435a4611190e30a984502266352678cb90 100644 (file)
@@ -35,6 +35,8 @@
 # include "config.h"
 #endif
 
 # include "config.h"
 #endif
 
+#include <string.h>
+
 #include "slh-dsa.h"
 #include "slh-dsa-internal.h"
 
 #include "slh-dsa.h"
 #include "slh-dsa-internal.h"
 
@@ -65,19 +67,25 @@ slh_dsa_sha2_128s_generate_keypair (uint8_t *pub, uint8_t *priv,
 }
 
 /* Only the "pure" and deterministic variant. */
 }
 
 /* Only the "pure" and deterministic variant. */
-void
+int
 slh_dsa_sha2_128s_sign (const uint8_t *pub, const uint8_t *priv,
                        size_t length, const uint8_t *msg,
                        uint8_t *signature)
 {
   struct sha256_ctx tree_ctx, scratch_ctx;
   uint8_t digest[SLH_DSA_M];
 slh_dsa_sha2_128s_sign (const uint8_t *pub, const uint8_t *priv,
                        size_t length, const uint8_t *msg,
                        uint8_t *signature)
 {
   struct sha256_ctx tree_ctx, scratch_ctx;
   uint8_t digest[SLH_DSA_M];
+  int res;
+
   _slh_dsa_pure_rdigest (&_slh_hash_sha256,
                         pub, priv + _SLH_DSA_128_SIZE, length, msg,
                         signature, sizeof (digest), digest);
   _slh_dsa_pure_rdigest (&_slh_hash_sha256,
                         pub, priv + _SLH_DSA_128_SIZE, length, msg,
                         signature, sizeof (digest), digest);
-  _slh_dsa_sign (&_slh_dsa_128s_params, &_slh_hash_sha256,
-                pub, priv, digest, signature + _SLH_DSA_128_SIZE,
-                &tree_ctx, &scratch_ctx);
+  res =_slh_dsa_sign (&_slh_dsa_128s_params, &_slh_hash_sha256,
+                     pub, priv, digest, signature + _SLH_DSA_128_SIZE,
+                     &tree_ctx, &scratch_ctx);
+  if (!res)
+    memset (signature, 0, SLH_DSA_128S_SIGNATURE_SIZE);
+
+  return res;
 }
 
 int
 }
 
 int
index a0901f69fddb5c863ad3d60561b89db5c5bed9a3..1161f582c9dc4b37a0507a6fdc9ce89089fd9653 100644 (file)
@@ -35,6 +35,8 @@
 # include "config.h"
 #endif
 
 # include "config.h"
 #endif
 
+#include <string.h>
+
 #include "slh-dsa.h"
 #include "slh-dsa-internal.h"
 
 #include "slh-dsa.h"
 #include "slh-dsa-internal.h"
 
@@ -65,19 +67,25 @@ slh_dsa_shake_128f_generate_keypair (uint8_t *pub, uint8_t *priv,
 }
 
 /* Only the "pure" and deterministic variant. */
 }
 
 /* Only the "pure" and deterministic variant. */
-void
+int
 slh_dsa_shake_128f_sign (const uint8_t *pub, const uint8_t *priv,
                         size_t length, const uint8_t *msg,
                         uint8_t *signature)
 {
   struct sha3_ctx tree_ctx, scratch_ctx;
   uint8_t digest[SLH_DSA_M];
 slh_dsa_shake_128f_sign (const uint8_t *pub, const uint8_t *priv,
                         size_t length, const uint8_t *msg,
                         uint8_t *signature)
 {
   struct sha3_ctx tree_ctx, scratch_ctx;
   uint8_t digest[SLH_DSA_M];
+  int res;
+
   _slh_dsa_pure_rdigest (&_slh_hash_shake,
                         pub, priv + _SLH_DSA_128_SIZE, length, msg,
                         signature, sizeof (digest), digest);
   _slh_dsa_pure_rdigest (&_slh_hash_shake,
                         pub, priv + _SLH_DSA_128_SIZE, length, msg,
                         signature, sizeof (digest), digest);
-  _slh_dsa_sign (&_slh_dsa_128f_params, &_slh_hash_shake,
-                pub, priv, digest, signature + _SLH_DSA_128_SIZE,
-                &tree_ctx, &scratch_ctx);
+  res = _slh_dsa_sign (&_slh_dsa_128f_params, &_slh_hash_shake,
+                      pub, priv, digest, signature + _SLH_DSA_128_SIZE,
+                      &tree_ctx, &scratch_ctx);
+  if (!res)
+    memset (signature, 0, SLH_DSA_128F_SIGNATURE_SIZE);
+
+  return res;
 }
 
 int
 }
 
 int
index 8dd0d2fe9f150c94017a8a911d2bdfe7914834cf..b8a4062be860ad96f6f58c4af52a5a18922b3b6e 100644 (file)
@@ -35,6 +35,8 @@
 # include "config.h"
 #endif
 
 # include "config.h"
 #endif
 
+#include <string.h>
+
 #include "slh-dsa.h"
 #include "slh-dsa-internal.h"
 
 #include "slh-dsa.h"
 #include "slh-dsa-internal.h"
 
@@ -65,19 +67,25 @@ slh_dsa_shake_128s_generate_keypair (uint8_t *pub, uint8_t *priv,
 }
 
 /* Only the "pure" and deterministic variant. */
 }
 
 /* Only the "pure" and deterministic variant. */
-void
+int
 slh_dsa_shake_128s_sign (const uint8_t *pub, const uint8_t *priv,
                         size_t length, const uint8_t *msg,
                         uint8_t *signature)
 {
   struct sha3_ctx tree_ctx, scratch_ctx;
   uint8_t digest[SLH_DSA_M];
 slh_dsa_shake_128s_sign (const uint8_t *pub, const uint8_t *priv,
                         size_t length, const uint8_t *msg,
                         uint8_t *signature)
 {
   struct sha3_ctx tree_ctx, scratch_ctx;
   uint8_t digest[SLH_DSA_M];
+  int res;
+
   _slh_dsa_pure_rdigest (&_slh_hash_shake,
                         pub, priv + _SLH_DSA_128_SIZE, length, msg,
                         signature, sizeof (digest), digest);
   _slh_dsa_pure_rdigest (&_slh_hash_shake,
                         pub, priv + _SLH_DSA_128_SIZE, length, msg,
                         signature, sizeof (digest), digest);
-  _slh_dsa_sign (&_slh_dsa_128s_params, &_slh_hash_shake,
-                pub, priv, digest, signature + _SLH_DSA_128_SIZE,
-                &tree_ctx, &scratch_ctx);
+  res = _slh_dsa_sign (&_slh_dsa_128s_params, &_slh_hash_shake,
+                      pub, priv, digest, signature + _SLH_DSA_128_SIZE,
+                      &tree_ctx, &scratch_ctx);
+  if (!res)
+    memset (signature, 0, SLH_DSA_128S_SIGNATURE_SIZE);
+
+  return res;
 }
 
 int
 }
 
 int
index 4a3e9a5b4304bd75568414da7b7e7032c518c331..9ee74d520d4567d4bcd444828ebf0a4b9e5c19f7 100644 (file)
--- a/slh-dsa.c
+++ b/slh-dsa.c
@@ -35,7 +35,6 @@
 # include "config.h"
 #endif
 
 # include "config.h"
 #endif
 
-#include <assert.h>
 #include <string.h>
 
 #include "memops.h"
 #include <string.h>
 
 #include "memops.h"
@@ -66,7 +65,7 @@ _slh_dsa_pure_rdigest (const struct slh_hash *hash,
   _slh_dsa_pure_digest (hash, pub, length, msg, randomizer, digest_size, digest);
 }
 
   _slh_dsa_pure_digest (hash, pub, length, msg, randomizer, digest_size, digest);
 }
 
-void
+int
 _slh_dsa_sign (const struct slh_dsa_params *params,
               const struct slh_hash *hash,
               const uint8_t *pub, const uint8_t *priv,
 _slh_dsa_sign (const struct slh_dsa_params *params,
               const struct slh_hash *hash,
               const uint8_t *pub, const uint8_t *priv,
@@ -103,7 +102,7 @@ _slh_dsa_sign (const struct slh_dsa_params *params,
 
       _xmss_sign (&merkle_ctx, params->xmss.h, leaf_idx, root, signature, root);
     }
 
       _xmss_sign (&merkle_ctx, params->xmss.h, leaf_idx, root, signature, root);
     }
-  assert (memeql_sec (root, pub + _SLH_DSA_128_SIZE, sizeof (root)));
+  return memeql_sec (root, pub + _SLH_DSA_128_SIZE, sizeof (root));
 }
 
 int
 }
 
 int
index 0d4c774daac951493fa7891b2f46a83f52650e2d..09b8edf924c91431a06afe8f20c00b57ed967883 100644 (file)
--- a/slh-dsa.h
+++ b/slh-dsa.h
@@ -100,19 +100,19 @@ slh_dsa_sha2_128f_generate_keypair (uint8_t *pub, uint8_t *key,
                                    void *random_ctx, nettle_random_func *random);
 
 /* Only the "pure" and deterministic variant. */
                                    void *random_ctx, nettle_random_func *random);
 
 /* Only the "pure" and deterministic variant. */
-void
+int
 slh_dsa_shake_128s_sign (const uint8_t *pub, const uint8_t *priv,
                         size_t length, const uint8_t *msg,
                         uint8_t *signature);
 slh_dsa_shake_128s_sign (const uint8_t *pub, const uint8_t *priv,
                         size_t length, const uint8_t *msg,
                         uint8_t *signature);
-void
+int
 slh_dsa_shake_128f_sign (const uint8_t *pub, const uint8_t *priv,
                         size_t length, const uint8_t *msg,
                         uint8_t *signature);
 slh_dsa_shake_128f_sign (const uint8_t *pub, const uint8_t *priv,
                         size_t length, const uint8_t *msg,
                         uint8_t *signature);
-void
+int
 slh_dsa_sha2_128s_sign (const uint8_t *pub, const uint8_t *priv,
                        size_t length, const uint8_t *msg,
                        uint8_t *signature);
 slh_dsa_sha2_128s_sign (const uint8_t *pub, const uint8_t *priv,
                        size_t length, const uint8_t *msg,
                        uint8_t *signature);
-void
+int
 slh_dsa_sha2_128f_sign (const uint8_t *pub, const uint8_t *priv,
                        size_t length, const uint8_t *msg,
                        uint8_t *signature);
 slh_dsa_sha2_128f_sign (const uint8_t *pub, const uint8_t *priv,
                        size_t length, const uint8_t *msg,
                        uint8_t *signature);
index 1be9b24fa6abbc4f4b797f3b86f364daee404f20..5b3ab1852d31327f3f00299c9a5c12140b840c4f 100644 (file)
@@ -255,16 +255,15 @@ test_slh_dsa_128_root (root_func *f,
   ASSERT (MEMEQ (sizeof (pub), pub, exp_pub->data));
 }
 
   ASSERT (MEMEQ (sizeof (pub), pub, exp_pub->data));
 }
 
-typedef void sign_func (const uint8_t *pub, const uint8_t *priv,
-                       size_t length, const uint8_t *msg,
-                       uint8_t *signature);
+typedef int sign_func (const uint8_t *pub, const uint8_t *priv,
+                      size_t length, const uint8_t *msg,
+                      uint8_t *signature);
 typedef int verify_func (const uint8_t *pub,
                         size_t length, const uint8_t *msg,
                         const uint8_t *signature);
 struct slh_dsa_alg
 {
   const char *name;
 typedef int verify_func (const uint8_t *pub,
                         size_t length, const uint8_t *msg,
                         const uint8_t *signature);
 struct slh_dsa_alg
 {
   const char *name;
-  size_t key_size;
   size_t signature_size;
   sign_func *sign;
   verify_func *verify;
   size_t signature_size;
   sign_func *sign;
   verify_func *verify;
@@ -273,7 +272,6 @@ struct slh_dsa_alg
 static const struct slh_dsa_alg
 slh_dsa_shake_128s = {
   "slh_dsa_shake_128s",
 static const struct slh_dsa_alg
 slh_dsa_shake_128s = {
   "slh_dsa_shake_128s",
-  SLH_DSA_128_KEY_SIZE,
   SLH_DSA_128S_SIGNATURE_SIZE,
   slh_dsa_shake_128s_sign,
   slh_dsa_shake_128s_verify,
   SLH_DSA_128S_SIGNATURE_SIZE,
   slh_dsa_shake_128s_sign,
   slh_dsa_shake_128s_verify,
@@ -282,7 +280,6 @@ slh_dsa_shake_128s = {
 static const struct slh_dsa_alg
 slh_dsa_shake_128f = {
   "slh_dsa_shake_128f",
 static const struct slh_dsa_alg
 slh_dsa_shake_128f = {
   "slh_dsa_shake_128f",
-  SLH_DSA_128_KEY_SIZE,
   SLH_DSA_128F_SIGNATURE_SIZE,
   slh_dsa_shake_128f_sign,
   slh_dsa_shake_128f_verify,
   SLH_DSA_128F_SIGNATURE_SIZE,
   slh_dsa_shake_128f_sign,
   slh_dsa_shake_128f_verify,
@@ -291,7 +288,6 @@ slh_dsa_shake_128f = {
 static const struct slh_dsa_alg
 slh_dsa_sha2_128s = {
   "slh_dsa_sha2_128s",
 static const struct slh_dsa_alg
 slh_dsa_sha2_128s = {
   "slh_dsa_sha2_128s",
-  SLH_DSA_128_KEY_SIZE,
   SLH_DSA_128S_SIGNATURE_SIZE,
   slh_dsa_sha2_128s_sign,
   slh_dsa_sha2_128s_verify,
   SLH_DSA_128S_SIGNATURE_SIZE,
   slh_dsa_sha2_128s_sign,
   slh_dsa_sha2_128s_verify,
@@ -300,7 +296,6 @@ slh_dsa_sha2_128s = {
 static const struct slh_dsa_alg
 slh_dsa_sha2_128f = {
   "slh_dsa_sha2_128f",
 static const struct slh_dsa_alg
 slh_dsa_sha2_128f = {
   "slh_dsa_sha2_128f",
-  SLH_DSA_128_KEY_SIZE,
   SLH_DSA_128F_SIGNATURE_SIZE,
   slh_dsa_sha2_128f_sign,
   slh_dsa_sha2_128f_verify,
   SLH_DSA_128F_SIGNATURE_SIZE,
   slh_dsa_sha2_128f_sign,
   slh_dsa_sha2_128f_verify,
@@ -312,11 +307,13 @@ test_slh_dsa (const struct slh_dsa_alg *alg,
              const struct tstring *msg, const struct tstring *ref)
 {
   uint8_t *sig = xalloc (alg->signature_size);
              const struct tstring *msg, const struct tstring *ref)
 {
   uint8_t *sig = xalloc (alg->signature_size);
-  ASSERT (pub->length == alg->key_size);
-  ASSERT (priv->length == alg->key_size);
+  uint8_t bad_key[SLH_DSA_128_KEY_SIZE];
+
+  ASSERT (pub->length == SLH_DSA_128_KEY_SIZE);
+  ASSERT (priv->length == SLH_DSA_128_KEY_SIZE);
   ASSERT (ref->length == alg->signature_size);
 
   ASSERT (ref->length == alg->signature_size);
 
-  alg->sign (pub->data, priv->data, msg->length, msg->data, sig);
+  ASSERT (alg->sign (pub->data, priv->data, msg->length, msg->data, sig));
   if (! MEMEQ (alg->signature_size, sig, ref->data))
     {
       size_t i;
   if (! MEMEQ (alg->signature_size, sig, ref->data))
     {
       size_t i;
@@ -334,6 +331,16 @@ test_slh_dsa (const struct slh_dsa_alg *alg,
   sig[alg->signature_size-1] ^= 1;
   ASSERT (!alg->verify (pub->data, msg->length, msg->data, sig));
 
   sig[alg->signature_size-1] ^= 1;
   ASSERT (!alg->verify (pub->data, msg->length, msg->data, sig));
 
+  memcpy (bad_key, pub->data, sizeof (bad_key));
+  bad_key[5] ^= 1; /* Modifies public seed */
+  ASSERT (!alg->sign (bad_key, priv->data, msg->length, msg->data, sig));
+  ASSERT (sig[alg->signature_size - 1] == 0);
+
+  memcpy (bad_key, priv->data, sizeof (bad_key));
+  bad_key[5] ^= 1; /* Modifies private seed */
+  ASSERT (!alg->sign (pub->data, bad_key, msg->length, msg->data, sig));
+  ASSERT (sig[alg->signature_size - 1] == 0);
+
   free (sig);
 }
 
   free (sig);
 }