Skip to content

Commit 1bf2165

Browse files
committed
refactor ecc_sign_hash_ex
1 parent 873153d commit 1bf2165

8 files changed

+364
-165
lines changed

src/headers/tomcrypt_pk.h

+19-9
Original file line numberDiff line numberDiff line change
@@ -299,23 +299,33 @@ int ecc_decrypt_key(const unsigned char *in, unsigned long inlen,
299299
unsigned char *out, unsigned long *outlen,
300300
const ecc_key *key);
301301

302-
#define ecc_sign_hash_rfc7518(in_, inlen_, out_, outlen_, prng_, wprng_, key_) \
303-
ecc_sign_hash_ex(in_, inlen_, out_, outlen_, prng_, wprng_, LTC_ECCSIG_RFC7518, NULL, key_)
302+
int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
303+
unsigned char *out, unsigned long *outlen,
304+
prng_state *prng, int wprng, const ecc_key *key);
304305

305-
#define ecc_sign_hash(in_, inlen_, out_, outlen_, prng_, wprng_, key_) \
306-
ecc_sign_hash_ex(in_, inlen_, out_, outlen_, prng_, wprng_, LTC_ECCSIG_ANSIX962, NULL, key_)
306+
int ecc_sign_hash_rfc7518(const unsigned char *in, unsigned long inlen,
307+
unsigned char *out, unsigned long *outlen,
308+
prng_state *prng, int wprng, const ecc_key *key);
309+
310+
int ecc_sign_hash_rfc7518_ex(const unsigned char *in, unsigned long inlen,
311+
unsigned char *out, unsigned long *outlen,
312+
prng_state *prng, int wprng,
313+
int *recid, const ecc_key *key);
314+
315+
int ecc_sign_hash_rfc5656(const unsigned char *in, unsigned long inlen,
316+
unsigned char *out, unsigned long *outlen,
317+
prng_state *prng, int wprng, const ecc_key *key);
318+
319+
int ecc_sign_hash_eth27(const unsigned char *in, unsigned long inlen,
320+
unsigned char *out, unsigned long *outlen,
321+
prng_state *prng, int wprng, const ecc_key *key);
307322

308323
#define ecc_verify_hash_rfc7518(sig_, siglen_, hash_, hashlen_, stat_, key_) \
309324
ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_RFC7518, stat_, key_)
310325

311326
#define ecc_verify_hash(sig_, siglen_, hash_, hashlen_, stat_, key_) \
312327
ecc_verify_hash_ex(sig_, siglen_, hash_, hashlen_, LTC_ECCSIG_ANSIX962, stat_, key_)
313328

314-
int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
315-
unsigned char *out, unsigned long *outlen,
316-
prng_state *prng, int wprng, ecc_signature_type sigformat,
317-
int *recid, const ecc_key *key);
318-
319329
int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
320330
const unsigned char *hash, unsigned long hashlen,
321331
ecc_signature_type sigformat, int *stat, const ecc_key *key);

src/headers/tomcrypt_private.h

+4
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ int ecc_copy_curve(const ecc_key *srckey, ecc_key *key);
226226
int ecc_set_curve_by_size(int size, ecc_key *key);
227227
int ecc_import_subject_public_key_info(const unsigned char *in, unsigned long inlen, ecc_key *key);
228228

229+
int ecc_sign_hash_internal(const unsigned char *in, unsigned long inlen,
230+
void *r, void *s, prng_state *prng, int wprng,
231+
int *recid, const ecc_key *key);
232+
229233
#ifdef LTC_SSH
230234
int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);
231235
#endif

src/pk/ecc/ecc_sign_hash.c

+14-153
Original file line numberDiff line numberDiff line change
@@ -12,175 +12,36 @@
1212
#ifdef LTC_MECC
1313

