From ca68daf8e1caa67c31242bd39704d1967cd35e11 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Mon, 8 Jun 2026 18:33:45 +0200 Subject: [PATCH 1/2] test: refactor: simplify tests by using `_ecmult_gen_ge` helper If the generator point multiplication result in Jacobian coordinates is immediately converted to affine coordinates after and is not needed for anything else, we can deduplicate by using the helper introduced in #1861. Note that in a very strict sense this is not a refactor, as the Jacobian object is now cleared out which was not done on master, but for the logic in the tests this shouldn't matter at all. --- src/tests.c | 19 +++++-------------- src/tests_exhaustive.c | 4 +--- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/tests.c b/src/tests.c index 9084c1d6..95f177ad 100644 --- a/src/tests.c +++ b/src/tests.c @@ -241,7 +241,6 @@ static void run_proper_context_tests(int use_prealloc) { void *my_ctx_prealloc = NULL; unsigned char seed[32] = {0x17}; - secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar msg, key, nonce; secp256k1_scalar sigr, sigs; @@ -329,8 +328,7 @@ static void run_proper_context_tests(int use_prealloc) { /*** attempt to use them ***/ testutil_random_scalar_order_test(&msg); testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen_gej(&my_ctx->ecmult_gen_ctx, &pubj, &key); - secp256k1_ge_set_gej(&pub, &pubj); + secp256k1_ecmult_gen_ge(&my_ctx->ecmult_gen_ctx, &pub, &key); /* obtain a working nonce */ do { @@ -4304,19 +4302,16 @@ static void test_ec_combine(void) { const secp256k1_pubkey* d[6]; secp256k1_pubkey sd; secp256k1_pubkey sd2; - secp256k1_gej Qj; secp256k1_ge Q; int i; for (i = 1; i <= 6; i++) { secp256k1_scalar s; testutil_random_scalar_order_test(&s); secp256k1_scalar_add(&sum, &sum, &s); - secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &Qj, &s); - secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &Q, &s); secp256k1_pubkey_save(&data[i - 1], &Q); d[i - 1] = &data[i - 1]; - secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &Qj, &sum); - secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &Q, &sum); secp256k1_pubkey_save(&sd, &Q); CHECK(secp256k1_ec_pubkey_combine(CTX, &sd2, d, i) == 1); CHECK(secp256k1_memcmp_var(&sd, &sd2, sizeof(sd)) == 0); @@ -6515,7 +6510,6 @@ static void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const se } static void test_ecdsa_sign_verify(void) { - secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar one; secp256k1_scalar msg, key; @@ -6524,8 +6518,7 @@ static void test_ecdsa_sign_verify(void) { int recid; testutil_random_scalar_order_test(&msg); testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &pubj, &key); - secp256k1_ge_set_gej(&pub, &pubj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &pub, &key); getrec = testrand_bits(1); /* The specific way in which this conditional is written sidesteps a potential bug in clang. See the commit messages of the commit that introduced this comment for details. */ @@ -7284,7 +7277,6 @@ static void run_ecdsa_edge_cases(void) { /* Test the case where ECDSA recomputes a point that is infinity. */ { - secp256k1_gej keyj; secp256k1_ge key; secp256k1_scalar msg; secp256k1_scalar sr, ss; @@ -7292,8 +7284,7 @@ static void run_ecdsa_edge_cases(void) { secp256k1_scalar_negate(&ss, &ss); secp256k1_scalar_inverse(&ss, &ss); secp256k1_scalar_set_int(&sr, 1); - secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &keyj, &sr); - secp256k1_ge_set_gej(&key, &keyj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &key, &sr); msg = ss; CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); } diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index 888b7ac9..80f71562 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -421,12 +421,10 @@ int main(int argc, char** argv) { /* Verify against ecmult_gen */ { secp256k1_scalar scalar_i; - secp256k1_gej generatedj; secp256k1_ge generated; secp256k1_scalar_set_int(&scalar_i, i); - secp256k1_ecmult_gen_gej(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); - secp256k1_ge_set_gej(&generated, &generatedj); + secp256k1_ecmult_gen_ge(&ctx->ecmult_gen_ctx, &generated, &scalar_i); CHECK(!secp256k1_ge_is_infinity(&group[i])); CHECK(secp256k1_ge_eq_var(&group[i], &generated)); From 2ee79e77e65bf5f7f747df1d978d04f1ace1e3a0 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Tue, 9 Jun 2026 17:04:53 +0200 Subject: [PATCH 2/2] test: add unit test for `_ecmult_gen_ge` --- src/tests.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/tests.c b/src/tests.c index 95f177ad..5070f590 100644 --- a/src/tests.c +++ b/src/tests.c @@ -5781,6 +5781,25 @@ static void run_ecmult_constants(void) { } } +static void run_ecmult_gen_ge(void) { + /* Test that secp256k1_ecmult_gen_ge result matches secp256k1_ecmult_gen_gej with + * manual Jacobian-to-affine conversion (secp256k1_ge_set_gej) over random scalars */ + int i; + + for (i = 0; i < COUNT; i++) { + secp256k1_scalar scalar; + secp256k1_gej result_gej; + secp256k1_ge result_ge, expected_ge; + + testutil_random_scalar_order_test(&scalar); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &result_gej, &scalar); + secp256k1_ge_set_gej(&expected_ge, &result_gej); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &result_ge, &scalar); + + CHECK(secp256k1_ge_eq_var(&result_ge, &expected_ge)); + } +} + static void test_ecmult_gen_blind(void) { /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ secp256k1_scalar key; @@ -7960,6 +7979,7 @@ static const struct tf_test_entry tests_ecmult[] = { CASE(ecmult_near_split_bound), CASE(ecmult_chain), CASE(ecmult_constants), + CASE(ecmult_gen_ge), CASE(ecmult_gen_blind), CASE(ecmult_const_tests), CASE(ecmult_multi_tests),