Skip to content

Commit e29363a

Browse files
author
Jong-Shian Wu
committed
make uECC_sign_deterministic conform to RFC 6979
1 parent 81ff1f5 commit e29363a

File tree

2 files changed

+62
-5
lines changed

2 files changed

+62
-5
lines changed

uECC.c

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2594,17 +2594,38 @@ int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES],
25942594
uint8_t *V = K + hash_context->result_size;
25952595
uECC_word_t tries;
25962596
unsigned i;
2597+
uECC_word_t tmp[uECC_N_WORDS]; // an integer converted from message_hash
2598+
uint8_t reduced_msg_hash[uECC_N_BYTES] = { 0 };
2599+
25972600
for (i = 0; i < hash_context->result_size; ++i) {
25982601
V[i] = 0x01;
25992602
K[i] = 0;
26002603
}
26012604

2605+
// Convert the octet string of length `uECC_BYTES` into an integer tmp.
2606+
// Since this must be done when generating an ECDSA signature, we may
2607+
// choose to refactor the codebase so that this operation is done only
2608+
// once.
2609+
vli_bytesToNative(tmp, message_hash);
2610+
2611+
// Modular reduction: tmp <- tmp mod n (ONLY FOR RFC6979)
2612+
while (vli_cmp_n(tmp, curve_n) >= 0) {
2613+
vli_sub(tmp, tmp, curve_n);
2614+
}
2615+
2616+
// Convert the integer tmp back to an octet string (ONLY FOR RFC6979)
2617+
#if (uECC_CURVE == uECC_secp160r1)
2618+
vli_nativeToBytes(reduced_msg_hash + 1, tmp);
2619+
#else
2620+
vli_nativeToBytes(reduced_msg_hash, tmp);
2621+
#endif
2622+
26022623
// K = HMAC_K(V || 0x00 || int2octets(x) || h(m))
26032624
HMAC_init(hash_context, K);
26042625
V[hash_context->result_size] = 0x00;
26052626
HMAC_update(hash_context, V, hash_context->result_size + 1);
26062627
HMAC_update(hash_context, private_key, uECC_BYTES);
2607-
HMAC_update(hash_context, message_hash, uECC_BYTES);
2628+
HMAC_update(hash_context, reduced_msg_hash, uECC_N_BYTES);
26082629
HMAC_finish(hash_context, K, K);
26092630

26102631
update_V(hash_context, K, V);
@@ -2614,13 +2635,14 @@ int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES],
26142635
V[hash_context->result_size] = 0x01;
26152636
HMAC_update(hash_context, V, hash_context->result_size + 1);
26162637
HMAC_update(hash_context, private_key, uECC_BYTES);
2617-
HMAC_update(hash_context, message_hash, uECC_BYTES);
2638+
HMAC_update(hash_context, reduced_msg_hash, uECC_N_BYTES);
26182639
HMAC_finish(hash_context, K, K);
26192640

26202641
update_V(hash_context, K, V);
26212642

26222643
for (tries = 0; tries < MAX_TRIES; ++tries) {
2623-
uECC_word_t T[uECC_N_WORDS];
2644+
uECC_word_t k[uECC_N_WORDS] = { 0 }; // the RFC6979 ephemeral key in each round
2645+
uint8_t T[uECC_N_BYTES];
26242646
uint8_t *T_ptr = (uint8_t *)T;
26252647
unsigned T_bytes = 0;
26262648
while (T_bytes < sizeof(T)) {
@@ -2630,10 +2652,37 @@ int uECC_sign_deterministic(const uint8_t private_key[uECC_BYTES],
26302652
}
26312653
}
26322654
#if (uECC_CURVE == uECC_secp160r1)
2633-
T[uECC_WORDS] &= 0x01;
2655+
//
2656+
// NOTE:
2657+
//
2658+
// The function vli_bytesToNative converts a big-endian array of
2659+
// length uECC_BYTES=20 where each unit is 1-byte long into a native
2660+
// little-endian array of length uECC_WORDS=20/5/3 where each unit is
2661+
// 1/4/8-byte long.
2662+
//
2663+
// Maybe we should have a version of vli_bytesToNative that does the
2664+
// same thing for uECC_N_BYTES=21 and uECC_N_WORDS=21/6/3?
2665+
//
2666+
// TODO:
2667+
//
2668+
// Before vli_bytesToNative() we should right-shift all bits in T by 7
2669+
// so that the leftmost 161 bits in T are used in order to comform to
2670+
// RFC6979.
2671+
//
2672+
vli_bytesToNative(k, T + 1);
2673+
if (T[0] & 1) {
2674+
// k <- k + 2^160
2675+
#if (uECC_WORD_SIZE == 1 || uECC_WORD_SIZE == 4)
2676+
k[uECC_N_WORDS - 1] = 1;
2677+
#elif (uECC_WORD_SIZE == 8)
2678+
k[uECC_N_WORDS - 1] ^= (1 << 32);
2679+
#endif
2680+
}
2681+
#else
2682+
vli_bytesToNative(k, T);
26342683
#endif
26352684

2636-
if (uECC_sign_with_k(private_key, message_hash, T, signature)) {
2685+
if (uECC_sign_with_k(private_key, message_hash, k, signature)) {
26372686
return 1;
26382687
}
26392688

uECC.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ faster by about 8% but increases the code size. */
6060

6161
#define uECC_BYTES uECC_CONCAT(uECC_size_, uECC_CURVE)
6262

63+
#define uECC_n_size_1 21 /* secp160r1 */
64+
#define uECC_n_size_2 24 /* secp192r1 */
65+
#define uECC_n_size_3 32 /* secp256r1 */
66+
#define uECC_n_size_4 32 /* secp256k1 */
67+
#define uECC_n_size_5 28 /* secp224r1 */
68+
69+
#define uECC_N_BYTES uECC_CONCAT(uECC_n_size_, uECC_CURVE)
70+
6371
#ifdef __cplusplus
6472
extern "C"
6573
{

0 commit comments

Comments
 (0)