Skip to content

Commit 41d9ee3

Browse files
committed
refactor ecc_verify_hash_ex
1 parent 1bf2165 commit 41d9ee3

8 files changed

+370
-181
lines changed

src/headers/tomcrypt_pk.h

+13-7
Original file line numberDiff line numberDiff line change
@@ -320,15 +320,21 @@ int ecc_sign_hash_eth27(const unsigned char *in, unsigned long inlen,
320320
unsigned char *out, unsigned long *outlen,
321321
prng_state *prng, int wprng, const ecc_key *key);
322322

323-
#define ecc_verify_hash_rfc7518(sig_, siglen_, hash_, hashlen_, stat_, key_) \
324-
ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_RFC7518, stat_, key_)
323+
int ecc_verify_hash(const unsigned char *sig, unsigned long siglen,
324+
const unsigned char *hash, unsigned long hashlen,
325+
int *stat, const ecc_key *key);
326+
327+
int ecc_verify_hash_rfc7518(const unsigned char *sig, unsigned long siglen,
328+
const unsigned char *hash, unsigned long hashlen,
329+
int *stat, const ecc_key *key);
325330

326-
#define ecc_verify_hash(sig_, siglen_, hash_, hashlen_, stat_, key_) \
327-
ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_ANSIX962, stat_, key_)
331+
int ecc_verify_hash_rfc5656(const unsigned char *sig, unsigned long siglen,
332+
const unsigned char *hash, unsigned long hashlen,
333+
int *stat, const ecc_key *key);
328334

329-
int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
330-
const unsigned char *hash, unsigned long hashlen,
331-
ecc_signature_type sigformat, int *stat, const ecc_key *key);
335+
int ecc_verify_hash_eth27(const unsigned char *sig, unsigned long siglen,
336+
const unsigned char *hash, unsigned long hashlen,
337+
int *stat, const ecc_key *key);
332338

333339
int ecc_recover_key(const unsigned char *sig, unsigned long siglen,
334340
const unsigned char *hash, unsigned long hashlen,

src/headers/tomcrypt_private.h

+4
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ int ecc_sign_hash_internal(const unsigned char *in, unsigned long inlen,
230230
void *r, void *s, prng_state *prng, int wprng,
231231
int *recid, const ecc_key *key);
232232

233+
int ecc_verify_hash_internal(void *r, void *s,
234+
const unsigned char *hash, unsigned long hashlen,
235+
int *stat, const ecc_key *key);
236+
233237
#ifdef LTC_SSH
234238
int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);
235239
#endif

src/pk/ecc/ecc_verify_hash.c

+14-172
Original file line numberDiff line numberDiff line change
@@ -17,194 +17,36 @@
1717
*/
1818

