Hello,

The attached patch adds support for the deterministic DSA and ECDSA, as
defined in RFC 6979, which enables us to use the signing function
without randomness.

The original code has been hosted in GnuTLS for a while, implemented as
a custom random function which can be used in combination with dsa_sign
and ecdsa_sign.  While this approach works in general, it requires
pre/post processing: e.g., access to ECC q[1] and cancelling out the
Nettle's tweak in dsa_sign adding 1[2] to the random value.  Therefore,
I would rather like this to be included in Nettle itself.  Note also
that this implementation should be identical to the latest code in
GnuTLS, which addresses the Minerva attack[3].

The same patch is also available at GitLab:
https://git.lysator.liu.se/nettle/nettle/-/merge_requests/64

Footnotes:
[1]  
https://gitlab.com/gnutls/gnutls/-/blob/c1428c07d406f18cca94f94e2b7ca1f866df42d9/lib/nettle/int/ecdsa-compute-k.c#L32

[2]  
https://gitlab.com/gnutls/gnutls/-/blob/c1428c07d406f18cca94f94e2b7ca1f866df42d9/lib/nettle/int/dsa-compute-k.c#L212

[3]  https://nvd.nist.gov/vuln/detail/CVE-2024-28834

Regards,
-- 
Daiki Ueno
>From 0b9860dfa63becdc2e2d8468889c35a2991c0329 Mon Sep 17 00:00:00 2001
From: Daiki Ueno <du...@redhat.com>
Date: Sun, 14 Apr 2024 09:05:19 +0900
Subject: [PATCH] Add support for deterministic DSA and ECDSA

This implements deterministic nonce construction for DSA and ECDSA,
as defined in RFC 6979.

Signed-off-by: Daiki Ueno <du...@redhat.com>
---
 Makefile.in                          |   5 +-
 dsa-compute-k.c                      | 173 +++++++++++++++++++++++++++
 dsa-compute-k.h                      |  49 ++++++++
 dsa-sign.c                           |  65 ++++++++++
 dsa.h                                |   9 ++
 ecdsa-sign.c                         |  26 ++++
 ecdsa.h                              |  10 ++
 gmp-glue.h                           |   5 +-
 nettle-internal.h                    |   1 +
 testsuite/.gitignore                 |   2 +
 testsuite/Makefile.in                |   3 +-
 testsuite/deterministic-dsa-test.c   |  96 +++++++++++++++
 testsuite/deterministic-ecdsa-test.c |  82 +++++++++++++
 13 files changed, 522 insertions(+), 4 deletions(-)
 create mode 100644 dsa-compute-k.c
 create mode 100644 dsa-compute-k.h
 create mode 100644 testsuite/deterministic-dsa-test.c
 create mode 100644 testsuite/deterministic-ecdsa-test.c

diff --git a/Makefile.in b/Makefile.in
index 29ad54d7..227c459a 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -225,7 +225,8 @@ hogweed_SOURCES = sexp.c sexp-format.c \
 		  ed25519-sha512.c ed25519-sha512-pubkey.c \
 		  ed25519-sha512-sign.c ed25519-sha512-verify.c \
 		  ed448-shake256.c ed448-shake256-pubkey.c \
-		  ed448-shake256-sign.c ed448-shake256-verify.c
+		  ed448-shake256-sign.c ed448-shake256-verify.c \
+		  dsa-compute-k.c
 
 OPT_SOURCES = fat-arm.c fat-arm64.c fat-ppc.c fat-s390x.c fat-x86_64.c mini-gmp.c
 
@@ -278,7 +279,7 @@ DISTFILES = $(SOURCES) $(HEADERS) getopt.h getopt_int.h \
 	ctr-internal.h chacha-internal.h sha3-internal.h \
 	salsa20-internal.h umac-internal.h hogweed-internal.h \
 	rsa-internal.h pkcs1-internal.h dsa-internal.h eddsa-internal.h \
-	gmp-glue.h ecc-internal.h fat-setup.h oaep.h \
+	gmp-glue.h ecc-internal.h fat-setup.h oaep.h dsa-compute-k.h \
 	mini-gmp.h asm.m4 m4-utils.m4 \
 	nettle.texinfo nettle.info nettle.html nettle.pdf sha-example.c
 
