From 7eb86bdb0154a24a627c342c7bfcc95320155779 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 20 Nov 2025 12:40:50 +0000 Subject: [PATCH 01/28] autotools: Rename `build-aux` to `autotools-aux` This change improves separation from CMake build directories, which typically use the "build" prefix. Additionally, corresponding `.gitignore` entries have been refactored. --- .gitignore | 17 +++-------------- Makefile.am | 2 +- {build-aux => autotools-aux}/m4/bitcoin_secp.m4 | 0 configure.ac | 4 ++-- src/CMakeLists.txt | 2 +- 5 files changed, 7 insertions(+), 18 deletions(-) rename {build-aux => autotools-aux}/m4/bitcoin_secp.m4 (100%) diff --git a/.gitignore b/.gitignore index ce33a84a..cae28210 100644 --- a/.gitignore +++ b/.gitignore @@ -45,20 +45,9 @@ coverage.*.html *.gcno *.gcov -build-aux/ar-lib -build-aux/config.guess -build-aux/config.sub -build-aux/depcomp -build-aux/install-sh -build-aux/ltmain.sh -build-aux/m4/libtool.m4 -build-aux/m4/lt~obsolete.m4 -build-aux/m4/ltoptions.m4 -build-aux/m4/ltsugar.m4 -build-aux/m4/ltversion.m4 -build-aux/missing -build-aux/compile -build-aux/test-driver +/autotools-aux/ +!/autotools-aux/m4/bitcoin_secp.m4 + libsecp256k1.pc ### CMake diff --git a/Makefile.am b/Makefile.am index dc798575..07d7a2ba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -ACLOCAL_AMFLAGS = -I build-aux/m4 +ACLOCAL_AMFLAGS = -I autotools-aux/m4 # AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo # which does not have an explicit foo_CFLAGS variable set. diff --git a/build-aux/m4/bitcoin_secp.m4 b/autotools-aux/m4/bitcoin_secp.m4 similarity index 100% rename from build-aux/m4/bitcoin_secp.m4 rename to autotools-aux/m4/bitcoin_secp.m4 diff --git a/configure.ac b/configure.ac index 6028ee28..36699c17 100644 --- a/configure.ac +++ b/configure.ac @@ -19,8 +19,8 @@ define(_LIB_VERSION_AGE, 0) AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) -AC_CONFIG_AUX_DIR([build-aux]) -AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CONFIG_AUX_DIR([autotools-aux]) +AC_CONFIG_MACRO_DIR([autotools-aux/m4]) AC_CANONICAL_HOST # Require Automake 1.11.2 for AM_PROG_AR diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ecbbbbe8..46db7780 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -95,7 +95,7 @@ set_target_properties(secp256k1_objs PROPERTIES ) # This emulates Libtool to make sure Libtool and CMake agree on the ABI version, -# see below "Calculate the version variables" in build-aux/ltmain.sh. +# see below "Calculate the version variables" in autotools-aux/ltmain.sh. math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}") set_target_properties(secp256k1 PROPERTIES SOVERSION ${${PROJECT_NAME}_soversion} From 748c0fdd67c646c83bd62e74a8e205e04d314e07 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 20 Nov 2025 12:42:08 +0000 Subject: [PATCH 02/28] Add CMake build directory patterns to `.gitignore` --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index cae28210..fbc311d7 100644 --- a/.gitignore +++ b/.gitignore @@ -52,8 +52,8 @@ libsecp256k1.pc ### CMake /CMakeUserPresets.json -# Default CMake build directory. -/build +# CMake build directories. +/*build* ### Python __pycache__/ From bb1d199de572ed3358a21a68f2fccd1037eee601 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 7 Jan 2026 11:30:16 +0100 Subject: [PATCH 03/28] ecmult: Use size_t for array indices into tables --- src/ecmult.h | 2 +- src/ecmult_compute_table_impl.h | 2 +- src/ecmult_impl.h | 27 ++++++++++++++------------- src/precompute_ecmult.c | 2 +- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/ecmult.h b/src/ecmult.h index 326a5eeb..8d0a9f49 100644 --- a/src/ecmult.h +++ b/src/ecmult.h @@ -38,7 +38,7 @@ #endif /** The number of entries a table with precomputed multiples needs to have. */ -#define ECMULT_TABLE_SIZE(w) (1L << ((w)-2)) +#define ECMULT_TABLE_SIZE(w) ((size_t)1 << ((w)-2)) /** Double multiply: R = na*A + ng*G */ static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); diff --git a/src/ecmult_compute_table_impl.h b/src/ecmult_compute_table_impl.h index 69d59ce5..09b899b4 100644 --- a/src/ecmult_compute_table_impl.h +++ b/src/ecmult_compute_table_impl.h @@ -16,7 +16,7 @@ static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen) { secp256k1_gej gj; secp256k1_ge ge, dgen; - int j; + size_t j; gj = *gen; secp256k1_ge_set_gej_var(&ge, &gj); diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index c421750d..4046cd4c 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -311,8 +311,9 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state * } for (np = 0; np < no; ++np) { - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i].x, &secp256k1_const_beta); + size_t j; + for (j = 0; j < ECMULT_TABLE_SIZE(WINDOW_A); j++) { + secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + j], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + j].x, &secp256k1_const_beta); } } @@ -517,7 +518,6 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi size_t np; size_t no = 0; int i; - int j; for (np = 0; np < num; ++np) { if (secp256k1_scalar_is_zero(&sc[np]) || secp256k1_ge_is_infinity(&pt[np])) { @@ -535,16 +535,17 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi for (i = n_wnaf - 1; i >= 0; i--) { secp256k1_gej running_sum; + int j; + size_t buc; - for(j = 0; j < ECMULT_TABLE_SIZE(bucket_window+2); j++) { - secp256k1_gej_set_infinity(&buckets[j]); + for (buc = 0; buc < ECMULT_TABLE_SIZE(bucket_window+2); buc++) { + secp256k1_gej_set_infinity(&buckets[buc]); } for (np = 0; np < no; ++np) { int n = state->wnaf_na[np*n_wnaf + i]; struct secp256k1_pippenger_point_state point_state = state->ps[np]; secp256k1_ge tmp; - int idx; if (i == 0) { /* correct for wnaf skew */ @@ -555,16 +556,16 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi } } if (n > 0) { - idx = (n - 1)/2; - secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL); + buc = (n - 1)/2; + secp256k1_gej_add_ge_var(&buckets[buc], &buckets[buc], &pt[point_state.input_pos], NULL); } else if (n < 0) { - idx = -(n + 1)/2; + buc = -(n + 1)/2; secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]); - secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &tmp, NULL); + secp256k1_gej_add_ge_var(&buckets[buc], &buckets[buc], &tmp, NULL); } } - for(j = 0; j < bucket_window; j++) { + for (j = 0; j < bucket_window; j++) { secp256k1_gej_double_var(r, r, NULL); } @@ -577,8 +578,8 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi * * The doubling is done implicitly by deferring the final window doubling (of 'r'). */ - for(j = ECMULT_TABLE_SIZE(bucket_window+2) - 1; j > 0; j--) { - secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[j], NULL); + for (buc = ECMULT_TABLE_SIZE(bucket_window+2) - 1; buc > 0; buc--) { + secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[buc], NULL); secp256k1_gej_add_var(r, r, &running_sum, NULL); } diff --git a/src/precompute_ecmult.c b/src/precompute_ecmult.c index 021fe394..8579c85f 100644 --- a/src/precompute_ecmult.c +++ b/src/precompute_ecmult.c @@ -20,7 +20,7 @@ #include "ecmult_compute_table_impl.h" static void print_table(FILE *fp, const char *name, int window_g, const secp256k1_ge_storage* table) { - int j; + size_t j; int i; fprintf(fp, "const secp256k1_ge_storage %s[ECMULT_TABLE_SIZE(WINDOW_G)] = {\n", name); From 47eb70959a91bbfa10dc209e8ccbe7350f5b9b04 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 7 Jan 2026 11:32:20 +0100 Subject: [PATCH 04/28] ecmult: Use size_t for array indices in _odd_multiplies_table --- src/ecmult_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index 4046cd4c..1a05244c 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -70,10 +70,10 @@ * Lastly the zr[0] value, which isn't used above, is set so that: * - a.z = z(pre_a[0]) / zr[0] */ -static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) { +static void secp256k1_ecmult_odd_multiples_table(size_t n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) { secp256k1_gej d, ai; secp256k1_ge d_ge; - int i; + size_t i; VERIFY_CHECK(!secp256k1_gej_is_infinity(a)); From 4ac651144b9a9b4f4cf144b2b067e5f73a53b68e Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:18:48 +0000 Subject: [PATCH 05/28] cmake, refactor: Deduplicate test-related code Co-authored-by: furszy --- src/CMakeLists.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ecbbbbe8..10f96c30 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -144,15 +144,16 @@ if(SECP256K1_BUILD_TESTS) list(APPEND TEST_DEFINITIONS SUPPORTS_CONCURRENCY=1) endif() - add_executable(noverify_tests tests.c) - target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm) - target_compile_definitions(noverify_tests PRIVATE ${TEST_DEFINITIONS}) - add_test(NAME secp256k1_noverify_tests COMMAND noverify_tests) + function(add_executable_and_tests exe_name verify_definition) + add_executable(${exe_name} tests.c) + target_link_libraries(${exe_name} secp256k1_precomputed secp256k1_asm) + target_compile_definitions(${exe_name} PRIVATE ${verify_definition} ${TEST_DEFINITIONS}) + add_test(NAME secp256k1_${exe_name} COMMAND ${exe_name}) + endfunction() + + add_executable_and_tests(noverify_tests "") if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage") - add_executable(tests tests.c) - target_compile_definitions(tests PRIVATE VERIFY ${TEST_DEFINITIONS}) - target_link_libraries(tests secp256k1_precomputed secp256k1_asm) - add_test(NAME secp256k1_tests COMMAND tests) + add_executable_and_tests(tests VERIFY) endif() unset(TEST_DEFINITIONS) endif() From f95b263f2366a87c7aa9e7b98882f92d6bb5caec Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:19:05 +0000 Subject: [PATCH 06/28] cmake: Add DiscoverTests module Co-authored-by: Daniel Pfeifer --- cmake/DiscoverTests.cmake | 71 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 cmake/DiscoverTests.cmake diff --git a/cmake/DiscoverTests.cmake b/cmake/DiscoverTests.cmake new file mode 100644 index 00000000..683780a8 --- /dev/null +++ b/cmake/DiscoverTests.cmake @@ -0,0 +1,71 @@ +# TODO: rework/remove once test discovery is implemented upstream: +# https://gitlab.kitware.com/cmake/cmake/-/issues/26920 +function(discover_tests target) + set(options "") + set(oneValueArgs DISCOVERY_MATCH TEST_NAME_REPLACEMENT TEST_ARGS_REPLACEMENT) + set(multiValueArgs DISCOVERY_ARGS PROPERTIES) + cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${oneValueArgs}" "${multiValueArgs}") + + set(file_base ${CMAKE_CURRENT_BINARY_DIR}/${target}) + set(include_file ${file_base}_include.cmake) + + set(properties_content) + list(LENGTH arg_PROPERTIES properties_len) + if(properties_len GREATER "0") + set(properties_content " set_tests_properties(\"\${test_name}\" PROPERTIES\n") + math(EXPR num_properties "${properties_len} / 2") + foreach(i RANGE 0 ${num_properties} 2) + math(EXPR value_index "${i} + 1") + list(GET arg_PROPERTIES ${i} name) + list(GET arg_PROPERTIES ${value_index} value) + string(APPEND properties_content " \"${name}\" \"${value}\"\n") + endforeach() + string(APPEND properties_content " )\n") + endif() + + string(CONCAT include_content + "set(runner [[$]])\n" + "set(launcher [[$]])\n" + "set(emulator [[$<$:$>]])\n" + "\n" + "execute_process(\n" + " COMMAND \${launcher} \${emulator} \${runner} ${arg_DISCOVERY_ARGS}\n" + " OUTPUT_VARIABLE output OUTPUT_STRIP_TRAILING_WHITESPACE\n" + " ERROR_VARIABLE output ERROR_STRIP_TRAILING_WHITESPACE\n" + " RESULT_VARIABLE result\n" + ")\n" + "\n" + "if(NOT result EQUAL 0)\n" + " add_test([[${target}_DISCOVERY_FAILURE]] \${launcher} \${emulator} \${runner} ${arg_DISCOVERY_ARGS})\n" + "else()\n" + " string(REPLACE \"\\n\" \";\" lines \"\${output}\")\n" + " foreach(line IN LISTS lines)\n" + " if(line MATCHES \"${arg_DISCOVERY_MATCH}\")\n" + " string(REGEX REPLACE \"${arg_DISCOVERY_MATCH}\" \"${arg_TEST_NAME_REPLACEMENT}\" test_name \"\${line}\")\n" + " string(REGEX REPLACE \"${arg_DISCOVERY_MATCH}\" \"${arg_TEST_ARGS_REPLACEMENT}\" test_args \"\${line}\")\n" + " separate_arguments(test_args)\n" + " add_test(\"\${test_name}\" \${launcher} \${emulator} \${runner} \${test_args})\n" + ${properties_content} + " endif()\n" + " endforeach()\n" + "endif()\n" + ) + + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + file(GENERATE + OUTPUT ${file_base}_include-$.cmake + CONTENT "${include_content}" + ) + file(WRITE ${include_file} + "include(\"${file_base}_include-\${CTEST_CONFIGURATION_TYPE}.cmake\")" + ) + else() + file(GENERATE + OUTPUT ${include_file} + CONTENT "${include_content}" + ) + endif() + + set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES ${include_file}) +endfunction() From 29f26ec3cfb5abf9a9ac3106c11aeb24e573fc24 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 20 Jan 2026 16:53:17 +0000 Subject: [PATCH 07/28] cmake: Integrate DiscoverTests and normalize test names Updates the build system to use the new DiscoverTests module. This also standardizes test names to use dot-separated parts for consistency. --- examples/CMakeLists.txt | 3 +-- src/CMakeLists.txt | 10 ++++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c9da9de6..86172f88 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,8 +8,7 @@ function(add_example name) secp256k1 $<$:bcrypt> ) - set(test_name ${name}_example) - add_test(NAME secp256k1_${test_name} COMMAND ${target_name}) + add_test(NAME secp256k1.example.${name} COMMAND ${target_name}) endfunction() add_example(ecdsa) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 10f96c30..6186369d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -148,7 +148,13 @@ if(SECP256K1_BUILD_TESTS) add_executable(${exe_name} tests.c) target_link_libraries(${exe_name} secp256k1_precomputed secp256k1_asm) target_compile_definitions(${exe_name} PRIVATE ${verify_definition} ${TEST_DEFINITIONS}) - add_test(NAME secp256k1_${exe_name} COMMAND ${exe_name}) + include(DiscoverTests) + discover_tests(${exe_name} + DISCOVERY_ARGS "--list_tests" + DISCOVERY_MATCH "^\\t\\\\[ *[0-9]+\\\\] ([^ ].*)$" + TEST_NAME_REPLACEMENT "secp256k1.${exe_name}.\\\\1" + TEST_ARGS_REPLACEMENT "--target=\\\\1 --log=1" + ) endfunction() add_executable_and_tests(noverify_tests "") @@ -163,7 +169,7 @@ if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) add_executable(exhaustive_tests tests_exhaustive.c) target_link_libraries(exhaustive_tests secp256k1_asm) target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) - add_test(NAME secp256k1_exhaustive_tests COMMAND exhaustive_tests) + add_test(NAME secp256k1.exhaustive_tests COMMAND exhaustive_tests) endif() if(SECP256K1_BUILD_CTIME_TESTS) From 8354618e02bcccf3893bcf0ec99639b6e520509f Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 13 Jan 2026 17:26:47 +0000 Subject: [PATCH 08/28] cmake: Set `LABELS` property for tests --- examples/CMakeLists.txt | 3 +++ src/CMakeLists.txt | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 86172f88..808917c4 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -9,6 +9,9 @@ function(add_example name) $<$:bcrypt> ) add_test(NAME secp256k1.example.${name} COMMAND ${target_name}) + set_tests_properties(secp256k1.example.${name} PROPERTIES + LABELS secp256k1_example + ) endfunction() add_example(ecdsa) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6186369d..f80573ca 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -154,6 +154,8 @@ if(SECP256K1_BUILD_TESTS) DISCOVERY_MATCH "^\\t\\\\[ *[0-9]+\\\\] ([^ ].*)$" TEST_NAME_REPLACEMENT "secp256k1.${exe_name}.\\\\1" TEST_ARGS_REPLACEMENT "--target=\\\\1 --log=1" + PROPERTIES + LABELS "secp256k1_${exe_name}" ) endfunction() @@ -170,6 +172,9 @@ if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) target_link_libraries(exhaustive_tests secp256k1_asm) target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) add_test(NAME secp256k1.exhaustive_tests COMMAND exhaustive_tests) + set_tests_properties(secp256k1.exhaustive_tests PROPERTIES + LABELS secp256k1_exhaustive + ) endif() if(SECP256K1_BUILD_CTIME_TESTS) From 1bc74a22f87dd7c3da706095a06765db1bbfc7c1 Mon Sep 17 00:00:00 2001 From: 8144225309 Date: Thu, 22 Jan 2026 10:28:30 -0500 Subject: [PATCH 09/28] test: show both Autotools and CMake usage for ctime_tests The existing message only shows the libtool command, which is specific to Autotools builds. Fixes #1697 --- src/ctime_tests.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ctime_tests.c b/src/ctime_tests.c index f81bdb92..f80042a8 100644 --- a/src/ctime_tests.c +++ b/src/ctime_tests.c @@ -49,7 +49,7 @@ int main(void) { if (!SECP256K1_CHECKMEM_RUNNING()) { fprintf(stderr, "This test can only usefully be run inside valgrind because it was not compiled under msan.\n"); - fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n"); + fprintf(stderr, "Usage: valgrind ./ctime_tests (or with Autotools: libtool --mode=execute valgrind ./ctime_tests)\n"); return EXIT_FAILURE; } ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY); From 0267b6551268deafdf22d1bdcf171ece181df88e Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Fri, 30 Jan 2026 14:32:36 +0000 Subject: [PATCH 10/28] release process: mention the `[Unreleased]` link clearly Adding this link was forgotten in the first version of the 0.7.1 release PR but caught in PR review. --- doc/release-process.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/release-process.md b/doc/release-process.md index a64bae0f..3cf183df 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -61,7 +61,7 @@ Perform these checks when reviewing the release PR (see below): 4. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that * sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`, * increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and - * adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md). + * adds an `[Unreleased]` section header and a corresponding `[Unreleased]` link at the bottom of [CHANGELOG.md](../CHANGELOG.md). If other maintainers are not present to approve the PR, it can be merged without ACKs. 5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). From 0ffb1749a5811bb63902f00c9fa73b49588d0557 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sun, 1 Feb 2026 18:51:16 +0000 Subject: [PATCH 11/28] ci, docker: Fix LLVM repository signature failure The LLVM apt repository uses legacy SHA1 signatures which are now rejected by the stricter Sequoia PGP policy. This change extends the 'sha1.second_preimage_resistance' cutoff date to 9999-01-01 in the default Sequoia config. This effectively whitelists the legacy signature algorithm, preventing "OpenPGP signature verification failed" errors during `apt-get update`. See https://github.com/llvm/llvm-project/issues/153385. --- ci/linux-debian.Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci/linux-debian.Dockerfile b/ci/linux-debian.Dockerfile index a575d9b1..a862f1b1 100644 --- a/ci/linux-debian.Dockerfile +++ b/ci/linux-debian.Dockerfile @@ -67,6 +67,9 @@ RUN \ wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \ # Add repository for this Debian release . /etc/os-release && echo "deb http://apt.llvm.org/${VERSION_CODENAME} llvm-toolchain-${VERSION_CODENAME} main" >> /etc/apt/sources.list && \ + # Temporarily work around Sequoia PGP policy deadline for legacy repositories. + # See https://github.com/llvm/llvm-project/issues/153385. + sed -i 's/\(sha1\.second_preimage_resistance =\).*/\1 9999-01-01/' /usr/share/apt/default-sequoia.config && \ apt-get update && \ # Determine the version number of the LLVM development branch LLVM_VERSION=$(apt-cache search --names-only '^clang-[0-9]+$' | sort -V | tail -1 | cut -f1 -d" " | cut -f2 -d"-" ) && \ From 2f18567d2494a3dddbec62ab414bd5784d2be3f8 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 2 Feb 2026 11:17:18 +0000 Subject: [PATCH 12/28] ci: Rotate Docker cache keys every 4 weeks This forces a periodic clean build to ensure we do not rely on stale cache layers indefinitely. --- .github/actions/run-in-docker-action/action.yml | 3 +-- .github/workflows/ci.yml | 12 ++++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/actions/run-in-docker-action/action.yml b/.github/actions/run-in-docker-action/action.yml index 5d46ca1b..0884d3a4 100644 --- a/.github/actions/run-in-docker-action/action.yml +++ b/.github/actions/run-in-docker-action/action.yml @@ -6,8 +6,7 @@ inputs: required: true scope: description: 'A cached image scope' - required: false - default: ${{ runner.arch }} + required: true command: description: 'A command to run in a container' required: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59d22514..3e74f3d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,6 +48,8 @@ jobs: docker_cache: name: "Build ${{ matrix.arch }} Docker image" runs-on: ${{ matrix.runner }} + outputs: + cache_scope: ${{ steps.cache_timestamp.outputs.period }} strategy: fail-fast: false @@ -59,6 +61,10 @@ jobs: runner: ubuntu-24.04-arm steps: + - name: Get cache validity period + id: cache_timestamp + run: echo "period=$(($(date +%V) / 4))" >> "$GITHUB_OUTPUT" + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: @@ -70,8 +76,8 @@ jobs: uses: docker/build-push-action@v6 with: file: ./ci/linux-debian.Dockerfile - cache-from: type=gha,scope=${{ runner.arch }} - cache-to: type=gha,scope=${{ runner.arch }},mode=min + cache-from: type=gha,scope=${{ runner.arch }}-${{ steps.cache_timestamp.outputs.period }} + cache-to: type=gha,scope=${{ runner.arch }}-${{ steps.cache_timestamp.outputs.period }},mode=min x86_64-debian: name: "x86_64: Linux (Debian stable)" @@ -117,6 +123,7 @@ jobs: uses: ./.github/actions/run-in-docker-action with: dockerfile: ./ci/linux-debian.Dockerfile + scope: ${{ runner.arch }}-${{ needs.docker_cache.outputs.cache_scope }} command: ./ci/ci.sh - &PRINT_LOGS @@ -636,6 +643,7 @@ jobs: uses: ./.github/actions/run-in-docker-action with: dockerfile: ./ci/linux-debian.Dockerfile + scope: ${{ runner.arch }}-${{ needs.docker_cache.outputs.cache_scope }} command: | g++ -Werror include/*.h clang -Werror -x c++-header include/*.h From 2ccff6eb73665b72cd4b2019a68f90ffcadad18c Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Mon, 2 Feb 2026 11:21:11 +0000 Subject: [PATCH 13/28] ci: Add weekly schedule --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e74f3d0..308035c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,10 @@ on: - '**' tags-ignore: - '**' + schedule: + # Run on the default branch every Monday morning. + # This also warms the Docker caches after key rotation. + - cron: '22 2 * * 1' concurrency: group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }} From 13e3bee5048fe9115e607f1065af3c82a22192ac Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 28 Jan 2026 11:10:47 +0000 Subject: [PATCH 14/28] refactor: Remove trailing whitespace --- include/secp256k1.h | 2 +- src/bench.h | 2 +- src/field.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/secp256k1.h b/include/secp256k1.h index 2799d4a1..9de45f1f 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -349,7 +349,7 @@ SECP256K1_API void secp256k1_context_destroy( * writes the message to stderr and calls abort. This default callback can be * replaced at link time if the preprocessor macro * USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build - * has been configured with --enable-external-default-callbacks (GNU Autotools) or + * has been configured with --enable-external-default-callbacks (GNU Autotools) or * -DSECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS=ON (CMake). Then the * following two symbols must be provided to link against: * - void secp256k1_default_illegal_callback_fn(const char *message, void *data); diff --git a/src/bench.h b/src/bench.h index 72a3f211..f88277aa 100644 --- a/src/bench.h +++ b/src/bench.h @@ -59,7 +59,7 @@ static void print_number(const int64_t x) { y /= 10; } } else if (c == 0) { /* fractional part is 0 */ - buffer[--ptr] = '0'; + buffer[--ptr] = '0'; } buffer[--ptr] = '.'; do { diff --git a/src/field.h b/src/field.h index e3f0234f..945029ec 100644 --- a/src/field.h +++ b/src/field.h @@ -233,7 +233,7 @@ static void secp256k1_fe_add_int(secp256k1_fe *r, int a); #define secp256k1_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, secp256k1_fe_mul_int_unchecked(r, a)) /** Like secp256k1_fe_mul_int but a is not checked to be an integer constant expression. - * + * * Should not be called directly outside of tests. */ static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a); From fb229e7602e47de1df23141838c0596a4b64aeca Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:40:41 +0000 Subject: [PATCH 15/28] build: Add `-Wtrailing-whitespace=any` compiler flag --- CMakeLists.txt | 1 + configure.ac | 1 + src/checkmem.h | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 01b14b53..4953a4b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,6 +224,7 @@ else() try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only. try_append_c_flags(-Wshadow) try_append_c_flags(-Wstrict-prototypes) + try_append_c_flags(-Wtrailing-whitespace=any) # GCC >= 15.0 try_append_c_flags(-Wundef) endif() diff --git a/configure.ac b/configure.ac index 6efb4aab..e68af3ca 100644 --- a/configure.ac +++ b/configure.ac @@ -111,6 +111,7 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only + SECP_TRY_APPEND_CFLAGS([-Wtrailing-whitespace=any], $1) # GCC >= 15.0 CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" fi diff --git a/src/checkmem.h b/src/checkmem.h index 08eae47d..88c65c8e 100644 --- a/src/checkmem.h +++ b/src/checkmem.h @@ -78,10 +78,15 @@ # if defined(__clang__) && defined(__APPLE__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wreserved-identifier" +# elif defined(__GNUC__) && (__GNUC__ >= 15) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wtrailing-whitespace" # endif # include # if defined(__clang__) && defined(__APPLE__) # pragma clang diagnostic pop +# elif defined(__GNUC__) && (__GNUC__ >= 15) +# pragma GCC diagnostic pop # endif # define SECP256K1_CHECKMEM_ENABLED 1 # define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len)) From 86cae58d2f342f8a3b49dd70dca8989cb271c504 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:43:40 +0000 Subject: [PATCH 16/28] build: Add `-Wleading-whitespace=spaces` compiler flag --- CMakeLists.txt | 1 + configure.ac | 1 + 2 files changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4953a4b4..4ef69c08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,6 +217,7 @@ else() try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0. try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only. try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions. + try_append_c_flags(-Wleading-whitespace=spaces) # GCC >= 15.0 try_append_c_flags(-Wnested-externs) try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic. try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic. diff --git a/configure.ac b/configure.ac index e68af3ca..a21447ce 100644 --- a/configure.ac +++ b/configure.ac @@ -112,6 +112,7 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only SECP_TRY_APPEND_CFLAGS([-Wtrailing-whitespace=any], $1) # GCC >= 15.0 + SECP_TRY_APPEND_CFLAGS([-Wleading-whitespace=spaces], $1) # GCC >= 15.0 CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" fi From 97b3c47849a7d124506a6208e1583ab74270188b Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Fri, 30 Jan 2026 15:58:30 +0100 Subject: [PATCH 17/28] refactor: remove unnecessary `malloc` result casts It seems that there is no good reason to do this and it's even considered bad practice, see e.g. https://stackoverflow.com/a/605858 This commit touches mostly test code, the only two functions used in production are `secp256k1_context_{create,clone}`. Instances were found manually via `$ git grep "malloc("` --- src/modules/schnorrsig/bench_impl.h | 16 ++++++++-------- src/secp256k1.c | 4 ++-- src/tests.c | 14 +++++++------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/modules/schnorrsig/bench_impl.h b/src/modules/schnorrsig/bench_impl.h index 93a878ed..069464d0 100644 --- a/src/modules/schnorrsig/bench_impl.h +++ b/src/modules/schnorrsig/bench_impl.h @@ -51,18 +51,18 @@ static void run_schnorrsig_bench(int iters, int argc, char** argv) { int d = argc == 1; data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *)); - data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); - data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); - data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *)); + data.keypairs = malloc(iters * sizeof(secp256k1_keypair *)); + data.pk = malloc(iters * sizeof(unsigned char *)); + data.msgs = malloc(iters * sizeof(unsigned char *)); + data.sigs = malloc(iters * sizeof(unsigned char *)); CHECK(MSGLEN >= 4); for (i = 0; i < iters; i++) { unsigned char sk[32]; - unsigned char *msg = (unsigned char *)malloc(MSGLEN); - unsigned char *sig = (unsigned char *)malloc(64); - secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair)); - unsigned char *pk_char = (unsigned char *)malloc(32); + unsigned char *msg = malloc(MSGLEN); + unsigned char *sig = malloc(64); + secp256k1_keypair *keypair = malloc(sizeof(*keypair)); + unsigned char *pk_char = malloc(32); secp256k1_xonly_pubkey pk; msg[0] = sk[0] = i; msg[1] = sk[1] = i >> 8; diff --git a/src/secp256k1.c b/src/secp256k1.c index ddd98495..218ceafb 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -140,7 +140,7 @@ secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigne secp256k1_context* secp256k1_context_create(unsigned int flags) { size_t const prealloc_size = secp256k1_context_preallocated_size(flags); - secp256k1_context* ctx = (secp256k1_context*)checked_malloc(&default_error_callback, prealloc_size); + secp256k1_context* ctx = checked_malloc(&default_error_callback, prealloc_size); if (EXPECT(secp256k1_context_preallocated_create(ctx, flags) == NULL, 0)) { free(ctx); return NULL; @@ -168,7 +168,7 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { ARG_CHECK(secp256k1_context_is_proper(ctx)); prealloc_size = secp256k1_context_preallocated_clone_size(ctx); - ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size); + ret = checked_malloc(&ctx->error_callback, prealloc_size); ret = secp256k1_context_preallocated_clone(ctx, ret); return ret; } diff --git a/src/tests.c b/src/tests.c index e09f5c7d..23f1dc09 100644 --- a/src/tests.c +++ b/src/tests.c @@ -3676,8 +3676,8 @@ static void test_ge(void) { * negation, and then those two again but with randomized Z coordinate. * - The same is then done for lambda*p1 and lambda^2*p1. */ - secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs)); - secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs)); + secp256k1_ge *ge = checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs)); + secp256k1_gej *gej = checked_malloc(&CTX->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs)); secp256k1_fe zf, r; secp256k1_fe zfi2, zfi3; @@ -3811,7 +3811,7 @@ static void test_ge(void) { /* Test adding all points together in random order equals infinity. */ { secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY; - secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej)); + secp256k1_gej *gej_shuffled = checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej)); for (i = 0; i < 4 * runs + 1; i++) { gej_shuffled[i] = gej[i]; } @@ -3832,8 +3832,8 @@ static void test_ge(void) { /* Test batch gej -> ge conversion without known z ratios. */ { - secp256k1_ge *ge_set_all_var = (secp256k1_ge *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); - secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); + secp256k1_ge *ge_set_all_var = checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); + secp256k1_ge *ge_set_all = checked_malloc(&CTX->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); secp256k1_ge_set_all_gej_var(&ge_set_all_var[0], &gej[0], 4 * runs + 1); for (i = 0; i < 4 * runs + 1; i++) { secp256k1_fe s; @@ -5175,8 +5175,8 @@ static void test_ecmult_multi_batch_size_helper(void) { static void test_ecmult_multi_batching(void) { static const int n_points = 2*ECMULT_PIPPENGER_THRESHOLD; secp256k1_scalar scG; - secp256k1_scalar *sc = (secp256k1_scalar *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_scalar) * n_points); - secp256k1_ge *pt = (secp256k1_ge *)checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * n_points); + secp256k1_scalar *sc = checked_malloc(&CTX->error_callback, sizeof(secp256k1_scalar) * n_points); + secp256k1_ge *pt = checked_malloc(&CTX->error_callback, sizeof(secp256k1_ge) * n_points); secp256k1_gej r; secp256k1_gej r2; ecmult_multi_data data; From 3ae72e78677eae2acc75eb0dd2b98fc59a825b29 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 3 Feb 2026 08:51:11 +0000 Subject: [PATCH 18/28] ci: Disable Docker build summary generation These summaries provide little practical value to the development workflow and clutter the CI output. --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 308035c6..432bb89a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,9 @@ env: SYMBOL_CHECK: 'yes' # Compile and run the examples. EXAMPLES: 'yes' + # Disable Docker build summary generation. + # See https://github.com/docker/build-push-action/blob/master/README.md#environment-variables. + DOCKER_BUILD_SUMMARY: false jobs: docker_cache: From 4fb7ccf5d41c6ae3f69eeee9807457e2186ae0d2 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:24:14 +0000 Subject: [PATCH 19/28] ci: Enforce base-10 evaluation --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 308035c6..78c9b94e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,7 +67,7 @@ jobs: steps: - name: Get cache validity period id: cache_timestamp - run: echo "period=$(($(date +%V) / 4))" >> "$GITHUB_OUTPUT" + run: echo "period=$((10#$(date +%V) / 4))" >> "$GITHUB_OUTPUT" - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 From f47bbc07f0a1979a9e363898c5191811f9d8def5 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 4 Feb 2026 17:35:09 +0530 Subject: [PATCH 20/28] test: add unit tests for secp256k1_scalar_check_overflow --- src/tests.c | 59 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/tests.c b/src/tests.c index e09f5c7d..b2e43eda 100644 --- a/src/tests.c +++ b/src/tests.c @@ -2193,8 +2193,58 @@ static void run_scalar_set_b32_seckey_tests(void) { CHECK(secp256k1_scalar_set_b32_seckey(&s2, b32) == 0); } +static void test_scalar_check_overflow(void) { + secp256k1_scalar s; + const secp256k1_scalar n_minus_1 = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364140UL + ); + const secp256k1_scalar n = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL + ); + const secp256k1_scalar n_plus_1 = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364142UL + ); + const secp256k1_scalar max = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + + int i; + + secp256k1_scalar_set_int(&s, 0); + CHECK(secp256k1_scalar_check_overflow(&s) == 0); + CHECK(secp256k1_scalar_check_overflow(&n_minus_1) == 0); + CHECK(secp256k1_scalar_check_overflow(&n) == 1); + CHECK(secp256k1_scalar_check_overflow(&n_plus_1) == 1); + CHECK(secp256k1_scalar_check_overflow(&max) == 1); + + for (i = 0; i < 2 * COUNT; i++) { + int expected_overflow; + int overflow = 0; + unsigned char b32[32]; + + testrand256(b32); + + /* Force top bits to be 0xFF sometimes to ensure we hit overflows */ + if (i % 2 == 0) { + memset(b32, 0xFF, 16); + } + + expected_overflow = (secp256k1_memcmp_var(b32, secp256k1_group_order_bytes, 32) >= 0); + + secp256k1_scalar_set_b32(&s, b32, &overflow); + CHECK(overflow == expected_overflow); + } +} + static void run_scalar_tests(void) { int i; + + test_scalar_check_overflow(); + for (i = 0; i < 128 * COUNT; i++) { scalar_test(); } @@ -2258,15 +2308,6 @@ static void run_scalar_tests(void) { } } - { - /* Does check_overflow check catch all ones? */ - static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL - ); - CHECK(secp256k1_scalar_check_overflow(&overflowed)); - } - { /* Static test vectors. * These were reduced from ~10^12 random vectors based on comparison-decision From c49c9be5045cfade519446d6fd707b2c36e18387 Mon Sep 17 00:00:00 2001 From: kevkevinpal Date: Fri, 23 Jan 2026 18:27:35 +0000 Subject: [PATCH 21/28] bench: Update help functions in bench and bench_internal In the bench and bench_internal help functions argv was not being passed, in this change we pass in argv[0] and use it in the help text. Additionally instead of passing all of argv in bench_ecmult we now just pass argv[0] and is used as the executable_path variable. --- src/bench.c | 10 +++++----- src/bench_ecmult.c | 10 +++++----- src/bench_internal.c | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/bench.c b/src/bench.c index a5231b71..de7fef94 100644 --- a/src/bench.c +++ b/src/bench.c @@ -12,7 +12,7 @@ #include "util.h" #include "bench.h" -static void help(int default_iters) { +static void help(const char *executable_path, int default_iters) { printf("Benchmarks the following algorithms:\n"); printf(" - ECDSA signing/verification\n"); @@ -36,7 +36,7 @@ static void help(int default_iters) { printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); printf("\n"); - printf("Usage: ./bench [args]\n"); + printf("Usage: %s [args]\n", executable_path); printf("By default, all benchmarks will be run.\n"); printf("args:\n"); printf(" help : display this help and exit\n"); @@ -189,7 +189,7 @@ int main(int argc, char** argv) { int default_iters = 20000; int iters = get_iters(default_iters); if (iters == 0) { - help(default_iters); + help(argv[0], default_iters); return EXIT_FAILURE; } @@ -197,11 +197,11 @@ int main(int argc, char** argv) { if (have_flag(argc, argv, "-h") || have_flag(argc, argv, "--help") || have_flag(argc, argv, "help")) { - help(default_iters); + help(argv[0], default_iters); return EXIT_SUCCESS; } else if (invalid_args) { fprintf(stderr, "./bench: unrecognized argument.\n\n"); - help(default_iters); + help(argv[0], default_iters); return EXIT_FAILURE; } } diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c index bcf8b431..7393730d 100644 --- a/src/bench_ecmult.c +++ b/src/bench_ecmult.c @@ -19,13 +19,13 @@ #define POINTS 32768 -static void help(char **argv, int default_iters) { +static void help(const char *executable_path, int default_iters) { printf("Benchmark EC multiplication algorithms\n"); printf("\n"); printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); printf("\n"); - printf("Usage: %s \n", argv[0]); + printf("Usage: %s [args]\n", executable_path); printf("The output shows the number of multiplied and summed points right after the\n"); printf("function name. The letter 'g' indicates that one of the points is the generator.\n"); printf("The benchmarks are divided by the number of points.\n"); @@ -314,7 +314,7 @@ int main(int argc, char **argv) { int default_iters = 10000; int iters = get_iters(default_iters); if (iters == 0) { - help(argv, default_iters); + help(argv[0], default_iters); return EXIT_FAILURE; } @@ -324,7 +324,7 @@ int main(int argc, char **argv) { if(have_flag(argc, argv, "-h") || have_flag(argc, argv, "--help") || have_flag(argc, argv, "help")) { - help(argv, default_iters); + help(argv[0], default_iters); return EXIT_SUCCESS; } else if(have_flag(argc, argv, "pippenger_wnaf")) { printf("Using pippenger_wnaf:\n"); @@ -336,7 +336,7 @@ int main(int argc, char **argv) { printf("Using simple algorithm:\n"); } else { fprintf(stderr, "%s: unrecognized argument '%s'.\n\n", argv[0], argv[1]); - help(argv, default_iters); + help(argv[0], default_iters); return EXIT_FAILURE; } } diff --git a/src/bench_internal.c b/src/bench_internal.c index 001bd25e..fe16e93a 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -18,13 +18,13 @@ #include "ecmult_impl.h" #include "bench.h" -static void help(int default_iters) { +static void help(const char *executable_path, int default_iters) { printf("Benchmarks various internal routines.\n"); printf("\n"); printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); printf("\n"); - printf("Usage: ./bench_internal [args]\n"); + printf("Usage: %s [args]\n", executable_path); printf("By default, all benchmarks will be run.\n"); printf("args:\n"); printf(" help : display this help and exit\n"); @@ -389,7 +389,7 @@ int main(int argc, char **argv) { int default_iters = 20000; int iters = get_iters(default_iters); if (iters == 0) { - help(default_iters); + help(argv[0], default_iters); return EXIT_FAILURE; } @@ -397,7 +397,7 @@ int main(int argc, char **argv) { if (have_flag(argc, argv, "-h") || have_flag(argc, argv, "--help") || have_flag(argc, argv, "help")) { - help(default_iters); + help(argv[0], default_iters); return EXIT_SUCCESS; } } From ed02466d3f9c07afc8bcd56aa9f295cfa8e3c4ed Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 13 Feb 2026 21:38:35 +0000 Subject: [PATCH 22/28] ci: Load Docker image by ID from builder step --- .github/actions/run-in-docker-action/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/run-in-docker-action/action.yml b/.github/actions/run-in-docker-action/action.yml index 0884d3a4..bbbcf324 100644 --- a/.github/actions/run-in-docker-action/action.yml +++ b/.github/actions/run-in-docker-action/action.yml @@ -44,7 +44,7 @@ runs: $(echo '${{ toJSON(env) }}' | jq -r 'keys[] | "--env \(.) "') \ --volume ${{ github.workspace }}:${{ github.workspace }} \ --workdir ${{ github.workspace }} \ - $(docker images -q | head -n1) \ + ${{ case(steps.main_builder.outcome == 'success', steps.main_builder.outputs.imageid, steps.retry_builder.outputs.imageid) }} \ bash -c " git config --global --add safe.directory ${{ github.workspace }} ${{ inputs.command }} From 307b49f1b996024d458a9b69e9df8d15b628d34a Mon Sep 17 00:00:00 2001 From: gzJx0DuTRHytnHe7P5RmMbPf3wKy2BztweVGXTf <249832636+gzJx0DuTRHytnHe7P5RmMbPf3wKy2BztweVGXTf@users.noreply.github.com> Date: Wed, 11 Feb 2026 15:35:26 +0100 Subject: [PATCH 23/28] ellswift: fix overflow flag handling in secp256k1_ellswift_xdh The secp256k1_ellswift_xdh function uses overflow = secp256k1_scalar_is_zero(&s) which overwrites the overflow flag from the preceding secp256k1_scalar_set_b32 call. This means secret keys >= the curve order are silently accepted (reduced mod n) instead of being rejected. The fix changes = to |=, matching the correct pattern already used in secp256k1_ecdh (main_impl.h, line 51). The ECDH module's test suite explicitly tests overflow rejection (passes secp256k1_group_order_bytes as a key and checks the function returns 0). The ellswift test suite has no corresponding test, which is why this went undetected. --- src/modules/ellswift/main_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/ellswift/main_impl.h b/src/modules/ellswift/main_impl.h index 096f4a3c..4a425665 100644 --- a/src/modules/ellswift/main_impl.h +++ b/src/modules/ellswift/main_impl.h @@ -564,7 +564,7 @@ int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output, /* Load private key (using one if invalid). */ secp256k1_scalar_set_b32(&s, seckey32, &overflow); - overflow = secp256k1_scalar_is_zero(&s); + overflow |= secp256k1_scalar_is_zero(&s); secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow); /* Compute shared X coordinate. */ From b99a94c3827e1b8e8505648758512eb3cf4aae03 Mon Sep 17 00:00:00 2001 From: gzJx0DuTRHytnHe7P5RmMbPf3wKy2BztweVGXTf <249832636+gzJx0DuTRHytnHe7P5RmMbPf3wKy2BztweVGXTf@users.noreply.github.com> Date: Fri, 13 Feb 2026 00:19:54 +0100 Subject: [PATCH 24/28] Add tests for bad scalar inputs in ellswift XDH --- src/modules/ellswift/tests_impl.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/modules/ellswift/tests_impl.h b/src/modules/ellswift/tests_impl.h index 4cc7f4b5..e3090411 100644 --- a/src/modules/ellswift/tests_impl.h +++ b/src/modules/ellswift/tests_impl.h @@ -460,6 +460,33 @@ void ellswift_hash_init_tests(void) { test_sha256_tag_midstate(&sha_optimized, bip324_tag, sizeof(bip324_tag)); } +void ellswift_xdh_bad_scalar_tests(void) { + unsigned char s_zero[32] = { 0 }; + unsigned char s_overflow_minus1[32] = { 0 }; + unsigned char s_overflow_plus1[32] = { 0 }; + unsigned char s_good[32] = { 0 }; + unsigned char ell_a64[64], ell_b64[64]; + unsigned char output[32]; + secp256k1_scalar rand_scalar; + + testutil_random_scalar_order(&rand_scalar); + secp256k1_scalar_get_b32(s_good, &rand_scalar); + + CHECK(secp256k1_ellswift_create(CTX, ell_a64, s_good, NULL) == 1); + + testrand256_test(ell_b64); + testrand256_test(ell_b64 + 32); + + memcpy(s_overflow_minus1, secp256k1_group_order_bytes, 32); + s_overflow_minus1[31] -= 1; + memcpy(s_overflow_plus1, secp256k1_group_order_bytes, 32); + s_overflow_plus1[31] += 1; + CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, s_zero, 0, &ellswift_xdh_hash_x32, NULL) == 0); + CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, secp256k1_group_order_bytes, 0, &ellswift_xdh_hash_x32, NULL) == 0); + CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, s_overflow_plus1, 0, &ellswift_xdh_hash_x32, NULL) == 0); + CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, s_overflow_minus1, 0, &ellswift_xdh_hash_x32, NULL) == 1); +} + /* --- Test registry --- */ static const struct tf_test_entry tests_ellswift[] = { CASE1(ellswift_encoding_test_vectors_tests), @@ -470,6 +497,7 @@ static const struct tf_test_entry tests_ellswift[] = { CASE1(ellswift_compute_shared_secret_tests), CASE1(ellswift_xdh_correctness_tests), CASE1(ellswift_hash_init_tests), + CASE1(ellswift_xdh_bad_scalar_tests), }; #endif From 76e92cfeeaf67aa3fd780f83e780b92518012c84 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Fri, 20 Feb 2026 08:42:32 +0000 Subject: [PATCH 25/28] Revert "ci, docker: Fix LLVM repository signature failure" This reverts commit 0ffb1749a5811bb63902f00c9fa73b49588d0557. --- ci/linux-debian.Dockerfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/ci/linux-debian.Dockerfile b/ci/linux-debian.Dockerfile index a862f1b1..a575d9b1 100644 --- a/ci/linux-debian.Dockerfile +++ b/ci/linux-debian.Dockerfile @@ -67,9 +67,6 @@ RUN \ wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \ # Add repository for this Debian release . /etc/os-release && echo "deb http://apt.llvm.org/${VERSION_CODENAME} llvm-toolchain-${VERSION_CODENAME} main" >> /etc/apt/sources.list && \ - # Temporarily work around Sequoia PGP policy deadline for legacy repositories. - # See https://github.com/llvm/llvm-project/issues/153385. - sed -i 's/\(sha1\.second_preimage_resistance =\).*/\1 9999-01-01/' /usr/share/apt/default-sequoia.config && \ apt-get update && \ # Determine the version number of the LLVM development branch LLVM_VERSION=$(apt-cache search --names-only '^clang-[0-9]+$' | sort -V | tail -1 | cut -f1 -d" " | cut -f2 -d"-" ) && \ From 79e9f252379d426ff4da586c9a1fcae35287587f Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Wed, 25 Feb 2026 08:42:29 +0100 Subject: [PATCH 26/28] ci: Fix leftover use of old ECMULTGENPRECISION --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f8c9734..44c2754b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -514,7 +514,7 @@ jobs: matrix: env_vars: - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } - - { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 } + - { WIDEMUL: 'int128_struct', ECMULTGENKB: 2, ECMULTWINDOW: 4 } - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } - { WIDEMUL: 'int128', RECOVERY: 'yes' } - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' } From f48b1bfa5d40a4d7303b196017d2e298520d1066 Mon Sep 17 00:00:00 2001 From: w0xlt <94266259+w0xlt@users.noreply.github.com> Date: Wed, 18 Feb 2026 15:21:54 -0800 Subject: [PATCH 27/28] hash: add midstate initializer and use it for tagged hashes Introduce secp256k1_sha256_initialize_midstate() in the hash layer and use it at all tagged-hash midstate call sites across schnorrsig, musig, and ellswift. Document the byte-counter contract at the declaration site in hash.h and add run_sha256_initialize_midstate_tests() to directly verify helper behavior against initialize_tagged. Also switch the helper to take const uint32_t state[8] to reduce argument-order risk at call sites. --- src/hash.h | 4 +++ src/hash_impl.h | 7 +++++ src/modules/ellswift/main_impl.h | 48 ++++++++++-------------------- src/modules/musig/keyagg_impl.h | 32 +++++++------------- src/modules/musig/session_impl.h | 45 ++++++++++------------------ src/modules/schnorrsig/main_impl.h | 47 ++++++++++------------------- src/tests.c | 15 +++++++++- 7 files changed, 80 insertions(+), 118 deletions(-) diff --git a/src/hash.h b/src/hash.h index 6d903ca7..43cdd60c 100644 --- a/src/hash.h +++ b/src/hash.h @@ -17,6 +17,10 @@ typedef struct { } secp256k1_sha256; static void secp256k1_sha256_initialize(secp256k1_sha256 *hash); +/* Initialize a SHA256 hash state with a precomputed midstate. + * The byte counter must be a multiple of 64, i.e., there must be no unwritten + * bytes in the buffer. */ +static void secp256k1_sha256_initialize_midstate(secp256k1_sha256 *hash, uint64_t bytes, const uint32_t state[8]); 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); diff --git a/src/hash_impl.h b/src/hash_impl.h index 43419177..da3b4660 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -40,6 +40,13 @@ static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { hash->bytes = 0; } +static void secp256k1_sha256_initialize_midstate(secp256k1_sha256 *hash, uint64_t bytes, const uint32_t state[8]) { + VERIFY_CHECK((bytes & 0x3F) == 0); + VERIFY_CHECK(state != NULL); + memcpy(hash->s, state, sizeof(hash->s)); + hash->bytes = bytes; +} + /** 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]; diff --git a/src/modules/ellswift/main_impl.h b/src/modules/ellswift/main_impl.h index 096f4a3c..2a378255 100644 --- a/src/modules/ellswift/main_impl.h +++ b/src/modules/ellswift/main_impl.h @@ -383,17 +383,11 @@ 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); - hash->s[0] = 0xd1a6524bul; - hash->s[1] = 0x028594b3ul; - hash->s[2] = 0x96e42f4eul; - hash->s[3] = 0x1037a177ul; - hash->s[4] = 0x1b8fcb8bul; - hash->s[5] = 0x56023885ul; - hash->s[6] = 0x2560ede1ul; - hash->s[7] = 0xd626b715ul; - - hash->bytes = 64; + static const uint32_t midstate[8] = { + 0xd1a6524bul, 0x028594b3ul, 0x96e42f4eul, 0x1037a177ul, + 0x1b8fcb8bul, 0x56023885ul, 0x2560ede1ul, 0xd626b715ul + }; + secp256k1_sha256_initialize_midstate(hash, 64, midstate); } int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) { @@ -427,17 +421,11 @@ 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); - hash->s[0] = 0xd29e1bf5ul; - hash->s[1] = 0xf7025f42ul; - hash->s[2] = 0x9b024773ul; - hash->s[3] = 0x094cb7d5ul; - hash->s[4] = 0xe59ed789ul; - hash->s[5] = 0x03bc9786ul; - hash->s[6] = 0x68335b35ul; - hash->s[7] = 0x4e363b53ul; - - hash->bytes = 64; + static const uint32_t midstate[8] = { + 0xd29e1bf5ul, 0xf7025f42ul, 0x9b024773ul, 0x094cb7d5ul, + 0xe59ed789ul, 0x03bc9786ul, 0x68335b35ul, 0x4e363b53ul + }; + secp256k1_sha256_initialize_midstate(hash, 64, midstate); } int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *auxrnd32) { @@ -510,17 +498,11 @@ static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsign /** 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); - hash->s[0] = 0x8c12d730ul; - hash->s[1] = 0x827bd392ul; - hash->s[2] = 0x9e4fb2eeul; - hash->s[3] = 0x207b373eul; - hash->s[4] = 0x2292bd7aul; - hash->s[5] = 0xaa5441bcul; - hash->s[6] = 0x15c3779ful; - hash->s[7] = 0xcfb52549ul; - - hash->bytes = 64; + static const uint32_t midstate[8] = { + 0x8c12d730ul, 0x827bd392ul, 0x9e4fb2eeul, 0x207b373eul, + 0x2292bd7aul, 0xaa5441bcul, 0x15c3779ful, 0xcfb52549ul + }; + secp256k1_sha256_initialize_midstate(hash, 64, midstate); } 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) { diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h index e412a27e..4eb48ddc 100644 --- a/src/modules/musig/keyagg_impl.h +++ b/src/modules/musig/keyagg_impl.h @@ -62,17 +62,11 @@ 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); - - sha->s[0] = 0xb399d5e0ul; - sha->s[1] = 0xc8fff302ul; - sha->s[2] = 0x6badac71ul; - sha->s[3] = 0x07c5b7f1ul; - sha->s[4] = 0x9701e2eful; - sha->s[5] = 0x2a72ecf8ul; - sha->s[6] = 0x201a4c7bul; - sha->s[7] = 0xab148a38ul; - sha->bytes = 64; + static const uint32_t midstate[8] = { + 0xb399d5e0ul, 0xc8fff302ul, 0x6badac71ul, 0x07c5b7f1ul, + 0x9701e2eful, 0x2a72ecf8ul, 0x201a4c7bul, 0xab148a38ul + }; + secp256k1_sha256_initialize_midstate(sha, 64, midstate); } /* Computes pks_hash = tagged_hash(pk[0], ..., pk[np-1]) */ @@ -97,17 +91,11 @@ 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); - - sha->s[0] = 0x6ef02c5aul; - sha->s[1] = 0x06a480deul; - sha->s[2] = 0x1f298665ul; - sha->s[3] = 0x1d1134f2ul; - sha->s[4] = 0x56a0b063ul; - sha->s[5] = 0x52da4147ul; - sha->s[6] = 0xf280d9d4ul; - sha->s[7] = 0x4484be15ul; - sha->bytes = 64; + static const uint32_t midstate[8] = { + 0x6ef02c5aul, 0x06a480deul, 0x1f298665ul, 0x1d1134f2ul, + 0x56a0b063ul, 0x52da4147ul, 0xf280d9d4ul, 0x4484be15ul + }; + secp256k1_sha256_initialize_midstate(sha, 64, midstate); } /* Compute KeyAgg coefficient which is constant 1 for the second pubkey and diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index 05c96310..42fcd81e 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -309,31 +309,21 @@ 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); - sha->s[0] = 0xa19e884bul; - sha->s[1] = 0xf463fe7eul; - sha->s[2] = 0x2f18f9a2ul; - sha->s[3] = 0xbeb0f9fful; - sha->s[4] = 0x0f37e8b0ul; - sha->s[5] = 0x06ebd26ful; - sha->s[6] = 0xe3b243d2ul; - sha->s[7] = 0x522fb150ul; - sha->bytes = 64; + static const uint32_t midstate[8] = { + 0xa19e884bul, 0xf463fe7eul, 0x2f18f9a2ul, 0xbeb0f9fful, + 0x0f37e8b0ul, 0x06ebd26ful, 0xe3b243d2ul, 0x522fb150ul + }; + secp256k1_sha256_initialize_midstate(sha, 64, midstate); } /* 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); - sha->s[0] = 0x07101b64ul; - sha->s[1] = 0x18003414ul; - sha->s[2] = 0x0391bc43ul; - sha->s[3] = 0x0e6258eeul; - sha->s[4] = 0x29d26b72ul; - sha->s[5] = 0x8343937eul; - sha->s[6] = 0xb7a0a4fbul; - sha->s[7] = 0xff568a30ul; - sha->bytes = 64; + static const uint32_t midstate[8] = { + 0x07101b64ul, 0x18003414ul, 0x0391bc43ul, 0x0e6258eeul, + 0x29d26b72ul, 0x8343937eul, 0xb7a0a4fbul, 0xff568a30ul + }; + secp256k1_sha256_initialize_midstate(sha, 64, midstate); } 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) { @@ -543,16 +533,11 @@ 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); - sha->s[0] = 0x2c7d5a45ul; - sha->s[1] = 0x06bf7e53ul; - sha->s[2] = 0x89be68a6ul; - sha->s[3] = 0x971254c0ul; - sha->s[4] = 0x60ac12d2ul; - sha->s[5] = 0x72846dcdul; - sha->s[6] = 0x6c81212ful; - sha->s[7] = 0xde7a2500ul; - sha->bytes = 64; + static const uint32_t midstate[8] = { + 0x2c7d5a45ul, 0x06bf7e53ul, 0x89be68a6ul, 0x971254c0ul, + 0x60ac12d2ul, 0x72846dcdul, 0x6c81212ful, 0xde7a2500ul + }; + secp256k1_sha256_initialize_midstate(sha, 64, midstate); } /* tagged_hash(aggnonce[0], aggnonce[1], agg_pk, msg) */ diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index b410b19e..21c1f412 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -14,33 +14,21 @@ /* 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); - sha->s[0] = 0x46615b35ul; - sha->s[1] = 0xf4bfbff7ul; - sha->s[2] = 0x9f8dc671ul; - sha->s[3] = 0x83627ab3ul; - sha->s[4] = 0x60217180ul; - sha->s[5] = 0x57358661ul; - sha->s[6] = 0x21a29e54ul; - sha->s[7] = 0x68b07b4cul; - - sha->bytes = 64; + static const uint32_t midstate[8] = { + 0x46615b35ul, 0xf4bfbff7ul, 0x9f8dc671ul, 0x83627ab3ul, + 0x60217180ul, 0x57358661ul, 0x21a29e54ul, 0x68b07b4cul + }; + secp256k1_sha256_initialize_midstate(sha, 64, midstate); } /* 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); - sha->s[0] = 0x24dd3219ul; - sha->s[1] = 0x4eba7e70ul; - sha->s[2] = 0xca0fabb9ul; - sha->s[3] = 0x0fa3166dul; - sha->s[4] = 0x3afbe4b1ul; - sha->s[5] = 0x4c44df97ul; - sha->s[6] = 0x4aac2739ul; - sha->s[7] = 0x249e850aul; - - sha->bytes = 64; + static const uint32_t midstate[8] = { + 0x24dd3219ul, 0x4eba7e70ul, 0xca0fabb9ul, 0x0fa3166dul, + 0x3afbe4b1ul, 0x4c44df97ul, 0x4aac2739ul, 0x249e850aul + }; + secp256k1_sha256_initialize_midstate(sha, 64, midstate); } /* algo argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340 @@ -104,16 +92,11 @@ const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340 = nonce_ /* 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); - sha->s[0] = 0x9cecba11ul; - sha->s[1] = 0x23925381ul; - sha->s[2] = 0x11679112ul; - sha->s[3] = 0xd1627e0ful; - sha->s[4] = 0x97c87550ul; - sha->s[5] = 0x003cc765ul; - sha->s[6] = 0x90f61164ul; - sha->s[7] = 0x33e9b66aul; - sha->bytes = 64; + static const uint32_t midstate[8] = { + 0x9cecba11ul, 0x23925381ul, 0x11679112ul, 0xd1627e0ful, + 0x97c87550ul, 0x003cc765ul, 0x90f61164ul, 0x33e9b66aul + }; + secp256k1_sha256_initialize_midstate(sha, 64, midstate); } static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32) diff --git a/src/tests.c b/src/tests.c index e09f5c7d..2e855790 100644 --- a/src/tests.c +++ b/src/tests.c @@ -739,6 +739,19 @@ static void run_tagged_sha256_tests(void) { CHECK(secp256k1_memcmp_var(hash32, hash_expected, sizeof(hash32)) == 0); } +static void run_sha256_initialize_midstate_tests(void) { + /* Midstate for the tagged hash with tag "sha256_midstate_test_tag". */ + static const unsigned char tag[] = "sha256_midstate_test_tag"; + static const uint32_t midstate[8] = { + 0xa9ec59eaul, 0x9b4c2ffful, 0x400821e2ul, 0x0dcf3847ul, + 0xbe7ea179ul, 0xa5772bdcul, 0x7d29bfe3ul, 0xa486b855ul + }; + secp256k1_sha256 sha; + + secp256k1_sha256_initialize_midstate(&sha, 64, midstate); + test_sha256_tag_midstate(&sha, tag, sizeof(tag) - 1); +} + /***** MODINV TESTS *****/ /* Compute the modular inverse of (odd) x mod 2^64. */ @@ -7709,6 +7722,7 @@ static const struct tf_test_entry tests_hash[] = { CASE(hmac_sha256_tests), CASE(rfc6979_hmac_sha256_tests), CASE(tagged_sha256_tests), + CASE(sha256_initialize_midstate_tests), }; static const struct tf_test_entry tests_scalar[] = { @@ -7848,4 +7862,3 @@ int main(int argc, char **argv) { if (tf_init(&tf, argc, argv) != 0) return EXIT_FAILURE; return tf_run(&tf); } - From 8d0eda07e9eae7418ce6d23f904faca3ddfb0eb0 Mon Sep 17 00:00:00 2001 From: Tim Ruffing Date: Mon, 2 Mar 2026 15:06:39 +0100 Subject: [PATCH 28/28] testrand: Remove testrand_finish This removes printing of the "random run = " at the end of the tests. I haven't seen a single case where this proved to be useful. And as of 48789dafc2a866bbc639184f0387637c0decb8c5, this is anyway printed only at the end of the exhaustive tests and not the normal tests, so the probability that this will be useful in the future is very low. --- src/testrand.h | 3 --- src/testrand_impl.h | 6 ------ src/tests_exhaustive.c | 2 -- 3 files changed, 11 deletions(-) diff --git a/src/testrand.h b/src/testrand.h index 3c1ed3d4..215b6fc7 100644 --- a/src/testrand.h +++ b/src/testrand.h @@ -42,7 +42,4 @@ static void testrand_flip(unsigned char *b, size_t len); /** Initialize the test RNG using (hex encoded) array up to 16 bytes, or randomly if hexseed is NULL. */ static void testrand_init(const char* hexseed); -/** Print final test information. */ -static void testrand_finish(void); - #endif /* SECP256K1_TESTRAND_H */ diff --git a/src/testrand_impl.h b/src/testrand_impl.h index b84f5730..6d9fd63a 100644 --- a/src/testrand_impl.h +++ b/src/testrand_impl.h @@ -158,10 +158,4 @@ static void testrand_init(const char* hexseed) { testrand_seed(seed16); } -static void testrand_finish(void) { - unsigned char run32[32]; - testrand256(run32); - printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); -} - #endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index 13bda611..68d4bec3 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -459,8 +459,6 @@ int main(int argc, char** argv) { secp256k1_context_destroy(ctx); } - testrand_finish(); - printf("no problems found\n"); return EXIT_SUCCESS; }