Squashed 'src/secp256k1/' changes from 57315a6985..7262adb4b4
What changed, and why it matters
This is a routine subtree update that pulls in many upstream libsecp256k1 changes. The most notable user-visible change is a new API that lets callers replace the internal SHA256 compression function with a custom one (for example, a hardware-accelerated version). The update also fixes a small bug in the EllSwift ECDH helper where an all-zero secret key was not always rejected, and it adds several code-quality and test improvements. There is no evidence in the commit message or diff of an undisclosed security vulnerability being patched.
Review the new pluggable SHA256 API for correct use in downstream code; ensure any custom compression function is audited and constant-time where required. Verify that the EllSwift scalar fix and ECDSA VERIFY_CHECK do not break existing tests or consensus-critical behavior. Treat this as a normal dependency update, not as an emergency security patch, unless additional vendor guidance is published.
Security signals we found
New API allows runtime replacement of SHA256 compression function (pluggable crypto primitive).
EllSwift XDH scalar validation fix: zero/overflow scalar handling now uses bitwise-OR to avoid masking zero scalar with overflow flag.
ECDSA verification adds VERIFY_CHECK for field-element deserialization range.
Tagged-hash midstate initialization refactored into a dedicated helper with VERIFY_CHECK on byte alignment.
No CVE, advisory, or vendor security disclosure referenced in commit or diff.
Evidence from the diff
The commit squashes upstream libsecp256k1 changes into Bitcoin Core’s src/secp256k1 subtree. Key technical changes observed in the diff: (1) introduction of a pluggable SHA256 compression function via secp256k1_context_set_sha256_compression() and a per-context secp256k1_hash_ctx; (2) propagation of that hash context through SHA256, HMAC-SHA256, RFC6979, ECDH, EllSwift, MuSig, and Schnorr signature code paths; (3) replacement of hand-rolled tagged-hash midstate initialization with a new secp256k1_sha256_initialize_midstate() helper; (4) a bug fix in secp256k1_ellswift_xdh() changing overflow = secp256k1_scalar_is_zero(&s) to overflow |= secp256k1_scalar_is_zero(&s) so that a zero scalar is not masked by a previous overflow condition, plus new tests for bad scalar inputs; (5) an ECDSA verification VERIFY_CHECK added around secp256k1_fe_set_b32_limit; (6) build/CI/test cleanups including ARRAY_SIZE macro, malloc cast removal, GitHub Actions version bumps, and dynamic test discovery. The commit does not describe any of these as security fixes except implicitly through the VERIFY_CHECK and the EllSwift scalar-handling fix.
Changed components
src/secp256k1/include/secp256k1.hsrc/secp256k1/src/hash.hsrc/secp256k1/src/hash_impl.hsrc/secp256k1/src/secp256k1.csrc/secp256k1/src/ecdsa_impl.hsrc/secp256k1/src/eckey_impl.hsrc/secp256k1/src/ecmult*.hsrc/secp256k1/src/modules/ecdh/main_impl.hsrc/secp256k1/src/modules/ellswift/main_impl.hsrc/secp256k1/src/modules/musig/*.hsrc/secp256k1/src/modules/schnorrsig/main_impl.hBitcoin Core's libsecp256k1 subtreeInspect captured patch +1052 / −512
diff --git a/.github/actions/install-homebrew-valgrind/action.yml b/.github/actions/install-homebrew-valgrind/action.yml
index ce10eb26..e9aa6150 100644
--- a/.github/actions/install-homebrew-valgrind/action.yml
+++ b/.github/actions/install-homebrew-valgrind/action.yml
@@ -16,7 +16,7 @@ runs:
cat valgrind_fingerprint
shell: bash
- - uses: actions/cache@v4
+ - uses: actions/cache@v5
id: cache
with:
path: ${{ env.CI_HOMEBREW_CELLAR_VALGRIND }}
diff --git a/.github/actions/run-in-docker-action/action.yml b/.github/actions/run-in-docker-action/action.yml
index 0884d3a4..f0eb9810 100644
--- a/.github/actions/run-in-docker-action/action.yml
+++ b/.github/actions/run-in-docker-action/action.yml
@@ -13,9 +13,9 @@ inputs:
runs:
using: "composite"
steps:
- - uses: docker/setup-buildx-action@v3
+ - uses: docker/setup-buildx-action@v4
- - uses: docker/build-push-action@v6
+ - uses: docker/build-push-action@v7
id: main_builder
continue-on-error: true
with:
@@ -24,7 +24,7 @@ runs:
load: true
cache-from: type=gha,scope=${{ inputs.scope }}
- - uses: docker/build-push-action@v6
+ - uses: docker/build-push-action@v7
id: retry_builder
if: steps.main_builder.outcome == 'failure'
with:
@@ -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 }}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 308035c6..152f9a1f 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:
@@ -67,17 +70,17 @@ 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
+ uses: docker/setup-buildx-action@v4
with:
# See: https://github.com/moby/buildkit/issues/3969.
driver-opts: |
network=host
- name: Build container
- uses: docker/build-push-action@v6
+ uses: docker/build-push-action@v7
with:
file: ./ci/linux-debian.Dockerfile
cache-from: type=gha,scope=${{ runner.arch }}-${{ steps.cache_timestamp.outputs.period }}
@@ -511,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' }
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"-" ) && \
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 [[$<TARGET_FILE:${target}>]])\n"
+ "set(launcher [[$<TARGET_PROPERTY:${target},TEST_LAUNCHER>]])\n"
+ "set(emulator [[$<$<BOOL:${CMAKE_CROSSCOMPILING}>:$<TARGET_PROPERTY:${target},CROSSCOMPILING_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-$<CONFIG>.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()
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index c9da9de6..808917c4 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -8,8 +8,10 @@ function(add_example name)
secp256k1
$<$<PLATFORM_ID:Windows>:bcrypt>
)
- set(test_name ${name}_example)
- add_test(NAME secp256k1_${test_name} COMMAND ${target_name})
+ 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/include/secp256k1.h b/include/secp256k1.h
index 9de45f1f..b7ec6a22 100644
--- a/include/secp256k1.h
+++ b/include/secp256k1.h
@@ -6,6 +6,7 @@ extern "C" {
#endif
#include <stddef.h>
+#include <stdint.h>
/** Unless explicitly stated all pointer arguments must not be NULL.
*
@@ -404,6 +405,46 @@ SECP256K1_API void secp256k1_context_set_error_callback(
const void *data
) SECP256K1_ARG_NONNULL(1);
+/** A pointer to a function implementing SHA256's internal compression function.
+ *
+ * This function processes one or more contiguous 64-byte message blocks and
+ * updates the internal SHA256 state accordingly. The function is not responsible
+ * for counting consumed blocks or bytes, nor for performing padding.
+ *
+ * In/Out: state: pointer to eight 32-bit words representing the current internal state;
+ * the state is updated in place.
+ * In: blocks64: pointer to concatenation of n_blocks blocks, of 64 bytes each.
+ * no alignment guarantees are made for this pointer.
+ * n_blocks: number of contiguous 64-byte blocks to process.
+ */
+typedef void (*secp256k1_sha256_compression_function)(
+ uint32_t *state,
+ const unsigned char *blocks64,
+ size_t n_blocks
+);
+
+/**
+ * Set a callback function to override the internal SHA256 compression function.
+ *
+ * This installs a function to replace the built-in block-compression
+ * step used by the library's internal SHA256 implementation.
+ * The provided callback must exactly implement the effect of n_blocks
+ * repeated applications of the SHA256 compression function.
+ *
+ * This API exists to support environments that wish to route the
+ * SHA256 compression step through a hardware-accelerated or otherwise
+ * specialized implementation. It is NOT meant for replacing SHA256
+ * with a different hash function.
+ *
+ * Args: ctx: pointer to a context object.
+ * In: fn_compression: pointer to a function implementing the compression function;
+ * passing NULL restores the default implementation.
+ */
+SECP256K1_API void secp256k1_context_set_sha256_compression(
+ secp256k1_context *ctx,
+ secp256k1_sha256_compression_function fn_compression
+) 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/CMakeLists.txt b/src/CMakeLists.txt
index 46db7780..322f1987 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -144,15 +144,24 @@ 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})
+ 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"
+ PROPERTIES
+ LABELS "secp256k1_${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()
@@ -162,7 +171,10 @@ 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 $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
- add_test(NAME secp256k1_exhaustive_tests COMMAND exhaustive_tests)
+ 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)
diff --git a/src/bench.c b/src/bench.c
index a5231b71..f561ad1c 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");
@@ -183,13 +183,12 @@ int main(int argc, char** argv) {
"ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec",
"keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode",
"ellswift_decode", "ellswift_keygen", "ellswift_ecdh"};
- size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]);
- int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size);
+ int invalid_args = have_invalid_args(argc, argv, valid_args, ARRAY_SIZE(valid_args));
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 +196,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..eb546db4 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 <help|pippenger_wnaf|strauss_wnaf|simple>\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");
@@ -259,7 +259,7 @@ static void bench_ecmult_multi_teardown(void* arg, int iters) {
}
}
-static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
+static void generate_scalar(const secp256k1_context *ctx, uint32_t num, secp256k1_scalar* scalar) {
secp256k1_sha256 sha256;
unsigned char c[10] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0};
unsigned char buf[32];
@@ -269,8 +269,8 @@ static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
c[8] = num >> 16;
c[9] = num >> 24;
secp256k1_sha256_initialize(&sha256);
- secp256k1_sha256_write(&sha256, c, sizeof(c));
- secp256k1_sha256_finalize(&sha256, buf);
+ secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha256, c, sizeof(c));
+ secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha256, buf);
secp256k1_scalar_set_b32(scalar, buf, &overflow);
CHECK(!overflow);
}
@@ -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;
}
}
@@ -362,7 +362,7 @@ int main(int argc, char **argv) {
secp256k1_gej_set_ge(&data.pubkeys_gej[0], &secp256k1_ge_const_g);
secp256k1_scalar_set_int(&data.seckeys[0], 1);
for (i = 0; i < POINTS; ++i) {
- generate_scalar(i, &data.scalars[i]);
+ generate_scalar(data.ctx, i, &data.scalars[i]);
if (i) {
secp256k1_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL);
secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]);
diff --git a/src/bench_internal.c b/src/bench_internal.c
index 001bd25e..f3c1be98 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");
@@ -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]);
@@ -344,11 +348,12 @@ static void bench_sha256(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_sha256 sha;
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(data->ctx);
for (i = 0; i < iters; i++) {
secp256k1_sha256_initialize(&sha);
- secp256k1_sha256_write(&sha, data->data, 32);
- secp256k1_sha256_finalize(&sha, data->data);
+ secp256k1_sha256_write(hash_ctx, &sha, data->data, 32);
+ secp256k1_sha256_finalize(hash_ctx, &sha, data->data);
}
}
@@ -356,11 +361,12 @@ static void bench_hmac_sha256(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_hmac_sha256 hmac;
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(data->ctx);
for (i = 0; i < iters; i++) {
- secp256k1_hmac_sha256_initialize(&hmac, data->data, 32);
- secp256k1_hmac_sha256_write(&hmac, data->data, 32);
- secp256k1_hmac_sha256_finalize(&hmac, data->data);
+ secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, data->data, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, data->data, 32);
+ secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, data->data);
}
}
@@ -368,10 +374,11 @@ static void bench_rfc6979_hmac_sha256(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_rfc6979_hmac_sha256 rng;
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(data->ctx);
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(hash_ctx, &rng, data->data, 64);
+ secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, data->data, 32);
}
}
@@ -389,7 +396,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 +404,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;
}
}
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);
diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h
index ce36e85e..163539eb 100644
--- a/src/ecdsa_impl.h
+++ b/src/ecdsa_impl.h
@@ -196,6 +196,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
unsigned char c[32];
secp256k1_scalar sn, u1, u2;
#if !defined(EXHAUSTIVE_TEST_ORDER)
+ int range;
secp256k1_fe xr;
#endif
secp256k1_gej pubkeyj;
@@ -226,9 +227,16 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
return secp256k1_scalar_eq(sigr, &computed_r);
}
#else
+
+ /* Interpret sigr as a field element xr */
secp256k1_scalar_get_b32(c, sigr);
- /* we can ignore the fe_set_b32_limit return value, because we know the input is in range */
- (void)secp256k1_fe_set_b32_limit(&xr, c);
+ range = secp256k1_fe_set_b32_limit(&xr, c);
+#ifdef VERIFY
+ /* We know that c is in range; it comes from a scalar. */
+ VERIFY_CHECK(range);
+#else
+ (void)range;
+#endif
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
* in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),
diff --git a/src/eckey_impl.h b/src/eckey_impl.h
index 48745e8f..57024e40 100644
--- a/src/eckey_impl.h
+++ b/src/eckey_impl.h
@@ -86,7 +86,7 @@ static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_s
}
secp256k1_gej_set_ge(&pt, key);
- secp256k1_ecmult(&pt, &pt, tweak, &secp256k1_scalar_zero);
+ secp256k1_ecmult(&pt, &pt, tweak, NULL);
secp256k1_ge_set_gej(key, &pt);
return 1;
}
diff --git a/src/ecmult.h b/src/ecmult.h
index 8d0a9f49..342195d9 100644
--- a/src/ecmult.h
+++ b/src/ecmult.h
@@ -40,7 +40,10 @@
/** The number of entries a table with precomputed multiples needs to have. */
#define ECMULT_TABLE_SIZE(w) ((size_t)1 << ((w)-2))
-/** Double multiply: R = na*A + ng*G */
+/** Double multiply: R = na*A + ng*G
+ *
+ * Passing NULL as ng is equivalent to the zero scalar but a tiny bit faster.
+ */
static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data);
diff --git a/src/ecmult_gen.h b/src/ecmult_gen.h
index 43dd10c3..8bc4f14c 100644
--- a/src/ecmult_gen.h
+++ b/src/ecmult_gen.h
@@ -7,6 +7,7 @@
#ifndef SECP256K1_ECMULT_GEN_H
#define SECP256K1_ECMULT_GEN_H
+#include "hash.h"
#include "scalar.h"
#include "group.h"
@@ -132,12 +133,12 @@ typedef struct {
secp256k1_fe proj_blind;
} secp256k1_ecmult_gen_context;
-static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx);
+static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_hash_ctx *hash_ctx);
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);
/** Multiply with the generator: R = a*G */
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a);
-static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32);
+static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32);
#endif /* SECP256K1_ECMULT_GEN_H */
diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h
index 2159eed5..5a954977 100644
--- a/src/ecmult_gen_impl.h
+++ b/src/ecmult_gen_impl.h
@@ -14,8 +14,8 @@
#include "hash_impl.h"
#include "precomputed_ecmult_gen.h"
-static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx) {
- secp256k1_ecmult_gen_blind(ctx, NULL);
+static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx) {
+ secp256k1_ecmult_gen_blind(ctx, hash_ctx, NULL);
ctx->built = 1;
}
@@ -282,7 +282,7 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
}
/* Setup blinding values for secp256k1_ecmult_gen. */
-static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) {
+static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32) {
secp256k1_scalar b;
secp256k1_scalar diff;
secp256k1_gej gb;
@@ -309,17 +309,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(hash_ctx, &rng, keydata, 64);
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(hash_ctx, &rng, nonce32, 32);
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(hash_ctx, &rng, nonce32, 32);
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 6d903ca7..79d97671 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -10,6 +10,12 @@
#include <stdlib.h>
#include <stdint.h>
+typedef struct {
+ secp256k1_sha256_compression_function fn_sha256_compression;
+} secp256k1_hash_ctx;
+
+static void secp256k1_hash_ctx_init(secp256k1_hash_ctx *hash_ctx);
+
typedef struct {
uint32_t s[8];
unsigned char buf[64];
@@ -17,17 +23,21 @@ typedef struct {
} secp256k1_sha256;
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
-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);
+/* 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(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *data, size_t size);
+static void secp256k1_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, unsigned char *out32);
static void secp256k1_sha256_clear(secp256k1_sha256 *hash);
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_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_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size);
+static void secp256k1_hmac_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size);
+static void secp256k1_hmac_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, unsigned char *out32);
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash);
typedef struct {
@@ -36,8 +46,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(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen);
+static void secp256k1_rfc6979_hmac_sha256_generate(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen);
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 43419177..7c40f82e 100644
--- a/src/hash_impl.h
+++ b/src/hash_impl.h
@@ -40,8 +40,15 @@ 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) {
+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;
@@ -123,26 +130,52 @@ static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) {
s[7] += h;
}
-static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) {
+static void secp256k1_sha256_transform(uint32_t *state, const unsigned char *blocks64, size_t n_blocks) {
+ while (n_blocks--) {
+ secp256k1_sha256_transform_impl(state, blocks64);
+ blocks64 += 64;
+ }
+}
+
+static void secp256k1_hash_ctx_init(secp256k1_hash_ctx *hash_ctx) {
+ VERIFY_CHECK(hash_ctx != NULL);
+ hash_ctx->fn_sha256_compression = secp256k1_sha256_transform;
+}
+
+static void secp256k1_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *data, size_t len) {
+ size_t chunk_len;
size_t bufsize = hash->bytes & 0x3F;
hash->bytes += len;
VERIFY_CHECK(hash->bytes >= len);
- while (len >= 64 - bufsize) {
- /* Fill the buffer, and process it. */
- size_t chunk_len = 64 - bufsize;
+ VERIFY_CHECK(hash_ctx != NULL);
+ VERIFY_CHECK(hash_ctx->fn_sha256_compression != NULL);
+
+ /* If we exceed the 64-byte block size with this input, process it and wipe the buffer */
+ chunk_len = 64 - bufsize;
+ if (bufsize && len >= chunk_len) {
memcpy(hash->buf + bufsize, data, chunk_len);
data += chunk_len;
len -= chunk_len;
- secp256k1_sha256_transform(hash->s, hash->buf);
+ hash_ctx->fn_sha256_compression(hash->s, hash->buf, 1);
bufsize = 0;
}
+
+ /* If we still have data to process, invoke compression directly on the input */
+ if (len >= 64) {
+ const size_t n_blocks = len / 64;
+ const size_t advance = n_blocks * 64;
+ hash_ctx->fn_sha256_compression(hash->s, data, n_blocks);
+ data += advance;
+ len -= advance;
+ }
+
+ /* Fill the buffer with what remains */
if (len) {
- /* Fill the buffer with what remains. */
memcpy(hash->buf + bufsize, data, len);
}
}
-static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
+static void secp256k1_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, unsigned char *out32) {
static const unsigned char pad[64] = {0x80};
unsigned char sizedesc[8];
int i;
@@ -150,8 +183,8 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out
VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61));
secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29);
secp256k1_write_be32(&sizedesc[4], hash->bytes << 3);
- secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
- secp256k1_sha256_write(hash, sizedesc, 8);
+ secp256k1_sha256_write(hash_ctx, hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
+ secp256k1_sha256_write(hash_ctx, hash, sizedesc, 8);
for (i = 0; i < 8; i++) {
secp256k1_write_be32(&out32[4*i], hash->s[i]);
hash->s[i] = 0;
@@ -160,22 +193,22 @@ 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(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) {
unsigned char buf[32];
secp256k1_sha256_initialize(hash);
- secp256k1_sha256_write(hash, tag, taglen);
- secp256k1_sha256_finalize(hash, buf);
+ secp256k1_sha256_write(hash_ctx, hash, tag, taglen);
+ secp256k1_sha256_finalize(hash_ctx, hash, buf);
secp256k1_sha256_initialize(hash);
- secp256k1_sha256_write(hash, buf, 32);
- secp256k1_sha256_write(hash, buf, 32);
+ secp256k1_sha256_write(hash_ctx, hash, buf, 32);
+ secp256k1_sha256_write(hash_ctx, hash, buf, 32);
}
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(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
size_t n;
unsigned char rkey[64];
if (keylen <= sizeof(rkey)) {
@@ -184,8 +217,8 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const
} else {
secp256k1_sha256 sha256;
secp256k1_sha256_initialize(&sha256);
- secp256k1_sha256_write(&sha256, key, keylen);
- secp256k1_sha256_finalize(&sha256, rkey);
+ secp256k1_sha256_write(hash_ctx, &sha256, key, keylen);
+ secp256k1_sha256_finalize(hash_ctx, &sha256, rkey);
memset(rkey + 32, 0, 32);
}
@@ -193,33 +226,33 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const
for (n = 0; n < sizeof(rkey); n++) {
rkey[n] ^= 0x5c;
}
- secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey));
+ secp256k1_sha256_write(hash_ctx, &hash->outer, rkey, sizeof(rkey));
secp256k1_sha256_initialize(&hash->inner);
for (n = 0; n < sizeof(rkey); n++) {
rkey[n] ^= 0x5c ^ 0x36;
}
- secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey));
+ secp256k1_sha256_write(hash_ctx, &hash->inner, rkey, sizeof(rkey));
secp256k1_memclear_explicit(rkey, sizeof(rkey));
}
-static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
- secp256k1_sha256_write(&hash->inner, data, size);
+static void secp256k1_hmac_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
+ secp256k1_sha256_write(hash_ctx, &hash->inner, data, size);
}
-static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) {
+static void secp256k1_hmac_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, unsigned char *out32) {
unsigned char temp[32];
- secp256k1_sha256_finalize(&hash->inner, temp);
- secp256k1_sha256_write(&hash->outer, temp, 32);
+ secp256k1_sha256_finalize(hash_ctx, &hash->inner, temp);
+ secp256k1_sha256_write(hash_ctx, &hash->outer, temp, 32);
secp256k1_memclear_explicit(temp, sizeof(temp));
- secp256k1_sha256_finalize(&hash->outer, out32);
+ secp256k1_sha256_finalize(hash_ctx, &hash->outer, out32);
}
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(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
secp256k1_hmac_sha256 hmac;
static const unsigned char zero[1] = {0x00};
static const unsigned char one[1] = {0x01};
@@ -228,47 +261,47 @@ 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_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_write(&hmac, rng->v, 32);
- secp256k1_hmac_sha256_finalize(&hmac, rng->v);
+ secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, zero, 1);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, key, keylen);
+ secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k);
+ secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
+ secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
/* RFC6979 3.2.f. */
- secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
- 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_write(&hmac, rng->v, 32);
- secp256k1_hmac_sha256_finalize(&hmac, rng->v);
+ secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, one, 1);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, key, keylen);
+ secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k);
+ secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
+ secp256k1_hmac_sha256_finalize(hash_ctx, &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(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) {
/* 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_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_write(&hmac, rng->v, 32);
- secp256k1_hmac_sha256_finalize(&hmac, rng->v);
+ secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, zero, 1);
+ secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k);
+ secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
+ secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
}
while (outlen > 0) {
secp256k1_hmac_sha256 hmac;
size_t now = outlen;
- secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
- secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
- secp256k1_hmac_sha256_finalize(&hmac, rng->v);
+ secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
+ secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
+ secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
if (now > 32) {
now = 32;
}
diff --git a/src/modules/ecdh/main_impl.h b/src/modules/ecdh/main_impl.h
index 9f2dfdd5..b0359b2c 100644
--- a/src/modules/ecdh/main_impl.h
+++ b/src/modules/ecdh/main_impl.h
@@ -10,20 +10,24 @@
#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_hash_ctx *hash_ctx, unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
unsigned char version = (y32[31] & 0x01) | 0x02;
secp256k1_sha256 sha;
(void)data;
secp256k1_sha256_initialize(&sha);
- secp256k1_sha256_write(&sha, &version, 1);
- secp256k1_sha256_write(&sha, x32, 32);
- secp256k1_sha256_finalize(&sha, output);
+ secp256k1_sha256_write(hash_ctx, &sha, &version, 1);
+ secp256k1_sha256_write(hash_ctx, &sha, x32, 32);
+ secp256k1_sha256_finalize(hash_ctx, &sha, output);
secp256k1_sha256_clear(&sha);
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(secp256k1_get_hash_context(secp256k1_context_static), 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 +45,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 +60,12 @@ 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) {
+ /* Use ctx-aware function by default */
+ ret = ecdh_hash_function_sha256_impl(secp256k1_get_hash_context(ctx), 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 cb1d953d..c75ce9ff 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;
@@ -83,13 +84,37 @@ static void test_ecdh_generator_basepoint(void) {
/* 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_write(&sha, point_ser, point_ser_len);
- secp256k1_sha256_finalize(&sha, output_ser);
+ secp256k1_sha256_write(secp256k1_get_hash_context(CTX), &sha, point_ser, point_ser_len);
+ secp256k1_sha256_finalize(secp256k1_get_hash_context(CTX), &sha, output_ser);
/* compare */
CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0);
}
}
+DEFINE_SHA256_TRANSFORM_PROBE(sha256_ecdh)
+static void test_ecdh_ctx_sha256(void) {
+ /* Check ctx-provided SHA256 compression override takes effect */
+ secp256k1_context *ctx = secp256k1_context_clone(CTX);
+ unsigned char out_default[65], out_custom[65];
+ const unsigned char sk[32] = {1};
+ secp256k1_pubkey pubkey;
+ CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, sk) == 1);
+
+ /* Default behavior */
+ CHECK(secp256k1_ecdh(ctx, out_default, &pubkey, sk, NULL, NULL) == 1);
+ CHECK(!sha256_ecdh_called);
+
+ /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */
+ ctx->hash_ctx.fn_sha256_compression = sha256_ecdh;
+ CHECK(secp256k1_ecdh(ctx, out_custom, &pubkey, sk, NULL, NULL) == 1);
+
+ /* Outputs must differ if custom compression was used */
+ CHECK(secp256k1_memcmp_var(out_default, out_custom, 32) != 0);
+ 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 };
@@ -187,6 +212,7 @@ static const struct tf_test_entry tests_ecdh[] = {
CASE1(test_bad_scalar),
CASE1(test_result_basepoint),
CASE1(test_ecdh_wycheproof),
+ CASE1(test_ecdh_ctx_sha256),
};
#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
diff --git a/src/modules/ellswift/main_impl.h b/src/modules/ellswift/main_impl.h
index 096f4a3c..27cb3db6 100644
--- a/src/modules/ellswift/main_impl.h
+++ b/src/modules/ellswift/main_impl.h
@@ -307,7 +307,7 @@ static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_
* hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness.
* Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a
* 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */
-static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) {
+static void secp256k1_ellswift_prng(const secp256k1_hash_ctx *hash_ctx, unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) {
secp256k1_sha256 hash = *hasher;
unsigned char buf4[4];
#ifdef VERIFY
@@ -317,8 +317,8 @@ static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256
buf4[1] = cnt >> 8;
buf4[2] = cnt >> 16;
buf4[3] = cnt >> 24;
- secp256k1_sha256_write(&hash, buf4, 4);
- secp256k1_sha256_finalize(&hash, out32);
+ secp256k1_sha256_write(hash_ctx, &hash, buf4, 4);
+ secp256k1_sha256_finalize(hash_ctx, &hash, out32);
/* Writing and finalizing together should trigger exactly one SHA256 compression. */
VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1));
@@ -330,7 +330,7 @@ static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256
* needs encoding.
*
* hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */
-static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) {
+static void secp256k1_ellswift_xelligatorswift_var(const secp256k1_context *ctx, unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) {
/* Pool of 3-bit branch values. */
unsigned char branch_hash[32];
/* Number of 3-bit values in branch_hash left. */
@@ -346,14 +346,14 @@ static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1
secp256k1_fe u;
/* If the pool of branch values is empty, populate it. */
if (branches_left == 0) {
- secp256k1_ellswift_prng(branch_hash, hasher, cnt++);
+ secp256k1_ellswift_prng(secp256k1_get_hash_context(ctx), branch_hash, hasher, cnt++);
branches_left = 64;
}
/* Take a 3-bit branch value from the branch pool (top bit is discarded). */
--branches_left;
branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7;
/* Compute a new u value by hashing. */
- secp256k1_ellswift_prng(u32, hasher, cnt++);
+ secp256k1_ellswift_prng(secp256k1_get_hash_context(ctx), u32, hasher, cnt++);
/* overflow is not a problem (we prefer uniform u32 over uniform u). */
secp256k1_fe_set_b32_mod(&u, u32);
/* Since u is the output of a hash, it should practically never be 0. We could apply the
@@ -372,8 +372,8 @@ static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1
* as input, and returns an encoding that matches the provided Y coordinate rather than a random
* one.
*/
-static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) {
- secp256k1_ellswift_xelligatorswift_var(u32, t, &p->x, hasher);
+static void secp256k1_ellswift_elligatorswift_var(const secp256k1_context *ctx, unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) {
+ secp256k1_ellswift_xelligatorswift_var(ctx, u32, t, &p->x, hasher);
secp256k1_fe_normalize_var(t);
if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) {
secp256k1_fe_negate(t, t, 1);
@@ -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) {
@@ -412,11 +406,11 @@ int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64
* BIP340 tagged hash with tag "secp256k1_ellswift_encode". */
secp256k1_ellswift_sha256_init_encode(&hash);
secp256k1_eckey_pubkey_serialize33(&p, p64);
- secp256k1_sha256_write(&hash, p64, sizeof(p64));
- secp256k1_sha256_write(&hash, rnd32, 32);
+ secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, p64, sizeof(p64));
+ secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, rnd32, 32);
/* Compute ElligatorSwift encoding and construct output. */
- secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
+ secp256k1_ellswift_elligatorswift_var(ctx, ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
return 1;
}
@@ -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) {
@@ -464,13 +452,13 @@ 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_sha256_write(&hash, seckey32, 32);
- secp256k1_sha256_write(&hash, zero32, sizeof(zero32));
+ secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, seckey32, 32);
+ secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, zero32, sizeof(zero32));
secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */
- if (auxrnd32) secp256k1_sha256_write(&hash, auxrnd32, 32);
+ if (auxrnd32) secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, auxrnd32, 32);
/* Compute ElligatorSwift encoding and construct output. */
- secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
+ secp256k1_ellswift_elligatorswift_var(ctx, ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
secp256k1_memczero(ell64, 64, !ret);
@@ -494,50 +482,52 @@ 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_hash_ctx *hash_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_write(&sha, data, 64);
- secp256k1_sha256_write(&sha, ell_a64, 64);
- secp256k1_sha256_write(&sha, ell_b64, 64);
- secp256k1_sha256_write(&sha, x32, 32);
- secp256k1_sha256_finalize(&sha, output);
+ secp256k1_sha256_write(hash_ctx, &sha, data, 64);
+ secp256k1_sha256_write(hash_ctx, &sha, ell_a64, 64);
+ secp256k1_sha256_write(hash_ctx, &sha, ell_b64, 64);
+ secp256k1_sha256_write(hash_ctx, &sha, x32, 32);
+ secp256k1_sha256_finalize(hash_ctx, &sha, output);
secp256k1_sha256_clear(&sha);
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(secp256k1_get_hash_context(secp256k1_context_static), 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);
- 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) {
+static int ellswift_xdh_hash_function_bip324_impl(const secp256k1_hash_ctx *hash_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_sha256_write(&sha, ell_a64, 64);
- secp256k1_sha256_write(&sha, ell_b64, 64);
- secp256k1_sha256_write(&sha, x32, 32);
- secp256k1_sha256_finalize(&sha, output);
+ secp256k1_sha256_write(hash_ctx, &sha, ell_a64, 64);
+ secp256k1_sha256_write(hash_ctx, &sha, ell_b64, 64);
+ secp256k1_sha256_write(hash_ctx, &sha, x32, 32);
+ secp256k1_sha256_finalize(hash_ctx, &sha, output);
secp256k1_sha256_clear(&sha);
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(secp256k1_get_hash_context(secp256k1_context_static), 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;
@@ -564,7 +554,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. */
@@ -572,8 +562,14 @@ 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 ctx-aware function by default */
+ if (hashfp == secp256k1_ellswift_xdh_hash_function_bip324) {
+ ret = ellswift_xdh_hash_function_bip324_impl(secp256k1_get_hash_context(ctx), output, sx, ell_a64, ell_b64, data);
+ } else if (hashfp == secp256k1_ellswift_xdh_hash_function_prefix) {
+ ret = ellswift_xdh_hash_function_prefix_impl(secp256k1_get_hash_context(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 4cc7f4b5..7da08d50 100644
--- a/src/modules/ellswift/tests_impl.h
+++ b/src/modules/ellswift/tests_impl.h
@@ -8,6 +8,7 @@
#include "../../../include/secp256k1_ellswift.h"
#include "../../unit_test.h"
+#include "../../util.h"
struct ellswift_xswiftec_inv_test {
int enc_bitmap;
@@ -180,7 +181,7 @@ static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32
/* Run the test vectors for ellswift encoding */
void ellswift_encoding_test_vectors_tests(void) {
int i;
- for (i = 0; (unsigned)i < sizeof(ellswift_xswiftec_inv_tests) / sizeof(ellswift_xswiftec_inv_tests[0]); ++i) {
+ for (i = 0; (unsigned)i < ARRAY_SIZE(ellswift_xswiftec_inv_tests); ++i) {
const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i];
int c;
for (c = 0; c < 8; ++c) {
@@ -200,7 +201,7 @@ void ellswift_encoding_test_vectors_tests(void) {
/* Run the test vectors for ellswift decoding */
void ellswift_decoding_test_vectors_tests(void) {
int i;
- for (i = 0; (unsigned)i < sizeof(ellswift_decode_tests) / sizeof(ellswift_decode_tests[0]); ++i) {
+ for (i = 0; (unsigned)i < ARRAY_SIZE(ellswift_decode_tests); ++i) {
const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i];
secp256k1_pubkey pubkey;
secp256k1_ge ge;
@@ -217,7 +218,7 @@ void ellswift_decoding_test_vectors_tests(void) {
/* Run the test vectors for ellswift expected xdh BIP324 shared secrets */
void ellswift_xdh_test_vectors_tests(void) {
int i;
- for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) {
+ for (i = 0; (unsigned)i < ARRAY_SIZE(ellswift_xdh_tests_bip324); ++i) {
const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i];
unsigned char shared_secret[32];
int ret;
@@ -431,9 +432,48 @@ void ellswift_xdh_correctness_tests(void) {
}
}
+DEFINE_SHA256_TRANSFORM_PROBE(sha256_ellswift_xdh)
+void ellswift_xdh_ctx_sha256_tests(void) {
+ /* Check ctx-provided SHA256 compression override takes effect */
+ secp256k1_context *ctx = secp256k1_context_clone(CTX);
+ unsigned char out_default[65], out_custom[65];
+ const unsigned char skA[32] = {1}, skB[32] = {2};
+ unsigned char keyA[64], keyB[64], data[64] = {0};
+ secp256k1_ellswift_xdh_hash_function hash_fn;
+ int i;
+
+ CHECK(secp256k1_ellswift_create(ctx, keyA, skA, NULL));
+ CHECK(secp256k1_ellswift_create(ctx, keyB, skB, NULL));
+
+ for (i = 0; i < 2; i++) {
+ if (i == 0) {
+ hash_fn = secp256k1_ellswift_xdh_hash_function_bip324;
+ } else {
+ hash_fn = secp256k1_ellswift_xdh_hash_function_prefix;
+ }
+ /* Default behavior. No ctx-provided SHA256 compression */
+ CHECK(secp256k1_ellswift_xdh(ctx, out_default, keyA, keyB, skA, 0, hash_fn, data));
+ CHECK(!sha256_ellswift_xdh_called);
+
+ /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */
+ ctx->hash_ctx.fn_sha256_compression = sha256_ellswift_xdh;
+ CHECK(secp256k1_ellswift_xdh(ctx, out_custom, keyA, keyB, skA, 0, hash_fn, data));
+ CHECK(sha256_ellswift_xdh_called);
+ /* Outputs must differ if custom compression was used */
+ CHECK(secp256k1_memcmp_var(out_default, out_custom, 32) != 0);
+
+ /* Restore defaults */
+ sha256_ellswift_xdh_called = 0;
+ secp256k1_context_set_sha256_compression(ctx, NULL);
+ }
+
+ secp256k1_context_destroy(ctx);
+}
+
/* Test hash initializers */
void ellswift_hash_init_tests(void) {
secp256k1_sha256 sha_optimized;
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(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,19 +485,46 @@ void ellswift_hash_init_tests(void) {
* 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));
+ test_sha256_tag_midstate(hash_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));
+ test_sha256_tag_midstate(hash_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));
+ test_sha256_tag_midstate(hash_ctx, &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 --- */
@@ -470,6 +537,8 @@ 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),
+ CASE1(ellswift_xdh_ctx_sha256_tests),
};
#endif
diff --git a/src/modules/musig/keyagg.h b/src/modules/musig/keyagg.h
index a0b37252..30e77aa9 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_hash_ctx *hash_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 e412a27e..f67245d5 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]) */
@@ -88,26 +82,20 @@ static int secp256k1_musig_compute_pks_hash(const secp256k1_context *ctx, unsign
return 0;
}
VERIFY_CHECK(ser_len == sizeof(ser));
- secp256k1_sha256_write(&sha, ser, sizeof(ser));
+ secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha, ser, sizeof(ser));
}
- secp256k1_sha256_finalize(&sha, pks_hash);
+ secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha, pks_hash);
return 1;
}
/* 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
@@ -115,7 +103,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_hash_ctx *hash_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)
@@ -125,20 +113,20 @@ static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsig
secp256k1_sha256 sha;
unsigned char buf[33];
secp256k1_musig_keyaggcoef_sha256(&sha);
- secp256k1_sha256_write(&sha, pks_hash, 32);
+ secp256k1_sha256_write(hash_ctx, &sha, pks_hash, 32);
/* Serialization does not fail since the pk is not the point at infinity
* (according to this function's precondition). */
secp256k1_eckey_pubkey_serialize33(pk, buf);
- secp256k1_sha256_write(&sha, buf, sizeof(buf));
- secp256k1_sha256_finalize(&sha, buf);
+ secp256k1_sha256_write(hash_ctx, &sha, buf, sizeof(buf));
+ secp256k1_sha256_finalize(hash_ctx, &sha, buf);
secp256k1_scalar_set_b32(r, buf, NULL);
}
}
/* 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_hash_ctx *hash_ctx, secp256k1_scalar *r, const secp256k1_keyagg_cache_internal *cache_i, secp256k1_ge *pk) {
+ secp256k1_musig_keyaggcoef_internal(hash_ctx, r, cache_i->pks_hash, pk, &cache_i->second_pk);
}
typedef struct {
@@ -161,7 +149,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(secp256k1_get_hash_context(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 05c96310..6a37bfdf 100644
--- a/src/modules/musig/session_impl.h
+++ b/src/modules/musig/session_impl.h
@@ -289,54 +289,44 @@ int secp256k1_musig_partial_sig_serialize(const secp256k1_context* ctx, unsigned
}
/* Write optional inputs into the hash */
-static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) {
+static void secp256k1_nonce_function_musig_helper(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) {
unsigned char zero[7] = { 0 };
/* The spec requires length prefixes to be between 1 and 8 bytes
* (inclusive) */
VERIFY_CHECK(prefix_size >= 1 && prefix_size <= 8);
/* Since the length of all input data fits in a byte, we can always pad the
* length prefix with prefix_size - 1 zero bytes. */
- secp256k1_sha256_write(sha, zero, prefix_size - 1);
+ secp256k1_sha256_write(hash_ctx, sha, zero, prefix_size - 1);
if (data != NULL) {
- secp256k1_sha256_write(sha, &len, 1);
- secp256k1_sha256_write(sha, data, len);
+ secp256k1_sha256_write(hash_ctx, sha, &len, 1);
+ secp256k1_sha256_write(hash_ctx, sha, data, len);
} else {
len = 0;
- secp256k1_sha256_write(sha, &len, 1);
+ secp256k1_sha256_write(hash_ctx, sha, &len, 1);
}
}
/* 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 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 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(const secp256k1_hash_ctx *hash_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;
@@ -344,8 +334,8 @@ static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned c
if (seckey32 != NULL) {
secp256k1_nonce_function_musig_sha256_tagged_aux(&sha);
- secp256k1_sha256_write(&sha, session_secrand, 32);
- secp256k1_sha256_finalize(&sha, rand);
+ secp256k1_sha256_write(hash_ctx, &sha, session_secrand, 32);
+ secp256k1_sha256_finalize(hash_ctx, &sha, rand);
for (i = 0; i < 32; i++) {
rand[i] ^= seckey32[i];
}
@@ -354,21 +344,21 @@ static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned c
}
secp256k1_nonce_function_musig_sha256_tagged(&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);
+ secp256k1_sha256_write(hash_ctx, &sha, rand, sizeof(rand));
+ secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 1, pk33, 33);
+ secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 1, agg_pk32, 32);
msg_present = msg32 != NULL;
- secp256k1_sha256_write(&sha, &msg_present, 1);
+ secp256k1_sha256_write(hash_ctx, &sha, &msg_present, 1);
if (msg_present) {
- secp256k1_nonce_function_musig_helper(&sha, 8, msg32, 32);
+ secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 8, msg32, 32);
}
- secp256k1_nonce_function_musig_helper(&sha, 4, extra_input32, 32);
+ secp256k1_nonce_function_musig_helper(hash_ctx, &sha, 4, extra_input32, 32);
for (i = 0; i < 2; i++) {
unsigned char buf[32];
secp256k1_sha256 sha_tmp = sha;
- secp256k1_sha256_write(&sha_tmp, &i, 1);
- secp256k1_sha256_finalize(&sha_tmp, buf);
+ secp256k1_sha256_write(hash_ctx, &sha_tmp, &i, 1);
+ secp256k1_sha256_finalize(hash_ctx, &sha_tmp, buf);
secp256k1_scalar_set_b32(&k[i], buf, NULL);
/* Attempt to erase secret data */
@@ -417,7 +407,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(secp256k1_get_hash_context(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);
@@ -543,20 +533,15 @@ 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) */
-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_hash_ctx *hash_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;
@@ -564,11 +549,11 @@ static void secp256k1_musig_compute_noncehash(unsigned char *noncehash, secp256k
secp256k1_musig_compute_noncehash_sha256_tagged(&sha);
for (i = 0; i < 2; i++) {
secp256k1_musig_ge_serialize_ext(buf, &aggnonce[i]);
- secp256k1_sha256_write(&sha, buf, sizeof(buf));
+ secp256k1_sha256_write(hash_ctx, &sha, buf, sizeof(buf));
}
- secp256k1_sha256_write(&sha, agg_pk32, 32);
- secp256k1_sha256_write(&sha, msg, 32);
- secp256k1_sha256_finalize(&sha, noncehash);
+ secp256k1_sha256_write(hash_ctx, &sha, agg_pk32, 32);
+ secp256k1_sha256_write(hash_ctx, &sha, msg, 32);
+ secp256k1_sha256_finalize(hash_ctx, &sha, noncehash);
}
/* out_nonce = nonce_pts[0] + b*nonce_pts[1] */
@@ -580,12 +565,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(secp256k1_get_hash_context(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 +607,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(secp256k1_get_hash_context(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 +678,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(secp256k1_get_hash_context(ctx), &mu, &cache_i, &pk);
secp256k1_scalar_mul(&sk, &sk, &mu);
if (!secp256k1_musig_session_load(ctx, &session_i, session)) {
@@ -753,7 +738,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(secp256k1_get_hash_context(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 de09c5e2..cc644916 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_hash_ctx *hash_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(hash_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(hash_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_hash_ctx *hash_ctx = secp256k1_get_hash_context(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(hash_ctx, args, 0, sizeof(session_secrand));
+ musig_nonce_bitflip(hash_ctx, args, 1, sizeof(msg));
+ musig_nonce_bitflip(hash_ctx, args, 2, sizeof(sk));
+ musig_nonce_bitflip(hash_ctx, args, 3, sizeof(pk));
+ musig_nonce_bitflip(hash_ctx, args, 4, sizeof(agg_pk));
+ musig_nonce_bitflip(hash_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(hash_ctx, k[0], args[0], args[1], args[2], args[3], args[4], args[5]);
+ secp256k1_nonce_function_musig(hash_ctx, k[1], args[0], NULL, args[2], args[3], args[4], args[5]);
+ secp256k1_nonce_function_musig(hash_ctx, k[2], args[0], args[1], NULL, args[3], args[4], args[5]);
+ secp256k1_nonce_function_musig(hash_ctx, k[3], args[0], args[1], args[2], NULL, args[4], args[5]);
+ secp256k1_nonce_function_musig(hash_ctx, k[4], args[0], args[1], args[2], args[3], NULL, args[5]);
+ secp256k1_nonce_function_musig(hash_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_hash_ctx *hash_ctx = secp256k1_get_hash_context(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));
+ test_sha256_tag_midstate(hash_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));
+ test_sha256_tag_midstate(hash_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));
+ test_sha256_tag_midstate(hash_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));
+ test_sha256_tag_midstate(hash_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));
+ test_sha256_tag_midstate(hash_ctx, &sha, tag, sizeof(tag));
}
}
@@ -769,7 +771,7 @@ static void musig_test_vectors_keyagg(void) {
size_t i;
const struct musig_key_agg_vector *vector = &musig_key_agg_vector;
- for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->valid_case); i++) {
const struct musig_key_agg_valid_test_case *c = &vector->valid_case[i];
enum MUSIG_ERROR error;
secp256k1_musig_keyagg_cache keyagg_cache;
@@ -779,7 +781,7 @@ static void musig_test_vectors_keyagg(void) {
CHECK(secp256k1_memcmp_var(agg_pk, c->expected, sizeof(agg_pk)) == 0);
}
- for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->error_case); i++) {
const struct musig_key_agg_error_test_case *c = &vector->error_case[i];
enum MUSIG_ERROR error;
secp256k1_musig_keyagg_cache keyagg_cache;
@@ -793,7 +795,7 @@ static void musig_test_vectors_noncegen(void) {
size_t i;
const struct musig_nonce_gen_vector *vector = &musig_nonce_gen_vector;
- for (i = 0; i < sizeof(vector->test_case)/sizeof(vector->test_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->test_case); i++) {
const struct musig_nonce_gen_test_case *c = &vector->test_case[i];
secp256k1_musig_keyagg_cache keyagg_cache;
secp256k1_musig_keyagg_cache *keyagg_cache_ptr = NULL;
@@ -847,7 +849,7 @@ static void musig_test_vectors_nonceagg(void) {
int j;
const struct musig_nonce_agg_vector *vector = &musig_nonce_agg_vector;
- for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->valid_case); i++) {
const struct musig_nonce_agg_test_case *c = &vector->valid_case[i];
secp256k1_musig_pubnonce pubnonce[2];
const secp256k1_musig_pubnonce *pubnonce_ptr[2];
@@ -862,7 +864,7 @@ static void musig_test_vectors_nonceagg(void) {
CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce66, &aggnonce));
CHECK(secp256k1_memcmp_var(aggnonce66, c->expected, 33) == 0);
}
- for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->error_case); i++) {
const struct musig_nonce_agg_test_case *c = &vector->error_case[i];
secp256k1_musig_pubnonce pubnonce[2];
for (j = 0; j < 2; j++) {
@@ -886,7 +888,7 @@ static void musig_test_vectors_signverify(void) {
size_t i;
const struct musig_sign_verify_vector *vector = &musig_sign_verify_vector;
- for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->valid_case); i++) {
const struct musig_valid_case *c = &vector->valid_case[i];
enum MUSIG_ERROR error;
secp256k1_musig_keyagg_cache keyagg_cache;
@@ -914,7 +916,7 @@ static void musig_test_vectors_signverify(void) {
CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[0]));
CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session));
}
- for (i = 0; i < sizeof(vector->sign_error_case)/sizeof(vector->sign_error_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->sign_error_case); i++) {
const struct musig_sign_error_case *c = &vector->sign_error_case[i];
enum MUSIG_ERROR error;
secp256k1_musig_keyagg_cache keyagg_cache;
@@ -953,7 +955,7 @@ static void musig_test_vectors_signverify(void) {
musig_test_set_secnonce(&secnonce, vector->secnonces[c->secnonce_index], &pubkey);
CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session));
}
- for (i = 0; i < sizeof(vector->verify_fail_case)/sizeof(vector->verify_fail_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->verify_fail_case); i++) {
const struct musig_verify_fail_error_case *c = &vector->verify_fail_case[i];
enum MUSIG_ERROR error;
secp256k1_musig_keyagg_cache keyagg_cache;
@@ -987,7 +989,7 @@ static void musig_test_vectors_signverify(void) {
expected = c->error != MUSIG_SIG_VERIFY;
CHECK(expected == secp256k1_musig_partial_sig_verify(CTX, &partial_sig, pubnonce, &pubkey, &keyagg_cache, &session));
}
- for (i = 0; i < sizeof(vector->verify_error_case)/sizeof(vector->verify_error_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->verify_error_case); i++) {
const struct musig_verify_fail_error_case *c = &vector->verify_error_case[i];
enum MUSIG_ERROR error;
secp256k1_musig_keyagg_cache keyagg_cache;
@@ -1015,7 +1017,7 @@ static void musig_test_vectors_tweak(void) {
CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, vector->aggnonce));
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0])));
- for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->valid_case); i++) {
const struct musig_tweak_case *c = &vector->valid_case[i];
enum MUSIG_ERROR error;
secp256k1_musig_keyagg_cache keyagg_cache;
@@ -1039,7 +1041,7 @@ static void musig_test_vectors_tweak(void) {
CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce, vector->pubnonces[c->nonce_indices[c->signer_index]]));
CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig, &pubnonce, &pubkey, &keyagg_cache, &session));
}
- for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->error_case); i++) {
const struct musig_tweak_case *c = &vector->error_case[i];
enum MUSIG_ERROR error;
secp256k1_musig_keyagg_cache keyagg_cache;
@@ -1052,7 +1054,7 @@ static void musig_test_vectors_sigagg(void) {
size_t i, j;
const struct musig_sig_agg_vector *vector = &musig_sig_agg_vector;
- for (i = 0; i < sizeof(vector->valid_case)/sizeof(vector->valid_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->valid_case); i++) {
const struct musig_sig_agg_case *c = &vector->valid_case[i];
enum MUSIG_ERROR error;
unsigned char final_sig[64];
@@ -1061,8 +1063,8 @@ static void musig_test_vectors_sigagg(void) {
secp256k1_xonly_pubkey agg_pk;
secp256k1_musig_aggnonce aggnonce;
secp256k1_musig_session session;
- secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))];
- const secp256k1_musig_partial_sig *partial_sig_ptr[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))];
+ secp256k1_musig_partial_sig partial_sig[ARRAY_SIZE(vector->psigs)];
+ const secp256k1_musig_partial_sig *partial_sig_ptr[ARRAY_SIZE(vector->psigs)];
CHECK(musig_vectors_keyagg_and_tweak(&error, &keyagg_cache, agg_pk32, vector->pubkeys, vector->tweaks, c->key_indices_len, c->key_indices, c->tweak_indices_len, c->tweak_indices, c->is_xonly));
CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, c->aggnonce));
@@ -1078,9 +1080,9 @@ static void musig_test_vectors_sigagg(void) {
CHECK(secp256k1_xonly_pubkey_parse(CTX, &agg_pk, agg_pk32));
CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, vector->msg, sizeof(vector->msg), &agg_pk) == 1);
}
- for (i = 0; i < sizeof(vector->error_case)/sizeof(vector->error_case[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(vector->error_case); i++) {
const struct musig_sig_agg_case *c = &vector->error_case[i];
- secp256k1_musig_partial_sig partial_sig[(sizeof(vector->psigs)/sizeof(vector->psigs[0]))];
+ secp256k1_musig_partial_sig partial_sig[ARRAY_SIZE(vector->psigs)];
for (j = 0; j < c->psig_indices_len; j++) {
int expected = c->invalid_sig_idx != (int)j;
CHECK(expected == secp256k1_musig_partial_sig_parse(CTX, &partial_sig[j], vector->psigs[c->psig_indices[j]]));
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/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h
index b410b19e..5100557f 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
@@ -49,7 +37,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_hash_ctx *hash_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;
@@ -60,8 +48,8 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms
if (data != NULL) {
secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha);
- secp256k1_sha256_write(&sha, data, 32);
- secp256k1_sha256_finalize(&sha, masked_key);
+ secp256k1_sha256_write(hash_ctx, &sha, data, 32);
+ secp256k1_sha256_finalize(hash_ctx, &sha, masked_key);
for (i = 0; i < 32; i++) {
masked_key[i] ^= key32[i];
}
@@ -85,48 +73,47 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms
&& secp256k1_memcmp_var(algo, bip340_algo, algolen) == 0) {
secp256k1_nonce_function_bip340_sha256_tagged(&sha);
} else {
- secp256k1_sha256_initialize_tagged(&sha, algo, algolen);
+ secp256k1_sha256_initialize_tagged(hash_ctx, &sha, algo, algolen);
}
/* Hash masked-key||pk||msg using the tagged hash as per the spec */
- secp256k1_sha256_write(&sha, masked_key, 32);
- secp256k1_sha256_write(&sha, xonly_pk32, 32);
- secp256k1_sha256_write(&sha, msg, msglen);
- secp256k1_sha256_finalize(&sha, nonce32);
+ secp256k1_sha256_write(hash_ctx, &sha, masked_key, 32);
+ secp256k1_sha256_write(hash_ctx, &sha, xonly_pk32, 32);
+ secp256k1_sha256_write(hash_ctx, &sha, msg, msglen);
+ secp256k1_sha256_finalize(hash_ctx, &sha, nonce32);
secp256k1_sha256_clear(&sha);
secp256k1_memclear_explicit(masked_key, sizeof(masked_key));
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(secp256k1_get_hash_context(secp256k1_context_static), 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);
- 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)
+static void secp256k1_schnorrsig_challenge(const secp256k1_hash_ctx *hash_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_sha256_write(&sha, r32, 32);
- secp256k1_sha256_write(&sha, pubkey32, 32);
- secp256k1_sha256_write(&sha, msg, msglen);
- secp256k1_sha256_finalize(&sha, buf);
+ secp256k1_sha256_write(hash_ctx, &sha, r32, 32);
+ secp256k1_sha256_write(hash_ctx, &sha, pubkey32, 32);
+ secp256k1_sha256_write(hash_ctx, &sha, msg, msglen);
+ secp256k1_sha256_finalize(hash_ctx, &sha, buf);
/* Set scalar e to the challenge hash modulo the curve order as per
* BIP340. */
secp256k1_scalar_set_b32(e, buf, NULL);
@@ -150,10 +137,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 +147,15 @@ 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) {
+ /* Use context-aware nonce function by default */
+ ret &= nonce_function_bip340_impl(secp256k1_get_hash_context(ctx), 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 +173,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(secp256k1_get_hash_context(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 +243,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(secp256k1_get_hash_context(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 601b5497..57efe348 100644
--- a/src/modules/schnorrsig/tests_exhaustive_impl.h
+++ b/src/modules/schnorrsig/tests_exhaustive_impl.h
@@ -56,7 +56,7 @@ static const unsigned char invalid_pubkey_bytes[][32] = {
}
};
-#define NUM_INVALID_KEYS (sizeof(invalid_pubkey_bytes) / sizeof(invalid_pubkey_bytes[0]))
+#define NUM_INVALID_KEYS (ARRAY_SIZE(invalid_pubkey_bytes))
static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg,
size_t msglen,
@@ -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(secp256k1_get_hash_context(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(secp256k1_get_hash_context(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 9a1b15f0..56812e7f 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;
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(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));
+ test_sha256_tag_midstate(hash_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));
+ test_sha256_tag_midstate(hash_ctx, &sha_optimized, aux_tag, sizeof(aux_tag));
testrand256(msg);
testrand256(key);
@@ -162,8 +164,9 @@ 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;
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
- secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag));
+ secp256k1_sha256_initialize_tagged(hash_ctx, &sha, (unsigned char *) tag, sizeof(tag));
secp256k1_schnorrsig_sha256_tagged(&sha_optimized);
test_sha256_eq(&sha, &sha_optimized);
}
@@ -849,6 +852,29 @@ 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_ctx_sha256(void) {
+ /* Check ctx-provided SHA256 compression override takes effect */
+ secp256k1_context *ctx = secp256k1_context_clone(CTX);
+ unsigned char out_default[64], out_custom[64];
+ unsigned char sk[32] = {1}, msg32[32] = {1};
+ secp256k1_keypair keypair;
+ CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
+
+ /* Default behavior. No ctx-provided SHA256 compression */
+ CHECK(secp256k1_schnorrsig_sign32(ctx, out_default, msg32, &keypair, NULL));
+ CHECK(!sha256_schnorrsig_called);
+
+ /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */
+ ctx->hash_ctx.fn_sha256_compression = sha256_schnorrsig;
+ CHECK(secp256k1_schnorrsig_sign32(ctx, out_custom, msg32, &keypair, NULL));
+ CHECK(sha256_schnorrsig_called);
+ /* Outputs must differ if custom compression was used */
+ CHECK(secp256k1_memcmp_var(out_default, out_custom, 64) != 0);
+
+ 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
@@ -978,6 +1004,7 @@ static const struct tf_test_entry tests_schnorrsig[] = {
CASE1(test_schnorrsig_sign),
CASE1(test_schnorrsig_sign_verify),
CASE1(test_schnorrsig_taproot),
+ CASE1(test_schnorrsig_ctx_sha256),
};
#endif
diff --git a/src/precompute_ecmult_gen.c b/src/precompute_ecmult_gen.c
index cd0fe70f..a03abdb5 100644
--- a/src/precompute_ecmult_gen.c
+++ b/src/precompute_ecmult_gen.c
@@ -80,7 +80,7 @@ int main(int argc, char **argv) {
fprintf(fp, "const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS] = {\n");
fprintf(fp, "#if 0\n");
- for (config = 0; config < sizeof(CONFIGS) / sizeof(*CONFIGS); ++config) {
+ for (config = 0; config < ARRAY_SIZE(CONFIGS); ++config) {
print_table(fp, CONFIGS[config][0], CONFIGS[config][1]);
if (CONFIGS[config][0] == COMB_BLOCKS && CONFIGS[config][1] == COMB_TEETH) {
did_current_config = 1;
diff --git a/src/secp256k1.c b/src/secp256k1.c
index ddd98495..e4b80fff 100644
--- a/src/secp256k1.c
+++ b/src/secp256k1.c
@@ -60,6 +60,7 @@
* context_eq function. */
struct secp256k1_context_struct {
secp256k1_ecmult_gen_context ecmult_gen_ctx;
+ secp256k1_hash_ctx hash_ctx;
secp256k1_callback illegal_callback;
secp256k1_callback error_callback;
int declassify;
@@ -67,6 +68,7 @@ struct secp256k1_context_struct {
static const secp256k1_context secp256k1_context_static_ = {
{ 0 },
+ { secp256k1_sha256_transform },
{ secp256k1_default_illegal_callback_fn, 0 },
{ secp256k1_default_error_callback_fn, 0 },
0
@@ -129,10 +131,11 @@ 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;
+ secp256k1_hash_ctx_init(&ret->hash_ctx);
/* Flags have been checked by secp256k1_context_preallocated_size. */
VERIFY_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_CONTEXT);
- secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx);
+ secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->hash_ctx);
ret->declassify = !!(flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY);
return ret;
@@ -140,7 +143,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 +171,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;
}
@@ -220,6 +223,22 @@ void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(co
ctx->error_callback.data = data;
}
+void secp256k1_context_set_sha256_compression(secp256k1_context *ctx, secp256k1_sha256_compression_function fn_compression) {
+ VERIFY_CHECK(ctx != NULL);
+ ARG_CHECK_VOID(secp256k1_context_is_proper(ctx));
+ if (!fn_compression) { /* Reset hash context */
+ secp256k1_hash_ctx_init(&ctx->hash_ctx);
+ return;
+ }
+ /* Check and set */
+ ARG_CHECK_VOID(secp256k1_selftest_sha256(fn_compression));
+ ctx->hash_ctx.fn_sha256_compression = fn_compression;
+}
+
+static SECP256K1_INLINE const secp256k1_hash_ctx* secp256k1_get_hash_context(const secp256k1_context *ctx) {
+ return &ctx->hash_ctx;
+}
+
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,7 +495,7 @@ 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_hash_ctx *hash_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;
@@ -501,9 +520,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(hash_ctx, &rng, keydata, offset);
for (i = 0; i <= counter; i++) {
- secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
+ secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, nonce32, 32);
}
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
@@ -512,6 +531,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(secp256k1_get_hash_context(secp256k1_context_static), 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;
@@ -527,9 +550,6 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc
if (recid) {
*recid = 0;
}
- if (noncefp == NULL) {
- noncefp = secp256k1_nonce_function_default;
- }
/* Fail if the secret key is invalid. */
is_sec_valid = secp256k1_scalar_set_b32_seckey(&sec, seckey);
@@ -537,7 +557,14 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc
secp256k1_scalar_set_b32(&msg, msg32, NULL);
while (1) {
int is_nonce_valid;
- ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
+
+ if (noncefp == NULL) {
+ /* Use ctx-aware function by default */
+ ret = nonce_function_rfc6979_impl(secp256k1_get_hash_context(ctx), nonce32, msg32, seckey, NULL, (void*)noncedata, count);
+ } else {
+ ret = !!noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
+ }
+
if (!ret) {
break;
}
@@ -757,7 +784,7 @@ int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *see
ARG_CHECK(secp256k1_context_is_proper(ctx));
if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
- secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
+ secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, secp256k1_get_hash_context(ctx), seed32);
}
return 1;
}
@@ -795,9 +822,9 @@ 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_write(&sha, msg, msglen);
- secp256k1_sha256_finalize(&sha, hash32);
+ secp256k1_sha256_initialize_tagged(secp256k1_get_hash_context(ctx), &sha, tag, taglen);
+ secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha, msg, msglen);
+ secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha, hash32);
secp256k1_sha256_clear(&sha);
return 1;
}
diff --git a/src/selftest.h b/src/selftest.h
index d083ac95..de0e0597 100644
--- a/src/selftest.h
+++ b/src/selftest.h
@@ -11,7 +11,8 @@
#include <string.h>
-static int secp256k1_selftest_sha256(void) {
+static int secp256k1_selftest_sha256(secp256k1_sha256_compression_function fn_compression) {
+ secp256k1_hash_ctx hash_ctx;
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,
@@ -20,13 +21,15 @@ static int secp256k1_selftest_sha256(void) {
unsigned char out[32];
secp256k1_sha256 hasher;
secp256k1_sha256_initialize(&hasher);
- secp256k1_sha256_write(&hasher, (const unsigned char*)input63, 63);
- secp256k1_sha256_finalize(&hasher, out);
+ hash_ctx.fn_sha256_compression = fn_compression;
+ secp256k1_sha256_write(&hash_ctx, &hasher, (const unsigned char*)input63, 63);
+ secp256k1_sha256_finalize(&hash_ctx, &hasher, out);
return secp256k1_memcmp_var(out, output32, 32) == 0;
}
static int secp256k1_selftest_passes(void) {
- return secp256k1_selftest_sha256();
+ /* Use default sha256 compression */
+ return secp256k1_selftest_sha256(secp256k1_sha256_transform);
}
#endif /* SECP256K1_SELFTEST_H */
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..58e71e10 100644
--- a/src/testrand_impl.h
+++ b/src/testrand_impl.h
@@ -22,12 +22,13 @@ SECP256K1_INLINE static void testrand_seed(const unsigned char *seed16) {
unsigned char out32[32];
secp256k1_sha256 hash;
int i;
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(secp256k1_context_static);
/* Use SHA256(PREFIX || seed16) as initial state. */
secp256k1_sha256_initialize(&hash);
- secp256k1_sha256_write(&hash, PREFIX, sizeof(PREFIX));
- secp256k1_sha256_write(&hash, seed16, 16);
- secp256k1_sha256_finalize(&hash, out32);
+ secp256k1_sha256_write(hash_ctx, &hash, PREFIX, sizeof(PREFIX));
+ secp256k1_sha256_write(hash_ctx, &hash, seed16, 16);
+ secp256k1_sha256_finalize(hash_ctx, &hash, out32);
for (i = 0; i < 4; ++i) {
uint64_t s = 0;
int j;
@@ -158,10 +159,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.c b/src/tests.c
index e09f5c7d..862bef61 100644
--- a/src/tests.c
+++ b/src/tests.c
@@ -92,7 +92,7 @@ static void run_xoshiro256pp_tests(void) {
{
size_t i;
/* Sanity check that we run before the actual seeding. */
- for (i = 0; i < sizeof(secp256k1_test_state)/sizeof(secp256k1_test_state[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(secp256k1_test_state); i++) {
CHECK(secp256k1_test_state[i] == 0);
}
}
@@ -132,6 +132,7 @@ static int ecmult_gen_context_eq(const secp256k1_ecmult_gen_context *a, const se
static int context_eq(const secp256k1_context *a, const secp256k1_context *b) {
return a->declassify == b->declassify
&& ecmult_gen_context_eq(&a->ecmult_gen_ctx, &b->ecmult_gen_ctx)
+ && a->hash_ctx.fn_sha256_compression == b->hash_ctx.fn_sha256_compression
&& a->illegal_callback.fn == b->illegal_callback.fn
&& a->illegal_callback.data == b->illegal_callback.data
&& a->error_callback.fn == b->error_callback.fn
@@ -146,7 +147,7 @@ static void run_deprecated_context_flags_test(void) {
SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY };
secp256k1_context *none_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
int i;
- for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++) {
+ for (i = 0; i < (int)(ARRAY_SIZE(flags)); i++) {
secp256k1_context *tmp_ctx;
CHECK(secp256k1_context_preallocated_size(SECP256K1_CONTEXT_NONE) == secp256k1_context_preallocated_size(flags[i]));
tmp_ctx = secp256k1_context_create(flags[i]);
@@ -432,18 +433,158 @@ static void run_scratch_tests(void) {
secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */
}
+/* A compression function that does nothing */
+static void invalid_sha256_compression(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_compression(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_compression_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_ctx.fn_sha256_compression == secp256k1_sha256_transform);
+
+ /* 2) Verify providing a bad compression function fails during set */
+ CHECK_ILLEGAL_VOID(ctx, secp256k1_context_set_sha256_compression(ctx, invalid_sha256_compression));
+ CHECK(ctx->hash_ctx.fn_sha256_compression == secp256k1_sha256_transform);
+
+ /* 3) Provide sha256 to ctx and verify it is called when provided */
+ own_transform_called = 0;
+ secp256k1_context_set_sha256_compression(ctx, good_sha256_compression);
+ CHECK(own_transform_called);
+
+ /* 4) Verify callback makes it across clone */
+ ctx_cloned = secp256k1_context_clone(ctx);
+ CHECK(ctx_cloned->hash_ctx.fn_sha256_compression == good_sha256_compression);
+
+ /* 5) A hash operation should invoke the installed callback */
+ own_transform_called = 0;
+ secp256k1_sha256_initialize(&sha);
+ secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha, (const unsigned char*)"a", 1);
+ secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha, sha_out);
+ CHECK(own_transform_called);
+
+ /* 6) Unset sha256 and verify the default one is set again */
+ secp256k1_context_set_sha256_compression(ctx, NULL);
+ CHECK(ctx->hash_ctx.fn_sha256_compression == secp256k1_sha256_transform);
+
+ secp256k1_context_destroy(ctx);
+ secp256k1_context_destroy(ctx_cloned);
+}
+
+static void run_sha256_multi_block_compression_tests(void) {
+ secp256k1_hash_ctx hash_ctx;
+ secp256k1_sha256 sha256_one;
+ secp256k1_sha256 sha256_two;
+ unsigned char out_one[32], out_two[32];
+
+ hash_ctx.fn_sha256_compression = secp256k1_sha256_transform;
+
+ { /* 1) Writing one 64-byte full block vs two 32-byte blocks */
+ const unsigned char data[64] = "totally serious test message to hash, definitely no random data";
+ unsigned char data32[32];
+
+ secp256k1_sha256_initialize(&sha256_one);
+ secp256k1_sha256_initialize(&sha256_two);
+
+ /* Write the 64-byte block */
+ secp256k1_sha256_write(&hash_ctx, &sha256_one, data, 64);
+ secp256k1_sha256_finalize(&hash_ctx, &sha256_one, out_one);
+
+ /* Write the two 32-byte blocks */
+ memcpy(data32, data, 32);
+ secp256k1_sha256_write(&hash_ctx, &sha256_two, data32, 32);
+ memcpy(data32, data + 32, 32);
+ secp256k1_sha256_write(&hash_ctx, &sha256_two, data32, 32);
+ secp256k1_sha256_finalize(&hash_ctx, &sha256_two, out_two);
+
+ CHECK(secp256k1_memcmp_var(out_one, out_two, 32) == 0);
+ }
+
+ { /* 2) Writing one 80-byte block vs two 40-byte blocks */
+ const unsigned char data[80] = "Genesis: The Times 03/Jan/2009 Chancellor on brink of second bailout for banks ";
+ unsigned char data40[40];
+
+ secp256k1_sha256_initialize(&sha256_one);
+ secp256k1_sha256_initialize(&sha256_two);
+
+ /* Write the 80-byte block */
+ secp256k1_sha256_write(&hash_ctx, &sha256_one, data, 80);
+ secp256k1_sha256_finalize(&hash_ctx, &sha256_one, out_one);
+
+ /* Write the two 40-byte blocks */
+ memcpy(data40, data, 40);
+ secp256k1_sha256_write(&hash_ctx, &sha256_two, data40, 40);
+ memcpy(data40, data + 40, 40);
+ secp256k1_sha256_write(&hash_ctx, &sha256_two, data40, 40);
+ secp256k1_sha256_finalize(&hash_ctx, &sha256_two, out_two);
+
+ CHECK(secp256k1_memcmp_var(out_one, out_two, 32) == 0);
+ }
+
+ { /* 3) Writing multiple consecutive full blocks in one write (128 bytes) */
+ unsigned char data[128];
+ unsigned char i;
+ for (i = 0; i < 128; i++) data[i] = i;
+
+ secp256k1_sha256_initialize(&sha256_one);
+ secp256k1_sha256_initialize(&sha256_two);
+
+ /* Single write of 128 bytes (two full 64-byte blocks) */
+ secp256k1_sha256_write(&hash_ctx, &sha256_one, data, 128);
+ secp256k1_sha256_finalize(&hash_ctx, &sha256_one, out_one);
+
+ /* Two separate writes of 64 bytes each */
+ secp256k1_sha256_write(&hash_ctx, &sha256_two, data, 64);
+ secp256k1_sha256_write(&hash_ctx, &sha256_two, data + 64, 64);
+ secp256k1_sha256_finalize(&hash_ctx, &sha256_two, out_two);
+
+ CHECK(secp256k1_memcmp_var(out_one, out_two, 32) == 0);
+ }
+
+ { /* 4) Mixed small + large writes in sequence */
+ unsigned char data[150];
+ unsigned char i;
+ for (i = 0; i < 150; i++) data[i] = i;
+
+ secp256k1_sha256_initialize(&sha256_one);
+ secp256k1_sha256_initialize(&sha256_two);
+
+ /* Single write of 150 bytes */
+ secp256k1_sha256_write(&hash_ctx, &sha256_one, data, 150);
+ secp256k1_sha256_finalize(&hash_ctx, &sha256_one, out_one);
+
+ /* Split writes: 10, 64, 64, 12 bytes */
+ secp256k1_sha256_write(&hash_ctx, &sha256_two, data, 10);
+ secp256k1_sha256_write(&hash_ctx, &sha256_two, data + 10, 64);
+ secp256k1_sha256_write(&hash_ctx, &sha256_two, data + 74, 64);
+ secp256k1_sha256_write(&hash_ctx, &sha256_two, data + 138, 12);
+ secp256k1_sha256_finalize(&hash_ctx, &sha256_two, out_two);
+
+ CHECK(secp256k1_memcmp_var(out_one, out_two, 32) == 0);
+ }
+}
+
static void run_ctz_tests(void) {
static const uint32_t b32[] = {1, 0xffffffff, 0x5e56968f, 0xe0d63129};
static const uint64_t b64[] = {1, 0xffffffffffffffff, 0xbcd02462139b3fc3, 0x98b5f80c769693ef};
int shift;
unsigned i;
- for (i = 0; i < sizeof(b32) / sizeof(b32[0]); ++i) {
+ for (i = 0; i < ARRAY_SIZE(b32); ++i) {
for (shift = 0; shift < 32; ++shift) {
CHECK(secp256k1_ctz32_var_debruijn(b32[i] << shift) == shift);
CHECK(secp256k1_ctz32_var(b32[i] << shift) == shift);
}
}
- for (i = 0; i < sizeof(b64) / sizeof(b64[0]); ++i) {
+ for (i = 0; i < ARRAY_SIZE(b64); ++i) {
for (shift = 0; shift < 64; ++shift) {
CHECK(secp256k1_ctz64_var_debruijn(b64[i] << shift) == shift);
CHECK(secp256k1_ctz64_var(b64[i] << shift) == shift);
@@ -454,6 +595,7 @@ static void run_ctz_tests(void) {
/***** HASH TESTS *****/
static void run_sha256_known_output_tests(void) {
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
static const char *inputs[] = {
"", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
@@ -478,7 +620,7 @@ static void run_sha256_known_output_tests(void) {
unsigned int i, ninputs;
/* Skip last input vector for low iteration counts */
- ninputs = sizeof(inputs)/sizeof(inputs[0]) - 1;
+ ninputs = ARRAY_SIZE(inputs) - 1;
CONDITIONAL_TEST(16, "run_sha256_known_output_tests 1000000") ninputs++;
for (i = 0; i < ninputs; i++) {
@@ -489,10 +631,10 @@ static void run_sha256_known_output_tests(void) {
j = repeat[i];
secp256k1_sha256_initialize(&hasher);
while (j > 0) {
- secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
+ secp256k1_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
j--;
}
- secp256k1_sha256_finalize(&hasher, out);
+ secp256k1_sha256_finalize(hash_ctx, &hasher, out);
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
/* 2. Run: split the input bytestrings randomly before writing */
if (strlen(inputs[i]) > 0) {
@@ -500,11 +642,11 @@ static void run_sha256_known_output_tests(void) {
secp256k1_sha256_initialize(&hasher);
j = repeat[i];
while (j > 0) {
- secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
- secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
+ secp256k1_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i]), split);
+ secp256k1_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
j--;
}
- secp256k1_sha256_finalize(&hasher, out);
+ secp256k1_sha256_finalize(hash_ctx, &hasher, out);
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
}
}
@@ -602,12 +744,13 @@ static void run_sha256_counter_tests(void) {
{0x2c, 0xf3, 0xa9, 0xf6, 0x15, 0x25, 0x80, 0x70, 0x76, 0x99, 0x7d, 0xf1, 0xc3, 0x2f, 0xa3, 0x31, 0xff, 0x92, 0x35, 0x2e, 0x8d, 0x04, 0x13, 0x33, 0xd8, 0x0d, 0xdb, 0x4a, 0xf6, 0x8c, 0x03, 0x34},
{0xec, 0x12, 0x24, 0x9f, 0x35, 0xa4, 0x29, 0x8b, 0x9e, 0x4a, 0x95, 0xf8, 0x61, 0xaf, 0x61, 0xc5, 0x66, 0x55, 0x3e, 0x3f, 0x2a, 0x98, 0xea, 0x71, 0x16, 0x6b, 0x1c, 0xd9, 0xe4, 0x09, 0xd2, 0x8e},
};
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
unsigned int i;
- for (i = 0; i < sizeof(midstates)/sizeof(midstates[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(midstates); i++) {
unsigned char out[32];
secp256k1_sha256 hasher = midstates[i];
- secp256k1_sha256_write(&hasher, (const unsigned char*)input, strlen(input));
- secp256k1_sha256_finalize(&hasher, out);
+ secp256k1_sha256_write(hash_ctx, &hasher, (const unsigned char*)input, strlen(input));
+ secp256k1_sha256_finalize(hash_ctx, &hasher, out);
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
}
}
@@ -624,9 +767,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_hash_ctx *hash_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(hash_ctx, &sha, tag, taglen);
test_sha256_eq(&sha, sha_tagged);
}
@@ -656,19 +799,20 @@ 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_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
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_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
- secp256k1_hmac_sha256_finalize(&hasher, out);
+ secp256k1_hmac_sha256_initialize(hash_ctx, &hasher, (const unsigned char*)(keys[i]), strlen(keys[i]));
+ secp256k1_hmac_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
+ secp256k1_hmac_sha256_finalize(hash_ctx, &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_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);
+ secp256k1_hmac_sha256_initialize(hash_ctx, &hasher, (const unsigned char*)(keys[i]), strlen(keys[i]));
+ secp256k1_hmac_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i]), split);
+ secp256k1_hmac_sha256_write(hash_ctx, &hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
+ secp256k1_hmac_sha256_finalize(hash_ctx, &hasher, out);
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
}
}
@@ -689,27 +833,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}
};
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
secp256k1_rfc6979_hmac_sha256 rng;
unsigned char out[32];
int i;
- secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64);
+ secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, key1, 64);
for (i = 0; i < 3; i++) {
- secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32);
+ secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, out, 32);
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(hash_ctx, &rng, key1, 65);
for (i = 0; i < 3; i++) {
- secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32);
+ secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, out, 32);
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(hash_ctx, &rng, key2, 64);
for (i = 0; i < 3; i++) {
- secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32);
+ secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, out, 32);
CHECK(secp256k1_memcmp_var(out, out2[i], 32) == 0);
}
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
@@ -739,6 +884,20 @@ 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
+ };
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
+ secp256k1_sha256 sha;
+
+ secp256k1_sha256_initialize_midstate(&sha, 64, midstate);
+ test_sha256_tag_midstate(hash_ctx, &sha, tag, sizeof(tag) - 1);
+}
+
/***** MODINV TESTS *****/
/* Compute the modular inverse of (odd) x mod 2^64. */
@@ -1649,7 +1808,7 @@ static void run_modinv_tests(void) {
int i, j, ok;
/* Test known inputs/outputs */
- for (i = 0; (size_t)i < sizeof(CASES) / sizeof(CASES[0]); ++i) {
+ for (i = 0; (size_t)i < ARRAY_SIZE(CASES); ++i) {
uint16_t out[16];
test_modinv32_uint16(out, CASES[i][0], CASES[i][1]);
for (j = 0; j < 16; ++j) CHECK(out[j] == CASES[i][2][j]);
@@ -2193,8 +2352,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();
}
@@ -2247,7 +2456,7 @@ static void run_scalar_tests(void) {
SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful),
};
unsigned n;
- for (n = 0; n < sizeof(HALF_TESTS) / sizeof(HALF_TESTS[0]); ++n) {
+ for (n = 0; n < ARRAY_SIZE(HALF_TESTS); ++n) {
secp256k1_scalar s;
secp256k1_scalar_half(&s, &HALF_TESTS[n]);
secp256k1_scalar_add(&s, &s, &s);
@@ -2258,15 +2467,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
@@ -3524,7 +3724,7 @@ static void run_inverse_tests(void)
secp256k1_scalar x_scalar;
memset(b32, 0, sizeof(b32));
/* Test fixed test cases through test_inverse_{scalar,field}, both ways. */
- for (i = 0; (size_t)i < sizeof(fe_cases)/sizeof(fe_cases[0]); ++i) {
+ for (i = 0; (size_t)i < ARRAY_SIZE(fe_cases); ++i) {
for (var = 0; var <= 1; ++var) {
test_inverse_field(&x_fe, &fe_cases[i][0], var);
CHECK(fe_equal(&x_fe, &fe_cases[i][1]));
@@ -3532,7 +3732,7 @@ static void run_inverse_tests(void)
CHECK(fe_equal(&x_fe, &fe_cases[i][0]));
}
}
- for (i = 0; (size_t)i < sizeof(scalar_cases)/sizeof(scalar_cases[0]); ++i) {
+ for (i = 0; (size_t)i < ARRAY_SIZE(scalar_cases); ++i) {
for (var = 0; var <= 1; ++var) {
test_inverse_scalar(&x_scalar, &scalar_cases[i][0], var);
CHECK(secp256k1_scalar_eq(&x_scalar, &scalar_cases[i][1]));
@@ -3676,8 +3876,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 +4011,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 +4032,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;
@@ -4326,11 +4526,19 @@ static void test_point_times_order(const secp256k1_gej *point) {
CHECK(secp256k1_ge_is_valid_var(&res3) == 0);
/* check zero/one edge cases */
secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_zero);
+ secp256k1_ecmult(&res2, point, &secp256k1_scalar_zero, NULL);
secp256k1_ge_set_gej(&res3, &res1);
+ CHECK(secp256k1_gej_is_infinity(&res1));
+ CHECK(secp256k1_gej_is_infinity(&res2));
CHECK(secp256k1_ge_is_infinity(&res3));
+
secp256k1_ecmult(&res1, point, &secp256k1_scalar_one, &secp256k1_scalar_zero);
+ secp256k1_ecmult(&res2, point, &secp256k1_scalar_one, NULL);
secp256k1_ge_set_gej(&res3, &res1);
CHECK(secp256k1_gej_eq_ge_var(point, &res3));
+ secp256k1_ge_set_gej(&res3, &res2);
+ CHECK(secp256k1_gej_eq_ge_var(point, &res3));
+
secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_one);
secp256k1_ge_set_gej(&res3, &res1);
CHECK(secp256k1_ge_eq_var(&secp256k1_ge_const_g, &res3));
@@ -4408,7 +4616,7 @@ static void run_ecmult_near_split_bound(void) {
int i;
unsigned j;
for (i = 0; i < 4*COUNT; ++i) {
- for (j = 0; j < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++j) {
+ for (j = 0; j < ARRAY_SIZE(scalars_near_split_bounds); ++j) {
test_ecmult_target(&scalars_near_split_bounds[j], 0);
test_ecmult_target(&scalars_near_split_bounds[j], 1);
test_ecmult_target(&scalars_near_split_bounds[j], 2);
@@ -4532,7 +4740,7 @@ static void ecmult_const_edges(void) {
secp256k1_ge point;
secp256k1_gej res;
size_t i;
- size_t cases = 1 + sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]);
+ size_t cases = 1 + ARRAY_SIZE(scalars_near_split_bounds);
/* We are trying to reach the following edge cases (variables are defined as
* in ecmult_const_impl.h):
@@ -5175,8 +5383,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;
@@ -5426,32 +5634,33 @@ static int test_ecmult_accumulate_cb(secp256k1_scalar* sc, secp256k1_ge* pt, siz
}
static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, secp256k1_scratch* scratch) {
- /* Compute x*G in 6 different ways, serialize it uncompressed, and feed it into acc. */
- secp256k1_gej rj1, rj2, rj3, rj4, rj5, rj6, gj, infj;
+ /* Compute x*G in many different ways, serialize it uncompressed, and feed it into acc. */
+ secp256k1_gej gj, infj;
secp256k1_ge r;
+ secp256k1_gej rj[7];
unsigned char bytes[65];
+ size_t i;
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
secp256k1_gej_set_infinity(&infj);
- secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &rj1, x);
- secp256k1_ecmult(&rj2, &gj, x, &secp256k1_scalar_zero);
- secp256k1_ecmult(&rj3, &infj, &secp256k1_scalar_zero, x);
- CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &rj4, x, NULL, NULL, 0));
- CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &rj5, &secp256k1_scalar_zero, test_ecmult_accumulate_cb, (void*)x, 1));
- secp256k1_ecmult_const(&rj6, &secp256k1_ge_const_g, x);
- secp256k1_ge_set_gej_var(&r, &rj1);
- CHECK(secp256k1_gej_eq_ge_var(&rj2, &r));
- CHECK(secp256k1_gej_eq_ge_var(&rj3, &r));
- CHECK(secp256k1_gej_eq_ge_var(&rj4, &r));
- CHECK(secp256k1_gej_eq_ge_var(&rj5, &r));
- CHECK(secp256k1_gej_eq_ge_var(&rj6, &r));
+ secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &rj[0], x);
+ secp256k1_ecmult(&rj[1], &gj, x, NULL);
+ secp256k1_ecmult(&rj[2], &gj, x, &secp256k1_scalar_zero);
+ secp256k1_ecmult(&rj[3], &infj, &secp256k1_scalar_zero, x);
+ CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &rj[4], x, NULL, NULL, 0));
+ CHECK(secp256k1_ecmult_multi_var(&CTX->error_callback, scratch, &rj[5], &secp256k1_scalar_zero, test_ecmult_accumulate_cb, (void*)x, 1));
+ secp256k1_ecmult_const(&rj[6], &secp256k1_ge_const_g, x);
+ secp256k1_ge_set_gej_var(&r, &rj[0]);
+ for (i = 0; i < ARRAY_SIZE(rj); i++) {
+ CHECK(secp256k1_gej_eq_ge_var(&rj[i], &r));
+ }
if (secp256k1_ge_is_infinity(&r)) {
/* Store infinity as 0x00 */
const unsigned char zerobyte[1] = {0};
- secp256k1_sha256_write(acc, zerobyte, 1);
+ secp256k1_sha256_write(secp256k1_get_hash_context(CTX), acc, zerobyte, 1);
} else {
/* Store other points using their uncompressed serialization. */
secp256k1_eckey_pubkey_serialize65(&r, bytes);
- secp256k1_sha256_write(acc, bytes, sizeof(bytes));
+ secp256k1_sha256_write(secp256k1_get_hash_context(CTX), acc, bytes, sizeof(bytes));
}
}
@@ -5493,7 +5702,7 @@ static void test_ecmult_constants_2bit(void) {
test_ecmult_accumulate(&acc, &x, scratch);
}
}
- secp256k1_sha256_finalize(&acc, b32);
+ secp256k1_sha256_finalize(secp256k1_get_hash_context(CTX), &acc, b32);
CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0);
secp256k1_scratch_space_destroy(CTX, scratch);
@@ -5512,6 +5721,7 @@ 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;
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(CTX, 65536);
inp[0] = prefix & 0xFF;
@@ -5531,12 +5741,12 @@ static void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsign
inp[4] = i & 0xff;
inp[5] = (i >> 8) & 0xff;
secp256k1_sha256_initialize(&gen);
- secp256k1_sha256_write(&gen, inp, sizeof(inp));
- secp256k1_sha256_finalize(&gen, b32);
+ secp256k1_sha256_write(hash_ctx, &gen, inp, sizeof(inp));
+ secp256k1_sha256_finalize(hash_ctx, &gen, b32);
secp256k1_scalar_set_b32(&x, b32, NULL);
test_ecmult_accumulate(&acc, &x, scratch);
}
- secp256k1_sha256_finalize(&acc, b32);
+ secp256k1_sha256_finalize(hash_ctx, &acc, b32);
CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0);
secp256k1_scratch_space_destroy(CTX, scratch);
@@ -5590,7 +5800,7 @@ static void test_ecmult_gen_blind(void) {
testrand256(seed32);
b = CTX->ecmult_gen_ctx.scalar_offset;
p = CTX->ecmult_gen_ctx.ge_offset;
- secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, seed32);
+ secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, secp256k1_get_hash_context(CTX), seed32);
CHECK(!secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset));
secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej2, &key);
CHECK(!gej_xyz_equals_gej(&pgej, &pgej2));
@@ -5603,10 +5813,10 @@ static void test_ecmult_gen_blind_reset(void) {
/* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */
secp256k1_scalar b;
secp256k1_ge p1, p2;
- secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0);
+ secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, secp256k1_get_hash_context(CTX), 0);
b = CTX->ecmult_gen_ctx.scalar_offset;
p1 = CTX->ecmult_gen_ctx.ge_offset;
- secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, 0);
+ secp256k1_ecmult_gen_blind(&CTX->ecmult_gen_ctx, secp256k1_get_hash_context(CTX), 0);
CHECK(secp256k1_scalar_eq(&b, &CTX->ecmult_gen_ctx.scalar_offset));
p2 = CTX->ecmult_gen_ctx.ge_offset;
CHECK(secp256k1_ge_eq_var(&p1, &p2));
@@ -5684,7 +5894,7 @@ static void run_endomorphism_tests(void) {
testutil_random_scalar_order_test(&full);
test_scalar_split(&full);
}
- for (i = 0; i < sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); ++i) {
+ for (i = 0; i < ARRAY_SIZE(scalars_near_split_bounds); ++i) {
test_scalar_split(&scalars_near_split_bounds[i]);
}
}
@@ -7068,7 +7278,7 @@ static void run_ecdsa_der_parse(void) {
}
/* Tests several edge cases. */
-static void test_ecdsa_edge_cases(void) {
+static void run_ecdsa_edge_cases(void) {
int t;
secp256k1_ecdsa_signature sig;
@@ -7401,8 +7611,25 @@ static void test_ecdsa_edge_cases(void) {
}
}
-static void run_ecdsa_edge_cases(void) {
- test_ecdsa_edge_cases();
+DEFINE_SHA256_TRANSFORM_PROBE(sha256_ecdsa)
+static void ecdsa_ctx_sha256(void) {
+ /* Check ctx-provided SHA256 compression override takes effect */
+ secp256k1_context *ctx = secp256k1_context_clone(CTX);
+ secp256k1_ecdsa_signature out_default, out_custom;
+ unsigned char sk[32] = {1}, msg32[32] = {1};
+
+ /* Default behavior. No ctx-provided SHA256 compression */
+ CHECK(secp256k1_ecdsa_sign(ctx, &out_default, msg32, sk, NULL, NULL));
+ CHECK(!sha256_ecdsa_called);
+
+ /* Override SHA256 compression directly, bypassing the ctx setter sanity checks */
+ ctx->hash_ctx.fn_sha256_compression = sha256_ecdsa;
+ CHECK(secp256k1_ecdsa_sign(ctx, &out_custom, msg32, sk, NULL, NULL));
+ CHECK(sha256_ecdsa_called);
+ /* Outputs must differ if custom compression was used */
+ CHECK(secp256k1_memcmp_var(out_default.data, out_custom.data, 64) != 0);
+
+ secp256k1_context_destroy(ctx);
}
/** Wycheproof tests
@@ -7413,6 +7640,7 @@ static void test_ecdsa_wycheproof(void) {
#include "wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h"
int t;
+ const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
for (t = 0; t < SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS; t++) {
secp256k1_ecdsa_signature signature;
secp256k1_sha256 hasher;
@@ -7427,8 +7655,8 @@ static void test_ecdsa_wycheproof(void) {
secp256k1_sha256_initialize(&hasher);
msg = &wycheproof_ecdsa_messages[testvectors[t].msg_offset];
- secp256k1_sha256_write(&hasher, msg, testvectors[t].msg_len);
- secp256k1_sha256_finalize(&hasher, out);
+ secp256k1_sha256_write(hash_ctx, &hasher, msg, testvectors[t].msg_len);
+ secp256k1_sha256_finalize(hash_ctx, &hasher, out);
sig = &wycheproof_ecdsa_signatures[testvectors[t].sig_offset];
if (secp256k1_ecdsa_signature_parse_der(CTX, &signature, sig, testvectors[t].sig_len) == 1) {
@@ -7692,6 +7920,8 @@ static const struct tf_test_entry tests_general[] = {
CASE(all_static_context_tests),
CASE(deprecated_context_flags_test),
CASE(scratch_tests),
+ CASE(plug_sha256_compression_tests),
+ CASE(sha256_multi_block_compression_tests),
};
static const struct tf_test_entry tests_integer[] = {
@@ -7709,6 +7939,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[] = {
@@ -7761,6 +7992,7 @@ static const struct tf_test_entry tests_ecdsa[] = {
CASE(ecdsa_end_to_end),
CASE(ecdsa_edge_cases),
CASE(ecdsa_wycheproof),
+ CASE1(ecdsa_ctx_sha256),
};
static const struct tf_test_entry tests_utils[] = {
@@ -7837,7 +8069,7 @@ static int teardown(void) {
int main(int argc, char **argv) {
struct tf_framework tf = {0};
tf.registry_modules = registry_modules;
- tf.num_modules = sizeof(registry_modules) / sizeof(registry_modules[0]);
+ tf.num_modules = ARRAY_SIZE(registry_modules);
tf.registry_no_rng = ®istry_modules_no_rng;
/* Add context creation/destruction functions */
@@ -7848,4 +8080,3 @@ int main(int argc, char **argv) {
if (tf_init(&tf, argc, argv) != 0) return EXIT_FAILURE;
return tf_run(&tf);
}
-
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;
}
diff --git a/src/testutil.h b/src/testutil.h
index 93ee3d58..8fa69a02 100644
--- a/src/testutil.h
+++ b/src/testutil.h
@@ -11,6 +11,15 @@
#include "testrand.h"
#include "util.h"
+/* Helper for when we need to check that the ctx-provided sha256 compression 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); \
+ s[0] ^= 0xdeadbeef; /* intentional perturbation for testing */ \
+ }
+
/* 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,
diff --git a/src/unit_test.h b/src/unit_test.h
index bf301e53..5259efbf 100644
--- a/src/unit_test.h
+++ b/src/unit_test.h
@@ -6,6 +6,8 @@
#ifndef SECP256K1_UNIT_TEST_H
#define SECP256K1_UNIT_TEST_H
+#include "util.h"
+
/* --------------------------------------------------------- */
/* Configurable constants */
/* --------------------------------------------------------- */
@@ -27,7 +29,7 @@
#define MAKE_TEST_MODULE(name) { \
#name, \
tests_##name, \
- sizeof(tests_##name) / sizeof(tests_##name[0]) \
+ ARRAY_SIZE(tests_##name) \
}
/* Macro to wrap a test internal function with a COUNT loop (iterations number) */
diff --git a/src/util.h b/src/util.h
index 46ab3810..5d03e4c7 100644
--- a/src/util.h
+++ b/src/util.h
@@ -181,6 +181,8 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_
#define ROUND_TO_ALIGN(size) (CEIL_DIV(size, ALIGNMENT) * ALIGNMENT)
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
/* Macro for restrict, when available and not in a VERIFY build. */
#if defined(SECP256K1_BUILD) && defined(VERIFY)
# define SECP256K1_RESTRICT
Why this scored 34/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.