Browse Source

Move RFC6979 hash alg to a new ecc signature options struct

Fixes #700

Signed-off-by: Steffen Jaeckel <[email protected]>
Steffen Jaeckel 2 months ago
parent
commit
35a4a5fc1b

+ 8 - 4
demos/timing.c

@@ -872,7 +872,7 @@ static void time_ecc(void)
    unsigned char buf[2][256] = { 0 };
    unsigned long i, w, x, y, z;
    int           err, stat;
-   static unsigned long sizes[] = {
+   const unsigned long sizes[] = {
 #ifdef LTC_ECC_SECP112R1
 112/8,
 #endif
@@ -898,6 +898,11 @@ static void time_ecc(void)
 521/8,
 #endif
 100000};
+   ltc_ecc_sig_opts sig_opts = {
+                                .type = LTC_ECCSIG_RFC7518,
+                                .prng = &yarrow_prng,
+                                .wprng = find_prng ("yarrow")
+   };
 
    if (ltc_mp.name == NULL) return;
 
@@ -969,8 +974,7 @@ static void time_ecc(void)
           t_start();
           t1 = t_read();
           z = sizeof(buf[1]);
-          if ((err = ecc_sign_hash(buf[0], 20, buf[1], &z, &yarrow_prng,
-                                   find_prng("yarrow"), &key)) != CRYPT_OK) {
+          if ((err = ecc_sign_hash_v2(buf[0], 20, buf[1], &z, &sig_opts, &key)) != CRYPT_OK) {
               fprintf(stderr, "\n\necc_sign_hash says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
               exit(EXIT_FAILURE);
            }
@@ -988,7 +992,7 @@ static void time_ecc(void)
        for (y = 0; y < 256; y++) {
           t_start();
           t1 = t_read();
-          if ((err = ecc_verify_hash(buf[1], z, buf[0], 20, &stat, &key)) != CRYPT_OK) {
+          if ((err = ecc_verify_hash_v2(buf[1], z, buf[0], 20, &sig_opts, &stat, &key)) != CRYPT_OK) {
               fprintf(stderr, "\n\necc_verify_hash says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
               exit(EXIT_FAILURE);
           }

+ 80 - 56
src/headers/tomcrypt_pk.h

@@ -281,20 +281,10 @@ typedef struct {
 
     /** The private key */
     void *k;
-
-    /** The hash algorithm to use when creating a signature.
-     *  Setting this will enable RFC6979 compatible signature generation.
-     *  The macro ECC_SET_RFC6979_HASH_ALG() is provided as a helper
-     *  to set this.*/
-    const char *rfc6979_hash_alg;
 } ecc_key;
 
-#define ECC_SET_RFC6979_HASH_ALG(key, alg) do { \
-   (key)->rfc6979_hash_alg = (alg);             \
-} while(0)
-
 /** Formats of ECC signatures */
-typedef enum ecc_signature_type_ {
+typedef enum ecc_signature_type {
    /* ASN.1 encoded, ANSI X9.62 */
    LTC_ECCSIG_ANSIX962   = 0x0,
    /* raw R, S values */
@@ -305,6 +295,28 @@ typedef enum ecc_signature_type_ {
    LTC_ECCSIG_RFC5656    = 0x3,
 } ecc_signature_type;
 
+typedef struct ltc_ecc_sig_opts {
+   /** Signature type */
+   ecc_signature_type type;
+   /** The PRNG to use.
+    *  This must be set in case deterministic signature generation
+    *  according to RFC6979 is not enabled.
+    */
+   prng_state *prng;
+   int wprng;
+
+   /** Enable generation of a recovery ID.
+    *  This must be set in case one requires the recovery ID of a
+    *  signature operation.
+    */
+   int *recid;
+
+   /** The hash algorithm to use when creating a signature.
+    *  Setting this will enable RFC6979 compatible signature generation.
+    */
+   const char *rfc6979_hash_alg;
+} ltc_ecc_sig_opts;
+
 /** the ECC params provided */
 extern const ltc_ecc_curve ltc_ecc_curves[];
 
@@ -340,6 +352,21 @@ int  ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_k
 int  ecc_shared_secret(const ecc_key *private_key, const ecc_key *public_key,
                        unsigned char *out, unsigned long *outlen);
 
+int ecc_sign_hash_v2(const unsigned char    *in,
+                           unsigned long     inlen,
+                           unsigned char    *out,
+                           unsigned long    *outlen,
+                           ltc_ecc_sig_opts *opts,
+                     const       ecc_key    *key);
+
+int ecc_verify_hash_v2(const unsigned char *sig,
+                             unsigned long  siglen,
+                       const unsigned char *hash,
+                             unsigned long  hashlen,
+                          ltc_ecc_sig_opts *opts,
+                                       int *stat,
+                       const       ecc_key *key);
+
 #if defined(LTC_DER)
 int  ecc_encrypt_key(const unsigned char *in,   unsigned long inlen,
                            unsigned char *out,  unsigned long *outlen,
@@ -349,7 +376,42 @@ int  ecc_encrypt_key(const unsigned char *in,   unsigned long inlen,
 int  ecc_decrypt_key(const unsigned char *in,  unsigned long  inlen,
                            unsigned char *out, unsigned long *outlen,
                            const ecc_key *key);
-
+#endif /* LTC_DER */
+
+#define ltc_ecc_sign_hash(i, il, o, ol, p, wp, k)         \
+      ecc_sign_hash_v2(i, il, o, ol,                      \
+                       &(ltc_ecc_sig_opts){               \
+                           .type = LTC_ECCSIG_ANSIX962,   \
+                           .prng = p,                     \
+                           .wprng = wp,                   \
+                        }, k)
+#define ltc_ecc_sign_hash_rfc7518(i, il, o, ol, p, wp, k)    \
+      ecc_sign_hash_v2(i, il, o, ol,                         \
+                       &(ltc_ecc_sig_opts){                  \
+                           .type = LTC_ECCSIG_RFC7518,       \
+                           .prng = p,                        \
+                           .wprng = wp,                      \
+                        }, k)
+
+#define ltc_ecc_verify_hash(s, sl, h, hl, st, k)          \
+      ecc_verify_hash_v2(s, sl, h, hl,                    \
+                         &(ltc_ecc_sig_opts){             \
+                             .type = LTC_ECCSIG_ANSIX962, \
+                          }, st, k)
+#define ltc_ecc_verify_hash_rfc7518(s, sl, h, hl, st, k)     \
+      ecc_verify_hash_v2(s, sl, h, hl,                       \
+                         &(ltc_ecc_sig_opts){                \
+                             .type = LTC_ECCSIG_RFC7518,     \
+                          }, st, k)
+
+#ifdef LTC_NO_DEPRECATED_APIS
+#define ecc_sign_hash ltc_ecc_sign_hash
+#define ecc_verify_hash ltc_ecc_verify_hash
+#define ecc_sign_hash_rfc7518 ltc_ecc_sign_hash_rfc7518
+#define ecc_verify_hash_rfc7518 ltc_ecc_verify_hash_rfc7518
+#else /* LTC_NO_DEPRECATED_APIS */
+#if defined(LTC_DER)
+LTC_DEPRECATED(ecc_sign_hash_v2)
 int ecc_sign_hash(const unsigned char *in,
                         unsigned long  inlen,
                         unsigned char *out,
@@ -358,14 +420,16 @@ int ecc_sign_hash(const unsigned char *in,
                                   int  wprng,
                   const       ecc_key *key);
 
+LTC_DEPRECATED(ecc_verify_hash_v2)
 int ecc_verify_hash(const unsigned char *sig,
                           unsigned long  siglen,
                     const unsigned char *hash,
                           unsigned long  hashlen,
                                     int *stat,
                     const       ecc_key *key);
-#endif
+#endif /* LTC_DER */
 
+LTC_DEPRECATED(ecc_sign_hash_v2)
 int ecc_sign_hash_rfc7518(const unsigned char *in,
                                 unsigned long  inlen,
                                 unsigned char *out,
@@ -374,60 +438,20 @@ int ecc_sign_hash_rfc7518(const unsigned char *in,
                                           int  wprng,
                           const       ecc_key *key);
 
-int ecc_sign_hash_rfc7518_ex(const unsigned char *in,
-                                   unsigned long  inlen,
-                                   unsigned char *out,
-                                   unsigned long *outlen,
-                                      prng_state *prng,
-                                             int  wprng,
-                                             int *recid,
-                             const       ecc_key *key);
-
+LTC_DEPRECATED(ecc_verify_hash_v2)
 int ecc_verify_hash_rfc7518(const unsigned char *sig,
                                   unsigned long  siglen,
                             const unsigned char *hash,
                                   unsigned long  hashlen,
                                             int *stat,
                             const       ecc_key *key);
-
-#if defined(LTC_SSH)
-int ecc_sign_hash_rfc5656(const unsigned char *in,
-                                unsigned long  inlen,
-                                unsigned char *out,
-                                unsigned long *outlen,
-                                   prng_state *prng,
-                                          int  wprng,
-                          const       ecc_key *key);
-
-int ecc_verify_hash_rfc5656(const unsigned char *sig,
-                                  unsigned long  siglen,
-                            const unsigned char *hash,
-                                  unsigned long  hashlen,
-                                            int *stat,
-                            const       ecc_key *key);
-#endif
-
-int ecc_sign_hash_eth27(const unsigned char *in,
-                              unsigned long  inlen,
-                              unsigned char *out,
-                              unsigned long *outlen,
-                                 prng_state *prng,
-                                        int  wprng,
-                        const       ecc_key *key);
-
-int ecc_verify_hash_eth27(const unsigned char *sig,
-                                unsigned long  siglen,
-                          const unsigned char *hash,
-                                unsigned long  hashlen,
-                                          int *stat,
-                          const       ecc_key *key);
+#endif /* LTC_NO_DEPRECATED_APIS */
 
 int  ecc_recover_key(const unsigned char *sig,
                            unsigned long  siglen,
                      const unsigned char *hash,
                            unsigned long  hashlen,
-                                     int  recid,
-                      ecc_signature_type  sigformat,
+                        ltc_ecc_sig_opts *opts,
                                  ecc_key *key);
 
 #endif

+ 54 - 3
src/headers/tomcrypt_private.h

@@ -441,15 +441,66 @@ int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_ke
 int ecc_import_with_curve(const unsigned char *in, unsigned long inlen, int type, ecc_key *key);
 int ecc_import_with_oid(const unsigned char *in, unsigned long inlen, unsigned long *oid, unsigned long oid_len, int type, ecc_key *key);
 
+int ecc_sign_hash_rfc7518_internal(const unsigned char    *in,
+                                   unsigned long     inlen,
+                                   unsigned char    *out,
+                                   unsigned long    *outlen,
+                                   ltc_ecc_sig_opts *opts,
+                             const       ecc_key    *key);
+
+int ecc_verify_hash_rfc7518_internal(const unsigned char *sig,
+                                  unsigned long  siglen,
+                            const unsigned char *hash,
+                                  unsigned long  hashlen,
+                                            int *stat,
+                            const       ecc_key *key);
+
+#ifdef LTC_DER
+int ecc_verify_hash_x962(const unsigned char *sig,
+                               unsigned long  siglen,
+                         const unsigned char *hash,
+                               unsigned long  hashlen,
+                                         int *stat,
+                         const       ecc_key *key);
+int ecc_sign_hash_x962(const unsigned char    *in,
+                             unsigned long     inlen,
+                             unsigned char    *out,
+                             unsigned long    *outlen,
+                             ltc_ecc_sig_opts *opts,
+                       const       ecc_key    *key);
+#endif
+
+#if defined(LTC_SSH)
+int ecc_sign_hash_rfc5656(const unsigned char    *in,
+                                unsigned long     inlen,
+                                unsigned char    *out,
+                                unsigned long    *outlen,
+                                ltc_ecc_sig_opts *opts,
+                          const       ecc_key    *key);
+
+int ecc_verify_hash_rfc5656(const unsigned char *sig,
+                                  unsigned long  siglen,
+                            const unsigned char *hash,
+                                  unsigned long  hashlen,
+                                            int *stat,
+                            const       ecc_key *key);
+#endif
+
+int ecc_sign_hash_eth27(const unsigned char    *in,  unsigned long     inlen,
+                              unsigned char    *out, unsigned long    *outlen,
+                              ltc_ecc_sig_opts *opts, const       ecc_key    *key);
+
+int ecc_verify_hash_eth27(const unsigned char *sig,        unsigned long  siglen,
+                          const unsigned char *hash,       unsigned long  hashlen,
+                                          int *stat, const       ecc_key *key);
 int ecc_sign_hash_internal(const unsigned char *in,  unsigned long inlen,
-                           void *r, void *s, prng_state *prng, int wprng,
-                           int *recid, const ecc_key *key);
+                           void *r, void *s, ltc_ecc_sig_opts *opts, const ecc_key *key);
 
 int ecc_verify_hash_internal(void *r, void *s,
                              const unsigned char *hash, unsigned long hashlen,
                              int *stat, const ecc_key *key);
 
-int ecc_rfc6979_key(const ecc_key *priv, const unsigned char *in, unsigned long inlen, ecc_key *key);
+int ecc_rfc6979_key(const ecc_key *priv, const unsigned char *in, unsigned long inlen, const char *rfc6979_hash_alg, ecc_key *key);
 
 #ifdef LTC_SSH
 int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);

+ 82 - 0
src/misc/deprecated.c

@@ -0,0 +1,82 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifndef LTC_NO_DEPRECATED_APIS
+
+#ifdef LTC_MECC
+/**
+  Sign a message digest (ANSI X9.62 format)
+  @param in        The message digest to sign
+  @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 key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
+                        unsigned char *out, unsigned long *outlen,
+                        prng_state *prng, int  wprng, const ecc_key *key)
+{
+   return ltc_ecc_sign_hash(in, inlen, out, outlen, prng, wprng, key);
+}
+
+/**
+   Verify an ECC signature (ANSI X9.62 format)
+   @param sig         The signature to verify
+   @param siglen      The length of the signature (octets)
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        [out] Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return CRYPT_OK if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash(const unsigned char *sig,
+                          unsigned long  siglen,
+                    const unsigned char *hash,
+                          unsigned long  hashlen,
+                                    int *stat,
+                    const       ecc_key *key)
+{
+   return ltc_ecc_verify_hash(sig, siglen, hash, hashlen, stat, key);
+}
+
+/**
+  Sign a message digest (RFC7518 format)
+  @param in        The message digest to sign
+  @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 opts      The signature options that shall be applied
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_rfc7518(const unsigned char *in,  unsigned long inlen,
+                          unsigned char *out, unsigned long *outlen,
+                          prng_state *prng, int  wprng, const ecc_key *key)
+{
+   return ltc_ecc_sign_hash_rfc7518(in, inlen, out, outlen, prng, wprng, key);
+}
+
+/**
+   Verify an ECC signature (RFC7518 format)
+   @param sig         The signature to verify
+   @param siglen      The length of the signature (octets)
+   @param hash        The hash (message digest) that was signed
+   @param hashlen     The length of the hash (octets)
+   @param stat        [out] Result of signature, 1==valid, 0==invalid
+   @param key         The corresponding public ECC key
+   @return CRYPT_OK if successful (even if the signature is not valid)
+*/
+int ecc_verify_hash_rfc7518(const unsigned char *sig,  unsigned long siglen,
+                            const unsigned char *hash, unsigned long hashlen,
+                            int *stat, const ecc_key *key)
+{
+   return ltc_ecc_verify_hash_rfc7518(sig, siglen, hash, hashlen, stat, key);
+}
+#endif /* LTC_MECC */
+
+#endif /* LTC_NO_DEPRECATED_APIS */

+ 0 - 1
src/pk/ecc/ecc_make_key.c

@@ -59,7 +59,6 @@ int ecc_generate_key(prng_state *prng, int wprng, ecc_key *key)
       goto error;
    }
    key->type = PK_PRIVATE;
-   key->rfc6979_hash_alg = NULL;
 
    /* success */
    err = CRYPT_OK;

+ 8 - 6
src/pk/ecc/ecc_recover_key.c

@@ -23,20 +23,21 @@
 */
 int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
                     const unsigned char *hash, unsigned long hashlen,
-                    int recid, ecc_signature_type sigformat, ecc_key *key)
+                    ltc_ecc_sig_opts *opts, ecc_key *key)
 {
    ecc_point     *mG = NULL, *mQ = NULL, *mR = NULL;
    void          *p, *m, *a, *b;
    void          *r, *s, *v, *w, *t1, *t2, *u1, *u2, *v1, *v2, *e, *x, *y, *a_plus3;
    void          *mu = NULL, *ma = NULL;
    void          *mp = NULL;
-   int           err;
+   int           err, recid;
    unsigned long pbits, pbytes, i, shift_right;
    unsigned char ch, buf[MAXBLOCKSIZE];
 
    LTC_ARGCHK(sig  != NULL);
    LTC_ARGCHK(hash != NULL);
    LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(opts != NULL);
 
    /* BEWARE: requires sqrtmod_prime */
    if (ltc_mp.sqrtmod_prime == NULL) {
@@ -64,8 +65,9 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
       err = CRYPT_MEM;
       goto error;
    }
+   recid = (opts->recid != NULL) ? *(opts->recid) : -1;
 
-   if (sigformat == LTC_ECCSIG_RFC7518) {
+   if (opts->type == LTC_ECCSIG_RFC7518) {
       /* RFC7518 format - raw (r,s) */
       i = ltc_mp_unsigned_bin_size(key->dp.order);
       if (siglen != (2*i)) {
@@ -75,7 +77,7 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
       if ((err = ltc_mp_read_unsigned_bin(r, sig,   i)) != CRYPT_OK)                                    { goto error; }
       if ((err = ltc_mp_read_unsigned_bin(s, sig+i, i)) != CRYPT_OK)                                    { goto error; }
    }
-   else if (sigformat == LTC_ECCSIG_ETH27) {
+   else if (opts->type == LTC_ECCSIG_ETH27) {
       /* Ethereum (v,r,s) format */
       if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
          /* Only valid for secp256k1 - OID 1.3.132.0.10 */
@@ -97,7 +99,7 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
       if ((err = ltc_mp_read_unsigned_bin(s, sig+32, 32)) != CRYPT_OK)                                  { goto error; }
    }
 #ifdef LTC_DER
-   else if (sigformat == LTC_ECCSIG_ANSIX962) {
+   else if (opts->type == LTC_ECCSIG_ANSIX962) {
          /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
          if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
                                                  LTC_ASN1_INTEGER, 1UL, r,
@@ -106,7 +108,7 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
    }
 #endif
 #ifdef LTC_SSH
-   else if (sigformat == LTC_ECCSIG_RFC5656) {
+   else if (opts->type == LTC_ECCSIG_RFC5656) {
       char name[64], name2[64];
       unsigned long namelen = sizeof(name);
       unsigned long name2len = sizeof(name2);

+ 3 - 3
src/pk/ecc/ecc_rfc6979_key.c

@@ -19,7 +19,7 @@
   @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, unsigned long inlen, ecc_key *key)
+int ecc_rfc6979_key(const ecc_key *priv, const unsigned char *in, unsigned long inlen, const char *rfc6979_hash_alg, ecc_key *key)
 {
    int            err, hash = -1;
    unsigned char  v[MAXBLOCKSIZE], k[MAXBLOCKSIZE];
@@ -32,10 +32,10 @@ int ecc_rfc6979_key(const ecc_key *priv, const unsigned char *in, unsigned long
    LTC_ARGCHK(key         != NULL);
    LTC_ARGCHK(key->dp.size > 0);
 
-   if (priv->rfc6979_hash_alg == NULL) {
+   if (rfc6979_hash_alg == NULL) {
       return CRYPT_INVALID_ARG;
    }
-   hash = find_hash(priv->rfc6979_hash_alg);
+   hash = find_hash(rfc6979_hash_alg);
    if ((err = hash_is_valid(hash)) != CRYPT_OK) {
       return err;
    }

+ 0 - 2
src/pk/ecc/ecc_set_curve.c

@@ -19,8 +19,6 @@ int ecc_set_curve(const ltc_ecc_curve *cu, ecc_key *key)
       return err;
    }
 
-   key->rfc6979_hash_alg = NULL;
-
    /* A, B, order, prime, Gx, Gy */
    if ((err = ltc_mp_read_radix(key->dp.prime, cu->prime, 16)) != CRYPT_OK) { goto error; }
    if ((err = ltc_mp_read_radix(key->dp.order, cu->order, 16)) != CRYPT_OK) { goto error; }

+ 0 - 1
src/pk/ecc/ecc_set_key.c

@@ -46,7 +46,6 @@ int ecc_set_key(const unsigned char *in, unsigned long inlen, int type, ecc_key
    }
 
    key->type = type;
-   key->rfc6979_hash_alg = NULL;
    return CRYPT_OK;
 
 error:

+ 31 - 23
src/pk/ecc/ecc_sign_hash.c

@@ -3,7 +3,25 @@
 
 #include "tomcrypt_private.h"
 
-#if defined(LTC_MECC) && defined(LTC_DER)
+#if defined(LTC_MECC)
+
+typedef int (*ecc_sign_fn)(const unsigned char    *in,
+                                 unsigned long     inlen,
+                                 unsigned char    *out,
+                                 unsigned long    *outlen,
+                                 ltc_ecc_sig_opts *opts,
+                           const       ecc_key    *key);
+
+static const ecc_sign_fn s_ecc_sign_hash[] = {
+#ifdef LTC_DER
+                                [LTC_ECCSIG_ANSIX962] = ecc_sign_hash_x962,
+#endif
+                                [LTC_ECCSIG_RFC7518] = ecc_sign_hash_rfc7518_internal,
+                                [LTC_ECCSIG_ETH27] = ecc_sign_hash_eth27,
+#ifdef LTC_SSH
+                                [LTC_ECCSIG_RFC5656] = ecc_sign_hash_rfc5656,
+#endif
+};
 
 /**
   Sign a message digest (ANSI X9.62 format)
@@ -11,32 +29,22 @@
   @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 opts      The signature options that shall be applied
   @param key       A private ECC key
   @return CRYPT_OK if successful
 */
-int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
-                  unsigned char *out, unsigned long *outlen,
-                  prng_state *prng, int wprng, const ecc_key *key)
+int ecc_sign_hash_v2(const unsigned char    *in,
+                        unsigned long     inlen,
+                        unsigned char    *out,
+                        unsigned long    *outlen,
+                        ltc_ecc_sig_opts *opts,
+                  const       ecc_key    *key)
 {
-   int err;
-   void *r, *s;
-
-   LTC_ARGCHK(out    != NULL);
-   LTC_ARGCHK(outlen != NULL);
-
-   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
-   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, NULL, key)) != CRYPT_OK) goto error;
-
-   /* store as ASN.1 SEQUENCE { r, s -- integer } */
-   err = der_encode_sequence_multi(out, outlen,
-                                   LTC_ASN1_INTEGER, 1UL, r,
-                                   LTC_ASN1_INTEGER, 1UL, s,
-                                   LTC_ASN1_EOL, 0UL, NULL);
-error:
-   ltc_mp_deinit_multi(r, s, LTC_NULL);
-   return err;
+   if (opts->type < 0 || opts->type >= LTC_ARRAY_SIZE(s_ecc_sign_hash))
+      return CRYPT_PK_INVALID_TYPE;
+   if (s_ecc_sign_hash[opts->type] == NULL)
+      return CRYPT_PK_INVALID_TYPE;
+   return s_ecc_sign_hash[opts->type](in, inlen, out, outlen, opts, key);
 }
 
 #endif

+ 9 - 5
src/pk/ecc/ecc_sign_hash_eth27.c

@@ -11,14 +11,13 @@
   @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 opts      The signature options that shall be applied
   @param key       A private ECC key
   @return CRYPT_OK if successful
 */
 int ecc_sign_hash_eth27(const unsigned char *in,  unsigned long inlen,
                         unsigned char *out, unsigned long *outlen,
-                        prng_state *prng, int wprng, const ecc_key *key)
+                        ltc_ecc_sig_opts *opts, const ecc_key *key)
 {
    int err, recid;
    void *r, *s;
@@ -26,6 +25,7 @@ int ecc_sign_hash_eth27(const unsigned char *in,  unsigned long inlen,
 
    LTC_ARGCHK(out    != NULL);
    LTC_ARGCHK(outlen != NULL);
+   LTC_ARGCHK(opts   != NULL);
    LTC_ARGCHK(key    != NULL);
 
    /* Only valid for secp256k1 - OID 1.3.132.0.10 */
@@ -38,7 +38,9 @@ int ecc_sign_hash_eth27(const unsigned char *in,  unsigned long inlen,
    }
 
    if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
-   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, &recid, key)) != CRYPT_OK) goto error;
+   if (opts->recid == NULL)
+      opts->recid = &recid;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, opts, key)) != CRYPT_OK) goto error;
 
    zeromem(out, 65);
    *outlen = 65;
@@ -46,10 +48,12 @@ int ecc_sign_hash_eth27(const unsigned char *in,  unsigned long inlen,
    if ((err = ltc_mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) goto error;
    i = ltc_mp_unsigned_bin_size(s);
    if ((err = ltc_mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) goto error;
-   out[64] = (unsigned char)(recid + 27); /* Recovery ID is 27/28 for Ethereum */
+   out[64] = (unsigned char)(*(opts->recid) + 27); /* Recovery ID is 27/28 for Ethereum */
    err = CRYPT_OK;
 
 error:
+   if (opts->recid == &recid)
+      opts->recid = NULL;
    ltc_mp_deinit_multi(r, s, LTC_NULL);
    return err;
 }

+ 8 - 8
src/pk/ecc/ecc_sign_hash_internal.c

@@ -6,8 +6,7 @@
 #ifdef LTC_MECC
 
 int ecc_sign_hash_internal(const unsigned char *in,  unsigned long inlen,
-                           void *r, void *s, prng_state *prng, int wprng,
-                           int *recid, const ecc_key *key)
+                           void *r, void *s, ltc_ecc_sig_opts *opts, const ecc_key *key)
 {
    ecc_key       pubkey;
    void          *e, *p, *b;
@@ -19,6 +18,7 @@ int ecc_sign_hash_internal(const unsigned char *in,  unsigned long inlen,
    LTC_ARGCHK(r      != NULL);
    LTC_ARGCHK(s      != NULL);
    LTC_ARGCHK(in     != NULL);
+   LTC_ARGCHK(opts   != NULL);
    LTC_ARGCHK(key    != NULL);
 
    /* is this a private key? */
@@ -58,16 +58,16 @@ int ecc_sign_hash_internal(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 (key->rfc6979_hash_alg != NULL) {
-         if ((err = ecc_rfc6979_key(key, in, inlen, &pubkey)) != CRYPT_OK)     { goto errnokey; }
+      if (opts->rfc6979_hash_alg != NULL) {
+         if ((err = ecc_rfc6979_key(key, in, inlen, opts->rfc6979_hash_alg, &pubkey)) != CRYPT_OK)     { goto errnokey; }
       } else {
-         if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK)       { goto errnokey; }
+         if ((err = ecc_generate_key(opts->prng, opts->wprng, &pubkey)) != CRYPT_OK)       { goto errnokey; }
       }
 
       /* find r = x1 mod n */
       if ((err = ltc_mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK)               { goto error; }
 
-      if (recid) {
+      if (opts->recid) {
          /* find recovery ID (if needed) */
          v = 0;
          if (ltc_mp_copy(pubkey.pubkey.x, s) != CRYPT_OK)                      { goto error; }
@@ -82,7 +82,7 @@ int ecc_sign_hash_internal(const unsigned char *in,  unsigned long inlen,
       if (ltc_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 */
+         if ((err = rand_bn_upto(b, p, opts->prng, opts->wprng)) != CRYPT_OK)              { goto error; } /* b = blinding value */
          /* find s = (e + xr)/k */
          if ((err = ltc_mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK)      { goto error; } /* k = kb */
          if ((err = ltc_mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK)         { goto error; } /* k = 1/kb */
@@ -102,7 +102,7 @@ int ecc_sign_hash_internal(const unsigned char *in,  unsigned long inlen,
       goto errnokey;
    }
 
-   if (recid) *recid = v;
+   if (opts->recid) *opts->recid = v;
 
    goto errnokey;
 error:

+ 3 - 4
src/pk/ecc/ecc_sign_hash_rfc5656.c

@@ -11,14 +11,13 @@
   @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 opts      The signature options that shall be applied
   @param key       A private ECC key
   @return CRYPT_OK if successful
 */
 int ecc_sign_hash_rfc5656(const unsigned char *in,  unsigned long inlen,
                           unsigned char *out, unsigned long *outlen,
-                          prng_state *prng, int wprng, const ecc_key *key)
+                          ltc_ecc_sig_opts *opts, const ecc_key *key)
 {
    int err;
    void *r, *s;
@@ -32,7 +31,7 @@ int ecc_sign_hash_rfc5656(const unsigned char *in,  unsigned long inlen,
    if ((err = ecc_ssh_ecdsa_encode_name(name, &namelen, key)) != CRYPT_OK) return err;
 
    if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
-   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, NULL, key)) != CRYPT_OK) goto error;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, opts, key)) != CRYPT_OK) goto error;
 
    /* Store as SSH data sequence, per RFC4251 */
    err = ssh_encode_sequence_multi(out, outlen,

+ 5 - 26
src/pk/ecc/ecc_sign_hash_rfc7518.c

@@ -11,16 +11,13 @@
   @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 recid     [out] Recovery ID
+  @param opts      The signature options that shall be applied
   @param key       A private ECC key
   @return CRYPT_OK if successful
 */
-int ecc_sign_hash_rfc7518_ex(const unsigned char *in,  unsigned long inlen,
-                             unsigned char *out, unsigned long *outlen,
-                             prng_state *prng, int wprng,
-                             int *recid, const ecc_key *key)
+int ecc_sign_hash_rfc7518_internal(const unsigned char *in,  unsigned long inlen,
+                                         unsigned char *out, unsigned long *outlen,
+                                         ltc_ecc_sig_opts *opts, const ecc_key *key)
 {
    int err;
    void *r, *s;
@@ -38,7 +35,7 @@ int ecc_sign_hash_rfc7518_ex(const unsigned char *in,  unsigned long inlen,
    }
 
    if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
-   if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, recid, key)) != CRYPT_OK) goto error;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, opts, key)) != CRYPT_OK) goto error;
 
    zeromem(out, 2 * pbytes);
    *outlen = 2 * pbytes;
@@ -52,22 +49,4 @@ error:
    return err;
 }
 
-/**
-  Sign a message digest (RFC7518 format)
-  @param in        The message digest to sign
-  @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 key       A private ECC key
-  @return CRYPT_OK if successful
-*/
-int ecc_sign_hash_rfc7518(const unsigned char *in,  unsigned long inlen,
-                          unsigned char *out, unsigned long *outlen,
-                          prng_state *prng, int wprng, const ecc_key *key)
-{
-   return ecc_sign_hash_rfc7518_ex(in, inlen, out, outlen, prng, wprng, NULL, key);
-}
-
 #endif

+ 44 - 0
src/pk/ecc/ecc_sign_hash_x962.c

@@ -0,0 +1,44 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#if defined(LTC_MECC) && defined(LTC_DER)
+
+/**
+  Sign a message digest (ANSI X9.62 format)
+  @param in        The message digest to sign
+  @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 opts      The signature options that shall be applied
+  @param key       A private ECC key
+  @return CRYPT_OK if successful
+*/
+int ecc_sign_hash_x962(const unsigned char    *in,
+                             unsigned long     inlen,
+                             unsigned char    *out,
+                             unsigned long    *outlen,
+                             ltc_ecc_sig_opts *opts,
+                       const       ecc_key    *key)
+{
+   int err;
+   void *r, *s;
+
+   LTC_ARGCHK(out    != NULL);
+   LTC_ARGCHK(outlen != NULL);
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ecc_sign_hash_internal(in, inlen, r, s, opts, key)) != CRYPT_OK) goto error;
+
+   /* store as ASN.1 SEQUENCE { r, s -- integer } */
+   err = der_encode_sequence_multi(out, outlen,
+                                   LTC_ASN1_INTEGER, 1UL, r,
+                                   LTC_ASN1_INTEGER, 1UL, s,
+                                   LTC_ASN1_EOL, 0UL, NULL);
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 31 - 22
src/pk/ecc/ecc_verify_hash.c

@@ -10,8 +10,26 @@
   ECC Crypto, Tom St Denis
 */
 
+typedef int (*ecc_verify_fn)(const unsigned char *sig,
+                                   unsigned long  siglen,
+                             const unsigned char *hash,
+                                   unsigned long  hashlen,
+                                             int *stat,
+                             const       ecc_key *key);
+
+static const ecc_verify_fn s_ecc_verify_hash[] = {
+#ifdef LTC_DER
+                                [LTC_ECCSIG_ANSIX962] = ecc_verify_hash_x962,
+#endif
+                                [LTC_ECCSIG_RFC7518] = ecc_verify_hash_rfc7518_internal,
+                                [LTC_ECCSIG_ETH27] = ecc_verify_hash_eth27,
+#ifdef LTC_SSH
+                                [LTC_ECCSIG_RFC5656] = ecc_verify_hash_rfc5656,
+#endif
+};
+
 /**
-   Verify an ECC signature (ANSI X9.62 format)
+   Verify an ECC signature
    @param sig         The signature to verify
    @param siglen      The length of the signature (octets)
    @param hash        The hash (message digest) that was signed
@@ -20,28 +38,19 @@
    @param key         The corresponding public ECC key
    @return CRYPT_OK if successful (even if the signature is not valid)
 */
-int ecc_verify_hash(const unsigned char *sig,  unsigned long siglen,
-                    const unsigned char *hash, unsigned long hashlen,
-                    int *stat, const ecc_key *key)
+int ecc_verify_hash_v2(const unsigned char *sig,
+                             unsigned long  siglen,
+                       const unsigned char *hash,
+                             unsigned long  hashlen,
+                          ltc_ecc_sig_opts *opts,
+                                       int *stat,
+                       const       ecc_key *key)
 {
-   void *r, *s;
-   int err;
-
-   LTC_ARGCHK(sig != NULL);
-
-   if ((err = ltc_mp_init_multi(&r, &s, NULL)) != CRYPT_OK) return err;
-
-   /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
-   if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
-                                     LTC_ASN1_INTEGER, 1UL, r,
-                                     LTC_ASN1_INTEGER, 1UL, s,
-                                     LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK)                         { goto error; }
-
-   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
-
-error:
-   ltc_mp_deinit_multi(r, s, LTC_NULL);
-   return err;
+   if (opts->type < 0 || opts->type >= LTC_ARRAY_SIZE(s_ecc_verify_hash))
+      return CRYPT_PK_INVALID_TYPE;
+   if (s_ecc_verify_hash[opts->type] == NULL)
+      return CRYPT_PK_INVALID_TYPE;
+   return s_ecc_verify_hash[opts->type](sig, siglen, hash, hashlen, stat, key);
 }
 
 #endif

+ 1 - 1
src/pk/ecc/ecc_verify_hash_eth27.c

@@ -6,7 +6,7 @@
 #ifdef LTC_MECC
 
 /**
-  @file ecc_verify_hash.c
+  @file ecc_verify_hash_eth27.c
   ECC Crypto, Tom St Denis
 */
 

+ 2 - 12
src/pk/ecc/ecc_verify_hash_rfc7518.c

@@ -6,21 +6,11 @@
 #ifdef LTC_MECC
 
 /**
-  @file ecc_verify_hash.c
+  @file ecc_verify_hash_rfc7518.c
   ECC Crypto, Tom St Denis
 */
 
-/**
-   Verify an ECC signature (RFC7518 format)
-   @param sig         The signature to verify
-   @param siglen      The length of the signature (octets)
-   @param hash        The hash (message digest) that was signed
-   @param hashlen     The length of the hash (octets)
-   @param stat        [out] Result of signature, 1==valid, 0==invalid
-   @param key         The corresponding public ECC key
-   @return CRYPT_OK if successful (even if the signature is not valid)
-*/
-int ecc_verify_hash_rfc7518(const unsigned char *sig,  unsigned long siglen,
+int ecc_verify_hash_rfc7518_internal(const unsigned char *sig,  unsigned long siglen,
                             const unsigned char *hash, unsigned long hashlen,
                             int *stat, const ecc_key *key)
 {

+ 37 - 0
src/pk/ecc/ecc_verify_hash_x962.c

@@ -0,0 +1,37 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#if defined(LTC_MECC) && defined(LTC_DER)
+
+/**
+  @file ecc_verify_hash_x962.c
+  ECC Crypto, Tom St Denis
+*/
+
+int ecc_verify_hash_x962(const unsigned char *sig,  unsigned long siglen,
+                         const unsigned char *hash, unsigned long hashlen,
+                         int *stat, const ecc_key *key)
+{
+   void *r, *s;
+   int err;
+
+   LTC_ARGCHK(sig != NULL);
+
+   if ((err = ltc_mp_init_multi(&r, &s, NULL)) != CRYPT_OK) return err;
+
+   /* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) }  */
+   if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
+                                     LTC_ASN1_INTEGER, 1UL, r,
+                                     LTC_ASN1_INTEGER, 1UL, s,
+                                     LTC_ASN1_EOL, 0UL, LTC_NULL)) != CRYPT_OK)                         { goto error; }
+
+   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
+
+error:
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
+   return err;
+}
+
+#endif

+ 97 - 54
tests/ecc_test.c

@@ -316,7 +316,7 @@ static int s_ecc_issue443_447(void)
    DO(ecc_find_curve("secp256r1", &cu));
    DO(ecc_set_curve(cu, &key));
    DO(ecc_set_key(pub1, sizeof(pub1), PK_PUBLIC, &key));
-   err = ecc_verify_hash_rfc7518(sig1, sizeof(sig1), hash, hashlen, &stat, &key); /* should fail */
+   err = ecc_verify_hash_rfc7518_internal(sig1, sizeof(sig1), hash, hashlen, &stat, &key); /* should fail */
    ecc_free(&key);
    if (err != CRYPT_INVALID_PACKET) return CRYPT_FAIL_TESTVECTOR;
 
@@ -325,7 +325,7 @@ static int s_ecc_issue443_447(void)
    DO(ecc_find_curve("secp521r1", &cu));
    DO(ecc_set_curve(cu, &key));
    DO(ecc_set_key(pub2, sizeof(pub2), PK_PUBLIC, &key));
-   err = ecc_verify_hash_rfc7518(sig2, sizeof(sig2), hash, hashlen, &stat, &key); /* should fail */
+   err = ecc_verify_hash_rfc7518_internal(sig2, sizeof(sig2), hash, hashlen, &stat, &key); /* should fail */
    ecc_free(&key);
    if (err != CRYPT_INVALID_PACKET) return CRYPT_FAIL_TESTVECTOR;
 
@@ -401,6 +401,10 @@ static int s_ecc_old_api(void)
    unsigned long x, y, z, s;
    int           stat, stat2;
    ecc_key usera, userb, pubKey, privKey;
+   ltc_ecc_sig_opts sig_opts = {
+                                .prng = &yarrow_prng,
+                                .wprng = find_prng ("yarrow")
+   };
    int low, high;
 
    ecc_sizes(&low, &high);
@@ -500,10 +504,10 @@ static int s_ecc_old_api(void)
          buf[0][ch] = ch;
       }
       x = sizeof (buf[1]);
-      DO(ecc_sign_hash (buf[0], 16, buf[1], &x, &yarrow_prng, find_prng ("yarrow"), &privKey));
-      DO(ecc_verify_hash (buf[1], x, buf[0], 16, &stat, &pubKey));
+      DO(ecc_sign_hash_v2(buf[0], 16, buf[1], &x, &sig_opts, &privKey));
+      DO(ecc_verify_hash_v2(buf[1], x, buf[0], 16, &sig_opts, &stat, &pubKey));
       buf[0][0] ^= 1;
-      DO(ecc_verify_hash (buf[1], x, buf[0], 16, &stat2, &privKey));
+      DO(ecc_verify_hash_v2(buf[1], x, buf[0], 16, &sig_opts, &stat2, &privKey));
       if (!(stat == 1 && stat2 == 0)) {
          fprintf(stderr, "ecc_verify_hash failed %d, %d, ", stat, stat2);
          return 1;
@@ -513,10 +517,10 @@ static int s_ecc_old_api(void)
          buf[0][ch] = ch;
       }
       x = sizeof (buf[1]);
-      DO(ecc_sign_hash_rfc7518(buf[0], 16, buf[1], &x, &yarrow_prng, find_prng ("yarrow"), &privKey));
-      DO(ecc_verify_hash_rfc7518(buf[1], x, buf[0], 16, &stat, &pubKey));
+      DO(ecc_sign_hash_v2(buf[0], 16, buf[1], &x, &sig_opts, &privKey));
+      DO(ecc_verify_hash_v2(buf[1], x, buf[0], 16, &sig_opts, &stat, &pubKey));
       buf[0][0] ^= 1;
-      DO(ecc_verify_hash_rfc7518(buf[1], x, buf[0], 16, &stat2, &privKey));
+      DO(ecc_verify_hash_v2(buf[1], x, buf[0], 16, &sig_opts, &stat2, &privKey));
       if (!(stat == 1 && stat2 == 0)) {
          fprintf(stderr, "ecc_verify_hash_rfc7518 failed %d, %d, ", stat, stat2);
          return 1;
@@ -549,13 +553,32 @@ int ecc_key_cmp(const int should_type, const ecc_key *should, const ecc_key *is)
 
 static int s_ecc_new_api(void)
 {
-   int i, j, stat;
+   int i, stat;
    const ltc_ecc_curve* dp;
    ecc_key key, privkey, pubkey;
    unsigned char buf[1000];
-   unsigned long len;
-   unsigned char data16[16] = { 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1 };
+   unsigned long len, j;
+#ifdef LTC_ECC_SHAMIR
+   unsigned long k;
+#endif
+   unsigned char data16[MAXBLOCKSIZE];
    unsigned long len16;
+   const ecc_signature_type sig_algs[] = {
+#ifdef LTC_DER
+                                          LTC_ECCSIG_ANSIX962,
+#endif
+                                          LTC_ECCSIG_RFC7518,
+                                          LTC_ECCSIG_ETH27,
+#ifdef LTC_SSH
+                                          LTC_ECCSIG_RFC5656,
+#endif
+   };
+   ltc_ecc_sig_opts sig_opts = {
+                                .type = LTC_ECCSIG_ANSIX962,
+                                .prng = &yarrow_prng,
+                                .wprng = find_prng ("yarrow")
+   };
+   XMEMSET(data16, 0xd1, sizeof(data16));
 
    for (i = 0; i < (int)LTC_ARRAY_SIZE(curvenames); i++) {
       DO(ecc_find_curve(curvenames[i], &dp));
@@ -606,50 +629,50 @@ static int s_ecc_new_api(void)
       DO(ecc_set_curve(dp, &pubkey));
       DO(ecc_set_key(buf, len, PK_PUBLIC, &pubkey));
 
-      /* test signature */
-      len = sizeof(buf);
-      DO(ecc_sign_hash(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &privkey));
-      stat = 0;
-      DO(ecc_verify_hash(buf, len, data16, 16, &stat, &pubkey));
-      if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
-
-#ifdef LTC_SSH
-      /* test SSH+ECDSA/RFC5656 signature */
-      len = sizeof(buf);
-      DO(ecc_sign_hash_rfc5656(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &privkey));
-      stat = 0;
-      DO(ecc_verify_hash_rfc5656(buf, len, data16, 16, &stat, &pubkey));
-      if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
-#endif
+      for (j = 0; j < LTC_ARRAY_SIZE(sig_algs); ++j) {
+         /* test signature */
+         if (sig_algs[j] == LTC_ECCSIG_ETH27 && XSTRCMP(dp->OID, "1.3.132.0.10"))
+            continue;
+         len = sizeof(buf);
+         sig_opts.type = sig_algs[j];
+         DO(ecc_sign_hash_v2(data16, privkey.dp.size, buf, &len, &sig_opts, &privkey));
+         stat = 0;
+         DO(ecc_verify_hash_v2(buf, len, data16, privkey.dp.size, &sig_opts, &stat, &pubkey));
+         if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
 
 #ifdef LTC_ECC_SHAMIR
-      if (strcmp(ltc_mp.name, "TomsFastMath") != 0) {
-         /* XXX-FIXME: TFM does not support sqrtmod_prime */
-         int found = 0;
-         ecc_key reckey;
-         /* test recovery */
-         len = sizeof(buf);
-         DO(ecc_sign_hash(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &privkey));
-         DO(ecc_set_curve(dp, &reckey));
-         for (j = 0; j < 2*(1+(int)privkey.dp.cofactor); j++) {
-            stat = ecc_recover_key(buf, len, data16, 16, j, LTC_ECCSIG_ANSIX962, &reckey);
-            if (stat != CRYPT_OK) continue; /* last two will almost always fail, only possible if x<(prime mod order) */
-            stat = ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey);
-            if (stat == CRYPT_OK) found++;
+         if (strcmp(ltc_mp.name, "TomsFastMath") != 0) {
+            /* XXX-FIXME: TFM does not support sqrtmod_prime */
+            int found = 0, recid;
+            ecc_key reckey;
+            /* test recovery */
+            sig_opts.recid = &recid;
+            len = sizeof(buf);
+            DO(ecc_sign_hash_v2(data16, privkey.dp.size, buf, &len, &sig_opts, &privkey));
+            DO(ecc_set_curve(dp, &reckey));
+            for (k = 0; k < 2*(1+privkey.dp.cofactor); k++) {
+               recid = k;
+               stat = ecc_recover_key(buf, len, data16, privkey.dp.size, &sig_opts, &reckey);
+               if (stat != CRYPT_OK) continue; /* last two will almost always fail, only possible if x<(prime mod order) */
+               stat = ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey);
+               if (stat == CRYPT_OK) found++;
+            }
+            sig_opts.recid = NULL;
+            if (found != 1) return CRYPT_FAIL_TESTVECTOR; /* unique match */
+            ecc_free(&reckey);
          }
-         if (found != 1) return CRYPT_FAIL_TESTVECTOR; /* unique match */
-         ecc_free(&reckey);
-      }
 #endif
 
+      }
+
       /* test encryption */
       len = sizeof(buf);
       DO(ecc_encrypt_key(data16, 16, buf, &len, &yarrow_prng, find_prng("yarrow"), find_hash("sha256"), &pubkey));
       zeromem(data16, 16);
       len16 = 16;
       DO(ecc_decrypt_key(buf, len, data16, &len16, &privkey));
-      if (len16 != 16) return CRYPT_FAIL_TESTVECTOR;
-      for (j = 0; j < 16; j++) if (data16[j] != 0xd1) return CRYPT_FAIL_TESTVECTOR;
+      if ((int)len16 != 16) return CRYPT_FAIL_TESTVECTOR;
+      for (j = 0; (int)j < 16; j++) if (data16[j] != 0xd1) return CRYPT_FAIL_TESTVECTOR;
 
       /* cleanup */
       ecc_free(&privkey);
@@ -993,6 +1016,11 @@ static int s_ecc_rfc6979(void)
    char name[128], tmp[MAXBLOCKSIZE];
    unsigned int t, s, i, h;
    unsigned long pklen, hashlen, curvelen, inputlen, siglen, shouldlen, shouldlen2;
+   ltc_ecc_sig_opts sig_opts = {
+                                .type = LTC_ECCSIG_RFC7518,
+                                .prng = &yarrow_prng,
+                                .wprng = find_prng ("yarrow")
+   };
    for (t = 0; tests[t].curve; ++t) {
       curvelen = XSTRLEN(tests[t].curve);
       XMEMCPY(name, tests[t].curve, curvelen);
@@ -1020,9 +1048,9 @@ static int s_ecc_rfc6979(void)
          XMEMCPY(&name[curvelen + inputlen], hashes[h], 7);
          hashlen = sizeof(hash);
          DOX(hash_memory(find_hash(hashes[h]), inputs[i], XSTRLEN(inputs[i]), hash, &hashlen), name);
-         ECC_SET_RFC6979_HASH_ALG(&key, hashes[h]);
+         sig_opts.rfc6979_hash_alg = hashes[h];
          siglen = sizeof(sig);
-         DOX(ecc_sign_hash_rfc7518(hash, hashlen, sig, &siglen, &yarrow_prng, find_prng ("yarrow"), &key), name);
+         DOX(ecc_sign_hash_v2(hash, hashlen, sig, &siglen, &sig_opts, &key), name);
          XMEMSET(should, 0, sizeof(should));
          shouldlen = sizeof(should);
          DOX(base16_decode(tests[t].signatures[s].r, XSTRLEN(tests[t].signatures[s].r), should, &shouldlen), name);
@@ -1907,6 +1935,11 @@ static int s_ecc_test_ethereum(void)
    unsigned char buf[128];
    unsigned long len;
    unsigned char data16[16] = { 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1 };
+   ltc_ecc_sig_opts sig_opts = {
+                                .type = LTC_ECCSIG_ETH27,
+                                .prng = &yarrow_prng,
+                                .wprng = find_prng ("yarrow"),
+   };
 
    DO(ecc_find_curve("SECP256K1", &dp));
 
@@ -1914,15 +1947,15 @@ static int s_ecc_test_ethereum(void)
 
    /* test Ethereum signature */
    len = sizeof(buf);
-   DO(ecc_sign_hash_eth27(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &key));
+   DO(ecc_sign_hash_v2(data16, 16, buf, &len, &sig_opts, &key));
    stat = 0;
-   DO(ecc_verify_hash_eth27(buf, len, data16, 16, &stat, &key));
+   DO(ecc_verify_hash_v2(buf, len, data16, 16, &sig_opts, &stat, &key));
    if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
 
    /* XXX-FIXME: TFM does not support sqrtmod_prime */
    if (strcmp(ltc_mp.name, "TomsFastMath") != 0) {
       DO(ecc_set_curve(dp, &reckey));
-      DO(ecc_recover_key(buf, len, data16, 16, -1, LTC_ECCSIG_ETH27, &reckey));
+      DO(ecc_recover_key(buf, len, data16, 16, &sig_opts, &reckey));
       DO(ecc_key_cmp(PK_PUBLIC, &key, &reckey));
 
       /* cleanup */
@@ -1962,6 +1995,11 @@ static int s_ecc_test_recovery(void)
       0xb7, 0x3c, 0x97, 0x55, 0xfa, 0x69, 0xf8, 0xef, 0xe9, 0xcf, 0x12, 0xaf, 0x48, 0x25, 0xe3, 0xe0,
       0x1b
    };
+   ltc_ecc_sig_opts sig_opts = {
+                                .prng = &yarrow_prng,
+                                .wprng = find_prng ("yarrow"),
+                                .recid = &recid
+   };
 
    /* XXX-FIXME: TFM does not support sqrtmod_prime */
    if (strcmp(ltc_mp.name, "TomsFastMath") == 0) return CRYPT_NOP;
@@ -1973,18 +2011,23 @@ static int s_ecc_test_recovery(void)
    DO(ecc_set_key(eth_pubkey, sizeof(eth_pubkey), PK_PUBLIC, &pubkey));
 
    DO(ecc_set_curve(dp, &reckey));
-   DO(ecc_recover_key(eth_sig, sizeof(eth_sig)-1, eth_hash, sizeof(eth_hash), 0, LTC_ECCSIG_RFC7518, &reckey));
+   recid = 0;
+   sig_opts.type = LTC_ECCSIG_RFC7518;
+   DO(ecc_recover_key(eth_sig, sizeof(eth_sig)-1, eth_hash, sizeof(eth_hash), &sig_opts, &reckey));
    DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey));
    ecc_free(&reckey);
 
    DO(ecc_set_curve(dp, &reckey));
-   DO(ecc_recover_key(eth_sig, sizeof(eth_sig), eth_hash, sizeof(eth_hash), -1, LTC_ECCSIG_ETH27, &reckey));
+   recid = -1;
+   sig_opts.type = LTC_ECCSIG_ETH27;
+   DO(ecc_recover_key(eth_sig, sizeof(eth_sig), eth_hash, sizeof(eth_hash), &sig_opts, &reckey));
    DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey));
    ecc_free(&reckey);
 
    ecc_free(&pubkey);
 #endif
 
+   sig_opts.type = LTC_ECCSIG_RFC7518;
    for (i = 0; i < (int)LTC_ARRAY_SIZE(curvenames); i++) {
       DO(ecc_find_curve(curvenames[i], &dp));
 
@@ -2013,16 +2056,16 @@ static int s_ecc_test_recovery(void)
       /* test signature */
       len = sizeof(buf);
       recid = 0;
-      DO(ecc_sign_hash_rfc7518_ex(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &recid, &privkey));
+      DO(ecc_sign_hash_v2(data16, 16, buf, &len, &sig_opts, &privkey));
 
       /* test verification */
       stat = 0;
-      DO(ecc_verify_hash_rfc7518(buf, len, data16, 16, &stat, &pubkey));
+      DO(ecc_verify_hash_v2(buf, len, data16, 16, &sig_opts, &stat, &pubkey));
       if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
 
       /* test recovery */
       DO(ecc_set_curve(dp, &reckey));
-      stat = ecc_recover_key(buf, len, data16, 16, recid, LTC_ECCSIG_RFC7518, &reckey);
+      stat = ecc_recover_key(buf, len, data16, 16, &sig_opts, &reckey);
       if (stat != CRYPT_OK) return CRYPT_FAIL_TESTVECTOR;
       DO(ecc_key_cmp(PK_PUBLIC, &pubkey, &reckey));