diff --git a/dsa-compute-k.c b/dsa-compute-k.c
new file mode 100644
index 00000000..28b4f6d5
--- /dev/null
+++ b/dsa-compute-k.c
@@ -0,0 +1,173 @@
+/* dsa-compute-k.c
+
+   The DSA publickey algorithm, deterministic nonce construction (RFC 6979).
+
+   Copyright (C) 2019-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 "dsa-compute-k.h"
+
+#include "gmp-glue.h"
+#include "nettle-internal.h"
+#include <string.h>
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+void
+_dsa_compute_k (mp_limb_t *k, const mp_limb_t *q, const mp_limb_t *x,
+		mp_bitcnt_t q_bits,
+		void *hmac_ctx, const struct nettle_mac *hmac,
+		const uint8_t *digest)
+{
+  uint8_t V[NETTLE_MAX_HASH_DIGEST_SIZE];
+  uint8_t K[NETTLE_MAX_HASH_DIGEST_SIZE];
+  TMP_GMP_DECL(xp, uint8_t);
+  TMP_GMP_DECL(tp, uint8_t);
+  const mp_bitcnt_t k_bits = hmac->digest_size * 8;
+  mp_size_t kn = NETTLE_BIT_SIZE_TO_LIMB_SIZE (k_bits);
+  mp_size_t qn = NETTLE_BIT_SIZE_TO_LIMB_SIZE (q_bits);
+  size_t nbytes = (q_bits + 7) / 8;
+  const uint8_t c0 = 0x00;
+  const uint8_t c1 = 0x01;
+  mp_limb_t cy;
+  mp_limb_t *scratch;
+
+  assert (hmac->digest_size == hmac->key_size);
+
+  TMP_GMP_ALLOC (xp, nbytes);
+  TMP_GMP_ALLOC (tp, nbytes);
+
+  scratch = gmp_alloc_limbs (NETTLE_OCTET_SIZE_TO_LIMB_SIZE (nbytes));
+
+  /* int2octets(x) */
+  mpn_get_base256 (xp, nbytes, x, qn);
+
+  /* bits2octets (k) */
+  mpn_set_base256 (k, kn, digest, hmac->digest_size);
+
+  if (kn < qn)
+    /* qlen > blen: add zero bits to the left */
+    mpn_zero (&k[kn], qn - kn);
+  else if (k_bits > q_bits)
+    {
+      /* qlen < blen: keep the leftmost qlen bits.  We do this in 2
+       * steps because mpn_rshift only accepts shift count in the
+       * range 1 to mp_bits_per_limb-1.
+       */
+      mp_bitcnt_t shift = k_bits - q_bits;
+
+      if (shift / GMP_NUMB_BITS > 0)
+	{
+	  mpn_copyi (k, &k[shift / GMP_NUMB_BITS], qn);
+	  kn -= shift / GMP_NUMB_BITS;
+	}
+
+      if (shift % GMP_NUMB_BITS > 0)
+	mpn_rshift (k, k, kn, shift % GMP_NUMB_BITS);
+    }
+
+  cy = mpn_sub_n (k, k, q, qn);
+  mpn_cnd_add_n (cy, k, k, q, qn);
+  mpn_get_base256 (tp, nbytes, k, qn);
+
+  /* Step b */
+  memset (V, c1, hmac->digest_size);
+
+  /* Step c */
+  memset (K, c0, hmac->digest_size);
+
+  /* Step d */
+  hmac->set_key (hmac_ctx, K);
+  hmac->update (hmac_ctx, hmac->digest_size, V);
+  hmac->update (hmac_ctx, 1, &c0);
+  hmac->update (hmac_ctx, nbytes, xp);
+  hmac->update (hmac_ctx, nbytes, tp);
+  hmac->digest (hmac_ctx, hmac->digest_size, K);
+
+  /* Step e */
+  hmac->set_key (hmac_ctx, K);
+  hmac->update (hmac_ctx, hmac->digest_size, V);
+  hmac->digest (hmac_ctx, hmac->digest_size, V);
+
+  /* Step f */
+  hmac->set_key (hmac_ctx, K);
+  hmac->update (hmac_ctx, hmac->digest_size, V);
+  hmac->update (hmac_ctx, 1, &c1);
+  hmac->update (hmac_ctx, nbytes, xp);
+  hmac->update (hmac_ctx, nbytes, tp);
+  hmac->digest (hmac_ctx, hmac->digest_size, K);
+
+  /* Step g */
+  hmac->set_key (hmac_ctx, K);
+  hmac->update (hmac_ctx, hmac->digest_size, V);
+  hmac->digest (hmac_ctx, hmac->digest_size, V);
+
+  /* Step h */
+  for (;;)
+    {
+      /* Step 1 */
+      size_t tlen = 0;
+
+      /* Step 2 */
+      while (tlen < nbytes)
+	{
+	  size_t remaining = MIN (nbytes - tlen, hmac->digest_size);
+	  hmac->set_key (hmac_ctx, K);
+	  hmac->update (hmac_ctx, hmac->digest_size, V);
+	  hmac->digest (hmac_ctx, hmac->digest_size, V);
+	  memcpy (&tp[tlen], V, remaining);
+	  tlen += remaining;
+	}
+
+      /* Step 3 */
+      mpn_set_base256 (k, qn, tp, tlen);
+      if (tlen * 8 > q_bits)
+	mpn_rshift (k, k, qn, tlen * 8 - q_bits);
+      /* Check if k is in [1,q-1] */
+      if (!sec_zero_p (k, qn) && mpn_sub_n (scratch, k, q, qn))
+	break;
+
+      hmac->set_key (hmac_ctx, K);
+      hmac->update (hmac_ctx, hmac->digest_size, V);
+      hmac->update (hmac_ctx, 1, &c0);
+      hmac->digest (hmac_ctx, hmac->digest_size, K);
+
+      hmac->set_key (hmac_ctx, K);
+      hmac->update (hmac_ctx, hmac->digest_size, V);
+      hmac->digest (hmac_ctx, hmac->digest_size, V);
+  }
+
+  TMP_GMP_FREE (xp);
+  TMP_GMP_FREE (tp);
+  gmp_free_limbs (scratch, NETTLE_OCTET_SIZE_TO_LIMB_SIZE (nbytes));
+}
diff --git a/dsa-compute-k.h b/dsa-compute-k.h
new file mode 100644
index 00000000..a65c1f0a
--- /dev/null
+++ b/dsa-compute-k.h
@@ -0,0 +1,49 @@
+/* dsa-compute-k.h
+
+   The DSA publickey algorithm, deterministic nonce construction (RFC 6979).
+
+   Copyright (C) 2019-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/.
+*/
+
+#ifndef NETTLE_DSA_COMPUTE_K_H_INCLUDED
+#define NETTLE_DSA_COMPUTE_K_H_INCLUDED
+
+#include "bignum.h"
+#include "nettle-meta.h"
+
+/* Namespace mangling */
+#define _dsa_compute_k _nettle_dsa_compute_k
+
+void
+_dsa_compute_k (mp_limb_t *k, const mp_limb_t *q, const mp_limb_t *x,
+		mp_bitcnt_t q_bits,
+		void *hmac_ctx, const struct nettle_mac *hmac,
+		const uint8_t *digest);
+
+#endif /* NETTLE_DSA_COMPUTE_K_H_INCLUDED */
diff --git a/dsa-sign.c b/dsa-sign.c
index 42a0a581..8a561499 100644
--- a/dsa-sign.c
+++ b/dsa-sign.c
@@ -39,9 +39,12 @@
 #include <stdlib.h>
 
 #include "dsa.h"
