Skip to content

Commit aa9cc52

Browse files
committed
Improve field/scalar inverse tests
Add a new run_inverse_tests that replaces all existing field/scalar inverse tests, and tests a few identities for fixed inputs, small numbers (-999...999), random inputs (structured and unstructured), as well as comparing with the output of secp256k1_fe_inv_all_var.
1 parent 1e0e885 commit aa9cc52

File tree

1 file changed

+164
-61
lines changed

1 file changed

+164
-61
lines changed

src/tests.c

Lines changed: 164 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,33 +1418,6 @@ void scalar_test(void) {
14181418
}
14191419
#endif
14201420

1421-
{
1422-
/* Test that scalar inverses are equal to the inverse of their number modulo the order. */
1423-
if (!secp256k1_scalar_is_zero(&s)) {
1424-
secp256k1_scalar inv;
1425-
#ifndef USE_NUM_NONE
1426-
secp256k1_num invnum;
1427-
secp256k1_num invnum2;
1428-
#endif
1429-
secp256k1_scalar_inverse(&inv, &s);
1430-
#ifndef USE_NUM_NONE
1431-
secp256k1_num_mod_inverse(&invnum, &snum, &order);
1432-
secp256k1_scalar_get_num(&invnum2, &inv);
1433-
CHECK(secp256k1_num_eq(&invnum, &invnum2));
1434-
#endif
1435-
secp256k1_scalar_mul(&inv, &inv, &s);
1436-
/* Multiplying a scalar with its inverse must result in one. */
1437-
CHECK(secp256k1_scalar_is_one(&inv));
1438-
secp256k1_scalar_inverse(&inv, &inv);
1439-
/* Inverting one must result in one. */
1440-
CHECK(secp256k1_scalar_is_one(&inv));
1441-
#ifndef USE_NUM_NONE
1442-
secp256k1_scalar_get_num(&invnum, &inv);
1443-
CHECK(secp256k1_num_is_one(&invnum));
1444-
#endif
1445-
}
1446-
}
1447-
14481421
{
14491422
/* Test commutativity of add. */
14501423
secp256k1_scalar r1, r2;
@@ -2275,13 +2248,6 @@ int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
22752248
return secp256k1_fe_equal_var(&an, &bn);
22762249
}
22772250

