diff --git a/.cirrus.yml b/.cirrus.yml index 81a4f0432..023cd1916 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -29,6 +29,8 @@ env: BENCH: yes SECP256K1_BENCH_ITERS: 2 CTIMETESTS: yes + SYMBOL_CHECK: yes + VIRTUAL_ENV: /root/venv # Compile and run the tests EXAMPLES: yes @@ -53,6 +55,7 @@ cat_logs_snippet: &CAT_LOGS linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER env_script: + - export PATH="$VIRTUAL_ENV/bin:$PATH" - env | tee /tmp/env build_script: - DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm" diff --git a/.github/actions/print-logs/action.yml b/.github/actions/print-logs/action.yml new file mode 100644 index 000000000..33de35cb3 --- /dev/null +++ b/.github/actions/print-logs/action.yml @@ -0,0 +1,34 @@ +name: "Print logs" +description: "Print the log files produced by ci/ci.sh" +runs: + using: "composite" + steps: + - shell: bash + run: | + # Print the log files produced by ci/ci.sh + + # Helper functions + group() { + title=$1 + echo "::group::$title" + } + endgroup() { + echo "::endgroup::" + } + cat_file() { + file=$1 + group "$file" + cat "$file" + endgroup + } + + # Print all *.log files + shopt -s nullglob + for file in *.log; do + cat_file "$file" + done + + # Print environment + group "CI env" + env + endgroup diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5673c1384..b39223558 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,7 @@ env: BENCH: 'yes' SECP256K1_BENCH_ITERS: 2 CTIMETESTS: 'yes' + SYMBOL_CHECK: 'yes' # Compile and run the examples. EXAMPLES: 'yes' @@ -114,23 +115,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} i686_debian: name: "i686: Linux (Debian stable)" @@ -172,23 +159,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} s390x_debian: name: "s390x (big-endian): Linux (Debian stable, QEMU)" @@ -226,23 +199,10 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} + arm32_debian: name: "ARM32: Linux (Debian stable, QEMU)" @@ -288,23 +248,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} arm64_debian: name: "ARM64: Linux (Debian stable, QEMU)" @@ -353,23 +299,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} ppc64le_debian: name: "ppc64le: Linux (Debian stable, QEMU)" @@ -407,23 +339,10 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} + valgrind_debian: name: "Valgrind (memcheck)" @@ -471,23 +390,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} sanitizers_debian: name: "UBSan, ASan, LSan" @@ -524,6 +429,7 @@ jobs: ASAN_OPTIONS: 'strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1' LSAN_OPTIONS: 'use_unaligned=1' SECP256K1_TEST_ITERS: 32 + SYMBOL_CHECK: 'no' steps: - name: Checkout @@ -536,23 +442,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} msan_debian: name: "MSan" @@ -596,6 +488,7 @@ jobs: SECP256K1_TEST_ITERS: 32 ASM: 'no' WITH_VALGRIND: 'no' + SYMBOL_CHECK: 'no' steps: - name: Checkout @@ -608,23 +501,10 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} + mingw_debian: name: ${{ matrix.configuration.job_name }} @@ -672,33 +552,19 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} x86_64-macos-native: - name: "x86_64: macOS Ventura, Valgrind" - # See: https://github.com/actions/runner-images#available-images. - runs-on: macos-13 + name: "x86_64: macOS Sequoia, Valgrind" + runs-on: macos-15-intel env: CC: 'clang' HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_INSTALL_CLEANUP: 1 + SYMBOL_CHECK: 'no' strategy: fail-fast: false @@ -731,23 +597,19 @@ jobs: env: ${{ matrix.env_vars }} run: ./ci/ci.sh - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Symbol check + env: + VIRTUAL_ENV: '${{ github.workspace }}/venv' + run: | + python3 --version + python3 -m venv $VIRTUAL_ENV + export PATH="$VIRTUAL_ENV/bin:$PATH" + python3 -m pip install lief + python3 ./tools/symbol-check.py .libs/libsecp256k1.dylib + + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} arm64-macos-native: name: "ARM64: macOS Sonoma" @@ -760,6 +622,7 @@ jobs: HOMEBREW_NO_INSTALL_CLEANUP: 1 WITH_VALGRIND: 'no' CTIMETESTS: 'no' + SYMBOL_CHECK: 'no' strategy: fail-fast: false @@ -787,23 +650,20 @@ jobs: env: ${{ matrix.env_vars }} run: ./ci/ci.sh - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Symbol check + env: + VIRTUAL_ENV: '${{ github.workspace }}/venv' + run: | + python3 --version + python3 -m venv $VIRTUAL_ENV + export PATH="$VIRTUAL_ENV/bin:$PATH" + python3 -m pip install lief + python3 ./tools/symbol-check.py .libs/libsecp256k1.dylib + + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} + win64-native: name: ${{ matrix.configuration.job_name }} @@ -816,6 +676,7 @@ jobs: configuration: - job_name: 'x64 (MSVC): Windows (VS 2022, shared)' cmake_options: '-A x64 -DBUILD_SHARED_LIBS=ON' + symbol_check: 'true' - job_name: 'x64 (MSVC): Windows (VS 2022, static)' cmake_options: '-A x64 -DBUILD_SHARED_LIBS=OFF' - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct)' @@ -825,6 +686,8 @@ jobs: cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE' - job_name: 'x86 (MSVC): Windows (VS 2022)' cmake_options: '-A Win32' + - job_name: 'x64 (MSVC): Windows (clang-cl)' + cmake_options: '-T ClangCL' steps: - name: Checkout @@ -842,6 +705,14 @@ jobs: run: | cd build/bin/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true + - name: Symbol check + if: ${{ matrix.configuration.symbol_check }} + shell: bash + run: | + py -3 --version + py -3 -m pip install lief + py -3 ./tools/symbol-check.py build/bin/RelWithDebInfo/libsecp256k1-*.dll + - name: Check run: | ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1) @@ -900,23 +771,9 @@ jobs: dockerfile: ./ci/linux-debian.Dockerfile tag: linux-debian-image - - run: cat tests.log || true - if: ${{ always() }} - - run: cat noverify_tests.log || true - if: ${{ always() }} - - run: cat exhaustive_tests.log || true - if: ${{ always() }} - - run: cat ctime_tests.log || true - if: ${{ always() }} - - run: cat bench.log || true - if: ${{ always() }} - - run: cat config.log || true - if: ${{ always() }} - - run: cat test_env.log || true - if: ${{ always() }} - - name: CI env - run: env - if: ${{ always() }} + - name: Print logs + uses: ./.github/actions/print-logs + if: ${{ !cancelled() }} cxx_headers_debian: name: "C++ (public headers)" diff --git a/CHANGELOG.md b/CHANGELOG.md index db6267665..ac7cae793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +#### Removed +- Removed previously deprecated function aliases `secp256k1_ec_privkey_negate`, `secp256k1_ec_privkey_tweak_add` and + `secp256k1_ec_privkey_tweak_mul`. Use `secp256k1_ec_seckey_negate`, `secp256k1_ec_seckey_tweak_add` and + `secp256k1_ec_seckey_tweak_mul` instead. + ## [0.6.0] - 2024-11-04 #### Added diff --git a/CMakeLists.txt b/CMakeLists.txt index c93407360..05e497ea3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -295,17 +295,21 @@ endif() include(TryAppendCFlags) if(MSVC) - # Keep the following commands ordered lexicographically. + # For both cl and clang-cl compilers. try_append_c_flags(/W3) # Production quality warning level. + # Eliminate deprecation warnings for the older, less secure functions. + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) +else() + try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers. +endif() +if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") + # Keep the following commands ordered lexicographically. try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned". try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data". try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data". - # Eliminate deprecation warnings for the older, less secure functions. - add_compile_definitions(_CRT_SECURE_NO_WARNINGS) else() # Keep the following commands ordered lexicographically. try_append_c_flags(-pedantic) - try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers. try_append_c_flags(-Wcast-align) # GCC >= 2.95. try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0. try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only. @@ -320,8 +324,6 @@ else() try_append_c_flags(-Wundef) endif() -set(CMAKE_C_VISIBILITY_PRESET hidden) - set(print_msan_notice) if(SECP256K1_BUILD_CTIME_TESTS) include(CheckMemorySanitizer) diff --git a/Makefile.am b/Makefile.am index 9cfa9acd4..5d1cce5c6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -49,6 +49,7 @@ noinst_HEADERS += src/assumptions.h noinst_HEADERS += src/checkmem.h noinst_HEADERS += src/testutil.h noinst_HEADERS += src/util.h +noinst_HEADERS += src/util_local_visibility.h noinst_HEADERS += src/int128.h noinst_HEADERS += src/int128_impl.h noinst_HEADERS += src/int128_native.h diff --git a/ci/ci.sh b/ci/ci.sh index cb6dc1d5b..5921415fa 100755 --- a/ci/ci.sh +++ b/ci/ci.sh @@ -13,9 +13,9 @@ print_environment() { # does not rely on bash. for var in WERROR_CFLAGS MAKEFLAGS BUILD \ ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ - EXPERIMENTAL ECDH RECOVERY EXTRAKEYS SCHNORRSIG MUSIG SCHNORRSIG_HALFAGG ELLSWIFT \ + EXPERIMENTAL ECDH RECOVERY EXTRAKEYS MUSIG SCHNORRSIG SCHNORRSIG_HALFAGG ELLSWIFT \ ECDSA_S2C GENERATOR RANGEPROOF WHITELIST ECDSAADAPTOR BPPP \ - SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ + SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS SYMBOL_CHECK \ EXAMPLES \ HOST WRAPPER_CMD \ CC CFLAGS CPPFLAGS AR NM \ @@ -99,10 +99,10 @@ if [ $build_exit_code -ne 0 ]; then *snapshot*) # Ignore internal compiler errors in gcc-snapshot and clang-snapshot grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log - return $?; + exit $? ;; *) - return 1; + exit 1 ;; esac fi @@ -112,6 +112,20 @@ file *tests* || true file bench* || true file .libs/* || true +if [ "$SYMBOL_CHECK" = "yes" ] +then + python3 --version + case "$HOST" in + *mingw*) + ls -l .libs + python3 ./tools/symbol-check.py .libs/libsecp256k1-*.dll + ;; + *) + python3 ./tools/symbol-check.py .libs/libsecp256k1.so + ;; + esac +fi + # This tells `make check` to wrap test invocations. export LOG_COMPILER="$WRAPPER_CMD" diff --git a/ci/linux-debian.Dockerfile b/ci/linux-debian.Dockerfile index 3cc5f5e15..a601542fc 100644 --- a/ci/linux-debian.Dockerfile +++ b/ci/linux-debian.Dockerfile @@ -32,7 +32,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \ gcc-mingw-w64-x86-64-win32 wine64 wine \ gcc-mingw-w64-i686-win32 wine32 \ - python3 && \ + python3-full && \ if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \ apt-get install --no-install-recommends -y \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 ;\ @@ -80,3 +80,7 @@ RUN \ apt-get autoremove -y wget && \ apt-get clean && rm -rf /var/lib/apt/lists/* +ENV VIRTUAL_ENV=/root/venv +RUN python3 -m venv $VIRTUAL_ENV +ENV PATH="$VIRTUAL_ENV/bin:$PATH" +RUN pip install lief diff --git a/configure.ac b/configure.ac index f84ec5fe2..f07e6a983 100644 --- a/configure.ac +++ b/configure.ac @@ -111,7 +111,6 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [ SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only - SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0 CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" fi @@ -626,6 +625,7 @@ echo "Build Options:" echo " with external callbacks = $enable_external_default_callbacks" echo " with benchmarks = $enable_benchmark" echo " with tests = $enable_tests" +echo " with exhaustive tests = $enable_exhaustive_tests" echo " with ctime tests = $enable_ctime_tests" echo " with coverage = $enable_coverage" echo " with examples = $enable_examples" diff --git a/include/secp256k1.h b/include/secp256k1.h index c6e9417f0..1d25a02ab 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -230,10 +230,10 @@ typedef int (*secp256k1_nonce_function)( * * It is highly recommended to call secp256k1_selftest before using this context. */ -SECP256K1_API const secp256k1_context *secp256k1_context_static; +SECP256K1_API const secp256k1_context * const secp256k1_context_static; /** Deprecated alias for secp256k1_context_static. */ -SECP256K1_API const secp256k1_context *secp256k1_context_no_precomp +SECP256K1_API const secp256k1_context * const secp256k1_context_no_precomp SECP256K1_DEPRECATED("Use secp256k1_context_static instead"); /** Perform basic self tests (to be used in conjunction with secp256k1_context_static) @@ -701,21 +701,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate( unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); -/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in - * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate( - const secp256k1_context *ctx, - unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) - SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead"); - /** Negates a public key in place. * * Returns: 1 always * Args: ctx: pointer to a context object * In/Out: pubkey: pointer to the public key to be negated. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate( +SECP256K1_API int secp256k1_ec_pubkey_negate( const secp256k1_context *ctx, secp256k1_pubkey *pubkey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); @@ -741,15 +733,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add( const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in - * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( - const secp256k1_context *ctx, - unsigned char *seckey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) - SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_add instead"); - /** Tweak a public key by adding tweak times the generator to it. * * Returns: 0 if the arguments are invalid or the resulting public key would be @@ -788,15 +771,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul( const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in - * future versions. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( - const secp256k1_context *ctx, - unsigned char *seckey, - const unsigned char *tweak32 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) - SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_mul instead"); - /** Tweak a public key by multiplying it by a tweak value. * * Returns: 0 if the arguments are invalid. 1 otherwise. @@ -883,7 +857,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( * msg: pointer to an array containing the message * msglen: length of the message array */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256( +SECP256K1_API int secp256k1_tagged_sha256( const secp256k1_context *ctx, unsigned char *hash32, const unsigned char *tag, diff --git a/include/secp256k1_extrakeys.h b/include/secp256k1_extrakeys.h index 48c98693c..1a517ded9 100644 --- a/include/secp256k1_extrakeys.h +++ b/include/secp256k1_extrakeys.h @@ -90,7 +90,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_cmp( * the negation of the pubkey and set to 0 otherwise. * In: pubkey: pointer to a public key that is converted. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey( +SECP256K1_API int secp256k1_xonly_pubkey_from_pubkey( const secp256k1_context *ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, @@ -179,7 +179,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create( * Out: seckey: pointer to a 32-byte buffer for the secret key. * In: keypair: pointer to a keypair. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec( +SECP256K1_API int secp256k1_keypair_sec( const secp256k1_context *ctx, unsigned char *seckey, const secp256k1_keypair *keypair @@ -192,7 +192,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec( * Out: pubkey: pointer to a pubkey object, set to the keypair public key. * In: keypair: pointer to a keypair. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub( +SECP256K1_API int secp256k1_keypair_pub( const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair @@ -211,7 +211,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub( * pk_parity argument of secp256k1_xonly_pubkey_from_pubkey. * In: keypair: pointer to a keypair. */ -SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub( +SECP256K1_API int secp256k1_keypair_xonly_pub( const secp256k1_context *ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, diff --git a/src/eckey_impl.h b/src/eckey_impl.h index 121966f8b..a88a5964d 100644 --- a/src/eckey_impl.h +++ b/src/eckey_impl.h @@ -9,6 +9,7 @@ #include "eckey.h" +#include "util.h" #include "scalar.h" #include "field.h" #include "group.h" @@ -35,6 +36,8 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char } static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { + VERIFY_CHECK(compressed == 0 || compressed == 1); + if (secp256k1_ge_is_infinity(elem)) { return 0; } diff --git a/src/group.h b/src/group.h index 11bfc6262..70968c1c2 100644 --- a/src/group.h +++ b/src/group.h @@ -86,7 +86,11 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); /** Set a group element equal to another which is given in jacobian coordinates. */ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a); -/** Set a batch of group elements equal to the inputs given in jacobian coordinates */ +/** Set group elements r[0:len] (affine) equal to group elements a[0:len] (jacobian). + * None of the group elements in a[0:len] may be infinity. Constant time. */ +static void secp256k1_ge_set_all_gej(secp256k1_ge *r, const secp256k1_gej *a, size_t len); + +/** Set group elements r[0:len] (affine) equal to group elements a[0:len] (jacobian). */ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len); /** Bring a batch of inputs to the same global z "denominator", based on ratios between diff --git a/src/group_impl.h b/src/group_impl.h index 6f87a2b03..326c67ac1 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -195,6 +195,44 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { SECP256K1_GE_VERIFY(r); } +static void secp256k1_ge_set_all_gej(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { + secp256k1_fe u; + size_t i; +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GEJ_VERIFY(&a[i]); + VERIFY_CHECK(!secp256k1_gej_is_infinity(&a[i])); + } +#endif + + if (len == 0) { + return; + } + + /* Use destination's x coordinates as scratch space */ + r[0].x = a[0].z; + for (i = 1; i < len; i++) { + secp256k1_fe_mul(&r[i].x, &r[i - 1].x, &a[i].z); + } + secp256k1_fe_inv(&u, &r[len - 1].x); + + for (i = len - 1; i > 0; i--) { + secp256k1_fe_mul(&r[i].x, &r[i - 1].x, &u); + secp256k1_fe_mul(&u, &u, &a[i].z); + } + r[0].x = u; + + for (i = 0; i < len; i++) { + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x); + } + +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&r[i]); + } +#endif +} + static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { secp256k1_fe u; size_t i; diff --git a/src/modules/ecdsa_adaptor/main_impl.h b/src/modules/ecdsa_adaptor/main_impl.h index 5d16e0117..25232b488 100644 --- a/src/modules/ecdsa_adaptor/main_impl.h +++ b/src/modules/ecdsa_adaptor/main_impl.h @@ -341,7 +341,7 @@ int secp256k1_ecdsa_adaptor_recover(const secp256k1_context* ctx, unsigned char /* We declassify non-secret enckey_expected_ge to allow using it as a * branch point. */ secp256k1_declassify(ctx, &enckey_expected_ge, sizeof(enckey_expected_ge)); - if (!secp256k1_eckey_pubkey_serialize(&enckey_expected_ge, enckey_expected33, &size, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_eckey_pubkey_serialize(&enckey_expected_ge, enckey_expected33, &size, 1)) { /* Unreachable from tests (and other VERIFY builds) and therefore this * branch should be ignored in test coverage analysis. * diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index da3f19623..8e18c151a 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -395,6 +395,7 @@ static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned c static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp256k1_musig_secnonce *secnonce, secp256k1_musig_pubnonce *pubnonce, const unsigned char *input_nonce, const unsigned char *seckey, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_musig_keyagg_cache *keyagg_cache, const unsigned char *extra_input32) { secp256k1_scalar k[2]; secp256k1_ge nonce_pts[2]; + secp256k1_gej nonce_ptj[2]; int i; unsigned char pk_ser[33]; size_t pk_ser_len = sizeof(pk_ser); @@ -444,13 +445,20 @@ static int secp256k1_musig_nonce_gen_internal(const secp256k1_context* ctx, secp secp256k1_musig_secnonce_save(secnonce, k, &pk); secp256k1_musig_secnonce_invalidate(ctx, secnonce, !ret); + /* Compute pubnonce as two gejs */ for (i = 0; i < 2; i++) { - secp256k1_gej nonce_ptj; - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj, &k[i]); - secp256k1_ge_set_gej(&nonce_pts[i], &nonce_ptj); - secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i])); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &nonce_ptj[i], &k[i]); secp256k1_scalar_clear(&k[i]); - secp256k1_gej_clear(&nonce_ptj); + } + + /* Batch convert to two public ges */ + secp256k1_ge_set_all_gej(nonce_pts, nonce_ptj, 2); + for (i = 0; i < 2; i++) { + secp256k1_gej_clear(&nonce_ptj[i]); + } + + for (i = 0; i < 2; i++) { + secp256k1_declassify(ctx, &nonce_pts[i], sizeof(nonce_pts[i])); } /* None of the nonce_pts will be infinity because k != 0 with overwhelming * probability */ diff --git a/src/modules/schnorrsig_halfagg/main_impl.h b/src/modules/schnorrsig_halfagg/main_impl.h index 0d3662ba7..af612195b 100644 --- a/src/modules/schnorrsig_halfagg/main_impl.h +++ b/src/modules/schnorrsig_halfagg/main_impl.h @@ -8,7 +8,7 @@ /* Initializes SHA256 with fixed midstate. This midstate was computed by applying * SHA256 to SHA256("HalfAgg/randomizer")||SHA256("HalfAgg/randomizer"). */ -void secp256k1_schnorrsig_sha256_tagged_aggregation(secp256k1_sha256 *sha) { +static void secp256k1_schnorrsig_sha256_tagged_aggregation(secp256k1_sha256 *sha) { secp256k1_sha256_initialize(sha); sha->s[0] = 0xd11f5532ul; sha->s[1] = 0xfa57f70ful; diff --git a/src/modules/whitelist/whitelist_impl.h b/src/modules/whitelist/whitelist_impl.h index 48f8bcca6..bb244907f 100644 --- a/src/modules/whitelist/whitelist_impl.h +++ b/src/modules/whitelist/whitelist_impl.h @@ -18,7 +18,7 @@ static int secp256k1_whitelist_hash_pubkey(secp256k1_scalar* output, secp256k1_g secp256k1_ge_set_gej(&ge, pubkey); secp256k1_sha256_initialize(&sha); - if (!secp256k1_eckey_pubkey_serialize(&ge, c, &size, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_eckey_pubkey_serialize(&ge, c, &size, 1)) { return 0; } secp256k1_sha256_write(&sha, c, size); @@ -95,7 +95,7 @@ static int secp256k1_whitelist_compute_keys_and_message(const secp256k1_context* secp256k1_pubkey_load(ctx, &subkey_ge, sub_pubkey); /* commit to sub-key */ - if (!secp256k1_eckey_pubkey_serialize(&subkey_ge, c, &size, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_eckey_pubkey_serialize(&subkey_ge, c, &size, 1)) { return 0; } secp256k1_sha256_write(&sha, c, size); @@ -106,12 +106,12 @@ static int secp256k1_whitelist_compute_keys_and_message(const secp256k1_context* /* commit to fixed keys */ secp256k1_pubkey_load(ctx, &offline_ge, &offline_pubkeys[i]); - if (!secp256k1_eckey_pubkey_serialize(&offline_ge, c, &size, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_eckey_pubkey_serialize(&offline_ge, c, &size, 1)) { return 0; } secp256k1_sha256_write(&sha, c, size); secp256k1_pubkey_load(ctx, &online_ge, &online_pubkeys[i]); - if (!secp256k1_eckey_pubkey_serialize(&online_ge, c, &size, SECP256K1_EC_COMPRESSED)) { + if (!secp256k1_eckey_pubkey_serialize(&online_ge, c, &size, 1)) { return 0; } secp256k1_sha256_write(&sha, c, size); diff --git a/src/precomputed_ecmult.h b/src/precomputed_ecmult.h index 17df10296..e5a85f684 100644 --- a/src/precomputed_ecmult.h +++ b/src/precomputed_ecmult.h @@ -13,6 +13,8 @@ extern "C" { #include "ecmult.h" #include "group.h" +#include "util_local_visibility.h" + #if defined(EXHAUSTIVE_TEST_ORDER) # if EXHAUSTIVE_TEST_ORDER == 7 # define WINDOW_G 3 @@ -27,8 +29,8 @@ static secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; static secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; #else /* !defined(EXHAUSTIVE_TEST_ORDER) */ # define WINDOW_G ECMULT_WINDOW_SIZE -extern const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; -extern const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; +SECP256K1_LOCAL_VAR const secp256k1_ge_storage secp256k1_pre_g[ECMULT_TABLE_SIZE(WINDOW_G)]; +SECP256K1_LOCAL_VAR const secp256k1_ge_storage secp256k1_pre_g_128[ECMULT_TABLE_SIZE(WINDOW_G)]; #endif /* defined(EXHAUSTIVE_TEST_ORDER) */ #ifdef __cplusplus diff --git a/src/precomputed_ecmult_gen.h b/src/precomputed_ecmult_gen.h index 283738a5c..00ddce108 100644 --- a/src/precomputed_ecmult_gen.h +++ b/src/precomputed_ecmult_gen.h @@ -13,10 +13,12 @@ extern "C" { #include "group.h" #include "ecmult_gen.h" +#include "util_local_visibility.h" + #ifdef EXHAUSTIVE_TEST_ORDER static secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; #else -extern const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; +SECP256K1_LOCAL_VAR const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[COMB_BLOCKS][COMB_POINTS]; #endif /* defined(EXHAUSTIVE_TEST_ORDER) */ #ifdef __cplusplus diff --git a/src/secp256k1.c b/src/secp256k1.c index 6ebfdbb01..7deb93a46 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -92,8 +92,8 @@ static const secp256k1_context secp256k1_context_static_ = { { secp256k1_default_error_callback_fn, 0 }, 0 }; -const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_; -const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_; +const secp256k1_context * const secp256k1_context_static = &secp256k1_context_static_; +const secp256k1_context * const secp256k1_context_no_precomp = &secp256k1_context_static_; /* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof. * @@ -301,7 +301,7 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o ARG_CHECK(pubkey != NULL); ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { - ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, !!(flags & SECP256K1_FLAGS_BIT_COMPRESSION)); if (ret) { *outputlen = len; } @@ -684,10 +684,6 @@ int secp256k1_ec_seckey_negate(const secp256k1_context* ctx, unsigned char *seck return ret; } -int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) { - return secp256k1_ec_seckey_negate(ctx, seckey); -} - int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) { int ret = 0; secp256k1_ge p; @@ -731,10 +727,6 @@ int secp256k1_ec_seckey_tweak_add(const secp256k1_context* ctx, unsigned char *s return ret; } -int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - return secp256k1_ec_seckey_tweak_add(ctx, seckey, tweak32); -} - static int secp256k1_ec_pubkey_tweak_add_helper(secp256k1_ge *p, const unsigned char *tweak32) { secp256k1_scalar term; int overflow = 0; @@ -779,10 +771,6 @@ int secp256k1_ec_seckey_tweak_mul(const secp256k1_context* ctx, unsigned char *s return ret; } -int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak32) { - return secp256k1_ec_seckey_tweak_mul(ctx, seckey, tweak32); -} - int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak32) { secp256k1_ge p; secp256k1_scalar factor; diff --git a/src/tests.c b/src/tests.c index c1f8ba7fd..5e05030e3 100644 --- a/src/tests.c +++ b/src/tests.c @@ -87,15 +87,6 @@ static void counting_callback_fn(const char* str, void* data) { (*p)++; } -static void uncounting_illegal_callback_fn(const char* str, void* data) { - /* Dummy callback function that just counts (backwards). */ - int32_t *p; - (void)str; - p = data; - CHECK(*p != INT32_MIN); - (*p)--; -} - static void run_util_tests(void) { int i; uint64_t r; @@ -3877,14 +3868,38 @@ 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_set_all_gej_var(ge_set_all, gej, 4 * runs + 1); + 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; + testutil_random_fe_non_zero(&s); + secp256k1_gej_rescale(&gej[i], &s); + CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge_set_all_var[i])); + } + + /* Skip infinity at &gej[0]. */ + secp256k1_ge_set_all_gej(&ge_set_all[1], &gej[1], 4 * runs); + for (i = 1; i < 4 * runs + 1; i++) { secp256k1_fe s; testutil_random_fe_non_zero(&s); secp256k1_gej_rescale(&gej[i], &s); CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge_set_all[i])); + CHECK(secp256k1_ge_eq_var(&ge_set_all_var[i], &ge_set_all[i])); } + + /* Test with an array of length 1. */ + secp256k1_ge_set_all_gej_var(ge_set_all_var, &gej[1], 1); + secp256k1_ge_set_all_gej(ge_set_all, &gej[1], 1); + CHECK(secp256k1_gej_eq_ge_var(&gej[1], &ge_set_all_var[1])); + CHECK(secp256k1_gej_eq_ge_var(&gej[1], &ge_set_all[1])); + CHECK(secp256k1_ge_eq_var(&ge_set_all_var[1], &ge_set_all[1])); + + /* Test with an array of length 0. */ + secp256k1_ge_set_all_gej_var(NULL, NULL, 0); + secp256k1_ge_set_all_gej(NULL, NULL, 0); + + free(ge_set_all_var); free(ge_set_all); } @@ -6410,11 +6425,6 @@ static void run_eckey_negate_test(void) { CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); - /* Check that privkey alias gives same result */ - CHECK(secp256k1_ec_seckey_negate(CTX, seckey) == 1); - CHECK(secp256k1_ec_privkey_negate(CTX, seckey_tmp) == 1); - CHECK(secp256k1_memcmp_var(seckey, seckey_tmp, 32) == 0); - /* Negating all 0s fails */ memset(seckey, 0, 32); memset(seckey_tmp, 0, 32); @@ -6575,22 +6585,15 @@ static void test_ecdsa_end_to_end(void) { if (testrand_int(3) == 0) { int ret1; int ret2; - int ret3; unsigned char rnd[32]; - unsigned char privkey_tmp[32]; secp256k1_pubkey pubkey2; testrand256_test(rnd); - memcpy(privkey_tmp, privkey, 32); ret1 = secp256k1_ec_seckey_tweak_add(CTX, privkey, rnd); ret2 = secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, rnd); - /* Check that privkey alias gives same result */ - ret3 = secp256k1_ec_privkey_tweak_add(CTX, privkey_tmp, rnd); CHECK(ret1 == ret2); - CHECK(ret2 == ret3); if (ret1 == 0) { return; } - CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } @@ -6599,22 +6602,15 @@ static void test_ecdsa_end_to_end(void) { if (testrand_int(3) == 0) { int ret1; int ret2; - int ret3; unsigned char rnd[32]; - unsigned char privkey_tmp[32]; secp256k1_pubkey pubkey2; testrand256_test(rnd); - memcpy(privkey_tmp, privkey, 32); ret1 = secp256k1_ec_seckey_tweak_mul(CTX, privkey, rnd); ret2 = secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, rnd); - /* Check that privkey alias gives same result */ - ret3 = secp256k1_ec_privkey_tweak_mul(CTX, privkey_tmp, rnd); CHECK(ret1 == ret2); - CHECK(ret2 == ret3); if (ret1 == 0) { return; } - CHECK(secp256k1_memcmp_var(privkey, privkey_tmp, 32) == 0); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey2, privkey) == 1); CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } diff --git a/src/util_local_visibility.h b/src/util_local_visibility.h new file mode 100644 index 000000000..8912a64d1 --- /dev/null +++ b/src/util_local_visibility.h @@ -0,0 +1,12 @@ +#ifndef SECP256K1_LOCAL_VISIBILITY_H +#define SECP256K1_LOCAL_VISIBILITY_H + +/* Global variable visibility */ +/* See: https://github.com/bitcoin-core/secp256k1/issues/1181 */ +#if !defined(_WIN32) && defined(__GNUC__) && (__GNUC__ >= 4) +# define SECP256K1_LOCAL_VAR extern __attribute__ ((visibility ("hidden"))) +#else +# define SECP256K1_LOCAL_VAR extern +#endif + +#endif /* SECP256K1_LOCAL_VISIBILITY_H */ diff --git a/tools/symbol-check.py b/tools/symbol-check.py new file mode 100755 index 000000000..e7f478082 --- /dev/null +++ b/tools/symbol-check.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +"""Check that a libsecp256k1 shared library exports only expected symbols. + +Usage examples: + - When building with Autotools: + ./tools/symbol-check.py .libs/libsecp256k1.so + ./tools/symbol-check.py .libs/libsecp256k1-.dll + ./tools/symbol-check.py .libs/libsecp256k1.dylib + + - When building with CMake: + ./tools/symbol-check.py build/lib/libsecp256k1.so + ./tools/symbol-check.py build/bin/libsecp256k1-.dll + ./tools/symbol-check.py build/lib/libsecp256k1.dylib""" + +import re +import sys +import subprocess + +import lief + + +class UnexpectedExport(RuntimeError): + pass + + +def get_exported_exports(library) -> list[str]: + """Adapter function to get exported symbols based on the library format.""" + if library.format == lief.Binary.FORMATS.ELF: + return [symbol.name for symbol in library.exported_symbols] + elif library.format == lief.Binary.FORMATS.PE: + return [entry.name for entry in library.get_export().entries] + elif library.format == lief.Binary.FORMATS.MACHO: + return [symbol.name[1:] for symbol in library.exported_symbols] + raise NotImplementedError(f"Unsupported format: {library.format}") + + +def grep_expected_symbols() -> list[str]: + """Guess the list of expected exported symbols from the source code.""" + grep_output = subprocess.check_output( + ["git", "grep", r"^\s*SECP256K1_API", "--", "include"], + universal_newlines=True, + encoding="utf-8" + ) + lines = grep_output.split("\n") + pattern = re.compile(r'\bsecp256k1_\w+') + exported: list[str] = [pattern.findall(line)[-1] for line in lines if line.strip()] + return exported + + +def check_symbols(library, expected_exports) -> None: + """Check that the library exports only the expected symbols.""" + actual_exports = get_exported_exports(library) + unexpected_exports = set(actual_exports) - set(expected_exports) + if unexpected_exports != set(): + raise UnexpectedExport(f"Unexpected exported symbols: {unexpected_exports}") + +def main(): + if len(sys.argv) != 2: + print(__doc__) + return 1 + library = lief.parse(sys.argv[1]) + expected_exports = grep_expected_symbols() + try: + check_symbols(library, expected_exports) + except UnexpectedExport as e: + print(f"{sys.argv[0]}: In {sys.argv[1]}: {e}") + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main())