Commit 12a5d089 authored by Michael Hamburg's avatar Michael Hamburg

decaf seems to work for monty; needs more testing, negative testing. Now...

decaf seems to work for monty; needs more testing, negative testing. Now should match sage script exactly.
parent 4f27b22a
......@@ -243,7 +243,7 @@ convert_tw_niels_to_tw_extensible (
}
void
deserialize_montgomery_decaf (
decaf_deserialize_montgomery (
montgomery_aux_a_t a,
const field_a_t s
) {
......@@ -254,20 +254,6 @@ deserialize_montgomery_decaf (
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
......@@ -407,6 +393,82 @@ decaf_make_even (
field_strong_reduce ( a );
}
mask_t
decaf_serialize_montgomery (
field_a_t out,
const montgomery_aux_a_t a,
mask_t swapped
) {
field_a_t xz_d, xz_a, x0, den, L0, L1, L2, L3;
mask_t zcase, output_zero, flip, succ, za_zero;
field_mul(xz_d, a->xd, a->zd);
field_mul(xz_a, a->xa, a->za);
output_zero = field_is_zero(xz_d);
za_zero = field_is_zero(a->za);
field_addw(xz_d, -output_zero); /* make xz_d always nonzero */
zcase = output_zero | field_is_zero(xz_a);
field_sqr(x0, a->s0);
/* Curve test in zcase */
field_copy(L0,x0);
field_addw(L0,1);
field_sqr(L1,L0);
field_mulw_scc_wr(L0,x0,-4*EDWARDS_D);
field_add(L1,L1,L0);
constant_time_select(xz_a,L1,xz_a,sizeof(xz_a),zcase);
/* Compute denominator */
field_mul(L0, x0, xz_d);
field_mulw(L2, L0, 4);
field_mul(L1, L2, xz_a);
field_isr(den, L1);
/* Check squareness */
field_sqr(L2, den);
field_mul(L0, L1, L2);
field_addw(L0, 1);
succ = ~field_low_bit(a->s0) & ~field_is_zero(L0);
/* Compute y/x */
field_mul(L1, x0, a->xd);
field_sub(L1, a->zd, L1);
field_mul(L0, a->za, L1); /* L0 = "opq" */
field_mul(L1, x0, a->zd);
field_sub(L1, L1, a->xd);
field_mul(L2, a->xa, L1); /* L2 = "pqr" */
field_sub(L1, L0, L2);
field_add(L0, L0, L2);
field_mul(L2, L1, den); /* L2 = y0 / x0 */
field_mul(L1, L0, den); /* L1 = yO / xO */
flip = field_low_bit(L1) ^ field_low_bit(L2) ^ za_zero;
constant_time_select(L0, a->zd, a->xd, sizeof(L0), flip); /* L0 = "times" */
/* OK, done with y-coordinates */
/* OK, now correct for swappage */
field_add(den,den,den);
field_mul(L1,den,a->s0);
field_sqr(L2,L1);
field_mul(L3,L2,xz_a);
constant_time_select(den,L3,L1,sizeof(den),swapped &~ zcase);
/* compute the output */
field_mul(L1,L0,den);
constant_time_select(L2,a->s0,a->zs,sizeof(L2),zcase); /* zs, but s0 in zcase */
field_mul(L0,L1,L2);
constant_time_select(L3,a->xd,a->zd,sizeof(L3),za_zero);
constant_time_select(L2,L3,a->xs,sizeof(L2),zcase); /* xs, but zq or qq in zcase */
field_mul(out,L0,L2);
constant_time_mask(out,out,sizeof(field_a_t),~output_zero);
decaf_make_even(out);
return succ;
}
void
decaf_serialize_extensible (
field_a_t b,
......
......@@ -41,7 +41,7 @@
#else
#define FIELD_HASH_BYTES (SHA512_OUTPUT_BYTES * ((FIELD_BYTES-1)/SHA512_OUTPUT_BYTES + 1))
static inline void field_hash_final (
sha512_ctx_a_t *ctx,
sha512_ctx_a_t ctx,
unsigned char out[FIELD_HASH_BYTES]
) {
/* SHA PRNG I guess? I really should have used SHAKE */
......
......@@ -191,7 +191,7 @@ constant_time_lookup (
static __inline__ void
__attribute__((unused,always_inline))
constant_time_mask (
void *__restrict__ a_,
void * a_,
const void *b_,
word_t elem_bytes,
mask_t mask
......
......@@ -296,14 +296,14 @@ serialize_montgomery (
);
mask_t
serialize_montgomery_decaf (
decaf_serialize_montgomery (
field_a_t b,
const montgomery_aux_a_t a,
const field_a_t sbz
mask_t swapped
);
void
deserialize_montgomery_decaf (
decaf_deserialize_montgomery (
montgomery_aux_a_t a,
const field_a_t s
);
......
......@@ -100,7 +100,7 @@ montgomery_ladder (
/**
* Full Montgomery aux ladder in decaf format.
*
* Out = [2^n_extra_doubles * scalar] * in, where
* Out = scalar * in, where
* scalar is little-endian and has length $nbits$ bits.
*
* This function (once it's done; TODO) will always reject points
......@@ -115,20 +115,17 @@ montgomery_ladder (
* @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 (
decaf_montgomery_ladder (
field_a_t out,
const field_a_t in,
const word_t *scalar,
unsigned int nbits,
unsigned int n_extra_doubles
unsigned int nbits
) __attribute__((warn_unused_result));
/**
......
......@@ -49,15 +49,14 @@ montgomery_ladder (
}
mask_t
montgomery_ladder_decaf (
decaf_montgomery_ladder (
field_a_t out,
const field_a_t in,
const word_t *scalar,
unsigned int nbits,
unsigned int n_extra_doubles
unsigned int nbits
) {
montgomery_aux_a_t mont;
deserialize_montgomery_decaf(mont, in);
decaf_deserialize_montgomery(mont, in);
int i,j,n=(nbits-1)%WORD_BITS;
mask_t pflip = 0;
......@@ -75,12 +74,7 @@ montgomery_ladder_decaf (
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);
return decaf_serialize_montgomery(out, mont, pflip);
}
static __inline__ void
......
......@@ -328,7 +328,7 @@ int main(int argc, char **argv) {
when = now();
for (i=0; i<nbase/10; i++) {
ignore_result(montgomery_ladder_decaf(a,b,sk,FIELD_BITS,0));
ignore_result(decaf_montgomery_ladder(a,b,sk,FIELD_BITS));
}
when = now() - when;
printf("decafladder: %5.1fµs\n", when * 1e6 / i);
......
......@@ -362,14 +362,15 @@ 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;
word_t scalar = 1;
mask_t res = decaf_montgomery_ladder(serf2,serf,&scalar,1+(i%31));
if (~res | ~field_eq(serf2,serf)) {
youfail();
printf("Decaf Montgomery ladder i=%d res=%d\n", 1+(i%31), (int)res);
field_print(" s", serf);
field_print(" o", serf2);
printf("\n");
}
}
if (hits < 1000) {
youfail();
......
......@@ -17,7 +17,7 @@ single_scalarmul_compatibility_test (
int nbits
) {
struct tw_extensible_t text, work;
field_a_t mont, ct, vl, vt;
field_a_t mont, ct, vl, vt, decaf_s, decaf_m, decaf_te;
int ret = 0, i;
mask_t succ, succm;
......@@ -126,6 +126,19 @@ single_scalarmul_compatibility_test (
for (i=0; i<nsizes; i++) {
consistent &= field_eq(mont,wout[i]);
}
/* Do decaf */
copy_tw_extensible(&work,&text);
double_tw_extensible(&work);
decaf_serialize_tw_extensible(decaf_s, &work);
mask_t succ_dm, succ_dta;
succ_dm = decaf_montgomery_ladder(decaf_m, decaf_s, scalar, nbits);
succ_dta = deserialize_and_twist_approx(&work, mont);
decaf_serialize_tw_extensible(decaf_te, &work);
consistent &= field_eq(decaf_m, decaf_te);
consistent &= succ_dm & succ_dta;
/* If inconsistent, complain. */
if (!consistent) {
......@@ -152,6 +165,11 @@ single_scalarmul_compatibility_test (
field_print(" vt ", vt);
}
printf("decaf: succ = %d, %d\n", (int)succ_dm, (int)succ_dta);
field_print(" s0", decaf_s);
field_print(" dm", decaf_m);
field_print(" dt", decaf_te);
ret = -1;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment