Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 33 additions & 7 deletions uECC.c
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,7 @@ static int uECC_sign_with_k(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uECC_word_t *k,
uint8_t *recid,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding another parameter, you could return the recid in the first byte of k. That would reduce the overhead when people don't care about the recid.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh, that looks quite hacky. And uECC_sign_with_k is a static function, only used internally.

uint8_t *signature,
uECC_Curve curve) {

Expand All @@ -1245,9 +1246,9 @@ static int uECC_sign_with_k(const uint8_t *private_key,
uECC_word_t p[uECC_MAX_WORDS * 2];
#endif
uECC_word_t carry;
wordcount_t num_words = curve->num_words;
wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
bitcount_t num_n_bits = curve->num_n_bits;
const wordcount_t num_words = curve->num_words;
const wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits);
const bitcount_t num_n_bits = curve->num_n_bits;

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

if (recid) {
*recid = uECC_vli_testBit(p + num_words, 0);
}

/* Prevent side channel analysis of uECC_vli_modInv() to determine
bits of k / the private key by premultiplying by a random number */
uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */
uECC_vli_modInv(k, k, curve->n, num_n_words); /* k = 1 / k' */
uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k = 1 / k */

#if uECC_VLI_NATIVE_LITTLE_ENDIAN == 0
uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r */
uECC_vli_nativeToBytes(signature, curve->num_bytes, p); /* store r = p.x */
#endif

#if uECC_VLI_NATIVE_LITTLE_ENDIAN
Expand All @@ -1299,7 +1304,7 @@ static int uECC_sign_with_k(const uint8_t *private_key,
bcopy((uint8_t *) signature + curve->num_bytes, (uint8_t *) s, curve->num_bytes);
#else
uECC_vli_nativeToBytes(signature + curve->num_bytes, curve->num_bytes, s);
#endif
#endif
return 1;
}

Expand All @@ -1316,7 +1321,28 @@ int uECC_sign(const uint8_t *private_key,
return 0;
}

if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, curve)) {
if (uECC_sign_with_k(private_key, message_hash, hash_size, k, 0, signature, curve)) {
return 1;
}
}
return 0;
}

int uECC_sign_recoverable(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uint8_t *recid,
uint8_t *signature,
uECC_Curve curve) {
uECC_word_t k[uECC_MAX_WORDS];
uECC_word_t tries;

for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) {
if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) {
return 0;
}

if (uECC_sign_with_k(private_key, message_hash, hash_size, k, recid, signature, curve)) {
return 1;
}
}
Expand Down Expand Up @@ -1432,7 +1458,7 @@ int uECC_sign_deterministic(const uint8_t *private_key,
mask >> ((bitcount_t)(num_n_words * uECC_WORD_SIZE * 8 - num_n_bits));
}

if (uECC_sign_with_k(private_key, message_hash, hash_size, T, signature, curve)) {
if (uECC_sign_with_k(private_key, message_hash, hash_size, T, 0, signature, curve)) {
return 1;
}

Expand Down
25 changes: 25 additions & 0 deletions uECC.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,31 @@ Returns 1 if the key was computed successfully, 0 if an error occurred.
*/
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);

/* uECC_sign_recoverable() function.
Generate an ECDSA signature for a given hash value, with public key recovery.

Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
this function along with your private key.

Inputs:
private_key - Your private key.
message_hash - The hash of the message to sign.
hash_size - The size of message_hash in bytes.

Outputs:
recid - 0 or 1 recovery ID (the sign of P.y)
signature - Will be filled in with the signature value. Must be at least 2 * curve size long.
For example, if the curve is secp256r1, signature must be 64 bytes long.

Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign_recoverable(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uint8_t *recid,
uint8_t *signature,
uECC_Curve curve);

/* uECC_sign() function.
Generate an ECDSA signature for a given hash value.

Expand Down