diff --git a/include/decaf.h b/include/decaf.h index 9eb5e78..b7f0ff2 100644 --- a/include/decaf.h +++ b/include/decaf.h @@ -63,6 +63,11 @@ typedef struct decaf_448_point_s { decaf_word_t x[DECAF_448_LIMBS],y[DECAF_448_LIMBS],z[DECAF_448_LIMBS],t[DECAF_448_LIMBS]; } decaf_448_point_t[1]; +/** Precomputed table based on a point. Can be trivial implementation. */ +typedef struct decaf_448_precomputed_s { + decaf_448_point_t p[1]; +} decaf_448_precomputed_t[1]; + /** Scalar is stored packed, because we don't need the speed. */ typedef struct decaf_448_scalar_s { decaf_word_t limb[DECAF_448_SCALAR_LIMBS]; @@ -78,23 +83,26 @@ static const decaf_bool_t DECAF_SUCCESS = -(decaf_bool_t)1 /*DECAF_TRUE*/, /** The prime p, for debugging purposes. * TODO: prevent this scalar from actually being used for non-debugging purposes? */ -const decaf_448_scalar_t decaf_448_scalar_p API_VIS; +extern const decaf_448_scalar_t decaf_448_scalar_p API_VIS; /** A scalar equal to 1. */ -const decaf_448_scalar_t decaf_448_scalar_one API_VIS; +extern const decaf_448_scalar_t decaf_448_scalar_one API_VIS; /** A scalar equal to 0. */ -const decaf_448_scalar_t decaf_448_scalar_zero API_VIS; +extern const decaf_448_scalar_t decaf_448_scalar_zero API_VIS; /** The identity point on the curve. */ -const decaf_448_point_t decaf_448_point_identity API_VIS; +extern const decaf_448_point_t decaf_448_point_identity API_VIS; /** * An arbitrarily chosen base point on the curve. * Equal to Ed448-Goldilocks base point defined by DJB, except of course that * it's on the twist in this case. TODO: choose a base point with nice encoding? */ -const decaf_448_point_t decaf_448_point_base API_VIS; +extern const struct decaf_448_point_s *decaf_448_point_base API_VIS; + +/** Precomputed table for the base point on the curve. */ +extern const decaf_448_precomputed_t decaf_448_precomputed_base API_VIS; #ifdef __cplusplus extern "C" { @@ -300,6 +308,37 @@ void decaf_448_point_scalarmul ( const decaf_448_scalar_t scalar ) API_VIS NONNULL3; +/** + * @brief Precompute a table for fast scalar multiplication. + * Some implementations do not include precomputed points; for + * those implementations, this implementation simply copies the + * point. + * + * @param [out] a A precomputed table of multiples of the point. + * @param [in] b Any point. + */ +void decaf_448_precompute ( + decaf_448_precomputed_t a, + const decaf_448_point_t b +) API_VIS NONNULL2; + +/** + * @brief Multiply a precomputed base point by a scalar: + * scaled = scalar*base. + * Some implementations do not include precomputed points; for + * those implementations, this function is the same as + * decaf_448_point_scalarmul + * + * @param [out] scaled The scaled point base*scalar + * @param [in] base The point to be scaled. + * @param [in] scalar The scalar to multiply by. + */ +void decaf_448_precomputed_scalarmul ( + decaf_448_point_t scaled, + const decaf_448_precomputed_t base, + const decaf_448_scalar_t scalar +) API_VIS NONNULL3; + /** * @brief Multiply two base points by two scalars: * scaled = scalar1*base1 + scalar2*base2. diff --git a/src/decaf.c b/src/decaf.c index 0574186..b763bf9 100644 --- a/src/decaf.c +++ b/src/decaf.c @@ -66,7 +66,8 @@ static const decaf_448_scalar_t decaf_448_scalar_r2 = {{{ static const decaf_word_t DECAF_MONTGOMERY_FACTOR = (decaf_word_t)(0x3bd440fae918bc5ull); /** base = twist of Goldilocks base point (~,19). */ -const decaf_448_point_t decaf_448_point_base = {{ + +const decaf_448_precomputed_t decaf_448_precomputed_base = {{{{{ { LIMB(0xb39a2d57e08c7b),LIMB(0xb38639c75ff281), LIMB(0x2ec981082b3288),LIMB(0x99fe8607e5237c), LIMB(0x0e33fbb1fadd1f),LIMB(0xe714f67055eb4a), @@ -80,7 +81,9 @@ const decaf_448_point_t decaf_448_point_base = {{ LIMB(0x0d79c0a7729a69),LIMB(0xc18d3f24aebc1c), LIMB(0x1fbb5389b3fda5),LIMB(0xbb24f674635948), LIMB(0x723a55709a3983),LIMB(0xe1c0107a823dd4) } -}}; +}}}}}; + +const struct decaf_448_point_s *decaf_448_point_base = decaf_448_precomputed_base->p[0]; #if (defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__)) || defined(DECAF_FORCE_UNROLL) #if DECAF_448_LIMBS==8 @@ -698,3 +701,18 @@ decaf_bool_t decaf_448_point_valid ( out &= ~gf_eq(p->z,ZERO); return out; } + +void decaf_448_precompute ( + decaf_448_precomputed_t a, + const decaf_448_point_t b +) { + decaf_448_point_copy(a->p[0],b); +} + +void decaf_448_precomputed_scalarmul ( + decaf_448_point_t a, + const decaf_448_precomputed_t b, + const decaf_448_scalar_t scalar +) { + decaf_448_point_scalarmul(a,b->p[0],scalar); +} diff --git a/test/test_scalarmul.c b/test/test_scalarmul.c index 79266e4..43c4057 100644 --- a/test/test_scalarmul.c +++ b/test/test_scalarmul.c @@ -111,10 +111,22 @@ single_scalarmul_compatibility_test ( scalarmul_vt(&work, scalar, nbits); untwist_and_double_and_serialize(vt, &work); - decaf_448_point_t ed2; + decaf_448_point_t ed2, ed3; + decaf_448_precomputed_t dpre; tw_extended_a_t ed; convert_tw_extensible_to_tw_extended(ed, &text); - decaf_448_point_scalarmul(ed2, (struct decaf_448_point_s *)ed, (struct decaf_448_scalar_s *)scalar); + decaf_448_point_scalarmul( + ed2, + (struct decaf_448_point_s *)ed, + (struct decaf_448_scalar_s *)scalar + ); + decaf_448_precompute(dpre, (struct decaf_448_point_s *)ed); + decaf_448_precomputed_scalarmul( + ed3, + dpre, + (struct decaf_448_scalar_s *)scalar + ); + scalarmul_ed(ed, scalar); field_copy(work.x, ed->x); @@ -124,9 +136,11 @@ single_scalarmul_compatibility_test ( field_set_ui(work.u, 1); untwist_and_double_and_serialize(sced, &work); - uint8_t ser1[(FIELD_BITS+6)/8], ser2[(FIELD_BITS+6)/8]; + uint8_t ser1[DECAF_448_SER_BYTES], ser2[DECAF_448_SER_BYTES], + ser3[DECAF_448_SER_BYTES]; decaf_448_point_encode(ser1, (struct decaf_448_point_s *)ed); decaf_448_point_encode(ser2, ed2); + decaf_448_point_encode(ser3, ed3); /* check consistency mont vs window */ consistent &= field_eq(mont, ct); @@ -134,6 +148,7 @@ single_scalarmul_compatibility_test ( consistent &= field_eq(mont, vt); consistent &= field_eq(mont, sced); consistent &= memcmp(ser1,ser2,sizeof(ser1)) ? 0 : -1; + consistent &= memcmp(ser1,ser3,sizeof(ser1)) ? 0 : -1; } /* check consistency mont vs combs */