Browse Source

refactor ecc_verify_hash_ex

Karel Miko 7 years ago
parent
commit
6561b37bac

+ 13 - 7
src/headers/tomcrypt_pk.h

@@ -358,15 +358,21 @@ 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);
 
-#define ecc_verify_hash_rfc7518(sig_, siglen_, hash_, hashlen_, stat_, key_) \
-   ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_RFC7518, stat_, key_)
+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_rfc7518(const unsigned char *sig,  unsigned long siglen,
+                            const unsigned char *hash, unsigned long hashlen,
+                            int *stat, const ecc_key *key);
 
-#define ecc_verify_hash(sig_, siglen_, hash_, hashlen_, stat_, key_) \
-   ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_ANSIX962, stat_, 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);
 
-int  ecc_verify_hash_ex(const unsigned char *sig,  unsigned long siglen,
-                        const unsigned char *hash, unsigned long hashlen,
-                        ecc_signature_type sigformat, int *stat, 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_recover_key(const unsigned char *sig,  unsigned long siglen,
                      const unsigned char *hash, unsigned long hashlen,

+ 4 - 0
src/headers/tomcrypt_private.h

@@ -424,6 +424,10 @@ 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);
 
+int ecc_verify_hash_internal(void *r, void *s,
+                             const unsigned char *hash, unsigned long hashlen,
+                             int *stat, const ecc_key *key);
+
 #ifdef LTC_SSH
 int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);
 #endif

+ 13 - 172
src/pk/ecc/ecc_verify_hash.c

@@ -11,195 +11,36 @@
 */
 
 /**
-   Verify an ECC signature in RFC7518 format
+   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 sigformat   The format of the signature (ecc_signature_type)
-   @param stat        Result of signature, 1==valid, 0==invalid
+   @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_ex(const unsigned char *sig,  unsigned long siglen,
-                       const unsigned char *hash, unsigned long hashlen,
-                       ecc_signature_type sigformat, int *stat, const ecc_key *key)
+int ecc_verify_hash(const unsigned char *sig,  unsigned long siglen,
+                    const unsigned char *hash, unsigned long hashlen,
+                    int *stat, const ecc_key *key)
 {
-   ecc_point     *mG = NULL, *mQ = NULL;
-   void          *r, *s, *v, *w, *u1, *u2, *e, *p, *m, *a, *a_plus3;
-   void          *mu = NULL, *ma = NULL;
-   void          *mp = NULL;
-   int           err;
-   unsigned long pbits, pbytes, i, shift_right;
-   unsigned char ch, buf[MAXBLOCKSIZE];
+   void *r, *s;
+   int err;
 
-   LTC_ARGCHK(sig  != NULL);
-   LTC_ARGCHK(hash != NULL);
-   LTC_ARGCHK(stat != NULL);
-   LTC_ARGCHK(key  != NULL);
+   LTC_ARGCHK(sig != NULL);
 
-   /* default to invalid signature */
-   *stat = 0;
+   if ((err = ltc_mp_init_multi(&r, &s, NULL)) != CRYPT_OK) return err;
 