+#include "dsa-compute-k.h"
 #include "dsa-internal.h"
 
 #include "bignum.h"
+#include "gmp-glue.h"
+#include "nettle-internal.h"
 
 
 int
@@ -99,3 +102,65 @@ dsa_sign(const struct dsa_params *params,
 
   return res;
 }
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+int
+dsa_sign_deterministic(const struct dsa_params *params,
+		       const mpz_t x,
+		       void *hmac_ctx, const struct nettle_mac *hmac,
+		       const uint8_t *digest,
+		       struct dsa_signature *signature)
+{
+  mp_limb_t *kp;
+  mpz_t k;
+  mpz_t i;
+  mpz_t h;
+  mpz_t tmp;
+  int res;
+
+  /* Check that p is odd, so that invalid keys don't result in a crash
+     inside mpz_powm_sec. */
+  if (mpz_even_p (params->p))
+    return 0;
+
+  kp = gmp_alloc_limbs (MAX(mpz_size (params->q),
+			    NETTLE_OCTET_SIZE_TO_LIMB_SIZE (NETTLE_MAX_HASH_DIGEST_SIZE)));
+
+  _dsa_compute_k (kp, mpz_limbs_read (params->q), mpz_limbs_read (x),
+		  mpz_sizeinbase(params->q, 2), hmac_ctx, hmac,
+		  digest);
+
+  mpz_roinit_n (k, kp, mpz_size (params->q));
+
+  /* Compute r = (g^k (mod p)) (mod q) */
+  mpz_powm_sec(tmp, params->g, k, params->p);
+  mpz_fdiv_r(signature->r, tmp, params->q);
+
+  /* Compute hash */
+  mpz_init(h);
+  _nettle_dsa_hash (h, mpz_sizeinbase(params->q, 2), hmac->digest_size, digest);
+
+  /* Compute i = k^-1 (mod q) */
+  mpz_init(i);
+  if (mpz_invert(i, k, params->q))
+    {
+      /* Compute signature s = k^-1 (h + xr) (mod q) */
+      mpz_mul(tmp, signature->r, x);
+      mpz_fdiv_r(tmp, tmp, params->q);
+      mpz_add(tmp, tmp, h);
+      mpz_mul(tmp, tmp, i);
+      mpz_fdiv_r(signature->s, tmp, params->q);
+      res = 1;
+    }
+  else
+    /* What do we do now? The key is invalid. */
+    res = 0;
+
+  mpz_clear(i);
+  mpz_clear(h);
+  mpz_clear(tmp);
+  gmp_free_limbs (kp, mpz_size (params->q));
+
+  return res;
+}
diff --git a/dsa.h b/dsa.h
index 553ef327..b612fdb6 100644
--- a/dsa.h
+++ b/dsa.h
@@ -36,6 +36,7 @@
 
 #include "nettle-types.h"
 #include "bignum.h"
