Add functions to test if X coordinate is valid

This commit is contained in:
Pieter Wuille 2022-11-04 16:17:56 -04:00
parent a597a5a9ce
commit 79e5b2a8b8
3 changed files with 63 additions and 1 deletions

View File

@ -51,6 +51,12 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se
* for Y. Return value indicates whether the result is valid. */ * for Y. Return value indicates whether the result is valid. */
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd); static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
/** Determine whether x is a valid X coordinate on the curve. */
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x);
/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd);
/** Check whether a group element is the point at infinity. */ /** Check whether a group element is the point at infinity. */
static int secp256k1_ge_is_infinity(const secp256k1_ge *a); static int secp256k1_ge_is_infinity(const secp256k1_ge *a);

View File

@ -823,4 +823,32 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
#endif #endif
} }
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x) {
secp256k1_fe c;
secp256k1_fe_sqr(&c, x);
secp256k1_fe_mul(&c, &c, x);
secp256k1_fe_add_int(&c, SECP256K1_B);
return secp256k1_fe_is_square_var(&c);
}
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd) {
/* We want to determine whether (xn/xd) is on the curve.
*
* (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square).
*/
secp256k1_fe r, t;
#ifdef VERIFY
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd));
#endif
secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */
secp256k1_fe_sqr(&t, xn); /* t = xn^2 */
secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */
secp256k1_fe_sqr(&t, xd); /* t = xd^2 */
secp256k1_fe_sqr(&t, &t); /* t = xd^4 */
VERIFY_CHECK(SECP256K1_B <= 31);
secp256k1_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */
secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */
return secp256k1_fe_is_square_var(&r);
}
#endif /* SECP256K1_GROUP_IMPL_H */ #endif /* SECP256K1_GROUP_IMPL_H */

View File

@ -3775,7 +3775,7 @@ static void test_ge(void) {
*/ */
secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs)); secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));
secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs)); secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));
secp256k1_fe zf; secp256k1_fe zf, r;
secp256k1_fe zfi2, zfi3; secp256k1_fe zfi2, zfi3;
secp256k1_gej_set_infinity(&gej[0]); secp256k1_gej_set_infinity(&gej[0]);
@ -3817,6 +3817,11 @@ static void test_ge(void) {
secp256k1_fe_sqr(&zfi2, &zfi3); secp256k1_fe_sqr(&zfi2, &zfi3);
secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); secp256k1_fe_mul(&zfi3, &zfi3, &zfi2);
/* Generate random r */
do {
random_field_element_test(&r);
} while(secp256k1_fe_is_zero(&r));
for (i1 = 0; i1 < 1 + 4 * runs; i1++) { for (i1 = 0; i1 < 1 + 4 * runs; i1++) {
int i2; int i2;
for (i2 = 0; i2 < 1 + 4 * runs; i2++) { for (i2 = 0; i2 < 1 + 4 * runs; i2++) {
@ -3929,6 +3934,29 @@ static void test_ge(void) {
free(ge_set_all); free(ge_set_all);
} }
/* Test that all elements have X coordinates on the curve. */
for (i = 1; i < 4 * runs + 1; i++) {
secp256k1_fe n;
CHECK(secp256k1_ge_x_on_curve_var(&ge[i].x));
/* And the same holds after random rescaling. */
secp256k1_fe_mul(&n, &zf, &ge[i].x);
CHECK(secp256k1_ge_x_frac_on_curve_var(&n, &zf));
}
/* Test correspondence of secp256k1_ge_x{,_frac}_on_curve_var with ge_set_xo. */
{
secp256k1_fe n;
secp256k1_ge q;
int ret_on_curve, ret_frac_on_curve, ret_set_xo;
secp256k1_fe_mul(&n, &zf, &r);
ret_on_curve = secp256k1_ge_x_on_curve_var(&r);
ret_frac_on_curve = secp256k1_ge_x_frac_on_curve_var(&n, &zf);
ret_set_xo = secp256k1_ge_set_xo_var(&q, &r, 0);
CHECK(ret_on_curve == ret_frac_on_curve);
CHECK(ret_on_curve == ret_set_xo);
if (ret_set_xo) CHECK(secp256k1_fe_equal_var(&r, &q.x));
}
/* Test batch gej -> ge conversion with many infinities. */ /* Test batch gej -> ge conversion with many infinities. */
for (i = 0; i < 4 * runs + 1; i++) { for (i = 0; i < 4 * runs + 1; i++) {
int odd; int odd;