Skip to content

Commit 5f8e5b8

Browse files
committed
Add functions to test if X coordinate is valid
1 parent dc7b969 commit 5f8e5b8

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

src/group.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se
5151
* for Y. Return value indicates whether the result is valid. */
5252
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
5353

54+
/** Determine whether x is a valid X coordinate on the curve. */
55+
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x);
56+
57+
/** Determine whether fraction xn/xd is a valid X coordinate on the curve. */
58+
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd);
59+
5460
/** Check whether a group element is the point at infinity. */
5561
static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
5662

src/group_impl.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,4 +695,33 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
695695
#endif
696696
}
697697

698+
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe* x)
699+
{
700+
secp256k1_fe c;
701+
secp256k1_fe_sqr(&c, x);
702+
secp256k1_fe_mul(&c, &c, x);
703+
secp256k1_fe_add(&c, &secp256k1_fe_const_b);
704+
return secp256k1_fe_jacobi_var(&c) >= 0;
705+
}
706+
707+
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe* xn, const secp256k1_fe* xd) {
708+
/* We want to determine whether (xn/xd) is on the curve.
709+
*
710+
* (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square).
711+
*/
712+
secp256k1_fe r, t;
713+
secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */
714+
secp256k1_fe_sqr(&t, xn); /* t = xn^2 */
715+
secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */
716+
secp256k1_fe_sqr(&t, xd); /* t = xd^2 */
717+
secp256k1_fe_sqr(&t, &t); /* t = xd^4 */
718+
#if defined(EXHAUSTIVE_GROUP_ORDER)
719+
secp256k1_fe_mul(&t, &t, &secp256k1_fe_const_b); /* t = 7*xd^4 */
720+
#else
721+
secp256k1_fe_mul_int(&t, 7);
722+
#endif
723+
secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */
724+
return secp256k1_fe_jacobi_var(&r) >= 0;
725+
}
726+
698727
#endif /* SECP256K1_GROUP_IMPL_H */

src/tests.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3273,7 +3273,7 @@ void test_ge(void) {
32733273
*/
32743274
secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));
32753275
secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));
3276-
secp256k1_fe zf;
3276+
secp256k1_fe zf, r;
32773277
secp256k1_fe zfi2, zfi3;
32783278

32793279
secp256k1_gej_set_infinity(&gej[0]);
@@ -3315,6 +3315,11 @@ void test_ge(void) {
33153315
secp256k1_fe_sqr(&zfi2, &zfi3);
33163316
secp256k1_fe_mul(&zfi3, &zfi3, &zfi2);
33173317

3318+
/* Generate random r */
3319+
do {
3320+
random_field_element_test(&r);
3321+
} while(secp256k1_fe_is_zero(&r));
3322+
33183323
for (i1 = 0; i1 < 1 + 4 * runs; i1++) {
33193324
int i2;
33203325
for (i2 = 0; i2 < 1 + 4 * runs; i2++) {
@@ -3427,6 +3432,29 @@ void test_ge(void) {
34273432
free(ge_set_all);
34283433
}
34293434

3435+
/* Test all elements have X coordinates on the curve. */
3436+
for (i = 1; i < 4 * runs + 1; i++) {
3437+
secp256k1_fe n;
3438+
CHECK(secp256k1_ge_x_on_curve_var(&ge[i].x));
3439+
/* And the same holds after random rescaling. */
3440+
secp256k1_fe_mul(&n, &zf, &ge[i].x);
3441+
CHECK(secp256k1_ge_x_frac_on_curve_var(&n, &zf));
3442+
}
3443+
3444+
/* Test correspondence secp256k1_ge_x{,_frac}_on_curve_var with ge_set_xo. */
3445+
{
3446+
secp256k1_fe n;
3447+
secp256k1_ge q;
3448+
int ret_on_curve, ret_frac_on_curve, ret_set_xo;
3449+
secp256k1_fe_mul(&n, &zf, &r);
3450+
ret_on_curve = secp256k1_ge_x_on_curve_var(&r);
3451+
ret_frac_on_curve = secp256k1_ge_x_frac_on_curve_var(&n, &zf);
3452+
ret_set_xo = secp256k1_ge_set_xo_var(&q, &r, 0);
3453+
CHECK(ret_on_curve == ret_frac_on_curve);
3454+
CHECK(ret_on_curve == ret_set_xo);
3455+
if (ret_set_xo) CHECK(secp256k1_fe_equal_var(&r, &q.x));
3456+
}
3457+
34303458
/* Test batch gej -> ge conversion with many infinities. */
34313459
for (i = 0; i < 4 * runs + 1; i++) {
34323460
int odd;

0 commit comments

Comments
 (0)