+#include "nettle-meta.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -47,6 +48,7 @@ extern "C" {
 #define dsa_signature_init nettle_dsa_signature_init
 #define dsa_signature_clear nettle_dsa_signature_clear
 #define dsa_sign nettle_dsa_sign
+#define dsa_sign_deterministic nettle_dsa_sign_deterministic
 #define dsa_verify nettle_dsa_verify
 #define dsa_generate_params nettle_dsa_generate_params
 #define dsa_generate_keypair nettle_dsa_generate_keypair
@@ -109,6 +111,13 @@ dsa_sign(const struct dsa_params *params,
 	 const uint8_t *digest,
 	 struct dsa_signature *signature);
 
+int
+dsa_sign_deterministic(const struct dsa_params *params,
+		       const mpz_t x,
+		       void *hmac_ctx, const struct nettle_mac *hmac,
+		       const uint8_t *digest,
+		       struct dsa_signature *signature);
+
 int
 dsa_verify(const struct dsa_params *params,
 	   const mpz_t y,
diff --git a/ecdsa-sign.c b/ecdsa-sign.c
index e6fb3287..6e7fb2e0 100644
--- a/ecdsa-sign.c
+++ b/ecdsa-sign.c
@@ -40,6 +40,7 @@
 
 #include "ecdsa.h"
 #include "ecc-internal.h"
+#include "dsa-compute-k.h"
 #include "nettle-internal.h"
 
 void
@@ -69,3 +70,28 @@ ecdsa_sign (const struct ecc_scalar *key,
     }
   while (mpz_sgn (signature->r) == 0 || mpz_sgn (signature->s) == 0);
 }
