From 1f3f0a4e2200dbf84a7ca0cae2b0073dfcb5013a Mon Sep 17 00:00:00 2001 From: fanquake Date: Thu, 18 Jun 2026 09:38:02 +0200 Subject: [PATCH] Squashed 'src/secp256k1/' changes from 7262adb4b4..bd0287d650 bd0287d650 Merge bitcoin-core/secp256k1#1859: field: force-inline 5x52 mul and sqr fdcf2d41e2 Merge bitcoin-core/secp256k1#1865: test: enable -Wunused-function in test suite (Fix #1831) b2d2bd362d Merge bitcoin-core/secp256k1#1860: cmake: Emulate Libtool's behavior on NetBSD and OpenBSD 87bec430bf Merge bitcoin-core/secp256k1#1867: test: musig: fix dead "aggnonce encodes two points at infinity" check 71fcd8410e field: force-inline 5x52 mul and sqr a77dacad9a test: enable -Wunused-function in test suite (Fix #1831) aea86bc350 Merge bitcoin-core/secp256k1#1864: test: refactor: simplify tests by using `_ecmult_gen_ge` helper, add test 2ee79e77e6 test: add unit test for `_ecmult_gen_ge` d7125e517d test: musig: fix dead "aggnonce encodes two points at infinity" check 1eab757207 cmake: Fix shared library versioning on OpenBSD a401c5145a cmake: Fix shared library versioning on NetBSD 8a0f4002c7 cmake, refactor: Improve documenting in `SetLibtoolAbiVersion` module acf2084aa7 cmake, refactor: Introduce `SetLibtoolAbiVersion` module 0f4a7e6bf9 Merge bitcoin-core/secp256k1#1855: bench: add internal benchmark for `secp256k1_fe_normalize_var` ca68daf8e1 test: refactor: simplify tests by using `_ecmult_gen_ge` helper 13db747f2b Merge bitcoin-core/secp256k1#1861: refactor: introduce `_ecmult_gen_ge` helper (preventing accidental gej leaks) 9e017e5062 refactor: rename `_ecmult_gen` -> `_ecmult_gen_gej` for consistency a3296d5e23 refactor: introduce `_ecmult_gen_ge` helper (preventing accidental gej leaks) c63062380f Merge bitcoin-core/secp256k1#1852: Add exhaustive test for ECDH module 240578eef5 bench: add internal benchmark for `secp256k1_fe_normalize_var` 5698e66c64 Add exhaustive test for ECDH module a39093de15 Merge bitcoin-core/secp256k1#1851: doc: correct API docs for ECDSA signing out-params (s/array/signature object/) 8363a2d8d1 Merge bitcoin-core/secp256k1#1854: tests: compare full MuSig aggregate nonce af1fdd1215 tests: compare full MuSig aggregate nonce 40a0d874a6 doc: correct API docs for ECDSA signing out-params (s/array/signature object/) b11340b3ce Merge bitcoin-core/secp256k1#1849: musig: always clear out secret key in `secp256k1_musig_nonce_gen_counter` 8479eafa57 musig: always clear out secret key in `secp256k1_musig_nonce_gen_counter` c1a9e4fe64 Merge bitcoin-core/secp256k1#1848: ci: Bump GCC snapshot major version to 17 3cca6451a2 ci: Bump GCC snapshot major version to 17 ea174fe045 Merge bitcoin-core/secp256k1#1846: ci: Replace `ilammy/msvc-dev-cmd` with manual MSVC setup 285cb788e9 ci: Replace `ilammy/msvc-dev-cmd` with manual MSVC setup git-subtree-dir: src/secp256k1 git-subtree-split: bd0287d650c24dc41e0362675a9f6a49ee952def --- .github/workflows/ci.yml | 5 +- CMakeLists.txt | 2 + ci/linux-debian.Dockerfile | 2 +- cmake/SetLibtoolAbiVersion.cmake | 61 ++++++++++++++++++++++ include/secp256k1.h | 2 +- include/secp256k1_recovery.h | 2 +- src/CMakeLists.txt | 33 ++---------- src/bench_ecmult.c | 4 +- src/bench_internal.c | 12 +++++ src/ctime_tests.c | 9 ++++ src/ecdsa_impl.h | 5 +- src/ecmult_gen.h | 3 +- src/ecmult_gen_impl.h | 16 ++++-- src/field_5x52_impl.h | 4 +- src/field_5x52_int128_impl.h | 4 +- src/modules/ecdh/Makefile.am.include | 1 + src/modules/ecdh/tests_exhaustive_impl.h | 56 +++++++++++++++++++++ src/modules/musig/session_impl.h | 8 ++- src/modules/musig/tests_impl.h | 4 +- src/modules/schnorrsig/main_impl.h | 5 +- src/secp256k1.c | 5 +- src/tests.c | 64 ++++++++++++++++-------- src/tests_exhaustive.c | 20 ++++++-- src/unit_test.c | 9 ++++ src/util.h | 11 ++++ 25 files changed, 257 insertions(+), 90 deletions(-) create mode 100644 cmake/SetLibtoolAbiVersion.cmake create mode 100644 src/modules/ecdh/tests_exhaustive_impl.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 152f9a1f4d6..9b836cd6d6e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -604,11 +604,10 @@ jobs: steps: - *CHECKOUT - - name: Add cl.exe to PATH - uses: ilammy/msvc-dev-cmd@v1 - - name: C++ (public headers) + shell: cmd run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" cl.exe -c -WX -TP include/*.h cxx_fpermissive_debian: diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ef69c08913..a84305c340f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,6 +147,8 @@ if(MSVC) string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") + # Match GCC/Clang's size-optimization macro for the inline guard + add_compile_definitions($<$:__OPTIMIZE_SIZE__=1>) else() string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") diff --git a/ci/linux-debian.Dockerfile b/ci/linux-debian.Dockerfile index a575d9b1c48..e743cda8598 100644 --- a/ci/linux-debian.Dockerfile +++ b/ci/linux-debian.Dockerfile @@ -40,7 +40,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-instal apt-get clean && rm -rf /var/lib/apt/lists/* # Build and install gcc snapshot -ARG GCC_SNAPSHOT_MAJOR=16 +ARG GCC_SNAPSHOT_MAJOR=17 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ wget libgmp-dev libmpfr-dev libmpc-dev flex && \ mkdir gcc && cd gcc && \ diff --git a/cmake/SetLibtoolAbiVersion.cmake b/cmake/SetLibtoolAbiVersion.cmake new file mode 100644 index 00000000000..0e981053df7 --- /dev/null +++ b/cmake/SetLibtoolAbiVersion.cmake @@ -0,0 +1,61 @@ +#[=[ +This emulates Libtool to make sure Libtool and CMake agree on +the ABI version and file naming for shared libraries. + +The `version_type` variable is set in `libtool.m4` (installed +by autoreconf into autotools-aux/m4/). +For the `major` and `versuffix` variables, see below "Calculate +the version variables" in `ltmain.sh` (installed by autoreconf +into autotools-aux/). +]=] +function(set_libtool_abi_version target current revision age) + if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD)$") + # version_type = linux | freebsd-elf + # major = $current - $age + # versuffix = $major.$age.$revision + math(EXPR _major "${current} - ${age}") + set_target_properties(${target} PROPERTIES + SOVERSION ${_major} + VERSION ${_major}.${age}.${revision} + ) + elseif(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") + # version_type = sunos + # major = $current + # versuffix = $current.$revision + set_target_properties(${target} PROPERTIES + SOVERSION ${current} + VERSION ${current}.${revision} + ) + elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + # version_type = sunos + # major = $current + # versuffix = $current.$revision + set_target_properties(${target} PROPERTIES + # OpenBSD has no `soname_spec` defined in `libtool.m4`. + VERSION ${current}.${revision} + ) + elseif(APPLE) + # version_type = darwin + # major = $current - $age + math(EXPR _major "${current} - ${age}") + math(EXPR _compatibility "${current} + 1") + set_target_properties(${target} PROPERTIES + SOVERSION ${_major} + MACHO_COMPATIBILITY_VERSION ${_compatibility} + MACHO_CURRENT_VERSION ${_compatibility}.${revision} + ) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + # version_type = windows + # major = $current - $age + # versuffix = $major + math(EXPR _major "${current} - ${age}") + set(_windows_name "secp256k1") + if(MSVC) + set(_windows_name "${PROJECT_NAME}") + endif() + set_target_properties(${target} PROPERTIES + ARCHIVE_OUTPUT_NAME "${_windows_name}" + RUNTIME_OUTPUT_NAME "${_windows_name}-${_major}" + ) + endif() +endfunction() diff --git a/include/secp256k1.h b/include/secp256k1.h index b7ec6a22831..2f3383e16ab 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -687,7 +687,7 @@ SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_default; * Returns: 1: signature created * 0: the nonce generation function failed, or the secret key was invalid. * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: sig: pointer to an array where the signature will be placed. + * Out: sig: pointer to a signature object. * In: msghash32: the 32-byte message hash being signed. * seckey: pointer to a 32-byte secret key. * noncefp: pointer to a nonce generation function. If NULL, diff --git a/include/secp256k1_recovery.h b/include/secp256k1_recovery.h index 2430f993971..45f20aba764 100644 --- a/include/secp256k1_recovery.h +++ b/include/secp256k1_recovery.h @@ -73,7 +73,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( * Returns: 1: signature created * 0: the nonce generation function failed, or the secret key was invalid. * Args: ctx: pointer to a context object (not secp256k1_context_static). - * Out: sig: pointer to an array where the signature will be placed. + * Out: sig: pointer to a signature object. * In: msghash32: the 32-byte message hash being signed. * seckey: pointer to a 32-byte secret key. * noncefp: pointer to a nonce generation function. If NULL, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 322f1987dde..a45eeb93e45 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -94,35 +94,12 @@ set_target_properties(secp256k1_objs PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "$" ) -# This emulates Libtool to make sure Libtool and CMake agree on the ABI version, -# see below "Calculate the version variables" in autotools-aux/ltmain.sh. -math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}") -set_target_properties(secp256k1 PROPERTIES - SOVERSION ${${PROJECT_NAME}_soversion} +include(SetLibtoolAbiVersion) +set_libtool_abi_version(secp256k1 + ${${PROJECT_NAME}_LIB_VERSION_CURRENT} + ${${PROJECT_NAME}_LIB_VERSION_REVISION} + ${${PROJECT_NAME}_LIB_VERSION_AGE} ) -if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD)$") - set_target_properties(secp256k1 PROPERTIES - VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION} - ) -elseif(APPLE) - math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1") - set_target_properties(secp256k1 PROPERTIES - MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version} - MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION} - ) - unset(${PROJECT_NAME}_compatibility_version) -elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(${PROJECT_NAME}_windows "secp256k1") - if(MSVC) - set(${PROJECT_NAME}_windows "${PROJECT_NAME}") - endif() - set_target_properties(secp256k1 PROPERTIES - ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}" - RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}" - ) - unset(${PROJECT_NAME}_windows) -endif() -unset(${PROJECT_NAME}_soversion) if(SECP256K1_BUILD_BENCHMARK) add_executable(bench bench.c) diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c index eb546db414a..12d550a6aeb 100644 --- a/src/bench_ecmult.c +++ b/src/bench_ecmult.c @@ -88,7 +88,7 @@ static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset secp256k1_scalar_add(&sum_scalars, &sum_scalars, &s); } } - secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars); + secp256k1_ecmult_gen_gej(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars); CHECK(secp256k1_gej_eq_var(&tmp, &sum_output)); } @@ -104,7 +104,7 @@ static void bench_ecmult_gen(void* arg, int iters) { int i; for (i = 0; i < iters; ++i) { - secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) % POINTS]); + secp256k1_ecmult_gen_gej(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) % POINTS]); } } diff --git a/src/bench_internal.c b/src/bench_internal.c index f3c1be987f7..453f3bb3f83 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -194,6 +194,17 @@ static void bench_field_normalize(void* arg, int iters) { } } +static void bench_field_normalize_var(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + + /* Note that this benchmark measures the optimistic path. The worst-case path with the final + reduction is very unlikely to be needed, so this is representative of the common case. */ + for (i = 0; i < iters; i++) { + secp256k1_fe_normalize_var(&data->fe[0]); + } +} + static void bench_field_normalize_weak(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -421,6 +432,7 @@ int main(int argc, char **argv) { if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "half")) run_benchmark("field_half", bench_field_half, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, iters*100); + if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_var", bench_field_normalize_var, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10); diff --git a/src/ctime_tests.c b/src/ctime_tests.c index f80042a8e86..8a885ca2b4f 100644 --- a/src/ctime_tests.c +++ b/src/ctime_tests.c @@ -40,6 +40,11 @@ #include "../include/secp256k1_ellswift.h" #endif +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic warning "-Wunused-function" +#endif + static void run_tests(secp256k1_context *ctx, unsigned char *key); int main(void) { @@ -265,3 +270,7 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) { #endif } + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h index 163539ebc14..32f1e58500b 100644 --- a/src/ecdsa_impl.h +++ b/src/ecdsa_impl.h @@ -273,14 +273,12 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25 static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) { unsigned char b[32]; - secp256k1_gej rp; secp256k1_ge r; secp256k1_scalar n; int overflow = 0; int high; - secp256k1_ecmult_gen(ctx, &rp, nonce); - secp256k1_ge_set_gej(&r, &rp); + secp256k1_ecmult_gen_ge(ctx, &r, nonce); secp256k1_fe_normalize(&r.x); secp256k1_fe_normalize(&r.y); secp256k1_fe_get_b32(b, &r.x); @@ -296,7 +294,6 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec secp256k1_scalar_inverse(sigs, nonce); secp256k1_scalar_mul(sigs, sigs, &n); secp256k1_scalar_clear(&n); - secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); high = secp256k1_scalar_is_high(sigs); secp256k1_scalar_cond_negate(sigs, high); diff --git a/src/ecmult_gen.h b/src/ecmult_gen.h index 8bc4f14c310..770b2cb21a1 100644 --- a/src/ecmult_gen.h +++ b/src/ecmult_gen.h @@ -137,7 +137,8 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* 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_gej(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); +static void secp256k1_ecmult_gen_ge(const secp256k1_ecmult_gen_context* ctx, secp256k1_ge *r, const secp256k1_scalar *a); static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32); diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h index 5a954977ebe..a7a6d34d71b 100644 --- a/src/ecmult_gen_impl.h +++ b/src/ecmult_gen_impl.h @@ -51,7 +51,7 @@ static void secp256k1_ecmult_gen_scalar_diff(secp256k1_scalar* diff) { secp256k1_scalar_add(diff, diff, &neghalf); } -static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { +static void secp256k1_ecmult_gen_gej(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { uint32_t comb_off; secp256k1_ge add; secp256k1_fe neg; @@ -281,11 +281,19 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25 secp256k1_memclear_explicit(&recoded, sizeof(recoded)); } +SECP256K1_INLINE static void secp256k1_ecmult_gen_ge(const secp256k1_ecmult_gen_context *ctx, secp256k1_ge *r, const secp256k1_scalar *a) { + secp256k1_gej rj; + secp256k1_ecmult_gen_gej(ctx, &rj, a); + secp256k1_ge_set_gej(r, &rj); + /* Jacobian coordinates resulting from our multiplication algorithm could potentially leak + * information about the secret input scalar, so clear the memory out to be on the safe side. */ + secp256k1_gej_clear(&rj); +} + /* Setup blinding values for secp256k1_ecmult_gen. */ 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; secp256k1_fe f; unsigned char nonce32[32]; secp256k1_rfc6979_hmac_sha256 rng; @@ -325,15 +333,13 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const * which secp256k1_gej_add_ge cannot handle. */ secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b)); secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_ecmult_gen(ctx, &gb, &b); + secp256k1_ecmult_gen_ge(ctx, &ctx->ge_offset, &b); secp256k1_scalar_negate(&b, &b); secp256k1_scalar_add(&ctx->scalar_offset, &b, &diff); - secp256k1_ge_set_gej(&ctx->ge_offset, &gb); /* Clean up. */ secp256k1_memclear_explicit(nonce32, sizeof(nonce32)); secp256k1_scalar_clear(&b); - secp256k1_gej_clear(&gb); secp256k1_fe_clear(&f); secp256k1_rfc6979_hmac_sha256_clear(&rng); } diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index 3a976135ebd..0e0e2d652a7 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -338,11 +338,11 @@ SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp25 r->n[4] += a->n[4]; } -SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { +SECP256K1_FORCE_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { secp256k1_fe_mul_inner(r->n, a->n, b->n); } -SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { +SECP256K1_FORCE_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_fe_sqr_inner(r->n, a->n); } diff --git a/src/field_5x52_int128_impl.h b/src/field_5x52_int128_impl.h index f23f8ee1c44..8d1977b2718 100644 --- a/src/field_5x52_int128_impl.h +++ b/src/field_5x52_int128_impl.h @@ -15,7 +15,7 @@ #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) #define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n))) -SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { +SECP256K1_FORCE_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { secp256k1_uint128 c, d; uint64_t t3, t4, tx, u0; uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; @@ -151,7 +151,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { +SECP256K1_FORCE_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { secp256k1_uint128 c, d; uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; uint64_t t3, t4, tx, u0; diff --git a/src/modules/ecdh/Makefile.am.include b/src/modules/ecdh/Makefile.am.include index 18660535291..81bc6279173 100644 --- a/src/modules/ecdh/Makefile.am.include +++ b/src/modules/ecdh/Makefile.am.include @@ -1,5 +1,6 @@ include_HEADERS += include/secp256k1_ecdh.h noinst_HEADERS += src/modules/ecdh/main_impl.h noinst_HEADERS += src/modules/ecdh/tests_impl.h +noinst_HEADERS += src/modules/ecdh/tests_exhaustive_impl.h noinst_HEADERS += src/modules/ecdh/bench_impl.h noinst_HEADERS += src/wycheproof/ecdh_secp256k1_test.h diff --git a/src/modules/ecdh/tests_exhaustive_impl.h b/src/modules/ecdh/tests_exhaustive_impl.h new file mode 100644 index 00000000000..2bcd243493a --- /dev/null +++ b/src/modules/ecdh/tests_exhaustive_impl.h @@ -0,0 +1,56 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_TESTS_EXHAUSTIVE_H +#define SECP256K1_MODULE_ECDH_TESTS_EXHAUSTIVE_H + +#include "../../../include/secp256k1_ecdh.h" +#include "main_impl.h" + +static void test_exhaustive_ecdh(const secp256k1_context *ctx, const secp256k1_ge *group) { + int i, j; + unsigned char seckeys[EXHAUSTIVE_TEST_ORDER - 1][32]; + secp256k1_pubkey pubkeys[EXHAUSTIVE_TEST_ORDER - 1]; + + /* Construct key pairs (32-byte secret key, public key object) for the entire group. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + secp256k1_scalar scalar; + secp256k1_scalar_set_int(&scalar, i); + secp256k1_scalar_get_b32(seckeys[i - 1], &scalar); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkeys[i - 1], seckeys[i - 1])); + } + + /* Loop over key combinations. */ + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { + unsigned char ecdh_result_ij[32]; + unsigned char ecdh_result_ji[32]; + + /* Calculate ECDH(i*G, j) and ECDH(j*G, i) using API function and verify that the results match. */ + CHECK(secp256k1_ecdh(ctx, ecdh_result_ij, &pubkeys[i - 1], seckeys[j - 1], NULL, NULL)); + CHECK(secp256k1_ecdh(ctx, ecdh_result_ji, &pubkeys[j - 1], seckeys[i - 1], NULL, NULL)); + CHECK(secp256k1_memcmp_var(ecdh_result_ij, ecdh_result_ji, 32) == 0); + + /* Recalculate the expected ECDH result manually by invoking the default ECDH hash + * function on the precomputed group element (group[i * j]) coordinates, and verify + * that it matches the previously calculated public API results. */ + { + secp256k1_ge ecdh_ge_expected = group[(i * j) % EXHAUSTIVE_TEST_ORDER]; + unsigned char ecdh_result_expected[32]; + unsigned char x[32]; + unsigned char y[32]; + + secp256k1_fe_normalize_var(&ecdh_ge_expected.x); + secp256k1_fe_normalize_var(&ecdh_ge_expected.y); + secp256k1_fe_get_b32(x, &ecdh_ge_expected.x); + secp256k1_fe_get_b32(y, &ecdh_ge_expected.y); + CHECK(secp256k1_ecdh_hash_function_default(ecdh_result_expected, x, y, NULL)); + CHECK(secp256k1_memcmp_var(ecdh_result_ij, ecdh_result_expected, 32) == 0); + } + } + } +} + +#endif diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index 6a37bfdf8e0..c05801eecf0 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -415,7 +415,7 @@ static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp /* Compute pubnonce as two gejs */ for (i = 0; i < 2; i++) { - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj[i], &k[i]); + secp256k1_ecmult_gen_gej(&ctx->ecmult_gen_ctx, &nonce_ptj[i], &k[i]); secp256k1_scalar_clear(&k[i]); } @@ -483,11 +483,9 @@ int secp256k1_musig_nonce_gen_counter(const secp256k1_context* ctx, secp256k1_mu (void) ret; #endif - if (!secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, &pubkey, msg32, keyagg_cache, extra_input32)) { - return 0; - } + ret = secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, &pubkey, msg32, keyagg_cache, extra_input32); secp256k1_memclear_explicit(seckey, sizeof(seckey)); - return 1; + return ret; } static int secp256k1_musig_sum_pubnonces(const secp256k1_context* ctx, secp256k1_gej *summed_pubnonces, const secp256k1_musig_pubnonce * const* pubnonces, size_t n_pubnonces) { diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index cc6449166a7..3a30c233a00 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -374,7 +374,7 @@ static void musig_api_tests(void) { secp256k1_ge aggnonce_pt[2]; secp256k1_musig_aggnonce_load(CTX, aggnonce_pt, &aggnonce); for (i = 0; i < 2; i++) { - secp256k1_ge_is_infinity(&aggnonce_pt[i]); + CHECK(secp256k1_ge_is_infinity(&aggnonce_pt[i]) == 1); } } CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); @@ -862,7 +862,7 @@ static void musig_test_vectors_nonceagg(void) { } CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2)); CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce66, &aggnonce)); - CHECK(secp256k1_memcmp_var(aggnonce66, c->expected, 33) == 0); + CHECK(secp256k1_memcmp_var(aggnonce66, c->expected, sizeof(aggnonce66)) == 0); } for (i = 0; i < ARRAY_SIZE(vector->error_case); i++) { const struct musig_nonce_agg_test_case *c = &vector->error_case[i]; diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index 5100557f4dd..efc7216546d 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -123,7 +123,6 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi secp256k1_scalar sk; secp256k1_scalar e; secp256k1_scalar k; - secp256k1_gej rj; secp256k1_ge pk; secp256k1_ge r; unsigned char nonce32[32] = { 0 }; @@ -160,8 +159,7 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi ret &= !secp256k1_scalar_is_zero(&k); secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k); - secp256k1_ge_set_gej(&r, &rj); + secp256k1_ecmult_gen_ge(&ctx->ecmult_gen_ctx, &r, &k); /* We declassify r to allow using it as a branch point. This is fine * because r is not a secret. */ @@ -183,7 +181,6 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi secp256k1_scalar_clear(&sk); secp256k1_memclear_explicit(seckey, sizeof(seckey)); secp256k1_memclear_explicit(nonce32, sizeof(nonce32)); - secp256k1_gej_clear(&rj); return ret; } diff --git a/src/secp256k1.c b/src/secp256k1.c index e4b80fff24c..b216872e12a 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -624,15 +624,12 @@ int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char } static int secp256k1_ec_pubkey_create_helper(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_scalar *seckey_scalar, secp256k1_ge *p, const unsigned char *seckey) { - secp256k1_gej pj; int ret; ret = secp256k1_scalar_set_b32_seckey(seckey_scalar, seckey); secp256k1_scalar_cmov(seckey_scalar, &secp256k1_scalar_one, !ret); - secp256k1_ecmult_gen(ecmult_gen_ctx, &pj, seckey_scalar); - secp256k1_ge_set_gej(p, &pj); - secp256k1_gej_clear(&pj); + secp256k1_ecmult_gen_ge(ecmult_gen_ctx, p, seckey_scalar); return ret; } diff --git a/src/tests.c b/src/tests.c index 862bef61a7c..6c3cd39f2fe 100644 --- a/src/tests.c +++ b/src/tests.c @@ -37,6 +37,11 @@ #include "int128_impl.h" #endif +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic warning "-Wunused-function" +#endif + #define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else static secp256k1_context *CTX = NULL; @@ -241,7 +246,6 @@ static void run_proper_context_tests(int use_prealloc) { void *my_ctx_prealloc = NULL; unsigned char seed[32] = {0x17}; - secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar msg, key, nonce; secp256k1_scalar sigr, sigs; @@ -329,8 +333,7 @@ static void run_proper_context_tests(int use_prealloc) { /*** attempt to use them ***/ testutil_random_scalar_order_test(&msg); testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen(&my_ctx->ecmult_gen_ctx, &pubj, &key); - secp256k1_ge_set_gej(&pub, &pubj); + secp256k1_ecmult_gen_ge(&my_ctx->ecmult_gen_ctx, &pub, &key); /* obtain a working nonce */ do { @@ -4304,19 +4307,16 @@ static void test_ec_combine(void) { const secp256k1_pubkey* d[6]; secp256k1_pubkey sd; secp256k1_pubkey sd2; - secp256k1_gej Qj; secp256k1_ge Q; int i; for (i = 1; i <= 6; i++) { secp256k1_scalar s; testutil_random_scalar_order_test(&s); secp256k1_scalar_add(&sum, &sum, &s); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &s); - secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &Q, &s); secp256k1_pubkey_save(&data[i - 1], &Q); d[i - 1] = &data[i - 1]; - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &Qj, &sum); - secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &Q, &sum); secp256k1_pubkey_save(&sd, &Q); CHECK(secp256k1_ec_pubkey_combine(CTX, &sd2, d, i) == 1); CHECK(secp256k1_memcmp_var(&sd, &sd2, sizeof(sd)) == 0); @@ -4593,9 +4593,9 @@ static void test_ecmult_target(const secp256k1_scalar* target, int mode) { /* EC multiplications */ if (mode == 0) { - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p1j, &n1); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p2j, &n2); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &ptj, target); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &p1j, &n1); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &p2j, &n2); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &ptj, target); } else if (mode == 1) { secp256k1_ecmult(&p1j, &pj, &n1, &secp256k1_scalar_zero); secp256k1_ecmult(&p2j, &pj, &n2, &secp256k1_scalar_zero); @@ -5162,7 +5162,7 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) { secp256k1_scalar_mul(&scalars[filled], &sc_tmp, &g_scalar); secp256k1_scalar_inverse_var(&sc_tmp, &sc_tmp); secp256k1_scalar_negate(&sc_tmp, &sc_tmp); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &gejs[filled], &sc_tmp); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &gejs[filled], &sc_tmp); ++filled; ++mults; } @@ -5642,7 +5642,7 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar size_t i; secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); secp256k1_gej_set_infinity(&infj); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &rj[0], x); + secp256k1_ecmult_gen_gej(&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); @@ -5786,6 +5786,25 @@ static void run_ecmult_constants(void) { } } +static void run_ecmult_gen_ge(void) { + /* Test that secp256k1_ecmult_gen_ge result matches secp256k1_ecmult_gen_gej with + * manual Jacobian-to-affine conversion (secp256k1_ge_set_gej) over random scalars */ + int i; + + for (i = 0; i < COUNT; i++) { + secp256k1_scalar scalar; + secp256k1_gej result_gej; + secp256k1_ge result_ge, expected_ge; + + testutil_random_scalar_order_test(&scalar); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &result_gej, &scalar); + secp256k1_ge_set_gej(&expected_ge, &result_gej); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &result_ge, &scalar); + + CHECK(secp256k1_ge_eq_var(&result_ge, &expected_ge)); + } +} + static void test_ecmult_gen_blind(void) { /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ secp256k1_scalar key; @@ -5796,13 +5815,13 @@ static void test_ecmult_gen_blind(void) { secp256k1_ge p; secp256k1_ge pge; testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pgej, &key); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &pgej, &key); testrand256(seed32); b = CTX->ecmult_gen_ctx.scalar_offset; p = CTX->ecmult_gen_ctx.ge_offset; 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); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &pgej2, &key); CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); CHECK(!secp256k1_ge_eq_var(&p, &CTX->ecmult_gen_ctx.ge_offset)); secp256k1_ge_set_gej(&pge, &pgej); @@ -5832,7 +5851,7 @@ static void test_ecmult_gen_edge_cases(void) { for (i = -1; i < 2; ++i) { /* Run test with gn = i - scalar_offset (so that the ecmult_gen recoded value represents i). */ - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &res1, &gn); + secp256k1_ecmult_gen_gej(&CTX->ecmult_gen_ctx, &res1, &gn); secp256k1_ecmult(&res2, NULL, &secp256k1_scalar_zero, &gn); secp256k1_ecmult_const(&res3, &secp256k1_ge_const_g, &gn); CHECK(secp256k1_gej_eq_var(&res1, &res2)); @@ -6515,7 +6534,6 @@ static void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const se } static void test_ecdsa_sign_verify(void) { - secp256k1_gej pubj; secp256k1_ge pub; secp256k1_scalar one; secp256k1_scalar msg, key; @@ -6524,8 +6542,7 @@ static void test_ecdsa_sign_verify(void) { int recid; testutil_random_scalar_order_test(&msg); testutil_random_scalar_order_test(&key); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubj, &key); - secp256k1_ge_set_gej(&pub, &pubj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &pub, &key); getrec = testrand_bits(1); /* The specific way in which this conditional is written sidesteps a potential bug in clang. See the commit messages of the commit that introduced this comment for details. */ @@ -7284,7 +7301,6 @@ static void run_ecdsa_edge_cases(void) { /* Test the case where ECDSA recomputes a point that is infinity. */ { - secp256k1_gej keyj; secp256k1_ge key; secp256k1_scalar msg; secp256k1_scalar sr, ss; @@ -7292,8 +7308,7 @@ static void run_ecdsa_edge_cases(void) { secp256k1_scalar_negate(&ss, &ss); secp256k1_scalar_inverse(&ss, &ss); secp256k1_scalar_set_int(&sr, 1); - secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &keyj, &sr); - secp256k1_ge_set_gej(&key, &keyj); + secp256k1_ecmult_gen_ge(&CTX->ecmult_gen_ctx, &key, &sr); msg = ss; CHECK(secp256k1_ecdsa_sig_verify(&sr, &ss, &key, &msg) == 0); } @@ -7969,6 +7984,7 @@ static const struct tf_test_entry tests_ecmult[] = { CASE(ecmult_near_split_bound), CASE(ecmult_chain), CASE(ecmult_constants), + CASE(ecmult_gen_ge), CASE(ecmult_gen_blind), CASE(ecmult_const_tests), CASE(ecmult_multi_tests), @@ -8080,3 +8096,7 @@ int main(int argc, char **argv) { if (tf_init(&tf, argc, argv) != 0) return EXIT_FAILURE; return tf_run(&tf); } + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index 68d4bec3f07..99d7b2448d4 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -31,6 +31,11 @@ #include "testutil.h" #include "util.h" +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic warning "-Wunused-function" +#endif + static int count = 2; static uint32_t num_cores = 1; @@ -337,6 +342,10 @@ static void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_g */ } +#ifdef ENABLE_MODULE_ECDH +#include "modules/ecdh/tests_exhaustive_impl.h" +#endif + #ifdef ENABLE_MODULE_RECOVERY #include "modules/recovery/tests_exhaustive_impl.h" #endif @@ -417,12 +426,10 @@ int main(int argc, char** argv) { /* Verify against ecmult_gen */ { secp256k1_scalar scalar_i; - secp256k1_gej generatedj; secp256k1_ge generated; secp256k1_scalar_set_int(&scalar_i, i); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); - secp256k1_ge_set_gej(&generated, &generatedj); + secp256k1_ecmult_gen_ge(&ctx->ecmult_gen_ctx, &generated, &scalar_i); CHECK(!secp256k1_ge_is_infinity(&group[i])); CHECK(secp256k1_ge_eq_var(&group[i], &generated)); @@ -437,6 +444,9 @@ int main(int argc, char** argv) { test_exhaustive_sign(ctx, group); test_exhaustive_verify(ctx, group); +#ifdef ENABLE_MODULE_ECDH + test_exhaustive_ecdh(ctx, group); +#endif #ifdef ENABLE_MODULE_RECOVERY test_exhaustive_recovery(ctx, group); #endif @@ -462,3 +472,7 @@ int main(int argc, char** argv) { printf("no problems found\n"); return EXIT_SUCCESS; } + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/src/unit_test.c b/src/unit_test.c index a1858a117a7..2ac709cc6c4 100644 --- a/src/unit_test.c +++ b/src/unit_test.c @@ -17,6 +17,11 @@ #include "testrand.h" #include "tests_common.h" +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic warning "-Wunused-function" +#endif + #define UNUSED(x) (void)(x) /* Number of times certain tests will run */ @@ -477,3 +482,7 @@ static int tf_run(struct tf_framework* tf) { return status; } + +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif diff --git a/src/util.h b/src/util.h index 5d03e4c76dd..492a5929ef9 100644 --- a/src/util.h +++ b/src/util.h @@ -57,6 +57,17 @@ static void print_buf_plain(const unsigned char *buf, size_t len) { # define SECP256K1_INLINE inline # endif +# if !defined(_DEBUG) && !defined(__NO_INLINE__) && !defined(__OPTIMIZE_SIZE__) +# if defined(__OPTIMIZE__) && (SECP256K1_GNUC_PREREQ(3, 0) || defined(__clang__)) +# define SECP256K1_FORCE_INLINE SECP256K1_INLINE __attribute__((always_inline)) +# elif defined(_MSC_VER) +# define SECP256K1_FORCE_INLINE __forceinline +# endif +# endif +# ifndef SECP256K1_FORCE_INLINE +# define SECP256K1_FORCE_INLINE SECP256K1_INLINE +# endif + /** Assert statically that expr is true. * * This is a statement-like macro and can only be used inside functions.