Skip to content
Permalink
Browse files Browse the repository at this point in the history
Constant time EC map to affine for private operations
For fast math, use a constant time modular inverse when mapping to
affine when operation involves a private key - key gen, calc shared
secret, sign.
  • Loading branch information
SparkiDev committed Mar 19, 2020
1 parent eb6f44e commit 1de07da
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 8 deletions.
54 changes: 46 additions & 8 deletions wolfcrypt/src/ecc.c
Expand Up @@ -2285,9 +2285,10 @@ int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a,
P [in/out] The point to map
modulus The modulus of the field the ECC curve is in
mp The "b" value from montgomery_setup()
ct Operation should be constant time.
return MP_OKAY on success
*/
int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp)
int ecc_map_ex(ecc_point* P, mp_int* modulus, mp_digit mp, int ct)
{
#ifndef WOLFSSL_SP_MATH
#ifdef WOLFSSL_SMALL_STACK
Expand All @@ -2307,6 +2308,8 @@ int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp)
mp_int *x, *y, *z;
int err;

(void)ct;

if (P == NULL || modulus == NULL)
return ECC_BAD_ARG_E;

Expand Down Expand Up @@ -2402,12 +2405,23 @@ int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp)
z = P->z;
#endif

/* first map z back to normal */
err = mp_montgomery_reduce(z, modulus, mp);

/* get 1/z */
if (err == MP_OKAY)
err = mp_invmod(z, modulus, t1);
if (err == MP_OKAY) {
#if defined(ECC_TIMING_RESISTANT) && defined(USE_FAST_MATH)
if (ct) {
err = mp_invmod_mont_ct(z, modulus, t1, mp);
if (err == MP_OKAY)
err = mp_montgomery_reduce(t1, modulus, mp);
}
else
#endif
{
/* first map z back to normal */
err = mp_montgomery_reduce(z, modulus, mp);
if (err == MP_OKAY)
err = mp_invmod(z, modulus, t1);
}
}

/* get 1/z^2 and 1/z^3 */
if (err == MP_OKAY)
Expand Down Expand Up @@ -2484,6 +2498,10 @@ int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp)
#endif
}

int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp)
{
return ecc_map_ex(P, modulus, mp, 0);
}
#endif /* !WOLFSSL_SP_MATH || WOLFSSL_PUBLIC_ECC_ADD_DBL */

