| @@ -248,34 +248,47 @@ deserialize_montgomery_decaf ( | |||
| const field_a_t s | |||
| ) { | |||
| field_copy ( a->s0, s ); | |||
| field_copy ( a->xa, s ); | |||
| field_sqr ( a->xa, s ); | |||
| field_set_ui ( a->za, 1 ); | |||
| field_set_ui ( a->xd, 1 ); | |||
| 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 | |||
| ) { | |||
| ANALYZE_THIS_ROUTINE_CAREFULLY; | |||
| field_add_nr ( a->xs, a->xa, a->za ); | |||
| field_subx_nr ( a->zs, a->xa, a->za ); | |||
| field_add_nr ( a->xa, a->xd, a->zd ); | |||
| field_subx_nr ( a->za, a->xd, a->zd ); | |||
| field_mul ( a->xd, a->xa, a->zs ); | |||
| field_mul ( a->zd, a->xs, a->za ); | |||
| field_add_nr ( a->xs, a->xd, a->zd ); | |||
| field_subx_nr ( a->zd, a->xd, a->zd ); | |||
| field_mul ( a->zs, a->zd, a->s0 ); | |||
| field_sqr ( a->zd, a->xa ); | |||
| field_sqr ( a->xa, a->za ); | |||
| field_subx_nr ( a->za, a->zd, a->xa ); | |||
| IF32( field_weak_reduce( a->za ) ); | |||
| field_mul ( a->xd, a->xa, a->zd ); | |||
| field_mulw_scc_wr ( a->zd, a->xa, 1-EDWARDS_D ); | |||
| field_add_nr ( a->xa, a->za, a->zd ); | |||
| field_mul ( a->zd, a->xa, a->za ); | |||
| field_add_nr ( a->xs, a->xa, a->za ); | |||
| field_subx_nr ( a->zs, a->xa, a->za ); | |||
| field_add_nr ( a->xa, a->xd, a->zd ); | |||
| field_subx_nr ( a->za, a->xd, a->zd ); | |||
| field_mul ( a->xd, a->xa, a->zs ); | |||
| field_mul ( a->zd, a->xs, a->za ); | |||
| field_add_nr ( a->xs, a->xd, a->zd ); | |||
| field_subx_nr ( a->zd, a->xd, a->zd ); | |||
| field_mul ( a->zs, a->zd, a->s0 ); | |||
| field_sqr ( a->zd, a->xa ); | |||
| field_sqr ( a->xa, a->za ); | |||
| field_subx_nr ( a->za, a->zd, a->xa ); | |||
| field_mul ( a->xd, a->xa, a->zd ); | |||
| field_mulw_scc_wr ( a->zd, a->za, 1-EDWARDS_D ); | |||
| field_add_nr ( a->xa, a->xa, a->zd ); | |||
| field_mul ( a->zd, a->xa, a->za ); | |||
| field_sqr ( a->xa, a->xs ); | |||
| field_sqr ( a->za, a->zs ); | |||
| } | |||
| @@ -294,6 +294,13 @@ serialize_montgomery ( | |||
| const montgomery_a_t a, | |||
| const field_a_t sbz | |||
| ); | |||
| mask_t | |||
| serialize_montgomery_decaf ( | |||
| field_a_t b, | |||
| const montgomery_aux_a_t a, | |||
| const field_a_t sbz | |||
| ); | |||
| void | |||
| deserialize_montgomery_decaf ( | |||
| @@ -97,6 +97,40 @@ montgomery_ladder ( | |||
| unsigned int n_extra_doubles | |||
| ) __attribute__((warn_unused_result)); | |||
| /** | |||
| * Full Montgomery aux ladder in decaf format. | |||
| * | |||
| * Out = [2^n_extra_doubles * scalar] * in, where | |||
| * scalar is little-endian and has length $nbits$ bits. | |||
| * | |||
| * This function (once it's done; TODO) will always reject points | |||
| * on the twist. | |||
| * | |||
| * This function takes constant time with respect to $*in$ | |||
| * and $*scalar$, but not of course with respect to nbits or | |||
| * n_extra_doubles. | |||
| * | |||
| * @param [out] out The output point. | |||
| * @param [in] in The base point. | |||
| * @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 ( | |||
| field_a_t out, | |||
| const field_a_t in, | |||
| const word_t *scalar, | |||
| unsigned int nbits, | |||
| unsigned int n_extra_doubles | |||
| ) __attribute__((warn_unused_result)); | |||
| /** | |||
| * Scalar multiply a twisted Edwards-form point. | |||
| * | |||
| @@ -48,6 +48,41 @@ montgomery_ladder ( | |||
| return serialize_montgomery(out, mont, in); | |||
| } | |||
| mask_t | |||
| montgomery_ladder_decaf ( | |||
| field_a_t out, | |||
| const field_a_t in, | |||
| const word_t *scalar, | |||
| unsigned int nbits, | |||
| unsigned int n_extra_doubles | |||
| ) { | |||
| montgomery_aux_a_t mont; | |||
| deserialize_montgomery_decaf(mont, in); | |||
| int i,j,n=(nbits-1)%WORD_BITS; | |||
| mask_t pflip = 0; | |||
| for (j=(nbits+WORD_BITS-1)/WORD_BITS-1; j>=0; j--) { | |||
| word_t w = scalar[j]; | |||
| for (i=n; i>=0; i--) { | |||
| mask_t flip = -((w>>i)&1); | |||
| constant_time_cond_swap(mont->xa,mont->xd,sizeof(mont->xd),flip^pflip); | |||
| constant_time_cond_swap(mont->za,mont->zd,sizeof(mont->xd),flip^pflip); | |||
| montgomery_aux_step(mont); | |||
| pflip = flip; | |||
| } | |||
| n = WORD_BITS-1; | |||
| } | |||
| 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); | |||
| } | |||
| static __inline__ void | |||
| __attribute__((unused,always_inline)) | |||
| constant_time_lookup_tw_pniels ( | |||
| @@ -325,6 +325,13 @@ int main(int argc, char **argv) { | |||
| } | |||
| when = now() - when; | |||
| printf("full ladder: %5.1fµs\n", when * 1e6 / i); | |||
| when = now(); | |||
| for (i=0; i<nbase/10; i++) { | |||
| ignore_result(montgomery_ladder_decaf(a,b,sk,FIELD_BITS,0)); | |||
| } | |||
| when = now() - when; | |||
| printf("decafladder: %5.1fµs\n", when * 1e6 / i); | |||
| when = now(); | |||
| for (i=0; i<nbase/10; i++) { | |||
| @@ -3,6 +3,7 @@ | |||
| #include <stdio.h> | |||
| #include "ec_point.h" | |||
| #include "scalarmul.h" | |||
| #include "magic.h" | |||
| #include "field.h" | |||
| #include "crandom.h" | |||
| @@ -261,22 +262,32 @@ int test_decaf (void) { | |||
| int i, hits = 0, fails = 0; | |||
| for (i=0; i<1000; i++) { | |||
| uint8_t ser[FIELD_BYTES]; | |||
| crandom_generate(&crand, ser, sizeof(ser)); | |||
| #if (FIELD_BITS % 8) | |||
| ser[FIELD_BYTES-1] &= (1<<(FIELD_BITS%8)) - 1; | |||
| #endif | |||
| ser[0] &= ~1; | |||
| int j; | |||
| mask_t succ = 0; | |||
| for (j=0; j<128 && !succ; j++) { | |||
| crandom_generate(&crand, ser, sizeof(ser)); | |||
| #if (FIELD_BITS % 8) | |||
| ser[FIELD_BYTES-1] &= (1<<(FIELD_BITS%8)) - 1; | |||
| #endif | |||
| ser[0] &= ~1; | |||
| mask_t succ = field_deserialize(serf, ser); | |||
| succ = field_deserialize(serf, ser); | |||
| if (!succ) { | |||
| youfail(); | |||
| printf(" Unlikely: fail at field_deserialize\n"); | |||
| return -1; | |||
| } | |||
| succ &= decaf_deserialize_affine(&base, serf, 0); | |||
| } | |||
| if (!succ) { | |||
| youfail(); | |||
| printf(" Unlikely: fail at field_deserialize\n"); | |||
| printf("Unlikely: fail 128 desers\n"); | |||
| return -1; | |||
| } | |||
| succ &= decaf_deserialize_affine(&base, serf, 0); | |||
| if (!succ) continue; | |||
| hits++; | |||
| field_a_t serf2; | |||
| struct extensible_t ext; | |||
| @@ -351,10 +362,18 @@ 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; | |||
| } | |||
| if (hits < 350) { | |||
| if (hits < 1000) { | |||
| youfail(); | |||
| printf(" Unlikely: only %d successes in decaf_deser\n", hits); | |||
| printf(" Fail: only %d successes in decaf_deser\n", hits); | |||
| return -1; | |||
| } else if (fails) { | |||
| return -1; | |||