diff --git a/src/ec_point.c b/src/ec_point.c index 7e2a61c..f9de136 100644 --- a/src/ec_point.c +++ b/src/ec_point.c @@ -7,6 +7,11 @@ * @author Mike Hamburg * @warning This file was automatically generated. * Then it was edited by hand. Good luck, have fun. + * + * This file contains a huge number of different options for EC point arithmetic, + * but only a few of them will be used by any given library. They are here for + * reference and for consistency checks. The Goldilocks library link step strips + * out unused functions. */ #include "ec_point.h" @@ -19,7 +24,7 @@ add_tw_niels_to_tw_extensible ( ) { ANALYZE_THIS_ROUTINE_CAREFULLY; field_a_t L0, L1; - field_sub ( L1, d->y, d->x ); + field_subx_nr ( L1, d->y, d->x ); field_mul ( L0, e->a, L1 ); field_add_nr ( L1, d->x, d->y ); field_mul ( d->y, e->b, L1 ); @@ -34,6 +39,62 @@ add_tw_niels_to_tw_extensible ( field_mul ( d->y, L0, d->u ); } +void +add_tw_extended ( + tw_extended_a_t d, + const tw_extended_a_t e +) { + ANALYZE_THIS_ROUTINE_CAREFULLY; + field_a_t L0, L1, L2; + field_subx_nr ( L1, d->y, d->x ); + field_subx_nr ( L2, e->y, e->x ); + field_mul ( L0, L2, L1 ); + field_add_nr ( L1, d->y, d->x ); + field_add_nr ( L2, e->y, e->x ); + field_mul ( d->y, L2, L1 ); + field_mul ( L1, e->t, d->t ); + field_mulw_scc_wr ( d->x, L1, 2-2*EDWARDS_D ); + field_add_nr ( L1, L0, d->y ); + field_subx_nr ( L2, d->y, L0 ); + field_mul ( L0, d->z, e->z ); + field_add_nr ( L0, L0, L0 ); + field_add_nr ( d->y, L0, d->x ); + field_subx_nr ( L0, L0, d->x ); + field_mul ( d->z, L0, d->y ); + field_mul ( d->x, d->y, L2 ); + field_mul ( d->y, L0, L1 ); + field_mul ( d->t, L1, L2 ); +} + +void +add_sub_tw_extended ( + tw_extended_a_t d, + const tw_extended_a_t e, + mask_t sub +) { + field_a_t L0, L1, L2, L3; + field_sub ( L1, d->y, d->x ); + field_sub ( L2, e->y, e->x ); + field_add ( L3, e->y, e->x ); + constant_time_cond_swap(L2,L3,sizeof(L2),sub); + field_mul ( L0, L2, L1 ); + field_add ( L1, d->y, d->x ); + field_mul ( d->y, L3, L1 ); + field_mul ( L1, e->t, d->t ); + field_mulw_scc_wr ( d->x, L1, 2-2*EDWARDS_D ); + field_add ( L1, L0, d->y ); + field_sub ( L2, d->y, L0 ); + field_mul ( L0, d->z, e->z ); + field_add ( L0, L0, L0 ); + field_add ( d->y, L0, d->x ); + field_sub ( L0, L0, d->x ); + constant_time_cond_swap(L0,d->y,sizeof(L0),sub); + field_mul ( d->z, L0, d->y ); + field_mul ( d->x, d->y, L2 ); + field_mul ( d->y, L0, L1 ); + field_mul ( d->t, L1, L2 ); +} + void sub_tw_niels_from_tw_extensible ( tw_extensible_a_t d, @@ -194,6 +255,17 @@ convert_tw_affine_to_tw_extensible ( field_copy ( b->u, a->y ); } +void +convert_tw_extensible_to_tw_extended ( + tw_extended_a_t b, + const tw_extensible_a_t a +) { + field_copy ( b->x, a->x ); + field_copy ( b->y, a->y ); + field_copy ( b->z, a->z ); + field_mul ( b->t, a->t, a->u ); +} + void convert_affine_to_extensible ( extensible_a_t b, @@ -523,6 +595,90 @@ decaf_serialize_tw_extensible ( decaf_abs ( b ); } +void +decaf_serialize_tw_extended ( + field_a_t b, + const tw_extended_a_t a +) { + field_a_t L0, L1, L2, L3; + field_mulw_scc ( L0, a->y, 1-EDWARDS_D ); + field_mul ( L2, L0, a->t ); + field_mul ( L0, a->x, a->z ); + field_sub ( L3, L2, L0 ); + field_add ( L0, a->z, a->y ); + field_sub ( L1, a->z, a->y ); + field_mul ( L2, L1, L0 ); + field_mulw_scc ( L1, L2, -EDWARDS_D ); + field_isr ( L0, L1 ); + field_mulw_scc ( L1, L0, -EDWARDS_D ); + field_mul ( L2, L1, L0 ); + field_mul ( L0, L2, L3 ); + field_add ( L3, L1, L1 ); + field_mul ( L2, L3, a->z ); + field_cond_neg ( L1, ~field_high_bit(L2) ); + field_mul ( L2, L1, a->y ); + field_add ( b, L0, L2 ); + decaf_abs ( b ); +} + +/* +static void +tw_extended_efgh ( + tw_extended_a_t a, + field_a_t x, + field_a_t xz, + field_a_t y, + field_a_t yz +) { + field_mul(a->x,x,yz); + field_mul(a->y,y,xz); + field_mul(a->z,xz,yz); + field_mul(a->t,x,y); +} +*/ + +mask_t +decaf_deserialize_tw_extended ( + tw_extended_a_t a, + const field_a_t s, + mask_t allow_identity +) { + field_a_t L0, L1, L2, L3, L4; + mask_t succ, zero; + zero = field_is_zero(s); + succ = allow_identity | ~zero; + succ &= ~field_high_bit(s); + + field_sqr ( L0, s ); // L0 = s^2 + field_neg ( a->z, L0 ); + field_addw ( a->z, 1 ); + field_sqr ( L1, a->z ); + field_mulw_scc_wr ( L2, L0, 4-4*EDWARDS_D ); + field_add ( L2, L2, L1 ); // L2 = [t^2] + field_mul ( L1, L2, L0 ); // L1 = [t^2] s^2 + + field_isr ( L3, L1 ); // L3 =? 1/ts; check it + field_sqr ( L4, L3 ); + field_mul ( L0, L4, L1 ); + field_addw( L0, 1 ); + succ &= ~field_is_zero( L0 ); + + field_mul ( L1, L2, L3 ); // L1 = t^2 * 1/ts = t/s + field_cond_neg ( L3, field_high_bit(L1) ); // negate 1/ts? + + field_add( a->x, s, s ); + field_mul ( L2, L3, s ); + + field_neg ( L1, a->z ); + field_addw ( L1, 2 ); + field_mul ( L0, L1, L2 ); + field_mul(a->y,L0,a->z); + field_mul(a->t,a->x,L0); + field_addw ( a->y, -zero ); + + return succ; +} + mask_t decaf_deserialize_affine ( affine_a_t a, @@ -803,6 +959,16 @@ set_identity_extensible ( field_set_ui( a->u, 0 ); } +void +set_identity_tw_extended ( + tw_extended_a_t a +) { + field_set_ui( a->x, 0 ); + field_set_ui( a->y, 1 ); + field_set_ui( a->z, 1 ); + field_set_ui( a->t, 0 ); +} + void set_identity_tw_extensible ( tw_extensible_a_t a @@ -827,12 +993,21 @@ decaf_eq_extensible ( const struct extensible_t* a, const struct extensible_t* b ) { - field_a_t L0, L1, L2; - field_mul ( L2, b->y, a->x ); + field_a_t L0, L1; + field_mul ( L0, b->y, a->x ); field_mul ( L1, a->y, b->x ); - field_sub ( L0, L2, L1 ); - field_bias ( L0, 2 ); - return field_is_zero ( L0 ); + return field_eq(L0,L1); +} + +mask_t +decaf_eq_tw_extended ( + const tw_extended_a_t a, + const tw_extended_a_t b +) { + field_a_t L0, L1; + field_mul ( L0, b->y, a->x ); + field_mul ( L1, a->y, b->x ); + return field_eq(L0,L1); } mask_t diff --git a/src/include/ec_point.h b/src/include/ec_point.h index 0338782..db5ee7d 100644 --- a/src/include/ec_point.h +++ b/src/include/ec_point.h @@ -4,7 +4,11 @@ * Copyright (c) 2014 Cryptography Research, Inc. \n * Released under the MIT License. See LICENSE.txt for license information. * @author Mike Hamburg - * @warning This file was automatically generated. + * + * This file contains a huge number of different options for EC point arithmetic, + * but only a few of them will be used by any given library. They are here for + * reference and for consistency checks. The Goldilocks library link step strips + * out unused functions. */ #ifndef __CC_INCLUDED_EC_POINT_H__ @@ -75,6 +79,14 @@ typedef struct tw_extensible_t { field_a_t x, y, z, t, u; } tw_extensible_a_t[1]; +/** + * Extended coordinates for twisted Edwards curves. + * Jack of all trades, master of none. + */ +typedef struct tw_extended_t { + field_a_t x, y, z, t; +} tw_extended_a_t[1]; + /** * Niels coordinates for twisted Edwards curves. * @@ -140,6 +152,15 @@ copy_tw_extensible ( const tw_extensible_a_t ds ) __attribute__((unused,always_inline)); +/** + * Auto-generated copy method. + */ +static __inline__ void +copy_tw_extended ( + tw_extended_a_t a, + const tw_extended_a_t ds +) __attribute__((unused,always_inline)); + /** * Auto-generated copy method. */ @@ -272,6 +293,25 @@ convert_tw_niels_to_tw_extensible ( const tw_niels_a_t d ); +void +convert_tw_extensible_to_tw_extended ( + tw_extended_a_t b, + const tw_extensible_a_t a +); + +void +add_tw_extended ( + tw_extended_a_t d, + const tw_extended_a_t e +); + +void +add_sub_tw_extended ( + tw_extended_a_t d, + const tw_extended_a_t e, + mask_t sub +); + void montgomery_step ( montgomery_a_t a @@ -435,6 +475,21 @@ decaf_serialize_tw_extensible ( const tw_extensible_a_t a ); + +mask_t +decaf_deserialize_tw_extended ( + tw_extended_a_t a, + const field_a_t s, + mask_t allow_identity +) +__attribute__((warn_unused_result)); + +void +decaf_serialize_tw_extended ( + field_a_t b, + const tw_extended_a_t a +); + void set_identity_extensible ( extensible_a_t a @@ -445,6 +500,11 @@ set_identity_tw_extensible ( tw_extensible_a_t a ); +void +set_identity_tw_extended ( + tw_extended_a_t a +); + void set_identity_affine ( affine_a_t a @@ -486,6 +546,13 @@ decaf_eq_tw_extensible ( ) __attribute__((warn_unused_result)); +mask_t +decaf_eq_tw_extended ( + const tw_extended_a_t a, + const tw_extended_a_t b +) +__attribute__((warn_unused_result)); + mask_t decaf_eq_extensible ( const extensible_a_t a, @@ -592,6 +659,17 @@ copy_tw_extensible ( field_copy ( a->u, ds->u ); } +void +copy_tw_extended ( + tw_extended_a_t a, + const tw_extended_a_t ds +) { + field_copy ( a->x, ds->x ); + field_copy ( a->y, ds->y ); + field_copy ( a->z, ds->z ); + field_copy ( a->t, ds->t ); +} + void copy_tw_niels ( tw_niels_a_t a, diff --git a/src/include/scalarmul.h b/src/include/scalarmul.h index 0fe8dac..4191bec 100644 --- a/src/include/scalarmul.h +++ b/src/include/scalarmul.h @@ -145,6 +145,23 @@ scalarmul ( /* TODO? int nbits */ ); +/** + * Scalar multiply a twisted Edwards-form point, simply, in extended coordinates. + * + * This function takes constant time. + * + * Currently the scalar is always exactly 448 bits long. + * + * @param [inout] working The point to multply. + * @param [in] scalar The scalar, in little-endian form. + */ +void +scalarmul_ed ( + tw_extended_a_t working, + const word_t scalar[SCALAR_WORDS] + /* TODO? int nbits */ +); + /** * Scalar multiply a twisted Edwards-form point. Use the same * algorithm as scalarmul(), but uses variable array indices. diff --git a/src/scalarmul.c b/src/scalarmul.c index 8f861d5..f3ffd99 100644 --- a/src/scalarmul.c +++ b/src/scalarmul.c @@ -88,6 +88,17 @@ constant_time_lookup_tw_pniels ( constant_time_lookup(out,in,sizeof(*out),nin,idx); } +static __inline__ void +__attribute__((unused,always_inline)) +constant_time_lookup_tw_extended ( + tw_extended_a_t out, + const tw_extended_a_t *in, + int nin, + int idx +) { + constant_time_lookup(out,in,sizeof(*out),nin,idx); +} + static __inline__ void __attribute__((unused,always_inline)) constant_time_lookup_tw_niels ( @@ -189,6 +200,65 @@ scalarmul ( } } +void +scalarmul_ed ( + tw_extended_a_t working, + const word_t scalar[SCALAR_WORDS] +) { + const int WINDOW = SCALARMUL_FIXED_WINDOW_SIZE, + WINDOW_MASK = (1<> 1, + NTABLE = 1<<(WINDOW-1), + nbits = ROUND_UP(SCALAR_BITS,WINDOW); + + word_t scalar2[SCALAR_WORDS]; + convert_to_signed_window_form ( + scalar2, scalar, SCALAR_WORDS, + SCALARMUL_FIXED_WINDOW_ADJUSTMENT, SCALAR_WORDS + ); + + tw_extended_a_t + tmp VECTOR_ALIGNED, + multiples[NTABLE] VECTOR_ALIGNED; + + copy_tw_extended(tmp, working); + add_tw_extended(tmp, tmp); + copy_tw_extended(multiples[0], working); + + int i,j; + for (i=1; i> (i%WORD_BITS) & WINDOW_MASK, + inv = (bits>>(WINDOW-1))-1; + bits ^= inv; + + set_identity_tw_extended(working); + + for (; i>=0; i-=WINDOW) { + if (i != nbits-WINDOW) { + for (j=0; j> (i%WORD_BITS); + + if (i/WORD_BITS < SCALAR_WORDS-1 && i%WORD_BITS >= WORD_BITS-WINDOW) { + bits ^= scalar2[i/WORD_BITS+1] << (WORD_BITS - (i%WORD_BITS)); + } + + bits &= WINDOW_MASK; + inv = (bits>>(WINDOW-1))-1; + bits ^= inv; + + constant_time_lookup_tw_extended(tmp, (const tw_extended_a_t*)multiples, NTABLE, bits & WINDOW_T_MASK); + add_sub_tw_extended(working, tmp, inv); + } +} + void scalarmul_vlook ( tw_extensible_a_t working, diff --git a/test/bench.c b/test/bench.c index 6769ae8..ddf02ef 100644 --- a/test/bench.c +++ b/test/bench.c @@ -267,12 +267,23 @@ int main(int argc, char **argv) { memset(&ext,0,sizeof(ext)); memset(&niels,0,sizeof(niels)); /* avoid assertions in p521 even though this isn't a valid ext or niels */ + + tw_extended_a_t ed; + convert_tw_extensible_to_tw_extended(ed,&ext); + when = now(); for (i=0; ix); + field_print(" y", ed->y); + field_print(" z", ed->z); + field_print(" t", ed->t); + printf(" tw deser is %s\n", validate_tw_extensible(&tw_ext) ? "valid" : "invalid"); + field_print(" S", serf2); + fails ++; + } + word_t scalar = 1; mask_t res = decaf_montgomery_ladder(serf2,serf,&scalar,1+(i%31)); if (~res | ~field_eq(serf2,serf)) { diff --git a/test/test_scalarmul.c b/test/test_scalarmul.c index b38021b..d7e7c90 100644 --- a/test/test_scalarmul.c +++ b/test/test_scalarmul.c @@ -17,7 +17,7 @@ single_scalarmul_compatibility_test ( int nbits ) { struct tw_extensible_t text, work; - field_a_t mont, ct, vl, vt, decaf_s, decaf_m, decaf_te; + field_a_t mont, ct, vl, vt, sced, decaf_s, decaf_m, decaf_te; int ret = 0, i; mask_t succ, succm; @@ -110,11 +110,21 @@ single_scalarmul_compatibility_test ( scalarmul_vt(&work, scalar, nbits); untwist_and_double_and_serialize(vt, &work); - + tw_extended_a_t ed; + convert_tw_extensible_to_tw_extended(ed, &text); + scalarmul_ed(ed, scalar); + field_copy(work.x, ed->x); + field_copy(work.y, ed->y); + field_copy(work.z, ed->z); + field_copy(work.t, ed->t); + field_set_ui(work.u, 1); + untwist_and_double_and_serialize(sced, &work); + /* check consistency mont vs window */ consistent &= field_eq(mont, ct); consistent &= field_eq(mont, vl); consistent &= field_eq(mont, vt); + consistent &= field_eq(mont, sced); } /* check consistency mont vs combs */ @@ -163,6 +173,7 @@ single_scalarmul_compatibility_test ( field_print(" ct ", ct); field_print(" vl ", vl); field_print(" vt ", vt); + field_print(" ed ", sced); } printf("decaf: succ = %d, %d\n", (int)succ_dm, (int)succ_dta);