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