| @@ -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; | |||
| } | |||