From 246f86f129a09761d2fa1bcea4fc5301e6e67f58 Mon Sep 17 00:00:00 2001
From: Russ Williams <37781645+rmw42@users.noreply.github.com>
Date: Sat, 19 Jan 2019 19:44:29 +0000
Subject: [PATCH 1/2] Update makefiles
---
libtomcrypt_VS2008.vcproj | 4 ++++
makefile.mingw | 8 ++++----
makefile.msvc | 8 ++++----
makefile.unix | 8 ++++----
makefile_include.mk | 8 ++++----
5 files changed, 20 insertions(+), 16 deletions(-)
diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj
index a0b5ddfc8..dc0ee5980 100644
--- a/libtomcrypt_VS2008.vcproj
+++ b/libtomcrypt_VS2008.vcproj
@@ -2382,6 +2382,10 @@
RelativePath="src\pk\ecc\ecc_recover_key.c"
>
+
+
diff --git a/makefile.mingw b/makefile.mingw
index 04296fc41..50ebebcad 100644
--- a/makefile.mingw
+++ b/makefile.mingw
@@ -184,10 +184,10 @@ src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curv
src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
-src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
-src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
-src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o \
-src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/ecc/ecc_rfc6979_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
+src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
+src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
+src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
diff --git a/makefile.msvc b/makefile.msvc
index b9bb484fb..6e377baab 100644
--- a/makefile.msvc
+++ b/makefile.msvc
@@ -177,10 +177,10 @@ src/pk/ecc/ecc_export.obj src/pk/ecc/ecc_export_openssl.obj src/pk/ecc/ecc_find_
src/pk/ecc/ecc_free.obj src/pk/ecc/ecc_get_key.obj src/pk/ecc/ecc_get_oid_str.obj src/pk/ecc/ecc_get_size.obj \
src/pk/ecc/ecc_import.obj src/pk/ecc/ecc_import_openssl.obj src/pk/ecc/ecc_import_pkcs8.obj \
src/pk/ecc/ecc_import_x509.obj src/pk/ecc/ecc_make_key.obj src/pk/ecc/ecc_recover_key.obj \
-src/pk/ecc/ecc_set_curve.obj src/pk/ecc/ecc_set_curve_internal.obj src/pk/ecc/ecc_set_key.obj \
-src/pk/ecc/ecc_shared_secret.obj src/pk/ecc/ecc_sign_hash.obj src/pk/ecc/ecc_sizes.obj \
-src/pk/ecc/ecc_ssh_ecdsa_encode_name.obj src/pk/ecc/ecc_verify_hash.obj src/pk/ecc/ltc_ecc_export_point.obj \
-src/pk/ecc/ltc_ecc_import_point.obj src/pk/ecc/ltc_ecc_is_point.obj \
+src/pk/ecc/ecc_rfc6979_key.obj src/pk/ecc/ecc_set_curve.obj src/pk/ecc/ecc_set_curve_internal.obj \
+src/pk/ecc/ecc_set_key.obj src/pk/ecc/ecc_shared_secret.obj src/pk/ecc/ecc_sign_hash.obj \
+src/pk/ecc/ecc_sizes.obj src/pk/ecc/ecc_ssh_ecdsa_encode_name.obj src/pk/ecc/ecc_verify_hash.obj \
+src/pk/ecc/ltc_ecc_export_point.obj src/pk/ecc/ltc_ecc_import_point.obj src/pk/ecc/ltc_ecc_is_point.obj \
src/pk/ecc/ltc_ecc_is_point_at_infinity.obj src/pk/ecc/ltc_ecc_map.obj src/pk/ecc/ltc_ecc_mul2add.obj \
src/pk/ecc/ltc_ecc_mulmod.obj src/pk/ecc/ltc_ecc_mulmod_timing.obj src/pk/ecc/ltc_ecc_points.obj \
src/pk/ecc/ltc_ecc_projective_add_point.obj src/pk/ecc/ltc_ecc_projective_dbl_point.obj \
diff --git a/makefile.unix b/makefile.unix
index b0a57b673..30690ef5d 100644
--- a/makefile.unix
+++ b/makefile.unix
@@ -194,10 +194,10 @@ src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curv
src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
-src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
-src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
-src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o \
-src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/ecc/ecc_rfc6979_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
+src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
+src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
+src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
diff --git a/makefile_include.mk b/makefile_include.mk
index 791d5cc3b..13b46201a 100644
--- a/makefile_include.mk
+++ b/makefile_include.mk
@@ -354,10 +354,10 @@ src/pk/ecc/ecc_export.o src/pk/ecc/ecc_export_openssl.o src/pk/ecc/ecc_find_curv
src/pk/ecc/ecc_free.o src/pk/ecc/ecc_get_key.o src/pk/ecc/ecc_get_oid_str.o src/pk/ecc/ecc_get_size.o \
src/pk/ecc/ecc_import.o src/pk/ecc/ecc_import_openssl.o src/pk/ecc/ecc_import_pkcs8.o \
src/pk/ecc/ecc_import_x509.o src/pk/ecc/ecc_make_key.o src/pk/ecc/ecc_recover_key.o \
-src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o src/pk/ecc/ecc_set_key.o \
-src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o src/pk/ecc/ecc_sizes.o \
-src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o src/pk/ecc/ltc_ecc_export_point.o \
-src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
+src/pk/ecc/ecc_rfc6979_key.o src/pk/ecc/ecc_set_curve.o src/pk/ecc/ecc_set_curve_internal.o \
+src/pk/ecc/ecc_set_key.o src/pk/ecc/ecc_shared_secret.o src/pk/ecc/ecc_sign_hash.o \
+src/pk/ecc/ecc_sizes.o src/pk/ecc/ecc_ssh_ecdsa_encode_name.o src/pk/ecc/ecc_verify_hash.o \
+src/pk/ecc/ltc_ecc_export_point.o src/pk/ecc/ltc_ecc_import_point.o src/pk/ecc/ltc_ecc_is_point.o \
src/pk/ecc/ltc_ecc_is_point_at_infinity.o src/pk/ecc/ltc_ecc_map.o src/pk/ecc/ltc_ecc_mul2add.o \
src/pk/ecc/ltc_ecc_mulmod.o src/pk/ecc/ltc_ecc_mulmod_timing.o src/pk/ecc/ltc_ecc_points.o \
src/pk/ecc/ltc_ecc_projective_add_point.o src/pk/ecc/ltc_ecc_projective_dbl_point.o \
From 969c524747ba1bf497ae2397f03d2d3fce649718 Mon Sep 17 00:00:00 2001
From: Russ Williams <37781645+rmw42@users.noreply.github.com>
Date: Sat, 19 Jan 2019 19:45:20 +0000
Subject: [PATCH 2/2] RFC6979: implementation, tests, docs
---
doc/crypt.tex | 7 +-
src/headers/tomcrypt_pk.h | 1 +
src/pk/ecc/ecc_rfc6979_key.c | 143 +++++++++++++++++++++++++++++++++++
src/pk/ecc/ecc_sign_hash.c | 37 ++++++---
tests/ecc_test.c | 9 +++
5 files changed, 184 insertions(+), 13 deletions(-)
create mode 100644 src/pk/ecc/ecc_rfc6979_key.c
diff --git a/doc/crypt.tex b/doc/crypt.tex
index 2347062c9..89be85c45 100644
--- a/doc/crypt.tex
+++ b/doc/crypt.tex
@@ -5518,8 +5518,11 @@ \subsection{Signature Generation}
\end{verbatim}
This function will ECDSA sign the message digest stored in the array pointed to by \textit{in} of length \textit{inlen} octets. The signature
-will be stored in the array pointed to by \textit{out} of length \textit{outlen} octets. The function requires a properly seeded PRNG, and
-the ECC \textit{key} provided must be a private key.
+will be stored in the array pointed to by \textit{out} of length \textit{outlen} octets. The function requires that the ECC
+\textit{key} provided must be a private key.
+
+It requires a properly seeded PRNG for standard ECDSA, or if \textit{prng} is NULL and/or \textit{wprng} is less than zero,
+the private key and the message itself will be used to create a deterministic signature according to RFC6979.
\index{ecc\_sign\_hash\_rfc7518()}
\begin{verbatim}
diff --git a/src/headers/tomcrypt_pk.h b/src/headers/tomcrypt_pk.h
index fc196d01a..04394c473 100644
--- a/src/headers/tomcrypt_pk.h
+++ b/src/headers/tomcrypt_pk.h
@@ -265,6 +265,7 @@ int ecc_get_size(const ecc_key *key);
int ecc_find_curve(const char* name_or_oid, const ltc_ecc_curve** cu);
int ecc_set_curve(const ltc_ecc_curve *cu, ecc_key *key);
int ecc_generate_key(prng_state *prng, int wprng, ecc_key *key);
+int ecc_rfc6979_key(const ecc_key *priv, const unsigned char *in, int inlen, ecc_key *key);
int ecc_set_key(const unsigned char *in, unsigned long inlen, int type, ecc_key *key);
int ecc_get_key(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
int ecc_get_oid_str(char *out, unsigned long *outlen, const ecc_key *key);
diff --git a/src/pk/ecc/ecc_rfc6979_key.c b/src/pk/ecc/ecc_rfc6979_key.c
new file mode 100644
index 000000000..a13b9f8f0
--- /dev/null
+++ b/src/pk/ecc/ecc_rfc6979_key.c
@@ -0,0 +1,143 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+
+#include "tomcrypt_private.h"
+
+/**
+ @file ecc_rfc6979_key.c
+ ECC Crypto, Russ Williams
+*/
+
+#ifdef LTC_MECC
+#ifdef LTC_SHA256
+
+/**
+ Make deterministic ECC key using the RFC6979 method
+ @param priv [in] Private key for HMAC
+ @param in Message to sign for HMAC
+ @param inlen Length of the message
+ @param key [out] Newly created deterministic key
+ @return CRYPT_OK if successful, upon error all allocated memory will be freed
+*/
+int ecc_rfc6979_key(const ecc_key *priv, const unsigned char *in, int inlen, ecc_key *key)
+{
+ int err, hash, i;
+ unsigned char v[32], k[32], digest[32]; /* No way to determine hash so always use SHA256 */
+ unsigned char buffer[256];
+ unsigned long outlen, buflen, qlen;
+
+ LTC_ARGCHK(ltc_mp.name != NULL);
+ LTC_ARGCHK(key != NULL);
+ LTC_ARGCHK(key->dp.size > 0);
+
+ hash = find_hash("sha256");
+ if (hash == -1) {err = CRYPT_ERROR; goto error;}
+
+ /* Length, in bytes, of key */
+ i = mp_count_bits(key->dp.order);
+ qlen = (i+7) >> 3;
+
+ /* RFC6979 3.2b, set V */
+ for (i=0; i<32; i++) v[i] = 0x01;
+
+ /* RFC6979 3.2c, set K */
+ for (i=0; i<32; i++) k[i] = 0x00;
+
+ /* RFC6979 3.2d, set K to HMAC_K(V::0x00::priv::in) */
+ XMEMCPY(&buffer[0], v, 32);
+ buffer[32] = 0x00;
+ if ((err = mp_to_unsigned_bin(priv->k, &buffer[33]) != CRYPT_OK)) { goto error; }
+ XMEMCPY(&buffer[33+qlen], in, inlen);
+ buflen = 32 + 1 + qlen + inlen;
+ outlen = sizeof(digest);
+ if((err = hmac_memory(hash, k, 32, buffer, buflen, digest, &outlen)) != CRYPT_OK) { goto error; }
+ XMEMCPY(k, digest, 32);
+
+ /* RFC6979 3.2e, set V = HMAC_K(V) */
+ outlen = sizeof(digest);
+ if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
+ XMEMCPY(v, digest, 32);
+
+ /* RFC6979 3.2f, set K to HMAC_K(V::0x01::priv::in) */
+ XMEMCPY(&buffer[0], v, 32);
+ buffer[32] = 0x01;
+ if ((err = mp_to_unsigned_bin(priv->k, &buffer[33]) != CRYPT_OK)) { goto error; }
+ XMEMCPY(&buffer[33+qlen], in, inlen);
+ buflen = 32 + 1 + qlen + inlen;
+ outlen = sizeof(digest);
+ if((err = hmac_memory(hash, k, 32, buffer, buflen, digest, &outlen)) != CRYPT_OK) { goto error; }
+ XMEMCPY(k, digest, 32);
+
+ /* RFC6979 3.2g, set V = HMAC_K(V) */
+ outlen = sizeof(digest);
+ if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
+ XMEMCPY(v, digest, 32);
+
+ /* RFC6979 3.2h, generate and check key */
+ do {
+ /* concatenate hash bits into T */
+ buflen = 0;
+ while (buflen < qlen) {
+ outlen = sizeof(digest);
+ if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
+ XMEMCPY(v, digest, 32);
+ XMEMCPY(&buffer[buflen], v, 32);
+ buflen += 32;
+ }
+
+ /* key->k = bits2int(T) */
+ if ((err = mp_read_unsigned_bin(key->k, (unsigned char *)buffer, qlen)) != CRYPT_OK) { goto error; }
+
+ /* make the public key */
+ if ((err = ltc_mp.ecc_ptmul(key->k, &key->dp.base, &key->pubkey, key->dp.A, key->dp.prime, 1)) != CRYPT_OK) {
+ goto error;
+ }
+
+ /* check that k is in range [1,q-1] */
+ if (mp_cmp_d(key->k, 0) == LTC_MP_GT && mp_cmp(key->k, key->dp.order) == LTC_MP_LT) {
+ /* TODO: Check that pubkey.x != 0 (mod p) */
+
+ /* if we have a valid key, exit loop */
+ break;
+ } else {
+ /* K = HMAC_K(V::0x00) */
+ XMEMCPY(&buffer[0], v, 32);
+ buffer[32] = 0x00;
+ buflen = 32 + 1;
+ outlen = sizeof(digest);
+ if((err = hmac_memory(hash, k, 32, buffer, buflen, digest, &outlen)) != CRYPT_OK) { goto error; }
+ XMEMCPY(k, digest, 32);
+
+ /* V = HMAC_K(V) */
+ outlen = sizeof(digest);
+ if((err = hmac_memory(hash, k, 32, v, 32, digest, &outlen)) != CRYPT_OK) { goto error; }
+ XMEMCPY(v, digest, 32);
+
+ /* ... and try again! */
+ }
+ } while (1);
+
+ key->type = PK_PRIVATE;
+
+ /* success */
+ err = CRYPT_OK;
+ goto cleanup;
+
+error:
+ ecc_free(key);
+cleanup:
+ return err;
+}
+
+#endif
+#endif
+/* ref: $Format:%D$ */
+/* git commit: $Format:%H$ */
+/* commit time: $Format:%ai$ */
+
diff --git a/src/pk/ecc/ecc_sign_hash.c b/src/pk/ecc/ecc_sign_hash.c
index c7a808d8d..84780b685 100644
--- a/src/pk/ecc/ecc_sign_hash.c
+++ b/src/pk/ecc/ecc_sign_hash.c
@@ -22,8 +22,8 @@
@param inlen The length of the digest
@param out [out] The destination for the signature
@param outlen [in/out] The max size and resulting size of the signature
- @param prng An active PRNG state
- @param wprng The index of the PRNG you wish to use
+ @param prng An active PRNG state, NULL for RFC6979 deterministic signatures
+ @param wprng The index of the PRNG you wish to use, -1 for RFC6979 deterministic signatures
@param sigformat The format of the signature to generate (ecc_signature_type)
@param recid [out] The recovery ID for this signature (optional)
@param key A private ECC key
@@ -37,6 +37,7 @@ int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
ecc_key pubkey;
void *r, *s, *e, *p, *b;
int v = 0;
+ int blinding = 1;
int err, max_iterations = LTC_PK_MAX_RETRIES;
unsigned long pbits, pbytes, i, shift_right;
unsigned char ch, buf[MAXBLOCKSIZE];
@@ -79,7 +80,13 @@ int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
/* make up a key and export the public copy */
do {
if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK) { goto errnokey; }
- if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK) { goto errnokey; }
+
+ if (wprng < 0 || prng == NULL) {
+ blinding = 0;
+ if ((err = ecc_rfc6979_key(key, in, inlen, &pubkey)) != CRYPT_OK) { goto errnokey; }
+ } else {
+ if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK) { goto errnokey; }
+ }
/* find r = x1 mod n */
if ((err = mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; }
@@ -99,15 +106,23 @@ int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
if (mp_iszero(r) == LTC_MP_YES) {
ecc_free(&pubkey);
} else {
- if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK) { goto error; } /* b = blinding value */
/* find s = (e + xr)/k */
- if ((err = mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = kb */
- if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/kb */
- if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */
- if ((err = mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK) { goto error; } /* s = xr/kb */
- if ((err = mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK) { goto error; } /* e = e/kb */
- if ((err = mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e/kb + xr/kb */
- if ((err = mp_mulmod(s, b, p, s)) != CRYPT_OK) { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
+ if (blinding) {
+ if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK) { goto error; } /* b = blinding value */
+ if ((err = mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = kb */
+ if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/kb */
+ if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */
+ if ((err = mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK) { goto error; } /* s = xr/kb */
+ if ((err = mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK) { goto error; } /* e = e/kb */
+ if ((err = mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e/kb + xr/kb */
+ if ((err = mp_mulmod(s, b, p, s)) != CRYPT_OK) { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
+ } else {
+ if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/k */
+ if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */
+ if ((err = mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK) { goto error; } /* s = xr/k */
+ if ((err = mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK) { goto error; } /* e = e/k */
+ if ((err = mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = (e + xr)/k */
+ }
ecc_free(&pubkey);
if (mp_iszero(s) == LTC_MP_NO) {
break;
diff --git a/tests/ecc_test.c b/tests/ecc_test.c
index 880ded55b..57801335f 100644
--- a/tests/ecc_test.c
+++ b/tests/ecc_test.c
@@ -605,6 +605,15 @@ static int _ecc_new_api(void)
}
#endif
+#ifdef LTC_SHA256
+ /* test RFC6979 signature */
+ len = sizeof(buf);
+ DO(ecc_sign_hash(data16, 16, buf, &len, NULL, -1, &privkey));
+ stat = 0;
+ DO(ecc_verify_hash(buf, len, data16, 16, &stat, &pubkey));
+ if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
+#endif
+
/* test encryption */
len = sizeof(buf);
DO(ecc_encrypt_key(data16, 16, buf, &len, &yarrow_prng, find_prng("yarrow"), find_hash("sha256"), &pubkey));