@@ -16,7 +16,8 @@ | |||
* decaf_448_decode can fail because not every sequence of bytes is a valid group | |||
* element. | |||
* | |||
* The formulas contain no data-dependent branches, timing or memory accesses. | |||
* The formulas contain no data-dependent branches, timing or memory accesses, | |||
* except for decaf_448_base_double_scalarmul_non_secret. | |||
* | |||
* This library may support multiple curves eventually. The Ed448-Goldilocks | |||
* specific identifiers are prefixed with DECAF_448 or decaf_448. | |||
@@ -116,8 +117,6 @@ extern const struct decaf_448_precomputed_s *decaf_448_precomputed_base API_VIS; | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/* TODO: scalar invert? */ | |||
/** | |||
* @brief Read a scalar from wire format or from bytes. | |||
@@ -207,6 +206,17 @@ void decaf_448_scalar_mul ( | |||
const decaf_448_scalar_t b | |||
) API_VIS NONNULL3 NOINLINE; | |||
/** | |||
* @brief Invert a scalar. When passed zero, return 0. The input and output may alias. | |||
* @param [in] a A scalar. | |||
* @param [out] out 1/a. | |||
* @return DECAF_TRUE The input is nonzero. | |||
*/ | |||
decaf_bool_t decaf_448_scalar_invert ( | |||
decaf_448_scalar_t out, | |||
const decaf_448_scalar_t a | |||
) API_VIS NONNULL2 NOINLINE; | |||
/** | |||
* @brief Copy a scalar. The scalars may use the same memory, in which | |||
* case this function does nothing. | |||
@@ -11,6 +11,7 @@ | |||
#define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s */ | |||
#include "decaf.h" | |||
#include <string.h> | |||
#include <assert.h> | |||
#define WBITS DECAF_WORD_BITS | |||
@@ -363,6 +364,33 @@ void decaf_448_scalar_mul ( | |||
decaf_448_montmul(out,out,decaf_448_scalar_r2,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
} | |||
decaf_bool_t decaf_448_scalar_invert ( | |||
decaf_448_scalar_t out, | |||
const decaf_448_scalar_t a | |||
) { | |||
decaf_448_scalar_t b, ma; | |||
int i; | |||
decaf_448_montmul(b,decaf_448_scalar_one,decaf_448_scalar_r2,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
decaf_448_montmul(ma,a,decaf_448_scalar_r2,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
for (i=DECAF_448_SCALAR_BITS-1; i>=0; i--) { | |||
decaf_448_montmul(b,b,b,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
decaf_word_t w = decaf_448_scalar_p->limb[i/WBITS]; | |||
if (i<WBITS) { | |||
assert(w >= 2); | |||
w-=2; | |||
} | |||
if (1 & w>>(i%WBITS)) { | |||
decaf_448_montmul(b,b,ma,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
} | |||
} | |||
decaf_448_montmul(out,b,decaf_448_scalar_one,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
decaf_448_scalar_destroy(b); | |||
decaf_448_scalar_destroy(ma); | |||
return ~decaf_448_scalar_eq(out,decaf_448_scalar_zero); | |||
} | |||
void decaf_448_scalar_sub ( | |||
decaf_448_scalar_t out, | |||
const decaf_448_scalar_t a, | |||
@@ -340,6 +340,66 @@ void decaf_448_scalar_mul ( | |||
decaf_448_montmul(out,out,decaf_448_scalar_r2,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
} | |||
/* PERF: could implement this */ | |||
siv decaf_448_montsqr ( | |||
decaf_448_scalar_t out, | |||
const decaf_448_scalar_t a | |||
) { | |||
decaf_448_montmul(out,a,a,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
} | |||
decaf_bool_t decaf_448_scalar_invert ( | |||
decaf_448_scalar_t out, | |||
const decaf_448_scalar_t a | |||
) { | |||
decaf_448_scalar_t chain[7], tmp; | |||
decaf_448_montmul(chain[0],a,decaf_448_scalar_r2,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
unsigned int i,j; | |||
/* Addition chain generated by a not-too-clever SAGE script. First part: compute a^(2^222-1) */ | |||
struct { uint8_t widx, sidx, sct, midx; } muls [] = { | |||
{2,0,1,0}, {3,2,1,0}, {4,3,1,0}, {5,4,1,0}, /* 0x3,7,f,1f */ | |||
{1,5,1,0}, {1,1,3,3}, {6,1,9,1}, {1,6,1,0}, {6,1,18,6}, /* a^(2^37-1) */ | |||
{1,6,37,6}, {1,1,37,6}, {1,1,111,1} /* a^(2^222-1) */ | |||
}; | |||
/* Second part: sliding window */ | |||
struct { uint8_t sct, midx; } muls1 [] = { | |||
{6, 5}, {4, 2}, {3, 0}, {2, 0}, {4, 0}, {8, 5}, | |||
{2, 0}, {5, 3}, {4, 0}, {4, 0}, {5, 3}, {3, 2}, | |||
{3, 2}, {3, 2}, {2, 0}, {3, 0}, {4, 2}, {2, 0}, | |||
{4, 3}, {3, 2}, {2, 0}, {3, 2}, {5, 2}, {3, 2}, | |||
{2, 0}, {3, 0}, {7, 0}, {5, 0}, {3, 2}, {3, 2}, | |||
{4, 2}, {5, 0}, {5, 3}, {3, 0}, {2, 0}, {5, 2}, | |||
{4, 3}, {4, 0}, {3, 2}, {7, 4}, {2, 0}, {2, 0}, | |||
{2, 0}, {2, 0}, {3, 0}, {5, 2}, {5, 4}, {5, 2}, | |||
{5, 0}, {2, 0}, {3, 0}, {3, 0}, {2, 0}, {2, 0}, | |||
{2, 0}, {3, 2}, {2, 0}, {3, 2}, {5, 0}, {4, 0}, | |||
{6, 4}, {4, 0} | |||
}; | |||
for (i=0; i<sizeof(muls)/sizeof(muls[0]); i++) { | |||
decaf_448_montsqr(tmp, chain[muls[i].sidx]); | |||
for (j=1; j<muls[i].sct; j++) { | |||
decaf_448_montsqr(tmp, tmp); | |||
} | |||
decaf_448_montmul(chain[muls[i].widx], tmp, chain[muls[i].midx], decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
} | |||
for (i=0; i<sizeof(muls1)/sizeof(muls1[0]); i++) { | |||
decaf_448_montsqr(tmp, chain[1]); | |||
for (j=1; j<muls1[i].sct; j++) { | |||
decaf_448_montsqr(tmp, tmp); | |||
} | |||
decaf_448_montmul(chain[1], tmp, chain[muls1[i].midx], decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
} | |||
decaf_448_montmul(out,chain[1],decaf_448_scalar_one,decaf_448_scalar_p,DECAF_MONTGOMERY_FACTOR); | |||
for (i=0; i<sizeof(chain)/sizeof(chain[0]); i++) { | |||
decaf_448_scalar_destroy(chain[i]); | |||
} | |||
return ~decaf_448_scalar_eq(out,decaf_448_scalar_zero); | |||
} | |||
void decaf_448_scalar_sub ( | |||
decaf_448_scalar_t out, | |||
const decaf_448_scalar_t a, | |||
@@ -276,6 +276,13 @@ int main(int argc, char **argv) { | |||
when = now() - when; | |||
printf("decaf mulsc: %5.1fns\n", when * 1e9 / i); | |||
when = now(); | |||
for (i=0; i<nbase/10; i++) { | |||
decaf_448_scalar_invert(csc,bsc); | |||
} | |||
when = now() - when; | |||
printf("decaf invsc: %5.1fµs\n", when * 1e6 / i); | |||
memset(&ext,0,sizeof(ext)); | |||
memset(&niels,0,sizeof(niels)); /* avoid assertions in p521 even though this isn't a valid ext or niels */ | |||
@@ -215,7 +215,8 @@ static mask_t test_add_sub_RAW ( | |||
static mask_t test_scalar ( | |||
const mpz_t x, | |||
const mpz_t y | |||
const mpz_t y, | |||
int inv | |||
) { | |||
decaf_448_scalar_t xx,yy,tt; | |||
mpz_t t; | |||
@@ -236,6 +237,18 @@ static mask_t test_scalar ( | |||
mpz_mul(t,x,y); | |||
succ &= scalar_assert_eq_gmp("scalar mul",xx,yy,tt,x,y,t); | |||
if (inv) { | |||
decaf_bool_t ret = decaf_448_scalar_invert(tt,xx); | |||
if (!mpz_cmp_ui(x,0)) { | |||
mpz_set_ui(t,0); | |||
succ &= (ret == 0) ? MASK_SUCCESS : MASK_FAILURE; | |||
} else { | |||
mpz_invert(t,x,mp_scalar_field); | |||
succ &= (ret == MASK_SUCCESS) ? MASK_SUCCESS : MASK_FAILURE; | |||
} | |||
succ &= scalar_assert_eq_gmp("scalar inv",xx,yy,tt,x,y,t); | |||
} | |||
mpz_clear(t); | |||
return succ; | |||
@@ -361,7 +374,7 @@ int test_arithmetic (void) { | |||
succ &= test_add_sub_RAW(x,y,word); | |||
succ &= test_mul_sqr(x,y,word); | |||
succ &= test_scalar(x,y); | |||
succ &= test_scalar(x,y,(j%20==0)); | |||
if (j < 1000) | |||
succ &= test_isr(x); | |||