From c0da4f60e2145a9838c0c5d0a02592faf16d2d8d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 4 Sep 2023 12:51:20 -0400 Subject: [PATCH] Squashed 'src/secp256k1/' changes from c545fdc374..199d27cea3 199d27cea3 Merge bitcoin-core/secp256k1#1415: release: Prepare for 0.4.0 16339804c9 release: Prepare for 0.4.0 d9a85065a9 changelog: Catch up in preparation of release 0b4640aedd Merge bitcoin-core/secp256k1#1413: ci: Add `release` job 8659a01714 ci: Add `release` job f9b38894ba ci: Update `actions/checkout` version 727bec5bc2 Merge bitcoin-core/secp256k1#1414: ci/gha: Add ARM64 QEMU jobs for clang and clang-snapshot 2635068abf ci/gha: Let MSan continue checking after errors in all jobs e78c7b68eb ci/Dockerfile: Reduce size of Docker image further 2f0d3bbffb ci/Dockerfile: Warn if `ulimit -n` is too high when running Docker 4b8a647ad3 ci/gha: Add ARM64 QEMU jobs for clang and clang-snapshot 6ebe7d2bb3 ci/Dockerfile: Always use versioned clang packages 65c79fe2d0 Merge bitcoin-core/secp256k1#1412: ci: Switch macOS from Ventura to Monterey and add Valgrind c223d7e33d ci: Switch macOS from Ventura to Monterey and add Valgrind ea26b71c3a Merge bitcoin-core/secp256k1#1411: ci: Make repetitive command the default one cce0456304 ci: Make repetitive command the default one 317a4c48f0 ci: Move `git config ...` to `run-in-docker-action` 4d7fe60905 Merge bitcoin-core/secp256k1#1409: ci: Move remained task from Cirrus to GitHub Actions 676ed8f9cf ci: Move "C++ (public headers)" from Cirrus to GitHub Actions 61fc3a2dc8 ci: Move "C++ -fpermissive..." from Cirrus to GitHub Actions d51fb0a533 ci: Move "MSan" from Cirrus to GitHub Actions c22ac27529 ci: Move sanitizers task from Cirrus to GitHub Actions 26a989924b Merge bitcoin-core/secp256k1#1410: ci: Use concurrency for pull requests only ee1be62d84 ci: Use concurrency for pull requests only 6ee14550c8 Merge bitcoin-core/secp256k1#1406: ci, gha: Move more non-x86_64 tasks from Cirrus CI to GitHub Actions fc3dea29ea ci: Move "ppc64le: Linux..." from Cirrus to GitHub Actions 7782dc8276 ci: Move "ARM64: Linux..." from Cirrus to GitHub Actions 0a16de671c ci: Move "ARM32: Linux..." from Cirrus to GitHub Actions ea33914e00 ci: Move "s390x (big-endian): Linux..." from Cirrus to GitHub Actions 880be8af99 ci: Move "i686: Linux (Debian stable)" from Cirrus to GiHub Actions 2e6cf9bae5 Merge bitcoin-core/secp256k1#1396: ci, gha: Add "x86_64: Linux (Debian stable)" GitHub Actions job 5373693e45 Merge bitcoin-core/secp256k1#1405: ci: Drop no longer needed workaround ef9fe959de ci: Drop no longer needed workaround e10878f58e ci, gha: Drop `driver-opts.network` input for `setup-buildx-action` 4ad4914bd1 ci, gha: Add `retry_builder` Docker image builder 6617a620d9 ci: Remove "x86_64: Linux (Debian stable)" task from Cirrus CI 03c9e6508c ci, gha: Add "x86_64: Linux (Debian stable)" GitHub Actions job ad3e65d9fe ci: Remove GCC build files and sage to reduce size of Docker image 6b9507adf6 Merge bitcoin-core/secp256k1#1398: ci, gha: Add Windows jobs based on Linux image 87d35f30c0 ci: Rename `cirrus.sh` to more general `ci.sh` d6281dd008 ci: Remove Windows tasks from Cirrus CI 2b6f9cd546 ci, gha: Add Windows jobs based on Linux image 48b1d939b5 Merge bitcoin-core/secp256k1#1403: ci, gha: Ensure only a single workflow processes `github.ref` at a time 0ba2b94551 Merge bitcoin-core/secp256k1#1373: Add invariant checking for scalars 060e32cb60 Merge bitcoin-core/secp256k1#1401: ci, gha: Run all MSVC tests on Windows natively de657c2044 Merge bitcoin-core/secp256k1#1062: Removes `_fe_equal_var`, and unwanted `_fe_normalize_weak` calls (in tests) bcffeb14bc Merge bitcoin-core/secp256k1#1404: ci: Remove "arm64: macOS Ventura" task from Cirrus CI c2f6435802 ci: Add comment about switching macOS to M1 on GHA later 4a24fae0bc ci: Remove "arm64: macOS Ventura" task from Cirrus CI b0886fd35c ci, gha: Ensure only a single workflow processes `github.ref` at a time 3d05c86d63 Merge bitcoin-core/secp256k1#1394: ci, gha: Run "x86_64: macOS Ventura" job on GitHub Actions d78bec7001 ci: Remove Windows MSVC tasks from Cirrus CI 3545dc2b9b ci, gha: Run all MSVC tests on Windows natively 5d8fa825e2 Merge bitcoin-core/secp256k1#1274: test: Silent noisy clang warnings about Valgrind code on macOS x86_64 8e54a346d2 ci, gha: Run "x86_64: macOS Ventura" job on GitHub Actions b327abfcea Merge bitcoin-core/secp256k1#1402: ci: Use Homebrew's gcc in native macOS task d62db57427 ci: Use Homebrew's gcc in native macOS task 54058d16fe field: remove `secp256k1_fe_equal_var` bb4efd6404 tests: remove unwanted `secp256k1_fe_normalize_weak` call eedd781085 Merge bitcoin-core/secp256k1#1348: tighten group magnitude limits, save normalize_weak calls in group add methods (revival of #1032) b2f6712dd3 Merge bitcoin-core/secp256k1#1400: ctimetests: Use new SECP256K1_CHECKMEM macros also for ellswift 9c91ea41b1 ci: Enable ellswift module where it's missing db32a24761 ctimetests: Use new SECP256K1_CHECKMEM macros also for ellswift ce765a5b8e Merge bitcoin-core/secp256k1#1399: ci, gha: Run "SageMath prover" job on GitHub Actions 8408dfdc4c Revert "ci: Run sage prover on CI" c8d9914fb1 ci, gha: Run "SageMath prover" job on GitHub Actions 8d2960c8e2 Merge bitcoin-core/secp256k1#1397: ci: Remove "Windows (VS 2022)" task from Cirrus CI f1774e5ec4 ci, gha: Make MSVC job presentation more explicit 5ee039bb58 ci: Remove "Windows (VS 2022)" task from Cirrus CI 96294c00fb Merge bitcoin-core/secp256k1#1389: ci: Run "Windows (VS 2022)" job on GitHub Actions a2f7ccdecc ci: Run "Windows (VS 2022)" job on GitHub Actions 374e2b54e2 Merge bitcoin-core/secp256k1#1290: cmake: Set `ENVIRONMENT` property for examples on Windows 1b13415df9 Merge bitcoin-core/secp256k1#1391: refactor: take use of `secp256k1_scalar_{zero,one}` constants (part 2) a1bd4971d6 refactor: take use of `secp256k1_scalar_{zero,one}` constants (part 2) b7c685e74a Save _normalize_weak calls in group add methods c83afa66e0 Tighten group magnitude limits 26392da2fb Merge bitcoin-core/secp256k1#1386: ci: print $ELLSWIFT in cirrus.sh d23da6d557 use secp256k1_scalar_verify checks 4692478853 ci: print $ELLSWIFT in cirrus.sh c7d0454932 add verification for scalars c734c64278 Merge bitcoin-core/secp256k1#1384: build: enable ellswift module via SECP_CONFIG_DEFINES ad152151b0 update max scalar in scalar_cmov_test and fix schnorrsig_verify exhaustive test 78ca880788 build: enable ellswift module via SECP_CONFIG_DEFINES 0e00fc7d10 Merge bitcoin-core/secp256k1#1383: util: remove unused checked_realloc b097a466c1 util: remove unused checked_realloc 2bd5f3e618 Merge bitcoin-core/secp256k1#1382: refactor: Drop unused cast 4f8c5bd761 refactor: Drop unused cast 173e8d061a Implement current magnitude assumptions 49afd2f5d8 Take use of _fe_verify_magnitude in field_impl.h 4e9661fc42 Add _fe_verify_magnitude (no-op unless VERIFY is enabled) 690b0fc05a add missing group element invariant checks 175db31149 ci: Drop no longer needed `PATH` variable update on Windows 116d2ab3df cmake: Set `ENVIRONMENT` property for examples on Windows cef373997c cmake, refactor: Use helper function instead of interface library 747ada3587 test: Silent noisy clang warnings about Valgrind code on macOS x86_64 git-subtree-dir: src/secp256k1 git-subtree-split: 199d27cea32203b224b208627533c2e813cd3b21 --- .cirrus.yml | 413 --------- .../install-homebrew-valgrind/action.yml | 33 + .../actions/run-in-docker-action/action.yml | 49 ++ .github/workflows/ci.yml | 806 ++++++++++++++++++ CHANGELOG.md | 12 +- CMakeLists.txt | 8 +- ci/{cirrus.sh => ci.sh} | 17 +- ci/linux-debian.Dockerfile | 72 +- configure.ac | 14 +- examples/CMakeLists.txt | 40 +- src/bench_ecmult.c | 3 +- src/checkmem.h | 7 + src/ctime_tests.c | 20 +- src/field.h | 9 +- src/field_impl.h | 42 +- src/group.h | 8 + src/group_impl.h | 165 ++-- src/hash_impl.h | 2 +- src/modules/extrakeys/tests_exhaustive_impl.h | 2 +- src/modules/schnorrsig/main_impl.h | 2 +- .../schnorrsig/tests_exhaustive_impl.h | 10 +- src/scalar.h | 3 + src/scalar_4x64_impl.h | 79 +- src/scalar_8x32_impl.h | 80 +- src/scalar_impl.h | 19 + src/scalar_low_impl.h | 70 +- src/tests.c | 157 ++-- src/tests_exhaustive.c | 20 +- src/util.h | 8 - 29 files changed, 1476 insertions(+), 694 deletions(-) delete mode 100644 .cirrus.yml create mode 100644 .github/actions/install-homebrew-valgrind/action.yml create mode 100644 .github/actions/run-in-docker-action/action.yml create mode 100644 .github/workflows/ci.yml rename ci/{cirrus.sh => ci.sh} (90%) diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index ae205c624c14d..0000000000000 --- a/.cirrus.yml +++ /dev/null @@ -1,413 +0,0 @@ -env: - ### cirrus config - CIRRUS_CLONE_DEPTH: 1 - ### compiler options - HOST: - WRAPPER_CMD: - # Specific warnings can be disabled with -Wno-error=foo. - # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual. - WERROR_CFLAGS: -Werror -pedantic-errors - MAKEFLAGS: -j4 - BUILD: check - ### secp256k1 config - ECMULTWINDOW: auto - ECMULTGENPRECISION: auto - ASM: no - WIDEMUL: auto - WITH_VALGRIND: yes - EXTRAFLAGS: - ### secp256k1 modules - EXPERIMENTAL: no - ECDH: no - RECOVERY: no - SCHNORRSIG: no - ELLSWIFT: no - ### test options - SECP256K1_TEST_ITERS: - BENCH: yes - SECP256K1_BENCH_ITERS: 2 - CTIMETESTS: yes - # Compile and run the tests - EXAMPLES: yes - -# https://cirrus-ci.org/pricing/#compute-credits -credits_snippet: &CREDITS - # Don't use any credits for now. - use_compute_credits: false - -cat_logs_snippet: &CAT_LOGS - always: - cat_tests_log_script: - - cat tests.log || true - cat_noverify_tests_log_script: - - cat noverify_tests.log || true - cat_exhaustive_tests_log_script: - - cat exhaustive_tests.log || true - cat_ctime_tests_log_script: - - cat ctime_tests.log || true - cat_bench_log_script: - - cat bench.log || true - cat_config_log_script: - - cat config.log || true - cat_test_env_script: - - cat test_env.log || true - cat_ci_env_script: - - env - -linux_container_snippet: &LINUX_CONTAINER - container: - dockerfile: ci/linux-debian.Dockerfile - # Reduce number of CPUs to be able to do more builds in parallel. - cpu: 1 - # Gives us more CPUs for free if they're available. - greedy: true - # More than enough for our scripts. - memory: 2G - -task: - name: "x86_64: Linux (Debian stable)" - << : *LINUX_CONTAINER - matrix: - - env: {WIDEMUL: int64, RECOVERY: yes} - - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes} - - env: {WIDEMUL: int128} - - env: {WIDEMUL: int128_struct, ELLSWIFT: yes} - - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes, ELLSWIFT: yes} - - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes} - - env: {WIDEMUL: int128, ASM: x86_64 , ELLSWIFT: yes} - - env: { RECOVERY: yes, SCHNORRSIG: yes} - - env: {CTIMETESTS: no, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, CPPFLAGS: -DVERIFY} - - env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no} - - env: {CPPFLAGS: -DDETERMINISTIC} - - env: {CFLAGS: -O0, CTIMETESTS: no} - - env: {CFLAGS: -O1, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes} - - env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } - - env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 } - matrix: - - env: - CC: gcc - - env: - CC: clang - - env: - CC: gcc-snapshot - - env: - CC: clang-snapshot - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "i686: Linux (Debian stable)" - << : *LINUX_CONTAINER - env: - HOST: i686-linux-gnu - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - matrix: - - env: - CC: i686-linux-gnu-gcc - - env: - CC: clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "arm64: macOS Ventura" - macos_instance: - image: ghcr.io/cirruslabs/macos-ventura-base:latest - env: - HOMEBREW_NO_AUTO_UPDATE: 1 - HOMEBREW_NO_INSTALL_CLEANUP: 1 - # Cirrus gives us a fixed number of 4 virtual CPUs. Not that we even have that many jobs at the moment... - MAKEFLAGS: -j5 - env: - ASM: no - WITH_VALGRIND: no - CTIMETESTS: no - CC: clang - matrix: - - env: {WIDEMUL: int64, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes} - - env: {WIDEMUL: int64, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, CC: gcc} - - env: {WIDEMUL: int128_struct, ECMULTGENPRECISION: 2, ECMULTWINDOW: 4} - - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes} - - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes} - - env: {WIDEMUL: int128, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, CC: gcc} - - env: {WIDEMUL: int128, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, CPPFLAGS: -DVERIFY} - - env: {BUILD: distcheck} - brew_script: - - brew install automake libtool gcc - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - << : *CREDITS - -task: - name: "s390x (big-endian): Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-s390x - SECP256K1_TEST_ITERS: 16 - HOST: s390x-linux-gnu - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - CTIMETESTS: no - test_script: - # https://sourceware.org/bugzilla/show_bug.cgi?id=27008 - - rm /etc/ld.so.cache - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "ARM32: Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-arm - SECP256K1_TEST_ITERS: 16 - HOST: arm-linux-gnueabihf - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - CTIMETESTS: no - matrix: - - env: {} - - env: {EXPERIMENTAL: yes, ASM: arm32} - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "ARM64: Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-aarch64 - SECP256K1_TEST_ITERS: 16 - HOST: aarch64-linux-gnu - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - CTIMETESTS: no - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "ppc64le: Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-ppc64le - SECP256K1_TEST_ITERS: 16 - HOST: powerpc64le-linux-gnu - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - CTIMETESTS: no - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: wine - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - CTIMETESTS: no - matrix: - - name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)" - env: - HOST: x86_64-w64-mingw32 - - name: "i686 (mingw32-w64): Windows (Debian stable, Wine)" - env: - HOST: i686-w64-mingw32 - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: wine - WERROR_CFLAGS: -WX - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - EXPERIMENTAL: yes - SCHNORRSIG: yes - ELLSWIFT: yes - CTIMETESTS: no - # Use a MinGW-w64 host to tell ./configure we're building for Windows. - # This will detect some MinGW-w64 tools but then make will need only - # the MSVC tools CC, AR and NM as specified below. - HOST: x86_64-w64-mingw32 - CC: /opt/msvc/bin/x64/cl - AR: /opt/msvc/bin/x64/lib - NM: /opt/msvc/bin/x64/dumpbin -symbols -headers - # Set non-essential options that affect the CLI messages here. - # (They depend on the user's taste, so we don't want to set them automatically in configure.ac.) - CFLAGS: -nologo -diagnostics:caret - LDFLAGS: -Xlinker -Xlinker -Xlinker -nologo - matrix: - - name: "x86_64 (MSVC): Windows (Debian stable, Wine)" - - name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)" - env: - WIDEMUL: int128_struct - - name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct with __(u)mulh)" - env: - WIDEMUL: int128_struct - CPPFLAGS: -DSECP256K1_MSVC_MULH_TEST_OVERRIDE - - name: "i686 (MSVC): Windows (Debian stable, Wine)" - env: - HOST: i686-w64-mingw32 - CC: /opt/msvc/bin/x86/cl - AR: /opt/msvc/bin/x86/lib - NM: /opt/msvc/bin/x86/dumpbin -symbols -headers - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -# Sanitizers -task: - << : *LINUX_CONTAINER - env: - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - CTIMETESTS: no - matrix: - - name: "Valgrind (memcheck)" - container: - cpu: 2 - env: - # The `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (https://www.valgrind.org/docs/manual/manual-core.html) - WRAPPER_CMD: "valgrind --error-exitcode=42" - SECP256K1_TEST_ITERS: 2 - - name: "UBSan, ASan, LSan" - container: - memory: 2G - env: - CFLAGS: "-fsanitize=undefined,address -g" - UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1" - ASAN_OPTIONS: "strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1" - LSAN_OPTIONS: "use_unaligned=1" - SECP256K1_TEST_ITERS: 32 - # Try to cover many configurations with just a tiny matrix. - matrix: - - env: - ASM: auto - - env: - ASM: no - ECMULTGENPRECISION: 2 - ECMULTWINDOW: 2 - matrix: - - env: - CC: clang - - env: - HOST: i686-linux-gnu - CC: i686-linux-gnu-gcc - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -# Memory sanitizers -task: - << : *LINUX_CONTAINER - name: "MSan" - env: - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - CTIMETESTS: yes - CC: clang - SECP256K1_TEST_ITERS: 32 - ASM: no - WITH_VALGRIND: no - container: - memory: 2G - matrix: - - env: - CFLAGS: "-fsanitize=memory -g" - - env: - ECMULTGENPRECISION: 2 - ECMULTWINDOW: 2 - CFLAGS: "-fsanitize=memory -g -O3" - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "C++ -fpermissive (entire project)" - << : *LINUX_CONTAINER - env: - CC: g++ - CFLAGS: -fpermissive -g - CPPFLAGS: -DSECP256K1_CPLUSPLUS_TEST_OVERRIDE - WERROR_CFLAGS: - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "C++ (public headers)" - << : *LINUX_CONTAINER - test_script: - - g++ -Werror include/*.h - - clang -Werror -x c++-header include/*.h - - /opt/msvc/bin/x64/cl.exe -c -WX -TP include/*.h - -task: - name: "sage prover" - << : *LINUX_CONTAINER - test_script: - - cd sage - - sage prove_group_implementations.sage - -task: - name: "x86_64: Windows (VS 2022)" - windows_container: - image: cirrusci/windowsservercore:visualstudio2022 - cpu: 4 - memory: 3840MB - env: - PATH: '%CIRRUS_WORKING_DIR%\build\src\RelWithDebInfo;%PATH%' - x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"' - # Ignore MSBuild warning MSB8029. - # See: https://learn.microsoft.com/en-us/visualstudio/msbuild/errors/msb8029?view=vs-2022 - IgnoreWarnIntDirInTempDetected: 'true' - matrix: - - env: - BUILD_SHARED_LIBS: ON - - env: - BUILD_SHARED_LIBS: OFF - git_show_script: - # Print commit to allow reproducing the job outside of CI. - - git show --no-patch - configure_script: - - '%x64_NATIVE_TOOLS%' - - cmake -E env CFLAGS="/WX" cmake -A x64 -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% - build_script: - - '%x64_NATIVE_TOOLS%' - - cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5 - check_script: - - '%x64_NATIVE_TOOLS%' - - ctest -C RelWithDebInfo --test-dir build -j 5 - - build\src\RelWithDebInfo\bench_ecmult.exe - - build\src\RelWithDebInfo\bench_internal.exe - - build\src\RelWithDebInfo\bench.exe diff --git a/.github/actions/install-homebrew-valgrind/action.yml b/.github/actions/install-homebrew-valgrind/action.yml new file mode 100644 index 0000000000000..094ff891f71f7 --- /dev/null +++ b/.github/actions/install-homebrew-valgrind/action.yml @@ -0,0 +1,33 @@ +name: "Install Valgrind" +description: "Install Homebrew's Valgrind package and cache it." +runs: + using: "composite" + steps: + - run: | + brew tap LouisBrunner/valgrind + brew fetch --HEAD LouisBrunner/valgrind/valgrind + echo "CI_HOMEBREW_CELLAR_VALGRIND=$(brew --cellar valgrind)" >> "$GITHUB_ENV" + shell: bash + + - run: | + sw_vers > valgrind_fingerprint + brew --version >> valgrind_fingerprint + git -C "$(brew --cache)/valgrind--git" rev-parse HEAD >> valgrind_fingerprint + cat valgrind_fingerprint + shell: bash + + - uses: actions/cache@v3 + id: cache + with: + path: ${{ env.CI_HOMEBREW_CELLAR_VALGRIND }} + key: ${{ github.job }}-valgrind-${{ hashFiles('valgrind_fingerprint') }} + + - if: steps.cache.outputs.cache-hit != 'true' + run: | + brew install --HEAD LouisBrunner/valgrind/valgrind + shell: bash + + - if: steps.cache.outputs.cache-hit == 'true' + run: | + brew link valgrind + shell: bash diff --git a/.github/actions/run-in-docker-action/action.yml b/.github/actions/run-in-docker-action/action.yml new file mode 100644 index 0000000000000..d357c3cf751c8 --- /dev/null +++ b/.github/actions/run-in-docker-action/action.yml @@ -0,0 +1,49 @@ +name: 'Run in Docker with environment' +description: 'Run a command in a Docker container, while passing explicitly set environment variables into the container.' +inputs: + dockerfile: + description: 'A Dockerfile that defines an image' + required: true + tag: + description: 'A tag of an image' + required: true + command: + description: 'A command to run in a container' + required: false + default: ./ci/ci.sh +runs: + using: "composite" + steps: + - uses: docker/setup-buildx-action@v2 + + - uses: docker/build-push-action@v4 + id: main_builder + continue-on-error: true + with: + context: . + file: ${{ inputs.dockerfile }} + tags: ${{ inputs.tag }} + load: true + cache-from: type=gha + + - uses: docker/build-push-action@v4 + id: retry_builder + if: steps.main_builder.outcome == 'failure' + with: + context: . + file: ${{ inputs.dockerfile }} + tags: ${{ inputs.tag }} + load: true + cache-from: type=gha + + - # Tell Docker to pass environment variables in `env` into the container. + run: > + docker run \ + $(echo '${{ toJSON(env) }}' | jq -r 'keys[] | "--env \(.) "') \ + --volume ${{ github.workspace }}:${{ github.workspace }} \ + --workdir ${{ github.workspace }} \ + ${{ inputs.tag }} bash -c " + git config --global --add safe.directory ${{ github.workspace }} + ${{ inputs.command }} + " + shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000000..b9a9eaa82e969 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,806 @@ +name: CI +on: + pull_request: + push: + branches: + - '**' + tags-ignore: + - '**' + +concurrency: + group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }} + cancel-in-progress: true + +env: + ### compiler options + HOST: + WRAPPER_CMD: + # Specific warnings can be disabled with -Wno-error=foo. + # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual. + WERROR_CFLAGS: '-Werror -pedantic-errors' + MAKEFLAGS: '-j4' + BUILD: 'check' + ### secp256k1 config + ECMULTWINDOW: 'auto' + ECMULTGENPRECISION: 'auto' + ASM: 'no' + WIDEMUL: 'auto' + WITH_VALGRIND: 'yes' + EXTRAFLAGS: + ### secp256k1 modules + EXPERIMENTAL: 'no' + ECDH: 'no' + RECOVERY: 'no' + SCHNORRSIG: 'no' + ELLSWIFT: 'no' + ### test options + SECP256K1_TEST_ITERS: + BENCH: 'yes' + SECP256K1_BENCH_ITERS: 2 + CTIMETESTS: 'yes' + # Compile and run the examples. + EXAMPLES: 'yes' + +jobs: + docker_cache: + name: "Build Docker image" + runs-on: ubuntu-latest + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + # See: https://github.com/moby/buildkit/issues/3969. + driver-opts: | + network=host + + - name: Build container + uses: docker/build-push-action@v4 + with: + file: ./ci/linux-debian.Dockerfile + tags: linux-debian-image + cache-from: type=gha + cache-to: type=gha,mode=min + + linux_debian: + name: "x86_64: Linux (Debian stable)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' } + - env_vars: { WIDEMUL: 'int64', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128' } + - env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes' } + - env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' } + - env_vars: { RECOVERY: 'yes', SCHNORRSIG: 'yes' } + - env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', CPPFLAGS: '-DVERIFY' } + - env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' } + - env_vars: { CPPFLAGS: '-DDETERMINISTIC' } + - env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' } + - env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + - env_vars: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 } + cc: + - 'gcc' + - 'clang' + - 'gcc-snapshot' + - 'clang-snapshot' + + env: + CC: ${{ matrix.cc }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + i686_debian: + name: "i686: Linux (Debian stable)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + cc: + - 'i686-linux-gnu-gcc' + - 'clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include' + + env: + HOST: 'i686-linux-gnu' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + CC: ${{ matrix.cc }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + s390x_debian: + name: "s390x (big-endian): Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-s390x' + SECP256K1_TEST_ITERS: 16 + HOST: 's390x-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + arm32_debian: + name: "ARM32: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: {} + - env_vars: { EXPERIMENTAL: 'yes', ASM: 'arm32' } + + env: + WRAPPER_CMD: 'qemu-arm' + SECP256K1_TEST_ITERS: 16 + HOST: 'arm-linux-gnueabihf' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + arm64_debian: + name: "ARM64: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-aarch64' + SECP256K1_TEST_ITERS: 16 + HOST: 'aarch64-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { } # gcc + - env_vars: # clang + CC: 'clang --target=aarch64-linux-gnu' + - env_vars: # clang-snapshot + CC: 'clang-snapshot --target=aarch64-linux-gnu' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + ppc64le_debian: + name: "ppc64le: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-ppc64le' + SECP256K1_TEST_ITERS: 16 + HOST: 'powerpc64le-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + valgrind_debian: + name: "Valgrind (memcheck)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { CC: 'clang', ASM: 'auto' } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' } + - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + + env: + # The `--error-exitcode` is required to make the test fail if valgrind found errors, + # otherwise it will return 0 (https://www.valgrind.org/docs/manual/manual-core.html). + WRAPPER_CMD: 'valgrind --error-exitcode=42' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + SECP256K1_TEST_ITERS: 2 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + sanitizers_debian: + name: "UBSan, ASan, LSan" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { CC: 'clang', ASM: 'auto' } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' } + - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + + env: + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + CFLAGS: '-fsanitize=undefined,address -g' + UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1' + ASAN_OPTIONS: 'strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1' + LSAN_OPTIONS: 'use_unaligned=1' + SECP256K1_TEST_ITERS: 32 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + msan_debian: + name: "MSan" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g' + - env_vars: + ECMULTGENPRECISION: 2 + ECMULTWINDOW: 2 + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g -O3' + + env: + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'yes' + CC: 'clang' + SECP256K1_TEST_ITERS: 32 + ASM: 'no' + WITH_VALGRIND: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + mingw_debian: + name: ${{ matrix.configuration.job_name }} + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'wine' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + configuration: + - job_name: 'x86_64 (mingw32-w64): Windows (Debian stable, Wine)' + env_vars: + HOST: 'x86_64-w64-mingw32' + - job_name: 'i686 (mingw32-w64): Windows (Debian stable, Wine)' + env_vars: + HOST: 'i686-w64-mingw32' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + macos-native: + name: "x86_64: macOS Monterey" + # See: https://github.com/actions/runner-images#available-images. + runs-on: macos-12 # Use M1 once available https://github.com/github/roadmap/issues/528 + + env: + CC: 'clang' + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 + + strategy: + fail-fast: false + matrix: + env_vars: + - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 } + - { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' } + - BUILD: 'distcheck' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Homebrew packages + run: | + brew install automake libtool gcc + ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc + + - name: Install and cache Valgrind + uses: ./.github/actions/install-homebrew-valgrind + + - name: CI script + 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() }} + + win64-native: + name: ${{ matrix.configuration.job_name }} + # See: https://github.com/actions/runner-images#available-images. + runs-on: windows-2022 + + strategy: + fail-fast: false + matrix: + configuration: + - job_name: 'x64 (MSVC): Windows (VS 2022, shared)' + cmake_options: '-A x64 -DBUILD_SHARED_LIBS=ON' + - 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)' + cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct' + - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct with __(u)mulh)' + cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct' + cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE' + - job_name: 'x86 (MSVC): Windows (VS 2022)' + cmake_options: '-A Win32' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Generate buildsystem + run: cmake -E env CFLAGS="/WX ${{ matrix.configuration.cpp_flags }}" cmake -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON ${{ matrix.configuration.cmake_options }} + + - name: Build + run: cmake --build build --config RelWithDebInfo -- /p:UseMultiToolTask=true /maxCpuCount + + - name: Binaries info + # Use the bash shell included with Git for Windows. + shell: bash + run: | + cd build/src/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true + + - name: Check + run: | + ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1) + build\src\RelWithDebInfo\bench_ecmult.exe + build\src\RelWithDebInfo\bench_internal.exe + build\src\RelWithDebInfo\bench.exe + + win64-native-headers: + name: "x64 (MSVC): C++ (public headers)" + # See: https://github.com/actions/runner-images#available-images. + runs-on: windows-2022 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Add cl.exe to PATH + uses: ilammy/msvc-dev-cmd@v1 + + - name: C++ (public headers) + run: | + cl.exe -c -WX -TP include/*.h + + cxx_fpermissive_debian: + name: "C++ -fpermissive (entire project)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + CC: 'g++' + CFLAGS: '-fpermissive -g' + CPPFLAGS: '-DSECP256K1_CPLUSPLUS_TEST_OVERRIDE' + WERROR_CFLAGS: + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + 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() }} + + cxx_headers_debian: + name: "C++ (public headers)" + runs-on: ubuntu-latest + needs: docker_cache + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + command: | + g++ -Werror include/*.h + clang -Werror -x c++-header include/*.h + + sage: + name: "SageMath prover" + runs-on: ubuntu-latest + container: + image: sagemath/sagemath:latest + options: --user root + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + run: | + cd sage + sage prove_group_implementations.sage + + release: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - run: ./autogen.sh && ./configure --enable-dev-mode && make distcheck + + - name: Check installation with Autotools + env: + CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }} + run: | + ./autogen.sh && ./configure --prefix=${{ env.CI_INSTALL }} && make clean && make install && ls -RlAh ${{ env.CI_INSTALL }} + gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=${{ env.CI_INSTALL }}/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"${{ env.CI_INSTALL }}/lib" && ./ecdsa + + - name: Check installation with CMake + env: + CI_BUILD: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/build + CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install + run: | + cmake -B ${{ env.CI_BUILD }} -DCMAKE_INSTALL_PREFIX=${{ env.CI_INSTALL }} && cmake --build ${{ env.CI_BUILD }} --target install && ls -RlAh ${{ env.CI_INSTALL }} + gcc -o ecdsa examples/ecdsa.c -I ${{ env.CI_INSTALL }}/include -L ${{ env.CI_INSTALL }}/lib*/ -l secp256k1 -Wl,-rpath,"${{ env.CI_INSTALL }}/lib",-rpath,"${{ env.CI_INSTALL }}/lib64" && ./ecdsa diff --git a/CHANGELOG.md b/CHANGELOG.md index dacb0a3f48c03..e8d8db5a1e036 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.4.0] - 2023-09-04 #### Added - New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them. @@ -13,10 +13,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Header file `include/secp256k1_ellswift.h` which defines the new API. - Document `doc/ellswift.md` which explains the mathematical background of the scheme. - The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based. + - We now test the library with unreleased development snapshots of GCC and Clang. This gives us an early chance to catch miscompilations and constant-time issues introduced by the compiler (such as those that led to the previous two releases). + +#### Fixed + - Fixed symbol visibility in Windows DLL builds, where three internal library symbols were wrongly exported. #### Changed - When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`. +#### ABI Compatibility +This release is backward compatible with the ABI of 0.3.0, 0.3.1, and 0.3.2. Symbol visibility is now believed to be handled properly on supported platforms and is now considered to be part of the ABI. Please report any improperly exported symbols as a bug. + ## [0.3.2] - 2023-05-13 We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`. @@ -97,7 +104,8 @@ This version was in fact never released. The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6). Therefore, this version number does not uniquely identify a set of source files. -[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...HEAD +[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...HEAD +[0.4.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...v0.4.0 [0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3107eb3bf1666..cdac47ba9d1cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ project(libsecp256k1 # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of # the API. All changes in experimental modules are treated as # backwards-compatible and therefore at most increase the minor version. - VERSION 0.3.3 + VERSION 0.4.0 DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1." HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1" LANGUAGES C @@ -34,9 +34,9 @@ endif() # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # All changes in experimental modules are treated as if they don't affect the # interface and therefore only increase the revision. -set(${PROJECT_NAME}_LIB_VERSION_CURRENT 2) -set(${PROJECT_NAME}_LIB_VERSION_REVISION 3) -set(${PROJECT_NAME}_LIB_VERSION_AGE 0) +set(${PROJECT_NAME}_LIB_VERSION_CURRENT 3) +set(${PROJECT_NAME}_LIB_VERSION_REVISION 0) +set(${PROJECT_NAME}_LIB_VERSION_AGE 1) set(CMAKE_C_STANDARD 90) set(CMAKE_C_EXTENSIONS OFF) diff --git a/ci/cirrus.sh b/ci/ci.sh similarity index 90% rename from ci/cirrus.sh rename to ci/ci.sh index 48a9783cc4173..719e7851efdf9 100755 --- a/ci/cirrus.sh +++ b/ci/ci.sh @@ -13,7 +13,7 @@ print_environment() { # does not rely on bash. for var in WERROR_CFLAGS MAKEFLAGS BUILD \ ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ - EXPERIMENTAL ECDH RECOVERY SCHNORRSIG \ + EXPERIMENTAL ECDH RECOVERY SCHNORRSIG ELLSWIFT \ SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ EXAMPLES \ HOST WRAPPER_CMD \ @@ -31,18 +31,15 @@ print_environment() { } print_environment -# Start persistent wineserver if necessary. -# This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously. -case "$WRAPPER_CMD" in - *wine*) - # Make sure to shutdown wineserver whenever we exit. - trap "wineserver -k || true" EXIT INT HUP - wineserver -p +env >> test_env.log + +# If gcc is requested, assert that it's in fact gcc (and not some symlinked Apple clang). +case "${CC:-undefined}" in + *gcc*) + $CC -v 2>&1 | grep -q "gcc version" || exit 1; ;; esac -env >> test_env.log - if [ -n "${CC+x}" ]; then # The MSVC compiler "cl" doesn't understand "-v" $CC -v || true diff --git a/ci/linux-debian.Dockerfile b/ci/linux-debian.Dockerfile index dbb1dd2919295..e719907e8937a 100644 --- a/ci/linux-debian.Dockerfile +++ b/ci/linux-debian.Dockerfile @@ -1,7 +1,18 @@ -FROM debian:stable +FROM debian:stable-slim SHELL ["/bin/bash", "-c"] +WORKDIR /root + +# A too high maximum number of file descriptors (with the default value +# inherited from the docker host) can cause issues with some of our tools: +# - sanitizers hanging: https://github.com/google/sanitizers/issues/1662 +# - valgrind crashing: https://stackoverflow.com/a/75293014 +# This is not be a problem on our CI hosts, but developers who run the image +# on their machines may run into this (e.g., on Arch Linux), so warn them. +# (Note that .bashrc is only executed in interactive bash shells.) +RUN echo 'if [[ $(ulimit -n) -gt 200000 ]]; then echo "WARNING: Very high value reported by \"ulimit -n\". Consider passing \"--ulimit nofile=32768\" to \"docker run\"."; fi' >> /root/.bashrc + RUN dpkg --add-architecture i386 && \ dpkg --add-architecture s390x && \ dpkg --add-architecture armhf && \ @@ -11,7 +22,7 @@ RUN dpkg --add-architecture i386 && \ # dkpg-dev: to make pkg-config work in cross-builds # llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces RUN apt-get update && apt-get install --no-install-recommends -y \ - git ca-certificates wget \ + git ca-certificates \ make automake libtool pkg-config dpkg-dev valgrind qemu-user \ gcc clang llvm libclang-rt-dev libc6-dbg \ g++ \ @@ -22,13 +33,13 @@ 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 \ - sagemath - -WORKDIR /root + python3 # Build and install gcc snapshot ARG GCC_SNAPSHOT_MAJOR=14 -RUN wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --level 1 --no-directories "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}" && \ +RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ + mkdir gcc && cd gcc && \ + wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --level 1 --no-directories "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}" && \ wget "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}/sha512.sum" && \ sha512sum --check --ignore-missing sha512.sum && \ # We should have downloaded exactly one tar.xz file @@ -36,40 +47,29 @@ RUN wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --leve [[ $(ls *.tar.xz | wc -l) -eq "1" ]] && \ tar xf *.tar.xz && \ mkdir gcc-build && cd gcc-build && \ - apt-get update && apt-get install --no-install-recommends -y libgmp-dev libmpfr-dev libmpc-dev flex && \ ../*/configure --prefix=/opt/gcc-snapshot --enable-languages=c --disable-bootstrap --disable-multilib --without-isl && \ make -j $(nproc) && \ make install && \ - ln -s /opt/gcc-snapshot/bin/gcc /usr/bin/gcc-snapshot + cd ../.. && rm -rf gcc && \ + ln -s /opt/gcc-snapshot/bin/gcc /usr/bin/gcc-snapshot && \ + apt-get autoremove -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \ + apt-get clean && rm -rf /var/lib/apt/lists/* -# Install clang snapshot -RUN wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \ +# Install clang snapshot, see https://apt.llvm.org/ +RUN \ + # Setup GPG keys of LLVM repository + apt-get update && apt-get install --no-install-recommends -y wget && \ + 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 && \ - # Install clang snapshot - apt-get update && apt-get install --no-install-recommends -y clang && \ - # Remove just the "clang" symlink again - apt-get remove -y clang && \ - # We should have exactly two clang versions now - ls /usr/bin/clang* && \ - [[ $(ls /usr/bin/clang-?? | sort | wc -l) -eq "2" ]] && \ - # Create symlinks for them - ln -s $(ls /usr/bin/clang-?? | sort | tail -1) /usr/bin/clang-snapshot && \ - ln -s $(ls /usr/bin/clang-?? | sort | head -1) /usr/bin/clang + 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"-" ) && \ + # Install + apt-get install --no-install-recommends -y "clang-${LLVM_VERSION}" && \ + # Create symlink + ln -s "/usr/bin/clang-${LLVM_VERSION}" /usr/bin/clang-snapshot && \ + # Clean up + apt-get autoremove -y wget && \ + apt-get clean && rm -rf /var/lib/apt/lists/* -# The "wine" package provides a convenience wrapper that we need -RUN apt-get update && apt-get install --no-install-recommends -y \ - git ca-certificates wine64 wine python3-simplejson python3-six msitools winbind procps && \ -# Workaround for `wine` package failure to employ the Debian alternatives system properly. - ln -s /usr/lib/wine/wine64 /usr/bin/wine64 && \ -# Set of tools for using MSVC on Linux. - git clone https://github.com/mstorsjo/msvc-wine && \ - mkdir /opt/msvc && \ - python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \ -# Since commit 2146cbfaf037e21de56c7157ec40bb6372860f51, the -# msvc-wine effectively initializes the wine prefix when running -# the install.sh script. - msvc-wine/install.sh /opt/msvc && \ -# Wait until the wineserver process has exited before closing the session, -# to avoid corrupting the wine prefix. - while (ps -A | grep wineserver) > /dev/null; do sleep 1; done diff --git a/configure.ac b/configure.ac index a502d1304a7b2..e3877850d3cfb 100644 --- a/configure.ac +++ b/configure.ac @@ -4,18 +4,18 @@ AC_PREREQ([2.60]) # the API. All changes in experimental modules are treated as # backwards-compatible and therefore at most increase the minor version. define(_PKG_VERSION_MAJOR, 0) -define(_PKG_VERSION_MINOR, 3) -define(_PKG_VERSION_PATCH, 3) -define(_PKG_VERSION_IS_RELEASE, false) +define(_PKG_VERSION_MINOR, 4) +define(_PKG_VERSION_PATCH, 0) +define(_PKG_VERSION_IS_RELEASE, true) # The library version is based on libtool versioning of the ABI. The set of # rules for updating the version can be found here: # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # All changes in experimental modules are treated as if they don't affect the # interface and therefore only increase the revision. -define(_LIB_VERSION_CURRENT, 2) -define(_LIB_VERSION_REVISION, 3) -define(_LIB_VERSION_AGE, 0) +define(_LIB_VERSION_CURRENT, 3) +define(_LIB_VERSION_REVISION, 0) +define(_LIB_VERSION_AGE, 1) AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) @@ -401,7 +401,7 @@ if test x"$enable_module_schnorrsig" = x"yes"; then fi if test x"$enable_module_ellswift" = x"yes"; then - AC_DEFINE(ENABLE_MODULE_ELLSWIFT, 1, [Define this symbol to enable the ElligatorSwift module]) + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1" fi # Test if extrakeys is set after the schnorrsig module to allow the schnorrsig diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e2ea47300854b..607bb6777052b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,24 +1,30 @@ -add_library(example INTERFACE) -target_include_directories(example INTERFACE - ${PROJECT_SOURCE_DIR}/include -) -target_link_libraries(example INTERFACE - secp256k1 - $<$:bcrypt> -) +function(add_example name) + set(target_name ${name}_example) + add_executable(${target_name} ${name}.c) + target_include_directories(${target_name} PRIVATE + ${PROJECT_SOURCE_DIR}/include + ) + target_link_libraries(${target_name} + secp256k1 + $<$:bcrypt> + ) + set(test_name ${name}_example) + add_test(NAME ${test_name} COMMAND ${target_name}) + if(BUILD_SHARED_LIBS AND MSVC) + # The DLL must reside either in the same folder where the executable is + # or somewhere in PATH. Using the latter option. + set_tests_properties(${test_name} PROPERTIES + ENVIRONMENT "PATH=$;$ENV{PATH}" + ) + endif() +endfunction() -add_executable(ecdsa_example ecdsa.c) -target_link_libraries(ecdsa_example example) -add_test(NAME ecdsa_example COMMAND ecdsa_example) +add_example(ecdsa) if(SECP256K1_ENABLE_MODULE_ECDH) - add_executable(ecdh_example ecdh.c) - target_link_libraries(ecdh_example example) - add_test(NAME ecdh_example COMMAND ecdh_example) + add_example(ecdh) endif() if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) - add_executable(schnorr_example schnorr.c) - target_link_libraries(schnorr_example example) - add_test(NAME schnorr_example COMMAND schnorr_example) + add_example(schnorr) endif() diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c index 8818aa81b5b17..7dc52ad87be4c 100644 --- a/src/bench_ecmult.c +++ b/src/bench_ecmult.c @@ -244,7 +244,6 @@ static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) { static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_g, int num_iters) { char str[32]; - static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); size_t iters = 1 + num_iters / count; size_t iter; @@ -262,7 +261,7 @@ static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_ secp256k1_scalar_add(&total, &total, &tmp); } secp256k1_scalar_negate(&total, &total); - secp256k1_ecmult(&data->expected_output[iter], NULL, &zero, &total); + secp256k1_ecmult(&data->expected_output[iter], NULL, &secp256k1_scalar_zero, &total); } /* Run the benchmark. */ diff --git a/src/checkmem.h b/src/checkmem.h index 571e4cc38970b..f2169decfc094 100644 --- a/src/checkmem.h +++ b/src/checkmem.h @@ -58,7 +58,14 @@ #if !defined SECP256K1_CHECKMEM_ENABLED # if defined VALGRIND # include +# if defined(__clang__) && defined(__APPLE__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wreserved-identifier" +# endif # include +# if defined(__clang__) && defined(__APPLE__) +# pragma clang diagnostic pop +# endif # define SECP256K1_CHECKMEM_ENABLED 1 # define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len)) # define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len)) diff --git a/src/ctime_tests.c b/src/ctime_tests.c index af7891a91ce29..a384e831529da 100644 --- a/src/ctime_tests.c +++ b/src/ctime_tests.c @@ -181,27 +181,27 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) { #endif #ifdef ENABLE_MODULE_ELLSWIFT - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ellswift_create(ctx, ellswift, key, ellswift); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); for (i = 0; i < 2; i++) { - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_DEFINED(&ellswift, sizeof(ellswift)); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_bip324, NULL); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); - VALGRIND_MAKE_MEM_UNDEFINED(key, 32); - VALGRIND_MAKE_MEM_DEFINED(&ellswift, sizeof(ellswift)); + SECP256K1_CHECKMEM_UNDEFINE(key, 32); + SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_prefix, (void *)prefix); - VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); } diff --git a/src/field.h b/src/field.h index bb99f948ef1f0..ccd228e1ae659 100644 --- a/src/field.h +++ b/src/field.h @@ -176,12 +176,6 @@ static int secp256k1_fe_is_odd(const secp256k1_fe *a); */ static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); -/** Determine whether two field elements are equal, without constant-time guarantee. - * - * Identical in behavior to secp256k1_fe_equal, but not constant time in either a or b. - */ -static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); - /** Compare the values represented by 2 field elements, without constant-time guarantee. * * On input, a and b must be valid normalized field elements. @@ -352,4 +346,7 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *a); /** Check invariants on a field element (no-op unless VERIFY is enabled). */ static void secp256k1_fe_verify(const secp256k1_fe *a); +/** Check that magnitude of a is at most m (no-op unless VERIFY is enabled). */ +static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m); + #endif /* SECP256K1_FIELD_H */ diff --git a/src/field_impl.h b/src/field_impl.h index 7f18ebdc94e07..80d34b9ef23fe 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -23,27 +23,14 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp #ifdef VERIFY secp256k1_fe_verify(a); secp256k1_fe_verify(b); - VERIFY_CHECK(a->magnitude <= 1); - VERIFY_CHECK(b->magnitude <= 31); + secp256k1_fe_verify_magnitude(a, 1); + secp256k1_fe_verify_magnitude(b, 31); #endif secp256k1_fe_negate(&na, a, 1); secp256k1_fe_add(&na, b); return secp256k1_fe_normalizes_to_zero(&na); } -SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) { - secp256k1_fe na; -#ifdef VERIFY - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); - VERIFY_CHECK(a->magnitude <= 1); - VERIFY_CHECK(b->magnitude <= 31); -#endif - secp256k1_fe_negate(&na, a, 1); - secp256k1_fe_add(&na, b); - return secp256k1_fe_normalizes_to_zero_var(&na); -} - static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a) { /** Given that p is congruent to 3 mod 4, we can compute the square root of * a mod p as the (p+1)/4'th power of a. @@ -60,7 +47,7 @@ static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k #ifdef VERIFY VERIFY_CHECK(r != a); secp256k1_fe_verify(a); - VERIFY_CHECK(a->magnitude <= 8); + secp256k1_fe_verify_magnitude(a, 8); #endif /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in @@ -151,7 +138,7 @@ static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k if (!ret) { secp256k1_fe_negate(&t1, &t1, 1); secp256k1_fe_normalize_var(&t1); - VERIFY_CHECK(secp256k1_fe_equal_var(&t1, a)); + VERIFY_CHECK(secp256k1_fe_equal(&t1, a)); } #endif return ret; @@ -159,19 +146,26 @@ static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k #ifndef VERIFY static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; } +static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { (void)a; (void)m; } #else static void secp256k1_fe_impl_verify(const secp256k1_fe *a); static void secp256k1_fe_verify(const secp256k1_fe *a) { /* Magnitude between 0 and 32. */ - VERIFY_CHECK((a->magnitude >= 0) && (a->magnitude <= 32)); + secp256k1_fe_verify_magnitude(a, 32); /* Normalized is 0 or 1. */ VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1)); /* If normalized, magnitude must be 0 or 1. */ - if (a->normalized) VERIFY_CHECK(a->magnitude <= 1); + if (a->normalized) secp256k1_fe_verify_magnitude(a, 1); /* Invoke implementation-specific checks. */ secp256k1_fe_impl_verify(a); } +static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { + VERIFY_CHECK(m >= 0); + VERIFY_CHECK(m <= 32); + VERIFY_CHECK(a->magnitude <= m); +} + static void secp256k1_fe_impl_normalize(secp256k1_fe *r); SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) { secp256k1_fe_verify(r); @@ -293,7 +287,7 @@ static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_ SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { secp256k1_fe_verify(a); VERIFY_CHECK(m >= 0 && m <= 31); - VERIFY_CHECK(a->magnitude <= m); + secp256k1_fe_verify_magnitude(a, m); secp256k1_fe_impl_negate_unchecked(r, a, m); r->magnitude = m + 1; r->normalized = 0; @@ -326,8 +320,8 @@ static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { secp256k1_fe_verify(a); secp256k1_fe_verify(b); - VERIFY_CHECK(a->magnitude <= 8); - VERIFY_CHECK(b->magnitude <= 8); + secp256k1_fe_verify_magnitude(a, 8); + secp256k1_fe_verify_magnitude(b, 8); VERIFY_CHECK(r != b); VERIFY_CHECK(a != b); secp256k1_fe_impl_mul(r, a, b); @@ -339,7 +333,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_f static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a); SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { secp256k1_fe_verify(a); - VERIFY_CHECK(a->magnitude <= 8); + secp256k1_fe_verify_magnitude(a, 8); secp256k1_fe_impl_sqr(r, a); r->magnitude = 1; r->normalized = 0; @@ -418,7 +412,7 @@ SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { static void secp256k1_fe_impl_half(secp256k1_fe *r); SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) { secp256k1_fe_verify(r); - VERIFY_CHECK(r->magnitude < 32); + secp256k1_fe_verify_magnitude(r, 31); secp256k1_fe_impl_half(r); r->magnitude = (r->magnitude >> 1) + 1; r->normalized = 0; diff --git a/src/group.h b/src/group.h index 1cc61371615a8..86eb9e1f82b65 100644 --- a/src/group.h +++ b/src/group.h @@ -44,6 +44,14 @@ typedef struct { #define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) +/** Maximum allowed magnitudes for group element coordinates + * in affine (x, y) and jacobian (x, y, z) representation. */ +#define SECP256K1_GE_X_MAGNITUDE_MAX 4 +#define SECP256K1_GE_Y_MAGNITUDE_MAX 3 +#define SECP256K1_GEJ_X_MAGNITUDE_MAX 4 +#define SECP256K1_GEJ_Y_MAGNITUDE_MAX 4 +#define SECP256K1_GEJ_Z_MAGNITUDE_MAX 1 + /** Set a group element equal to the point with given X and Y coordinates */ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); diff --git a/src/group_impl.h b/src/group_impl.h index ffdfeaa10a98e..b9542ce8aea17 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -77,6 +77,8 @@ static void secp256k1_ge_verify(const secp256k1_ge *a) { #ifdef VERIFY secp256k1_fe_verify(&a->x); secp256k1_fe_verify(&a->y); + secp256k1_fe_verify_magnitude(&a->x, SECP256K1_GE_X_MAGNITUDE_MAX); + secp256k1_fe_verify_magnitude(&a->y, SECP256K1_GE_Y_MAGNITUDE_MAX); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); #endif (void)a; @@ -87,6 +89,9 @@ static void secp256k1_gej_verify(const secp256k1_gej *a) { secp256k1_fe_verify(&a->x); secp256k1_fe_verify(&a->y); secp256k1_fe_verify(&a->z); + secp256k1_fe_verify_magnitude(&a->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); + secp256k1_fe_verify_magnitude(&a->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); + secp256k1_fe_verify_magnitude(&a->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); #endif (void)a; @@ -99,11 +104,13 @@ static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, c secp256k1_gej_verify(a); secp256k1_fe_verify(zi); VERIFY_CHECK(!a->infinity); + secp256k1_fe_sqr(&zi2, zi); secp256k1_fe_mul(&zi3, &zi2, zi); secp256k1_fe_mul(&r->x, &a->x, &zi2); secp256k1_fe_mul(&r->y, &a->y, &zi3); r->infinity = a->infinity; + secp256k1_ge_verify(r); } @@ -114,39 +121,47 @@ static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, con secp256k1_ge_verify(a); secp256k1_fe_verify(zi); VERIFY_CHECK(!a->infinity); + secp256k1_fe_sqr(&zi2, zi); secp256k1_fe_mul(&zi3, &zi2, zi); secp256k1_fe_mul(&r->x, &a->x, &zi2); secp256k1_fe_mul(&r->y, &a->y, &zi3); r->infinity = a->infinity; + secp256k1_ge_verify(r); } static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { secp256k1_fe_verify(x); secp256k1_fe_verify(y); + r->infinity = 0; r->x = *x; r->y = *y; + secp256k1_ge_verify(r); } static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { secp256k1_ge_verify(a); + return a->infinity; } static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { secp256k1_ge_verify(a); + *r = *a; secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); + secp256k1_ge_verify(r); } static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe z2, z3; secp256k1_gej_verify(a); + r->infinity = a->infinity; secp256k1_fe_inv(&a->z, &a->z); secp256k1_fe_sqr(&z2, &a->z); @@ -156,12 +171,15 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe_set_int(&a->z, 1); r->x = a->x; r->y = a->y; + + secp256k1_gej_verify(a); secp256k1_ge_verify(r); } static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe z2, z3; secp256k1_gej_verify(a); + if (secp256k1_gej_is_infinity(a)) { secp256k1_ge_set_infinity(r); return; @@ -174,6 +192,8 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe_mul(&a->y, &a->y, &z3); secp256k1_fe_set_int(&a->z, 1); secp256k1_ge_set_xy(r, &a->x, &a->y); + + secp256k1_gej_verify(a); secp256k1_ge_verify(r); } @@ -181,9 +201,13 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a secp256k1_fe u; size_t i; size_t last_i = SIZE_MAX; - +#ifdef VERIFY for (i = 0; i < len; i++) { secp256k1_gej_verify(&a[i]); + } +#endif + + for (i = 0; i < len; i++) { if (a[i].infinity) { secp256k1_ge_set_infinity(&r[i]); } else { @@ -217,36 +241,46 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a if (!a[i].infinity) { 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_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr) { - size_t i = len - 1; + size_t i; secp256k1_fe zs; - - if (len > 0) { - /* Verify inputs a[len-1] and zr[len-1]. */ +#ifdef VERIFY + for (i = 0; i < len; i++) { secp256k1_ge_verify(&a[i]); secp256k1_fe_verify(&zr[i]); + } +#endif + + if (len > 0) { + i = len - 1; /* Ensure all y values are in weak normal form for fast negation of points */ secp256k1_fe_normalize_weak(&a[i].y); zs = zr[i]; /* Work our way backwards, using the z-ratios to scale the x/y values. */ while (i > 0) { - /* Verify all inputs a[i] and zr[i]. */ - secp256k1_fe_verify(&zr[i]); - secp256k1_ge_verify(&a[i]); if (i != len - 1) { secp256k1_fe_mul(&zs, &zs, &zr[i]); } i--; secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs); - /* Verify the output a[i]. */ - secp256k1_ge_verify(&a[i]); } } + +#ifdef VERIFY + for (i = 0; i < len; i++) { + secp256k1_ge_verify(&a[i]); + } +#endif } static void secp256k1_gej_set_infinity(secp256k1_gej *r) { @@ -254,6 +288,7 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) { secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); secp256k1_fe_clear(&r->z); + secp256k1_gej_verify(r); } @@ -261,6 +296,7 @@ static void secp256k1_ge_set_infinity(secp256k1_ge *r) { r->infinity = 1; secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); + secp256k1_ge_verify(r); } @@ -269,18 +305,23 @@ static void secp256k1_gej_clear(secp256k1_gej *r) { secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); secp256k1_fe_clear(&r->z); + + secp256k1_gej_verify(r); } static void secp256k1_ge_clear(secp256k1_ge *r) { r->infinity = 0; secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); + + secp256k1_ge_verify(r); } static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { secp256k1_fe x2, x3; int ret; secp256k1_fe_verify(x); + r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); @@ -291,16 +332,19 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o if (secp256k1_fe_is_odd(&r->y) != odd) { secp256k1_fe_negate(&r->y, &r->y, 1); } + secp256k1_ge_verify(r); return ret; } static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { secp256k1_ge_verify(a); + r->infinity = a->infinity; r->x = a->x; r->y = a->y; secp256k1_fe_set_int(&r->z, 1); + secp256k1_gej_verify(r); } @@ -308,6 +352,7 @@ static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) secp256k1_gej tmp; secp256k1_gej_verify(b); secp256k1_gej_verify(a); + secp256k1_gej_neg(&tmp, a); secp256k1_gej_add_var(&tmp, &tmp, b, NULL); return secp256k1_gej_is_infinity(&tmp); @@ -315,37 +360,39 @@ static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { secp256k1_fe r; - -#ifdef VERIFY secp256k1_fe_verify(x); - VERIFY_CHECK(a->x.magnitude <= 31); secp256k1_gej_verify(a); +#ifdef VERIFY VERIFY_CHECK(!a->infinity); #endif secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); - return secp256k1_fe_equal_var(&r, &a->x); + return secp256k1_fe_equal(&r, &a->x); } static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { secp256k1_gej_verify(a); + r->infinity = a->infinity; r->x = a->x; r->y = a->y; r->z = a->z; secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); + secp256k1_gej_verify(r); } static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { secp256k1_gej_verify(a); + return a->infinity; } static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { secp256k1_fe y2, x3; secp256k1_ge_verify(a); + if (a->infinity) { return 0; } @@ -353,14 +400,14 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { secp256k1_fe_sqr(&y2, &a->y); secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); secp256k1_fe_add_int(&x3, SECP256K1_B); - return secp256k1_fe_equal_var(&y2, &x3); + return secp256k1_fe_equal(&y2, &x3); } static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) { /* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */ secp256k1_fe l, s, t; - secp256k1_gej_verify(a); + r->infinity = a->infinity; /* Formula used: @@ -387,10 +434,13 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25 secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */ secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */ secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */ + secp256k1_gej_verify(r); } static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { + secp256k1_gej_verify(a); + /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. @@ -401,7 +451,6 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s * the infinity flag even though the point doubles to infinity, and the result * point will be gibberish (z = 0 but infinity = 0). */ - secp256k1_gej_verify(a); if (a->infinity) { secp256k1_gej_set_infinity(r); if (rzr != NULL) { @@ -416,15 +465,16 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s } secp256k1_gej_double(r, a); + secp256k1_gej_verify(r); } static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { /* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t; - secp256k1_gej_verify(a); secp256k1_gej_verify(b); + if (a->infinity) { VERIFY_CHECK(rzr == NULL); *r = *b; @@ -479,14 +529,16 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); + secp256k1_gej_verify(r); } static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { - /* 8 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */ + /* Operations: 8 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t; secp256k1_gej_verify(a); secp256k1_ge_verify(b); + if (a->infinity) { VERIFY_CHECK(rzr == NULL); secp256k1_gej_set_ge(r, b); @@ -501,11 +553,11 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c } secp256k1_fe_sqr(&z12, &a->z); - u1 = a->x; secp256k1_fe_normalize_weak(&u1); + u1 = a->x; secp256k1_fe_mul(&u2, &b->x, &z12); - s1 = a->y; secp256k1_fe_normalize_weak(&s1); + s1 = a->y; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); - secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2); secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); if (secp256k1_fe_normalizes_to_zero_var(&h)) { if (secp256k1_fe_normalizes_to_zero_var(&i)) { @@ -539,16 +591,18 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); + secp256k1_gej_verify(r); if (rzr != NULL) secp256k1_fe_verify(rzr); } static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { - /* 9 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */ + /* Operations: 9 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */ secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t; - + secp256k1_gej_verify(a); secp256k1_ge_verify(b); secp256k1_fe_verify(bzinv); + if (a->infinity) { secp256k1_fe bzinv2, bzinv3; r->infinity = b->infinity; @@ -557,6 +611,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe_mul(&r->x, &b->x, &bzinv2); secp256k1_fe_mul(&r->y, &b->y, &bzinv3); secp256k1_fe_set_int(&r->z, 1); + secp256k1_gej_verify(r); return; } if (b->infinity) { @@ -575,11 +630,11 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe_mul(&az, &a->z, bzinv); secp256k1_fe_sqr(&z12, &az); - u1 = a->x; secp256k1_fe_normalize_weak(&u1); + u1 = a->x; secp256k1_fe_mul(&u2, &b->x, &z12); - s1 = a->y; secp256k1_fe_normalize_weak(&s1); + s1 = a->y; secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az); - secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2); secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1); if (secp256k1_fe_normalizes_to_zero_var(&h)) { if (secp256k1_fe_normalizes_to_zero_var(&i)) { @@ -607,19 +662,19 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe_mul(&r->y, &t, &i); secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_add(&r->y, &h3); + secp256k1_gej_verify(r); } static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) { - /* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */ + /* Operations: 7 mul, 5 sqr, 21 add/cmov/half/mul_int/negate/normalizes_to_zero */ secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; secp256k1_fe m_alt, rr_alt; int degenerate; secp256k1_gej_verify(a); secp256k1_ge_verify(b); VERIFY_CHECK(!b->infinity); - VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); /* In: * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. @@ -672,17 +727,17 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const */ secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ - u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ + u1 = a->x; /* u1 = U1 = X1*Z2^2 (GEJ_X_M) */ secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ - s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ + s1 = a->y; /* s1 = S1 = Y1*Z2^3 (GEJ_Y_M) */ secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ - t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ - m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ + t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (GEJ_X_M+1) */ + m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (GEJ_Y_M+1) */ secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ - secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ - secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ - secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ + secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 (2) */ + secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (1) */ + secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (2) */ /* If lambda = R/M = R/0 we have a problem (except in the "trivial" * case that Z = z1z2 = 0, and this is special-cased later on). */ degenerate = secp256k1_fe_normalizes_to_zero(&m); @@ -692,24 +747,25 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), * so we set R/M equal to this. */ rr_alt = s1; - secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */ - secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */ + secp256k1_fe_mul_int(&rr_alt, 2); /* rr_alt = Y1*Z2^3 - Y2*Z1^3 (GEJ_Y_M*2) */ + secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 (GEJ_X_M+2) */ - secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); - secp256k1_fe_cmov(&m_alt, &m, !degenerate); + secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); /* rr_alt (GEJ_Y_M*2) */ + secp256k1_fe_cmov(&m_alt, &m, !degenerate); /* m_alt (GEJ_X_M+2) */ /* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0. * From here on out Ralt and Malt represent the numerator * and denominator of lambda; R and M represent the explicit * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ - secp256k1_fe_negate(&q, &t, 2); /* q = -T (3) */ + secp256k1_fe_negate(&q, &t, + SECP256K1_GEJ_X_MAGNITUDE_MAX + 1); /* q = -T (GEJ_X_M+2) */ secp256k1_fe_mul(&q, &q, &n); /* q = Q = -T*Malt^2 (1) */ /* These two lines use the observation that either M == Malt or M == 0, * so M^3 * Malt is either Malt^4 (which is computed by squaring), or * zero (which is "computed" by cmov). So the cost is one squaring * versus two multiplications. */ - secp256k1_fe_sqr(&n, &n); - secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ + secp256k1_fe_sqr(&n, &n); /* n = Malt^4 (1) */ + secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (GEJ_Y_M+1) */ secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */ secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */ @@ -717,9 +773,10 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */ secp256k1_fe_add(&t, &q); /* t = 2*X3 + Q (5) */ secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */ - secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (3) */ - secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */ - secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */ + secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (GEJ_Y_M+2) */ + secp256k1_fe_negate(&r->y, &t, + SECP256K1_GEJ_Y_MAGNITUDE_MAX + 2); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (GEJ_Y_M+3) */ + secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 ((GEJ_Y_M+3)/2 + 1) */ /* In case a->infinity == 1, replace r with (b->x, b->y, 1). */ secp256k1_fe_cmov(&r->x, &b->x, a->infinity); @@ -743,6 +800,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const * We have degenerate = false, r->z = (y1 + y2) * Z. * Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */ r->infinity = secp256k1_fe_normalizes_to_zero(&r->z); + secp256k1_gej_verify(r); } @@ -754,11 +812,13 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { #ifdef VERIFY VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s)); #endif + secp256k1_fe_sqr(&zz, s); secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ secp256k1_fe_mul(&r->y, &r->y, &zz); secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ + secp256k1_gej_verify(r); } @@ -766,6 +826,7 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge secp256k1_fe x, y; secp256k1_ge_verify(a); VERIFY_CHECK(!a->infinity); + x = a->x; secp256k1_fe_normalize(&x); y = a->y; @@ -778,17 +839,19 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag secp256k1_fe_from_storage(&r->x, &a->x); secp256k1_fe_from_storage(&r->y, &a->y); r->infinity = 0; + secp256k1_ge_verify(r); } static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) { secp256k1_gej_verify(r); secp256k1_gej_verify(a); + secp256k1_fe_cmov(&r->x, &a->x, flag); secp256k1_fe_cmov(&r->y, &a->y, flag); secp256k1_fe_cmov(&r->z, &a->z, flag); - r->infinity ^= (r->infinity ^ a->infinity) & flag; + secp256k1_gej_verify(r); } @@ -798,9 +861,11 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, } static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { - *r = *a; secp256k1_ge_verify(a); + + *r = *a; secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta); + secp256k1_ge_verify(r); } @@ -808,8 +873,8 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { #ifdef EXHAUSTIVE_TEST_ORDER secp256k1_gej out; int i; - secp256k1_ge_verify(ge); + /* A very simple EC multiplication ladder that avoids a dependency on ecmult. */ secp256k1_gej_set_infinity(&out); for (i = 0; i < 32; ++i) { @@ -820,6 +885,8 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) { } return secp256k1_gej_is_infinity(&out); #else + secp256k1_ge_verify(ge); + (void)ge; /* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */ return 1; diff --git a/src/hash_impl.h b/src/hash_impl.h index 0991fe78383b4..89f75ace74a20 100644 --- a/src/hash_impl.h +++ b/src/hash_impl.h @@ -138,7 +138,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char * } if (len) { /* Fill the buffer with what remains. */ - memcpy(((unsigned char*)hash->buf) + bufsize, data, len); + memcpy(hash->buf + bufsize, data, len); } } diff --git a/src/modules/extrakeys/tests_exhaustive_impl.h b/src/modules/extrakeys/tests_exhaustive_impl.h index d3d817a131f40..645bae2d470bf 100644 --- a/src/modules/extrakeys/tests_exhaustive_impl.h +++ b/src/modules/extrakeys/tests_exhaustive_impl.h @@ -48,7 +48,7 @@ static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp25 /* Compare the xonly_pubkey bytes against the precomputed group. */ secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]); - CHECK(secp256k1_fe_equal_var(&fe, &group[i].x)); + CHECK(secp256k1_fe_equal(&fe, &group[i].x)); /* Check the parity against the precomputed group. */ fe = group[i].y; diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index 4e7b45a045591..26727e46514bc 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -261,7 +261,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha secp256k1_fe_normalize_var(&r.y); return !secp256k1_fe_is_odd(&r.y) && - secp256k1_fe_equal_var(&rx, &r.x); + secp256k1_fe_equal(&rx, &r.x); } #endif diff --git a/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/modules/schnorrsig/tests_exhaustive_impl.h index 55f9028a6386f..bc31d8110720b 100644 --- a/src/modules/schnorrsig/tests_exhaustive_impl.h +++ b/src/modules/schnorrsig/tests_exhaustive_impl.h @@ -110,15 +110,15 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons if (!e_done[e]) { /* Iterate over the possible valid last 32 bytes in the signature. 0..order=that s value; order+1=random bytes */ - int count_valid = 0, s; + int count_valid = 0; + unsigned int s; for (s = 0; s <= EXHAUSTIVE_TEST_ORDER + 1; ++s) { int expect_valid, valid; if (s <= EXHAUSTIVE_TEST_ORDER) { - secp256k1_scalar s_s; - secp256k1_scalar_set_int(&s_s, s); - secp256k1_scalar_get_b32(sig64 + 32, &s_s); + memset(sig64 + 32, 0, 32); + secp256k1_write_be32(sig64 + 60, s); expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER && - (s_s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); + (s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); } else { secp256k1_testrand256(sig64 + 32); expect_valid = 0; diff --git a/src/scalar.h b/src/scalar.h index 63c0d646a3c26..4b3c2998bb655 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -99,4 +99,7 @@ static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_ /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/ static void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag); +/** Check invariants on a scalar (no-op unless VERIFY is enabled). */ +static void secp256k1_scalar_verify(const secp256k1_scalar *r); + #endif /* SECP256K1_SCALAR_H */ diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index 1d14740577677..715cc12ee53ef 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -41,16 +41,22 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig r->d[1] = 0; r->d[2] = 0; r->d[3] = 0; + + secp256k1_scalar_verify(r); } SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + secp256k1_scalar_verify(a); VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); + return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1); } SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + secp256k1_scalar_verify(a); VERIFY_CHECK(count < 32); VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 6 == offset >> 6) { return secp256k1_scalar_get_bits(a, offset, count); } else { @@ -74,6 +80,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { secp256k1_uint128 t; VERIFY_CHECK(overflow <= 1); + secp256k1_u128_from_u64(&t, r->d[0]); secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_0); r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); @@ -85,12 +92,17 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigne r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); secp256k1_u128_accum_u64(&t, r->d[3]); r->d[3] = secp256k1_u128_to_u64(&t); + + secp256k1_scalar_verify(r); return overflow; } static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { int overflow; secp256k1_uint128 t; + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); + secp256k1_u128_from_u64(&t, a->d[0]); secp256k1_u128_accum_u64(&t, b->d[0]); r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); @@ -106,13 +118,17 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, overflow = secp256k1_u128_to_u64(&t) + secp256k1_scalar_check_overflow(r); VERIFY_CHECK(overflow == 0 || overflow == 1); secp256k1_scalar_reduce(r, overflow); + + secp256k1_scalar_verify(r); return overflow; } static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { secp256k1_uint128 t; volatile int vflag = flag; + secp256k1_scalar_verify(r); VERIFY_CHECK(bit < 256); + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ secp256k1_u128_from_u64(&t, r->d[0]); secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); @@ -126,6 +142,8 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int secp256k1_u128_accum_u64(&t, r->d[3]); secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); r->d[3] = secp256k1_u128_to_u64(&t); + + secp256k1_scalar_verify(r); #ifdef VERIFY VERIFY_CHECK(secp256k1_u128_hi_u64(&t) == 0); #endif @@ -141,9 +159,13 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b if (overflow) { *overflow = over; } + + secp256k1_scalar_verify(r); } static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + secp256k1_scalar_verify(a); + secp256k1_write_be64(&bin[0], a->d[3]); secp256k1_write_be64(&bin[8], a->d[2]); secp256k1_write_be64(&bin[16], a->d[1]); @@ -151,12 +173,16 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* } SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; } static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); secp256k1_uint128 t; + secp256k1_scalar_verify(a); + secp256k1_u128_from_u64(&t, ~a->d[0]); secp256k1_u128_accum_u64(&t, SECP256K1_N_0 + 1); r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); @@ -169,15 +195,21 @@ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar secp256k1_u128_accum_u64(&t, ~a->d[3]); secp256k1_u128_accum_u64(&t, SECP256K1_N_3); r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; + + secp256k1_scalar_verify(r); } SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; } static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { int yes = 0; int no = 0; + secp256k1_scalar_verify(a); + no |= (a->d[3] < SECP256K1_N_H_3); yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */ @@ -194,6 +226,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { uint64_t mask = -vflag; uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; secp256k1_uint128 t; + secp256k1_scalar_verify(r); + secp256k1_u128_from_u64(&t, r->d[0] ^ mask); secp256k1_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask); r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); @@ -206,6 +240,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { secp256k1_u128_accum_u64(&t, r->d[3] ^ mask); secp256k1_u128_accum_u64(&t, SECP256K1_N_3 & mask); r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; + + secp256k1_scalar_verify(r); return 2 * (mask == 0) - 1; } @@ -764,23 +800,34 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { uint64_t l[8]; + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); + secp256k1_scalar_mul_512(l, a, b); secp256k1_scalar_reduce_512(r, l); + + secp256k1_scalar_verify(r); } static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { int ret; + secp256k1_scalar_verify(r); VERIFY_CHECK(n > 0); VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n)); r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n)); r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n)); r->d[3] = (r->d[3] >> n); + + secp256k1_scalar_verify(r); return ret; } static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { + secp256k1_scalar_verify(k); + r1->d[0] = k->d[0]; r1->d[1] = k->d[1]; r1->d[2] = 0; @@ -789,9 +836,15 @@ static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r r2->d[1] = k->d[3]; r2->d[2] = 0; r2->d[3] = 0; + + secp256k1_scalar_verify(r1); + secp256k1_scalar_verify(r2); } SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; } @@ -800,7 +853,10 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, unsigned int shiftlimbs; unsigned int shiftlow; unsigned int shifthigh; + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); VERIFY_CHECK(shift >= 256); + secp256k1_scalar_mul_512(l, a, b); shiftlimbs = shift >> 6; shiftlow = shift & 0x3F; @@ -810,18 +866,24 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); + + secp256k1_scalar_verify(r); } static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { uint64_t mask0, mask1; volatile int vflag = flag; + secp256k1_scalar_verify(a); SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); + mask0 = vflag + ~((uint64_t)0); mask1 = ~mask0; r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1); r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1); r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1); + + secp256k1_scalar_verify(r); } static void secp256k1_scalar_from_signed62(secp256k1_scalar *r, const secp256k1_modinv64_signed62 *a) { @@ -841,18 +903,13 @@ static void secp256k1_scalar_from_signed62(secp256k1_scalar *r, const secp256k1_ r->d[2] = a2 >> 4 | a3 << 58; r->d[3] = a3 >> 6 | a4 << 56; -#ifdef VERIFY - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); -#endif + secp256k1_scalar_verify(r); } static void secp256k1_scalar_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_scalar *a) { const uint64_t M62 = UINT64_MAX >> 2; const uint64_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3]; - -#ifdef VERIFY - VERIFY_CHECK(secp256k1_scalar_check_overflow(a) == 0); -#endif + secp256k1_scalar_verify(a); r->v[0] = a0 & M62; r->v[1] = (a0 >> 62 | a1 << 2) & M62; @@ -871,10 +928,13 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar #ifdef VERIFY int zero_in = secp256k1_scalar_is_zero(x); #endif + secp256k1_scalar_verify(x); + secp256k1_scalar_to_signed62(&s, x); secp256k1_modinv64(&s, &secp256k1_const_modinfo_scalar); secp256k1_scalar_from_signed62(r, &s); + secp256k1_scalar_verify(r); #ifdef VERIFY VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); #endif @@ -885,16 +945,21 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc #ifdef VERIFY int zero_in = secp256k1_scalar_is_zero(x); #endif + secp256k1_scalar_verify(x); + secp256k1_scalar_to_signed62(&s, x); secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_scalar); secp256k1_scalar_from_signed62(r, &s); + secp256k1_scalar_verify(r); #ifdef VERIFY VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); #endif } SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + return !(a->d[0] & 1); } diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index 80ef3ef2488e9..5ca1342273790 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -58,16 +58,22 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig r->d[5] = 0; r->d[6] = 0; r->d[7] = 0; + + secp256k1_scalar_verify(r); } SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + secp256k1_scalar_verify(a); VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); + return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1); } SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + secp256k1_scalar_verify(a); VERIFY_CHECK(count < 32); VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 5 == offset >> 5) { return secp256k1_scalar_get_bits(a, offset, count); } else { @@ -97,6 +103,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) { uint64_t t; VERIFY_CHECK(overflow <= 1); + t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; @@ -113,12 +120,17 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_ r->d[6] = t & 0xFFFFFFFFUL; t >>= 32; t += (uint64_t)r->d[7]; r->d[7] = t & 0xFFFFFFFFUL; + + secp256k1_scalar_verify(r); return overflow; } static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { int overflow; uint64_t t = (uint64_t)a->d[0] + b->d[0]; + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)a->d[1] + b->d[1]; r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; @@ -137,13 +149,17 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, overflow = t + secp256k1_scalar_check_overflow(r); VERIFY_CHECK(overflow == 0 || overflow == 1); secp256k1_scalar_reduce(r, overflow); + + secp256k1_scalar_verify(r); return overflow; } static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { uint64_t t; volatile int vflag = flag; + secp256k1_scalar_verify(r); VERIFY_CHECK(bit < 256); + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; @@ -161,9 +177,10 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F)); r->d[7] = t & 0xFFFFFFFFULL; + + secp256k1_scalar_verify(r); #ifdef VERIFY VERIFY_CHECK((t >> 32) == 0); - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); #endif } @@ -181,9 +198,13 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b if (overflow) { *overflow = over; } + + secp256k1_scalar_verify(r); } static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + secp256k1_scalar_verify(a); + secp256k1_write_be32(&bin[0], a->d[7]); secp256k1_write_be32(&bin[4], a->d[6]); secp256k1_write_be32(&bin[8], a->d[5]); @@ -195,12 +216,16 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* } SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; } static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; + secp256k1_scalar_verify(a); + r->d[0] = t & nonzero; t >>= 32; t += (uint64_t)(~a->d[1]) + SECP256K1_N_1; r->d[1] = t & nonzero; t >>= 32; @@ -216,15 +241,21 @@ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar r->d[6] = t & nonzero; t >>= 32; t += (uint64_t)(~a->d[7]) + SECP256K1_N_7; r->d[7] = t & nonzero; + + secp256k1_scalar_verify(r); } SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; } static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { int yes = 0; int no = 0; + secp256k1_scalar_verify(a); + no |= (a->d[7] < SECP256K1_N_H_7); yes |= (a->d[7] > SECP256K1_N_H_7) & ~no; no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */ @@ -247,6 +278,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { uint32_t mask = -vflag; uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + secp256k1_scalar_verify(r); + r->d[0] = t & nonzero; t >>= 32; t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); r->d[1] = t & nonzero; t >>= 32; @@ -262,6 +295,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { r->d[6] = t & nonzero; t >>= 32; t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); r->d[7] = t & nonzero; + + secp256k1_scalar_verify(r); return 2 * (mask == 0) - 1; } @@ -569,14 +604,21 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, con static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { uint32_t l[16]; + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); + secp256k1_scalar_mul_512(l, a, b); secp256k1_scalar_reduce_512(r, l); + + secp256k1_scalar_verify(r); } static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { int ret; + secp256k1_scalar_verify(r); VERIFY_CHECK(n > 0); VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n)); r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n)); @@ -586,10 +628,14 @@ static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n)); r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n)); r->d[7] = (r->d[7] >> n); + + secp256k1_scalar_verify(r); return ret; } static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { + secp256k1_scalar_verify(k); + r1->d[0] = k->d[0]; r1->d[1] = k->d[1]; r1->d[2] = k->d[2]; @@ -606,9 +652,15 @@ static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r r2->d[5] = 0; r2->d[6] = 0; r2->d[7] = 0; + + secp256k1_scalar_verify(r1); + secp256k1_scalar_verify(r2); } SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; } @@ -617,7 +669,10 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, unsigned int shiftlimbs; unsigned int shiftlow; unsigned int shifthigh; + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); VERIFY_CHECK(shift >= 256); + secp256k1_scalar_mul_512(l, a, b); shiftlimbs = shift >> 5; shiftlow = shift & 0x1F; @@ -631,12 +686,16 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); + + secp256k1_scalar_verify(r); } static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { uint32_t mask0, mask1; volatile int vflag = flag; + secp256k1_scalar_verify(a); SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d)); + mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); @@ -647,6 +706,8 @@ static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const se r->d[5] = (r->d[5] & mask0) | (a->d[5] & mask1); r->d[6] = (r->d[6] & mask0) | (a->d[6] & mask1); r->d[7] = (r->d[7] & mask0) | (a->d[7] & mask1); + + secp256k1_scalar_verify(r); } static void secp256k1_scalar_from_signed30(secp256k1_scalar *r, const secp256k1_modinv32_signed30 *a) { @@ -675,19 +736,14 @@ static void secp256k1_scalar_from_signed30(secp256k1_scalar *r, const secp256k1_ r->d[6] = a6 >> 12 | a7 << 18; r->d[7] = a7 >> 14 | a8 << 16; -#ifdef VERIFY - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); -#endif + secp256k1_scalar_verify(r); } static void secp256k1_scalar_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_scalar *a) { const uint32_t M30 = UINT32_MAX >> 2; const uint32_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3], a4 = a->d[4], a5 = a->d[5], a6 = a->d[6], a7 = a->d[7]; - -#ifdef VERIFY - VERIFY_CHECK(secp256k1_scalar_check_overflow(a) == 0); -#endif + secp256k1_scalar_verify(a); r->v[0] = a0 & M30; r->v[1] = (a0 >> 30 | a1 << 2) & M30; @@ -710,10 +766,13 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar #ifdef VERIFY int zero_in = secp256k1_scalar_is_zero(x); #endif + secp256k1_scalar_verify(x); + secp256k1_scalar_to_signed30(&s, x); secp256k1_modinv32(&s, &secp256k1_const_modinfo_scalar); secp256k1_scalar_from_signed30(r, &s); + secp256k1_scalar_verify(r); #ifdef VERIFY VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); #endif @@ -724,16 +783,21 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc #ifdef VERIFY int zero_in = secp256k1_scalar_is_zero(x); #endif + secp256k1_scalar_verify(x); + secp256k1_scalar_to_signed30(&s, x); secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_scalar); secp256k1_scalar_from_signed30(r, &s); + secp256k1_scalar_verify(r); #ifdef VERIFY VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); #endif } SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + return !(a->d[0] & 1); } diff --git a/src/scalar_impl.h b/src/scalar_impl.h index bed7f95fcb0df..3eca23b4f92fc 100644 --- a/src/scalar_impl.h +++ b/src/scalar_impl.h @@ -30,9 +30,19 @@ static const secp256k1_scalar secp256k1_scalar_zero = SECP256K1_SCALAR_CONST(0, static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin) { int overflow; secp256k1_scalar_set_b32(r, bin, &overflow); + + secp256k1_scalar_verify(r); return (!overflow) & (!secp256k1_scalar_is_zero(r)); } +static void secp256k1_scalar_verify(const secp256k1_scalar *r) { +#ifdef VERIFY + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); +#endif + + (void)r; +} + #if defined(EXHAUSTIVE_TEST_ORDER) /* Begin of section generated by sage/gen_exhaustive_groups.sage. */ # if EXHAUSTIVE_TEST_ORDER == 7 @@ -53,11 +63,16 @@ static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned c * (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n). */ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) { + secp256k1_scalar_verify(k); VERIFY_CHECK(r1 != k); VERIFY_CHECK(r2 != k); VERIFY_CHECK(r1 != r2); + *r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER; *r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; + + secp256k1_scalar_verify(r1); + secp256k1_scalar_verify(r2); } #else /** @@ -140,9 +155,11 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C4UL, 0x221208ACUL, 0x9DF506C6UL, 0x1571B4AEUL, 0x8AC47F71UL ); + secp256k1_scalar_verify(k); VERIFY_CHECK(r1 != k); VERIFY_CHECK(r2 != k); VERIFY_CHECK(r1 != r2); + /* these _var calls are constant time since the shift amount is constant */ secp256k1_scalar_mul_shift_var(&c1, k, &g1, 384); secp256k1_scalar_mul_shift_var(&c2, k, &g2, 384); @@ -153,6 +170,8 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT secp256k1_scalar_negate(r1, r1); secp256k1_scalar_add(r1, r1, k); + secp256k1_scalar_verify(r1); + secp256k1_scalar_verify(r2); #ifdef VERIFY secp256k1_scalar_split_lambda_verify(r1, r2, k); #endif diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h index 428a5deb3349a..e2356a5be18f8 100644 --- a/src/scalar_low_impl.h +++ b/src/scalar_low_impl.h @@ -14,13 +14,22 @@ #include SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + return !(*a & 1); } SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; } -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; } + +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { + *r = v % EXHAUSTIVE_TEST_ORDER; + + secp256k1_scalar_verify(r); +} SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + secp256k1_scalar_verify(a); + if (offset < 32) return ((*a >> offset) & ((((uint32_t)1) << count) - 1)); else @@ -28,24 +37,34 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_s } SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + secp256k1_scalar_verify(a); + return secp256k1_scalar_get_bits(a, offset, count); } SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); + *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; + + secp256k1_scalar_verify(r); return *r < *b; } static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + secp256k1_scalar_verify(r); + if (flag && bit < 32) *r += ((uint32_t)1 << bit); + + secp256k1_scalar_verify(r); #ifdef VERIFY VERIFY_CHECK(bit < 32); /* Verify that adding (1 << bit) will not overflow any in-range scalar *r by overflowing the underlying uint32_t. */ VERIFY_CHECK(((uint32_t)1 << bit) - 1 <= UINT32_MAX - EXHAUSTIVE_TEST_ORDER); - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); #endif } @@ -61,82 +80,129 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b } } if (overflow) *overflow = over; + + secp256k1_scalar_verify(r); } static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + secp256k1_scalar_verify(a); + memset(bin, 0, 32); bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; } SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + return *a == 0; } static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + if (*a == 0) { *r = 0; } else { *r = EXHAUSTIVE_TEST_ORDER - *a; } + + secp256k1_scalar_verify(r); } SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + return *a == 1; } static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + return *a > EXHAUSTIVE_TEST_ORDER / 2; } static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + secp256k1_scalar_verify(r); + if (flag) secp256k1_scalar_negate(r, r); + + secp256k1_scalar_verify(r); return flag ? -1 : 1; } static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); + *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; + + secp256k1_scalar_verify(r); } static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { int ret; + secp256k1_scalar_verify(r); VERIFY_CHECK(n > 0); VERIFY_CHECK(n < 16); + ret = *r & ((1 << n) - 1); *r >>= n; + + secp256k1_scalar_verify(r); return ret; } static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + secp256k1_scalar_verify(a); + *r1 = *a; *r2 = 0; + + secp256k1_scalar_verify(r1); + secp256k1_scalar_verify(r2); } SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + secp256k1_scalar_verify(a); + secp256k1_scalar_verify(b); + return *a == *b; } static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { uint32_t mask0, mask1; volatile int vflag = flag; + secp256k1_scalar_verify(a); SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r)); + mask0 = vflag + ~((uint32_t)0); mask1 = ~mask0; *r = (*r & mask0) | (*a & mask1); + + secp256k1_scalar_verify(r); } static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { int i; *r = 0; + secp256k1_scalar_verify(x); + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) *r = i; + + secp256k1_scalar_verify(r); /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus * have a composite group order; fix it in exhaustive_tests.c). */ VERIFY_CHECK(*r != 0); } static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { + secp256k1_scalar_verify(x); + secp256k1_scalar_inverse(r, x); + + secp256k1_scalar_verify(r); } #endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/tests.c b/src/tests.c index 920d31b48111c..d3959406c7f29 100644 --- a/src/tests.c +++ b/src/tests.c @@ -89,9 +89,9 @@ static void uncounting_illegal_callback_fn(const char* str, void* data) { (*p)--; } -static void random_field_element_magnitude(secp256k1_fe *fe) { +static void random_field_element_magnitude(secp256k1_fe *fe, int m) { secp256k1_fe zero; - int n = secp256k1_testrand_int(9); + int n = secp256k1_testrand_int(m + 1); secp256k1_fe_normalize(fe); if (n == 0) { return; @@ -121,6 +121,30 @@ static void random_fe_non_zero_test(secp256k1_fe *fe) { } while(secp256k1_fe_is_zero(fe)); } +static void random_fe_magnitude(secp256k1_fe *fe) { + random_field_element_magnitude(fe, 8); +} + +static void random_ge_x_magnitude(secp256k1_ge *ge) { + random_field_element_magnitude(&ge->x, SECP256K1_GE_X_MAGNITUDE_MAX); +} + +static void random_ge_y_magnitude(secp256k1_ge *ge) { + random_field_element_magnitude(&ge->y, SECP256K1_GE_Y_MAGNITUDE_MAX); +} + +static void random_gej_x_magnitude(secp256k1_gej *gej) { + random_field_element_magnitude(&gej->x, SECP256K1_GEJ_X_MAGNITUDE_MAX); +} + +static void random_gej_y_magnitude(secp256k1_gej *gej) { + random_field_element_magnitude(&gej->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX); +} + +static void random_gej_z_magnitude(secp256k1_gej *gej) { + random_field_element_magnitude(&gej->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX); +} + static void random_group_element_test(secp256k1_ge *ge) { secp256k1_fe fe; do { @@ -2967,8 +2991,7 @@ static int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { secp256k1_fe an = *a; secp256k1_fe bn = *b; secp256k1_fe_normalize_weak(&an); - secp256k1_fe_normalize_var(&bn); - return secp256k1_fe_equal_var(&an, &bn); + return secp256k1_fe_equal(&an, &bn); } static void run_field_convert(void) { @@ -2991,9 +3014,9 @@ static void run_field_convert(void) { secp256k1_fe_storage fes2; /* Check conversions to fe. */ CHECK(secp256k1_fe_set_b32_limit(&fe2, b32)); - CHECK(secp256k1_fe_equal_var(&fe, &fe2)); + CHECK(secp256k1_fe_equal(&fe, &fe2)); secp256k1_fe_from_storage(&fe2, &fes); - CHECK(secp256k1_fe_equal_var(&fe, &fe2)); + CHECK(secp256k1_fe_equal(&fe, &fe2)); /* Check conversion from fe. */ secp256k1_fe_get_b32(b322, &fe); CHECK(secp256k1_memcmp_var(b322, b32, 32) == 0); @@ -3150,7 +3173,7 @@ static void run_field_misc(void) { CHECK(check_fe_equal(&q, &z)); /* Test the fe equality and comparison operations. */ CHECK(secp256k1_fe_cmp_var(&x, &x) == 0); - CHECK(secp256k1_fe_equal_var(&x, &x)); + CHECK(secp256k1_fe_equal(&x, &x)); z = x; secp256k1_fe_add(&z,&y); /* Test fe conditional move; z is not normalized here. */ @@ -3175,7 +3198,7 @@ static void run_field_misc(void) { q = z; secp256k1_fe_normalize_var(&x); secp256k1_fe_normalize_var(&z); - CHECK(!secp256k1_fe_equal_var(&x, &z)); + CHECK(!secp256k1_fe_equal(&x, &z)); secp256k1_fe_normalize_var(&q); secp256k1_fe_cmov(&q, &z, (i&1)); #ifdef VERIFY @@ -3279,13 +3302,13 @@ static void run_fe_mul(void) { for (i = 0; i < 100 * COUNT; ++i) { secp256k1_fe a, b, c, d; random_fe(&a); - random_field_element_magnitude(&a); + random_fe_magnitude(&a); random_fe(&b); - random_field_element_magnitude(&b); + random_fe_magnitude(&b); random_fe_test(&c); - random_field_element_magnitude(&c); + random_fe_magnitude(&c); random_fe_test(&d); - random_field_element_magnitude(&d); + random_fe_magnitude(&d); test_fe_mul(&a, &a, 1); test_fe_mul(&c, &c, 1); test_fe_mul(&a, &b, 0); @@ -3680,8 +3703,8 @@ static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { if (a->infinity) { return; } - CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); + CHECK(secp256k1_fe_equal(&a->x, &b->x)); + CHECK(secp256k1_fe_equal(&a->y, &b->y)); } /* This compares jacobian points including their Z, not just their geometric meaning. */ @@ -3716,11 +3739,11 @@ static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ secp256k1_fe_sqr(&z2s, &b->z); secp256k1_fe_mul(&u1, &a->x, &z2s); - u2 = b->x; secp256k1_fe_normalize_weak(&u2); + u2 = b->x; secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); - s2 = b->y; secp256k1_fe_normalize_weak(&s2); - CHECK(secp256k1_fe_equal_var(&u1, &u2)); - CHECK(secp256k1_fe_equal_var(&s1, &s2)); + s2 = b->y; + CHECK(secp256k1_fe_equal(&u1, &u2)); + CHECK(secp256k1_fe_equal(&s1, &s2)); } static void test_ge(void) { @@ -3759,17 +3782,17 @@ static void test_ge(void) { secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); for (j = 0; j < 4; j++) { - random_field_element_magnitude(&ge[1 + j + 4 * i].x); - random_field_element_magnitude(&ge[1 + j + 4 * i].y); - random_field_element_magnitude(&gej[1 + j + 4 * i].x); - random_field_element_magnitude(&gej[1 + j + 4 * i].y); - random_field_element_magnitude(&gej[1 + j + 4 * i].z); + random_ge_x_magnitude(&ge[1 + j + 4 * i]); + random_ge_y_magnitude(&ge[1 + j + 4 * i]); + random_gej_x_magnitude(&gej[1 + j + 4 * i]); + random_gej_y_magnitude(&gej[1 + j + 4 * i]); + random_gej_z_magnitude(&gej[1 + j + 4 * i]); } } /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ random_fe_non_zero_test(&zf); - random_field_element_magnitude(&zf); + random_fe_magnitude(&zf); secp256k1_fe_inv_var(&zfi3, &zf); secp256k1_fe_sqr(&zfi2, &zfi3); secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); @@ -3788,7 +3811,7 @@ static void test_ge(void) { /* Check Z ratio. */ if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) { secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); - CHECK(secp256k1_fe_equal_var(&zrz, &refj.z)); + CHECK(secp256k1_fe_equal(&zrz, &refj.z)); } secp256k1_ge_set_gej_var(&ref, &refj); @@ -3797,7 +3820,7 @@ static void test_ge(void) { ge_equals_gej(&ref, &resj); if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) { secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); - CHECK(secp256k1_fe_equal_var(&zrz, &resj.z)); + CHECK(secp256k1_fe_equal(&zrz, &resj.z)); } /* Test gej + ge (var, with additional Z factor). */ @@ -3805,8 +3828,8 @@ static void test_ge(void) { secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); - random_field_element_magnitude(&ge2_zfi.x); - random_field_element_magnitude(&ge2_zfi.y); + random_ge_x_magnitude(&ge2_zfi); + random_ge_y_magnitude(&ge2_zfi); secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); ge_equals_gej(&ref, &resj); } @@ -3826,7 +3849,7 @@ static void test_ge(void) { ge_equals_gej(&ref, &resj); /* Check Z ratio. */ secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z); - CHECK(secp256k1_fe_equal_var(&zr2, &resj.z)); + CHECK(secp256k1_fe_equal(&zr2, &resj.z)); /* Normal doubling. */ secp256k1_gej_double_var(&resj, &gej[i2], NULL); ge_equals_gej(&ref, &resj); @@ -3909,7 +3932,7 @@ static void test_ge(void) { ret_set_xo = secp256k1_ge_set_xo_var(&q, &r, 0); CHECK(ret_on_curve == ret_frac_on_curve); CHECK(ret_on_curve == ret_set_xo); - if (ret_set_xo) CHECK(secp256k1_fe_equal_var(&r, &q.x)); + if (ret_set_xo) CHECK(secp256k1_fe_equal(&r, &q.x)); } /* Test batch gej -> ge conversion with many infinities. */ @@ -4092,7 +4115,7 @@ static void run_gej(void) { } static void test_ec_combine(void) { - secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar sum = secp256k1_scalar_zero; secp256k1_pubkey data[6]; const secp256k1_pubkey* d[6]; secp256k1_pubkey sd; @@ -4149,8 +4172,8 @@ static void test_group_decompress(const secp256k1_fe* x) { CHECK(!ge_odd.infinity); /* Check that the x coordinates check out. */ - CHECK(secp256k1_fe_equal_var(&ge_even.x, x)); - CHECK(secp256k1_fe_equal_var(&ge_odd.x, x)); + CHECK(secp256k1_fe_equal(&ge_even.x, x)); + CHECK(secp256k1_fe_equal(&ge_odd.x, x)); /* Check odd/even Y in ge_odd, ge_even. */ CHECK(secp256k1_fe_is_odd(&ge_odd.y)); @@ -4202,18 +4225,18 @@ static void test_pre_g_table(const secp256k1_ge_storage * pre_g, size_t n) { secp256k1_ge_from_storage(&q, &pre_g[i]); CHECK(secp256k1_ge_is_valid_var(&q)); - secp256k1_fe_negate(&dqx, &q.x, 1); secp256k1_fe_add(&dqx, &gg.x); secp256k1_fe_normalize_weak(&dqx); - dqy = q.y; secp256k1_fe_add(&dqy, &gg.y); secp256k1_fe_normalize_weak(&dqy); + secp256k1_fe_negate(&dqx, &q.x, 1); secp256k1_fe_add(&dqx, &gg.x); + dqy = q.y; secp256k1_fe_add(&dqy, &gg.y); /* Check that -q is not equal to gg */ CHECK(!secp256k1_fe_normalizes_to_zero_var(&dqx) || !secp256k1_fe_normalizes_to_zero_var(&dqy)); /* Check that -q is not equal to p */ - CHECK(!secp256k1_fe_equal_var(&dpx, &dqx) || !secp256k1_fe_equal_var(&dpy, &dqy)); + CHECK(!secp256k1_fe_equal(&dpx, &dqx) || !secp256k1_fe_equal(&dpy, &dqy)); /* Check that p, -q and gg are colinear */ secp256k1_fe_mul(&dpx, &dpx, &dqy); secp256k1_fe_mul(&dpy, &dpy, &dqx); - CHECK(secp256k1_fe_equal_var(&dpx, &dpy)); + CHECK(secp256k1_fe_equal(&dpx, &dpy)); p = q; } @@ -4264,8 +4287,8 @@ static void run_ecmult_chain(void) { static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); /* accumulators with the resulting coefficients to A and G */ - secp256k1_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar ae = secp256k1_scalar_one; + secp256k1_scalar ge = secp256k1_scalar_zero; /* actual points */ secp256k1_gej x; secp256k1_gej x2; @@ -4306,8 +4329,6 @@ static void test_point_times_order(const secp256k1_gej *point) { /* X * (point + G) + (order-X) * (pointer + G) = 0 */ secp256k1_scalar x; secp256k1_scalar nx; - secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); secp256k1_gej res1, res2; secp256k1_ge res3; unsigned char pub[65]; @@ -4325,13 +4346,13 @@ static void test_point_times_order(const secp256k1_gej *point) { psize = 65; CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); /* check zero/one edge cases */ - secp256k1_ecmult(&res1, point, &zero, &zero); + secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_zero); secp256k1_ge_set_gej(&res3, &res1); CHECK(secp256k1_ge_is_infinity(&res3)); - secp256k1_ecmult(&res1, point, &one, &zero); + secp256k1_ecmult(&res1, point, &secp256k1_scalar_one, &secp256k1_scalar_zero); secp256k1_ge_set_gej(&res3, &res1); ge_equals_gej(&res3, point); - secp256k1_ecmult(&res1, point, &zero, &one); + secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_one); secp256k1_ge_set_gej(&res3, &res1); ge_equals_ge(&res3, &secp256k1_ge_const_g); } @@ -4371,7 +4392,6 @@ static void test_ecmult_target(const secp256k1_scalar* target, int mode) { secp256k1_scalar n1, n2; secp256k1_ge p; secp256k1_gej pj, p1j, p2j, ptj; - static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); /* Generate random n1,n2 such that n1+n2 = -target. */ random_scalar_order_test(&n1); @@ -4390,9 +4410,9 @@ static void test_ecmult_target(const secp256k1_scalar* target, int mode) { secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &p2j, &n2); secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &ptj, target); } else if (mode == 1) { - secp256k1_ecmult(&p1j, &pj, &n1, &zero); - secp256k1_ecmult(&p2j, &pj, &n2, &zero); - secp256k1_ecmult(&ptj, &pj, target, &zero); + secp256k1_ecmult(&p1j, &pj, &n1, &secp256k1_scalar_zero); + secp256k1_ecmult(&p2j, &pj, &n2, &secp256k1_scalar_zero); + secp256k1_ecmult(&ptj, &pj, target, &secp256k1_scalar_zero); } else { secp256k1_ecmult_const(&p1j, &p, &n1); secp256k1_ecmult_const(&p2j, &p, &n2); @@ -4435,7 +4455,7 @@ static void run_point_times_order(void) { secp256k1_fe_sqr(&x, &x); } secp256k1_fe_normalize_var(&x); - CHECK(secp256k1_fe_equal_var(&x, &xr)); + CHECK(secp256k1_fe_equal(&x, &xr)); } static void ecmult_const_random_mult(void) { @@ -4487,19 +4507,17 @@ static void ecmult_const_commutativity(void) { } static void ecmult_const_mult_zero_one(void) { - secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); secp256k1_scalar negone; secp256k1_gej res1; secp256k1_ge res2; secp256k1_ge point; - secp256k1_scalar_negate(&negone, &one); + secp256k1_scalar_negate(&negone, &secp256k1_scalar_one); random_group_element_test(&point); - secp256k1_ecmult_const(&res1, &point, &zero); + secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_zero); secp256k1_ge_set_gej(&res2, &res1); CHECK(secp256k1_ge_is_infinity(&res2)); - secp256k1_ecmult_const(&res1, &point, &one); + secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_one); secp256k1_ge_set_gej(&res2, &res1); ge_equals_ge(&res2, &point); secp256k1_ecmult_const(&res1, &point, &negone); @@ -4854,7 +4872,7 @@ static int test_ecmult_multi_random(secp256k1_scratch *scratch) { * scalars[0..filled-1] and gejs[0..filled-1] are the scalars and points * which form its normal inputs. */ int filled = 0; - secp256k1_scalar g_scalar = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar g_scalar = secp256k1_scalar_zero; secp256k1_scalar scalars[128]; secp256k1_gej gejs[128]; /* The expected result, and the computed result. */ @@ -5465,16 +5483,15 @@ static void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar /* 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; secp256k1_ge r; - const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); unsigned char bytes[65]; size_t size = 65; 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, &zero); - secp256k1_ecmult(&rj3, &infj, &zero, x); + secp256k1_ecmult(&rj2, &gj, x, &secp256k1_scalar_zero); + secp256k1_ecmult(&rj3, &infj, &secp256k1_scalar_zero, x); secp256k1_ecmult_multi_var(NULL, scratch, &rj4, x, NULL, NULL, 0); - secp256k1_ecmult_multi_var(NULL, scratch, &rj5, &zero, test_ecmult_accumulate_cb, (void*)x, 1); + secp256k1_ecmult_multi_var(NULL, 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); ge_equals_gej(&r, &rj2); @@ -7599,33 +7616,31 @@ static void fe_storage_cmov_test(void) { } static void scalar_cmov_test(void) { - static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); - static const secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); static const secp256k1_scalar max = SECP256K1_SCALAR_CONST( - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, - 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364140UL ); secp256k1_scalar r = max; - secp256k1_scalar a = zero; + secp256k1_scalar a = secp256k1_scalar_zero; secp256k1_scalar_cmov(&r, &a, 0); CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); - r = zero; a = max; + r = secp256k1_scalar_zero; a = max; secp256k1_scalar_cmov(&r, &a, 1); CHECK(secp256k1_memcmp_var(&r, &max, sizeof(r)) == 0); - a = zero; + a = secp256k1_scalar_zero; secp256k1_scalar_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &zero, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_zero, sizeof(r)) == 0); - a = one; + a = secp256k1_scalar_one; secp256k1_scalar_cmov(&r, &a, 1); - CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_one, sizeof(r)) == 0); - r = one; a = zero; + r = secp256k1_scalar_one; a = secp256k1_scalar_zero; secp256k1_scalar_cmov(&r, &a, 0); - CHECK(secp256k1_memcmp_var(&r, &one, sizeof(r)) == 0); + CHECK(secp256k1_memcmp_var(&r, &secp256k1_scalar_one, sizeof(r)) == 0); } static void ge_storage_cmov_test(void) { diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index dbb6b7eb46df8..3af8ec1ee5257 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -38,8 +38,8 @@ static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { if (a->infinity) { return; } - CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); + CHECK(secp256k1_fe_equal(&a->x, &b->x)); + CHECK(secp256k1_fe_equal(&a->y, &b->y)); } static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { @@ -52,11 +52,11 @@ static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ secp256k1_fe_sqr(&z2s, &b->z); secp256k1_fe_mul(&u1, &a->x, &z2s); - u2 = b->x; secp256k1_fe_normalize_weak(&u2); + u2 = b->x; secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); - s2 = b->y; secp256k1_fe_normalize_weak(&s2); - CHECK(secp256k1_fe_equal_var(&u1, &u2)); - CHECK(secp256k1_fe_equal_var(&s1, &s2)); + s2 = b->y; + CHECK(secp256k1_fe_equal(&u1, &u2)); + CHECK(secp256k1_fe_equal(&s1, &s2)); } static void random_fe(secp256k1_fe *x) { @@ -219,14 +219,14 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */ ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0); CHECK(ret); - CHECK(secp256k1_fe_equal_var(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); + CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); /* Test secp256k1_ecmult_const_xonly with all curve X coordinates, with random xd. */ random_fe_non_zero(&xd); secp256k1_fe_mul(&xn, &xd, &group[i].x); ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 0); CHECK(ret); - CHECK(secp256k1_fe_equal_var(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); + CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x)); } } } @@ -475,8 +475,8 @@ int main(int argc, char** argv) { CHECK(group[i].infinity == 0); CHECK(generated.infinity == 0); - CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x)); - CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y)); + CHECK(secp256k1_fe_equal(&generated.x, &group[i].x)); + CHECK(secp256k1_fe_equal(&generated.y, &group[i].y)); } } diff --git a/src/util.h b/src/util.h index 801ea0c885ed9..cf7e5d1af55ca 100644 --- a/src/util.h +++ b/src/util.h @@ -152,14 +152,6 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_ return ret; } -static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void *ptr, size_t size) { - void *ret = realloc(ptr, size); - if (ret == NULL) { - secp256k1_callback_call(cb, "Out of memory"); - } - return ret; -} - #if defined(__BIGGEST_ALIGNMENT__) #define ALIGNMENT __BIGGEST_ALIGNMENT__ #else