| @@ -248,34 +248,47 @@ deserialize_montgomery_decaf ( | |||||
| const field_a_t s | const field_a_t s | ||||
| ) { | ) { | ||||
| field_copy ( a->s0, 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->za, 1 ); | ||||
| field_set_ui ( a->xd, 1 ); | field_set_ui ( a->xd, 1 ); | ||||
| 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 | ||||
| ) { | ) { | ||||
| ANALYZE_THIS_ROUTINE_CAREFULLY; | 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->xa, a->xs ); | ||||
| field_sqr ( a->za, a->zs ); | field_sqr ( a->za, a->zs ); | ||||
| } | } | ||||
| @@ -294,6 +294,13 @@ serialize_montgomery ( | |||||
| const montgomery_a_t a, | const montgomery_a_t a, | ||||
| const field_a_t sbz | 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 | void | ||||
| deserialize_montgomery_decaf ( | deserialize_montgomery_decaf ( | ||||
| @@ -97,6 +97,40 @@ montgomery_ladder ( | |||||
| unsigned int n_extra_doubles | unsigned int n_extra_doubles | ||||
| ) __attribute__((warn_unused_result)); | ) __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. | * Scalar multiply a twisted Edwards-form point. | ||||
| * | * | ||||
| @@ -48,6 +48,41 @@ montgomery_ladder ( | |||||
| return serialize_montgomery(out, mont, in); | 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 | static __inline__ void | ||||
| __attribute__((unused,always_inline)) | __attribute__((unused,always_inline)) | ||||
| constant_time_lookup_tw_pniels ( | constant_time_lookup_tw_pniels ( | ||||
| @@ -325,6 +325,13 @@ int main(int argc, char **argv) { | |||||
| } | } | ||||
| when = now() - when; | when = now() - when; | ||||
| printf("full ladder: %5.1fµs\n", when * 1e6 / i); | 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(); | when = now(); | ||||
| for (i=0; i<nbase/10; i++) { | for (i=0; i<nbase/10; i++) { | ||||
| @@ -3,6 +3,7 @@ | |||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include "ec_point.h" | #include "ec_point.h" | ||||
| #include "scalarmul.h" | |||||
| #include "magic.h" | #include "magic.h" | ||||
| #include "field.h" | #include "field.h" | ||||
| #include "crandom.h" | #include "crandom.h" | ||||
| @@ -261,22 +262,32 @@ int test_decaf (void) { | |||||
| int i, hits = 0, fails = 0; | int i, hits = 0, fails = 0; | ||||
| for (i=0; i<1000; i++) { | for (i=0; i<1000; i++) { | ||||
| uint8_t ser[FIELD_BYTES]; | 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) { | if (!succ) { | ||||
| youfail(); | youfail(); | ||||
| printf(" Unlikely: fail at field_deserialize\n"); | |||||
| printf("Unlikely: fail 128 desers\n"); | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| succ &= decaf_deserialize_affine(&base, serf, 0); | |||||
| if (!succ) continue; | |||||
| hits++; | hits++; | ||||
| field_a_t serf2; | field_a_t serf2; | ||||
| struct extensible_t ext; | struct extensible_t ext; | ||||
| @@ -351,10 +362,18 @@ 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; | |||||
| } | } | ||||
| if (hits < 350) { | |||||
| if (hits < 1000) { | |||||
| youfail(); | youfail(); | ||||
| printf(" Unlikely: only %d successes in decaf_deser\n", hits); | |||||
| printf(" Fail: only %d successes in decaf_deser\n", hits); | |||||
| return -1; | return -1; | ||||
| } else if (fails) { | } else if (fails) { | ||||
| return -1; | return -1; | ||||