@@ -54,6 +54,7 @@ extern "C" { | |||||
/* Goldilocks' build flags default to hidden and stripping executables. */ | /* Goldilocks' build flags default to hidden and stripping executables. */ | ||||
#define API_VIS __attribute__((visibility("default"))) | #define API_VIS __attribute__((visibility("default"))) | ||||
#define WARN_UNUSED __attribute__((warn_unused_result)) | #define WARN_UNUSED __attribute__((warn_unused_result)) | ||||
#define NONNULL1 __attribute__((nonnull(1))) | |||||
#define NONNULL2 __attribute__((nonnull(1,2))) | #define NONNULL2 __attribute__((nonnull(1,2))) | ||||
#define NONNULL3 __attribute__((nonnull(1,2,3))) | #define NONNULL3 __attribute__((nonnull(1,2,3))) | ||||
@@ -158,6 +159,31 @@ void decaf_scalarmul ( | |||||
unsigned int scalar_words | unsigned int scalar_words | ||||
) API_VIS NONNULL3; | ) 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 API_VIS | ||||
#undef WARN_UNUSED | #undef WARN_UNUSED | ||||
#undef NONNULL2 | #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 ); | gf_mul ( b, q->y, p->x ); | ||||
return gf_eq(a,b); | 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); | mask_t succ_dec = decaf_decode(pt_dec2, ser_de, -1); | ||||
field_serialize(ser_ed, out_ed); | 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) | if ((care_should && should != s_m) | ||||
|| ~s_base || s_e != s_te || s_m != s_te || s_ed != s_te | || ~s_base || s_e != s_te || s_m != s_te || s_ed != s_te | ||||
|| (s_te && ~field_eq(out_e,out_m)) | || (s_te && ~field_eq(out_e,out_m)) | ||||
|| (s_ed && ~field_eq(out_e,out_ed)) | || (s_ed && ~field_eq(out_e,out_ed)) | ||||
|| memcmp(ser_de, ser_ed, 56) | || memcmp(ser_de, ser_ed, 56) | ||||
|| (s_e & ~succ_dec) | || (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(); | youfail(); | ||||
field_print(" base", base); | field_print(" base", base); | ||||
@@ -377,8 +383,9 @@ int test_decaf_evil (void) { | |||||
field_print(" oute", out_e); | field_print(" oute", out_e); | ||||
field_print(" outE", out_ed); | field_print(" outE", out_ed); | ||||
field_print(" outm", out_m); | 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)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 | -(int)should,-(int)care_should | ||||
); | ); | ||||
ret = -1; | ret = -1; | ||||
@@ -538,6 +545,7 @@ int test_decaf (void) { | |||||
printf(" Fail: only %d successes in decaf_deser\n", hits); | printf(" Fail: only %d successes in decaf_deser\n", hits); | ||||
return -1; | return -1; | ||||
} else if (fails) { | } else if (fails) { | ||||
printf(" %d fails\n", fails); | |||||
return -1; | return -1; | ||||
} else { | } else { | ||||
return 0; | return 0; | ||||