1919
/**
20-
Verify an ECC signature in RFC7518 format
20+
Verify an ECC signature (ANSI X9.62 format)
2121
@param sig The signature to verify
2222
@param siglen The length of the signature (octets)
2323
@param hash The hash (message digest) that was signed
2424
@param hashlen The length of the hash (octets)
25-
@param sigformat The format of the signature (ecc_signature_type)
26-
@param stat Result of signature, 1==valid, 0==invalid
25+
@param stat [out] Result of signature, 1==valid, 0==invalid
2726
@param key The corresponding public ECC key
2827
@return CRYPT_OK if successful (even if the signature is not valid)
2928
*/
30-
int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
31-
const unsigned char *hash, unsigned long hashlen,
32-
ecc_signature_type sigformat, int *stat, const ecc_key *key)
29+
int ecc_verify_hash(const unsigned char *sig, unsigned long siglen,
30+
const unsigned char *hash, unsigned long hashlen,
31+
int *stat, const ecc_key *key)
3332
{
34-
ecc_point *mG = NULL, *mQ = NULL;
35-
void *r, *s, *v, *w, *u1, *u2, *e, *p, *m, *a, *a_plus3;
36-
void *mu = NULL, *ma = NULL;
37-
void *mp = NULL;
38-
int err;
39-
unsigned long pbits, pbytes, i, shift_right;
40-
unsigned char ch, buf[MAXBLOCKSIZE];
33+
void *r, *s;
34+
int err;
4135

42-
LTC_ARGCHK(sig != NULL);
43-
LTC_ARGCHK(hash != NULL);
44-
LTC_ARGCHK(stat != NULL);
45-
LTC_ARGCHK(key != NULL);
36+
LTC_ARGCHK(sig != NULL);
4637

47-
/* default to invalid signature */
48-
*stat = 0;
38+
if ((err = mp_init_multi(&r, &s, NULL)) != CRYPT_OK) return err;
4939

50-
/* allocate ints */
51-
if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &e, &a_plus3, NULL)) != CRYPT_OK) {
52-
return err;
53-
}
54-
55-
p = key->dp.order;
56-
m = key->dp.prime;
57-
a = key->dp.A;
58-
if ((err = mp_add_d(a, 3, a_plus3)) != CRYPT_OK) {
59-
goto error;
60-
}
61-
62-
/* allocate points */
63-
mG = ltc_ecc_new_point();
64-
mQ = ltc_ecc_new_point();
65-
if (mQ == NULL || mG == NULL) {
66-
err = CRYPT_MEM;
67-
goto error;
68-
}
69-
70-
if (sigformat == LTC_ECCSIG_ANSIX962) {
71-
/* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) } */
72-
if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
40+
/* ANSI X9.62 format - ASN.1 encoded SEQUENCE{ INTEGER(r), INTEGER(s) } */
41+
if ((err = der_decode_sequence_multi_ex(sig, siglen, LTC_DER_SEQ_SEQUENCE | LTC_DER_SEQ_STRICT,
7342
LTC_ASN1_INTEGER, 1UL, r,
7443
LTC_ASN1_INTEGER, 1UL, s,
75-
LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { goto error; }
76-
}
77-
else if (sigformat == LTC_ECCSIG_RFC7518) {
78-
/* RFC7518 format - raw (r,s) */
79-
i = mp_unsigned_bin_size(key->dp.order);
80-
if (siglen != (2 * i)) {
81-
err = CRYPT_INVALID_PACKET;
82-
goto error;
83-
}
84-
if ((err = mp_read_unsigned_bin(r, (unsigned char *)sig, i)) != CRYPT_OK) { goto error; }
85-
if ((err = mp_read_unsigned_bin(s, (unsigned char *)sig+i, i)) != CRYPT_OK) { goto error; }
86-
}
87-
else if (sigformat == LTC_ECCSIG_ETH27) {
88-
/* Ethereum (v,r,s) format */
89-
if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
90-
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
91-
err = CRYPT_ERROR; goto error;
92-
}
93-
if (siglen != 65) { /* Only secp256k1 curves use this format, so must be 65 bytes long */
94-
err = CRYPT_INVALID_PACKET;
95-
goto error;
96-
}
97-
if ((err = mp_read_unsigned_bin(r, (unsigned char *)sig, 32)) != CRYPT_OK) { goto error; }
98-
if ((err = mp_read_unsigned_bin(s, (unsigned char *)sig+32, 32)) != CRYPT_OK) { goto error; }
99-
}
100-
#ifdef LTC_SSH
101-
else if (sigformat == LTC_ECCSIG_RFC5656) {
102-
char name[64], name2[64];
103-
unsigned long namelen = sizeof(name2);
104-
105-
/* Decode as SSH data sequence, per RFC4251 */
106-
if ((err = ssh_decode_sequence_multi(sig, siglen,
107-
LTC_SSHDATA_STRING, name, 64,
108-
LTC_SSHDATA_MPINT, r,
109-
LTC_SSHDATA_MPINT, s,
110-
LTC_SSHDATA_EOL, NULL)) != CRYPT_OK) { goto error; }
111-
112-
113-
/* Check curve matches identifier string */
114-
if ((err = ecc_ssh_ecdsa_encode_name(name2, &namelen, key)) != CRYPT_OK) { goto error; }
115-
if (XSTRCMP(name,name2) != 0) {
116-
err = CRYPT_INVALID_ARG;
117-
goto error;
118-
}
119-
}
120-
#endif
121-
else {
122-
/* Unknown signature format */
123-
err = CRYPT_ERROR;
124-
goto error;
125-
}
126-
127-
/* check for zero */
128-
if (mp_cmp_d(r, 0) != LTC_MP_GT || mp_cmp_d(s, 0) != LTC_MP_GT ||
129-
mp_cmp(r, p) != LTC_MP_LT || mp_cmp(s, p) != LTC_MP_LT) {
130-
err = CRYPT_INVALID_PACKET;
131-
goto error;
132-
}
133-
134-
/* read hash - truncate if needed */
135-
pbits = mp_count_bits(p);
136-
pbytes = (pbits+7) >> 3;
137-
if (pbits > hashlen*8) {
138-
if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, hashlen)) != CRYPT_OK) { goto error; }
139-
}
140-
else if (pbits % 8 == 0) {
141-
if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, pbytes)) != CRYPT_OK) { goto error; }
142-
}
143-
else {
144-
shift_right = 8 - pbits % 8;
145-
for (i=0, ch=0; i<pbytes; i++) {
146-
buf[i] = ch;
147-
ch = (hash[i] << (8-shift_right));
148-
buf[i] = buf[i] ^ (hash[i] >> shift_right);
149-
}
150-
if ((err = mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK) { goto error; }
151-
}
152-
153-
/* w = s^-1 mod n */
154-
if ((err = mp_invmod(s, p, w)) != CRYPT_OK) { goto error; }
155-
156-
/* u1 = ew */
157-
if ((err = mp_mulmod(e, w, p, u1)) != CRYPT_OK) { goto error; }
158-
159-
/* u2 = rw */
160-
if ((err = mp_mulmod(r, w, p, u2)) != CRYPT_OK) { goto error; }
161-
162-
/* find mG and mQ */
163-
if ((err = ltc_ecc_copy_point(&key->dp.base, mG)) != CRYPT_OK) { goto error; }
164-
if ((err = ltc_ecc_copy_point(&key->pubkey, mQ)) != CRYPT_OK) { goto error; }
165-
166-
/* find the montgomery mp */
167-
if ((err = mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; }
168-
169-
/* for curves with a == -3 keep ma == NULL */
170-
if (mp_cmp(a_plus3, m) != LTC_MP_EQ) {
171-
if ((err = mp_init_multi(&mu, &ma, NULL)) != CRYPT_OK) { goto error; }
172-
if ((err = mp_montgomery_normalization(mu, m)) != CRYPT_OK) { goto error; }
173-
if ((err = mp_mulmod(a, mu, m, ma)) != CRYPT_OK) { goto error; }
174-
}
175-
176-
/* compute u1*mG + u2*mQ = mG */
177-
if (ltc_mp.ecc_mul2add == NULL) {
178-
if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, a, m, 0)) != CRYPT_OK) { goto error; }
179-
if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, a, m, 0)) != CRYPT_OK) { goto error; }
180-
181-
/* add them */
182-
if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, ma, m, mp)) != CRYPT_OK) { goto error; }
183-
184-
/* reduce */
185-
if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK) { goto error; }
186-
} else {
187-
/* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */
188-
if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, ma, m)) != CRYPT_OK) { goto error; }
189-
}
190-
191-
/* v = X_x1 mod n */
192-
if ((err = mp_mod(mG->x, p, v)) != CRYPT_OK) { goto error; }
44+
LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) goto error;
19345

