Merge BlockstreamResearch/secp256k1-zkp#365: tests: Port hash context tests to zkp modules

72867fd682 tests: Port hash context tests to zkp modules (mllwchrry)

Pull request description:

  Ports the hash context tests from bitcoin-core/secp256k1#1777 to the zkp-specific modules.


ACKs for top commit:
  apoelstra:
    ACK 72867fd682279ff2c79cf13f4f8d8484048d2527; successfully ran local tests


Tree-SHA512: 1714a4c5fd793b32a0f00a92670a48709e4d01917bb81739428601c6e88e89f871cdc1294024e6df7272d6c16e681309d9b3448adcd07ce37bfa2be2dc3f4172
This commit is contained in:
Andrew Poelstra
2026-08-18 15:20:17 +00:00
6 changed files with 177 additions and 1 deletions

View File

@@ -664,6 +664,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),
@@ -676,6 +704,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

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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