mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-02-01 03:01:05 +00:00
Squashed 'src/secp256k1/' changes from b9313c6e1a..d543c0d917
d543c0d917 Merge bitcoin-core/secp256k1#1734: Introduce (mini) unit test framework f44c1ebd96 Merge bitcoin-core/secp256k1#1719: ci: DRY workflow using anchors a44a339384 Merge bitcoin-core/secp256k1#1750: ci: Use clang-snapshot in "MSan" job 15d014804e ci: Drop default for `inputs.command` in `run-in-docker-action` 1decc49a1f ci: Use YAML anchor and aliases for repeated "CI script" steps dff1bc107d ci, refactor: Generalize use of `matrix.configuration.env_vars` 4b644da199 ci: Use YAML anchor and aliases for repeated "Print logs" steps a889cd93df ci: Bump `actions/checkout` version 574c2f3080 ci: Use YAML anchor and aliases for repeated "Checkout" steps 53585f93b7 ci: Use clang-snapshot in "MSan" job 6894c964f3 Fix Clang 21+ `-Wuninitialized-const-pointer` warning when using MSan 2b7337f63a Merge bitcoin-core/secp256k1#1756: ci: Fix image caching and apply other improvements f163c35897 ci: Set `DEBIAN_FRONTEND=noninteractive` 70ae177ca0 ci: Bump `docker/build-push-action` version b2a95a420f ci: Drop `tags` input for `docker/build-push-action` 122014edb3 ci: Add `scope` parameter to `cache-{to,from}` options 2f4546ce56 test: add --log option to display tests execution 95b9953ea4 test: Add option to display all available tests 953f7b0088 test: support running specific tests/modules targets 0302c1a3d7 test: add --help for command-line options 9ec3bfe22d test: adapt modules to the new test infrastructure 48789dafc2 test: introduce (mini) unit test framework baa265429f Merge bitcoin-core/secp256k1#1727: docs: Clarify that callback can be called more than once 4d90585fea docs: Improve API docs of _context_set_illegal_callback 895f53d1cf docs: Clarify that callback can be called more than once de6af6ae35 Merge bitcoin-core/secp256k1#1748: bench: improve context creation in ECDH benchmark 5817885153 Merge bitcoin-core/secp256k1#1749: build: Fix warnings in x86_64 assembly check ab560078aa build: Fix warnings in x86_64 assembly check 10dab907e7 Merge bitcoin-core/secp256k1#1741: doc: clarify API doc of `secp256k1_ecdsa_recover` return value dfe284ed2d bench: improve context creation in ECDH benchmark 7321bdf27b doc: clarify API doc of `secp256k1_ecdsa_recover` return value b475654302 Merge bitcoin-core/secp256k1#1745: test: introduce group order byte-array constant for deduplication 9cce703863 refactor: move 'gettime_i64()' to tests_common.h 0c91c56041 test: introduce group order byte-array constant for deduplication 88be4e8d86 Merge bitcoin-core/secp256k1#1735: musig: Invalidate secnonce in secp256k1_musig_partial_sign 36e76952cb Merge bitcoin-core/secp256k1#1738: check-abi: remove support for obsolete CMake library output location (src/libsecp256k1.so) 399b582a5f Split memclear into two versions 4985ac0f89 Merge bitcoin-core/secp256k1#1737: doc: mention ctx requirement for `_ellswift_create` (not secp256k1_context_static) 7ebaa134a7 check-abi: remove support for obsolete CMake library output location (src/libsecp256k1.so) 806de38bfc doc: mention ctx requirement for `_ellswift_create` (not secp256k1_context_static) 03fb60ad2e Merge bitcoin-core/secp256k1#1681: doc: Recommend clang-cl when building on Windows d93380fb35 Merge bitcoin-core/secp256k1#1731: schnorrsig: Securely clear buf containing k or its negation 8113671f80 Merge bitcoin-core/secp256k1#1729: hash: Use size_t instead of int for RFC6979 outlen copy 325d65a8cf Rename and clear var containing k or -k 960ba5f9c6 Use size_t instead of int for RFC6979 outlen copy 737912430d ci: Add more tests for clang-cl 7379a5bed3 doc: Recommend clang-cl when building on Windows f36afb8b3d Merge bitcoin-core/secp256k1#1725: tests: refactor tagged hash verification 5153cf1c91 tests: refactor tagged hash tests d2dcf52091 Merge bitcoin-core/secp256k1#1726: docs: fix broken link to Tromer's cache.pdf paper 489a43d1bf docs: fix broken link to eprint cache.pdf paper d599714147 Merge bitcoin-core/secp256k1#1722: docs: Exclude modules' `bench_impl.h` headers from coverage report 0458def51e doc: Add `--gcov-ignore-parse-errors=all` option to `gcovr` invocations 1aecce5936 doc: Add `--merge-mode-functions=separate` option to `gcovr` invocations 106a7cbf41 doc: Exclude modules' `bench_impl.h` headers from coverage report a9e955d3ea autotools, docs: Adjust help string for `--enable-coverage` option e523e4f90e Merge bitcoin-core/secp256k1#1720: chore(ci): Fix typo in Dockerfile comment 24ba8ff168 chore(ci): Fix typo in Dockerfile comment 74b8068c5d Merge bitcoin-core/secp256k1#1717: test: update wycheproof test vectors c25c3c8a88 test: update wycheproof test vectors 20e3b44746 Merge bitcoin-core/secp256k1#1688: cmake: Avoid contaminating parent project's cache with `BUILD_SHARED_LIBS` 2c076d907a Merge bitcoin-core/secp256k1#1711: tests: update Wycheproof 7b07b22957 cmake: Avoid contaminating parent project's cache with BUILD_SHARED_LIBS 5433648ca0 Fix typos and spellings 9ea54c69b7 tests: update Wycheproof files git-subtree-dir: src/secp256k1 git-subtree-split: d543c0d917a76a201578948701cc30ef336e0fe6
This commit is contained in:
parent
5600e6fc4b
commit
3cbf7cb3e6
23
.github/actions/run-in-docker-action/action.yml
vendored
23
.github/actions/run-in-docker-action/action.yml
vendored
@ -4,37 +4,35 @@ inputs:
|
||||
dockerfile:
|
||||
description: 'A Dockerfile that defines an image'
|
||||
required: true
|
||||
tag:
|
||||
description: 'A tag of an image'
|
||||
required: true
|
||||
scope:
|
||||
description: 'A cached image scope'
|
||||
required: false
|
||||
default: ${{ runner.arch }}
|
||||
command:
|
||||
description: 'A command to run in a container'
|
||||
required: false
|
||||
default: ./ci/ci.sh
|
||||
required: true
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
- uses: docker/build-push-action@v5
|
||||
- uses: docker/build-push-action@v6
|
||||
id: main_builder
|
||||
continue-on-error: true
|
||||
with:
|
||||
context: .
|
||||
file: ${{ inputs.dockerfile }}
|
||||
tags: ${{ inputs.tag }}
|
||||
load: true
|
||||
cache-from: type=gha
|
||||
cache-from: type=gha,scope=${{ inputs.scope }}
|
||||
|
||||
- uses: docker/build-push-action@v5
|
||||
- uses: docker/build-push-action@v6
|
||||
id: retry_builder
|
||||
if: steps.main_builder.outcome == 'failure'
|
||||
with:
|
||||
context: .
|
||||
file: ${{ inputs.dockerfile }}
|
||||
tags: ${{ inputs.tag }}
|
||||
load: true
|
||||
cache-from: type=gha
|
||||
cache-from: type=gha,scope=${{ inputs.scope }}
|
||||
|
||||
- # Workaround for https://github.com/google/sanitizers/issues/1614 .
|
||||
# The underlying issue has been fixed in clang 18.1.3.
|
||||
@ -47,7 +45,8 @@ runs:
|
||||
$(echo '${{ toJSON(env) }}' | jq -r 'keys[] | "--env \(.) "') \
|
||||
--volume ${{ github.workspace }}:${{ github.workspace }} \
|
||||
--workdir ${{ github.workspace }} \
|
||||
${{ inputs.tag }} bash -c "
|
||||
$(docker images -q | head -n1) \
|
||||
bash -c "
|
||||
git config --global --add safe.directory ${{ github.workspace }}
|
||||
${{ inputs.command }}
|
||||
"
|
||||
|
||||
276
.github/workflows/ci.yml
vendored
276
.github/workflows/ci.yml
vendored
@ -67,12 +67,11 @@ jobs:
|
||||
network=host
|
||||
|
||||
- name: Build container
|
||||
uses: docker/build-push-action@v5
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
file: ./ci/linux-debian.Dockerfile
|
||||
tags: ${{ matrix.arch }}-debian-image
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=min
|
||||
cache-from: type=gha,scope=${{ runner.arch }}
|
||||
cache-to: type=gha,scope=${{ runner.arch }},mode=min
|
||||
|
||||
x86_64-debian:
|
||||
name: "x86_64: Linux (Debian stable)"
|
||||
@ -108,17 +107,20 @@ jobs:
|
||||
CC: ${{ matrix.cc }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- &CHECKOUT
|
||||
name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: CI script
|
||||
- &CI_SCRIPT_IN_DOCKER
|
||||
name: CI script
|
||||
env: ${{ matrix.configuration.env_vars }}
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: x64-debian-image
|
||||
command: ./ci/ci.sh
|
||||
|
||||
- name: Print logs
|
||||
- &PRINT_LOGS
|
||||
name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
@ -130,6 +132,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars: {}
|
||||
cc:
|
||||
- 'i686-linux-gnu-gcc'
|
||||
- 'clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include'
|
||||
@ -145,24 +149,20 @@ jobs:
|
||||
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: x64-debian-image
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
- *CHECKOUT
|
||||
- *CI_SCRIPT_IN_DOCKER
|
||||
- *PRINT_LOGS
|
||||
|
||||
s390x_debian:
|
||||
name: "s390x (big-endian): Linux (Debian stable, QEMU)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars: {}
|
||||
|
||||
env:
|
||||
WRAPPER_CMD: 'qemu-s390x'
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
@ -177,19 +177,9 @@ jobs:
|
||||
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: x64-debian-image
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- *CHECKOUT
|
||||
- *CI_SCRIPT_IN_DOCKER
|
||||
- *PRINT_LOGS
|
||||
|
||||
arm32_debian:
|
||||
name: "ARM32: Linux (Debian stable, QEMU)"
|
||||
@ -217,19 +207,9 @@ jobs:
|
||||
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: x64-debian-image
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
- *CHECKOUT
|
||||
- *CI_SCRIPT_IN_DOCKER
|
||||
- *PRINT_LOGS
|
||||
|
||||
arm64-debian:
|
||||
name: "arm64: Linux (Debian stable)"
|
||||
@ -251,6 +231,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars: {}
|
||||
cc:
|
||||
- 'gcc'
|
||||
- 'clang'
|
||||
@ -258,24 +240,20 @@ jobs:
|
||||
- 'clang-snapshot'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: arm64-debian-image
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
- *CHECKOUT
|
||||
- *CI_SCRIPT_IN_DOCKER
|
||||
- *PRINT_LOGS
|
||||
|
||||
ppc64le_debian:
|
||||
name: "ppc64le: Linux (Debian stable, QEMU)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars: {}
|
||||
|
||||
env:
|
||||
WRAPPER_CMD: 'qemu-ppc64le'
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
@ -290,51 +268,35 @@ jobs:
|
||||
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: x64-debian-image
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- *CHECKOUT
|
||||
- *CI_SCRIPT_IN_DOCKER
|
||||
- *PRINT_LOGS
|
||||
|
||||
valgrind_debian:
|
||||
name: "Valgrind ${{ matrix.binary_arch }} (memcheck)"
|
||||
runs-on: ${{ matrix.runner }}
|
||||
name: "Valgrind ${{ matrix.configuration.binary_arch }} (memcheck)"
|
||||
runs-on: ${{ matrix.configuration.runner }}
|
||||
needs: docker_cache
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- docker_arch: x64
|
||||
runner: ubuntu-latest
|
||||
configuration:
|
||||
- runner: ubuntu-latest
|
||||
binary_arch: x64
|
||||
env_vars: { CC: 'clang', ASM: 'auto' }
|
||||
- docker_arch: x64
|
||||
runner: ubuntu-latest
|
||||
- runner: ubuntu-latest
|
||||
binary_arch: i686
|
||||
env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' }
|
||||
- docker_arch: arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
- runner: ubuntu-24.04-arm
|
||||
binary_arch: arm64
|
||||
env_vars: { CC: 'clang', ASM: 'auto' }
|
||||
- docker_arch: x64
|
||||
runner: ubuntu-latest
|
||||
- runner: ubuntu-latest
|
||||
binary_arch: x64
|
||||
env_vars: { CC: 'clang', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
|
||||
- docker_arch: x64
|
||||
runner: ubuntu-latest
|
||||
- runner: ubuntu-latest
|
||||
binary_arch: i686
|
||||
env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
|
||||
- docker_arch: arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
- runner: ubuntu-24.04-arm
|
||||
binary_arch: arm64
|
||||
env_vars: { CC: 'clang', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
|
||||
|
||||
@ -352,19 +314,9 @@ jobs:
|
||||
SECP256K1_TEST_ITERS: 2
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
env: ${{ matrix.env_vars }}
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: ${{ matrix.docker_arch }}-debian-image
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
- *CHECKOUT
|
||||
- *CI_SCRIPT_IN_DOCKER
|
||||
- *PRINT_LOGS
|
||||
|
||||
sanitizers_debian:
|
||||
name: "UBSan, ASan, LSan"
|
||||
@ -396,19 +348,9 @@ jobs:
|
||||
SYMBOL_CHECK: '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: x64-debian-image
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
- *CHECKOUT
|
||||
- *CI_SCRIPT_IN_DOCKER
|
||||
- *PRINT_LOGS
|
||||
|
||||
msan_debian:
|
||||
name: "MSan"
|
||||
@ -432,6 +374,9 @@ jobs:
|
||||
# when ctime_tests when enabled.
|
||||
CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -fsanitize-memory-param-retval -g'
|
||||
CTIMETESTS: 'no'
|
||||
cc:
|
||||
- 'clang'
|
||||
- 'clang-snapshot'
|
||||
|
||||
env:
|
||||
ECDH: 'yes'
|
||||
@ -440,27 +385,16 @@ jobs:
|
||||
SCHNORRSIG: 'yes'
|
||||
MUSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
CC: 'clang'
|
||||
CC: ${{ matrix.cc }}
|
||||
SECP256K1_TEST_ITERS: 32
|
||||
ASM: 'no'
|
||||
WITH_VALGRIND: 'no'
|
||||
SYMBOL_CHECK: '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: x64-debian-image
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- *CHECKOUT
|
||||
- *CI_SCRIPT_IN_DOCKER
|
||||
- *PRINT_LOGS
|
||||
|
||||
mingw_debian:
|
||||
name: ${{ matrix.configuration.job_name }}
|
||||
@ -490,19 +424,9 @@ jobs:
|
||||
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: x64-debian-image
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
- *CHECKOUT
|
||||
- *CI_SCRIPT_IN_DOCKER
|
||||
- *PRINT_LOGS
|
||||
|
||||
x86_64-macos-native:
|
||||
name: "x86_64: macOS Ventura, Valgrind"
|
||||
@ -531,8 +455,7 @@ jobs:
|
||||
- BUILD: 'distcheck'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- *CHECKOUT
|
||||
|
||||
- name: Install Homebrew packages
|
||||
run: |
|
||||
@ -542,7 +465,8 @@ jobs:
|
||||
- name: Install and cache Valgrind
|
||||
uses: ./.github/actions/install-homebrew-valgrind
|
||||
|
||||
- name: CI script
|
||||
- &CI_SCRIPT_ON_HOST
|
||||
name: CI script
|
||||
env: ${{ matrix.env_vars }}
|
||||
run: ./ci/ci.sh
|
||||
|
||||
@ -552,9 +476,7 @@ jobs:
|
||||
python3 -m pip install lief
|
||||
python3 ./tools/symbol-check.py .libs/libsecp256k1.dylib
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
- *PRINT_LOGS
|
||||
|
||||
arm64-macos-native:
|
||||
name: "ARM64: macOS Sonoma"
|
||||
@ -583,17 +505,14 @@ jobs:
|
||||
- BUILD: 'distcheck'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- *CHECKOUT
|
||||
|
||||
- name: Install Homebrew packages
|
||||
run: |
|
||||
brew install --quiet automake libtool gcc
|
||||
ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc
|
||||
|
||||
- name: CI script
|
||||
env: ${{ matrix.env_vars }}
|
||||
run: ./ci/ci.sh
|
||||
- *CI_SCRIPT_ON_HOST
|
||||
|
||||
- name: Symbol check
|
||||
env:
|
||||
@ -605,10 +524,7 @@ jobs:
|
||||
python3 -m pip install lief
|
||||
python3 ./tools/symbol-check.py .libs/libsecp256k1.dylib
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
|
||||
- *PRINT_LOGS
|
||||
|
||||
win64-native:
|
||||
name: ${{ matrix.configuration.job_name }}
|
||||
@ -631,12 +547,19 @@ jobs:
|
||||
cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE'
|
||||
- job_name: 'x86 (MSVC): Windows (VS 2022)'
|
||||
cmake_options: '-A Win32'
|
||||
- job_name: 'x64 (MSVC): Windows (clang-cl)'
|
||||
cmake_options: '-T ClangCL'
|
||||
- job_name: 'x64 (clang-cl): Windows (VS 2022, shared)'
|
||||
cmake_options: '-T ClangCL -DBUILD_SHARED_LIBS=ON'
|
||||
symbol_check: 'true'
|
||||
- job_name: 'x64 (clang-cl): Windows (VS 2022, static)'
|
||||
cmake_options: '-T ClangCL -DBUILD_SHARED_LIBS=OFF'
|
||||
- job_name: 'x64 (clang-cl): Windows (VS 2022, int128_struct)'
|
||||
cmake_options: '-T ClangCL -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct'
|
||||
- job_name: 'x64 (clang-cl): Windows (VS 2022, int128_struct with __(u)mulh)'
|
||||
cmake_options: '-T ClangCL -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct'
|
||||
cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- *CHECKOUT
|
||||
|
||||
- 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 }}
|
||||
@ -671,8 +594,7 @@ jobs:
|
||||
runs-on: windows-2022
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- *CHECKOUT
|
||||
|
||||
- name: Add cl.exe to PATH
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
@ -686,6 +608,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars: {}
|
||||
|
||||
env:
|
||||
CC: 'g++'
|
||||
CFLAGS: '-fpermissive -g'
|
||||
@ -699,18 +626,9 @@ jobs:
|
||||
ELLSWIFT: 'yes'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: x64-debian-image
|
||||
|
||||
- name: Print logs
|
||||
uses: ./.github/actions/print-logs
|
||||
if: ${{ !cancelled() }}
|
||||
- *CHECKOUT
|
||||
- *CI_SCRIPT_IN_DOCKER
|
||||
- *PRINT_LOGS
|
||||
|
||||
cxx_headers_debian:
|
||||
name: "C++ (public headers)"
|
||||
@ -718,14 +636,12 @@ jobs:
|
||||
needs: docker_cache
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- *CHECKOUT
|
||||
|
||||
- name: CI script
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: x64-debian-image
|
||||
command: |
|
||||
g++ -Werror include/*.h
|
||||
clang -Werror -x c++-header include/*.h
|
||||
@ -738,8 +654,7 @@ jobs:
|
||||
options: --user root
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- *CHECKOUT
|
||||
|
||||
- name: CI script
|
||||
run: |
|
||||
@ -750,8 +665,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- *CHECKOUT
|
||||
|
||||
- run: ./autogen.sh && ./configure --enable-dev-mode && make distcheck
|
||||
|
||||
|
||||
@ -34,10 +34,8 @@ set(CMAKE_C_EXTENSIONS OFF)
|
||||
#=============================
|
||||
# Configurable options
|
||||
#=============================
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries." ON)
|
||||
option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF)
|
||||
if(SECP256K1_DISABLE_SHARED)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
if(libsecp256k1_IS_TOP_LEVEL)
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries." ON)
|
||||
endif()
|
||||
|
||||
option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL})
|
||||
|
||||
@ -92,12 +92,14 @@ Run the tests:
|
||||
|
||||
To create a report, `gcovr` is recommended, as it includes branch coverage reporting:
|
||||
|
||||
$ gcovr --exclude 'src/bench*' --print-summary
|
||||
$ gcovr --gcov-ignore-parse-errors=all --merge-mode-functions=separate --exclude 'src/bench*' --exclude 'src/modules/.*/bench_impl.h' --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
|
||||
$ gcovr --gcov-ignore-parse-errors=all --merge-mode-functions=separate --exclude 'src/bench*' --exclude 'src/modules/.*/bench_impl.h' --html --html-details -o coverage/coverage.html
|
||||
|
||||
On `gcovr` >=8.3, `--gcov-ignore-parse-errors=all` can be replaced with `--gcov-suspicious-hits-threshold=140737488355330`.
|
||||
|
||||
#### Exhaustive tests
|
||||
|
||||
|
||||
@ -45,7 +45,10 @@ 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/tests_common.h
|
||||
noinst_HEADERS += src/testutil.h
|
||||
noinst_HEADERS += src/unit_test.h
|
||||
noinst_HEADERS += src/unit_test.c
|
||||
noinst_HEADERS += src/util.h
|
||||
noinst_HEADERS += src/util_local_visibility.h
|
||||
noinst_HEADERS += src/int128.h
|
||||
@ -120,7 +123,7 @@ if USE_TESTS
|
||||
TESTS += noverify_tests
|
||||
noinst_PROGRAMS += noverify_tests
|
||||
noverify_tests_SOURCES = src/tests.c
|
||||
noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES) $(TEST_DEFINES)
|
||||
noverify_tests_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
|
||||
noverify_tests_LDFLAGS = -static
|
||||
if !ENABLE_COVERAGE
|
||||
|
||||
@ -135,13 +135,11 @@ To cross compile for Android with [NDK](https://developer.android.com/ndk/guides
|
||||
|
||||
### 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+.
|
||||
The following example assumes Visual Studio 2022. Using clang-cl is recommended.
|
||||
|
||||
In "Developer Command Prompt for VS 2022":
|
||||
|
||||
>cmake -G "Visual Studio 17 2022" -A x64 -B build
|
||||
>cmake -B build -T ClangCL
|
||||
>cmake --build build --config RelWithDebInfo
|
||||
|
||||
Usage examples
|
||||
|
||||
@ -3,7 +3,7 @@ AC_DEFUN([SECP_X86_64_ASM_CHECK],[
|
||||
AC_MSG_CHECKING(for x86_64 assembly availability)
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <stdint.h>]],[[
|
||||
uint64_t a = 11, tmp;
|
||||
uint64_t a = 11, tmp = 0;
|
||||
__asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
|
||||
]])], [has_x86_64_asm=yes], [has_x86_64_asm=no])
|
||||
AC_MSG_RESULT([$has_x86_64_asm])
|
||||
|
||||
@ -19,9 +19,9 @@ RUN dpkg --add-architecture i386 && \
|
||||
dpkg --add-architecture arm64 && \
|
||||
dpkg --add-architecture ppc64el
|
||||
|
||||
# dkpg-dev: to make pkg-config work in cross-builds
|
||||
# dpkg-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 \
|
||||
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
||||
git ca-certificates \
|
||||
make automake libtool pkg-config dpkg-dev valgrind qemu-user \
|
||||
gcc clang llvm libclang-rt-dev libc6-dbg \
|
||||
@ -34,14 +34,15 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
gcc-mingw-w64-i686-win32 wine32 \
|
||||
python3-full && \
|
||||
if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \
|
||||
apt-get install --no-install-recommends -y \
|
||||
DEBIAN_FRONTEND=noninteractive 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=16
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \
|
||||
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
|
||||
wget libgmp-dev libmpfr-dev libmpc-dev flex && \
|
||||
mkdir gcc && cd gcc && \
|
||||
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" && \
|
||||
@ -62,7 +63,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev
|
||||
# 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 && \
|
||||
apt-get update && DEBIAN_FRONTEND=noninteractive 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 && \
|
||||
@ -70,7 +71,7 @@ RUN \
|
||||
# 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}" && \
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y "clang-${LLVM_VERSION}" "libclang-rt-${LLVM_VERSION}-dev" && \
|
||||
# Create symlink
|
||||
ln -s "/usr/bin/clang-${LLVM_VERSION}" /usr/bin/clang-snapshot && \
|
||||
# Clean up
|
||||
|
||||
@ -4,10 +4,11 @@ function(check_x86_64_assembly)
|
||||
check_c_source_compiles("
|
||||
#include <stdint.h>
|
||||
|
||||
int main()
|
||||
int main(void)
|
||||
{
|
||||
uint64_t a = 11, tmp;
|
||||
uint64_t a = 11, tmp = 0;
|
||||
__asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\");
|
||||
return 0;
|
||||
}
|
||||
" HAVE_X86_64_ASM)
|
||||
set(HAVE_X86_64_ASM ${HAVE_X86_64_ASM} PARENT_SCOPE)
|
||||
|
||||
10
configure.ac
10
configure.ac
@ -144,7 +144,7 @@ AC_ARG_ENABLE(benchmark,
|
||||
[SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(coverage,
|
||||
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [],
|
||||
AS_HELP_STRING([--enable-coverage],[enable coverage analysis support [default=no]]), [],
|
||||
[SECP_SET_DEFAULT([enable_coverage], [no], [no])])
|
||||
|
||||
AC_ARG_ENABLE(tests,
|
||||
@ -443,6 +443,14 @@ if test x"$enable_experimental" = x"no"; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for concurrency support (tests only)
|
||||
if test "x$enable_tests" != x"no"; then
|
||||
AC_CHECK_HEADERS([sys/types.h sys/wait.h unistd.h])
|
||||
AS_IF([test "x$ac_cv_header_sys_types_h" = xyes && test "x$ac_cv_header_sys_wait_h" = xyes &&
|
||||
test "x$ac_cv_header_unistd_h" = xyes], [TEST_DEFINES="-DSUPPORTS_CONCURRENCY=1"], TEST_DEFINES="")
|
||||
AC_SUBST(TEST_DEFINES)
|
||||
fi
|
||||
|
||||
###
|
||||
### Generate output
|
||||
###
|
||||
|
||||
@ -261,7 +261,7 @@ SECP256K1_DEPRECATED("Use secp256k1_context_static instead");
|
||||
* secp256k1_context_create (or secp256k1_context_preallocated_create), which will
|
||||
* take care of performing the self tests.
|
||||
*
|
||||
* If the tests fail, this function will call the default error handler to abort the
|
||||
* If the tests fail, this function will call the default error callback to abort the
|
||||
* program (see secp256k1_context_set_error_callback).
|
||||
*/
|
||||
SECP256K1_API void secp256k1_selftest(void);
|
||||
@ -334,36 +334,37 @@ SECP256K1_API void secp256k1_context_destroy(
|
||||
* an API call. It will only trigger for violations that are mentioned
|
||||
* explicitly in the header.
|
||||
*
|
||||
* The philosophy is that these shouldn't be dealt with through a
|
||||
* specific return value, as calling code should not have branches to deal with
|
||||
* the case that this code itself is broken.
|
||||
* The philosophy is that these shouldn't be dealt with through a specific
|
||||
* return value, as calling code should not have branches to deal with the case
|
||||
* that this code itself is broken.
|
||||
*
|
||||
* On the other hand, during debug stage, one would want to be informed about
|
||||
* such mistakes, and the default (crashing) may be inadvisable.
|
||||
* When this callback is triggered, the API function called is guaranteed not
|
||||
* to cause a crash, though its return value and output arguments are
|
||||
* undefined.
|
||||
* such mistakes, and the default (crashing) may be inadvisable. Should this
|
||||
* callback return instead of crashing, the return value and output arguments
|
||||
* of the API function call are undefined. Moreover, the same API call may
|
||||
* trigger the callback again in this case.
|
||||
*
|
||||
* When this function has not been called (or called with fn==NULL), then the
|
||||
* default handler will be used. The library provides a default handler which
|
||||
* writes the message to stderr and calls abort. This default handler can be
|
||||
* When this function has not been called (or called with fun==NULL), then the
|
||||
* default callback will be used. The library provides a default callback which
|
||||
* writes the message to stderr and calls abort. This default callback can be
|
||||
* replaced at link time if the preprocessor macro
|
||||
* USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build
|
||||
* has been configured with --enable-external-default-callbacks. Then the
|
||||
* following two symbols must be provided to link against:
|
||||
* - void secp256k1_default_illegal_callback_fn(const char *message, void *data);
|
||||
* - void secp256k1_default_error_callback_fn(const char *message, void *data);
|
||||
* The library can call these default handlers even before a proper callback data
|
||||
* The library may call a default callback even before a proper callback data
|
||||
* pointer could have been set using secp256k1_context_set_illegal_callback or
|
||||
* secp256k1_context_set_error_callback, e.g., when the creation of a context
|
||||
* fails. In this case, the corresponding default handler will be called with
|
||||
* fails. In this case, the corresponding default callback will be called with
|
||||
* the data pointer argument set to NULL.
|
||||
*
|
||||
* 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.
|
||||
* (NULL restores the default callback.)
|
||||
* data: the opaque pointer to pass to fun above, must be NULL for the
|
||||
* default callback.
|
||||
*
|
||||
* See also secp256k1_context_set_error_callback.
|
||||
*/
|
||||
@ -380,8 +381,8 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
|
||||
* to abort the program.
|
||||
*
|
||||
* This can only trigger in case of a hardware failure, miscompilation,
|
||||
* memory corruption, serious bug in the library, or other error would can
|
||||
* otherwise result in undefined behaviour. It will not trigger due to mere
|
||||
* memory corruption, serious bug in the library, or other error that would
|
||||
* result in undefined behaviour. It will not trigger due to mere
|
||||
* incorrect usage of the API (see secp256k1_context_set_illegal_callback
|
||||
* for that). After this callback returns, anything may happen, including
|
||||
* crashing.
|
||||
@ -389,9 +390,10 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
|
||||
* 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
|
||||
* default callback, see secp256k1_context_set_illegal_callback
|
||||
* for details).
|
||||
* data: the opaque pointer to pass to fun above, must be NULL for the default handler.
|
||||
* data: the opaque pointer to pass to fun above, must be NULL for the
|
||||
* default callback.
|
||||
*
|
||||
* See also secp256k1_context_set_illegal_callback.
|
||||
*/
|
||||
|
||||
@ -130,7 +130,7 @@ SECP256K1_API int secp256k1_ellswift_decode(
|
||||
*
|
||||
* Returns: 1: secret was valid, public key was stored.
|
||||
* 0: secret was invalid, try again.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Args: ctx: pointer to a context object (not secp256k1_context_static)
|
||||
* Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift
|
||||
* public key
|
||||
* In: seckey32: pointer to a 32-byte secret key
|
||||
|
||||
@ -92,7 +92,17 @@ SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
|
||||
|
||||
/** Recover an ECDSA public key from a signature.
|
||||
*
|
||||
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
|
||||
* Successful public key recovery guarantees that the signature, after normalization,
|
||||
* passes `secp256k1_ecdsa_verify`. Thus, explicit verification is not necessary.
|
||||
*
|
||||
* However, a recoverable signature that successfully passes `secp256k1_ecdsa_recover`,
|
||||
* when converted to a non-recoverable signature (using
|
||||
* `secp256k1_ecdsa_recoverable_signature_convert`), is not guaranteed to be
|
||||
* normalized and thus not guaranteed to pass `secp256k1_ecdsa_verify`. If a
|
||||
* normalized signature is required, call `secp256k1_ecdsa_signature_normalize`
|
||||
* after `secp256k1_ecdsa_recoverable_signature_convert`.
|
||||
*
|
||||
* Returns: 1: public key successfully recovered
|
||||
* 0: otherwise.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to the recovered public key.
|
||||
|
||||
@ -134,15 +134,27 @@ if(SECP256K1_BUILD_BENCHMARK)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_BUILD_TESTS)
|
||||
include(CheckIncludeFile)
|
||||
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
|
||||
check_include_file(sys/wait.h HAVE_SYS_WAIT_H)
|
||||
check_include_file(unistd.h HAVE_UNISTD_H)
|
||||
|
||||
set(TEST_DEFINITIONS "")
|
||||
if(HAVE_SYS_TYPES_H AND HAVE_SYS_WAIT_H AND HAVE_UNISTD_H)
|
||||
list(APPEND TEST_DEFINITIONS SUPPORTS_CONCURRENCY=1)
|
||||
endif()
|
||||
|
||||
add_executable(noverify_tests tests.c)
|
||||
target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm)
|
||||
target_compile_definitions(noverify_tests PRIVATE ${TEST_DEFINITIONS})
|
||||
add_test(NAME secp256k1_noverify_tests COMMAND noverify_tests)
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
|
||||
add_executable(tests tests.c)
|
||||
target_compile_definitions(tests PRIVATE VERIFY)
|
||||
target_compile_definitions(tests PRIVATE VERIFY ${TEST_DEFINITIONS})
|
||||
target_link_libraries(tests secp256k1_precomputed secp256k1_asm)
|
||||
add_test(NAME secp256k1_tests COMMAND tests)
|
||||
endif()
|
||||
unset(TEST_DEFINITIONS)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
|
||||
|
||||
22
src/bench.h
22
src/bench.h
@ -12,27 +12,7 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
# include <time.h>
|
||||
#else
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static int64_t gettime_i64(void) {
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
/* C11 way to get wallclock time */
|
||||
struct timespec tv;
|
||||
if (!timespec_get(&tv, TIME_UTC)) {
|
||||
fputs("timespec_get failed!", stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
|
||||
#endif
|
||||
}
|
||||
#include "tests_common.h"
|
||||
|
||||
#define FP_EXP (6)
|
||||
#define FP_MULT (1000000LL)
|
||||
|
||||
@ -48,7 +48,17 @@
|
||||
# if __has_feature(memory_sanitizer)
|
||||
# include <sanitizer/msan_interface.h>
|
||||
# define SECP256K1_CHECKMEM_ENABLED 1
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len))
|
||||
# if defined(__clang__) && ((__clang_major__ == 21 && __clang_minor__ >= 1) || __clang_major__ >= 22)
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) do { \
|
||||
/* Work around https://github.com/llvm/llvm-project/issues/160094 */ \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wuninitialized-const-pointer\"") \
|
||||
__msan_allocated_memory((p), (len)); \
|
||||
_Pragma("clang diagnostic pop") \
|
||||
} while(0)
|
||||
# else
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len))
|
||||
# endif
|
||||
# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len))
|
||||
# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) __msan_unpoison((p), (len))
|
||||
# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len))
|
||||
|
||||
@ -213,7 +213,7 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
|
||||
* but this would simply discard the bits that fall off at the bottom,
|
||||
* and thus, for example, bitdata could still have only two values if we
|
||||
* happen to shift by exactly 31 positions. We use a rotation instead,
|
||||
* which ensures that bitdata doesn't loose entropy. This relies on the
|
||||
* which ensures that bitdata doesn't lose entropy. This relies on the
|
||||
* rotation being atomic, i.e., the compiler emitting an actual rot
|
||||
* instruction. */
|
||||
uint32_t bitdata = secp256k1_rotr32(recoded[bit_pos >> 5], bit_pos & 0x1f);
|
||||
@ -242,7 +242,7 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
|
||||
* (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and
|
||||
* "Cache Attacks and Countermeasures: the Case of AES", RSA 2006,
|
||||
* by Dag Arne Osvik, Adi Shamir, and Eran Tromer
|
||||
* (https://www.tau.ac.il/~tromer/papers/cache.pdf)
|
||||
* (https://eprint.iacr.org/2005/271.pdf)
|
||||
*/
|
||||
for (index = 0; index < COMB_POINTS; ++index) {
|
||||
secp256k1_ge_storage_cmov(&adds, &secp256k1_ecmult_gen_prec_table[block][index], index == abs);
|
||||
@ -277,8 +277,8 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
|
||||
/* Cleanup. */
|
||||
secp256k1_fe_clear(&neg);
|
||||
secp256k1_ge_clear(&add);
|
||||
secp256k1_memclear(&adds, sizeof(adds));
|
||||
secp256k1_memclear(&recoded, sizeof(recoded));
|
||||
secp256k1_memclear_explicit(&adds, sizeof(adds));
|
||||
secp256k1_memclear_explicit(&recoded, sizeof(recoded));
|
||||
}
|
||||
|
||||
/* Setup blinding values for secp256k1_ecmult_gen. */
|
||||
@ -310,7 +310,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
|
||||
VERIFY_CHECK(seed32 != NULL);
|
||||
memcpy(keydata + 32, seed32, 32);
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
|
||||
secp256k1_memclear(keydata, sizeof(keydata));
|
||||
secp256k1_memclear_explicit(keydata, sizeof(keydata));
|
||||
|
||||
/* Compute projective blinding factor (cannot be 0). */
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
@ -331,7 +331,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
|
||||
secp256k1_ge_set_gej(&ctx->ge_offset, &gb);
|
||||
|
||||
/* Clean up. */
|
||||
secp256k1_memclear(nonce32, sizeof(nonce32));
|
||||
secp256k1_memclear_explicit(nonce32, sizeof(nonce32));
|
||||
secp256k1_scalar_clear(&b);
|
||||
secp256k1_gej_clear(&gb);
|
||||
secp256k1_fe_clear(&f);
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
|
||||
secp256k1_memclear(a, sizeof(secp256k1_fe));
|
||||
secp256k1_memclear_explicit(a, sizeof(secp256k1_fe));
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
|
||||
@ -337,11 +337,11 @@ static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
|
||||
}
|
||||
|
||||
static void secp256k1_gej_clear(secp256k1_gej *r) {
|
||||
secp256k1_memclear(r, sizeof(secp256k1_gej));
|
||||
secp256k1_memclear_explicit(r, sizeof(secp256k1_gej));
|
||||
}
|
||||
|
||||
static void secp256k1_ge_clear(secp256k1_ge *r) {
|
||||
secp256k1_memclear(r, sizeof(secp256k1_ge));
|
||||
secp256k1_memclear_explicit(r, sizeof(secp256k1_ge));
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
||||
|
||||
@ -172,7 +172,7 @@ static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const uns
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_clear(secp256k1_sha256 *hash) {
|
||||
secp256k1_memclear(hash, sizeof(*hash));
|
||||
secp256k1_memclear_explicit(hash, sizeof(*hash));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
|
||||
@ -200,7 +200,7 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const
|
||||
rkey[n] ^= 0x5c ^ 0x36;
|
||||
}
|
||||
secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey));
|
||||
secp256k1_memclear(rkey, sizeof(rkey));
|
||||
secp256k1_memclear_explicit(rkey, sizeof(rkey));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
|
||||
@ -211,12 +211,12 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned
|
||||
unsigned char temp[32];
|
||||
secp256k1_sha256_finalize(&hash->inner, temp);
|
||||
secp256k1_sha256_write(&hash->outer, temp, 32);
|
||||
secp256k1_memclear(temp, sizeof(temp));
|
||||
secp256k1_memclear_explicit(temp, sizeof(temp));
|
||||
secp256k1_sha256_finalize(&hash->outer, out32);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash) {
|
||||
secp256k1_memclear(hash, sizeof(*hash));
|
||||
secp256k1_memclear_explicit(hash, sizeof(*hash));
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
|
||||
@ -265,7 +265,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256
|
||||
|
||||
while (outlen > 0) {
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
int now = outlen;
|
||||
size_t now = outlen;
|
||||
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(&hmac, rng->v);
|
||||
@ -285,7 +285,7 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||
secp256k1_memclear(rng, sizeof(*rng));
|
||||
secp256k1_memclear_explicit(rng, sizeof(*rng));
|
||||
}
|
||||
|
||||
#undef Round
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
#include "../../../include/secp256k1_ecdh.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
const secp256k1_context *ctx;
|
||||
secp256k1_pubkey point;
|
||||
unsigned char scalar[32];
|
||||
} bench_ecdh_data;
|
||||
@ -46,12 +46,9 @@ static void run_ecdh_bench(int iters, int argc, char** argv) {
|
||||
bench_ecdh_data data;
|
||||
int d = argc == 1;
|
||||
|
||||
/* create a context with no capabilities */
|
||||
data.ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
|
||||
data.ctx = secp256k1_context_static;
|
||||
|
||||
if (d || have_flag(argc, argv, "ecdh")) run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_MODULE_ECDH_BENCH_H */
|
||||
|
||||
@ -62,8 +62,8 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
|
||||
|
||||
ret = hashfp(output, x, y, data);
|
||||
|
||||
secp256k1_memclear(x, sizeof(x));
|
||||
secp256k1_memclear(y, sizeof(y));
|
||||
secp256k1_memclear_explicit(x, sizeof(x));
|
||||
secp256k1_memclear_explicit(y, sizeof(y));
|
||||
secp256k1_scalar_clear(&s);
|
||||
secp256k1_ge_clear(&pt);
|
||||
secp256k1_gej_clear(&res);
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
#ifndef SECP256K1_MODULE_ECDH_TESTS_H
|
||||
#define SECP256K1_MODULE_ECDH_TESTS_H
|
||||
|
||||
#include "../../unit_test.h"
|
||||
|
||||
static int ecdh_hash_function_test_xpassthru(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||
(void)y;
|
||||
(void)data;
|
||||
@ -90,12 +92,7 @@ static void test_ecdh_generator_basepoint(void) {
|
||||
|
||||
static void test_bad_scalar(void) {
|
||||
unsigned char s_zero[32] = { 0 };
|
||||
unsigned char s_overflow[32] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
|
||||
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41
|
||||
};
|
||||
unsigned char s_overflow[32] = { 0 };
|
||||
unsigned char s_rand[32] = { 0 };
|
||||
unsigned char output[32];
|
||||
secp256k1_scalar rand;
|
||||
@ -107,6 +104,7 @@ static void test_bad_scalar(void) {
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1);
|
||||
|
||||
/* Try to multiply it by bad values */
|
||||
memcpy(s_overflow, secp256k1_group_order_bytes, 32);
|
||||
CHECK(secp256k1_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 0);
|
||||
/* ...and a good one */
|
||||
@ -182,12 +180,13 @@ static void test_ecdh_wycheproof(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void run_ecdh_tests(void) {
|
||||
test_ecdh_api();
|
||||
test_ecdh_generator_basepoint();
|
||||
test_bad_scalar();
|
||||
test_result_basepoint();
|
||||
test_ecdh_wycheproof();
|
||||
}
|
||||
/* --- Test registry --- */
|
||||
static const struct tf_test_entry tests_ecdh[] = {
|
||||
CASE1(test_ecdh_api),
|
||||
CASE1(test_ecdh_generator_basepoint),
|
||||
CASE1(test_bad_scalar),
|
||||
CASE1(test_result_basepoint),
|
||||
CASE1(test_ecdh_wycheproof),
|
||||
};
|
||||
|
||||
#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
|
||||
|
||||
@ -582,7 +582,7 @@ int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output,
|
||||
/* Invoke hasher */
|
||||
ret = hashfp(output, sx, ell_a64, ell_b64, data);
|
||||
|
||||
secp256k1_memclear(sx, sizeof(sx));
|
||||
secp256k1_memclear_explicit(sx, sizeof(sx));
|
||||
secp256k1_fe_clear(&px);
|
||||
secp256k1_scalar_clear(&s);
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
#define SECP256K1_MODULE_ELLSWIFT_TESTS_H
|
||||
|
||||
#include "../../../include/secp256k1_ellswift.h"
|
||||
#include "../../unit_test.h"
|
||||
|
||||
struct ellswift_xswiftec_inv_test {
|
||||
int enc_bitmap;
|
||||
@ -405,32 +406,38 @@ void run_ellswift_tests(void) {
|
||||
|
||||
/* Test hash initializers. */
|
||||
{
|
||||
secp256k1_sha256 sha, sha_optimized;
|
||||
secp256k1_sha256 sha_optimized;
|
||||
/* "secp256k1_ellswift_encode" */
|
||||
static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'};
|
||||
/* "secp256k1_ellswift_create" */
|
||||
static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'};
|
||||
/* "bip324_ellswift_xonly_ecdh" */
|
||||
static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'};
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_encode has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, encode_tag, sizeof(encode_tag));
|
||||
secp256k1_ellswift_sha256_init_encode(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
test_sha256_tag_midstate(&sha_optimized, encode_tag, sizeof(encode_tag));
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_create has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, create_tag, sizeof(create_tag));
|
||||
secp256k1_ellswift_sha256_init_create(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
test_sha256_tag_midstate(&sha_optimized, create_tag, sizeof(create_tag));
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_bip324 has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, bip324_tag, sizeof(bip324_tag));
|
||||
secp256k1_ellswift_sha256_init_bip324(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
test_sha256_tag_midstate(&sha_optimized, bip324_tag, sizeof(bip324_tag));
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Test registry --- */
|
||||
/* TODO: subdivide test in cases */
|
||||
static const struct tf_test_entry tests_ellswift[] = {
|
||||
CASE(ellswift_tests),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#define SECP256K1_MODULE_EXTRAKEYS_TESTS_H
|
||||
|
||||
#include "../../../include/secp256k1_extrakeys.h"
|
||||
#include "../../unit_test.h"
|
||||
|
||||
static void test_xonly_pubkey(void) {
|
||||
secp256k1_pubkey pk;
|
||||
@ -467,17 +468,17 @@ static void test_keypair_add(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void run_extrakeys_tests(void) {
|
||||
/* --- Test registry --- */
|
||||
static const struct tf_test_entry tests_extrakeys[] = {
|
||||
/* xonly key test cases */
|
||||
test_xonly_pubkey();
|
||||
test_xonly_pubkey_tweak();
|
||||
test_xonly_pubkey_tweak_check();
|
||||
test_xonly_pubkey_tweak_recursive();
|
||||
test_xonly_pubkey_comparison();
|
||||
|
||||
CASE1(test_xonly_pubkey),
|
||||
CASE1(test_xonly_pubkey_tweak),
|
||||
CASE1(test_xonly_pubkey_tweak_check),
|
||||
CASE1(test_xonly_pubkey_tweak_recursive),
|
||||
CASE1(test_xonly_pubkey_comparison),
|
||||
/* keypair tests */
|
||||
test_keypair();
|
||||
test_keypair_add();
|
||||
}
|
||||
CASE1(test_keypair),
|
||||
CASE1(test_keypair_add),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -385,10 +385,10 @@ static void secp256k1_nonce_function_musig(secp256k1_scalar *k, const unsigned c
|
||||
secp256k1_scalar_set_b32(&k[i], buf, NULL);
|
||||
|
||||
/* Attempt to erase secret data */
|
||||
secp256k1_memclear(buf, sizeof(buf));
|
||||
secp256k1_memclear_explicit(buf, sizeof(buf));
|
||||
secp256k1_sha256_clear(&sha_tmp);
|
||||
}
|
||||
secp256k1_memclear(rand, sizeof(rand));
|
||||
secp256k1_memclear_explicit(rand, sizeof(rand));
|
||||
secp256k1_sha256_clear(&sha);
|
||||
}
|
||||
|
||||
@ -518,7 +518,7 @@ int secp256k1_musig_nonce_gen_counter(const secp256k1_context* ctx, secp256k1_mu
|
||||
if (!secp256k1_musig_nonce_gen_internal(ctx, secnonce, pubnonce, buf, seckey, &pubkey, msg32, keyagg_cache, extra_input32)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_memclear(seckey, sizeof(seckey));
|
||||
secp256k1_memclear_explicit(seckey, sizeof(seckey));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -679,7 +679,7 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, secp256k1_musig_p
|
||||
ret = secp256k1_musig_secnonce_load(ctx, k, &pk, secnonce);
|
||||
/* Set nonce to zero to avoid nonce reuse. This will cause subsequent calls
|
||||
* of this function to fail */
|
||||
memset(secnonce, 0, sizeof(*secnonce));
|
||||
secp256k1_memzero_explicit(secnonce, sizeof(*secnonce));
|
||||
if (!ret) {
|
||||
secp256k1_musig_partial_sign_clear(&sk, k);
|
||||
return 0;
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include "../../group.h"
|
||||
#include "../../hash.h"
|
||||
#include "../../util.h"
|
||||
#include "../../unit_test.h"
|
||||
|
||||
#include "vectors.h"
|
||||
|
||||
@ -36,7 +37,7 @@ static int create_keypair_and_pk(secp256k1_keypair *keypair, secp256k1_pubkey *p
|
||||
|
||||
/* Just a simple (non-tweaked) 2-of-2 MuSig aggregate, sign, verify
|
||||
* test. */
|
||||
static void musig_simple_test(void) {
|
||||
static void musig_simple_test_internal(void) {
|
||||
unsigned char sk[2][32];
|
||||
secp256k1_keypair keypair[2];
|
||||
secp256k1_musig_pubnonce pubnonce[2];
|
||||
@ -548,40 +549,39 @@ static void musig_nonce_test(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void sha256_tag_test_internal(secp256k1_sha256 *sha_tagged, unsigned char *tag, size_t taglen) {
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256_initialize_tagged(&sha, tag, taglen);
|
||||
test_sha256_eq(&sha, sha_tagged);
|
||||
}
|
||||
|
||||
/* Checks that the initialized tagged hashes have the expected
|
||||
* state. */
|
||||
static void sha256_tag_test(void) {
|
||||
secp256k1_sha256 sha;
|
||||
{
|
||||
char tag[] = "KeyAgg list";
|
||||
/* "KeyAgg list" */
|
||||
static const unsigned char tag[] = {'K', 'e', 'y', 'A', 'g', 'g', ' ', 'l', 'i', 's', 't'};
|
||||
secp256k1_musig_keyagglist_sha256(&sha);
|
||||
sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1);
|
||||
test_sha256_tag_midstate(&sha, tag, sizeof(tag));
|
||||
}
|
||||
{
|
||||
char tag[] = "KeyAgg coefficient";
|
||||
/* "KeyAgg coefficient" */
|
||||
static const unsigned char tag[] = {'K', 'e', 'y', 'A', 'g', 'g', ' ', 'c', 'o', 'e', 'f', 'f', 'i', 'c', 'i', 'e', 'n', 't'};
|
||||
secp256k1_musig_keyaggcoef_sha256(&sha);
|
||||
sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1);
|
||||
test_sha256_tag_midstate(&sha, tag, sizeof(tag));
|
||||
}
|
||||
{
|
||||
unsigned char tag[] = "MuSig/aux";
|
||||
/* "MuSig/aux" */
|
||||
static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'a', 'u', 'x' };
|
||||
secp256k1_nonce_function_musig_sha256_tagged_aux(&sha);
|
||||
sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1);
|
||||
test_sha256_tag_midstate(&sha, tag, sizeof(tag));
|
||||
}
|
||||
{
|
||||
unsigned char tag[] = "MuSig/nonce";
|
||||
/* "MuSig/nonce" */
|
||||
static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'n', 'o', 'n', 'c', 'e' };
|
||||
secp256k1_nonce_function_musig_sha256_tagged(&sha);
|
||||
sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1);
|
||||
test_sha256_tag_midstate(&sha, tag, sizeof(tag));
|
||||
}
|
||||
{
|
||||
unsigned char tag[] = "MuSig/noncecoef";
|
||||
/* "MuSig/noncecoef" */
|
||||
static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'n', 'o', 'n', 'c', 'e', 'c', 'o', 'e', 'f' };
|
||||
secp256k1_musig_compute_noncehash_sha256_tagged(&sha);
|
||||
sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1);
|
||||
test_sha256_tag_midstate(&sha, tag, sizeof(tag));
|
||||
}
|
||||
}
|
||||
|
||||
@ -630,7 +630,7 @@ static void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const
|
||||
|
||||
/* Create aggregate public key P[0], tweak multiple times (using xonly and
|
||||
* plain tweaking) and test signing. */
|
||||
static void musig_tweak_test(void) {
|
||||
static void musig_tweak_test_internal(void) {
|
||||
unsigned char sk[2][32];
|
||||
secp256k1_pubkey pk[2];
|
||||
const secp256k1_pubkey *pk_ptr[2];
|
||||
@ -1115,28 +1115,24 @@ static void musig_test_static_nonce_gen_counter(void) {
|
||||
CHECK(secp256k1_memcmp_var(pubnonce66, expected_pubnonce, sizeof(pubnonce66)) == 0);
|
||||
}
|
||||
|
||||
static void run_musig_tests(void) {
|
||||
int i;
|
||||
/* --- Test registry --- */
|
||||
REPEAT_TEST(musig_simple_test)
|
||||
/* Run multiple times to ensure that pk and nonce have different y parities */
|
||||
REPEAT_TEST(musig_tweak_test)
|
||||
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
musig_simple_test();
|
||||
}
|
||||
musig_api_tests();
|
||||
musig_nonce_test();
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
/* Run multiple times to ensure that pk and nonce have different y
|
||||
* parities */
|
||||
musig_tweak_test();
|
||||
}
|
||||
sha256_tag_test();
|
||||
musig_test_vectors_keyagg();
|
||||
musig_test_vectors_noncegen();
|
||||
musig_test_vectors_nonceagg();
|
||||
musig_test_vectors_signverify();
|
||||
musig_test_vectors_tweak();
|
||||
musig_test_vectors_sigagg();
|
||||
|
||||
musig_test_static_nonce_gen_counter();
|
||||
}
|
||||
static const struct tf_test_entry tests_musig[] = {
|
||||
CASE1(musig_simple_test),
|
||||
CASE1(musig_api_tests),
|
||||
CASE1(musig_nonce_test),
|
||||
CASE1(musig_tweak_test),
|
||||
CASE1(sha256_tag_test),
|
||||
CASE1(musig_test_vectors_keyagg),
|
||||
CASE1(musig_test_vectors_noncegen),
|
||||
CASE1(musig_test_vectors_nonceagg),
|
||||
CASE1(musig_test_vectors_signverify),
|
||||
CASE1(musig_test_vectors_tweak),
|
||||
CASE1(musig_test_vectors_sigagg),
|
||||
CASE1(musig_test_static_nonce_gen_counter),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H
|
||||
#define SECP256K1_MODULE_RECOVERY_TESTS_H
|
||||
|
||||
#include "../../unit_test.h"
|
||||
|
||||
static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
|
||||
(void) msg32;
|
||||
(void) key32;
|
||||
@ -28,7 +30,7 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c
|
||||
return testrand_bits(1);
|
||||
}
|
||||
|
||||
static void test_ecdsa_recovery_api(void) {
|
||||
static void test_ecdsa_recovery_api_internal(void) {
|
||||
/* Setup contexts that just count errors */
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_pubkey recpubkey;
|
||||
@ -92,7 +94,7 @@ static void test_ecdsa_recovery_api(void) {
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0);
|
||||
}
|
||||
|
||||
static void test_ecdsa_recovery_end_to_end(void) {
|
||||
static void test_ecdsa_recovery_end_to_end_internal(void) {
|
||||
unsigned char extra[32] = {0x00};
|
||||
unsigned char privkey[32];
|
||||
unsigned char message[32];
|
||||
@ -324,15 +326,14 @@ static void test_ecdsa_recovery_edge_cases(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void run_recovery_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
test_ecdsa_recovery_api();
|
||||
}
|
||||
for (i = 0; i < 64*COUNT; i++) {
|
||||
test_ecdsa_recovery_end_to_end();
|
||||
}
|
||||
test_ecdsa_recovery_edge_cases();
|
||||
}
|
||||
/* --- Test registry --- */
|
||||
REPEAT_TEST(test_ecdsa_recovery_api)
|
||||
REPEAT_TEST_MULT(test_ecdsa_recovery_end_to_end, 64)
|
||||
|
||||
static const struct tf_test_entry tests_recovery[] = {
|
||||
CASE1(test_ecdsa_recovery_api),
|
||||
CASE1(test_ecdsa_recovery_end_to_end),
|
||||
CASE1(test_ecdsa_recovery_edge_cases)
|
||||
};
|
||||
|
||||
#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */
|
||||
|
||||
@ -94,7 +94,7 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms
|
||||
secp256k1_sha256_write(&sha, msg, msglen);
|
||||
secp256k1_sha256_finalize(&sha, nonce32);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
secp256k1_memclear(masked_key, sizeof(masked_key));
|
||||
secp256k1_memclear_explicit(masked_key, sizeof(masked_key));
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -139,7 +139,7 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge pk;
|
||||
secp256k1_ge r;
|
||||
unsigned char buf[32] = { 0 };
|
||||
unsigned char nonce32[32] = { 0 };
|
||||
unsigned char pk_buf[32];
|
||||
unsigned char seckey[32];
|
||||
int ret = 1;
|
||||
@ -164,8 +164,8 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
|
||||
|
||||
secp256k1_scalar_get_b32(seckey, &sk);
|
||||
secp256k1_fe_get_b32(pk_buf, &pk.x);
|
||||
ret &= !!noncefp(buf, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata);
|
||||
secp256k1_scalar_set_b32(&k, buf, NULL);
|
||||
ret &= !!noncefp(nonce32, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata);
|
||||
secp256k1_scalar_set_b32(&k, nonce32, NULL);
|
||||
ret &= !secp256k1_scalar_is_zero(&k);
|
||||
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
|
||||
|
||||
@ -190,7 +190,8 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
|
||||
secp256k1_memczero(sig64, 64, !ret);
|
||||
secp256k1_scalar_clear(&k);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
secp256k1_memclear(seckey, sizeof(seckey));
|
||||
secp256k1_memclear_explicit(seckey, sizeof(seckey));
|
||||
secp256k1_memclear_explicit(nonce32, sizeof(nonce32));
|
||||
secp256k1_gej_clear(&rj);
|
||||
|
||||
return ret;
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#define SECP256K1_MODULE_SCHNORRSIG_TESTS_H
|
||||
|
||||
#include "../../../include/secp256k1_schnorrsig.h"
|
||||
#include "../../unit_test.h"
|
||||
|
||||
/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many
|
||||
* bytes) changes the hash function
|
||||
@ -21,11 +22,12 @@ static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, s
|
||||
}
|
||||
|
||||
static void run_nonce_function_bip340_tests(void) {
|
||||
unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'};
|
||||
unsigned char aux_tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'a', 'u', 'x'};
|
||||
/* "BIP0340/nonce" */
|
||||
static const unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'};
|
||||
/* "BIP0340/aux" */
|
||||
static const unsigned char aux_tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'a', 'u', 'x'};
|
||||
unsigned char algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'};
|
||||
size_t algolen = sizeof(algo);
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256 sha_optimized;
|
||||
unsigned char nonce[32], nonce_z[32];
|
||||
unsigned char msg[32];
|
||||
@ -39,16 +41,15 @@ static void run_nonce_function_bip340_tests(void) {
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_nonce_function_bip340_sha256_tagged has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, tag, sizeof(tag));
|
||||
secp256k1_nonce_function_bip340_sha256_tagged(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
test_sha256_tag_midstate(&sha_optimized, tag, sizeof(tag));
|
||||
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_nonce_function_bip340_sha256_tagged_aux has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag));
|
||||
secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
test_sha256_tag_midstate(&sha_optimized, aux_tag, sizeof(aux_tag));
|
||||
|
||||
testrand256(msg);
|
||||
testrand256(key);
|
||||
@ -802,7 +803,7 @@ static int nonce_function_overflowing(unsigned char *nonce32, const unsigned cha
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_schnorrsig_sign(void) {
|
||||
static void test_schnorrsig_sign_internal(void) {
|
||||
unsigned char sk[32];
|
||||
secp256k1_xonly_pubkey pk;
|
||||
secp256k1_keypair keypair;
|
||||
@ -852,7 +853,7 @@ static void test_schnorrsig_sign(void) {
|
||||
/* Creates N_SIGS valid signatures and verifies them with verify and
|
||||
* verify_batch (TODO). Then flips some bits and checks that verification now
|
||||
* fails. */
|
||||
static void test_schnorrsig_sign_verify(void) {
|
||||
static void test_schnorrsig_sign_verify_internal(void) {
|
||||
unsigned char sk[32];
|
||||
unsigned char msg[N_SIGS][32];
|
||||
unsigned char sig[N_SIGS][64];
|
||||
@ -965,18 +966,18 @@ static void test_schnorrsig_taproot(void) {
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1);
|
||||
}
|
||||
|
||||
static void run_schnorrsig_tests(void) {
|
||||
int i;
|
||||
run_nonce_function_bip340_tests();
|
||||
/* --- Test registry --- */
|
||||
REPEAT_TEST(test_schnorrsig_sign)
|
||||
REPEAT_TEST(test_schnorrsig_sign_verify)
|
||||
|
||||
test_schnorrsig_api();
|
||||
test_schnorrsig_sha256_tagged();
|
||||
test_schnorrsig_bip_vectors();
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
test_schnorrsig_sign();
|
||||
test_schnorrsig_sign_verify();
|
||||
}
|
||||
test_schnorrsig_taproot();
|
||||
}
|
||||
static const struct tf_test_entry tests_schnorrsig[] = {
|
||||
CASE(nonce_function_bip340_tests),
|
||||
CASE1(test_schnorrsig_api),
|
||||
CASE1(test_schnorrsig_sha256_tagged),
|
||||
CASE1(test_schnorrsig_bip_vectors),
|
||||
CASE1(test_schnorrsig_sign),
|
||||
CASE1(test_schnorrsig_sign_verify),
|
||||
CASE1(test_schnorrsig_taproot),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -28,7 +28,7 @@ static const secp256k1_scalar secp256k1_scalar_one = SECP256K1_SCALAR_CONST(0, 0
|
||||
static const secp256k1_scalar secp256k1_scalar_zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) {
|
||||
secp256k1_memclear(r, sizeof(secp256k1_scalar));
|
||||
secp256k1_memclear_explicit(r, sizeof(secp256k1_scalar));
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin) {
|
||||
|
||||
@ -499,7 +499,7 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
|
||||
}
|
||||
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||
|
||||
secp256k1_memclear(keydata, sizeof(keydata));
|
||||
secp256k1_memclear_explicit(keydata, sizeof(keydata));
|
||||
secp256k1_rfc6979_hmac_sha256_clear(&rng);
|
||||
return 1;
|
||||
}
|
||||
@ -550,7 +550,7 @@ static int secp256k1_ecdsa_sign_inner(const secp256k1_context* ctx, secp256k1_sc
|
||||
* seckey. As a result is_sec_valid is included in ret only after ret was
|
||||
* used as a branching variable. */
|
||||
ret &= is_sec_valid;
|
||||
secp256k1_memclear(nonce32, sizeof(nonce32));
|
||||
secp256k1_memclear_explicit(nonce32, sizeof(nonce32));
|
||||
secp256k1_scalar_clear(&msg);
|
||||
secp256k1_scalar_clear(&non);
|
||||
secp256k1_scalar_clear(&sec);
|
||||
|
||||
344
src/tests.c
344
src/tests.c
@ -25,6 +25,8 @@
|
||||
#include "checkmem.h"
|
||||
#include "testutil.h"
|
||||
#include "util.h"
|
||||
#include "unit_test.h"
|
||||
#include "unit_test.c"
|
||||
|
||||
#include "../contrib/lax_der_parsing.c"
|
||||
#include "../contrib/lax_der_privatekey_parsing.c"
|
||||
@ -37,7 +39,6 @@
|
||||
|
||||
#define CONDITIONAL_TEST(cnt, nam) if (COUNT < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else
|
||||
|
||||
static int COUNT = 16;
|
||||
static secp256k1_context *CTX = NULL;
|
||||
static secp256k1_context *STATIC_CTX = NULL;
|
||||
|
||||
@ -227,6 +228,12 @@ static void run_static_context_tests(int use_prealloc) {
|
||||
}
|
||||
}
|
||||
|
||||
static void run_all_static_context_tests(void)
|
||||
{
|
||||
run_static_context_tests(0);
|
||||
run_static_context_tests(1);
|
||||
}
|
||||
|
||||
static void run_proper_context_tests(int use_prealloc) {
|
||||
int32_t dummy = 0;
|
||||
secp256k1_context *my_ctx, *my_ctx_fresh;
|
||||
@ -349,6 +356,12 @@ static void run_proper_context_tests(int use_prealloc) {
|
||||
secp256k1_context_preallocated_destroy(NULL);
|
||||
}
|
||||
|
||||
static void run_all_proper_context_tests(void)
|
||||
{
|
||||
run_proper_context_tests(0);
|
||||
run_proper_context_tests(1);
|
||||
}
|
||||
|
||||
static void run_scratch_tests(void) {
|
||||
const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
|
||||
|
||||
@ -609,6 +622,13 @@ static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256
|
||||
CHECK(sha1->bytes == sha2->bytes);
|
||||
CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
|
||||
}
|
||||
/* Convenience function for using test_sha256_eq to verify the correctness of a
|
||||
* tagged hash midstate. This function is used by some module tests. */
|
||||
static void test_sha256_tag_midstate(secp256k1_sha256 *sha_tagged, const unsigned char *tag, size_t taglen) {
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256_initialize_tagged(&sha, tag, taglen);
|
||||
test_sha256_eq(&sha, sha_tagged);
|
||||
}
|
||||
|
||||
static void run_hmac_sha256_tests(void) {
|
||||
static const char *keys[6] = {
|
||||
@ -3904,7 +3924,7 @@ static void test_ge(void) {
|
||||
free(gej);
|
||||
}
|
||||
|
||||
static void test_intialized_inf(void) {
|
||||
static void test_initialized_inf(void) {
|
||||
secp256k1_ge p;
|
||||
secp256k1_gej pj, npj, infj1, infj2, infj3;
|
||||
secp256k1_fe zinv;
|
||||
@ -4030,7 +4050,7 @@ static void run_ge(void) {
|
||||
test_ge();
|
||||
}
|
||||
test_add_neg_y_diff_x();
|
||||
test_intialized_inf();
|
||||
test_initialized_inf();
|
||||
test_ge_bytes();
|
||||
}
|
||||
|
||||
@ -6029,12 +6049,7 @@ static void run_ec_pubkey_parse_test(void) {
|
||||
}
|
||||
|
||||
static void run_eckey_edge_case_test(void) {
|
||||
const unsigned char orderc[32] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
|
||||
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41
|
||||
};
|
||||
const unsigned char *orderc = secp256k1_group_order_bytes;
|
||||
const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00};
|
||||
unsigned char ctmp[33];
|
||||
unsigned char ctmp2[33];
|
||||
@ -6348,13 +6363,7 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char
|
||||
return 1;
|
||||
}
|
||||
if (counter < 5) {
|
||||
static const unsigned char order[] = {
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
|
||||
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
|
||||
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41
|
||||
};
|
||||
memcpy(nonce32, order, 32);
|
||||
memcpy(nonce32, secp256k1_group_order_bytes, 32);
|
||||
if (counter == 4) {
|
||||
nonce32[31]++;
|
||||
}
|
||||
@ -7372,12 +7381,7 @@ static void test_ecdsa_edge_cases(void) {
|
||||
/* Privkey export where pubkey is the point at infinity. */
|
||||
{
|
||||
unsigned char privkey[300];
|
||||
unsigned char seckey[32] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
|
||||
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
|
||||
};
|
||||
const unsigned char *seckey = secp256k1_group_order_bytes;
|
||||
size_t outlen = 300;
|
||||
CHECK(!ec_privkey_export_der(CTX, privkey, &outlen, seckey, 0));
|
||||
outlen = 300;
|
||||
@ -7659,38 +7663,137 @@ static void run_cmov_tests(void) {
|
||||
ge_storage_cmov_test();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
/* Disable buffering for stdout to improve reliability of getting
|
||||
* diagnostic information. Happens right at the start of main because
|
||||
* setbuf must be used before any other operation on the stream. */
|
||||
setbuf(stdout, NULL);
|
||||
/* Also disable buffering for stderr because it's not guaranteed that it's
|
||||
* unbuffered on all systems. */
|
||||
setbuf(stderr, NULL);
|
||||
/* --------------------------------------------------------- */
|
||||
/* Test Registry */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
/* find iteration count */
|
||||
if (argc > 1) {
|
||||
COUNT = strtol(argv[1], NULL, 0);
|
||||
} else {
|
||||
const char* env = getenv("SECP256K1_TEST_ITERS");
|
||||
if (env && strlen(env) > 0) {
|
||||
COUNT = strtol(env, NULL, 0);
|
||||
}
|
||||
}
|
||||
if (COUNT <= 0) {
|
||||
fputs("An iteration count of 0 or less is not allowed.\n", stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("test count = %i\n", COUNT);
|
||||
/* --- Special test cases that must run before RNG initialization --- */
|
||||
static const struct tf_test_entry tests_no_rng[] = {
|
||||
CASE(xoshiro256pp_tests),
|
||||
};
|
||||
static const struct tf_test_module registry_modules_no_rng = MAKE_TEST_MODULE(no_rng);
|
||||
|
||||
/* run test RNG tests (must run before we really initialize the test RNG) */
|
||||
run_xoshiro256pp_tests();
|
||||
/* --- Standard test cases start here --- */
|
||||
static const struct tf_test_entry tests_general[] = {
|
||||
CASE(selftest_tests),
|
||||
CASE(all_proper_context_tests),
|
||||
CASE(all_static_context_tests),
|
||||
CASE(deprecated_context_flags_test),
|
||||
CASE(scratch_tests),
|
||||
};
|
||||
|
||||
/* find random seed */
|
||||
testrand_init(argc > 2 ? argv[2] : NULL);
|
||||
static const struct tf_test_entry tests_integer[] = {
|
||||
#ifdef SECP256K1_WIDEMUL_INT128
|
||||
CASE(int128_tests),
|
||||
#endif
|
||||
CASE(ctz_tests),
|
||||
CASE(modinv_tests),
|
||||
CASE(inverse_tests),
|
||||
};
|
||||
|
||||
/*** Setup test environment ***/
|
||||
static const struct tf_test_entry tests_hash[] = {
|
||||
CASE(sha256_known_output_tests),
|
||||
CASE(sha256_counter_tests),
|
||||
CASE(hmac_sha256_tests),
|
||||
CASE(rfc6979_hmac_sha256_tests),
|
||||
CASE(tagged_sha256_tests),
|
||||
};
|
||||
|
||||
static const struct tf_test_entry tests_scalar[] = {
|
||||
CASE(scalar_tests),
|
||||
};
|
||||
|
||||
static const struct tf_test_entry tests_field[] = {
|
||||
CASE(field_half),
|
||||
CASE(field_misc),
|
||||
CASE(field_convert),
|
||||
CASE(field_be32_overflow),
|
||||
CASE(fe_mul),
|
||||
CASE(sqr),
|
||||
CASE(sqrt),
|
||||
};
|
||||
|
||||
static const struct tf_test_entry tests_group[] = {
|
||||
CASE(ge),
|
||||
CASE(gej),
|
||||
CASE(group_decompress),
|
||||
};
|
||||
|
||||
static const struct tf_test_entry tests_ecmult[] = {
|
||||
CASE(ecmult_pre_g),
|
||||
CASE(wnaf),
|
||||
CASE(point_times_order),
|
||||
CASE(ecmult_near_split_bound),
|
||||
CASE(ecmult_chain),
|
||||
CASE(ecmult_constants),
|
||||
CASE(ecmult_gen_blind),
|
||||
CASE(ecmult_const_tests),
|
||||
CASE(ecmult_multi_tests),
|
||||
CASE(ec_combine),
|
||||
};
|
||||
|
||||
static const struct tf_test_entry tests_ec[] = {
|
||||
CASE(endomorphism_tests),
|
||||
CASE(ec_pubkey_parse_test),
|
||||
CASE(eckey_edge_case_test),
|
||||
CASE(eckey_negate_test),
|
||||
};
|
||||
|
||||
static const struct tf_test_entry tests_ecdsa[] = {
|
||||
CASE(ec_illegal_argument_tests),
|
||||
CASE(pubkey_comparison),
|
||||
CASE(pubkey_sort),
|
||||
CASE(random_pubkeys),
|
||||
CASE(ecdsa_der_parse),
|
||||
CASE(ecdsa_sign_verify),
|
||||
CASE(ecdsa_end_to_end),
|
||||
CASE(ecdsa_edge_cases),
|
||||
CASE(ecdsa_wycheproof),
|
||||
};
|
||||
|
||||
static const struct tf_test_entry tests_utils[] = {
|
||||
CASE(hsort_tests),
|
||||
CASE(secp256k1_memczero_test),
|
||||
CASE(secp256k1_is_zero_array_test),
|
||||
CASE(secp256k1_byteorder_tests),
|
||||
CASE(cmov_tests),
|
||||
};
|
||||
|
||||
/* Register test modules */
|
||||
static const struct tf_test_module registry_modules[] = {
|
||||
MAKE_TEST_MODULE(general),
|
||||
MAKE_TEST_MODULE(integer),
|
||||
MAKE_TEST_MODULE(hash),
|
||||
MAKE_TEST_MODULE(scalar),
|
||||
MAKE_TEST_MODULE(field),
|
||||
MAKE_TEST_MODULE(group),
|
||||
MAKE_TEST_MODULE(ecmult),
|
||||
MAKE_TEST_MODULE(ec),
|
||||
#ifdef ENABLE_MODULE_ECDH
|
||||
MAKE_TEST_MODULE(ecdh),
|
||||
#endif
|
||||
MAKE_TEST_MODULE(ecdsa),
|
||||
#ifdef ENABLE_MODULE_RECOVERY
|
||||
/* ECDSA pubkey recovery tests */
|
||||
MAKE_TEST_MODULE(recovery),
|
||||
#endif
|
||||
#ifdef ENABLE_MODULE_EXTRAKEYS
|
||||
MAKE_TEST_MODULE(extrakeys),
|
||||
#endif
|
||||
#ifdef ENABLE_MODULE_SCHNORRSIG
|
||||
MAKE_TEST_MODULE(schnorrsig),
|
||||
#endif
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
MAKE_TEST_MODULE(musig),
|
||||
#endif
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
MAKE_TEST_MODULE(ellswift),
|
||||
#endif
|
||||
MAKE_TEST_MODULE(utils),
|
||||
};
|
||||
|
||||
/* Setup test environment */
|
||||
static int setup(void) {
|
||||
/* Create a global context available to all tests */
|
||||
CTX = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
/* Randomize the context only with probability 15/16
|
||||
@ -7709,129 +7812,28 @@ int main(int argc, char **argv) {
|
||||
CHECK(STATIC_CTX != NULL);
|
||||
memcpy(STATIC_CTX, secp256k1_context_static, sizeof(secp256k1_context));
|
||||
CHECK(!secp256k1_context_is_proper(STATIC_CTX));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*** Run actual tests ***/
|
||||
|
||||
/* selftest tests */
|
||||
run_selftest_tests();
|
||||
|
||||
/* context tests */
|
||||
run_proper_context_tests(0); run_proper_context_tests(1);
|
||||
run_static_context_tests(0); run_static_context_tests(1);
|
||||
run_deprecated_context_flags_test();
|
||||
|
||||
/* scratch tests */
|
||||
run_scratch_tests();
|
||||
|
||||
/* integer arithmetic tests */
|
||||
#ifdef SECP256K1_WIDEMUL_INT128
|
||||
run_int128_tests();
|
||||
#endif
|
||||
run_ctz_tests();
|
||||
run_modinv_tests();
|
||||
run_inverse_tests();
|
||||
|
||||
/* sorting tests */
|
||||
run_hsort_tests();
|
||||
|
||||
/* hash tests */
|
||||
run_sha256_known_output_tests();
|
||||
run_sha256_counter_tests();
|
||||
run_hmac_sha256_tests();
|
||||
run_rfc6979_hmac_sha256_tests();
|
||||
run_tagged_sha256_tests();
|
||||
|
||||
/* scalar tests */
|
||||
run_scalar_tests();
|
||||
|
||||
/* field tests */
|
||||
run_field_half();
|
||||
run_field_misc();
|
||||
run_field_convert();
|
||||
run_field_be32_overflow();
|
||||
run_fe_mul();
|
||||
run_sqr();
|
||||
run_sqrt();
|
||||
|
||||
/* group tests */
|
||||
run_ge();
|
||||
run_gej();
|
||||
run_group_decompress();
|
||||
|
||||
/* ecmult tests */
|
||||
run_ecmult_pre_g();
|
||||
run_wnaf();
|
||||
run_point_times_order();
|
||||
run_ecmult_near_split_bound();
|
||||
run_ecmult_chain();
|
||||
run_ecmult_constants();
|
||||
run_ecmult_gen_blind();
|
||||
run_ecmult_const_tests();
|
||||
run_ecmult_multi_tests();
|
||||
run_ec_combine();
|
||||
|
||||
/* endomorphism tests */
|
||||
run_endomorphism_tests();
|
||||
|
||||
/* EC point parser test */
|
||||
run_ec_pubkey_parse_test();
|
||||
|
||||
/* EC key edge cases */
|
||||
run_eckey_edge_case_test();
|
||||
|
||||
/* EC key arithmetic test */
|
||||
run_eckey_negate_test();
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDH
|
||||
/* ecdh tests */
|
||||
run_ecdh_tests();
|
||||
#endif
|
||||
|
||||
/* ecdsa tests */
|
||||
run_ec_illegal_argument_tests();
|
||||
run_pubkey_comparison();
|
||||
run_pubkey_sort();
|
||||
run_random_pubkeys();
|
||||
run_ecdsa_der_parse();
|
||||
run_ecdsa_sign_verify();
|
||||
run_ecdsa_end_to_end();
|
||||
run_ecdsa_edge_cases();
|
||||
run_ecdsa_wycheproof();
|
||||
|
||||
#ifdef ENABLE_MODULE_RECOVERY
|
||||
/* ECDSA pubkey recovery tests */
|
||||
run_recovery_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_EXTRAKEYS
|
||||
run_extrakeys_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_SCHNORRSIG
|
||||
run_schnorrsig_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
run_musig_tests();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
run_ellswift_tests();
|
||||
#endif
|
||||
|
||||
/* util tests */
|
||||
run_secp256k1_memczero_test();
|
||||
run_secp256k1_is_zero_array_test();
|
||||
run_secp256k1_byteorder_tests();
|
||||
|
||||
run_cmov_tests();
|
||||
|
||||
/*** Tear down test environment ***/
|
||||
/* Shutdown test environment */
|
||||
static int teardown(void) {
|
||||
free(STATIC_CTX);
|
||||
secp256k1_context_destroy(CTX);
|
||||
|
||||
testrand_finish();
|
||||
|
||||
printf("no problems found\n");
|
||||
return EXIT_SUCCESS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
struct tf_framework tf = {0};
|
||||
tf.registry_modules = registry_modules;
|
||||
tf.num_modules = sizeof(registry_modules) / sizeof(registry_modules[0]);
|
||||
tf.registry_no_rng = ®istry_modules_no_rng;
|
||||
|
||||
/* Add context creation/destruction functions */
|
||||
tf.fn_setup = setup;
|
||||
tf.fn_teardown = teardown;
|
||||
|
||||
/* Init and run framework */
|
||||
if (tf_init(&tf, argc, argv) != 0) return EXIT_FAILURE;
|
||||
return tf_run(&tf);
|
||||
}
|
||||
|
||||
|
||||
42
src/tests_common.h
Normal file
42
src/tests_common.h
Normal file
@ -0,0 +1,42 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_TESTS_COMMON_H
|
||||
#define SECP256K1_TESTS_COMMON_H
|
||||
|
||||
/***********************************************************************
|
||||
* Test Support Utilities
|
||||
*
|
||||
* This file provides general-purpose functions for tests and benchmark
|
||||
* programs. Unlike testutil.h, this file is not linked to the library,
|
||||
* allowing each program to choose whether to run against the production
|
||||
* API or access library internals directly.
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
# include <time.h>
|
||||
#else
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static int64_t gettime_i64(void) {
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
/* C11 way to get wallclock time */
|
||||
struct timespec tv;
|
||||
if (!timespec_get(&tv, TIME_UTC)) {
|
||||
fputs("timespec_get failed!", stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_TESTS_COMMON_H */
|
||||
@ -11,6 +11,14 @@
|
||||
#include "testrand.h"
|
||||
#include "util.h"
|
||||
|
||||
/* group order of the secp256k1 curve in 32-byte big endian representation */
|
||||
static const unsigned char secp256k1_group_order_bytes[32] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
|
||||
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41
|
||||
};
|
||||
|
||||
static void testutil_random_fe(secp256k1_fe *x) {
|
||||
unsigned char bin[32];
|
||||
do {
|
||||
|
||||
479
src/unit_test.c
Normal file
479
src/unit_test.c
Normal file
@ -0,0 +1,479 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(SUPPORTS_CONCURRENCY)
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "unit_test.h"
|
||||
#include "testrand.h"
|
||||
#include "tests_common.h"
|
||||
|
||||
#define UNUSED(x) (void)(x)
|
||||
|
||||
/* Number of times certain tests will run */
|
||||
int COUNT = 16;
|
||||
|
||||
static int parse_jobs_count(const char* key, const char* value, struct tf_framework* tf);
|
||||
static int parse_iterations(const char* key, const char* value, struct tf_framework* tf);
|
||||
static int parse_seed(const char* key, const char* value, struct tf_framework* tf);
|
||||
static int parse_target(const char* key, const char* value, struct tf_framework* tf);
|
||||
static int parse_logging(const char* key, const char* value, struct tf_framework* tf);
|
||||
|
||||
/* Mapping table: key -> handler */
|
||||
typedef int (*ArgHandler)(const char* key, const char* value, struct tf_framework* tf);
|
||||
struct ArgMap {
|
||||
const char* key;
|
||||
ArgHandler handler;
|
||||
};
|
||||
|
||||
/*
|
||||
* Main entry point for handling command-line arguments.
|
||||
*
|
||||
* Developers should extend this map whenever new command-line
|
||||
* options are introduced. Each new argument should be validated,
|
||||
* converted to the appropriate type, and stored in 'tf->args' struct.
|
||||
*/
|
||||
static struct ArgMap arg_map[] = {
|
||||
{ "t", parse_target }, { "target", parse_target },
|
||||
{ "j", parse_jobs_count }, { "jobs", parse_jobs_count },
|
||||
{ "i", parse_iterations }, { "iterations", parse_iterations },
|
||||
{ "seed", parse_seed },
|
||||
{ "log", parse_logging },
|
||||
{ NULL, NULL } /* sentinel */
|
||||
};
|
||||
|
||||
/* Display options that are not printed elsewhere */
|
||||
static void print_args(const struct tf_args* args) {
|
||||
printf("iterations = %d\n", COUNT);
|
||||
printf("jobs = %d. %s execution.\n", args->num_processes, args->num_processes > 1 ? "Parallel" : "Sequential");
|
||||
}
|
||||
|
||||
/* Main entry point for reading environment variables */
|
||||
static int read_env(struct tf_framework* tf) {
|
||||
const char* env_iter = getenv("SECP256K1_TEST_ITERS");
|
||||
if (env_iter && strlen(env_iter) > 0) {
|
||||
return parse_iterations("i", env_iter, tf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_arg(const char* key, const char* value, struct tf_framework* tf) {
|
||||
int i;
|
||||
for (i = 0; arg_map[i].key != NULL; i++) {
|
||||
if (strcmp(key, arg_map[i].key) == 0) {
|
||||
return arg_map[i].handler(key, value, tf);
|
||||
}
|
||||
}
|
||||
/* Unknown key: report just so typos don't silently pass. */
|
||||
fprintf(stderr, "Unknown argument '-%s=%s'\n", key, value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void help(void) {
|
||||
printf("Usage: ./tests [options]\n\n");
|
||||
printf("Run the test suite for the project with optional configuration.\n\n");
|
||||
printf("Options:\n");
|
||||
printf(" --help, -h Show this help message\n");
|
||||
printf(" --list_tests, -l Display list of all available tests and modules\n");
|
||||
printf(" --jobs=<num>, -j=<num> Number of parallel worker processes (default: 0 = sequential)\n");
|
||||
printf(" --iterations=<num>, -i=<num> Number of iterations for each test (default: 16)\n");
|
||||
printf(" --seed=<hex> Set a specific RNG seed (default: random)\n");
|
||||
printf(" --target=<test name>, -t=<name> Run a specific test (can be provided multiple times)\n");
|
||||
printf(" --target=<module name>, -t=<module> Run all tests within a specific module (can be provided multiple times)\n");
|
||||
printf(" --log=<0|1> Enable or disable test execution logging (default: 0 = disabled)\n");
|
||||
printf("\n");
|
||||
printf("Notes:\n");
|
||||
printf(" - All arguments must be provided in the form '--key=value', '-key=value' or '-k=value'.\n");
|
||||
printf(" - Single or double dashes are allowed for multi character options.\n");
|
||||
printf(" - Unknown arguments are reported but ignored.\n");
|
||||
printf(" - Sequential execution occurs if -jobs=0 or unspecified.\n");
|
||||
printf(" - Iterations and seed can also be passed as positional arguments before any other argument for backward compatibility.\n");
|
||||
}
|
||||
|
||||
/* Print all tests in registry */
|
||||
static void print_test_list(struct tf_framework* tf) {
|
||||
int m, t, total = 0;
|
||||
printf("\nAvailable tests (%d modules):\n", tf->num_modules);
|
||||
printf("========================================\n");
|
||||
for (m = 0; m < tf->num_modules; m++) {
|
||||
const struct tf_test_module* mod = &tf->registry_modules[m];
|
||||
printf("Module: %s (%d tests)\n", mod->name, mod->size);
|
||||
for (t = 0; t < mod->size; t++) {
|
||||
printf("\t[%3d] %s\n", total + 1, mod->data[t].name);
|
||||
total++;
|
||||
}
|
||||
printf("----------------------------------------\n");
|
||||
}
|
||||
printf("\nRun specific module: ./tests -t=<module_name>\n");
|
||||
printf("Run specific test: ./tests -t=<test_name>\n\n");
|
||||
}
|
||||
|
||||
static int parse_jobs_count(const char* key, const char* value, struct tf_framework* tf) {
|
||||
char* ptr_val;
|
||||
long val = strtol(value, &ptr_val, 10); /* base 10 */
|
||||
if (*ptr_val != '\0') {
|
||||
fprintf(stderr, "Invalid number for -%s=%s\n", key, value);
|
||||
return -1;
|
||||
}
|
||||
if (val < 0 || val > MAX_SUBPROCESSES) {
|
||||
fprintf(stderr, "Arg '-%s' out of range: '%ld'. Range: 0..%d\n", key, val, MAX_SUBPROCESSES);
|
||||
return -1;
|
||||
}
|
||||
tf->args.num_processes = (int) val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_iterations(const char* key, const char* value, struct tf_framework* tf) {
|
||||
UNUSED(key); UNUSED(tf);
|
||||
if (!value) return 0;
|
||||
COUNT = (int) strtol(value, NULL, 0);
|
||||
if (COUNT <= 0) {
|
||||
fputs("An iteration count of 0 or less is not allowed.\n", stderr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_seed(const char* key, const char* value, struct tf_framework* tf) {
|
||||
UNUSED(key);
|
||||
tf->args.custom_seed = (!value || strcmp(value, "NULL") == 0) ? NULL : value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_logging(const char* key, const char* value, struct tf_framework* tf) {
|
||||
UNUSED(key);
|
||||
tf->args.logging = value && strcmp(value, "1") == 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Strip up to two leading dashes */
|
||||
static const char* normalize_key(const char* arg, const char** err_msg) {
|
||||
const char* key;
|
||||
if (!arg || arg[0] != '-') {
|
||||
*err_msg = "missing initial dash";
|
||||
return NULL;
|
||||
}
|
||||
/* single-dash short option */
|
||||
if (arg[1] != '-') return arg + 1;
|
||||
|
||||
/* double-dash checks now */
|
||||
if (arg[2] == '\0') {
|
||||
*err_msg = "missing option name after double dash";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (arg[2] == '-') {
|
||||
*err_msg = "too many leading dashes";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = arg + 2;
|
||||
if (key[1] == '\0') {
|
||||
*err_msg = "short option cannot use double dash";
|
||||
return NULL;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
static int parse_target(const char* key, const char* value, struct tf_framework* tf) {
|
||||
int group, idx;
|
||||
const struct tf_test_entry* entry;
|
||||
UNUSED(key);
|
||||
/* Find test index in the registry */
|
||||
for (group = 0; group < tf->num_modules; group++) {
|
||||
const struct tf_test_module* module = &tf->registry_modules[group];
|
||||
int add_all = strcmp(value, module->name) == 0; /* select all from module */
|
||||
for (idx = 0; idx < module->size; idx++) {
|
||||
entry = &module->data[idx];
|
||||
if (add_all || strcmp(value, entry->name) == 0) {
|
||||
if (tf->args.targets.size >= MAX_ARGS) {
|
||||
fprintf(stderr, "Too many -target args (max: %d)\n", MAX_ARGS);
|
||||
return -1;
|
||||
}
|
||||
tf->args.targets.slots[tf->args.targets.size++] = entry;
|
||||
/* Matched a single test, we're done */
|
||||
if (!add_all) return 0;
|
||||
}
|
||||
}
|
||||
/* If add_all was true, we added all tests in the module, so return */
|
||||
if (add_all) return 0;
|
||||
}
|
||||
fprintf(stderr, "Error: target '%s' not found (missing or module disabled).\n"
|
||||
"Run program with -list_tests option to display available tests and modules.\n", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Read args: all must be in the form -key=value, --key=value or -key=value */
|
||||
static int read_args(int argc, char** argv, int start, struct tf_framework* tf) {
|
||||
int i;
|
||||
const char* key;
|
||||
const char* value;
|
||||
char* eq;
|
||||
const char* err_msg = "unknown error";
|
||||
for (i = start; i < argc; i++) {
|
||||
char* raw_arg = argv[i];
|
||||
if (!raw_arg || raw_arg[0] != '-') {
|
||||
fprintf(stderr, "Invalid arg '%s': must start with '-'\n", raw_arg ? raw_arg : "(null)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
key = normalize_key(raw_arg, &err_msg);
|
||||
if (!key || *key == '\0') {
|
||||
fprintf(stderr, "Invalid arg '%s': %s. Must be -k=value or --key=value\n", raw_arg, err_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
eq = strchr(raw_arg, '=');
|
||||
if (!eq || eq == raw_arg + 1) {
|
||||
/* Allowed options without value */
|
||||
if (strcmp(key, "h") == 0 || strcmp(key, "help") == 0) {
|
||||
tf->args.help = 1;
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(key, "l") == 0 || strcmp(key, "list_tests") == 0) {
|
||||
tf->args.list_tests = 1;
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "Invalid arg '%s': must be -k=value or --key=value\n", raw_arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*eq = '\0'; /* split key and value */
|
||||
value = eq + 1;
|
||||
if (!value || *value == '\0') { /* value is empty */
|
||||
fprintf(stderr, "Invalid arg '%s': value cannot be empty\n", raw_arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parse_arg(key, value, tf) != 0) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void run_test_log(const struct tf_test_entry* t) {
|
||||
int64_t start_time = gettime_i64();
|
||||
printf("Running %s..\n", t->name);
|
||||
t->func();
|
||||
printf("Test %s PASSED (%.3f sec)\n", t->name, (double)(gettime_i64() - start_time) / 1000000);
|
||||
}
|
||||
|
||||
static void run_test(const struct tf_test_entry* t) { t->func(); }
|
||||
|
||||
/* Process tests in sequential order */
|
||||
static int run_sequential(struct tf_framework* tf) {
|
||||
int it;
|
||||
for (it = 0; it < tf->args.targets.size; it++) {
|
||||
tf->fn_run_test(tf->args.targets.slots[it]);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#if defined(SUPPORTS_CONCURRENCY)
|
||||
static const int MAX_TARGETS = 255;
|
||||
|
||||
/* Process tests in parallel */
|
||||
static int run_concurrent(struct tf_framework* tf) {
|
||||
/* Sub-processes info */
|
||||
pid_t workers[MAX_SUBPROCESSES];
|
||||
int pipefd[2];
|
||||
int status = EXIT_SUCCESS;
|
||||
int it; /* loop iterator */
|
||||
unsigned char idx; /* test index */
|
||||
|
||||
if (tf->args.targets.size > MAX_TARGETS) {
|
||||
fprintf(stderr, "Internal Error: the number of targets (%d) exceeds the maximum supported (%d). "
|
||||
"If you need more, extend 'run_concurrent()' to handle additional targets.\n",
|
||||
tf->args.targets.size, MAX_TARGETS);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
if (pipe(pipefd) != 0) {
|
||||
perror("Error during pipe setup");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Launch worker processes */
|
||||
for (it = 0; it < tf->args.num_processes; it++) {
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("Error during process fork");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (pid == 0) {
|
||||
/* Child worker: read jobs from the shared pipe */
|
||||
close(pipefd[1]); /* children never write */
|
||||
while (read(pipefd[0], &idx, sizeof(idx)) == sizeof(idx)) {
|
||||
tf->fn_run_test(tf->args.targets.slots[(int)idx]);
|
||||
}
|
||||
_exit(EXIT_SUCCESS); /* finish child process */
|
||||
} else {
|
||||
/* Parent: save worker pid */
|
||||
workers[it] = pid;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parent: write all tasks into the pipe */
|
||||
close(pipefd[0]); /* close read end */
|
||||
for (it = 0; it < tf->args.targets.size; it++) {
|
||||
idx = (unsigned char)it;
|
||||
if (write(pipefd[1], &idx, sizeof(idx)) == -1) {
|
||||
perror("Error during workload distribution");
|
||||
close(pipefd[1]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
/* Close write end to signal EOF */
|
||||
close(pipefd[1]);
|
||||
/* Wait for all workers */
|
||||
for (it = 0; it < tf->args.num_processes; it++) {
|
||||
int ret = 0;
|
||||
if (waitpid(workers[it], &ret, 0) == -1 || ret != 0) {
|
||||
status = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tf_init(struct tf_framework* tf, int argc, char** argv)
|
||||
{
|
||||
/* Caller must set the registry and its size before calling tf_init */
|
||||
if (tf->registry_modules == NULL || tf->num_modules <= 0) {
|
||||
fprintf(stderr, "Error: tests registry not provided or empty\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Initialize command-line options */
|
||||
tf->args.num_processes = 0;
|
||||
tf->args.custom_seed = NULL;
|
||||
tf->args.help = 0;
|
||||
tf->args.targets.size = 0;
|
||||
tf->args.list_tests = 0;
|
||||
tf->args.logging = 0;
|
||||
|
||||
/* Disable buffering for stdout to improve reliability of getting
|
||||
* diagnostic information. Happens right at the start of main because
|
||||
* setbuf must be used before any other operation on the stream. */
|
||||
setbuf(stdout, NULL);
|
||||
/* Also disable buffering for stderr because it's not guaranteed that it's
|
||||
* unbuffered on all systems. */
|
||||
setbuf(stderr, NULL);
|
||||
|
||||
/* Parse env args */
|
||||
if (read_env(tf) != 0) return EXIT_FAILURE;
|
||||
|
||||
/* Parse command-line args */
|
||||
if (argc > 1) {
|
||||
int named_arg_start = 1; /* index to begin processing named arguments */
|
||||
if (argc - 1 > MAX_ARGS) { /* first arg is always the binary path */
|
||||
fprintf(stderr, "Too many command-line arguments (max: %d)\n", MAX_ARGS);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Compatibility Note: The first two args were the number of iterations and the seed. */
|
||||
/* If provided, parse them and adjust the starting index for named arguments accordingly. */
|
||||
if (argv[1][0] != '-') {
|
||||
int has_seed = argc > 2 && argv[2][0] != '-';
|
||||
if (parse_iterations("i", argv[1], tf) != 0) return EXIT_FAILURE;
|
||||
if (has_seed) parse_seed("seed", argv[2], tf);
|
||||
named_arg_start = has_seed ? 3 : 2;
|
||||
}
|
||||
if (read_args(argc, argv, named_arg_start, tf) != 0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (tf->args.help) {
|
||||
help();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (tf->args.list_tests) {
|
||||
print_test_list(tf);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
tf->fn_run_test = tf->args.logging ? run_test_log : run_test;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static int tf_run(struct tf_framework* tf) {
|
||||
/* Process exit status */
|
||||
int status;
|
||||
/* Whether to run all tests */
|
||||
int run_all;
|
||||
/* Loop iterator */
|
||||
int it;
|
||||
/* Initial test time */
|
||||
int64_t start_time = gettime_i64();
|
||||
/* Verify 'tf_init' has been called */
|
||||
if (!tf->fn_run_test) {
|
||||
fprintf(stderr, "Error: No test runner set. You must call 'tf_init' first to initialize the framework "
|
||||
"or manually assign 'fn_run_test' before calling 'tf_run'.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Populate targets with all tests if none were explicitly specified */
|
||||
run_all = tf->args.targets.size == 0;
|
||||
if (run_all) {
|
||||
int group, idx;
|
||||
for (group = 0; group < tf->num_modules; group++) {
|
||||
const struct tf_test_module* module = &tf->registry_modules[group];
|
||||
for (idx = 0; idx < module->size; idx++) {
|
||||
if (tf->args.targets.size >= MAX_ARGS) {
|
||||
fprintf(stderr, "Internal Error: Number of tests (%d) exceeds MAX_ARGS (%d). "
|
||||
"Increase MAX_ARGS to accommodate all tests.\n", tf->args.targets.size, MAX_ARGS);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
tf->args.targets.slots[tf->args.targets.size++] = &module->data[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!tf->args.logging) printf("Tests running silently. Use '-log=1' to enable detailed logging\n");
|
||||
|
||||
/* Log configuration */
|
||||
print_args(&tf->args);
|
||||
|
||||
/* Run test RNG tests (must run before we really initialize the test RNG) */
|
||||
/* Note: currently, these tests are executed sequentially because there */
|
||||
/* is really only one test. */
|
||||
for (it = 0; tf->registry_no_rng && it < tf->registry_no_rng->size; it++) {
|
||||
if (run_all) { /* future: support filtering */
|
||||
tf->fn_run_test(&tf->registry_no_rng->data[it]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize test RNG and library contexts */
|
||||
testrand_init(tf->args.custom_seed);
|
||||
if (tf->fn_setup && tf->fn_setup() != 0) return EXIT_FAILURE;
|
||||
|
||||
/* Check whether to process tests sequentially or concurrently */
|
||||
if (tf->args.num_processes <= 1) {
|
||||
status = run_sequential(tf);
|
||||
} else {
|
||||
#if defined(SUPPORTS_CONCURRENCY)
|
||||
status = run_concurrent(tf);
|
||||
#else
|
||||
fputs("Parallel execution not supported on your system. Running sequentially...\n", stderr);
|
||||
status = run_sequential(tf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Print accumulated time */
|
||||
printf("Total execution time: %.3f seconds\n", (double)(gettime_i64() - start_time) / 1000000);
|
||||
if (tf->fn_teardown && tf->fn_teardown() != 0) return EXIT_FAILURE;
|
||||
|
||||
return status;
|
||||
}
|
||||
145
src/unit_test.h
Normal file
145
src/unit_test.h
Normal file
@ -0,0 +1,145 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_UNIT_TEST_H
|
||||
#define SECP256K1_UNIT_TEST_H
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/* Configurable constants */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
/* Maximum number of command-line arguments.
|
||||
* Must be at least as large as the total number of tests
|
||||
* to allow specifying all tests individually. */
|
||||
#define MAX_ARGS 150
|
||||
/* Maximum number of parallel jobs */
|
||||
#define MAX_SUBPROCESSES 16
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/* Test Framework Registry Macros */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
#define CASE(name) { #name, run_##name }
|
||||
#define CASE1(name) { #name, name }
|
||||
|
||||
#define MAKE_TEST_MODULE(name) { \
|
||||
#name, \
|
||||
tests_##name, \
|
||||
sizeof(tests_##name) / sizeof(tests_##name[0]) \
|
||||
}
|
||||
|
||||
/* Macro to wrap a test internal function with a COUNT loop (iterations number) */
|
||||
#define REPEAT_TEST(fn) REPEAT_TEST_MULT(fn, 1)
|
||||
#define REPEAT_TEST_MULT(fn, multiplier) \
|
||||
static void fn(void) { \
|
||||
int i; \
|
||||
int repeat = COUNT * (multiplier); \
|
||||
for (i = 0; i < repeat; i++) \
|
||||
fn##_internal(); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/* Test Framework API */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
typedef void (*test_fn)(void);
|
||||
|
||||
struct tf_test_entry {
|
||||
const char* name;
|
||||
test_fn func;
|
||||
};
|
||||
|
||||
struct tf_test_module {
|
||||
const char* name;
|
||||
const struct tf_test_entry* data;
|
||||
int size;
|
||||
};
|
||||
|
||||
typedef int (*setup_ctx_fn)(void);
|
||||
typedef int (*teardown_fn)(void);
|
||||
typedef void (*run_test_fn)(const struct tf_test_entry*);
|
||||
|
||||
struct tf_targets {
|
||||
/* Target tests indexes */
|
||||
const struct tf_test_entry* slots[MAX_ARGS];
|
||||
/* Next available slot */
|
||||
int size;
|
||||
};
|
||||
|
||||
/* --- Command-line args --- */
|
||||
struct tf_args {
|
||||
/* 0 => sequential; 1..MAX_SUBPROCESSES => parallel workers */
|
||||
int num_processes;
|
||||
/* Specific RNG seed */
|
||||
const char* custom_seed;
|
||||
/* Whether to print the help msg */
|
||||
int help;
|
||||
/* Whether to print the tests list msg */
|
||||
int list_tests;
|
||||
/* Target tests indexes */
|
||||
struct tf_targets targets;
|
||||
/* Enable test execution logging */
|
||||
int logging;
|
||||
};
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/* Public API */
|
||||
/* --------------------------------------------------------- */
|
||||
|
||||
struct tf_framework {
|
||||
/* Command-line args */
|
||||
struct tf_args args;
|
||||
/* Test modules registry */
|
||||
const struct tf_test_module* registry_modules;
|
||||
/* Num of modules */
|
||||
int num_modules;
|
||||
/* Registry for tests that require no RNG init */
|
||||
const struct tf_test_module* registry_no_rng;
|
||||
/* Specific context setup and teardown functions */
|
||||
setup_ctx_fn fn_setup;
|
||||
teardown_fn fn_teardown;
|
||||
/* Test runner function (can be customized) */
|
||||
run_test_fn fn_run_test;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize the test framework.
|
||||
*
|
||||
* Must be called before tf_run() and before any output is performed to
|
||||
* stdout or stderr, because this function disables buffering on both
|
||||
* streams to ensure reliable diagnostic output.
|
||||
*
|
||||
* Parses command-line arguments and configures the framework context.
|
||||
* The caller must initialize the following members of 'tf' before calling:
|
||||
* - tf->registry_modules
|
||||
* - tf->num_modules
|
||||
*
|
||||
* Side effects:
|
||||
* - stdout and stderr are set to unbuffered mode via setbuf().
|
||||
* This allows immediate flushing of diagnostic messages but may
|
||||
* affect performance for other output operations.
|
||||
*
|
||||
* Returns:
|
||||
* EXIT_SUCCESS (0) on success,
|
||||
* EXIT_FAILURE (non-zero) on error.
|
||||
*/
|
||||
static int tf_init(struct tf_framework* tf, int argc, char** argv);
|
||||
|
||||
/*
|
||||
* Run tests based on the provided test framework context.
|
||||
*
|
||||
* This function uses the configuration stored in the tf_framework
|
||||
* (targets, number of processes, iteration count, etc.) to determine
|
||||
* which tests to execute and how to execute them.
|
||||
*
|
||||
* Returns:
|
||||
* EXIT_SUCCESS (0) if all tests passed,
|
||||
* EXIT_FAILURE (non-zero) otherwise.
|
||||
*/
|
||||
static int tf_run(struct tf_framework* tf);
|
||||
|
||||
#endif /* SECP256K1_UNIT_TEST_H */
|
||||
19
src/util.h
19
src/util.h
@ -219,8 +219,8 @@ static SECP256K1_INLINE void secp256k1_memczero(void *s, size_t len, int flag) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
|
||||
static SECP256K1_INLINE void secp256k1_memclear(void *ptr, size_t len) {
|
||||
/* Zeroes memory to prevent leaking sensitive info. Won't be optimized out. */
|
||||
static SECP256K1_INLINE void secp256k1_memzero_explicit(void *ptr, size_t len) {
|
||||
#if defined(_MSC_VER)
|
||||
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
|
||||
SecureZeroMemory(ptr, len);
|
||||
@ -242,6 +242,19 @@ static SECP256K1_INLINE void secp256k1_memclear(void *ptr, size_t len) {
|
||||
void *(*volatile const volatile_memset)(void *, int, size_t) = memset;
|
||||
volatile_memset(ptr, 0, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out.
|
||||
* The state of the memory after this call is unspecified so callers must not
|
||||
* make any assumptions about its contents.
|
||||
*
|
||||
* In VERIFY builds, it has the side effect of marking the memory as undefined.
|
||||
* This helps to detect use-after-clear bugs where code incorrectly reads from
|
||||
* cleansed memory during testing.
|
||||
*/
|
||||
static SECP256K1_INLINE void secp256k1_memclear_explicit(void *ptr, size_t len) {
|
||||
/* The current implementation zeroes, but callers must not rely on this */
|
||||
secp256k1_memzero_explicit(ptr, len);
|
||||
#ifdef VERIFY
|
||||
SECP256K1_CHECKMEM_UNDEFINE(ptr, len);
|
||||
#endif
|
||||
@ -277,7 +290,7 @@ static SECP256K1_INLINE int secp256k1_is_zero_array(const unsigned char *s, size
|
||||
}
|
||||
ret = (acc == 0);
|
||||
/* acc may contain secret values. Try to explicitly clear it. */
|
||||
secp256k1_memclear(&acc, sizeof(acc));
|
||||
secp256k1_memclear_explicit(&acc, sizeof(acc));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
* The file `ecdsa_secp256k1_sha256_bitcoin_test.json` in this directory
|
||||
comes from project Wycheproof with git commit
|
||||
`df4e933efef449fc88af0c06e028d425d84a9495`, see
|
||||
https://github.com/C2SP/wycheproof/blob/df4e933efef449fc88af0c06e028d425d84a9495/testvectors_v1/ecdsa_secp256k1_sha256_bitcoin_test.json
|
||||
`7ae4532f417575ced2b1cbbabed81a7fecfaef5d`, see
|
||||
https://github.com/C2SP/wycheproof/blob/7ae4532f417575ced2b1cbbabed81a7fecfaef5d/testvectors_v1/ecdsa_secp256k1_sha256_bitcoin_test.json
|
||||
|
||||
* The file `ecdh_secp256k1_test.json` in this directory
|
||||
comes from project Wycheproof with git commit
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
"numberOfTests" : 463,
|
||||
"header" : [
|
||||
"Test vectors of type EcdsaBitcoinVerify are meant for the verification",
|
||||
"of a ECDSA variant used for bitcoin, that add signature non-malleability."
|
||||
"of a ECDSA variant used for Bitcoin, that add signature non-malleability."
|
||||
],
|
||||
"notes" : {
|
||||
"ArithmeticError" : {
|
||||
@ -47,7 +47,7 @@
|
||||
"InvalidSignature" : {
|
||||
"bugType" : "AUTH_BYPASS",
|
||||
"description" : "The signature contains special case values such as r=0 and s=0. Buggy implementations may accept such values, if the implementation does not check boundaries and computes s^(-1) == 0.",
|
||||
"effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.",
|
||||
"effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowing the message to sign.",
|
||||
"cves" : [
|
||||
"CVE-2022-21449",
|
||||
"CVE-2021-43572",
|
||||
@ -57,7 +57,7 @@
|
||||
"InvalidTypesInSignature" : {
|
||||
"bugType" : "AUTH_BYPASS",
|
||||
"description" : "The signature contains invalid types. Dynamic typed languages sometime coerce such values of different types into integers. If an implementation is careless and has additional bugs, such as not checking integer boundaries then it may be possible that such signatures are accepted.",
|
||||
"effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowning the message to sign.",
|
||||
"effect" : "Accepting such signatures can have the effect that an adversary can forge signatures without even knowing the message to sign.",
|
||||
"cves" : [
|
||||
"CVE-2022-21449"
|
||||
]
|
||||
@ -95,8 +95,8 @@
|
||||
},
|
||||
"SignatureMalleabilityBitcoin" : {
|
||||
"bugType" : "SIGNATURE_MALLEABILITY",
|
||||
"description" : "\"BitCoins\"-curves are curves where signature malleability can be a serious issue. An implementation should only accept a signature s where s < n/2. If an implementation is not meant for uses cases that require signature malleability then this implementation should be tested with another set of test vectors.",
|
||||
"effect" : "In bitcoin exchanges, it may be used to make a double deposits or double withdrawals",
|
||||
"description" : "Signature malleability can be a serious issue in Bitcoin. An implementation should only accept a signature s where s < n/2. If an implementation is meant for use cases that tolerate signature malleability then this implementation should not be tested with this set of test vectors.",
|
||||
"effect" : "In Bitcoin exchanges, it may be used to make a double deposits or double withdrawals",
|
||||
"links" : [
|
||||
"https://en.bitcoin.it/wiki/Transaction_malleability",
|
||||
"https://en.bitcoinwiki.org/wiki/Transaction_Malleability"
|
||||
|
||||
@ -49,14 +49,7 @@ checkout_and_build() {
|
||||
-DSECP256K1_BUILD_CTIME_TESTS=OFF \
|
||||
-DSECP256K1_BUILD_EXAMPLES=OFF
|
||||
cmake --build . -j "$(nproc)"
|
||||
# FIXME: Just set LIBPATH to lib/libsecp256k1.so once version 0.6.0 is
|
||||
# released.
|
||||
if [ -f "src/libsecp256k1.so" ]; then
|
||||
LIBPATH="src/libsecp256k1.so"
|
||||
else
|
||||
LIBPATH="lib/libsecp256k1.so"
|
||||
fi
|
||||
abi-dumper $LIBPATH -o ABI.dump -lver "$2" -public-headers ../include/
|
||||
abi-dumper lib/libsecp256k1.so -o ABI.dump -lver "$2" -public-headers ../include/
|
||||
cd "$_orig_dir"
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user