Commit dc1e4edc authored by Michael Hamburg's avatar Michael Hamburg

decaf elligator

parent 74dbbf0b
......@@ -54,6 +54,7 @@ extern "C" {
/* Goldilocks' build flags default to hidden and stripping executables. */
#define API_VIS __attribute__((visibility("default")))
#define WARN_UNUSED __attribute__((warn_unused_result))
#define NONNULL1 __attribute__((nonnull(1)))
#define NONNULL2 __attribute__((nonnull(1,2)))
#define NONNULL3 __attribute__((nonnull(1,2,3)))
......@@ -158,6 +159,31 @@ void decaf_scalarmul (
unsigned int scalar_words
) API_VIS NONNULL3;
/**
* @brief Test that a point is valid, for debugging purposes.
*
* @param [in] point The number to test.
* @retval DECAF_TRUE The point is valid.
* @retval DECAF_FALSE The point is invalid.
*/
decaf_bool_t decaf_valid (
const decaf_point_t toTest
) API_VIS WARN_UNUSED NONNULL1;
/**
* @brief Elligator-like hash to curve.
*
* May be up to 4:1 on [0,(p-1)/2]
* // TODO: check that it isn't more.
*
* @param [in] ser A serialized point.
* @param [out] pt The hashed input
*/
void decaf_nonuniform_map_to_curve (
decaf_point_t pt,
const unsigned char ser[DECAF_SER_BYTES]
) API_VIS NONNULL2;
#undef API_VIS
#undef WARN_UNUSED
#undef NONNULL2
......
......@@ -371,3 +371,91 @@ decaf_bool_t decaf_eq ( const decaf_point_t p, const decaf_point_t q ) {
gf_mul ( b, q->y, p->x );
return gf_eq(a,b);
}
static const int QUADRATIC_NONRESIDUE = -1;
void decaf_nonuniform_map_to_curve (
decaf_point_t p,
const unsigned char ser[DECAF_SER_BYTES]
) {
/*
sage: XXD = (u*r^2 + 1) * (d - u*r^2) * (1 - u*d*r^2) / (d+1)
sage: factor(XX / (1/XXD))
(u*r^2 - d)^2
sage: factor((ey-1)/(ey+1)/(1/d * 1/XXD))
(u*d*r^2 - 1)^2
sage: factor(XX2 / (u*r^2/XXD))
(u*d*r^2 - 1)^2
sage: factor((ey2-1)/(ey2+1)/(1/d * u*r^2/XXD))
(u*r^2 - d)^2
*/
gf r,urr,a,b,c,dee,e,ur2_d,udr2_1;
(void)gf_deser(r,ser);
gf_canon(r); // just in case
gf_sqr(a,r);
gf_mlw(urr,a,QUADRATIC_NONRESIDUE); // urr = u*r^2
gf_mlw(dee,ONE,EDWARDS_D);
gf_add(a,urr,ONE);
gf_sub(ur2_d,dee,urr); // ur2_d = -(ur^2-d)
gf_mul(c,a,ur2_d);
gf_mlw(b,urr,-EDWARDS_D);
gf_add(udr2_1,b,ONE); // udr2_1 = -(udr^2-1)
gf_mul(a,c,udr2_1);
gf_mlw(c,a,EDWARDS_D+1); // c = (u*r^2 + 1) * (d - u*r^2) * (1 - u*d*r^2) * (d+1)
gf_isqrt(b,c); // FIELD: if 5 mod 8, multiply result by u.
gf_sqr(a,b);
gf_mul(e,a,c);
mask_t square = gf_eq(e,ONE);
gf_mul(a,b,r);
cond_sel(b,a,b,square);
cond_neg(b,hibit(b));
gf_mlw(a,b,EDWARDS_D+1);
/* Here: a = sqrt( (d+1) / (ur^2?) * (u*r^2 + 1) * (d - u*r^2) * (1 - u*d*r^2)) */
cond_swap(ur2_d,udr2_1,~square);
gf_mul(e,ur2_d,a);
gf_mul(b,udr2_1,a);
gf_sqr(c,b);
/* Here:
* ed_x = 2e/(1-e^2)
* c = * (ed_y-1)/(ed_y+1)
*
* Special cases:
* e^2 = 1: impossible for cofactor-4 curves (would isogenize to order-4 point)
* e = 0 <-> also c = 0: maps to (0,1), which is fine.
*/
gf_sqr(a,e);
gf_sub(a,ONE,a);
gf_add(e,e,e);
gf_add(b,dee,c);
gf_sub(c,dee,c);
gf_mul(p->x,e,c);
gf_mul(p->z,a,c);
gf_mul(p->y,b,a);
gf_mul(p->t,b,e);
}
decaf_bool_t decaf_valid (
const decaf_point_t p
) {
gf a,b,c;
gf_mul(a,p->x,p->y);
gf_mul(b,p->z,p->t);
mask_t out = gf_eq(a,b);
gf_sqr(a,p->x);
gf_sqr(b,p->y);
gf_sub(a,b,a);
gf_sqr(b,p->t);
gf_mlw(c,b,1-EDWARDS_D);
gf_sqr(b,p->z);
gf_sub(b,b,c);
out &= gf_eq(a,b);
return out;
}
......@@ -363,13 +363,19 @@ int test_decaf_evil (void) {
mask_t succ_dec = decaf_decode(pt_dec2, ser_de, -1);
field_serialize(ser_ed, out_ed);
decaf_point_t p;
decaf_nonuniform_map_to_curve (p,random_input);
mask_t succ_nur = decaf_valid(p);
if ((care_should && should != s_m)
|| ~s_base || s_e != s_te || s_m != s_te || s_ed != s_te
|| (s_te && ~field_eq(out_e,out_m))
|| (s_ed && ~field_eq(out_e,out_ed))
|| memcmp(ser_de, ser_ed, 56)
|| (s_e & ~succ_dec)
|| (s_e & ~decaf_eq(pt_dec, pt_dec2))
|| (s_e & ~decaf_eq(pt_dec, pt_dec2)
|| (s_e & ~decaf_valid(pt_dec))
|| ~succ_nur)
) {
youfail();
field_print(" base", base);
......@@ -377,8 +383,9 @@ int test_decaf_evil (void) {
field_print(" oute", out_e);
field_print(" outE", out_ed);
field_print(" outm", out_m);
printf(" succ: m=%d, e=%d, t=%d, b=%d, T=%d, D=%d, should=%d[%d]\n",
printf(" succ: m=%d, e=%d, t=%d, b=%d, T=%d, D=%d, nur=%d, should=%d[%d]\n",
-(int)s_m,-(int)s_e,-(int)s_te,-(int)s_base,-(int)s_ed,-(int)succ_dec,
-(int)succ_nur,
-(int)should,-(int)care_should
);
ret = -1;
......@@ -538,6 +545,7 @@ int test_decaf (void) {
printf(" Fail: only %d successes in decaf_deser\n", hits);
return -1;
} else if (fails) {
printf(" %d fails\n", fails);
return -1;
} else {
return 0;
......
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