From 28eb9ba7ee1b92f9c7e5653c3827d0b73cbadc3e Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 15 Dec 2025 14:44:50 -0500 Subject: [PATCH 1/3] tests: use local context instead of using global one No functional change. Refactor several test implementations to use a local context variable. This is a preparatory change that makes it straightforward for a follow-up to run these tests with a different context instance (with a different sha256 function), without touching the test code again. --- src/modules/ecdh/tests_impl.h | 13 +++++++------ src/modules/ellswift/tests_impl.h | 29 +++++++++++++++-------------- src/modules/schnorrsig/tests_impl.h | 27 ++++++++++++++------------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/modules/ecdh/tests_impl.h b/src/modules/ecdh/tests_impl.h index cb1d953d2a..f3f5ccdca0 100644 --- a/src/modules/ecdh/tests_impl.h +++ b/src/modules/ecdh/tests_impl.h @@ -53,6 +53,7 @@ static void test_ecdh_generator_basepoint(void) { unsigned char s_one[32] = { 0 }; secp256k1_pubkey point[2]; int i; + secp256k1_context *ctx = CTX; s_one[31] = 1; /* Check against pubkey creation when the basepoint is the generator */ @@ -68,20 +69,20 @@ static void test_ecdh_generator_basepoint(void) { testutil_random_scalar_order(&s); secp256k1_scalar_get_b32(s_b32, &s); - CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1); - CHECK(secp256k1_ec_pubkey_create(CTX, &point[1], s_b32) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); /* compute using ECDH function with custom hash function */ - CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); /* compute "explicitly" */ - CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); /* compare */ CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0); /* compute using ECDH function with default hash function */ - CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); /* compute "explicitly" */ - CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); secp256k1_sha256_initialize(&sha); secp256k1_sha256_write(&sha, point_ser, point_ser_len); secp256k1_sha256_finalize(&sha, output_ser); diff --git a/src/modules/ellswift/tests_impl.h b/src/modules/ellswift/tests_impl.h index 4cc7f4b559..7982d8e2b0 100644 --- a/src/modules/ellswift/tests_impl.h +++ b/src/modules/ellswift/tests_impl.h @@ -319,6 +319,7 @@ void ellswift_compute_shared_secret_tests(void) { void ellswift_xdh_correctness_tests(void) { int i; + secp256k1_context *ctx = CTX; /* Verify the joint behavior of secp256k1_ellswift_xdh */ for (i = 0; i < 200 * COUNT; i++) { unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32]; @@ -357,18 +358,18 @@ void ellswift_xdh_correctness_tests(void) { /* Construct ElligatorSwift-encoded public keys for those keys. */ /* For A: */ - ret = secp256k1_ellswift_create(CTX, ell64a, sec32a, auxrnd32a); + ret = secp256k1_ellswift_create(ctx, ell64a, sec32a, auxrnd32a); CHECK(ret); /* For B: */ - ret = secp256k1_ellswift_create(CTX, ell64b, sec32b, auxrnd32b); + ret = secp256k1_ellswift_create(ctx, ell64b, sec32b, auxrnd32b); CHECK(ret); /* Compute the shared secret both ways and compare with each other. */ /* For A: */ - ret = secp256k1_ellswift_xdh(CTX, share32a, ell64a, ell64b, sec32a, 0, hash_function, data); + ret = secp256k1_ellswift_xdh(ctx, share32a, ell64a, ell64b, sec32a, 0, hash_function, data); CHECK(ret); /* For B: */ - ret = secp256k1_ellswift_xdh(CTX, share32b, ell64a, ell64b, sec32b, 1, hash_function, data); + ret = secp256k1_ellswift_xdh(ctx, share32b, ell64a, ell64b, sec32b, 1, hash_function, data); CHECK(ret); /* And compare: */ CHECK(secp256k1_memcmp_var(share32a, share32b, 32) == 0); @@ -377,13 +378,13 @@ void ellswift_xdh_correctness_tests(void) { /* For A (using a bad public key for B): */ memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad)); testrand_flip(ell64b_bad, sizeof(ell64b_bad)); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); + ret = secp256k1_ellswift_xdh(ctx, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); CHECK(ret); /* Mismatching encodings don't get detected by secp256k1_ellswift_xdh. */ CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); /* For B (using a bad public key for A): */ memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad)); testrand_flip(ell64a_bad, sizeof(ell64a_bad)); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); + ret = secp256k1_ellswift_xdh(ctx, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); CHECK(ret); CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); @@ -391,12 +392,12 @@ void ellswift_xdh_correctness_tests(void) { /* For A: */ memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad)); testrand_flip(sec32a_bad, sizeof(sec32a_bad)); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data); + ret = secp256k1_ellswift_xdh(ctx, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data); CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); /* For B: */ memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad)); testrand_flip(sec32b_bad, sizeof(sec32b_bad)); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data); + ret = secp256k1_ellswift_xdh(ctx, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data); CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); if (hash_function != ellswift_xdh_hash_x32) { @@ -404,27 +405,27 @@ void ellswift_xdh_correctness_tests(void) { /* For A (changing B's public key): */ memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad)); testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad)); - ret = secp256k1_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad); + ret = secp256k1_ellswift_create(ctx, ell64b_bad, sec32b, auxrnd32b_bad); CHECK(ret); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); + ret = secp256k1_ellswift_xdh(ctx, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data); CHECK(ret); CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); /* For B (changing A's public key): */ memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad)); testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad)); - ret = secp256k1_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad); + ret = secp256k1_ellswift_create(ctx, ell64a_bad, sec32a, auxrnd32a_bad); CHECK(ret); - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); + ret = secp256k1_ellswift_xdh(ctx, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data); CHECK(ret); CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); /* Verify that swapping sides changes the shared secret. */ /* For A (claiming to be B): */ - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a, 1, hash_function, data); + ret = secp256k1_ellswift_xdh(ctx, share32_bad, ell64a, ell64b, sec32a, 1, hash_function, data); CHECK(ret); CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0); /* For B (claiming to be A): */ - ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b, 0, hash_function, data); + ret = secp256k1_ellswift_xdh(ctx, share32_bad, ell64a, ell64b, sec32b, 0, hash_function, data); CHECK(ret); CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0); } diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index 9a1b15f0b2..aeb9e8353d 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -813,39 +813,40 @@ static void test_schnorrsig_sign_internal(void) { unsigned char zeros64[64] = { 0 }; secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; unsigned char aux_rand[32]; + secp256k1_context *ctx = CTX; testrand256(sk); testrand256(aux_rand); - CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); - CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair)); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); + CHECK(secp256k1_keypair_create(ctx, &keypair, sk)); + CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); + CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk)); /* Check that deprecated alias gives the same result */ - CHECK(secp256k1_schnorrsig_sign(CTX, sig2, msg, &keypair, NULL) == 1); + CHECK(secp256k1_schnorrsig_sign(ctx, sig2, msg, &keypair, NULL) == 1); CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); /* Test different nonce functions */ - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk)); memset(sig, 1, sizeof(sig)); extraparams.noncefp = nonce_function_failing; - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); memset(&sig, 1, sizeof(sig)); extraparams.noncefp = nonce_function_0; - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); memset(&sig, 1, sizeof(sig)); extraparams.noncefp = nonce_function_overflowing; - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk)); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk)); /* When using the default nonce function, schnorrsig_sign_custom produces * the same result as schnorrsig_sign with aux_rand = extraparams.ndata */ extraparams.noncefp = NULL; extraparams.ndata = aux_rand; - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig2, msg, &keypair, extraparams.ndata) == 1); + CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); + CHECK(secp256k1_schnorrsig_sign32(ctx, sig2, msg, &keypair, extraparams.ndata) == 1); CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); } From 6b75057a41b4642a3ea57f9e0e03ec0389363772 Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 24 Nov 2025 15:57:43 -0500 Subject: [PATCH 2/3] Add ability to provide SHA256 compression at compile-time Introduces a new `sha` module that exposes the SHA256 compression function and allows users to provide their own implementation. This moves the built-in transform logic out of `hash_impl.h` into a dedicated module (`src/modules/sha`), adds the corresponding public header (`secp256k1_sha.h`), and wires the module through Autotools and CMake via: `--with-external-sha256` / SECP256K1_EXTERNAL_SHA256_PATH. Existing behavior is unchanged; the library compiles and links the default transform function by default. --- CMakeLists.txt | 1 + Makefile.am | 6 ++ configure.ac | 14 +++ include/secp256k1_sha.h | 39 +++++++++ src/CMakeLists.txt | 16 ++++ src/hash_impl.h | 109 +----------------------- src/modules/sha/Makefile.am.include | 2 + src/modules/sha/main_impl.h | 127 ++++++++++++++++++++++++++++ src/secp256k1.c | 6 ++ 9 files changed, 214 insertions(+), 106 deletions(-) create mode 100644 include/secp256k1_sha.h create mode 100644 src/modules/sha/Makefile.am.include create mode 100644 src/modules/sha/main_impl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 11dc3f6e53..f0bf4a6fad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,6 +285,7 @@ message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRA message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}") message(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}") message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}") +message(" External SHA256 ..................... ${SECP256K1_EXTERNAL_SHA256_PATH-NONE}") message("Parameters:") message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}") message(" ecmult gen table size ............... ${SECP256K1_ECMULT_GEN_KB} KiB") diff --git a/Makefile.am b/Makefile.am index dc798575e3..7dd9f68664 100644 --- a/Makefile.am +++ b/Makefile.am @@ -62,6 +62,9 @@ noinst_HEADERS += src/scratch_impl.h noinst_HEADERS += src/selftest.h noinst_HEADERS += src/testrand.h noinst_HEADERS += src/testrand_impl.h +if !SECP256K1_EXTERNAL_SHA256 +noinst_HEADERS += src/modules/sha/main_impl.h +endif noinst_HEADERS += src/hash.h noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h @@ -314,3 +317,6 @@ endif if ENABLE_MODULE_ELLSWIFT include src/modules/ellswift/Makefile.am.include endif + +# Always include SHA module files, but they conditionally compile +include src/modules/sha/Makefile.am.include diff --git a/configure.ac b/configure.ac index 6028ee288d..cf0a2e748f 100644 --- a/configure.ac +++ b/configure.ac @@ -134,6 +134,12 @@ SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS) ### Define config arguments ### +AC_ARG_WITH([external-sha256], + AS_HELP_STRING([--with-external-sha256=PATH], [use external SHA256 compression implementation]), + [external_sha256_path="$withval"], + [external_sha256_path=""] +) + # In dev mode, we enable all binaries and modules by default but individual options can still be overridden explicitly. # Check for dev mode first because SECP_SET_DEFAULT needs enable_dev_mode set. AC_ARG_ENABLE(dev_mode, [], [], @@ -397,6 +403,12 @@ SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS" # Processing must be done in a reverse topological sorting of the dependency graph # (dependent module first). + +if test "x$external_sha256_path" != "x"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DSECP256K1_EXTERNAL_SHA256=1" + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DSECP256K1_EXTERNAL_SHA256_HEADER='\"$external_sha256_path\"'" +fi + if test x"$enable_module_ellswift" = x"yes"; then SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1" fi @@ -470,6 +482,7 @@ AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x" AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"]) +AM_CONDITIONAL([SECP256K1_EXTERNAL_SHA256], [test "x$SHA256_EXTERNAL_SRC" != "x"]) AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"]) AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"]) AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"]) @@ -494,6 +507,7 @@ echo " module extrakeys = $enable_module_extrakeys" echo " module schnorrsig = $enable_module_schnorrsig" echo " module musig = $enable_module_musig" echo " module ellswift = $enable_module_ellswift" +echo " external sha256 = ${external_sha256_path:-none}" echo echo " asm = $set_asm" echo " ecmult window size = $set_ecmult_window" diff --git a/include/secp256k1_sha.h b/include/secp256k1_sha.h new file mode 100644 index 0000000000..1d017f4450 --- /dev/null +++ b/include/secp256k1_sha.h @@ -0,0 +1,39 @@ +#ifndef SECP256K1_SHA_H +#define SECP256K1_SHA_H + +#include "secp256k1.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * SHA-256 block compression function. + * + * Performs the SHA-256 transform step on a single 64-byte message block, + * updating the 8-word `state` in place. This is the raw block-level primitive: + * no padding, no message scheduling across blocks, and no length encoding. + * Only the compression function is applied. + * + * If `rounds` is greater than 1, the same 64-byte block is re-compressed + * repeatedly onto the updated state. + * + * The caller must supply a fully-formed, 64-byte, block-aligned message block. + * + * @param state Current hash state (8 x 32-bit words), updated in place. + * @param block Pointer to a 64-byte message block. + * @param rounds Number of times to apply the compression to this block. + */ +SECP256K1_API void secp256k1_sha256_transform( + uint32_t *state, + const unsigned char *block, + size_t rounds +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_SHA_H */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ecbbbbe8e9..beb4e46a8f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,10 +3,26 @@ add_library(secp256k1) set_property(TARGET secp256k1 PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1.h ${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h + ${PROJECT_SOURCE_DIR}/include/secp256k1_sha.h ) # Processing must be done in a topological sorting of the dependency graph # (dependent module first). + +if(SECP256K1_EXTERNAL_SHA256_PATH) + if(EXISTS "${SECP256K1_EXTERNAL_SHA256_PATH}") + add_compile_definitions(SECP256K1_EXTERNAL_SHA256=1) + add_compile_definitions(SECP256K1_EXTERNAL_SHA256_HEADER="${SECP256K1_EXTERNAL_SHA256_PATH}") + else() + message(FATAL_ERROR "SECP256K1_EXTERNAL_SHA256_PATH does not exist: ${SECP256K1_EXTERNAL_SHA256_PATH}") + endif() +else() + # No external override. Compile internal implementation + target_sources(secp256k1 PRIVATE + ${PROJECT_SOURCE_DIR}/src/modules/sha/main_impl.h + ) +endif() + if(SECP256K1_ENABLE_MODULE_ELLSWIFT) add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1) set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h) diff --git a/src/hash_impl.h b/src/hash_impl.h index 4341917773..bbeb550c58 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -10,24 +10,12 @@ #include "hash.h" #include "util.h" +#include "../include/secp256k1_sha.h" + #include #include #include -#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) -#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) -#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10)) -#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7)) -#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3)) -#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10)) - -#define Round(a,b,c,d,e,f,g,h,k,w) do { \ - uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \ - uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \ - (d) += t1; \ - (h) = t1 + t2; \ -} while(0) - static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { hash->s[0] = 0x6a09e667ul; hash->s[1] = 0xbb67ae85ul; @@ -40,89 +28,6 @@ static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { hash->bytes = 0; } -/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ -static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) { - uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; - uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; - - Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = secp256k1_read_be32(&buf[0])); - Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = secp256k1_read_be32(&buf[4])); - Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = secp256k1_read_be32(&buf[8])); - Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = secp256k1_read_be32(&buf[12])); - Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = secp256k1_read_be32(&buf[16])); - Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = secp256k1_read_be32(&buf[20])); - Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = secp256k1_read_be32(&buf[24])); - Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = secp256k1_read_be32(&buf[28])); - Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = secp256k1_read_be32(&buf[32])); - Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = secp256k1_read_be32(&buf[36])); - Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = secp256k1_read_be32(&buf[40])); - Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = secp256k1_read_be32(&buf[44])); - Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = secp256k1_read_be32(&buf[48])); - Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = secp256k1_read_be32(&buf[52])); - Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = secp256k1_read_be32(&buf[56])); - Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = secp256k1_read_be32(&buf[60])); - - Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); - - Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); - - Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); - Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); - Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); - Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); - Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); - Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); - Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); - Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); - Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); - Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); - - s[0] += a; - s[1] += b; - s[2] += c; - s[3] += d; - s[4] += e; - s[5] += f; - s[6] += g; - s[7] += h; -} - static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) { size_t bufsize = hash->bytes & 0x3F; hash->bytes += len; @@ -133,7 +38,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char * memcpy(hash->buf + bufsize, data, chunk_len); data += chunk_len; len -= chunk_len; - secp256k1_sha256_transform(hash->s, hash->buf); + secp256k1_sha256_transform(hash->s, hash->buf, 1); bufsize = 0; } if (len) { @@ -288,12 +193,4 @@ static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *r secp256k1_memclear_explicit(rng, sizeof(*rng)); } -#undef Round -#undef sigma1 -#undef sigma0 -#undef Sigma1 -#undef Sigma0 -#undef Maj -#undef Ch - #endif /* SECP256K1_HASH_IMPL_H */ diff --git a/src/modules/sha/Makefile.am.include b/src/modules/sha/Makefile.am.include new file mode 100644 index 0000000000..17e42a1b38 --- /dev/null +++ b/src/modules/sha/Makefile.am.include @@ -0,0 +1,2 @@ +include_HEADERS += include/secp256k1_sha.h +noinst_HEADERS += src/modules/sha/main_impl.h diff --git a/src/modules/sha/main_impl.h b/src/modules/sha/main_impl.h new file mode 100644 index 0000000000..da75a370d8 --- /dev/null +++ b/src/modules/sha/main_impl.h @@ -0,0 +1,127 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_SHA_MAIN_H +#define SECP256K1_MODULE_SHA_MAIN_H + +#if !defined(SECP256K1_EXTERNAL_SHA256) + +#include "../../../include/secp256k1_sha.h" +#include "../../util.h" + +#include + +#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10)) +#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7)) +#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3)) +#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10)) + +#define Round(a,b,c,d,e,f,g,h,k,w) do { \ + uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \ + uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \ + (d) += t1; \ + (h) = t1 + t2; \ +} while(0) + +/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ +static void secp256k1_sha256_transform_impl(uint32_t* s, const unsigned char* buf) { + uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; + uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; + + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = secp256k1_read_be32(&buf[0])); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = secp256k1_read_be32(&buf[4])); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = secp256k1_read_be32(&buf[8])); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = secp256k1_read_be32(&buf[12])); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = secp256k1_read_be32(&buf[16])); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = secp256k1_read_be32(&buf[20])); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = secp256k1_read_be32(&buf[24])); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = secp256k1_read_be32(&buf[28])); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = secp256k1_read_be32(&buf[32])); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = secp256k1_read_be32(&buf[36])); + Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = secp256k1_read_be32(&buf[40])); + Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = secp256k1_read_be32(&buf[44])); + Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = secp256k1_read_be32(&buf[48])); + Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = secp256k1_read_be32(&buf[52])); + Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = secp256k1_read_be32(&buf[56])); + Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = secp256k1_read_be32(&buf[60])); + + Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); + + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + s[5] += f; + s[6] += g; + s[7] += h; +} + +void secp256k1_sha256_transform(uint32_t *state, const unsigned char *block, size_t rounds) { + while (rounds--) secp256k1_sha256_transform_impl(state, block); +} + +#undef Round +#undef sigma1 +#undef sigma0 +#undef Sigma1 +#undef Sigma0 +#undef Maj +#undef Ch + +#endif /* !SECP256K1_EXTERNAL_SHA256 */ + +#endif /* SECP256K1_MODULE_SHA_MAIN_H */ diff --git a/src/secp256k1.c b/src/secp256k1.c index ddd9849546..6b37b12f68 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -825,3 +825,9 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, #ifdef ENABLE_MODULE_ELLSWIFT # include "modules/ellswift/main_impl.h" #endif + +#ifdef SECP256K1_EXTERNAL_SHA256 +#include SECP256K1_EXTERNAL_SHA256_HEADER +#else +#include "modules/sha/main_impl.h" +#endif From 3683e07ef4b6a062eec1776220eeeec0c30bc2ec Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 24 Nov 2025 14:33:58 -0500 Subject: [PATCH 3/3] Add API to override SHA256 transform at runtime This introduces `secp256k1_context_set_sha256_transform_callback()`, which allows users to provide their own SHA256 block-compression function at runtime. This is useful in setups where the optimal implementation is detected dynamically, where rebuilding the library is not possible, or when the compression function is not written in bare C89. 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. --- include/secp256k1.h | 24 ++ src/bench_ecmult.c | 2 +- src/bench_internal.c | 12 +- src/ecmult_gen_impl.h | 9 +- src/hash.h | 15 +- src/hash_impl.h | 37 +-- src/modules/ecdh/main_impl.h | 24 +- src/modules/ecdh/tests_impl.h | 21 +- src/modules/ellswift/main_impl.h | 43 ++-- src/modules/ellswift/tests_impl.h | 31 ++- src/modules/musig/keyagg.h | 2 +- src/modules/musig/keyagg_impl.h | 20 +- src/modules/musig/session_impl.h | 36 +-- src/modules/musig/tests_impl.h | 52 +++-- src/modules/schnorrsig/main_impl.h | 50 ++-- .../schnorrsig/tests_exhaustive_impl.h | 4 +- src/modules/schnorrsig/tests_impl.h | 31 ++- src/secp256k1.c | 45 +++- src/selftest.h | 7 +- src/testrand_impl.h | 3 +- src/tests.c | 215 ++++++++++++------ src/testutil.h | 8 + 22 files changed, 458 insertions(+), 233 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index b0a13b144d..2a691967fd 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -6,6 +6,7 @@ extern "C" { #endif #include +#include /** Unless explicitly stated all pointer arguments must not be NULL. * @@ -403,6 +404,29 @@ SECP256K1_API void secp256k1_context_set_error_callback( const void *data ) SECP256K1_ARG_NONNULL(1); +/** + * Set a callback function to override the internal SHA-256 transform. + * + * This installs a function to replace the built-in block-compression + * step used by the library's internal SHA-256 implementation. + * The provided callback must be functionally identical (bit-for-bit) + * to the default transform. Any deviation will cause incorrect results + * and undefined behaviour. + * + * This API exists to support environments that wish to route the + * SHA-256 compression step through a hardware-accelerated or otherwise + * specialized implementation. It is not meant for modifying the + * semantics of SHA-256. + * + * Args: ctx: pointer to a context object. + * In: callback: pointer to a function implementing the transform step. + * (passing NULL restores the default implementation) + */ +SECP256K1_API void secp256k1_context_set_sha256_transform( + secp256k1_context *ctx, + void (*fn_sha256_transform)(uint32_t *state, const unsigned char *block, size_t rounds) +) SECP256K1_ARG_NONNULL(1); + /** Parse a variable-length public key into the pubkey object. * * Returns: 1 if the public key was fully valid. diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c index c9a1d90026..97a9ebf49a 100644 --- a/src/bench_ecmult.c +++ b/src/bench_ecmult.c @@ -265,7 +265,7 @@ static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) { c[7] = num >> 8; c[8] = num >> 16; c[9] = num >> 24; - secp256k1_sha256_initialize(&sha256); + secp256k1_sha256_initialize(&sha256, /*fn_transform=*/NULL); secp256k1_sha256_write(&sha256, c, sizeof(c)); secp256k1_sha256_finalize(&sha256, buf); secp256k1_scalar_set_b32(scalar, buf, &overflow); diff --git a/src/bench_internal.c b/src/bench_internal.c index 8688a4dc77..6f7d499d49 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -38,6 +38,7 @@ static void help(int default_iters) { } typedef struct { + const secp256k1_context* ctx; secp256k1_scalar scalar[2]; secp256k1_fe fe[4]; secp256k1_ge ge[2]; @@ -82,6 +83,9 @@ static void bench_setup(void* arg) { } }; + /* Customize context if needed */ + data->ctx = secp256k1_context_static; + secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL); secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL); secp256k1_fe_set_b32_limit(&data->fe[0], init[0]); @@ -346,7 +350,7 @@ static void bench_sha256(void* arg, int iters) { secp256k1_sha256 sha; for (i = 0; i < iters; i++) { - secp256k1_sha256_initialize(&sha); + secp256k1_sha256_initialize(&sha, data->ctx->hash_context.fn_sha256_transform); secp256k1_sha256_write(&sha, data->data, 32); secp256k1_sha256_finalize(&sha, data->data); } @@ -358,7 +362,7 @@ static void bench_hmac_sha256(void* arg, int iters) { secp256k1_hmac_sha256 hmac; for (i = 0; i < iters; i++) { - secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); + secp256k1_hmac_sha256_initialize(&hmac, data->data, 32, data->ctx->hash_context.fn_sha256_transform); secp256k1_hmac_sha256_write(&hmac, data->data, 32); secp256k1_hmac_sha256_finalize(&hmac, data->data); } @@ -370,8 +374,8 @@ static void bench_rfc6979_hmac_sha256(void* arg, int iters) { secp256k1_rfc6979_hmac_sha256 rng; for (i = 0; i < iters; i++) { - secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); - secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64, data->ctx->hash_context.fn_sha256_transform); + secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32, data->ctx->hash_context.fn_sha256_transform); } } diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h index 2159eed5e1..cd91df756b 100644 --- a/src/ecmult_gen_impl.h +++ b/src/ecmult_gen_impl.h @@ -291,6 +291,9 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_rfc6979_hmac_sha256 rng; unsigned char keydata[64]; + /* future: use context callback */ + const secp256k1_fn_sha256_transform fn_sha256_transform = NULL; + /* Compute the (2^COMB_BITS - 1)/2 term once. */ secp256k1_ecmult_gen_scalar_diff(&diff); @@ -309,17 +312,17 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const */ VERIFY_CHECK(seed32 != NULL); memcpy(keydata + 32, seed32, 32); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64, fn_sha256_transform); secp256k1_memclear_explicit(keydata, sizeof(keydata)); /* Compute projective blinding factor (cannot be 0). */ - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32, fn_sha256_transform); secp256k1_fe_set_b32_mod(&f, nonce32); secp256k1_fe_cmov(&f, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&f)); ctx->proj_blind = f; /* For a random blinding value b, set scalar_offset=diff-b, ge_offset=bG */ - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32, fn_sha256_transform); secp256k1_scalar_set_b32(&b, nonce32, NULL); /* The blinding value cannot be zero, as that would mean ge_offset = infinity, * which secp256k1_gej_add_ge cannot handle. */ diff --git a/src/hash.h b/src/hash.h index 6d903ca7e0..6259c8236d 100644 --- a/src/hash.h +++ b/src/hash.h @@ -10,13 +10,20 @@ #include #include +typedef void (*secp256k1_fn_sha256_transform)(uint32_t *state, const unsigned char *block, size_t rounds); + +struct secp256k1_hash_context { + secp256k1_fn_sha256_transform fn_sha256_transform; +}; + typedef struct { uint32_t s[8]; unsigned char buf[64]; uint64_t bytes; + secp256k1_fn_sha256_transform fn_transform; } secp256k1_sha256; -static void secp256k1_sha256_initialize(secp256k1_sha256 *hash); +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash, secp256k1_fn_sha256_transform fn_transform); static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size); static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32); static void secp256k1_sha256_clear(secp256k1_sha256 *hash); @@ -25,7 +32,7 @@ typedef struct { secp256k1_sha256 inner, outer; } secp256k1_hmac_sha256; -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size); +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size, secp256k1_fn_sha256_transform fn_sha256_transform); static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size); static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32); static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash); @@ -36,8 +43,8 @@ typedef struct { int retry; } secp256k1_rfc6979_hmac_sha256; -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen, secp256k1_fn_sha256_transform fn_sha256_transform); +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen, secp256k1_fn_sha256_transform fn_sha256_transform); static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng); static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng); diff --git a/src/hash_impl.h b/src/hash_impl.h index bbeb550c58..ecbe1e5e16 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -16,7 +16,7 @@ #include #include -static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash, secp256k1_fn_sha256_transform fn_transform) { hash->s[0] = 0x6a09e667ul; hash->s[1] = 0xbb67ae85ul; hash->s[2] = 0x3c6ef372ul; @@ -26,6 +26,7 @@ static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { hash->s[6] = 0x1f83d9abul; hash->s[7] = 0x5be0cd19ul; hash->bytes = 0; + hash->fn_transform = fn_transform == NULL ? secp256k1_sha256_transform : fn_transform; } static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) { @@ -38,7 +39,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char * memcpy(hash->buf + bufsize, data, chunk_len); data += chunk_len; len -= chunk_len; - secp256k1_sha256_transform(hash->s, hash->buf, 1); + hash->fn_transform(hash->s, hash->buf, 1); bufsize = 0; } if (len) { @@ -65,13 +66,13 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out /* Initializes a sha256 struct and writes the 64 byte string * SHA256(tag)||SHA256(tag) into it. */ -static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) { +static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen, secp256k1_fn_sha256_transform fn_sha256_transform) { unsigned char buf[32]; - secp256k1_sha256_initialize(hash); + secp256k1_sha256_initialize(hash, fn_sha256_transform); secp256k1_sha256_write(hash, tag, taglen); secp256k1_sha256_finalize(hash, buf); - secp256k1_sha256_initialize(hash); + secp256k1_sha256_initialize(hash, fn_sha256_transform); secp256k1_sha256_write(hash, buf, 32); secp256k1_sha256_write(hash, buf, 32); } @@ -80,7 +81,7 @@ static void secp256k1_sha256_clear(secp256k1_sha256 *hash) { secp256k1_memclear_explicit(hash, sizeof(*hash)); } -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen, secp256k1_fn_sha256_transform fn_sha256_transform) { size_t n; unsigned char rkey[64]; if (keylen <= sizeof(rkey)) { @@ -88,19 +89,19 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const memset(rkey + keylen, 0, sizeof(rkey) - keylen); } else { secp256k1_sha256 sha256; - secp256k1_sha256_initialize(&sha256); + secp256k1_sha256_initialize(&sha256, fn_sha256_transform); secp256k1_sha256_write(&sha256, key, keylen); secp256k1_sha256_finalize(&sha256, rkey); memset(rkey + 32, 0, 32); } - secp256k1_sha256_initialize(&hash->outer); + secp256k1_sha256_initialize(&hash->outer, fn_sha256_transform); for (n = 0; n < sizeof(rkey); n++) { rkey[n] ^= 0x5c; } secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey)); - secp256k1_sha256_initialize(&hash->inner); + secp256k1_sha256_initialize(&hash->inner, fn_sha256_transform); for (n = 0; n < sizeof(rkey); n++) { rkey[n] ^= 0x5c ^ 0x36; } @@ -124,7 +125,7 @@ static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash) { secp256k1_memclear_explicit(hash, sizeof(*hash)); } -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen, secp256k1_fn_sha256_transform fn_sha256_transform) { secp256k1_hmac_sha256 hmac; static const unsigned char zero[1] = {0x00}; static const unsigned char one[1] = {0x01}; @@ -133,37 +134,37 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */ /* RFC6979 3.2.d. */ - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32, fn_sha256_transform); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, zero, 1); secp256k1_hmac_sha256_write(&hmac, key, keylen); secp256k1_hmac_sha256_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32, fn_sha256_transform); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_finalize(&hmac, rng->v); /* RFC6979 3.2.f. */ - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32, fn_sha256_transform); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, one, 1); secp256k1_hmac_sha256_write(&hmac, key, keylen); secp256k1_hmac_sha256_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32, fn_sha256_transform); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_finalize(&hmac, rng->v); rng->retry = 0; } -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen, secp256k1_fn_sha256_transform fn_sha256_transform) { /* RFC6979 3.2.h. */ static const unsigned char zero[1] = {0x00}; if (rng->retry) { secp256k1_hmac_sha256 hmac; - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32, fn_sha256_transform); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, zero, 1); secp256k1_hmac_sha256_finalize(&hmac, rng->k); - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32, fn_sha256_transform); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_finalize(&hmac, rng->v); } @@ -171,7 +172,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 while (outlen > 0) { secp256k1_hmac_sha256 hmac; size_t now = outlen; - secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32, fn_sha256_transform); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_finalize(&hmac, rng->v); if (now > 32) { diff --git a/src/modules/ecdh/main_impl.h b/src/modules/ecdh/main_impl.h index 9f2dfdd56a..ac6ca7d0a9 100644 --- a/src/modules/ecdh/main_impl.h +++ b/src/modules/ecdh/main_impl.h @@ -10,12 +10,13 @@ #include "../../../include/secp256k1_ecdh.h" #include "../../ecmult_const_impl.h" -static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { +static int ecdh_hash_function_sha256_impl(const secp256k1_context *ctx, unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { unsigned char version = (y32[31] & 0x01) | 0x02; secp256k1_sha256 sha; + secp256k1_fn_sha256_transform fn_sha256_transform = ctx ? ctx->hash_context.fn_sha256_transform : NULL; (void)data; - secp256k1_sha256_initialize(&sha); + secp256k1_sha256_initialize(&sha, fn_sha256_transform); secp256k1_sha256_write(&sha, &version, 1); secp256k1_sha256_write(&sha, x32, 32); secp256k1_sha256_finalize(&sha, output); @@ -24,6 +25,10 @@ static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char return 1; } +static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) { + return ecdh_hash_function_sha256_impl(/*ctx=*/NULL, output, x32, y32, data); +} + const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256; const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256; @@ -41,10 +46,6 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se ARG_CHECK(point != NULL); ARG_CHECK(scalar != NULL); - if (hashfp == NULL) { - hashfp = secp256k1_ecdh_hash_function_default; - } - secp256k1_pubkey_load(ctx, &pt, point); secp256k1_scalar_set_b32(&s, scalar, &overflow); @@ -60,7 +61,16 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se secp256k1_fe_get_b32(x, &pt.x); secp256k1_fe_get_b32(y, &pt.y); - ret = hashfp(output, x, y, data); + if (hashfp == NULL) { + if (ctx->hash_context.fn_sha256_transform != NULL) { + /* Use context-aware function when custom SHA256 is provided */ + ret = ecdh_hash_function_sha256_impl(ctx, output, x, y, data); + } else { + ret = secp256k1_ecdh_hash_function_default(output, x, y, data);; + } + } else { + ret = hashfp(output, x, y, data); + } secp256k1_memclear_explicit(x, sizeof(x)); secp256k1_memclear_explicit(y, sizeof(y)); diff --git a/src/modules/ecdh/tests_impl.h b/src/modules/ecdh/tests_impl.h index f3f5ccdca0..693e66162c 100644 --- a/src/modules/ecdh/tests_impl.h +++ b/src/modules/ecdh/tests_impl.h @@ -8,6 +8,7 @@ #define SECP256K1_MODULE_ECDH_TESTS_H #include "../../unit_test.h" +#include "../../testutil.h" static int ecdh_hash_function_test_xpassthru(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { (void)y; @@ -49,15 +50,14 @@ static void test_ecdh_api(void) { CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); } -static void test_ecdh_generator_basepoint(void) { +static void test_ecdh_generator_basepoint_impl(secp256k1_context *ctx) { unsigned char s_one[32] = { 0 }; secp256k1_pubkey point[2]; int i; - secp256k1_context *ctx = CTX; s_one[31] = 1; /* Check against pubkey creation when the basepoint is the generator */ - for (i = 0; i < 2 * COUNT; ++i) { + for (i = 0; i < COUNT; ++i) { secp256k1_sha256 sha; unsigned char s_b32[32]; unsigned char output_ecdh[65]; @@ -83,7 +83,7 @@ static void test_ecdh_generator_basepoint(void) { CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); /* compute "explicitly" */ CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); - secp256k1_sha256_initialize(&sha); + secp256k1_sha256_initialize(&sha, ctx->hash_context.fn_sha256_transform); secp256k1_sha256_write(&sha, point_ser, point_ser_len); secp256k1_sha256_finalize(&sha, output_ser); /* compare */ @@ -91,6 +91,19 @@ static void test_ecdh_generator_basepoint(void) { } } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_ecdh) +static void test_ecdh_generator_basepoint(void) { + secp256k1_context *ctx = secp256k1_context_clone(CTX); + /* Baseline run using the default SHA256 implementation */ + test_ecdh_generator_basepoint_impl(ctx); + + /* Re-run using a context-provided SHA256 transform */ + secp256k1_context_set_sha256_transform(ctx, sha256_ecdh); + test_ecdh_generator_basepoint_impl(ctx); + CHECK(sha256_ecdh_called); + secp256k1_context_destroy(ctx); +} + static void test_bad_scalar(void) { unsigned char s_zero[32] = { 0 }; unsigned char s_overflow[32] = { 0 }; diff --git a/src/modules/ellswift/main_impl.h b/src/modules/ellswift/main_impl.h index 096f4a3c71..7aa018f56c 100644 --- a/src/modules/ellswift/main_impl.h +++ b/src/modules/ellswift/main_impl.h @@ -382,8 +382,8 @@ static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_ } /** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_encode". */ -static void secp256k1_ellswift_sha256_init_encode(secp256k1_sha256* hash) { - secp256k1_sha256_initialize(hash); +static void secp256k1_ellswift_sha256_init_encode(const secp256k1_context *ctx, secp256k1_sha256* hash) { + secp256k1_sha256_initialize(hash, ctx->hash_context.fn_sha256_transform); hash->s[0] = 0xd1a6524bul; hash->s[1] = 0x028594b3ul; hash->s[2] = 0x96e42f4eul; @@ -410,7 +410,7 @@ int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64 /* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using * BIP340 tagged hash with tag "secp256k1_ellswift_encode". */ - secp256k1_ellswift_sha256_init_encode(&hash); + secp256k1_ellswift_sha256_init_encode(ctx, &hash); secp256k1_eckey_pubkey_serialize33(&p, p64); secp256k1_sha256_write(&hash, p64, sizeof(p64)); secp256k1_sha256_write(&hash, rnd32, 32); @@ -426,8 +426,8 @@ int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64 } /** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_create". */ -static void secp256k1_ellswift_sha256_init_create(secp256k1_sha256* hash) { - secp256k1_sha256_initialize(hash); +static void secp256k1_ellswift_sha256_init_create(const secp256k1_context *ctx, secp256k1_sha256* hash) { + secp256k1_sha256_initialize(hash, ctx->hash_context.fn_sha256_transform); hash->s[0] = 0xd29e1bf5ul; hash->s[1] = 0xf7025f42ul; hash->s[2] = 0x9b024773ul; @@ -463,7 +463,7 @@ int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64 /* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++), * using BIP340 tagged hash with tag "secp256k1_ellswift_create". */ - secp256k1_ellswift_sha256_init_create(&hash); + secp256k1_ellswift_sha256_init_create(ctx, &hash); secp256k1_sha256_write(&hash, seckey32, 32); secp256k1_sha256_write(&hash, zero32, sizeof(zero32)); secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */ @@ -494,10 +494,10 @@ int secp256k1_ellswift_decode(const secp256k1_context *ctx, secp256k1_pubkey *pu return 1; } -static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { +static int ellswift_xdh_hash_function_prefix_impl(const secp256k1_context *ctx, unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { secp256k1_sha256 sha; - secp256k1_sha256_initialize(&sha); + secp256k1_sha256_initialize(&sha, ctx ? ctx->hash_context.fn_sha256_transform : NULL); secp256k1_sha256_write(&sha, data, 64); secp256k1_sha256_write(&sha, ell_a64, 64); secp256k1_sha256_write(&sha, ell_b64, 64); @@ -508,9 +508,13 @@ static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsign return 1; } +static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + return ellswift_xdh_hash_function_prefix_impl(/*ctx=*/NULL, output, x32, ell_a64, ell_b64, data); +} + /** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */ -static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) { - secp256k1_sha256_initialize(hash); +static void secp256k1_ellswift_sha256_init_bip324(const secp256k1_context *ctx, secp256k1_sha256* hash) { + secp256k1_sha256_initialize(hash, ctx ? ctx->hash_context.fn_sha256_transform : NULL); hash->s[0] = 0x8c12d730ul; hash->s[1] = 0x827bd392ul; hash->s[2] = 0x9e4fb2eeul; @@ -523,12 +527,12 @@ static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) { hash->bytes = 64; } -static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { +static int ellswift_xdh_hash_function_bip324_impl(const secp256k1_context *ctx, unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { secp256k1_sha256 sha; (void)data; - secp256k1_ellswift_sha256_init_bip324(&sha); + secp256k1_ellswift_sha256_init_bip324(ctx, &sha); secp256k1_sha256_write(&sha, ell_a64, 64); secp256k1_sha256_write(&sha, ell_b64, 64); secp256k1_sha256_write(&sha, x32, 32); @@ -538,6 +542,10 @@ static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsign return 1; } +static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) { + return ellswift_xdh_hash_function_bip324_impl(/*ctx=*/NULL, output, x32, ell_a64, ell_b64, data); +} + const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix; const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324; @@ -572,8 +580,15 @@ int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output, secp256k1_fe_normalize(&px); secp256k1_fe_get_b32(sx, &px); - /* Invoke hasher */ - ret = hashfp(output, sx, ell_a64, ell_b64, data); + /* Invoke hasher. + * Use context-aware function when custom SHA256 is provided */ + if (hashfp == secp256k1_ellswift_xdh_hash_function_bip324 && ctx->hash_context.fn_sha256_transform != NULL) { + ret = ellswift_xdh_hash_function_bip324_impl(ctx, output, sx, ell_a64, ell_b64, data); + } else if (hashfp == secp256k1_ellswift_xdh_hash_function_prefix && ctx->hash_context.fn_sha256_transform != NULL) { + ret = ellswift_xdh_hash_function_prefix_impl(ctx, output, sx, ell_a64, ell_b64, data); + } else { + ret = hashfp(output, sx, ell_a64, ell_b64, data); + } secp256k1_memclear_explicit(sx, sizeof(sx)); secp256k1_fe_clear(&px); diff --git a/src/modules/ellswift/tests_impl.h b/src/modules/ellswift/tests_impl.h index 7982d8e2b0..cfcee225dd 100644 --- a/src/modules/ellswift/tests_impl.h +++ b/src/modules/ellswift/tests_impl.h @@ -317,11 +317,10 @@ void ellswift_compute_shared_secret_tests(void) { } } -void ellswift_xdh_correctness_tests(void) { +void ellswift_xdh_correctness_tests_impl(secp256k1_context *ctx) { int i; - secp256k1_context *ctx = CTX; /* Verify the joint behavior of secp256k1_ellswift_xdh */ - for (i = 0; i < 200 * COUNT; i++) { + for (i = 0; i < 100 * COUNT; i++) { unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32]; unsigned char sec32a[32], sec32b[32], sec32a_bad[32], sec32b_bad[32]; secp256k1_scalar seca, secb; @@ -432,9 +431,23 @@ void ellswift_xdh_correctness_tests(void) { } } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_ellswift_xdh) +void ellswift_xdh_correctness_tests(void) { + secp256k1_context *ctx = secp256k1_context_clone(CTX); + /* Baseline run using the default SHA256 implementation */ + ellswift_xdh_correctness_tests_impl(ctx); + + /* Re-run using a context-provided SHA256 transform */ + secp256k1_context_set_sha256_transform(ctx, sha256_ellswift_xdh); + ellswift_xdh_correctness_tests_impl(ctx); + CHECK(sha256_ellswift_xdh_called); + secp256k1_context_destroy(ctx); +} + /* Test hash initializers */ void ellswift_hash_init_tests(void) { secp256k1_sha256 sha_optimized; + secp256k1_context *ctx = CTX; /* "secp256k1_ellswift_encode" */ static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'}; /* "secp256k1_ellswift_create" */ @@ -445,20 +458,20 @@ void ellswift_hash_init_tests(void) { /* Check that hash initialized by * secp256k1_ellswift_sha256_init_encode has the expected * state. */ - secp256k1_ellswift_sha256_init_encode(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, encode_tag, sizeof(encode_tag)); + secp256k1_ellswift_sha256_init_encode(ctx, &sha_optimized); + test_sha256_tag_midstate(ctx, &sha_optimized, encode_tag, sizeof(encode_tag)); /* Check that hash initialized by * secp256k1_ellswift_sha256_init_create has the expected * state. */ - secp256k1_ellswift_sha256_init_create(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, create_tag, sizeof(create_tag)); + secp256k1_ellswift_sha256_init_create(ctx, &sha_optimized); + test_sha256_tag_midstate(ctx, &sha_optimized, create_tag, sizeof(create_tag)); /* Check that hash initialized by * secp256k1_ellswift_sha256_init_bip324 has the expected * state. */ - secp256k1_ellswift_sha256_init_bip324(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, bip324_tag, sizeof(bip324_tag)); + secp256k1_ellswift_sha256_init_bip324(ctx, &sha_optimized); + test_sha256_tag_midstate(ctx, &sha_optimized, bip324_tag, sizeof(bip324_tag)); } /* --- Test registry --- */ diff --git a/src/modules/musig/keyagg.h b/src/modules/musig/keyagg.h index a0b37252f8..8973d16d3a 100644 --- a/src/modules/musig/keyagg.h +++ b/src/modules/musig/keyagg.h @@ -27,6 +27,6 @@ typedef struct { static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_keyagg_cache_internal *cache_i, const secp256k1_musig_keyagg_cache *cache); -static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk); +static void secp256k1_musig_keyaggcoef(const secp256k1_context *ctx, secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk); #endif diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h index e412a27eca..81e4d09225 100644 --- a/src/modules/musig/keyagg_impl.h +++ b/src/modules/musig/keyagg_impl.h @@ -61,8 +61,8 @@ static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_k /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("KeyAgg list")||SHA256("KeyAgg list"). */ -static void secp256k1_musig_keyagglist_sha256(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); +static void secp256k1_musig_keyagglist_sha256(const secp256k1_context *ctx, secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha, ctx->hash_context.fn_sha256_transform); sha->s[0] = 0xb399d5e0ul; sha->s[1] = 0xc8fff302ul; @@ -80,7 +80,7 @@ static int secp256k1_musig_compute_pks_hash(const secp256k1_context *ctx, unsign secp256k1_sha256 sha; size_t i; - secp256k1_musig_keyagglist_sha256(&sha); + secp256k1_musig_keyagglist_sha256(ctx, &sha); for (i = 0; i < np; i++) { unsigned char ser[33]; size_t ser_len = sizeof(ser); @@ -96,8 +96,8 @@ static int secp256k1_musig_compute_pks_hash(const secp256k1_context *ctx, unsign /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */ -static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); +static void secp256k1_musig_keyaggcoef_sha256(const secp256k1_context *ctx, secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha, ctx->hash_context.fn_sha256_transform); sha->s[0] = 0x6ef02c5aul; sha->s[1] = 0x06a480deul; @@ -115,7 +115,7 @@ static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) { * second_pk is the point at infinity in case there is no second_pk. Assumes * that pk is not the point at infinity and that the Y-coordinates of pk and * second_pk are normalized. */ -static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pks_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) { +static void secp256k1_musig_keyaggcoef_internal(const secp256k1_context *ctx, secp256k1_scalar *r, const unsigned char *pks_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) { VERIFY_CHECK(!secp256k1_ge_is_infinity(pk)); if (!secp256k1_ge_is_infinity(second_pk) @@ -124,7 +124,7 @@ static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsig } else { secp256k1_sha256 sha; unsigned char buf[33]; - secp256k1_musig_keyaggcoef_sha256(&sha); + secp256k1_musig_keyaggcoef_sha256(ctx, &sha); secp256k1_sha256_write(&sha, pks_hash, 32); /* Serialization does not fail since the pk is not the point at infinity * (according to this function's precondition). */ @@ -137,8 +137,8 @@ static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsig /* Assumes that pk is not the point at infinity and that the Y-coordinates of pk * and cache_i->second_pk are normalized. */ -static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) { - secp256k1_musig_keyaggcoef_internal(r, cache_i->pks_hash, pk, &cache_i->second_pk); +static void secp256k1_musig_keyaggcoef(const secp256k1_context *ctx, secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) { + secp256k1_musig_keyaggcoef_internal(ctx, r, cache_i->pks_hash, pk, &cache_i->second_pk); } typedef struct { @@ -161,7 +161,7 @@ static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_g #else (void) ret; #endif - secp256k1_musig_keyaggcoef_internal(sc, ctx->pks_hash, pt, &ctx->second_pk); + secp256k1_musig_keyaggcoef_internal(ctx->ctx, sc, ctx->pks_hash, pt, &ctx->second_pk); return 1; } diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index 05c9631004..771a718d9d 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -308,8 +308,8 @@ static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigne /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("MuSig/aux")||SHA256("MuSig/aux"). */ -static void secp256k1_nonce_function_musig_sha256_tagged_aux(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); +static void secp256k1_nonce_function_musig_sha256_tagged_aux(const secp256k1_context *ctx, secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha, ctx->hash_context.fn_sha256_transform); sha->s[0] = 0xa19e884bul; sha->s[1] = 0xf463fe7eul; sha->s[2] = 0x2f18f9a2ul; @@ -323,8 +323,8 @@ static void secp256k1_nonce_function_musig_sha256_tagged_aux(secp256k1_sha256 *s /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("MuSig/nonce")||SHA256("MuSig/nonce"). */ -static void secp256k1_nonce_function_musig_sha256_tagged(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); +static void secp256k1_nonce_function_musig_sha256_tagged(const secp256k1_context *ctx, secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha, ctx->hash_context.fn_sha256_transform); sha->s[0] = 0x07101b64ul; sha->s[1] = 0x18003414ul; sha->s[2] = 0x0391bc43ul; @@ -336,14 +336,14 @@ static void secp256k1_nonce_function_musig_sha256_tagged(secp256k1_sha256 *sha) sha->bytes = 64; } -static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { +static void secp256k1_nonce_function_musig(const secp256k1_context *ctx, secp256k1_scalar *k, const unsigned char *session_secrand, const unsigned char *msg32, const unsigned char *seckey32, const unsigned char *pk33, const unsigned char *agg_pk32, const unsigned char *extra_input32) { secp256k1_sha256 sha; unsigned char rand[32]; unsigned char i; unsigned char msg_present; if (seckey32 != NULL) { - secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); + secp256k1_nonce_function_musig_sha256_tagged_aux(ctx, &sha); secp256k1_sha256_write(&sha, session_secrand, 32); secp256k1_sha256_finalize(&sha, rand); for (i = 0; i < 32; i++) { @@ -353,7 +353,7 @@ static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned c memcpy(rand, session_secrand, sizeof(rand)); } - secp256k1_nonce_function_musig_sha256_tagged(&sha); + secp256k1_nonce_function_musig_sha256_tagged(ctx, &sha); secp256k1_sha256_write(&sha, rand, sizeof(rand)); secp256k1_nonce_function_musig_helper(&sha, 1, pk33, 33); secp256k1_nonce_function_musig_helper(&sha, 1, agg_pk32, 32); @@ -417,7 +417,7 @@ static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp /* A pubkey cannot be the point at infinity */ secp256k1_eckey_pubkey_serialize33(&pk, pk_ser); - secp256k1_nonce_function_musig(k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); + secp256k1_nonce_function_musig(ctx, k, input_nonce, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0])); VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[1])); secp256k1_musig_secnonce_save(secnonce, k, &pk); @@ -542,8 +542,8 @@ int secp256k1_musig_nonce_agg(const secp256k1_context* ctx, secp256k1_musig_aggn /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("MuSig/noncecoef")||SHA256("MuSig/noncecoef"). */ -static void secp256k1_musig_compute_noncehash_sha256_tagged(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); +static void secp256k1_musig_compute_noncehash_sha256_tagged(const secp256k1_context *ctx, secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha, ctx->hash_context.fn_sha256_transform); sha->s[0] = 0x2c7d5a45ul; sha->s[1] = 0x06bf7e53ul; sha->s[2] = 0x89be68a6ul; @@ -556,12 +556,12 @@ static void secp256k1_musig_compute_noncehash_sha256_tagged(secp256k1_sha256 *sh } /* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */ -static void secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) { +static void secp256k1_musig_compute_noncehash(const secp256k1_context *ctx, unsigned char *noncehash, secp256k1_ge *aggnonce, const unsigned char *agg_pk32, const unsigned char *msg) { unsigned char buf[33]; secp256k1_sha256 sha; int i; - secp256k1_musig_compute_noncehash_sha256_tagged(&sha); + secp256k1_musig_compute_noncehash_sha256_tagged(ctx, &sha); for (i = 0; i < 2; i++) { secp256k1_musig_ge_serialize_ext(buf, &aggnonce[i]); secp256k1_sha256_write(&sha, buf, sizeof(buf)); @@ -580,12 +580,12 @@ static void secp256k1_effective_nonce(secp256k1_gej *out_nonce, const secp256k1_ secp256k1_gej_add_ge_var(out_nonce, out_nonce, &nonce_pts[0], NULL); } -static void secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_ge *aggnonce_pts, const unsigned char *agg_pk32, const unsigned char *msg) { +static void secp256k1_musig_nonce_process_internal(const secp256k1_context *ctx, int *fin_nonce_parity, unsigned char *fin_nonce, secp256k1_scalar *b, secp256k1_ge *aggnonce_pts, const unsigned char *agg_pk32, const unsigned char *msg) { unsigned char noncehash[32]; secp256k1_ge fin_nonce_pt; secp256k1_gej fin_nonce_ptj; - secp256k1_musig_compute_noncehash(noncehash, aggnonce_pts, agg_pk32, msg); + secp256k1_musig_compute_noncehash(ctx, noncehash, aggnonce_pts, agg_pk32, msg); secp256k1_scalar_set_b32(b, noncehash, NULL); /* fin_nonce = aggnonce_pts[0] + b*aggnonce_pts[1] */ secp256k1_effective_nonce(&fin_nonce_ptj, aggnonce_pts, b); @@ -622,8 +622,8 @@ int secp256k1_musig_nonce_process(const secp256k1_context* ctx, secp256k1_musig_ return 0; } - secp256k1_musig_nonce_process_internal(&session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_pts, agg_pk32, msg32); - secp256k1_schnorrsig_challenge(&session_i.challenge, fin_nonce, msg32, 32, agg_pk32); + secp256k1_musig_nonce_process_internal(ctx, &session_i.fin_nonce_parity, fin_nonce, &session_i.noncecoef, aggnonce_pts, agg_pk32, msg32); + secp256k1_schnorrsig_challenge(ctx, &session_i.challenge, fin_nonce, msg32, 32, agg_pk32); /* If there is a tweak then set `challenge` times `tweak` to the `s`-part.*/ secp256k1_scalar_set_int(&session_i.s_part, 0); @@ -693,7 +693,7 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p } /* Multiply KeyAgg coefficient */ - secp256k1_musig_keyaggcoef(&mu, &cache_i, &pk); + secp256k1_musig_keyaggcoef(ctx, &mu, &cache_i, &pk); secp256k1_scalar_mul(&sk, &sk, &mu); if (!secp256k1_musig_session_load(ctx, &session_i, session)) { @@ -753,7 +753,7 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2 /* Multiplying the challenge by the KeyAgg coefficient is equivalent * to multiplying the signer's public key by the coefficient, except * much easier to do. */ - secp256k1_musig_keyaggcoef(&mu, &cache_i, &pkp); + secp256k1_musig_keyaggcoef(ctx, &mu, &cache_i, &pkp); secp256k1_scalar_mul(&e, &session_i.challenge, &mu); /* Negate e if secp256k1_fe_is_odd(&cache_i.pk.y)) XOR cache_i.parity_acc. diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index de09c5e280..d40ee9bd3b 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -505,12 +505,12 @@ static void musig_api_tests(void) { CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); } -static void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { +static void musig_nonce_bitflip(const secp256k1_context *ctx, unsigned char **args, size_t n_flip, size_t n_bytes) { secp256k1_scalar k1[2], k2[2]; - secp256k1_nonce_function_musig(k1, args[0], args[1], args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(ctx, k1, args[0], args[1], args[2], args[3], args[4], args[5]); testrand_flip(args[n_flip], n_bytes); - secp256k1_nonce_function_musig(k2, args[0], args[1], args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(ctx, k2, args[0], args[1], args[2], args[3], args[4], args[5]); CHECK(secp256k1_scalar_eq(&k1[0], &k2[0]) == 0); CHECK(secp256k1_scalar_eq(&k1[1], &k2[1]) == 0); } @@ -526,6 +526,7 @@ static void musig_nonce_test(void) { int i, j; secp256k1_scalar k[6][2]; + const secp256k1_context *ctx = CTX; testrand_bytes_test(session_secrand, sizeof(session_secrand)); testrand_bytes_test(sk, sizeof(sk)); testrand_bytes_test(pk, sizeof(pk)); @@ -541,12 +542,12 @@ static void musig_nonce_test(void) { args[4] = agg_pk; args[5] = extra_input; for (i = 0; i < COUNT; i++) { - musig_nonce_bitflip(args, 0, sizeof(session_secrand)); - musig_nonce_bitflip(args, 1, sizeof(msg)); - musig_nonce_bitflip(args, 2, sizeof(sk)); - musig_nonce_bitflip(args, 3, sizeof(pk)); - musig_nonce_bitflip(args, 4, sizeof(agg_pk)); - musig_nonce_bitflip(args, 5, sizeof(extra_input)); + musig_nonce_bitflip(ctx, args, 0, sizeof(session_secrand)); + musig_nonce_bitflip(ctx, args, 1, sizeof(msg)); + musig_nonce_bitflip(ctx, args, 2, sizeof(sk)); + musig_nonce_bitflip(ctx, args, 3, sizeof(pk)); + musig_nonce_bitflip(ctx, args, 4, sizeof(agg_pk)); + musig_nonce_bitflip(ctx, args, 5, sizeof(extra_input)); } /* Check that if any argument is NULL, a different nonce is produced than if * any other argument is NULL. */ @@ -555,12 +556,12 @@ static void musig_nonce_test(void) { memcpy(pk, session_secrand, sizeof(session_secrand)); memcpy(agg_pk, session_secrand, sizeof(agg_pk)); memcpy(extra_input, session_secrand, sizeof(extra_input)); - secp256k1_nonce_function_musig(k[0], args[0], args[1], args[2], args[3], args[4], args[5]); - secp256k1_nonce_function_musig(k[1], args[0], NULL, args[2], args[3], args[4], args[5]); - secp256k1_nonce_function_musig(k[2], args[0], args[1], NULL, args[3], args[4], args[5]); - secp256k1_nonce_function_musig(k[3], args[0], args[1], args[2], NULL, args[4], args[5]); - secp256k1_nonce_function_musig(k[4], args[0], args[1], args[2], args[3], NULL, args[5]); - secp256k1_nonce_function_musig(k[5], args[0], args[1], args[2], args[3], args[4], NULL); + secp256k1_nonce_function_musig(ctx, k[0], args[0], args[1], args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(ctx, k[1], args[0], NULL, args[2], args[3], args[4], args[5]); + secp256k1_nonce_function_musig(ctx, k[2], args[0], args[1], NULL, args[3], args[4], args[5]); + secp256k1_nonce_function_musig(ctx, k[3], args[0], args[1], args[2], NULL, args[4], args[5]); + secp256k1_nonce_function_musig(ctx, k[4], args[0], args[1], args[2], args[3], NULL, args[5]); + secp256k1_nonce_function_musig(ctx, k[5], args[0], args[1], args[2], args[3], args[4], NULL); for (i = 0; i < 6; i++) { CHECK(!secp256k1_scalar_eq(&k[i][0], &k[i][1])); for (j = i+1; j < 6; j++) { @@ -574,35 +575,36 @@ static void musig_nonce_test(void) { * state. */ static void sha256_tag_test(void) { secp256k1_sha256 sha; + const secp256k1_context *ctx = CTX; { /* "KeyAgg list" */ static const unsigned char tag[] = {'K', 'e', 'y', 'A', 'g', 'g', ' ', 'l', 'i', 's', 't'}; - secp256k1_musig_keyagglist_sha256(&sha); - test_sha256_tag_midstate(&sha, tag, sizeof(tag)); + secp256k1_musig_keyagglist_sha256(ctx, &sha); + test_sha256_tag_midstate(ctx, &sha, tag, sizeof(tag)); } { /* "KeyAgg coefficient" */ static const unsigned char tag[] = {'K', 'e', 'y', 'A', 'g', 'g', ' ', 'c', 'o', 'e', 'f', 'f', 'i', 'c', 'i', 'e', 'n', 't'}; - secp256k1_musig_keyaggcoef_sha256(&sha); - test_sha256_tag_midstate(&sha, tag, sizeof(tag)); + secp256k1_musig_keyaggcoef_sha256(ctx, &sha); + test_sha256_tag_midstate(ctx, &sha, tag, sizeof(tag)); } { /* "MuSig/aux" */ static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'a', 'u', 'x' }; - secp256k1_nonce_function_musig_sha256_tagged_aux(&sha); - test_sha256_tag_midstate(&sha, tag, sizeof(tag)); + secp256k1_nonce_function_musig_sha256_tagged_aux(ctx, &sha); + test_sha256_tag_midstate(ctx, &sha, tag, sizeof(tag)); } { /* "MuSig/nonce" */ static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'n', 'o', 'n', 'c', 'e' }; - secp256k1_nonce_function_musig_sha256_tagged(&sha); - test_sha256_tag_midstate(&sha, tag, sizeof(tag)); + secp256k1_nonce_function_musig_sha256_tagged(ctx, &sha); + test_sha256_tag_midstate(ctx, &sha, tag, sizeof(tag)); } { /* "MuSig/noncecoef" */ static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'n', 'o', 'n', 'c', 'e', 'c', 'o', 'e', 'f' }; - secp256k1_musig_compute_noncehash_sha256_tagged(&sha); - test_sha256_tag_midstate(&sha, tag, sizeof(tag)); + secp256k1_musig_compute_noncehash_sha256_tagged(ctx, &sha); + test_sha256_tag_midstate(ctx, &sha, tag, sizeof(tag)); } } diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index b410b19eca..5dbb4089a5 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -13,8 +13,8 @@ /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */ -static void secp256k1_nonce_function_bip340_sha256_tagged(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); +static void secp256k1_nonce_function_bip340_sha256_tagged(const secp256k1_context *ctx, secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha, ctx ? ctx->hash_context.fn_sha256_transform : NULL); sha->s[0] = 0x46615b35ul; sha->s[1] = 0xf4bfbff7ul; sha->s[2] = 0x9f8dc671ul; @@ -29,8 +29,8 @@ static void secp256k1_nonce_function_bip340_sha256_tagged(secp256k1_sha256 *sha) /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("BIP0340/aux")||SHA256("BIP0340/aux"). */ -static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); +static void secp256k1_nonce_function_bip340_sha256_tagged_aux(const secp256k1_context *ctx, secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha, ctx ? ctx->hash_context.fn_sha256_transform : NULL); sha->s[0] = 0x24dd3219ul; sha->s[1] = 0x4eba7e70ul; sha->s[2] = 0xca0fabb9ul; @@ -49,7 +49,7 @@ static const unsigned char bip340_algo[] = {'B', 'I', 'P', '0', '3', '4', '0', ' static const unsigned char schnorrsig_extraparams_magic[4] = SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC; -static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { +static int nonce_function_bip340_impl(const secp256k1_context *ctx, unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { secp256k1_sha256 sha; unsigned char masked_key[32]; int i; @@ -59,7 +59,7 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms } if (data != NULL) { - secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha); + secp256k1_nonce_function_bip340_sha256_tagged_aux(ctx, &sha); secp256k1_sha256_write(&sha, data, 32); secp256k1_sha256_finalize(&sha, masked_key); for (i = 0; i < 32; i++) { @@ -83,9 +83,9 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms * in the spec, an optimized tagging implementation is used. */ if (algolen == sizeof(bip340_algo) && secp256k1_memcmp_var(algo, bip340_algo, algolen) == 0) { - secp256k1_nonce_function_bip340_sha256_tagged(&sha); + secp256k1_nonce_function_bip340_sha256_tagged(ctx, &sha); } else { - secp256k1_sha256_initialize_tagged(&sha, algo, algolen); + secp256k1_sha256_initialize_tagged(&sha, algo, algolen, /*fn_sha256_transform=*/ctx ? ctx->hash_context.fn_sha256_transform : NULL); } /* Hash masked-key||pk||msg using the tagged hash as per the spec */ @@ -99,12 +99,16 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms return 1; } +static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) { + return nonce_function_bip340_impl(/*ctx=*/NULL, nonce32, msg, msglen, key32, xonly_pk32, algo, algolen, data); +} + const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340 = nonce_function_bip340; /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge"). */ -static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) { - secp256k1_sha256_initialize(sha); +static void secp256k1_schnorrsig_sha256_tagged(const secp256k1_context *ctx, secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha, ctx->hash_context.fn_sha256_transform); sha->s[0] = 0x9cecba11ul; sha->s[1] = 0x23925381ul; sha->s[2] = 0x11679112ul; @@ -116,13 +120,13 @@ static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) { sha->bytes = 64; } -static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32) +static void secp256k1_schnorrsig_challenge(const secp256k1_context *ctx, secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32) { unsigned char buf[32]; secp256k1_sha256 sha; /* tagged hash(r.x, pk.x, msg) */ - secp256k1_schnorrsig_sha256_tagged(&sha); + secp256k1_schnorrsig_sha256_tagged(ctx, &sha); secp256k1_sha256_write(&sha, r32, 32); secp256k1_sha256_write(&sha, pubkey32, 32); secp256k1_sha256_write(&sha, msg, msglen); @@ -150,10 +154,6 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi ARG_CHECK(msg != NULL || msglen == 0); ARG_CHECK(keypair != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_bip340; - } - ret &= secp256k1_keypair_load(ctx, &sk, &pk, keypair); /* Because we are signing for a x-only pubkey, the secret key is negated * before signing if the point corresponding to the secret key does not @@ -164,7 +164,19 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi secp256k1_scalar_get_b32(seckey, &sk); secp256k1_fe_get_b32(pk_buf, &pk.x); - ret &= !!noncefp(nonce32, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); + + /* Compute nonce */ + if (noncefp == NULL || noncefp == secp256k1_nonce_function_bip340) { + if (ctx->hash_context.fn_sha256_transform != NULL) { + /* Use context-aware nonce function when custom SHA256 is provided */ + ret &= nonce_function_bip340_impl(ctx, nonce32, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); + } else { + ret &= secp256k1_nonce_function_bip340(nonce32, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); + } + } else { + ret &= !!noncefp(nonce32, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata); + } + secp256k1_scalar_set_b32(&k, nonce32, NULL); ret &= !secp256k1_scalar_is_zero(&k); secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret); @@ -182,7 +194,7 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi secp256k1_fe_normalize_var(&r.x); secp256k1_fe_get_b32(&sig64[0], &r.x); - secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, pk_buf); + secp256k1_schnorrsig_challenge(ctx, &e, &sig64[0], msg, msglen, pk_buf); secp256k1_scalar_mul(&e, &e, &sk); secp256k1_scalar_add(&e, &e, &k); secp256k1_scalar_get_b32(&sig64[32], &e); @@ -252,7 +264,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha /* Compute e. */ secp256k1_fe_get_b32(buf, &pk.x); - secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, buf); + secp256k1_schnorrsig_challenge(ctx, &e, &sig64[0], msg, msglen, buf); /* Compute rj = s*G + (-e)*pkj */ secp256k1_scalar_negate(&e, &e); diff --git a/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/modules/schnorrsig/tests_exhaustive_impl.h index 601b54975d..dae8f5e876 100644 --- a/src/modules/schnorrsig/tests_exhaustive_impl.h +++ b/src/modules/schnorrsig/tests_exhaustive_impl.h @@ -105,7 +105,7 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons secp256k1_scalar e; unsigned char msg32[32]; testrand256(msg32); - secp256k1_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32); + secp256k1_schnorrsig_challenge(ctx, &e, sig64, msg32, sizeof(msg32), pk32); /* Only do work if we hit a challenge we haven't tried before. */ if (!e_done[e]) { /* Iterate over the possible valid last 32 bytes in the signature. @@ -162,7 +162,7 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign while (e_count_done < EXHAUSTIVE_TEST_ORDER) { secp256k1_scalar e; testrand256(msg32); - secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]); + secp256k1_schnorrsig_challenge(ctx, &e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]); /* Only do work if we hit a challenge we haven't tried before. */ if (!e_done[e]) { secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER; diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index aeb9e8353d..8098ebb1a3 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -38,18 +38,20 @@ static void run_nonce_function_bip340_tests(void) { unsigned char *args[5]; int i; + secp256k1_context *ctx = CTX; + /* Check that hash initialized by * secp256k1_nonce_function_bip340_sha256_tagged has the expected * state. */ - secp256k1_nonce_function_bip340_sha256_tagged(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, tag, sizeof(tag)); + secp256k1_nonce_function_bip340_sha256_tagged(ctx, &sha_optimized); + test_sha256_tag_midstate(ctx, &sha_optimized, tag, sizeof(tag)); /* Check that hash initialized by * secp256k1_nonce_function_bip340_sha256_tagged_aux has the expected * state. */ - secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized); - test_sha256_tag_midstate(&sha_optimized, aux_tag, sizeof(aux_tag)); + secp256k1_nonce_function_bip340_sha256_tagged_aux(ctx, &sha_optimized); + test_sha256_tag_midstate(ctx, &sha_optimized, aux_tag, sizeof(aux_tag)); testrand256(msg); testrand256(key); @@ -162,9 +164,10 @@ static void test_schnorrsig_sha256_tagged(void) { unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'c', 'h', 'a', 'l', 'l', 'e', 'n', 'g', 'e'}; secp256k1_sha256 sha; secp256k1_sha256 sha_optimized; + secp256k1_context *ctx = CTX; - secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag)); - secp256k1_schnorrsig_sha256_tagged(&sha_optimized); + secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag), ctx->hash_context.fn_sha256_transform); + secp256k1_schnorrsig_sha256_tagged(ctx, &sha_optimized); test_sha256_eq(&sha, &sha_optimized); } @@ -803,7 +806,7 @@ static int nonce_function_overflowing(unsigned char *nonce32, const unsigned cha return 1; } -static void test_schnorrsig_sign_internal(void) { +static void test_schnorrsig_sign_with_ctx(secp256k1_context *ctx) { unsigned char sk[32]; secp256k1_xonly_pubkey pk; secp256k1_keypair keypair; @@ -813,7 +816,6 @@ static void test_schnorrsig_sign_internal(void) { unsigned char zeros64[64] = { 0 }; secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; unsigned char aux_rand[32]; - secp256k1_context *ctx = CTX; testrand256(sk); testrand256(aux_rand); @@ -850,6 +852,19 @@ static void test_schnorrsig_sign_internal(void) { CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); } +DEFINE_SHA256_TRANSFORM_PROBE(sha256_schnorrsig) +static void test_schnorrsig_sign_internal(void) { + secp256k1_context *ctx = secp256k1_context_clone(CTX); + /* Baseline run using the default SHA256 implementation */ + test_schnorrsig_sign_with_ctx(ctx); + + /* Re-run using a context-provided SHA256 transform */ + secp256k1_context_set_sha256_transform(ctx, sha256_schnorrsig); + test_schnorrsig_sign_with_ctx(ctx); + CHECK(sha256_schnorrsig_called); + secp256k1_context_destroy(ctx); +} + #define N_SIGS 3 /* Creates N_SIGS valid signatures and verifies them with verify and * verify_batch (TODO). Then flips some bits and checks that verification now diff --git a/src/secp256k1.c b/src/secp256k1.c index 6b37b12f68..8f1e1e21b0 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -19,6 +19,7 @@ #include "../include/secp256k1.h" #include "../include/secp256k1_preallocated.h" +#include "../include/secp256k1_sha.h" #include "assumptions.h" #include "checkmem.h" @@ -63,13 +64,16 @@ struct secp256k1_context_struct { secp256k1_callback illegal_callback; secp256k1_callback error_callback; int declassify; + + struct secp256k1_hash_context hash_context; }; static const secp256k1_context secp256k1_context_static_ = { { 0 }, { secp256k1_default_illegal_callback_fn, 0 }, { secp256k1_default_error_callback_fn, 0 }, - 0 + 0, + { 0 } }; const secp256k1_context * const secp256k1_context_static = &secp256k1_context_static_; const secp256k1_context * const secp256k1_context_no_precomp = &secp256k1_context_static_; @@ -129,6 +133,7 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne ret = (secp256k1_context*)prealloc; ret->illegal_callback = default_illegal_callback; ret->error_callback = default_error_callback; + ret->hash_context.fn_sha256_transform = secp256k1_sha256_transform; /* Flags have been checked by secp256k1_context_preallocated_size. */ VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT); @@ -220,6 +225,17 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co ctx->error_callback.data = data; } +void secp256k1_context_set_sha256_transform(secp256k1_context *ctx, secp256k1_fn_sha256_transform fn_sha256_transform) { + VERIFY_CHECK(ctx != NULL); + if (!fn_sha256_transform) { /* Reset function */ + ctx->hash_context.fn_sha256_transform = secp256k1_sha256_transform; + return; + } + /* Check and set */ + ARG_CHECK_VOID(secp256k1_selftest_sha256(fn_sha256_transform)); + ctx->hash_context.fn_sha256_transform = fn_sha256_transform; +} + static secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context* ctx, size_t max_size) { VERIFY_CHECK(ctx != NULL); return secp256k1_scratch_create(&ctx->error_callback, max_size); @@ -476,11 +492,12 @@ static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *off *offset += len; } -static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { +static int nonce_function_rfc6979_impl(const secp256k1_context *ctx, unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { unsigned char keydata[112]; unsigned int offset = 0; secp256k1_rfc6979_hmac_sha256 rng; unsigned int i; + secp256k1_fn_sha256_transform fn_sha256_transform = ctx ? ctx->hash_context.fn_sha256_transform : NULL; secp256k1_scalar msg; unsigned char msgmod32[32]; secp256k1_scalar_set_b32(&msg, msg32, NULL); @@ -501,9 +518,9 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m if (algo16 != NULL) { buffer_append(keydata, &offset, algo16, 16); } - secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, offset, fn_sha256_transform); for (i = 0; i <= counter; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32, fn_sha256_transform); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); @@ -512,6 +529,10 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m return 1; } +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + return nonce_function_rfc6979_impl(/*ctx=*/NULL, nonce32, msg32, key32, algo16, data, counter); +} + const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; @@ -521,6 +542,7 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc int is_sec_valid; unsigned char nonce32[32]; unsigned int count = 0; + int use_ctx_rfc6979 = 0; /* Default initialization here is important so we won't pass uninit values to the cmov in the end */ *r = secp256k1_scalar_zero; *s = secp256k1_scalar_zero; @@ -528,7 +550,12 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc *recid = 0; } if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; + /* Use context-aware nonce function when custom SHA256 is provided */ + if (ctx->hash_context.fn_sha256_transform != NULL) { + use_ctx_rfc6979 = 1; + } else { + noncefp = secp256k1_nonce_function_default; + } } /* Fail if the secret key is invalid. */ @@ -537,7 +564,11 @@ 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 (use_ctx_rfc6979) { /* Optimized version */ + ret = nonce_function_rfc6979_impl(ctx, nonce32, msg32, seckey, NULL, (void*)noncedata, count); + } else { + ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + } if (!ret) { break; } @@ -795,7 +826,7 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, ARG_CHECK(tag != NULL); ARG_CHECK(msg != NULL); - secp256k1_sha256_initialize_tagged(&sha, tag, taglen); + secp256k1_sha256_initialize_tagged(&sha, tag, taglen, ctx->hash_context.fn_sha256_transform); secp256k1_sha256_write(&sha, msg, msglen); secp256k1_sha256_finalize(&sha, hash32); secp256k1_sha256_clear(&sha); diff --git a/src/selftest.h b/src/selftest.h index d083ac9524..ce43a00b19 100644 --- a/src/selftest.h +++ b/src/selftest.h @@ -11,7 +11,7 @@ #include -static int secp256k1_selftest_sha256(void) { +static int secp256k1_selftest_sha256(secp256k1_fn_sha256_transform fn_transform) { static const char *input63 = "For this sample, this 63-byte string will be used as input data"; static const unsigned char output32[32] = { 0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, @@ -19,14 +19,15 @@ static int secp256k1_selftest_sha256(void) { }; unsigned char out[32]; secp256k1_sha256 hasher; - secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_initialize(&hasher, fn_transform); secp256k1_sha256_write(&hasher, (const unsigned char*)input63, 63); secp256k1_sha256_finalize(&hasher, out); return secp256k1_memcmp_var(out, output32, 32) == 0; } static int secp256k1_selftest_passes(void) { - return secp256k1_selftest_sha256(); + /* Use default sha256 transform */ + return secp256k1_selftest_sha256(/*fn_transform=*/NULL); } #endif /* SECP256K1_SELFTEST_H */ diff --git a/src/testrand_impl.h b/src/testrand_impl.h index b84f5730a9..f969e6e730 100644 --- a/src/testrand_impl.h +++ b/src/testrand_impl.h @@ -22,9 +22,10 @@ SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16) { unsigned char out32[32]; secp256k1_sha256 hash; int i; + const secp256k1_context *ctx = secp256k1_context_static; /* Use SHA256(PREFIX || seed16) as initial state. */ - secp256k1_sha256_initialize(&hash); + secp256k1_sha256_initialize(&hash, ctx->hash_context.fn_sha256_transform); secp256k1_sha256_write(&hash, PREFIX, sizeof(PREFIX)); secp256k1_sha256_write(&hash, seed16, 16); secp256k1_sha256_finalize(&hash, out32); diff --git a/src/tests.c b/src/tests.c index 14aa785895..408bdcd9ef 100644 --- a/src/tests.c +++ b/src/tests.c @@ -432,6 +432,53 @@ static void run_scratch_tests(void) { secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */ } +/* A compression function that does nothing */ +static void invalid_sha256_transform(uint32_t *s, const unsigned char *msg, size_t rounds) { + (void)s; (void)msg; (void)rounds; +} + +static int own_transform_called = 0; +static void good_sha256_transform(uint32_t *s, const unsigned char *msg, size_t rounds) { + own_transform_called = 1; + secp256k1_sha256_transform(s, msg, rounds); +} + +static void run_plug_sha256_transform_tests(void) { + secp256k1_context *ctx, *ctx_cloned; + secp256k1_sha256 sha; + unsigned char sha_out[32]; + /* 1) Verify the context is initialized with the default compression function */ + ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + CHECK(ctx->hash_context.fn_sha256_transform == secp256k1_sha256_transform); + + /* 2) Verify providing a bad Transform fails during set */ + CHECK_ILLEGAL_VOID(ctx, secp256k1_context_set_sha256_transform(ctx, invalid_sha256_transform)); + CHECK(ctx->hash_context.fn_sha256_transform == secp256k1_sha256_transform); + + /* 3) Provide sha256 to ctx and verify it is called when provided */ + own_transform_called = 0; + secp256k1_context_set_sha256_transform(ctx, good_sha256_transform); + CHECK(own_transform_called); + + /* 4) Verify callback makes it across clone */ + ctx_cloned = secp256k1_context_clone(ctx); + CHECK(ctx_cloned->hash_context.fn_sha256_transform == good_sha256_transform); + + /* 5) A hash operation should invoke the installed callback */ + own_transform_called = 0; + secp256k1_sha256_initialize(&sha, ctx->hash_context.fn_sha256_transform); + secp256k1_sha256_write(&sha, (const unsigned char*)"a", 1); + secp256k1_sha256_finalize(&sha, sha_out); + CHECK(own_transform_called); + + /* 6) Unset sha256 and verify the default one is set again */ + secp256k1_context_set_sha256_transform(ctx, NULL); + CHECK(ctx->hash_context.fn_sha256_transform == secp256k1_sha256_transform); + + secp256k1_context_destroy(ctx); + secp256k1_context_destroy(ctx_cloned); +} + static void run_ctz_tests(void) { static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129}; static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef}; @@ -454,6 +501,7 @@ static void run_ctz_tests(void) { /***** HASH TESTS *****/ static void run_sha256_known_output_tests(void) { + const secp256k1_context *ctx = secp256k1_context_static; static const char *inputs[] = { "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", @@ -487,7 +535,7 @@ static void run_sha256_known_output_tests(void) { unsigned int j; /* 1. Run: simply write the input bytestrings */ j = repeat[i]; - secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_initialize(&hasher, ctx->hash_context.fn_sha256_transform); while (j > 0) { secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); j--; @@ -497,7 +545,7 @@ static void run_sha256_known_output_tests(void) { /* 2. Run: split the input bytestrings randomly before writing */ if (strlen(inputs[i]) > 0) { int split = testrand_int(strlen(inputs[i])); - secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_initialize(&hasher, ctx->hash_context.fn_sha256_transform); j = repeat[i]; while (j > 0) { secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); @@ -558,33 +606,33 @@ static void run_sha256_counter_tests(void) { static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; static const secp256k1_sha256 midstates[] = { {{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda}, - {0x00}, 0xfffc0}, + {0x00}, 0xfffc0, secp256k1_sha256_transform}, {{0xa0d29445, 0x9287de66, 0x76aabd71, 0x41acd765, 0x0c7528b4, 0x84e14906, 0x942faec6, 0xcc5a7b26}, - {0x00}, 0x1fffc0}, + {0x00}, 0x1fffc0, secp256k1_sha256_transform}, {{0x50449526, 0xb9f1d657, 0xa0fc13e9, 0x50860f10, 0xa550c431, 0x3fbc97c1, 0x7bbb2d89, 0xdb67bac1}, - {0x00}, 0x3fffc0}, + {0x00}, 0x3fffc0, secp256k1_sha256_transform}, {{0x54a6efdc, 0x46762e7b, 0x88bfe73f, 0xbbd149c7, 0x41620c43, 0x1168da7b, 0x2c5960f9, 0xeccffda6}, - {0x00}, 0x7fffc0}, + {0x00}, 0x7fffc0, secp256k1_sha256_transform}, {{0x2515a8f5, 0x5faa2977, 0x3a850486, 0xac858cad, 0x7b7276ee, 0x235c0385, 0xc53a157c, 0x7cb3e69c}, - {0x00}, 0xffffc0}, + {0x00}, 0xffffc0, secp256k1_sha256_transform}, {{0x34f39828, 0x409fedb7, 0x4bbdd0fb, 0x3b643634, 0x7806bf2e, 0xe0d1b713, 0xca3f2e1e, 0xe38722c2}, - {0x00}, 0x1ffffc0}, + {0x00}, 0x1ffffc0, secp256k1_sha256_transform}, {{0x389ef5c5, 0x38c54167, 0x8f5d56ab, 0x582a75cc, 0x8217caef, 0xf10947dd, 0x6a1998a8, 0x048f0b8c}, - {0x00}, 0x3ffffc0}, + {0x00}, 0x3ffffc0, secp256k1_sha256_transform}, {{0xd6c3f394, 0x0bee43b9, 0x6783f497, 0x29fa9e21, 0x6ce491c1, 0xa81fe45e, 0x2fc3859a, 0x269012d0}, - {0x00}, 0x7ffffc0}, + {0x00}, 0x7ffffc0, secp256k1_sha256_transform}, {{0x6dd3c526, 0x44d88aa0, 0x806a1bae, 0xfbcc0d32, 0x9d6144f3, 0x9d2bd757, 0x9851a957, 0xb50430ad}, - {0x00}, 0xfffffc0}, + {0x00}, 0xfffffc0, secp256k1_sha256_transform}, {{0x2add4021, 0xdfe8a9e6, 0xa56317c6, 0x7a15f5bb, 0x4a48aacd, 0x5d368414, 0x4f00e6f0, 0xd9355023}, - {0x00}, 0x1fffffc0}, + {0x00}, 0x1fffffc0, secp256k1_sha256_transform}, {{0xb66666b4, 0xdbeac32b, 0x0ea351ae, 0xcba9da46, 0x6278b874, 0x8c508e23, 0xe16ca776, 0x8465bac1}, - {0x00}, 0x3fffffc0}, + {0x00}, 0x3fffffc0, secp256k1_sha256_transform}, {{0xb6744789, 0x9cce87aa, 0xc4c478b7, 0xf38404d8, 0x2e38ba62, 0xa3f7019b, 0x50458fe7, 0x3047dbec}, - {0x00}, 0x7fffffc0}, + {0x00}, 0x7fffffc0, secp256k1_sha256_transform}, {{0x8b1297ba, 0xba261a80, 0x2ba1b0dd, 0xfbc67d6d, 0x61072c4e, 0x4b5a2a0f, 0x52872760, 0x2dfeb162}, - {0x00}, 0xffffffc0}, + {0x00}, 0xffffffc0, secp256k1_sha256_transform}, {{0x24f33cf7, 0x41ad6583, 0x41c8ff5d, 0xca7ef35f, 0x50395756, 0x021b743e, 0xd7126cd7, 0xd037473a}, - {0x00}, 0x1ffffffc0}, + {0x00}, 0x1ffffffc0, secp256k1_sha256_transform}, }; static const unsigned char outputs[][32] = { {0x0e, 0x83, 0xe2, 0xc9, 0x4f, 0xb2, 0xb8, 0x2b, 0x89, 0x06, 0x92, 0x78, 0x04, 0x03, 0x48, 0x5c, 0x48, 0x44, 0x67, 0x61, 0x77, 0xa4, 0xc7, 0x90, 0x9e, 0x92, 0x55, 0x10, 0x05, 0xfe, 0x39, 0x15}, @@ -624,9 +672,9 @@ static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 } /* Convenience function for using test_sha256_eq to verify the correctness of a * tagged hash midstate. This function is used by some module tests. */ -static void test_sha256_tag_midstate(secp256k1_sha256 *sha_tagged, const unsigned char *tag, size_t taglen) { +static void test_sha256_tag_midstate(const secp256k1_context *ctx, secp256k1_sha256 *sha_tagged, const unsigned char *tag, size_t taglen) { secp256k1_sha256 sha; - secp256k1_sha256_initialize_tagged(&sha, tag, taglen); + secp256k1_sha256_initialize_tagged(&sha, tag, taglen, ctx->hash_context.fn_sha256_transform); test_sha256_eq(&sha, sha_tagged); } @@ -656,16 +704,17 @@ static void run_hmac_sha256_tests(void) { {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} }; int i; + const secp256k1_context *ctx = secp256k1_context_static; for (i = 0; i < 6; i++) { secp256k1_hmac_sha256 hasher; unsigned char out[32]; - secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i]), ctx->hash_context.fn_sha256_transform); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); secp256k1_hmac_sha256_finalize(&hasher, out); CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { int split = testrand_int(strlen(inputs[i])); - secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i]), ctx->hash_context.fn_sha256_transform); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); secp256k1_hmac_sha256_finalize(&hasher, out); @@ -689,27 +738,28 @@ static void run_rfc6979_hmac_sha256_tests(void) { {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} }; + secp256k1_context ctx = secp256k1_context_static_; secp256k1_rfc6979_hmac_sha256 rng; unsigned char out[32]; int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64, ctx.hash_context.fn_sha256_transform); for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32, ctx.hash_context.fn_sha256_transform); CHECK(secp256k1_memcmp_var(out, out1[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65, ctx.hash_context.fn_sha256_transform); for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32, ctx.hash_context.fn_sha256_transform); CHECK(secp256k1_memcmp_var(out, out1[i], 32) != 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64, ctx.hash_context.fn_sha256_transform); for (i = 0; i < 3; i++) { - secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32, ctx.hash_context.fn_sha256_transform); CHECK(secp256k1_memcmp_var(out, out2[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); @@ -5468,6 +5518,7 @@ static void test_ecmult_constants_2bit(void) { secp256k1_sha256 acc; unsigned char b32[32]; int i, j; + secp256k1_context ctx = secp256k1_context_static_; secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536); /* Expected hash of all the computed points; created with an independent @@ -5478,7 +5529,7 @@ static void test_ecmult_constants_2bit(void) { 0x3a, 0x75, 0x87, 0x60, 0x1a, 0xf9, 0x63, 0x60, 0xd0, 0xcb, 0x1f, 0xaa, 0x85, 0x9a, 0xb7, 0xb4 }; - secp256k1_sha256_initialize(&acc); + secp256k1_sha256_initialize(&acc, ctx.hash_context.fn_sha256_transform); for (i = 0; i <= 36; ++i) { secp256k1_scalar_set_int(&x, i); test_ecmult_accumulate(&acc, &x, scratch); @@ -5512,13 +5563,14 @@ static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsign unsigned char b32[32]; unsigned char inp[6]; size_t i; + secp256k1_context ctx = secp256k1_context_static_; secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536); inp[0] = prefix & 0xFF; inp[1] = (prefix >> 8) & 0xFF; inp[2] = (prefix >> 16) & 0xFF; inp[3] = (prefix >> 24) & 0xFF; - secp256k1_sha256_initialize(&acc); + secp256k1_sha256_initialize(&acc, ctx.hash_context.fn_sha256_transform); secp256k1_scalar_set_int(&x, 0); test_ecmult_accumulate(&acc, &x, scratch); secp256k1_scalar_set_int(&x, 1); @@ -5530,7 +5582,7 @@ static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsign secp256k1_sha256 gen; inp[4] = i & 0xff; inp[5] = (i >> 8) & 0xff; - secp256k1_sha256_initialize(&gen); + secp256k1_sha256_initialize(&gen, ctx.hash_context.fn_sha256_transform); secp256k1_sha256_write(&gen, inp, sizeof(inp)); secp256k1_sha256_finalize(&gen, b32); secp256k1_scalar_set_b32(&x, b32, NULL); @@ -7068,7 +7120,7 @@ static void run_ecdsa_der_parse(void) { } /* Tests several edge cases. */ -static void test_ecdsa_edge_cases(void) { +static void test_ecdsa_edge_cases(secp256k1_context* ctx) { int t; secp256k1_ecdsa_signature sig; @@ -7082,7 +7134,7 @@ static void test_ecdsa_edge_cases(void) { secp256k1_scalar_negate(&ss, &ss); secp256k1_scalar_inverse(&ss, &ss); secp256k1_scalar_set_int(&sr, 1); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &keyj, &sr); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr); secp256k1_ge_set_gej(&key, &keyj); msg = ss; CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); @@ -7263,42 +7315,42 @@ static void test_ecdsa_edge_cases(void) { 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, }; - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 0); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); msg[31] = 0xaa; - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, NULL, msg, key, precomputed_nonce_function, nonce2)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, NULL, key, precomputed_nonce_function, nonce2)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, msg, NULL, precomputed_nonce_function, nonce2)); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, key) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, NULL, msg, &pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, NULL, &pubkey)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, NULL)); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_verify(ctx, &sig, msg, NULL)); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); + CHECK_ILLEGAL(ctx, secp256k1_ec_pubkey_create(ctx, &pubkey, NULL)); /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey)); siglen = 72; - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, NULL, &siglen, &sig)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, NULL, &sig)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, NULL)); - CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, NULL, signature, siglen)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, &sig, NULL, siglen)); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, signature, siglen) == 1); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen)); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1); siglen = 10; /* Too little room for a signature does not fail via ARGCHECK. */ - CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 0); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_normalize(CTX, NULL, NULL)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, NULL, &sig)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, signature, NULL)); - CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, signature, &sig) == 1); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, NULL, signature)); - CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, &sig, NULL)); - CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 1); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature)); + CHECK_ILLEGAL(ctx, secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL)); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1); memset(signature, 255, 64); - CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 0); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0); } /* Nonce function corner cases. */ @@ -7315,33 +7367,33 @@ static void test_ecdsa_edge_cases(void) { msg[31] = 1; /* High key results in signature failure. */ memset(key, 0xFF, 32); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); CHECK(is_empty_signature(&sig)); /* Zero key results in signature failure. */ memset(key, 0, 32); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, NULL, extra) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); CHECK(is_empty_signature(&sig)); /* Nonce function failure results in signature failure. */ key[31] = 1; - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_fail, extra) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0); CHECK(is_empty_signature(&sig)); /* The retry loop successfully makes its way to the first good value. */ - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, nonce_function_test_retry, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1); CHECK(!is_empty_signature(&sig)); - CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); CHECK(!is_empty_signature(&sig2)); CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function is deterministic. */ - CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); CHECK(secp256k1_memcmp_var(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function changes output with different messages. */ for(i = 0; i < 256; i++) { int j; msg[0] = i; - CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); - secp256k1_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); for (j = 0; j < i; j++) { CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } @@ -7352,9 +7404,9 @@ static void test_ecdsa_edge_cases(void) { for(i = 256; i < 512; i++) { int j; key[0] = i - 256; - CHECK(secp256k1_ecdsa_sign(CTX, &sig2, msg, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); CHECK(!is_empty_signature(&sig2)); - secp256k1_ecdsa_signature_load(CTX, &sr[i], &ss, &sig2); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); for (j = 0; j < i; j++) { CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } @@ -7395,14 +7447,25 @@ static void test_ecdsa_edge_cases(void) { unsigned char privkey[300]; const unsigned char *seckey = secp256k1_group_order_bytes; size_t outlen = 300; - CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 0)); + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); outlen = 300; - CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 1)); + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1)); } } + +DEFINE_SHA256_TRANSFORM_PROBE(sha256_ecdsa) static void run_ecdsa_edge_cases(void) { - test_ecdsa_edge_cases(); + secp256k1_context *ctx = secp256k1_context_clone(CTX); + /* Baseline run using the default SHA256 implementation */ + test_ecdsa_edge_cases(ctx); + + /* Re-run using a context-provided SHA256 transform */ + secp256k1_context_set_sha256_transform(ctx, sha256_ecdsa); + test_ecdsa_edge_cases(ctx); + CHECK(sha256_ecdsa_called); + + secp256k1_context_destroy(ctx); } /** Wycheproof tests @@ -7413,6 +7476,7 @@ static void test_ecdsa_wycheproof(void) { #include "wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h" int t; + const secp256k1_context* ctx = secp256k1_context_static; for (t = 0; t < SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS; t++) { secp256k1_ecdsa_signature signature; secp256k1_sha256 hasher; @@ -7425,7 +7489,7 @@ static void test_ecdsa_wycheproof(void) { pk = &wycheproof_ecdsa_public_keys[testvectors[t].pk_offset]; CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pk, 65) == 1); - secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_initialize(&hasher, ctx->hash_context.fn_sha256_transform); msg = &wycheproof_ecdsa_messages[testvectors[t].msg_offset]; secp256k1_sha256_write(&hasher, msg, testvectors[t].msg_len); secp256k1_sha256_finalize(&hasher, out); @@ -7692,6 +7756,7 @@ static const struct tf_test_entry tests_general[] = { CASE(all_static_context_tests), CASE(deprecated_context_flags_test), CASE(scratch_tests), + CASE(plug_sha256_transform_tests), }; static const struct tf_test_entry tests_integer[] = { diff --git a/src/testutil.h b/src/testutil.h index 480f6a1a0c..6566110ad3 100644 --- a/src/testutil.h +++ b/src/testutil.h @@ -11,6 +11,14 @@ #include "testrand.h" #include "util.h" +/* Helper for when we need to check that the custom sha256 transform was called */ +#define DEFINE_SHA256_TRANSFORM_PROBE(name) \ + static int name##_called = 0; \ + static void name(uint32_t *s, const unsigned char *msg, size_t rounds) { \ + name##_called = 1; \ + secp256k1_sha256_transform(s, msg, rounds); \ + } + /* group order of the secp256k1 curve in 32-byte big endian representation */ static const unsigned char secp256k1_group_order_bytes[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,