From fe65087fc238aafb7517dfa238f15fab9865107c Mon Sep 17 00:00:00 2001 From: Ken MacKay Date: Tue, 21 May 2013 22:19:45 -0700 Subject: [PATCH] Initial ECDSA implementation. --- ecdh.c | 687 +++++++++++++++++++++++++++++++---------------- ecdh.h | 12 +- test/check_dsa.c | 81 ++++++ test/dsa1.c | 55 ++++ 4 files changed, 607 insertions(+), 228 deletions(-) create mode 100644 test/check_dsa.c create mode 100644 test/dsa1.c diff --git a/ecdh.c b/ecdh.c index 5bb4b89..08c44f6 100644 --- a/ecdh.c +++ b/ecdh.c @@ -4,12 +4,26 @@ typedef unsigned int uint; +#define CONCAT1(a, b) a##b +#define CONCAT(a, b) CONCAT1(a, b) + #define Curve_P_4 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD} #define Curve_P_5 {0x7FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} #define Curve_P_6 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} #define Curve_P_7 {0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} #define Curve_P_8 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF} +#define Curve_A_4 {0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD} +#define Curve_B_4 {0x2CEE5ED3, 0xD824993C, 0x1079F43D, 0xE87579C1} +#define Curve_A_5 {0x7FFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define Curve_B_5 {0xC565FA45, 0x81D4D4AD, 0x65ACF89F, 0x54BD7A8B, 0x1C97BEFC} +#define Curve_A_6 {0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define Curve_B_6 {0xC146B9B1, 0xFEB8DEEC, 0x72243049, 0x0FA7E9AB, 0xE59C80E7, 0x64210519} +#define Curve_A_7 {0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define Curve_B_7 {0x2355FFB4, 0x270B3943, 0xD7BFD8BA, 0x5044B0B7, 0xF5413256, 0x0C04B3AB, 0xB4050A85} +#define Curve_A_8 {0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF} +#define Curve_B_8 {0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, 0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8} + #define Curve_G_4 { \ {0xA52C5B86, 0x0C28607C, 0x8B899B2D, 0x161FF752}, \ {0xDDED7A83, 0xC02DA292, 0x5BAFEB13, 0xCF5AC839}} @@ -31,32 +45,40 @@ typedef unsigned int uint; {0x37BF51F5, 0xCBB64068, 0x6B315ECE, 0x2BCE3357, 0x7C0F9E16, 0x8EE7EB4A, 0xFE1A7F9B, 0x4FE342E2}} #define Curve_N_4 {0x9038A115, 0x75A30D1B, 0x00000000, 0xFFFFFFFE} -#define Curve_N_5 {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} /* n for secp160r1 is larger than 160 bits */ +#define N_size_4 4 +#define Curve_N_5 {0xca752257, 0xf927aed3, 0x0001f4c8, 0x00000000, 0x00000000, 0x00000001} +#define N_size_5 6 #define Curve_N_6 {0xB4D22831, 0x146BC9B1, 0x99DEF836, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define N_size_6 6 #define Curve_N_7 {0x5C5C2A3D, 0x13DD2945, 0xE0B8F03E, 0xFFFF16A2, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define N_size_7 7 #define Curve_N_8 {0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF} +#define N_size_8 8 -#define CONCAT1(a, b) a##b -#define CONCAT(a, b) CONCAT1(a, b) +#define N_size CONCAT(N_size_, ECC_CURVE) static uint32_t curve_p[NUM_ECC_DIGITS] = CONCAT(Curve_P_, ECC_CURVE); +static uint32_t curve_a[NUM_ECC_DIGITS] = CONCAT(Curve_A_, ECC_CURVE); +static uint32_t curve_b[NUM_ECC_DIGITS] = CONCAT(Curve_B_, ECC_CURVE); static EccPoint curve_G = CONCAT(Curve_G_, ECC_CURVE); -static uint32_t curve_n[NUM_ECC_DIGITS] = CONCAT(Curve_N_, ECC_CURVE); +static uint32_t curve_n[N_size] = CONCAT(Curve_N_, ECC_CURVE); -static void vli_clear(uint32_t *p_vli) +static void vli_modMult(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, uint p_size, uint32_t *p_mod, uint p_modSize); + +static void vli_clear(uint32_t *p_vli, uint p_size) { uint i; - for(i=0; i= 0 && p_vli[i] == 0; --i) + for (i = p_size - 1; i >= 0 && p_vli[i] == 0; --i) { } @@ -86,12 +108,12 @@ static uint vli_numDigits(uint32_t *p_vli) } /* Counts the number of bits required for p_vli. */ -static uint vli_numBits(uint32_t *p_vli) +static uint vli_numBits(uint32_t *p_vli, uint p_size) { uint i; uint32_t l_digit; - uint l_numDigits = vli_numDigits(p_vli); + uint l_numDigits = vli_numDigits(p_vli, p_size); if(l_numDigits == 0) { return 0; @@ -107,20 +129,20 @@ static uint vli_numBits(uint32_t *p_vli) } /* Sets p_dest = p_src. */ -static void vli_set(uint32_t *p_dest, uint32_t *p_src) +static void vli_set(uint32_t *p_dest, uint32_t *p_src, uint p_size) { uint i; - for(i=0; i= 0; --i) + for(i = p_size-1; i >= 0; --i) { if(p_left[i] > p_right[i]) { @@ -135,11 +157,11 @@ static int vli_cmp(uint32_t *p_left, uint32_t *p_right) } /* Computes p_result = p_in << c, returning carry. Can modify in place (if p_result == p_in). 0 < p_shift < 32. */ -static uint32_t vli_lshift(uint32_t *p_result, uint32_t *p_in, uint p_shift) +static uint32_t vli_lshift(uint32_t *p_result, uint32_t *p_in, uint p_shift, uint p_size) { uint32_t l_carry = 0; uint i; - for(i = 0; i < NUM_ECC_DIGITS; ++i) + for(i = 0; i < p_size; ++i) { uint32_t l_temp = p_in[i]; p_result[i] = (l_temp << p_shift) | l_carry; @@ -150,12 +172,12 @@ static uint32_t vli_lshift(uint32_t *p_result, uint32_t *p_in, uint p_shift) } /* Computes p_vli = p_vli >> 1. */ -static void vli_rshift1(uint32_t *p_vli) +static void vli_rshift1(uint32_t *p_vli, uint p_size) { uint32_t *l_end = p_vli; uint32_t l_carry = 0; - p_vli += NUM_ECC_DIGITS; + p_vli += p_size; while(p_vli-- > l_end) { uint32_t l_temp = *p_vli; @@ -166,11 +188,11 @@ static void vli_rshift1(uint32_t *p_vli) /* Computes p_result = p_left + p_right, returning carry. Can modify in place. Could be much more efficient in asm. */ -static uint32_t vli_add(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right) +static uint32_t vli_add(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, uint p_size) { uint32_t l_carry = 0; uint i; - for(i=0; i= 0) + uint32_t l_carry = vli_add(p_result, p_left, p_right, p_size); + if(l_carry || vli_cmp(p_result, p_mod, p_size) >= 0) { /* p_result > p_mod (p_result = p_mod + remainder), so subtract p_mod to get remainder. */ - vli_sub(p_result, p_result, p_mod); + vli_sub(p_result, p_result, p_mod, p_size); } } /* Computes p_result = (p_left - p_right) % p_mod. Assumes that p_left < p_mod and p_right < p_mod, p_result != p_mod. */ -static void vli_modSub(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, uint32_t *p_mod) +static void vli_modSub(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, uint32_t *p_mod, uint p_size) { - uint32_t l_borrow = vli_sub(p_result, p_left, p_right); + uint32_t l_borrow = vli_sub(p_result, p_left, p_right, p_size); if(l_borrow) { /* In this case, p_result == -diff == (max int) - diff. Since -x % d == d - x, we can get the correct result from p_result + p_mod (with overflow). */ - vli_add(p_result, p_result, p_mod); + vli_add(p_result, p_result, p_mod, p_size ); } } #if ECC_CURVE == secp128r1 -/* Computes p_result = p_product % p_mod. +/* Computes p_result = p_product % curve_p. See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */ -static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) +static void vli_mmod_fast(uint32_t *p_result, uint32_t *p_product) { - uint32_t l_tmp[4]; + uint32_t l_tmp[NUM_ECC_DIGITS]; int l_carry; - vli_set(p_result, p_product); + vli_set(p_result, p_product, NUM_ECC_DIGITS); l_tmp[0] = p_product[4]; l_tmp[1] = p_product[5]; l_tmp[2] = p_product[6]; l_tmp[3] = (p_product[7] & 0x00000001) | (p_product[4] << 1); - l_carry = vli_add(p_result, p_result, l_tmp); + l_carry = vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[0] = (p_product[4] >> 31) | (p_product[5] << 1); l_tmp[1] = (p_product[5] >> 31) | (p_product[6] << 1); l_tmp[2] = (p_product[6] >> 31) | (p_product[7] << 1); l_tmp[3] = (p_product[7] >> 31) | ((p_product[4] & 0x80000000) >> 30) | (p_product[5] << 2); - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[0] = (p_product[5] >> 30) | (p_product[6] << 2); l_tmp[1] = (p_product[6] >> 30) | (p_product[7] << 2); l_tmp[2] = (p_product[7] >> 30); l_tmp[3] = ((p_product[5] & 0xC0000000) >> 29) | (p_product[6] << 3); - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[0] = (p_product[6] >> 29) | (p_product[7] << 3); l_tmp[1] = (p_product[7] >> 29); l_tmp[2] = 0; l_tmp[3] = ((p_product[6] & 0xE0000000) >> 28) | (p_product[7] << 4); - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[0] = (p_product[7] >> 28); l_tmp[1] = 0; l_tmp[2] = 0; l_tmp[3] = (p_product[7] & 0xFFFFFFFE); - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[0] = 0; l_tmp[1] = 0; l_tmp[2] = 0; l_tmp[3] = ((p_product[7] & 0xF0000000) >> 27); - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); - while(l_carry || vli_cmp(p_mod, p_result) != 1) + while(l_carry || vli_cmp(curve_p, p_result, NUM_ECC_DIGITS) != 1) { - l_carry -= vli_sub(p_result, p_result, p_mod); + l_carry -= vli_sub(p_result, p_result, curve_p, NUM_ECC_DIGITS); } } #elif ECC_CURVE == secp160r1 -/* Computes p_result = p_product % p_mod. +/* Computes p_result = p_product % curve_p. See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */ -static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) +static void vli_mmod_fast(uint32_t *p_result, uint32_t *p_product) { - uint32_t l_tmp[5]; + uint32_t l_tmp[NUM_ECC_DIGITS]; int l_carry; - vli_set(p_result, p_product); + vli_set(p_result, p_product, NUM_ECC_DIGITS); l_tmp[0] = (p_product[5] & 0x7FFFFFFF) | (p_product[5] << 31); l_tmp[1] = (p_product[5] >> 1) | (p_product[6] << 31); l_tmp[2] = (p_product[6] >> 1) | (p_product[7] << 31); l_tmp[3] = (p_product[7] >> 1) | (p_product[8] << 31); l_tmp[4] = (p_product[8] >> 1) | (p_product[9] << 31); - l_carry = vli_add(p_result, p_result, l_tmp); + l_carry = vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[0] = (p_product[9] >> 1) | (p_product[5] & 0x80000000); l_tmp[1] = p_product[6]; l_tmp[2] = p_product[7]; l_tmp[3] = p_product[8]; l_tmp[4] = p_product[9]; - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[0] = ((p_product[9] & 0x00000002) << 30); l_tmp[1] = (p_product[9] >> 2); l_tmp[2] = 0; l_tmp[3] = 0; l_tmp[4] = 0; - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); - while(l_carry || vli_cmp(p_mod, p_result) != 1) + while(l_carry || vli_cmp(curve_p, p_result, NUM_ECC_DIGITS) != 1) { - l_carry -= vli_sub(p_result, p_result, p_mod); + l_carry -= vli_sub(p_result, p_result, curve_p, NUM_ECC_DIGITS); } } #elif ECC_CURVE == secp192r1 -/* Computes p_result = p_product % p_mod. +/* Computes p_result = p_product % curve_p. See algorithm 5 and 6 from http://www.isys.uni-klu.ac.at/PDF/2001-0126-MT.pdf */ -static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) +static void vli_mmod_fast(uint32_t *p_result, uint32_t *p_product) { - uint32_t l_tmp[6]; + uint32_t l_tmp[NUM_ECC_DIGITS]; int l_carry; - vli_set(p_result, p_product); + vli_set(p_result, p_product, NUM_ECC_DIGITS); - vli_set(l_tmp, &p_product[6]); - l_carry = vli_add(p_result, p_result, l_tmp); + vli_set(l_tmp, &p_product[6], NUM_ECC_DIGITS); + l_carry = vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[0] = l_tmp[1] = 0; l_tmp[2] = p_product[6]; l_tmp[3] = p_product[7]; l_tmp[4] = p_product[8]; l_tmp[5] = p_product[9]; - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[0] = l_tmp[2] = p_product[10]; l_tmp[1] = l_tmp[3] = p_product[11]; l_tmp[4] = l_tmp[5] = 0; - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); - while(l_carry || vli_cmp(p_mod, p_result) != 1) + while(l_carry || vli_cmp(curve_p, p_result, NUM_ECC_DIGITS) != 1) { - l_carry -= vli_sub(p_result, p_result, p_mod); + l_carry -= vli_sub(p_result, p_result, curve_p, NUM_ECC_DIGITS); } } #elif ECC_CURVE == secp224r1 -/* Computes p_result = p_product % p_mod. +/* Computes p_result = p_product % curve_p. See http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) +static void vli_mmod_fast(uint32_t *p_result, uint32_t *p_product) { - uint32_t l_tmp[7]; + uint32_t l_tmp[NUM_ECC_DIGITS]; int l_carry; - vli_set(p_result, p_product); + vli_set(p_result, p_product, NUM_ECC_DIGITS); l_tmp[0] = l_tmp[1] = l_tmp[2] = 0; l_tmp[3] = p_product[7]; l_tmp[4] = p_product[8]; l_tmp[5] = p_product[9]; l_tmp[6] = p_product[10]; - l_carry = vli_add(p_result, p_result, l_tmp); + l_carry = vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[3] = p_product[11]; l_tmp[4] = p_product[12]; l_tmp[5] = p_product[13]; l_tmp[6] = 0; - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); vli_set(l_tmp, &p_product[7]); - l_carry -= vli_sub(p_result, p_result, l_tmp); + l_carry -= vli_sub(p_result, p_result, l_tmp, NUM_ECC_DIGITS); l_tmp[0] = p_product[11]; l_tmp[1] = p_product[12]; l_tmp[2] = p_product[13]; l_tmp[3] = l_tmp[4] = l_tmp[5] = l_tmp[6] = 0; - l_carry -= vli_sub(p_result, p_result, l_tmp); + l_carry -= vli_sub(p_result, p_result, l_tmp, NUM_ECC_DIGITS); if(l_carry < 0) { do { - l_carry += vli_add(p_result, p_result, p_mod); + l_carry += vli_add(p_result, p_result, curve_p, NUM_ECC_DIGITS); } while(l_carry < 0); } else { - while(l_carry || vli_cmp(p_mod, p_result) != 1) + while(l_carry || vli_cmp(curve_p, p_result, NUM_ECC_DIGITS) != 1) { - l_carry -= vli_sub(p_result, p_result, p_mod); + l_carry -= vli_sub(p_result, p_result, curve_p, NUM_ECC_DIGITS); } } } #elif ECC_CURVE == secp256r1 -/* Computes p_result = p_product % p_mod +/* Computes p_result = p_product % curve_p from http://www.nsa.gov/ia/_files/nist-routines.pdf */ -static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) +static void vli_mmod_fast(uint32_t *p_result, uint32_t *p_product) { - uint32_t l_tmp[8]; + uint32_t l_tmp[NUM_ECC_DIGITS]; int l_carry; /* t */ - vli_set(p_result, p_product); + vli_set(p_result, p_product, NUM_ECC_DIGITS); /* s1 */ l_tmp[0] = l_tmp[1] = l_tmp[2] = 0; @@ -458,8 +480,8 @@ static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) l_tmp[5] = p_product[13]; l_tmp[6] = p_product[14]; l_tmp[7] = p_product[15]; - l_carry = vli_lshift(l_tmp, l_tmp, 1); - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry = vli_lshift(l_tmp, l_tmp, 1, NUM_ECC_DIGITS); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); /* s2 */ l_tmp[3] = p_product[12]; @@ -467,8 +489,8 @@ static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) l_tmp[5] = p_product[14]; l_tmp[6] = p_product[15]; l_tmp[7] = 0; - l_carry += vli_lshift(l_tmp, l_tmp, 1); - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_lshift(l_tmp, l_tmp, 1, NUM_ECC_DIGITS); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); /* s3 */ l_tmp[0] = p_product[8]; @@ -477,7 +499,7 @@ static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) l_tmp[3] = l_tmp[4] = l_tmp[5] = 0; l_tmp[6] = p_product[14]; l_tmp[7] = p_product[15]; - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); /* s4 */ l_tmp[0] = p_product[9]; @@ -488,7 +510,7 @@ static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) l_tmp[5] = p_product[15]; l_tmp[6] = p_product[13]; l_tmp[7] = p_product[8]; - l_carry += vli_add(p_result, p_result, l_tmp); + l_carry += vli_add(p_result, p_result, l_tmp, NUM_ECC_DIGITS); /* d1 */ l_tmp[0] = p_product[11]; @@ -497,7 +519,7 @@ static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) l_tmp[3] = l_tmp[4] = l_tmp[5] = 0; l_tmp[6] = p_product[8]; l_tmp[7] = p_product[10]; - l_carry -= vli_sub(p_result, p_result, l_tmp); + l_carry -= vli_sub(p_result, p_result, l_tmp, NUM_ECC_DIGITS); /* d2 */ l_tmp[0] = p_product[12]; @@ -507,7 +529,7 @@ static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) l_tmp[4] = l_tmp[5] = 0; l_tmp[6] = p_product[9]; l_tmp[7] = p_product[11]; - l_carry -= vli_sub(p_result, p_result, l_tmp); + l_carry -= vli_sub(p_result, p_result, l_tmp, NUM_ECC_DIGITS); /* d3 */ l_tmp[0] = p_product[13]; @@ -518,7 +540,7 @@ static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) l_tmp[5] = p_product[10]; l_tmp[6] = 0; l_tmp[7] = p_product[12]; - l_carry -= vli_sub(p_result, p_result, l_tmp); + l_carry -= vli_sub(p_result, p_result, l_tmp, NUM_ECC_DIGITS); /* d4 */ l_tmp[0] = p_product[14]; @@ -529,46 +551,46 @@ static void vli_mmod(uint32_t *p_result, uint32_t *p_product, uint32_t *p_mod) l_tmp[5] = p_product[11]; l_tmp[6] = 0; l_tmp[7] = p_product[13]; - l_carry -= vli_sub(p_result, p_result, l_tmp); + l_carry -= vli_sub(p_result, p_result, l_tmp, NUM_ECC_DIGITS); if(l_carry < 0) { do { - l_carry += vli_add(p_result, p_result, p_mod); + l_carry += vli_add(p_result, p_result, curve_p, NUM_ECC_DIGITS); } while(l_carry < 0); } else { - while(l_carry || vli_cmp(p_mod, p_result) != 1) + while(l_carry || vli_cmp(curve_p, p_result, NUM_ECC_DIGITS) != 1) { - l_carry -= vli_sub(p_result, p_result, p_mod); + l_carry -= vli_sub(p_result, p_result, curve_p, NUM_ECC_DIGITS); } } } #endif -/* Computes p_result = (p_left * p_right) % p_mod. */ -static void vli_modMult(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, uint32_t *p_mod) +/* Computes p_result = (p_left * p_right) % curve_p. */ +static void vli_modMult_fast(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right) { - uint32_t l_product[2 * NUM_ECC_DIGITS]; - vli_mult(l_product, p_left, p_right); - vli_mmod(p_result, l_product, p_mod); + uint32_t l_product[2 * NUM_ECC_DIGITS]; + vli_mult(l_product, p_left, p_right, NUM_ECC_DIGITS); + vli_mmod_fast(p_result, l_product); } #if ECC_SQUARE_FUNC /* Computes p_result = p_left^2. */ -static void vli_square(uint32_t *p_result, uint32_t *p_left) +static void vli_square(uint32_t *p_result, uint32_t *p_left, uint p_size) { uint64_t r01 = 0; uint32_t r2 = 0; uint i, k; - for(k=0; k < NUM_ECC_DIGITS*2 - 1; ++k) + for(k=0; k < p_size*2 - 1; ++k) { - uint l_min = (k < NUM_ECC_DIGITS ? 0 : (k + 1) - NUM_ECC_DIGITS); + uint l_min = (k < p_size ? 0 : (k + 1) - p_size); for(i=l_min; i<=k && i<=k-i; ++i) { #if ECC_SOFT_MULT64 @@ -594,20 +616,21 @@ static void vli_square(uint32_t *p_result, uint32_t *p_left) r2 = 0; } - p_result[NUM_ECC_DIGITS*2 - 1] = (uint32_t)r01; + p_result[p_size*2 - 1] = (uint32_t)r01; } -/* Computes p_result = p_left^2 % p_mod. */ -static void vli_modSquare(uint32_t *p_result, uint32_t *p_left, uint32_t *p_mod) +/* Computes p_result = p_left^2 % curve_p. */ +static void vli_modSquare_fast(uint32_t *p_result, uint32_t *p_left) { uint32_t l_product[2 * NUM_ECC_DIGITS]; - vli_square(l_product, p_left); - vli_mmod(p_result, l_product, p_mod); + vli_square(l_product, p_left, NUM_ECC_DIGITS); + vli_mmod_fast(p_result, l_product); } #else /* ECC_SQUARE_FUNC */ -#define vli_modSquare(result, left, mod) vli_modMult((result), (left), (left), (mod)) +#define vli_square(result, left, size) vli_mult((result), (left), (left), (size)) +#define vli_modSquare_fast(result, left) vli_modMult_fast((result), (left), (left)) #endif /* ECC_SQUARE_FUNC */ @@ -615,98 +638,98 @@ static void vli_modSquare(uint32_t *p_result, uint32_t *p_left, uint32_t *p_mod) /* Computes p_result = (p_left / p_right) % p_mod. All VLIs are the same size. See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */ -static void vli_modDiv(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, uint32_t *p_mod) +static void vli_modDiv(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, uint32_t *p_mod, uint p_size) { - uint32_t a[NUM_ECC_DIGITS], b[NUM_ECC_DIGITS], u[NUM_ECC_DIGITS], v[NUM_ECC_DIGITS]; + uint32_t a[p_size], b[p_size], u[p_size], v[p_size]; uint32_t l_carry; + + vli_set(a, p_right, p_size); + vli_set(b, p_mod, p_size); + vli_set(u, p_left, p_size); + vli_clear(v, p_size); + int l_cmpResult; - - vli_set(a, p_right); - vli_set(b, p_mod); - vli_set(u, p_left); - vli_clear(v); - - while ((l_cmpResult = vli_cmp(a, b)) != 0) + while ((l_cmpResult = vli_cmp(a, b, p_size)) != 0) { l_carry = 0; if(EVEN(a)) { - vli_rshift1(a); + vli_rshift1(a, p_size); if(!EVEN(u)) { - l_carry = vli_add(u, u, p_mod); + l_carry = vli_add(u, u, p_mod, p_size); } - vli_rshift1(u); + vli_rshift1(u, p_size); if(l_carry) { - u[NUM_ECC_DIGITS-1] |= 0x80000000; + u[p_size-1] |= 0x80000000; } } else if(EVEN(b)) { - vli_rshift1(b); + vli_rshift1(b, p_size); if(!EVEN(v)) { - l_carry = vli_add(v, v, p_mod); + l_carry = vli_add(v, v, p_mod, p_size); } - vli_rshift1(v); + vli_rshift1(v, p_size); if(l_carry) { - v[NUM_ECC_DIGITS-1] |= 0x80000000; + v[p_size-1] |= 0x80000000; } } else if(l_cmpResult > 0) { - vli_sub(a, a, b); - vli_rshift1(a); - if(vli_cmp(u, v) < 0) + vli_sub(a, a, b, p_size); + vli_rshift1(a, p_size); + if(vli_cmp(u, v, p_size) < 0) { - vli_add(u, u, p_mod); + vli_add(u, u, p_mod, p_size); } - vli_sub(u, u, v); + vli_sub(u, u, v, p_size); if(!EVEN(u)) { - l_carry = vli_add(u, u, p_mod); + l_carry = vli_add(u, u, p_mod, p_size); } - vli_rshift1(u); + vli_rshift1(u, p_size); if(l_carry) { - u[NUM_ECC_DIGITS-1] |= 0x80000000; + u[p_size-1] |= 0x80000000; } } else { - vli_sub(b, b, a); - vli_rshift1(b); - if(vli_cmp(v, u) < 0) + vli_sub(b, b, a, p_size); + vli_rshift1(b, p_size); + if(vli_cmp(v, u, p_size) < 0) { - vli_add(v, v, p_mod); + vli_add(v, v, p_mod, p_size); } - vli_sub(v, v, u); + vli_sub(v, v, u, p_size); if(!EVEN(v)) { - l_carry = vli_add(v, v, p_mod); + l_carry = vli_add(v, v, p_mod, p_size); } - vli_rshift1(v); + vli_rshift1(v, p_size); if(l_carry) { - v[NUM_ECC_DIGITS-1] |= 0x80000000; + v[p_size-1] |= 0x80000000; } } } - vli_set(p_result, u); + vli_set(p_result, u, p_size); } /* Computes p_result = (1 / p_input) % p_mod. All VLIs are the same size. */ -static void vli_modInv(uint32_t *p_result, uint32_t *p_input, uint32_t *p_mod) +static void vli_modInv(uint32_t *p_result, uint32_t *p_input, uint32_t *p_mod, uint p_size) { - uint32_t n[NUM_ECC_DIGITS]; + uint32_t n[p_size]; - vli_clear(n); + vli_clear(n, p_size); n[0] = 1; - vli_modDiv(p_result, n, p_input, p_mod); + vli_modDiv(p_result, n, p_input, p_mod, p_size); } /* ------ Point operations ------ */ @@ -714,8 +737,8 @@ static void vli_modInv(uint32_t *p_result, uint32_t *p_input, uint32_t *p_mod) /* Clears a point (set it to the point at infinity). */ static void EccPoint_clear(EccPoint *p_point) { - vli_clear(p_point->x); - vli_clear(p_point->y); + vli_clear(p_point->x, NUM_ECC_DIGITS); + vli_clear(p_point->y, NUM_ECC_DIGITS); } /* Copies a point. */ @@ -723,15 +746,15 @@ static void EccPoint_copy(EccPoint *p_dest, EccPoint *p_src) { if(p_dest != p_src) { - vli_set(p_dest->x, p_src->x); - vli_set(p_dest->y, p_src->y); + vli_set(p_dest->x, p_src->x, NUM_ECC_DIGITS); + vli_set(p_dest->y, p_src->y, NUM_ECC_DIGITS); } } /* Returns 1 if p_point is the point at infinity, 0 otherwise. */ static int EccPoint_isZero(EccPoint *p_point) { - return (vli_zero(p_point->x) && vli_zero(p_point->y)); + return (vli_isZero(p_point->x, NUM_ECC_DIGITS) && vli_isZero(p_point->y, NUM_ECC_DIGITS)); } /* Modified Jacobian point doubling. Note that we use the fact that a is equivalent to -3 (mod p) for the supported @@ -744,43 +767,43 @@ static void EccPoint_double_projective(EccPoint *P3, uint32_t *Z3, EccPoint *P1, uint32_t l_tmp3[NUM_ECC_DIGITS]; uint32_t l_tmp4[NUM_ECC_DIGITS]; - if(vli_zero(Z1)) + if(vli_isZero(Z1, NUM_ECC_DIGITS)) { - vli_clear(Z3); + vli_clear(Z3, NUM_ECC_DIGITS); return; } - vli_modSquare(l_tmp1, Z1, curve_p); /* tmp1 = Z1^2 */ - vli_modAdd(l_tmp2, P1->x, l_tmp1, curve_p); /* tmp2 = x1 + Z1^2 */ - vli_modSub(l_tmp1, P1->x, l_tmp1, curve_p); /* tmp1 = x1 - Z1^2 */ - vli_modMult(l_tmp1, l_tmp1, l_tmp2, curve_p); /* tmp1 = (x1 + Z1^2) * (x1 - Z1^2) */ - vli_modAdd(l_tmp2, l_tmp1, l_tmp1, curve_p); /* tmp2 = 2 * (x1 + Z1^2) * (x1 - Z1^2) */ - vli_modAdd(l_tmp1, l_tmp2, l_tmp1, curve_p); /* tmp1 = M = 3 * (x1 + Z1^2) * (x1 - Z1^2) */ - vli_modMult(Z3, P1->y, Z1, curve_p); /* Z3 = y1 * Z1 */ + vli_modSquare_fast(l_tmp1, Z1); /* tmp1 = Z1^2 */ + vli_modAdd(l_tmp2, P1->x, l_tmp1, curve_p, NUM_ECC_DIGITS); /* tmp2 = x1 + Z1^2 */ + vli_modSub(l_tmp1, P1->x, l_tmp1, curve_p, NUM_ECC_DIGITS); /* tmp1 = x1 - Z1^2 */ + vli_modMult_fast(l_tmp1, l_tmp1, l_tmp2); /* tmp1 = (x1 + Z1^2) * (x1 - Z1^2) */ + vli_modAdd(l_tmp2, l_tmp1, l_tmp1, curve_p, NUM_ECC_DIGITS); /* tmp2 = 2 * (x1 + Z1^2) * (x1 - Z1^2) */ + vli_modAdd(l_tmp1, l_tmp2, l_tmp1, curve_p, NUM_ECC_DIGITS); /* tmp1 = M = 3 * (x1 + Z1^2) * (x1 - Z1^2) */ + vli_modMult_fast(Z3, P1->y, Z1); /* Z3 = y1 * Z1 */ - vli_modAdd(Z3, Z3, Z3, curve_p); /* Z3 = 2 * y1 * Z1 */ + vli_modAdd(Z3, Z3, Z3, curve_p, NUM_ECC_DIGITS); /* Z3 = 2 * y1 * Z1 */ - vli_modSquare(l_tmp3, P1->y, curve_p); /* tmp3 = y1^2 */ - vli_modMult(l_tmp2, l_tmp3, P1->x, curve_p); /* tmp2 = x1 * y1^2 */ - vli_modAdd(l_tmp2, l_tmp2, l_tmp2, curve_p); /* tmp2 = 2 * x1 * y1^2 */ - vli_modAdd(l_tmp2, l_tmp2, l_tmp2, curve_p); /* tmp2 = S = 4 * x1 * y1^2 */ + vli_modSquare_fast(l_tmp3, P1->y); /* tmp3 = y1^2 */ + vli_modMult_fast(l_tmp2, l_tmp3, P1->x); /* tmp2 = x1 * y1^2 */ + vli_modAdd(l_tmp2, l_tmp2, l_tmp2, curve_p, NUM_ECC_DIGITS); /* tmp2 = 2 * x1 * y1^2 */ + vli_modAdd(l_tmp2, l_tmp2, l_tmp2, curve_p, NUM_ECC_DIGITS); /* tmp2 = S = 4 * x1 * y1^2 */ /* Now tmp1 = M, tmp2 = S */ - vli_modAdd(l_tmp4, l_tmp2, l_tmp2, curve_p); /* tmp4 = 2*S */ - vli_modSquare(P3->x, l_tmp1, curve_p); /* x3 = M^2 */ - vli_modSub(P3->x, P3->x, l_tmp4, curve_p); /* x3 = T = M^2 - 2*S */ + vli_modAdd(l_tmp4, l_tmp2, l_tmp2, curve_p, NUM_ECC_DIGITS); /* tmp4 = 2*S */ + vli_modSquare_fast(P3->x, l_tmp1); /* x3 = M^2 */ + vli_modSub(P3->x, P3->x, l_tmp4, curve_p, NUM_ECC_DIGITS); /* x3 = T = M^2 - 2*S */ /* Now tmp1 = M, tmp2 = S, x3 = T */ /* tmp3 is still y1^2 at this point */ - vli_modSquare(l_tmp3, l_tmp3, curve_p); /* tmp3 = y1^4 */ - vli_modAdd(l_tmp3, l_tmp3, l_tmp3, curve_p); /* tmp3 = 2 * y1^4 */ - vli_modAdd(l_tmp3, l_tmp3, l_tmp3, curve_p); /* tmp3 = 4 * y1^4 */ - vli_modAdd(l_tmp3, l_tmp3, l_tmp3, curve_p); /* tmp3 = U = 8 * y1^4 */ + vli_modSquare_fast(l_tmp3, l_tmp3); /* tmp3 = y1^4 */ + vli_modAdd(l_tmp3, l_tmp3, l_tmp3, curve_p, NUM_ECC_DIGITS); /* tmp3 = 2 * y1^4 */ + vli_modAdd(l_tmp3, l_tmp3, l_tmp3, curve_p, NUM_ECC_DIGITS); /* tmp3 = 4 * y1^4 */ + vli_modAdd(l_tmp3, l_tmp3, l_tmp3, curve_p, NUM_ECC_DIGITS); /* tmp3 = U = 8 * y1^4 */ /* Now tmp1 = M, tmp2 = S, x3 = T, tmp3 = U */ - vli_modSub(l_tmp2, l_tmp2, P3->x, curve_p); /* tmp2 = S - T */ - vli_modMult(l_tmp2, l_tmp1, l_tmp2, curve_p); /* tmp2 = M * (S - T) */ - vli_modSub(P3->y, l_tmp2, l_tmp3, curve_p); /* y3 = M * (S - T) - U */ + vli_modSub(l_tmp2, l_tmp2, P3->x, curve_p, NUM_ECC_DIGITS); /* tmp2 = S - T */ + vli_modMult_fast(l_tmp2, l_tmp1, l_tmp2); /* tmp2 = M * (S - T) */ + vli_modSub(P3->y, l_tmp2, l_tmp3, curve_p, NUM_ECC_DIGITS); /* y3 = M * (S - T) - U */ } /* Modified Jacobian point addition; P3 = P1 + P2. Note that P1 and P3 are in projective coordinates, @@ -795,83 +818,83 @@ static void EccPoint_add_mixed(EccPoint *P3, uint32_t *Z3, EccPoint *P1, uint32_ if(EccPoint_isZero(P2)) { EccPoint_copy(P3, P1); - vli_set(Z3, Z1); + vli_set(Z3, Z1, NUM_ECC_DIGITS); return; } - if(vli_zero(Z1)) + if(vli_isZero(Z1, NUM_ECC_DIGITS)) { EccPoint_copy(P3, P2); - vli_clear(Z3); + vli_clear(Z3, NUM_ECC_DIGITS); Z3[0] = 1; return; } - vli_modSquare(l_tmp1, Z1, curve_p); /* tmp1 = Z1^2 */ - vli_modMult(l_tmp2, l_tmp1, Z1, curve_p); /* tmp2 = Z1^3 */ - vli_modMult(l_tmp1, l_tmp1, P2->x, curve_p); /* tmp1 = Z1^2 * x2 */ - vli_modSub(l_tmp3, l_tmp1, P1->x, curve_p); /* tmp3 = (Z1^2 * x2) - x1 */ + vli_modSquare_fast(l_tmp1, Z1); /* tmp1 = Z1^2 */ + vli_modMult_fast(l_tmp2, l_tmp1, Z1); /* tmp2 = Z1^3 */ + vli_modMult_fast(l_tmp1, l_tmp1, P2->x); /* tmp1 = Z1^2 * x2 */ + vli_modSub(l_tmp3, l_tmp1, P1->x, curve_p, NUM_ECC_DIGITS); /* tmp3 = (Z1^2 * x2) - x1 */ /* tmp2 = Z1^3, tmp3 = H */ - vli_modMult(l_tmp2, l_tmp2, P2->y, curve_p); /* tmp2 = Z1^3 * y2 */ - vli_modSub(l_tmp4, l_tmp2, P1->y, curve_p); /* tmp4 = (Z1^3 * y2) - y1 */ + vli_modMult_fast(l_tmp2, l_tmp2, P2->y); /* tmp2 = Z1^3 * y2 */ + vli_modSub(l_tmp4, l_tmp2, P1->y, curve_p, NUM_ECC_DIGITS); /* tmp4 = (Z1^3 * y2) - y1 */ /* tmp4 = r */ - if(vli_zero(l_tmp3)) + if(vli_isZero(l_tmp3, NUM_ECC_DIGITS)) { - if(vli_zero(l_tmp4)) + if(vli_isZero(l_tmp4, NUM_ECC_DIGITS)) { /* The points are equal, so we use the doubling formula. */ EccPoint_double_projective(P3, Z3, P1, Z1); } else { - vli_clear(Z3); + vli_clear(Z3, NUM_ECC_DIGITS); } return; } - vli_modMult(Z3, Z1, l_tmp3, curve_p); /* Z3 = H * Z1 */ + vli_modMult_fast(Z3, Z1, l_tmp3); /* Z3 = H * Z1 */ - vli_modSquare(l_tmp1, l_tmp3, curve_p); /* tmp1 = H^2 */ - vli_modMult(l_tmp2, l_tmp1, l_tmp3, curve_p); /* tmp2 = H^3 */ - vli_modMult(l_tmp1, l_tmp1, P1->x, curve_p); /* tmp1 = H^2 * x1 */ + vli_modSquare_fast(l_tmp1, l_tmp3); /* tmp1 = H^2 */ + vli_modMult_fast(l_tmp2, l_tmp1, l_tmp3); /* tmp2 = H^3 */ + vli_modMult_fast(l_tmp1, l_tmp1, P1->x); /* tmp1 = H^2 * x1 */ /* tmp1 = H^2 * x1, tmp2 = H^3, tmp3 = H, tmp4 = r */ - vli_modAdd(l_tmp3, l_tmp1, l_tmp1, curve_p); /* tmp3 = 2 * H^2 * x1 */ - vli_modSquare(P3->x, l_tmp4, curve_p); /* x3 = r^2 */ - vli_modSub(P3->x, P3->x, l_tmp3, curve_p); /* x3 = r^2 - (2 * H^2 * x1) */ - vli_modSub(P3->x, P3->x, l_tmp2, curve_p); /* x3 = r^2 - (2 * H^2 * x1) - H^3 */ + vli_modAdd(l_tmp3, l_tmp1, l_tmp1, curve_p, NUM_ECC_DIGITS); /* tmp3 = 2 * H^2 * x1 */ + vli_modSquare_fast(P3->x, l_tmp4); /* x3 = r^2 */ + vli_modSub(P3->x, P3->x, l_tmp3, curve_p, NUM_ECC_DIGITS); /* x3 = r^2 - (2 * H^2 * x1) */ + vli_modSub(P3->x, P3->x, l_tmp2, curve_p, NUM_ECC_DIGITS); /* x3 = r^2 - (2 * H^2 * x1) - H^3 */ /* tmp1 = H^2 * x1, tmp2 = H^3, tmp4 = r */ - vli_modSub(l_tmp3, l_tmp1, P3->x, curve_p); /* tmp3 = (H^2 * x1) - x3 */ - vli_modMult(l_tmp3, l_tmp3, l_tmp4, curve_p); /* tmp3 = r * ((H^2 * x1) - x3) */ - vli_modMult(l_tmp1, l_tmp2, P1->y, curve_p); /* tmp1 = H^3 * y1 */ - vli_modSub(P3->y, l_tmp3, l_tmp1, curve_p); /* y3 = r * ((H^2 * x1) - x3) - (H^3 * y1) */ + vli_modSub(l_tmp3, l_tmp1, P3->x, curve_p, NUM_ECC_DIGITS); /* tmp3 = (H^2 * x1) - x3 */ + vli_modMult_fast(l_tmp3, l_tmp3, l_tmp4); /* tmp3 = r * ((H^2 * x1) - x3) */ + vli_modMult_fast(l_tmp1, l_tmp2, P1->y); /* tmp1 = H^3 * y1 */ + vli_modSub(P3->y, l_tmp3, l_tmp1, curve_p, NUM_ECC_DIGITS); /* y3 = r * ((H^2 * x1) - x3) - (H^3 * y1) */ } #if ECC_USE_NAF /* Computes p_result = p_point * p_scalar. p_result must not be the same as p_point. Uses modified Jacobian coordinates to reduce divisions, and NAF to reduce point adds. */ -void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint32_t *p_scalar) +static void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint32_t *p_scalar, uint p_size) { uint32_t l_tmp[NUM_ECC_DIGITS]; uint32_t Z1[NUM_ECC_DIGITS]; uint32_t l_plus[NUM_ECC_DIGITS]; uint32_t l_minus[NUM_ECC_DIGITS]; - int l_numBits = vli_numBits(p_scalar); + int l_numBits = vli_numBits(p_scalar, p_size); uint l_carry; int i; - vli_clear(Z1); - vli_clear(l_plus); - vli_clear(l_minus); + vli_clear(Z1, NUM_ECC_DIGITS); + vli_clear(l_plus, NUM_ECC_DIGITS); + vli_clear(l_minus, NUM_ECC_DIGITS); EccPoint l_neg; - vli_set(l_neg.x, p_point->x); - vli_sub(l_neg.y, curve_p, p_point->y); + vli_set(l_neg.x, p_point->x, NUM_ECC_DIGITS); + vli_sub(l_neg.y, curve_p, p_point->y, NUM_ECC_DIGITS); l_carry = 0; for(i = 0; i < l_numBits; ++i) @@ -916,27 +939,27 @@ void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint32_t *p_scalar) } - vli_modInv(Z1, Z1, curve_p); /* Z1 = 1/Z */ - vli_modSquare(l_tmp, Z1, curve_p); /* tmp = 1/Z^2 */ - vli_modMult(p_result->x, p_result->x, l_tmp, curve_p); /* x = x/Z^2 */ + vli_modInv(Z1, Z1, curve_p, NUM_ECC_DIGITS); /* Z1 = 1/Z */ + vli_modSquare_fast(l_tmp, Z1); /* tmp = 1/Z^2 */ + vli_modMult_fast(p_result->x, p_result->x, l_tmp); /* x = x/Z^2 */ - vli_modMult(l_tmp, Z1, l_tmp, curve_p); /* tmp = 1/Z^3 */ - vli_modMult(p_result->y, p_result->y, l_tmp, curve_p); /* y = y/Z^3 */ + vli_modMult_fast(l_tmp, Z1, l_tmp); /* tmp = 1/Z^3 */ + vli_modMult_fast(p_result->y, p_result->y, l_tmp); /* y = y/Z^3 */ } #else /* ECC_USE_NAF */ /* Computes p_result = p_point * p_scalar. p_result must not be the same as p_point. Uses modified Jacobian coordinates to reduce divisions. */ -void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint32_t *p_scalar) +static void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint32_t *p_scalar, uint p_size) { uint32_t l_tmp[NUM_ECC_DIGITS]; uint32_t Z1[NUM_ECC_DIGITS]; - uint l_numBits = vli_numBits(p_scalar); + uint l_numBits = vli_numBits(p_scalar, p_size); int i; - vli_clear(Z1); + vli_clear(Z1, NUM_ECC_DIGITS); EccPoint_clear(p_result); for(i = l_numBits - 1; i >= 0; --i) @@ -948,12 +971,12 @@ void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint32_t *p_scalar) } } - vli_modInv(Z1, Z1, curve_p); /* Z1 = 1/Z */ - vli_modSquare(l_tmp, Z1, curve_p); /* tmp = 1/Z^2 */ - vli_modMult(p_result->x, p_result->x, l_tmp, curve_p); /* x = x/Z^2 */ + vli_modInv(Z1, Z1, curve_p, NUM_ECC_DIGITS); /* Z1 = 1/Z */ + vli_modSquare_fast(l_tmp, Z1); /* tmp = 1/Z^2 */ + vli_modMult_fast(p_result->x, p_result->x, l_tmp); /* x = x/Z^2 */ - vli_modMult(l_tmp, Z1, l_tmp, curve_p); /* tmp = 1/Z^3 */ - vli_modMult(p_result->y, p_result->y, l_tmp, curve_p); /* y = y/Z^3 */ + vli_modMult_fast(l_tmp, Z1, l_tmp); /* tmp = 1/Z^3 */ + vli_modMult_fast(p_result->y, p_result->y, l_tmp); /* y = y/Z^3 */ } #endif /* ECC_USE_NAF */ @@ -962,13 +985,13 @@ int ecdh_shared_secret(uint32_t p_secret[NUM_ECC_DIGITS], EccPoint *p_publicKey, { EccPoint l_product; - EccPoint_mult(&l_product, p_publicKey, p_privateKey); + EccPoint_mult(&l_product, p_publicKey, p_privateKey, NUM_ECC_DIGITS); if(EccPoint_isZero(&l_product)) { return 0; } - vli_set(p_secret, l_product.x); + vli_set(p_secret, l_product.x, NUM_ECC_DIGITS); return 1; } @@ -977,17 +1000,227 @@ int ecdh_make_key(EccPoint *p_publicKey, uint32_t p_privateKey[NUM_ECC_DIGITS], { /* Make sure the private key is in the range [1, n-1]. For the supported curves, n is always large enough that we only need to subtract once at most. */ - vli_set(p_privateKey, p_random); - if(vli_cmp(curve_n, p_privateKey) != 1) + vli_set(p_privateKey, p_random, NUM_ECC_DIGITS); +#if (ECC_CURVE != secp160r1) + if(vli_cmp(curve_n, p_privateKey, NUM_ECC_DIGITS) != 1) { - vli_sub(p_privateKey, p_privateKey, curve_n); + vli_sub(p_privateKey, p_privateKey, curve_n, NUM_ECC_DIGITS); } +#endif - if(vli_zero(p_privateKey)) + if(vli_isZero(p_privateKey, NUM_ECC_DIGITS)) { return 0; /* The private key cannot be 0 (mod p). */ } - EccPoint_mult(p_publicKey, &curve_G, p_privateKey); + EccPoint_mult(p_publicKey, &curve_G, p_privateKey, NUM_ECC_DIGITS); return 1; } + +int ecc_valid_public_key(EccPoint *p_publicKey) +{ + uint32_t l_tmp1[NUM_ECC_DIGITS]; + uint32_t l_tmp2[NUM_ECC_DIGITS]; + + if(EccPoint_isZero(p_publicKey)) + { + return 0; + } + + if(vli_cmp(curve_p, p_publicKey->x, NUM_ECC_DIGITS) != 1 || vli_cmp(curve_p, p_publicKey->y, NUM_ECC_DIGITS) != 1) + { + return 0; + } + + vli_modSquare_fast(l_tmp1, p_publicKey->y); /* tmp1 = y^2 */ + + vli_modSquare_fast(l_tmp2, p_publicKey->x); /* tmp2 = x^2 */ + vli_modAdd(l_tmp2, l_tmp2, curve_a, curve_p, NUM_ECC_DIGITS); /* tmp2 = x^2 + a */ + vli_modMult_fast(l_tmp2, l_tmp2, p_publicKey->x); /* tmp2 = x^3 + ax */ + vli_modAdd(l_tmp2, l_tmp2, curve_b, curve_p, NUM_ECC_DIGITS); /* tmp2 = x^3 + ax + b */ + + /* Make sure that y^2 == x^3 + ax + b */ + if(vli_cmp(l_tmp1, l_tmp2, NUM_ECC_DIGITS) != 0) + { + return 0; + } + + return 1; +} + +/* -------- ECDSA code -------- */ + +/* Computes p_result = p_left % p_mod */ +/* Size of p_result == size of p_mod == p_modSize */ +static void vli_mod(uint32_t *p_result, uint32_t *p_left, uint p_leftSize, uint32_t *p_mod, uint p_modSize) +{ + uint l_modBits = vli_numBits(p_mod, p_modSize); + if(l_modBits == 0) + { /* Divide by 0. */ + return; + } + + uint l_leftDigits = vli_numDigits(p_left, p_leftSize); + uint l_leftBits = vli_numBits(p_left, l_leftDigits); + + if(l_leftBits < l_modBits) + { /* p_left < p_mod, so p_result = p_left. */ + vli_set(p_result, p_left, p_modSize); /* Use p_modSize because that is the size of p_result. */ + return; + } + + /* Shift p_mod by (l_leftBits - l_modBits). This multiplies p_mod by the largest + power of two possible while still resulting in a number less than p_left. */ + uint32_t l_multiple[l_leftDigits]; + memset(l_multiple, 0, l_leftDigits * sizeof(uint32_t)); + uint l_digitShift = (l_leftBits - l_modBits) / 32; + uint l_bitShift = (l_leftBits - l_modBits) % 32; + vli_set(l_multiple + l_digitShift, p_mod, p_modSize); + if(l_bitShift) + { + vli_lshift(l_multiple, l_multiple, l_bitShift, l_leftDigits); + } + + /* Copy left side into remainder. */ + uint32_t l_remainder[l_leftDigits]; + vli_set(l_remainder, p_left, l_leftDigits); + + /* Copy right side into divisor of same size (so we can compare). */ + uint32_t l_divisor[l_leftDigits]; + memset(l_divisor, 0, l_leftDigits * sizeof(uint32_t)); + vli_set(l_divisor, p_mod, p_modSize); + + /* Subtract all multiples of l_divisor (= p_mod) to get the remainder. */ + while(vli_cmp(l_multiple, l_divisor, l_leftDigits) >= 0) + { + if(vli_cmp(l_multiple, l_remainder, l_leftDigits) <= 0) + { + vli_sub(l_remainder, l_remainder, l_multiple, l_leftDigits); + } + vli_rshift1(l_multiple, l_leftDigits); + } + vli_set(p_result, l_remainder, p_modSize); +} + +/* Computes p_result = (p_left * p_right) % p_mod. */ +static void vli_modMult(uint32_t *p_result, uint32_t *p_left, uint32_t *p_right, uint p_size, uint32_t *p_mod, uint p_modSize) +{ + uint32_t l_product[2 * p_size]; + vli_mult(l_product, p_left, p_right, p_size); + vli_mod(p_result, l_product, 2 * p_size, p_mod, p_modSize); +} + +int ecdsa_sign(uint32_t p_privateKey[NUM_ECC_DIGITS], uint32_t p_random[NUM_ECC_DIGITS], uint32_t p_hash[NUM_ECC_DIGITS], + uint32_t r[NUM_ECC_DIGITS], uint32_t s[NUM_ECC_DIGITS]) +{ + uint32_t k[N_size], s1[N_size], e[N_size]; + EccPoint l_tmp; + + if(vli_isZero(p_random, NUM_ECC_DIGITS)) + { /* The random number must not be 0. */ + return 0; + } + + vli_clear(k, N_size); + vli_set(k, p_random, NUM_ECC_DIGITS); +#if (ECC_CURVE != secp160r1) + if(vli_cmp(curve_n, k, NUM_ECC_DIGITS) != 1) + { + vli_sub(k, k, curve_n, NUM_ECC_DIGITS); + } +#endif + + /* tmp = k * G */ + EccPoint_mult(&l_tmp, &curve_G, k, NUM_ECC_DIGITS); + + /* r = x1 (mod n) */ + vli_set(r, l_tmp.x, NUM_ECC_DIGITS); +#if (ECC_CURVE != secp160r1) + if(vli_cmp(curve_n, r, NUM_ECC_DIGITS) != 1) + { + vli_sub(r, r, curve_n, NUM_ECC_DIGITS); + } +#endif + if(vli_isZero(r, NUM_ECC_DIGITS)) + { /* If r == 0, fail (need a different random number). */ + return 0; + } + + vli_clear(e, N_size); + vli_set(e, p_hash, NUM_ECC_DIGITS); + + vli_modMult(s1, r, p_privateKey, NUM_ECC_DIGITS, curve_n, N_size); /* s1 = r*d */ + vli_modAdd(s1, e, s1, curve_n, N_size); /* s1 = e + r*d */ + vli_modDiv(s1, s1, k, curve_n, N_size); /* s1 = (e + r*d) / k */ + + if(vli_numDigits(s1, N_size) > NUM_ECC_DIGITS) + { /* s is too big to fit in the result buffer (should be very rare, and only happens when using secp160r1). */ + return 0; + } + + vli_set(s, s1, NUM_ECC_DIGITS); + + return 1; +} + +int ecdsa_verify(EccPoint *p_publicKey, uint32_t p_hash[NUM_ECC_DIGITS], uint32_t r[NUM_ECC_DIGITS], uint32_t s[NUM_ECC_DIGITS]) +{ + uint32_t w[N_size], u1[N_size], u2[N_size]; + EccPoint l_tmp1, l_tmp2, l_tmp3; + + if(vli_isZero(r, NUM_ECC_DIGITS) || vli_isZero(s, NUM_ECC_DIGITS)) + { /* r, s must not be 0. */ + return 0; + } + +#if (ECC_CURVE != secp160r1) + if(vli_cmp(curve_n, r, NUM_ECC_DIGITS) != 1 || vli_cmp(curve_n, s, NUM_ECC_DIGITS) != 1) + { /* r, s must be < n. */ + return 0; + } +#endif + + vli_clear(w, N_size); + vli_set(w, s, NUM_ECC_DIGITS); + vli_modInv(w, w, curve_n, N_size); /* w = s^-1 */ + + vli_clear(u1, N_size); + vli_set(u1, p_hash, NUM_ECC_DIGITS); + vli_modMult(u1, u1, w, N_size, curve_n, N_size); /* u1 = e*w */ + + vli_clear(u2, N_size); + vli_set(u2, r, NUM_ECC_DIGITS); + vli_modMult(u2, u2, w, N_size, curve_n, N_size); /* u2 = r*w */ + + EccPoint_mult(&l_tmp1, &curve_G, u1, N_size); + EccPoint_mult(&l_tmp2, p_publicKey, u2, N_size); + + + + uint32_t Z1[NUM_ECC_DIGITS] = {1}; + uint32_t t[NUM_ECC_DIGITS]; + EccPoint_add_mixed(&l_tmp3, Z1, &l_tmp1, Z1, &l_tmp2); + + vli_modInv(Z1, Z1, curve_p, NUM_ECC_DIGITS); /* Z1 = 1/Z */ + vli_modSquare_fast(t, Z1); /* t = 1/Z^2 */ + vli_modMult_fast(l_tmp3.x, l_tmp3.x, t); /* x = x/Z^2 */ + + vli_modMult_fast(t, Z1, t); /* t = 1/Z^3 */ + vli_modMult_fast(l_tmp3.y, l_tmp3.y, t); /* y = y/Z^3 */ + + if(EccPoint_isZero(&l_tmp3)) + { /* Resulting point == infinity */ + return 0; + } + + /* v = x1 (mod n) */ +#if (ECC_CURVE != secp160r1) + if(vli_cmp(curve_n, l_tmp3.x, NUM_ECC_DIGITS) != 1) + { + vli_sub(l_tmp3.x, l_tmp3.x, curve_n, NUM_ECC_DIGITS); + } +#endif + + /* Accept only if v == r. */ + return (vli_cmp(l_tmp3.x, r, NUM_ECC_DIGITS) == 0); +} diff --git a/ecdh.h b/ecdh.h index 4cb0c6e..4ffe59c 100644 --- a/ecdh.h +++ b/ecdh.h @@ -16,7 +16,7 @@ ECC_SOFT_MULT64 - For platforms that do not have instructions to allow a fast 64 #define ECC_USE_NAF 1 #define ECC_SOFT_MULT64 1 -#define ECC_CURVE secp128r1 +#define ECC_CURVE secp160r1 #define secp128r1 4 #define secp160r1 5 @@ -38,5 +38,15 @@ typedef struct EccPoint int ecdh_shared_secret(uint32_t p_secret[NUM_ECC_DIGITS], EccPoint *p_publicKey, uint32_t p_privateKey[NUM_ECC_DIGITS]); int ecdh_make_key(EccPoint *p_publicKey, uint32_t p_privateKey[NUM_ECC_DIGITS], uint32_t p_random[NUM_ECC_DIGITS]); +int ecc_valid_public_key(EccPoint *p_publicKey); + +/* Note: It is recommended that you hash the result of ecdh_shared_secret before using it for symmetric encryption or HMAC. +If you do not hash the shared secret, you must call ecc_valid_public_key() to verify that the remote side's public key is valid. +If this is not done, an attacker could create a public key that would cause your use of the shared secret to leak information +about your private key. */ + +int ecdsa_sign(uint32_t p_privateKey[NUM_ECC_DIGITS], uint32_t p_random[NUM_ECC_DIGITS], uint32_t p_hash[NUM_ECC_DIGITS], + uint32_t r[NUM_ECC_DIGITS], uint32_t s[NUM_ECC_DIGITS]); +int ecdsa_verify(EccPoint *p_publicKey, uint32_t p_hash[NUM_ECC_DIGITS], uint32_t r[NUM_ECC_DIGITS], uint32_t s[NUM_ECC_DIGITS]); #endif /* _MICRO_ECDH_H_ */ diff --git a/test/check_dsa.c b/test/check_dsa.c new file mode 100644 index 0000000..b743255 --- /dev/null +++ b/test/check_dsa.c @@ -0,0 +1,81 @@ +#include "ecdh.h" + +#include +#include +#include +#include + +extern void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint32_t *p_scalar); + +void vli_print(uint32_t *p_vli, unsigned int p_size) +{ + while(p_size) + { + printf("%08X ", (unsigned)p_vli[p_size - 1]); + --p_size; + } +} + +int randfd; + +void getRandomBytes(void *p_dest, unsigned p_size) +{ + if(read(randfd, p_dest, p_size) != (int)p_size) + { + printf("Failed to get random bytes.\n"); + } +} + +int main() +{ + EccPoint l_public; + uint32_t l_private[NUM_ECC_DIGITS]; + + uint32_t l_hash[NUM_ECC_DIGITS]; + uint32_t l_random[NUM_ECC_DIGITS]; + + uint32_t r[NUM_ECC_DIGITS]; + uint32_t s[NUM_ECC_DIGITS]; + + int i; + + randfd = open("/dev/urandom", O_RDONLY); + if(randfd == -1) + { + printf("No access to urandom\n"); + return -1; + } + + printf("Testing 256 signatures\n"); + + for(i=0; i<256; ++i) + { + printf("."); + fflush(stdout); + getRandomBytes((char *)l_private, NUM_ECC_DIGITS * sizeof(uint32_t)); + + ecdh_make_key(&l_public, l_private, l_private); + + getRandomBytes((char *)l_hash, NUM_ECC_DIGITS * sizeof(uint32_t)); + getRandomBytes((char *)l_random, NUM_ECC_DIGITS * sizeof(uint32_t)); + + if(!ecdsa_sign(l_private, l_random, l_hash, r, s)) + { + printf("ecdsa_sign() failed\n"); + continue; + } + + if(!ecc_valid_public_key(&l_public)) + { + printf("Not a valid public key!\n"); + continue; + } + + if(!ecdsa_verify(&l_public, l_hash, r, s)) + { + printf("ecdsa_verify() failed\n"); + } + } + + return 0; +} diff --git a/test/dsa1.c b/test/dsa1.c new file mode 100644 index 0000000..ada8a8e --- /dev/null +++ b/test/dsa1.c @@ -0,0 +1,55 @@ +#include "ecdh.h" + +#if (ECC_CURVE == secp160r1) + +#include +#include + +void vli_print(uint32_t *p_vli, unsigned int p_size) +{ + while(p_size) + { + printf("%08X ", (unsigned)p_vli[p_size - 1]); + --p_size; + } +} + +/* Test data from http://www.secg.org/collateral/gec2.pdf page 2 + Requires that ECC_CURVE be set to secp160r1. */ + +int main() +{ + uint32_t l_privateKey[NUM_ECC_DIGITS] = {0xB2A4E982, 0x72CB6D57, 0xB0733079, 0x3CE144E6, 0xAA374FFC}; + EccPoint l_publicKey = { + {0x51419DC0, 0x3C032062, 0x0E75A24A, 0xECC406ED, 0x51B4496F}, + {0x1756AA6C, 0x4F381CCC, 0x68D79389, 0x73A514B4, 0xC28DCB4B} + }; + uint32_t l_random[NUM_ECC_DIGITS] = {0xdecd52da, 0x2ac5d528, 0xb9185c8b, 0x681a3f28, 0x7b012db7}; + uint32_t l_hash[NUM_ECC_DIGITS] = {0x9cd0d89d, 0x7850c26c, 0xba3e2571, 0x4706816a, 0xa9993e36}; + + uint32_t r[NUM_ECC_DIGITS]; + uint32_t s[NUM_ECC_DIGITS]; + + if(!ecdsa_sign(l_privateKey, l_random, l_hash, r, s)) + { + printf("ecdsa_sign() failed\n"); + } + + printf("r: "); + vli_print(r, NUM_ECC_DIGITS); + printf("\n"); + printf("s: "); + vli_print(s, NUM_ECC_DIGITS); + printf("\n"); + + if(!ecdsa_verify(&l_publicKey, l_hash, r, s)) + { + printf("ecdsa_verify() failed\n"); + } + + return 0; +} + +#endif + +