-   /* allocate ints */
-   if ((err = ltc_mp_init_multi(&r, &s, &v, &w, &u1, &u2, &e, &a_plus3, LTC_NULL)) != CRYPT_OK) {
-      return err;
-   }
-
-   p = key->dp.order;
-   m = key->dp.prime;
-   a = key->dp.A;
-   if ((err = ltc_mp_add_d(a, 3, a_plus3)) != CRYPT_OK) {
-      goto error;
-   }
-
-   /* allocate points */
-   mG = ltc_ecc_new_point();
-   mQ = ltc_ecc_new_point();
-   if (mQ  == NULL || mG == NULL) {
-      err = CRYPT_MEM;
-      goto error;
-   }
-
-   if (sigformat == 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,
+   /* 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; }
-   }
-   else if (sigformat == LTC_ECCSIG_RFC7518) {
-      /* RFC7518 format - raw (r,s) */
-      i = ltc_mp_unsigned_bin_size(key->dp.order);
-      if (siglen != (2 * i)) {
-         err = CRYPT_INVALID_PACKET;
-         goto error;
-      }
-      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) {
-      /* 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 */
-         err = CRYPT_ERROR; goto error;
-      }
-      if (siglen != 65) { /* Only secp256k1 curves use this format, so must be 65 bytes long */
-         err = CRYPT_INVALID_PACKET;
-         goto error;
-      }
-      if ((err = ltc_mp_read_unsigned_bin(r, sig,  32)) != CRYPT_OK)                                        { goto error; }
-      if ((err = ltc_mp_read_unsigned_bin(s, sig+32, 32)) != CRYPT_OK)                                      { goto error; }
-   }
-#ifdef LTC_SSH
-   else if (sigformat == LTC_ECCSIG_RFC5656) {
-      char name[64], name2[64];
-      unsigned long namelen = sizeof(name);
-      unsigned long name2len = sizeof(name2);
-
-      /* Decode as SSH data sequence, per RFC4251 */
-      if ((err = ssh_decode_sequence_multi(sig, &siglen,
-                                           LTC_SSHDATA_STRING, name, &namelen,
-                                           LTC_SSHDATA_MPINT,  r,
-                                           LTC_SSHDATA_MPINT,  s,
-                                           LTC_SSHDATA_EOL,    NULL)) != CRYPT_OK)                      { goto error; }
-
-
-      /* Check curve matches identifier string */
-      if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK)                         { goto error; }
-      if ((namelen != name2len) || (XSTRCMP(name, name2) != 0)) {
-         err = CRYPT_INVALID_ARG;
-         goto error;
-      }
-   }
-#endif
-   else {
-      /* Unknown signature format */
-      err = CRYPT_ERROR;
-      goto error;
-   }
-
-   /* check for zero */
-   if (ltc_mp_cmp_d(r, 0) != LTC_MP_GT || ltc_mp_cmp_d(s, 0) != LTC_MP_GT ||
-       ltc_mp_cmp(r, p) != LTC_MP_LT || ltc_mp_cmp(s, p) != LTC_MP_LT) {
-      err = CRYPT_INVALID_PACKET;
-      goto error;
-   }
-
-   /* read hash - truncate if needed */
-   pbits = ltc_mp_count_bits(p);
-   pbytes = (pbits+7) >> 3;
-   if (pbits > hashlen*8) {
-      if ((err = ltc_mp_read_unsigned_bin(e, hash, hashlen)) != CRYPT_OK)                                   { goto error; }
-   }
-   else if (pbits % 8 == 0) {
-      if ((err = ltc_mp_read_unsigned_bin(e, hash, pbytes)) != CRYPT_OK)                                    { goto error; }
-   }
-   else {
-      shift_right = 8 - pbits % 8;
-      for (i=0, ch=0; i<pbytes; i++) {
-        buf[i] = ch;
-        ch = (hash[i] << (8-shift_right));
-        buf[i] = buf[i] ^ (hash[i] >> shift_right);
-      }
-      if ((err = ltc_mp_read_unsigned_bin(e, buf, pbytes)) != CRYPT_OK)                                     { goto error; }
-   }
-
-   /*  w  = s^-1 mod n */
-   if ((err = ltc_mp_invmod(s, p, w)) != CRYPT_OK)                                                          { goto error; }
-
-   /* u1 = ew */
-   if ((err = ltc_mp_mulmod(e, w, p, u1)) != CRYPT_OK)                                                      { goto error; }
-
-   /* u2 = rw */
-   if ((err = ltc_mp_mulmod(r, w, p, u2)) != CRYPT_OK)                                                      { goto error; }
-
-   /* find mG and mQ */
-   if ((err = ltc_ecc_copy_point(&key->dp.base, mG)) != CRYPT_OK)                                       { goto error; }
-   if ((err = ltc_ecc_copy_point(&key->pubkey, mQ)) != CRYPT_OK)                                        { goto error; }
-
-   /* find the montgomery mp */
-   if ((err = ltc_mp_montgomery_setup(m, &mp)) != CRYPT_OK)                                                 { goto error; }
-
-   /* for curves with a == -3 keep ma == NULL */
-   if (ltc_mp_cmp(a_plus3, m) != LTC_MP_EQ) {
-      if ((err = ltc_mp_init_multi(&mu, &ma, LTC_NULL)) != CRYPT_OK)                                        { goto error; }
-      if ((err = ltc_mp_montgomery_normalization(mu, m)) != CRYPT_OK)                                       { goto error; }
-      if ((err = ltc_mp_mulmod(a, mu, m, ma)) != CRYPT_OK)                                                  { goto error; }
-   }
-
-   /* compute u1*mG + u2*mQ = mG */
-   if (ltc_mp.ecc_mul2add == NULL) {
-      if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, a, m, 0)) != CRYPT_OK)                                    { goto error; }
-      if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, a, m, 0)) != CRYPT_OK)                                    { goto error; }
-
-      /* add them */
-      if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, ma, m, mp)) != CRYPT_OK)                                  { goto error; }
-
-      /* reduce */
-      if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK)                                                { goto error; }
-   } else {
-      /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
-      if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, ma, m)) != CRYPT_OK)                            { goto error; }
-   }
-
-   /* v = X_x1 mod n */
-   if ((err = ltc_mp_mod(mG->x, p, v)) != CRYPT_OK)                                                         { goto error; }
 
