From 4f27b22a1d94dca48e50358e0f23034ac73a68f3 Mon Sep 17 00:00:00 2001 From: Michael Hamburg Date: Fri, 23 Jan 2015 12:53:40 -0800 Subject: [PATCH] decaf ladder is "correct", but not yet serializing to decaf --- src/ec_point.c | 49 ++++++++++++++++++++++++++--------------- src/include/ec_point.h | 7 ++++++ src/include/scalarmul.h | 34 ++++++++++++++++++++++++++++ src/scalarmul.c | 35 +++++++++++++++++++++++++++++ test/bench.c | 7 ++++++ test/test_pointops.c | 43 ++++++++++++++++++++++++++---------- 6 files changed, 145 insertions(+), 30 deletions(-) diff --git a/src/ec_point.c b/src/ec_point.c index 1a61051..df3294c 100644 --- a/src/ec_point.c +++ b/src/ec_point.c @@ -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 ); } diff --git a/src/include/ec_point.h b/src/include/ec_point.h index e3494b9..a22572f 100644 --- a/src/include/ec_point.h +++ b/src/include/ec_point.h @@ -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 ( diff --git a/src/include/scalarmul.h b/src/include/scalarmul.h index dab8a99..fb2bbd8 100644 --- a/src/include/scalarmul.h +++ b/src/include/scalarmul.h @@ -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. * diff --git a/src/scalarmul.c b/src/scalarmul.c index 93d9443..bd9c2a9 100644 --- a/src/scalarmul.c +++ b/src/scalarmul.c @@ -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 ( diff --git a/test/bench.c b/test/bench.c index c1cc6ff..5549a7d 100644 --- a/test/bench.c +++ b/test/bench.c @@ -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 #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;