From 72867fd682279ff2c79cf13f4f8d8484048d2527 Mon Sep 17 00:00:00 2001 From: mllwchrry Date: Wed, 3 Jun 2026 17:38:36 +0300 Subject: [PATCH] tests: Port hash context tests to zkp modules --- src/modules/bppp/tests_impl.h | 29 ++++++++++++++++ src/modules/ecdsa_adaptor/tests_impl.h | 25 ++++++++++++++ src/modules/ecdsa_s2c/tests_impl.h | 24 ++++++++++++- src/modules/rangeproof/tests_impl.h | 27 +++++++++++++++ src/modules/schnorrsig_halfagg/tests_impl.h | 37 +++++++++++++++++++++ src/modules/surjection/tests_impl.h | 36 ++++++++++++++++++++ 6 files changed, 177 insertions(+), 1 deletion(-) diff --git a/src/modules/bppp/tests_impl.h b/src/modules/bppp/tests_impl.h index 47a00c6d..d7931aa9 100644 --- a/src/modules/bppp/tests_impl.h +++ b/src/modules/bppp/tests_impl.h @@ -662,6 +662,34 @@ static void norm_arg_test_all(void) { norm_arg_test(64, 64); } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_bppp) +static void test_bppp_ctx_sha256(void) { + /* Check ctx-provided SHA256 compression override takes effect */ + secp256k1_context *ctx = secp256k1_context_clone(CTX); + unsigned char out_default[66], out_custom[66]; + secp256k1_bppp_generators *gens; + size_t len = sizeof(out_default); + + /* Default behavior. No ctx-provided SHA256 compression */ + gens = secp256k1_bppp_generators_create(ctx, 2); + CHECK(gens != NULL); + CHECK(secp256k1_bppp_generators_serialize(ctx, gens, out_default, &len)); + secp256k1_bppp_generators_destroy(ctx, gens); + CHECK(!sha256_bppp_called); + + /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */ + ctx->hash_ctx.fn_sha256_compression = sha256_bppp; + gens = secp256k1_bppp_generators_create(ctx, 2); + CHECK(gens != NULL); + CHECK(secp256k1_bppp_generators_serialize(ctx, gens, out_custom, &len)); + secp256k1_bppp_generators_destroy(ctx, gens); + CHECK(sha256_bppp_called); + /* Outputs must differ if custom compression was used */ + CHECK(secp256k1_memcmp_var(out_default, out_custom, 66) != 0); + + secp256k1_context_destroy(ctx); +} + /* --- Test registry --- */ static const struct tf_test_entry tests_bppp[] = { CASE1(test_log_exp), @@ -674,6 +702,7 @@ static const struct tf_test_entry tests_bppp[] = { CASE1(norm_arg_test_all), CASE1(norm_arg_verify_vectors), CASE1(norm_arg_prove_vectors), + CASE1(test_bppp_ctx_sha256), }; #endif diff --git a/src/modules/ecdsa_adaptor/tests_impl.h b/src/modules/ecdsa_adaptor/tests_impl.h index 3ed01568..e8122f64 100644 --- a/src/modules/ecdsa_adaptor/tests_impl.h +++ b/src/modules/ecdsa_adaptor/tests_impl.h @@ -1182,6 +1182,30 @@ static void adaptor_test_issue335(void) { } } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_ecdsa_adaptor) +static void test_ecdsa_adaptor_ctx_sha256(void) { + /* Check ctx-provided SHA256 compression override takes effect */ + secp256k1_context *ctx = secp256k1_context_clone(CTX); + unsigned char out_default[162], out_custom[162]; + unsigned char sk[32] = {1}, msg32[32] = {1}; + unsigned char enckey_sk[32] = {2}; + secp256k1_pubkey enckey; + CHECK(secp256k1_ec_pubkey_create(ctx, &enckey, enckey_sk)); + + /* Default behavior. No ctx-provided SHA256 compression */ + CHECK(secp256k1_ecdsa_adaptor_encrypt(ctx, out_default, sk, &enckey, msg32, NULL, NULL)); + CHECK(!sha256_ecdsa_adaptor_called); + + /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */ + ctx->hash_ctx.fn_sha256_compression = sha256_ecdsa_adaptor; + CHECK(secp256k1_ecdsa_adaptor_encrypt(ctx, out_custom, sk, &enckey, msg32, NULL, NULL)); + CHECK(sha256_ecdsa_adaptor_called); + /* Outputs must differ if custom compression was used */ + CHECK(secp256k1_memcmp_var(out_default, out_custom, 162) != 0); + + secp256k1_context_destroy(ctx); +} + /* --- Test registry --- */ REPEAT_TEST(dleq_tests) REPEAT_TEST(adaptor_tests) @@ -1195,6 +1219,7 @@ static const struct tf_test_entry tests_ecdsa_adaptor[] = { CASE1(adaptor_tests), CASE1(multi_hop_lock_tests), CASE1(adaptor_test_issue335), + CASE1(test_ecdsa_adaptor_ctx_sha256), }; #endif /* SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H */ diff --git a/src/modules/ecdsa_s2c/tests_impl.h b/src/modules/ecdsa_s2c/tests_impl.h index ba4f158c..ea0b650d 100644 --- a/src/modules/ecdsa_s2c/tests_impl.h +++ b/src/modules/ecdsa_s2c/tests_impl.h @@ -325,6 +325,27 @@ static void test_ecdsa_anti_exfil(void) { } } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_ecdsa_s2c) +static void test_ecdsa_s2c_ctx_sha256(void) { + /* Check ctx-provided SHA256 compression override takes effect */ + secp256k1_context *ctx = secp256k1_context_clone(CTX); + secp256k1_ecdsa_signature out_default, out_custom; + unsigned char sk[32] = {1}, msg32[32] = {1}, s2c_data[32] = {1}; + + /* Default behavior. No ctx-provided SHA256 compression */ + CHECK(secp256k1_ecdsa_s2c_sign(ctx, &out_default, NULL, msg32, sk, s2c_data)); + CHECK(!sha256_ecdsa_s2c_called); + + /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */ + ctx->hash_ctx.fn_sha256_compression = sha256_ecdsa_s2c; + CHECK(secp256k1_ecdsa_s2c_sign(ctx, &out_custom, NULL, msg32, sk, s2c_data)); + CHECK(sha256_ecdsa_s2c_called); + /* Outputs must differ if custom compression was used */ + CHECK(secp256k1_memcmp_var(out_default.data, out_custom.data, 64) != 0); + + secp256k1_context_destroy(ctx); +} + /* --- Test registry --- */ static const struct tf_test_entry tests_ecdsa_s2c[] = { CASE1(run_s2c_opening_test), @@ -333,7 +354,8 @@ static const struct tf_test_entry tests_ecdsa_s2c[] = { CASE1(test_ecdsa_s2c_fixed_vectors), CASE1(test_ecdsa_s2c_sign_verify), CASE1(test_ecdsa_anti_exfil_signer_commit), - CASE1(test_ecdsa_anti_exfil) + CASE1(test_ecdsa_anti_exfil), + CASE1(test_ecdsa_s2c_ctx_sha256), }; #endif /* SECP256K1_MODULE_ECDSA_S2C_TESTS_H */ diff --git a/src/modules/rangeproof/tests_impl.h b/src/modules/rangeproof/tests_impl.h index 85c97c54..19c83ecb 100644 --- a/src/modules/rangeproof/tests_impl.h +++ b/src/modules/rangeproof/tests_impl.h @@ -1319,6 +1319,32 @@ static void test_single_value_proof_all(void) { test_single_value_proof(UINT64_MAX); } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_rangeproof) +static void test_rangeproof_ctx_sha256(void) { + /* Check ctx-provided SHA256 compression override takes effect */ + secp256k1_context *ctx = secp256k1_context_clone(CTX); + unsigned char proof_default[5134], proof_custom[5134]; + size_t len = sizeof(proof_default); + unsigned char blind[32] = {1}; + secp256k1_pedersen_commitment commit; + + CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, 1, secp256k1_generator_h)); + + /* Default behavior. No ctx-provided SHA256 compression */ + CHECK(secp256k1_rangeproof_sign(ctx, proof_default, &len, 0, &commit, blind, commit.data, 0, 0, 1, NULL, 0, NULL, 0, secp256k1_generator_h)); + CHECK(!sha256_rangeproof_called); + + /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */ + ctx->hash_ctx.fn_sha256_compression = sha256_rangeproof; + len = sizeof(proof_custom); + CHECK(secp256k1_rangeproof_sign(ctx, proof_custom, &len, 0, &commit, blind, commit.data, 0, 0, 1, NULL, 0, NULL, 0, secp256k1_generator_h)); + CHECK(sha256_rangeproof_called); + /* Outputs must differ if custom compression was used */ + CHECK(secp256k1_memcmp_var(proof_default, proof_custom, len) != 0); + + secp256k1_context_destroy(ctx); +} + /* --- Test registry --- */ REPEAT_TEST(test_rangeproof_api) REPEAT_TEST(test_borromean) @@ -1332,6 +1358,7 @@ static const struct tf_test_entry tests_rangeproof[] = { CASE1(test_rangeproof), CASE1(test_rangeproof_null_blinder), CASE1(test_multiple_generators), + CASE1(test_rangeproof_ctx_sha256), }; #endif diff --git a/src/modules/schnorrsig_halfagg/tests_impl.h b/src/modules/schnorrsig_halfagg/tests_impl.h index f4092842..f7625168 100644 --- a/src/modules/schnorrsig_halfagg/tests_impl.h +++ b/src/modules/schnorrsig_halfagg/tests_impl.h @@ -319,6 +319,42 @@ static void test_schnorrsig_aggregate_overflow_internal(void) { } } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_schnorrsig_halfagg) +static void test_schnorrsig_halfagg_ctx_sha256(void) { + /* Check ctx-provided SHA256 compression override takes effect */ + secp256k1_context *ctx = secp256k1_context_clone(CTX); + unsigned char aggsig_default[96], aggsig_custom[96]; + unsigned char sk[2][32] = {{1}, {2}}; + unsigned char msgs[2*32]; + secp256k1_keypair keypairs[2]; + secp256k1_xonly_pubkey pks[2]; + unsigned char sigs[2*64]; + size_t aggsig_len; + size_t i; + + memset(msgs, 1, sizeof(msgs)); + for (i = 0; i < 2; i++) { + CHECK(secp256k1_keypair_create(CTX, &keypairs[i], sk[i])); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pks[i], NULL, &keypairs[i])); + CHECK(secp256k1_schnorrsig_sign32(CTX, &sigs[i*64], &msgs[i*32], &keypairs[i], NULL)); + } + + /* Default behavior. No ctx-provided SHA256 compression */ + aggsig_len = sizeof(aggsig_default); + CHECK(secp256k1_schnorrsig_aggregate(ctx, aggsig_default, &aggsig_len, pks, msgs, sigs, 2)); + CHECK(!sha256_schnorrsig_halfagg_called); + + /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */ + ctx->hash_ctx.fn_sha256_compression = sha256_schnorrsig_halfagg; + aggsig_len = sizeof(aggsig_custom); + CHECK(secp256k1_schnorrsig_aggregate(ctx, aggsig_custom, &aggsig_len, pks, msgs, sigs, 2)); + CHECK(sha256_schnorrsig_halfagg_called); + /* Outputs must differ if custom compression was used */ + CHECK(secp256k1_memcmp_var(aggsig_default, aggsig_custom, 96) != 0); + + secp256k1_context_destroy(ctx); +} + /* --- Test registry --- */ REPEAT_TEST(test_schnorrsig_aggregate) REPEAT_TEST(test_schnorrsig_aggregate_api) @@ -332,6 +368,7 @@ static const struct tf_test_entry tests_schnorrsig_halfagg[] = { CASE1(test_schnorrsig_aggregate_api), CASE1(test_schnorrsig_aggregate_unforge), CASE1(test_schnorrsig_aggregate_overflow), + CASE1(test_schnorrsig_halfagg_ctx_sha256), }; #undef N_MAX diff --git a/src/modules/surjection/tests_impl.h b/src/modules/surjection/tests_impl.h index 0680a2ab..7153a6f2 100644 --- a/src/modules/surjection/tests_impl.h +++ b/src/modules/surjection/tests_impl.h @@ -784,6 +784,41 @@ static void test_surjectionproof_generate_changes_s_values(void) { } } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_surjection) +static void test_surjectionproof_ctx_sha256(void) { + /* Check ctx-provided SHA256 compression override takes effect */ + secp256k1_context *ctx = secp256k1_context_clone(CTX); + unsigned char serialized_default[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(1, 1)]; + unsigned char serialized_custom[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(1, 1)]; + unsigned char seed[32] = {1}; + unsigned char input_blinding[32] = {1}, output_blinding[32] = {2}; + secp256k1_fixed_asset_tag fixed_tag = {{1}}; + secp256k1_generator input_tag, output_tag; + secp256k1_surjectionproof proof; + size_t input_index; + size_t serialized_len = sizeof(serialized_default); + + CHECK(secp256k1_generator_generate_blinded(CTX, &input_tag, fixed_tag.data, input_blinding)); + CHECK(secp256k1_generator_generate_blinded(CTX, &output_tag, fixed_tag.data, output_blinding)); + + /* Default behavior. No ctx-provided SHA256 compression */ + CHECK(secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, &fixed_tag, 1, 1, &fixed_tag, 100, seed) > 0); + CHECK(secp256k1_surjectionproof_generate(ctx, &proof, &input_tag, 1, &output_tag, 0, input_blinding, output_blinding)); + CHECK(secp256k1_surjectionproof_serialize(ctx, serialized_default, &serialized_len, &proof)); + CHECK(!sha256_surjection_called); + + /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */ + ctx->hash_ctx.fn_sha256_compression = sha256_surjection; + CHECK(secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, &fixed_tag, 1, 1, &fixed_tag, 100, seed) > 0); + CHECK(secp256k1_surjectionproof_generate(ctx, &proof, &input_tag, 1, &output_tag, 0, input_blinding, output_blinding)); + CHECK(secp256k1_surjectionproof_serialize(ctx, serialized_custom, &serialized_len, &proof)); + CHECK(sha256_surjection_called); + /* Outputs must differ if custom compression was used */ + CHECK(secp256k1_memcmp_var(serialized_default, serialized_custom, serialized_len) != 0); + + secp256k1_context_destroy(ctx); +} + /* --- Test registry --- */ static const struct tf_test_entry tests_surjection[] = { CASE1(test_surjectionproof_api), @@ -797,6 +832,7 @@ static const struct tf_test_entry tests_surjection[] = { CASE1(test_no_used_inputs_verify), CASE1(test_bad_serialize), CASE1(test_bad_parse), + CASE1(test_surjectionproof_ctx_sha256), }; #endif