@@ -243,7 +243,7 @@ convert_tw_niels_to_tw_extensible ( | |||
} | |||
void | |||
deserialize_montgomery_decaf ( | |||
decaf_deserialize_montgomery ( | |||
montgomery_aux_a_t a, | |||
const field_a_t s | |||
) { | |||
@@ -254,20 +254,6 @@ deserialize_montgomery_decaf ( | |||
field_set_ui ( a->zd, 0 ); | |||
} | |||
mask_t | |||
serialize_montgomery_decaf ( | |||
field_a_t b, | |||
const montgomery_aux_a_t a, | |||
const field_a_t sbz | |||
) { | |||
field_a_t L0, L1; | |||
field_isr(L0,a->zd); | |||
field_sqr(L1,L0); | |||
field_mul(b,a->xd,L1); | |||
(void)sbz; | |||
return 0; // Fail, because this routine isn't done yet. | |||
} | |||
void | |||
montgomery_aux_step ( | |||
struct montgomery_aux_t* a | |||
@@ -407,6 +393,82 @@ decaf_make_even ( | |||
field_strong_reduce ( a ); | |||
} | |||
mask_t | |||
decaf_serialize_montgomery ( | |||
field_a_t out, | |||
const montgomery_aux_a_t a, | |||
mask_t swapped | |||
) { | |||
field_a_t xz_d, xz_a, x0, den, L0, L1, L2, L3; | |||
mask_t zcase, output_zero, flip, succ, za_zero; | |||
field_mul(xz_d, a->xd, a->zd); | |||
field_mul(xz_a, a->xa, a->za); | |||
output_zero = field_is_zero(xz_d); | |||
za_zero = field_is_zero(a->za); | |||
field_addw(xz_d, -output_zero); /* make xz_d always nonzero */ | |||
zcase = output_zero | field_is_zero(xz_a); | |||
field_sqr(x0, a->s0); | |||
/* Curve test in zcase */ | |||
field_copy(L0,x0); | |||
field_addw(L0,1); | |||
field_sqr(L1,L0); | |||
field_mulw_scc_wr(L0,x0,-4*EDWARDS_D); | |||
field_add(L1,L1,L0); | |||
constant_time_select(xz_a,L1,xz_a,sizeof(xz_a),zcase); | |||
/* Compute denominator */ | |||
field_mul(L0, x0, xz_d); | |||
field_mulw(L2, L0, 4); | |||
field_mul(L1, L2, xz_a); | |||
field_isr(den, L1); | |||
/* Check squareness */ | |||
field_sqr(L2, den); | |||
field_mul(L0, L1, L2); | |||
field_addw(L0, 1); | |||
succ = ~field_low_bit(a->s0) & ~field_is_zero(L0); | |||
/* Compute y/x */ | |||
field_mul(L1, x0, a->xd); | |||
field_sub(L1, a->zd, L1); | |||
field_mul(L0, a->za, L1); /* L0 = "opq" */ | |||
field_mul(L1, x0, a->zd); | |||
field_sub(L1, L1, a->xd); | |||
field_mul(L2, a->xa, L1); /* L2 = "pqr" */ | |||
field_sub(L1, L0, L2); | |||
field_add(L0, L0, L2); | |||
field_mul(L2, L1, den); /* L2 = y0 / x0 */ | |||
field_mul(L1, L0, den); /* L1 = yO / xO */ | |||
flip = field_low_bit(L1) ^ field_low_bit(L2) ^ za_zero; | |||
constant_time_select(L0, a->zd, a->xd, sizeof(L0), flip); /* L0 = "times" */ | |||
/* OK, done with y-coordinates */ | |||
/* OK, now correct for swappage */ | |||
field_add(den,den,den); | |||
field_mul(L1,den,a->s0); | |||
field_sqr(L2,L1); | |||
field_mul(L3,L2,xz_a); | |||
constant_time_select(den,L3,L1,sizeof(den),swapped &~ zcase); | |||
/* compute the output */ | |||
field_mul(L1,L0,den); | |||
constant_time_select(L2,a->s0,a->zs,sizeof(L2),zcase); /* zs, but s0 in zcase */ | |||
field_mul(L0,L1,L2); | |||
constant_time_select(L3,a->xd,a->zd,sizeof(L3),za_zero); | |||
constant_time_select(L2,L3,a->xs,sizeof(L2),zcase); /* xs, but zq or qq in zcase */ | |||
field_mul(out,L0,L2); | |||
constant_time_mask(out,out,sizeof(field_a_t),~output_zero); | |||
decaf_make_even(out); | |||
return succ; | |||
} | |||
void | |||
decaf_serialize_extensible ( | |||
field_a_t b, | |||
@@ -41,7 +41,7 @@ | |||
#else | |||
#define FIELD_HASH_BYTES (SHA512_OUTPUT_BYTES * ((FIELD_BYTES-1)/SHA512_OUTPUT_BYTES + 1)) | |||
static inline void field_hash_final ( | |||
sha512_ctx_a_t *ctx, | |||
sha512_ctx_a_t ctx, | |||
unsigned char out[FIELD_HASH_BYTES] | |||
) { | |||
/* SHA PRNG I guess? I really should have used SHAKE */ | |||
@@ -191,7 +191,7 @@ constant_time_lookup ( | |||
static __inline__ void | |||
__attribute__((unused,always_inline)) | |||
constant_time_mask ( | |||
void *__restrict__ a_, | |||
void * a_, | |||
const void *b_, | |||
word_t elem_bytes, | |||
mask_t mask | |||
@@ -296,14 +296,14 @@ serialize_montgomery ( | |||
); | |||
mask_t | |||
serialize_montgomery_decaf ( | |||
decaf_serialize_montgomery ( | |||
field_a_t b, | |||
const montgomery_aux_a_t a, | |||
const field_a_t sbz | |||
mask_t swapped | |||
); | |||
void | |||
deserialize_montgomery_decaf ( | |||
decaf_deserialize_montgomery ( | |||
montgomery_aux_a_t a, | |||
const field_a_t s | |||
); | |||
@@ -100,7 +100,7 @@ montgomery_ladder ( | |||
/** | |||
* Full Montgomery aux ladder in decaf format. | |||
* | |||
* Out = [2^n_extra_doubles * scalar] * in, where | |||
* Out = scalar * in, where | |||
* scalar is little-endian and has length $nbits$ bits. | |||
* | |||
* This function (once it's done; TODO) will always reject points | |||
@@ -115,20 +115,17 @@ montgomery_ladder ( | |||
* @param [in] scalar The scalar's little-endian representation. | |||
* @param [in] nbits The number of bits in the scalar. Note that | |||
* unlike in Curve25519, we do not require the top bit to be set. | |||
* @param [in] n_extra_doubles The number of extra doubles to do at | |||
* the end. | |||
* | |||
* @retval MASK_SUCCESS The operation was successful. | |||
* @retval MASK_FAILURE The input point was invalid, or the output | |||
* would be the identity or the point of order 2. | |||
*/ | |||
mask_t | |||
montgomery_ladder_decaf ( | |||
decaf_montgomery_ladder ( | |||
field_a_t out, | |||
const field_a_t in, | |||
const word_t *scalar, | |||
unsigned int nbits, | |||
unsigned int n_extra_doubles | |||
unsigned int nbits | |||
) __attribute__((warn_unused_result)); | |||
/** | |||
@@ -49,15 +49,14 @@ montgomery_ladder ( | |||
} | |||
mask_t | |||
montgomery_ladder_decaf ( | |||
decaf_montgomery_ladder ( | |||
field_a_t out, | |||
const field_a_t in, | |||
const word_t *scalar, | |||
unsigned int nbits, | |||
unsigned int n_extra_doubles | |||
unsigned int nbits | |||
) { | |||
montgomery_aux_a_t mont; | |||
deserialize_montgomery_decaf(mont, in); | |||
decaf_deserialize_montgomery(mont, in); | |||
int i,j,n=(nbits-1)%WORD_BITS; | |||
mask_t pflip = 0; | |||
@@ -75,12 +74,7 @@ montgomery_ladder_decaf ( | |||
constant_time_cond_swap(mont->xa,mont->xd,sizeof(mont->xd),pflip); | |||
constant_time_cond_swap(mont->za,mont->zd,sizeof(mont->xd),pflip); | |||
assert(n_extra_doubles < INT_MAX); | |||
for (j=0; j<(int)n_extra_doubles; j++) { | |||
montgomery_aux_step(mont); | |||
} | |||
return serialize_montgomery_decaf(out, mont, in); | |||
return decaf_serialize_montgomery(out, mont, pflip); | |||
} | |||
static __inline__ void | |||
@@ -328,7 +328,7 @@ int main(int argc, char **argv) { | |||
when = now(); | |||
for (i=0; i<nbase/10; i++) { | |||
ignore_result(montgomery_ladder_decaf(a,b,sk,FIELD_BITS,0)); | |||
ignore_result(decaf_montgomery_ladder(a,b,sk,FIELD_BITS)); | |||
} | |||
when = now() - when; | |||
printf("decafladder: %5.1fµs\n", when * 1e6 / i); | |||
@@ -362,14 +362,15 @@ int test_decaf (void) { | |||
fails ++; | |||
} | |||
word_t scalar = i; | |||
mask_t res = montgomery_ladder_decaf(serf2,serf,&scalar,i,0); | |||
// youfail(); | |||
// printf("Decaf Montgomery ladder i=%d res=%d\n", i, (int)res); | |||
// field_print(" s", serf); | |||
// field_print(" o", serf2); | |||
// printf("\n"); | |||
(void)res; | |||
word_t scalar = 1; | |||
mask_t res = decaf_montgomery_ladder(serf2,serf,&scalar,1+(i%31)); | |||
if (~res | ~field_eq(serf2,serf)) { | |||
youfail(); | |||
printf("Decaf Montgomery ladder i=%d res=%d\n", 1+(i%31), (int)res); | |||
field_print(" s", serf); | |||
field_print(" o", serf2); | |||
printf("\n"); | |||
} | |||
} | |||
if (hits < 1000) { | |||
youfail(); | |||
@@ -17,7 +17,7 @@ single_scalarmul_compatibility_test ( | |||
int nbits | |||
) { | |||
struct tw_extensible_t text, work; | |||
field_a_t mont, ct, vl, vt; | |||
field_a_t mont, ct, vl, vt, decaf_s, decaf_m, decaf_te; | |||
int ret = 0, i; | |||
mask_t succ, succm; | |||
@@ -126,6 +126,19 @@ single_scalarmul_compatibility_test ( | |||
for (i=0; i<nsizes; i++) { | |||
consistent &= field_eq(mont,wout[i]); | |||
} | |||
/* Do decaf */ | |||
copy_tw_extensible(&work,&text); | |||
double_tw_extensible(&work); | |||
decaf_serialize_tw_extensible(decaf_s, &work); | |||
mask_t succ_dm, succ_dta; | |||
succ_dm = decaf_montgomery_ladder(decaf_m, decaf_s, scalar, nbits); | |||
succ_dta = deserialize_and_twist_approx(&work, mont); | |||
decaf_serialize_tw_extensible(decaf_te, &work); | |||
consistent &= field_eq(decaf_m, decaf_te); | |||
consistent &= succ_dm & succ_dta; | |||
/* If inconsistent, complain. */ | |||
if (!consistent) { | |||
@@ -152,6 +165,11 @@ single_scalarmul_compatibility_test ( | |||
field_print(" vt ", vt); | |||
} | |||
printf("decaf: succ = %d, %d\n", (int)succ_dm, (int)succ_dta); | |||
field_print(" s0", decaf_s); | |||
field_print(" dm", decaf_m); | |||
field_print(" dt", decaf_te); | |||
ret = -1; | |||
} | |||