Convert hash to int in sign/verify (#53)

Previously, callers would need to manually convert the hash value
appropriately if it was not the same length as curve_n. Now, callers
just pass in the full hash value and the length; uECC will convert
the hash as appropriate.
This commit is contained in:
Ken MacKay
2015-10-12 21:29:57 -07:00
parent 4ae15e365b
commit 0283b542ef
3 changed files with 50 additions and 15 deletions
+2 -2
View File
@@ -31,12 +31,12 @@ int main() {
}
memcpy(hash, public, sizeof(hash));
if (!uECC_sign(private, hash, sig, curves[c])) {
if (!uECC_sign(private, hash, sizeof(hash), sig, curves[c])) {
printf("uECC_sign() failed\n");
return 1;
}
if (!uECC_verify(public, hash, sig, curves[c])) {
if (!uECC_verify(public, hash, sizeof(hash), sig, curves[c])) {
printf("uECC_verify() failed\n");
return 1;
}
+36 -8
View File
@@ -1014,8 +1014,33 @@ int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uEC
/* -------- ECDSA code -------- */
static void bits2int(uECC_word_t *native,
const uint8_t *bits,
unsigned bits_size,
uECC_Curve curve) {
unsigned num_n_bytes = BITS_TO_BYTES(curve->num_n_bits);
unsigned num_n_words = BITS_TO_WORDS(curve->num_n_bits);
if (bits_size > num_n_bytes) {
bits_size = num_n_bytes;
}
uECC_vli_bytesToNative(native, bits, bits_size, curve);
if (bits_size * 8 <= (unsigned)curve->num_n_bits) {
return;
}
int shift = bits_size * 8 - curve->num_n_bits;
uECC_word_t carry = 0;
uECC_word_t *end = native;
native += num_n_words;
while (native-- > end) {
uECC_word_t temp = *native;
*native = (temp >> shift) | carry;
carry = temp << (uECC_WORD_BITS - shift);
}
}
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 *signature,
uECC_Curve curve) {
@@ -1071,7 +1096,7 @@ got_random:
uECC_vli_set(s, p, num_words);
uECC_vli_modMult(s, tmp, s, curve->n, num_n_words); /* s = r*d */
uECC_vli_bytesToNative(tmp, message_hash, curve->num_bytes, curve);
bits2int(tmp, message_hash, hash_size, curve);
uECC_vli_modAdd(s, tmp, s, curve->n, num_n_words); /* s = e + r*d */
uECC_vli_modMult(s, s, k, curve->n, num_n_words); /* s = (e + r*d) / k */
if (uECC_vli_numBits(s, num_n_words) > (bitcount_t)curve->num_bytes * 8) {
@@ -1083,6 +1108,7 @@ got_random:
int uECC_sign(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uint8_t *signature,
uECC_Curve curve) {
uECC_word_t k[uECC_MAX_WORDS];
@@ -1095,7 +1121,7 @@ int uECC_sign(const uint8_t *private_key,
return 0;
}
if (uECC_sign_with_k(private_key, message_hash, k, signature, curve)) {
if (uECC_sign_with_k(private_key, message_hash, hash_size, k, signature, curve)) {
return 1;
}
}
@@ -1146,13 +1172,14 @@ static void update_V(uECC_HashContext *hash_context, uint8_t *K, uint8_t *V) {
}
/* Deterministic signing, similar to RFC 6979. Differences are:
* We just use (truncated) H(m) directly rather than bits2octets(H(m))
* We just use H(m) directly rather than bits2octets(H(m))
(it is not reduced modulo curve_n).
* We generate a value for k (aka T) directly rather than converting endianness.
Layout of hash_context->tmp: <K> | <V> | (1 byte overlapped 0x00 or 0x01) / <HMAC pad> */
int uECC_sign_deterministic(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uECC_HashContext *hash_context,
uint8_t *signature,
uECC_Curve curve) {
@@ -1173,7 +1200,7 @@ int uECC_sign_deterministic(const uint8_t *private_key,
V[hash_context->result_size] = 0x00;
HMAC_update(hash_context, V, hash_context->result_size + 1);
HMAC_update(hash_context, private_key, num_bytes);
HMAC_update(hash_context, message_hash, num_bytes);
HMAC_update(hash_context, message_hash, hash_size);
HMAC_finish(hash_context, K, K);
update_V(hash_context, K, V);
@@ -1183,7 +1210,7 @@ int uECC_sign_deterministic(const uint8_t *private_key,
V[hash_context->result_size] = 0x01;
HMAC_update(hash_context, V, hash_context->result_size + 1);
HMAC_update(hash_context, private_key, num_bytes);
HMAC_update(hash_context, message_hash, num_bytes);
HMAC_update(hash_context, message_hash, hash_size);
HMAC_finish(hash_context, K, K);
update_V(hash_context, K, V);
@@ -1208,7 +1235,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, T, signature, curve)) {
if (uECC_sign_with_k(private_key, message_hash, hash_size, T, signature, curve)) {
return 1;
}
@@ -1228,7 +1255,8 @@ static bitcount_t smax(bitcount_t a, bitcount_t b) {
}
int uECC_verify(const uint8_t *public_key,
const uint8_t *hash,
const uint8_t *message_hash,
unsigned hash_size,
const uint8_t *signature,
uECC_Curve curve) {
uECC_word_t u1[uECC_MAX_WORDS], u2[uECC_MAX_WORDS];
@@ -1272,7 +1300,7 @@ int uECC_verify(const uint8_t *public_key,
/* Calculate u1 and u2. */
uECC_vli_modInv(z, s, curve->n, num_n_words); /* z = 1/s */
u1[num_n_words - 1] = 0;
uECC_vli_bytesToNative(u1, hash, curve->num_bytes, curve);
bits2int(u1, message_hash, hash_size, curve);
uECC_vli_modMult(u1, u1, z, curve->n, num_n_words); /* u1 = e/s */
uECC_vli_modMult(u2, r, z, curve->n, num_n_words); /* u2 = r/s */
+12 -5
View File
@@ -209,6 +209,7 @@ 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:
signature - Will be filled in with the signature value. Must be at least 2 * curve size long.
@@ -218,6 +219,7 @@ Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uint8_t *signature,
uECC_Curve curve);
@@ -277,11 +279,13 @@ this function; however, if the RNG is defined it will improve resistance to side
attacks.
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 and a hash context.
this function along with your private key and a hash context. Note that the message_hash
does not need to be computed with the same hash function used by hash_context.
Inputs:
private_key - Your private key.
message_hash - The hash of the message to sign.
hash_size - The size of message_hash in bytes.
hash_context - A hash context to use.
Outputs:
@@ -291,6 +295,7 @@ Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign_deterministic(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uECC_HashContext *hash_context,
uint8_t *signature,
uECC_Curve curve);
@@ -302,14 +307,16 @@ Usage: Compute the hash of the signed data using the same hash as the signer and
pass it to this function along with the signer's public key and the signature values (r and s).
Inputs:
public_key - The signer's public key
hash - The hash of the signed data.
signature - The signature value.
public_key - The signer's public key.
message_hash - The hash of the signed data.
hash_size - The size of message_hash in bytes.
signature - The signature value.
Returns 1 if the signature is valid, 0 if it is invalid.
*/
int uECC_verify(const uint8_t *private_key,
const uint8_t *hash,
const uint8_t *message_hash,
unsigned hash_size,
const uint8_t *signature,
uECC_Curve curve);