-   /* does v == r */
-   if (ltc_mp_cmp(v, r) == LTC_MP_EQ) {
-      *stat = 1;
-   }
+   err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
 
-   /* clear up and return */
-   err = CRYPT_OK;
 error:
-   if (mG != NULL) ltc_ecc_del_point(mG);
-   if (mQ != NULL) ltc_ecc_del_point(mQ);
-   if (mu != NULL) ltc_mp_clear(mu);
-   if (ma != NULL) ltc_mp_clear(ma);
-   ltc_mp_deinit_multi(r, s, v, w, u1, u2, e, a_plus3, LTC_NULL);
-   if (mp != NULL) ltc_mp_montgomery_free(mp);
+   ltc_mp_deinit_multi(r, s, LTC_NULL);
    return err;
 }
 

+ 53 - 0
src/pk/ecc/ecc_verify_hash_eth27.c

@@ -0,0 +1,53 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+/**
+  @file ecc_verify_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+/**
+   Verify an ECC signature (Ethereum format with recovery_id+27)
+   @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_eth27(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);
+   LTC_ARGCHK(key != NULL);
+
+   /* Only valid for secp256k1 - OID 1.3.132.0.10 */
+   if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
+      return CRYPT_ERROR;
+   }
+   /* Only secp256k1 curves uses this format, so must be 65 bytes long */
+   if (siglen != 65) {
+      return CRYPT_INVALID_PACKET;
+   }
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+   if ((err = ltc_mp_read_unsigned_bin(r, (unsigned char *)sig, 32)) != CRYPT_OK) goto error;
+   if ((err = ltc_mp_read_unsigned_bin(s, (unsigned char *)sig + 32, 32)) != 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

+ 137 - 0
src/pk/ecc/ecc_verify_hash_internal.c

@@ -0,0 +1,137 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+int ecc_verify_hash_internal(void *r, void *s,
+                             const unsigned char *hash, unsigned long hashlen,
+                             int *stat, const ecc_key *key)
+{
+   ecc_point     *mG = NULL, *mQ = NULL;
+   void          *v, *w, *u1, *u2, *e, *p, *m, *a, *a_plus3;
+   void          *mu = NULL, *ma = NULL;
+   void          *mp = NULL;
+   int           err;
+   unsigned long pbits, pbytes, i, shift_right;
+   unsigned char ch, buf[MAXBLOCKSIZE];
+
+   LTC_ARGCHK(r    != NULL);
+   LTC_ARGCHK(s    != NULL);
+   LTC_ARGCHK(hash != NULL);
+   LTC_ARGCHK(stat != NULL);
+   LTC_ARGCHK(key  != NULL);
+
+   /* default to invalid signature */
+   *stat = 0;
+
+   /* allocate ints */
+   if ((err = ltc_mp_init_multi(&v, &w, &u1, &u2, &e, &a_plus3, LTC_NULL)) != CRYPT_OK) {
+      return err;
+   }
+
+   p = key->dp.order;
+   m = key->dp.prime;
+   a = key->dp.A;
+   if ((err = ltc_mp_add_d(a, 3, a_plus3)) != CRYPT_OK) {
+      goto error;
+   }
+
+   /* allocate points */
+   mG = ltc_ecc_new_point();
+   mQ = ltc_ecc_new_point();
+   if (mQ  == NULL || mG == NULL) {
+      err = CRYPT_MEM;
+      goto error;
+   }
+
+   /* check for zero */
+   if (ltc_mp_cmp_d(r, 0) != LTC_MP_GT || ltc_mp_cmp_d(s, 0) != LTC_MP_GT ||
+       ltc_mp_cmp(r, p) != LTC_MP_LT || ltc_mp_cmp(s, p) != LTC_MP_LT) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* read hash - truncate if needed */
+   pbits = ltc_mp_count_bits(p);
+   pbytes = (pbits+7) >> 3;
+   if (pbits > hashlen*8) {
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)hash, hashlen)) != CRYPT_OK)                  { goto error; }
+   }
+   else if (pbits % 8 == 0) {
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)hash, pbytes)) != CRYPT_OK)                   { goto error; }
+   }
+   else {
+      if (pbytes >= MAXBLOCKSIZE) {
+         err = CRYPT_BUFFER_OVERFLOW;
+         goto error;
+      }
+      shift_right = 8 - pbits % 8;
+      for (i=0, ch=0; i<pbytes; i++) {
+        buf[i] = ch;
+        ch = (hash[i] << (8-shift_right));
+        buf[i] = buf[i] ^ (hash[i] >> shift_right);
+      }
+      if ((err = ltc_mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK)                    { goto error; }
+   }
+
+   /*  w  = s^-1 mod n */
+   if ((err = ltc_mp_invmod(s, p, w)) != CRYPT_OK)                                                          { goto error; }
+
+   /* u1 = ew */
+   if ((err = ltc_mp_mulmod(e, w, p, u1)) != CRYPT_OK)                                                      { goto error; }
+
+   /* u2 = rw */
+   if ((err = ltc_mp_mulmod(r, w, p, u2)) != CRYPT_OK)                                                      { goto error; }
+
+   /* find mG and mQ */
+   if ((err = ltc_ecc_copy_point(&key->dp.base, mG)) != CRYPT_OK)                                       { goto error; }
+   if ((err = ltc_ecc_copy_point(&key->pubkey, mQ)) != CRYPT_OK)                                        { goto error; }
+
+   /* find the montgomery mp */
+   if ((err = ltc_mp_montgomery_setup(m, &mp)) != CRYPT_OK)                                                 { goto error; }
+
+   /* for curves with a == -3 keep ma == NULL */
+   if (ltc_mp_cmp(a_plus3, m) != LTC_MP_EQ) {
+      if ((err = ltc_mp_init_multi(&mu, &ma, NULL)) != CRYPT_OK)                                            { goto error; }
+      if ((err = ltc_mp_montgomery_normalization(mu, m)) != CRYPT_OK)                                       { goto error; }
+      if ((err = ltc_mp_mulmod(a, mu, m, ma)) != CRYPT_OK)                                                  { goto error; }
+   }
+
+   /* compute u1*mG + u2*mQ = mG */
+   if (ltc_mp.ecc_mul2add == NULL) {
+      if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, a, m, 0)) != CRYPT_OK)                                    { goto error; }
+      if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, a, m, 0)) != CRYPT_OK)                                    { goto error; }
+
+      /* add them */
+      if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, ma, m, mp)) != CRYPT_OK)                                  { goto error; }
+
+      /* reduce */
+      if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK)                                                { goto error; }
+   } else {
+      /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
+      if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, ma, m)) != CRYPT_OK)                            { goto error; }
+   }
+
+   /* v = X_x1 mod n */
+   if ((err = ltc_mp_mod(mG->x, p, v)) != CRYPT_OK)                                                         { goto error; }
+
+   /* does v == r */
+   if (ltc_mp_cmp(v, r) == LTC_MP_EQ) {
+      *stat = 1;
+   }
+
+   /* clear up and return */
+   err = CRYPT_OK;
+error:
+   if (mG != NULL) ltc_ecc_del_point(mG);
+   if (mQ != NULL) ltc_ecc_del_point(mQ);
+   if (mu != NULL) ltc_mp_clear(mu);
+   if (ma != NULL) ltc_mp_clear(ma);
+   ltc_mp_deinit_multi(v, w, u1, u2, e, a_plus3, LTC_NULL);
+   if (mp != NULL) ltc_mp_montgomery_free(mp);
+   return err;
+}
+
+#endif

