diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 6e3e67676..000000000 --- a/.cirrus.yml +++ /dev/null @@ -1,234 +0,0 @@ -env: - ### cirrus config - CIRRUS_CLONE_DEPTH: 1 - PACKAGE_MANAGER_INSTALL: "apt-get update && apt-get install -y" - MAKEJOBS: "-j10" - TEST_RUNNER_PORT_MIN: "14000" # Must be larger than 12321, which is used for the http cache. See https://cirrus-ci.org/guide/writing-tasks/#http-cache - CI_FAILFAST_TEST_LEAVE_DANGLING: "1" # Cirrus CI does not care about dangling processes and setting this variable avoids killing the CI script itself on error - CCACHE_MAXSIZE: "200M" - CCACHE_DIR: "/tmp/ccache_dir" - CCACHE_NOHASHDIR: "1" # Debug info might contain a stale path if the build dir changes, but this is fine - -# https://cirrus-ci.org/guide/persistent-workers/ -# -# It is possible to select a specific persistent worker by label. Refer to the -# Cirrus CI docs for more details. -# -# Generally, a persistent worker must run Ubuntu 23.04+ or Debian 12+. -# Specifically, -# - apt-get is required due to PACKAGE_MANAGER_INSTALL -# - podman-docker-4.1+ is required due to the use of `podman` when -# RESTART_CI_DOCKER_BEFORE_RUN is set and 4.1+ due to the bugfix in 4.1 -# (https://github.com/bitcoin/bitcoin/pull/21652#issuecomment-1657098200) -# - The ./ci/ depedencies (with cirrus-cli) should be installed: -# -# ``` -# apt update && apt install screen python3 bash podman-docker curl -y && curl -L -o cirrus "https://github.com/cirruslabs/cirrus-cli/releases/latest/download/cirrus-linux-$(dpkg --print-architecture)" && mv cirrus /usr/local/bin/cirrus && chmod +x /usr/local/bin/cirrus -# ``` -# -# - There are no strict requirements on the hardware, because having less CPUs -# runs the same CI script (maybe slower). To avoid rare and intermittent OOM -# due to short memory usage spikes, it is recommended to add (and persist) -# swap: -# -# ``` -# fallocate -l 16G /swapfile_ci && chmod 600 /swapfile_ci && mkswap /swapfile_ci && swapon /swapfile_ci && ( echo '/swapfile_ci none swap sw 0 0' | tee -a /etc/fstab ) -# ``` -# -# - To register the persistent worker, open a `screen` session and run: -# -# ``` -# RESTART_CI_DOCKER_BEFORE_RUN=1 screen cirrus worker run --labels type=todo_fill_in_type --token todo_fill_in_token -# ``` -# -# The following specific types should exist, with the following requirements: -# - small: For an x86_64 machine, recommended to have 2 CPUs and 8 GB of memory. -# - medium: For an x86_64 machine, recommended to have 4 CPUs and 16 GB of memory. -# - lunar: For a machine running the Linux kernel shipped with Ubuntu Lunar 23.04. The machine is recommended to have 4 CPUs and 16 GB of memory. -# - arm64: For an aarch64 machine, recommended to have 2 CPUs and 8 GB of memory. - -# https://cirrus-ci.org/guide/tips-and-tricks/#sharing-configuration-between-tasks -filter_template: &FILTER_TEMPLATE - skip: $CIRRUS_REPO_FULL_NAME == "BGL-core/gui" && $CIRRUS_PR == "" # No need to run on the read-only mirror, unless it is a PR. https://cirrus-ci.org/guide/writing-tasks/#conditional-task-execution - stateful: false # https://cirrus-ci.org/guide/writing-tasks/#stateful-tasks - -base_template: &BASE_TEMPLATE - << : *FILTER_TEMPLATE - merge_base_script: - # Unconditionally install git (used in fingerprint_script). - - bash -c "$PACKAGE_MANAGER_INSTALL git" - - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi - - git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge" - - git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts - # Also, the merge commit is used to lint COMMIT_RANGE="HEAD~..HEAD" - -main_template: &MAIN_TEMPLATE - timeout_in: 120m # https://cirrus-ci.org/faq/#instance-timed-out - ci_script: - - ./ci/test_run_all.sh - -global_task_template: &GLOBAL_TASK_TEMPLATE - << : *BASE_TEMPLATE - << : *MAIN_TEMPLATE - -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: 'lint' - << : *BASE_TEMPLATE - container: - image: debian:bookworm - cpu: 1 - memory: 1G - # For faster CI feedback, immediately schedule the linters - << : *CREDITS_TEMPLATE - python_cache: - folder: "/python_build" - fingerprint_script: cat .python-version /etc/os-release - unshallow_script: - - git fetch --unshallow --no-tags - lint_script: - - ./ci/lint_run_all.sh - -task: - name: 'tidy' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: medium - env: - FILE_ENV: "./ci/test/00_setup_env_native_tidy.sh" - -task: - name: 'ARM, unit tests, no functional tests' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: arm64 # Use arm64 worker to sidestep qemu and avoid a slow CI: https://github.com/bitcoin/bitcoin/pull/28087#issuecomment-1649399453 - env: - FILE_ENV: "./ci/test/00_setup_env_arm.sh" - -task: - name: 'Win64, unit tests, no gui tests, no boost::process, no functional tests' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: small - env: - FILE_ENV: "./ci/test/00_setup_env_win64.sh" - -task: - name: '32-bit CentOS, dash, gui' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: small - env: - FILE_ENV: "./ci/test/00_setup_env_i686_centos.sh" - -task: - name: 'previous releases, qt5 dev package and depends packages, DEBUG' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: small - env: - FILE_ENV: "./ci/test/00_setup_env_native_qt5.sh" - -task: - name: 'TSan, depends, gui' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: medium - env: - FILE_ENV: "./ci/test/00_setup_env_native_tsan.sh" - -task: - name: 'MSan, depends' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: small - timeout_in: 300m # Use longer timeout for the *rare* case where a full build (llvm + msan + depends + ...) needs to be done. - env: - FILE_ENV: "./ci/test/00_setup_env_native_msan.sh" - -task: - name: 'ASan + LSan + UBSan + integer, no depends, USDT' - enable_bpfcc_script: - # In the image build step, no external environment variables are available, - # so any settings will need to be written to the settings env file: - - sed -i "s|\${CIRRUS_CI}|true|g" ./ci/test/00_setup_env_native_asan.sh - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: lunar # Must use the lunar-specific worker (needed for USDT functional tests) - env: - FILE_ENV: "./ci/test/00_setup_env_native_asan.sh" - -task: - name: 'fuzzer,address,undefined,integer, no depends' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: medium - env: - FILE_ENV: "./ci/test/00_setup_env_native_fuzz.sh" - -task: - name: 'multiprocess, i686, DEBUG' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: medium - env: - FILE_ENV: "./ci/test/00_setup_env_i686_multiprocess.sh" - -task: - name: 'no wallet, libBGLkernel' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: small - env: - FILE_ENV: "./ci/test/00_setup_env_native_nowallet_libBGLkernel.sh" - -task: - name: 'macOS-cross 11.0, gui, no tests' - << : *GLOBAL_TASK_TEMPLATE - persistent_worker: - labels: - type: small - env: - FILE_ENV: "./ci/test/00_setup_env_mac.sh" diff --git a/.github/actions/install-homebrew-valgrind/action.yml b/.github/actions/install-homebrew-valgrind/action.yml new file mode 100644 index 000000000..094ff891f --- /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 000000000..d357c3cf7 --- /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 index 7aaf40e4c..b9a9eaa82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,6 @@ -# Copyright (c) 2023 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - name: CI on: - # See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request. pull_request: - # See: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#push. push: branches: - '**' @@ -18,269 +12,795 @@ concurrency: cancel-in-progress: true env: - DANGER_RUN_CI_ON_HOST: 1 - CI_FAILFAST_TEST_LEAVE_DANGLING: 1 # GHA does not care about dangling processes and setting this variable avoids killing the CI script itself on error - MAKEJOBS: '-j10' + ### 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: - test-each-commit: - name: 'test each commit' - runs-on: ubuntu-22.04 - if: github.event_name == 'pull_request' - timeout-minutes: 360 # Use maximum time, see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idtimeout-minutes. Assuming a worst case time of 1 hour per commit, this leads to a --max-count=6 below. - env: - MAX_COUNT: '--max-count=6' + docker_cache: + name: "Build Docker image" + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 with: - ref: ${{ github.event.pull_request.head.sha }} - fetch-depth: '8' # Two more than $MAX_COUNT - - run: git checkout HEAD~ # Skip the top commit, because it is already checked by the other tasks. - - run: sudo apt install clang ccache build-essential libtool autotools-dev automake pkg-config bsdmainutils python3-zmq libevent-dev libboost-dev libsqlite3-dev libdb++-dev systemtap-sdt-dev libminiupnpc-dev libnatpmp-dev libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools qtwayland5 libqrencode-dev -y - # Use clang++, because it is a bit faster and uses less memory than g++ - - run: git rebase --exec "echo Running test-one-commit on \$( git log -1 ) && ./autogen.sh && CC=clang CXX=clang++ ./configure && make clean && make -j $(nproc) check && ./test/functional/test_runner.py -j $(( $(nproc) * 2 ))" "$( git log '^'$( git log --merges -1 --format='%H' ) HEAD --format='%H' ${MAX_COUNT} | tail -1 )~1" - - macos-native-x86_64: - name: 'macOS 13 native, x86_64, no depends, sqlite only, gui' - # Use latest image, but hardcode version to avoid silent upgrades (and breaks). - # See: https://github.com/actions/runner-images#available-images. - runs-on: macos-13 # Use M1 once available https://github.com/github/roadmap/issues/528 + # See: https://github.com/moby/buildkit/issues/3969. + driver-opts: | + network=host - # No need to run on the read-only mirror, unless it is a PR. - if: github.repository != 'bitcoin-core/gui' || github.event_name == 'pull_request' - - timeout-minutes: 120 + - 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: - FILE_ENV: './ci/test/00_setup_env_mac_native.sh' - BASE_ROOT_DIR: ${{ github.workspace }} + CC: ${{ matrix.cc }} steps: - name: Checkout uses: actions/checkout@v4 - - name: Clang version - run: clang --version + - 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' - - name: Install Homebrew packages - run: brew install boost libevent qt@5 miniupnpc libnatpmp ccache zeromq qrencode libtool automake gnu-getopt + env: + HOST: 'i686-linux-gnu' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + CC: ${{ matrix.cc }} - - name: Set Ccache directory - run: echo "CCACHE_DIR=${RUNNER_TEMP}/ccache_dir" >> "$GITHUB_ENV" + steps: + - name: Checkout + uses: actions/checkout@v4 - - name: Restore Ccache cache - id: ccache-cache - uses: actions/cache/restore@v3 + - name: CI script + uses: ./.github/actions/run-in-docker-action with: - path: ${{ env.CCACHE_DIR }} - key: ${{ github.job }}-ccache-${{ github.run_id }} - restore-keys: ${{ github.job }}-ccache- + 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 - run: ./ci/test_run_all.sh + 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: Save Ccache cache - uses: actions/cache/save@v3 - if: github.event_name != 'pull_request' && steps.ccache-cache.outputs.cache-hit != 'true' + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action with: - path: ${{ env.CCACHE_DIR }} - # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache - key: ${{ github.job }}-ccache-${{ github.run_id }} + 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 - win64-native: - name: 'Win64 native, VS 2022' - # Use latest image, but hardcode version to avoid silent upgrades (and breaks). - # See: https://github.com/actions/runner-images#available-images. - runs-on: windows-2022 + 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 - # No need to run on the read-only mirror, unless it is a PR. - if: github.repository != 'bitcoin-core/gui' || github.event_name == 'pull_request' + - 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: - CCACHE_MAXSIZE: '200M' - CI_CCACHE_VERSION: '4.7.5' - CI_QT_CONF: '-release -silent -opensource -confirm-license -opengl desktop -static -static-runtime -mp -qt-zlib -qt-pcre -qt-libpng -nomake examples -nomake tests -nomake tools -no-angle -no-dbus -no-gif -no-gtk -no-ico -no-icu -no-libjpeg -no-libudev -no-sql-sqlite -no-sql-odbc -no-sqlite -no-vulkan -skip qt3d -skip qtactiveqt -skip qtandroidextras -skip qtcharts -skip qtconnectivity -skip qtdatavis3d -skip qtdeclarative -skip doc -skip qtdoc -skip qtgamepad -skip qtgraphicaleffects -skip qtimageformats -skip qtlocation -skip qtlottie -skip qtmacextras -skip qtmultimedia -skip qtnetworkauth -skip qtpurchasing -skip qtquick3d -skip qtquickcontrols -skip qtquickcontrols2 -skip qtquicktimeline -skip qtremoteobjects -skip qtscript -skip qtscxml -skip qtsensors -skip qtserialbus -skip qtserialport -skip qtspeech -skip qtsvg -skip qtvirtualkeyboard -skip qtwayland -skip qtwebchannel -skip qtwebengine -skip qtwebglplugin -skip qtwebsockets -skip qtwebview -skip qtx11extras -skip qtxmlpatterns -no-openssl -no-feature-bearermanagement -no-feature-printdialog -no-feature-printer -no-feature-printpreviewdialog -no-feature-printpreviewwidget -no-feature-sql -no-feature-sqlmodel -no-feature-textbrowser -no-feature-textmarkdownwriter -no-feature-textodfwriter -no-feature-xml' - CI_QT_DIR: 'qt-everywhere-src-5.15.5' - CI_QT_URL: 'https://download.qt.io/official_releases/qt/5.15/5.15.5/single/qt-everywhere-opensource-src-5.15.5.zip' - PYTHONUTF8: 1 - TEST_RUNNER_TIMEOUT_FACTOR: 40 + 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: Fix Visual Studio installation - # See: https://github.com/actions/runner-images/issues/7832#issuecomment-1617585694. - run: | - Set-Location "C:\Program Files (x86)\Microsoft Visual Studio\Installer\" - $InstallPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" - $componentsToRemove= @( - "Microsoft.VisualStudio.Component.VC.14.35.17.5.ARM" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.ARM.Spectre" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.ARM64" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.ARM64.Spectre" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.x86.x64" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.x86.x64.Spectre" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.ATL" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.ATL.Spectre" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.ATL.ARM" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.ATL.ARM.Spectre" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.ATL.ARM64" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.ATL.ARM64.Spectre" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.MFC" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.MFC.Spectre" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.MFC.ARM" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.MFC.ARM.Spectre" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.MFC.ARM64" - "Microsoft.VisualStudio.Component.VC.14.35.17.5.MFC.ARM64.Spectre" - ) - [string]$workloadArgs = $componentsToRemove | ForEach-Object {" --remove " + $_} - $Arguments = ('/c', "vs_installer.exe", 'modify', '--installPath', "`"$InstallPath`"",$workloadArgs, '--quiet', '--norestart', '--nocache') - # should be run twice - $process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden - $process = Start-Process -FilePath cmd.exe -ArgumentList $Arguments -Wait -PassThru -WindowStyle Hidden - - - name: Configure Developer Command Prompt for Microsoft Visual C++ - # Using microsoft/setup-msbuild is not enough. - uses: ilammy/msvc-dev-cmd@v1 + - name: CI script + uses: ./.github/actions/run-in-docker-action with: - arch: x64 + 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 } - - name: Check MSBuild and Qt - run: | - msbuild -version | Out-File -FilePath "$env:GITHUB_WORKSPACE\msbuild_version" - Get-Content -Path "$env:GITHUB_WORKSPACE\msbuild_version" - $env:CI_QT_URL | Out-File -FilePath "$env:GITHUB_WORKSPACE\qt_url" - $env:CI_QT_CONF | Out-File -FilePath "$env:GITHUB_WORKSPACE\qt_conf" - - - name: Restore static Qt cache - id: static-qt-cache - uses: actions/cache/restore@v3 + 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: - path: C:\Qt_static - key: ${{ github.job }}-static-qt-${{ hashFiles('msbuild_version', 'qt_url', 'qt_conf') }} + 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 } - - name: Build static Qt. Download - if: steps.static-qt-cache.outputs.cache-hit != 'true' - shell: cmd - run: | - curl --location --output C:\qt-src.zip %CI_QT_URL% - choco install --yes --no-progress jom + 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 - - name: Build static Qt. Expand source archive - if: steps.static-qt-cache.outputs.cache-hit != 'true' - shell: cmd - run: tar -xf C:\qt-src.zip -C C:\ + steps: + - name: Checkout + uses: actions/checkout@v4 - - name: Build static Qt. Create build directory - if: steps.static-qt-cache.outputs.cache-hit != 'true' - run: | - Rename-Item -Path "C:\$env:CI_QT_DIR" -NewName "C:\qt-src" - New-Item -ItemType Directory -Path "C:\qt-src\build" - - - name: Build static Qt. Configure - if: steps.static-qt-cache.outputs.cache-hit != 'true' - working-directory: C:\qt-src\build - shell: cmd - run: ..\configure %CI_QT_CONF% -prefix C:\Qt_static - - - name: Build static Qt. Build - if: steps.static-qt-cache.outputs.cache-hit != 'true' - working-directory: C:\qt-src\build - shell: cmd - run: jom - - - name: Build static Qt. Install - if: steps.static-qt-cache.outputs.cache-hit != 'true' - working-directory: C:\qt-src\build - shell: cmd - run: jom install - - - name: Save static Qt cache - if: steps.static-qt-cache.outputs.cache-hit != 'true' - uses: actions/cache/save@v3 + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action with: - path: C:\Qt_static - key: ${{ github.job }}-static-qt-${{ hashFiles('msbuild_version', 'qt_url', 'qt_conf') }} + 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: Ccache installation cache - id: ccache-installation-cache - uses: actions/cache@v3 + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action with: - path: | - C:\ProgramData\chocolatey\lib\ccache - C:\ProgramData\chocolatey\bin\ccache.exe - C:\ccache\cl.exe - key: ${{ github.job }}-ccache-installation-${{ env.CI_CCACHE_VERSION }} - - - name: Install Ccache - if: steps.ccache-installation-cache.outputs.cache-hit != 'true' - run: | - choco install --yes --no-progress ccache --version=$env:CI_CCACHE_VERSION - New-Item -ItemType Directory -Path "C:\ccache" - Copy-Item -Path "$env:ChocolateyInstall\lib\ccache\tools\ccache-$env:CI_CCACHE_VERSION-windows-x86_64\ccache.exe" -Destination "C:\ccache\cl.exe" + 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: Restore Ccache cache - id: ccache-cache - uses: actions/cache/restore@v3 + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action with: - path: ~/AppData/Local/ccache - key: ${{ github.job }}-ccache-${{ github.run_id }} - restore-keys: ${{ github.job }}-ccache- + 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 - - name: Using vcpkg with MSBuild + 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: | - Set-Location "$env:VCPKG_INSTALLATION_ROOT" - Add-Content -Path "triplets\x64-windows-static.cmake" -Value "set(VCPKG_BUILD_TYPE release)" - vcpkg --vcpkg-root "$env:VCPKG_INSTALLATION_ROOT" integrate install - git rev-parse HEAD | Out-File -FilePath "$env:GITHUB_WORKSPACE\vcpkg_commit" - Get-Content -Path "$env:GITHUB_WORKSPACE\vcpkg_commit" - - - name: vcpkg tools cache - uses: actions/cache@v3 - with: - path: C:/vcpkg/downloads/tools - key: ${{ github.job }}-vcpkg-tools + brew install automake libtool gcc + ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc - - name: vcpkg binary cache - uses: actions/cache@v3 - with: - path: ~/AppData/Local/vcpkg/archives - key: ${{ github.job }}-vcpkg-binary-${{ hashFiles('vcpkg_commit', 'msbuild_version', 'build_msvc/vcpkg.json') }} + - name: Install and cache Valgrind + uses: ./.github/actions/install-homebrew-valgrind - - name: Generate project files - run: py -3 build_msvc\msvc-autogen.py + - 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 - shell: cmd + 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: | - ccache --zero-stats - msbuild build_msvc\bitcoin.sln -property:CLToolPath=C:\ccache;CLToolExe=cl.exe;UseMultiToolTask=true;Configuration=Release -maxCpuCount -verbosity:minimal -noLogo + cl.exe -c -WX -TP include/*.h + + cxx_fpermissive_debian: + name: "C++ -fpermissive (entire project)" + runs-on: ubuntu-latest + needs: docker_cache - - name: Ccache stats - run: ccache --show-stats + env: + CC: 'g++' + CFLAGS: '-fpermissive -g' + CPPFLAGS: '-DSECP256K1_CPLUSPLUS_TEST_OVERRIDE' + WERROR_CFLAGS: + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' - - name: Save Ccache cache - uses: actions/cache/save@v3 - if: github.event_name != 'pull_request' && steps.ccache-cache.outputs.cache-hit != 'true' + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action with: - path: ~/AppData/Local/ccache - # https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache - key: ${{ github.job }}-ccache-${{ github.run_id }} + 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 - - name: Run unit tests - run: src\test_bitcoin.exe -l test_suite + steps: + - name: Checkout + uses: actions/checkout@v4 - - name: Run benchmarks - run: src\bench_bitcoin.exe -sanity-check + - 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 - - name: Run util tests - run: py -3 test\util\test_runner.py + release: + runs-on: ubuntu-latest - - name: Run rpcauth test - run: py -3 test\util\rpcauth-test.py + steps: + - name: Checkout + uses: actions/checkout@v4 + + - run: ./autogen.sh && ./configure --enable-dev-mode && make distcheck - - name: Run functional tests + - name: Check installation with Autotools env: - TEST_RUNNER_EXTRA: ${{ github.event_name != 'pull_request' && '--extended' || '' }} - run: py -3 test\functional\test_runner.py --jobs $env:NUMBER_OF_PROCESSORS --ci --quiet --tmpdirprefix=$env:RUNNER_TEMP --combinedlogslen=99999999 --timeout-factor=$env:TEST_RUNNER_TIMEOUT_FACTOR $env:TEST_RUNNER_EXTRA + 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/ci/ci.sh b/ci/ci.sh new file mode 100755 index 000000000..719e7851e --- /dev/null +++ b/ci/ci.sh @@ -0,0 +1,132 @@ +#!/bin/sh + +set -eux + +export LC_ALL=C + +# Print commit and relevant CI environment to allow reproducing the job outside of CI. +git show --no-patch +print_environment() { + # Turn off -x because it messes up the output + set +x + # There are many ways to print variable names and their content. This one + # does not rely on bash. + for var in WERROR_CFLAGS MAKEFLAGS BUILD \ + ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ + EXPERIMENTAL ECDH RECOVERY SCHNORRSIG ELLSWIFT \ + SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ + EXAMPLES \ + HOST WRAPPER_CMD \ + CC CFLAGS CPPFLAGS AR NM + do + eval "isset=\${$var+x}" + if [ -n "$isset" ]; then + eval "val=\${$var}" + # shellcheck disable=SC2154 + printf '%s="%s" ' "$var" "$val" + fi + done + echo "$0" + set -x +} +print_environment + +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 + +if [ -n "${CC+x}" ]; then + # The MSVC compiler "cl" doesn't understand "-v" + $CC -v || true +fi +if [ "$WITH_VALGRIND" = "yes" ]; then + valgrind --version +fi +if [ -n "$WRAPPER_CMD" ]; then + $WRAPPER_CMD --version +fi + +# Workaround for https://bugs.kde.org/show_bug.cgi?id=452758 (fixed in valgrind 3.20.0). +case "${CC:-undefined}" in + clang*) + if [ "$CTIMETESTS" = "yes" ] && [ "$WITH_VALGRIND" = "yes" ] + then + export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4" + else + case "$WRAPPER_CMD" in + valgrind*) + export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4" + ;; + esac + fi + ;; +esac + +./autogen.sh + +./configure \ + --enable-experimental="$EXPERIMENTAL" \ + --with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \ + --with-ecmult-window="$ECMULTWINDOW" \ + --with-ecmult-gen-precision="$ECMULTGENPRECISION" \ + --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ + --enable-module-ellswift="$ELLSWIFT" \ + --enable-module-schnorrsig="$SCHNORRSIG" \ + --enable-examples="$EXAMPLES" \ + --enable-ctime-tests="$CTIMETESTS" \ + --with-valgrind="$WITH_VALGRIND" \ + --host="$HOST" $EXTRAFLAGS + +# We have set "-j" in MAKEFLAGS. +make + +# Print information about binaries so that we can see that the architecture is correct +file *tests* || true +file bench* || true +file .libs/* || true + +# This tells `make check` to wrap test invocations. +export LOG_COMPILER="$WRAPPER_CMD" + +make "$BUILD" + +# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool +EXEC='./libtool --mode=execute' +if [ -n "$WRAPPER_CMD" ] +then + EXEC="$EXEC $WRAPPER_CMD" +fi + +if [ "$BENCH" = "yes" ] +then + { + $EXEC ./bench_ecmult + $EXEC ./bench_internal + $EXEC ./bench + } >> bench.log 2>&1 +fi + +if [ "$CTIMETESTS" = "yes" ] +then + if [ "$WITH_VALGRIND" = "yes" ]; then + ./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1 + else + $EXEC ./ctime_tests > ctime_tests.log 2>&1 + fi +fi + +# Rebuild precomputed files (if not cross-compiling). +if [ -z "$HOST" ] +then + make clean-precomp clean-testvectors + make precomp testvectors +fi + +# Check that no repo files have been modified by the build. +# (This fails for example if the precomp files need to be updated in the repo.) +git diff --exit-code diff --git a/ci/linux-debian.Dockerfile b/ci/linux-debian.Dockerfile index c7d57a617..e719907e8 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++ \ @@ -20,14 +31,15 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \ gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \ gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \ - wine gcc-mingw-w64-x86-64 \ - sagemath - -WORKDIR /root + gcc-mingw-w64-x86-64-win32 wine64 wine \ + gcc-mingw-w64-i686-win32 wine32 \ + 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 @@ -35,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 801835623..fe2532f1d 100755 --- a/configure.ac +++ b/configure.ac @@ -1,15 +1,32 @@ -AC_PREREQ([2.69]) -define(_CLIENT_VERSION_MAJOR, 0) -define(_CLIENT_VERSION_MINOR, 1) -define(_CLIENT_VERSION_BUILD, 11) -define(_CLIENT_VERSION_RC, 0) -define(_CLIENT_VERSION_IS_RELEASE, true) +<<<<<<< HEAD +AC_PREREQ([2.60]) + +# 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. +define(_PKG_VERSION_MAJOR, 0) +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, 3) +define(_LIB_VERSION_REVISION, 0) +define(_LIB_VERSION_AGE, 1) define(_COPYRIGHT_YEAR, 2024) define(_COPYRIGHT_HOLDERS,[The %s developers]) define(_COPYRIGHT_HOLDERS_SUBSTITUTION,[[Bitgesell Core]]) AC_INIT([Bitgesell Core],m4_join([.], _CLIENT_VERSION_MAJOR, _CLIENT_VERSION_MINOR, _CLIENT_VERSION_BUILD)m4_if(_CLIENT_VERSION_RC, [0], [], [rc]_CLIENT_VERSION_RC),[https://github.com/BitgesellOfficial/bitgesell/issues],[BGL],[https://bitgesell.ca/]) +AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1]) AC_CONFIG_SRCDIR([src/validation.cpp]) AC_CONFIG_HEADERS([src/config/BGL-config.h]) + + + AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([build-aux/m4]) @@ -1721,25 +1738,8 @@ else AC_MSG_RESULT([no]) fi -dnl enable upnp support -AC_MSG_CHECKING([whether to build with support for UPnP]) -if test "$have_miniupnpc" = "no"; then - if test "$use_upnp" = "yes"; then - AC_MSG_ERROR([UPnP requested but cannot be built. Use --without-miniupnpc]) - fi - AC_MSG_RESULT([no]) - use_upnp=no -else - if test "$use_upnp" != "no"; then - AC_MSG_RESULT([yes]) - use_upnp=yes - AC_DEFINE([USE_UPNP], [1], [Define to 1 if UPnP support should be compiled in.]) - if test "$TARGET_OS" = "windows"; then - MINIUPNPC_CPPFLAGS="$MINIUPNPC_CPPFLAGS -DMINIUPNP_STATICLIB" - fi - else - AC_MSG_RESULT([no]) - fi +if test x"$enable_module_ellswift" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1" fi dnl Enable NAT-PMP support. diff --git a/src/checkmem.h b/src/checkmem.h index 571e4cc38..f2169decf 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 5f5b86adf..06a593b01 100644 --- a/src/ctime_tests.c +++ b/src/ctime_tests.c @@ -204,27 +204,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/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt index 71b99b312..685132bfa 100644 --- a/src/secp256k1/CMakeLists.txt +++ b/src/secp256k1/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.4.2 + 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 @@ -35,7 +35,7 @@ endif() # 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 3) -set(${PROJECT_NAME}_LIB_VERSION_REVISION 2) +set(${PROJECT_NAME}_LIB_VERSION_REVISION 0) set(${PROJECT_NAME}_LIB_VERSION_AGE 1) set(CMAKE_C_STANDARD 90) diff --git a/src/secp256k1/ci/cirrus.sh b/src/secp256k1/ci/cirrus.sh index 48a9783cc..719e7851e 100755 --- a/src/secp256k1/ci/cirrus.sh +++ b/src/secp256k1/ci/cirrus.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/src/secp256k1/src/bench_ecmult.c b/src/secp256k1/src/bench_ecmult.c index b7b8413f0..ea7cf8d6d 100644 --- a/src/secp256k1/src/bench_ecmult.c +++ b/src/secp256k1/src/bench_ecmult.c @@ -246,7 +246,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; @@ -264,7 +263,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/secp256k1/src/field.h b/src/secp256k1/src/field.h index bb99f948e..ccd228e1a 100644 --- a/src/secp256k1/src/field.h +++ b/src/secp256k1/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/secp256k1/src/field_impl.h b/src/secp256k1/src/field_impl.h index 7f18ebdc9..80d34b9ef 100644 --- a/src/secp256k1/src/field_impl.h +++ b/src/secp256k1/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/secp256k1/src/group.h b/src/secp256k1/src/group.h index 95aa58c92..2202a391f 100644 --- a/src/secp256k1/src/group.h +++ b/src/secp256k1/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/secp256k1/src/group_impl.h b/src/secp256k1/src/group_impl.h index ffdfeaa10..b9542ce8a 100644 --- a/src/secp256k1/src/group_impl.h +++ b/src/secp256k1/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/secp256k1/src/hash_impl.h b/src/secp256k1/src/hash_impl.h index 0991fe783..89f75ace7 100644 --- a/src/secp256k1/src/hash_impl.h +++ b/src/secp256k1/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/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h b/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h index 3adc5df6e..acc3dfc10 100644 --- a/src/secp256k1/src/modules/extrakeys/tests_exhaustive_impl.h +++ b/src/secp256k1/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/secp256k1/src/modules/schnorrsig/main_impl.h b/src/secp256k1/src/modules/schnorrsig/main_impl.h index 4e7b45a04..26727e465 100644 --- a/src/secp256k1/src/modules/schnorrsig/main_impl.h +++ b/src/secp256k1/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/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h index d8df9dd2d..0df1061ab 100644 --- a/src/secp256k1/src/modules/schnorrsig/tests_exhaustive_impl.h +++ b/src/secp256k1/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/secp256k1/src/scalar.h b/src/secp256k1/src/scalar.h index 63c0d646a..4b3c2998b 100644 --- a/src/secp256k1/src/scalar.h +++ b/src/secp256k1/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/secp256k1/src/scalar_4x64_impl.h b/src/secp256k1/src/scalar_4x64_impl.h index 365797f60..727004369 100644 --- a/src/secp256k1/src/scalar_4x64_impl.h +++ b/src/secp256k1/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,37 +80,55 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { uint128_t t; VERIFY_CHECK(overflow <= 1); - t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1; - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2; - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint64_t)r->d[3]; - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; + + 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); + secp256k1_u128_accum_u64(&t, r->d[1]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_1); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2]); + secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_2); + 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; - uint128_t t = (uint128_t)a->d[0] + b->d[0]; - r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[1] + b->d[1]; - r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[2] + b->d[2]; - r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - t += (uint128_t)a->d[3] + b->d[3]; - r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; - overflow = t + secp256k1_scalar_check_overflow(r); + 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); + secp256k1_u128_accum_u64(&t, a->d[1]); + secp256k1_u128_accum_u64(&t, b->d[1]); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[2]); + secp256k1_u128_accum_u64(&t, b->d[2]); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, a->d[3]); + secp256k1_u128_accum_u64(&t, b->d[3]); + r->d[3] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + 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)); @@ -118,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((t >> 64) == 0); VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); @@ -134,9 +160,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]); @@ -144,28 +174,43 @@ 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); - uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; - r->d[0] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[1]) + SECP256K1_N_1; - r->d[1] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[2]) + SECP256K1_N_2; - r->d[2] = t & nonzero; t >>= 64; - t += (uint128_t)(~a->d[3]) + SECP256K1_N_3; - r->d[3] = t & nonzero; + 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); + secp256k1_u128_accum_u64(&t, ~a->d[1]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_1); + r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, ~a->d[2]); + secp256k1_u128_accum_u64(&t, SECP256K1_N_2); + r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + 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. */ @@ -181,14 +226,23 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { volatile int vflag = flag; uint64_t mask = -vflag; uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; - uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); - r->d[0] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); - r->d[1] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); - r->d[2] = t & nonzero; t >>= 64; - t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); - r->d[3] = t & nonzero; + 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); + secp256k1_u128_accum_u64(&t, r->d[1] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_1 & mask); + r->d[1] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, r->d[2] ^ mask); + secp256k1_u128_accum_u64(&t, SECP256K1_N_2 & mask); + r->d[2] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); + 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; } @@ -741,23 +795,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; @@ -766,9 +831,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; } @@ -777,7 +848,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; @@ -787,18 +861,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) { @@ -818,18 +898,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; @@ -848,10 +923,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 @@ -862,16 +940,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/secp256k1/src/scalar_8x32_impl.h b/src/secp256k1/src/scalar_8x32_impl.h index 80ef3ef24..5ca134227 100644 --- a/src/secp256k1/src/scalar_8x32_impl.h +++ b/src/secp256k1/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/secp256k1/src/scalar_impl.h b/src/secp256k1/src/scalar_impl.h index bed7f95fc..3eca23b4f 100644 --- a/src/secp256k1/src/scalar_impl.h +++ b/src/secp256k1/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/secp256k1/src/scalar_low_impl.h b/src/secp256k1/src/scalar_low_impl.h index 428a5deb3..e2356a5be 100644 --- a/src/secp256k1/src/scalar_low_impl.h +++ b/src/secp256k1/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/secp256k1/src/tests.c b/src/secp256k1/src/tests.c index 2b634d32b..4f54b8dbe 100644 --- a/src/secp256k1/src/tests.c +++ b/src/secp256k1/src/tests.c @@ -88,9 +88,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; @@ -120,6 +120,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 { @@ -2968,8 +2992,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) { @@ -2992,9 +3015,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); @@ -3151,7 +3174,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. */ @@ -3176,7 +3199,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 @@ -3280,13 +3303,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); @@ -3681,8 +3704,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. */ @@ -3717,11 +3740,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) { @@ -3760,17 +3783,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); @@ -3789,7 +3812,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); @@ -3798,7 +3821,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). */ @@ -3806,8 +3829,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); } @@ -3827,7 +3850,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); @@ -3910,7 +3933,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. */ @@ -4093,7 +4116,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; @@ -4150,8 +4173,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)); @@ -4203,18 +4226,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; } @@ -4265,8 +4288,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; @@ -4312,8 +4335,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]; @@ -4331,13 +4352,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); } @@ -4377,7 +4398,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); @@ -4396,9 +4416,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); @@ -4441,7 +4461,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) { @@ -4493,19 +4513,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); @@ -4860,7 +4878,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. */ @@ -5473,16 +5491,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); @@ -7607,33 +7624,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/secp256k1/src/tests_exhaustive.c b/src/secp256k1/src/tests_exhaustive.c index 05e33cdef..5a2ba397e 100644 --- a/src/secp256k1/src/tests_exhaustive.c +++ b/src/secp256k1/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/secp256k1/src/util.h b/src/secp256k1/src/util.h index 801ea0c88..cf7e5d1af 100644 --- a/src/secp256k1/src/util.h +++ b/src/secp256k1/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