2278-
int check_fe_inverse(const secp256k1_fe *a, const secp256k1_fe *ai) {
2279-
secp256k1_fe x;
2280-
secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
2281-
secp256k1_fe_mul(&x, a, ai);
2282-
return check_fe_equal(&x, &one);
2283-
}
2284-
22852251
void run_field_convert(void) {
22862252
static const unsigned char b32[32] = {
22872253
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -2401,30 +2367,6 @@ void run_field_misc(void) {
24012367
}
24022368
}
24032369

2404-
void run_field_inv(void) {
2405-
secp256k1_fe x, xi, xii;
2406-
int i;
2407-
for (i = 0; i < 10*count; i++) {
2408-
random_fe_non_zero(&x);
2409-
secp256k1_fe_inv(&xi, &x);
2410-
CHECK(check_fe_inverse(&x, &xi));
2411-
secp256k1_fe_inv(&xii, &xi);
2412-
CHECK(check_fe_equal(&x, &xii));
2413-
}
2414-
}
2415-
2416-
void run_field_inv_var(void) {
2417-
secp256k1_fe x, xi, xii;
2418-
int i;
2419-
for (i = 0; i < 10*count; i++) {
2420-
random_fe_non_zero(&x);
2421-
secp256k1_fe_inv_var(&xi, &x);
2422-
CHECK(check_fe_inverse(&x, &xi));
2423-
secp256k1_fe_inv_var(&xii, &xi);
2424-
CHECK(check_fe_equal(&x, &xii));
2425-
}
2426-
}
2427-
24282370
void run_sqr(void) {
24292371
secp256k1_fe x, s;
24302372

@@ -2489,6 +2431,169 @@ void run_sqrt(void) {
24892431
}
24902432
}
24912433

2434+
/***** FIELD/SCALAR INVERSE TESTS *****/
2435+
2436+
static const secp256k1_scalar scalar_minus_one = SECP256K1_SCALAR_CONST(
2437+
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE,
2438+
0xBAAEDCE6, 0xAF48A03B, 0xBFD25E8C, 0xD0364140
2439+
);
2440+
2441+
static const secp256k1_fe fe_minus_one = SECP256K1_FE_CONST(
2442+
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
2443+
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFC2E
2444+
);
2445+
2446+
/* These tests test the following identities:
2447+
*
2448+
* for x==0: 1/x == 0
2449+
* for x!=0: x*(1/x) == 1
2450+
* for x!=0 and x!=1: 1/(1/x - 1) + 1 == -1/(x-1)
2451+
*/
2452+
2453+
void test_inverse_scalar(secp256k1_scalar* out, const secp256k1_scalar* x, int var)
2454+
{
2455+
secp256k1_scalar l, r, t;
2456+
2457+
(var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse_var)(&l, x); /* l = 1/x */
2458+
if (out) *out = l;
2459+
if (secp256k1_scalar_is_zero(x)) {
2460+
CHECK(secp256k1_scalar_is_zero(&l));
2461+
return;
2462+
}
2463+
secp256k1_scalar_mul(&t, x, &l); /* t = x*(1/x) */
2464+
CHECK(secp256k1_scalar_is_one(&t)); /* x*(1/x) == 1 */
2465+
secp256k1_scalar_add(&r, x, &scalar_minus_one); /* r = x-1 */
2466+
if (secp256k1_scalar_is_zero(&r)) return;
2467+
(var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse_var)(&r, &r); /* r = 1/(x-1) */
2468+
secp256k1_scalar_add(&l, &scalar_minus_one, &l); /* l = 1/x-1 */
2469+
(var ? secp256k1_scalar_inverse_var : secp256k1_scalar_inverse_var)(&l, &l); /* l = 1/(1/x-1) */
2470+
secp256k1_scalar_add(&l, &l, &secp256k1_scalar_one); /* l = 1/(1/x-1)+1 */
2471+
secp256k1_scalar_add(&l, &r, &l); /* l = 1/(1/x-1)+1 + 1/(x-1) */
2472+
CHECK(secp256k1_scalar_is_zero(&l)); /* l == 0 */
2473+
}
2474+
2475+
void test_inverse_field(secp256k1_fe* out, const secp256k1_fe* x, int var)
2476+
{
2477+
secp256k1_fe l, r, t;
2478+
2479+
(var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&l, x) ; /* l = 1/x */
2480+
if (out) *out = l;
2481+
t = *x; /* t = x */
2482+
if (secp256k1_fe_normalizes_to_zero_var(&t)) {
2483+
CHECK(secp256k1_fe_normalizes_to_zero(&l));
2484+
return;
2485+
}
2486+
secp256k1_fe_mul(&t, x, &l); /* t = x*(1/x) */
2487+
secp256k1_fe_add(&t, &fe_minus_one); /* t = x*(1/x)-1 */
2488+
CHECK(secp256k1_fe_normalizes_to_zero(&t)); /* x*(1/x)-1 == 0 */
2489+
r = *x; /* r = x */
2490+
secp256k1_fe_add(&r, &fe_minus_one); /* r = x-1 */
2491+
if (secp256k1_fe_normalizes_to_zero_var(&r)) return;
2492+
(var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&r, &r); /* r = 1/(x-1) */
2493+
secp256k1_fe_add(&l, &fe_minus_one); /* l = 1/x-1 */
2494+
(var ? secp256k1_fe_inv_var : secp256k1_fe_inv)(&l, &l); /* l = 1/(1/x-1) */
2495+
secp256k1_fe_add(&l, &secp256k1_fe_one); /* l = 1/(1/x-1)+1 */
2496+
secp256k1_fe_add(&l, &r); /* l = 1/(1/x-1)+1 + 1/(x-1) */
2497+
CHECK(secp256k1_fe_normalizes_to_zero_var(&l)); /* l == 0 */
2498+
}
2499+
2500+
void run_inverse_tests(void)
2501+
{
2502+
/* Fixed test cases for field inverses: pairs of (x, 1/x) mod p. */
2503+
static const secp256k1_fe fe_cases[][2] = {
2504+
/* 0 */
2505+
{SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0),
2506+
SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)},
2507+
/* 1 */
2508+
{SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1),
2509+
SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1)},
2510+
/* -1 */
2511+
{SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc2e),
2512+
SECP256K1_FE_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xfffffc2e)},
2513+
/* 2 */
2514+
{SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2),
2515+
SECP256K1_FE_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x7ffffe18)},
2516+
/* 2**128 */
2517+
{SECP256K1_FE_CONST(0, 0, 0, 1, 0, 0, 0, 0),
2518+
SECP256K1_FE_CONST(0xbcb223fe, 0xdc24a059, 0xd838091d, 0xd2253530, 0xffffffff, 0xffffffff, 0xffffffff, 0x434dd931)},
2519+
/* Input known to need 637 divsteps */
2520+
{SECP256K1_FE_CONST(0xe34e9c95, 0x6bee8a84, 0x0dcb632a, 0xdb8a1320, 0x66885408, 0x06f3f996, 0x7c11ca84, 0x19199ec3),
2521+
SECP256K1_FE_CONST(0xbd2cbd8f, 0x1c536828, 0x9bccda44, 0x2582ac0c, 0x870152b0, 0x8a3f09fb, 0x1aaadf92, 0x19b618e5)}
2522+
};
2523+
/* Fixed test cases for scalar inverses: pairs of (x, 1/x) mod n. */
2524+
static const secp256k1_scalar scalar_cases[][2] = {
2525+
/* 0 */
2526+
{SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0),
2527+
SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0)},
2528+
/* 1 */
2529+
{SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1),
2530+
SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1)},
2531+
/* -1 */
2532+
{SECP256K1_SCALAR_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xbaaedce6, 0xaf48a03b, 0xbfd25e8c, 0xd0364140),
2533+
SECP256K1_SCALAR_CONST(0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe, 0xbaaedce6, 0xaf48a03b, 0xbfd25e8c, 0xd0364140)},
2534+
/* 2 */
2535+
{SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 2),
2536+
SECP256K1_SCALAR_CONST(0x7fffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x5d576e73, 0x57a4501d, 0xdfe92f46, 0x681b20a1)},
2537+
/* 2**128 */
2538+
{SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0),
2539+
SECP256K1_SCALAR_CONST(0x50a51ac8, 0x34b9ec24, 0x4b0dff66, 0x5588b13e, 0x9984d5b3, 0xcf80ef0f, 0xd6a23766, 0xa3ee9f22)},
2540+
/* Input known to need 635 divsteps */
2541+
{SECP256K1_SCALAR_CONST(0xcb9f1d35, 0xdd4416c2, 0xcd71bf3f, 0x6365da66, 0x3c9b3376, 0x8feb7ae9, 0x32a5ef60, 0x19199ec3),
2542+
SECP256K1_SCALAR_CONST(0x1d7c7bba, 0xf1893d53, 0xb834bd09, 0x36b411dc, 0x42c2e42f, 0xec72c428, 0x5e189791, 0x8e9bc708)}
2543+
};
2544+
int i, var, testrand;
2545+
unsigned char b32[32];
2546+
secp256k1_fe x_fe;
2547+
secp256k1_scalar x_scalar;
2548+
memset(b32, 0, sizeof(b32));
2549+
/* Test fixed test cases through test_inverse_{scalar,field}, both ways. */
2550+
for (i = 0; (size_t)i < sizeof(fe_cases)/sizeof(fe_cases[0]); ++i) {
2551+
for (var = 0; var <= 1; ++var) {
2552+
test_inverse_field(&x_fe, &fe_cases[i][0], var);
2553+
check_fe_equal(&x_fe, &fe_cases[i][1]);
2554+
test_inverse_field(&x_fe, &fe_cases[i][1], var);
2555+
check_fe_equal(&x_fe, &fe_cases[i][0]);
2556+
}
2557+
}
2558+
for (i = 0; (size_t)i < sizeof(scalar_cases)/sizeof(scalar_cases[0]); ++i) {
2559+
for (var = 0; var <= 1; ++var) {
2560+
test_inverse_scalar(&x_scalar, &scalar_cases[i][0], var);
2561+
CHECK(secp256k1_scalar_eq(&x_scalar, &scalar_cases[i][1]));
2562+
test_inverse_scalar(&x_scalar, &scalar_cases[i][1], var);
2563+
CHECK(secp256k1_scalar_eq(&x_scalar, &scalar_cases[i][0]));
2564+
}
2565+
}
2566+
/* Test inputs 0..999 and their respective negations. */
2567+
for (i = 0; i < 1000; ++i) {
2568+
b32[31] = i & 0xff;
2569+
b32[30] = (i >> 8) & 0xff;
2570+
secp256k1_scalar_set_b32(&x_scalar, b32, NULL);
2571+
secp256k1_fe_set_b32(&x_fe, b32);
2572+
for (var = 0; var <= 1; ++var) {
2573+
test_inverse_scalar(NULL, &x_scalar, var);
2574+
test_inverse_field(NULL, &x_fe, var);
2575+
}
2576+
secp256k1_scalar_negate(&x_scalar, &x_scalar);
2577+
secp256k1_fe_negate(&x_fe, &x_fe, 1);
2578+
for (var = 0; var <= 1; ++var) {
2579+
test_inverse_scalar(NULL, &x_scalar, var);
2580+
test_inverse_field(NULL, &x_fe, var);
2581+
}
2582+
}
2583+
/* test 128*count random inputs; half with testrand256_test, half with testrand256 */
2584+
for (testrand = 0; testrand <= 1; ++testrand) {
2585+
for (i = 0; i < 64 * count; ++i) {
2586+
(testrand ? secp256k1_testrand256_test : secp256k1_testrand256)(b32);
2587+
secp256k1_scalar_set_b32(&x_scalar, b32, NULL);
2588+
secp256k1_fe_set_b32(&x_fe, b32);
2589+
for (var = 0; var <= 1; ++var) {
2590+
test_inverse_scalar(NULL, &x_scalar, var);
2591+
test_inverse_field(NULL, &x_fe, var);
2592+
}
2593+
}
2594+
}
2595+
}
2596+
24922597
/***** GROUP TESTS *****/
24932598

24942599
void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
@@ -6068,8 +6173,8 @@ int main(int argc, char **argv) {
60686173
run_rand_int();
60696174

60706175
run_ctz_tests();
6071-
60726176
run_modinv_tests();
6177+
run_inverse_tests();
60736178

60746179
run_sha256_tests();
60756180
run_hmac_sha256_tests();
@@ -6084,8 +6189,6 @@ int main(int argc, char **argv) {
60846189
run_scalar_tests();
60856190

60866191
/* field tests */
6087-
run_field_inv();
6088-
run_field_inv_var();
60896192
run_field_misc();
60906193
run_field_convert();
60916194
run_sqr();

0 commit comments

Comments
 (0)