Add API to override SHA256 compression at runtime

This introduces `secp256k1_context_set_sha256_compression()`,
which allows users to provide their own SHA256 block-compression
function at runtime.

This is useful in setups where the fastest implementation can only
be determined dynamically based on the available CPU features, and
rebuilding the library is not possible.

The callback is installed on the `secp256k1_context` and is then used
by all operations that compute SHA256 hashes. As part of the setup,
the library performs sanity checks to ensure that the supplied
function is equivalent to the default transform.

Passing NULL to the callback setter restores the built-in
implementation.
This commit is contained in:
furszy
2026-01-23 13:41:55 -05:00
parent fdb6a91a5e
commit 0753f8b909
11 changed files with 247 additions and 21 deletions

View File

@@ -223,6 +223,18 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co
ctx->error_callback.data = data;
}
void secp256k1_context_set_sha256_compression(secp256k1_context *ctx, secp256k1_sha256_compression_function fn_compression) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK_VOID(secp256k1_context_is_proper(ctx));
if (!fn_compression) { /* Reset hash context */
secp256k1_hash_ctx_init(&ctx->hash_ctx);
return;
}
/* Check and set */
ARG_CHECK_VOID(secp256k1_selftest_sha256(fn_compression));
ctx->hash_ctx.fn_sha256_compression = fn_compression;
}
static SECP256K1_INLINE const secp256k1_hash_ctx* secp256k1_get_hash_context(const secp256k1_context *ctx) {
return &ctx->hash_ctx;
}
@@ -538,9 +550,6 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc
if (recid) {
*recid = 0;
}
if (noncefp == NULL) {
noncefp = secp256k1_nonce_function_default;
}
/* Fail if the secret key is invalid. */
is_sec_valid = secp256k1_scalar_set_b32_seckey(&sec, seckey);
@@ -548,7 +557,14 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc
secp256k1_scalar_set_b32(&msg, msg32, NULL);
while (1) {
int is_nonce_valid;
ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
if (noncefp == NULL) {
/* Use ctx-aware function by default */
ret = nonce_function_rfc6979_impl(secp256k1_get_hash_context(ctx), nonce32, msg32, seckey, NULL, (void*)noncedata, count);
} else {
ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
}
if (!ret) {
break;
}