@@ -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; | |||