diff --git a/.cirrus.yml b/.cirrus.yml index 0a278eb5bc..04aa8f2409 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -22,13 +22,6 @@ env: RECOVERY: no SCHNORRSIG: no ELLSWIFT: no - ECDSA_S2C: no - GENERATOR: no - RANGEPROOF: no - WHITELIST: no - MUSIG: no - ECDSAADAPTOR: no - BPPP: no ### test options SECP256K1_TEST_ITERS: BENCH: yes @@ -37,11 +30,6 @@ env: # Compile and run the tests EXAMPLES: yes -# https://cirrus-ci.org/pricing/#compute-credits -credits_snippet: &CREDITS - # Don't use any credits for now. - use_compute_credits: false - cat_logs_snippet: &CAT_LOGS always: cat_tests_log_script: @@ -61,402 +49,47 @@ cat_logs_snippet: &CAT_LOGS cat_ci_env_script: - env -linux_container_snippet: &LINUX_CONTAINER - container: - dockerfile: ci/linux-debian.Dockerfile - # Reduce number of CPUs to be able to do more builds in parallel. - cpu: 1 - # Gives us more CPUs for free if they're available. - greedy: true - # More than enough for our scripts. - memory: 2G - -task: - name: "x86_64: Linux (Debian stable)" - << : *LINUX_CONTAINER - matrix: - - env: {WIDEMUL: int64, RECOVERY: yes} - - env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes} - - env: {WIDEMUL: int128} - - env: {WIDEMUL: int128_struct} - - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes, ELLSWIFT: yes} - - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes} - - env: {WIDEMUL: int128, ASM: x86_64 , ELLSWIFT: yes} - - env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes} - - env: {CTIMETESTS: no, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes, CPPFLAGS: -DVERIFY} - - env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no} - - env: {CPPFLAGS: -DDETERMINISTIC} - - env: {CFLAGS: -O0, CTIMETESTS: no} - - env: {CFLAGS: -O1, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes} - - env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } - - env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 } - matrix: - - env: - CC: gcc - - env: - CC: clang - - env: - CC: gcc-snapshot - - env: - CC: clang-snapshot - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "i686: Linux (Debian stable)" - << : *LINUX_CONTAINER - env: - HOST: i686-linux-gnu - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - EXPERIMENTAL: yes - ECDSA_S2C: yes - RANGEPROOF: yes - WHITELIST: yes - GENERATOR: yes - MUSIG: yes - ECDSAADAPTOR: yes - BPPP: yes - matrix: - - env: - CC: i686-linux-gnu-gcc - - env: - CC: clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "arm64: macOS Ventura" - macos_instance: - image: ghcr.io/cirruslabs/macos-ventura-base:latest - # tasks with valgrind enabled take about 90 minutes - timeout_in: 120m - env: - HOMEBREW_NO_AUTO_UPDATE: 1 - HOMEBREW_NO_INSTALL_CLEANUP: 1 - # Cirrus gives us a fixed number of 4 virtual CPUs. Not that we even have that many jobs at the moment... - MAKEFLAGS: -j5 - env: - ASM: no - WITH_VALGRIND: no - CTIMETESTS: no - CC: clang - matrix: - - env: {WIDEMUL: int64, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes} - - env: {WIDEMUL: int64, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, CC: gcc} - - env: {WIDEMUL: int128_struct, ECMULTGENPRECISION: 2, ECMULTWINDOW: 4} - - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes} - - env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes} - - env: {WIDEMUL: int128, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, CC: gcc} - - env: {WIDEMUL: int128, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, CPPFLAGS: -DVERIFY} - - env: {BUILD: distcheck} - brew_script: - - brew install automake libtool gcc - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - << : *CREDITS - -task: - name: "s390x (big-endian): Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-s390x - SECP256K1_TEST_ITERS: 16 - HOST: s390x-linux-gnu - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - EXPERIMENTAL: yes - ECDSA_S2C: yes - RANGEPROOF: yes - WHITELIST: yes - GENERATOR: yes - MUSIG: yes - ECDSAADAPTOR: yes - BPPP: yes - CTIMETESTS: no - test_script: - # https://sourceware.org/bugzilla/show_bug.cgi?id=27008 - - rm /etc/ld.so.cache - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "ARM32: Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-arm - SECP256K1_TEST_ITERS: 16 - HOST: arm-linux-gnueabihf - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - CTIMETESTS: no - matrix: - - env: {} - - env: {EXPERIMENTAL: yes, ASM: arm32} - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "ARM64: Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-aarch64 - SECP256K1_TEST_ITERS: 16 - HOST: aarch64-linux-gnu - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - CTIMETESTS: no - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "ppc64le: Linux (Debian stable, QEMU)" - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: qemu-ppc64le - SECP256K1_TEST_ITERS: 16 - HOST: powerpc64le-linux-gnu - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - CTIMETESTS: no - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: wine - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - CTIMETESTS: no - matrix: - - name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)" - env: - HOST: x86_64-w64-mingw32 - - name: "i686 (mingw32-w64): Windows (Debian stable, Wine)" - env: - HOST: i686-w64-mingw32 - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - << : *LINUX_CONTAINER - env: - WRAPPER_CMD: wine - WERROR_CFLAGS: -WX - WITH_VALGRIND: no - ECDH: yes - RECOVERY: yes - EXPERIMENTAL: yes - SCHNORRSIG: yes - ELLSWIFT: yes - ECDSA_S2C: yes - GENERATOR: yes - RANGEPROOF: yes - WHITELIST: yes - MUSIG: yes - ECDSAADAPTOR: yes - BPPP: yes - CTIMETESTS: no - # Use a MinGW-w64 host to tell ./configure we're building for Windows. - # This will detect some MinGW-w64 tools but then make will need only - # the MSVC tools CC, AR and NM as specified below. - HOST: x86_64-w64-mingw32 - CC: /opt/msvc/bin/x64/cl - AR: /opt/msvc/bin/x64/lib - NM: /opt/msvc/bin/x64/dumpbin -symbols -headers - # Set non-essential options that affect the CLI messages here. - # (They depend on the user's taste, so we don't want to set them automatically in configure.ac.) - CFLAGS: -nologo -diagnostics:caret - LDFLAGS: -Xlinker -Xlinker -Xlinker -nologo - matrix: - - name: "x86_64 (MSVC): Windows (Debian stable, Wine)" - - name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)" - env: - WIDEMUL: int128_struct - - name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct with __(u)mulh)" - env: - WIDEMUL: int128_struct - CPPFLAGS: -DSECP256K1_MSVC_MULH_TEST_OVERRIDE - - name: "i686 (MSVC): Windows (Debian stable, Wine)" - env: - HOST: i686-w64-mingw32 - CC: /opt/msvc/bin/x86/cl - AR: /opt/msvc/bin/x86/lib - NM: /opt/msvc/bin/x86/dumpbin -symbols -headers - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -# Sanitizers -task: - timeout_in: 120m - << : *LINUX_CONTAINER - env: - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - EXPERIMENTAL: yes - ECDSA_S2C: yes - RANGEPROOF: yes - WHITELIST: yes - GENERATOR: yes - MUSIG: yes - ECDSAADAPTOR: yes - BPPP: yes - CTIMETESTS: no - matrix: - - name: "Valgrind (memcheck)" - container: - cpu: 2 - env: - # The `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (https://www.valgrind.org/docs/manual/manual-core.html) - WRAPPER_CMD: "valgrind --error-exitcode=42" - SECP256K1_TEST_ITERS: 2 - - name: "UBSan, ASan, LSan" - container: - memory: 2G - env: - CFLAGS: "-fsanitize=undefined,address -g" - UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1" - ASAN_OPTIONS: "strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1" - LSAN_OPTIONS: "use_unaligned=1" - SECP256K1_TEST_ITERS: 32 - # Try to cover many configurations with just a tiny matrix. - matrix: - - env: - ASM: auto - - env: - ASM: no - ECMULTGENPRECISION: 2 - ECMULTWINDOW: 2 - matrix: - - env: - CC: clang - - env: - HOST: i686-linux-gnu - CC: i686-linux-gnu-gcc - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -# Memory sanitizers -task: - << : *LINUX_CONTAINER - name: "MSan" - env: - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - EXPERIMENTAL: yes - ECDSA_S2C: yes - GENERATOR: yes - RANGEPROOF: yes - WHITELIST: yes - MUSIG: yes - ECDSAADAPTOR: yes - BPPP: yes - CTIMETESTS: yes - CC: clang - SECP256K1_TEST_ITERS: 32 - ASM: no - WITH_VALGRIND: no - container: - memory: 2G - matrix: - - env: - CFLAGS: "-fsanitize=memory -g" - - env: - ECMULTGENPRECISION: 2 - ECMULTWINDOW: 2 - CFLAGS: "-fsanitize=memory -g -O3" - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "C++ -fpermissive (entire project)" - << : *LINUX_CONTAINER - env: - CC: g++ - CFLAGS: -fpermissive -g - CPPFLAGS: -DSECP256K1_CPLUSPLUS_TEST_OVERRIDE - WERROR_CFLAGS: - ECDH: yes - RECOVERY: yes - SCHNORRSIG: yes - ELLSWIFT: yes - test_script: - - ./ci/cirrus.sh - << : *CAT_LOGS - -task: - name: "C++ (public headers)" - << : *LINUX_CONTAINER - test_script: - - g++ -Werror include/*.h - - clang -Werror -x c++-header include/*.h - - /opt/msvc/bin/x64/cl.exe -c -WX -TP include/*.h - -task: - name: "sage prover" - << : *LINUX_CONTAINER - test_script: - - cd sage - - sage prove_group_implementations.sage - -task: - name: "x86_64: Windows (VS 2022)" - windows_container: - image: cirrusci/windowsservercore:visualstudio2022 - cpu: 4 - memory: 3840MB - env: - PATH: '%CIRRUS_WORKING_DIR%\build\src\RelWithDebInfo;%PATH%' - x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"' - # Ignore MSBuild warning MSB8029. - # See: https://learn.microsoft.com/en-us/visualstudio/msbuild/errors/msb8029?view=vs-2022 - IgnoreWarnIntDirInTempDetected: 'true' - matrix: - - env: - BUILD_SHARED_LIBS: ON - - env: - BUILD_SHARED_LIBS: OFF - git_show_script: - # Print commit to allow reproducing the job outside of CI. - - git show --no-patch - configure_script: - - '%x64_NATIVE_TOOLS%' - - cmake -E env CFLAGS="/WX" cmake -A x64 -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS% +linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER + env_script: + - env | tee /tmp/env build_script: - - '%x64_NATIVE_TOOLS%' - - cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5 - check_script: - - '%x64_NATIVE_TOOLS%' - - ctest -C RelWithDebInfo --test-dir build -j 5 - - build\src\RelWithDebInfo\bench_ecmult.exe - - build\src\RelWithDebInfo\bench_internal.exe - - build\src\RelWithDebInfo\bench.exe + - DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm" + - docker image prune --force # Cleanup stale layers + test_script: + - docker run --rm --mount "type=bind,src=./,dst=/ci_secp256k1" --env-file /tmp/env --replace --name "ci_secp256k1_arm" "ci_secp256k1_arm" bash -c "cd /ci_secp256k1/ && ./ci/ci.sh" + +task: + name: "ARM64: Linux (Debian stable)" + persistent_worker: + labels: + type: arm64 + env: + ECDH: yes + RECOVERY: yes + SCHNORRSIG: yes + ELLSWIFT: yes + matrix: + # Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU + - env: { CC: 'gcc-snapshot' } + << : *LINUX_ARM64_CONTAINER + << : *CAT_LOGS + +task: + name: "ARM64: Linux (Debian stable), Valgrind" + persistent_worker: + labels: + type: arm64 + env: + ECDH: yes + RECOVERY: yes + SCHNORRSIG: yes + ELLSWIFT: yes + WRAPPER_CMD: 'valgrind --error-exitcode=42' + SECP256K1_TEST_ITERS: 2 + matrix: + - env: { CC: 'gcc' } + - env: { CC: 'clang' } + - env: { CC: 'gcc-snapshot' } + - env: { CC: 'clang-snapshot' } + << : *LINUX_ARM64_CONTAINER + << : *CAT_LOGS diff --git a/.github/actions/install-homebrew-valgrind/action.yml b/.github/actions/install-homebrew-valgrind/action.yml new file mode 100644 index 0000000000..094ff891f7 --- /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 0000000000..dbfaa4fece --- /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@v3 + + - uses: docker/build-push-action@v5 + 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@v5 + id: retry_builder + if: steps.main_builder.outcome == 'failure' + with: + context: . + file: ${{ inputs.dockerfile }} + tags: ${{ inputs.tag }} + load: true + cache-from: type=gha + + - # Tell Docker to pass environment variables in `env` into the container. + run: > + docker run \ + $(echo '${{ toJSON(env) }}' | jq -r 'keys[] | "--env \(.) "') \ + --volume ${{ github.workspace }}:${{ github.workspace }} \ + --workdir ${{ github.workspace }} \ + ${{ inputs.tag }} bash -c " + git config --global --add safe.directory ${{ github.workspace }} + ${{ inputs.command }} + " + shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..36293f1366 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,904 @@ +name: CI +on: + pull_request: + push: + branches: + - '**' + tags-ignore: + - '**' + +concurrency: + group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }} + cancel-in-progress: true + +env: + ### compiler options + HOST: + WRAPPER_CMD: + # Specific warnings can be disabled with -Wno-error=foo. + # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual. + WERROR_CFLAGS: '-Werror -pedantic-errors' + MAKEFLAGS: '-j4' + BUILD: 'check' + ### secp256k1 config + ECMULTWINDOW: 'auto' + ECMULTGENPRECISION: 'auto' + ASM: 'no' + WIDEMUL: 'auto' + WITH_VALGRIND: 'yes' + EXTRAFLAGS: + ### secp256k1 modules + EXPERIMENTAL: 'no' + ECDH: 'no' + RECOVERY: 'no' + SCHNORRSIG: 'no' + ELLSWIFT: 'no' + ECDSA_S2C: 'no' + GENERATOR: 'no' + RANGEPROOF: 'no' + WHITELIST: 'no' + MUSIG: 'no' + ECDSAADAPTOR: 'no' + BPPP: 'no' + SCHNORRSIG_HALFAGG: 'no' + ### test options + SECP256K1_TEST_ITERS: + BENCH: 'yes' + SECP256K1_BENCH_ITERS: 2 + CTIMETESTS: 'yes' + # Compile and run the examples. + EXAMPLES: 'yes' + +jobs: + docker_cache: + name: "Build Docker image" + runs-on: ubuntu-latest + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + # See: https://github.com/moby/buildkit/issues/3969. + driver-opts: | + network=host + + - name: Build container + uses: docker/build-push-action@v5 + 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', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: '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', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'} + - env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' } + - env_vars: { RECOVERY: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'} + - env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CPPFLAGS: '-DVERIFY' } + - env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' } + - env_vars: { CPPFLAGS: '-DDETERMINISTIC' } + - env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' } + - env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' } + - env_vars: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + - env_vars: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 } + cc: + - 'gcc' + - 'clang' + - 'gcc-snapshot' + - 'clang-snapshot' + + env: + CC: ${{ matrix.cc }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + i686_debian: + name: "i686: Linux (Debian stable)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + cc: + - 'i686-linux-gnu-gcc' + - 'clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include' + + env: + HOST: 'i686-linux-gnu' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + EXPERIMENTAL: 'yes' + ECDSA_S2C: 'yes' + RANGEPROOF: 'yes' + WHITELIST: 'yes' + GENERATOR: 'yes' + MUSIG: 'yes' + ECDSAADAPTOR: 'yes' + BPPP: 'yes' + SCHNORRSIG_HALFAGG: 'yes' + CC: ${{ matrix.cc }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + s390x_debian: + name: "s390x (big-endian): Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-s390x' + SECP256K1_TEST_ITERS: 16 + HOST: 's390x-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + EXPERIMENTAL: 'yes' + ECDSA_S2C: 'yes' + RANGEPROOF: 'yes' + WHITELIST: 'yes' + GENERATOR: 'yes' + MUSIG: 'yes' + ECDSAADAPTOR: 'yes' + BPPP: 'yes' + SCHNORRSIG_HALFAGG: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + arm32_debian: + name: "ARM32: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: {} + - env_vars: { EXPERIMENTAL: 'yes', ASM: 'arm32' } + + env: + WRAPPER_CMD: 'qemu-arm' + SECP256K1_TEST_ITERS: 16 + HOST: 'arm-linux-gnueabihf' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + EXPERIMENTAL: 'yes' + ECDSA_S2C: 'yes' + GENERATOR: 'yes' + RANGEPROOF: 'yes' + WHITELIST: 'yes' + MUSIG: 'yes' + ECDSAADAPTOR: 'yes' + BPPP: 'yes' + SCHNORRSIG_HALFAGG: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + arm64_debian: + name: "ARM64: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-aarch64' + SECP256K1_TEST_ITERS: 16 + HOST: 'aarch64-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + EXPERIMENTAL: 'yes' + ECDSA_S2C: 'yes' + GENERATOR: 'yes' + RANGEPROOF: 'yes' + WHITELIST: 'yes' + MUSIG: 'yes' + ECDSAADAPTOR: 'yes' + BPPP: 'yes' + SCHNORRSIG_HALFAGG: 'yes' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { } # gcc + - env_vars: # clang + CC: 'clang --target=aarch64-linux-gnu' + - env_vars: # clang-snapshot + CC: 'clang-snapshot --target=aarch64-linux-gnu' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + ppc64le_debian: + name: "ppc64le: Linux (Debian stable, QEMU)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'qemu-ppc64le' + SECP256K1_TEST_ITERS: 16 + HOST: 'powerpc64le-linux-gnu' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + EXPERIMENTAL: 'yes' + ECDSA_S2C: 'yes' + GENERATOR: 'yes' + RANGEPROOF: 'yes' + WHITELIST: 'yes' + MUSIG: 'yes' + ECDSAADAPTOR: 'yes' + BPPP: 'yes' + SCHNORRSIG_HALFAGG: 'yes' + CTIMETESTS: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + valgrind_debian: + name: "Valgrind (memcheck)" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { CC: 'clang', ASM: 'auto' } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' } + - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + + env: + # The `--error-exitcode` is required to make the test fail if valgrind found errors, + # otherwise it will return 0 (https://www.valgrind.org/docs/manual/manual-core.html). + WRAPPER_CMD: 'valgrind --error-exitcode=42' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + EXPERIMENTAL: 'yes' + ECDSA_S2C: 'yes' + GENERATOR: 'yes' + RANGEPROOF: 'yes' + WHITELIST: 'yes' + MUSIG: 'yes' + ECDSAADAPTOR: 'yes' + BPPP: 'yes' + SCHNORRSIG_HALFAGG: 'yes' + CTIMETESTS: 'no' + SECP256K1_TEST_ITERS: 2 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + sanitizers_debian: + name: "UBSan, ASan, LSan" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: { CC: 'clang', ASM: 'auto' } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' } + - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } + + env: + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + EXPERIMENTAL: 'yes' + ECDSA_S2C: 'yes' + GENERATOR: 'yes' + RANGEPROOF: 'yes' + WHITELIST: 'yes' + MUSIG: 'yes' + ECDSAADAPTOR: 'yes' + BPPP: 'yes' + SCHNORRSIG_HALFAGG: 'yes' + CTIMETESTS: 'no' + CFLAGS: '-fsanitize=undefined,address -g' + UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1' + ASAN_OPTIONS: 'strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1' + LSAN_OPTIONS: 'use_unaligned=1' + SECP256K1_TEST_ITERS: 32 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + msan_debian: + name: "MSan" + runs-on: ubuntu-latest + needs: docker_cache + + strategy: + fail-fast: false + matrix: + configuration: + - env_vars: + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g' + - env_vars: + ECMULTGENPRECISION: 2 + ECMULTWINDOW: 2 + CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g -O3' + + env: + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + EXPERIMENTAL: 'yes' + ECDSA_S2C: 'yes' + GENERATOR: 'yes' + RANGEPROOF: 'yes' + WHITELIST: 'yes' + MUSIG: 'yes' + ECDSAADAPTOR: 'yes' + BPPP: 'yes' + SCHNORRSIG_HALFAGG: 'yes' + CTIMETESTS: 'yes' + CC: 'clang' + SECP256K1_TEST_ITERS: 32 + ASM: 'no' + WITH_VALGRIND: 'no' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + mingw_debian: + name: ${{ matrix.configuration.job_name }} + runs-on: ubuntu-latest + needs: docker_cache + + env: + WRAPPER_CMD: 'wine' + WITH_VALGRIND: 'no' + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + EXPERIMENTAL: 'yes' + ECDSA_S2C: 'yes' + GENERATOR: 'yes' + RANGEPROOF: 'yes' + WHITELIST: 'yes' + MUSIG: 'yes' + ECDSAADAPTOR: 'yes' + BPPP: 'yes' + SCHNORRSIG_HALFAGG: 'yes' + CTIMETESTS: 'no' + + strategy: + fail-fast: false + matrix: + configuration: + - job_name: 'x86_64 (mingw32-w64): Windows (Debian stable, Wine)' + env_vars: + HOST: 'x86_64-w64-mingw32' + - job_name: 'i686 (mingw32-w64): Windows (Debian stable, Wine)' + env_vars: + HOST: 'i686-w64-mingw32' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + env: ${{ matrix.configuration.env_vars }} + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + macos-native: + name: "x86_64: macOS Monterey" + # See: https://github.com/actions/runner-images#available-images. + runs-on: macos-12 # Use M1 once available https://github.com/github/roadmap/issues/528 + + env: + CC: 'clang' + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 + + strategy: + fail-fast: false + matrix: + env_vars: + - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' } + - { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 } + - { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CC: 'gcc' } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 } + - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' } + - BUILD: 'distcheck' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Homebrew packages + run: | + brew install automake libtool gcc + ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc + + - name: Install and cache Valgrind + uses: ./.github/actions/install-homebrew-valgrind + + - name: CI script + env: ${{ matrix.env_vars }} + run: ./ci/ci.sh + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + win64-native: + name: ${{ matrix.configuration.job_name }} + # See: https://github.com/actions/runner-images#available-images. + runs-on: windows-2022 + + strategy: + fail-fast: false + matrix: + configuration: + - job_name: 'x64 (MSVC): Windows (VS 2022, shared)' + cmake_options: '-A x64 -DBUILD_SHARED_LIBS=ON' + - job_name: 'x64 (MSVC): Windows (VS 2022, static)' + cmake_options: '-A x64 -DBUILD_SHARED_LIBS=OFF' + - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct)' + cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct' + - job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct with __(u)mulh)' + cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct' + cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE' + - job_name: 'x86 (MSVC): Windows (VS 2022)' + cmake_options: '-A Win32' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Generate buildsystem + run: cmake -E env CFLAGS="/WX ${{ matrix.configuration.cpp_flags }}" cmake -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON ${{ matrix.configuration.cmake_options }} + + - name: Build + run: cmake --build build --config RelWithDebInfo -- /p:UseMultiToolTask=true /maxCpuCount + + - name: Binaries info + # Use the bash shell included with Git for Windows. + shell: bash + run: | + cd build/src/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true + + - name: Check + run: | + ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1) + build\src\RelWithDebInfo\bench_ecmult.exe + build\src\RelWithDebInfo\bench_internal.exe + build\src\RelWithDebInfo\bench.exe + + win64-native-headers: + name: "x64 (MSVC): C++ (public headers)" + # See: https://github.com/actions/runner-images#available-images. + runs-on: windows-2022 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Add cl.exe to PATH + uses: ilammy/msvc-dev-cmd@v1 + + - name: C++ (public headers) + run: | + cl.exe -c -WX -TP include/*.h + + cxx_fpermissive_debian: + name: "C++ -fpermissive (entire project)" + runs-on: ubuntu-latest + needs: docker_cache + + env: + CC: 'g++' + CFLAGS: '-fpermissive -g' + CPPFLAGS: '-DSECP256K1_CPLUSPLUS_TEST_OVERRIDE' + WERROR_CFLAGS: + ECDH: 'yes' + RECOVERY: 'yes' + SCHNORRSIG: 'yes' + ELLSWIFT: 'yes' + EXPERIMENTAL: 'yes' + ECDSA_S2C: 'yes' + GENERATOR: 'yes' + RANGEPROOF: 'yes' + WHITELIST: 'yes' + MUSIG: 'yes' + ECDSAADAPTOR: 'yes' + BPPP: 'yes' + SCHNORRSIG_HALFAGG: 'yes' + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + + - run: cat tests.log || true + if: ${{ always() }} + - run: cat noverify_tests.log || true + if: ${{ always() }} + - run: cat exhaustive_tests.log || true + if: ${{ always() }} + - run: cat ctime_tests.log || true + if: ${{ always() }} + - run: cat bench.log || true + if: ${{ always() }} + - run: cat config.log || true + if: ${{ always() }} + - run: cat test_env.log || true + if: ${{ always() }} + - name: CI env + run: env + if: ${{ always() }} + + cxx_headers_debian: + name: "C++ (public headers)" + runs-on: ubuntu-latest + needs: docker_cache + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + uses: ./.github/actions/run-in-docker-action + with: + dockerfile: ./ci/linux-debian.Dockerfile + tag: linux-debian-image + command: | + g++ -Werror include/*.h + clang -Werror -x c++-header include/*.h + + sage: + name: "SageMath prover" + runs-on: ubuntu-latest + container: + image: sagemath/sagemath:latest + options: --user root + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: CI script + run: | + cd sage + sage prove_group_implementations.sage + + release: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - run: ./autogen.sh && ./configure --enable-dev-mode && make distcheck + + - name: Check installation with Autotools + env: + CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install + run: | + ./autogen.sh && ./configure --prefix=${{ env.CI_INSTALL }} && make clean && make install && ls -RlAh ${{ env.CI_INSTALL }} + gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=${{ env.CI_INSTALL }}/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"${{ env.CI_INSTALL }}/lib" && ./ecdsa + + - name: Check installation with CMake + env: + CI_BUILD: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/build + CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install + run: | + cmake -B ${{ env.CI_BUILD }} -DCMAKE_INSTALL_PREFIX=${{ env.CI_INSTALL }} && cmake --build ${{ env.CI_BUILD }} --target install && ls -RlAh ${{ env.CI_INSTALL }} + gcc -o ecdsa examples/ecdsa.c -I ${{ env.CI_INSTALL }}/include -L ${{ env.CI_INSTALL }}/lib*/ -l secp256k1 -Wl,-rpath,"${{ env.CI_INSTALL }}/lib",-rpath,"${{ env.CI_INSTALL }}/lib64" && ./ecdsa diff --git a/CHANGELOG.md b/CHANGELOG.md index bddfe156bf..cdfe06bce1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,16 +10,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.4.1] - 2023-12-21 + +#### Changed + - The point multiplication algorithm used for ECDH operations (module `ecdh`) was replaced with a slightly faster one. + - Optional handwritten x86_64 assembly for field operations was removed because modern C compilers are able to output more efficient assembly. This change results in a significant speedup of some library functions when handwritten x86_64 assembly is enabled (`--with-asm=x86_64` in GNU Autotools, `-DSECP256K1_ASM=x86_64` in CMake), which is the default on x86_64. Benchmarks with GCC 10.5.0 show a 10% speedup for `secp256k1_ecdsa_verify` and `secp256k1_schnorrsig_verify`. + +#### ABI Compatibility +The ABI is backward compatible with versions 0.4.0 and 0.3.x. + +## [0.4.0] - 2023-09-04 + #### Added - New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them. ElligatorSwift permits representing secp256k1 public keys as 64-byte arrays which cannot be distinguished from uniformly random. See: - Header file `include/secp256k1_ellswift.h` which defines the new API. - Document `doc/ellswift.md` which explains the mathematical background of the scheme. - The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based. + - We now test the library with unreleased development snapshots of GCC and Clang. This gives us an early chance to catch miscompilations and constant-time issues introduced by the compiler (such as those that led to the previous two releases). + +#### Fixed + - Fixed symbol visibility in Windows DLL builds, where three internal library symbols were wrongly exported. #### Changed - When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`. +#### ABI Compatibility +This release is backward compatible with the ABI of 0.3.0, 0.3.1, and 0.3.2. Symbol visibility is now believed to be handled properly on supported platforms and is now considered to be part of the ABI. Please report any improperly exported symbols as a bug. + ## [0.3.2] - 2023-05-13 We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`. @@ -100,7 +118,9 @@ This version was in fact never released. The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6). Therefore, this version number does not uniquely identify a set of source files. -[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...HEAD +[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.1...HEAD +[0.4.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...v0.4.1 +[0.4.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...v0.4.0 [0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 3107eb3bf1..2d9d9d2c97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ project(libsecp256k1 # The package (a.k.a. release) version is based on semantic versioning 2.0.0 of # the API. All changes in experimental modules are treated as # backwards-compatible and therefore at most increase the minor version. - VERSION 0.3.3 + VERSION 0.4.2 DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1." HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1" LANGUAGES C @@ -34,9 +34,9 @@ endif() # https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # All changes in experimental modules are treated as if they don't affect the # interface and therefore only increase the revision. -set(${PROJECT_NAME}_LIB_VERSION_CURRENT 2) -set(${PROJECT_NAME}_LIB_VERSION_REVISION 3) -set(${PROJECT_NAME}_LIB_VERSION_AGE 0) +set(${PROJECT_NAME}_LIB_VERSION_CURRENT 3) +set(${PROJECT_NAME}_LIB_VERSION_REVISION 2) +set(${PROJECT_NAME}_LIB_VERSION_AGE 1) set(CMAKE_C_STANDARD 90) set(CMAKE_C_EXTENSIONS OFF) @@ -51,29 +51,102 @@ endif() option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL}) +## Modules + +# We declare all options before processing them, to make sure we can express +# dependendencies while processing. option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON) -if(SECP256K1_ENABLE_MODULE_ECDH) - add_compile_definitions(ENABLE_MODULE_ECDH=1) -endif() - option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF) -if(SECP256K1_ENABLE_MODULE_RECOVERY) - add_compile_definitions(ENABLE_MODULE_RECOVERY=1) -endif() - option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON) option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON) +option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON) + +option(SECP256K1_ENABLE_MODULE_GENERATOR "Enable NUMS generator module." ON) +option(SECP256K1_ENABLE_MODULE_RANGEPROOF "Enable Range proof module." ON) +option(SECP256K1_ENABLE_MODULE_SURJECTIONPROOF "Enable Surjection proof module." ON) +option(SECP256K1_ENABLE_MODULE_WHITELIST "Enable key whitelist module." ON) +option(SECP256K1_ENABLE_MODULE_MUSIG "Enable MuSig module." ON) +option(SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR "Enable ecdsa adaptor signatures module." ON) +option(SECP256K1_ENABLE_MODULE_ECDSA_S2C "Enable ECDSA sign-to-contract module." ON) +option(SECP256K1_ENABLE_MODULE_BPPP "Enable Bulletproofs++ module." ON) + +# Processing must be done in a topological sorting of the dependency graph +# (dependent module first). +if(SECP256K1_ENABLE_MODULE_BPPP) + if(DEFINED SECP256K1_ENABLE_MODULE_GENERATOR AND NOT SECP256K1_ENABLE_MODULE_GENERATOR) + message(FATAL_ERROR "Module dependency error: You have disabled the generator module explicitly, but it is required by the bppp module.") + endif() + set(SECP256K1_ENABLE_MODULE_GENERATOR ON) + add_compile_definitions(ENABLE_MODULE_BPPP=1) +endif() + +if(SECP256K1_ENABLE_MODULE_ECDSA_S2C) + add_compile_definitions(ENABLE_MODULE_ECDSA_S2C=1) +endif() + +if(SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR) + add_compile_definitions(ENABLE_MODULE_ECDSA_ADAPTOR=1) +endif() + +if(SECP256K1_ENABLE_MODULE_MUSIG) + if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG) + message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.") + endif() + set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON) + add_compile_definitions(ENABLE_MODULE_MUSIG=1) +endif() + +if(SECP256K1_ENABLE_MODULE_WHITELIST) + if(DEFINED SECP256K1_ENABLE_MODULE_RANGEPROOF AND NOT SECP256K1_ENABLE_MODULE_RANGEPROOF) + message(FATAL_ERROR "Module dependency error: You have disabled the rangeproof module explicitly, but it is required by the whitelist module.") + endif() + set(SECP256K1_ENABLE_MODULE_RANGEPROOF ON) + add_compile_definitions(ENABLE_MODULE_WHITELIST=1) +endif() + +if(SECP256K1_ENABLE_MODULE_SURJECTIONPROOF) + if(DEFINED SECP256K1_ENABLE_MODULE_RANGEPROOF AND NOT SECP256K1_ENABLE_MODULE_RANGEPROOF) + message(FATAL_ERROR "Module dependency error: You have disabled the rangeproof module explicitly, but it is required by the surjectionproof module.") + endif() + set(SECP256K1_ENABLE_MODULE_RANGEPROOF ON) + add_compile_definitions(ENABLE_MODULE_SURJECTIONPROOF=1) +endif() + +if(SECP256K1_ENABLE_MODULE_RANGEPROOF) + if(DEFINED SECP256K1_ENABLE_MODULE_GENERATOR AND NOT SECP256K1_ENABLE_MODULE_GENERATOR) + message(FATAL_ERROR "Module dependency error: You have disabled the generator module explicitly, but it is required by the rangeproof module.") + endif() + set(SECP256K1_ENABLE_MODULE_GENERATOR ON) + add_compile_definitions(ENABLE_MODULE_RANGEPROOF=1) +endif() + +if(SECP256K1_ENABLE_MODULE_GENERATOR) + add_compile_definitions(ENABLE_MODULE_GENERATOR=1) +endif() + + +if(SECP256K1_ENABLE_MODULE_ELLSWIFT) + add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1) +endif() + if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) + if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS) + message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.") + endif() set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON) add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1) endif() + if(SECP256K1_ENABLE_MODULE_EXTRAKEYS) add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1) endif() -option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON) -if(SECP256K1_ENABLE_MODULE_ELLSWIFT) - add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1) +if(SECP256K1_ENABLE_MODULE_RECOVERY) + add_compile_definitions(ENABLE_MODULE_RECOVERY=1) +endif() + +if(SECP256K1_ENABLE_MODULE_ECDH) + add_compile_definitions(ENABLE_MODULE_ECDH=1) endif() option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF) @@ -107,7 +180,7 @@ if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) endif() mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) -set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]") +set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]") set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32") check_string_option_value(SECP256K1_ASM) if(SECP256K1_ASM STREQUAL "arm32") @@ -117,7 +190,7 @@ if(SECP256K1_ASM STREQUAL "arm32") if(HAVE_ARM32_ASM) add_compile_definitions(USE_EXTERNAL_ASM=1) else() - message(FATAL_ERROR "ARM32 assembly optimization requested but not available.") + message(FATAL_ERROR "ARM32 assembly requested but not available.") endif() elseif(SECP256K1_ASM) include(CheckX86_64Assembly) @@ -128,14 +201,14 @@ elseif(SECP256K1_ASM) elseif(SECP256K1_ASM STREQUAL "AUTO") set(SECP256K1_ASM "OFF") else() - message(FATAL_ERROR "x86_64 assembly optimization requested but not available.") + message(FATAL_ERROR "x86_64 assembly requested but not available.") endif() endif() option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF) if(NOT SECP256K1_EXPERIMENTAL) if(SECP256K1_ASM STREQUAL "arm32") - message(FATAL_ERROR "ARM32 assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.") + message(FATAL_ERROR "ARM32 assembly is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.") endif() endif() @@ -254,9 +327,14 @@ if(SECP256K1_BUILD_BENCHMARK OR SECP256K1_BUILD_TESTS OR SECP256K1_BUILD_EXHAUST enable_testing() endif() +set(SECP256K1_LATE_CFLAGS "" CACHE STRING "Compiler flags that are added to the command line after all other flags added by the build system.") +include(AllTargetsCompileOptions) + add_subdirectory(src) +all_targets_compile_options(src "${SECP256K1_LATE_CFLAGS}") if(SECP256K1_BUILD_EXAMPLES) add_subdirectory(examples) + all_targets_compile_options(examples "${SECP256K1_LATE_CFLAGS}") endif() message("\n") @@ -276,11 +354,19 @@ message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOV message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}") message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}") message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}") +message(" generator ........................... ${SECP256K1_ENABLE_MODULE_GENERATOR}") +message(" rangeproof .......................... ${SECP256K1_ENABLE_MODULE_RANGEPROOF}") +message(" surjectionproof ..................... ${SECP256K1_ENABLE_MODULE_SURJECTIONPROOF}") +message(" whitelist ........................... ${SECP256K1_ENABLE_MODULE_WHITELIST}") +message(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}") +message(" ecdsa-s2c ........................... ${SECP256K1_ENABLE_MODULE_ECDSA_S2C}") +message(" ecdsa-adaptor ....................... ${SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR}") +message(" bppp ................................ ${SECP256K1_ENABLE_MODULE_BPPP}") message("Parameters:") message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}") message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}") message("Optional features:") -message(" assembly optimization ............... ${SECP256K1_ASM}") +message(" assembly ............................ ${SECP256K1_ASM}") message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}") if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY) message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}") @@ -330,6 +416,9 @@ else() message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") endif() +if(SECP256K1_LATE_CFLAGS) + message("SECP256K1_LATE_CFLAGS ................. ${SECP256K1_LATE_CFLAGS}") +endif() message("\n") if(SECP256K1_EXPERIMENTAL) message( diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..5fbf7332c9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,107 @@ +# Contributing to libsecp256k1 + +## Scope + +libsecp256k1 is a library for elliptic curve cryptography on the curve secp256k1, not a general-purpose cryptography library. +The library primarily serves the needs of the Bitcoin Core project but provides additional functionality for the benefit of the wider Bitcoin ecosystem. + +## Adding new functionality or modules + +The libsecp256k1 project welcomes contributions in the form of new functionality or modules, provided they are within the project's scope. + +It is the responsibility of the contributors to convince the maintainers that the proposed functionality is within the project's scope, high-quality and maintainable. +Contributors are recommended to provide the following in addition to the new code: + +* **Specification:** + A specification can help significantly in reviewing the new code as it provides documentation and context. + It may justify various design decisions, give a motivation and outline security goals. + If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code. +* **Security Arguments:** + In addition to a defining the security goals, it should be argued that the new functionality meets these goals. + Depending on the nature of the new functionality, a wide range of security arguments are acceptable, ranging from being "obviously secure" to rigorous proofs of security. +* **Relevance Arguments:** + The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases. + +These are not the only factors taken into account when considering to add new functionality. +The proposed new libsecp256k1 code must be of high quality, including API documentation and tests, as well as featuring a misuse-resistant API design. + +We recommend reaching out to other contributors (see [Communication Channels](#communication-channels)) and get feedback before implementing new functionality. + +## Communication channels + +Most communication about libsecp256k1 occurs on the GitHub repository: in issues, pull request or on the discussion board. + +Additionally, there is an IRC channel dedicated to libsecp256k1, with biweekly meetings (see channel topic). +The channel is `#secp256k1` on Libera Chat. +The easiest way to participate on IRC is with the web client, [web.libera.chat](https://web.libera.chat/#secp256k1). +Chat history logs can be found at https://gnusha.org/secp256k1/. + +## Contributor workflow & peer review + +The Contributor Workflow & Peer Review in libsecp256k1 are similar to Bitcoin Core's workflow and review processes described in its [CONTRIBUTING.md](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md). + +### Coding conventions + +In addition, libsecp256k1 tries to maintain the following coding conventions: + +* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Moreover, it should be possible to use the library without any heap allocations. +* The tests should cover all lines and branches of the library (see [Test coverage](#coverage)). +* Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)). +* Local variables containing secret data should be cleared explicitly to try to delete secrets from memory. +* Use `secp256k1_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)). + +#### Style conventions + +* Commits should be atomic and diffs should be easy to read. For this reason, do not mix any formatting fixes or code moves with actual code changes. Make sure each individual commit is hygienic: that it builds successfully on its own without warnings, errors, regressions, or test failures. +* New code should adhere to the style of existing, in particular surrounding, code. Other than that, we do not enforce strict rules for code formatting. +* The code conforms to C89. Most notably, that means that only `/* ... */` comments are allowed (no `//` line comments). Moreover, any declarations in a `{ ... }` block (e.g., a function) must appear at the beginning of the block before any statements. When you would like to declare a variable in the middle of a block, you can open a new block: + ```C + void secp256k_foo(void) { + unsigned int x; /* declaration */ + int y = 2*x; /* declaration */ + x = 17; /* statement */ + { + int a, b; /* declaration */ + a = x + y; /* statement */ + secp256k_bar(x, &b); /* statement */ + } + } + ``` +* Use `unsigned int` instead of just `unsigned`. +* Use `void *ptr` instead of `void* ptr`. +* Arguments of the publicly-facing API must have a specific order defined in [include/secp256k1.h](include/secp256k1.h). +* User-facing comment lines in headers should be limited to 80 chars if possible. +* All identifiers in file scope should start with `secp256k1_`. +* Avoid trailing whitespace. + +### Tests + +#### Coverage + +This library aims to have full coverage of reachable lines and branches. + +To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary): + + $ ./configure --enable-coverage + +Run the tests: + + $ make check + +To create a report, `gcovr` is recommended, as it includes branch coverage reporting: + + $ gcovr --exclude 'src/bench*' --print-summary + +To create a HTML report with coloured and annotated source code: + + $ mkdir -p coverage + $ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html + +#### Exhaustive tests + +There are tests of several functions in which a small group replaces secp256k1. +These tests are *exhaustive* since they provide all elements and scalars of the small group as input arguments (see [src/tests_exhaustive.c](src/tests_exhaustive.c)). + +### Benchmarks + +See `src/bench*.c` for examples of benchmarks. diff --git a/Makefile.am b/Makefile.am index 0ca6c57cf3..329f86ca8f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,7 +39,6 @@ noinst_HEADERS += src/field_10x26_impl.h noinst_HEADERS += src/field_5x52.h noinst_HEADERS += src/field_5x52_impl.h noinst_HEADERS += src/field_5x52_int128_impl.h -noinst_HEADERS += src/field_5x52_asm_impl.h noinst_HEADERS += src/modinv32.h noinst_HEADERS += src/modinv32_impl.h noinst_HEADERS += src/modinv64.h @@ -48,6 +47,7 @@ noinst_HEADERS += src/precomputed_ecmult.h noinst_HEADERS += src/precomputed_ecmult_gen.h noinst_HEADERS += src/assumptions.h noinst_HEADERS += src/checkmem.h +noinst_HEADERS += src/testutil.h noinst_HEADERS += src/util.h noinst_HEADERS += src/int128.h noinst_HEADERS += src/int128_impl.h @@ -265,6 +265,10 @@ EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json EXTRA_DIST += tools/tests_wycheproof_generate.py +if ENABLE_MODULE_SCHNORRSIG_HALFAGG +include src/modules/schnorrsig_halfagg/Makefile.am.include +endif + if ENABLE_MODULE_BPPP include src/modules/bppp/Makefile.am.include endif diff --git a/README.md b/README.md index 067f0beb3e..88bdb2ba4f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ libsecp256k1-zkp ================ -[![Build Status](https://api.cirrus-ci.com/github/BlockstreamResearch/secp256k1-zkp.svg?branch=master)](https://cirrus-ci.com/github/BlockstreamResearch/secp256k1-zkp) ![Dependencies: None](https://img.shields.io/badge/dependencies-none-success) A fork of [libsecp256k1](https://github.com/bitcoin-core/secp256k1) with support for advanced and experimental features such as Confidential Assets and MuSig2 @@ -19,7 +18,8 @@ Experimental features are made available for testing and review by the community Build steps ----------- -libsecp256k1-zkp is built using autotools: +Building with Autotools +----------------------- $ ./autogen.sh $ ./configure @@ -29,6 +29,43 @@ libsecp256k1-zkp is built using autotools: To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags. For experimental modules, you will also need `--enable-experimental` as well as a flag for each individual module, e.g. `--enable-module-musig`. +Building with CMake (experimental) +---------------------------------- + +To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree. + +### Building on POSIX systems + + $ mkdir build && cd build + $ cmake .. + $ cmake --build . + $ ctest # run the test suite + $ sudo cmake --build . --target install # optional + +To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake .. -LH` to see the full list of available flags. + +### Cross compiling + +To alleviate issues with cross compiling, preconfigured toolchain files are available in the `cmake` directory. +For example, to cross compile for Windows: + + $ cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-w64-mingw32.toolchain.cmake + +To cross compile for Android with [NDK](https://developer.android.com/ndk/guides/cmake) (using NDK's toolchain file, and assuming the `ANDROID_NDK_ROOT` environment variable has been set): + + $ cmake .. -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28 + +### Building on Windows + +To build on Windows with Visual Studio, a proper [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) must be specified for a new build tree. + +The following example assumes using of Visual Studio 2022 and CMake v3.21+. + +In "Developer Command Prompt for VS 2022": + + >cmake -G "Visual Studio 17 2022" -A x64 -S . -B build + >cmake --build build --config RelWithDebInfo + Usage examples ----------- @@ -40,28 +77,6 @@ Usage examples can be found in the [examples](examples) directory. To compile th To compile the Schnorr signature, ECDH and MuSig examples, you need to enable the corresponding module by providing a flag to the `configure` script, for example `--enable-module-schnorrsig`. -Test coverage ------------ - -This library aims to have full coverage of the reachable lines and branches. - -To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary): - - $ ./configure --enable-coverage - -Run the tests: - - $ make check - -To create a report, `gcovr` is recommended, as it includes branch coverage reporting: - - $ gcovr --exclude 'src/bench*' --print-summary - -To create a HTML report with coloured and annotated source code: - - $ mkdir -p coverage - $ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html - Benchmark ------------ If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1-zkp functions will be present in the root directory after the build. @@ -78,3 +93,8 @@ Reporting a vulnerability ------------ See [SECURITY.md](SECURITY.md) + +Contributing to libsecp256k1 +------------ + +See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/ci/cirrus.sh b/ci/ci.sh similarity index 83% rename from ci/cirrus.sh rename to ci/ci.sh index 68f40668d0..47c4ae67c5 100755 --- a/ci/cirrus.sh +++ b/ci/ci.sh @@ -13,7 +13,7 @@ print_environment() { # does not rely on bash. for var in WERROR_CFLAGS MAKEFLAGS BUILD \ ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ - EXPERIMENTAL ECDH RECOVERY SCHNORRSIG ELLSWIFT \ + EXPERIMENTAL ECDH RECOVERY SCHNORRSIG SCHNORRSIG_HALFAGG ELLSWIFT \ ECDSA_S2C GENERATOR RANGEPROOF WHITELIST MUSIG ECDSAADAPTOR BPPP \ SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\ EXAMPLES \ @@ -32,18 +32,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 @@ -85,13 +82,28 @@ esac --enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \ --enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \ --enable-module-schnorrsig="$SCHNORRSIG" \ + --enable-module-schnorrsig-halfagg="$SCHNORRSIG_HALFAGG" \ --enable-examples="$EXAMPLES" \ --enable-ctime-tests="$CTIMETESTS" \ --with-valgrind="$WITH_VALGRIND" \ --host="$HOST" $EXTRAFLAGS # We have set "-j" in MAKEFLAGS. -make +build_exit_code=0 +make > make.log 2>&1 || build_exit_code=$? +cat make.log +if [ $build_exit_code -ne 0 ]; then + case "${CC:-undefined}" in + *snapshot*) + # Ignore internal compiler errors in gcc-snapshot and clang-snapshot + grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log + return $?; + ;; + *) + return 1; + ;; + esac +fi # Print information about binaries so that we can see that the architecture is correct file *tests* || true diff --git a/ci/linux-debian.Dockerfile b/ci/linux-debian.Dockerfile index dbb1dd2919..5ce715b41b 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,65 +22,58 @@ 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++ \ gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan8:i386 \ gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \ 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 \ gcc-mingw-w64-x86-64-win32 wine64 wine \ gcc-mingw-w64-i686-win32 wine32 \ - sagemath - -WORKDIR /root + python3 && \ + if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \ + apt-get install --no-install-recommends -y \ + gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 ;\ + fi && \ + apt-get clean && rm -rf /var/lib/apt/lists/* # 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 ls && \ - [[ $(ls *.tar.xz | wc -l) -eq "1" ]] && \ + [ $(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/cmake/AllTargetsCompileOptions.cmake b/cmake/AllTargetsCompileOptions.cmake new file mode 100644 index 0000000000..6e420e0fde --- /dev/null +++ b/cmake/AllTargetsCompileOptions.cmake @@ -0,0 +1,12 @@ +# Add compile options to all targets added in the subdirectory. +function(all_targets_compile_options dir options) + get_directory_property(targets DIRECTORY ${dir} BUILDSYSTEM_TARGETS) + separate_arguments(options) + set(compiled_target_types STATIC_LIBRARY SHARED_LIBRARY OBJECT_LIBRARY EXECUTABLE) + foreach(target ${targets}) + get_target_property(type ${target} TYPE) + if(type IN_LIST compiled_target_types) + target_compile_options(${target} PRIVATE ${options}) + endif() + endforeach() +endfunction() diff --git a/cmake/GeneratePkgConfigFile.cmake b/cmake/GeneratePkgConfigFile.cmake new file mode 100644 index 0000000000..9c1d7f1ddd --- /dev/null +++ b/cmake/GeneratePkgConfigFile.cmake @@ -0,0 +1,8 @@ +function(generate_pkg_config_file in_file) + set(prefix ${CMAKE_INSTALL_PREFIX}) + set(exec_prefix \${prefix}) + set(libdir \${exec_prefix}/${CMAKE_INSTALL_LIBDIR}) + set(includedir \${prefix}/${CMAKE_INSTALL_INCLUDEDIR}) + set(PACKAGE_VERSION ${PROJECT_VERSION}) + configure_file(${in_file} ${PROJECT_NAME}.pc @ONLY) +endfunction() diff --git a/configure.ac b/configure.ac index d4934d32d9..4d2a6e67e9 100644 --- a/configure.ac +++ b/configure.ac @@ -168,24 +168,30 @@ AC_ARG_ENABLE(examples, AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [], [SECP_SET_DEFAULT([enable_examples], [no], [yes])]) -AC_ARG_ENABLE(module_bppp, - AS_HELP_STRING([--enable-module-bppp],[enable Bulletproofs++ module (experimental)]), - [], - [SECP_SET_DEFAULT([enable_module_bppp], [no], [yes])]) - AC_ARG_ENABLE(module_ecdh, AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=yes]]), [], [SECP_SET_DEFAULT([enable_module_ecdh], [yes], [yes])]) -AC_ARG_ENABLE(module_musig, - AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]), - [], - [SECP_SET_DEFAULT([enable_module_musig], [no], [yes])]) - AC_ARG_ENABLE(module_recovery, AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [], [SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])]) +AC_ARG_ENABLE(module_extrakeys, + AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])]) + +AC_ARG_ENABLE(module_schnorrsig, + AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])]) + +AC_ARG_ENABLE(module_schnorrsig_halfagg, + AS_HELP_STRING([--enable-module-schnorrsig-halfagg],[enable schnorrsig half-aggregation module (experimental) [default=no]]), [], + [SECP_SET_DEFAULT([enable_module_schnorrsig_halfagg], [no], [yes])]) + +AC_ARG_ENABLE(module_ellswift, + AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [], + [SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])]) + AC_ARG_ENABLE(module_generator, AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module [default=no]]), [], @@ -196,28 +202,35 @@ AC_ARG_ENABLE(module_rangeproof, [], [SECP_SET_DEFAULT([enable_module_rangeproof], [no], [yes])]) +AC_ARG_ENABLE(module_surjectionproof, + AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module [default=no]]), + [], + [SECP_SET_DEFAULT([enable_module_surjectionproof], [no], [yes])]) +AC_ARG_ENABLE(reduced_surjection_proof_size, + AS_HELP_STRING([--enable-reduced-surjection-proof-size],[use reduced surjection proof size (disabling parsing and verification) [default=no]]), + [], + [SECP_SET_DEFAULT([enable_reduced_surjection_proof_size], [no], [no])]) + AC_ARG_ENABLE(module_whitelist, AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module [default=no]]), [], [SECP_SET_DEFAULT([enable_module_whitelist], [no], [yes])]) -AC_ARG_ENABLE(module_extrakeys, - AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [], - [SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])]) - -AC_ARG_ENABLE(module_schnorrsig, - AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [], - [SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])]) - -AC_ARG_ENABLE(module_ellswift, - AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [], - [SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])]) +AC_ARG_ENABLE(module_musig, + AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]), + [], + [SECP_SET_DEFAULT([enable_module_musig], [no], [yes])]) AC_ARG_ENABLE(module_ecdsa_s2c, AS_HELP_STRING([--enable-module-ecdsa-s2c],[enable ECDSA sign-to-contract module [default=no]]), [], [SECP_SET_DEFAULT([enable_module_ecdsa_s2c], [no], [yes])]) +AC_ARG_ENABLE(module_bppp, + AS_HELP_STRING([--enable-module-bppp],[enable Bulletproofs++ module (experimental)]), + [], + [SECP_SET_DEFAULT([enable_module_bppp], [no], [yes])]) + AC_ARG_ENABLE(module_ecdsa-adaptor, AS_HELP_STRING([--enable-module-ecdsa-adaptor],[enable ECDSA adaptor module [default=no]]), [], @@ -227,16 +240,6 @@ AC_ARG_ENABLE(external_default_callbacks, AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [], [SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])]) -AC_ARG_ENABLE(module_surjectionproof, - AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module [default=no]]), - [], - [SECP_SET_DEFAULT([enable_module_surjectionproof], [no], [yes])]) - -AC_ARG_ENABLE(reduced_surjection_proof_size, - AS_HELP_STRING([--enable-reduced-surjection-proof-size],[use reduced surjection proof size (disabling parsing and verification) [default=no]]), - [], - [SECP_SET_DEFAULT([use_reduced_surjection_proof_size], [no], [no])]) - # Test-only override of the (autodetected by the C code) "widemul" setting. # Legal values are: # * int64 (for [u]int64_t), @@ -246,7 +249,7 @@ AC_ARG_ENABLE(reduced_surjection_proof_size, AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto]) AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto], -[assembly optimizations to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto]) +[assembly to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto]) AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto], [window size for ecmult precomputation for verification, specified as integer in range [2..24].] @@ -336,24 +339,24 @@ else x86_64) SECP_X86_64_ASM_CHECK if test x"$has_x86_64_asm" != x"yes"; then - AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) + AC_MSG_ERROR([x86_64 assembly requested but not available]) fi ;; arm32) SECP_ARM32_ASM_CHECK if test x"$has_arm32_asm" != x"yes"; then - AC_MSG_ERROR([ARM32 assembly optimization requested but not available]) + AC_MSG_ERROR([ARM32 assembly requested but not available]) fi ;; no) ;; *) - AC_MSG_ERROR([invalid assembly optimization selection]) + AC_MSG_ERROR([invalid assembly selection]) ;; esac fi -# Select assembly optimization +# Select assembly enable_external_asm=no case $set_asm in @@ -366,7 +369,7 @@ arm32) no) ;; *) - AC_MSG_ERROR([invalid assembly optimizations]) + AC_MSG_ERROR([invalid assembly selection]) ;; esac @@ -444,78 +447,97 @@ SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS" ### Handle module options ### -# Besides testing whether modules are enabled, the following code also enables -# module dependencies. The order of the tests matters: the dependency must be -# tested first. +# Processing must be done in a reverse topological sorting of the dependency graph +# (dependent module first). +if test x"$enable_module_schnorrsig_halfagg" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG_HALFAGG=1" + enable_module_schnorrsig=yes +fi -if test x"$enable_module_ecdh" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1" +if test x"$enable_module_bppp" = x"yes"; then + if test x"$enable_module_generator" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the generator module explicitly, but it is required by the bppp module.]) + fi + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_BPPP=1" + enable_module_generator=yes +fi + +if test x"$enable_module_ecdsa_s2c" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDSA_S2C=1" +fi + +if test x"$enable_module_ecdsa_adaptor" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDSA_ADAPTOR=1" fi if test x"$enable_module_musig" = x"yes"; then + if test x"$enable_module_schnorrsig" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.]) + fi SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_MUSIG=1" enable_module_schnorrsig=yes fi -if test x"$enable_module_recovery" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1" -fi - if test x"$enable_module_whitelist" = x"yes"; then + if test x"$enable_module_rangeproof" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the rangeproof module explicitly, but it is required by the whitelist module.]) + fi SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_WHITELIST=1" enable_module_rangeproof=yes fi if test x"$enable_module_surjectionproof" = x"yes"; then + if test x"$enable_module_rangeproof" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the rangeproof module explicitly, but it is required by the surjectionproof module.]) + fi SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SURJECTIONPROOF=1" enable_module_rangeproof=yes fi if test x"$enable_module_rangeproof" = x"yes"; then + if test x"$enable_module_generator" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the generator module explicitly, but it is required by the rangeproof module.]) + fi SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RANGEPROOF=1" enable_module_generator=yes fi -if test x"$enable_module_bppp" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_BPPP=1" - enable_module_generator=yes -fi - if test x"$enable_module_generator" = x"yes"; then SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_GENERATOR=1" fi -if test x"$enable_module_schnorrsig" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1" - enable_module_extrakeys=yes -fi - if test x"$enable_module_ellswift" = x"yes"; then SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1" fi -# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig -# module to set enable_module_extrakeys=yes +if test x"$enable_module_schnorrsig" = x"yes"; then + if test x"$enable_module_extrakeys" = x"no"; then + AC_MSG_ERROR([Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.]) + fi + enable_module_extrakeys=yes + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1" +fi + if test x"$enable_module_extrakeys" = x"yes"; then SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=1" fi -if test x"$enable_module_ecdsa_s2c" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDSA_S2C=1" +if test x"$enable_module_recovery" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1" +fi + +if test x"$enable_module_ecdh" = x"yes"; then + SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1" fi if test x"$enable_external_default_callbacks" = x"yes"; then SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1" fi -if test x"$use_reduced_surjection_proof_size" = x"yes"; then +if test x"$enable_reduced_surjection_proof_size" = x"yes"; then SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_REDUCED_SURJECTION_PROOF_SIZE=1" fi -if test x"$enable_module_ecdsa_adaptor" = x"yes"; then - SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDSA_ADAPTOR=1" -fi - ### ### Check for --enable-experimental if necessary ### @@ -530,9 +552,21 @@ else # module (which automatically enables the module dependencies) we want to # print an error for the dependent module, not the module dependency. Hence, # we first test dependent modules. + if test x"$enable_module_schnorrsig_halfagg" = x"yes"; then + AC_MSG_ERROR([Schnorrsig Half-Aggregation module is experimental. Use --enable-experimental to allow.]) + fi if test x"$enable_module_bppp" = x"yes"; then AC_MSG_ERROR([Bulletproofs++ module is experimental. Use --enable-experimental to allow.]) fi + if test x"$enable_module_ecdsa_adaptor" = x"yes"; then + AC_MSG_ERROR([ecdsa adaptor signatures module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$enable_module_ecdsa_s2c" = x"yes"; then + AC_MSG_ERROR([ECDSA sign-to-contract module module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$enable_module_musig" = x"yes"; then + AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.]) + fi if test x"$enable_module_whitelist" = x"yes"; then AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.]) fi @@ -545,17 +579,8 @@ else if test x"$enable_module_generator" = x"yes"; then AC_MSG_ERROR([NUMS generator module is experimental. Use --enable-experimental to allow.]) fi - if test x"$enable_module_musig" = x"yes"; then - AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$enable_module_ecdsa_s2c" = x"yes"; then - AC_MSG_ERROR([ECDSA sign-to-contract module module is experimental. Use --enable-experimental to allow.]) - fi - if test x"$enable_module_ecdsa_adaptor" = x"yes"; then - AC_MSG_ERROR([ecdsa adaptor signatures module is experimental. Use --enable-experimental to allow.]) - fi if test x"$set_asm" = x"arm32"; then - AC_MSG_ERROR([ARM32 assembly optimization is experimental. Use --enable-experimental to allow.]) + AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.]) fi fi @@ -572,19 +597,20 @@ AM_CONDITIONAL([USE_CTIME_TESTS], [test x"$enable_ctime_tests" = x"yes"]) AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_BPPP], [test x"$enable_module_bppp" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDSA_S2C], [test x"$enable_module_ecdsa_s2c" = x"yes"]) AM_CONDITIONAL([ENABLE_MODULE_ECDSA_ADAPTOR], [test x"$enable_module_ecdsa_adaptor" = x"yes"]) -AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_BPPP], [test x"$enable_module_bppp" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG_HALFAGG], [test x"$enable_module_schnorrsig_halfagg" = x"yes"]) AM_CONDITIONAL([USE_REDUCED_SURJECTION_PROOF_SIZE], [test x"$use_reduced_surjection_proof_size" = x"yes"]) AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"]) AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"]) @@ -595,6 +621,10 @@ AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE) AC_OUTPUT +# The order in which all modules are listed here should be considered the +# canonical order. This order (or, when appropriate, its reserve) should be used +# everywhere we list or process modules, i.e., here and in other build system +# files and docs. echo echo "Build Options:" echo " with external callbacks = $enable_external_default_callbacks" @@ -608,26 +638,31 @@ echo " module recovery = $enable_module_recovery" echo " module extrakeys = $enable_module_extrakeys" echo " module schnorrsig = $enable_module_schnorrsig" echo " module ellswift = $enable_module_ellswift" +# libsecp256k1-zkp modules, in the order they were added to the libsecp256k1-zkp echo " module generator = $enable_module_generator" echo " module rangeproof = $enable_module_rangeproof" echo " module surjectionproof = $enable_module_surjectionproof" +if test x"$enable_module_surjectionproof" = x"yes" && test x"$enable_reduced_surjection_proof_size" = x"yes"; then +echo " reduced proof size = $enable_reduced_surjection_proof_size" +fi echo " module whitelist = $enable_module_whitelist" echo " module musig = $enable_module_musig" echo " module ecdsa-s2c = $enable_module_ecdsa_s2c" echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor" echo " module bppp = $enable_module_bppp" +echo " module schnorrsig-halfagg = $enable_module_schnorrsig_halfagg" echo -echo " asm = $set_asm" -echo " ecmult window size = $set_ecmult_window" -echo " ecmult gen prec. bits = $set_ecmult_gen_precision" +echo " asm = $set_asm" +echo " ecmult window size = $set_ecmult_window" +echo " ecmult gen prec. bits = $set_ecmult_gen_precision" # Hide test-only options unless they're used. if test x"$set_widemul" != xauto; then -echo " wide multiplication = $set_widemul" +echo " wide multiplication = $set_widemul" fi echo -echo " valgrind = $enable_valgrind" -echo " CC = $CC" -echo " CPPFLAGS = $CPPFLAGS" -echo " SECP_CFLAGS = $SECP_CFLAGS" -echo " CFLAGS = $CFLAGS" -echo " LDFLAGS = $LDFLAGS" +echo " valgrind = $enable_valgrind" +echo " CC = $CC" +echo " CPPFLAGS = $CPPFLAGS" +echo " SECP_CFLAGS = $SECP_CFLAGS" +echo " CFLAGS = $CFLAGS" +echo " LDFLAGS = $LDFLAGS" diff --git a/contrib/lax_der_parsing.h b/contrib/lax_der_parsing.h index 034a38e6a0..37c8c691f2 100644 --- a/contrib/lax_der_parsing.h +++ b/contrib/lax_der_parsing.h @@ -67,8 +67,8 @@ extern "C" { * * Returns: 1 when the signature could be parsed, 0 otherwise. * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the signature to be parsed + * Out: sig: pointer to a signature object + * In: input: pointer to the signature to be parsed * inputlen: the length of the array pointed to be input * * This function will accept any valid DER encoded signature, even if the diff --git a/doc/release-process.md b/doc/release-process.md index ea6087c9ff..cdf62430df 100644 --- a/doc/release-process.md +++ b/doc/release-process.md @@ -1,4 +1,4 @@ -# Release Process +# Release process This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`. @@ -14,26 +14,30 @@ This process also assumes that there will be no minor releases for old major rel We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core. -## Sanity Checks -Perform these checks before creating a release: +## Sanity checks +Perform these checks when reviewing the release PR (see below): 1. Ensure `make distcheck` doesn't fail. -```shell -./autogen.sh && ./configure --enable-dev-mode && make distcheck -``` + ```shell + ./autogen.sh && ./configure --enable-dev-mode && make distcheck + ``` 2. Check installation with autotools: -```shell -dir=$(mktemp -d) -./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -l $dir/include $dir/lib -gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa -``` + ```shell + dir=$(mktemp -d) + ./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -RlAh $dir + gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa + ``` 3. Check installation with CMake: -```shell -dir=$(mktemp -d) -build=$(mktemp -d) -cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -l $dir/include $dir/lib* -gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa -``` + ```shell + dir=$(mktemp -d) + build=$(mktemp -d) + cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -RlAh $dir + gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa + ``` +4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to verify that there are no unexpected ABI incompatibilities and that the version number and the release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required. + ```shell + tools/check-abi.sh + ``` ## Regular release @@ -41,28 +45,30 @@ gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rp * finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by * adding a section for the release (make sure that the version number is a link to a diff between the previous and new version), * removing the `[Unreleased]` section header, and - * including an entry for `### ABI Compatibility` if it doesn't exist that mentions the library soname of the release, - * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and - * if this is not a patch release - * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac` and + * including an entry for `### ABI Compatibility` if it doesn't exist, + * sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and, + * if this is not a patch release, + * updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac`, and * updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`. -2. After the PR is merged, tag the commit and push it: +2. Perform the [sanity checks](#sanity-checks) on the PR branch. +3. After the PR is merged, tag the commit, and push the tag: ``` RELEASE_COMMIT= git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH ``` -3. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that +4. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that * sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`, * increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and * adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md). If other maintainers are not present to approve the PR, it can be merged without ACKs. -4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). +5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). +6. Send an announcement email to the bitcoin-dev mailing list. ## Maintenance release -Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists. +Note that bug fixes need to be backported only to releases for which no compatible release without the bug exists. 1. If there's no maintenance branch `$MAJOR.$MINOR`, create one: ``` @@ -70,19 +76,18 @@ Note that bugfixes only need to be backported to releases for which no compatibl git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR ``` 2. Open a pull request to the `$MAJOR.$MINOR` branch that - * includes the bugfixes, + * includes the bug fixes, * finalizes the release notes similar to a regular release, * increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac` and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt` (with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example). -3. After the PRs are merged, update the release branch and tag the commit: +3. Perform the [sanity checks](#sanity-checks) on the PR branch. +4. After the PRs are merged, update the release branch, tag the commit, and push the tag: ``` git checkout $MAJOR.$MINOR && git pull git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" - ``` -4. Push tag: - ``` git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH ``` -5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). -6. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md). +6. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). +7. Send an announcement email to the bitcoin-dev mailing list. +8. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md). diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e2ea473008..607bb67770 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,24 +1,30 @@ -add_library(example INTERFACE) -target_include_directories(example INTERFACE - ${PROJECT_SOURCE_DIR}/include -) -target_link_libraries(example INTERFACE - secp256k1 - $<$:bcrypt> -) +function(add_example name) + set(target_name ${name}_example) + add_executable(${target_name} ${name}.c) + target_include_directories(${target_name} PRIVATE + ${PROJECT_SOURCE_DIR}/include + ) + target_link_libraries(${target_name} + secp256k1 + $<$:bcrypt> + ) + set(test_name ${name}_example) + add_test(NAME ${test_name} COMMAND ${target_name}) + if(BUILD_SHARED_LIBS AND MSVC) + # The DLL must reside either in the same folder where the executable is + # or somewhere in PATH. Using the latter option. + set_tests_properties(${test_name} PROPERTIES + ENVIRONMENT "PATH=$;$ENV{PATH}" + ) + endif() +endfunction() -add_executable(ecdsa_example ecdsa.c) -target_link_libraries(ecdsa_example example) -add_test(NAME ecdsa_example COMMAND ecdsa_example) +add_example(ecdsa) if(SECP256K1_ENABLE_MODULE_ECDH) - add_executable(ecdh_example ecdh.c) - target_link_libraries(ecdh_example example) - add_test(NAME ecdh_example COMMAND ecdh_example) + add_example(ecdh) endif() if(SECP256K1_ENABLE_MODULE_SCHNORRSIG) - add_executable(schnorr_example schnorr.c) - target_link_libraries(schnorr_example example) - add_test(NAME schnorr_example COMMAND schnorr_example) + add_example(schnorr) endif() diff --git a/include/secp256k1.h b/include/secp256k1.h index 936f0b42b7..f4053f2a93 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -265,7 +265,7 @@ SECP256K1_API void secp256k1_selftest(void); * memory allocation entirely, see secp256k1_context_static and the functions in * secp256k1_preallocated.h. * - * Returns: a newly created context object. + * Returns: pointer to a newly created context object. * In: flags: Always set to SECP256K1_CONTEXT_NONE (see below). * * The only valid non-deprecated flag in recent library versions is @@ -296,8 +296,8 @@ SECP256K1_API secp256k1_context *secp256k1_context_create( * Cloning secp256k1_context_static is not possible, and should not be emulated by * the caller (e.g., using memcpy). Create a new context instead. * - * Returns: a newly created context object. - * Args: ctx: an existing context to copy (not secp256k1_context_static) + * Returns: pointer to a newly created context object. + * Args: ctx: pointer to a context to copy (not secp256k1_context_static). */ SECP256K1_API secp256k1_context *secp256k1_context_clone( const secp256k1_context *ctx @@ -313,7 +313,7 @@ SECP256K1_API secp256k1_context *secp256k1_context_clone( * behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must * be used instead. * - * Args: ctx: an existing context to destroy, constructed using + * Args: ctx: pointer to a context to destroy, constructed using * secp256k1_context_create or secp256k1_context_clone * (i.e., not secp256k1_context_static). */ @@ -350,8 +350,8 @@ SECP256K1_API void secp256k1_context_destroy( * fails. In this case, the corresponding default handler will be called with * the data pointer argument set to NULL. * - * Args: ctx: an existing context object. - * In: fun: a pointer to a function to call when an illegal argument is + * Args: ctx: pointer to a context object. + * In: fun: pointer to a function to call when an illegal argument is * passed to the API, taking a message and an opaque pointer. * (NULL restores the default handler.) * data: the opaque pointer to pass to fun above, must be NULL for the default handler. @@ -377,8 +377,8 @@ SECP256K1_API void secp256k1_context_set_illegal_callback( * for that). After this callback returns, anything may happen, including * crashing. * - * Args: ctx: an existing context object. - * In: fun: a pointer to a function to call when an internal error occurs, + * Args: ctx: pointer to a context object. + * In: fun: pointer to a function to call when an internal error occurs, * taking a message and an opaque pointer (NULL restores the * default handler, see secp256k1_context_set_illegal_callback * for details). @@ -395,7 +395,7 @@ SECP256K1_API void secp256k1_context_set_error_callback( /** Create a secp256k1 scratch space object. * * Returns: a newly created scratch space. - * Args: ctx: an existing context object. + * Args: ctx: pointer to a context object. * In: size: amount of memory to be available as scratch space. Some extra * (<100 bytes) will be allocated for extra accounting. */ @@ -407,7 +407,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_sc /** Destroy a secp256k1 scratch space. * * The pointer may not be used afterwards. - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object. * scratch: space to destroy */ SECP256K1_API void secp256k1_scratch_space_destroy( @@ -419,7 +419,7 @@ SECP256K1_API void secp256k1_scratch_space_destroy( * * Returns: 1 if the public key was fully valid. * 0 if the public key could not be parsed or is invalid. - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object. * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a * parsed version of input. If not, its value is undefined. * In: input: pointer to a serialized public key @@ -439,14 +439,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( /** Serialize a pubkey object into a serialized byte sequence. * * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * Args: ctx: pointer to a context object. + * Out: output: pointer to a 65-byte (if compressed==0) or 33-byte (if * compressed==1) byte array to place the serialized key * in. - * In/Out: outputlen: a pointer to an integer which is initially set to the + * In/Out: outputlen: pointer to an integer which is initially set to the * size of output, and is overwritten with the written * size. - * In: pubkey: a pointer to a secp256k1_pubkey containing an + * In: pubkey: pointer to a secp256k1_pubkey containing an * initialized public key. * flags: SECP256K1_EC_COMPRESSED if serialization should be in * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. @@ -464,7 +464,7 @@ SECP256K1_API int secp256k1_ec_pubkey_serialize( * Returns: <0 if the first public key is less than the second * >0 if the first public key is greater than the second * 0 if the two public keys are equal - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object * In: pubkey1: first public key to compare * pubkey2: second public key to compare */ @@ -477,9 +477,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp( /** Parse an ECDSA signature in compact (64 bytes) format. * * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input64: a pointer to the 64-byte array to parse + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input64: pointer to the 64-byte array to parse * * The signature must consist of a 32-byte big endian R value, followed by a * 32-byte big endian S value. If R or S fall outside of [0..order-1], the @@ -498,9 +498,9 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( /** Parse a DER ECDSA signature. * * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the signature to be parsed + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input: pointer to the signature to be parsed * inputlen: the length of the array pointed to be input * * This function will accept any valid DER encoded signature, even if the @@ -520,13 +520,13 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_der( /** Serialize an ECDSA signature in DER format. * * Returns: 1 if enough space was available to serialize, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: output: a pointer to an array to store the DER serialization - * In/Out: outputlen: a pointer to a length integer. Initially, this integer + * Args: ctx: pointer to a context object + * Out: output: pointer to an array to store the DER serialization + * In/Out: outputlen: pointer to a length integer. Initially, this integer * should be set to the length of output. After the call * it will be set to the length of the serialization (even * if 0 was returned). - * In: sig: a pointer to an initialized signature object + * In: sig: pointer to an initialized signature object */ SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( const secp256k1_context *ctx, @@ -538,9 +538,9 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( /** Serialize an ECDSA signature in compact (64 byte) format. * * Returns: 1 - * Args: ctx: a secp256k1 context object - * Out: output64: a pointer to a 64-byte array to store the compact serialization - * In: sig: a pointer to an initialized signature object + * Args: ctx: pointer to a context object + * Out: output64: pointer to a 64-byte array to store the compact serialization + * In: sig: pointer to an initialized signature object * * See secp256k1_ecdsa_signature_parse_compact for details about the encoding. */ @@ -554,7 +554,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( * * Returns: 1: correct signature * 0: incorrect or unparseable signature - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object * In: sig: the signature being verified. * msghash32: the 32-byte message hash being verified. * The verifier must make sure to apply a cryptographic @@ -585,12 +585,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( /** Convert a signature to a normalized lower-S form. * * Returns: 1 if sigin was not normalized, 0 if it already was. - * Args: ctx: a secp256k1 context object - * Out: sigout: a pointer to a signature to fill with the normalized form, + * Args: ctx: pointer to a context object + * Out: sigout: pointer to a signature to fill with the normalized form, * or copy if the input was already normalized. (can be NULL if * you're only interested in whether the input was already * normalized). - * In: sigin: a pointer to a signature to check/normalize (can be identical to sigout) + * In: sigin: pointer to a signature to check/normalize (can be identical to sigout) * * With ECDSA a third-party can forge a second distinct signature of the same * message, given a single initial signature, but without knowing the key. This diff --git a/include/secp256k1_ecdh.h b/include/secp256k1_ecdh.h index 515e174299..4d9da3461d 100644 --- a/include/secp256k1_ecdh.h +++ b/include/secp256k1_ecdh.h @@ -39,7 +39,7 @@ SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_de * 0: scalar was invalid (zero or overflow) or hashfp returned 0 * Args: ctx: pointer to a context object. * Out: output: pointer to an array to be filled by hashfp. - * In: pubkey: a pointer to a secp256k1_pubkey containing an initialized public key. + * In: pubkey: pointer to a secp256k1_pubkey containing an initialized public key. * seckey: a 32-byte scalar with which to multiply the point. * hashfp: pointer to a hash function. If NULL, * secp256k1_ecdh_hash_function_sha256 is used diff --git a/include/secp256k1_ecdsa_adaptor.h b/include/secp256k1_ecdsa_adaptor.h index 225caa73f3..e50f94e928 100644 --- a/include/secp256k1_ecdsa_adaptor.h +++ b/include/secp256k1_ecdsa_adaptor.h @@ -71,7 +71,7 @@ SECP256K1_API const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_no * this file and applied the suggested countermeasures. * * Returns: 1 on success, 0 on failure - * Args: ctx: a secp256k1 context object (not secp256k1_context_static) + * Args: ctx: pointer to a context object (not secp256k1_context_static) * Out: adaptor_sig162: pointer to 162 byte to store the returned signature * In: seckey32: pointer to 32 byte secret key that will be used for * signing @@ -101,7 +101,7 @@ SECP256K1_API int secp256k1_ecdsa_adaptor_encrypt( * and the completed ECDSA signature. * * Returns: 1 on success, 0 on failure - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * In: adaptor_sig162: pointer to 162-byte signature to verify * pubkey: pointer to the public key corresponding to the secret key * used for signing @@ -121,7 +121,7 @@ SECP256K1_API int secp256k1_ecdsa_adaptor_verify( * Derives an ECDSA signature from an adaptor signature and an adaptor decryption key. * * Returns: 1 on success, 0 on failure - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * Out: sig: pointer to the ECDSA signature to create * In: deckey32: pointer to 32-byte decryption secret key for the adaptor * encryption public key @@ -140,7 +140,7 @@ SECP256K1_API int secp256k1_ecdsa_adaptor_decrypt( * signature. * * Returns: 1 on success, 0 on failure - * Args: ctx: a secp256k1 context object (not secp256k1_context_static) + * Args: ctx: pointer to a context object (not secp256k1_context_static) * Out: deckey32: pointer to 32-byte adaptor decryption key for the adaptor * encryption public key * In: sig: pointer to ECDSA signature to recover the adaptor decryption diff --git a/include/secp256k1_ecdsa_s2c.h b/include/secp256k1_ecdsa_s2c.h index 02b5051393..ea4219feb5 100644 --- a/include/secp256k1_ecdsa_s2c.h +++ b/include/secp256k1_ecdsa_s2c.h @@ -33,7 +33,7 @@ typedef struct { * * Returns: 1 if the opening could be parsed * 0 if the opening could not be parsed - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object * Out: opening: pointer to an opening object. If 1 is returned, it is set to a * parsed version of input. If not, its value is unspecified. * In: input33: pointer to 33-byte array with a serialized opening @@ -49,9 +49,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_parse * * Returns: 1 if the opening was successfully serialized. * 0 if the opening could not be serialized - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * Out: output33: pointer to a 33-byte array to place the serialized opening in - * In: opening: a pointer to an initialized `secp256k1_ecdsa_s2c_opening` + * In: opening: pointer to an initialized `secp256k1_ecdsa_s2c_opening` */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_serialize( const secp256k1_context *ctx, @@ -63,9 +63,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_seria * * Returns: 1: signature created * 0: the nonce generation function failed, or the private key was invalid. - * Args: ctx: pointer to a context object (not secp256k1_context_static) - * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * s2c_opening: if non-NULL, pointer to an secp256k1_ecdsa_s2c_opening structure to populate + * Args: ctx: pointer to a context object (not secp256k1_context_static) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * s2c_opening: if non-NULL, pointer to an secp256k1_ecdsa_s2c_opening structure to populate * In: msg32: the 32-byte message hash being signed (cannot be NULL) * seckey: pointer to a 32-byte secret key (cannot be NULL) * s2c_data32: pointer to a 32-byte data to commit to in the nonce (cannot be NULL) @@ -84,7 +84,7 @@ SECP256K1_API int secp256k1_ecdsa_s2c_sign( * Returns: 1: the signature contains a commitment to data32 (though it does * not necessarily need to be a valid siganture!) * 0: incorrect opening - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * In: sig: the signature containing the sign-to-contract commitment (cannot be NULL) * data32: the 32-byte data that was committed to (cannot be NULL) * opening: pointer to the opening created during signing (cannot be NULL) @@ -193,8 +193,8 @@ SECP256K1_API int secp256k1_ecdsa_anti_exfil_signer_commit( * * Returns: 1: signature created * 0: the nonce generation function failed, or the private key was invalid. - * Args: ctx: pointer to a context object (not secp256k1_context_static) - * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * Args: ctx: pointer to a context object (not secp256k1_context_static) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) * In: msg32: the 32-byte message hash being signed (cannot be NULL) * seckey: pointer to a 32-byte secret key (cannot be NULL) * host_data32: pointer to 32-byte host-provided randomness (cannot be NULL) @@ -211,7 +211,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_anti_exfil_sign( * * Returns: 1: the signature is valid and contains a commitment to host_data32 * 0: incorrect opening - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * In: sig: the signature produced by the signer (cannot be NULL) * msghash32: the 32-byte message hash being verified (cannot be NULL) * pubkey: pointer to the signer's public key (cannot be NULL) diff --git a/include/secp256k1_ellswift.h b/include/secp256k1_ellswift.h index f79bd88396..ae37287f82 100644 --- a/include/secp256k1_ellswift.h +++ b/include/secp256k1_ellswift.h @@ -87,7 +87,7 @@ SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_ * Returns: 1 always. * Args: ctx: pointer to a context object * Out: ell64: pointer to a 64-byte array to be filled - * In: pubkey: a pointer to a secp256k1_pubkey containing an + * In: pubkey: pointer to a secp256k1_pubkey containing an * initialized public key * rnd32: pointer to 32 bytes of randomness * @@ -169,7 +169,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create( * (will not be NULL) * ell_b64: pointer to the 64-byte encoded public key of party B * (will not be NULL) - * seckey32: a pointer to our 32-byte secret key + * seckey32: pointer to our 32-byte secret key * party: boolean indicating which party we are: zero if we are * party A, non-zero if we are party B. seckey32 must be * the private key corresponding to that party's ell_?64. diff --git a/include/secp256k1_extrakeys.h b/include/secp256k1_extrakeys.h index e5fddf56b4..9f0911634a 100644 --- a/include/secp256k1_extrakeys.h +++ b/include/secp256k1_extrakeys.h @@ -39,7 +39,7 @@ typedef struct { * Returns: 1 if the public key was fully valid. * 0 if the public key could not be parsed or is invalid. * - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object. * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a * parsed version of input. If not, it's set to an invalid value. * In: input32: pointer to a serialized xonly_pubkey. @@ -54,9 +54,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse( * * Returns: 1 always. * - * Args: ctx: a secp256k1 context object. - * Out: output32: a pointer to a 32-byte array to place the serialized key in. - * In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an initialized public key. + * Args: ctx: pointer to a context object. + * Out: output32: pointer to a 32-byte array to place the serialized key in. + * In: pubkey: pointer to a secp256k1_xonly_pubkey containing an initialized public key. */ SECP256K1_API int secp256k1_xonly_pubkey_serialize( const secp256k1_context *ctx, @@ -69,7 +69,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_serialize( * Returns: <0 if the first public key is less than the second * >0 if the first public key is greater than the second * 0 if the two public keys are equal - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object. * In: pubkey1: first public key to compare * pubkey2: second public key to compare */ @@ -240,22 +240,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add const unsigned char *tweak32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Compare two public keys using lexicographic order of their compressed - * serialization. - * - * Returns: <0 if the first public key is less than the second - * >0 if the first public key is greater than the second - * 0 if the two public keys are equal - * Args: ctx: a secp256k1 context object. - * In: pubkey1: first public key to compare - * pubkey2: second public key to compare - */ -SECP256K1_API int secp256k1_pubkey_cmp( - const secp256k1_context *ctx, - const secp256k1_pubkey *pk1, - const secp256k1_pubkey *pk2 -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); - /** Sort public keys using lexicographic order of their compressed * serialization. * diff --git a/include/secp256k1_generator.h b/include/secp256k1_generator.h index eacefad85a..0a59c36364 100644 --- a/include/secp256k1_generator.h +++ b/include/secp256k1_generator.h @@ -29,7 +29,7 @@ SECP256K1_API const secp256k1_generator *secp256k1_generator_h; /** Parse a 33-byte generator byte sequence into a generator object. * * Returns: 1 if input contains a valid generator. - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object * Out: gen: pointer to the output generator object * In: input: pointer to a 33-byte serialized generator */ @@ -42,9 +42,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_parse( /** Serialize a 33-byte generator into a serialized byte sequence. * * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 33-byte byte array - * In: gen: a pointer to a generator + * Args: ctx: pointer to a context object + * Out: output: pointer to a 33-byte byte array + * In: gen: pointer to a generator object */ SECP256K1_API int secp256k1_generator_serialize( const secp256k1_context *ctx, @@ -56,9 +56,9 @@ SECP256K1_API int secp256k1_generator_serialize( * * Returns: 0 in the highly unlikely case the seed is not acceptable, * 1 otherwise. - * Args: ctx: a secp256k1 context object - * Out: gen: a generator object - * In: seed32: a 32-byte seed + * Args: ctx: pointer to a context object + * Out: gen: pointer to a the new generator object + * In: seed32: 32-byte seed * * If successful a valid generator will be placed in gen. The produced * generators are distributed uniformly over the curve, and will not have a @@ -75,10 +75,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate( * * Returns: 0 in the highly unlikely case the seed is not acceptable or when * blind is out of range. 1 otherwise. - * Args: ctx: a secp256k1 context object (not secp256k1_context_static) - * Out: gen: a generator object - * In: seed32: a 32-byte seed - * blind32: a 32-byte secret value to blind the generator with. + * Args: ctx: pointer to a context object (not secp256k1_context_static) + * Out: gen: pointer to a generator object + * In: seed32: 32-byte seed + * blind32: 32-byte secret value to blind the generator with. * * The result is equivalent to first calling secp256k1_generator_generate, * converting the result to a public key, calling secp256k1_ec_pubkey_tweak_add, @@ -107,7 +107,7 @@ typedef struct { /** Parse a 33-byte commitment into a commitment object. * * Returns: 1 if input contains a valid commitment. - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object * Out: commit: pointer to the output commitment object * In: input: pointer to a 33-byte serialized commitment key */ @@ -120,9 +120,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_par /** Serialize a commitment object into a serialized byte sequence. * * Returns: 1 always. - * Args: ctx: a secp256k1 context object. - * Out: output: a pointer to a 33-byte byte array - * In: commit: a pointer to a secp256k1_pedersen_commitment containing an + * Args: ctx: pointer to a context object + * Out: output: pointer to a 33-byte byte array + * In: commit: pointer to a secp256k1_pedersen_commitment containing an * initialized commitment */ SECP256K1_API int secp256k1_pedersen_commitment_serialize( diff --git a/include/secp256k1_musig.h b/include/secp256k1_musig.h index a064ed33d1..28ecf1efc7 100644 --- a/include/secp256k1_musig.h +++ b/include/secp256k1_musig.h @@ -103,7 +103,7 @@ typedef struct { /** Parse a signer's public nonce. * * Returns: 1 when the nonce could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * Out: nonce: pointer to a nonce object * In: in66: pointer to the 66-byte nonce to be parsed */ @@ -116,7 +116,7 @@ SECP256K1_API int secp256k1_musig_pubnonce_parse( /** Serialize a signer's public nonce * * Returns: 1 when the nonce could be serialized, 0 otherwise - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * Out: out66: pointer to a 66-byte array to store the serialized nonce * In: nonce: pointer to the nonce */ @@ -129,7 +129,7 @@ SECP256K1_API int secp256k1_musig_pubnonce_serialize( /** Parse an aggregate public nonce. * * Returns: 1 when the nonce could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * Out: nonce: pointer to a nonce object * In: in66: pointer to the 66-byte nonce to be parsed */ @@ -142,7 +142,7 @@ SECP256K1_API int secp256k1_musig_aggnonce_parse( /** Serialize an aggregate public nonce * * Returns: 1 when the nonce could be serialized, 0 otherwise - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * Out: out66: pointer to a 66-byte array to store the serialized nonce * In: nonce: pointer to the nonce */ @@ -155,7 +155,7 @@ SECP256K1_API int secp256k1_musig_aggnonce_serialize( /** Serialize a MuSig partial signature * * Returns: 1 when the signature could be serialized, 0 otherwise - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * Out: out32: pointer to a 32-byte array to store the serialized signature * In: sig: pointer to the signature */ @@ -168,7 +168,7 @@ SECP256K1_API int secp256k1_musig_partial_sig_serialize( /** Parse a MuSig partial signature. * * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object + * Args: ctx: pointer to a context object * Out: sig: pointer to a signature object * In: in32: pointer to the 32-byte signature to be parsed * @@ -234,7 +234,7 @@ SECP256K1_API int secp256k1_musig_pubkey_agg( SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get( const secp256k1_context *ctx, secp256k1_pubkey *agg_pk, - secp256k1_musig_keyagg_cache *keyagg_cache + const secp256k1_musig_keyagg_cache *keyagg_cache ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Apply plain "EC" tweaking to a public key in a given keyagg_cache by diff --git a/include/secp256k1_preallocated.h b/include/secp256k1_preallocated.h index f37744777b..f2d95c245e 100644 --- a/include/secp256k1_preallocated.h +++ b/include/secp256k1_preallocated.h @@ -52,8 +52,8 @@ SECP256K1_API size_t secp256k1_context_preallocated_size( * in the memory. In simpler words, the prealloc pointer (or any pointer derived * from it) should not be used during the lifetime of the context object. * - * Returns: a newly created context object. - * In: prealloc: a pointer to a rewritable contiguous block of memory of + * Returns: pointer to newly created context object. + * In: prealloc: pointer to a rewritable contiguous block of memory of * size at least secp256k1_context_preallocated_size(flags) * bytes, as detailed above. * flags: which parts of the context to initialize. @@ -72,7 +72,7 @@ SECP256K1_API secp256k1_context *secp256k1_context_preallocated_create( * caller-provided memory. * * Returns: the required size of the caller-provided memory block. - * In: ctx: an existing context to copy. + * In: ctx: pointer to a context to copy. */ SECP256K1_API size_t secp256k1_context_preallocated_clone_size( const secp256k1_context *ctx @@ -91,9 +91,9 @@ SECP256K1_API size_t secp256k1_context_preallocated_clone_size( * Cloning secp256k1_context_static is not possible, and should not be emulated by * the caller (e.g., using memcpy). Create a new context instead. * - * Returns: a newly created context object. - * Args: ctx: an existing context to copy (not secp256k1_context_static). - * In: prealloc: a pointer to a rewritable contiguous block of memory of + * Returns: pointer to a newly created context object. + * Args: ctx: pointer to a context to copy (not secp256k1_context_static). + * In: prealloc: pointer to a rewritable contiguous block of memory of * size at least secp256k1_context_preallocated_size(flags) * bytes, as detailed above. */ @@ -118,7 +118,7 @@ SECP256K1_API secp256k1_context *secp256k1_context_preallocated_clone( * preallocated pointer given to secp256k1_context_preallocated_create or * secp256k1_context_preallocated_clone. * - * Args: ctx: an existing context to destroy, constructed using + * Args: ctx: pointer to a context to destroy, constructed using * secp256k1_context_preallocated_create or * secp256k1_context_preallocated_clone * (i.e., not secp256k1_context_static). diff --git a/include/secp256k1_recovery.h b/include/secp256k1_recovery.h index b12ca4d972..341b8bac63 100644 --- a/include/secp256k1_recovery.h +++ b/include/secp256k1_recovery.h @@ -28,9 +28,9 @@ typedef struct { /** Parse a compact ECDSA signature (64 bytes + recovery id). * * Returns: 1 when the signature could be parsed, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input64: a pointer to a 64-byte compact signature + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input64: pointer to a 64-byte compact signature * recid: the recovery id (0, 1, 2 or 3) */ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( @@ -43,9 +43,9 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( /** Convert a recoverable signature into a normal signature. * * Returns: 1 - * Args: ctx: a secp256k1 context object. - * Out: sig: a pointer to a normal signature. - * In: sigin: a pointer to a recoverable signature. + * Args: ctx: pointer to a context object. + * Out: sig: pointer to a normal signature. + * In: sigin: pointer to a recoverable signature. */ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( const secp256k1_context *ctx, @@ -56,10 +56,10 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( /** Serialize an ECDSA signature in compact format (64 bytes + recovery id). * * Returns: 1 - * Args: ctx: a secp256k1 context object. - * Out: output64: a pointer to a 64-byte array of the compact signature. - * recid: a pointer to an integer to hold the recovery id. - * In: sig: a pointer to an initialized signature object. + * Args: ctx: pointer to a context object. + * Out: output64: pointer to a 64-byte array of the compact signature. + * recid: pointer to an integer to hold the recovery id. + * In: sig: pointer to an initialized signature object. */ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( const secp256k1_context *ctx, diff --git a/include/secp256k1_schnorrsig.h b/include/secp256k1_schnorrsig.h index 26358533f6..23163de2fb 100644 --- a/include/secp256k1_schnorrsig.h +++ b/include/secp256k1_schnorrsig.h @@ -169,11 +169,11 @@ SECP256K1_API int secp256k1_schnorrsig_sign_custom( * * Returns: 1: correct signature * 0: incorrect signature - * Args: ctx: a secp256k1 context object. + * Args: ctx: pointer to a context object. * In: sig64: pointer to the 64-byte signature to verify. * msg: the message being verified. Can only be NULL if msglen is 0. * msglen: length of the message - * pubkey: pointer to an x-only public key to verify with (cannot be NULL) + * pubkey: pointer to an x-only public key to verify with */ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify( const secp256k1_context *ctx, diff --git a/include/secp256k1_schnorrsig_halfagg.h b/include/secp256k1_schnorrsig_halfagg.h new file mode 100644 index 0000000000..39eb508068 --- /dev/null +++ b/include/secp256k1_schnorrsig_halfagg.h @@ -0,0 +1,107 @@ +#ifndef SECP256K1_SCHNORRSIG_HALFAGG_H +#define SECP256K1_SCHNORRSIG_HALFAGG_H + +#include "secp256k1.h" +#include "secp256k1_extrakeys.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Incrementally (Half-)Aggregate a sequence of Schnorr + * signatures to an existing half-aggregate signature. + * + * Returns 1 on success, 0 on failure. + * Args: ctx: a secp256k1 context object. + * In/Out: aggsig: pointer to the serialized aggregate signature + * that is input. The first 32*(n_before+1) of this + * array should hold the input aggsig. It will be + * overwritten by the new serialized aggregate signature. + * It should be large enough for that, see aggsig_len. + * aggsig_len: size of aggsig array in bytes. + * Should be large enough to hold the new + * serialized aggregate signature, i.e., + * should satisfy aggsig_size >= 32*(n_before+n_new+1). + * It will be overwritten to be the exact size of the + * resulting aggsig. + * In: all_pubkeys: Array of (n_before + n_new) many x-only public keys, + * including both the ones for the already aggregated signature + * and the ones for the signatures that should be added. + * Can only be NULL if n_before + n_new is 0. + * all_msgs32: Array of (n_before + n_new) many 32-byte messages, + * including both the ones for the already aggregated signature + * and the ones for the signatures that should be added. + * Can only be NULL if n_before + n_new is 0. + * new_sigs64: Array of n_new many 64-byte signatures, containing the new + * signatures that should be added. Can only be NULL if n_new is 0. + * n_before: Number of signatures that have already been aggregated + * in the input aggregate signature. + * n_new: Number of signatures that should now be added + * to the aggregate signature. + */ +SECP256K1_API int secp256k1_schnorrsig_inc_aggregate( + const secp256k1_context *ctx, + unsigned char *aggsig, + size_t *aggsig_len, + const secp256k1_xonly_pubkey* all_pubkeys, + const unsigned char *all_msgs32, + const unsigned char *new_sigs64, + size_t n_before, + size_t n_new +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** (Half-)Aggregate a sequence of Schnorr signatures. + * + * Returns 1 on success, 0 on failure. + * Args: ctx: a secp256k1 context object. + * Out: aggsig: pointer to an array of aggsig_len many bytes to + * store the serialized aggregate signature. + * In/Out: aggsig_len: size of the aggsig array that is passed in bytes; + * will be overwritten to be the exact size of aggsig. + * In: pubkeys: Array of n many x-only public keys. + * Can only be NULL if n is 0. + * msgs32: Array of n many 32-byte messages. + * Can only be NULL if n is 0. + * sigs64: Array of n many 64-byte signatures. + * Can only be NULL if n is 0. + * n: number of signatures to be aggregated. + */ +SECP256K1_API int secp256k1_schnorrsig_aggregate( + const secp256k1_context *ctx, + unsigned char *aggsig, + size_t *aggsig_len, + const secp256k1_xonly_pubkey *pubkeys, + const unsigned char *msgs32, + const unsigned char *sigs64, + size_t n +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Verify a (Half-)aggregate Schnorr signature. + * + * Returns: 1: correct signature. + * 0: incorrect signature. + * Args: ctx: a secp256k1 context object. + * In: pubkeys: Array of n many x-only public keys. Can only be NULL if n is 0. + * msgs32: Array of n many 32-byte messages. Can only be NULL if n is 0. + * n: number of signatures to that have been aggregated. + * aggsig: Pointer to an array of aggsig_size many bytes + * containing the serialized aggregate + * signature to be verified. + * aggsig_len: Size of the aggregate signature in bytes. + * Should be aggsig_len = 32*(n+1) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_aggverify( + const secp256k1_context *ctx, + const secp256k1_xonly_pubkey *pubkeys, + const unsigned char *msgs32, + size_t n, + const unsigned char *aggsig, + size_t aggsig_len +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_SCHNORRSIG_HALFAGG_H */ diff --git a/include/secp256k1_surjectionproof.h b/include/secp256k1_surjectionproof.h index 6fee1e6046..c9a4aaee8b 100644 --- a/include/secp256k1_surjectionproof.h +++ b/include/secp256k1_surjectionproof.h @@ -56,9 +56,9 @@ typedef struct { /** Parse a surjection proof * * Returns: 1 when the proof could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: proof: a pointer to a proof object - * In: input: a pointer to the array to parse + * Args: ctx: pointer to a context object + * Out: proof: pointer to a proof object + * In: input: pointer to the array to parse * inputlen: length of the array pointed to by input * * The proof must consist of: @@ -79,12 +79,11 @@ SECP256K1_API int secp256k1_surjectionproof_parse( /** Serialize a surjection proof * * Returns: 1 if enough space was available to serialize, 0 otherwise - * Args: ctx: a secp256k1 context object - * Out: output: a pointer to an array to store the serialization - * In/Out: outputlen: a pointer to an integer which is initially set to the - * size of output, and is overwritten with the written - * size. - * In: proof: a pointer to an initialized proof object + * Args: ctx: pointer to a context object + * Out: output: pointer to an array to store the serialization + * In/Out: outputlen: pointer to an integer which is initially set to the size + * of output, and is overwritten with the written size. + * In: proof: pointer to an initialized proof object * * See secp256k1_surjectionproof_parse for details about the encoding. */ @@ -109,7 +108,7 @@ typedef struct { * * Returns: the number of inputs for the given proof * In: ctx: pointer to a context object - * proof: a pointer to a proof object + * proof: pointer to a proof object */ SECP256K1_API size_t secp256k1_surjectionproof_n_total_inputs( const secp256k1_context *ctx, @@ -120,7 +119,7 @@ SECP256K1_API size_t secp256k1_surjectionproof_n_total_inputs( * * Returns: the number of inputs for the given proof * In: ctx: pointer to a context object - * proof: a pointer to a proof object + * proof: pointer to a proof object */ SECP256K1_API size_t secp256k1_surjectionproof_n_used_inputs( const secp256k1_context *ctx, @@ -131,7 +130,7 @@ SECP256K1_API size_t secp256k1_surjectionproof_n_used_inputs( * * Returns: the total size * In: ctx: pointer to a context object - * proof: a pointer to a proof object + * proof: pointer to a proof object */ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size( const secp256k1_context *ctx, @@ -156,7 +155,7 @@ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size( * limited to 256 the probability of giving up is smaller than * (255/256)^(n_input_tags_to_use*max_n_iterations). * - * random_seed32: a random seed to be used for input selection + * random_seed32: random seed to be used for input selection * Out: proof: The proof whose bitvector will be initialized. In case of failure, * the state of the proof is undefined. * input_index: The index of the actual input that is secretly mapped to the output @@ -179,8 +178,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_initial * n: inputs were selected after n iterations of random selection * * In: ctx: pointer to a context object - * proof_out_p: a pointer to a pointer to `secp256k1_surjectionproof*`. - * the newly-allocated struct pointer will be saved here. + * proof_out_p: pointer to a pointer to `secp256k1_surjectionproof*`. + * The newly-allocated struct pointer will be saved here. * fixed_input_tags: fixed input tags `A_i` for all inputs. (If the fixed tag is not known, * e.g. in a coinjoin with others' inputs, an ephemeral tag can be given; * this won't match the output tag but might be used in the anonymity set.) @@ -192,8 +191,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_initial * limited to 256 the probability of giving up is smaller than * (255/256)^(n_input_tags_to_use*max_n_iterations). * - * random_seed32: a random seed to be used for input selection - * Out: proof_out_p: The pointer to newly-allocated proof whose bitvector will be initialized. + * random_seed32: random seed to be used for input selection + * Out: proof_out_p: pointer to newly-allocated proof whose bitvector will be initialized. * In case of failure, the pointer will be NULL. * input_index: The index of the actual input that is secretly mapped to the output */ diff --git a/include/secp256k1_whitelist.h b/include/secp256k1_whitelist.h index 096a0ee459..9f9decce99 100644 --- a/include/secp256k1_whitelist.h +++ b/include/secp256k1_whitelist.h @@ -40,9 +40,9 @@ typedef struct { /** Parse a whitelist signature * * Returns: 1 when the signature could be parsed, 0 otherwise. - * Args: ctx: a secp256k1 context object - * Out: sig: a pointer to a signature object - * In: input: a pointer to the array to parse + * Args: ctx: pointer to a context object + * Out: sig: pointer to a signature object + * In: input: pointer to the array to parse * input_len: the length of the above array * * The signature must consist of a 1-byte n_keys value, followed by a 32-byte @@ -67,7 +67,7 @@ SECP256K1_API int secp256k1_whitelist_signature_parse( /** Returns the number of keys a signature expects to have. * * Returns: the number of keys for the given signature - * In: sig: a pointer to a signature object + * In: sig: pointer to a signature object */ SECP256K1_API size_t secp256k1_whitelist_signature_n_keys( const secp256k1_whitelist_signature *sig @@ -76,10 +76,10 @@ SECP256K1_API size_t secp256k1_whitelist_signature_n_keys( /** Serialize a whitelist signature * * Returns: 1 - * Args: ctx: a secp256k1 context object - * Out: output64: a pointer to an array to store the serialization + * Args: ctx: pointer to a context object + * Out: output64: pointer to an array to store the serialization * In/Out: output_len: length of the above array, updated with the actual serialized length - * In: sig: a pointer to an initialized signature object + * In: sig: pointer to an initialized signature object * * See secp256k1_whitelist_signature_parse for details about the encoding. */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b305751b08..27e902045e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -120,6 +120,31 @@ if(SECP256K1_INSTALL) "${PROJECT_SOURCE_DIR}/include/secp256k1.h" "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h" ) + if(SECP256K1_ENABLE_MODULE_BPPP) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_bppp.h") + endif() + if(SECP256K1_ENABLE_MODULE_ECDSA_S2C) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdsa_s2c.h") + endif() + if(SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdsa_adaptor.h") + endif() + if(SECP256K1_ENABLE_MODULE_MUSIG) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h") + endif() + if(SECP256K1_ENABLE_MODULE_WHITELIST) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_whitelist.h") + endif() + if(SECP256K1_ENABLE_MODULE_SURJECTIONPROOF) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_surjectionproof.h") + endif() + if(SECP256K1_ENABLE_MODULE_RANGEPROOF) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_rangeproof.h") + endif() + if(SECP256K1_ENABLE_MODULE_GENERATOR) + list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_generator.h") + endif() + if(SECP256K1_ENABLE_MODULE_ECDH) list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h") endif() @@ -161,5 +186,13 @@ if(SECP256K1_INSTALL) ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME} -) + ) + + include(GeneratePkgConfigFile) + generate_pkg_config_file(${PROJECT_SOURCE_DIR}/libsecp256k1.pc.in) + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + ) endif() diff --git a/src/asm/field_10x26_arm.s b/src/asm/field_10x26_arm.s index 42cbf879ef..664b921400 100644 --- a/src/asm/field_10x26_arm.s +++ b/src/asm/field_10x26_arm.s @@ -913,3 +913,4 @@ secp256k1_fe_sqr_inner: ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner + .section .note.GNU-stack,"",%progbits diff --git a/src/assumptions.h b/src/assumptions.h index 8ed04209e9..7961005350 100644 --- a/src/assumptions.h +++ b/src/assumptions.h @@ -19,65 +19,69 @@ reduce the odds of experiencing an unwelcome surprise. */ -struct secp256k1_assumption_checker { - /* This uses a trick to implement a static assertion in C89: a type with an array of negative size is not - allowed. */ - int dummy_array[( - /* Bytes are 8 bits. */ - (CHAR_BIT == 8) && +#if defined(__has_attribute) +# if __has_attribute(__unavailable__) +__attribute__((__unavailable__("Don't call this function. It only exists because STATIC_ASSERT cannot be used outside a function."))) +# endif +#endif +static void secp256k1_assumption_checker(void) { + /* Bytes are 8 bits. */ + STATIC_ASSERT(CHAR_BIT == 8); - /* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32 - without signed overflow, which would be undefined behaviour. */ - (UINT_MAX <= UINT32_MAX) && + /* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32 + without signed overflow, which would be undefined behaviour. */ + STATIC_ASSERT(UINT_MAX <= UINT32_MAX); - /* Conversions from unsigned to signed outside of the bounds of the signed type are - implementation-defined. Verify that they function as reinterpreting the lower - bits of the input in two's complement notation. Do this for conversions: - - from uint(N)_t to int(N)_t with negative result - - from uint(2N)_t to int(N)_t with negative result - - from int(2N)_t to int(N)_t with negative result - - from int(2N)_t to int(N)_t with positive result */ + /* Conversions from unsigned to signed outside of the bounds of the signed type are + implementation-defined. Verify that they function as reinterpreting the lower + bits of the input in two's complement notation. Do this for conversions: + - from uint(N)_t to int(N)_t with negative result + - from uint(2N)_t to int(N)_t with negative result + - from int(2N)_t to int(N)_t with negative result + - from int(2N)_t to int(N)_t with positive result */ - /* To int8_t. */ - ((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55) && - ((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33) && - ((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF) && - ((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34) && + /* To int8_t. */ + STATIC_ASSERT(((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55)); + STATIC_ASSERT((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33); + STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF); + STATIC_ASSERT((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34); - /* To int16_t. */ - ((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322) && - ((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C) && - ((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4) && - ((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678) && + /* To int16_t. */ + STATIC_ASSERT((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322); + STATIC_ASSERT((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C); + STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4); + STATIC_ASSERT((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678); - /* To int32_t. */ - ((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B) && - ((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE) && - ((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8) && - ((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789) && + /* To int32_t. */ + STATIC_ASSERT((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B); + STATIC_ASSERT((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE); + STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8); + STATIC_ASSERT((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789); - /* To int64_t. */ - ((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) && + /* To int64_t. */ + STATIC_ASSERT((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL); #if defined(SECP256K1_INT128_NATIVE) - ((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) && - (((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) && - (((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) && + STATIC_ASSERT((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL); + STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL); + STATIC_ASSERT(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL); - /* To int128_t. */ - ((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)) && + /* To int128_t. */ + STATIC_ASSERT((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)); #endif - /* Right shift on negative signed values is implementation defined. Verify that it - acts as a right shift in two's complement with sign extension (i.e duplicating - the top bit into newly added bits). */ - ((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA) && - ((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) && - ((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) && - ((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) && + /* Right shift on negative signed values is implementation defined. Verify that it + acts as a right shift in two's complement with sign extension (i.e duplicating + the top bit into newly added bits). */ + STATIC_ASSERT((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA); + STATIC_ASSERT((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A); + STATIC_ASSERT((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48); + STATIC_ASSERT((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL); #if defined(SECP256K1_INT128_NATIVE) - ((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) && + STATIC_ASSERT((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)); #endif - 1) * 2 - 1]; -}; + + /* This function is not supposed to be called. */ + VERIFY_CHECK(0); +} #endif /* SECP256K1_ASSUMPTIONS_H */ diff --git a/src/bench_ecmult.c b/src/bench_ecmult.c index 8818aa81b5..7dc52ad87b 100644 --- a/src/bench_ecmult.c +++ b/src/bench_ecmult.c @@ -244,7 +244,6 @@ static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) { static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_g, int num_iters) { char str[32]; - static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); size_t iters = 1 + num_iters / count; size_t iter; @@ -262,7 +261,7 @@ static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_ secp256k1_scalar_add(&total, &total, &tmp); } secp256k1_scalar_negate(&total, &total); - secp256k1_ecmult(&data->expected_output[iter], NULL, &zero, &total); + secp256k1_ecmult(&data->expected_output[iter], NULL, &secp256k1_scalar_zero, &total); } /* Run the benchmark. */ diff --git a/src/bench_internal.c b/src/bench_internal.c index b89b73f514..a20435b7af 100644 --- a/src/bench_internal.c +++ b/src/bench_internal.c @@ -14,10 +14,28 @@ #include "field_impl.h" #include "group_impl.h" #include "scalar_impl.h" -#include "ecmult_const_impl.h" #include "ecmult_impl.h" #include "bench.h" +static void help(int default_iters) { + printf("Benchmarks various internal routines.\n"); + printf("\n"); + printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters); + printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n"); + printf("\n"); + printf("Usage: ./bench_internal [args]\n"); + printf("By default, all benchmarks will be run.\n"); + printf("args:\n"); + printf(" help : display this help and exit\n"); + printf(" scalar : all scalar operations (add, half, inverse, mul, negate, split)\n"); + printf(" field : all field operations (half, inverse, issquare, mul, normalize, sqr, sqrt)\n"); + printf(" group : all group operations (add, double, to_affine)\n"); + printf(" ecmult : all point multiplication operations (ecmult_wnaf) \n"); + printf(" hash : all hash algorithms (hmac, rng6979, sha256)\n"); + printf(" context : all context object operations (context_create)\n"); + printf("\n"); +} + typedef struct { secp256k1_scalar scalar[2]; secp256k1_fe fe[4]; @@ -107,6 +125,18 @@ static void bench_scalar_sqr(void* arg, int iters) { } } +static void bench_scalar_half(void* arg, int iters) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_scalar s = data->scalar[0]; + + for (i = 0; i < iters; i++) { + secp256k1_scalar_half(&s, &s); + } + + data->scalar[0] = s; +} + static void bench_scalar_mul(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -336,18 +366,6 @@ static void bench_ecmult_wnaf(void* arg, int iters) { CHECK(bits <= 256*iters); } -static void bench_wnaf_const(void* arg, int iters) { - int i, bits = 0, overflow = 0; - bench_inv *data = (bench_inv*)arg; - - for (i = 0; i < iters; i++) { - bits += secp256k1_wnaf_const(data->wnaf, &data->scalar[0], WINDOW_A, 256); - overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); - } - CHECK(overflow >= 0); - CHECK(bits <= 256*iters); -} - static void bench_sha256(void* arg, int iters) { int i; bench_inv *data = (bench_inv*)arg; @@ -393,10 +411,22 @@ static void bench_context(void* arg, int iters) { int main(int argc, char **argv) { bench_inv data; - int iters = get_iters(20000); + int default_iters = 20000; + int iters = get_iters(default_iters); int d = argc == 1; /* default */ + + if (argc > 1) { + if (have_flag(argc, argv, "-h") + || have_flag(argc, argv, "--help") + || have_flag(argc, argv, "help")) { + help(default_iters); + return 0; + } + } + print_output_table_header_row(); + if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "half")) run_benchmark("scalar_half", bench_scalar_half, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100); if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, iters*10); @@ -423,7 +453,6 @@ int main(int argc, char **argv) { if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_zinv_var", bench_group_add_zinv_var, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters); - if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters); diff --git a/src/checkmem.h b/src/checkmem.h index 571e4cc389..f2169decfc 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 f0f77662cd..407d2cc6a8 100644 --- a/src/ctime_tests.c +++ b/src/ctime_tests.c @@ -208,6 +208,10 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) { 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); + SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); + CHECK(ret == 1); + + 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); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); diff --git a/src/ecdsa_impl.h b/src/ecdsa_impl.h index e71254d9f9..ce36e85e6a 100644 --- a/src/ecdsa_impl.h +++ b/src/ecdsa_impl.h @@ -66,8 +66,7 @@ static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const } if (lenleft > sizeof(size_t)) { /* The resulting length would exceed the range of a size_t, so - * certainly longer than the passed array size. - */ + * it is certainly longer than the passed array size. */ return 0; } while (lenleft > 0) { @@ -76,7 +75,9 @@ static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const lenleft--; } if (*len > (size_t)(sigend - *sigp)) { - /* Result exceeds the length of the passed array. */ + /* Result exceeds the length of the passed array. + (Checking this is the responsibility of the caller but it + can't hurt do it here, too.) */ return 0; } if (*len < 128) { diff --git a/src/ecmult_const_impl.h b/src/ecmult_const_impl.h index 06f9e53ffd..7dc4aac25d 100644 --- a/src/ecmult_const_impl.h +++ b/src/ecmult_const_impl.h @@ -1,5 +1,5 @@ /*********************************************************************** - * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Copyright (c) 2015, 2022 Pieter Wuille, Andrew Poelstra * * Distributed under the MIT software license, see the accompanying * * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ @@ -12,208 +12,259 @@ #include "ecmult_const.h" #include "ecmult_impl.h" +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need 2^ECMULT_CONST_GROUP_SIZE - 1 to be less than EXHAUSTIVE_TEST_ORDER, because + * the tables cannot have infinities in them (this breaks the effective-affine technique's + * z-ratio tracking) */ +# if EXHAUSTIVE_TEST_ORDER == 199 +# define ECMULT_CONST_GROUP_SIZE 4 +# elif EXHAUSTIVE_TEST_ORDER == 13 +# define ECMULT_CONST_GROUP_SIZE 3 +# elif EXHAUSTIVE_TEST_ORDER == 7 +# define ECMULT_CONST_GROUP_SIZE 2 +# else +# error "Unknown EXHAUSTIVE_TEST_ORDER" +# endif +#else +/* Group size 4 or 5 appears optimal. */ +# define ECMULT_CONST_GROUP_SIZE 5 +#endif + +#define ECMULT_CONST_TABLE_SIZE (1L << (ECMULT_CONST_GROUP_SIZE - 1)) +#define ECMULT_CONST_GROUPS ((129 + ECMULT_CONST_GROUP_SIZE - 1) / ECMULT_CONST_GROUP_SIZE) +#define ECMULT_CONST_BITS (ECMULT_CONST_GROUPS * ECMULT_CONST_GROUP_SIZE) + /** Fill a table 'pre' with precomputed odd multiples of a. * * The resulting point set is brought to a single constant Z denominator, stores the X and Y - * coordinates as ge_storage points in pre, and stores the global Z in globalz. - * It only operates on tables sized for WINDOW_A wnaf multiples. + * coordinates as ge points in pre, and stores the global Z in globalz. + * + * 'pre' must be an array of size ECMULT_CONST_TABLE_SIZE. */ -static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { - secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; +static void secp256k1_ecmult_const_odd_multiples_table_globalz(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { + secp256k1_fe zr[ECMULT_CONST_TABLE_SIZE]; - secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr, globalz, a); - secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr); + secp256k1_ecmult_odd_multiples_table(ECMULT_CONST_TABLE_SIZE, pre, zr, globalz, a); + secp256k1_ge_table_set_globalz(ECMULT_CONST_TABLE_SIZE, pre, zr); } -/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ -#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ - int m = 0; \ - /* Extract the sign-bit for a constant time absolute-value. */ \ - int volatile mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \ - int abs_n = ((n) + mask) ^ mask; \ - int idx_n = abs_n >> 1; \ +/* Given a table 'pre' with odd multiples of a point, put in r the signed-bit multiplication of n with that point. + * + * For example, if ECMULT_CONST_GROUP_SIZE is 4, then pre is expected to contain 8 entries: + * [1*P, 3*P, 5*P, 7*P, 9*P, 11*P, 13*P, 15*P]. n is then expected to be a 4-bit integer (range 0-15), and its + * bits are interpreted as signs of powers of two to look up. + * + * For example, if n=4, which is 0100 in binary, which is interpreted as [- + - -], so the looked up value is + * [ -(2^3) + (2^2) - (2^1) - (2^0) ]*P = -7*P. Every valid n translates to an odd number in range [-15,15], + * which means we just need to look up one of the precomputed values, and optionally negate it. + */ +#define ECMULT_CONST_TABLE_GET_GE(r,pre,n) do { \ + unsigned int m = 0; \ + /* If the top bit of n is 0, we want the negation. */ \ + volatile unsigned int negative = ((n) >> (ECMULT_CONST_GROUP_SIZE - 1)) ^ 1; \ + /* Let n[i] be the i-th bit of n, then the index is + * sum(cnot(n[i]) * 2^i, i=0..l-2) + * where cnot(b) = b if n[l-1] = 1 and 1 - b otherwise. + * For example, if n = 4, in binary 0100, the index is 3, in binary 011. + * + * Proof: + * Let + * x = sum((2*n[i] - 1)*2^i, i=0..l-1) + * = 2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 1 + * be the value represented by n. + * The index is (x - 1)/2 if x > 0 and -(x + 1)/2 otherwise. + * Case x > 0: + * n[l-1] = 1 + * index = sum(n[i] * 2^i, i=0..l-1) - 2^(l-1) + * = sum(n[i] * 2^i, i=0..l-2) + * Case x <= 0: + * n[l-1] = 0 + * index = -(2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 2)/2 + * = 2^(l-1) - 1 - sum(n[i] * 2^i, i=0..l-1) + * = sum((1 - n[i]) * 2^i, i=0..l-2) + */ \ + unsigned int index = ((unsigned int)(-negative) ^ n) & ((1U << (ECMULT_CONST_GROUP_SIZE - 1)) - 1U); \ secp256k1_fe neg_y; \ - VERIFY_CHECK(((n) & 1) == 1); \ - VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ - VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ - VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \ - VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \ - /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one \ + VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \ + VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \ + /* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one * or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \ (r)->x = (pre)[m].x; \ (r)->y = (pre)[m].y; \ - for (m = 1; m < ECMULT_TABLE_SIZE(w); m++) { \ + for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \ /* This loop is used to avoid secret data in array indices. See * the comment in ecmult_gen_impl.h for rationale. */ \ - secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ - secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ + secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \ + secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \ } \ (r)->infinity = 0; \ secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ - secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ + secp256k1_fe_cmov(&(r)->y, &neg_y, negative); \ } while(0) -/** Convert a number to WNAF notation. - * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. - * It has the following guarantees: - * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) - * - each wnaf[i] is nonzero - * - the number of words set is always WNAF_SIZE(w) + 1 - * - * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar - * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) - * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlag Berlin Heidelberg 2003 - * - * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 - */ -static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w, int size) { - int global_sign; - int skew; - int word = 0; +/* For K as defined in the comment of secp256k1_ecmult_const, we have several precomputed + * formulas/constants. + * - in exhaustive test mode, we give an explicit expression to compute it at compile time: */ +#ifdef EXHAUSTIVE_TEST_ORDER +static const secp256k1_scalar secp256k1_ecmult_const_K = ((SECP256K1_SCALAR_CONST(0, 0, 0, (1U << (ECMULT_CONST_BITS - 128)) - 2U, 0, 0, 0, 0) + EXHAUSTIVE_TEST_ORDER - 1U) * (1U + EXHAUSTIVE_TEST_LAMBDA)) % EXHAUSTIVE_TEST_ORDER; +/* - for the real secp256k1 group we have constants for various ECMULT_CONST_BITS values. */ +#elif ECMULT_CONST_BITS == 129 +/* For GROUP_SIZE = 1,3. */ +static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xac9c52b3ul, 0x3fa3cf1ful, 0x5ad9e3fdul, 0x77ed9ba4ul, 0xa880b9fcul, 0x8ec739c2ul, 0xe0cfc810ul, 0xb51283ceul); +#elif ECMULT_CONST_BITS == 130 +/* For GROUP_SIZE = 2,5. */ +static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xa4e88a7dul, 0xcb13034eul, 0xc2bdd6bful, 0x7c118d6bul, 0x589ae848ul, 0x26ba29e4ul, 0xb5c2c1dcul, 0xde9798d9ul); +#elif ECMULT_CONST_BITS == 132 +/* For GROUP_SIZE = 4,6 */ +static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0x76b1d93dul, 0x0fae3c6bul, 0x3215874bul, 0x94e93813ul, 0x7937fe0dul, 0xb66bcaaful, 0xb3749ca5ul, 0xd7b6171bul); +#else +# error "Unknown ECMULT_CONST_BITS" +#endif - /* 1 2 3 */ - int u_last; - int u; - - int flip; - secp256k1_scalar s = *scalar; - - VERIFY_CHECK(w > 0); - VERIFY_CHECK(size > 0); - - /* Note that we cannot handle even numbers by negating them to be odd, as is - * done in other implementations, since if our scalars were specified to have - * width < 256 for performance reasons, their negations would have width 256 - * and we'd lose any performance benefit. Instead, we use a variation of a - * technique from Section 4.2 of the Okeya/Tagaki paper, which is to add 1 to the - * number we are encoding when it is even, returning a skew value indicating - * this, and having the caller compensate after doing the multiplication. +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q) { + /* The approach below combines the signed-digit logic from Mike Hamburg's + * "Fast and compact elliptic-curve cryptography" (https://eprint.iacr.org/2012/309) + * Section 3.3, with the GLV endomorphism. * - * In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in - * particular, to ensure that the outputs from the endomorphism-split fit into - * 128 bits). If we negate, the parity of our number flips, affecting whether - * we want to add to the scalar to ensure that it's odd. */ - flip = secp256k1_scalar_is_high(&s); - skew = flip ^ secp256k1_scalar_is_even(&s); - secp256k1_scalar_cadd_bit(&s, 0, skew); - global_sign = secp256k1_scalar_cond_negate(&s, flip); + * The idea there is to interpret the bits of a scalar as signs (1 = +, 0 = -), and compute a + * point multiplication in that fashion. Let v be an n-bit non-negative integer (0 <= v < 2^n), + * and v[i] its i'th bit (so v = sum(v[i] * 2^i, i=0..n-1)). Then define: + * + * C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1) + * + * Then it holds that C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1) + * = (2*sum(v[i] * 2^i, i=0..l-1) + 1 - 2^l) * A + * = (2*v + 1 - 2^l) * A + * + * Thus, one can compute q*A as C_256((q + 2^256 - 1) / 2, A). This is the basis for the + * paper's signed-digit multi-comb algorithm for multiplication using a precomputed table. + * + * It is appealing to try to combine this with the GLV optimization: the idea that a scalar + * s can be written as s1 + lambda*s2, where lambda is a curve-specific constant such that + * lambda*A is easy to compute, and where s1 and s2 are small. In particular we have the + * secp256k1_scalar_split_lambda function which performs such a split with the resulting s1 + * and s2 in range (-2^128, 2^128) mod n. This does work, but is uninteresting: + * + * To compute q*A: + * - Let s1, s2 = split_lambda(q) + * - Let R1 = C_256((s1 + 2^256 - 1) / 2, A) + * - Let R2 = C_256((s2 + 2^256 - 1) / 2, lambda*A) + * - Return R1 + R2 + * + * The issue is that while s1 and s2 are small-range numbers, (s1 + 2^256 - 1) / 2 (mod n) + * and (s2 + 2^256 - 1) / 2 (mod n) are not, undoing the benefit of the splitting. + * + * To make it work, we want to modify the input scalar q first, before splitting, and then only + * add a 2^128 offset of the split results (so that they end up in the single 129-bit range + * [0,2^129]). A slightly smaller offset would work due to the bounds on the split, but we pick + * 2^128 for simplicity. Let s be the scalar fed to split_lambda, and f(q) the function to + * compute it from q: + * + * To compute q*A: + * - Compute s = f(q) + * - Let s1, s2 = split_lambda(s) + * - Let v1 = s1 + 2^128 (mod n) + * - Let v2 = s2 + 2^128 (mod n) + * - Let R1 = C_l(v1, A) + * - Let R2 = C_l(v2, lambda*A) + * - Return R1 + R2 + * + * l will thus need to be at least 129, but we may overshoot by a few bits (see + * further), so keep it as a variable. + * + * To solve for s, we reason: + * q*A = R1 + R2 + * <=> q*A = C_l(s1 + 2^128, A) + C_l(s2 + 2^128, lambda*A) + * <=> q*A = (2*(s1 + 2^128) + 1 - 2^l) * A + (2*(s2 + 2^128) + 1 - 2^l) * lambda*A + * <=> q*A = (2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda)) * A + * <=> q = 2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda) (mod n) + * <=> q = 2*s + (2^129 + 1 - 2^l) * (1 + lambda) (mod n) + * <=> s = (q + (2^l - 2^129 - 1) * (1 + lambda)) / 2 (mod n) + * <=> f(q) = (q + K) / 2 (mod n) + * where K = (2^l - 2^129 - 1)*(1 + lambda) (mod n) + * + * We will process the computation of C_l(v1, A) and C_l(v2, lambda*A) in groups of + * ECMULT_CONST_GROUP_SIZE, so we set l to the smallest multiple of ECMULT_CONST_GROUP_SIZE + * that is not less than 129; this equals ECMULT_CONST_BITS. + */ - /* 4 */ - u_last = secp256k1_scalar_shr_int(&s, w); - do { - int even; - - /* 4.1 4.4 */ - u = secp256k1_scalar_shr_int(&s, w); - /* 4.2 */ - even = ((u & 1) == 0); - /* In contrast to the original algorithm, u_last is always > 0 and - * therefore we do not need to check its sign. In particular, it's easy - * to see that u_last is never < 0 because u is never < 0. Moreover, - * u_last is never = 0 because u is never even after a loop - * iteration. The same holds analogously for the initial value of - * u_last (in the first loop iteration). */ - VERIFY_CHECK(u_last > 0); - VERIFY_CHECK((u_last & 1) == 1); - u += even; - u_last -= even * (1 << w); - - /* 4.3, adapted for global sign change */ - wnaf[word++] = u_last * global_sign; - - u_last = u; - } while (word * w < size); - wnaf[word] = u * global_sign; - - VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); - VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w)); - return skew; -} - -static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) { - secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_ge tmpa; - secp256k1_fe Z; - - int skew_1; - secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; - int skew_lam; - secp256k1_scalar q_1, q_lam; - int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; - - int i; + /* The offset to add to s1 and s2 to make them non-negative. Equal to 2^128. */ + static const secp256k1_scalar S_OFFSET = SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0); + secp256k1_scalar s, v1, v2; + secp256k1_ge pre_a[ECMULT_CONST_TABLE_SIZE]; + secp256k1_ge pre_a_lam[ECMULT_CONST_TABLE_SIZE]; + secp256k1_fe global_z; + int group, i; + /* We're allowed to be non-constant time in the point, and the code below (in particular, + * secp256k1_ecmult_const_odd_multiples_table_globalz) cannot deal with infinity in a + * constant-time manner anyway. */ if (secp256k1_ge_is_infinity(a)) { secp256k1_gej_set_infinity(r); return; } - /* build wnaf representation for q. */ - /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ - secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar); - skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128); - skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128); + /* Compute v1 and v2. */ + secp256k1_scalar_add(&s, q, &secp256k1_ecmult_const_K); + secp256k1_scalar_half(&s, &s); + secp256k1_scalar_split_lambda(&v1, &v2, &s); + secp256k1_scalar_add(&v1, &v1, &S_OFFSET); + secp256k1_scalar_add(&v2, &v2, &S_OFFSET); - /* Calculate odd multiples of a. +#ifdef VERIFY + /* Verify that v1 and v2 are in range [0, 2^129-1]. */ + for (i = 129; i < 256; ++i) { + VERIFY_CHECK(secp256k1_scalar_get_bits(&v1, i, 1) == 0); + VERIFY_CHECK(secp256k1_scalar_get_bits(&v2, i, 1) == 0); + } +#endif + + /* Calculate odd multiples of A and A*lambda. * All multiples are brought to the same Z 'denominator', which is stored - * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * in global_z. Due to secp256k1' isomorphism we can do all operations pretending * that the Z coordinate was 1, use affine addition formulae, and correct * the Z coordinate of the result once at the end. */ - VERIFY_CHECK(!a->infinity); secp256k1_gej_set_ge(r, a); - secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_fe_normalize_weak(&pre_a[i].y); - } - for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_ecmult_const_odd_multiples_table_globalz(pre_a, &global_z, r); + for (i = 0; i < ECMULT_CONST_TABLE_SIZE; i++) { secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); } - /* first loop iteration (separated out so we can directly set r, rather - * than having it start at infinity, get doubled several times, then have - * its new value added to it) */ - i = wnaf_1[WNAF_SIZE_BITS(128, WINDOW_A - 1)]; - VERIFY_CHECK(i != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); - secp256k1_gej_set_ge(r, &tmpa); - i = wnaf_lam[WNAF_SIZE_BITS(128, WINDOW_A - 1)]; - VERIFY_CHECK(i != 0); - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); - secp256k1_gej_add_ge(r, r, &tmpa); - /* remaining loop iterations */ - for (i = WNAF_SIZE_BITS(128, WINDOW_A - 1) - 1; i >= 0; i--) { - int n; + /* Next, we compute r = C_l(v1, A) + C_l(v2, lambda*A). + * + * We proceed in groups of ECMULT_CONST_GROUP_SIZE bits, operating on that many bits + * at a time, from high in v1, v2 to low. Call these bits1 (from v1) and bits2 (from v2). + * + * Now note that ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1) loads into t a point equal + * to C_{ECMULT_CONST_GROUP_SIZE}(bits1, A), and analogously for pre_lam_a / bits2. + * This means that all we need to do is add these looked up values together, multiplied + * by 2^(ECMULT_GROUP_SIZE * group). + */ + for (group = ECMULT_CONST_GROUPS - 1; group >= 0; --group) { + /* Using the _var get_bits function is ok here, since it's only variable in offset and count, not in the scalar. */ + unsigned int bits1 = secp256k1_scalar_get_bits_var(&v1, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE); + unsigned int bits2 = secp256k1_scalar_get_bits_var(&v2, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE); + secp256k1_ge t; int j; - for (j = 0; j < WINDOW_A - 1; ++j) { - secp256k1_gej_double(r, r); + + ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1); + if (group == ECMULT_CONST_GROUPS - 1) { + /* Directly set r in the first iteration. */ + secp256k1_gej_set_ge(r, &t); + } else { + /* Shift the result so far up. */ + for (j = 0; j < ECMULT_CONST_GROUP_SIZE; ++j) { + secp256k1_gej_double(r, r); + } + secp256k1_gej_add_ge(r, r, &t); } - - n = wnaf_1[i]; - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); - VERIFY_CHECK(n != 0); - secp256k1_gej_add_ge(r, r, &tmpa); - n = wnaf_lam[i]; - ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); - VERIFY_CHECK(n != 0); - secp256k1_gej_add_ge(r, r, &tmpa); + ECMULT_CONST_TABLE_GET_GE(&t, pre_a_lam, bits2); + secp256k1_gej_add_ge(r, r, &t); } - { - /* Correct for wNAF skew */ - secp256k1_gej tmpj; - - secp256k1_ge_neg(&tmpa, &pre_a[0]); - secp256k1_gej_add_ge(&tmpj, r, &tmpa); - secp256k1_gej_cmov(r, &tmpj, skew_1); - - secp256k1_ge_neg(&tmpa, &pre_a_lam[0]); - secp256k1_gej_add_ge(&tmpj, r, &tmpa); - secp256k1_gej_cmov(r, &tmpj, skew_lam); - } - - secp256k1_fe_mul(&r->z, &r->z, &Z); + /* Map the result back to the secp256k1 curve from the isomorphic curve. */ + secp256k1_fe_mul(&r->z, &r->z, &global_z); } static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) { @@ -296,9 +347,7 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, secp256k1_fe_mul(&g, &g, n); if (d) { secp256k1_fe b; -#ifdef VERIFY VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero(d)); -#endif secp256k1_fe_sqr(&b, d); VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */ secp256k1_fe_mul_int(&b, SECP256K1_B); @@ -331,13 +380,9 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, p.infinity = 0; /* Perform x-only EC multiplication of P with q. */ -#ifdef VERIFY VERIFY_CHECK(!secp256k1_scalar_is_zero(q)); -#endif secp256k1_ecmult_const(&rj, &p, q); -#ifdef VERIFY VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj)); -#endif /* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to * (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate diff --git a/src/field.h b/src/field.h index bb99f948ef..bd589bf8a8 100644 --- a/src/field.h +++ b/src/field.h @@ -176,12 +176,6 @@ static int secp256k1_fe_is_odd(const secp256k1_fe *a); */ static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); -/** Determine whether two field elements are equal, without constant-time guarantee. - * - * Identical in behavior to secp256k1_fe_equal, but not constant time in either a or b. - */ -static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); - /** Compare the values represented by 2 field elements, without constant-time guarantee. * * On input, a and b must be valid normalized field elements. @@ -190,7 +184,8 @@ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); */ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Set a field element equal to a provided 32-byte big endian value, reducing it. +/** Set a field element equal to the element represented by a provided 32-byte big endian value + * interpreted modulo p. * * On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array. * On output, r = a (mod p). It will have magnitude 1, and not be normalized. @@ -351,5 +346,10 @@ 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); +#define SECP256K1_FE_VERIFY(a) secp256k1_fe_verify(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); +#define SECP256K1_FE_VERIFY_MAGNITUDE(a, m) secp256k1_fe_verify_magnitude(a, m) #endif /* SECP256K1_FIELD_H */ diff --git a/src/field_10x26_impl.h b/src/field_10x26_impl.h index 8445db1639..666068c712 100644 --- a/src/field_10x26_impl.h +++ b/src/field_10x26_impl.h @@ -403,11 +403,7 @@ void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a); #else -#ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) -#else -#define VERIFY_BITS(x, n) do { } while(0) -#endif SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { uint64_t c, d; diff --git a/src/field_5x52_asm_impl.h b/src/field_5x52_asm_impl.h deleted file mode 100644 index 04a9af2105..0000000000 --- a/src/field_5x52_asm_impl.h +++ /dev/null @@ -1,504 +0,0 @@ -/*********************************************************************** - * Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille * - * Distributed under the MIT software license, see the accompanying * - * file COPYING or https://www.opensource.org/licenses/mit-license.php.* - ***********************************************************************/ - -/** - * Changelog: - * - March 2013, Diederik Huys: original version - * - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm - * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly - */ - -#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H -#define SECP256K1_FIELD_INNER5X52_IMPL_H - -#include "util.h" - -SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { -/** - * Registers: rdx:rax = multiplication accumulator - * r9:r8 = c - * r15:rcx = d - * r10-r14 = a0-a4 - * rbx = b - * rdi = r - * rsi = a / t? - */ - uint64_t tmp1, tmp2, tmp3; -__asm__ __volatile__( - "movq 0(%%rsi),%%r10\n" - "movq 8(%%rsi),%%r11\n" - "movq 16(%%rsi),%%r12\n" - "movq 24(%%rsi),%%r13\n" - "movq 32(%%rsi),%%r14\n" - - /* d += a3 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r13\n" - "movq %%rax,%%rcx\n" - "movq %%rdx,%%r15\n" - /* d += a2 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d = a0 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c = a4 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r14\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += (c & M) * R */ - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* t3 (tmp1) = d & M */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - "movq %%rsi,%q1\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* d += a4 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a0 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += c * R */ - "movq %%r8,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* t4 = d & M (%%rsi) */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* tx = t4 >> 48 (tmp3) */ - "movq %%rsi,%%rax\n" - "shrq $48,%%rax\n" - "movq %%rax,%q3\n" - /* t4 &= (M >> 4) (tmp2) */ - "movq $0xffffffffffff,%%rax\n" - "andq %%rax,%%rsi\n" - "movq %%rsi,%q2\n" - /* c = a0 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r10\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += a4 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a1 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* u0 = d & M (%%rsi) */ - "movq %%rcx,%%rsi\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* u0 = (u0 << 4) | tx (%%rsi) */ - "shlq $4,%%rsi\n" - "movq %q3,%%rax\n" - "orq %%rax,%%rsi\n" - /* c += u0 * (R >> 4) */ - "movq $0x1000003d1,%%rax\n" - "mulq %%rsi\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[0] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,0(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a1 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a0 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a4 * b2 */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a2 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c += (d & M) * R */ - "movq %%rcx,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 */ - "shrdq $52,%%r15,%%rcx\n" - "xorq %%r15,%%r15\n" - /* r[1] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,8(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a2 * b0 */ - "movq 0(%%rbx),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a1 * b1 */ - "movq 8(%%rbx),%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* c += a0 * b2 (last use of %%r10 = a0) */ - "movq 16(%%rbx),%%rax\n" - "mulq %%r10\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */ - "movq %q2,%%rsi\n" - "movq %q1,%%r10\n" - /* d += a4 * b3 */ - "movq 24(%%rbx),%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* d += a3 * b4 */ - "movq 32(%%rbx),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rcx\n" - "adcq %%rdx,%%r15\n" - /* c += (d & M) * R */ - "movq %%rcx,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 (%%rcx only) */ - "shrdq $52,%%r15,%%rcx\n" - /* r[2] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,16(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += t3 */ - "addq %%r10,%%r8\n" - /* c += d * R */ - "movq %%rcx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[3] = c & M */ - "movq %%r8,%%rax\n" - "movq $0xfffffffffffff,%%rdx\n" - "andq %%rdx,%%rax\n" - "movq %%rax,24(%%rdi)\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* c += t4 (%%r8 only) */ - "addq %%rsi,%%r8\n" - /* r[4] = c */ - "movq %%r8,32(%%rdi)\n" -: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3) -: "b"(b), "D"(r) -: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" -); -} - -SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { -/** - * Registers: rdx:rax = multiplication accumulator - * r9:r8 = c - * rcx:rbx = d - * r10-r14 = a0-a4 - * r15 = M (0xfffffffffffff) - * rdi = r - * rsi = a / t? - */ - uint64_t tmp1, tmp2, tmp3; -__asm__ __volatile__( - "movq 0(%%rsi),%%r10\n" - "movq 8(%%rsi),%%r11\n" - "movq 16(%%rsi),%%r12\n" - "movq 24(%%rsi),%%r13\n" - "movq 32(%%rsi),%%r14\n" - "movq $0xfffffffffffff,%%r15\n" - - /* d = (a0*2) * a3 */ - "leaq (%%r10,%%r10,1),%%rax\n" - "mulq %%r13\n" - "movq %%rax,%%rbx\n" - "movq %%rdx,%%rcx\n" - /* d += (a1*2) * a2 */ - "leaq (%%r11,%%r11,1),%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c = a4 * a4 */ - "movq %%r14,%%rax\n" - "mulq %%r14\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += (c & M) * R */ - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* t3 (tmp1) = d & M */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - "movq %%rsi,%q1\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* a4 *= 2 */ - "addq %%r14,%%r14\n" - /* d += a0 * a4 */ - "movq %%r10,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d+= (a1*2) * a3 */ - "leaq (%%r11,%%r11,1),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += a2 * a2 */ - "movq %%r12,%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += c * R */ - "movq %%r8,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* t4 = d & M (%%rsi) */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* tx = t4 >> 48 (tmp3) */ - "movq %%rsi,%%rax\n" - "shrq $48,%%rax\n" - "movq %%rax,%q3\n" - /* t4 &= (M >> 4) (tmp2) */ - "movq $0xffffffffffff,%%rax\n" - "andq %%rax,%%rsi\n" - "movq %%rsi,%q2\n" - /* c = a0 * a0 */ - "movq %%r10,%%rax\n" - "mulq %%r10\n" - "movq %%rax,%%r8\n" - "movq %%rdx,%%r9\n" - /* d += a1 * a4 */ - "movq %%r11,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += (a2*2) * a3 */ - "leaq (%%r12,%%r12,1),%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* u0 = d & M (%%rsi) */ - "movq %%rbx,%%rsi\n" - "andq %%r15,%%rsi\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* u0 = (u0 << 4) | tx (%%rsi) */ - "shlq $4,%%rsi\n" - "movq %q3,%%rax\n" - "orq %%rax,%%rsi\n" - /* c += u0 * (R >> 4) */ - "movq $0x1000003d1,%%rax\n" - "mulq %%rsi\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[0] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,0(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* a0 *= 2 */ - "addq %%r10,%%r10\n" - /* c += a0 * a1 */ - "movq %%r10,%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a2 * a4 */ - "movq %%r12,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* d += a3 * a3 */ - "movq %%r13,%%rax\n" - "mulq %%r13\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c += (d & M) * R */ - "movq %%rbx,%%rax\n" - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 */ - "shrdq $52,%%rcx,%%rbx\n" - "xorq %%rcx,%%rcx\n" - /* r[1] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,8(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += a0 * a2 (last use of %%r10) */ - "movq %%r10,%%rax\n" - "mulq %%r12\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */ - "movq %q2,%%rsi\n" - "movq %q1,%%r10\n" - /* c += a1 * a1 */ - "movq %%r11,%%rax\n" - "mulq %%r11\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d += a3 * a4 */ - "movq %%r13,%%rax\n" - "mulq %%r14\n" - "addq %%rax,%%rbx\n" - "adcq %%rdx,%%rcx\n" - /* c += (d & M) * R */ - "movq %%rbx,%%rax\n" - "andq %%r15,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* d >>= 52 (%%rbx only) */ - "shrdq $52,%%rcx,%%rbx\n" - /* r[2] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,16(%%rdi)\n" - /* c >>= 52 */ - "shrdq $52,%%r9,%%r8\n" - "xorq %%r9,%%r9\n" - /* c += t3 */ - "addq %%r10,%%r8\n" - /* c += d * R */ - "movq %%rbx,%%rax\n" - "movq $0x1000003d10,%%rdx\n" - "mulq %%rdx\n" - "addq %%rax,%%r8\n" - "adcq %%rdx,%%r9\n" - /* r[3] = c & M */ - "movq %%r8,%%rax\n" - "andq %%r15,%%rax\n" - "movq %%rax,24(%%rdi)\n" - /* c >>= 52 (%%r8 only) */ - "shrdq $52,%%r9,%%r8\n" - /* c += t4 (%%r8 only) */ - "addq %%rsi,%%r8\n" - /* r[4] = c */ - "movq %%r8,32(%%rdi)\n" -: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3) -: "D"(r) -: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" -); -} - -#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/src/field_5x52_impl.h b/src/field_5x52_impl.h index ecb70502c2..76031f755e 100644 --- a/src/field_5x52_impl.h +++ b/src/field_5x52_impl.h @@ -12,11 +12,7 @@ #include "field.h" #include "modinv64_impl.h" -#if defined(USE_ASM_X86_64) -#include "field_5x52_asm_impl.h" -#else #include "field_5x52_int128_impl.h" -#endif #ifdef VERIFY static void secp256k1_fe_impl_verify(const secp256k1_fe *a) { diff --git a/src/field_5x52_int128_impl.h b/src/field_5x52_int128_impl.h index b2a391dec9..f23f8ee1c4 100644 --- a/src/field_5x52_int128_impl.h +++ b/src/field_5x52_int128_impl.h @@ -12,13 +12,8 @@ #include "int128.h" #include "util.h" -#ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) #define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n))) -#else -#define VERIFY_BITS(x, n) do { } while(0) -#define VERIFY_BITS_128(x, n) do { } while(0) -#endif SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { secp256k1_uint128 c, d; @@ -89,18 +84,18 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t secp256k1_u128_accum_mul(&d, a2, b[3]); secp256k1_u128_accum_mul(&d, a3, b[2]); secp256k1_u128_accum_mul(&d, a4, b[1]); - VERIFY_BITS_128(&d, 115); + VERIFY_BITS_128(&d, 114); /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52); VERIFY_BITS(u0, 52); - VERIFY_BITS_128(&d, 63); + VERIFY_BITS_128(&d, 62); /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ u0 = (u0 << 4) | tx; VERIFY_BITS(u0, 56); /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ secp256k1_u128_accum_mul(&c, u0, R >> 4); - VERIFY_BITS_128(&c, 115); + VERIFY_BITS_128(&c, 113); /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52); VERIFY_BITS(r[0], 52); @@ -159,7 +154,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { secp256k1_uint128 c, d; uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; - int64_t t3, t4, tx, u0; + uint64_t t3, t4, tx, u0; const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; VERIFY_BITS(a[0], 56); diff --git a/src/field_impl.h b/src/field_impl.h index 7f18ebdc94..989e9cdb2f 100644 --- a/src/field_impl.h +++ b/src/field_impl.h @@ -20,30 +20,16 @@ SECP256K1_INLINE static int secp256k1_fe_equal(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_VERIFY(a); + SECP256K1_FE_VERIFY(b); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 1); + SECP256K1_FE_VERIFY_MAGNITUDE(b, 31); + 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. @@ -57,11 +43,9 @@ static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; int j, ret; -#ifdef VERIFY VERIFY_CHECK(r != a); - secp256k1_fe_verify(a); - VERIFY_CHECK(a->magnitude <= 8); -#endif + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: @@ -151,7 +135,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,74 +143,93 @@ 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); + SECP256K1_FE_VERIFY(r); + secp256k1_fe_impl_normalize(r); r->magnitude = 1; r->normalized = 1; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r); SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { - secp256k1_fe_verify(r); + SECP256K1_FE_VERIFY(r); + secp256k1_fe_impl_normalize_weak(r); r->magnitude = 1; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r); SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) { - secp256k1_fe_verify(r); + SECP256K1_FE_VERIFY(r); + secp256k1_fe_impl_normalize_var(r); r->magnitude = 1; r->normalized = 1; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r); SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) { - secp256k1_fe_verify(r); + SECP256K1_FE_VERIFY(r); + return secp256k1_fe_impl_normalizes_to_zero(r); } static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r); SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) { - secp256k1_fe_verify(r); + SECP256K1_FE_VERIFY(r); + return secp256k1_fe_impl_normalizes_to_zero_var(r); } static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a); SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { VERIFY_CHECK(0 <= a && a <= 0x7FFF); + secp256k1_fe_impl_set_int(r, a); r->magnitude = (a != 0); r->normalized = 1; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a); SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) { VERIFY_CHECK(0 <= a && a <= 0x7FFF); - secp256k1_fe_verify(r); + SECP256K1_FE_VERIFY(r); + secp256k1_fe_impl_add_int(r, a); r->magnitude += 1; r->normalized = 0; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_clear(secp256k1_fe *a); @@ -234,29 +237,33 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { a->magnitude = 0; a->normalized = 1; secp256k1_fe_impl_clear(a); - secp256k1_fe_verify(a); + + SECP256K1_FE_VERIFY(a); } static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a); SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { - secp256k1_fe_verify(a); + SECP256K1_FE_VERIFY(a); VERIFY_CHECK(a->normalized); + return secp256k1_fe_impl_is_zero(a); } static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a); SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { - secp256k1_fe_verify(a); + SECP256K1_FE_VERIFY(a); VERIFY_CHECK(a->normalized); + return secp256k1_fe_impl_is_odd(a); } static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { - secp256k1_fe_verify(a); - secp256k1_fe_verify(b); + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(b); VERIFY_CHECK(a->normalized); VERIFY_CHECK(b->normalized); + return secp256k1_fe_impl_cmp_var(a, b); } @@ -265,7 +272,8 @@ SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const uns secp256k1_fe_impl_set_b32_mod(r, a); r->magnitude = 1; r->normalized = 0; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a); @@ -273,7 +281,7 @@ SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const un if (secp256k1_fe_impl_set_b32_limit(r, a)) { r->magnitude = 1; r->normalized = 1; - secp256k1_fe_verify(r); + SECP256K1_FE_VERIFY(r); return 1; } else { /* Mark the output field element as invalid. */ @@ -284,83 +292,97 @@ SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const un static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a); SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { - secp256k1_fe_verify(a); + SECP256K1_FE_VERIFY(a); VERIFY_CHECK(a->normalized); + secp256k1_fe_impl_get_b32(r, a); } static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m); SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) { - secp256k1_fe_verify(a); + 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; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a); SECP256K1_INLINE static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a) { - secp256k1_fe_verify(r); + SECP256K1_FE_VERIFY(r); + VERIFY_CHECK(a >= 0 && a <= 32); VERIFY_CHECK(a*r->magnitude <= 32); secp256k1_fe_impl_mul_int_unchecked(r, a); r->magnitude *= a; r->normalized = 0; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a); SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { - secp256k1_fe_verify(r); - secp256k1_fe_verify(a); + SECP256K1_FE_VERIFY(r); + SECP256K1_FE_VERIFY(a); VERIFY_CHECK(r->magnitude + a->magnitude <= 32); + secp256k1_fe_impl_add(r, a); r->magnitude += a->magnitude; r->normalized = 0; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); 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(a); + SECP256K1_FE_VERIFY(b); + 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); r->magnitude = 1; r->normalized = 0; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } 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(a); + SECP256K1_FE_VERIFY_MAGNITUDE(a, 8); + secp256k1_fe_impl_sqr(r, a); r->magnitude = 1; r->normalized = 0; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { VERIFY_CHECK(flag == 0 || flag == 1); - secp256k1_fe_verify(a); - secp256k1_fe_verify(r); + SECP256K1_FE_VERIFY(a); + SECP256K1_FE_VERIFY(r); + secp256k1_fe_impl_cmov(r, a, flag); if (a->magnitude > r->magnitude) r->magnitude = a->magnitude; if (!a->normalized) r->normalized = 0; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { - secp256k1_fe_verify(a); + SECP256K1_FE_VERIFY(a); VERIFY_CHECK(a->normalized); + secp256k1_fe_impl_to_storage(r, a); } @@ -369,36 +391,42 @@ SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const se secp256k1_fe_impl_from_storage(r, a); r->magnitude = 1; r->normalized = 1; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x); SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) { int input_is_zero = secp256k1_fe_normalizes_to_zero(x); - secp256k1_fe_verify(x); + SECP256K1_FE_VERIFY(x); + secp256k1_fe_impl_inv(r, x); r->magnitude = x->magnitude > 0; r->normalized = 1; + VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); - secp256k1_fe_verify(r); + SECP256K1_FE_VERIFY(r); } static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x); SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) { int input_is_zero = secp256k1_fe_normalizes_to_zero(x); - secp256k1_fe_verify(x); + SECP256K1_FE_VERIFY(x); + secp256k1_fe_impl_inv_var(r, x); r->magnitude = x->magnitude > 0; r->normalized = 1; + VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero); - secp256k1_fe_verify(r); + SECP256K1_FE_VERIFY(r); } static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x); SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) { int ret; secp256k1_fe tmp = *x, sqrt; - secp256k1_fe_verify(x); + SECP256K1_FE_VERIFY(x); + ret = secp256k1_fe_impl_is_square_var(x); secp256k1_fe_normalize_weak(&tmp); VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp)); @@ -409,20 +437,24 @@ static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m); SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) { VERIFY_CHECK(m >= 0); VERIFY_CHECK(m <= 32); + secp256k1_fe_impl_get_bounds(r, m); r->magnitude = m; r->normalized = (m == 0); - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } 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(r); + SECP256K1_FE_VERIFY_MAGNITUDE(r, 31); + secp256k1_fe_impl_half(r); r->magnitude = (r->magnitude >> 1) + 1; r->normalized = 0; - secp256k1_fe_verify(r); + + SECP256K1_FE_VERIFY(r); } #endif /* defined(VERIFY) */ diff --git a/src/group.h b/src/group.h index 0aebafeb4c..81b159c818 100644 --- a/src/group.h +++ b/src/group.h @@ -44,6 +44,14 @@ typedef struct { #define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) +/** Maximum allowed magnitudes for group element coordinates + * in affine (x, y) and jacobian (x, y, z) representation. */ +#define SECP256K1_GE_X_MAGNITUDE_MAX 4 +#define SECP256K1_GE_Y_MAGNITUDE_MAX 3 +#define SECP256K1_GEJ_X_MAGNITUDE_MAX 4 +#define SECP256K1_GEJ_Y_MAGNITUDE_MAX 4 +#define SECP256K1_GEJ_Z_MAGNITUDE_MAX 1 + /** Set a group element equal to the point with given X and Y coordinates */ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); @@ -100,6 +108,9 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a */ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr); +/** Check two group elements (affine) for equality in variable time. */ +static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b); + /** Set a group element (affine) equal to the point at infinity. */ static void secp256k1_ge_set_infinity(secp256k1_ge *r); @@ -112,6 +123,9 @@ static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); /** Check two group elements (jacobian) for equality in variable time. */ static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b); +/** Check two group elements (jacobian and affine) for equality in variable time. */ +static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b); + /** Compare the X coordinate of a group element (jacobian). * The magnitude of the group element's X coordinate must not exceed 31. */ static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a); @@ -169,6 +183,14 @@ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_g /** Rescale a jacobian point by b which must be non-zero. Constant-time. */ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); +/** Convert a group element that is not infinity to a 64-byte array. The output + * array is platform-dependent. */ +static void secp256k1_ge_to_bytes(unsigned char *buf, secp256k1_ge *a); + +/** Convert a 64-byte array into group element. This function assumes that the + * provided buffer correctly encodes a group element. */ +static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf); + /** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve. * * In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the @@ -182,8 +204,10 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge); /** Check invariants on an affine group element (no-op unless VERIFY is enabled). */ static void secp256k1_ge_verify(const secp256k1_ge *a); +#define SECP256K1_GE_VERIFY(a) secp256k1_ge_verify(a) /** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */ static void secp256k1_gej_verify(const secp256k1_gej *a); +#define SECP256K1_GEJ_VERIFY(a) secp256k1_gej_verify(a) #endif /* SECP256K1_GROUP_H */ diff --git a/src/group_impl.h b/src/group_impl.h index 278ffd13f7..f27b7d994b 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -7,6 +7,8 @@ #ifndef SECP256K1_GROUP_IMPL_H #define SECP256K1_GROUP_IMPL_H +#include + #include "field.h" #include "group.h" #include "util.h" @@ -74,21 +76,22 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G; /* End of section generated by sage/gen_exhaustive_groups.sage. */ static void secp256k1_ge_verify(const secp256k1_ge *a) { -#ifdef VERIFY - secp256k1_fe_verify(&a->x); - secp256k1_fe_verify(&a->y); + 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; } static void secp256k1_gej_verify(const secp256k1_gej *a) { -#ifdef VERIFY - secp256k1_fe_verify(&a->x); - secp256k1_fe_verify(&a->y); - secp256k1_fe_verify(&a->z); + 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; } @@ -96,57 +99,67 @@ static void secp256k1_gej_verify(const secp256k1_gej *a) { static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { secp256k1_fe zi2; secp256k1_fe zi3; - secp256k1_gej_verify(a); - secp256k1_fe_verify(zi); + 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); + + SECP256K1_GE_VERIFY(r); } /* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */ static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) { secp256k1_fe zi2; secp256k1_fe zi3; - secp256k1_ge_verify(a); - secp256k1_fe_verify(zi); + 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); + + 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); + SECP256K1_FE_VERIFY(x); + SECP256K1_FE_VERIFY(y); + r->infinity = 0; r->x = *x; r->y = *y; - secp256k1_ge_verify(r); + + SECP256K1_GE_VERIFY(r); } static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { - secp256k1_ge_verify(a); + SECP256K1_GE_VERIFY(a); + return a->infinity; } static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { - secp256k1_ge_verify(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); + + SECP256K1_GE_VERIFY(r); } static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { secp256k1_fe z2, z3; - secp256k1_gej_verify(a); + SECP256K1_GEJ_VERIFY(a); + r->infinity = a->infinity; secp256k1_fe_inv(&a->z, &a->z); secp256k1_fe_sqr(&z2, &a->z); @@ -156,12 +169,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_ge_verify(r); + + 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); + SECP256K1_GEJ_VERIFY(a); + if (secp256k1_gej_is_infinity(a)) { secp256k1_ge_set_infinity(r); return; @@ -174,16 +190,22 @@ 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_ge_verify(r); + + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(r); } static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) { 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++) { - secp256k1_gej_verify(&a[i]); if (a[i].infinity) { secp256k1_ge_set_infinity(&r[i]); } else { @@ -217,36 +239,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); } - secp256k1_ge_verify(&r[i]); } + +#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; +#ifdef VERIFY + for (i = 0; i < len; i++) { + SECP256K1_GE_VERIFY(&a[i]); + SECP256K1_FE_VERIFY(&zr[i]); + } +#endif if (len > 0) { - /* Verify inputs a[len-1] and zr[len-1]. */ - secp256k1_ge_verify(&a[i]); - secp256k1_fe_verify(&zr[i]); + 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,14 +286,16 @@ 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); + + SECP256K1_GEJ_VERIFY(r); } 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); + + SECP256K1_GE_VERIFY(r); } static void secp256k1_gej_clear(secp256k1_gej *r) { @@ -269,23 +303,32 @@ 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_xquad(secp256k1_ge *r, const secp256k1_fe *x) { secp256k1_fe x2, x3; - secp256k1_fe_verify(x); + int ret; + SECP256K1_FE_VERIFY(x); + r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; secp256k1_fe_add_int(&x3, SECP256K1_B); - return secp256k1_fe_sqrt(&r->y, &x3); + ret = secp256k1_fe_sqrt(&r->y, &x3); + + SECP256K1_GE_VERIFY(r); + return ret; } static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { @@ -295,61 +338,94 @@ 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); + + SECP256K1_GE_VERIFY(r); return ret; } static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { - secp256k1_ge_verify(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); + + SECP256K1_GEJ_VERIFY(r); } 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_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); } +static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b) { + secp256k1_gej tmp; + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + + secp256k1_gej_neg(&tmp, a); + secp256k1_gej_add_ge_var(&tmp, &tmp, b, NULL); + return secp256k1_gej_is_infinity(&tmp); +} + +static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b) { + secp256k1_fe tmp; + SECP256K1_GE_VERIFY(a); + SECP256K1_GE_VERIFY(b); + + if (a->infinity != b->infinity) return 0; + if (a->infinity) return 1; + + tmp = a->x; + secp256k1_fe_normalize_weak(&tmp); + if (!secp256k1_fe_equal(&tmp, &b->x)) return 0; + + tmp = a->y; + secp256k1_fe_normalize_weak(&tmp); + if (!secp256k1_fe_equal(&tmp, &b->y)) return 0; + + return 1; +} + 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); + SECP256K1_FE_VERIFY(x); + SECP256K1_GEJ_VERIFY(a); 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); + 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); + + SECP256K1_GEJ_VERIFY(r); } static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { - secp256k1_gej_verify(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); + SECP256K1_GE_VERIFY(a); + if (a->infinity) { return 0; } @@ -357,14 +433,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); - secp256k1_gej_verify(a); r->infinity = a->infinity; /* Formula used: @@ -391,10 +467,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); + + 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. @@ -405,7 +484,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) { @@ -420,15 +498,16 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s } secp256k1_gej_double(r, a); - secp256k1_gej_verify(r); + + 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); - secp256k1_gej_verify(a); - secp256k1_gej_verify(b); if (a->infinity) { VERIFY_CHECK(rzr == NULL); *r = *b; @@ -483,14 +562,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); + + 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); + SECP256K1_GEJ_VERIFY(a); + SECP256K1_GE_VERIFY(b); + if (a->infinity) { VERIFY_CHECK(rzr == NULL); secp256k1_gej_set_ge(r, b); @@ -505,11 +586,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)) { @@ -543,16 +624,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); + + 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); - secp256k1_ge_verify(b); - secp256k1_fe_verify(bzinv); if (a->infinity) { secp256k1_fe bzinv2, bzinv3; r->infinity = b->infinity; @@ -561,6 +644,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) { @@ -579,11 +663,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)) { @@ -611,19 +695,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); + + 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); + 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. @@ -676,17 +760,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); @@ -696,24 +780,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) */ @@ -721,9 +806,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); @@ -747,29 +833,31 @@ 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); + + SECP256K1_GEJ_VERIFY(r); } static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { /* Operations: 4 mul, 1 sqr */ secp256k1_fe zz; - secp256k1_gej_verify(r); - secp256k1_fe_verify(s); -#ifdef VERIFY + SECP256K1_GEJ_VERIFY(r); + SECP256K1_FE_VERIFY(s); 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); + + SECP256K1_GEJ_VERIFY(r); } static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { secp256k1_fe x, y; - secp256k1_ge_verify(a); + SECP256K1_GE_VERIFY(a); VERIFY_CHECK(!a->infinity); + x = a->x; secp256k1_fe_normalize(&x); y = a->y; @@ -782,18 +870,20 @@ 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); + + 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_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); + + SECP256K1_GEJ_VERIFY(r); } static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { @@ -802,10 +892,12 @@ 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) { + SECP256K1_GE_VERIFY(a); + *r = *a; - secp256k1_ge_verify(a); secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta); - secp256k1_ge_verify(r); + + SECP256K1_GE_VERIFY(r); } static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) { @@ -826,8 +918,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); - 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) { @@ -838,6 +930,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; @@ -858,9 +952,8 @@ static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp25 * (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square). */ secp256k1_fe r, t; -#ifdef VERIFY VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd)); -#endif + secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */ secp256k1_fe_sqr(&t, xn); /* t = xn^2 */ secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */ @@ -872,4 +965,24 @@ static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp25 return secp256k1_fe_is_square_var(&r); } +static void secp256k1_ge_to_bytes(unsigned char *buf, secp256k1_ge *a) { + secp256k1_ge_storage s; + + /* We require that the secp256k1_ge_storage type is exactly 64 bytes. + * This is formally not guaranteed by the C standard, but should hold on any + * sane compiler in the real world. */ + STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); + VERIFY_CHECK(!secp256k1_ge_is_infinity(a)); + secp256k1_ge_to_storage(&s, a); + memcpy(buf, &s, 64); +} + +static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf) { + secp256k1_ge_storage s; + + STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); + memcpy(&s, buf, 64); + secp256k1_ge_from_storage(r, &s); +} + #endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/src/modinv32_impl.h b/src/modinv32_impl.h index 0ea2699863..75eb354ff0 100644 --- a/src/modinv32_impl.h +++ b/src/modinv32_impl.h @@ -144,7 +144,6 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3 r->v[7] = r7; r->v[8] = r8; -#ifdef VERIFY VERIFY_CHECK(r0 >> 30 == 0); VERIFY_CHECK(r1 >> 30 == 0); VERIFY_CHECK(r2 >> 30 == 0); @@ -156,7 +155,6 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3 VERIFY_CHECK(r8 >> 30 == 0); VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 0) >= 0); /* r >= 0 */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */ -#endif } /* Data type for transition matrices (see section 3 of explanation). @@ -413,14 +411,13 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp int32_t di, ei, md, me, sd, se; int64_t cd, ce; int i; -#ifdef VERIFY VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */ VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */ -#endif + /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ sd = d->v[8] >> 31; se = e->v[8] >> 31; @@ -455,12 +452,11 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp /* What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. */ d->v[8] = (int32_t)cd; e->v[8] = (int32_t)ce; -#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ -#endif } /* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps. @@ -550,25 +546,23 @@ static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_m /* Update d,e using that transition matrix. */ secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo); /* Update f,g using that transition matrix. */ -#ifdef VERIFY VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif + secp256k1_modinv32_update_fg_30(&f, &g, &t); -#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif } /* At this point sufficient iterations have been performed that g must have reached 0 * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g * values i.e. +/- 1, and d now contains +/- the modular inverse. */ -#ifdef VERIFY + /* g == 0 */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0); /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ @@ -578,7 +572,6 @@ static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_m secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && (secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0 || secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) == 0))); -#endif /* Optionally negate d, normalize to [0,modulus), and return it. */ secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo); @@ -607,12 +600,12 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256 /* Update d,e using that transition matrix. */ secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo); /* Update f,g using that transition matrix. */ -#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif + secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t); /* If the bottom limb of g is 0, there is a chance g=0. */ if (g.v[0] == 0) { @@ -637,18 +630,17 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256 g.v[len - 2] |= (uint32_t)gn << 30; --len; } -#ifdef VERIFY + VERIFY_CHECK(++i < 25); /* We should never need more than 25*30 = 750 divsteps */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif } /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ -#ifdef VERIFY + /* g == 0 */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0); /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ @@ -658,7 +650,6 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256 secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 && (secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0 || secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) == 0))); -#endif /* Optionally negate d, normalize to [0,modulus), and return it. */ secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo); @@ -697,12 +688,11 @@ static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, co secp256k1_modinv32_trans2x2 t; eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac); /* Update f,g using that transition matrix. */ -#ifdef VERIFY VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif + secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t); /* If the bottom limb of f is 1, there is a chance that f=1. */ if (f.v[0] == 1) { @@ -723,12 +713,11 @@ static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, co cond |= gn; /* If so, reduce length. */ if (cond == 0) --len; -#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif } /* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */ diff --git a/src/modinv64_impl.h b/src/modinv64_impl.h index c7cef872a4..0dc1e80696 100644 --- a/src/modinv64_impl.h +++ b/src/modinv64_impl.h @@ -144,7 +144,6 @@ static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int6 r->v[3] = r3; r->v[4] = r4; -#ifdef VERIFY VERIFY_CHECK(r0 >> 62 == 0); VERIFY_CHECK(r1 >> 62 == 0); VERIFY_CHECK(r2 >> 62 == 0); @@ -152,7 +151,6 @@ static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int6 VERIFY_CHECK(r4 >> 62 == 0); VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 0) >= 0); /* r >= 0 */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */ -#endif } /* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)). @@ -216,7 +214,7 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_ t->v = (int64_t)v; t->q = (int64_t)q; t->r = (int64_t)r; -#ifdef VERIFY + /* The determinant of t must be a power of two. This guarantees that multiplication with t * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which * will be divided out again). As each divstep's individual matrix has determinant 2, the @@ -224,7 +222,7 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_ * 8*identity (which has determinant 2^6) means the overall outputs has determinant * 2^65. */ VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0)); -#endif + return zeta; } @@ -301,13 +299,13 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint t->v = (int64_t)v; t->q = (int64_t)q; t->r = (int64_t)r; -#ifdef VERIFY + /* The determinant of t must be a power of two. This guarantees that multiplication with t * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which * will be divided out again). As each divstep's individual matrix has determinant 2, the * aggregate of 62 of them will have determinant 2^62. */ VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0)); -#endif + return eta; } @@ -392,13 +390,13 @@ static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, u t->v = (int64_t)v; t->q = (int64_t)q; t->r = (int64_t)r; -#ifdef VERIFY + /* The determinant of t must be a power of two. This guarantees that multiplication with t * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which * will be divided out again). As each divstep's individual matrix has determinant 2 or -2, * the aggregate of 62 of them will have determinant 2^62 or -2^62. */ VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1)); -#endif + *jacp = jac; return eta; } @@ -417,14 +415,13 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp const int64_t u = t->u, v = t->v, q = t->q, r = t->r; int64_t md, me, sd, se; secp256k1_int128 cd, ce; -#ifdef VERIFY VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */ VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */ -#endif + /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ sd = d4 >> 63; se = e4 >> 63; @@ -489,12 +486,11 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp /* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */ d->v[4] = secp256k1_i128_to_i64(&cd); e->v[4] = secp256k1_i128_to_i64(&ce); -#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ -#endif } /* Compute (t/2^62) * [f, g], where t is a transition matrix scaled by 2^62. @@ -606,25 +602,23 @@ static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_m /* Update d,e using that transition matrix. */ secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo); /* Update f,g using that transition matrix. */ -#ifdef VERIFY VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif + secp256k1_modinv64_update_fg_62(&f, &g, &t); -#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif } /* At this point sufficient iterations have been performed that g must have reached 0 * and (if g was not originally 0) f must now equal +/- GCD of the initial f, g * values i.e. +/- 1, and d now contains +/- the modular inverse. */ -#ifdef VERIFY + /* g == 0 */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0); /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ @@ -634,7 +628,6 @@ static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_m secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && (secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0 || secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) == 0))); -#endif /* Optionally negate d, normalize to [0,modulus), and return it. */ secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo); @@ -663,12 +656,11 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256 /* Update d,e using that transition matrix. */ secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo); /* Update f,g using that transition matrix. */ -#ifdef VERIFY VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif + secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t); /* If the bottom limb of g is zero, there is a chance that g=0. */ if (g.v[0] == 0) { @@ -693,18 +685,17 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256 g.v[len - 2] |= (uint64_t)gn << 62; --len; } -#ifdef VERIFY + VERIFY_CHECK(++i < 12); /* We should never need more than 12*62 = 744 divsteps */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif } /* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of * the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */ -#ifdef VERIFY + /* g == 0 */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0); /* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */ @@ -714,7 +705,6 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256 secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 && (secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0 || secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) == 0))); -#endif /* Optionally negate d, normalize to [0,modulus), and return it. */ secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo); @@ -753,12 +743,11 @@ static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, co secp256k1_modinv64_trans2x2 t; eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac); /* Update f,g using that transition matrix. */ -#ifdef VERIFY VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif + secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t); /* If the bottom limb of f is 1, there is a chance that f=1. */ if (f.v[0] == 1) { @@ -779,12 +768,11 @@ static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, co cond |= gn; /* If so, reduce length. */ if (cond == 0) --len; -#ifdef VERIFY + VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */ -#endif } /* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */ diff --git a/src/modules/bppp/bppp_norm_product_impl.h b/src/modules/bppp/bppp_norm_product_impl.h index 848e8cde3b..daf7b0da74 100644 --- a/src/modules/bppp/bppp_norm_product_impl.h +++ b/src/modules/bppp/bppp_norm_product_impl.h @@ -118,7 +118,11 @@ static int secp256k1_bppp_commit( secp256k1_scalar v, l_c; /* First n_vec_len generators are Gs, rest are Hs*/ VERIFY_CHECK(g_vec->n == (n_vec_len + l_vec_len)); +#ifdef VERIFY VERIFY_CHECK(l_vec_len == c_vec_len); +#else + (void)c_vec_len; +#endif /* It is possible to extend to support n_vec and c_vec to not be power of two. For the initial iterations of the code, we stick to powers of two for simplicity.*/ @@ -238,17 +242,23 @@ static int secp256k1_bppp_rangeproof_norm_product_prove( ecmult_r_cb_data r_cb_data; size_t g_len = n_vec_len, h_len = l_vec_len; const size_t G_GENS_LEN = g_len; - size_t log_g_len, log_h_len; - size_t num_rounds; - VERIFY_CHECK(g_len > 0 && h_len > 0); - log_g_len = secp256k1_bppp_log2(g_len); - log_h_len = secp256k1_bppp_log2(h_len); - num_rounds = log_g_len > log_h_len ? log_g_len : log_h_len; - /* Check proof sizes.*/ - VERIFY_CHECK(*proof_len >= 65 * num_rounds + 64); - VERIFY_CHECK(g_vec_len == (n_vec_len + l_vec_len) && l_vec_len == c_vec_len); - VERIFY_CHECK(secp256k1_is_power_of_two(n_vec_len) && secp256k1_is_power_of_two(c_vec_len)); +#ifdef VERIFY + { + size_t log_g_len_ver, log_h_len_ver, num_rounds_ver; + VERIFY_CHECK(g_len > 0 && h_len > 0); /* Precondition for secp256k1_bppp_log2() */ + log_g_len_ver = secp256k1_bppp_log2(g_len); + log_h_len_ver = secp256k1_bppp_log2(h_len); + num_rounds_ver = log_g_len_ver > log_h_len_ver ? log_g_len_ver : log_h_len_ver; + /* Check proof sizes.*/ + VERIFY_CHECK(*proof_len >= 65 * num_rounds_ver + 64); + VERIFY_CHECK(g_vec_len == (n_vec_len + l_vec_len) && l_vec_len == c_vec_len); + VERIFY_CHECK(secp256k1_is_power_of_two(n_vec_len) && secp256k1_is_power_of_two(c_vec_len)); + } +#else + (void)g_vec_len; + (void)c_vec_len; +#endif x_cb_data.n = n_vec; x_cb_data.g = g_vec; @@ -536,9 +546,6 @@ static int secp256k1_bppp_rangeproof_norm_product_verify( secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint); - /* res1 and res2 should be equal. Could not find a simpler way to compare them */ - secp256k1_gej_neg(&res1, &res1); - secp256k1_gej_add_var(&res1, &res1, &res2, NULL); - return secp256k1_gej_is_infinity(&res1); + return secp256k1_gej_eq_var(&res1, &res2); } #endif diff --git a/src/modules/bppp/tests_impl.h b/src/modules/bppp/tests_impl.h index b55f158ec7..2ee2ac98c4 100644 --- a/src/modules/bppp/tests_impl.h +++ b/src/modules/bppp/tests_impl.h @@ -22,31 +22,19 @@ static void test_bppp_generators_api(void) { unsigned char gens_ser[330]; size_t len = sizeof(gens_ser); - int32_t ecount = 0; - - /* The BP generator API requires no precomp */ - secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - /* Create */ gens = secp256k1_bppp_generators_create(CTX, 10); - CHECK(gens != NULL && ecount == 0); + CHECK(gens != NULL); gens_orig = gens; /* Preserve for round-trip test */ /* Serialize */ - ecount = 0; - CHECK(!secp256k1_bppp_generators_serialize(CTX, NULL, gens_ser, &len)); - CHECK(ecount == 1); - CHECK(!secp256k1_bppp_generators_serialize(CTX, gens, NULL, &len)); - CHECK(ecount == 2); - CHECK(!secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, NULL)); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_bppp_generators_serialize(CTX, NULL, gens_ser, &len)); + CHECK_ILLEGAL(CTX, secp256k1_bppp_generators_serialize(CTX, gens, NULL, &len)); + CHECK_ILLEGAL(CTX, secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, NULL)); len = 0; - CHECK(!secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len)); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len)); len = sizeof(gens_ser) - 1; - CHECK(!secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len)); - CHECK(ecount == 5); + CHECK_ILLEGAL(CTX, secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len)); len = sizeof(gens_ser); { /* Output buffer can be greater than minimum needed */ @@ -54,39 +42,31 @@ static void test_bppp_generators_api(void) { size_t len_tmp = sizeof(gens_ser_tmp); CHECK(secp256k1_bppp_generators_serialize(CTX, gens, gens_ser_tmp, &len_tmp)); CHECK(len_tmp == sizeof(gens_ser_tmp) - 1); - CHECK(ecount == 5); } /* Parse */ CHECK(secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len)); - ecount = 0; - gens = secp256k1_bppp_generators_parse(CTX, NULL, sizeof(gens_ser)); - CHECK(gens == NULL && ecount == 1); + CHECK_ILLEGAL_VOID(CTX, gens = secp256k1_bppp_generators_parse(CTX, NULL, sizeof(gens_ser)); + CHECK(gens == NULL)); /* Not a multiple of 33 */ gens = secp256k1_bppp_generators_parse(CTX, gens_ser, sizeof(gens_ser) - 1); - CHECK(gens == NULL && ecount == 1); + CHECK(gens == NULL); gens = secp256k1_bppp_generators_parse(CTX, gens_ser, sizeof(gens_ser)); - CHECK(gens != NULL && ecount == 1); + CHECK(gens != NULL); /* Not valid generators */ memset(gens_ser, 1, sizeof(gens_ser)); CHECK(secp256k1_bppp_generators_parse(CTX, gens_ser, sizeof(gens_ser)) == NULL); - CHECK(ecount == 1); /* Check that round-trip succeeded */ CHECK(gens->n == gens_orig->n); for (len = 0; len < gens->n; len++) { - ge_equals_ge(&gens->gens[len], &gens_orig->gens[len]); + secp256k1_ge_eq_var(&gens->gens[len], &gens_orig->gens[len]); } /* Destroy (we allow destroying a NULL context, it's just a noop. like free().) */ - ecount = 0; secp256k1_bppp_generators_destroy(CTX, NULL); secp256k1_bppp_generators_destroy(CTX, gens); secp256k1_bppp_generators_destroy(CTX, gens_orig); - CHECK(ecount == 0); - - secp256k1_context_set_error_callback(CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); } static void test_bppp_generators_fixed(void) { @@ -113,11 +93,11 @@ static void test_bppp_generators_fixed(void) { len = 99; CHECK(secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len)); - CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0); + CHECK(secp256k1_memcmp_var(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0); len = sizeof(gens_ser); CHECK(secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len)); - CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0); + CHECK(secp256k1_memcmp_var(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0); secp256k1_bppp_generators_destroy(CTX, gens); } @@ -144,7 +124,7 @@ static void test_bppp_tagged_hash(void) { secp256k1_bppp_sha256_tagged_commitment_init(&sha); secp256k1_bppp_challenge_scalar(&s, &sha, 0); secp256k1_scalar_get_b32(output, &s); - CHECK(memcmp(output, expected, sizeof(output)) == 0); + CHECK(secp256k1_memcmp_var(output, expected, sizeof(output)) == 0); } { @@ -156,7 +136,7 @@ static void test_bppp_tagged_hash(void) { secp256k1_sha256_write(&sha, tmp, sizeof(tmp)); secp256k1_bppp_challenge_scalar(&s, &sha, 0); secp256k1_scalar_get_b32(output, &s); - CHECK(memcmp(output, expected, sizeof(output)) == 0); + CHECK(secp256k1_memcmp_var(output, expected, sizeof(output)) == 0); } } @@ -219,8 +199,8 @@ static void test_serialize_two_points_roundtrip(secp256k1_ge *X, secp256k1_ge *R secp256k1_bppp_serialize_points(buf, X, R); CHECK(secp256k1_bppp_parse_one_of_points(&X_tmp, buf, 0)); CHECK(secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 1)); - ge_equals_ge(X, &X_tmp); - ge_equals_ge(R, &R_tmp); + secp256k1_ge_eq_var(X, &X_tmp); + secp256k1_ge_eq_var(R, &R_tmp); } static void test_serialize_two_points(void) { diff --git a/src/modules/ecdh/tests_impl.h b/src/modules/ecdh/tests_impl.h index fa6f232227..6be96eacbe 100644 --- a/src/modules/ecdh/tests_impl.h +++ b/src/modules/ecdh/tests_impl.h @@ -25,32 +25,19 @@ static int ecdh_hash_function_custom(unsigned char *output, const unsigned char } static void test_ecdh_api(void) { - /* Setup context that just counts errors */ - secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); secp256k1_pubkey point; unsigned char res[32]; unsigned char s_one[32] = { 0 }; - int32_t ecount = 0; s_one[31] = 1; - secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount); - CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1); + CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1); /* Check all NULLs are detected */ - CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1); - CHECK(ecount == 3); - - /* Cleanup */ - secp256k1_context_destroy(tctx); + CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, NULL, &point, s_one, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, NULL, s_one, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, &point, NULL, NULL, NULL)); + CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1); } static void test_ecdh_generator_basepoint(void) { diff --git a/src/modules/ecdsa_adaptor/tests_impl.h b/src/modules/ecdsa_adaptor/tests_impl.h index e07757f33b..c3b3d43d73 100644 --- a/src/modules/ecdsa_adaptor/tests_impl.h +++ b/src/modules/ecdsa_adaptor/tests_impl.h @@ -824,13 +824,6 @@ static void test_ecdsa_adaptor_api(void) { unsigned char deckey[32]; /** setup **/ - int ecount; - - secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_testrand256(sk); secp256k1_testrand256(msg); secp256k1_testrand256(deckey); @@ -839,70 +832,37 @@ static void test_ecdsa_adaptor_api(void) { memset(&zero_pk, 0, sizeof(zero_pk)); /** main test body **/ - ecount = 0; CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, &enckey, msg, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_adaptor_encrypt(STATIC_CTX, asig, sk, &enckey, msg, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, NULL, sk, &enckey, msg, NULL, NULL) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, &enckey, NULL, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, asig, NULL, &enckey, msg, NULL, NULL) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, NULL, msg, NULL, NULL) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, &zero_pk, msg, NULL, NULL) == 0); - CHECK(ecount == 6); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_adaptor_encrypt(STATIC_CTX, asig, sk, &enckey, msg, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_encrypt(CTX, NULL, sk, &enckey, msg, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, &enckey, NULL, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_encrypt(CTX, asig, NULL, &enckey, msg, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, NULL, msg, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, &zero_pk, msg, NULL, NULL)); - ecount = 0; CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, &enckey, msg, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_adaptor_verify(CTX, asig, &pubkey, msg, &enckey) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_adaptor_verify(CTX, NULL, &pubkey, msg, &enckey) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_adaptor_verify(CTX, asig, &pubkey, NULL, &enckey) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_adaptor_verify(CTX, asig, &pubkey, msg, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_adaptor_verify(CTX, asig, NULL, msg, &enckey) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_adaptor_verify(CTX, asig, &zero_pk, msg, &enckey) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_adaptor_verify(CTX, asig, &pubkey, msg, &zero_pk) == 0); - CHECK(ecount == 6); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_verify(CTX, NULL, &pubkey, msg, &enckey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_verify(CTX, asig, &pubkey, NULL, &enckey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_verify(CTX, asig, &pubkey, msg, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_verify(CTX, asig, NULL, msg, &enckey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_verify(CTX, asig, &zero_pk, msg, &enckey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_verify(CTX, asig, &pubkey, msg, &zero_pk)); - ecount = 0; CHECK(secp256k1_ecdsa_adaptor_decrypt(CTX, &sig, deckey, asig) == 1); CHECK(secp256k1_ecdsa_adaptor_decrypt(CTX, &sig, deckey, asig) == 1); - CHECK(secp256k1_ecdsa_adaptor_decrypt(CTX, NULL, deckey, asig) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_adaptor_decrypt(CTX, &sig, NULL, asig) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_adaptor_decrypt(CTX, &sig, deckey, NULL) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_decrypt(CTX, NULL, deckey, asig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_decrypt(CTX, &sig, NULL, asig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_decrypt(CTX, &sig, deckey, NULL)); - ecount = 0; CHECK(secp256k1_ecdsa_adaptor_decrypt(CTX, &sig, deckey, asig) == 1); CHECK(secp256k1_ecdsa_adaptor_recover(CTX, deckey, &sig, asig, &enckey) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_adaptor_recover(STATIC_CTX, deckey, &sig, asig, &enckey) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_adaptor_recover(CTX, NULL, &sig, asig, &enckey) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_adaptor_recover(CTX, deckey, NULL, asig, &enckey) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_adaptor_recover(CTX, deckey, &sig, NULL, &enckey) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_adaptor_recover(CTX, deckey, &sig, asig, NULL) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_adaptor_recover(CTX, deckey, &sig, asig, &zero_pk) == 0); - CHECK(ecount == 6); - - secp256k1_context_set_error_callback(CTX, NULL, NULL); - secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_adaptor_recover(STATIC_CTX, deckey, &sig, asig, &enckey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_recover(CTX, NULL, &sig, asig, &enckey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_recover(CTX, deckey, NULL, asig, &enckey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_recover(CTX, deckey, &sig, NULL, &enckey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_recover(CTX, deckey, &sig, asig, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_recover(CTX, deckey, &sig, asig, &zero_pk)); } static void adaptor_tests(void) { diff --git a/src/modules/ecdsa_s2c/tests_impl.h b/src/modules/ecdsa_s2c/tests_impl.h index 27d270068b..7bbd8770eb 100644 --- a/src/modules/ecdsa_s2c/tests_impl.h +++ b/src/modules/ecdsa_s2c/tests_impl.h @@ -41,34 +41,25 @@ static void run_s2c_opening_test(void) { 0x02 }; secp256k1_ecdsa_s2c_opening opening; - int32_t ecount = 0; - - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); /* First parsing, then serializing works */ CHECK(secp256k1_ecdsa_s2c_opening_parse(CTX, &opening, input) == 1); CHECK(secp256k1_ecdsa_s2c_opening_serialize(CTX, output, &opening) == 1); CHECK(secp256k1_ecdsa_s2c_opening_parse(CTX, &opening, input) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_s2c_opening_parse(CTX, NULL, input) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_s2c_opening_parse(CTX, &opening, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_opening_parse(CTX, NULL, input)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_opening_parse(CTX, &opening, NULL)); CHECK(secp256k1_ecdsa_s2c_opening_parse(CTX, &opening, input) == 1); - CHECK(secp256k1_ecdsa_s2c_opening_serialize(CTX, NULL, &opening) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_s2c_opening_serialize(CTX, output, NULL) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_opening_serialize(CTX, NULL, &opening)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_opening_serialize(CTX, output, NULL)); - CHECK(ecount == 4); - /* Invalid pubkey makes parsing fail */ + /* Invalid pubkey makes parsing fail but they are not API errors */ input[0] = 0; /* bad oddness bit */ CHECK(secp256k1_ecdsa_s2c_opening_parse(CTX, &opening, input) == 0); input[0] = 2; input[31] = 1; /* point not on the curve */ CHECK(secp256k1_ecdsa_s2c_opening_parse(CTX, &opening, input) == 0); - CHECK(ecount == 4); /* neither of the above are API errors */ /* Try parsing and serializing a bunch of openings */ for (i = 0; i < COUNT; i++) { @@ -82,8 +73,6 @@ static void run_s2c_opening_test(void) { /* Set pubkey oddness tag to first bit of input[1] */ input[0] = (input[1] & 1) + 2; } - - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); } static void test_ecdsa_s2c_api(void) { @@ -96,98 +85,55 @@ static void test_ecdsa_s2c_api(void) { unsigned char hostrand_commitment[32]; secp256k1_pubkey pk; - int32_t ecount; - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sec)); - ecount = 0; - CHECK(secp256k1_ecdsa_s2c_sign(CTX, NULL, &s2c_opening, msg, sec, s2c_data) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_sign(CTX, NULL, &s2c_opening, msg, sec, s2c_data)); + /* NULL opening is not an API error */ CHECK(secp256k1_ecdsa_s2c_sign(CTX, &sig, NULL, msg, sec, s2c_data) == 1); - CHECK(ecount == 1); /* NULL opening is not an API error */ - CHECK(secp256k1_ecdsa_s2c_sign(CTX, &sig, &s2c_opening, NULL, sec, s2c_data) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_s2c_sign(CTX, &sig, &s2c_opening, msg, NULL, s2c_data) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_s2c_sign(CTX, &sig, &s2c_opening, msg, sec, NULL) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_sign(CTX, &sig, &s2c_opening, NULL, sec, s2c_data)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_sign(CTX, &sig, &s2c_opening, msg, NULL, s2c_data)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_sign(CTX, &sig, &s2c_opening, msg, sec, NULL)); CHECK(secp256k1_ecdsa_s2c_sign(CTX, &sig, &s2c_opening, msg, sec, s2c_data) == 1); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_s2c_sign(STATIC_CTX, &sig, &s2c_opening, msg, sec, s2c_data) == 0); - CHECK(ecount == 5); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_s2c_sign(STATIC_CTX, &sig, &s2c_opening, msg, sec, s2c_data)); CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pk) == 1); - ecount = 0; - CHECK(secp256k1_ecdsa_s2c_verify_commit(CTX, NULL, s2c_data, &s2c_opening) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_s2c_verify_commit(CTX, &sig, NULL, &s2c_opening) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_s2c_verify_commit(CTX, &sig, s2c_data, NULL) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_verify_commit(CTX, NULL, s2c_data, &s2c_opening)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_verify_commit(CTX, &sig, NULL, &s2c_opening)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_s2c_verify_commit(CTX, &sig, s2c_data, NULL)); CHECK(secp256k1_ecdsa_s2c_verify_commit(CTX, &sig, s2c_data, &s2c_opening) == 1); - CHECK(ecount == 3); + /* wrong data is not an API error */ CHECK(secp256k1_ecdsa_s2c_verify_commit(CTX, &sig, sec, &s2c_opening) == 0); - CHECK(ecount == 3); /* wrong data is not an API error */ /* Signing with NULL s2c_opening gives the same result */ CHECK(secp256k1_ecdsa_s2c_sign(CTX, &sig, NULL, msg, sec, s2c_data) == 1); CHECK(secp256k1_ecdsa_s2c_verify_commit(CTX, &sig, s2c_data, &s2c_opening) == 1); /* anti-exfil */ - ecount = 0; - CHECK(secp256k1_ecdsa_anti_exfil_host_commit(CTX, NULL, hostrand) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_anti_exfil_host_commit(CTX, hostrand_commitment, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_anti_exfil_host_commit(CTX, NULL, hostrand)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_anti_exfil_host_commit(CTX, hostrand_commitment, NULL)); CHECK(secp256k1_ecdsa_anti_exfil_host_commit(CTX, hostrand_commitment, hostrand) == 1); - CHECK(ecount == 2); - ecount = 0; - CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(CTX, NULL, msg, sec, hostrand_commitment) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(CTX, &s2c_opening, NULL, sec, hostrand_commitment) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(CTX, &s2c_opening, msg, NULL, hostrand_commitment) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(CTX, &s2c_opening, msg, sec, NULL) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_anti_exfil_signer_commit(CTX, NULL, msg, sec, hostrand_commitment)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_anti_exfil_signer_commit(CTX, &s2c_opening, NULL, sec, hostrand_commitment)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_anti_exfil_signer_commit(CTX, &s2c_opening, msg, NULL, hostrand_commitment)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_anti_exfil_signer_commit(CTX, &s2c_opening, msg, sec, NULL)); CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(CTX, &s2c_opening, msg, sec, hostrand_commitment) == 1); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(STATIC_CTX, &s2c_opening, msg, sec, hostrand_commitment) == 0); - CHECK(ecount == 5); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_anti_exfil_signer_commit(STATIC_CTX, &s2c_opening, msg, sec, hostrand_commitment)); - ecount = 0; - CHECK(secp256k1_anti_exfil_sign(CTX, NULL, msg, sec, hostrand) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_anti_exfil_sign(CTX, &sig, NULL, sec, hostrand) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_anti_exfil_sign(CTX, &sig, msg, NULL, hostrand) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_anti_exfil_sign(CTX, &sig, msg, sec, NULL) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_anti_exfil_sign(CTX, NULL, msg, sec, hostrand)); + CHECK_ILLEGAL(CTX, secp256k1_anti_exfil_sign(CTX, &sig, NULL, sec, hostrand)); + CHECK_ILLEGAL(CTX, secp256k1_anti_exfil_sign(CTX, &sig, msg, NULL, hostrand)); + CHECK_ILLEGAL(CTX, secp256k1_anti_exfil_sign(CTX, &sig, msg, sec, NULL)); CHECK(secp256k1_anti_exfil_sign(CTX, &sig, msg, sec, hostrand) == 1); - CHECK(ecount == 4); - CHECK(secp256k1_anti_exfil_sign(STATIC_CTX, &sig, msg, sec, hostrand) == 0); - CHECK(ecount == 5); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_anti_exfil_sign(STATIC_CTX, &sig, msg, sec, hostrand)); - ecount = 0; - CHECK(secp256k1_anti_exfil_host_verify(CTX, NULL, msg, &pk, hostrand, &s2c_opening) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_anti_exfil_host_verify(CTX, &sig, NULL, &pk, hostrand, &s2c_opening) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_anti_exfil_host_verify(CTX, &sig, msg, NULL, hostrand, &s2c_opening) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_anti_exfil_host_verify(CTX, &sig, msg, &pk, NULL, &s2c_opening) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_anti_exfil_host_verify(CTX, &sig, msg, &pk, hostrand, NULL) == 0); - CHECK(ecount == 5); + CHECK_ILLEGAL(CTX, secp256k1_anti_exfil_host_verify(CTX, NULL, msg, &pk, hostrand, &s2c_opening)); + CHECK_ILLEGAL(CTX, secp256k1_anti_exfil_host_verify(CTX, &sig, NULL, &pk, hostrand, &s2c_opening)); + CHECK_ILLEGAL(CTX, secp256k1_anti_exfil_host_verify(CTX, &sig, msg, NULL, hostrand, &s2c_opening)); + CHECK_ILLEGAL(CTX, secp256k1_anti_exfil_host_verify(CTX, &sig, msg, &pk, NULL, &s2c_opening)); + CHECK_ILLEGAL(CTX, secp256k1_anti_exfil_host_verify(CTX, &sig, msg, &pk, hostrand, NULL)); CHECK(secp256k1_anti_exfil_host_verify(CTX, &sig, msg, &pk, hostrand, &s2c_opening) == 1); - CHECK(ecount == 5); - - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); } /* When using sign-to-contract commitments, the nonce function is fixed, so we can use fixtures to test. */ diff --git a/src/modules/ellswift/main_impl.h b/src/modules/ellswift/main_impl.h index 00bb8a3da5..b54ec08a22 100644 --- a/src/modules/ellswift/main_impl.h +++ b/src/modules/ellswift/main_impl.h @@ -126,9 +126,8 @@ static void secp256k1_ellswift_xswiftec_frac_var(secp256k1_fe *xn, secp256k1_fe secp256k1_fe_mul(&l, &p, &u1); /* l = u*(g+s) */ secp256k1_fe_add(&n, &l); /* n = u*(c1*s+c2*g)+u*(g+s) */ secp256k1_fe_negate(xn, &n, 2); /* n = -u*(c1*s+c2*g)-u*(g+s) */ -#ifdef VERIFY + VERIFY_CHECK(secp256k1_ge_x_frac_on_curve_var(xn, &p)); -#endif /* Return x3 = n/p = -(u*(c1*s+c2*g)/(g+s)+u) */ } @@ -193,10 +192,8 @@ static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_ secp256k1_fe_normalize_weak(&x); secp256k1_fe_normalize_weak(&u); -#ifdef VERIFY VERIFY_CHECK(c >= 0 && c < 8); VERIFY_CHECK(secp256k1_ge_x_on_curve_var(&x)); -#endif if (!(c & 2)) { /* c is in {0, 1, 4, 5}. In this case we look for an inverse under the x1 (if c=0 or @@ -230,9 +227,7 @@ static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_ * that (-u-x)^3 + B is not square (the secp256k1_ge_x_on_curve_var(&m) * test above would have failed). This is a contradiction, and thus the * assumption s=0 is false. */ -#ifdef VERIFY VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&s)); -#endif /* If s is not square, fail. We have not fully computed s yet, but s is square iff * -(u^3+7)*(u^2+u*x+x^2) is square (because a/b is square iff a*b is square and b is @@ -272,7 +267,11 @@ static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_ secp256k1_fe_negate(&q, &q, 1); /* q = -s*(4*(u^3+7)+3*u^2*s) */ if (!secp256k1_fe_is_square_var(&q)) return 0; ret = secp256k1_fe_sqrt(&r, &q); /* r = sqrt(-s*(4*(u^3+7)+3*u^2*s)) */ +#ifdef VERIFY VERIFY_CHECK(ret); +#else + (void)ret; +#endif /* If (c & 1) = 1 and r = 0, fail. */ if (EXPECT((c & 1) && secp256k1_fe_normalizes_to_zero_var(&r), 0)) return 0; @@ -320,10 +319,9 @@ static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 buf4[3] = cnt >> 24; secp256k1_sha256_write(&hash, buf4, 4); secp256k1_sha256_finalize(&hash, out32); -#ifdef VERIFY + /* Writing and finalizing together should trigger exactly one SHA256 compression. */ VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1)); -#endif } /** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate. @@ -361,9 +359,8 @@ static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1 /* Since u is the output of a hash, it should practically never be 0. We could apply the * u=0 to u=1 correction here too to deal with that case still, but it's such a low * probability event that we do not bother. */ -#ifdef VERIFY VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&u)); -#endif + /* Find a remainder t, and return it if found. */ if (EXPECT(secp256k1_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break; } @@ -417,7 +414,11 @@ int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64 * BIP340 tagged hash with tag "secp256k1_ellswift_encode". */ secp256k1_ellswift_sha256_init_encode(&hash); ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1); +#ifdef VERIFY VERIFY_CHECK(ser_ret && ser_size == 33); +#else + (void)ser_ret; +#endif secp256k1_sha256_write(&hash, p64, sizeof(p64)); secp256k1_sha256_write(&hash, rnd32, 32); diff --git a/src/modules/ellswift/tests_exhaustive_impl.h b/src/modules/ellswift/tests_exhaustive_impl.h index e002a8c008..839c24aee4 100644 --- a/src/modules/ellswift/tests_exhaustive_impl.h +++ b/src/modules/ellswift/tests_exhaustive_impl.h @@ -32,7 +32,7 @@ static void test_exhaustive_ellswift(const secp256k1_context *ctx, const secp256 /* Decode ellswift pubkey and check that it matches the precomputed group element. */ secp256k1_ellswift_decode(ctx, &pub_decoded, ell64); secp256k1_pubkey_load(ctx, &ge_decoded, &pub_decoded); - ge_equals_ge(&ge_decoded, &group[i]); + CHECK(secp256k1_ge_eq_var(&ge_decoded, &group[i])); } } diff --git a/src/modules/ellswift/tests_impl.h b/src/modules/ellswift/tests_impl.h index 47f443d980..7d1efbc492 100644 --- a/src/modules/ellswift/tests_impl.h +++ b/src/modules/ellswift/tests_impl.h @@ -237,7 +237,7 @@ void run_ellswift_tests(void) { secp256k1_ellswift_decode(CTX, &pubkey2, ell64); secp256k1_pubkey_load(CTX, &g2, &pubkey2); /* Compare with original. */ - ge_equals_ge(&g, &g2); + CHECK(secp256k1_ge_eq_var(&g, &g2)); } /* Verify the behavior of secp256k1_ellswift_create */ for (i = 0; i < 400 * COUNT; i++) { @@ -259,7 +259,7 @@ void run_ellswift_tests(void) { secp256k1_ellswift_decode(CTX, &pub, ell64); secp256k1_pubkey_load(CTX, &dec, &pub); secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec); - ge_equals_gej(&dec, &res); + CHECK(secp256k1_gej_eq_ge_var(&res, &dec)); } /* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */ for (i = 0; i < 800 * COUNT; i++) { @@ -285,7 +285,7 @@ void run_ellswift_tests(void) { ret = secp256k1_ellswift_xdh(CTX, share32, ell64, ell64, sec32, i & 1, &ellswift_xdh_hash_x32, NULL); CHECK(ret); (void)secp256k1_fe_set_b32_limit(&share_x, share32); /* no overflow is possible */ - secp256k1_fe_verify(&share_x); + SECP256K1_FE_VERIFY(&share_x); /* Compute seckey*pubkey directly. */ secp256k1_ecmult(&resj, &decj, &sec, NULL); secp256k1_ge_set_gej(&res, &resj); diff --git a/src/modules/extrakeys/main_impl.h b/src/modules/extrakeys/main_impl.h index 7a7015e1e1..2ba414653a 100644 --- a/src/modules/extrakeys/main_impl.h +++ b/src/modules/extrakeys/main_impl.h @@ -283,33 +283,6 @@ int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_ke return ret; } -int secp256k1_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_pubkey* pk0, const secp256k1_pubkey* pk1) { - unsigned char out[2][33]; - const secp256k1_pubkey* pk[2]; - int i; - - VERIFY_CHECK(ctx != NULL); - pk[0] = pk0; pk[1] = pk1; - for (i = 0; i < 2; i++) { - size_t outputlen = sizeof(out[i]); - /* If the public key is NULL or invalid, pubkey_serialize will - * call the illegal_callback and return 0. In that case we will - * serialize the key as all zeros which is less than any valid public - * key. This results in consistent comparisons even if NULL or invalid - * pubkeys are involved and prevents edge cases such as sorting - * algorithms that use this function and do not terminate as a - * result. */ - if (!secp256k1_ec_pubkey_serialize(ctx, out[i], &outputlen, pk[i], SECP256K1_EC_COMPRESSED)) { - /* Note that pubkey_serialize should already set the output to - * zero in that case, but it's not guaranteed by the API, we can't - * test it and writing a VERIFY_CHECK is more complex than - * explicitly memsetting (again). */ - memset(out[i], 0, sizeof(out[i])); - } - } - return secp256k1_memcmp_var(out[0], out[1], sizeof(out[1])); -} - /* This struct wraps a const context pointer to satisfy the secp256k1_hsort api * which expects a non-const cmp_data pointer. */ typedef struct { @@ -317,7 +290,7 @@ typedef struct { } secp256k1_pubkey_sort_cmp_data; static int secp256k1_pubkey_sort_cmp(const void* pk1, const void* pk2, void *cmp_data) { - return secp256k1_pubkey_cmp(((secp256k1_pubkey_sort_cmp_data*)cmp_data)->ctx, + return secp256k1_ec_pubkey_cmp(((secp256k1_pubkey_sort_cmp_data*)cmp_data)->ctx, *(secp256k1_pubkey **)pk1, *(secp256k1_pubkey **)pk2); } diff --git a/src/modules/extrakeys/tests_exhaustive_impl.h b/src/modules/extrakeys/tests_exhaustive_impl.h index d3d817a131..645bae2d47 100644 --- a/src/modules/extrakeys/tests_exhaustive_impl.h +++ b/src/modules/extrakeys/tests_exhaustive_impl.h @@ -48,7 +48,7 @@ static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp25 /* Compare the xonly_pubkey bytes against the precomputed group. */ secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]); - CHECK(secp256k1_fe_equal_var(&fe, &group[i].x)); + CHECK(secp256k1_fe_equal(&fe, &group[i].x)); /* Check the parity against the precomputed group. */ fe = group[i].y; diff --git a/src/modules/extrakeys/tests_impl.h b/src/modules/extrakeys/tests_impl.h index ff37e02e82..60299ce0c6 100644 --- a/src/modules/extrakeys/tests_impl.h +++ b/src/modules/extrakeys/tests_impl.h @@ -9,11 +9,6 @@ #include "../../../include/secp256k1_extrakeys.h" -static void set_counting_callbacks(secp256k1_context *ctx0, int *ecount) { - secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount); - secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount); -} - static void test_xonly_pubkey(void) { secp256k1_pubkey pk; secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; @@ -28,10 +23,6 @@ static void test_xonly_pubkey(void) { int pk_parity; int i; - int ecount; - - set_counting_callbacks(CTX, &ecount); - secp256k1_testrand256(sk); memset(ones32, 0xFF, 32); secp256k1_testrand256(xy_sk); @@ -39,16 +30,12 @@ static void test_xonly_pubkey(void) { CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); /* Test xonly_pubkey_from_pubkey */ - ecount = 0; CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk)); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL)); memset(&pk, 0, sizeof(pk)); - CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk)); /* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */ memset(sk, 0, sizeof(sk)); @@ -72,28 +59,21 @@ static void test_xonly_pubkey(void) { CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); /* Test xonly_pubkey_serialize and xonly_pubkey_parse */ - ecount = 0; - CHECK(secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL) == 0); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL)); CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0); - CHECK(ecount == 2); { /* A pubkey filled with 0s will fail to serialize due to pubkey_load * special casing. */ secp256k1_xonly_pubkey pk_tmp; memset(&pk_tmp, 0, sizeof(pk_tmp)); - CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp) == 0); + /* pubkey_load calls illegal callback */ + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp)); } - /* pubkey_load called illegal callback */ - CHECK(ecount == 3); CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1); - ecount = 0; - CHECK(secp256k1_xonly_pubkey_parse(CTX, NULL, buf32) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, NULL, buf32)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL)); /* Serialization and parse roundtrip */ CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1); @@ -125,7 +105,6 @@ static void test_xonly_pubkey(void) { CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 1); } } - CHECK(ecount == 2); } static void test_xonly_pubkey_comparison(void) { @@ -139,29 +118,26 @@ static void test_xonly_pubkey_comparison(void) { }; secp256k1_xonly_pubkey pk1; secp256k1_xonly_pubkey pk2; - int ecount = 0; - - set_counting_callbacks(CTX, &ecount); CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk1, pk1_ser) == 1); CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk2, pk2_ser) == 1); - CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0); - CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0); - CHECK(ecount == 2); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0)); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0)); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk2) == 0); - CHECK(ecount == 2); memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ - CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0); - CHECK(ecount == 3); - CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0); - CHECK(ecount == 6); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0)); + { + int32_t ecount = 0; + secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0); + CHECK(ecount == 2); + secp256k1_context_set_illegal_callback(CTX, NULL, NULL); + } + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0)); } static void test_xonly_pubkey_tweak(void) { @@ -175,30 +151,20 @@ static void test_xonly_pubkey_tweak(void) { unsigned char tweak[32]; int i; - int ecount; - - set_counting_callbacks(CTX, &ecount); - memset(overflows, 0xff, sizeof(overflows)); secp256k1_testrand256(tweak); secp256k1_testrand256(sk); CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); - ecount = 0; CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(ecount == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(ecount == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak)); /* NULL internal_xonly_pk zeroes the output_pk */ CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL)); /* NULL tweak zeroes the output_pk */ CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); @@ -225,9 +191,7 @@ static void test_xonly_pubkey_tweak(void) { /* Invalid pk with a valid tweak */ memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); secp256k1_testrand256(tweak); - ecount = 0; - CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak)); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); } @@ -244,34 +208,23 @@ static void test_xonly_pubkey_tweak_check(void) { int pk_parity; unsigned char tweak[32]; - int ecount; - - set_counting_callbacks(CTX, &ecount); - memset(overflows, 0xff, sizeof(overflows)); secp256k1_testrand256(tweak); secp256k1_testrand256(sk); CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1); - ecount = 0; CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &output_xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); - CHECK(ecount == 0); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); - CHECK(ecount == 0); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak)); /* invalid pk_parity value */ CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, 2, &internal_xonly_pk, tweak) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak)); + CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL)); memset(tweak, 1, sizeof(tweak)); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, NULL, &internal_pk) == 1); @@ -290,7 +243,6 @@ static void test_xonly_pubkey_tweak_check(void) { CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); - CHECK(ecount == 3); } /* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1 @@ -335,33 +287,22 @@ static void test_keypair(void) { secp256k1_pubkey pk, pk_tmp; secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; int pk_parity, pk_parity_tmp; - int ecount; - - set_counting_callbacks(CTX, &ecount); - set_counting_callbacks(STATIC_CTX, &ecount); CHECK(sizeof(zeros96) == sizeof(keypair)); memset(overflows, 0xFF, sizeof(overflows)); /* Test keypair_create */ - ecount = 0; secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); - CHECK(ecount == 0); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); - CHECK(ecount == 0); - CHECK(secp256k1_keypair_create(CTX, NULL, sk) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_keypair_create(CTX, &keypair, NULL) == 0); + CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, NULL, sk)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, &keypair, NULL)); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - CHECK(ecount == 2); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_keypair_create(STATIC_CTX, &keypair, sk) == 0); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_keypair_create(STATIC_CTX, &keypair, sk)); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); - CHECK(ecount == 3); /* Invalid secret key */ CHECK(secp256k1_keypair_create(CTX, &keypair, zeros96) == 0); @@ -370,14 +311,11 @@ static void test_keypair(void) { CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); /* Test keypair_pub */ - ecount = 0; secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1); - CHECK(secp256k1_keypair_pub(CTX, NULL, &keypair) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_keypair_pub(CTX, &pk, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, NULL, &keypair)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, &pk, NULL)); CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); /* Using an invalid keypair is fine for keypair_pub */ @@ -392,23 +330,19 @@ static void test_keypair(void) { CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); /** Test keypair_xonly_pub **/ - ecount = 0; secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); - CHECK(secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair)); CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, NULL, &keypair) == 1); - CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL)); CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); /* Using an invalid keypair will set the xonly_pk to 0 (first reset * xonly_pk). */ CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1); memset(&keypair, 0, sizeof(keypair)); - CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 0); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair)); CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); - CHECK(ecount == 3); /** keypair holds the same xonly pubkey as pubkey_create **/ CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1); @@ -419,14 +353,11 @@ static void test_keypair(void) { CHECK(pk_parity == pk_parity_tmp); /* Test keypair_seckey */ - ecount = 0; secp256k1_testrand256(sk); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); - CHECK(secp256k1_keypair_sec(CTX, NULL, &keypair) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_keypair_sec(CTX, sk_tmp, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, NULL, &keypair)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, sk_tmp, NULL)); CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); /* keypair returns the same seckey it got */ @@ -439,9 +370,6 @@ static void test_keypair(void) { memset(&keypair, 0, sizeof(keypair)); CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1); CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); - - secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); } static void test_keypair_add(void) { @@ -451,9 +379,6 @@ static void test_keypair_add(void) { unsigned char zeros96[96] = { 0 }; unsigned char tweak[32]; int i; - int ecount = 0; - - set_counting_callbacks(CTX, &ecount); CHECK(sizeof(zeros96) == sizeof(keypair)); secp256k1_testrand256(sk); @@ -462,14 +387,10 @@ static void test_keypair_add(void) { CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); - CHECK(ecount == 0); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); - CHECK(ecount == 0); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak)); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL)); /* This does not set the keypair to zeroes */ CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0); @@ -503,20 +424,16 @@ static void test_keypair_add(void) { /* Invalid keypair with a valid tweak */ memset(&keypair, 0, sizeof(keypair)); secp256k1_testrand256(tweak); - ecount = 0; - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); /* Only seckey part of keypair invalid */ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); memset(&keypair, 0, 32); - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); /* Only pubkey part of keypair invalid */ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); memset(&keypair.data[32], 0, 64); - CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak)); /* Check that the keypair_tweak_add implementation is correct */ CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1); @@ -590,45 +507,6 @@ static void test_hsort(void) { } #undef NUM -static void test_pubkey_comparison(void) { - unsigned char pk1_ser[33] = { - 0x02, - 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, - 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 - }; - const unsigned char pk2_ser[33] = { - 0x03, - 0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d, - 0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c - }; - secp256k1_pubkey pk1; - secp256k1_pubkey pk2; - int ecount = 0; - - set_counting_callbacks(CTX, &ecount); - - CHECK(secp256k1_ec_pubkey_parse(CTX, &pk1, pk1_ser, sizeof(pk1_ser)) == 1); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk2_ser, sizeof(pk2_ser)) == 1); - - CHECK(secp256k1_pubkey_cmp(CTX, NULL, &pk2) < 0); - CHECK(ecount == 1); - CHECK(secp256k1_pubkey_cmp(CTX, &pk1, NULL) > 0); - CHECK(ecount == 2); - CHECK(secp256k1_pubkey_cmp(CTX, &pk1, &pk2) < 0); - CHECK(secp256k1_pubkey_cmp(CTX, &pk2, &pk1) > 0); - CHECK(secp256k1_pubkey_cmp(CTX, &pk1, &pk1) == 0); - CHECK(secp256k1_pubkey_cmp(CTX, &pk2, &pk2) == 0); - CHECK(ecount == 2); - memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ - CHECK(secp256k1_pubkey_cmp(CTX, &pk1, &pk2) < 0); - CHECK(ecount == 3); - CHECK(secp256k1_pubkey_cmp(CTX, &pk1, &pk1) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_pubkey_cmp(CTX, &pk2, &pk1) > 0); - CHECK(ecount == 6); - -} - static void test_sort_helper(secp256k1_pubkey *pk, size_t *pk_order, size_t n_pk) { size_t i; const secp256k1_pubkey *pk_test[5]; @@ -662,12 +540,9 @@ static void rand_pk(secp256k1_pubkey *pk) { } static void test_sort_api(void) { - int ecount = 0; secp256k1_pubkey pks[2]; const secp256k1_pubkey *pks_ptr[2]; - set_counting_callbacks(CTX, &ecount); - pks_ptr[0] = &pks[0]; pks_ptr[1] = &pks[1]; @@ -675,17 +550,19 @@ static void test_sort_api(void) { rand_pk(&pks[1]); CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, 2) == 1); - CHECK(secp256k1_pubkey_sort(CTX, NULL, 2) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_sort(CTX, NULL, 2)); CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, 0) == 1); /* Test illegal public keys */ memset(&pks[0], 0, sizeof(pks[0])); - CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, 2) == 1); - CHECK(ecount == 2); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, 2) == 1)); memset(&pks[1], 0, sizeof(pks[1])); - CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, 2) == 1); - CHECK(ecount > 2); - + { + int32_t ecount = 0; + secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, 2) == 1); + CHECK(ecount == 2); + secp256k1_context_set_illegal_callback(CTX, NULL, NULL); + } } static void test_sort(void) { @@ -791,7 +668,6 @@ static void run_extrakeys_tests(void) { test_keypair_add(); test_hsort(); - test_pubkey_comparison(); test_sort_api(); test_sort(); test_sort_vectors(); diff --git a/src/modules/generator/main_impl.h b/src/modules/generator/main_impl.h index 63318594d7..d3dce9fa80 100644 --- a/src/modules/generator/main_impl.h +++ b/src/modules/generator/main_impl.h @@ -24,7 +24,7 @@ import hashlib F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) G = '0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8' - H = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256(G.decode('hex')).hexdigest(),16))) + H = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256(bytes.fromhex(G)).hexdigest(),16))) print('%x %x' % H.xy()) */ static const secp256k1_generator secp256k1_generator_h_internal = {{ @@ -107,61 +107,78 @@ static void shallue_van_de_woestijne(secp256k1_ge* ge, const secp256k1_fe* t) { x2 = -(x1 + 1) x3 = 1 + 1/w^2 - To avoid the 2 divisions, compute the above in numerator/denominator form: - wn = c * t - wd = 1 + 7 + t^2 - x1n = d*wd - t*wn - x1d = wd - x2n = -(x1n + wd) - x2d = wd - x3n = wd^2 + c^2 + t^2 - x3d = (c * t)^2 + To avoid the 2 divisions, compute the joint denominator j = wd * x3d, where + wd = 1 + b + t^2 + x3d = c^2 * t^2 = -3 * t^2 - The joint denominator j = wd * c^2 * t^2, and - 1 / x1d = 1/j * c^2 * t^2 - 1 / x2d = x3d = 1/j * wd + so that if j != 0, then + + 1 / wd = 1/j * x3d + 1 / x3d = 1/j * wd + + x1 = d - c * t^2 * x3d / j + x3 = 1 + wd^3 / j + + If j = 0, the function outputs the point (d, f(d)). This point is equal + to (x1, f(x1)) as defined above if division by 0 is defined to be 0. In + below code this is not special-cased because secp256k1_fe_inv returns 0 + on input 0. + + j = 0 happens only when t = 0 (since wd != 0 as -8 is not a square). */ - static const secp256k1_fe c = SECP256K1_FE_CONST(0x0a2d2ba9, 0x3507f1df, 0x233770c2, 0xa797962c, 0xc61f6d15, 0xda14ecd4, 0x7d8d27ae, 0x1cd5f852); + static const secp256k1_fe negc = SECP256K1_FE_CONST(0xf5d2d456, 0xcaf80e20, 0xdcc88f3d, 0x586869d3, 0x39e092ea, 0x25eb132b, 0x8272d850, 0xe32a03dd); static const secp256k1_fe d = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40); - static const secp256k1_fe b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7); - static const secp256k1_fe b_plus_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 8); - secp256k1_fe wn, wd, x1n, x2n, x3n, x3d, jinv, tmp, x1, x2, x3, alphain, betain, gammain, y1, y2, y3; + secp256k1_fe wd, x3d, jinv, tmp, x1, x2, x3, alphain, betain, gammain, y1, y2, y3; int alphaquad, betaquad; - secp256k1_fe_mul(&wn, &c, t); /* mag 1 */ + /* wd = t^2 */ secp256k1_fe_sqr(&wd, t); /* mag 1 */ - secp256k1_fe_add(&wd, &b_plus_one); /* mag 2 */ - secp256k1_fe_mul(&tmp, t, &wn); /* mag 1 */ - secp256k1_fe_negate(&tmp, &tmp, 1); /* mag 2 */ - secp256k1_fe_mul(&x1n, &d, &wd); /* mag 1 */ - secp256k1_fe_add(&x1n, &tmp); /* mag 3 */ - x2n = x1n; /* mag 3 */ - secp256k1_fe_add(&x2n, &wd); /* mag 5 */ - secp256k1_fe_negate(&x2n, &x2n, 5); /* mag 6 */ - secp256k1_fe_mul(&x3d, &c, t); /* mag 1 */ - secp256k1_fe_sqr(&x3d, &x3d); /* mag 1 */ - secp256k1_fe_sqr(&x3n, &wd); /* mag 1 */ - secp256k1_fe_add(&x3n, &x3d); /* mag 2 */ - secp256k1_fe_mul(&jinv, &x3d, &wd); /* mag 1 */ + /* x1 = -c * t^2 */ + secp256k1_fe_mul(&x1, &negc, &wd); /* mag 1 */ + /* x3d = t^2 */ + x3d = wd; /* mag 1 */ + /* x3d = 3 * t^2 */ + secp256k1_fe_mul_int(&x3d, 3); /* mag 3 */ + /* x3d = -3 * t^2 */ + secp256k1_fe_negate(&x3d, &x3d, 3); /* mag 4 */ + /* wd = 1 + b + t^2 */ + secp256k1_fe_add_int(&wd, SECP256K1_B + 1); /* mag 2 */ + /* jinv = wd * x3d */ + secp256k1_fe_mul(&jinv, &wd, &x3d); /* mag 1 */ + /* jinv = 1/(wd * x3d) */ secp256k1_fe_inv(&jinv, &jinv); /* mag 1 */ - secp256k1_fe_mul(&x1, &x1n, &x3d); /* mag 1 */ + /* x1 = -c * t^2 * x3d */ + secp256k1_fe_mul(&x1, &x1, &x3d); /* mag 1 */ + /* x1 = -c * t^2 * x3d * 1/j */ secp256k1_fe_mul(&x1, &x1, &jinv); /* mag 1 */ - secp256k1_fe_mul(&x2, &x2n, &x3d); /* mag 1 */ - secp256k1_fe_mul(&x2, &x2, &jinv); /* mag 1 */ - secp256k1_fe_mul(&x3, &x3n, &wd); /* mag 1 */ + /* x1 = d + -c * t^2 * x3d * 1/j */ + secp256k1_fe_add(&x1, &d); /* mag 2 */ + /* x2 = x1 */ + x2 = x1; /* mag 2 */ + /* x2 = x1 + 1 */ + secp256k1_fe_add_int(&x2, 1); /* mag 3 */ + /* x2 = - (x1 + 1) */ + secp256k1_fe_negate(&x2, &x2, 3); /* mag 4 */ + /* x3 = wd^2 */ + secp256k1_fe_sqr(&x3, &wd); /* mag 1 */ + /* x3 = wd^3 */ + secp256k1_fe_mul(&x3, &x3, &wd); /* mag 1 */ + /* x3 = wd^3 * 1/j */ secp256k1_fe_mul(&x3, &x3, &jinv); /* mag 1 */ + /* x3 = 1 + (wd^3 * 1/j) */ + secp256k1_fe_add_int(&x3, 1); /* mag 2 */ secp256k1_fe_sqr(&alphain, &x1); /* mag 1 */ secp256k1_fe_mul(&alphain, &alphain, &x1); /* mag 1 */ - secp256k1_fe_add(&alphain, &b); /* mag 2 */ + secp256k1_fe_add_int(&alphain, SECP256K1_B); /* mag 2 */ secp256k1_fe_sqr(&betain, &x2); /* mag 1 */ secp256k1_fe_mul(&betain, &betain, &x2); /* mag 1 */ - secp256k1_fe_add(&betain, &b); /* mag 2 */ + secp256k1_fe_add_int(&betain, SECP256K1_B); /* mag 2 */ secp256k1_fe_sqr(&gammain, &x3); /* mag 1 */ secp256k1_fe_mul(&gammain, &gammain, &x3); /* mag 1 */ - secp256k1_fe_add(&gammain, &b); /* mag 2 */ + secp256k1_fe_add_int(&gammain, SECP256K1_B); /* mag 2 */ alphaquad = secp256k1_fe_sqrt(&y1, &alphain); betaquad = secp256k1_fe_sqrt(&y2, &betain); @@ -259,7 +276,6 @@ static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* co int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_pedersen_commitment* commit, const unsigned char *input) { secp256k1_fe x; - secp256k1_ge ge; VERIFY_CHECK(ctx != NULL); ARG_CHECK(commit != NULL); @@ -268,28 +284,20 @@ int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_ if ((input[0] & 0xFE) != 8 || !secp256k1_fe_set_b32_limit(&x, &input[1]) || - !secp256k1_ge_set_xquad(&ge, &x)) { + !secp256k1_ge_x_on_curve_var(&x)) { return 0; } - if (input[0] & 1) { - secp256k1_ge_neg(&ge, &ge); - } - secp256k1_pedersen_commitment_save(commit, &ge); + + memcpy(commit->data, input, 33); return 1; } int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pedersen_commitment* commit) { - secp256k1_ge ge; - VERIFY_CHECK(ctx != NULL); ARG_CHECK(output != NULL); ARG_CHECK(commit != NULL); - secp256k1_pedersen_commitment_load(&ge, commit); - - output[0] = 9 ^ secp256k1_fe_is_square_var(&ge.y); - secp256k1_fe_normalize_var(&ge.x); - secp256k1_fe_get_b32(&output[1], &ge.x); + memcpy(output, commit->data, 33); return 1; } diff --git a/src/modules/generator/tests_impl.h b/src/modules/generator/tests_impl.h index 6f247103fe..f5a34bc652 100644 --- a/src/modules/generator/tests_impl.h +++ b/src/modules/generator/tests_impl.h @@ -22,57 +22,35 @@ static void test_generator_api(void) { unsigned char blind[32]; unsigned char sergen[33]; secp256k1_generator gen; - int32_t ecount = 0; - secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); secp256k1_testrand256(key); secp256k1_testrand256(blind); CHECK(secp256k1_generator_generate(CTX, &gen, key) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_generator_generate(CTX, NULL, key) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_generator_generate(CTX, &gen, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_generator_generate(CTX, NULL, key)); + CHECK_ILLEGAL(CTX, secp256k1_generator_generate(CTX, &gen, NULL)); CHECK(secp256k1_generator_generate_blinded(CTX, &gen, key, blind) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_generator_generate_blinded(STATIC_CTX, &gen, key, blind) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_generator_generate_blinded(CTX, NULL, key, blind) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_generator_generate_blinded(CTX, &gen, NULL, blind) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_generator_generate_blinded(CTX, &gen, key, NULL) == 0); - CHECK(ecount == 6); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_generator_generate_blinded(STATIC_CTX, &gen, key, blind)); + CHECK_ILLEGAL(CTX, secp256k1_generator_generate_blinded(CTX, NULL, key, blind)); + CHECK_ILLEGAL(CTX, secp256k1_generator_generate_blinded(CTX, &gen, NULL, blind)); + CHECK_ILLEGAL(CTX, secp256k1_generator_generate_blinded(CTX, &gen, key, NULL)); CHECK(secp256k1_generator_serialize(CTX, sergen, &gen) == 1); - CHECK(ecount == 6); - CHECK(secp256k1_generator_serialize(CTX, NULL, &gen) == 0); - CHECK(ecount == 7); - CHECK(secp256k1_generator_serialize(CTX, sergen, NULL) == 0); - CHECK(ecount == 8); + CHECK_ILLEGAL(CTX, secp256k1_generator_serialize(CTX, NULL, &gen)); + CHECK_ILLEGAL(CTX, secp256k1_generator_serialize(CTX, sergen, NULL)); CHECK(secp256k1_generator_serialize(CTX, sergen, &gen) == 1); CHECK(secp256k1_generator_parse(CTX, &gen, sergen) == 1); - CHECK(ecount == 8); - CHECK(secp256k1_generator_parse(CTX, NULL, sergen) == 0); - CHECK(ecount == 9); - CHECK(secp256k1_generator_parse(CTX, &gen, NULL) == 0); - CHECK(ecount == 10); - - secp256k1_context_set_error_callback(CTX, NULL, NULL); - secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); + CHECK_ILLEGAL(CTX, secp256k1_generator_parse(CTX, NULL, sergen)); + CHECK_ILLEGAL(CTX, secp256k1_generator_parse(CTX, &gen, NULL)); } static void test_shallue_van_de_woestijne(void) { /* Matches with the output of the shallue_van_de_woestijne.sage SAGE program */ - static const secp256k1_ge_storage results[32] = { + static const secp256k1_ge_storage results[34] = { + SECP256K1_GE_STORAGE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40, 0x4218f20a, 0xe6c646b3, 0x63db6860, 0x5822fb14, 0x264ca8d2, 0x587fdd6f, 0xbc750d58, 0x7e76a7ee), + SECP256K1_GE_STORAGE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40, 0x4218f20a, 0xe6c646b3, 0x63db6860, 0x5822fb14, 0x264ca8d2, 0x587fdd6f, 0xbc750d58, 0x7e76a7ee), SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0x0225f529, 0xee75acaf, 0xccfc4560, 0x26c5e46b, 0xf80237a3, 0x3924655a, 0x16f90e88, 0x085ed52a), SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0xfdda0ad6, 0x118a5350, 0x3303ba9f, 0xd93a1b94, 0x07fdc85c, 0xc6db9aa5, 0xe906f176, 0xf7a12705), SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0x56716069, 0x6818286b, 0x72f01a3e, 0x5e8caca7, 0x36249160, 0xc7ded69d, 0xd51913c3, 0x03a2fa97), @@ -111,7 +89,7 @@ static void test_shallue_van_de_woestijne(void) { secp256k1_fe fe; secp256k1_ge_storage ges; int i, s; - for (i = 1; i <= 16; i++) { + for (i = 0; i <= 16; i++) { secp256k1_fe_set_int(&fe, i); for (s = 0; s < 2; s++) { @@ -120,9 +98,9 @@ static void test_shallue_van_de_woestijne(void) { secp256k1_fe_normalize(&fe); } shallue_van_de_woestijne(&ge, &fe); + CHECK(secp256k1_ge_is_valid_var(&ge)); secp256k1_ge_to_storage(&ges, &ge); - - CHECK(secp256k1_memcmp_var(&ges, &results[i * 2 + s - 2], sizeof(secp256k1_ge_storage)) == 0); + CHECK(secp256k1_memcmp_var(&ges, &results[i * 2 + s], sizeof(secp256k1_ge_storage)) == 0); } } } @@ -219,65 +197,35 @@ static void test_pedersen_api(void) { const unsigned char *blind_ptr = blind; unsigned char *blind_out_ptr = blind_out; uint64_t val = secp256k1_testrand32(); - int32_t ecount = 0; - - secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); secp256k1_testrand256(blind); CHECK(secp256k1_pedersen_commit(CTX, &commit, blind, val, secp256k1_generator_h) != 0); - CHECK(ecount == 0); - CHECK(secp256k1_pedersen_commit(STATIC_CTX, &commit, blind, val, secp256k1_generator_h) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_pedersen_commit(STATIC_CTX, &commit, blind, val, secp256k1_generator_h)); - CHECK(secp256k1_pedersen_commit(CTX, NULL, blind, val, secp256k1_generator_h) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_pedersen_commit(CTX, &commit, NULL, val, secp256k1_generator_h) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_pedersen_commit(CTX, &commit, blind, val, NULL) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_commit(CTX, NULL, blind, val, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_commit(CTX, &commit, NULL, val, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_commit(CTX, &commit, blind, val, NULL)); CHECK(secp256k1_pedersen_blind_sum(CTX, blind_out, &blind_ptr, 1, 1) != 0); - CHECK(ecount == 4); - CHECK(secp256k1_pedersen_blind_sum(CTX, NULL, &blind_ptr, 1, 1) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_pedersen_blind_sum(CTX, blind_out, NULL, 1, 1) == 0); - CHECK(ecount == 6); - CHECK(secp256k1_pedersen_blind_sum(CTX, blind_out, &blind_ptr, 0, 1) == 0); - CHECK(ecount == 7); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_sum(CTX, NULL, &blind_ptr, 1, 1)); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_sum(CTX, blind_out, NULL, 1, 1)); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_sum(CTX, blind_out, &blind_ptr, 0, 1)); CHECK(secp256k1_pedersen_blind_sum(CTX, blind_out, &blind_ptr, 0, 0) != 0); - CHECK(ecount == 7); CHECK(secp256k1_pedersen_commit(CTX, &commit, blind, val, secp256k1_generator_h) != 0); CHECK(secp256k1_pedersen_verify_tally(CTX, &commit_ptr, 1, &commit_ptr, 1) != 0); CHECK(secp256k1_pedersen_verify_tally(CTX, NULL, 0, &commit_ptr, 1) == 0); CHECK(secp256k1_pedersen_verify_tally(CTX, &commit_ptr, 1, NULL, 0) == 0); CHECK(secp256k1_pedersen_verify_tally(CTX, NULL, 0, NULL, 0) != 0); - CHECK(ecount == 7); - CHECK(secp256k1_pedersen_verify_tally(CTX, NULL, 1, &commit_ptr, 1) == 0); - CHECK(ecount == 8); - CHECK(secp256k1_pedersen_verify_tally(CTX, &commit_ptr, 1, NULL, 1) == 0); - CHECK(ecount == 9); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_verify_tally(CTX, NULL, 1, &commit_ptr, 1)); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_verify_tally(CTX, &commit_ptr, 1, NULL, 1)); CHECK(secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0); - CHECK(ecount == 9); - CHECK(secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0); - CHECK(ecount == 10); - CHECK(secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0); - CHECK(ecount == 11); - CHECK(secp256k1_pedersen_blind_generator_blind_sum(CTX, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0); - CHECK(ecount == 12); - CHECK(secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, NULL, &blind_out_ptr, 1, 0) == 0); - CHECK(ecount == 13); - CHECK(secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, NULL, 1, 0) == 0); - CHECK(ecount == 14); - - secp256k1_context_set_error_callback(CTX, NULL, NULL); - secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, &blind_out_ptr, 1, 1)); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, &blind_out_ptr, 0, 0)); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, NULL, &blind_ptr, &blind_out_ptr, 1, 0)); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, NULL, &blind_out_ptr, 1, 0)); + CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, NULL, 1, 0)); } static void test_pedersen(void) { @@ -316,7 +264,13 @@ static void test_pedersen(void) { } CHECK(secp256k1_pedersen_blind_sum(CTX, &blinds[(total - 1) * 32], bptr, total - 1, inputs)); for (i = 0; i < total; i++) { + unsigned char result[33]; + secp256k1_pedersen_commitment parse; + CHECK(secp256k1_pedersen_commit(CTX, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h)); + CHECK(secp256k1_pedersen_commitment_serialize(CTX, result, &commits[i])); + CHECK(secp256k1_pedersen_commitment_parse(CTX, &parse, result)); + CHECK(secp256k1_memcmp_var(&commits[i], &parse, 33) == 0); } CHECK(secp256k1_pedersen_verify_tally(CTX, cptr, inputs, &cptr[inputs], outputs)); CHECK(secp256k1_pedersen_verify_tally(CTX, &cptr[inputs], outputs, cptr, inputs)); diff --git a/src/modules/musig/keyagg.h b/src/modules/musig/keyagg.h index 9ccea847e4..620522febd 100644 --- a/src/modules/musig/keyagg.h +++ b/src/modules/musig/keyagg.h @@ -27,15 +27,6 @@ typedef struct { int parity_acc; } secp256k1_keyagg_cache_internal; -/* Save and load points to and from byte arrays, similar to - * secp256k1_pubkey_{save,load}. */ -static void secp256k1_point_save(unsigned char *data, secp256k1_ge *ge); - -/* In contrast to pubkey_load, point_load does not attempt to check that data - * has been initialized, since it is assumed that this check already happened - * (e.g. by comparing magic bytes) */ -static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data); - /* point_save_ext and point_load_ext are identical to point_save and point_load * except that they allow saving and loading the point at infinity */ static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge); diff --git a/src/modules/musig/keyagg_impl.h b/src/modules/musig/keyagg_impl.h index aeb942ac81..aff955420a 100644 --- a/src/modules/musig/keyagg_impl.h +++ b/src/modules/musig/keyagg_impl.h @@ -17,43 +17,11 @@ #include "../../hash.h" #include "../../util.h" -static void secp256k1_point_save(unsigned char *data, secp256k1_ge *ge) { - if (sizeof(secp256k1_ge_storage) == 64) { - secp256k1_ge_storage s; - secp256k1_ge_to_storage(&s, ge); - memcpy(data, &s, sizeof(s)); - } else { - VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); - secp256k1_fe_normalize_var(&ge->x); - secp256k1_fe_normalize_var(&ge->y); - secp256k1_fe_get_b32(data, &ge->x); - secp256k1_fe_get_b32(data + 32, &ge->y); - } -} - -static void secp256k1_point_load(secp256k1_ge *ge, const unsigned char *data) { - if (sizeof(secp256k1_ge_storage) == 64) { - /* When the secp256k1_ge_storage type is exactly 64 byte, use its - * representation as conversion is very fast. */ - secp256k1_ge_storage s; - memcpy(&s, data, sizeof(s)); - secp256k1_ge_from_storage(ge, &s); - } else { - /* Otherwise, fall back to 32-byte big endian for X and Y. */ - secp256k1_fe x, y; - int ret = 1; - ret &= secp256k1_fe_set_b32_limit(&x, data); - ret &= secp256k1_fe_set_b32_limit(&y, data + 32); - VERIFY_CHECK(ret); - secp256k1_ge_set_xy(ge, &x, &y); - } -} - static void secp256k1_point_save_ext(unsigned char *data, secp256k1_ge *ge) { if (secp256k1_ge_is_infinity(ge)) { memset(data, 0, 64); } else { - secp256k1_point_save(data, ge); + secp256k1_ge_to_bytes(data, ge); } } @@ -62,7 +30,7 @@ static void secp256k1_point_load_ext(secp256k1_ge *ge, const unsigned char *data if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) { secp256k1_ge_set_infinity(ge); } else { - secp256k1_point_load(ge, data); + secp256k1_ge_from_bytes(ge, data); } } @@ -82,7 +50,7 @@ static void secp256k1_keyagg_cache_save(secp256k1_musig_keyagg_cache *cache, sec unsigned char *ptr = cache->data; memcpy(ptr, secp256k1_musig_keyagg_cache_magic, 4); ptr += 4; - secp256k1_point_save(ptr, &cache_i->pk); + secp256k1_ge_to_bytes(ptr, &cache_i->pk); ptr += 64; secp256k1_point_save_ext(ptr, &cache_i->second_pk); ptr += 64; @@ -97,7 +65,7 @@ static int secp256k1_keyagg_cache_load(const secp256k1_context* ctx, secp256k1_k const unsigned char *ptr = cache->data; ARG_CHECK(secp256k1_memcmp_var(ptr, secp256k1_musig_keyagg_cache_magic, 4) == 0); ptr += 4; - secp256k1_point_load(&cache_i->pk, ptr); + secp256k1_ge_from_bytes(&cache_i->pk, ptr); ptr += 64; secp256k1_point_load_ext(&cache_i->second_pk, ptr); ptr += 64; @@ -163,16 +131,12 @@ static void secp256k1_musig_keyaggcoef_sha256(secp256k1_sha256 *sha) { /* Compute KeyAgg coefficient which is constant 1 for the second pubkey and * otherwise tagged_hash(pk_hash, x) where pk_hash is the hash of public keys. * second_pk is the point at infinity in case there is no second_pk. Assumes - * that pk is not the point at infinity and that the coordinates of pk and + * that pk is not the point at infinity and that the Y-coordinates of pk and * second_pk are normalized. */ static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *pk_hash, secp256k1_ge *pk, const secp256k1_ge *second_pk) { secp256k1_sha256 sha; VERIFY_CHECK(!secp256k1_ge_is_infinity(pk)); -#ifdef VERIFY - VERIFY_CHECK(pk->x.normalized && pk->y.normalized); - VERIFY_CHECK(secp256k1_ge_is_infinity(second_pk) || (second_pk->x.normalized && second_pk->y.normalized)); -#endif if (!secp256k1_ge_is_infinity(second_pk) && secp256k1_fe_equal(&pk->x, &second_pk->x) @@ -185,9 +149,13 @@ static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsig secp256k1_musig_keyaggcoef_sha256(&sha); secp256k1_sha256_write(&sha, pk_hash, 32); ret = secp256k1_eckey_pubkey_serialize(pk, buf, &buflen, 1); +#ifdef VERIFY /* Serialization does not fail since the pk is not the point at infinity * (according to this function's precondition). */ VERIFY_CHECK(ret && buflen == sizeof(buf)); +#else + (void) ret; +#endif secp256k1_sha256_write(&sha, buf, sizeof(buf)); secp256k1_sha256_finalize(&sha, buf); secp256k1_scalar_set_b32(r, buf, NULL); @@ -212,9 +180,13 @@ static int secp256k1_musig_pubkey_agg_callback(secp256k1_scalar *sc, secp256k1_g secp256k1_musig_pubkey_agg_ecmult_data *ctx = (secp256k1_musig_pubkey_agg_ecmult_data *) data; int ret; ret = secp256k1_pubkey_load(ctx->ctx, pt, ctx->pks[idx]); +#ifdef VERIFY /* pubkey_load can't fail because the same pks have already been loaded in * `musig_compute_pk_hash` (and we test this). */ VERIFY_CHECK(ret); +#else + (void) ret; +#endif secp256k1_musig_keyaggcoef_internal(sc, ctx->pk_hash, pt, &ctx->second_pk); return 1; } @@ -278,7 +250,7 @@ int secp256k1_musig_pubkey_agg(const secp256k1_context* ctx, secp256k1_scratch_s return 1; } -int secp256k1_musig_pubkey_get(const secp256k1_context* ctx, secp256k1_pubkey *agg_pk, secp256k1_musig_keyagg_cache *keyagg_cache) { +int secp256k1_musig_pubkey_get(const secp256k1_context* ctx, secp256k1_pubkey *agg_pk, const secp256k1_musig_keyagg_cache *keyagg_cache) { secp256k1_keyagg_cache_internal cache_i; VERIFY_CHECK(ctx != NULL); ARG_CHECK(agg_pk != NULL); diff --git a/src/modules/musig/session_impl.h b/src/modules/musig/session_impl.h index d2d400fe74..ff87f2fd32 100644 --- a/src/modules/musig/session_impl.h +++ b/src/modules/musig/session_impl.h @@ -26,7 +26,7 @@ static void secp256k1_musig_secnonce_save(secp256k1_musig_secnonce *secnonce, co memcpy(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4); secp256k1_scalar_get_b32(&secnonce->data[4], &k[0]); secp256k1_scalar_get_b32(&secnonce->data[36], &k[1]); - secp256k1_point_save(&secnonce->data[68], pk); + secp256k1_ge_to_bytes(&secnonce->data[68], pk); } static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1_scalar *k, secp256k1_ge *pk, secp256k1_musig_secnonce *secnonce) { @@ -34,7 +34,7 @@ static int secp256k1_musig_secnonce_load(const secp256k1_context* ctx, secp256k1 ARG_CHECK(secp256k1_memcmp_var(&secnonce->data[0], secp256k1_musig_secnonce_magic, 4) == 0); secp256k1_scalar_set_b32(&k[0], &secnonce->data[4], NULL); secp256k1_scalar_set_b32(&k[1], &secnonce->data[36], NULL); - secp256k1_point_load(pk, &secnonce->data[68]); + secp256k1_ge_from_bytes(pk, &secnonce->data[68]); /* We make very sure that the nonce isn't invalidated by checking the values * in addition to the magic. */ is_zero = secp256k1_scalar_is_zero(&k[0]) & secp256k1_scalar_is_zero(&k[1]); @@ -62,7 +62,7 @@ static void secp256k1_musig_pubnonce_save(secp256k1_musig_pubnonce* nonce, secp2 int i; memcpy(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4); for (i = 0; i < 2; i++) { - secp256k1_point_save(nonce->data + 4+64*i, &ge[i]); + secp256k1_ge_to_bytes(nonce->data + 4+64*i, &ge[i]); } } @@ -73,7 +73,7 @@ static int secp256k1_musig_pubnonce_load(const secp256k1_context* ctx, secp256k1 ARG_CHECK(secp256k1_memcmp_var(&nonce->data[0], secp256k1_musig_pubnonce_magic, 4) == 0); for (i = 0; i < 2; i++) { - secp256k1_point_load(&ge[i], nonce->data + 4 + 64*i); + secp256k1_ge_from_bytes(&ge[i], nonce->data + 4 + 64*i); } return 1; } @@ -174,8 +174,12 @@ int secp256k1_musig_pubnonce_serialize(const secp256k1_context* ctx, unsigned ch int ret; size_t size = 33; ret = secp256k1_eckey_pubkey_serialize(&ge[i], &out66[33*i], &size, 1); +#ifdef VERIFY /* serialize must succeed because the point was just loaded */ VERIFY_CHECK(ret && size == 33); +#else + (void) ret; +#endif } return 1; } @@ -258,16 +262,6 @@ int secp256k1_musig_partial_sig_parse(const secp256k1_context* ctx, secp256k1_mu return 1; } -/* Normalizes the x-coordinate of the given group element. */ -static int secp256k1_xonly_ge_serialize(unsigned char *output32, secp256k1_ge *ge) { - if (secp256k1_ge_is_infinity(ge)) { - return 0; - } - secp256k1_fe_normalize_var(&ge->x); - secp256k1_fe_get_b32(output32, &ge->x); - return 1; -} - /* Write optional inputs into the hash */ static void secp256k1_nonce_function_musig_helper(secp256k1_sha256 *sha, unsigned int prefix_size, const unsigned char *data, unsigned char len) { unsigned char zero[7] = { 0 }; @@ -364,22 +358,25 @@ int secp256k1_musig_nonce_gen(const secp256k1_context* ctx, secp256k1_musig_secn } if (keyagg_cache != NULL) { - int ret_tmp; if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { return 0; } - ret_tmp = secp256k1_xonly_ge_serialize(aggpk_ser, &cache_i.pk); - /* Serialization can not fail because the loaded point can not be infinity. */ - VERIFY_CHECK(ret_tmp); + /* The loaded point cache_i.pk can not be the point at infinity. */ + secp256k1_fe_get_b32(aggpk_ser, &cache_i.pk.x); aggpk_ser_ptr = aggpk_ser; } if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) { return 0; } pk_serialize_success = secp256k1_eckey_pubkey_serialize(&pk, pk_ser, &pk_ser_len, SECP256K1_EC_COMPRESSED); + +#ifdef VERIFY /* A pubkey cannot be the point at infinity */ VERIFY_CHECK(pk_serialize_success); VERIFY_CHECK(pk_ser_len == sizeof(pk_ser)); +#else + (void) pk_serialize_success; +#endif secp256k1_nonce_function_musig(k, session_id32, msg32, seckey, pk_ser, aggpk_ser_ptr, extra_input32); VERIFY_CHECK(!secp256k1_scalar_is_zero(&k[0])); @@ -460,7 +457,6 @@ static int secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigne secp256k1_ge fin_nonce_pt; secp256k1_gej fin_nonce_ptj; secp256k1_ge aggnonce[2]; - int ret; secp256k1_ge_set_gej(&aggnonce[0], &aggnoncej[0]); secp256k1_ge_set_gej(&aggnonce[1], &aggnoncej[1]); @@ -476,9 +472,9 @@ static int secp256k1_musig_nonce_process_internal(int *fin_nonce_parity, unsigne if (secp256k1_ge_is_infinity(&fin_nonce_pt)) { fin_nonce_pt = secp256k1_ge_const_g; } - ret = secp256k1_xonly_ge_serialize(fin_nonce, &fin_nonce_pt); - /* Can't fail since fin_nonce_pt is not infinity */ - VERIFY_CHECK(ret); + /* fin_nonce_pt is not the point at infinity */ + secp256k1_fe_normalize_var(&fin_nonce_pt.x); + secp256k1_fe_get_b32(fin_nonce, &fin_nonce_pt.x); secp256k1_fe_normalize_var(&fin_nonce_pt.y); *fin_nonce_parity = secp256k1_fe_is_odd(&fin_nonce_pt.y); return 1; @@ -574,8 +570,8 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p secp256k1_musig_partial_sign_clear(&sk, k); return 0; } - ARG_CHECK(secp256k1_fe_equal_var(&pk.x, &keypair_pk.x) - && secp256k1_fe_equal_var(&pk.y, &keypair_pk.y)); + ARG_CHECK(secp256k1_fe_equal(&pk.x, &keypair_pk.x) + && secp256k1_fe_equal(&pk.y, &keypair_pk.y)); if (!secp256k1_keyagg_cache_load(ctx, &cache_i, keyagg_cache)) { secp256k1_musig_partial_sign_clear(&sk, k); return 0; diff --git a/src/modules/musig/tests_impl.h b/src/modules/musig/tests_impl.h index d2e90d6be9..753b8ac5b7 100644 --- a/src/modules/musig/tests_impl.h +++ b/src/modules/musig/tests_impl.h @@ -160,13 +160,6 @@ static void musig_api_tests(secp256k1_scratch_space *scratch) { int i; /** setup **/ - int ecount; - - secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - memset(max64, 0xff, sizeof(max64)); memset(&invalid_keypair, 0, sizeof(invalid_keypair)); memset(&invalid_pk, 0, sizeof(invalid_pk)); @@ -206,7 +199,6 @@ static void musig_api_tests(secp256k1_scratch_space *scratch) { /** main test body **/ /** Key aggregation **/ - ecount = 0; CHECK(secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); /* pubkey_agg does not require a scratch space */ CHECK(secp256k1_musig_pubkey_agg(CTX, NULL, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); @@ -216,31 +208,23 @@ static void musig_api_tests(secp256k1_scratch_space *scratch) { secp256k1_scratch_space_destroy(CTX, scratch_small); CHECK(secp256k1_musig_pubkey_agg(CTX, scratch, NULL, &keyagg_cache, pk_ptr, 2) == 1); CHECK(secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, NULL, pk_ptr, 2) == 1); - CHECK(secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, NULL, 2) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, NULL, 2)); CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK(secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, invalid_pk_ptr2, 2)); CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK(secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, invalid_pk_ptr3, 3) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, invalid_pk_ptr3, 3)); CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK(secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, pk_ptr, 0) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, pk_ptr, 0)); CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); - CHECK(secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, NULL, 0) == 0); - CHECK(ecount == 5); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, NULL, 0)); CHECK(memcmp_and_randomize(agg_pk.data, zeros132, sizeof(agg_pk.data)) == 0); CHECK(secp256k1_musig_pubkey_agg(CTX, scratch, &agg_pk, &keyagg_cache, pk_ptr, 2) == 1); /* pubkey_get */ - ecount = 0; CHECK(secp256k1_musig_pubkey_get(CTX, &full_agg_pk, &keyagg_cache) == 1); - CHECK(secp256k1_musig_pubkey_get(CTX, NULL, &keyagg_cache) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_pubkey_get(CTX, &full_agg_pk, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_get(CTX, NULL, &keyagg_cache)); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubkey_get(CTX, &full_agg_pk, NULL)); CHECK(secp256k1_memcmp_var(&full_agg_pk, zeros132, sizeof(full_agg_pk)) == 0); /** Tweaking **/ @@ -251,7 +235,6 @@ static void musig_api_tests(secp256k1_scratch_space *scratch) { for (i = 0; i < 2; i++) { secp256k1_pubkey tmp_output_pk; secp256k1_musig_keyagg_cache tmp_keyagg_cache = keyagg_cache; - ecount = 0; CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, tweak) == 1); /* Reset keyagg_cache */ tmp_keyagg_cache = keyagg_cache; @@ -259,88 +242,61 @@ static void musig_api_tests(secp256k1_scratch_space *scratch) { tmp_keyagg_cache = keyagg_cache; CHECK((*tweak_func[i])(CTX, NULL, &tmp_keyagg_cache, tweak) == 1); tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(CTX, &tmp_output_pk, NULL, tweak) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, NULL, tweak)); CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); tmp_keyagg_cache = keyagg_cache; - CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, NULL)); CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); tmp_keyagg_cache = keyagg_cache; CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &tmp_keyagg_cache, max64) == 0); - CHECK(ecount == 2); CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); tmp_keyagg_cache = keyagg_cache; /* Uninitialized keyagg_cache */ - CHECK((*tweak_func[i])(CTX, &tmp_output_pk, &invalid_keyagg_cache, tweak) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, (*tweak_func[i])(CTX, &tmp_output_pk, &invalid_keyagg_cache, tweak)); CHECK(memcmp_and_randomize(tmp_output_pk.data, zeros132, sizeof(tmp_output_pk.data)) == 0); } } /** Session creation **/ - ecount = 0; CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_musig_nonce_gen(STATIC_CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_nonce_gen(CTX, NULL, &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], NULL, session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], NULL, sk[0], &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_musig_nonce_gen(STATIC_CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, NULL, &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], NULL, session_id[0], sk[0], &pk[0], msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], NULL, sk[0], &pk[0], msg, &keyagg_cache, max64)); CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); /* no seckey and session_id is 0 */ CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros132, NULL, &pk[0], msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 4); CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); /* session_id 0 is fine when a seckey is provided */ CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], zeros132, sk[0], &pk[0], msg, &keyagg_cache, max64) == 1); CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], NULL, &pk[0], msg, &keyagg_cache, max64) == 1); - CHECK(ecount == 4); /* invalid seckey */ CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], max64, &pk[0], msg, &keyagg_cache, max64) == 0); CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], NULL, msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64) == 0); - CHECK(ecount == 6); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], NULL, msg, &keyagg_cache, max64)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &invalid_pk, msg, &keyagg_cache, max64)); CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], NULL, &keyagg_cache, max64) == 1); - CHECK(ecount == 6); CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, NULL, max64) == 1); - CHECK(ecount == 6); - CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64) == 0); - CHECK(ecount == 7); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &invalid_keyagg_cache, max64)); CHECK(memcmp_and_randomize(secnonce[0].data, zeros132, sizeof(secnonce[0].data)) == 0); CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], sk[0], &pk[0], msg, &keyagg_cache, NULL) == 1); - CHECK(ecount == 7); /* Every in-argument except session_id and pubkey can be NULL */ CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[0], &pubnonce[0], session_id[0], NULL, &pk[0], NULL, NULL, NULL) == 1); CHECK(secp256k1_musig_nonce_gen(CTX, &secnonce[1], &pubnonce[1], session_id[1], sk[1], &pk[1], NULL, NULL, NULL) == 1); /** Serialize and parse public nonces **/ - ecount = 0; - CHECK(secp256k1_musig_pubnonce_serialize(CTX, NULL, &pubnonce[0]) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, NULL, &pubnonce[0])); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, NULL)); CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); - CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &invalid_pubnonce) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &invalid_pubnonce)); CHECK(memcmp_and_randomize(pubnonce_ser, zeros132, sizeof(pubnonce_ser)) == 0); CHECK(secp256k1_musig_pubnonce_serialize(CTX, pubnonce_ser, &pubnonce[0]) == 1); - ecount = 0; CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1); - CHECK(secp256k1_musig_pubnonce_parse(CTX, NULL, pubnonce_ser) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_parse(CTX, NULL, pubnonce_ser)); + CHECK_ILLEGAL(CTX, secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], NULL)); CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], zeros132) == 0); - CHECK(ecount == 2); CHECK(secp256k1_musig_pubnonce_parse(CTX, &pubnonce[0], pubnonce_ser) == 1); { @@ -352,16 +308,11 @@ static void musig_api_tests(secp256k1_scratch_space *scratch) { } /** Receive nonces and aggregate **/ - ecount = 0; CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); - CHECK(secp256k1_musig_nonce_agg(CTX, NULL, pubnonce_ptr, 2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, NULL, 2) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 0) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, invalid_pubnonce_ptr, 1) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, NULL, pubnonce_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, NULL, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 0)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_agg(CTX, &aggnonce, invalid_pubnonce_ptr, 1)); CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, inf_pubnonce_ptr, 2) == 1); { /* Check that the aggnonce encodes two points at infinity */ @@ -371,28 +322,20 @@ static void musig_api_tests(secp256k1_scratch_space *scratch) { secp256k1_ge_is_infinity(&aggnonce_pt[i]); } } - CHECK(ecount == 4); CHECK(secp256k1_musig_nonce_agg(CTX, &aggnonce, pubnonce_ptr, 2) == 1); /** Serialize and parse aggregate nonces **/ - ecount = 0; CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); - CHECK(secp256k1_musig_aggnonce_serialize(CTX, NULL, &aggnonce) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, NULL, &aggnonce)); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, NULL)); CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); - CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, (secp256k1_musig_aggnonce*) &invalid_pubnonce) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, (secp256k1_musig_aggnonce*) &invalid_pubnonce)); CHECK(memcmp_and_randomize(aggnonce_ser, zeros132, sizeof(aggnonce_ser)) == 0); CHECK(secp256k1_musig_aggnonce_serialize(CTX, aggnonce_ser, &aggnonce) == 1); - ecount = 0; CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, aggnonce_ser) == 1); - CHECK(secp256k1_musig_aggnonce_parse(CTX, NULL, aggnonce_ser) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_parse(CTX, NULL, aggnonce_ser)); + CHECK_ILLEGAL(CTX, secp256k1_musig_aggnonce_parse(CTX, &aggnonce, NULL)); CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, zeros132) == 1); CHECK(secp256k1_musig_aggnonce_parse(CTX, &aggnonce, aggnonce_ser) == 1); @@ -405,86 +348,59 @@ static void musig_api_tests(secp256k1_scratch_space *scratch) { } /** Process nonces **/ - ecount = 0; CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache, &adaptor) == 1); - CHECK(secp256k1_musig_nonce_process(CTX, NULL, &aggnonce, msg, &keyagg_cache, &adaptor) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_nonce_process(CTX, &session, NULL, msg, &keyagg_cache, &adaptor) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_musig_nonce_process(CTX, &session, (secp256k1_musig_aggnonce*) &invalid_pubnonce, msg, &keyagg_cache, &adaptor) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, NULL, &keyagg_cache, &adaptor) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, NULL, &adaptor) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &invalid_keyagg_cache, &adaptor) == 0); - CHECK(ecount == 6); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, NULL, &aggnonce, msg, &keyagg_cache, &adaptor)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, NULL, msg, &keyagg_cache, &adaptor)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, (secp256k1_musig_aggnonce*) &invalid_pubnonce, msg, &keyagg_cache, &adaptor)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, NULL, &keyagg_cache, &adaptor)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, NULL, &adaptor)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &invalid_keyagg_cache, &adaptor)); CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache, NULL) == 1); - CHECK(ecount == 6); - CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache, (secp256k1_pubkey *)&invalid_pk) == 0); - CHECK(ecount == 7); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache, (secp256k1_pubkey *)&invalid_pk)); CHECK(secp256k1_musig_nonce_process(CTX, &session, &aggnonce, msg, &keyagg_cache, &adaptor) == 1); - ecount = 0; memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 1); /* The secnonce is set to 0 and subsequent signing attempts fail */ CHECK(secp256k1_memcmp_var(&secnonce_tmp, zeros132, sizeof(secnonce_tmp)) == 0); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &session)); memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(secp256k1_musig_partial_sign(CTX, NULL, &secnonce_tmp, &keypair[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, NULL, &secnonce_tmp, &keypair[0], &keyagg_cache, &session)); memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], NULL, &keypair[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &invalid_secnonce, &keypair[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, NULL, &keyagg_cache, &session) == 0); - CHECK(ecount == 5); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], NULL, &keypair[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &invalid_secnonce, &keypair[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, NULL, &keyagg_cache, &session)); memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &invalid_keypair, &keyagg_cache, &session) == 0); - CHECK(ecount == 6); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &invalid_keypair, &keyagg_cache, &session)); memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); { unsigned char sk_tmp[32]; secp256k1_keypair keypair_tmp; secp256k1_testrand256(sk_tmp); CHECK(secp256k1_keypair_create(CTX, &keypair_tmp, sk_tmp)); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair_tmp, &keyagg_cache, &session) == 0); - CHECK(ecount == 7); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair_tmp, &keyagg_cache, &session)); memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); } - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], NULL, &session) == 0); - CHECK(ecount == 8); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], NULL, &session)); memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &invalid_keyagg_cache, &session) == 0); - CHECK(ecount == 9); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &invalid_keyagg_cache, &session)); memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, NULL) == 0); - CHECK(ecount == 10); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, NULL)); memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); - CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &invalid_session) == 0); - CHECK(ecount == 11); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce_tmp, &keypair[0], &keyagg_cache, &invalid_session)); memcpy(&secnonce_tmp, &secnonce[0], sizeof(secnonce_tmp)); CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[0], &secnonce[0], &keypair[0], &keyagg_cache, &session) == 1); CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig[1], &secnonce[1], &keypair[1], &keyagg_cache, &session) == 1); - ecount = 0; CHECK(secp256k1_musig_partial_sig_serialize(CTX, buf, &partial_sig[0]) == 1); - CHECK(secp256k1_musig_partial_sig_serialize(CTX, NULL, &partial_sig[0]) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_partial_sig_serialize(CTX, buf, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, NULL, &partial_sig[0])); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_serialize(CTX, buf, NULL)); CHECK(secp256k1_musig_partial_sig_parse(CTX, &partial_sig[0], buf) == 1); - CHECK(secp256k1_musig_partial_sig_parse(CTX, NULL, buf) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_parse(CTX, NULL, buf)); CHECK(secp256k1_musig_partial_sig_parse(CTX, &partial_sig[0], max64) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_musig_partial_sig_parse(CTX, &partial_sig[0], NULL) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_parse(CTX, &partial_sig[0], NULL)); { /* Check that serialize and parse results in the same value */ @@ -495,75 +411,46 @@ static void musig_api_tests(secp256k1_scratch_space *scratch) { } /** Partial signature verification */ - ecount = 0; CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); - CHECK(secp256k1_musig_partial_sig_verify(CTX, NULL, &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &invalid_partial_sig, &pubnonce[0], &pk[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], NULL, &pk[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &invalid_pubnonce, &pk[0], &keyagg_cache, &session) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], NULL, &keyagg_cache, &session) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &invalid_pk, &keyagg_cache, &session) == 0); - CHECK(ecount == 6); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], NULL, &session) == 0); - CHECK(ecount == 7); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &invalid_keyagg_cache, &session) == 0); - CHECK(ecount == 8); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, NULL) == 0); - CHECK(ecount == 9); - CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &invalid_session) == 0); - CHECK(ecount == 10); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, NULL, &pubnonce[0], &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &invalid_partial_sig, &pubnonce[0], &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], NULL, &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &invalid_pubnonce, &pk[0], &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], NULL, &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &invalid_pk, &keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], NULL, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &invalid_keyagg_cache, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &invalid_session)); CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[0], &pubnonce[0], &pk[0], &keyagg_cache, &session) == 1); CHECK(secp256k1_musig_partial_sig_verify(CTX, &partial_sig[1], &pubnonce[1], &pk[1], &keyagg_cache, &session) == 1); /** Signature aggregation and verification */ - ecount = 0; CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); - CHECK(secp256k1_musig_partial_sig_agg(CTX, NULL, &session, partial_sig_ptr, 2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, NULL, partial_sig_ptr, 2) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &invalid_session, partial_sig_ptr, 2) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, NULL, 2) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, invalid_partial_sig_ptr, 2) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 0) == 0); - CHECK(ecount == 6); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, NULL, &session, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, NULL, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &invalid_session, partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, NULL, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, invalid_partial_sig_ptr, 2)); + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 0)); CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 1) == 1); CHECK(secp256k1_musig_partial_sig_agg(CTX, pre_sig, &session, partial_sig_ptr, 2) == 1); /** Adaptor signature verification */ - ecount = 0; CHECK(secp256k1_musig_nonce_parity(CTX, &nonce_parity, &session) == 1); - CHECK(secp256k1_musig_nonce_parity(CTX, NULL, &session) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_nonce_parity(CTX, &nonce_parity, NULL) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_musig_nonce_parity(CTX, &nonce_parity, &invalid_session) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_parity(CTX, NULL, &session)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_parity(CTX, &nonce_parity, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_musig_nonce_parity(CTX, &nonce_parity, &invalid_session)); - ecount = 0; CHECK(secp256k1_musig_adapt(CTX, final_sig, pre_sig, sec_adaptor, nonce_parity) == 1); - CHECK(secp256k1_musig_adapt(CTX, NULL, pre_sig, sec_adaptor, 0) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_adapt(CTX, final_sig, NULL, sec_adaptor, 0) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_musig_adapt(CTX, NULL, pre_sig, sec_adaptor, 0)); + CHECK_ILLEGAL(CTX, secp256k1_musig_adapt(CTX, final_sig, NULL, sec_adaptor, 0)); CHECK(secp256k1_musig_adapt(CTX, final_sig, max64, sec_adaptor, 0) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_musig_adapt(CTX, final_sig, pre_sig, NULL, 0) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_musig_adapt(CTX, final_sig, pre_sig, NULL, 0)); CHECK(secp256k1_musig_adapt(CTX, final_sig, pre_sig, max64, 0) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_musig_adapt(CTX, final_sig, pre_sig, sec_adaptor, 2) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_musig_adapt(CTX, final_sig, pre_sig, sec_adaptor, 2)); /* sig and pre_sig argument point to the same location */ memcpy(final_sig, pre_sig, sizeof(final_sig)); CHECK(secp256k1_musig_adapt(CTX, final_sig, final_sig, sec_adaptor, nonce_parity) == 1); @@ -573,29 +460,17 @@ static void musig_api_tests(secp256k1_scratch_space *scratch) { CHECK(secp256k1_schnorrsig_verify(CTX, final_sig, msg, sizeof(msg), &agg_pk) == 1); /** Secret adaptor can be extracted from signature */ - ecount = 0; CHECK(secp256k1_musig_extract_adaptor(CTX, sec_adaptor1, final_sig, pre_sig, nonce_parity) == 1); CHECK(secp256k1_memcmp_var(sec_adaptor, sec_adaptor1, 32) == 0); /* wrong nonce parity */ CHECK(secp256k1_musig_extract_adaptor(CTX, sec_adaptor1, final_sig, pre_sig, !nonce_parity) == 1); CHECK(secp256k1_memcmp_var(sec_adaptor, sec_adaptor1, 32) != 0); - CHECK(secp256k1_musig_extract_adaptor(CTX, NULL, final_sig, pre_sig, 0) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_musig_extract_adaptor(CTX, sec_adaptor1, NULL, pre_sig, 0) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_musig_extract_adaptor(CTX, NULL, final_sig, pre_sig, 0)); + CHECK_ILLEGAL(CTX, secp256k1_musig_extract_adaptor(CTX, sec_adaptor1, NULL, pre_sig, 0)); CHECK(secp256k1_musig_extract_adaptor(CTX, sec_adaptor1, max64, pre_sig, 0) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_musig_extract_adaptor(CTX, sec_adaptor1, final_sig, NULL, 0) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_musig_extract_adaptor(CTX, sec_adaptor1, final_sig, NULL, 0)); CHECK(secp256k1_musig_extract_adaptor(CTX, sec_adaptor1, final_sig, max64, 0) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_musig_extract_adaptor(CTX, sec_adaptor1, final_sig, pre_sig, 2) == 0); - CHECK(ecount == 4); - - secp256k1_context_set_error_callback(CTX, NULL, NULL); - secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); + CHECK_ILLEGAL(CTX, secp256k1_musig_extract_adaptor(CTX, sec_adaptor1, final_sig, pre_sig, 2)); } static void musig_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) { @@ -1148,18 +1023,11 @@ static void musig_test_vectors_signverify(void) { CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, vector->pubkeys[0], sizeof(vector->pubkeys[0]))); musig_test_set_secnonce(&secnonce, vector->secnonces[c->secnonce_index], &pubkey); - { - /* In the last test vector we sign with an invalid secnonce, which - * triggers an illegal_callback. Hence, we need to use a custom - * context that does not abort in this case. */ - secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_NONE); - int32_t ecount = 0; - secp256k1_context_set_error_callback(ctx_tmp, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount); - expected = c->error != MUSIG_SECNONCE; - CHECK(expected == secp256k1_musig_partial_sign(ctx_tmp, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); - CHECK((!expected) == ecount); - secp256k1_context_destroy(ctx_tmp); + expected = c->error != MUSIG_SECNONCE; + if (expected) { + CHECK(secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); + } else { + CHECK_ILLEGAL(CTX, secp256k1_musig_partial_sign(CTX, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session)); } } for (i = 0; i < sizeof(vector->verify_fail_case)/sizeof(vector->verify_fail_case[0]); i++) { diff --git a/src/modules/rangeproof/tests_impl.h b/src/modules/rangeproof/tests_impl.h index 82768b9c58..49cc16cf87 100644 --- a/src/modules/rangeproof/tests_impl.h +++ b/src/modules/rangeproof/tests_impl.h @@ -16,7 +16,7 @@ #include "../../../include/secp256k1_rangeproof.h" -static void test_rangeproof_api(const int32_t *ecount) { +static void test_rangeproof_api(void) { unsigned char proof[5134]; unsigned char blind[32]; secp256k1_pedersen_commitment commit; @@ -33,32 +33,19 @@ static void test_rangeproof_api(const int32_t *ecount) { CHECK(secp256k1_pedersen_commit(CTX, &commit, blind, val, secp256k1_generator_h)); CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 1); - CHECK(*ecount == 0); - CHECK(secp256k1_rangeproof_sign(STATIC_CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_rangeproof_sign(STATIC_CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h)); - CHECK(secp256k1_rangeproof_sign(CTX, NULL, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 2); - CHECK(secp256k1_rangeproof_sign(CTX, proof, NULL, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 3); - CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, NULL, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 4); - CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, NULL, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 5); - CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, NULL, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 6); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_sign(CTX, NULL, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_sign(CTX, proof, NULL, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_sign(CTX, proof, &len, vmin, NULL, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, NULL, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, NULL, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h)); CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, vmin - 1, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 6); - CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 7); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, mlen, ext_commit, ext_commit_len, secp256k1_generator_h)); CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); - CHECK(*ecount == 7); - CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 8); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, ext_commit_len, secp256k1_generator_h)); CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, secp256k1_generator_h) != 0); - CHECK(*ecount == 8); - CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, NULL) == 0); - CHECK(*ecount == 9); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, NULL)); CHECK(secp256k1_rangeproof_sign(CTX, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); { @@ -73,41 +60,26 @@ static void test_rangeproof_api(const int32_t *ecount) { CHECK(min_value == vmin); CHECK(max_value >= val); - CHECK(secp256k1_rangeproof_info(CTX, NULL, &mantissa, &min_value, &max_value, proof, len) == 0); - CHECK(*ecount == 10); - CHECK(secp256k1_rangeproof_info(CTX, &exp, NULL, &min_value, &max_value, proof, len) == 0); - CHECK(*ecount == 11); - CHECK(secp256k1_rangeproof_info(CTX, &exp, &mantissa, NULL, &max_value, proof, len) == 0); - CHECK(*ecount == 12); - CHECK(secp256k1_rangeproof_info(CTX, &exp, &mantissa, &min_value, NULL, proof, len) == 0); - CHECK(*ecount == 13); - CHECK(secp256k1_rangeproof_info(CTX, &exp, &mantissa, &min_value, &max_value, NULL, len) == 0); - CHECK(*ecount == 14); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_info(CTX, NULL, &mantissa, &min_value, &max_value, proof, len)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_info(CTX, &exp, NULL, &min_value, &max_value, proof, len)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_info(CTX, &exp, &mantissa, NULL, &max_value, proof, len)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_info(CTX, &exp, &mantissa, &min_value, NULL, proof, len)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_info(CTX, &exp, &mantissa, &min_value, &max_value, NULL, len)); CHECK(secp256k1_rangeproof_info(CTX, &exp, &mantissa, &min_value, &max_value, proof, 0) == 0); - CHECK(*ecount == 14); } { uint64_t min_value; uint64_t max_value; CHECK(secp256k1_rangeproof_verify(CTX, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 1); - CHECK(*ecount == 14); - CHECK(secp256k1_rangeproof_verify(CTX, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 15); - CHECK(secp256k1_rangeproof_verify(CTX, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 16); - CHECK(secp256k1_rangeproof_verify(CTX, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 17); - CHECK(secp256k1_rangeproof_verify(CTX, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 18); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_verify(CTX, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_verify(CTX, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_verify(CTX, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_verify(CTX, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_generator_h)); CHECK(secp256k1_rangeproof_verify(CTX, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 18); - CHECK(secp256k1_rangeproof_verify(CTX, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 19); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_verify(CTX, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_generator_h)); CHECK(secp256k1_rangeproof_verify(CTX, &min_value, &max_value, &commit, proof, len, NULL, 0, secp256k1_generator_h) == 0); - CHECK(*ecount == 19); - CHECK(secp256k1_rangeproof_verify(CTX, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0); - CHECK(*ecount == 20); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_verify(CTX, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL)); } { unsigned char blind_out[32]; @@ -118,9 +90,7 @@ static void test_rangeproof_api(const int32_t *ecount) { size_t message_len = sizeof(message_out); CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 1); - CHECK(*ecount == 20); - CHECK(secp256k1_rangeproof_rewind(STATIC_CTX, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 21); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_rangeproof_rewind(STATIC_CTX, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h)); CHECK(min_value == vmin); CHECK(max_value >= val); @@ -128,32 +98,21 @@ static void test_rangeproof_api(const int32_t *ecount) { CHECK(message_len == sizeof(message_out)); CHECK(secp256k1_memcmp_var(message, message_out, sizeof(message_out)) == 0); + /* blindout may be NULL */ CHECK(secp256k1_rangeproof_rewind(CTX, NULL, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); - CHECK(*ecount == 21); /* blindout may be NULL */ + /* valueout may be NULL */ CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, NULL, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); - CHECK(*ecount == 21); /* valueout may be NULL */ - CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 22); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h)); CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); - CHECK(*ecount == 22); - CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, NULL, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 23); - CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 24); - CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 25); - CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 26); - CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 27); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, NULL, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h)); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_generator_h)); CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 27); - CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_generator_h) == 0); - CHECK(*ecount == 28); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_generator_h)); CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, secp256k1_generator_h) == 0); - CHECK(*ecount == 28); - CHECK(secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0); - CHECK(*ecount == 29); + CHECK_ILLEGAL(CTX, secp256k1_rangeproof_rewind(CTX, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL)); } /* This constant is hardcoded in these tests and elsewhere, so we @@ -162,26 +121,6 @@ static void test_rangeproof_api(const int32_t *ecount) { CHECK(secp256k1_rangeproof_max_size(CTX, UINT64_MAX, 0) == 5134); } -static void test_api(void) { - int32_t ecount; - int i; - - secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - - for (i = 0; i < COUNT; i++) { - ecount = 0; - test_rangeproof_api(&ecount); - } - - secp256k1_context_set_error_callback(CTX, NULL, NULL); - secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); -} - static void test_borromean(void) { unsigned char e0[32]; secp256k1_scalar s[64]; @@ -483,6 +422,7 @@ static void test_single_value_proof(uint64_t val) { uint64_t val_out = 0; size_t m_len_out = 0; + size_t i; secp256k1_testrand256(blind); secp256k1_testrand256(nonce); @@ -524,6 +464,30 @@ static void test_single_value_proof(uint64_t val) { CHECK(plen == 73); } + /* Test if trailing bytes are rejected. */ + proof[plen] = 0; + CHECK(secp256k1_rangeproof_verify( + CTX, + &min_val_out, &max_val_out, + &commit, + proof, plen + 1, + NULL, 0, + secp256k1_generator_h + ) == 0); + /* Test if single-bit malleation is caught */ + for (i = 0; i < plen*8; i++) { + proof[i >> 3] ^= 1 << (i & 7); + CHECK(secp256k1_rangeproof_verify( + CTX, + &min_val_out, &max_val_out, + &commit, + proof, plen, + NULL, 0, + secp256k1_generator_h + ) == 0); + proof[i >> 3] ^= 1 << (i & 7); + } + /* Test if unchanged proof is accepted. */ CHECK(secp256k1_rangeproof_verify( CTX, &min_val_out, &max_val_out, @@ -1384,7 +1348,9 @@ static void test_rangeproof_fixed_vectors_reproducible(void) { static void run_rangeproof_tests(void) { int i; - test_api(); + for (i = 0; i < COUNT; i++) { + test_rangeproof_api(); + } test_single_value_proof(0); test_single_value_proof(12345678); diff --git a/src/modules/recovery/tests_impl.h b/src/modules/recovery/tests_impl.h index 3502c71ffe..728ccfed8d 100644 --- a/src/modules/recovery/tests_impl.h +++ b/src/modules/recovery/tests_impl.h @@ -36,7 +36,6 @@ static void test_ecdsa_recovery_api(void) { secp256k1_ecdsa_recoverable_signature recsig; unsigned char privkey[32] = { 1 }; unsigned char message[32] = { 2 }; - int32_t ecount = 0; int recid = 0; unsigned char sig[74]; unsigned char zero_privkey[32] = { 0 }; @@ -45,86 +44,52 @@ static void test_ecdsa_recovery_api(void) { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - /* Construct and verify corresponding public key. */ CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1); /* Check bad contexts and NULLs for signing */ - ecount = 0; CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL)); /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, recovery_test_nonce_function, NULL); - CHECK(ecount == 4); /* These will all fail, but not in ARG_CHECK way */ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, zero_privkey, NULL, NULL) == 0); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, over_privkey, NULL, NULL) == 0); /* This one will succeed. */ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); - CHECK(ecount == 4); /* Check signing with a goofy nonce function */ /* Check bad contexts and NULLs for recovery */ - ecount = 0; CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, message) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_recover(CTX, NULL, &recsig, message) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, NULL, &recsig, message)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL)); /* Check NULLs for conversion */ CHECK(secp256k1_ecdsa_sign(CTX, &normal_sig, message, privkey, NULL, NULL) == 1); - ecount = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL)); CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, &recsig) == 1); /* Check NULLs for de/serialization */ CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1); - ecount = 0; - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL)); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &recsig) == 1); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1) == 0); - CHECK(ecount == 6); - CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5) == 0); - CHECK(ecount == 7); - /* overflow in signature will fail but not affect ecount */ + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5)); + /* overflow in signature will not result in calling illegal_callback */ memcpy(sig, over_privkey, 32); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0); - CHECK(ecount == 7); - - /* cleanup */ - secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); } static void test_ecdsa_recovery_end_to_end(void) { diff --git a/src/modules/schnorrsig/main_impl.h b/src/modules/schnorrsig/main_impl.h index 4e7b45a045..26727e4651 100644 --- a/src/modules/schnorrsig/main_impl.h +++ b/src/modules/schnorrsig/main_impl.h @@ -261,7 +261,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha secp256k1_fe_normalize_var(&r.y); return !secp256k1_fe_is_odd(&r.y) && - secp256k1_fe_equal_var(&rx, &r.x); + secp256k1_fe_equal(&rx, &r.x); } #endif diff --git a/src/modules/schnorrsig/tests_exhaustive_impl.h b/src/modules/schnorrsig/tests_exhaustive_impl.h index 55f9028a63..bc31d81107 100644 --- a/src/modules/schnorrsig/tests_exhaustive_impl.h +++ b/src/modules/schnorrsig/tests_exhaustive_impl.h @@ -110,15 +110,15 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons if (!e_done[e]) { /* Iterate over the possible valid last 32 bytes in the signature. 0..order=that s value; order+1=random bytes */ - int count_valid = 0, s; + int count_valid = 0; + unsigned int s; for (s = 0; s <= EXHAUSTIVE_TEST_ORDER + 1; ++s) { int expect_valid, valid; if (s <= EXHAUSTIVE_TEST_ORDER) { - secp256k1_scalar s_s; - secp256k1_scalar_set_int(&s_s, s); - secp256k1_scalar_get_b32(sig64 + 32, &s_s); + memset(sig64 + 32, 0, 32); + secp256k1_write_be32(sig64 + 60, s); expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER && - (s_s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); + (s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER); } else { secp256k1_testrand256(sig64 + 32); expect_valid = 0; diff --git a/src/modules/schnorrsig/tests_impl.h b/src/modules/schnorrsig/tests_impl.h index 90337ff03e..8ada90a87b 100644 --- a/src/modules/schnorrsig/tests_impl.h +++ b/src/modules/schnorrsig/tests_impl.h @@ -116,14 +116,6 @@ static void test_schnorrsig_api(void) { secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT; secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL}; - /** setup **/ - int ecount = 0; - - secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_testrand256(sk1); secp256k1_testrand256(sk2); secp256k1_testrand256(sk3); @@ -137,57 +129,30 @@ static void test_schnorrsig_api(void) { memset(&zero_pk, 0, sizeof(zero_pk)); /** main test body **/ - ecount = 0; CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL) == 0); - CHECK(ecount == 5); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL)); - ecount = 0; CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams)); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, 0, &keypairs[0], &extraparams) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams)); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1); - CHECK(ecount == 4); - CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0); - CHECK(ecount == 6); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams)); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams)); - ecount = 0; CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1); CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk[0]) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0]) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0]) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0])); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0])); CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, 0, &pk[0]) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk) == 0); - CHECK(ecount == 4); - - secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk)); } /* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the diff --git a/src/modules/schnorrsig_halfagg/Makefile.am.include b/src/modules/schnorrsig_halfagg/Makefile.am.include new file mode 100644 index 0000000000..8cc0407423 --- /dev/null +++ b/src/modules/schnorrsig_halfagg/Makefile.am.include @@ -0,0 +1,3 @@ +include_HEADERS += include/secp256k1_schnorrsig_halfagg.h +noinst_HEADERS += src/modules/schnorrsig_halfagg/main_impl.h +noinst_HEADERS += src/modules/schnorrsig_halfagg/tests_impl.h diff --git a/src/modules/schnorrsig_halfagg/main_impl.h b/src/modules/schnorrsig_halfagg/main_impl.h new file mode 100644 index 0000000000..7eac107986 --- /dev/null +++ b/src/modules/schnorrsig_halfagg/main_impl.h @@ -0,0 +1,202 @@ +#ifndef SECP256K1_MODULE_SCHNORRSIG_HALFAGG_MAIN_H +#define SECP256K1_MODULE_SCHNORRSIG_HALFAGG_MAIN_H + +#include "../../../include/secp256k1.h" +#include "../../../include/secp256k1_schnorrsig.h" +#include "../../../include/secp256k1_schnorrsig_halfagg.h" +#include "../../hash.h" + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("HalfAgg/randomizer")||SHA256("HalfAgg/randomizer"). */ +void secp256k1_schnorrsig_sha256_tagged_aggregation(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0xd11f5532ul; + sha->s[1] = 0xfa57f70ful; + sha->s[2] = 0x5db0d728ul; + sha->s[3] = 0xf806ffe1ul; + sha->s[4] = 0x1d4db069ul; + sha->s[5] = 0xb4d587e1ul; + sha->s[6] = 0x50451c2aul; + sha->s[7] = 0x10fb63e9ul; + + sha->bytes = 64; +} + +int secp256k1_schnorrsig_inc_aggregate(const secp256k1_context *ctx, unsigned char *aggsig, size_t *aggsig_len, const secp256k1_xonly_pubkey *all_pubkeys, const unsigned char *all_msgs32, const unsigned char *new_sigs64, size_t n_before, size_t n_new) { + size_t i; + size_t n; + secp256k1_sha256 hash; + secp256k1_scalar s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(aggsig != NULL); + ARG_CHECK(aggsig_len != NULL); + ARG_CHECK(new_sigs64 != NULL || n_new == 0); + + /* Check that aggsig_len is large enough, i.e. aggsig_len >= 32*(n+1) */ + n = n_before + n_new; + ARG_CHECK(n >= n_before); + ARG_CHECK(all_pubkeys != NULL || n == 0); + ARG_CHECK(all_msgs32 != NULL || n == 0); + if ((*aggsig_len / 32) <= 0 || ((*aggsig_len / 32) - 1) < n) { + return 0; + } + + /* Prepare hash with common prefix. The prefix is the tag and */ + /* r_0 || pk_0 || m_0 || .... || r_{n'-1} || pk_{n'-1} || m_{n'-1} */ + /* where n' = n_before */ + secp256k1_schnorrsig_sha256_tagged_aggregation(&hash); + for (i = 0; i < n_before; ++i) { + /* serialize pk_i */ + unsigned char pk_ser[32]; + if (!secp256k1_xonly_pubkey_serialize(ctx, pk_ser, &all_pubkeys[i])) { + return 0; + } + /* write r_i */ + secp256k1_sha256_write(&hash, &aggsig[i*32], 32); + /* write pk_i */ + secp256k1_sha256_write(&hash, pk_ser, 32); + /* write m_i*/ + secp256k1_sha256_write(&hash, &all_msgs32[i*32], 32); + } + + /* Compute s = s_old + sum_{i = n_before}^{n} z_i*s_i */ + /* where s_old = 0 if n_before = 0 */ + secp256k1_scalar_set_int(&s, 0); + if (n_before > 0) secp256k1_scalar_set_b32(&s, &aggsig[n_before*32], NULL); + for (i = n_before; i < n; ++i) { + unsigned char pk_ser[32]; + unsigned char hashoutput[32]; + secp256k1_sha256 hashcopy; + secp256k1_scalar si; + secp256k1_scalar zi; + + /* Step 0: Serialize pk_i into pk_ser */ + if (!secp256k1_xonly_pubkey_serialize(ctx, pk_ser, &all_pubkeys[i])) { + return 0; + } + + /* Step 1: z_i = TaggedHash(...) */ + /* 1.a) Write into hash r_i, pk_i, m_i, r_i */ + secp256k1_sha256_write(&hash, &new_sigs64[(i-n_before)*64], 32); + secp256k1_sha256_write(&hash, pk_ser, 32); + secp256k1_sha256_write(&hash, &all_msgs32[i*32], 32); + /* 1.b) Copy the hash */ + hashcopy = hash; + /* 1.c) Finalize the copy to get zi*/ + secp256k1_sha256_finalize(&hashcopy, hashoutput); + /* Note: No need to check overflow, comes from hash */ + secp256k1_scalar_set_b32(&zi, hashoutput, NULL); + + /* Step 2: s := s + zi*si */ + /* except if i == 0, then zi = 1 implicitly */ + secp256k1_scalar_set_b32(&si, &new_sigs64[(i-n_before)*64+32], NULL); + if (i != 0) secp256k1_scalar_mul(&si, &si, &zi); + secp256k1_scalar_add(&s, &s, &si); + } + + /* copy new rs into aggsig */ + for (i = n_before; i < n; ++i) { + memcpy(&aggsig[i*32], &new_sigs64[(i-n_before)*64], 32); + } + /* copy new s into aggsig */ + secp256k1_scalar_get_b32(&aggsig[n*32], &s); + *aggsig_len = 32 * (1 + n); + return 1; +} + +int secp256k1_schnorrsig_aggregate(const secp256k1_context *ctx, unsigned char *aggsig, size_t *aggsig_len, const secp256k1_xonly_pubkey *pubkeys, const unsigned char *msgs32, const unsigned char *sigs64, size_t n) { + return secp256k1_schnorrsig_inc_aggregate(ctx, aggsig, aggsig_len, pubkeys, msgs32, sigs64, 0, n); +} + +int secp256k1_schnorrsig_aggverify(const secp256k1_context *ctx, const secp256k1_xonly_pubkey *pubkeys, const unsigned char *msgs32, size_t n, const unsigned char *aggsig, size_t aggsig_len) { + size_t i; + secp256k1_gej lhs, rhs; + secp256k1_scalar s; + secp256k1_sha256 hash; + int overflow; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkeys != NULL || n == 0); + ARG_CHECK(msgs32 != NULL || n == 0); + ARG_CHECK(aggsig != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + + /* Check that aggsig_len is correct, i.e., aggsig_len = 32*(n+1) */ + if ((aggsig_len / 32) <= 0 || ((aggsig_len / 32)-1) != n || (aggsig_len % 32) != 0) { + return 0; + } + + /* Compute the rhs: */ + /* Set rhs = 0 */ + /* For each i in 0,.., n-1, do: */ + /* (1) z_i = TaggedHash(...) */ + /* (2) T_i = R_i+e_i*P_i */ + /* (3) rhs = rhs + z_i*T_i */ + secp256k1_gej_set_infinity(&rhs); + secp256k1_schnorrsig_sha256_tagged_aggregation(&hash); + for (i = 0; i < n; ++i) { + secp256k1_fe rx; + secp256k1_ge rp, pp; + secp256k1_scalar ei; + secp256k1_gej ppj, ti; + + unsigned char pk_ser[32]; + unsigned char hashoutput[32]; + secp256k1_sha256 hashcopy; + secp256k1_scalar zi; + + /* Step 0: Serialize pk_i into pk_ser */ + /* We need that in Step 1 and in Step 2 */ + if (!secp256k1_xonly_pubkey_load(ctx, &pp, &pubkeys[i])) { + return 0; + } + secp256k1_fe_get_b32(pk_ser, &pp.x); + + /* Step 1: z_i = TaggedHash(...) */ + /* 1.a) Write into hash r_i, pk_i, m_i, r_i */ + secp256k1_sha256_write(&hash, &aggsig[i*32], 32); + secp256k1_sha256_write(&hash, pk_ser, 32); + secp256k1_sha256_write(&hash, &msgs32[i*32], 32); + /* 1.b) Copy the hash */ + hashcopy = hash; + /* 1.c) Finalize the copy to get zi*/ + secp256k1_sha256_finalize(&hashcopy, hashoutput); + secp256k1_scalar_set_b32(&zi, hashoutput, NULL); + + /* Step 2: T_i = R_i+e_i*P_i */ + /* 2.a) R_i = lift_x(int(r_i)); fail if that fails */ + if (!secp256k1_fe_set_b32_limit(&rx, &aggsig[i*32])) { + return 0; + } + if (!secp256k1_ge_set_xo_var(&rp, &rx, 0)) { + return 0; + } + + /* 2.b) e_i = int(hash_{BIP0340/challenge}(bytes(r_i) || pk_i || m_i)) mod n */ + secp256k1_schnorrsig_challenge(&ei, &aggsig[i*32], &msgs32[i*32], 32, pk_ser); + secp256k1_gej_set_ge(&ppj, &pp); + /* 2.c) T_i = R_i + e_i*P_i */ + secp256k1_ecmult(&ti, &ppj, &ei, NULL); + secp256k1_gej_add_ge_var(&ti, &ti, &rp, NULL); + + /* Step 3: rhs = rhs + zi*T_i */ + /* Note that if i == 0, then zi = 1 implicitly */ + if (i != 0) secp256k1_ecmult(&ti, &ti, &zi, NULL); + secp256k1_gej_add_var(&rhs, &rhs, &ti, NULL); + } + + /* Compute the lhs as lhs = s*G */ + secp256k1_scalar_set_b32(&s, &aggsig[n*32], &overflow); + if (overflow) { + return 0; + } + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &lhs, &s); + + /* Check that lhs == rhs */ + secp256k1_gej_neg(&lhs, &lhs); + secp256k1_gej_add_var(&lhs, &lhs, &rhs, NULL); + return secp256k1_gej_is_infinity(&lhs); +} + +#endif diff --git a/src/modules/schnorrsig_halfagg/tests_impl.h b/src/modules/schnorrsig_halfagg/tests_impl.h new file mode 100644 index 0000000000..16ac3ab3b4 --- /dev/null +++ b/src/modules/schnorrsig_halfagg/tests_impl.h @@ -0,0 +1,338 @@ +#ifndef SECP256K1_MODULE_SCHNORRSIG_HALFAGG_TESTS_H +#define SECP256K1_MODULE_SCHNORRSIG_HALFAGG_TESTS_H + +#include "../../../include/secp256k1_schnorrsig_halfagg.h" + +#define N_MAX 50 + +/* We test that the hash initialized by secp256k1_schnorrsig_sha256_tagged_aggregate + * has the expected state. */ +void test_schnorrsig_sha256_tagged_aggregate(void) { + unsigned char tag[18] = "HalfAgg/randomizer"; + secp256k1_sha256 sha; + secp256k1_sha256 sha_optimized; + + secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag)); + secp256k1_schnorrsig_sha256_tagged_aggregation(&sha_optimized); + test_sha256_eq(&sha, &sha_optimized); +} + +/* Create n many x-only pubkeys and sigs for random messages */ +void test_schnorrsig_aggregate_input_helper(secp256k1_xonly_pubkey *pubkeys, unsigned char *msgs32, unsigned char *sigs64, size_t n) { + size_t i; + for (i = 0; i < n; ++i) { + unsigned char sk[32]; + secp256k1_keypair keypair; + secp256k1_testrand256(sk); + secp256k1_testrand256(&msgs32[i*32]); + + CHECK(secp256k1_keypair_create(CTX, &keypair, sk)); + CHECK(secp256k1_keypair_xonly_pub(CTX, &pubkeys[i], NULL, &keypair)); + CHECK(secp256k1_schnorrsig_sign(CTX, &sigs64[i*64], &msgs32[i*32], &keypair, NULL)); + } +} + +/* In this test we create a bunch of Schnorr signatures, + * aggregate some of them in one shot, and then + * aggregate the others incrementally to the already aggregated ones. + * The aggregate signature should verify after both steps. */ +void test_schnorrsig_aggregate(void) { + secp256k1_xonly_pubkey pubkeys[N_MAX]; + unsigned char msgs32[N_MAX*32]; + unsigned char sigs64[N_MAX*64]; + unsigned char aggsig[32*(N_MAX + 1) + 17]; + size_t aggsig_len = sizeof(aggsig); + + size_t n = secp256k1_testrand_int(N_MAX + 1); + size_t n_initial = secp256k1_testrand_int(n + 1); + size_t n_new = n - n_initial; + test_schnorrsig_aggregate_input_helper(pubkeys, msgs32, sigs64, n); + + /* Aggregate the first n_initial of them */ + CHECK(secp256k1_schnorrsig_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, sigs64, n_initial)); + /* Make sure that the aggregate signature verifies */ + CHECK(aggsig_len == 32*(n_initial + 1)); + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n_initial, aggsig, aggsig_len)); + /* Aggregate the remaining n_new many signatures to the already existing ones */ + aggsig_len = sizeof(aggsig); + secp256k1_schnorrsig_inc_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, &sigs64[n_initial*64], n_initial, n_new); + /* Make sure that the aggregate signature verifies */ + CHECK(aggsig_len == 32*(n + 1)); + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len)); + + /* Check that a direct aggregation of the n sigs yields an identical aggsig */ + { + unsigned char aggsig2[sizeof(aggsig)]; + size_t aggsig_len2 = sizeof(aggsig2); + CHECK(secp256k1_schnorrsig_aggregate(CTX, aggsig2, &aggsig_len2, pubkeys, msgs32, sigs64, n)); + CHECK(aggsig_len == aggsig_len2); + CHECK(secp256k1_memcmp_var(aggsig, aggsig2, aggsig_len) == 0); + } +} + +/* This tests the verification test vectors from + * https://github.com/BlockstreamResearch/cross-input-aggregation/blob/master/hacspec-halfagg/tests/tests.rs#L78 . */ +void test_schnorrsig_aggverify_spec_vectors(void) { + /* Test vector 0 */ + { + size_t n = 0; + const unsigned char aggsig[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + size_t aggsig_len = sizeof(aggsig); + CHECK(secp256k1_schnorrsig_aggverify(CTX, NULL, NULL, n, aggsig, aggsig_len)); + } + /* Test vector 1 */ + { + size_t n = 1; + const unsigned char pubkeys_ser[1*32] = { + 0x1b, 0x84, 0xc5, 0x56, 0x7b, 0x12, 0x64, 0x40, + 0x99, 0x5d, 0x3e, 0xd5, 0xaa, 0xba, 0x05, 0x65, + 0xd7, 0x1e, 0x18, 0x34, 0x60, 0x48, 0x19, 0xff, + 0x9c, 0x17, 0xf5, 0xe9, 0xd5, 0xdd, 0x07, 0x8f + }; + secp256k1_xonly_pubkey pubkeys[1]; + const unsigned char msgs32[1*32] = { + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 + }; + const unsigned char aggsig[1*32+32] = { + 0xb0, 0x70, 0xaa, 0xfc, 0xea, 0x43, 0x9a, 0x4f, + 0x6f, 0x1b, 0xbf, 0xc2, 0xeb, 0x66, 0xd2, 0x9d, + 0x24, 0xb0, 0xca, 0xb7, 0x4d, 0x6b, 0x74, 0x5c, + 0x3c, 0xfb, 0x00, 0x9c, 0xc8, 0xfe, 0x4a, 0xa8, + 0x0e, 0x06, 0x6c, 0x34, 0x81, 0x99, 0x36, 0x54, + 0x9f, 0xf4, 0x9b, 0x6f, 0xd4, 0xd4, 0x1e, 0xdf, + 0xc4, 0x01, 0xa3, 0x67, 0xb8, 0x7d, 0xdd, 0x59, + 0xfe, 0xe3, 0x81, 0x77, 0x96, 0x1c, 0x22, 0x5f, + }; + size_t aggsig_len = sizeof(aggsig); + size_t i; + for (i = 0; i < n; ++i) { + CHECK(secp256k1_xonly_pubkey_parse(CTX, &pubkeys[i], &pubkeys_ser[i*32])); + } + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len)); + } + /* Test vector 2 */ + { + size_t n = 2; + const unsigned char pubkeys_ser[2*32] = { + 0x1b, 0x84, 0xc5, 0x56, 0x7b, 0x12, 0x64, 0x40, + 0x99, 0x5d, 0x3e, 0xd5, 0xaa, 0xba, 0x05, 0x65, + 0xd7, 0x1e, 0x18, 0x34, 0x60, 0x48, 0x19, 0xff, + 0x9c, 0x17, 0xf5, 0xe9, 0xd5, 0xdd, 0x07, 0x8f, + + 0x46, 0x27, 0x79, 0xad, 0x4a, 0xad, 0x39, 0x51, + 0x46, 0x14, 0x75, 0x1a, 0x71, 0x08, 0x5f, 0x2f, + 0x10, 0xe1, 0xc7, 0xa5, 0x93, 0xe4, 0xe0, 0x30, + 0xef, 0xb5, 0xb8, 0x72, 0x1c, 0xe5, 0x5b, 0x0b, + }; + secp256k1_xonly_pubkey pubkeys[2]; + const unsigned char msgs32[2*32] = { + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + }; + const unsigned char aggsig[2*32+32] = { + 0xb0, 0x70, 0xaa, 0xfc, 0xea, 0x43, 0x9a, 0x4f, + 0x6f, 0x1b, 0xbf, 0xc2, 0xeb, 0x66, 0xd2, 0x9d, + 0x24, 0xb0, 0xca, 0xb7, 0x4d, 0x6b, 0x74, 0x5c, + 0x3c, 0xfb, 0x00, 0x9c, 0xc8, 0xfe, 0x4a, 0xa8, + 0xa3, 0xaf, 0xbd, 0xb4, 0x5a, 0x6a, 0x34, 0xbf, + 0x7c, 0x8c, 0x00, 0xf1, 0xb6, 0xd7, 0xe7, 0xd3, + 0x75, 0xb5, 0x45, 0x40, 0xf1, 0x37, 0x16, 0xc8, + 0x7b, 0x62, 0xe5, 0x1e, 0x2f, 0x4f, 0x22, 0xff, + 0xbf, 0x89, 0x13, 0xec, 0x53, 0x22, 0x6a, 0x34, + 0x89, 0x2d, 0x60, 0x25, 0x2a, 0x70, 0x52, 0x61, + 0x4c, 0xa7, 0x9a, 0xe9, 0x39, 0x98, 0x68, 0x28, + 0xd8, 0x1d, 0x23, 0x11, 0x95, 0x73, 0x71, 0xad, + }; + size_t aggsig_len = sizeof(aggsig); + size_t i; + for (i = 0; i < n; ++i) { + CHECK(secp256k1_xonly_pubkey_parse(CTX, &pubkeys[i], &pubkeys_ser[i*32])); + } + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len)); + } +} + +static void test_schnorrsig_aggregate_api(void) { + size_t n = secp256k1_testrand_int(N_MAX + 1); + size_t n_initial = secp256k1_testrand_int(n + 1); + size_t n_new = n - n_initial; + + /* Test preparation. */ + secp256k1_xonly_pubkey pubkeys[N_MAX]; + unsigned char msgs32[N_MAX*32]; + unsigned char sigs64[N_MAX*64]; + unsigned char aggsig[32*(N_MAX + 1)]; + test_schnorrsig_aggregate_input_helper(pubkeys, msgs32, sigs64, n); + + /* Test body 1: Check API of function aggregate. */ + { + /* Should not accept NULL for aggsig or aggsig length */ + size_t aggsig_len = sizeof(aggsig); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_aggregate(CTX, NULL, &aggsig_len, pubkeys, msgs32, sigs64, n_initial)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_aggregate(CTX, aggsig, NULL, pubkeys, msgs32, sigs64, n_initial)); + /* Should not accept NULL for keys, messages, or signatures if n_initial is not 0 */ + if (n_initial != 0) { + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_aggregate(CTX, aggsig, &aggsig_len, NULL, msgs32, sigs64, n_initial)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_aggregate(CTX, aggsig, &aggsig_len, pubkeys, NULL, sigs64, n_initial)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, NULL, n_initial)); + } + } + + /* Test body 2: Check API of function inc_aggregate. */ + { + size_t aggsig_len = sizeof(aggsig); + CHECK(secp256k1_schnorrsig_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, sigs64, n_initial)); + aggsig_len = 32*(n+1); + /* Should not accept NULL for aggsig or aggsig length */ + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_inc_aggregate(CTX, NULL, &aggsig_len, pubkeys, msgs32, &sigs64[n_initial*64], n_initial, n_new)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_inc_aggregate(CTX, aggsig, NULL, pubkeys, msgs32, &sigs64[n_initial*64], n_initial, n_new)); + /* Should not accept NULL for keys or messages if n is not 0 */ + if (n != 0) { + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_inc_aggregate(CTX, aggsig, &aggsig_len, NULL, msgs32, &sigs64[n_initial*64], n_initial, n_new)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_inc_aggregate(CTX, aggsig, &aggsig_len, pubkeys, NULL, &sigs64[n_initial*64], n_initial, n_new)); + } + /* Should not accept NULL for new_sigs64 if n_new is not 0 */ + if (n_new != 0) { + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_inc_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, NULL, n_initial, n_new)); + } + /* Should not accept overflowing number of sigs. */ + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_inc_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, &sigs64[n_initial*64], SIZE_MAX, SIZE_MAX)); + if (n_initial > 0) { + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_inc_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, &sigs64[n_initial*64], n_initial, SIZE_MAX)); + } + /* Should reject if aggsig_len is too small. */ + aggsig_len = 32*n; + CHECK(secp256k1_schnorrsig_inc_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, &sigs64[n_initial*64], n_initial, n_new) == 0); + aggsig_len = 32*(n+1) - 1; + CHECK(secp256k1_schnorrsig_inc_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, &sigs64[n_initial*64], n_initial, n_new) == 0); + } + + /* Test body 3: Check API of function aggverify. */ + { + size_t aggsig_len = sizeof(aggsig); + CHECK(secp256k1_schnorrsig_inc_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, &sigs64[n_initial*64], n_initial, n_new)); + /* Should not accept NULL for keys or messages if n is not 0 */ + if (n != 0) { + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_aggverify(CTX, NULL, msgs32, n, aggsig, aggsig_len)); + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_aggverify(CTX, pubkeys, NULL, n, aggsig, aggsig_len)); + } + /* Should never accept NULL the aggsig */ + CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, NULL, aggsig_len)); + /* Should reject for invalid aggsig_len. */ + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len + 1) == 0); + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len - 1) == 0); + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len + 32) == 0); + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len - 32) == 0); + } +} + +/* In this test, we make sure that trivial attempts to break + * the security of verification do not work. */ +static void test_schnorrsig_aggregate_unforge(void) { + secp256k1_xonly_pubkey pubkeys[N_MAX]; + unsigned char msgs32[N_MAX*32]; + unsigned char sigs64[N_MAX*64]; + unsigned char aggsig[32*(N_MAX + 1)]; + + size_t n = secp256k1_testrand_int(N_MAX + 1); + + /* Test 1: We fix a set of n messages and compute + * a random aggsig for them. This should not verify. */ + test_schnorrsig_aggregate_input_helper(pubkeys, msgs32, sigs64, n); + { + size_t aggsig_len = sizeof(aggsig); + size_t i; + /* Sample aggsig randomly */ + for (i = 0; i < n + 1; ++i) { + secp256k1_testrand256(&aggsig[i*32]); + } + /* Make sure that it does not verify */ + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len) == 0); + } + + /* Test 2: We fix a set of n messages and compute valid + * signatures for all but one. The resulting aggregate signature + * should not verify. */ + test_schnorrsig_aggregate_input_helper(pubkeys, msgs32, sigs64, n); + if (n > 0) { + size_t aggsig_len = sizeof(aggsig); + /* Replace a randomly chosen real sig with a random one. */ + size_t k = secp256k1_testrand_int(n); + secp256k1_testrand256(&sigs64[k*64]); + secp256k1_testrand256(&sigs64[k*64+32]); + /* Aggregate the n signatures */ + CHECK(secp256k1_schnorrsig_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, sigs64, n)); + /* Make sure the result does not verify */ + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len) == 0); + } + + /* Test 3: We generate a valid aggregate signature and then + * change one of the messages. This should not verify. */ + test_schnorrsig_aggregate_input_helper(pubkeys, msgs32, sigs64, n); + if (n > 0) { + size_t aggsig_len = sizeof(aggsig); + size_t k; + /* Aggregate the n signatures */ + CHECK(secp256k1_schnorrsig_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, sigs64, n)); + /* Change one of the messages */ + k = secp256k1_testrand_int(32*n); + msgs32[k] = msgs32[k]^0xff; + /* Make sure the result does not verify */ + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len) == 0); + } +} + +/* In this test, we make sure that the algorithms properly reject + * for overflowing and non parseable values. */ +static void test_schnorrsig_aggregate_overflow(void) { + secp256k1_xonly_pubkey pubkeys[N_MAX]; + unsigned char msgs32[N_MAX*32]; + unsigned char sigs64[N_MAX*64]; + unsigned char aggsig[32*(N_MAX + 1)]; + size_t n = secp256k1_testrand_int(N_MAX + 1); + + /* We check that verification returns 0 if the s in aggsig overflows. */ + test_schnorrsig_aggregate_input_helper(pubkeys, msgs32, sigs64, n); + { + size_t aggsig_len = sizeof(aggsig); + /* Aggregate */ + CHECK(secp256k1_schnorrsig_aggregate(CTX, aggsig, &aggsig_len, pubkeys, msgs32, sigs64, n)); + /* Make s in the aggsig overflow */ + memset(&aggsig[n*32], 0xFF, 32); + /* Should not verify */ + CHECK(secp256k1_schnorrsig_aggverify(CTX, pubkeys, msgs32, n, aggsig, aggsig_len) == 0); + } +} + +static void run_schnorrsig_halfagg_tests(void) { + int i; + + test_schnorrsig_sha256_tagged_aggregate(); + test_schnorrsig_aggverify_spec_vectors(); + + for (i = 0; i < COUNT; i++) { + test_schnorrsig_aggregate(); + test_schnorrsig_aggregate_api(); + test_schnorrsig_aggregate_unforge(); + test_schnorrsig_aggregate_overflow(); + } +} + +#undef N_MAX + +#endif diff --git a/src/modules/surjection/main_impl.h b/src/modules/surjection/main_impl.h index c6bdea2e50..f1d7d42ff5 100644 --- a/src/modules/surjection/main_impl.h +++ b/src/modules/surjection/main_impl.h @@ -9,10 +9,6 @@ #include #include -#if defined HAVE_CONFIG_H -#include "../../libsecp256k1-config.h" -#endif - #include "../../../include/secp256k1_rangeproof.h" #include "../../../include/secp256k1_surjectionproof.h" #include "../rangeproof/borromean.h" diff --git a/src/modules/surjection/surjection_impl.h b/src/modules/surjection/surjection_impl.h index f5adc7ebcc..e125cbc012 100644 --- a/src/modules/surjection/surjection_impl.h +++ b/src/modules/surjection/surjection_impl.h @@ -82,8 +82,12 @@ SECP256K1_INLINE static int secp256k1_surjection_compute_public_keys(secp256k1_g j++; } } +#ifdef VERIFY /* Caller needs to ensure that the number of set bits in used_tags (which we counted in j) equals n_pubkeys. */ VERIFY_CHECK(j == n_pubkeys); +#else + (void)n_pubkeys; +#endif return 1; } diff --git a/src/modules/surjection/tests_impl.h b/src/modules/surjection/tests_impl.h index d5eb7cd662..ad6ffa8dba 100644 --- a/src/modules/surjection/tests_impl.h +++ b/src/modules/surjection/tests_impl.h @@ -27,15 +27,9 @@ static void test_surjectionproof_api(void) { secp256k1_surjectionproof* proof_on_heap; size_t n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]); size_t input_index; - int32_t ecount = 0; size_t i; secp256k1_testrand256(seed); - secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - for (i = 0; i < n_inputs; i++) { secp256k1_testrand256(input_blinding_key[i]); @@ -49,155 +43,99 @@ static void test_surjectionproof_api(void) { /* check allocate_initialized */ CHECK(secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0); CHECK(proof_on_heap == 0); - CHECK(ecount == 0); CHECK(secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); CHECK(proof_on_heap != 0); secp256k1_surjectionproof_destroy(proof_on_heap); - CHECK(ecount == 0); - CHECK(secp256k1_surjectionproof_allocate_initialized(CTX, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_allocate_initialized(CTX, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed)); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed)); CHECK(proof_on_heap == 0); - CHECK(ecount == 2); - CHECK(secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed)); CHECK(proof_on_heap == 0); - CHECK(ecount == 3); - CHECK(secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed)); CHECK(proof_on_heap == 0); - CHECK(ecount == 4); CHECK(secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], 100, seed) != 0); CHECK(proof_on_heap != 0); secp256k1_surjectionproof_destroy(proof_on_heap); - CHECK(ecount == 4); - CHECK(secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed) == 0); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed)); CHECK(proof_on_heap == 0); - CHECK(ecount == 5); - CHECK(secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed) == 0); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed)); CHECK(proof_on_heap == 0); - CHECK(ecount == 6); CHECK((secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 0, seed) & 1) == 0); CHECK(proof_on_heap == 0); - CHECK(ecount == 6); - CHECK(secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL) == 0); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_allocate_initialized(CTX, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL)); CHECK(proof_on_heap == 0); - CHECK(ecount == 7); - /* we are now going to test essentially the same functions, just without heap allocation. - * reset ecount. */ - ecount = 0; + /* we are now going to test essentially the same functions, just without + * heap allocation. */ /* check initialize */ CHECK(secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 0); CHECK(secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); - CHECK(ecount == 0); - CHECK(secp256k1_surjectionproof_initialize(CTX, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_surjectionproof_initialize(CTX, &proof, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_initialize(CTX, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed)); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_initialize(CTX, &proof, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed)); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed)); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed)); CHECK(secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], 100, seed) != 0); - CHECK(ecount == 4); - CHECK(secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed) == 0); - CHECK(ecount == 6); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed)); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed)); CHECK((secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 0, seed) & 1) == 0); - CHECK(ecount == 6); - CHECK(secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL) == 0); - CHECK(ecount == 7); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL)); CHECK(secp256k1_surjectionproof_initialize(CTX, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); /* check generate */ CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0); - CHECK(ecount == 7); - CHECK(secp256k1_surjectionproof_generate(STATIC_CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 8); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_surjectionproof_generate(STATIC_CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key)); - CHECK(secp256k1_surjectionproof_generate(CTX, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 9); - CHECK(secp256k1_surjectionproof_generate(CTX, &proof, NULL, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 10); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_generate(CTX, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key)); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_generate(CTX, &proof, NULL, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key)); CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 10); CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 10); CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, 0, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 10); - CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, NULL, 0, input_blinding_key[0], output_blinding_key) == 0); - CHECK(ecount == 11); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, NULL, 0, input_blinding_key[0], output_blinding_key)); + /* the below line "succeeds" but generates an invalid proof as the input_index is wrong. it is fairly expensive to detect this. should we? */ CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 1, input_blinding_key[0], output_blinding_key) != 0); - CHECK(ecount == 11); /* the above line "succeeds" but generates an invalid proof as the input_index is wrong. it is fairly expensive to detect this. should we? */ CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, n_inputs + 1, input_blinding_key[0], output_blinding_key) != 0); - CHECK(ecount == 11); - CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, NULL, output_blinding_key) == 0); - CHECK(ecount == 12); - CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], NULL) == 0); - CHECK(ecount == 13); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, NULL, output_blinding_key)); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], NULL)); CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0); /* check verify */ CHECK(secp256k1_surjectionproof_verify(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 1); - CHECK(ecount == 13); - CHECK(secp256k1_surjectionproof_verify(CTX, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0); - CHECK(ecount == 14); - CHECK(secp256k1_surjectionproof_verify(CTX, &proof, NULL, n_inputs, &ephemeral_output_tag) == 0); - CHECK(ecount == 15); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_verify(CTX, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag)); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_verify(CTX, &proof, NULL, n_inputs, &ephemeral_output_tag)); CHECK(secp256k1_surjectionproof_verify(CTX, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag) == 0); - CHECK(ecount == 15); CHECK(secp256k1_surjectionproof_verify(CTX, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag) == 0); - CHECK(ecount == 15); - CHECK(secp256k1_surjectionproof_verify(CTX, &proof, ephemeral_input_tags, n_inputs, NULL) == 0); - CHECK(ecount == 16); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_verify(CTX, &proof, ephemeral_input_tags, n_inputs, NULL)); /* Test how surjectionproof_generate fails when the proof was not created * with surjectionproof_initialize */ - ecount = 0; CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 1); { secp256k1_surjectionproof tmp_proof = proof; tmp_proof.n_inputs = 0; - CHECK(secp256k1_surjectionproof_generate(CTX, &tmp_proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_generate(CTX, &tmp_proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key)); } - CHECK(ecount == 1); CHECK(secp256k1_surjectionproof_generate(CTX, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 1); /* Check serialize */ - ecount = 0; serialized_len = sizeof(serialized_proof); CHECK(secp256k1_surjectionproof_serialize(CTX, serialized_proof, &serialized_len, &proof) != 0); - CHECK(ecount == 0); serialized_len = sizeof(serialized_proof); - CHECK(secp256k1_surjectionproof_serialize(CTX, NULL, &serialized_len, &proof) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_serialize(CTX, NULL, &serialized_len, &proof)); serialized_len = sizeof(serialized_proof); - CHECK(secp256k1_surjectionproof_serialize(CTX, serialized_proof, NULL, &proof) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_serialize(CTX, serialized_proof, NULL, &proof)); serialized_len = sizeof(serialized_proof); - CHECK(secp256k1_surjectionproof_serialize(CTX, serialized_proof, &serialized_len, NULL) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_serialize(CTX, serialized_proof, &serialized_len, NULL)); serialized_len = sizeof(serialized_proof); CHECK(secp256k1_surjectionproof_serialize(CTX, serialized_proof, &serialized_len, &proof) != 0); /* Check parse */ CHECK(secp256k1_surjectionproof_parse(CTX, &proof, serialized_proof, serialized_len) != 0); - CHECK(ecount == 3); - CHECK(secp256k1_surjectionproof_parse(CTX, NULL, serialized_proof, serialized_len) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_surjectionproof_parse(CTX, &proof, NULL, serialized_len) == 0); - CHECK(ecount == 5); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_parse(CTX, NULL, serialized_proof, serialized_len)); + CHECK_ILLEGAL(CTX, secp256k1_surjectionproof_parse(CTX, &proof, NULL, serialized_len)); CHECK(secp256k1_surjectionproof_parse(CTX, &proof, serialized_proof, 0) == 0); - CHECK(ecount == 5); - - secp256k1_context_set_error_callback(CTX, NULL, NULL); - secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); } static void test_input_selection(size_t n_inputs) { diff --git a/src/scalar.h b/src/scalar.h index c9193ffafb..133d995767 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -25,7 +25,7 @@ static void secp256k1_scalar_clear(secp256k1_scalar *r); /** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */ static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count); -/** Access bits from a scalar. Not constant time. */ +/** Access bits from a scalar. Not constant time in offset and count. */ static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); /** Set a scalar from a big endian byte array. The scalar will be reduced modulo group order `n`. @@ -57,10 +57,6 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int /** Multiply two scalars (modulo the group order). */ static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); -/** Shift a scalar right by some amount strictly between 0 and 16, returning - * the low bits that were shifted off */ -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n); - /** Compute the square of a scalar (modulo the group order). */ static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a); @@ -73,6 +69,9 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc /** Compute the complement of a scalar (modulo the group order). */ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a); +/** Multiply a scalar with the multiplicative inverse of 2. */ +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a); + /** Check whether a scalar equals zero. */ static int secp256k1_scalar_is_zero(const secp256k1_scalar *a); @@ -105,4 +104,8 @@ 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); +#define SECP256K1_SCALAR_VERIFY(r) secp256k1_scalar_verify(r) + #endif /* SECP256K1_SCALAR_H */ diff --git a/src/scalar_4x64_impl.h b/src/scalar_4x64_impl.h index 7cd3347655..6d97bce260 100644 --- a/src/scalar_4x64_impl.h +++ b/src/scalar_4x64_impl.h @@ -42,6 +42,8 @@ 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 void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v) { @@ -52,13 +54,17 @@ SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint6 } 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 { @@ -82,6 +88,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { secp256k1_uint128 t; VERIFY_CHECK(overflow <= 1); + secp256k1_u128_from_u64(&t, r->d[0]); secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_0); r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); @@ -93,12 +100,17 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigne r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); secp256k1_u128_accum_u64(&t, r->d[3]); r->d[3] = secp256k1_u128_to_u64(&t); + + SECP256K1_SCALAR_VERIFY(r); return overflow; } static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { int overflow; secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); + secp256k1_u128_from_u64(&t, a->d[0]); secp256k1_u128_accum_u64(&t, b->d[0]); r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); @@ -114,13 +126,17 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, overflow = secp256k1_u128_to_u64(&t) + secp256k1_scalar_check_overflow(r); VERIFY_CHECK(overflow == 0 || overflow == 1); secp256k1_scalar_reduce(r, overflow); + + SECP256K1_SCALAR_VERIFY(r); return overflow; } static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { secp256k1_uint128 t; volatile int vflag = flag; + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(bit < 256); + bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ secp256k1_u128_from_u64(&t, r->d[0]); secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); @@ -134,9 +150,9 @@ 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); -#ifdef VERIFY + + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(secp256k1_u128_hi_u64(&t) == 0); -#endif } static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { @@ -149,9 +165,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]); @@ -159,12 +179,16 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* } SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; } static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + secp256k1_u128_from_u64(&t, ~a->d[0]); secp256k1_u128_accum_u64(&t, SECP256K1_N_0 + 1); r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); @@ -177,15 +201,62 @@ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar secp256k1_u128_accum_u64(&t, ~a->d[3]); secp256k1_u128_accum_u64(&t, SECP256K1_N_3); r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; + + SECP256K1_SCALAR_VERIFY(r); +} + +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { + /* Writing `/` for field division and `//` for integer division, we compute + * + * a/2 = (a - (a&1))/2 + (a&1)/2 + * = (a >> 1) + (a&1 ? 1/2 : 0) + * = (a >> 1) + (a&1 ? n//2+1 : 0), + * + * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n). + * For n//2, we have the constants SECP256K1_N_H_0, ... + * + * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here: + * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2 + * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2 + * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n. + */ + uint64_t mask = -(uint64_t)(a->d[0] & 1U); + secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(a); + + secp256k1_u128_from_u64(&t, (a->d[0] >> 1) | (a->d[1] << 63)); + secp256k1_u128_accum_u64(&t, (SECP256K1_N_H_0 + 1U) & mask); + r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, (a->d[1] >> 1) | (a->d[2] << 63)); + secp256k1_u128_accum_u64(&t, SECP256K1_N_H_1 & mask); + r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + secp256k1_u128_accum_u64(&t, (a->d[2] >> 1) | (a->d[3] << 63)); + secp256k1_u128_accum_u64(&t, SECP256K1_N_H_2 & mask); + r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64); + r->d[3] = secp256k1_u128_to_u64(&t) + (a->d[3] >> 1) + (SECP256K1_N_H_3 & mask); +#ifdef VERIFY + /* The line above only computed the bottom 64 bits of r->d[3]; redo the computation + * in full 128 bits to make sure the top 64 bits are indeed zero. */ + secp256k1_u128_accum_u64(&t, a->d[3] >> 1); + secp256k1_u128_accum_u64(&t, SECP256K1_N_H_3 & mask); + secp256k1_u128_rshift(&t, 64); + VERIFY_CHECK(secp256k1_u128_to_u64(&t) == 0); + + SECP256K1_SCALAR_VERIFY(r); +#endif } 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. */ @@ -202,6 +273,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { uint64_t mask = -vflag; uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; secp256k1_uint128 t; + SECP256K1_SCALAR_VERIFY(r); + secp256k1_u128_from_u64(&t, r->d[0] ^ mask); secp256k1_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask); r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64); @@ -214,6 +287,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { secp256k1_u128_accum_u64(&t, r->d[3] ^ mask); secp256k1_u128_accum_u64(&t, SECP256K1_N_3 & mask); r->d[3] = secp256k1_u128_to_u64(&t) & nonzero; + + SECP256K1_SCALAR_VERIFY(r); return 2 * (mask == 0) - 1; } @@ -933,20 +1008,13 @@ static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) { 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); -} -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { - int ret; - 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); - return ret; + SECP256K1_SCALAR_VERIFY(r); } static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { @@ -956,6 +1024,8 @@ static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) } 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; @@ -964,9 +1034,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; } @@ -975,7 +1051,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; @@ -985,18 +1064,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) { @@ -1016,18 +1101,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; @@ -1046,13 +1126,14 @@ 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); -#ifdef VERIFY + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); -#endif } static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { @@ -1060,16 +1141,19 @@ 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); -#ifdef VERIFY + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); -#endif } SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return !(a->d[0] & 1); } diff --git a/src/scalar_8x32_impl.h b/src/scalar_8x32_impl.h index e7091857f7..9c5e3a009a 100644 --- a/src/scalar_8x32_impl.h +++ b/src/scalar_8x32_impl.h @@ -60,6 +60,8 @@ 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 void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t v) { @@ -74,13 +76,17 @@ SECP256K1_INLINE static void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint6 } 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 { @@ -110,6 +116,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; @@ -126,12 +133,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; @@ -150,13 +162,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; @@ -174,10 +190,9 @@ 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; -#ifdef VERIFY + + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK((t >> 32) == 0); - VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); -#endif } static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { @@ -194,9 +209,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]); @@ -208,12 +227,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; @@ -229,15 +252,69 @@ 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); +} + +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { + /* Writing `/` for field division and `//` for integer division, we compute + * + * a/2 = (a - (a&1))/2 + (a&1)/2 + * = (a >> 1) + (a&1 ? 1/2 : 0) + * = (a >> 1) + (a&1 ? n//2+1 : 0), + * + * where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n). + * For n//2, we have the constants SECP256K1_N_H_0, ... + * + * This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here: + * - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2 + * - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2 + * Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n. + */ + uint32_t mask = -(uint32_t)(a->d[0] & 1U); + uint64_t t = (uint32_t)((a->d[0] >> 1) | (a->d[1] << 31)); + SECP256K1_SCALAR_VERIFY(a); + + t += (SECP256K1_N_H_0 + 1U) & mask; + r->d[0] = t; t >>= 32; + t += (uint32_t)((a->d[1] >> 1) | (a->d[2] << 31)); + t += SECP256K1_N_H_1 & mask; + r->d[1] = t; t >>= 32; + t += (uint32_t)((a->d[2] >> 1) | (a->d[3] << 31)); + t += SECP256K1_N_H_2 & mask; + r->d[2] = t; t >>= 32; + t += (uint32_t)((a->d[3] >> 1) | (a->d[4] << 31)); + t += SECP256K1_N_H_3 & mask; + r->d[3] = t; t >>= 32; + t += (uint32_t)((a->d[4] >> 1) | (a->d[5] << 31)); + t += SECP256K1_N_H_4 & mask; + r->d[4] = t; t >>= 32; + t += (uint32_t)((a->d[5] >> 1) | (a->d[6] << 31)); + t += SECP256K1_N_H_5 & mask; + r->d[5] = t; t >>= 32; + t += (uint32_t)((a->d[6] >> 1) | (a->d[7] << 31)); + t += SECP256K1_N_H_6 & mask; + r->d[6] = t; t >>= 32; + r->d[7] = (uint32_t)t + (uint32_t)(a->d[7] >> 1) + (SECP256K1_N_H_7 & mask); + + /* The line above only computed the bottom 32 bits of r->d[7]. Redo the computation + * in full 64 bits to make sure the top 32 bits are indeed zero. */ + VERIFY_CHECK((t + (a->d[7] >> 1) + (SECP256K1_N_H_7 & mask)) >> 32 == 0); + + 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. */ @@ -260,6 +337,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; @@ -275,6 +354,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; } @@ -665,24 +746,13 @@ static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) { 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); -} -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { - int ret; - 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)); - r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n)); - r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n)); - r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - 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); - return ret; + SECP256K1_SCALAR_VERIFY(r); } static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { @@ -692,6 +762,8 @@ static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) } 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]; @@ -708,9 +780,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; } @@ -719,7 +797,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; @@ -733,12 +814,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); @@ -749,6 +834,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) { @@ -777,19 +864,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; @@ -812,13 +894,14 @@ 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); -#ifdef VERIFY + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); -#endif } static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { @@ -826,16 +909,19 @@ 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); -#ifdef VERIFY + SECP256K1_SCALAR_VERIFY(r); VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in); -#endif } SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + return !(a->d[0] & 1); } diff --git a/src/scalar_impl.h b/src/scalar_impl.h index bed7f95fcb..972d8041b0 100644 --- a/src/scalar_impl.h +++ b/src/scalar_impl.h @@ -30,9 +30,17 @@ 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) { + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); + + (void)r; +} + #if defined(EXHAUSTIVE_TEST_ORDER) /* Begin of section generated by sage/gen_exhaustive_groups.sage. */ # if EXHAUSTIVE_TEST_ORDER == 7 @@ -53,11 +61,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 +153,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 +168,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 @@ -212,7 +229,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT * <= {triangle inequality} * a1*|k*b2/n - c1| + a2*|k*(-b1)/n - c2| * < {Lemma 1 and Lemma 2} - * a1*(2^-1 + epslion1) + a2*(2^-1 + epsilon2) + * a1*(2^-1 + epsilon1) + a2*(2^-1 + epsilon2) * < {rounding up to an integer} * (a1 + a2 + 1)/2 * < {rounding up to a power of 2} @@ -230,7 +247,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT * <= {triangle inequality} * (-b1)*|k*b2/n - c1| + b2*|k*(-b1)/n - c2| * < {Lemma 1 and Lemma 2} - * (-b1)*(2^-1 + epslion1) + b2*(2^-1 + epsilon2) + * (-b1)*(2^-1 + epsilon1) + b2*(2^-1 + epsilon2) * < {rounding up to an integer} * (-b1 + b2)/2 + 1 * < {rounding up to a power of 2} diff --git a/src/scalar_low.h b/src/scalar_low.h index 67051bd30b..2711eb932d 100644 --- a/src/scalar_low.h +++ b/src/scalar_low.h @@ -1,5 +1,5 @@ /*********************************************************************** - * Copyright (c) 2015 Andrew Poelstra * + * Copyright (c) 2015, 2022 Andrew Poelstra, Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ @@ -12,6 +12,13 @@ /** A scalar modulo the group order of the secp256k1 curve. */ typedef uint32_t secp256k1_scalar; -#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) (d0) +/* A compile-time constant equal to 2^32 (modulo order). */ +#define SCALAR_2P32 ((0xffffffffUL % EXHAUSTIVE_TEST_ORDER) + 1U) + +/* Compute a*2^32 + b (modulo order). */ +#define SCALAR_HORNER(a, b) (((uint64_t)(a) * SCALAR_2P32 + (b)) % EXHAUSTIVE_TEST_ORDER) + +/* Evaluates to the provided 256-bit constant reduced modulo order. */ +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER((d7), (d6)), (d5)), (d4)), (d3)), (d2)), (d1)), (d0)) #endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/scalar_low_impl.h b/src/scalar_low_impl.h index f78075567a..c3c7e73882 100644 --- a/src/scalar_low_impl.h +++ b/src/scalar_low_impl.h @@ -14,14 +14,28 @@ #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_u64(secp256k1_scalar *r, uint64_t v) { *r = v % EXHAUSTIVE_TEST_ORDER; } + +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 void secp256k1_scalar_set_u64(secp256k1_scalar *r, uint64_t 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 @@ -29,25 +43,33 @@ 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); -#ifdef VERIFY + + SECP256K1_SCALAR_VERIFY(r); 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 } static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { @@ -62,49 +84,63 @@ 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) { - *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; -} + SECP256K1_SCALAR_VERIFY(a); + SECP256K1_SCALAR_VERIFY(b); -static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { - int ret; - VERIFY_CHECK(n > 0); - VERIFY_CHECK(n < 16); - ret = *r & ((1 << n) - 1); - *r >>= n; - return ret; + *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; + + SECP256K1_SCALAR_VERIFY(r); } static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { @@ -112,36 +148,64 @@ static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) } 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); +} + +static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) { + SECP256K1_SCALAR_VERIFY(a); + + *r = (*a + ((-(uint32_t)(*a & 1)) & EXHAUSTIVE_TEST_ORDER)) >> 1; + + SECP256K1_SCALAR_VERIFY(r); } #endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/secp256k1.c b/src/secp256k1.c index 7f7fb52e5e..4c57826932 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -258,36 +258,13 @@ static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, } static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { - if (sizeof(secp256k1_ge_storage) == 64) { - /* When the secp256k1_ge_storage type is exactly 64 byte, use its - * representation inside secp256k1_pubkey, as conversion is very fast. - * Note that secp256k1_pubkey_save must use the same representation. */ - secp256k1_ge_storage s; - memcpy(&s, &pubkey->data[0], sizeof(s)); - secp256k1_ge_from_storage(ge, &s); - } else { - /* Otherwise, fall back to 32-byte big endian for X and Y. */ - secp256k1_fe x, y; - ARG_CHECK(secp256k1_fe_set_b32_limit(&x, pubkey->data)); - ARG_CHECK(secp256k1_fe_set_b32_limit(&y, pubkey->data + 32)); - secp256k1_ge_set_xy(ge, &x, &y); - } + secp256k1_ge_from_bytes(ge, pubkey->data); ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); return 1; } static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { - if (sizeof(secp256k1_ge_storage) == 64) { - secp256k1_ge_storage s; - secp256k1_ge_to_storage(&s, ge); - memcpy(&pubkey->data[0], &s, sizeof(s)); - } else { - VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); - secp256k1_fe_normalize_var(&ge->x); - secp256k1_fe_normalize_var(&ge->y); - secp256k1_fe_get_b32(pubkey->data, &ge->x); - secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); - } + secp256k1_ge_to_bytes(pubkey->data, ge); } int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { @@ -855,8 +832,12 @@ static void secp256k1_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) { int ret; size_t size = 33; ret = secp256k1_eckey_pubkey_serialize(ge, out33, &size, 1); +#ifdef VERIFY /* Serialize must succeed because the point is not at infinity */ VERIFY_CHECK(ret && size == 33); +#else + (void) ret; +#endif } } @@ -865,7 +846,7 @@ static void secp256k1_ge_serialize_ext(unsigned char *out33, secp256k1_ge* ge) { static int secp256k1_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) { unsigned char zeros[33] = { 0 }; - if (memcmp(in33, zeros, sizeof(zeros)) == 0) { + if (secp256k1_memcmp_var(in33, zeros, sizeof(zeros)) == 0) { secp256k1_ge_set_infinity(ge); return 1; } @@ -892,6 +873,10 @@ static int secp256k1_ge_parse_ext(secp256k1_ge* ge, const unsigned char *in33) { # include "modules/schnorrsig/main_impl.h" #endif +#ifdef ENABLE_MODULE_SCHNORRSIG_HALFAGG +# include "modules/schnorrsig_halfagg/main_impl.h" +#endif + #ifdef ENABLE_MODULE_ELLSWIFT # include "modules/ellswift/main_impl.h" #endif diff --git a/src/tests.c b/src/tests.c index 300a0324f4..7c2f30e35e 100644 --- a/src/tests.c +++ b/src/tests.c @@ -23,6 +23,7 @@ #include "../include/secp256k1_preallocated.h" #include "testrand_impl.h" #include "checkmem.h" +#include "testutil.h" #include "util.h" #include "../contrib/lax_der_parsing.c" @@ -52,26 +53,32 @@ static int all_bytes_equal(const void* s, unsigned char value, size_t n) { return 1; } -/* TODO Use CHECK_ILLEGAL(_VOID) everywhere and get rid of the uncounting callback */ -/* CHECK that expr_or_stmt calls the illegal callback of ctx exactly once - * - * For checking functions that use ARG_CHECK_VOID */ -#define CHECK_ILLEGAL_VOID(ctx, expr_or_stmt) do { \ - int32_t _calls_to_illegal_callback = 0; \ - secp256k1_callback _saved_illegal_cb = ctx->illegal_callback; \ - secp256k1_context_set_illegal_callback(ctx, \ - counting_illegal_callback_fn, &_calls_to_illegal_callback); \ +#define CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, callback, callback_setter) do { \ + int32_t _calls_to_callback = 0; \ + secp256k1_callback _saved_callback = ctx->callback; \ + callback_setter(ctx, counting_callback_fn, &_calls_to_callback); \ { expr_or_stmt; } \ - ctx->illegal_callback = _saved_illegal_cb; \ - CHECK(_calls_to_illegal_callback == 1); \ + ctx->callback = _saved_callback; \ + CHECK(_calls_to_callback == 1); \ } while(0); -/* CHECK that expr calls the illegal callback of ctx exactly once and that expr == 0 +/* CHECK that expr_or_stmt calls the error or illegal callback of ctx exactly once * - * For checking functions that use ARG_CHECK */ -#define CHECK_ILLEGAL(ctx, expr) CHECK_ILLEGAL_VOID(ctx, CHECK((expr) == 0)) + * Useful for checking functions that return void (e.g., API functions that use ARG_CHECK_VOID) */ +#define CHECK_ERROR_VOID(ctx, expr_or_stmt) \ + CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, error_callback, secp256k1_context_set_error_callback) +#define CHECK_ILLEGAL_VOID(ctx, expr_or_stmt) \ + CHECK_COUNTING_CALLBACK_VOID(ctx, expr_or_stmt, illegal_callback, secp256k1_context_set_illegal_callback) -static void counting_illegal_callback_fn(const char* str, void* data) { +/* CHECK that + * - expr calls the illegal callback of ctx exactly once and, + * - expr == 0 (or equivalently, expr == NULL) + * + * Useful for checking functions that return an integer or a pointer. */ +#define CHECK_ILLEGAL(ctx, expr) CHECK_ILLEGAL_VOID(ctx, CHECK((expr) == 0)) +#define CHECK_ERROR(ctx, expr) CHECK_ERROR_VOID(ctx, CHECK((expr) == 0)) + +static void counting_callback_fn(const char* str, void* data) { /* Dummy callback function that just counts. */ int32_t *p; (void)str; @@ -89,9 +96,9 @@ static void uncounting_illegal_callback_fn(const char* str, void* data) { (*p)--; } -static void random_field_element_magnitude(secp256k1_fe *fe) { +static void random_field_element_magnitude(secp256k1_fe *fe, int m) { secp256k1_fe zero; - int n = secp256k1_testrand_int(9); + int n = secp256k1_testrand_int(m + 1); secp256k1_fe_normalize(fe); if (n == 0) { return; @@ -121,6 +128,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 { @@ -295,55 +326,34 @@ static void run_deprecated_context_flags_test(void) { } static void run_ec_illegal_argument_tests(void) { - int ecount = 0; - int ecount2 = 10; secp256k1_pubkey pubkey; secp256k1_pubkey zero_pubkey; secp256k1_ecdsa_signature sig; unsigned char ctmp[32]; /* Setup */ - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount2); memset(ctmp, 1, 32); memset(&zero_pubkey, 0, sizeof(zero_pubkey)); /* Verify context-type checking illegal-argument errors. */ - CHECK(secp256k1_ec_pubkey_create(STATIC_CTX, &pubkey, ctmp) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ec_pubkey_create(STATIC_CTX, &pubkey, ctmp)); SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, ctmp) == 1); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ecdsa_sign(STATIC_CTX, &sig, ctmp, ctmp, NULL, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign(STATIC_CTX, &sig, ctmp, ctmp, NULL, NULL)); SECP256K1_CHECKMEM_UNDEFINE(&sig, sizeof(sig)); CHECK(secp256k1_ecdsa_sign(CTX, &sig, ctmp, ctmp, NULL, NULL) == 1); SECP256K1_CHECKMEM_CHECK(&sig, sizeof(sig)); - CHECK(ecount2 == 10); CHECK(secp256k1_ecdsa_verify(CTX, &sig, ctmp, &pubkey) == 1); - CHECK(ecount2 == 10); CHECK(secp256k1_ecdsa_verify(STATIC_CTX, &sig, ctmp, &pubkey) == 1); - CHECK(ecount == 2); CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp) == 1); - CHECK(ecount2 == 10); CHECK(secp256k1_ec_pubkey_tweak_add(STATIC_CTX, &pubkey, ctmp) == 1); - CHECK(ecount == 2); CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, ctmp) == 1); - CHECK(ecount2 == 10); CHECK(secp256k1_ec_pubkey_negate(STATIC_CTX, &pubkey) == 1); - CHECK(ecount == 2); CHECK(secp256k1_ec_pubkey_negate(CTX, &pubkey) == 1); - CHECK(ecount == 2); - CHECK(secp256k1_ec_pubkey_negate(STATIC_CTX, &zero_pubkey) == 0); - CHECK(ecount == 3); - CHECK(secp256k1_ec_pubkey_negate(CTX, NULL) == 0); - CHECK(ecount2 == 11); + CHECK_ILLEGAL(STATIC_CTX, secp256k1_ec_pubkey_negate(STATIC_CTX, &zero_pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_negate(CTX, NULL)); CHECK(secp256k1_ec_pubkey_tweak_mul(STATIC_CTX, &pubkey, ctmp) == 1); - CHECK(ecount == 3); - - /* Clean up */ - secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); } static void run_static_context_tests(int use_prealloc) { @@ -378,8 +388,8 @@ static void run_static_context_tests(int use_prealloc) { { /* Verify that setting and resetting illegal callback works */ int32_t dummy = 0; - secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &dummy); - CHECK(STATIC_CTX->illegal_callback.fn == counting_illegal_callback_fn); + secp256k1_context_set_illegal_callback(STATIC_CTX, counting_callback_fn, &dummy); + CHECK(STATIC_CTX->illegal_callback.fn == counting_callback_fn); CHECK(STATIC_CTX->illegal_callback.data == &dummy); secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL); CHECK(STATIC_CTX->illegal_callback.fn == secp256k1_default_illegal_callback_fn); @@ -470,8 +480,8 @@ static void run_proper_context_tests(int use_prealloc) { CHECK(context_eq(my_ctx, my_ctx_fresh)); /* Verify that setting and resetting illegal callback works */ - secp256k1_context_set_illegal_callback(my_ctx, counting_illegal_callback_fn, &dummy); - CHECK(my_ctx->illegal_callback.fn == counting_illegal_callback_fn); + secp256k1_context_set_illegal_callback(my_ctx, counting_callback_fn, &dummy); + CHECK(my_ctx->illegal_callback.fn == counting_callback_fn); CHECK(my_ctx->illegal_callback.data == &dummy); secp256k1_context_set_illegal_callback(my_ctx, NULL, NULL); CHECK(my_ctx->illegal_callback.fn == secp256k1_default_illegal_callback_fn); @@ -512,19 +522,14 @@ static void run_proper_context_tests(int use_prealloc) { static void run_scratch_tests(void) { const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT; - int32_t ecount = 0; size_t checkpoint; size_t checkpoint_2; secp256k1_scratch_space *scratch; secp256k1_scratch_space local_scratch; - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount); - /* Test public API */ scratch = secp256k1_scratch_space_create(CTX, 1000); CHECK(scratch != NULL); - CHECK(ecount == 0); /* Test internal API */ CHECK(secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0) == 1000); @@ -557,22 +562,16 @@ static void run_scratch_tests(void) { /* try to apply a bad checkpoint */ checkpoint_2 = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch); secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint); - CHECK(ecount == 0); - secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */ - CHECK(ecount == 1); - secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */ - CHECK(ecount == 2); + CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, checkpoint_2)); /* checkpoint_2 is after checkpoint */ + CHECK_ERROR_VOID(CTX, secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, (size_t) -1)); /* this is just wildly invalid */ /* try to use badly initialized scratch space */ secp256k1_scratch_space_destroy(CTX, scratch); memset(&local_scratch, 0, sizeof(local_scratch)); scratch = &local_scratch; - CHECK(!secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0)); - CHECK(ecount == 3); - CHECK(secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500) == NULL); - CHECK(ecount == 4); - secp256k1_scratch_space_destroy(CTX, scratch); - CHECK(ecount == 5); + CHECK_ERROR(CTX, secp256k1_scratch_max_allocation(&CTX->error_callback, scratch, 0)); + CHECK_ERROR(CTX, secp256k1_scratch_alloc(&CTX->error_callback, scratch, 500)); + CHECK_ERROR_VOID(CTX, secp256k1_scratch_space_destroy(CTX, scratch)); /* Test that large integers do not wrap around in a bad way */ scratch = secp256k1_scratch_space_create(CTX, 1000); @@ -588,9 +587,6 @@ static void run_scratch_tests(void) { /* cleanup */ secp256k1_scratch_space_destroy(CTX, NULL); /* no-op */ - - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - secp256k1_context_set_error_callback(CTX, NULL, NULL); } static void run_ctz_tests(void) { @@ -870,7 +866,6 @@ static void run_rfc6979_hmac_sha256_tests(void) { } static void run_tagged_sha256_tests(void) { - int ecount = 0; unsigned char tag[32] = { 0 }; unsigned char msg[32] = { 0 }; unsigned char hash32[32]; @@ -881,16 +876,11 @@ static void run_tagged_sha256_tests(void) { 0xE2, 0x76, 0x55, 0x9A, 0x3B, 0xDE, 0x55, 0xB3 }; - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - /* API test */ CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1); - CHECK(secp256k1_tagged_sha256(CTX, NULL, tag, sizeof(tag), msg, sizeof(msg)) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_tagged_sha256(CTX, hash32, NULL, 0, msg, sizeof(msg)) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), NULL, 0) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, NULL, tag, sizeof(tag), msg, sizeof(msg))); + CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, hash32, NULL, 0, msg, sizeof(msg))); + CHECK_ILLEGAL(CTX, secp256k1_tagged_sha256(CTX, hash32, tag, sizeof(tag), NULL, 0)); /* Static test vector */ memcpy(tag, "tag", 3); @@ -2236,20 +2226,6 @@ static void scalar_test(void) { CHECK(secp256k1_scalar_eq(&n, &s)); } - { - /* test secp256k1_scalar_shr_int */ - secp256k1_scalar r; - int i; - random_scalar_order_test(&r); - for (i = 0; i < 100; ++i) { - int low; - int shift = 1 + secp256k1_testrand_int(15); - int expected = r.d[0] % (1ULL << shift); - low = secp256k1_scalar_shr_int(&r, shift); - CHECK(expected == low); - } - } - { /* Test commutativity of add. */ secp256k1_scalar r1, r2; @@ -2349,6 +2325,13 @@ static void scalar_test(void) { CHECK(secp256k1_scalar_eq(&r1, &secp256k1_scalar_zero)); } + { + /* Test halving. */ + secp256k1_scalar r; + secp256k1_scalar_add(&r, &s, &s); + secp256k1_scalar_half(&r, &r); + CHECK(secp256k1_scalar_eq(&r, &s)); + } } static void run_scalar_set_b32_seckey_tests(void) { @@ -2401,6 +2384,38 @@ static void run_scalar_tests(void) { CHECK(secp256k1_scalar_is_zero(&o)); } + { + /* Test that halving and doubling roundtrips on some fixed values. */ + static const secp256k1_scalar HALF_TESTS[] = { + /* 0 */ + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0), + /* 1 */ + SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1), + /* -1 */ + SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd0364140ul), + /* -2 (largest odd value) */ + SECP256K1_SCALAR_CONST(0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffeul, 0xbaaedce6ul, 0xaf48a03bul, 0xbfd25e8cul, 0xd036413Ful), + /* Half the secp256k1 order */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a0ul), + /* Half the secp256k1 order + 1 */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0x5d576e73ul, 0x57a4501dul, 0xdfe92f46ul, 0x681b20a1ul), + /* 2^255 */ + SECP256K1_SCALAR_CONST(0x80000000ul, 0, 0, 0, 0, 0, 0, 0), + /* 2^255 - 1 */ + SECP256K1_SCALAR_CONST(0x7ffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful, 0xfffffffful), + }; + unsigned n; + for (n = 0; n < sizeof(HALF_TESTS) / sizeof(HALF_TESTS[0]); ++n) { + secp256k1_scalar s; + secp256k1_scalar_half(&s, &HALF_TESTS[n]); + secp256k1_scalar_add(&s, &s, &s); + CHECK(secp256k1_scalar_eq(&s, &HALF_TESTS[n])); + secp256k1_scalar_add(&s, &s, &s); + secp256k1_scalar_half(&s, &s); + CHECK(secp256k1_scalar_eq(&s, &HALF_TESTS[n])); + } + } + { /* Does check_overflow check catch all ones? */ static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST( @@ -2981,40 +2996,15 @@ static void run_scalar_tests(void) { CHECK(secp256k1_scalar_eq(&secp256k1_scalar_one, &zz)); } secp256k1_scalar_mul(&z, &x, &x); - CHECK(!secp256k1_scalar_check_overflow(&z)); secp256k1_scalar_sqr(&zz, &x); - CHECK(!secp256k1_scalar_check_overflow(&zz)); CHECK(secp256k1_scalar_eq(&zz, &z)); - CHECK(secp256k1_scalar_eq(&r2, &zz)); + CHECK(secp256k1_scalar_eq(&r2, &z)); } } } /***** FIELD TESTS *****/ -static void random_fe(secp256k1_fe *x) { - unsigned char bin[32]; - do { - secp256k1_testrand256(bin); - if (secp256k1_fe_set_b32_limit(x, bin)) { - return; - } - } while(1); -} - -static void random_fe_non_zero(secp256k1_fe *nz) { - int tries = 10; - while (--tries >= 0) { - random_fe(nz); - secp256k1_fe_normalize(nz); - if (!secp256k1_fe_is_zero(nz)) { - break; - } - } - /* Infinitesimal probability of spurious failure here */ - CHECK(tries >= 0); -} - static void random_fe_non_square(secp256k1_fe *ns) { secp256k1_fe r; random_fe_non_zero(ns); @@ -3027,8 +3017,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) { @@ -3051,9 +3040,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); @@ -3210,7 +3199,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. */ @@ -3235,7 +3224,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 @@ -3339,13 +3328,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); @@ -3735,15 +3724,6 @@ static void run_inverse_tests(void) /***** GROUP TESTS *****/ -static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); -} - /* This compares jacobian points including their Z, not just their geometric meaning. */ static int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { secp256k1_gej a2; @@ -3766,23 +3746,6 @@ static int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { return ret; } -static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { - secp256k1_fe z2s; - secp256k1_fe u1, u2, s1, s2; - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - /* 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); - 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)); -} - static void test_ge(void) { int i, i1; int runs = 6; @@ -3801,11 +3764,12 @@ static void test_ge(void) { secp256k1_ge_clear(&ge[0]); secp256k1_ge_set_gej_var(&ge[0], &gej[0]); for (i = 0; i < runs; i++) { - int j; + int j, k; secp256k1_ge g; random_group_element_test(&g); if (i >= runs - 2) { secp256k1_ge_mul_lambda(&g, &ge[1]); + CHECK(!secp256k1_ge_eq_var(&g, &ge[1])); } if (i >= runs - 1) { secp256k1_ge_mul_lambda(&g, &g); @@ -3819,17 +3783,27 @@ 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]); + } + + for (j = 0; j < 4; ++j) { + for (k = 0; k < 4; ++k) { + int expect_equal = (j >> 1) == (k >> 1); + CHECK(secp256k1_ge_eq_var(&ge[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal); + CHECK(secp256k1_gej_eq_var(&gej[1 + j + 4 * i], &gej[1 + k + 4 * i]) == expect_equal); + CHECK(secp256k1_gej_eq_ge_var(&gej[1 + j + 4 * i], &ge[1 + k + 4 * i]) == expect_equal); + CHECK(secp256k1_gej_eq_ge_var(&gej[1 + k + 4 * i], &ge[1 + j + 4 * i]) == expect_equal); + } } } /* 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); @@ -3848,16 +3822,16 @@ 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); /* Test gej + ge with Z ratio result (var). */ secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); - ge_equals_gej(&ref, &resj); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); 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). */ @@ -3865,17 +3839,17 @@ 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); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); } /* Test gej + ge (const). */ if (i2 != 0) { /* secp256k1_gej_add_ge does not support its second argument being infinity. */ secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]); - ge_equals_gej(&ref, &resj); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); } /* Test doubling (var). */ @@ -3883,16 +3857,16 @@ static void test_ge(void) { secp256k1_fe zr2; /* Normal doubling with Z ratio result. */ secp256k1_gej_double_var(&resj, &gej[i1], &zr2); - ge_equals_gej(&ref, &resj); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); /* 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); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); /* Constant-time doubling. */ secp256k1_gej_double(&resj, &gej[i2]); - ge_equals_gej(&ref, &resj); + CHECK(secp256k1_gej_eq_ge_var(&resj, &ref)); } /* Test adding opposites. */ @@ -3904,12 +3878,12 @@ static void test_ge(void) { if (i1 == 0) { CHECK(secp256k1_ge_is_infinity(&ge[i1])); CHECK(secp256k1_gej_is_infinity(&gej[i1])); - ge_equals_gej(&ref, &gej[i2]); + CHECK(secp256k1_gej_eq_ge_var(&gej[i2], &ref)); } if (i2 == 0) { CHECK(secp256k1_ge_is_infinity(&ge[i2])); CHECK(secp256k1_gej_is_infinity(&gej[i2])); - ge_equals_gej(&ref, &gej[i1]); + CHECK(secp256k1_gej_eq_ge_var(&gej[i1], &ref)); } } } @@ -3944,7 +3918,7 @@ static void test_ge(void) { secp256k1_fe s; random_fe_non_zero(&s); secp256k1_gej_rescale(&gej[i], &s); - ge_equals_gej(&ge_set_all[i], &gej[i]); + CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge_set_all[i])); } free(ge_set_all); } @@ -3969,7 +3943,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. */ @@ -3988,7 +3962,7 @@ static void test_ge(void) { secp256k1_ge_set_all_gej_var(ge, gej, 4 * runs + 1); /* check result */ for (i = 0; i < 4 * runs + 1; i++) { - ge_equals_gej(&ge[i], &gej[i]); + CHECK(secp256k1_gej_eq_ge_var(&gej[i], &ge[i])); } /* Test batch gej -> ge conversion with all infinities. */ @@ -4087,15 +4061,29 @@ static void test_add_neg_y_diff_x(void) { secp256k1_gej_add_var(&resj, &aj, &bj, NULL); secp256k1_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); + CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); secp256k1_gej_add_ge(&resj, &aj, &b); secp256k1_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); + CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL); secp256k1_ge_set_gej(&res, &resj); - ge_equals_gej(&res, &sumj); + CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); +} + +static void test_ge_bytes(void) { + int i; + + for (i = 0; i < COUNT; i++) { + unsigned char buf[64]; + secp256k1_ge p, q; + + random_group_element_test(&p); + secp256k1_ge_to_bytes(buf, &p); + secp256k1_ge_from_bytes(&q, buf); + CHECK(secp256k1_ge_eq_var(&p, &q)); + } } static void run_ge(void) { @@ -4105,6 +4093,7 @@ static void run_ge(void) { } test_add_neg_y_diff_x(); test_intialized_inf(); + test_ge_bytes(); } static void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) { @@ -4152,7 +4141,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; @@ -4205,7 +4194,7 @@ static void test_ec_commit(void) { secp256k1_sha256_initialize(&sha); CHECK(secp256k1_ec_commit_seckey(&seckey_s, &pubkey, &sha, data, 32) == 1); secp256k1_ecmult_gen(&CTX->ecmult_gen_ctx, &pubkeyj, &seckey_s); - ge_equals_gej(&commitment, &pubkeyj); + secp256k1_gej_eq_ge_var(&pubkeyj, &commitment); /* Check that verification fails with different data */ secp256k1_sha256_initialize(&sha); @@ -4245,7 +4234,7 @@ static void test_ec_commit_api(void) { secp256k1_ge pubkey_tmp = pubkey; secp256k1_sha256_initialize(&sha); CHECK(secp256k1_ec_commit(&pubkey_tmp, &pubkey_tmp, &sha, data, 1) == 1); - ge_equals_ge(&commitment, &pubkey_tmp); + secp256k1_ge_eq_var(&commitment, &pubkey_tmp); } secp256k1_sha256_initialize(&sha); @@ -4293,9 +4282,9 @@ 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_quad.x, x)); - CHECK(secp256k1_fe_equal_var(&ge_even.x, x)); - CHECK(secp256k1_fe_equal_var(&ge_odd.x, x)); + CHECK(secp256k1_fe_equal(&ge_quad.x, x)); + CHECK(secp256k1_fe_equal(&ge_even.x, x)); + CHECK(secp256k1_fe_equal(&ge_odd.x, x)); /* Check that the Y coordinate result in ge_quad is a square. */ CHECK(secp256k1_fe_is_square_var(&ge_quad.y)); @@ -4368,18 +4357,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; } @@ -4430,8 +4419,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; @@ -4472,8 +4461,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]; @@ -4491,15 +4478,15 @@ 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); + CHECK(secp256k1_gej_eq_ge_var(point, &res3)); + secp256k1_ecmult(&res1, point, &secp256k1_scalar_zero, &secp256k1_scalar_one); secp256k1_ge_set_gej(&res3, &res1); - ge_equals_ge(&res3, &secp256k1_ge_const_g); + CHECK(secp256k1_ge_eq_var(&secp256k1_ge_const_g, &res3)); } /* These scalars reach large (in absolute value) outputs when fed to secp256k1_scalar_split_lambda. @@ -4537,7 +4524,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); @@ -4556,9 +4542,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); @@ -4601,7 +4587,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) { @@ -4628,7 +4614,7 @@ static void ecmult_const_random_mult(void) { secp256k1_ecmult_const(&b, &a, &xn); CHECK(secp256k1_ge_is_valid_var(&a)); - ge_equals_gej(&expected_b, &b); + CHECK(secp256k1_gej_eq_ge_var(&b, &expected_b)); } static void ecmult_const_commutativity(void) { @@ -4649,29 +4635,76 @@ static void ecmult_const_commutativity(void) { secp256k1_ecmult_const(&res2, &mid2, &a); secp256k1_ge_set_gej(&mid1, &res1); secp256k1_ge_set_gej(&mid2, &res2); - ge_equals_ge(&mid1, &mid2); + CHECK(secp256k1_ge_eq_var(&mid1, &mid2)); } 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 s; secp256k1_scalar negone; secp256k1_gej res1; secp256k1_ge res2; secp256k1_ge point; - secp256k1_scalar_negate(&negone, &one); + secp256k1_ge inf; + random_scalar_order_test(&s); + secp256k1_scalar_negate(&negone, &secp256k1_scalar_one); random_group_element_test(&point); - secp256k1_ecmult_const(&res1, &point, &zero); + secp256k1_ge_set_infinity(&inf); + + /* 0*point */ + secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_zero); + CHECK(secp256k1_gej_is_infinity(&res1)); + + /* s*inf */ + secp256k1_ecmult_const(&res1, &inf, &s); + CHECK(secp256k1_gej_is_infinity(&res1)); + + /* 1*point */ + secp256k1_ecmult_const(&res1, &point, &secp256k1_scalar_one); secp256k1_ge_set_gej(&res2, &res1); - CHECK(secp256k1_ge_is_infinity(&res2)); - secp256k1_ecmult_const(&res1, &point, &one); - secp256k1_ge_set_gej(&res2, &res1); - ge_equals_ge(&res2, &point); + CHECK(secp256k1_ge_eq_var(&res2, &point)); + + /* -1*point */ secp256k1_ecmult_const(&res1, &point, &negone); secp256k1_gej_neg(&res1, &res1); secp256k1_ge_set_gej(&res2, &res1); - ge_equals_ge(&res2, &point); + CHECK(secp256k1_ge_eq_var(&res2, &point)); +} + +static void ecmult_const_check_result(const secp256k1_ge *A, const secp256k1_scalar* q, const secp256k1_gej *res) { + secp256k1_gej pointj, res2j; + secp256k1_ge res2; + secp256k1_gej_set_ge(&pointj, A); + secp256k1_ecmult(&res2j, &pointj, q, &secp256k1_scalar_zero); + secp256k1_ge_set_gej(&res2, &res2j); + CHECK(secp256k1_gej_eq_ge_var(res, &res2)); +} + +static void ecmult_const_edges(void) { + secp256k1_scalar q; + secp256k1_ge point; + secp256k1_gej res; + size_t i; + size_t cases = 1 + sizeof(scalars_near_split_bounds) / sizeof(scalars_near_split_bounds[0]); + + /* We are trying to reach the following edge cases (variables are defined as + * in ecmult_const_impl.h): + * 1. i = 0: s = 0 <=> q = -K + * 2. i > 0: v1, v2 large values + * <=> s1, s2 large values + * <=> s = scalars_near_split_bounds[i] + * <=> q = 2*scalars_near_split_bounds[i] - K + */ + for (i = 0; i < cases; ++i) { + secp256k1_scalar_negate(&q, &secp256k1_ecmult_const_K); + if (i > 0) { + secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); + secp256k1_scalar_add(&q, &q, &scalars_near_split_bounds[i - 1]); + } + random_group_element_test(&point); + secp256k1_ecmult_const(&res, &point, &q); + ecmult_const_check_result(&point, &q, &res); + } } static void ecmult_const_mult_xonly(void) { @@ -4752,11 +4785,12 @@ static void ecmult_const_chain_multiply(void) { secp256k1_ecmult_const(&point, &tmp, &scalar); } secp256k1_ge_set_gej(&res, &point); - ge_equals_gej(&res, &expected_point); + CHECK(secp256k1_gej_eq_ge_var(&expected_point, &res)); } static void run_ecmult_const_tests(void) { ecmult_const_mult_zero_one(); + ecmult_const_edges(); ecmult_const_random_mult(); ecmult_const_commutativity(); ecmult_const_chain_multiply(); @@ -5020,7 +5054,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. */ @@ -5417,73 +5451,17 @@ static void test_wnaf(const secp256k1_scalar *number, int w) { CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ } -static void test_constant_wnaf_negate(const secp256k1_scalar *number) { - secp256k1_scalar neg1 = *number; - secp256k1_scalar neg2 = *number; - int sign1 = 1; - int sign2 = 1; - - if (!secp256k1_scalar_get_bits(&neg1, 0, 1)) { - secp256k1_scalar_negate(&neg1, &neg1); - sign1 = -1; - } - sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2)); - CHECK(sign1 == sign2); - CHECK(secp256k1_scalar_eq(&neg1, &neg2)); -} - -static void test_constant_wnaf(const secp256k1_scalar *number, int w) { - secp256k1_scalar x, shift; - int wnaf[256] = {0}; - int i; - int skew; - int bits = 256; - secp256k1_scalar num = *number; - secp256k1_scalar scalar_skew; - - secp256k1_scalar_set_int(&x, 0); - secp256k1_scalar_set_int(&shift, 1 << w); - for (i = 0; i < 16; ++i) { - secp256k1_scalar_shr_int(&num, 8); - } - bits = 128; - skew = secp256k1_wnaf_const(wnaf, &num, w, bits); - - for (i = WNAF_SIZE_BITS(bits, w); i >= 0; --i) { - secp256k1_scalar t; - int v = wnaf[i]; - CHECK(v != 0); /* check nonzero */ - CHECK(v & 1); /* check parity */ - CHECK(v > -(1 << w)); /* check range above */ - CHECK(v < (1 << w)); /* check range below */ - - secp256k1_scalar_mul(&x, &x, &shift); - if (v >= 0) { - secp256k1_scalar_set_int(&t, v); - } else { - secp256k1_scalar_set_int(&t, -v); - secp256k1_scalar_negate(&t, &t); - } - secp256k1_scalar_add(&x, &x, &t); - } - /* Skew num because when encoding numbers as odd we use an offset */ - secp256k1_scalar_set_int(&scalar_skew, skew); - secp256k1_scalar_add(&num, &num, &scalar_skew); - CHECK(secp256k1_scalar_eq(&x, &num)); -} - static void test_fixed_wnaf(const secp256k1_scalar *number, int w) { secp256k1_scalar x, shift; int wnaf[256] = {0}; int i; int skew; - secp256k1_scalar num = *number; + secp256k1_scalar num, unused; secp256k1_scalar_set_int(&x, 0); secp256k1_scalar_set_int(&shift, 1 << w); - for (i = 0; i < 16; ++i) { - secp256k1_scalar_shr_int(&num, 8); - } + /* Make num a 128-bit scalar. */ + secp256k1_scalar_split_128(&num, &unused, number); skew = secp256k1_wnaf_fixed(wnaf, &num, w); for (i = WNAF_SIZE(w)-1; i >= 0; --i) { @@ -5575,32 +5553,7 @@ static void test_fixed_wnaf_small(void) { static void run_wnaf(void) { int i; - secp256k1_scalar n = {{0}}; - - test_constant_wnaf(&n, 4); - /* Sanity check: 1 and 2 are the smallest odd and even numbers and should - * have easier-to-diagnose failure modes */ - n.d[0] = 1; - test_constant_wnaf(&n, 4); - n.d[0] = 2; - test_constant_wnaf(&n, 4); - /* Test -1, because it's a special case in wnaf_const */ - n = secp256k1_scalar_one; - secp256k1_scalar_negate(&n, &n); - test_constant_wnaf(&n, 4); - - /* Test -2, which may not lead to overflows in wnaf_const */ - secp256k1_scalar_add(&n, &secp256k1_scalar_one, &secp256k1_scalar_one); - secp256k1_scalar_negate(&n, &n); - test_constant_wnaf(&n, 4); - - /* Test (1/2) - 1 = 1/-2 and 1/2 = (1/-2) + 1 - as corner cases of negation handling in wnaf_const */ - secp256k1_scalar_inverse(&n, &n); - test_constant_wnaf(&n, 4); - - secp256k1_scalar_add(&n, &n, &secp256k1_scalar_one); - test_constant_wnaf(&n, 4); + secp256k1_scalar n; /* Test 0 for fixed wnaf */ test_fixed_wnaf_small(); @@ -5608,8 +5561,6 @@ static void run_wnaf(void) { for (i = 0; i < COUNT; i++) { random_scalar_order(&n); test_wnaf(&n, 4+(i%10)); - test_constant_wnaf_negate(&n); - test_constant_wnaf(&n, 4 + (i % 10)); test_fixed_wnaf(&n, 4 + (i % 10)); } secp256k1_scalar_set_int(&n, 0); @@ -5631,23 +5582,22 @@ 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); - ge_equals_gej(&r, &rj3); - ge_equals_gej(&r, &rj4); - ge_equals_gej(&r, &rj5); - ge_equals_gej(&r, &rj6); + CHECK(secp256k1_gej_eq_ge_var(&rj2, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj3, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj4, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj5, &r)); + CHECK(secp256k1_gej_eq_ge_var(&rj6, &r)); if (secp256k1_ge_is_infinity(&r)) { /* Store infinity as 0x00 */ const unsigned char zerobyte[1] = {0}; @@ -5801,7 +5751,7 @@ static void test_ecmult_gen_blind(void) { CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); CHECK(!gej_xyz_equals_gej(&i, &CTX->ecmult_gen_ctx.initial)); secp256k1_ge_set_gej(&pge, &pgej); - ge_equals_gej(&pge, &pgej2); + CHECK(secp256k1_gej_eq_ge_var(&pgej2, &pge)); } static void test_ecmult_gen_blind_reset(void) { @@ -5878,9 +5828,7 @@ static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, in secp256k1_pubkey pubkey; secp256k1_ge ge; size_t pubkeyclen; - int32_t ecount; - ecount = 0; - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); + for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { /* Smaller sizes are tested exhaustively elsewhere. */ int32_t i; @@ -5905,7 +5853,6 @@ static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, in size_t outl; memset(&pubkey, 0, sizeof(pubkey)); SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - ecount = 0; CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 1); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); outl = 65; @@ -5931,21 +5878,16 @@ static void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, in CHECK(pubkeyo[0] == 4); CHECK(secp256k1_memcmp_var(&pubkeyo[1], input, 64) == 0); } - CHECK(ecount == 0); } else { /* These cases must fail to parse. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, pubkeyclen) == 0); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); } } } - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); } static void run_ec_pubkey_parse_test(void) { @@ -6128,142 +6070,99 @@ static void run_ec_pubkey_parse_test(void) { 0xB8, 0x00 }; unsigned char sout[65]; - unsigned char shortkey[2]; + unsigned char shortkey[2] = { 0 }; secp256k1_ge ge; secp256k1_pubkey pubkey; size_t len; int32_t i; - int32_t ecount; - int32_t ecount2; - ecount = 0; + /* Nothing should be reading this far into pubkeyc. */ SECP256K1_CHECKMEM_UNDEFINE(&pubkeyc[65], 1); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); /* Zero length claimed, fail, zeroize, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; SECP256K1_CHECKMEM_UNDEFINE(shortkey, 2); SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 0) == 0); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); /* Length one claimed, fail, zeroize, no illegal arg error. */ for (i = 0; i < 256 ; i++) { memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; shortkey[0] = i; SECP256K1_CHECKMEM_UNDEFINE(&shortkey[1], 1); SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 1) == 0); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); } /* Length two claimed, fail, zeroize, no illegal arg error. */ for (i = 0; i < 65536 ; i++) { memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; shortkey[0] = i & 255; shortkey[1] = i >> 8; SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, shortkey, 2) == 0); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); } memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 33) == 0); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ - CHECK(secp256k1_ec_pubkey_parse(CTX, NULL, pubkeyc, 65) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, NULL, pubkeyc, 65)); /* NULL input string. Illegal arg and zeroize output. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, NULL, 65) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, &pubkey, NULL, 65)); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 1); - CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 64) == 0); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ memset(&pubkey, 0xfe, sizeof(pubkey)); - ecount = 0; SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 66) == 0); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); - CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_pubkey_load(CTX, &ge, &pubkey)); /* Valid parse. */ memset(&pubkey, 0, sizeof(pubkey)); - ecount = 0; SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkey, pubkeyc, 65) == 1); CHECK(secp256k1_ec_pubkey_parse(secp256k1_context_static, &pubkey, pubkeyc, 65) == 1); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(pubkey)); - CHECK(ecount == 0); SECP256K1_CHECKMEM_UNDEFINE(&ge, sizeof(ge)); CHECK(secp256k1_pubkey_load(CTX, &ge, &pubkey) == 1); SECP256K1_CHECKMEM_CHECK(&ge.x, sizeof(ge.x)); SECP256K1_CHECKMEM_CHECK(&ge.y, sizeof(ge.y)); SECP256K1_CHECKMEM_CHECK(&ge.infinity, sizeof(ge.infinity)); - ge_equals_ge(&secp256k1_ge_const_g, &ge); - CHECK(ecount == 0); + CHECK(secp256k1_ge_eq_var(&ge, &secp256k1_ge_const_g)); /* secp256k1_ec_pubkey_serialize illegal args. */ - ecount = 0; len = 65; - CHECK(secp256k1_ec_pubkey_serialize(CTX, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED)); CHECK(len == 0); - CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED)); len = 65; SECP256K1_CHECKMEM_UNDEFINE(sout, 65); - CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED)); SECP256K1_CHECKMEM_CHECK(sout, 65); - CHECK(ecount == 3); CHECK(len == 0); len = 65; - CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, ~0) == 0); - CHECK(ecount == 4); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, ~0)); CHECK(len == 0); len = 65; SECP256K1_CHECKMEM_UNDEFINE(sout, 65); CHECK(secp256k1_ec_pubkey_serialize(CTX, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); SECP256K1_CHECKMEM_CHECK(sout, 65); - CHECK(ecount == 4); CHECK(len == 65); /* Multiple illegal args. Should still set arg error only once. */ - ecount = 0; - ecount2 = 11; - CHECK(secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65) == 0); - CHECK(ecount == 1); - /* Does the illegal arg callback actually change the behavior? */ - secp256k1_context_set_illegal_callback(CTX, uncounting_illegal_callback_fn, &ecount2); - CHECK(secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65) == 0); - CHECK(ecount == 1); - CHECK(ecount2 == 10); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_parse(CTX, NULL, NULL, 65)); /* Try a bunch of prefabbed points with all possible encodings. */ for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { ec_pubkey_parse_pointtest(valid[i], 1, 1); @@ -6292,7 +6191,6 @@ static void run_eckey_edge_case_test(void) { secp256k1_pubkey pubkey_negone; const secp256k1_pubkey *pubkeys[3]; size_t len; - int32_t ecount; /* Group order is too large, reject. */ CHECK(secp256k1_ec_seckey_verify(CTX, orderc) == 0); SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(pubkey)); @@ -6414,88 +6312,59 @@ static void run_eckey_edge_case_test(void) { ctmp2[31] = 2; CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2) == 1); CHECK(secp256k1_memcmp_var(&pubkey, &pubkey2, sizeof(pubkey)) == 0); - /* Test argument errors. */ - ecount = 0; - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - CHECK(ecount == 0); /* Zeroize pubkey on parse error. */ memset(&pubkey, 0, 32); - CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, ctmp2)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(pubkey)) == 0); memcpy(&pubkey, &pubkey2, sizeof(pubkey)); memset(&pubkey2, 0, 32); - CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey2, ctmp2)); CHECK(secp256k1_memcmp_var(&pubkey2, zeros, sizeof(pubkey2)) == 0); /* Plain argument errors. */ - ecount = 0; CHECK(secp256k1_ec_seckey_verify(CTX, ctmp) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ec_seckey_verify(CTX, NULL) == 0); - CHECK(ecount == 1); - ecount = 0; + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_verify(CTX, NULL)); memset(ctmp2, 0, 32); ctmp2[31] = 4; - CHECK(secp256k1_ec_pubkey_tweak_add(CTX, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_add(CTX, &pubkey, NULL)); memset(ctmp2, 0, 32); ctmp2[31] = 4; - CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_tweak_mul(CTX, &pubkey, NULL)); memset(ctmp2, 0, 32); - CHECK(secp256k1_ec_seckey_tweak_add(CTX, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_seckey_tweak_add(CTX, ctmp, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_add(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_add(CTX, ctmp, NULL)); memset(ctmp2, 0, 32); ctmp2[31] = 1; - CHECK(secp256k1_ec_seckey_tweak_mul(CTX, NULL, ctmp2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_seckey_tweak_mul(CTX, ctmp, NULL) == 0); - CHECK(ecount == 2); - ecount = 0; - CHECK(secp256k1_ec_pubkey_create(CTX, NULL, ctmp) == 0); - CHECK(ecount == 1); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_mul(CTX, NULL, ctmp2)); + CHECK_ILLEGAL(CTX, secp256k1_ec_seckey_tweak_mul(CTX, ctmp, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, NULL, ctmp)); memset(&pubkey, 1, sizeof(pubkey)); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, NULL) == 0); - CHECK(ecount == 2); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); /* secp256k1_ec_pubkey_combine tests. */ - ecount = 0; pubkeys[0] = &pubkey_one; SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[0], sizeof(secp256k1_pubkey *)); SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[1], sizeof(secp256k1_pubkey *)); SECP256K1_CHECKMEM_UNDEFINE(&pubkeys[2], sizeof(secp256k1_pubkey *)); memset(&pubkey, 255, sizeof(secp256k1_pubkey)); SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 0) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 0)); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_pubkey_combine(CTX, NULL, pubkeys, 1) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, NULL, pubkeys, 1)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 2); memset(&pubkey, 255, sizeof(secp256k1_pubkey)); SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); - CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, NULL, 1) == 0); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_combine(CTX, &pubkey, NULL, 1)); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 3); pubkeys[0] = &pubkey_negone; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); SECP256K1_CHECKMEM_UNDEFINE(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 1) == 1); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - CHECK(ecount == 3); len = 33; CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); @@ -6508,7 +6377,6 @@ static void run_eckey_edge_case_test(void) { CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 0); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); - CHECK(ecount == 3); /* Passes through infinity but comes out one. */ pubkeys[2] = &pubkey_one; memset(&pubkey, 255, sizeof(secp256k1_pubkey)); @@ -6516,7 +6384,6 @@ static void run_eckey_edge_case_test(void) { CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 3) == 1); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - CHECK(ecount == 3); len = 33; CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); CHECK(secp256k1_ec_pubkey_serialize(CTX, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); @@ -6528,8 +6395,6 @@ static void run_eckey_edge_case_test(void) { CHECK(secp256k1_ec_pubkey_combine(CTX, &pubkey, pubkeys, 2) == 1); SECP256K1_CHECKMEM_CHECK(&pubkey, sizeof(secp256k1_pubkey)); CHECK(secp256k1_memcmp_var(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); - CHECK(ecount == 3); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); } static void run_eckey_negate_test(void) { @@ -6846,7 +6711,7 @@ static void test_random_pubkeys(void) { CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); CHECK(size == 65); CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); - ge_equals_ge(&elem,&elem2); + CHECK(secp256k1_ge_eq_var(&elem2, &elem)); /* Check that the X9.62 hybrid type is checked. */ in[0] = secp256k1_testrand_bits(1) ? 6 : 7; res = secp256k1_eckey_pubkey_parse(&elem2, in, size); @@ -6858,7 +6723,7 @@ static void test_random_pubkeys(void) { } } if (res) { - ge_equals_ge(&elem,&elem2); + CHECK(secp256k1_ge_eq_var(&elem, &elem2)); CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); CHECK(secp256k1_memcmp_var(&in[1], &out[1], 64) == 0); } @@ -6878,34 +6743,30 @@ static void run_pubkey_comparison(void) { }; secp256k1_pubkey pk1; secp256k1_pubkey pk2; - int32_t ecount = 0; CHECK(secp256k1_ec_pubkey_parse(CTX, &pk1, pk1_ser, sizeof(pk1_ser)) == 1); CHECK(secp256k1_ec_pubkey_parse(CTX, &pk2, pk2_ser, sizeof(pk2_ser)) == 1); - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); - CHECK(secp256k1_ec_pubkey_cmp(CTX, NULL, &pk2) < 0); - CHECK(ecount == 1); - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, NULL) > 0); - CHECK(ecount == 2); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, NULL, &pk2) < 0)); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, NULL) > 0)); CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk2) < 0); CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk1) > 0); CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk1, &pk1) == 0); CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk2) == 0); - CHECK(ecount == 2); { secp256k1_pubkey pk_tmp; memset(&pk_tmp, 0, sizeof(pk_tmp)); /* illegal pubkey */ - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk2) < 0); - CHECK(ecount == 3); - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk_tmp) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk_tmp) > 0); - CHECK(ecount == 6); + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk2) < 0)); + { + int32_t ecount = 0; + secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount); + CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk_tmp, &pk_tmp) == 0); + CHECK(ecount == 2); + secp256k1_context_set_illegal_callback(CTX, NULL, NULL); + } + CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_ec_pubkey_cmp(CTX, &pk2, &pk_tmp) > 0)); } - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); - /* Make pk2 the same as pk1 but with 3 rather than 2. Note that in * an uncompressed encoding, these would have the opposite ordering */ pk1_ser[0] = 3; @@ -7375,7 +7236,6 @@ static void test_ecdsa_edge_cases(void) { { secp256k1_pubkey pubkey; size_t siglen; - int32_t ecount; unsigned char signature[72]; static const unsigned char nonce[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -7401,72 +7261,42 @@ static void test_ecdsa_edge_cases(void) { 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, }; - ecount = 0; - secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount); CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 0); CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); msg[31] = 0xaa; CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce) == 1); - CHECK(ecount == 0); - CHECK(secp256k1_ecdsa_sign(CTX, NULL, msg, key, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, NULL, msg, key, precomputed_nonce_function, nonce2)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, NULL, key, precomputed_nonce_function, nonce2)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign(CTX, &sig, msg, NULL, precomputed_nonce_function, nonce2)); CHECK(secp256k1_ecdsa_sign(CTX, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, key) == 1); - CHECK(secp256k1_ecdsa_verify(CTX, NULL, msg, &pubkey) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, NULL, &pubkey) == 0); - CHECK(ecount == 5); - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, NULL) == 0); - CHECK(ecount == 6); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, NULL, msg, &pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, NULL, &pubkey)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, NULL)); CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey) == 1); - CHECK(ecount == 6); - CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, NULL) == 0); - CHECK(ecount == 7); + CHECK_ILLEGAL(CTX, secp256k1_ec_pubkey_create(CTX, &pubkey, NULL)); /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ - CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey) == 0); - CHECK(ecount == 8); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_verify(CTX, &sig, msg, &pubkey)); siglen = 72; - CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, NULL, &siglen, &sig) == 0); - CHECK(ecount == 9); - CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, NULL, &sig) == 0); - CHECK(ecount == 10); - CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, NULL) == 0); - CHECK(ecount == 11); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, NULL, &siglen, &sig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, NULL, &sig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, NULL)); CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 1); - CHECK(ecount == 11); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, NULL, signature, siglen) == 0); - CHECK(ecount == 12); - CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, NULL, siglen) == 0); - CHECK(ecount == 13); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, NULL, signature, siglen)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_der(CTX, &sig, NULL, siglen)); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, signature, siglen) == 1); - CHECK(ecount == 13); siglen = 10; /* Too little room for a signature does not fail via ARGCHECK. */ CHECK(secp256k1_ecdsa_signature_serialize_der(CTX, signature, &siglen, &sig) == 0); - CHECK(ecount == 13); - ecount = 0; - CHECK(secp256k1_ecdsa_signature_normalize(CTX, NULL, NULL) == 0); - CHECK(ecount == 1); - CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, NULL, &sig) == 0); - CHECK(ecount == 2); - CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, signature, NULL) == 0); - CHECK(ecount == 3); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_normalize(CTX, NULL, NULL)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, NULL, &sig)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_serialize_compact(CTX, signature, NULL)); CHECK(secp256k1_ecdsa_signature_serialize_compact(CTX, signature, &sig) == 1); - CHECK(ecount == 3); - CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, NULL, signature) == 0); - CHECK(ecount == 4); - CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, NULL) == 0); - CHECK(ecount == 5); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, NULL, signature)); + CHECK_ILLEGAL(CTX, secp256k1_ecdsa_signature_parse_compact(CTX, &sig, NULL)); CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 1); - CHECK(ecount == 5); memset(signature, 255, 64); CHECK(secp256k1_ecdsa_signature_parse_compact(CTX, &sig, signature) == 0); - CHECK(ecount == 5); - secp256k1_context_set_illegal_callback(CTX, NULL, NULL); } /* Nonce function corner cases. */ @@ -7616,6 +7446,10 @@ static void run_ecdsa_wycheproof(void) { test_ecdsa_wycheproof(); } +#ifdef ENABLE_MODULE_SCHNORRSIG_HALFAGG +# include "modules/schnorrsig_halfagg/tests_impl.h" +#endif + #ifdef ENABLE_MODULE_BPPP # include "modules/bppp/tests_impl.h" #endif @@ -7797,33 +7631,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) { @@ -7990,6 +7822,10 @@ int main(int argc, char **argv) { /* EC key arithmetic test */ run_eckey_negate_test(); +#ifdef ENABLE_MODULE_SCHNORRSIG_HALFAGG + run_schnorrsig_halfagg_tests(); +#endif + #ifdef ENABLE_MODULE_BPPP run_bppp_tests(); #endif diff --git a/src/tests_exhaustive.c b/src/tests_exhaustive.c index dbb6b7eb46..1a8be57d07 100644 --- a/src/tests_exhaustive.c +++ b/src/tests_exhaustive.c @@ -28,61 +28,11 @@ #include "testrand_impl.h" #include "ecmult_compute_table_impl.h" #include "ecmult_gen_compute_table_impl.h" +#include "testutil.h" #include "util.h" static int count = 2; -/** stolen from tests.c */ -static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); -} - -static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { - secp256k1_fe z2s; - secp256k1_fe u1, u2, s1, s2; - CHECK(a->infinity == b->infinity); - if (a->infinity) { - return; - } - /* 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); - 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)); -} - -static void random_fe(secp256k1_fe *x) { - unsigned char bin[32]; - do { - secp256k1_testrand256(bin); - if (secp256k1_fe_set_b32_limit(x, bin)) { - return; - } - } while(1); -} - -static void random_fe_non_zero(secp256k1_fe *nz) { - int tries = 10; - while (--tries >= 0) { - random_fe(nz); - secp256k1_fe_normalize(nz); - if (!secp256k1_fe_is_zero(nz)) { - break; - } - } - /* Infinitesimal probability of spurious failure here */ - CHECK(tries >= 0); -} -/** END stolen from tests.c */ - static uint32_t num_cores = 1; static uint32_t this_core = 0; @@ -117,7 +67,7 @@ static void test_exhaustive_endomorphism(const secp256k1_ge *group) { for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_ge res; secp256k1_ge_mul_lambda(&res, &group[i]); - ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res); + CHECK(secp256k1_ge_eq_var(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res)); } } @@ -143,21 +93,21 @@ static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_ secp256k1_gej tmp; /* add_var */ secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); - ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); /* add_ge */ if (j > 0) { secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]); - ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); } /* add_ge_var */ secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); - ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); /* add_zinv_var */ zless_gej.infinity = groupj[j].infinity; zless_gej.x = groupj[j].x; zless_gej.y = groupj[j].y; secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); - ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER])); } } @@ -165,9 +115,9 @@ static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_ for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { secp256k1_gej tmp; secp256k1_gej_double(&tmp, &groupj[i]); - ge_equals_gej(&group[(2 * i) % EXHAUSTIVE_TEST_ORDER], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER])); secp256k1_gej_double_var(&tmp, &groupj[i], NULL); - ge_equals_gej(&group[(2 * i) % EXHAUSTIVE_TEST_ORDER], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER])); } /* Check negation */ @@ -175,9 +125,9 @@ static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_ secp256k1_ge tmp; secp256k1_gej tmpj; secp256k1_ge_neg(&tmp, &group[i]); - ge_equals_ge(&group[EXHAUSTIVE_TEST_ORDER - i], &tmp); + CHECK(secp256k1_ge_eq_var(&tmp, &group[EXHAUSTIVE_TEST_ORDER - i])); secp256k1_gej_neg(&tmpj, &groupj[i]); - ge_equals_gej(&group[EXHAUSTIVE_TEST_ORDER - i], &tmpj); + CHECK(secp256k1_gej_eq_ge_var(&tmpj, &group[EXHAUSTIVE_TEST_ORDER - i])); } } @@ -194,8 +144,7 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge secp256k1_scalar_set_int(&ng, j); secp256k1_ecmult(&tmp, &groupj[r_log], &na, &ng); - ge_equals_gej(&group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER], &tmp); - + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER])); } } } @@ -213,20 +162,20 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge /* Test secp256k1_ecmult_const. */ secp256k1_ecmult_const(&tmp, &group[i], &ng); - ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * j) % EXHAUSTIVE_TEST_ORDER])); if (i != 0 && j != 0) { /* 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)); } } } @@ -265,7 +214,7 @@ static void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const sec data.pt[1] = group[y]; secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2); - ge_equals_gej(&group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER], &tmp); + CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER])); } } } @@ -475,8 +424,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/testutil.h b/src/testutil.h new file mode 100644 index 0000000000..4e2cb7d5b3 --- /dev/null +++ b/src/testutil.h @@ -0,0 +1,29 @@ +/*********************************************************************** + * Distributed under the MIT software license, see the accompanying * + * file COPYING or https://www.opensource.org/licenses/mit-license.php.* + ***********************************************************************/ + +#ifndef SECP256K1_TESTUTIL_H +#define SECP256K1_TESTUTIL_H + +#include "field.h" +#include "testrand.h" +#include "util.h" + +static void random_fe(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_testrand256(bin); + if (secp256k1_fe_set_b32_limit(x, bin)) { + return; + } + } while(1); +} + +static void random_fe_non_zero(secp256k1_fe *nz) { + do { + random_fe(nz); + } while (secp256k1_fe_is_zero(nz)); +} + +#endif /* SECP256K1_TESTUTIL_H */ diff --git a/src/util.h b/src/util.h index 9c0eb0fdd1..10ea51605e 100644 --- a/src/util.h +++ b/src/util.h @@ -51,13 +51,27 @@ static void print_buf_plain(const unsigned char *buf, size_t len) { # define SECP256K1_INLINE inline # endif +/** Assert statically that expr is true. + * + * This is a statement-like macro and can only be used inside functions. + */ +#define STATIC_ASSERT(expr) do { \ + switch(0) { \ + case 0: \ + /* If expr evaluates to 0, we have two case labels "0", which is illegal. */ \ + case /* ERROR: static assertion failed */ (expr): \ + ; \ + } \ +} while(0) + /** Assert statically that expr is an integer constant expression, and run stmt. * * Useful for example to enforce that magnitude arguments are constant. */ #define ASSERT_INT_CONST_AND_DO(expr, stmt) do { \ switch(42) { \ - case /* ERROR: integer argument is not constant */ expr: \ + /* C allows only integer constant expressions as case labels. */ \ + case /* ERROR: integer argument is not constant */ (expr): \ break; \ default: ; \ } \ @@ -132,16 +146,11 @@ static const secp256k1_callback default_error_callback = { } while(0) #endif -/* Like assert(), but when VERIFY is defined, and side-effect safe. */ -#if defined(COVERAGE) -#define VERIFY_CHECK(check) -#define VERIFY_SETUP(stmt) -#elif defined(VERIFY) +/* Like assert(), but when VERIFY is defined. */ +#if defined(VERIFY) #define VERIFY_CHECK CHECK -#define VERIFY_SETUP(stmt) do { stmt; } while(0) #else -#define VERIFY_CHECK(cond) do { (void)(cond); } while(0) -#define VERIFY_SETUP(stmt) +#define VERIFY_CHECK(cond) #endif static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { diff --git a/tools/check-abi.sh b/tools/check-abi.sh new file mode 100755 index 0000000000..55c945ac16 --- /dev/null +++ b/tools/check-abi.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +set -eu + +default_base_version="$(git describe --match "v*.*.*" --abbrev=0)" +default_new_version="HEAD" + +display_help_and_exit() { + echo "Usage: $0 [ []]" + echo "" + echo "Description: This script uses the ABI Compliance Checker tool to determine if the ABI" + echo " of a new version of libsecp256k1 has changed in a backward-incompatible way." + echo "" + echo "Options:" + echo " base_ver Specify the base version as a git commit-ish" + echo " (default: most recent reachable tag matching \"v.*.*\", currently \"$default_base_version\")" + echo " new_ver Specify the new version as a git commit-ish" + echo " (default: $default_new_version)" + echo " -h, --help Display this help message" + exit 0 +} + +if [ "$#" -eq 0 ]; then + base_version="$default_base_version" + new_version="$default_new_version" +elif [ "$#" -eq 1 ] && { [ "$1" = "-h" ] || [ "$1" = "--help" ]; }; then + display_help_and_exit +elif [ "$#" -eq 1 ] || [ "$#" -eq 2 ]; then + base_version="$1" + if [ "$#" -eq 2 ]; then + new_version="$2" + fi +else + echo "Invalid usage. See help:" + echo "" + display_help_and_exit +fi + +checkout_and_build() { + _orig_dir="$(pwd)" + git worktree add --detach "$1" "$2" + cd "$1" + mkdir build && cd build + cmake -S .. --preset dev-mode \ + -DCMAKE_C_COMPILER=gcc -DCMAKE_BUILD_TYPE=None -DCMAKE_C_FLAGS="-g -Og -gdwarf-4" \ + -DSECP256K1_BUILD_BENCHMARK=OFF \ + -DSECP256K1_BUILD_TESTS=OFF \ + -DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \ + -DSECP256K1_BUILD_CTIME_TESTS=OFF \ + -DSECP256K1_BUILD_EXAMPLES=OFF + cmake --build . -j "$(nproc)" + abi-dumper src/libsecp256k1.so -o ABI.dump -lver "$2" + cd "$_orig_dir" +} + +echo "Comparing $base_version (base version) to $new_version (new version)" +echo + +base_source_dir="$(mktemp -d)" +checkout_and_build "$base_source_dir" "$base_version" + +new_source_dir="$(mktemp -d)" +checkout_and_build "$new_source_dir" "$new_version" + +abi-compliance-checker -lib libsecp256k1 -old "${base_source_dir}/build/ABI.dump" -new "${new_source_dir}/build/ABI.dump" +git worktree remove "$base_source_dir" +git worktree remove "$new_source_dir"