1414
/**
15-
@file ecc_sign_hash.c
16-
ECC Crypto, Tom St Denis
17-
*/
18-
19-
/**
20-
Sign a message digest
15+
Sign a message digest (ANSI X9.62 format)
2116
@param in The message digest to sign
2217
@param inlen The length of the digest
2318
@param out [out] The destination for the signature
2419
@param outlen [in/out] The max size and resulting size of the signature
2520
@param prng An active PRNG state
2621
@param wprng The index of the PRNG you wish to use
27-
@param sigformat The format of the signature to generate (ecc_signature_type)
28-
@param recid [out] The recovery ID for this signature (optional)
2922
@param key A private ECC key
3023
@return CRYPT_OK if successful
3124
*/
32-
int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen,
33-
unsigned char *out, unsigned long *outlen,
34-
prng_state *prng, int wprng, ecc_signature_type sigformat,
35-
int *recid, const ecc_key *key)
25+
int ecc_sign_hash(const unsigned char *in, unsigned long inlen,
26+
unsigned char *out, unsigned long *outlen,
27+
prng_state *prng, int wprng, const ecc_key *key)
3628
{
37-
ecc_key pubkey;
38-
void *r, *s, *e, *p, *b;
39-
int v = 0;
40-
int err, max_iterations = LTC_PK_MAX_RETRIES;
41-
unsigned long pbits, pbytes, i, shift_right;
42-
unsigned char ch, buf[MAXBLOCKSIZE];
29+
int err;
30+
void *r, *s;
4331

44-
LTC_ARGCHK(in != NULL);
4532
LTC_ARGCHK(out != NULL);
4633
LTC_ARGCHK(outlen != NULL);
47-
LTC_ARGCHK(key != NULL);
48-
49-
/* is this a private key? */
50-
if (key->type != PK_PRIVATE) {
51-
return CRYPT_PK_NOT_PRIVATE;
52-
}
53-
54-
/* init the bignums */
55-
if ((err = mp_init_multi(&r, &s, &e, &b, NULL)) != CRYPT_OK) {
56-
return err;
57-
}
58-
59-
/* get the hash and load it as a bignum into 'e' */
60-
p = key->dp.order;
61-
pbits = mp_count_bits(p);
62-
pbytes = (pbits+7) >> 3;
63-
if (pbits > inlen*8) {
64-
if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, inlen)) != CRYPT_OK) { goto errnokey; }
65-
}
66-
else if (pbits % 8 == 0) {
67-
if ((err = mp_read_unsigned_bin(e, (unsigned char *)in, pbytes)) != CRYPT_OK) { goto errnokey; }
68-
}
69-
else {
70-
shift_right = 8 - pbits % 8;
71-
for (i=0, ch=0; i<pbytes; i++) {
72-
buf[i] = ch;
73-
ch = (in[i] << (8-shift_right));
74-
buf[i] = buf[i] ^ (in[i] >> shift_right);
75-
}
76-
if ((err = mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK) { goto errnokey; }
77-
}
78-
79-
/* make up a key and export the public copy */
80-
do {
81-
if ((err = ecc_copy_curve(key, &pubkey)) != CRYPT_OK) { goto errnokey; }
82-
if ((err = ecc_generate_key(prng, wprng, &pubkey)) != CRYPT_OK) { goto errnokey; }
8334

84-
/* find r = x1 mod n */
85-
if ((err = mp_mod(pubkey.pubkey.x, p, r)) != CRYPT_OK) { goto error; }
86-
87-
if (recid || sigformat==LTC_ECCSIG_ETH27) {
88-
/* find recovery ID (if needed) */
89-
v = 0;
90-
if (mp_copy(pubkey.pubkey.x, s) != CRYPT_OK) { goto error; }
91-
while (mp_cmp_d(s, 0) == LTC_MP_GT && mp_cmp(s, p) != LTC_MP_LT) {
92-
/* Compute x1 div n... this will almost never be reached for curves with order 1 */
93-
v += 2;
94-
if ((err = mp_sub(s, p, s)) != CRYPT_OK) { goto error; }
95-
}
96-
if (mp_isodd(pubkey.pubkey.y)) v += 1;
97-
}
98-
99-
if (mp_iszero(r) == LTC_MP_YES) {
100-
ecc_free(&pubkey);
101-
} else {
102-
if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK) { goto error; } /* b = blinding value */
103-
/* find s = (e + xr)/k */
104-
if ((err = mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = kb */
105-
if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK) { goto error; } /* k = 1/kb */
106-
if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK) { goto error; } /* s = xr */
107-
if ((err = mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK) { goto error; } /* s = xr/kb */
108-
if ((err = mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK) { goto error; } /* e = e/kb */
109-
if ((err = mp_add(e, s, s)) != CRYPT_OK) { goto error; } /* s = e/kb + xr/kb */
110-
if ((err = mp_mulmod(s, b, p, s)) != CRYPT_OK) { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
111-
ecc_free(&pubkey);
112-
if (mp_iszero(s) == LTC_MP_NO) {
113-
break;
114-
}
115-
}
116-
} while (--max_iterations > 0);
117-
118-
if (max_iterations == 0) {
119-
goto errnokey;
120-
}
121-
122-
if (recid) *recid = v;
123-
124-
if (sigformat == LTC_ECCSIG_ANSIX962) {
125-
/* store as ASN.1 SEQUENCE { r, s -- integer } */
126-
err = der_encode_sequence_multi(out, outlen,
127-
LTC_ASN1_INTEGER, 1UL, r,
128-
LTC_ASN1_INTEGER, 1UL, s,
129-
LTC_ASN1_EOL, 0UL, NULL);
130-
}
131-
else if (sigformat == LTC_ECCSIG_RFC7518) {
132-
/* RFC7518 format - raw (r,s) */
133-
if (*outlen < 2*pbytes) { err = CRYPT_MEM; goto errnokey; }
134-
zeromem(out, 2*pbytes);
135-
i = mp_unsigned_bin_size(r);
136-
if ((err = mp_to_unsigned_bin(r, out + (pbytes - i))) != CRYPT_OK) { goto errnokey; }
137-
i = mp_unsigned_bin_size(s);
138-
if ((err = mp_to_unsigned_bin(s, out + (2*pbytes - i))) != CRYPT_OK) { goto errnokey; }
139-
*outlen = 2*pbytes;
140-
err = CRYPT_OK;
141-
}
142-
else if (sigformat == LTC_ECCSIG_ETH27) {
143-
/* Ethereum (v,r,s) format */
144-
if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
145-
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
146-
err = CRYPT_ERROR; goto errnokey;
147-
}
148-
if (*outlen < 65) { err = CRYPT_MEM; goto errnokey; }
149-
zeromem(out, 65);
150-
i = mp_unsigned_bin_size(r);
151-
if ((err = mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) { goto errnokey; }
152-
i = mp_unsigned_bin_size(s);
153-
if ((err = mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) { goto errnokey; }
154-
out[64] = (unsigned char)(v + 27); /* Recovery ID is 27/28 for Ethereum */
155-
*outlen = 65;
156-
err = CRYPT_OK;
157-
}
158-
#ifdef LTC_SSH
159-
else if (sigformat == LTC_ECCSIG_RFC5656) {
160-
/* Get identifier string */
161-
char name[64];
162-
unsigned long namelen = sizeof(name);
163-
if ((err = ecc_ssh_ecdsa_encode_name(name, &namelen, key)) != CRYPT_OK) { goto errnokey; }
164-
165-
/* Store as SSH data sequence, per RFC4251 */
166-
err = ssh_encode_sequence_multi(out, outlen,
167-
LTC_SSHDATA_STRING, name,
168-
LTC_SSHDATA_MPINT, r,
169-
LTC_SSHDATA_MPINT, s,
170-
LTC_SSHDATA_EOL, NULL);
171-
}
172-
#endif
173-
else {
174-
/* Unknown signature format */
175-
err = CRYPT_ERROR;
176-
goto error;
177-
}
35+
if ((err = mp_init_multi(&r, &s, NULL)) != CRYPT_OK) return err;
36+
if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, NULL, key)) != CRYPT_OK) goto error;
17837

179-
goto errnokey;
38+
/* store as ASN.1 SEQUENCE { r, s -- integer } */
39+
err = der_encode_sequence_multi(out, outlen,
40+
LTC_ASN1_INTEGER, 1UL, r,
41+
LTC_ASN1_INTEGER, 1UL, s,
42+
LTC_ASN1_EOL, 0UL, NULL);
18043
error:
181-
ecc_free(&pubkey);
182-
errnokey:
183-
mp_clear_multi(r, s, e, b, NULL);
44+
mp_clear_multi(r, s, NULL);
18445
return err;
18546
}
18647

