@@ -16,7 +16,8 @@ | |||||
* decaf_448_decode can fail because not every sequence of bytes is a valid group | * decaf_448_decode can fail because not every sequence of bytes is a valid group | ||||
* element. | * 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 | * This library may support multiple curves eventually. The Ed448-Goldilocks | ||||
* specific identifiers are prefixed with DECAF_448 or decaf_448. | * 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 | #ifdef __cplusplus | ||||
extern "C" { | extern "C" { | ||||
#endif | #endif | ||||
/* TODO: scalar invert? */ | |||||
/** | /** | ||||
* @brief Read a scalar from wire format or from bytes. | * @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 | const decaf_448_scalar_t b | ||||
) API_VIS NONNULL3 NOINLINE; | ) 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 | * @brief Copy a scalar. The scalars may use the same memory, in which | ||||
* case this function does nothing. | * case this function does nothing. | ||||
@@ -11,6 +11,7 @@ | |||||
#define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s */ | #define __STDC_WANT_LIB_EXT1__ 1 /* for memset_s */ | ||||
#include "decaf.h" | #include "decaf.h" | ||||
#include <string.h> | #include <string.h> | ||||
#include <assert.h> | |||||
#define WBITS DECAF_WORD_BITS | #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_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 ( | void decaf_448_scalar_sub ( | ||||
decaf_448_scalar_t out, | decaf_448_scalar_t out, | ||||
const decaf_448_scalar_t a, | 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); | 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 ( | void decaf_448_scalar_sub ( | ||||
decaf_448_scalar_t out, | decaf_448_scalar_t out, | ||||
const decaf_448_scalar_t a, | const decaf_448_scalar_t a, | ||||
@@ -276,6 +276,13 @@ int main(int argc, char **argv) { | |||||
when = now() - when; | when = now() - when; | ||||
printf("decaf mulsc: %5.1fns\n", when * 1e9 / i); | 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(&ext,0,sizeof(ext)); | ||||
memset(&niels,0,sizeof(niels)); /* avoid assertions in p521 even though this isn't a valid ext or niels */ | 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 ( | static mask_t test_scalar ( | ||||
const mpz_t x, | const mpz_t x, | ||||
const mpz_t y | |||||
const mpz_t y, | |||||
int inv | |||||
) { | ) { | ||||
decaf_448_scalar_t xx,yy,tt; | decaf_448_scalar_t xx,yy,tt; | ||||
mpz_t t; | mpz_t t; | ||||
@@ -236,6 +237,18 @@ static mask_t test_scalar ( | |||||
mpz_mul(t,x,y); | mpz_mul(t,x,y); | ||||
succ &= scalar_assert_eq_gmp("scalar mul",xx,yy,tt,x,y,t); | 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); | mpz_clear(t); | ||||
return succ; | return succ; | ||||
@@ -361,7 +374,7 @@ int test_arithmetic (void) { | |||||
succ &= test_add_sub_RAW(x,y,word); | succ &= test_add_sub_RAW(x,y,word); | ||||
succ &= test_mul_sqr(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) | if (j < 1000) | ||||
succ &= test_isr(x); | succ &= test_isr(x); | ||||