Skip to content

Commit d3d6c51

Browse files
committed
implementation of PR80 - kmackay#80
1 parent 601bd11 commit d3d6c51

File tree

2 files changed

+57
-6
lines changed

2 files changed

+57
-6
lines changed

uECC.c

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,7 @@ static int uECC_sign_with_k(const uint8_t *private_key,
12331233
const uint8_t *message_hash,
12341234
unsigned hash_size,
12351235
uECC_word_t *k,
1236+
uint8_t *recid,
12361237
uint8_t *signature,
12371238
uECC_Curve curve) {
12381239

@@ -1245,9 +1246,9 @@ static int uECC_sign_with_k(const uint8_t *private_key,
12451246
uECC_word_t p[uECC_MAX_WORDS * 2];
12461247
#endif
12471248
uECC_word_t carry;
1248-
wordcount_t num_words = curve->num_words;
1249-
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
1250-
bitcount_t num_n_bits = curve->num_n_bits;
1249+
const wordcount_t num_words = curve->num_words;
1250+
const wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
1251+
const bitcount_t num_n_bits = curve->num_n_bits;
12511252

12521253
/* Make sure 0 < k < curve_n */
12531254
if (uECC_vli_isZero(k, num_words) || uECC_vli_cmp(curve->n, k, num_n_words) != 1) {
@@ -1269,14 +1270,18 @@ static int uECC_sign_with_k(const uint8_t *private_key,
12691270
return 0;
12701271
}
12711272

1273+
if (recid) {
1274+
*recid = uECC_vli_testBit(p + num_words, 0);
1275+
}
1276+
12721277
/* Prevent side channel analysis of uECC_vli_modInv() to determine
12731278
bits of k / the private key by premultiplying by a random number */
12741279
uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */
12751280
uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */
12761281
uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */
12771282

12781283
#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0
1279-
uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */
1284+
uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r = p.x */
12801285
#endif
12811286

12821287
#if uECC_VLI_NATIVE_LITTLE_ENDIAN
@@ -1316,13 +1321,34 @@ int uECC_sign(const uint8_t *private_key,
13161321
return 0;
13171322
}
13181323

1319-
if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, curve)) {
1324+
if (uECC_sign_with_k(private_key, message_hash, hash_size, k, 0, signature, curve)) {
13201325
return 1;
13211326
}
13221327
}
13231328
return 0;
13241329
}
13251330

1331+
int uECC_sign_recoverable(const uint8_t *private_key,
1332+
const uint8_t *message_hash,
1333+
unsigned hash_size,
1334+
uint8_t *recid,
1335+
uint8_t *signature,
1336+
uECC_Curve curve) {
1337+
uECC_word_t k[uECC_MAX_WORDS];
1338+
uECC_word_t tries;
1339+
1340+
for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
1341+
if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) {
1342+
return 0;
1343+
}
1344+
1345+
if (uECC_sign_with_k(private_key, message_hash, hash_size, k, recid, signature, curve)) {
1346+
return 1;
1347+
}
1348+
}
1349+
return 0;
1350+
}
1351+
13261352
/* Compute an HMAC using K as a key (as in RFC 6979). Note that K is always
13271353
the same size as the hash result size. */
13281354
static void HMAC_init(const uECC_HashContext *hash_context, const uint8_t *K) {
@@ -1432,7 +1458,7 @@ int uECC_sign_deterministic(const uint8_t *private_key,
14321458
mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits));
14331459
}
14341460

1435-
if (uECC_sign_with_k(private_key, message_hash, hash_size, T, signature, curve)) {
1461+
if (uECC_sign_with_k(private_key, message_hash, hash_size, T, 0, signature, curve)) {
14361462
return 1;
14371463
}
14381464

uECC.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,31 @@ Returns 1 if the key was computed successfully, 0 if an error occurred.
238238
*/
239239
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);
240240

241+
/* uECC_sign_recoverable() function.
242+
Generate an ECDSA signature for a given hash value, with public key recovery.
243+
244+
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
245+
this function along with your private key.
246+
247+
Inputs:
248+
private_key - Your private key.
249+
message_hash - The hash of the message to sign.
250+
hash_size - The size of message_hash in bytes.
251+
252+
Outputs:
253+
recid - 0 or 1 recovery ID (the sign of P.y)
254+
signature - Will be filled in with the signature value. Must be at least 2 * curve size long.
255+
For example, if the curve is secp256r1, signature must be 64 bytes long.
256+
257+
Returns 1 if the signature generated successfully, 0 if an error occurred.
258+
*/
259+
int uECC_sign_recoverable(const uint8_t *private_key,
260+
const uint8_t *message_hash,
261+
unsigned hash_size,
262+
uint8_t *recid,
263+
uint8_t *signature,
264+
uECC_Curve curve);
265+
241266
/* uECC_sign() function.
242267
Generate an ECDSA signature for a given hash value.
243268

0 commit comments

Comments
 (0)