194-
/* does v == r */
195-
if (mp_cmp(v, r) == LTC_MP_EQ) {
196-
*stat = 1;
197-
}
46+
err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
19847

199-
/* clear up and return */
200-
err = CRYPT_OK;
20148
error:
202-
if (mG != NULL) ltc_ecc_del_point(mG);
203-
if (mQ != NULL) ltc_ecc_del_point(mQ);
204-
if (mu != NULL) mp_clear(mu);
205-
if (ma != NULL) mp_clear(ma);
206-
mp_clear_multi(r, s, v, w, u1, u2, e, a_plus3, NULL);
207-
if (mp != NULL) mp_montgomery_free(mp);
49+
mp_clear_multi(r, s, NULL);
20850
return err;
20951
}
21052

src/pk/ecc/ecc_verify_hash_eth27.c

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
2+
*
3+
* LibTomCrypt is a library that provides various cryptographic
4+
* algorithms in a highly modular and flexible manner.
5+
*
6+
* The library is free for all purposes without any express
7+
* guarantee it works.
8+
*/
9+
10+
#include "tomcrypt_private.h"
11+
12+
#ifdef LTC_MECC
13+
14+
/**
15+
@file ecc_verify_hash.c
16+
ECC Crypto, Tom St Denis
17+
*/
18+
19+
/**
20+
Verify an ECC signature (Ethereum format with recovery_id+27)
21+
@param sig The signature to verify
22+
@param siglen The length of the signature (octets)
23+
@param hash The hash (message digest) that was signed
24+
@param hashlen The length of the hash (octets)
25+
@param stat [out] Result of signature, 1==valid, 0==invalid
26+
@param key The corresponding public ECC key
27+
@return CRYPT_OK if successful (even if the signature is not valid)
28+
*/
29+
int ecc_verify_hash_eth27(const unsigned char *sig, unsigned long siglen,
30+
const unsigned char *hash, unsigned long hashlen,
31+
int *stat, const ecc_key *key)
32+
{
33+
void *r, *s;
34+
int err;
35+
36+
LTC_ARGCHK(sig != NULL);
37+
LTC_ARGCHK(key != NULL);
38+
39+
if ((err = mp_init_multi(&r, &s, NULL)) != CRYPT_OK) return err;
40+
41+
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
42+
if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
43+
err = CRYPT_ERROR;
44+
goto error;
45+
}
46+
if (siglen != 65) { /* Only secp256k1 curves use this format, so must be 65 bytes long */
47+
err = CRYPT_INVALID_PACKET;
48+
goto error;
49+
}
50+
if ((err = mp_read_unsigned_bin(r, (unsigned char *)sig, 32)) != CRYPT_OK) goto error;
51+
if ((err = mp_read_unsigned_bin(s, (unsigned char *)sig + 32, 32)) != CRYPT_OK) goto error;
52+
53+
err = ecc_verify_hash_internal(r, s, hash, hashlen, stat, key);
54+
55+
error:
56+
mp_clear_multi(r, s, NULL);
57+
return err;
58+
}
59+
60+
#endif
61+
62+
/* ref: $Format:%D$ */
63+
/* git commit: $Format:%H$ */
64+
/* commit time: $Format:%ai$ */

0 commit comments

Comments
 (0)