+ 65 - 0
src/pk/ecc/ecc_verify_hash_rfc5656.c

@@ -0,0 +1,65 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#if defined(LTC_MECC) && defined(LTC_SSH)
+
+/**
+  @file ecc_verify_hash.c
+  ECC Crypto, Tom St Denis
+*/
+
+/**
+   Verify an ECC signature (RFC5656 / SSH 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_rfc5656(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;
+   char name[64], name2[64];
+   unsigned long namelen = sizeof(name);
+   unsigned long name2len = sizeof(name2);
+   unsigned long slen = siglen;
+
+   LTC_ARGCHK(sig != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+
+   /* Decode as SSH data sequence, per RFC4251 */
+   if ((err = ssh_decode_sequence_multi(sig, &slen,
+                                        LTC_SSHDATA_STRING, name, &namelen,
+                                        LTC_SSHDATA_MPINT,  r,
+                                        LTC_SSHDATA_MPINT,  s,
+                                        LTC_SSHDATA_EOL,    LTC_NULL)) != CRYPT_OK) goto error;
+
+   if (slen != siglen) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+
+   /* Check curve matches identifier string */
+   if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK) goto error;
+   if (XSTRCMP(name,name2) != 0) {
+      err = CRYPT_INVALID_ARG;
+      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

+ 52 - 0
src/pk/ecc/ecc_verify_hash_rfc7518.c

@@ -0,0 +1,52 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+
+#include "tomcrypt_private.h"
+
+#ifdef LTC_MECC
+
+/**
+  @file ecc_verify_hash.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,
+                            const unsigned char *hash, unsigned long hashlen,
+                            int *stat, const ecc_key *key)
+{
+   void *r, *s;
+   int err;
+   unsigned long i;
+
+   LTC_ARGCHK(sig != NULL);
+   LTC_ARGCHK(key != NULL);
+
+   if ((err = ltc_mp_init_multi(&r, &s, LTC_NULL)) != CRYPT_OK) return err;
+
+   /* RFC7518 format - raw (r,s) */
+   i = ltc_mp_unsigned_bin_size(key->dp.order);
+   if (siglen != (2 * i)) {
+      err = CRYPT_INVALID_PACKET;
+      goto error;
+   }
+   if ((err = ltc_mp_read_unsigned_bin(r, (unsigned char *)sig, i)) != CRYPT_OK) goto error;
+   if ((err = ltc_mp_read_unsigned_bin(s, (unsigned char *)sig + i, i)) != 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

+ 2 - 2
tests/ecc_test.c

@@ -618,7 +618,7 @@ static int s_ecc_new_api(void)
       len = sizeof(buf);
       DO(ecc_sign_hash_rfc5656(data16, 16, buf, &len, &yarrow_prng, find_prng ("yarrow"), &privkey));
       stat = 0;
-      DO(ecc_verify_hash_ex(buf, len, data16, 16, LTC_ECCSIG_RFC5656, &stat, &pubkey));
+      DO(ecc_verify_hash_rfc5656(buf, len, data16, 16, &stat, &pubkey));
       if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
 #endif
 
@@ -1599,7 +1599,7 @@ static int s_ecc_test_recovery(void)
 
       /* test verification */
       stat = 0;
-      DO(ecc_verify_hash_ex(buf, len, data16, 16, LTC_ECCSIG_RFC7518, &stat, &pubkey));
+      DO(ecc_verify_hash_rfc7518(buf, len, data16, 16, &stat, &pubkey));
       if (stat != 1) return CRYPT_FAIL_TESTVECTOR;
 
       /* test recovery */