+
+void
+ecdsa_sign_deterministic (const struct ecc_scalar *key,
+			  void *hmac_ctx, const struct nettle_mac *hmac,
+			  const uint8_t *digest,
+			  struct dsa_signature *signature)
+{
+  /* At most 936 bytes. */
+  TMP_DECL(k, mp_limb_t, ECC_MAX_SIZE + ECC_ECDSA_SIGN_ITCH (ECC_MAX_SIZE));
+  mp_limb_t size = key->ecc->p.size;
+  mp_limb_t *rp = mpz_limbs_write (signature->r, size);
+  mp_limb_t *sp = mpz_limbs_write (signature->s, size);
+
+  TMP_ALLOC (k, size + ECC_ECDSA_SIGN_ITCH (size));
+
+  _dsa_compute_k (k, key->ecc->q.m, key->p, key->ecc->q.bit_size,
+		  hmac_ctx, hmac, digest);
+
+  ecc_ecdsa_sign (key->ecc, key->p, k, hmac->digest_size, digest,
+		  rp, sp, k + size);
+  mpz_limbs_finish (signature->r, size);
+  mpz_limbs_finish (signature->s, size);
+
+  assert (mpz_sgn (signature->r) != 0 && mpz_sgn (signature->s) != 0);
+}
diff --git a/ecdsa.h b/ecdsa.h
index 259efc10..c9510c71 100644
--- a/ecdsa.h
+++ b/ecdsa.h
@@ -36,6 +36,7 @@
 
 #include "ecc.h"
 #include "dsa.h"
+#include "nettle-meta.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -43,6 +44,7 @@ extern "C" {
 
 /* Name mangling */
 #define ecdsa_sign nettle_ecdsa_sign
+#define ecdsa_sign_deterministic nettle_ecdsa_sign_deterministic
 #define ecdsa_verify nettle_ecdsa_verify
 #define ecdsa_generate_keypair nettle_ecdsa_generate_keypair
 #define ecc_ecdsa_sign nettle_ecc_ecdsa_sign
@@ -61,6 +63,14 @@ ecdsa_sign (const struct ecc_scalar *key,
 	    const uint8_t *digest,
 	    struct dsa_signature *signature);
 