src/pk/ecc/ecc_sign_hash_eth27.c

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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+
Sign a message digest (Ethereum format with recovery_id+27)
16+
@param in The message digest to sign
17+
@param inlen The length of the digest
18+
@param out [out] The destination for the signature
19+
@param outlen [in/out] The max size and resulting size of the signature
20+
@param prng An active PRNG state
21+
@param wprng The index of the PRNG you wish to use
22+
@param key A private ECC key
23+
@return CRYPT_OK if successful
24+
*/
25+
int ecc_sign_hash_eth27(const unsigned char *in, unsigned long inlen,
26+
unsigned char *out, unsigned long *outlen,
27+
prng_state *prng, int wprng, const ecc_key *key)
28+
{
29+
int err, recid;
30+
void *r, *s;
31+
unsigned long i;
32+
33+
LTC_ARGCHK(out != NULL);
34+
LTC_ARGCHK(outlen != NULL);
35+
LTC_ARGCHK(key != NULL);
36+
37+
if ((err = mp_init_multi(&r, &s, NULL)) != CRYPT_OK) return err;
38+
if ((err = ecc_sign_hash_internal(in, inlen, r, s, prng, wprng, &recid, key)) != CRYPT_OK) goto error;
39+
40+
/* Only valid for secp256k1 - OID 1.3.132.0.10 */
41+
if (pk_oid_cmp_with_ulong("1.3.132.0.10", key->dp.oid, key->dp.oidlen) != CRYPT_OK) {
42+
err = CRYPT_ERROR;
43+
goto error;
44+
}
45+
if (*outlen < 65) {
46+
err = CRYPT_BUFFER_OVERFLOW;
47+
*outlen = 65;
48+
goto error;
49+
}
50+
zeromem(out, 65);
51+
*outlen = 65;
52+
i = mp_unsigned_bin_size(r);
53+
if ((err = mp_to_unsigned_bin(r, out + 32 - i)) != CRYPT_OK) goto error;
54+
i = mp_unsigned_bin_size(s);
55+
if ((err = mp_to_unsigned_bin(s, out + 64 - i)) != CRYPT_OK) goto error;
56+
out[64] = (unsigned char)(recid + 27); /* Recovery ID is 27/28 for Ethereum */
57+
err = CRYPT_OK;
58+
59+
error:
60+
mp_clear_multi(r, s, NULL);
61+
return err;
62+
}
63+
64+
#endif
65+
66+
/* ref: $Format:%D$ */
67+
/* git commit: $Format:%H$ */
68+
/* commit time: $Format:%ai$ */

0 commit comments

Comments
 (0)