@@ -243,7 +243,7 @@ convert_tw_niels_to_tw_extensible ( | |||||
} | } | ||||
void | void | ||||
deserialize_montgomery_decaf ( | |||||
decaf_deserialize_montgomery ( | |||||
montgomery_aux_a_t a, | montgomery_aux_a_t a, | ||||
const field_a_t s | const field_a_t s | ||||
) { | ) { | ||||
@@ -254,20 +254,6 @@ deserialize_montgomery_decaf ( | |||||
field_set_ui ( a->zd, 0 ); | 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 | void | ||||
montgomery_aux_step ( | montgomery_aux_step ( | ||||
struct montgomery_aux_t* a | struct montgomery_aux_t* a | ||||
@@ -407,6 +393,82 @@ decaf_make_even ( | |||||
field_strong_reduce ( a ); | 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 | void | ||||
decaf_serialize_extensible ( | decaf_serialize_extensible ( | ||||
field_a_t b, | field_a_t b, | ||||
@@ -41,7 +41,7 @@ | |||||
#else | #else | ||||
#define FIELD_HASH_BYTES (SHA512_OUTPUT_BYTES * ((FIELD_BYTES-1)/SHA512_OUTPUT_BYTES + 1)) | #define FIELD_HASH_BYTES (SHA512_OUTPUT_BYTES * ((FIELD_BYTES-1)/SHA512_OUTPUT_BYTES + 1)) | ||||
static inline void field_hash_final ( | static inline void field_hash_final ( | ||||
sha512_ctx_a_t *ctx, | |||||
sha512_ctx_a_t ctx, | |||||
unsigned char out[FIELD_HASH_BYTES] | unsigned char out[FIELD_HASH_BYTES] | ||||
) { | ) { | ||||
/* SHA PRNG I guess? I really should have used SHAKE */ | /* SHA PRNG I guess? I really should have used SHAKE */ | ||||
@@ -191,7 +191,7 @@ constant_time_lookup ( | |||||
static __inline__ void | static __inline__ void | ||||
__attribute__((unused,always_inline)) | __attribute__((unused,always_inline)) | ||||
constant_time_mask ( | constant_time_mask ( | ||||
void *__restrict__ a_, | |||||
void * a_, | |||||
const void *b_, | const void *b_, | ||||
word_t elem_bytes, | word_t elem_bytes, | ||||
mask_t mask | mask_t mask | ||||
@@ -296,14 +296,14 @@ serialize_montgomery ( | |||||
); | ); | ||||
mask_t | mask_t | ||||
serialize_montgomery_decaf ( | |||||
decaf_serialize_montgomery ( | |||||
field_a_t b, | field_a_t b, | ||||
const montgomery_aux_a_t a, | const montgomery_aux_a_t a, | ||||
const field_a_t sbz | |||||
mask_t swapped | |||||
); | ); | ||||
void | void | ||||
deserialize_montgomery_decaf ( | |||||
decaf_deserialize_montgomery ( | |||||
montgomery_aux_a_t a, | montgomery_aux_a_t a, | ||||
const field_a_t s | const field_a_t s | ||||
); | ); | ||||
@@ -100,7 +100,7 @@ montgomery_ladder ( | |||||
/** | /** | ||||
* Full Montgomery aux ladder in decaf format. | * 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. | * scalar is little-endian and has length $nbits$ bits. | ||||
* | * | ||||
* This function (once it's done; TODO) will always reject points | * 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] scalar The scalar's little-endian representation. | ||||
* @param [in] nbits The number of bits in the scalar. Note that | * @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. | * 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_SUCCESS The operation was successful. | ||||
* @retval MASK_FAILURE The input point was invalid, or the output | * @retval MASK_FAILURE The input point was invalid, or the output | ||||
* would be the identity or the point of order 2. | * would be the identity or the point of order 2. | ||||
*/ | */ | ||||
mask_t | mask_t | ||||
montgomery_ladder_decaf ( | |||||
decaf_montgomery_ladder ( | |||||
field_a_t out, | field_a_t out, | ||||
const field_a_t in, | const field_a_t in, | ||||
const word_t *scalar, | const word_t *scalar, | ||||
unsigned int nbits, | |||||
unsigned int n_extra_doubles | |||||
unsigned int nbits | |||||
) __attribute__((warn_unused_result)); | ) __attribute__((warn_unused_result)); | ||||
/** | /** | ||||
@@ -49,15 +49,14 @@ montgomery_ladder ( | |||||
} | } | ||||
mask_t | mask_t | ||||
montgomery_ladder_decaf ( | |||||
decaf_montgomery_ladder ( | |||||
field_a_t out, | field_a_t out, | ||||
const field_a_t in, | const field_a_t in, | ||||
const word_t *scalar, | const word_t *scalar, | ||||
unsigned int nbits, | |||||
unsigned int n_extra_doubles | |||||
unsigned int nbits | |||||
) { | ) { | ||||
montgomery_aux_a_t mont; | montgomery_aux_a_t mont; | ||||
deserialize_montgomery_decaf(mont, in); | |||||
decaf_deserialize_montgomery(mont, in); | |||||
int i,j,n=(nbits-1)%WORD_BITS; | int i,j,n=(nbits-1)%WORD_BITS; | ||||
mask_t pflip = 0; | 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->xa,mont->xd,sizeof(mont->xd),pflip); | ||||
constant_time_cond_swap(mont->za,mont->zd,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 | static __inline__ void | ||||
@@ -328,7 +328,7 @@ int main(int argc, char **argv) { | |||||
when = now(); | when = now(); | ||||
for (i=0; i<nbase/10; i++) { | 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; | when = now() - when; | ||||
printf("decafladder: %5.1fµs\n", when * 1e6 / i); | printf("decafladder: %5.1fµs\n", when * 1e6 / i); | ||||
@@ -362,14 +362,15 @@ int test_decaf (void) { | |||||
fails ++; | 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) { | if (hits < 1000) { | ||||
youfail(); | youfail(); | ||||
@@ -17,7 +17,7 @@ single_scalarmul_compatibility_test ( | |||||
int nbits | int nbits | ||||
) { | ) { | ||||
struct tw_extensible_t text, work; | 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; | int ret = 0, i; | ||||
mask_t succ, succm; | mask_t succ, succm; | ||||
@@ -126,6 +126,19 @@ single_scalarmul_compatibility_test ( | |||||
for (i=0; i<nsizes; i++) { | for (i=0; i<nsizes; i++) { | ||||
consistent &= field_eq(mont,wout[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 inconsistent, complain. */ | ||||
if (!consistent) { | if (!consistent) { | ||||
@@ -152,6 +165,11 @@ single_scalarmul_compatibility_test ( | |||||
field_print(" vt ", vt); | 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; | ret = -1; | ||||
} | } | ||||