+/* Similar to ecdsa_sign, but this uses a deterministic construction
+   of nonce according to RFC 6979. */
+void
+ecdsa_sign_deterministic (const struct ecc_scalar *key,
+			  void *hmac_ctx, const struct nettle_mac *hmac,
+			  const uint8_t *digest,
+			  struct dsa_signature *signature);
+
 int
 ecdsa_verify (const struct ecc_point *pub,
 	      size_t length, const uint8_t *digest,
diff --git a/gmp-glue.h b/gmp-glue.h
index afe94635..7e5b664f 100644
--- a/gmp-glue.h
+++ b/gmp-glue.h
@@ -85,8 +85,11 @@ is_zero_limb (mp_limb_t x)
 int
 sec_zero_p (const mp_limb_t *ap, mp_size_t n);
 
+#define NETTLE_BIT_SIZE_TO_LIMB_SIZE(n) \
+  (((n) + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
+
 #define NETTLE_OCTET_SIZE_TO_LIMB_SIZE(n) \
-  (((n) * 8 + GMP_NUMB_BITS - 1) / GMP_NUMB_BITS)
+  NETTLE_BIT_SIZE_TO_LIMB_SIZE((n) * 8)
 
 /* Convenience functions */
 
diff --git a/nettle-internal.h b/nettle-internal.h
index 81d06e80..97190c92 100644
--- a/nettle-internal.h
+++ b/nettle-internal.h
@@ -75,6 +75,7 @@
 #define NETTLE_MAX_HASH_BLOCK_SIZE 144  /* For sha3_224*/
 #define NETTLE_MAX_HASH_DIGEST_SIZE 64
 #define NETTLE_MAX_HASH_CONTEXT_SIZE (sizeof(struct sha3_224_ctx))
+#define NETTLE_MAX_HMAC_CONTEXT_SIZE (sizeof(struct hmac_sha512_ctx))
 #define NETTLE_MAX_SEXP_ASSOC 17
 #define NETTLE_MAX_CIPHER_BLOCK_SIZE 32
 #define NETTLE_MAX_CIPHER_KEY_SIZE 32
diff --git a/testsuite/.gitignore b/testsuite/.gitignore
index b7929caa..60f9504b 100644
--- a/testsuite/.gitignore
+++ b/testsuite/.gitignore
@@ -24,6 +24,8 @@
 /cxx-test
 /des-test
 /des3-test
+/deterministic-dsa-test
+/deterministic-ecdsa-test
 /dlopen-test
 /dsa-keygen-test
 /dsa-test
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index de7fa590..48b6f2fb 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -58,7 +58,8 @@ TS_HOGWEED_SOURCES = sexp-test.c sexp-format-test.c \
 		     eddsa-compress-test.c eddsa-sign-test.c \
 		     eddsa-verify-test.c ed25519-test.c ed448-test.c \
 		     gostdsa-sign-test.c gostdsa-verify-test.c \
-		     gostdsa-keygen-test.c gostdsa-vko-test.c
+		     gostdsa-keygen-test.c gostdsa-vko-test.c \
+		     deterministic-dsa-test.c deterministic-ecdsa-test.c
 
 TS_SOURCES = $(TS_NETTLE_SOURCES) $(TS_HOGWEED_SOURCES)
 CXX_SOURCES = cxx-test.cxx
diff --git a/testsuite/deterministic-dsa-test.c b/testsuite/deterministic-dsa-test.c
new file mode 100644
index 00000000..4af9d417
--- /dev/null
+++ b/testsuite/deterministic-dsa-test.c
@@ -0,0 +1,96 @@
+#include "testutils.h"
+#include "nettle-internal.h"
+#include "nettle-meta.h"
+
+static void
+test_dsa (const struct dsa_params *params,
+	  const struct nettle_mac *hmac,
+	  const struct nettle_hash *hash,
+	  /* Private key */
+	  const char *sz,
+	  size_t length,
+	  const char *message,
+	  /* Expected signature */
+	  const char *r, const char *s)
+{
+  mpz_t z;
+  void *hmac_ctx;
+  void *hash_ctx;
+  uint8_t digest[NETTLE_MAX_HASH_DIGEST_SIZE];
+  struct dsa_signature ref;
+  struct dsa_signature sig;
+
+  mpz_init_set_str (z, sz, 16);
+
+  dsa_signature_init (&ref);
+  dsa_signature_init (&sig);
+
+  hash_ctx = xalloc (hash->context_size);
+  hash->init (hash_ctx);
+  hash->update (hash_ctx, length, (const uint8_t *) message);
+  hash->digest (hash_ctx, hash->digest_size, digest);
+
+  hmac_ctx = xalloc (hmac->context_size);
+  dsa_sign_deterministic (params, z,
+			  hmac_ctx, hmac,
+			  digest,
+			  &sig);
+
+  mpz_set_str (ref.r, r, 16);
+  mpz_set_str (ref.s, s, 16);
+
+  if (mpz_cmp (ref.r, sig.r) != 0 || mpz_cmp (ref.s, sig.s) != 0)
+    {
+      fprintf (stderr, "dsa_sign_deterministic failed, bit_size = %lu\n",
+	       mpz_sizeinbase (params->q, 2));
+      fprintf (stderr, "r     = ");
+      mpz_out_str (stderr, 16, sig.r);
+      fprintf (stderr, "\ns     = ");
+      mpz_out_str (stderr, 16, sig.s);
+      fprintf (stderr, "\nref.r = ");
+      mpz_out_str (stderr, 16, ref.r);
+      fprintf (stderr, "\nref.s = ");
+      mpz_out_str (stderr, 16, ref.s);
+      fprintf (stderr, "\n");
+      abort();
+    }
+
+  free (hash_ctx);
+  free (hmac_ctx);
+
+  dsa_signature_clear (&ref);
+  dsa_signature_clear (&sig);
+  mpz_clear (z);
+}
+
+void
+test_main (void)
+{
+  struct dsa_params params;
+
+  mpz_init_set_str (params.p,
+		    "86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447"
+		    "E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88"
+		    "73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C"
+		    "881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779",
+		    16);
+  mpz_init_set_str (params.q,
+		    "996F967F6C8E388D9E28D01E205FBA957A5698B1",
+		    16);
+  mpz_init_set_str (params.g,
+		    "07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D"
+		    "89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD"
+		    "87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4"
+		    "17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD",
+		    16);
+
+  test_dsa (&params,
+	    &nettle_hmac_sha256,
+	    &nettle_sha256,
+	    "411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", /* Private key */
+	    6, "sample", /* message */
+	    "81F2F5850BE5BC123C43F71A3033E9384611C545", /* r */
+	    "4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89"); /* s */
+
+  dsa_params_clear (&params);
+}
diff --git a/testsuite/deterministic-ecdsa-test.c b/testsuite/deterministic-ecdsa-test.c
new file mode 100644
index 00000000..1f9025a5
--- /dev/null
+++ b/testsuite/deterministic-ecdsa-test.c
@@ -0,0 +1,82 @@
+#include "testutils.h"
+#include "nettle-internal.h"
+#include "nettle-meta.h"
+
+static void
+test_ecdsa (const struct ecc_curve *ecc,
+	    const struct nettle_mac *hmac,
+	    const struct nettle_hash *hash,
+	    /* Private key */
+	    const char *sz,
+	    size_t length,
+	    const char *message,
+	    /* Expected signature */
+	    const char *r, const char *s)
+{
+  struct ecc_scalar key;
+  mp_limb_t *zp = xalloc_limbs (ecc->p.size);
+  mpz_t z;
+  void *hmac_ctx;
+  void *hash_ctx;
+  uint8_t digest[NETTLE_MAX_HASH_DIGEST_SIZE];
+  struct dsa_signature ref;
+  struct dsa_signature sig;
+
+  dsa_signature_init (&ref);
+  dsa_signature_init (&sig);
+
+  hash_ctx = xalloc (hash->context_size);
+  hash->init (hash_ctx);
+  hash->update (hash_ctx, length, (const uint8_t *) message);
+  hash->digest (hash_ctx, hash->digest_size, digest);
+
+  ecc_scalar_init (&key, ecc);
+
+  mpz_init_set_str (z, sz, 16);
+  ASSERT (ecc_scalar_set (&key, z));
+
+  hmac_ctx = xalloc (hmac->context_size);
+  ecdsa_sign_deterministic (&key,
+			    hmac_ctx, hmac,
+			    digest,
+			    &sig);
+
+  mpz_set_str (ref.r, r, 16);
+  mpz_set_str (ref.s, s, 16);
+
+  if (mpz_cmp (ref.r, sig.r) != 0 || mpz_cmp (ref.s, sig.s) != 0)
+    {
+      fprintf (stderr, "ecdsa_sign_deterministic failed, bit_size = %u\n", ecc->p.bit_size);
+      fprintf (stderr, "r     = ");
+      mpz_out_str (stderr, 16, sig.r);
+      fprintf (stderr, "\ns     = ");
+      mpz_out_str (stderr, 16, sig.s);
+      fprintf (stderr, "\nref.r = ");
+      mpz_out_str (stderr, 16, ref.r);
+      fprintf (stderr, "\nref.s = ");
+      mpz_out_str (stderr, 16, ref.s);
+      fprintf (stderr, "\n");
+      abort();
+    }
+
+  free (hash_ctx);
+  free (hmac_ctx);
+  free (zp);
+
+  ecc_scalar_clear (&key);
+  dsa_signature_clear (&ref);
+  dsa_signature_clear (&sig);
+  mpz_clear (z);
+}
+
+void
+test_main (void)
+{
+  test_ecdsa (&_nettle_secp_256r1,
+	      &nettle_hmac_sha256,
+	      &nettle_sha256,
+	      "C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721", /* Private key */
+	      6, "sample", /* message */
+	      "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716", /* r */
+	      "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8"); /* s */
+}
-- 
2.44.0

_______________________________________________
nettle-bugs mailing list -- nettle-bugs@lists.lysator.liu.se
To unsubscribe send an email to nettle-bugs-le...@lists.lysator.liu.se

Reply via email to