Skip to content

Commit 79e5b2a

Browse files
committed
Add functions to test if X coordinate is valid
1 parent a597a5a commit 79e5b2a

File tree

3 files changed

+63
-1
lines changed

3 files changed

+63
-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 (xd != 0). */
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: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -823,4 +823,32 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
823823
#endif
824824
}
825825

826+
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x) {
827+
secp256k1_fe c;
828+
secp256k1_fe_sqr(&c, x);
829+
secp256k1_fe_mul(&c, &c, x);
830+
secp256k1_fe_add_int(&c, SECP256K1_B);
831+
return secp256k1_fe_is_square_var(&c);
832+
}
833+
834+
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd) {
835+
/* We want to determine whether (xn/xd) is on the curve.
836+
*
837+
* (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square).
838+
*/
839+
secp256k1_fe r, t;
840+
#ifdef VERIFY
841+
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd));
842+
#endif
843+
secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */
844+
secp256k1_fe_sqr(&t, xn); /* t = xn^2 */
845+
secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */
846+
secp256k1_fe_sqr(&t, xd); /* t = xd^2 */
847+
secp256k1_fe_sqr(&t, &t); /* t = xd^4 */
848+
VERIFY_CHECK(SECP256K1_B <= 31);
849+
secp256k1_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */
850+
secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */
851+
return secp256k1_fe_is_square_var(&r);
852+
}
853+
826854
#endif /* SECP256K1_GROUP_IMPL_H */

src/tests.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3775,7 +3775,7 @@ static void test_ge(void) {
37753775
*/
37763776
secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs));
37773777
secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs));
3778-
secp256k1_fe zf;
3778+
secp256k1_fe zf, r;
37793779
secp256k1_fe zfi2, zfi3;
37803780

37813781
secp256k1_gej_set_infinity(&gej[0]);
@@ -3817,6 +3817,11 @@ static void test_ge(void) {
38173817
secp256k1_fe_sqr(&zfi2, &zfi3);
38183818
secp256k1_fe_mul(&zfi3, &zfi3, &zfi2);
38193819

3820+
/* Generate random r */
3821+
do {
3822+
random_field_element_test(&r);
3823+
} while(secp256k1_fe_is_zero(&r));
3824+
38203825
for (i1 = 0; i1 < 1 + 4 * runs; i1++) {
38213826
int i2;
38223827
for (i2 = 0; i2 < 1 + 4 * runs; i2++) {
@@ -3929,6 +3934,29 @@ static void test_ge(void) {
39293934
free(ge_set_all);
39303935
}
39313936

3937+
/* Test that all elements have X coordinates on the curve. */
3938+
for (i = 1; i < 4 * runs + 1; i++) {
3939+
secp256k1_fe n;
3940+
CHECK(secp256k1_ge_x_on_curve_var(&ge[i].x));
3941+
/* And the same holds after random rescaling. */
3942+
secp256k1_fe_mul(&n, &zf, &ge[i].x);
3943+
CHECK(secp256k1_ge_x_frac_on_curve_var(&n, &zf));
3944+
}
3945+
3946+
/* Test correspondence of secp256k1_ge_x{,_frac}_on_curve_var with ge_set_xo. */
3947+
{
3948+
secp256k1_fe n;
3949+
secp256k1_ge q;
3950+
int ret_on_curve, ret_frac_on_curve, ret_set_xo;
3951+
secp256k1_fe_mul(&n, &zf, &r);
3952+
ret_on_curve = secp256k1_ge_x_on_curve_var(&r);
3953+
ret_frac_on_curve = secp256k1_ge_x_frac_on_curve_var(&n, &zf);
3954+
ret_set_xo = secp256k1_ge_set_xo_var(&q, &r, 0);
3955+
CHECK(ret_on_curve == ret_frac_on_curve);
3956+
CHECK(ret_on_curve == ret_set_xo);
3957+
if (ret_set_xo) CHECK(secp256k1_fe_equal_var(&r, &q.x));
3958+
}
3959+
39323960
/* Test batch gej -> ge conversion with many infinities. */
39333961
for (i = 0; i < 4 * runs + 1; i++) {
39343962
int odd;

0 commit comments

Comments
 (0)