#if !defined(FREESCALE_LTC_ECC) && !defined(WOLFSSL_STM32_PKA)
Expand Down Expand Up @@ -3639,6 +3657,8 @@ static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point,
}
#else
{
mp_digit mp = 0;

/* make new point */
result = wc_ecc_new_point_h(private_key->heap);
if (result == NULL) {
Expand All @@ -3649,8 +3669,16 @@ static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point,
return MEMORY_E;
}

err = wc_ecc_mulmod_ex(k, point, result, curve->Af, curve->prime, 1,
/* Map in a separate call as this should be constant time */
err = wc_ecc_mulmod_ex(k, point, result, curve->Af, curve->prime, 0,
private_key->heap);
if (err == MP_OKAY) {
err = mp_montgomery_setup(curve->prime, &mp);
}
if (err == MP_OKAY) {
/* Use constant time map if compiled in */
err = ecc_map_ex(result, curve->prime, mp, 1);
}
if (err == MP_OKAY) {
x = mp_unsigned_bin_size(curve->prime);
if (*outlen < x || (int)x < mp_unsigned_bin_size(result->x)) {
Expand Down Expand Up @@ -4008,6 +4036,8 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn,
err = WC_KEY_SIZE_E;
#else
{
mp_digit mp;

if (err == MP_OKAY) {
base = wc_ecc_new_point_h(key->heap);
if (base == NULL)
Expand All @@ -4023,12 +4053,20 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn,

/* make the public key */
if (err == MP_OKAY) {
/* Map in a separate call as this should be constant time */
err = wc_ecc_mulmod_ex(&key->k, base, pub, curve->Af, curve->prime,
1, key->heap);
0, key->heap);
if (err == MP_MEM) {
err = MEMORY_E;
}
}
if (err == MP_OKAY) {
err = mp_montgomery_setup(curve->prime, &mp);
}
if (err == MP_OKAY) {
/* Use constant time map if compiled in */
err = ecc_map_ex(pub, curve->prime, mp, 1);
}

wc_ecc_del_point_h(base, key->heap);
}
Expand Down
75 changes: 75 additions & 0 deletions wolfcrypt/src/tfm.c
Expand Up @@ -1160,6 +1160,75 @@ int fp_invmod(fp_int *a, fp_int *b, fp_int *c)
return FP_OKAY;
}

#define CT_INV_MOD_PRE_CNT 8

/* modulus (b) must be greater than 2 and a prime */
int fp_invmod_mont_ct(fp_int *a, fp_int *b, fp_int *c, fp_digit mp)
{
int i, j;
#ifndef WOLFSSL_SMALL_STACK
fp_int t[1], e[1];
fp_int pre[CT_INV_MOD_PRE_CNT];
#else
fp_int* t;
fp_int* e;
fp_int* pre;
#endif

#ifdef WOLFSSL_SMALL_STACK
t = (fp_int*)XMALLOC(sizeof(fp_int) * (2 + CT_INV_MOD_PRE_CNT), NULL,
DYNAMIC_TYPE_BIGINT);
if (t == NULL)
return FP_MEM;
e = t + 1;
pre = t + 2;
#endif

fp_init(t);
fp_init(e);

fp_init(&pre[0]);
fp_copy(a, &pre[0]);
for (i = 1; i < CT_INV_MOD_PRE_CNT; i++) {
fp_init(&pre[i]);
fp_sqr(&pre[i-1], &pre[i]);
fp_montgomery_reduce(&pre[i], b, mp);
fp_mul(&pre[i], a, &pre[i]);
fp_montgomery_reduce(&pre[i], b, mp);
}

fp_sub_d(b, 2, e);
/* Highest bit is always set. */
for (i = fp_count_bits(e)-2, j = 1; i >= 0; i--, j++) {
if (!fp_is_bit_set(e, i) || j == CT_INV_MOD_PRE_CNT)
break;
}
fp_copy(&pre[j-1], t);
for (j = 0; i >= 0; i--) {
int set = fp_is_bit_set(e, i);

if ((j == CT_INV_MOD_PRE_CNT) || (!set && j > 0)) {
fp_mul(t, &pre[j-1], t);
fp_montgomery_reduce(t, b, mp);
j = 0;
}
fp_sqr(t, t);
fp_montgomery_reduce(t, b, mp);
j += set;
}
if (j > 0) {
fp_mul(t, &pre[j-1], c);
fp_montgomery_reduce(c, b, mp);
}
else
fp_copy(t, c);

#ifdef WOLFSSL_SMALL_STACK
XFREE(t, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return FP_OKAY;
}

/* d = a * b (mod c) */
int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
{
Expand Down Expand Up @@ -3545,6 +3614,12 @@ int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
return fp_invmod(a, b, c);
}

/* hac 14.61, pp608 */
int mp_invmod_mont_ct (mp_int * a, mp_int * b, mp_int * c, mp_digit mp)
{
return fp_invmod_mont_ct(a, b, c, mp);
}

/* this is a shell function that calls either the normal or Montgomery
* exptmod functions. Originally the call to the montgomery code was
* embedded in the normal function but that wasted a lot of stack space
Expand Down
1 change: 1 addition & 0 deletions wolfssl/wolfcrypt/ecc.h
Expand Up @@ -439,6 +439,7 @@ ECC_API int ecc_mul2add(ecc_point* A, mp_int* kA,
ecc_point* C, mp_int* a, mp_int* modulus, void* heap);

ECC_API int ecc_map(ecc_point*, mp_int*, mp_digit);
ECC_API int ecc_map_ex(ecc_point*, mp_int*, mp_digit, int ct);
ECC_API int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R,
mp_int* a, mp_int* modulus, mp_digit mp);
ECC_API int ecc_projective_dbl_point(ecc_point* P, ecc_point* R, mp_int* a,
Expand Down
2 changes: 2 additions & 0 deletions wolfssl/wolfcrypt/tfm.h
Expand Up @@ -535,6 +535,7 @@ int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c);

/* c = 1/a (mod b) */
int fp_invmod(fp_int *a, fp_int *b, fp_int *c);
int fp_invmod_mont_ct(fp_int *a, fp_int *b, fp_int *c, fp_digit mp);

/* c = (a, b) */
/*int fp_gcd(fp_int *a, fp_int *b, fp_int *c);*/
Expand Down Expand Up @@ -743,6 +744,7 @@ MP_API int mp_submod (mp_int* a, mp_int* b, mp_int* c, mp_int* d);
MP_API int mp_addmod (mp_int* a, mp_int* b, mp_int* c, mp_int* d);
MP_API int mp_mod(mp_int *a, mp_int *b, mp_int *c);
MP_API int mp_invmod(mp_int *a, mp_int *b, mp_int *c);
MP_API int mp_invmod_mont_ct(mp_int *a, mp_int *b, mp_int *c, fp_digit mp);
MP_API int mp_exptmod (mp_int * g, mp_int * x, mp_int * p, mp_int * y);
MP_API int mp_exptmod_ex (mp_int * g, mp_int * x, int minDigits, mp_int * p,
mp_int * y);
Expand Down

0 comments on commit 1de07da

Please sign in to comment.