Update src/secp256k1 to latest BlockstreamResearch/secp256k1-zkp master
What changed, and why it matters
This commit updates the embedded secp256k1-zkp cryptographic library inside the Elements project to the latest master from BlockstreamResearch. It is a large, routine dependency refresh touching build scripts, CI configuration, and many source files. The commit itself does not describe any specific security bug fix, and the visible changes are mostly build/CI modernization plus upstream synchronization. Because it is a wholesale submodule-style update, it could silently include upstream security fixes, but the provided diff does not identify any particular vulnerability or CVE.
Treat this as a routine but high-risk dependency update. Review the upstream secp256k1-zkp release notes and commit history between the old and new master for any security advisories or CVEs. Run the project's full test suite, including constant-time tests and fuzzing if available, before deploying. If Elements exposes secp256k1-zkp APIs to untrusted input, prioritize validating signature parsing, MuSig2, and rangeproof/surjectionproof modules.
Security signals we found
Large dependency subtree update of a cryptographic library (secp256k1-zkp)
Changelog mentions a fixed x86_64 assembly feature check that could silently fall back to slower C code when -Werror was in CFLAGS
Changelog mentions increased stack clearing of secrets
No explicit security fix, CVE, or vulnerability description in commit message or diff
CI adds symbol-check and MSan handling, but these are hardening/QA changes
Evidence from the diff
The diff is a massive subtree update of src/secp256k1 from BlockstreamResearch/secp256k1-zkp. Visible changes include: version bump to 0.7.2 (CMake) / 0.7.1-dev (autotools), build-aux renamed to autotools-aux, new CMake helper modules (CheckMemorySanitizer, DiscoverTests), CI workflow modernization (GitHub action version bumps, native arm64 runners, new symbol-check job, scheduled upstream sync workflow), removal of the standalone MUSIG CMake option in favor of automatic dependency handling, replacement of ECMULTGENPRECISION with ECMULTGENKB, new unit-test framework, and changelog entries noting a fixed x86_64 assembly feature check and increased secret stack clearing. No specific vulnerability, CVE, or security-relevant commit message is present in the supplied materials.
Changed components
src/secp256k1 (entire embedded secp256k1-zkp library)Elements build system (CMake/autotools integration)CI/CD workflows for secp256k1Inspect captured patch +19548 / −15229
diff --git a/src/secp256k1/.cirrus.yml b/src/secp256k1/.cirrus.yml
deleted file mode 100644
index baeaa5b..0000000
--- a/src/secp256k1/.cirrus.yml
+++ /dev/null
@@ -1,101 +0,0 @@
-env:
- ### cirrus config
- CIRRUS_CLONE_DEPTH: 1
- ### compiler options
- HOST:
- WRAPPER_CMD:
- # Specific warnings can be disabled with -Wno-error=foo.
- # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual.
- WERROR_CFLAGS: -Werror -pedantic-errors
- MAKEFLAGS: -j4
- BUILD: check
- ### secp256k1 config
- ECMULTWINDOW: auto
- ECMULTGENPRECISION: auto
- ASM: no
- WIDEMUL: auto
- WITH_VALGRIND: yes
- EXTRAFLAGS:
- ### secp256k1 modules
- EXPERIMENTAL: no
- ECDH: no
- RECOVERY: no
- EXTRAKEYS: no
- SCHNORRSIG: no
- MUSIG: no
- ELLSWIFT: no
- ### test options
- SECP256K1_TEST_ITERS: 64
- BENCH: yes
- SECP256K1_BENCH_ITERS: 2
- CTIMETESTS: yes
- # Compile and run the tests
- EXAMPLES: yes
-
-cat_logs_snippet: &CAT_LOGS
- always:
- cat_tests_log_script:
- - cat tests.log || true
- cat_noverify_tests_log_script:
- - cat noverify_tests.log || true
- cat_exhaustive_tests_log_script:
- - cat exhaustive_tests.log || true
- cat_ctime_tests_log_script:
- - cat ctime_tests.log || true
- cat_bench_log_script:
- - cat bench.log || true
- cat_config_log_script:
- - cat config.log || true
- cat_test_env_script:
- - cat test_env.log || true
- cat_ci_env_script:
- - env
-
-linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER
- env_script:
- - env | tee /tmp/env
- build_script:
- - DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm"
- - docker image prune --force # Cleanup stale layers
- test_script:
- - docker run --rm --mount "type=bind,src=./,dst=/ci_secp256k1" --env-file /tmp/env --replace --name "ci_secp256k1_arm" "ci_secp256k1_arm" bash -c "cd /ci_secp256k1/ && ./ci/ci.sh"
-
-task:
- name: "ARM64: Linux (Debian stable)"
- persistent_worker:
- labels:
- type: arm64
- env:
- ECDH: yes
- RECOVERY: yes
- EXTRAKEYS: yes
- SCHNORRSIG: yes
- MUSIG: yes
- ELLSWIFT: yes
- matrix:
- # Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU
- - env: { CC: 'gcc-snapshot' }
- << : *LINUX_ARM64_CONTAINER
- << : *CAT_LOGS
-
-task:
- name: "ARM64: Linux (Debian stable), Valgrind"
- persistent_worker:
- labels:
- type: arm64
- env:
- ECDH: yes
- RECOVERY: yes
- EXTRAKEYS: yes
- SCHNORRSIG: yes
- MUSIG: yes
- ELLSWIFT: yes
- WRAPPER_CMD: 'valgrind --error-exitcode=42'
- SECP256K1_TEST_ITERS: 2
- matrix:
- - env: { CC: 'gcc' }
- - env: { CC: 'clang' }
- - env: { CC: 'gcc-snapshot' }
- - env: { CC: 'clang-snapshot' }
- << : *LINUX_ARM64_CONTAINER
- << : *CAT_LOGS
diff --git a/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml b/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml
index ce10eb2..e9aa615 100644
--- a/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml
+++ b/src/secp256k1/.github/actions/install-homebrew-valgrind/action.yml
@@ -16,7 +16,7 @@ runs:
cat valgrind_fingerprint
shell: bash
- - uses: actions/cache@v4
+ - uses: actions/cache@v5
id: cache
with:
path: ${{ env.CI_HOMEBREW_CELLAR_VALGRIND }}
diff --git a/src/secp256k1/.github/actions/print-logs/action.yml b/src/secp256k1/.github/actions/print-logs/action.yml
new file mode 100644
index 0000000..33de35c
--- /dev/null
+++ b/src/secp256k1/.github/actions/print-logs/action.yml
@@ -0,0 +1,34 @@
+name: "Print logs"
+description: "Print the log files produced by ci/ci.sh"
+runs:
+ using: "composite"
+ steps:
+ - shell: bash
+ run: |
+ # Print the log files produced by ci/ci.sh
+
+ # Helper functions
+ group() {
+ title=$1
+ echo "::group::$title"
+ }
+ endgroup() {
+ echo "::endgroup::"
+ }
+ cat_file() {
+ file=$1
+ group "$file"
+ cat "$file"
+ endgroup
+ }
+
+ # Print all *.log files
+ shopt -s nullglob
+ for file in *.log; do
+ cat_file "$file"
+ done
+
+ # Print environment
+ group "CI env"
+ env
+ endgroup
diff --git a/src/secp256k1/.github/actions/run-in-docker-action/action.yml b/src/secp256k1/.github/actions/run-in-docker-action/action.yml
index 7493368..f0eb981 100644
--- a/src/secp256k1/.github/actions/run-in-docker-action/action.yml
+++ b/src/secp256k1/.github/actions/run-in-docker-action/action.yml
@@ -4,37 +4,34 @@ inputs:
dockerfile:
description: 'A Dockerfile that defines an image'
required: true
- tag:
- description: 'A tag of an image'
+ scope:
+ description: 'A cached image scope'
required: true
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/setup-buildx-action@v4
- - uses: docker/build-push-action@v5
+ - uses: docker/build-push-action@v7
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@v7
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 +44,8 @@ runs:
$(echo '${{ toJSON(env) }}' | jq -r 'keys[] | "--env \(.) "') \
--volume ${{ github.workspace }}:${{ github.workspace }} \
--workdir ${{ github.workspace }} \
- ${{ inputs.tag }} bash -c "
+ ${{ case(steps.main_builder.outcome == 'success', steps.main_builder.outputs.imageid, steps.retry_builder.outputs.imageid) }} \
+ bash -c "
git config --global --add safe.directory ${{ github.workspace }}
${{ inputs.command }}
"
diff --git a/src/secp256k1/.github/workflows/ci.yml b/src/secp256k1/.github/workflows/ci.yml
index 3f5476f..c667077 100644
--- a/src/secp256k1/.github/workflows/ci.yml
+++ b/src/secp256k1/.github/workflows/ci.yml
@@ -6,6 +6,10 @@ on:
- '**'
tags-ignore:
- '**'
+ schedule:
+ # Run on the default branch every Monday morning.
+ # This also warms the Docker caches after key rotation.
+ - cron: '22 2 * * 1'
concurrency:
group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }}
@@ -21,8 +25,8 @@ env:
MAKEFLAGS: '-j4'
BUILD: 'check'
### secp256k1 config
- ECMULTWINDOW: 'auto'
- ECMULTGENPRECISION: 'auto'
+ ECMULTWINDOW: 15
+ ECMULTGENKB: 86
ASM: 'no'
WIDEMUL: 'auto'
WITH_VALGRIND: 'yes'
@@ -38,8 +42,8 @@ env:
ECDSA_S2C: 'no'
GENERATOR: 'no'
RANGEPROOF: 'no'
+ SURJECTIONPROOF: 'no'
WHITELIST: 'no'
- MUSIG: 'no'
ECDSAADAPTOR: 'no'
BPPP: 'no'
SCHNORRSIG_HALFAGG: 'no'
@@ -48,30 +52,49 @@ env:
BENCH: 'yes'
SECP256K1_BENCH_ITERS: 2
CTIMETESTS: 'yes'
+ SYMBOL_CHECK: 'yes'
# Compile and run the examples.
EXAMPLES: 'yes'
+ # Disable Docker build summary generation.
+ # See https://github.com/docker/build-push-action/blob/master/README.md#environment-variables.
+ DOCKER_BUILD_SUMMARY: false
jobs:
docker_cache:
- name: "Build Docker image"
- runs-on: ubuntu-latest
+ name: "Build ${{ matrix.arch }} Docker image"
+ runs-on: ${{ matrix.runner }}
+ outputs:
+ cache_scope: ${{ steps.cache_timestamp.outputs.period }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - arch: x64
+ runner: ubuntu-latest
+ - arch: arm64
+ runner: ubuntu-24.04-arm
+
steps:
+ - name: Get cache validity period
+ id: cache_timestamp
+ run: echo "period=$((10#$(date +%V) / 4))" >> "$GITHUB_OUTPUT"
+
- name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
+ uses: docker/setup-buildx-action@v4
with:
# See: https://github.com/moby/buildkit/issues/3969.
driver-opts: |
network=host
- name: Build container
- uses: docker/build-push-action@v5
+ uses: docker/build-push-action@v7
with:
file: ./ci/linux-debian.Dockerfile
- tags: linux-debian-image
- cache-from: type=gha
- cache-to: type=gha,mode=min
+ cache-from: type=gha,scope=${{ runner.arch }}-${{ steps.cache_timestamp.outputs.period }}
+ cache-to: type=gha,scope=${{ runner.arch }}-${{ steps.cache_timestamp.outputs.period }},mode=min
- linux_debian:
+ x86_64-debian:
name: "x86_64: Linux (Debian stable)"
runs-on: ubuntu-latest
needs: docker_cache
@@ -81,20 +104,20 @@ jobs:
matrix:
configuration:
- env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' }
- - env_vars: { WIDEMUL: 'int64', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'}
+ - env_vars: { WIDEMUL: 'int64', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'}
- env_vars: { WIDEMUL: 'int128' }
- - env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' }
- - env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- - env_vars: { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'}
- - env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' }
- - env_vars: { RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'}
- - env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CPPFLAGS: '-DVERIFY' }
+ - env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' }
+ - env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
+ - env_vars: { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'}
+ - env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' }
+ - env_vars: { RECOVERY: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes'}
+ - env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CPPFLAGS: '-DVERIFY' }
- env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' }
- env_vars: { CPPFLAGS: '-DDETERMINISTIC' }
- env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' }
- - env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- - env_vars: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
- - env_vars: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 }
+ - env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes' }
+ - env_vars: { ECMULTGENKB: 2, ECMULTWINDOW: 2 }
+ - env_vars: { ECMULTGENKB: 86, ECMULTWINDOW: 4 }
cc:
- 'gcc'
- 'clang'
@@ -105,33 +128,23 @@ 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: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ scope: ${{ runner.arch }}-${{ needs.docker_cache.outputs.cache_scope }}
+ command: ./ci/ci.sh
+
+ - &PRINT_LOGS
+ name: Print logs
+ uses: ./.github/actions/print-logs
+ if: ${{ !cancelled() }}
i686_debian:
name: "i686: Linux (Debian stable)"
@@ -141,6 +154,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'
@@ -156,47 +171,29 @@ jobs:
EXPERIMENTAL: 'yes'
ECDSA_S2C: 'yes'
RANGEPROOF: 'yes'
+ SURJECTIONPROOF: 'yes'
WHITELIST: 'yes'
GENERATOR: 'yes'
- MUSIG: 'yes'
ECDSAADAPTOR: 'yes'
BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
CC: ${{ matrix.cc }}
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: CI script
- uses: ./.github/actions/run-in-docker-action
- with:
- dockerfile: ./ci/linux-debian.Dockerfile
- tag: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ - *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
@@ -211,41 +208,18 @@ jobs:
EXPERIMENTAL: 'yes'
ECDSA_S2C: 'yes'
RANGEPROOF: 'yes'
+ SURJECTIONPROOF: 'yes'
WHITELIST: 'yes'
GENERATOR: 'yes'
- MUSIG: 'yes'
ECDSAADAPTOR: 'yes'
BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
CTIMETESTS: 'no'
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: CI script
- uses: ./.github/actions/run-in-docker-action
- with:
- dockerfile: ./ci/linux-debian.Dockerfile
- tag: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ - *CHECKOUT
+ - *CI_SCRIPT_IN_DOCKER
+ - *PRINT_LOGS
arm32_debian:
name: "ARM32: Linux (Debian stable, QEMU)"
@@ -274,51 +248,25 @@ jobs:
ECDSA_S2C: 'yes'
GENERATOR: 'yes'
RANGEPROOF: 'yes'
+ SURJECTIONPROOF: 'yes'
WHITELIST: 'yes'
- MUSIG: 'yes'
ECDSAADAPTOR: 'yes'
BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
CTIMETESTS: 'no'
steps:
- - name: Checkout
- uses: actions/checkout@v4
+ - *CHECKOUT
+ - *CI_SCRIPT_IN_DOCKER
+ - *PRINT_LOGS
- - name: CI script
- env: ${{ matrix.configuration.env_vars }}
- uses: ./.github/actions/run-in-docker-action
- with:
- dockerfile: ./ci/linux-debian.Dockerfile
- tag: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
-
- arm64_debian:
- name: "ARM64: Linux (Debian stable, QEMU)"
- runs-on: ubuntu-latest
+ arm64-debian:
+ name: "arm64: Linux (Debian stable)"
+ runs-on: ubuntu-24.04-arm
needs: docker_cache
env:
- WRAPPER_CMD: 'qemu-aarch64'
SECP256K1_TEST_ITERS: 16
- HOST: 'aarch64-linux-gnu'
WITH_VALGRIND: 'no'
ECDH: 'yes'
RECOVERY: 'yes'
@@ -330,57 +278,40 @@ jobs:
ECDSA_S2C: 'yes'
GENERATOR: 'yes'
RANGEPROOF: 'yes'
+ SURJECTIONPROOF: 'yes'
WHITELIST: 'yes'
- MUSIG: 'yes'
ECDSAADAPTOR: 'yes'
BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
CTIMETESTS: 'no'
+ CC: ${{ matrix.cc }}
strategy:
fail-fast: false
matrix:
configuration:
- - env_vars: { } # gcc
- - env_vars: # clang
- CC: 'clang --target=aarch64-linux-gnu'
- - env_vars: # clang-snapshot
- CC: 'clang-snapshot --target=aarch64-linux-gnu'
+ - env_vars: {}
+ cc:
+ - 'gcc'
+ - 'clang'
+ - 'gcc-snapshot'
+ - 'clang-snapshot'
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: CI script
- env: ${{ matrix.configuration.env_vars }}
- uses: ./.github/actions/run-in-docker-action
- with:
- dockerfile: ./ci/linux-debian.Dockerfile
- tag: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ - *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
@@ -396,54 +327,45 @@ jobs:
ECDSA_S2C: 'yes'
GENERATOR: 'yes'
RANGEPROOF: 'yes'
+ SURJECTIONPROOF: 'yes'
WHITELIST: 'yes'
- MUSIG: 'yes'
ECDSAADAPTOR: 'yes'
BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
CTIMETESTS: 'no'
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: CI script
- uses: ./.github/actions/run-in-docker-action
- with:
- dockerfile: ./ci/linux-debian.Dockerfile
- tag: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ - *CHECKOUT
+ - *CI_SCRIPT_IN_DOCKER
+ - *PRINT_LOGS
valgrind_debian:
- name: "Valgrind (memcheck)"
- runs-on: ubuntu-latest
+ name: "Valgrind ${{ matrix.configuration.binary_arch }} (memcheck)"
+ runs-on: ${{ matrix.configuration.runner }}
needs: docker_cache
strategy:
fail-fast: false
matrix:
configuration:
- - env_vars: { CC: 'clang', ASM: 'auto' }
- - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' }
- - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
- - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
+ - runner: ubuntu-latest
+ binary_arch: x64
+ env_vars: { CC: 'clang', ASM: 'auto' }
+ - runner: ubuntu-latest
+ binary_arch: i686
+ env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' }
+ - runner: ubuntu-24.04-arm
+ binary_arch: arm64
+ env_vars: { CC: 'clang', ASM: 'auto' }
+ - runner: ubuntu-latest
+ binary_arch: x64
+ env_vars: { CC: 'clang', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
+ - runner: ubuntu-latest
+ binary_arch: i686
+ env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
+ - runner: ubuntu-24.04-arm
+ binary_arch: arm64
+ env_vars: { CC: 'clang', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
env:
# The `--error-exitcode` is required to make the test fail if valgrind found errors,
@@ -459,8 +381,8 @@ jobs:
ECDSA_S2C: 'yes'
GENERATOR: 'yes'
RANGEPROOF: 'yes'
+ SURJECTIONPROOF: 'yes'
WHITELIST: 'yes'
- MUSIG: 'yes'
ECDSAADAPTOR: 'yes'
BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
@@ -468,33 +390,9 @@ jobs:
SECP256K1_TEST_ITERS: 2
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: CI script
- env: ${{ matrix.configuration.env_vars }}
- uses: ./.github/actions/run-in-docker-action
- with:
- dockerfile: ./ci/linux-debian.Dockerfile
- tag: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ - *CHECKOUT
+ - *CI_SCRIPT_IN_DOCKER
+ - *PRINT_LOGS
sanitizers_debian:
name: "UBSan, ASan, LSan"
@@ -507,8 +405,8 @@ jobs:
configuration:
- env_vars: { CC: 'clang', ASM: 'auto' }
- env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' }
- - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
- - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
+ - env_vars: { CC: 'clang', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
+ - env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENKB: 2, ECMULTWINDOW: 2 }
env:
ECDH: 'yes'
@@ -521,8 +419,8 @@ jobs:
ECDSA_S2C: 'yes'
GENERATOR: 'yes'
RANGEPROOF: 'yes'
+ SURJECTIONPROOF: 'yes'
WHITELIST: 'yes'
- MUSIG: 'yes'
ECDSAADAPTOR: 'yes'
BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
@@ -532,35 +430,12 @@ jobs:
ASAN_OPTIONS: 'strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1'
LSAN_OPTIONS: 'use_unaligned=1'
SECP256K1_TEST_ITERS: 32
+ SYMBOL_CHECK: 'no'
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: CI script
- env: ${{ matrix.configuration.env_vars }}
- uses: ./.github/actions/run-in-docker-action
- with:
- dockerfile: ./ci/linux-debian.Dockerfile
- tag: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ - *CHECKOUT
+ - *CI_SCRIPT_IN_DOCKER
+ - *PRINT_LOGS
msan_debian:
name: "MSan"
@@ -572,11 +447,21 @@ jobs:
matrix:
configuration:
- env_vars:
+ CTIMETESTS: 'yes'
CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g'
- env_vars:
- ECMULTGENPRECISION: 2
+ ECMULTGENKB: 2
ECMULTWINDOW: 2
+ CTIMETESTS: 'yes'
CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g -O3'
+ - env_vars:
+ # -fsanitize-memory-param-retval is clang's default, but our build system disables it
+ # 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'
@@ -589,45 +474,21 @@ jobs:
ECDSA_S2C: 'yes'
GENERATOR: 'yes'
RANGEPROOF: 'yes'
+ SURJECTIONPROOF: 'yes'
WHITELIST: 'yes'
- MUSIG: 'yes'
ECDSAADAPTOR: 'yes'
BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
- CTIMETESTS: '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: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ - *CHECKOUT
+ - *CI_SCRIPT_IN_DOCKER
+ - *PRINT_LOGS
mingw_debian:
name: ${{ matrix.configuration.job_name }}
@@ -647,8 +508,8 @@ jobs:
ECDSA_S2C: 'yes'
GENERATOR: 'yes'
RANGEPROOF: 'yes'
+ SURJECTIONPROOF: 'yes'
WHITELIST: 'yes'
- MUSIG: 'yes'
ECDSAADAPTOR: 'yes'
BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
@@ -666,62 +527,37 @@ jobs:
HOST: 'i686-w64-mingw32'
steps:
- - name: Checkout
- uses: actions/checkout@v4
+ - *CHECKOUT
+ - *CI_SCRIPT_IN_DOCKER
+ - *PRINT_LOGS
- - name: CI script
- env: ${{ matrix.configuration.env_vars }}
- uses: ./.github/actions/run-in-docker-action
- with:
- dockerfile: ./ci/linux-debian.Dockerfile
- tag: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
-
- macos-native:
- name: "x86_64: macOS Monterey"
- # See: https://github.com/actions/runner-images#available-images.
- runs-on: macos-12 # Use M1 once available https://github.com/github/roadmap/issues/528
+ x86_64-macos-native:
+ name: "x86_64: macOS Sequoia, Valgrind"
+ runs-on: macos-15-intel
env:
CC: 'clang'
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
+ SYMBOL_CHECK: 'no'
strategy:
fail-fast: false
matrix:
env_vars:
- - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- - { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 }
- - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
+ - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
+ - { WIDEMUL: 'int128_struct', ECMULTGENKB: 2, ECMULTWINDOW: 4 }
+ - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes' }
- - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CC: 'gcc' }
- - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
- - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
- - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', MUSIG: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' }
+ - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
+ - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CC: 'gcc' }
+ - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
+ - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
+ - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' }
- BUILD: 'distcheck'
steps:
- - name: Checkout
- uses: actions/checkout@v4
+ - *CHECKOUT
- name: Install Homebrew packages
run: |
@@ -731,27 +567,23 @@ 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
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ - &SYMBOL_CHECK_MACOS
+ name: Symbol check
+ env:
+ VIRTUAL_ENV: '${{ github.workspace }}/venv'
+ run: |
+ python3 --version
+ python3 -m venv $VIRTUAL_ENV
+ export PATH="$VIRTUAL_ENV/bin:$PATH"
+ python3 -m pip install lief
+ python3 ./tools/symbol-check.py .libs/libsecp256k1.dylib
+
+ - *PRINT_LOGS
arm64-macos-native:
name: "ARM64: macOS Sonoma"
@@ -764,50 +596,32 @@ jobs:
HOMEBREW_NO_INSTALL_CLEANUP: 1
WITH_VALGRIND: 'no'
CTIMETESTS: 'no'
+ SYMBOL_CHECK: 'no'
strategy:
fail-fast: false
matrix:
env_vars:
- - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- - { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 }
- - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
+ - { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
+ - { WIDEMUL: 'int128_struct', ECMULTGENKB: 2, ECMULTWINDOW: 4 }
+ - { WIDEMUL: 'int128', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
- { WIDEMUL: 'int128', RECOVERY: 'yes' }
- - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
- - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' }
- - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY' }
+ - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes' }
+ - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CC: 'gcc' }
+ - { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', EXTRAKEYS: 'yes', SCHNORRSIG: 'yes', MUSIG: 'yes', ELLSWIFT: 'yes', EXPERIMENTAL: 'yes', ECDSA_S2C: 'yes', RANGEPROOF: 'yes', SURJECTIONPROOF: 'yes', WHITELIST: 'yes', GENERATOR: 'yes', ECDSAADAPTOR: 'yes', BPPP: 'yes', SCHNORRSIG_HALFAGG: 'yes', CPPFLAGS: '-DVERIFY' }
- 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
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ - *CI_SCRIPT_ON_HOST
+ - *SYMBOL_CHECK_MACOS
+ - *PRINT_LOGS
win64-native:
name: ${{ matrix.configuration.job_name }}
@@ -820,6 +634,7 @@ jobs:
configuration:
- job_name: 'x64 (MSVC): Windows (VS 2022, shared)'
cmake_options: '-A x64 -DBUILD_SHARED_LIBS=ON'
+ symbol_check: 'true'
- job_name: 'x64 (MSVC): Windows (VS 2022, static)'
cmake_options: '-A x64 -DBUILD_SHARED_LIBS=OFF'
- job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct)'
@@ -829,10 +644,19 @@ jobs:
cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE'
- job_name: 'x86 (MSVC): Windows (VS 2022)'
cmake_options: '-A Win32'
+ - 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 }}
@@ -846,6 +670,14 @@ jobs:
run: |
cd build/bin/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true
+ - name: Symbol check
+ if: ${{ matrix.configuration.symbol_check }}
+ shell: bash
+ run: |
+ py -3 --version
+ py -3 -m pip install lief
+ py -3 ./tools/symbol-check.py build/bin/RelWithDebInfo/libsecp256k1-*.dll
+
- name: Check
run: |
ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1)
@@ -859,14 +691,12 @@ jobs:
runs-on: windows-2022
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: Add cl.exe to PATH
- uses: ilammy/msvc-dev-cmd@v1
+ - *CHECKOUT
- name: C++ (public headers)
+ shell: cmd
run: |
+ call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
cl.exe -c -WX -TP include/*.h
cxx_fpermissive_debian:
@@ -874,6 +704,11 @@ jobs:
runs-on: ubuntu-latest
needs: docker_cache
+ strategy:
+ matrix:
+ configuration:
+ - env_vars: {}
+
env:
CC: 'g++'
CFLAGS: '-fpermissive -g'
@@ -889,39 +724,16 @@ jobs:
ECDSA_S2C: 'yes'
GENERATOR: 'yes'
RANGEPROOF: 'yes'
+ SURJECTIONPROOF: 'yes'
WHITELIST: 'yes'
- MUSIG: 'yes'
ECDSAADAPTOR: 'yes'
BPPP: 'yes'
SCHNORRSIG_HALFAGG: 'yes'
steps:
- - name: Checkout
- uses: actions/checkout@v4
-
- - name: CI script
- uses: ./.github/actions/run-in-docker-action
- with:
- dockerfile: ./ci/linux-debian.Dockerfile
- tag: linux-debian-image
-
- - run: cat tests.log || true
- if: ${{ always() }}
- - run: cat noverify_tests.log || true
- if: ${{ always() }}
- - run: cat exhaustive_tests.log || true
- if: ${{ always() }}
- - run: cat ctime_tests.log || true
- if: ${{ always() }}
- - run: cat bench.log || true
- if: ${{ always() }}
- - run: cat config.log || true
- if: ${{ always() }}
- - run: cat test_env.log || true
- if: ${{ always() }}
- - name: CI env
- run: env
- if: ${{ always() }}
+ - *CHECKOUT
+ - *CI_SCRIPT_IN_DOCKER
+ - *PRINT_LOGS
cxx_headers_debian:
name: "C++ (public headers)"
@@ -929,14 +741,13 @@ 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: linux-debian-image
+ scope: ${{ runner.arch }}-${{ needs.docker_cache.outputs.cache_scope }}
command: |
g++ -Werror include/*.h
clang -Werror -x c++-header include/*.h
@@ -949,8 +760,7 @@ jobs:
options: --user root
steps:
- - name: Checkout
- uses: actions/checkout@v4
+ - *CHECKOUT
- name: CI script
run: |
@@ -961,8 +771,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- - name: Checkout
- uses: actions/checkout@v4
+ - *CHECKOUT
- run: ./autogen.sh && ./configure --enable-dev-mode && make distcheck
diff --git a/src/secp256k1/.github/workflows/sync.yml b/src/secp256k1/.github/workflows/sync.yml
new file mode 100644
index 0000000..22e3a6a
--- /dev/null
+++ b/src/secp256k1/.github/workflows/sync.yml
@@ -0,0 +1,61 @@
+name: Upstream Sync
+
+on:
+ schedule:
+ - cron: '0 0 1 * *'
+ workflow_dispatch:
+
+jobs:
+ sync-upstream:
+ runs-on: ubuntu-latest
+ env:
+ UPSTREAM: "https://github.com/bitcoin-core/secp256k1.git"
+ BASE_BRANCH: "master"
+ UPSTREAM_REF: "upstream/master"
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v6
+ with:
+ fetch-depth: 0
+ token: ${{ secrets.SYNC_PAT }}
+
+ - name: Configure Git
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "github-actions[bot]@users.noreply.github.com"
+
+ - name: Fetch upstream
+ run: |
+ git remote add upstream ${{ env.UPSTREAM }}
+ git fetch upstream
+ gh repo set-default ${{ github.repository }}
+ env:
+ GH_TOKEN: ${{ secrets.SYNC_PAT }}
+
+ - name: Run sync-upstream.sh
+ id: sync
+ run: |
+ OUTPUT=$(./contrib/sync-upstream.sh --switch "${{ env.BASE_BRANCH }}" "${{ env.UPSTREAM_REF }}" 2>&1) || { echo "$OUTPUT"; exit 1; }
+ echo "$OUTPUT"
+ if echo "$OUTPUT" | grep -qv "^No merge commits"; then
+ echo "newcommits=true" >> "$GITHUB_OUTPUT"
+ else
+ echo "Skipping further workflow steps."
+ fi
+
+ - name: Push sync branch
+ id: push
+ if: steps.sync.outputs.newcommits == 'true'
+ run: |
+ if git push -u origin HEAD; then
+ echo "pushed=true" >> "$GITHUB_OUTPUT"
+ else
+ echo "Skipping further workflow steps."
+ fi
+
+ - name: Create pull request
+ if: steps.sync.outputs.newcommits == 'true' && steps.push.outputs.pushed == 'true'
+ env:
+ GH_TOKEN: ${{ secrets.SYNC_PAT }}
+ run: ./gh-pr-create.sh
diff --git a/src/secp256k1/.gitignore b/src/secp256k1/.gitignore
index c394577..8658272 100644
--- a/src/secp256k1/.gitignore
+++ b/src/secp256k1/.gitignore
@@ -7,7 +7,6 @@ bench_internal
bench_whitelist
noverify_tests
tests
-example_musig
exhaustive_tests
precompute_ecmult_gen
precompute_ecmult
@@ -50,26 +49,17 @@ coverage.*.html
*.gcno
*.gcov
-build-aux/ar-lib
-build-aux/config.guess
-build-aux/config.sub
-build-aux/depcomp
-build-aux/install-sh
-build-aux/ltmain.sh
-build-aux/m4/libtool.m4
-build-aux/m4/lt~obsolete.m4
-build-aux/m4/ltoptions.m4
-build-aux/m4/ltsugar.m4
-build-aux/m4/ltversion.m4
-build-aux/missing
-build-aux/compile
-build-aux/test-driver
+/autotools-aux/
+!/autotools-aux/m4/bitcoin_secp.m4
+
libsecp256k1.pc
contrib/gh-pr-create.sh
-musig_example
-
### CMake
/CMakeUserPresets.json
-# Default CMake build directory.
-/build
+# CMake build directories.
+/*build*
+
+### Python
+__pycache__/
+*.py[oc]
diff --git a/src/secp256k1/CHANGELOG.md b/src/secp256k1/CHANGELOG.md
index bbb704e..48cbdaf 100644
--- a/src/secp256k1/CHANGELOG.md
+++ b/src/secp256k1/CHANGELOG.md
@@ -8,6 +8,43 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [Unreleased]
+
+## [0.7.1] - 2026-01-26
+
+#### Changed
+ - Tests: Introduced a unit test framework with support for parallel test execution, selective test running, and named command-line arguments. Run `./tests -help` for usage information.
+
+#### Fixed
+ - Increased the number of cases where the library attempts to clear secrets from the stack.
+ - build: Fixed x86_64 assembly feature check that could fail when user-provided `CFLAGS` included `-Werror`. This would cause the build to fall back to the slower C implementation instead of using the optimized x86_64 assembly.
+
+#### ABI Compatibility
+The ABI is backward compatible with version 0.7.0.
+
+## [0.7.0] - 2025-07-21
+
+#### Added
+ - CMake: Added `secp256k1_objs` interface library to allow parent projects to embed libsecp256k1 object files into their own static libraries.
+ - build: Added `SECP256K1_NO_API_VISIBILITY_ATTRIBUTES` preprocessor flag (CMake option: `SECP256K1_ENABLE_API_VISIBILITY_ATTRIBUTES`) that disables explicit "visibility" attributes for API symbols. Defining this macro enables the user to control the visibility of the API symbols via `-fvisibility=<value>` when building libsecp256k1. (All non-API declarations will always have hidden visibility, even with `SECP256K1_ENABLE_API_VISIBILITY_ATTRIBUTES` defined.) For instance, `-fvisibility=hidden` can be useful even for the API symbols, e.g., when building a static libsecp256k1 which is linked into a shared library, and the latter should not re-export the libsecp256k1 API.
+
+#### Changed
+ - The pointers `secp256k1_context_static` and `secp256k1_context_no_precomp` to the constant context objects are now `const`.
+ - Removed `SECP256K1_WARN_UNUSED_RESULT` attribute (defined as `__attribute__ ((__warn_unused_result__))`) from several API functions that always return 1. Compilers will no longer warn if the return value is unused.
+ - CMake: Building with CMake is no longer considered experimental.
+ - CMake: The minimum required CMake version was increased to 3.22.
+ - CMake: Shared libraries built with CMake on FreeBSD now create the full versioned filename and symlink chain, matching the behavior of autotools builds.
+
+#### Removed
+- Removed previously deprecated function aliases `secp256k1_ec_privkey_negate`, `secp256k1_ec_privkey_tweak_add` and
+ `secp256k1_ec_privkey_tweak_mul`. Use `secp256k1_ec_seckey_negate`, `secp256k1_ec_seckey_tweak_add` and
+ `secp256k1_ec_seckey_tweak_mul` instead.
+
+#### ABI Compatibility
+The symbols `secp256k1_ec_privkey_negate`, `secp256k1_ec_privkey_tweak_add`, and `secp256k1_ec_privkey_tweak_mul` were removed.
+The pointers `secp256k1_context_static` and `secp256k1_context_no_precomp` have been made `const`.
+Otherwise, the library maintains backward compatibility with version 0.6.0.
+
## [0.6.0] - 2024-11-04
#### Added
@@ -111,7 +148,7 @@ We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to
- Fix "constant-timeness" issue with Clang >=14 that could leave applications using libsecp256k1 vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow and secret-dependent memory accesses in conditional moves of memory objects when libsecp256k1 is compiled with Clang >=14.
#### Added
- - Added tests against [Project Wycheproof's](https://github.com/google/wycheproof/) set of ECDSA test vectors (Bitcoin "low-S" variant), a fixed set of test cases designed to trigger various edge cases.
+ - Added tests against [Project Wycheproof's](https://github.com/C2SP/wycheproof/) set of ECDSA test vectors (Bitcoin "low-S" variant), a fixed set of test cases designed to trigger various edge cases.
#### Changed
- Increased minimum required CMake version to 3.13. CMake builds remain experimental.
@@ -165,6 +202,9 @@ This version was in fact never released.
The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6).
Therefore, this version number does not uniquely identify a set of source files.
+[Unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.7.1...HEAD
+[0.7.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.7.0...v0.7.1
+[0.7.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.6.0...v0.7.0
[0.6.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.1...v0.6.0
[0.5.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.5.0...v0.5.1
[0.5.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.1...v0.5.0
diff --git a/src/secp256k1/CMakeLists.txt b/src/secp256k1/CMakeLists.txt
index 8f83d27..c55cf10 100644
--- a/src/secp256k1/CMakeLists.txt
+++ b/src/secp256k1/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.16)
+cmake_minimum_required(VERSION 3.22)
#=============================
# Project / Package metadata
@@ -7,33 +7,22 @@ project(libsecp256k1
# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
# the API. All changes in experimental modules are treated as
# backwards-compatible and therefore at most increase the minor version.
- VERSION 0.6.0
+ VERSION 0.7.2
DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1."
HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1"
LANGUAGES C
)
enable_testing()
+include(CTestUseLaunchers) # Allow users to set CTEST_USE_LAUNCHERS in custom `ctest -S` scripts.
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
-if(CMAKE_VERSION VERSION_LESS 3.21)
- get_directory_property(parent_directory PARENT_DIRECTORY)
- if(parent_directory)
- set(PROJECT_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
- set(${PROJECT_NAME}_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
- else()
- set(PROJECT_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
- set(${PROJECT_NAME}_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
- endif()
- unset(parent_directory)
-endif()
-
# The library version is based on libtool versioning of the ABI. The set of
# rules for updating the version can be found here:
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
-set(${PROJECT_NAME}_LIB_VERSION_CURRENT 5)
-set(${PROJECT_NAME}_LIB_VERSION_REVISION 0)
+set(${PROJECT_NAME}_LIB_VERSION_CURRENT 6)
+set(${PROJECT_NAME}_LIB_VERSION_REVISION 2)
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
#=============================
@@ -45,18 +34,18 @@ 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})
+option(SECP256K1_ENABLE_API_VISIBILITY_ATTRIBUTES "Enable visibility attributes in the API." ON)
+
## Modules
# We declare all options before processing them, to make sure we can express
-# dependendencies while processing.
+# dependencies while processing.
option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
@@ -68,119 +57,35 @@ option(SECP256K1_ENABLE_MODULE_GENERATOR "Enable NUMS generator module." ON)
option(SECP256K1_ENABLE_MODULE_RANGEPROOF "Enable Range proof module." ON)
option(SECP256K1_ENABLE_MODULE_SURJECTIONPROOF "Enable Surjection proof module." ON)
option(SECP256K1_ENABLE_MODULE_WHITELIST "Enable key whitelist module." ON)
-option(SECP256K1_ENABLE_MODULE_MUSIG "Enable MuSig module." ON)
option(SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR "Enable ecdsa adaptor signatures module." ON)
option(SECP256K1_ENABLE_MODULE_ECDSA_S2C "Enable ECDSA sign-to-contract module." ON)
option(SECP256K1_ENABLE_MODULE_BPPP "Enable Bulletproofs++ module." ON)
-
-# Processing must be done in a topological sorting of the dependency graph
-# (dependent module first).
-if(SECP256K1_ENABLE_MODULE_BPPP)
- if(DEFINED SECP256K1_ENABLE_MODULE_GENERATOR AND NOT SECP256K1_ENABLE_MODULE_GENERATOR)
- message(FATAL_ERROR "Module dependency error: You have disabled the generator module explicitly, but it is required by the bppp module.")
- endif()
- set(SECP256K1_ENABLE_MODULE_GENERATOR ON)
- add_compile_definitions(ENABLE_MODULE_BPPP=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_ECDSA_S2C)
- add_compile_definitions(ENABLE_MODULE_ECDSA_S2C=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR)
- add_compile_definitions(ENABLE_MODULE_ECDSA_ADAPTOR=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_MUSIG)
- if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG)
- message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.")
- endif()
- set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON)
- add_compile_definitions(ENABLE_MODULE_MUSIG=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_WHITELIST)
- if(DEFINED SECP256K1_ENABLE_MODULE_RANGEPROOF AND NOT SECP256K1_ENABLE_MODULE_RANGEPROOF)
- message(FATAL_ERROR "Module dependency error: You have disabled the rangeproof module explicitly, but it is required by the whitelist module.")
- endif()
- set(SECP256K1_ENABLE_MODULE_RANGEPROOF ON)
- add_compile_definitions(ENABLE_MODULE_WHITELIST=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_SURJECTIONPROOF)
- if(DEFINED SECP256K1_ENABLE_MODULE_RANGEPROOF AND NOT SECP256K1_ENABLE_MODULE_RANGEPROOF)
- message(FATAL_ERROR "Module dependency error: You have disabled the rangeproof module explicitly, but it is required by the surjectionproof module.")
- endif()
- set(SECP256K1_ENABLE_MODULE_RANGEPROOF ON)
- add_compile_definitions(ENABLE_MODULE_SURJECTIONPROOF=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_RANGEPROOF)
- if(DEFINED SECP256K1_ENABLE_MODULE_GENERATOR AND NOT SECP256K1_ENABLE_MODULE_GENERATOR)
- message(FATAL_ERROR "Module dependency error: You have disabled the generator module explicitly, but it is required by the rangeproof module.")
- endif()
- set(SECP256K1_ENABLE_MODULE_GENERATOR ON)
- add_compile_definitions(ENABLE_MODULE_RANGEPROOF=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_GENERATOR)
- add_compile_definitions(ENABLE_MODULE_GENERATOR=1)
-endif()
-
-
-if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
- add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_MUSIG)
- if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG)
- message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.")
- endif()
- set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON)
- add_compile_definitions(ENABLE_MODULE_MUSIG=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
- if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS)
- message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.")
- endif()
- set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
- add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
- add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_RECOVERY)
- add_compile_definitions(ENABLE_MODULE_RECOVERY=1)
-endif()
-
-if(SECP256K1_ENABLE_MODULE_ECDH)
- add_compile_definitions(ENABLE_MODULE_ECDH=1)
-endif()
+option(SECP256K1_ENABLE_MODULE_SCHNORRSIG_HALFAGG "Enable schnorrsig half-aggregation module." ON)
option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1)
endif()
-set(SECP256K1_ECMULT_WINDOW_SIZE "AUTO" CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. \"AUTO\" is a reasonable setting for desktop machines (currently 15). [default=AUTO]")
-set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS "AUTO" 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24)
+set(SECP256K1_ECMULT_WINDOW_SIZE 15 CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. The default value is a reasonable setting for desktop machines (currently 15). [default=15]")
+set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24)
include(CheckStringOptionValue)
check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE)
-if(SECP256K1_ECMULT_WINDOW_SIZE STREQUAL "AUTO")
- set(SECP256K1_ECMULT_WINDOW_SIZE 15)
-endif()
add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE})
-set(SECP256K1_ECMULT_GEN_PREC_BITS "AUTO" CACHE STRING "Precision bits to tune the precomputed table size for signing, specified as integer 2, 4 or 8. \"AUTO\" is a reasonable setting for desktop machines (currently 4). [default=AUTO]")
-set_property(CACHE SECP256K1_ECMULT_GEN_PREC_BITS PROPERTY STRINGS "AUTO" 2 4 8)
-check_string_option_value(SECP256K1_ECMULT_GEN_PREC_BITS)
-if(SECP256K1_ECMULT_GEN_PREC_BITS STREQUAL "AUTO")
- set(SECP256K1_ECMULT_GEN_PREC_BITS 4)
+set(SECP256K1_ECMULT_GEN_KB 86 CACHE STRING "The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms). Larger values result in possibly better signing or key generation performance at the cost of a larger table. Valid choices are 2, 22, 86. The default value is a reasonable setting for desktop machines (currently 86). [default=86]")
+set_property(CACHE SECP256K1_ECMULT_GEN_KB PROPERTY STRINGS 2 22 86)
+check_string_option_value(SECP256K1_ECMULT_GEN_KB)
+if(SECP256K1_ECMULT_GEN_KB EQUAL 2)
+ add_compile_definitions(COMB_BLOCKS=2)
+ add_compile_definitions(COMB_TEETH=5)
+elseif(SECP256K1_ECMULT_GEN_KB EQUAL 22)
+ add_compile_definitions(COMB_BLOCKS=11)
+ add_compile_definitions(COMB_TEETH=6)
+elseif(SECP256K1_ECMULT_GEN_KB EQUAL 86)
+ add_compile_definitions(COMB_BLOCKS=43)
+ add_compile_definitions(COMB_TEETH=6)
endif()
-add_compile_definitions(ECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS})
set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]")
set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64")
@@ -278,43 +183,50 @@ mark_as_advanced(
CMAKE_SHARED_LINKER_FLAGS_COVERAGE
)
-get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
-set(default_build_type "RelWithDebInfo")
-if(is_multi_config)
- set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING
- "Supported configuration types."
- FORCE
- )
-else()
- set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
- STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage"
- )
- if(NOT CMAKE_BUILD_TYPE)
- message(STATUS "Setting build type to \"${default_build_type}\" as none was specified")
- set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING
- "Choose the type of build."
+if(PROJECT_IS_TOP_LEVEL)
+ get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ set(default_build_type "RelWithDebInfo")
+ if(is_multi_config)
+ set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING
+ "Supported configuration types."
FORCE
)
+ else()
+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
+ STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage"
+ )
+ if(NOT CMAKE_BUILD_TYPE)
+ message(STATUS "Setting build type to \"${default_build_type}\" as none was specified")
+ set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING
+ "Choose the type of build."
+ FORCE
+ )
+ endif()
endif()
endif()
include(TryAppendCFlags)
if(MSVC)
- # Keep the following commands ordered lexicographically.
+ # For both cl and clang-cl compilers.
try_append_c_flags(/W3) # Production quality warning level.
+ # Eliminate deprecation warnings for the older, less secure functions.
+ add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
+else()
+ try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers.
+endif()
+if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
+ # Keep the following commands ordered lexicographically.
try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
- # Eliminate deprecation warnings for the older, less secure functions.
- add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
else()
# Keep the following commands ordered lexicographically.
try_append_c_flags(-pedantic)
- try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers.
try_append_c_flags(-Wcast-align) # GCC >= 2.95.
try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0.
try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only.
try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
+ try_append_c_flags(-Wleading-whitespace=spaces) # GCC >= 15.0
try_append_c_flags(-Wnested-externs)
try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
@@ -322,24 +234,27 @@ else()
try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only.
try_append_c_flags(-Wshadow)
try_append_c_flags(-Wstrict-prototypes)
+ try_append_c_flags(-Wtrailing-whitespace=any) # GCC >= 15.0
try_append_c_flags(-Wundef)
endif()
-set(CMAKE_C_VISIBILITY_PRESET hidden)
-
-# Ask CTest to create a "check" target (e.g., make check) as alias for the "test" target.
-# CTEST_TEST_TARGET_ALIAS is not documented but supposed to be user-facing.
-# See: https://gitlab.kitware.com/cmake/cmake/-/commit/816c9d1aa1f2b42d40c81a991b68c96eb12b6d2
-set(CTEST_TEST_TARGET_ALIAS check)
-include(CTest)
-# We do not use CTest's BUILD_TESTING because a single toggle for all tests is too coarse for our needs.
-mark_as_advanced(BUILD_TESTING)
-if(SECP256K1_BUILD_BENCHMARK OR SECP256K1_BUILD_TESTS OR SECP256K1_BUILD_EXHAUSTIVE_TESTS OR SECP256K1_BUILD_CTIME_TESTS OR SECP256K1_BUILD_EXAMPLES)
- enable_testing()
+set(print_msan_notice)
+if(SECP256K1_BUILD_CTIME_TESTS)
+ include(CheckMemorySanitizer)
+ check_memory_sanitizer(msan_enabled)
+ if(msan_enabled)
+ try_append_c_flags(-fno-sanitize-memory-param-retval)
+ set(print_msan_notice YES)
+ endif()
+ unset(msan_enabled)
endif()
-set(SECP256K1_LATE_CFLAGS "" CACHE STRING "Compiler flags that are added to the command line after all other flags added by the build system.")
-include(AllTargetsCompileOptions)
+set(SECP256K1_APPEND_CFLAGS "" CACHE STRING "Compiler flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.")
+if(SECP256K1_APPEND_CFLAGS)
+ # Appending to this low-level rule variable is the only way to
+ # guarantee that the flags appear at the end of the command line.
+ string(APPEND CMAKE_C_COMPILE_OBJECT " ${SECP256K1_APPEND_CFLAGS}")
+endif()
set(SECP256K1_APPEND_LDFLAGS "" CACHE STRING "Linker flags that are appended to the command line after all other flags added by the build system. This variable is intended for debugging and special builds.")
if(SECP256K1_APPEND_LDFLAGS)
@@ -359,10 +274,8 @@ if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
endif()
add_subdirectory(src)
-all_targets_compile_options(src "${SECP256K1_LATE_CFLAGS}")
if(SECP256K1_BUILD_EXAMPLES)
add_subdirectory(examples)
- all_targets_compile_options(examples "${SECP256K1_LATE_CFLAGS}")
endif()
message("\n")
@@ -387,13 +300,13 @@ message(" generator ........................... ${SECP256K1_ENABLE_MODULE_GENER
message(" rangeproof .......................... ${SECP256K1_ENABLE_MODULE_RANGEPROOF}")
message(" surjectionproof ..................... ${SECP256K1_ENABLE_MODULE_SURJECTIONPROOF}")
message(" whitelist ........................... ${SECP256K1_ENABLE_MODULE_WHITELIST}")
-message(" musig ............................... ${SECP256K1_ENABLE_MODULE_MUSIG}")
message(" ecdsa-s2c ........................... ${SECP256K1_ENABLE_MODULE_ECDSA_S2C}")
message(" ecdsa-adaptor ....................... ${SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR}")
message(" bppp ................................ ${SECP256K1_ENABLE_MODULE_BPPP}")
+message(" schnorrsig-halfagg .................. ${SECP256K1_ENABLE_MODULE_SCHNORRSIG_HALFAGG}")
message("Parameters:")
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
-message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
+message(" ecmult gen table size ............... ${SECP256K1_ECMULT_GEN_KB} KiB")
message("Optional features:")
message(" assembly ............................ ${SECP256K1_ASM}")
message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}")
@@ -418,11 +331,12 @@ else()
set(cross_status "FALSE")
endif()
message("Cross compiling ....................... ${cross_status}")
+message("API visibility attributes ............. ${SECP256K1_ENABLE_API_VISIBILITY_ATTRIBUTES}")
message("Valgrind .............................. ${SECP256K1_VALGRIND}")
get_directory_property(definitions COMPILE_DEFINITIONS)
string(REPLACE ";" " " definitions "${definitions}")
message("Preprocessor defined macros ........... ${definitions}")
-message("C compiler ............................ ${CMAKE_C_COMPILER}")
+message("C compiler ............................ ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}, ${CMAKE_C_COMPILER}")
message("CFLAGS ................................ ${CMAKE_C_FLAGS}")
get_directory_property(compile_options COMPILE_OPTIONS)
string(REPLACE ";" " " compile_options "${compile_options}")
@@ -459,7 +373,6 @@ if(print_msan_notice)
" to avoid false positives in ctime_tests. Pass -DSECP256K1_BUILD_CTIME_TESTS=OFF to avoid this.\n"
)
endif()
-message("\n")
if(SECP256K1_EXPERIMENTAL)
message(
" ******\n"
diff --git a/src/secp256k1/CMakePresets.json b/src/secp256k1/CMakePresets.json
index b35cd80..6ed52b8 100644
--- a/src/secp256k1/CMakePresets.json
+++ b/src/secp256k1/CMakePresets.json
@@ -1,5 +1,4 @@
{
- "cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0},
"version": 3,
"configurePresets": [
{
diff --git a/src/secp256k1/CONTRIBUTING.md b/src/secp256k1/CONTRIBUTING.md
index a366d38..f001108 100644
--- a/src/secp256k1/CONTRIBUTING.md
+++ b/src/secp256k1/CONTRIBUTING.md
@@ -74,6 +74,7 @@ In addition, libsecp256k1 tries to maintain the following coding conventions:
* User-facing comment lines in headers should be limited to 80 chars if possible.
* All identifiers in file scope should start with `secp256k1_`.
* Avoid trailing whitespace.
+* Use the constants `EXIT_SUCCESS`/`EXIT_FAILURE` (defined in `stdlib.h`) to indicate program execution status for examples and other binaries.
### Tests
@@ -91,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
diff --git a/src/secp256k1/Makefile.am b/src/secp256k1/Makefile.am
index 9aded4b..51c8f6b 100644
--- a/src/secp256k1/Makefile.am
+++ b/src/secp256k1/Makefile.am
@@ -1,4 +1,4 @@
-ACLOCAL_AMFLAGS = -I build-aux/m4
+ACLOCAL_AMFLAGS = -I autotools-aux/m4
# AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo
# which does not have an explicit foo_CFLAGS variable set.
@@ -47,8 +47,12 @@ 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
noinst_HEADERS += src/int128_impl.h
noinst_HEADERS += src/int128_native.h
@@ -66,6 +70,8 @@ noinst_HEADERS += src/field.h
noinst_HEADERS += src/field_impl.h
noinst_HEADERS += src/bench.h
noinst_HEADERS += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
+noinst_HEADERS += src/hsort.h
+noinst_HEADERS += src/hsort_impl.h
noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
@@ -119,7 +125,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
@@ -184,17 +190,6 @@ schnorr_example_LDFLAGS += -lbcrypt
endif
TESTS += schnorr_example
endif
-if ENABLE_MODULE_MUSIG
-noinst_PROGRAMS += musig_example
-musig_example_SOURCES = examples/musig.c
-musig_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
-musig_example_LDADD = libsecp256k1.la
-musig_example_LDFLAGS = -static
-if BUILD_WINDOWS
-musig_example_LDFLAGS += -lbcrypt
-endif
-TESTS += musig_example
-endif
if ENABLE_MODULE_ELLSWIFT
noinst_PROGRAMS += ellswift_example
ellswift_example_SOURCES = examples/ellswift.c
@@ -260,9 +255,17 @@ maintainer-clean-local: clean-precomp
### (see the comments in the previous section for detailed rationale)
TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
+if ENABLE_MODULE_ECDH
+TESTVECTORS += src/wycheproof/ecdh_secp256k1_test.h
+endif
+
src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h:
mkdir -p $(@D)
- python3 $(top_srcdir)/tools/tests_wycheproof_generate.py $(top_srcdir)/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@
+ python3 $(top_srcdir)/tools/tests_wycheproof_generate_ecdsa.py $(top_srcdir)/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@
+
+src/wycheproof/ecdh_secp256k1_test.h:
+ mkdir -p $(@D)
+ python3 $(top_srcdir)/tools/tests_wycheproof_generate_ecdh.py $(top_srcdir)/src/wycheproof/ecdh_secp256k1_test.json > $@
testvectors: $(TESTVECTORS)
@@ -286,7 +289,9 @@ EXTRA_DIST += sage/secp256k1_params.sage
EXTRA_DIST += sage/weierstrass_prover.sage
EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING
EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json
-EXTRA_DIST += tools/tests_wycheproof_generate.py
+EXTRA_DIST += src/wycheproof/ecdh_secp256k1_test.json
+EXTRA_DIST += tools/tests_wycheproof_generate_ecdsa.py
+EXTRA_DIST += tools/tests_wycheproof_generate_ecdh.py
if ENABLE_MODULE_SCHNORRSIG_HALFAGG
include src/modules/schnorrsig_halfagg/Makefile.am.include
@@ -300,10 +305,6 @@ if ENABLE_MODULE_ECDH
include src/modules/ecdh/Makefile.am.include
endif
-if ENABLE_MODULE_MUSIG
-include src/modules/musig/Makefile.am.include
-endif
-
if ENABLE_MODULE_RECOVERY
include src/modules/recovery/Makefile.am.include
endif
diff --git a/src/secp256k1/README.md b/src/secp256k1/README.md
index 924947c..af62b83 100644
--- a/src/secp256k1/README.md
+++ b/src/secp256k1/README.md
@@ -3,67 +3,99 @@ libsecp256k1-zkp

-A fork of [libsecp256k1](https://github.com/bitcoin-core/secp256k1) with support for advanced and experimental features such as Confidential Assets and MuSig2
+A fork of [libsecp256k1](https://github.com/bitcoin-core/secp256k1) with support for advanced and experimental features
Added features:
* Experimental module for ECDSA adaptor signatures.
* Experimental module for ECDSA sign-to-contract.
-* Experimental module for [MuSig2](src/modules/musig/musig.md).
-* Experimental module for Confidential Assets (Pedersen commitments, range proofs, and [surjection proofs](src/modules/surjection/surjection.md)).
-* Experimental module for Bulletproofs++ range proofs.
+* Experimental modules for Confidential Assets (Pedersen commitments, range proofs, and [surjection proofs](src/modules/surjection/surjection.md)).
* Experimental module for [address whitelisting](src/modules/whitelist/whitelist.md).
+* Experimental module for Schnorr signature half-aggregation.
Experimental features are made available for testing and review by the community. The APIs of these features should not be considered stable.
Build steps
-----------
+Obtaining and verifying
+-----------------------
+
+The git tag for each release (e.g. `v0.6.0`) is GPG-signed by one of the maintainers.
+For a fully verified build of this project, it is recommended to obtain this repository
+via git, obtain the GPG keys of the signing maintainer(s), and then verify the release
+tag's signature using git.
+
+This can be done with the following steps:
+
+1. Obtain the GPG keys listed in [SECURITY.md](./SECURITY.md).
+2. If possible, cross-reference these key IDs with another source controlled by its owner (e.g.
+ social media, personal website). This is to mitigate the unlikely case that incorrect
+ content is being presented by this repository.
+3. Clone the repository:
+ ```
+ git clone https://github.com/bitcoin-core/secp256k1
+ ```
+4. Check out the latest release tag, e.g.
+ ```
+ git checkout v0.6.0
+ ```
+5. Use git to verify the GPG signature:
+ ```
+ % git tag -v v0.6.0 | grep -C 3 'Good signature'
+
+ gpg: Signature made Mon 04 Nov 2024 12:14:44 PM EST
+ gpg: using RSA key 4BBB845A6F5A65A69DFAEC234861DBF262123605
+ gpg: Good signature from "Jonas Nick <jonas@n-ck.net>" [unknown]
+ gpg: aka "Jonas Nick <jonasd.nick@gmail.com>" [unknown]
+ gpg: WARNING: This key is not certified with a trusted signature!
+ gpg: There is no indication that the signature belongs to the owner.
+ Primary key fingerprint: 36C7 1A37 C9D9 88BD E825 08D9 B1A7 0E4F 8DCD 0366
+ Subkey fingerprint: 4BBB 845A 6F5A 65A6 9DFA EC23 4861 DBF2 6212 3605
+ ```
+
Building with Autotools
-----------------------
- $ ./autogen.sh
- $ ./configure
- $ make
- $ make check # run the test suite
- $ sudo make install # optional
+ $ ./autogen.sh # Generate a ./configure script
+ $ ./configure # Generate a build system
+ $ make # Run the actual build process
+ $ make check # Run the test suite
+ $ sudo make install # Install the library into the system (optional)
-To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags. For experimental modules, you will also need `--enable-experimental` as well as a flag for each individual module, e.g. `--enable-module-musig`.
+To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags. For experimental modules, you will also need `--enable-experimental` as well as a flag for each individual module, e.g. `--enable-module-rangeproof`.
-Building with CMake (experimental)
-----------------------------------
+Building with CMake
+-------------------
To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree.
### Building on POSIX systems
- $ mkdir build && cd build
- $ cmake ..
- $ cmake --build .
- $ ctest # run the test suite
- $ sudo cmake --install . # optional
+ $ cmake -B build # Generate a build system in subdirectory "build"
+ $ cmake --build build # Run the actual build process
+ $ ctest --test-dir build # Run the test suite
+ $ sudo cmake --install build # Install the library into the system (optional)
-To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake .. -LH` to see the full list of available flags.
+To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake -B build -LH` or `ccmake -B build` to see the full list of available flags.
### Cross compiling
To alleviate issues with cross compiling, preconfigured toolchain files are available in the `cmake` directory.
For example, to cross compile for Windows:
- $ cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-w64-mingw32.toolchain.cmake
+ $ cmake -B build -DCMAKE_TOOLCHAIN_FILE=cmake/x86_64-w64-mingw32.toolchain.cmake
To cross compile for Android with [NDK](https://developer.android.com/ndk/guides/cmake) (using NDK's toolchain file, and assuming the `ANDROID_NDK_ROOT` environment variable has been set):
- $ cmake .. -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28
+ $ cmake -B build -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28
### Building on Windows
-To build on Windows with Visual Studio, a proper [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) must be specified for a new build tree.
-
-The following example assumes using of Visual Studio 2022 and CMake v3.21+.
+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 -S . -B build
+ >cmake -B build -T ClangCL
>cmake --build build --config RelWithDebInfo
Usage examples
@@ -73,10 +105,10 @@ Usage examples can be found in the [examples](examples) directory. To compile th
* [ECDSA example](examples/ecdsa.c)
* [Schnorr signatures example](examples/schnorr.c)
* [Deriving a shared secret (ECDH) example](examples/ecdh.c)
- * [MuSig example](examples/musig.c)
* [ElligatorSwift key exchange example](examples/ellswift.c)
+ * [MuSig2 Schnorr multi-signatures example](examples/musig.c)
-To compile the Schnorr signature, ECDH and MuSig examples, you need to enable the corresponding module by providing a flag to the `configure` script, for example `--enable-module-schnorrsig`.
+To compile the examples, make sure the corresponding modules are enabled.
Benchmark
------------
diff --git a/src/secp256k1/autotools-aux/m4/bitcoin_secp.m4 b/src/secp256k1/autotools-aux/m4/bitcoin_secp.m4
new file mode 100644
index 0000000..1428d4d
--- /dev/null
+++ b/src/secp256k1/autotools-aux/m4/bitcoin_secp.m4
@@ -0,0 +1,91 @@
+dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
+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 = 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])
+])
+
+AC_DEFUN([SECP_ARM32_ASM_CHECK], [
+ AC_MSG_CHECKING(for ARM32 assembly availability)
+ SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS"
+ CFLAGS="-x assembler"
+ AC_LINK_IFELSE([AC_LANG_SOURCE([[
+ .syntax unified
+ .eabi_attribute 24, 1
+ .eabi_attribute 25, 1
+ .text
+ .global main
+ main:
+ ldr r0, =0x002A
+ mov r7, #1
+ swi 0
+ ]])], [has_arm32_asm=yes], [has_arm32_asm=no])
+ AC_MSG_RESULT([$has_arm32_asm])
+ CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS"
+])
+
+AC_DEFUN([SECP_VALGRIND_CHECK],[
+AC_MSG_CHECKING([for valgrind support])
+if test x"$has_valgrind" != x"yes"; then
+ CPPFLAGS_TEMP="$CPPFLAGS"
+ CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+ #include <valgrind/memcheck.h>
+ ]], [[
+ #if defined(NVALGRIND)
+ # error "Valgrind does not support this platform."
+ #endif
+ ]])], [has_valgrind=yes])
+ CPPFLAGS="$CPPFLAGS_TEMP"
+fi
+AC_MSG_RESULT($has_valgrind)
+])
+
+AC_DEFUN([SECP_MSAN_CHECK], [
+AC_MSG_CHECKING(whether MemorySanitizer is enabled)
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ #if defined(__has_feature)
+ # if __has_feature(memory_sanitizer)
+ /* MemorySanitizer is enabled. */
+ # elif
+ # error "MemorySanitizer is disabled."
+ # endif
+ #else
+ # error "__has_feature is not defined."
+ #endif
+ ]])], [msan_enabled=yes], [msan_enabled=no])
+AC_MSG_RESULT([$msan_enabled])
+])
+
+dnl SECP_TRY_APPEND_CFLAGS(flags, VAR)
+dnl Append flags to VAR if CC accepts them.
+AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [
+ AC_MSG_CHECKING([if ${CC} supports $1])
+ SECP_TRY_APPEND_CFLAGS_saved_CFLAGS="$CFLAGS"
+ CFLAGS="$1 $CFLAGS"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], [flag_works=yes], [flag_works=no])
+ AC_MSG_RESULT($flag_works)
+ CFLAGS="$SECP_TRY_APPEND_CFLAGS_saved_CFLAGS"
+ if test x"$flag_works" = x"yes"; then
+ $2="$$2 $1"
+ fi
+ unset flag_works
+ AC_SUBST($2)
+])
+
+dnl SECP_SET_DEFAULT(VAR, default, default-dev-mode)
+dnl Set VAR to default or default-dev-mode, depending on whether dev mode is enabled
+AC_DEFUN([SECP_SET_DEFAULT], [
+ if test "${enable_dev_mode+set}" != set; then
+ AC_MSG_ERROR([[Set enable_dev_mode before calling SECP_SET_DEFAULT]])
+ fi
+ if test x"$enable_dev_mode" = x"yes"; then
+ $1="$3"
+ else
+ $1="$2"
+ fi
+])
diff --git a/src/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/secp256k1/build-aux/m4/bitcoin_secp.m4
deleted file mode 100644
index 11adef4..0000000
--- a/src/secp256k1/build-aux/m4/bitcoin_secp.m4
+++ /dev/null
@@ -1,75 +0,0 @@
-dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
-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;
- __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])
-])
-
-AC_DEFUN([SECP_ARM32_ASM_CHECK], [
- AC_MSG_CHECKING(for ARM32 assembly availability)
- SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS"
- CFLAGS="-x assembler"
- AC_LINK_IFELSE([AC_LANG_SOURCE([[
- .syntax unified
- .eabi_attribute 24, 1
- .eabi_attribute 25, 1
- .text
- .global main
- main:
- ldr r0, =0x002A
- mov r7, #1
- swi 0
- ]])], [has_arm32_asm=yes], [has_arm32_asm=no])
- AC_MSG_RESULT([$has_arm32_asm])
- CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS"
-])
-
-AC_DEFUN([SECP_VALGRIND_CHECK],[
-AC_MSG_CHECKING([for valgrind support])
-if test x"$has_valgrind" != x"yes"; then
- CPPFLAGS_TEMP="$CPPFLAGS"
- CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
- #include <valgrind/memcheck.h>
- ]], [[
- #if defined(NVALGRIND)
- # error "Valgrind does not support this platform."
- #endif
- ]])], [has_valgrind=yes])
- CPPFLAGS="$CPPFLAGS_TEMP"
-fi
-AC_MSG_RESULT($has_valgrind)
-])
-
-dnl SECP_TRY_APPEND_CFLAGS(flags, VAR)
-dnl Append flags to VAR if CC accepts them.
-AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [
- AC_MSG_CHECKING([if ${CC} supports $1])
- SECP_TRY_APPEND_CFLAGS_saved_CFLAGS="$CFLAGS"
- CFLAGS="$1 $CFLAGS"
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], [flag_works=yes], [flag_works=no])
- AC_MSG_RESULT($flag_works)
- CFLAGS="$SECP_TRY_APPEND_CFLAGS_saved_CFLAGS"
- if test x"$flag_works" = x"yes"; then
- $2="$$2 $1"
- fi
- unset flag_works
- AC_SUBST($2)
-])
-
-dnl SECP_SET_DEFAULT(VAR, default, default-dev-mode)
-dnl Set VAR to default or default-dev-mode, depending on whether dev mode is enabled
-AC_DEFUN([SECP_SET_DEFAULT], [
- if test "${enable_dev_mode+set}" != set; then
- AC_MSG_ERROR([[Set enable_dev_mode before calling SECP_SET_DEFAULT]])
- fi
- if test x"$enable_dev_mode" = x"yes"; then
- $1="$3"
- else
- $1="$2"
- fi
-])
diff --git a/src/secp256k1/ci/ci.sh b/src/secp256k1/ci/ci.sh
index 3d1f94c..2185e78 100755
--- a/src/secp256k1/ci/ci.sh
+++ b/src/secp256k1/ci/ci.sh
@@ -12,10 +12,10 @@ print_environment() {
# There are many ways to print variable names and their content. This one
# does not rely on bash.
for var in WERROR_CFLAGS MAKEFLAGS BUILD \
- ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
- EXPERIMENTAL ECDH RECOVERY EXTRAKEYS SCHNORRSIG SCHNORRSIG_HALFAGG ELLSWIFT \
- ECDSA_S2C GENERATOR RANGEPROOF WHITELIST MUSIG ECDSAADAPTOR BPPP \
- SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
+ ECMULTWINDOW ECMULTGENKB ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
+ EXPERIMENTAL ECDH RECOVERY EXTRAKEYS SCHNORRSIG MUSIG SCHNORRSIG_HALFAGG ELLSWIFT \
+ ECDSA_S2C GENERATOR RANGEPROOF SURJECTIONPROOF WHITELIST ECDSAADAPTOR BPPP \
+ SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS SYMBOL_CHECK \
EXAMPLES \
HOST WRAPPER_CMD \
CC CFLAGS CPPFLAGS AR NM \
@@ -53,37 +53,21 @@ if [ -n "$WRAPPER_CMD" ]; then
$WRAPPER_CMD --version
fi
-# Workaround for https://bugs.kde.org/show_bug.cgi?id=452758 (fixed in valgrind 3.20.0).
-case "${CC:-undefined}" in
- clang*)
- if [ "$CTIMETESTS" = "yes" ] && [ "$WITH_VALGRIND" = "yes" ]
- then
- export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4"
- else
- case "$WRAPPER_CMD" in
- valgrind*)
- export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4"
- ;;
- esac
- fi
- ;;
-esac
-
./autogen.sh
./configure \
--enable-experimental="$EXPERIMENTAL" \
--with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \
--with-ecmult-window="$ECMULTWINDOW" \
- --with-ecmult-gen-precision="$ECMULTGENPRECISION" \
+ --with-ecmult-gen-kb="$ECMULTGENKB" \
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
--enable-module-ellswift="$ELLSWIFT" \
+ --enable-module-extrakeys="$EXTRAKEYS" \
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
--enable-module-bppp="$BPPP" \
- --enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
- --enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
- --enable-module-extrakeys="$EXTRAKEYS" \
- --enable-module-schnorrsig="$SCHNORRSIG" \
+ --enable-module-rangeproof="$RANGEPROOF" --enable-module-surjectionproof="$SURJECTIONPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
+ --enable-module-schnorrsig="$SCHNORRSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
+ --enable-module-musig="$MUSIG" \
--enable-module-schnorrsig-halfagg="$SCHNORRSIG_HALFAGG" \
--enable-examples="$EXAMPLES" \
--enable-ctime-tests="$CTIMETESTS" \
@@ -99,10 +83,10 @@ if [ $build_exit_code -ne 0 ]; then
*snapshot*)
# Ignore internal compiler errors in gcc-snapshot and clang-snapshot
grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log
- return $?;
+ exit $?
;;
*)
- return 1;
+ exit 1
;;
esac
fi
@@ -112,6 +96,20 @@ file *tests* || true
file bench* || true
file .libs/* || true
+if [ "$SYMBOL_CHECK" = "yes" ]
+then
+ python3 --version
+ case "$HOST" in
+ *mingw*)
+ ls -l .libs
+ python3 ./tools/symbol-check.py .libs/libsecp256k1-*.dll
+ ;;
+ *)
+ python3 ./tools/symbol-check.py .libs/libsecp256k1.so
+ ;;
+ esac
+fi
+
# This tells `make check` to wrap test invocations.
export LOG_COMPILER="$WRAPPER_CMD"
diff --git a/src/secp256k1/ci/linux-debian.Dockerfile b/src/secp256k1/ci/linux-debian.Dockerfile
index 241bfa9..a609bc6 100644
--- a/src/secp256k1/ci/linux-debian.Dockerfile
+++ b/src/secp256k1/ci/linux-debian.Dockerfile
@@ -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 \
@@ -32,16 +32,17 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
gcc-mingw-w64-x86-64-win32 wine64 wine \
gcc-mingw-w64-i686-win32 wine32 \
- python3 && \
+ python3-full && \
if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \
- apt-get install --no-install-recommends -y \
+ 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=15
-RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \
+ARG GCC_SNAPSHOT_MAJOR=17
+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,18 +63,25 @@ 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 && \
+ # Temporarily work around Sequoia PGP policy deadline for legacy repositories.
+ # See https://github.com/llvm/llvm-project/issues/153385.
+ sed -i 's/\(sha1\.second_preimage_resistance =\).*/\1 9999-01-01/' /usr/share/apt/default-sequoia.config && \
apt-get update && \
# Determine the version number of the LLVM development branch
LLVM_VERSION=$(apt-cache search --names-only '^clang-[0-9]+$' | sort -V | tail -1 | cut -f1 -d" " | cut -f2 -d"-" ) && \
# Install
- apt-get install --no-install-recommends -y "clang-${LLVM_VERSION}" && \
+ 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
apt-get autoremove -y wget && \
apt-get clean && rm -rf /var/lib/apt/lists/*
+ENV VIRTUAL_ENV=/root/venv
+RUN python3 -m venv $VIRTUAL_ENV
+ENV PATH="$VIRTUAL_ENV/bin:$PATH"
+RUN pip install lief
diff --git a/src/secp256k1/cmake/AllTargetsCompileOptions.cmake b/src/secp256k1/cmake/AllTargetsCompileOptions.cmake
deleted file mode 100644
index 6e420e0..0000000
--- a/src/secp256k1/cmake/AllTargetsCompileOptions.cmake
+++ /dev/null
@@ -1,12 +0,0 @@
-# Add compile options to all targets added in the subdirectory.
-function(all_targets_compile_options dir options)
- get_directory_property(targets DIRECTORY ${dir} BUILDSYSTEM_TARGETS)
- separate_arguments(options)
- set(compiled_target_types STATIC_LIBRARY SHARED_LIBRARY OBJECT_LIBRARY EXECUTABLE)
- foreach(target ${targets})
- get_target_property(type ${target} TYPE)
- if(type IN_LIST compiled_target_types)
- target_compile_options(${target} PRIVATE ${options})
- endif()
- endforeach()
-endfunction()
diff --git a/src/secp256k1/cmake/CheckArm32Assembly.cmake b/src/secp256k1/cmake/CheckArm32Assembly.cmake
index 15c44b2..baeeff0 100644
--- a/src/secp256k1/cmake/CheckArm32Assembly.cmake
+++ b/src/secp256k1/cmake/CheckArm32Assembly.cmake
@@ -1,6 +1,6 @@
function(check_arm32_assembly)
try_compile(HAVE_ARM32_ASM
- ${CMAKE_BINARY_DIR}/check_arm32_assembly
- SOURCES ${CMAKE_SOURCE_DIR}/cmake/source_arm32.s
+ ${PROJECT_BINARY_DIR}/check_arm32_assembly
+ SOURCES ${PROJECT_SOURCE_DIR}/cmake/source_arm32.s
)
endfunction()
diff --git a/src/secp256k1/cmake/CheckMemorySanitizer.cmake b/src/secp256k1/cmake/CheckMemorySanitizer.cmake
new file mode 100644
index 0000000..d9ef681
--- /dev/null
+++ b/src/secp256k1/cmake/CheckMemorySanitizer.cmake
@@ -0,0 +1,18 @@
+include_guard(GLOBAL)
+include(CheckCSourceCompiles)
+
+function(check_memory_sanitizer output)
+ set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+ check_c_source_compiles("
+ #if defined(__has_feature)
+ # if __has_feature(memory_sanitizer)
+ /* MemorySanitizer is enabled. */
+ # elif
+ # error \"MemorySanitizer is disabled.\"
+ # endif
+ #else
+ # error \"__has_feature is not defined.\"
+ #endif
+ " HAVE_MSAN)
+ set(${output} ${HAVE_MSAN} PARENT_SCOPE)
+endfunction()
diff --git a/src/secp256k1/cmake/CheckX86_64Assembly.cmake b/src/secp256k1/cmake/CheckX86_64Assembly.cmake
index ae82cd4..ca18919 100644
--- a/src/secp256k1/cmake/CheckX86_64Assembly.cmake
+++ b/src/secp256k1/cmake/CheckX86_64Assembly.cmake
@@ -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)
diff --git a/src/secp256k1/cmake/DiscoverTests.cmake b/src/secp256k1/cmake/DiscoverTests.cmake
new file mode 100644
index 0000000..683780a
--- /dev/null
+++ b/src/secp256k1/cmake/DiscoverTests.cmake
@@ -0,0 +1,71 @@
+# TODO: rework/remove once test discovery is implemented upstream:
+# https://gitlab.kitware.com/cmake/cmake/-/issues/26920
+function(discover_tests target)
+ set(options "")
+ set(oneValueArgs DISCOVERY_MATCH TEST_NAME_REPLACEMENT TEST_ARGS_REPLACEMENT)
+ set(multiValueArgs DISCOVERY_ARGS PROPERTIES)
+ cmake_parse_arguments(PARSE_ARGV 1 arg "${options}" "${oneValueArgs}" "${multiValueArgs}")
+
+ set(file_base ${CMAKE_CURRENT_BINARY_DIR}/${target})
+ set(include_file ${file_base}_include.cmake)
+
+ set(properties_content)
+ list(LENGTH arg_PROPERTIES properties_len)
+ if(properties_len GREATER "0")
+ set(properties_content " set_tests_properties(\"\${test_name}\" PROPERTIES\n")
+ math(EXPR num_properties "${properties_len} / 2")
+ foreach(i RANGE 0 ${num_properties} 2)
+ math(EXPR value_index "${i} + 1")
+ list(GET arg_PROPERTIES ${i} name)
+ list(GET arg_PROPERTIES ${value_index} value)
+ string(APPEND properties_content " \"${name}\" \"${value}\"\n")
+ endforeach()
+ string(APPEND properties_content " )\n")
+ endif()
+
+ string(CONCAT include_content
+ "set(runner [[$<TARGET_FILE:${target}>]])\n"
+ "set(launcher [[$<TARGET_PROPERTY:${target},TEST_LAUNCHER>]])\n"
+ "set(emulator [[$<$<BOOL:${CMAKE_CROSSCOMPILING}>:$<TARGET_PROPERTY:${target},CROSSCOMPILING_EMULATOR>>]])\n"
+ "\n"
+ "execute_process(\n"
+ " COMMAND \${launcher} \${emulator} \${runner} ${arg_DISCOVERY_ARGS}\n"
+ " OUTPUT_VARIABLE output OUTPUT_STRIP_TRAILING_WHITESPACE\n"
+ " ERROR_VARIABLE output ERROR_STRIP_TRAILING_WHITESPACE\n"
+ " RESULT_VARIABLE result\n"
+ ")\n"
+ "\n"
+ "if(NOT result EQUAL 0)\n"
+ " add_test([[${target}_DISCOVERY_FAILURE]] \${launcher} \${emulator} \${runner} ${arg_DISCOVERY_ARGS})\n"
+ "else()\n"
+ " string(REPLACE \"\\n\" \";\" lines \"\${output}\")\n"
+ " foreach(line IN LISTS lines)\n"
+ " if(line MATCHES \"${arg_DISCOVERY_MATCH}\")\n"
+ " string(REGEX REPLACE \"${arg_DISCOVERY_MATCH}\" \"${arg_TEST_NAME_REPLACEMENT}\" test_name \"\${line}\")\n"
+ " string(REGEX REPLACE \"${arg_DISCOVERY_MATCH}\" \"${arg_TEST_ARGS_REPLACEMENT}\" test_args \"\${line}\")\n"
+ " separate_arguments(test_args)\n"
+ " add_test(\"\${test_name}\" \${launcher} \${emulator} \${runner} \${test_args})\n"
+ ${properties_content}
+ " endif()\n"
+ " endforeach()\n"
+ "endif()\n"
+ )
+
+ get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ file(GENERATE
+ OUTPUT ${file_base}_include-$<CONFIG>.cmake
+ CONTENT "${include_content}"
+ )
+ file(WRITE ${include_file}
+ "include(\"${file_base}_include-\${CTEST_CONFIGURATION_TYPE}.cmake\")"
+ )
+ else()
+ file(GENERATE
+ OUTPUT ${include_file}
+ CONTENT "${include_content}"
+ )
+ endif()
+
+ set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES ${include_file})
+endfunction()
diff --git a/src/secp256k1/configure.ac b/src/secp256k1/configure.ac
index af38577..05a8c58 100644
--- a/src/secp256k1/configure.ac
+++ b/src/secp256k1/configure.ac
@@ -4,23 +4,23 @@ AC_PREREQ([2.60])
# the API. All changes in experimental modules are treated as
# backwards-compatible and therefore at most increase the minor version.
define(_PKG_VERSION_MAJOR, 0)
-define(_PKG_VERSION_MINOR, 6)
+define(_PKG_VERSION_MINOR, 1)
define(_PKG_VERSION_PATCH, 0)
-define(_PKG_VERSION_IS_RELEASE, true)
+define(_PKG_VERSION_IS_RELEASE, false)
# The library version is based on libtool versioning of the ABI. The set of
# rules for updating the version can be found here:
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
-define(_LIB_VERSION_CURRENT, 5)
+define(_LIB_VERSION_CURRENT, 0)
define(_LIB_VERSION_REVISION, 0)
define(_LIB_VERSION_AGE, 0)
AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
-AC_CONFIG_AUX_DIR([build-aux])
-AC_CONFIG_MACRO_DIR([build-aux/m4])
+AC_CONFIG_AUX_DIR([autotools-aux])
+AC_CONFIG_MACRO_DIR([autotools-aux/m4])
AC_CANONICAL_HOST
# Require Automake 1.11.2 for AM_PROG_AR
@@ -111,7 +111,8 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only
- SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
+ SECP_TRY_APPEND_CFLAGS([-Wtrailing-whitespace=any], $1) # GCC >= 15.0
+ SECP_TRY_APPEND_CFLAGS([-Wleading-whitespace=spaces], $1) # GCC >= 15.0
CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
fi
@@ -145,7 +146,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,
@@ -184,6 +185,10 @@ AC_ARG_ENABLE(module_schnorrsig,
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])])
+AC_ARG_ENABLE(module_musig,
+ AS_HELP_STRING([--enable-module-musig],[enable MuSig2 module [default=yes]]), [],
+ [SECP_SET_DEFAULT([enable_module_musig], [yes], [yes])])
+
AC_ARG_ENABLE(module_schnorrsig_halfagg,
AS_HELP_STRING([--enable-module-schnorrsig-halfagg],[enable schnorrsig half-aggregation module (experimental) [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig_halfagg], [no], [yes])])
@@ -216,11 +221,6 @@ AC_ARG_ENABLE(module_whitelist,
[],
[SECP_SET_DEFAULT([enable_module_whitelist], [no], [yes])])
-AC_ARG_ENABLE(module_musig,
- AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]),
- [],
- [SECP_SET_DEFAULT([enable_module_musig], [no], [yes])])
-
AC_ARG_ENABLE(module_ecdsa_s2c,
AS_HELP_STRING([--enable-module-ecdsa-s2c],[enable ECDSA sign-to-contract module [default=no]]),
[],
@@ -251,23 +251,22 @@ AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_wide
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto],
[assembly to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
-AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto],
+AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE],
[window size for ecmult precomputation for verification, specified as integer in range [2..24].]
[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.]
[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.]
[A window size larger than 15 will require you delete the prebuilt precomputed_ecmult.c file so that it can be rebuilt.]
[For very large window sizes, use "make -j 1" to reduce memory use during compilation.]
-["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]]
+[The default value is a reasonable setting for desktop machines (currently 15). [default=15]]
)],
-[req_ecmult_window=$withval], [req_ecmult_window=auto])
+[set_ecmult_window=$withval], [set_ecmult_window=15])
-AC_ARG_WITH([ecmult-gen-precision], [AS_HELP_STRING([--with-ecmult-gen-precision=2|4|8|auto],
-[Precision bits to tune the precomputed table size for signing.]
-[The size of the table is 32kB for 2 bits, 64kB for 4 bits, 512kB for 8 bits of precision.]
-[A larger table size usually results in possible faster signing.]
-["auto" is a reasonable setting for desktop machines (currently 4). [default=auto]]
+AC_ARG_WITH([ecmult-gen-kb], [AS_HELP_STRING([--with-ecmult-gen-kb=2|22|86],
+[The size of the precomputed table for signing in multiples of 1024 bytes (on typical platforms).]
+[Larger values result in possibly better signing/keygeneration performance at the cost of a larger table.]
+[The default value is a reasonable setting for desktop machines (currently 86). [default=86]]
)],
-[req_ecmult_gen_precision=$withval], [req_ecmult_gen_precision=auto])
+[set_ecmult_gen_kb=$withval], [set_ecmult_gen_kb=86])
AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto],
[Build with extra checks for running inside Valgrind [default=auto]]
@@ -296,6 +295,20 @@ if test x"$enable_ctime_tests" = x"auto"; then
enable_ctime_tests=$enable_valgrind
fi
+print_msan_notice=no
+if test x"$enable_ctime_tests" = x"yes"; then
+ SECP_MSAN_CHECK
+ # MSan on Clang >=16 reports uninitialized memory in function parameters and return values, even if
+ # the uninitialized variable is never actually "used". This is called "eager" checking, and it's
+ # sounds like good idea for normal use of MSan. However, it yields many false positives in the
+ # ctime_tests because many return values depend on secret (i.e., "uninitialized") values, and
+ # we're only interested in detecting branches (which count as "uses") on secret data.
+ if test x"$msan_enabled" = x"yes"; then
+ SECP_TRY_APPEND_CFLAGS([-fno-sanitize-memory-param-retval], SECP_CFLAGS)
+ print_msan_notice=yes
+ fi
+fi
+
if test x"$enable_coverage" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1"
SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS"
@@ -396,14 +409,7 @@ auto)
;;
esac
-# Set ecmult window size
-if test x"$req_ecmult_window" = x"auto"; then
- set_ecmult_window=15
-else
- set_ecmult_window=$req_ecmult_window
-fi
-
-error_window_size=['window size for ecmult precomputation not an integer in range [2..24] or "auto"']
+error_window_size=['window size for ecmult precomputation not an integer in range [2..24]']
case $set_ecmult_window in
''|*[[!0-9]]*)
# no valid integer
@@ -418,19 +424,18 @@ case $set_ecmult_window in
;;
esac
-# Set ecmult gen precision
-if test x"$req_ecmult_gen_precision" = x"auto"; then
- set_ecmult_gen_precision=4
-else
- set_ecmult_gen_precision=$req_ecmult_gen_precision
-fi
-
-case $set_ecmult_gen_precision in
-2|4|8)
- SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_GEN_PREC_BITS=$set_ecmult_gen_precision"
+case $set_ecmult_gen_kb in
+2)
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=2 -DCOMB_TEETH=5"
+ ;;
+22)
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=11 -DCOMB_TEETH=6"
+ ;;
+86)
+ SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOMB_BLOCKS=43 -DCOMB_TEETH=6"
;;
*)
- AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"'])
+ AC_MSG_ERROR(['ecmult gen table size not 2, 22 or 86'])
;;
esac
@@ -450,6 +455,9 @@ SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
# Processing must be done in a reverse topological sorting of the dependency graph
# (dependent module first).
if test x"$enable_module_schnorrsig_halfagg" = x"yes"; then
+ if test x"$enable_module_schnorrsig" = x"no"; then
+ AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the schnorrsig_halfagg module.])
+ fi
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG_HALFAGG=1"
enable_module_schnorrsig=yes
fi
@@ -470,14 +478,6 @@ if test x"$enable_module_ecdsa_adaptor" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDSA_ADAPTOR=1"
fi
-if test x"$enable_module_musig" = x"yes"; then
- if test x"$enable_module_schnorrsig" = x"no"; then
- AC_MSG_ERROR([Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.])
- fi
- SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_MUSIG=1"
- enable_module_schnorrsig=yes
-fi
-
if test x"$enable_module_whitelist" = x"yes"; then
if test x"$enable_module_rangeproof" = x"no"; then
AC_MSG_ERROR([Module dependency error: You have disabled the rangeproof module explicitly, but it is required by the whitelist module.])
@@ -550,12 +550,7 @@ fi
### Check for --enable-experimental if necessary
###
-if test x"$enable_experimental" = x"yes"; then
- AC_MSG_NOTICE([******])
- AC_MSG_NOTICE([WARNING: experimental build])
- AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
- AC_MSG_NOTICE([******])
-else
+if test x"$enable_experimental" = x"no"; then
# The order of the following tests matters. If the user enables a dependent
# module (which automatically enables the module dependencies) we want to
# print an error for the dependent module, not the module dependency. Hence,
@@ -572,9 +567,6 @@ else
if test x"$enable_module_ecdsa_s2c" = x"yes"; then
AC_MSG_ERROR([ECDSA sign-to-contract module module is experimental. Use --enable-experimental to allow.])
fi
- if test x"$enable_module_musig" = x"yes"; then
- AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.])
- fi
if test x"$enable_module_whitelist" = x"yes"; then
AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.])
fi
@@ -592,6 +584,14 @@ else
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
###
@@ -615,7 +615,6 @@ AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"
AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"])
-AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_S2C], [test x"$enable_module_ecdsa_s2c" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_ADAPTOR], [test x"$enable_module_ecdsa_adaptor" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_BPPP], [test x"$enable_module_bppp" = x"yes"])
@@ -639,6 +638,7 @@ echo "Build Options:"
echo " with external callbacks = $enable_external_default_callbacks"
echo " with benchmarks = $enable_benchmark"
echo " with tests = $enable_tests"
+echo " with exhaustive tests = $enable_exhaustive_tests"
echo " with ctime tests = $enable_ctime_tests"
echo " with coverage = $enable_coverage"
echo " with examples = $enable_examples"
@@ -656,23 +656,36 @@ if test x"$enable_module_surjectionproof" = x"yes" && test x"$enable_reduced_sur
echo " reduced proof size = $enable_reduced_surjection_proof_size"
fi
echo " module whitelist = $enable_module_whitelist"
-echo " module musig = $enable_module_musig"
echo " module ecdsa-s2c = $enable_module_ecdsa_s2c"
echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor"
echo " module bppp = $enable_module_bppp"
echo " module schnorrsig-halfagg = $enable_module_schnorrsig_halfagg"
echo
-echo " asm = $set_asm"
-echo " ecmult window size = $set_ecmult_window"
-echo " ecmult gen prec. bits = $set_ecmult_gen_precision"
+echo " asm = $set_asm"
+echo " ecmult window size = $set_ecmult_window"
+echo " ecmult gen table size = $set_ecmult_gen_kb KiB"
# Hide test-only options unless they're used.
if test x"$set_widemul" != xauto; then
echo " wide multiplication = $set_widemul"
fi
echo
-echo " valgrind = $enable_valgrind"
-echo " CC = $CC"
-echo " CPPFLAGS = $CPPFLAGS"
-echo " SECP_CFLAGS = $SECP_CFLAGS"
-echo " CFLAGS = $CFLAGS"
-echo " LDFLAGS = $LDFLAGS"
+echo " valgrind = $enable_valgrind"
+echo " CC = $CC"
+echo " CPPFLAGS = $CPPFLAGS"
+echo " SECP_CFLAGS = $SECP_CFLAGS"
+echo " CFLAGS = $CFLAGS"
+echo " LDFLAGS = $LDFLAGS"
+
+if test x"$print_msan_notice" = x"yes"; then
+ echo
+ echo "Note:"
+ echo " MemorySanitizer detected, tried to add -fno-sanitize-memory-param-retval to SECP_CFLAGS"
+ echo " to avoid false positives in ctime_tests. Pass --disable-ctime-tests to avoid this."
+fi
+
+if test x"$enable_experimental" = x"yes"; then
+ echo
+ echo "WARNING: Experimental build"
+ echo " Experimental features do not have stable APIs or properties, and may not be safe for"
+ echo " production use."
+fi
diff --git a/src/secp256k1/contrib/musig2-vectors.py b/src/secp256k1/contrib/musig2-vectors.py
deleted file mode 100755
index 9742441..0000000
--- a/src/secp256k1/contrib/musig2-vectors.py
+++ /dev/null
@@ -1,656 +0,0 @@
-#!/usr/bin/env python3
-
-import sys
-import json
-import textwrap
-
-max_pubkeys = 0
-
-if len(sys.argv) < 2:
- print(
- "This script converts BIP MuSig2 test vectors in a given directory to a C file that can be used in the test framework."
- )
- print("Usage: %s <dir>" % sys.argv[0])
- sys.exit(1)
-
-
-def hexstr_to_intarray(str):
- return ", ".join([f"0x{b:02X}" for b in bytes.fromhex(str)])
-
-
-def create_init(name):
- return """
-static const struct musig_%s_vector musig_%s_vector = {
-""" % (
- name,
- name,
- )
-
-
-def init_array(key):
- return textwrap.indent("{ %s },\n" % hexstr_to_intarray(data[key]), 4 * " ")
-
-
-def init_arrays(key):
- s = textwrap.indent("{\n", 4 * " ")
- s += textwrap.indent(
- ",\n".join(["{ %s }" % hexstr_to_intarray(x) for x in data[key]]), 8 * " "
- )
- s += textwrap.indent("\n},\n", 4 * " ")
- return s
-
-
-def init_indices(array):
- return " %d, { %s }" % (
- len(array),
- ", ".join(map(str, array) if len(array) > 0 else "0"),
- )
-
-
-def init_is_xonly(case):
- if len(case["tweak_indices"]) > 0:
- return ", ".join(map(lambda x: "1" if x else "0", case["is_xonly"]))
- return "0"
-
-
-def init_optional_expected(case):
- return hexstr_to_intarray(case["expected"]) if "expected" in case else 0
-
-
-def init_cases(cases, f):
- s = textwrap.indent("{\n", 4 * " ")
- for (i, case) in enumerate(cases):
- s += textwrap.indent("%s\n" % f(case), 8 * " ")
- s += textwrap.indent("},\n", 4 * " ")
- return s
-
-
-def finish_init():
- return "};\n"
-
-
-s = (
- """/**
- * Automatically generated by %s.
- *
- * The test vectors for the KeySort function are included in this file. They can
- * be found in src/modules/extrakeys/tests_impl.h. */
-"""
- % sys.argv[0]
-)
-
-
-s += """
-enum MUSIG_ERROR {
- MUSIG_PUBKEY,
- MUSIG_TWEAK,
- MUSIG_PUBNONCE,
- MUSIG_AGGNONCE,
- MUSIG_SECNONCE,
- MUSIG_SIG,
- MUSIG_SIG_VERIFY,
- MUSIG_OTHER
-};
-"""
-
-# key agg vectors
-with open(sys.argv[1] + "/key_agg_vectors.json", "r") as f:
- data = json.load(f)
-
- max_key_indices = max(
- len(test_case["key_indices"]) for test_case in data["valid_test_cases"]
- )
- max_tweak_indices = max(
- len(test_case["tweak_indices"]) for test_case in data["error_test_cases"]
- )
- num_pubkeys = len(data["pubkeys"])
- max_pubkeys = max(num_pubkeys, max_pubkeys)
- num_tweaks = len(data["tweaks"])
- num_valid_cases = len(data["valid_test_cases"])
- num_error_cases = len(data["error_test_cases"])
-
- # Add structures for valid and error cases
- s += (
- """
-struct musig_key_agg_valid_test_case {
- size_t key_indices_len;
- size_t key_indices[%d];
- unsigned char expected[32];
-};
-"""
- % max_key_indices
- )
- s += """
-struct musig_key_agg_error_test_case {
- size_t key_indices_len;
- size_t key_indices[%d];
- size_t tweak_indices_len;
- size_t tweak_indices[%d];
- int is_xonly[%d];
- enum MUSIG_ERROR error;
-};
-""" % (
- max_key_indices,
- max_tweak_indices,
- max_tweak_indices,
- )
-
- # Add structure for entire vector
- s += """
-struct musig_key_agg_vector {
- unsigned char pubkeys[%d][33];
- unsigned char tweaks[%d][32];
- struct musig_key_agg_valid_test_case valid_case[%d];
- struct musig_key_agg_error_test_case error_case[%d];
-};
-""" % (
- num_pubkeys,
- num_tweaks,
- num_valid_cases,
- num_error_cases,
- )
-
- s += create_init("key_agg")
- # Add pubkeys and tweaks to the vector
- s += init_arrays("pubkeys")
- s += init_arrays("tweaks")
-
- # Add valid cases to the vector
- s += init_cases(
- data["valid_test_cases"],
- lambda case: "{ %s, { %s }},"
- % (init_indices(case["key_indices"]), hexstr_to_intarray(case["expected"])),
- )
-
- def comment_to_error(case):
- comment = case["comment"]
- if "public key" in comment.lower():
- return "MUSIG_PUBKEY"
- elif "tweak" in comment.lower():
- return "MUSIG_TWEAK"
- else:
- sys.exit("Unknown error")
-
- # Add error cases to the vector
- s += init_cases(
- data["error_test_cases"],
- lambda case: "{ %s, %s, { %s }, %s },"
- % (
- init_indices(case["key_indices"]),
- init_indices(case["tweak_indices"]),
- init_is_xonly(case),
- comment_to_error(case),
- ),
- )
-
- s += finish_init()
-
-# nonce gen vectors
-with open(sys.argv[1] + "/nonce_gen_vectors.json", "r") as f:
- data = json.load(f)
-
- # The MuSig2 implementation only allows messages of length 32
- data["test_cases"] = list(
- filter(lambda c: c["msg"] is None or len(c["msg"]) == 64, data["test_cases"])
- )
-
- num_tests = len(data["test_cases"])
-
- s += """
-struct musig_nonce_gen_test_case {
- unsigned char rand_[32];
- int has_sk;
- unsigned char sk[32];
- unsigned char pk[33];
- int has_aggpk;
- unsigned char aggpk[32];
- int has_msg;
- unsigned char msg[32];
- int has_extra_in;
- unsigned char extra_in[32];
- unsigned char expected_secnonce[97];
- unsigned char expected_pubnonce[66];
-};
-"""
-
- s += (
- """
-struct musig_nonce_gen_vector {
- struct musig_nonce_gen_test_case test_case[%d];
-};
-"""
- % num_tests
- )
-
- s += create_init("nonce_gen")
-
- def init_array_maybe(array):
- return "%d , { %s }" % (
- 0 if array is None else 1,
- hexstr_to_intarray(array) if array is not None else 0,
- )
-
- s += init_cases(
- data["test_cases"],
- lambda case: "{ { %s }, %s, { %s }, %s, %s, %s, { %s }, { %s } },"
- % (
- hexstr_to_intarray(case["rand_"]),
- init_array_maybe(case["sk"]),
- hexstr_to_intarray(case["pk"]),
- init_array_maybe(case["aggpk"]),
- init_array_maybe(case["msg"]),
- init_array_maybe(case["extra_in"]),
- hexstr_to_intarray(case["expected_secnonce"]),
- hexstr_to_intarray(case["expected_pubnonce"]),
- ),
- )
-
- s += finish_init()
-
-# nonce agg vectors
-with open(sys.argv[1] + "/nonce_agg_vectors.json", "r") as f:
- data = json.load(f)
-
- num_pnonces = len(data["pnonces"])
- num_valid_cases = len(data["valid_test_cases"])
- num_error_cases = len(data["error_test_cases"])
-
- pnonce_indices_len = 2
- for case in data["valid_test_cases"] + data["error_test_cases"]:
- assert len(case["pnonce_indices"]) == pnonce_indices_len
-
- # Add structures for valid and error cases
- s += """
-struct musig_nonce_agg_test_case {
- size_t pnonce_indices[2];
- /* if valid case */
- unsigned char expected[66];
- /* if error case */
- int invalid_nonce_idx;
-};
-"""
- # Add structure for entire vector
- s += """
-struct musig_nonce_agg_vector {
- unsigned char pnonces[%d][66];
- struct musig_nonce_agg_test_case valid_case[%d];
- struct musig_nonce_agg_test_case error_case[%d];
-};
-""" % (
- num_pnonces,
- num_valid_cases,
- num_error_cases,
- )
-
- s += create_init("nonce_agg")
- s += init_arrays("pnonces")
-
- for cases in (data["valid_test_cases"], data["error_test_cases"]):
- s += init_cases(
- cases,
- lambda case: "{ { %s }, { %s }, %d },"
- % (
- ", ".join(map(str, case["pnonce_indices"])),
- init_optional_expected(case),
- case["error"]["signer"] if "error" in case else 0,
- ),
- )
- s += finish_init()
-
-# sign/verify vectors
-with open(sys.argv[1] + "/sign_verify_vectors.json", "r") as f:
- data = json.load(f)
-
- # The MuSig2 implementation only allows messages of length 32
- assert list(filter(lambda x: len(x) == 64, data["msgs"]))[0] == data["msgs"][0]
- data["msgs"] = [data["msgs"][0]]
-
- def filter_msg32(k):
- return list(filter(lambda x: x["msg_index"] == 0, data[k]))
-
- data["valid_test_cases"] = filter_msg32("valid_test_cases")
- data["sign_error_test_cases"] = filter_msg32("sign_error_test_cases")
- data["verify_error_test_cases"] = filter_msg32("verify_error_test_cases")
- data["verify_fail_test_cases"] = filter_msg32("verify_fail_test_cases")
-
- num_pubkeys = len(data["pubkeys"])
- max_pubkeys = max(num_pubkeys, max_pubkeys)
- num_secnonces = len(data["secnonces"])
- num_pubnonces = len(data["pnonces"])
- num_aggnonces = len(data["aggnonces"])
- num_msgs = len(data["msgs"])
- num_valid_cases = len(data["valid_test_cases"])
- num_sign_error_cases = len(data["sign_error_test_cases"])
- num_verify_fail_cases = len(data["verify_fail_test_cases"])
- num_verify_error_cases = len(data["verify_error_test_cases"])
-
- all_cases = (
- data["valid_test_cases"]
- + data["sign_error_test_cases"]
- + data["verify_error_test_cases"]
- + data["verify_fail_test_cases"]
- )
- max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases)
- max_nonce_indices = max(
- len(test_case["nonce_indices"]) if "nonce_indices" in test_case else 0
- for test_case in all_cases
- )
- # Add structures for valid and error cases
- s += (
- """
-/* Omit pubnonces in the test vectors because our partial signature verification
- * implementation is able to accept the aggnonce directly. */
-struct musig_valid_case {
- size_t key_indices_len;
- size_t key_indices[%d];
- size_t aggnonce_index;
- size_t msg_index;
- size_t signer_index;
- unsigned char expected[32];
-};
-"""
- % max_key_indices
- )
-
- s += (
- """
-struct musig_sign_error_case {
- size_t key_indices_len;
- size_t key_indices[%d];
- size_t aggnonce_index;
- size_t msg_index;
- size_t secnonce_index;
- enum MUSIG_ERROR error;
-};
-"""
- % max_key_indices
- )
-
- s += """
-struct musig_verify_fail_error_case {
- unsigned char sig[32];
- size_t key_indices_len;
- size_t key_indices[%d];
- size_t nonce_indices_len;
- size_t nonce_indices[%d];
- size_t msg_index;
- size_t signer_index;
- enum MUSIG_ERROR error;
-};
-""" % (
- max_key_indices,
- max_nonce_indices,
- )
-
- # Add structure for entire vector
- s += """
-struct musig_sign_verify_vector {
- unsigned char sk[32];
- unsigned char pubkeys[%d][33];
- unsigned char secnonces[%d][194];
- unsigned char pubnonces[%d][194];
- unsigned char aggnonces[%d][66];
- unsigned char msgs[%d][32];
- struct musig_valid_case valid_case[%d];
- struct musig_sign_error_case sign_error_case[%d];
- struct musig_verify_fail_error_case verify_fail_case[%d];
- struct musig_verify_fail_error_case verify_error_case[%d];
-};
-""" % (
- num_pubkeys,
- num_secnonces,
- num_pubnonces,
- num_aggnonces,
- num_msgs,
- num_valid_cases,
- num_sign_error_cases,
- num_verify_fail_cases,
- num_verify_error_cases,
- )
-
- s += create_init("sign_verify")
- s += init_array("sk")
- s += init_arrays("pubkeys")
- s += init_arrays("secnonces")
- s += init_arrays("pnonces")
- s += init_arrays("aggnonces")
- s += init_arrays("msgs")
-
- s += init_cases(
- data["valid_test_cases"],
- lambda case: "{ %s, %d, %d, %d, { %s }},"
- % (
- init_indices(case["key_indices"]),
- case["aggnonce_index"],
- case["msg_index"],
- case["signer_index"],
- init_optional_expected(case),
- ),
- )
-
- def sign_error(case):
- comment = case["comment"]
- if "pubkey" in comment or "public key" in comment:
- return "MUSIG_PUBKEY"
- elif "Aggregate nonce" in comment:
- return "MUSIG_AGGNONCE"
- elif "Secnonce" in comment:
- return "MUSIG_SECNONCE"
- else:
- sys.exit("Unknown sign error")
-
- s += init_cases(
- data["sign_error_test_cases"],
- lambda case: "{ %s, %d, %d, %d, %s },"
- % (
- init_indices(case["key_indices"]),
- case["aggnonce_index"],
- case["msg_index"],
- case["secnonce_index"],
- sign_error(case),
- ),
- )
-
- def verify_error(case):
- comment = case["comment"]
- if "exceeds" in comment:
- return "MUSIG_SIG"
- elif "Wrong signer" in comment or "Wrong signature" in comment:
- return "MUSIG_SIG_VERIFY"
- elif "pubnonce" in comment:
- return "MUSIG_PUBNONCE"
- elif "pubkey" in comment:
- return "MUSIG_PUBKEY"
- else:
- sys.exit("Unknown verify error")
-
- for cases in ("verify_fail_test_cases", "verify_error_test_cases"):
- s += init_cases(
- data[cases],
- lambda case: "{ { %s }, %s, %s, %d, %d, %s },"
- % (
- hexstr_to_intarray(case["sig"]),
- init_indices(case["key_indices"]),
- init_indices(case["nonce_indices"]),
- case["msg_index"],
- case["signer_index"],
- verify_error(case),
- ),
- )
-
- s += finish_init()
-
-# tweak vectors
-with open(sys.argv[1] + "/tweak_vectors.json", "r") as f:
- data = json.load(f)
-
- num_pubkeys = len(data["pubkeys"])
- max_pubkeys = max(num_pubkeys, max_pubkeys)
- num_pubnonces = len(data["pnonces"])
- num_tweaks = len(data["tweaks"])
- num_valid_cases = len(data["valid_test_cases"])
- num_error_cases = len(data["error_test_cases"])
-
- all_cases = data["valid_test_cases"] + data["error_test_cases"]
- max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases)
- max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases)
- max_nonce_indices = max(len(test_case["nonce_indices"]) for test_case in all_cases)
- # Add structures for valid and error cases
- s += """
-struct musig_tweak_case {
- size_t key_indices_len;
- size_t key_indices[%d];
- size_t nonce_indices_len;
- size_t nonce_indices[%d];
- size_t tweak_indices_len;
- size_t tweak_indices[%d];
- int is_xonly[%d];
- size_t signer_index;
- unsigned char expected[32];
-};
-""" % (
- max_key_indices,
- max_nonce_indices,
- max_tweak_indices,
- max_tweak_indices,
- )
-
- # Add structure for entire vector
- s += """
-struct musig_tweak_vector {
- unsigned char sk[32];
- unsigned char secnonce[97];
- unsigned char aggnonce[66];
- unsigned char msg[32];
- unsigned char pubkeys[%d][33];
- unsigned char pubnonces[%d][194];
- unsigned char tweaks[%d][32];
- struct musig_tweak_case valid_case[%d];
- struct musig_tweak_case error_case[%d];
-};
-""" % (
- num_pubkeys,
- num_pubnonces,
- num_tweaks,
- num_valid_cases,
- num_error_cases,
- )
- s += create_init("tweak")
- s += init_array("sk")
- s += init_array("secnonce")
- s += init_array("aggnonce")
- s += init_array("msg")
- s += init_arrays("pubkeys")
- s += init_arrays("pnonces")
- s += init_arrays("tweaks")
-
- s += init_cases(
- data["valid_test_cases"],
- lambda case: "{ %s, %s, %s, { %s }, %d, { %s }},"
- % (
- init_indices(case["key_indices"]),
- init_indices(case["nonce_indices"]),
- init_indices(case["tweak_indices"]),
- init_is_xonly(case),
- case["signer_index"],
- init_optional_expected(case),
- ),
- )
-
- s += init_cases(
- data["error_test_cases"],
- lambda case: "{ %s, %s, %s, { %s }, %d, { %s }},"
- % (
- init_indices(case["key_indices"]),
- init_indices(case["nonce_indices"]),
- init_indices(case["tweak_indices"]),
- init_is_xonly(case),
- case["signer_index"],
- init_optional_expected(case),
- ),
- )
-
- s += finish_init()
-
-# sigagg vectors
-with open(sys.argv[1] + "/sig_agg_vectors.json", "r") as f:
- data = json.load(f)
-
- num_pubkeys = len(data["pubkeys"])
- max_pubkeys = max(num_pubkeys, max_pubkeys)
- num_tweaks = len(data["tweaks"])
- num_psigs = len(data["psigs"])
- num_valid_cases = len(data["valid_test_cases"])
- num_error_cases = len(data["error_test_cases"])
-
- all_cases = data["valid_test_cases"] + data["error_test_cases"]
- max_key_indices = max(len(test_case["key_indices"]) for test_case in all_cases)
- max_tweak_indices = max(len(test_case["tweak_indices"]) for test_case in all_cases)
- max_psig_indices = max(len(test_case["psig_indices"]) for test_case in all_cases)
-
- # Add structures for valid and error cases
- s += """
-/* Omit pubnonces in the test vectors because they're only needed for
- * implementations that do not directly accept an aggnonce. */
-struct musig_sig_agg_case {
- size_t key_indices_len;
- size_t key_indices[%d];
- size_t tweak_indices_len;
- size_t tweak_indices[%d];
- int is_xonly[%d];
- unsigned char aggnonce[66];
- size_t psig_indices_len;
- size_t psig_indices[%d];
- /* if valid case */
- unsigned char expected[64];
- /* if error case */
- int invalid_sig_idx;
-};
-""" % (
- max_key_indices,
- max_tweak_indices,
- max_tweak_indices,
- max_psig_indices,
- )
-
- # Add structure for entire vector
- s += """
-struct musig_sig_agg_vector {
- unsigned char pubkeys[%d][33];
- unsigned char tweaks[%d][32];
- unsigned char psigs[%d][32];
- unsigned char msg[32];
- struct musig_sig_agg_case valid_case[%d];
- struct musig_sig_agg_case error_case[%d];
-};
-""" % (
- num_pubkeys,
- num_tweaks,
- num_psigs,
- num_valid_cases,
- num_error_cases,
- )
-
- s += create_init("sig_agg")
- s += init_arrays("pubkeys")
- s += init_arrays("tweaks")
- s += init_arrays("psigs")
- s += init_array("msg")
-
- for cases in (data["valid_test_cases"], data["error_test_cases"]):
- s += init_cases(
- cases,
- lambda case: "{ %s, %s, { %s }, { %s }, %s, { %s }, %d },"
- % (
- init_indices(case["key_indices"]),
- init_indices(case["tweak_indices"]),
- init_is_xonly(case),
- hexstr_to_intarray(case["aggnonce"]),
- init_indices(case["psig_indices"]),
- init_optional_expected(case),
- case["error"]["signer"] if "error" in case else 0,
- ),
- )
- s += finish_init()
-s += "enum { MUSIG_VECTORS_MAX_PUBKEYS = %d };" % max_pubkeys
-print(s)
diff --git a/src/secp256k1/contrib/sync-upstream.sh b/src/secp256k1/contrib/sync-upstream.sh
index b910a59..e481504 100755
--- a/src/secp256k1/contrib/sync-upstream.sh
+++ b/src/secp256k1/contrib/sync-upstream.sh
@@ -3,138 +3,121 @@
set -eou pipefail
help() {
- echo "$0 [-b <branch>] range [end]"
- echo " merges every merge commit present in upstream and missing in <branch> (default: master)."
- echo " If the optional [end] commit is provided, only merges up to [end]."
- echo " If the optional [-b branch] provided, then ."
- echo
- echo "$0 [-b <branch>] select <commit> ... <commit>"
- echo " merges every selected merge commit into <branch> (default: master)"
- echo
- echo "This tool creates a branch and a script that can be executed to create the"
- echo "PR automatically. The script requires the github-cli tool (aka gh)."
- echo ""
- echo "Tip: \`git log --oneline upstream/master --merges\` shows merge commits."
- exit 1
-}
+cat <<EOT
+$0: Prepare a pull request that syncs a branch with upstream
-REMOTE=upstream
-REMOTE_BRANCH="$REMOTE/master"
-LOCAL_BRANCH="master"
-# Makes sure you have a remote "upstream" that is up-to-date
-setup() {
- ret=0
- git fetch "$REMOTE" &> /dev/null || ret="$?"
- if [ ${ret} == 0 ]; then
- return
- fi
- echo "Adding remote \"$REMOTE\" with URL git@github.com:bitcoin-core/secp256k1.git. Continue with y"
- read -r yn
- case $yn in
- [Yy]* ) ;;
- * ) exit 1;;
- esac
- git remote add "$REMOTE" git@github.com:bitcoin-core/secp256k1.git &> /dev/null
- git fetch "$REMOTE" &> /dev/null
-}
+Usage:
+ $0 [--switch] <base-branch> <upstream-ref>
-range() {
- RANGESTART_COMMIT=$(git merge-base "$REMOTE_BRANCH" "$LOCAL_BRANCH")
- RANGEEND_COMMIT=$(git rev-parse "$REMOTE_BRANCH")
- if [ "$#" = 1 ]; then
- RANGEEND_COMMIT=$1
- fi
-
- COMMITS=$(git --no-pager log --oneline --merges "$RANGESTART_COMMIT".."$RANGEEND_COMMIT")
- COMMITS=$(echo "$COMMITS" | tac | awk '{ print $1 }' ORS=' ')
- echo "Merging $COMMITS. Continue with y"
- read -r yn
- case $yn in
- [Yy]* ) ;;
- * ) exit 1;;
- esac
-}
+This script creates a sync local branch pointing to <upstream-ref>. Moreover, it
+generates a helper script for opening a pull request (PR) merging the created
+local branch into <base-branch>.
-# Process -b <branch> argument
-while getopts "b:" opt; do
- case $opt in
- b)
- LOCAL_BRANCH=$OPTARG
- ;;
- \?)
- echo "Invalid option: -$OPTARG" >&2
- ;;
- esac
-done
+The synced upstream PRs are listed in the title and the description of the PR.
+(This relies on upstream merging PRs using merge commits with titles of the form
+"Merge <repo>#<prnum>: ...".)
-# Shift off the processed options
-shift $((OPTIND -1))
+Arguments:
+ --switch: Try to switch to the created sync branch
+ <base-branch>: The branch to sync with upstream
+ <upstream-ref>: The upstream ref to merge into <base-branch>
-if [ "$#" -lt 1 ]; then
+Usage examples:
+ $0 --switch master upstream/master
+ $0 master abc1234
+
+To find candidate merge commits from <upstream-ref> (oldest first), use:
+ git log --oneline --topo-order --reverse --merges \$(git merge-base <upstream-ref> <base-branch>)..<upstream-ref>
+EOT
+}
+
+### Parse arguments
+SWITCH=false
+if [ "$#" -ge 1 ] && [ "$1" = "--switch" ]; then
+ SWITCH=true
+ shift
+fi
+if [ "$#" -ne 2 ]; then
help
+ exit 1
fi
+BASE_BRANCH="$1"
+UPSTREAM_REF="$2"
-case $1 in
- range)
- shift
- setup
- range "$@"
- REPRODUCE_COMMAND="$0 -b $LOCAL_BRANCH range $RANGEEND_COMMIT"
- ;;
- select)
- shift
- setup
- COMMITS=$*
- REPRODUCE_COMMAND="$0 -b $LOCAL_BRANCH select $@"
- ;;
- help)
- help
- ;;
- *)
- help
-esac
-
+### Create PR metadata
TITLE="Upstream PRs"
-BODY=""
-for COMMIT in $COMMITS
-do
- PRNUM=$(git log -1 "$COMMIT" --pretty=format:%s | sed s/'Merge \(bitcoin-core\/secp256k1\)\?#\([0-9]*\).*'/'\2'/)
+RANGESTART_COMMIT=$(git merge-base "$UPSTREAM_REF" "$BASE_BRANCH")
+RANGEEND_COMMIT=$(git rev-parse "$UPSTREAM_REF")
+COMMITS=$(git --no-pager log --pretty=format:%H --topo-order --reverse --merges "$RANGESTART_COMMIT".."$RANGEEND_COMMIT")
+# If there are no commits, exit successfully
+if [ -z "$COMMITS" ]; then
+ echo "No merge commits in range ${RANGESTART_COMMIT}..${RANGEEND_COMMIT}" >&2
+ exit 0
+fi
+BODY="${GITHUB_ACTIONS+*Note: This PR has been created by a GitHub Actions workflow without human involvement.*
+
+}"
+BODY+="This PR syncs the following upstream PRs:"
+for COMMIT in $COMMITS; do
+ PRNUM=$(git log -1 "$COMMIT" --pretty=format:%s | sed s/'Merge .*#\([0-9]*\):.*'/'\1'/)
TITLE="$TITLE $PRNUM,"
- BODY=$(printf "%s\n%s" "$BODY" "$(git log -1 "$COMMIT" --pretty=format:%s | sed s/'Merge \(bitcoin-core\/secp256k1\)\?#\([0-9]*\)'/'[bitcoin-core\/secp256k1#\2]'/)")
+ BODY=$(printf "%s\n * %s" "$BODY" "$(git log -1 "$COMMIT" --pretty=format:%s | sed s/'Merge '//)")
done
# Remove trailing ","
TITLE=${TITLE%?}
-BODY=$(printf "%s\n\n%s\n%s" "$BODY" "This PR can be recreated with \`$REPRODUCE_COMMAND\`." "Tip: Use \`git show --remerge-diff\` to show the changes manually added to the merge commit.")
+BODY+=$(cat <<'EOF'
+
+
+Usage hints:
+ * If this PR has merge conflicts, resolve these by switching to the PR branch and merging the base branch into it using `git merge <base-branch>`.
+ * To show the conflict resolution diff from an existing merge commit, use `git show --remerge-diff <merge-commit>`.
+ * In case you are recreating the PR branch locally, you can (during the conflict resolution state) replay this conflict resolution diff using `git read-tree --reset -u <merge-commit>`.
+ Be aware that this may discard your index as well as the uncommitted changes and untracked files in your worktree.
+EOF
+)
+
+### Create a sync branch locally.
+SYNC_BRANCH="sync-$(git rev-parse --short "$UPSTREAM_REF")"
+# This will error out if the branch already exists, which is what we want.
+git branch --no-track "$SYNC_BRANCH" "$UPSTREAM_REF"
+### Print the PR metadata
echo "-----------------------------------"
echo "$TITLE"
echo "-----------------------------------"
echo "$BODY"
echo "-----------------------------------"
-# Create branch from PR commit and create PR
-git checkout "$LOCAL_BRANCH"
-git pull --autostash
-git checkout -b temp-merge-"$PRNUM"
-# Escape single quote
-# ' -> '\''
+### Generate the helper script for creating the PR
+FNAME="gh-pr-create.sh"
+# Escape single quote ' -> '\''
quote() {
local quoted=${1//\'/\'\\\'\'}
printf "%s" "$quoted"
}
TITLE=$(quote "$TITLE")
BODY=$(quote "$BODY")
-
-BASEDIR=$(dirname "$0")
-FNAME="$BASEDIR/gh-pr-create.sh"
cat <<EOT > "$FNAME"
#!/bin/sh
-gh pr create -t '$TITLE' -b '$BODY' --web
-# Remove temporary branch
-git checkout "$LOCAL_BRANCH"
-git branch -D temp-merge-"$PRNUM"
+TITLE='$TITLE'
+BODY='$BODY'
+SYNC_BRANCH='$SYNC_BRANCH'
+BASE_BRANCH='$BASE_BRANCH'
+
+gh pr create --base "\$BASE_BRANCH" --head "\$SYNC_BRANCH" --title "\$TITLE" --body "\$BODY" "\$@"
EOT
chmod +x "$FNAME"
-echo Run "$FNAME" after solving the merge conflicts
-git merge --no-edit -m "Merge commits '$COMMITS' into temp-merge-$PRNUM" $COMMITS
+echo "Successfully created local sync branch $SYNC_BRANCH starting at $UPSTREAM_REF."
+echo
+echo "You can now:"
+echo " 1. Optionally resolve merge conflicts by merging $BASE_BRANCH into $SYNC_BRANCH."
+echo " 2. Push $SYNC_BRANCH to some GitHub remote."
+echo " 3. Run ./$FNAME to create a pull request. (Tip: Pass --dry-run first.)"
+
+if [ "${SWITCH:-false}" = true ]; then
+ echo
+ echo "Trying to switch to the sync branch..."
+ echo
+ git switch "$SYNC_BRANCH"
+fi
diff --git a/src/secp256k1/doc/musig-spec.mediawiki b/src/secp256k1/doc/musig-spec.mediawiki
deleted file mode 100644
index 017a0c3..0000000
--- a/src/secp256k1/doc/musig-spec.mediawiki
+++ /dev/null
@@ -1 +0,0 @@
-This document was moved to [https://github.com/jonasnick/bips/blob/musig2/bip-musig2.mediawiki https://github.com/jonasnick/bips/blob/musig2/bip-musig2.mediawiki].
\ No newline at end of file
diff --git a/src/secp256k1/doc/musig.md b/src/secp256k1/doc/musig.md
index ae21f9b..3732782 100644
--- a/src/secp256k1/doc/musig.md
+++ b/src/secp256k1/doc/musig.md
@@ -18,6 +18,7 @@ Therefore, users of the musig module must take great care to make sure of the fo
See also the comment on `secp256k1_musig_secnonce` in `include/secp256k1_musig.h`.
3. Opaque data structures are never written to or read from directly.
Instead, only the provided accessor functions are used.
+4. If adaptor signatures are used, all partial signatures are verified.
## Key Aggregation and (Taproot) Tweaking
@@ -52,3 +53,14 @@ Similarly, the API supports an alternative protocol flow where generating the ag
## Verification
A participant who wants to verify the partial signatures, but does not sign itself may do so using the above instructions except that the verifier skips steps 1, 4 and 7.
+
+## Atomic Swaps
+
+The signing API supports the production of "adaptor signatures", modified partial signatures
+which are offset by an auxiliary secret known to one party. That is,
+1. One party generates a (secret) adaptor `t` with corresponding (public) adaptor `T = t*G`.
+2. When calling `secp256k1_musig_nonce_process`, the public adaptor `T` is provided as the `adaptor` argument.
+3. The party who is going to extract the secret adaptor `t` later must verify all partial signatures.
+4. Due to step 2, the signature output of `secp256k1_musig_partial_sig_agg` is a pre-signature and not a valid Schnorr signature. All parties involved extract this session's `nonce_parity` with `secp256k1_musig_nonce_parity`.
+5. The party who knows `t` must "adapt" the pre-signature with `t` (and the `nonce_parity` using `secp256k1_musig_adapt` to complete the signature.
+6. Any party who sees both the final signature and the pre-signature (and has the `nonce_parity`) can extract `t` with `secp256k1_musig_extract_adaptor`.
diff --git a/src/secp256k1/doc/release-process.md b/src/secp256k1/doc/release-process.md
index a64bae0..3cf183d 100644
--- a/src/secp256k1/doc/release-process.md
+++ b/src/secp256k1/doc/release-process.md
@@ -61,7 +61,7 @@ Perform these checks when reviewing the release PR (see below):
4. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that
* sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`,
* increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and
- * adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md).
+ * adds an `[Unreleased]` section header and a corresponding `[Unreleased]` link at the bottom of [CHANGELOG.md](../CHANGELOG.md).
If other maintainers are not present to approve the PR, it can be merged without ACKs.
5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
diff --git a/src/secp256k1/examples/CMakeLists.txt b/src/secp256k1/examples/CMakeLists.txt
index c9da9de..808917c 100644
--- a/src/secp256k1/examples/CMakeLists.txt
+++ b/src/secp256k1/examples/CMakeLists.txt
@@ -8,8 +8,10 @@ function(add_example name)
secp256k1
$<$<PLATFORM_ID:Windows>:bcrypt>
)
- set(test_name ${name}_example)
- add_test(NAME secp256k1_${test_name} COMMAND ${target_name})
+ add_test(NAME secp256k1.example.${name} COMMAND ${target_name})
+ set_tests_properties(secp256k1.example.${name} PROPERTIES
+ LABELS secp256k1_example
+ )
endfunction()
add_example(ecdsa)
diff --git a/src/secp256k1/examples/ecdh.c b/src/secp256k1/examples/ecdh.c
index 13aa760..67b8c20 100644
--- a/src/secp256k1/examples/ecdh.c
+++ b/src/secp256k1/examples/ecdh.c
@@ -8,6 +8,7 @@
*************************************************************************/
#include <stdio.h>
+#include <stdlib.h>
#include <assert.h>
#include <string.h>
@@ -33,7 +34,7 @@ int main(void) {
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Randomizing the context is recommended to protect against side-channel
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
@@ -44,14 +45,14 @@ int main(void) {
/*** Key Generation ***/
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
printf("Failed to generate randomness\n");
- return 1;
+ return EXIT_FAILURE;
}
/* If the secret key is zero or out of range (greater than secp256k1's
* order), we fail. Note that the probability of this occurring is negligible
* with a properly functioning random number generator. */
if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) {
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Public key creation using a valid context with a verified secret key should never fail */
@@ -116,5 +117,5 @@ int main(void) {
secure_erase(shared_secret1, sizeof(shared_secret1));
secure_erase(shared_secret2, sizeof(shared_secret2));
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/src/secp256k1/examples/ecdsa.c b/src/secp256k1/examples/ecdsa.c
index 80ae9d4..ae16c18 100644
--- a/src/secp256k1/examples/ecdsa.c
+++ b/src/secp256k1/examples/ecdsa.c
@@ -8,6 +8,7 @@
*************************************************************************/
#include <stdio.h>
+#include <stdlib.h>
#include <assert.h>
#include <string.h>
@@ -40,7 +41,7 @@ int main(void) {
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Randomizing the context is recommended to protect against side-channel
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
@@ -51,14 +52,14 @@ int main(void) {
/*** Key Generation ***/
if (!fill_random(seckey, sizeof(seckey))) {
printf("Failed to generate randomness\n");
- return 1;
+ return EXIT_FAILURE;
}
/* If the secret key is zero or out of range (greater than secp256k1's
* order), we fail. Note that the probability of this occurring is negligible
* with a properly functioning random number generator. */
if (!secp256k1_ec_seckey_verify(ctx, seckey)) {
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Public key creation using a valid context with a verified secret key should never fail */
@@ -92,13 +93,13 @@ int main(void) {
/* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */
if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) {
printf("Failed parsing the signature\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) {
printf("Failed parsing the public key\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
@@ -133,5 +134,5 @@ int main(void) {
* will remove any writes that aren't used. */
secure_erase(seckey, sizeof(seckey));
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/src/secp256k1/examples/ellswift.c b/src/secp256k1/examples/ellswift.c
index afb2fee..d58e96b 100644
--- a/src/secp256k1/examples/ellswift.c
+++ b/src/secp256k1/examples/ellswift.c
@@ -13,6 +13,7 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#include <assert.h>
#include <string.h>
@@ -38,7 +39,7 @@ int main(void) {
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Randomizing the context is recommended to protect against side-channel
* leakage. See `secp256k1_context_randomize` in secp256k1.h for more
@@ -49,14 +50,14 @@ int main(void) {
/*** Generate secret keys ***/
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
printf("Failed to generate randomness\n");
- return 1;
+ return EXIT_FAILURE;
}
/* If the secret key is zero or out of range (greater than secp256k1's
* order), we fail. Note that the probability of this occurring is negligible
* with a properly functioning random number generator. */
if (!secp256k1_ec_seckey_verify(ctx, seckey1) || !secp256k1_ec_seckey_verify(ctx, seckey2)) {
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Generate ElligatorSwift public keys. This should never fail with valid context and
@@ -64,7 +65,7 @@ int main(void) {
optional, but recommended. */
if (!fill_random(auxrand1, sizeof(auxrand1)) || !fill_random(auxrand2, sizeof(auxrand2))) {
printf("Failed to generate randomness\n");
- return 1;
+ return EXIT_FAILURE;
}
return_val = secp256k1_ellswift_create(ctx, ellswift_pubkey1, seckey1, auxrand1);
assert(return_val);
@@ -117,5 +118,5 @@ int main(void) {
secure_erase(shared_secret1, sizeof(shared_secret1));
secure_erase(shared_secret2, sizeof(shared_secret2));
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/src/secp256k1/examples/musig.c b/src/secp256k1/examples/musig.c
index 16dd12f..1aff0b5 100644
--- a/src/secp256k1/examples/musig.c
+++ b/src/secp256k1/examples/musig.c
@@ -1,5 +1,4 @@
/*************************************************************************
- * Written in 2018 by Jonas Nick *
* To the extent possible under law, the author(s) have dedicated all *
* copyright and related and neighboring rights to the software in this *
* file to the public domain worldwide. This software is distributed *
@@ -9,16 +8,18 @@
/** This file demonstrates how to use the MuSig module to create a
* 3-of-3 multisignature. Additionally, see the documentation in
- * include/secp256k1_musig.h and src/modules/musig/musig.md.
+ * include/secp256k1_musig.h and doc/musig.md.
*/
#include <stdio.h>
+#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <secp256k1.h>
-#include <secp256k1_schnorrsig.h>
+#include <secp256k1_extrakeys.h>
#include <secp256k1_musig.h>
+#include <secp256k1_schnorrsig.h>
#include "examples_util.h"
@@ -38,18 +39,23 @@ struct signer {
/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */
static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {
unsigned char seckey[32];
- while (1) {
- if (!fill_random(seckey, sizeof(seckey))) {
- printf("Failed to generate randomness\n");
- return 1;
- }
- if (secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) {
- break;
- }
+
+ if (!fill_random(seckey, sizeof(seckey))) {
+ printf("Failed to generate randomness\n");
+ return 0;
+ }
+ /* Try to create a keypair with a valid context. This only fails if the
+ * secret key is zero or out of range (greater than secp256k1's order). Note
+ * that the probability of this occurring is negligible with a properly
+ * functioning random number generator. */
+ if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) {
+ return 0;
}
if (!secp256k1_keypair_pub(ctx, &signer->pubkey, &signer_secrets->keypair)) {
return 0;
}
+
+ secure_erase(seckey, sizeof(seckey));
return 1;
}
@@ -57,8 +63,12 @@ static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *s
* and return the tweaked aggregate pk. */
static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) {
secp256k1_pubkey output_pk;
+ /* For BIP 32 tweaking the plain_tweak is set to a hash as defined in BIP
+ * 32. */
unsigned char plain_tweak[32] = "this could be a BIP32 tweak....";
- unsigned char xonly_tweak[32] = "this could be a taproot tweak..";
+ /* For Taproot tweaking the xonly_tweak is set to the TapTweak hash as
+ * defined in BIP 341 */
+ unsigned char xonly_tweak[32] = "this could be a Taproot tweak..";
/* Plain tweaking which, for example, allows deriving multiple child
@@ -66,14 +76,14 @@ static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, s
if (!secp256k1_musig_pubkey_ec_tweak_add(ctx, NULL, cache, plain_tweak)) {
return 0;
}
- /* Note that we did not provided an output_pk argument, because the
+ /* Note that we did not provide an output_pk argument, because the
* resulting pk is also saved in the cache and so if one is just interested
- * in signing the output_pk argument is unnecessary. On the other hand, if
+ * in signing, the output_pk argument is unnecessary. On the other hand, if
* one is not interested in signing, the same output_pk can be obtained by
* calling `secp256k1_musig_pubkey_get` right after key aggregation to get
* the full pubkey and then call `secp256k1_ec_pubkey_tweak_add`. */
- /* Xonly tweaking which, for example, allows creating taproot commitments */
+ /* Xonly tweaking which, for example, allows creating Taproot commitments */
if (!secp256k1_musig_pubkey_xonly_tweak_add(ctx, &output_pk, cache, xonly_tweak)) {
return 0;
}
@@ -85,7 +95,7 @@ static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, s
/* Now we convert the output_pk to an xonly pubkey to allow to later verify
* the Schnorr signature against it. For this purpose we can ignore the
* `pk_parity` output argument; we would need it if we would have to open
- * the taproot commitment. */
+ * the Taproot commitment. */
if (!secp256k1_xonly_pubkey_from_pubkey(ctx, agg_pk, NULL, &output_pk)) {
return 0;
}
@@ -99,14 +109,15 @@ static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secr
const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS];
/* The same for all signers */
secp256k1_musig_session session;
+ secp256k1_musig_aggnonce agg_pubnonce;
for (i = 0; i < N_SIGNERS; i++) {
unsigned char seckey[32];
- unsigned char session_id[32];
+ unsigned char session_secrand[32];
/* Create random session ID. It is absolutely necessary that the session ID
* is unique for every call of secp256k1_musig_nonce_gen. Otherwise
* it's trivial for an attacker to extract the secret key! */
- if (!fill_random(session_id, sizeof(session_id))) {
+ if (!fill_random(session_secrand, sizeof(session_secrand))) {
return 0;
}
if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {
@@ -114,25 +125,29 @@ static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secr
}
/* Initialize session and create secret nonce for signing and public
* nonce to send to the other signers. */
- if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_id, seckey, &signer[i].pubkey, msg32, NULL, NULL)) {
+ if (!secp256k1_musig_nonce_gen(ctx, &signer_secrets[i].secnonce, &signer[i].pubnonce, session_secrand, seckey, &signer[i].pubkey, msg32, NULL, NULL)) {
return 0;
}
pubnonces[i] = &signer[i].pubnonce;
+
+ secure_erase(seckey, sizeof(seckey));
}
- /* Communication round 1: A production system would exchange public nonces
- * here before moving on. */
- for (i = 0; i < N_SIGNERS; i++) {
- secp256k1_musig_aggnonce agg_pubnonce;
- /* Create aggregate nonce and initialize the session */
- if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) {
- return 0;
- }
+ /* Communication round 1: Every signer sends their pubnonce to the
+ * coordinator. The coordinator runs secp256k1_musig_nonce_agg and sends
+ * agg_pubnonce to each signer */
+ if (!secp256k1_musig_nonce_agg(ctx, &agg_pubnonce, pubnonces, N_SIGNERS)) {
+ return 0;
+ }
+
+ /* Every signer creates a partial signature */
+ for (i = 0; i < N_SIGNERS; i++) {
+ /* Initialize the signing session by processing the aggregate nonce */
if (!secp256k1_musig_nonce_process(ctx, &session, &agg_pubnonce, msg32, cache, NULL)) {
return 0;
}
/* partial_sign will clear the secnonce by setting it to 0. That's because
- * you must _never_ reuse the secnonce (or use the same session_id to
+ * you must _never_ reuse the secnonce (or use the same session_secrand to
* create a secnonce). If you do, you effectively reuse the nonce and
* leak the secret key. */
if (!secp256k1_musig_partial_sign(ctx, &signer[i].partial_sig, &signer_secrets[i].secnonce, &signer_secrets[i].keypair, cache, &session)) {
@@ -140,8 +155,8 @@ static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secr
}
partial_sigs[i] = &signer[i].partial_sig;
}
- /* Communication round 2: A production system would exchange
- * partial signatures here before moving on. */
+ /* Communication round 2: Every signer sends their partial signature to the
+ * coordinator, who verifies the partial signatures and aggregates them. */
for (i = 0; i < N_SIGNERS; i++) {
/* To check whether signing was successful, it suffices to either verify
* the aggregate signature with the aggregate public key using
@@ -161,7 +176,7 @@ static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secr
return secp256k1_musig_partial_sig_agg(ctx, sig64, &session, partial_sigs, N_SIGNERS);
}
- int main(void) {
+int main(void) {
secp256k1_context* ctx;
int i;
struct signer_secrets signer_secrets[N_SIGNERS];
@@ -169,46 +184,78 @@ static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secr
const secp256k1_pubkey *pubkeys_ptr[N_SIGNERS];
secp256k1_xonly_pubkey agg_pk;
secp256k1_musig_keyagg_cache cache;
- unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
+ unsigned char msg[32] = "this_could_be_the_hash_of_a_msg";
unsigned char sig[64];
/* Create a secp256k1 context */
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
printf("Creating key pairs......");
+ fflush(stdout);
for (i = 0; i < N_SIGNERS; i++) {
if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) {
printf("FAILED\n");
- return 1;
+ return EXIT_FAILURE;
}
pubkeys_ptr[i] = &signers[i].pubkey;
}
printf("ok\n");
+
+ /* The aggregate public key produced by secp256k1_musig_pubkey_agg depends
+ * on the order of the provided public keys. If there is no canonical order
+ * of the signers, the individual public keys can optionally be sorted with
+ * secp256k1_ec_pubkey_sort to ensure that the aggregate public key is
+ * independent of the order of signers. */
+ printf("Sorting public keys.....");
+ fflush(stdout);
+ if (!secp256k1_ec_pubkey_sort(ctx, pubkeys_ptr, N_SIGNERS)) {
+ printf("FAILED\n");
+ return EXIT_FAILURE;
+ }
+ printf("ok\n");
+
printf("Combining public keys...");
- /* If you just want to aggregate and not sign the cache can be NULL */
- if (!secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pubkeys_ptr, N_SIGNERS)) {
+ fflush(stdout);
+ /* If you just want to aggregate and not sign, you can call
+ * secp256k1_musig_pubkey_agg with the keyagg_cache argument set to NULL
+ * while providing a non-NULL agg_pk argument. */
+ if (!secp256k1_musig_pubkey_agg(ctx, NULL, &cache, pubkeys_ptr, N_SIGNERS)) {
printf("FAILED\n");
- return 1;
+ return EXIT_FAILURE;
}
printf("ok\n");
printf("Tweaking................");
+ fflush(stdout);
/* Optionally tweak the aggregate key */
if (!tweak(ctx, &agg_pk, &cache)) {
printf("FAILED\n");
- return 1;
+ return EXIT_FAILURE;
}
printf("ok\n");
printf("Signing message.........");
+ fflush(stdout);
if (!sign(ctx, signer_secrets, signers, &cache, msg, sig)) {
printf("FAILED\n");
- return 1;
+ return EXIT_FAILURE;
}
printf("ok\n");
printf("Verifying signature.....");
+ fflush(stdout);
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &agg_pk)) {
printf("FAILED\n");
- return 1;
+ return EXIT_FAILURE;
}
printf("ok\n");
+
+ /* It's best practice to try to clear secrets from memory after using them.
+ * This is done because some bugs can allow an attacker to leak memory, for
+ * example through "out of bounds" array access (see Heartbleed), or the OS
+ * swapping them to disk. Hence, we overwrite secret key material with zeros.
+ *
+ * Here we are preventing these writes from being optimized out, as any good compiler
+ * will remove any writes that aren't used. */
+ for (i = 0; i < N_SIGNERS; i++) {
+ secure_erase(&signer_secrets[i], sizeof(signer_secrets[i]));
+ }
secp256k1_context_destroy(ctx);
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/src/secp256k1/examples/schnorr.c b/src/secp256k1/examples/schnorr.c
index 909fcaa..49baed2 100644
--- a/src/secp256k1/examples/schnorr.c
+++ b/src/secp256k1/examples/schnorr.c
@@ -8,6 +8,7 @@
*************************************************************************/
#include <stdio.h>
+#include <stdlib.h>
#include <assert.h>
#include <string.h>
@@ -34,7 +35,7 @@ int main(void) {
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Randomizing the context is recommended to protect against side-channel
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
@@ -45,7 +46,7 @@ int main(void) {
/*** Key Generation ***/
if (!fill_random(seckey, sizeof(seckey))) {
printf("Failed to generate randomness\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Try to create a keypair with a valid context. This only fails if the
* secret key is zero or out of range (greater than secp256k1's order). Note
@@ -53,7 +54,7 @@ int main(void) {
* functioning random number generator. */
if (!secp256k1_keypair_create(ctx, &keypair, seckey)) {
printf("Generated secret key is invalid. This indicates an issue with the random number generator.\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Extract the X-only public key from the keypair. We pass NULL for
@@ -90,7 +91,7 @@ int main(void) {
/* Generate 32 bytes of randomness to use with BIP-340 schnorr signing. */
if (!fill_random(auxiliary_rand, sizeof(auxiliary_rand))) {
printf("Failed to generate randomness\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Generate a Schnorr signature.
@@ -110,7 +111,7 @@ int main(void) {
* be parsed correctly */
if (!secp256k1_xonly_pubkey_parse(ctx, &pubkey, serialized_pubkey)) {
printf("Failed parsing the public key\n");
- return 1;
+ return EXIT_FAILURE;
}
/* Compute the tagged hash on the received messages using the same tag as the signer. */
@@ -149,5 +150,5 @@ int main(void) {
* Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
secure_erase(seckey, sizeof(seckey));
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h
index 0936f68..b7ec6a2 100644
--- a/src/secp256k1/include/secp256k1.h
+++ b/src/secp256k1/include/secp256k1.h
@@ -6,6 +6,7 @@ extern "C" {
#endif
#include <stddef.h>
+#include <stdint.h>
/** Unless explicitly stated all pointer arguments must not be NULL.
*
@@ -121,45 +122,57 @@ typedef int (*secp256k1_nonce_function)(
#endif
/* Symbol visibility. */
-#if defined(_WIN32)
- /* GCC for Windows (e.g., MinGW) accepts the __declspec syntax
- * for MSVC compatibility. A __declspec declaration implies (but is not
- * exactly equivalent to) __attribute__ ((visibility("default"))), and so we
- * actually want __declspec even on GCC, see "Microsoft Windows Function
- * Attributes" in the GCC manual and the recommendations in
- * https://gcc.gnu.org/wiki/Visibility. */
-# if defined(SECP256K1_BUILD)
-# if defined(DLL_EXPORT) || defined(SECP256K1_DLL_EXPORT)
- /* Building libsecp256k1 as a DLL.
- * 1. If using Libtool, it defines DLL_EXPORT automatically.
- * 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */
-# define SECP256K1_API extern __declspec (dllexport)
-# else
- /* Building libsecp256k1 as a static library on Windows.
- * No declspec is needed, and so we would want the non-Windows-specific
- * logic below take care of this case. However, this may result in setting
- * __attribute__ ((visibility("default"))), which is supposed to be a noop
- * on Windows but may trigger warnings when compiling with -flto due to a
- * bug in GCC, see
- * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */
-# define SECP256K1_API extern
-# endif
- /* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static
- * library on Windows. */
-# elif !defined(SECP256K1_STATIC)
- /* Consuming libsecp256k1 as a DLL. */
-# define SECP256K1_API extern __declspec (dllimport)
-# endif
+#if !defined(SECP256K1_API) && defined(SECP256K1_NO_API_VISIBILITY_ATTRIBUTES)
+ /* The user has requested that we don't specify visibility attributes in
+ * the public API.
+ *
+ * Since all our non-API declarations use the static qualifier, this means
+ * that the user can use -fvisibility=<value> to set the visibility of the
+ * API symbols. For instance, -fvisibility=hidden can be useful *even for
+ * the API symbols*, e.g., when building a static library which is linked
+ * into a shared library, and the latter should not re-export the
+ * libsecp256k1 API.
+ *
+ * While visibility is a concept that applies only to shared libraries,
+ * setting visibility will still make a difference when building a static
+ * library: the visibility settings will be stored in the static library,
+ * solely for the potential case that the static library will be linked into
+ * a shared library. In that case, the stored visibility settings will
+ * resurface and be honored for the shared library. */
+# define SECP256K1_API extern
#endif
-#ifndef SECP256K1_API
-/* All cases not captured by the Windows-specific logic. */
-# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
- /* Building libsecp256k1 using GCC or compatible. */
-# define SECP256K1_API extern __attribute__ ((visibility ("default")))
-# else
- /* Fall back to standard C's extern. */
-# define SECP256K1_API extern
-# endif
+#if !defined(SECP256K1_API)
+# if defined(SECP256K1_BUILD)
+ /* On Windows, assume a shared library only if explicitly requested.
+ * 1. If using Libtool, it defines DLL_EXPORT automatically.
+ * 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */
+# if defined(_WIN32) && (defined(SECP256K1_DLL_EXPORT) || defined(DLL_EXPORT))
+ /* GCC for Windows (e.g., MinGW) accepts the __declspec syntax for
+ * MSVC compatibility. A __declspec declaration implies (but is not
+ * exactly equivalent to) __attribute__ ((visibility("default"))),
+ * and so we actually want __declspec even on GCC, see "Microsoft
+ * Windows Function Attributes" in the GCC manual and the
+ * recommendations in https://gcc.gnu.org/wiki/Visibility . */
+# define SECP256K1_API extern __declspec(dllexport)
+ /* Avoid __attribute__ ((visibility("default"))) on Windows to get rid
+ * of warnings when compiling with -flto due to a bug in GCC, see
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116478 . */
+# elif !defined(_WIN32) && defined (__GNUC__) && (__GNUC__ >= 4)
+# define SECP256K1_API extern __attribute__ ((visibility("default")))
+# else
+# define SECP256K1_API extern
+# endif
+# else
+ /* On Windows, SECP256K1_STATIC must be defined when consuming
+ * libsecp256k1 as a static library. Note that SECP256K1_STATIC is a
+ * "consumer-only" macro, and it has no meaning when building
+ * libsecp256k1. */
+# if defined(_WIN32) && !defined(SECP256K1_STATIC)
+# define SECP256K1_API extern __declspec(dllimport)
+# else
+# define SECP256K1_API extern
+# endif
+# endif
#endif
/* Warning attributes
@@ -230,10 +243,10 @@ typedef int (*secp256k1_nonce_function)(
*
* It is highly recommended to call secp256k1_selftest before using this context.
*/
-SECP256K1_API const secp256k1_context *secp256k1_context_static;
+SECP256K1_API const secp256k1_context * const secp256k1_context_static;
/** Deprecated alias for secp256k1_context_static. */
-SECP256K1_API const secp256k1_context *secp256k1_context_no_precomp
+SECP256K1_API const secp256k1_context * const secp256k1_context_no_precomp
SECP256K1_DEPRECATED("Use secp256k1_context_static instead");
/** Perform basic self tests (to be used in conjunction with secp256k1_context_static)
@@ -249,7 +262,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);
@@ -322,36 +335,38 @@ 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.
- *
- * 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
+ * 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 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
+ * has been configured with --enable-external-default-callbacks (GNU Autotools) or
+ * -DSECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS=ON (CMake). 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.
*/
@@ -368,8 +383,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.
@@ -377,9 +392,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.
*/
@@ -389,6 +405,46 @@ SECP256K1_API void secp256k1_context_set_error_callback(
const void *data
) SECP256K1_ARG_NONNULL(1);
+/** A pointer to a function implementing SHA256's internal compression function.
+ *
+ * This function processes one or more contiguous 64-byte message blocks and
+ * updates the internal SHA256 state accordingly. The function is not responsible
+ * for counting consumed blocks or bytes, nor for performing padding.
+ *
+ * In/Out: state: pointer to eight 32-bit words representing the current internal state;
+ * the state is updated in place.
+ * In: blocks64: pointer to concatenation of n_blocks blocks, of 64 bytes each.
+ * no alignment guarantees are made for this pointer.
+ * n_blocks: number of contiguous 64-byte blocks to process.
+ */
+typedef void (*secp256k1_sha256_compression_function)(
+ uint32_t *state,
+ const unsigned char *blocks64,
+ size_t n_blocks
+);
+
+/**
+ * Set a callback function to override the internal SHA256 compression function.
+ *
+ * This installs a function to replace the built-in block-compression
+ * step used by the library's internal SHA256 implementation.
+ * The provided callback must exactly implement the effect of n_blocks
+ * repeated applications of the SHA256 compression function.
+ *
+ * This API exists to support environments that wish to route the
+ * SHA256 compression step through a hardware-accelerated or otherwise
+ * specialized implementation. It is NOT meant for replacing SHA256
+ * with a different hash function.
+ *
+ * Args: ctx: pointer to a context object.
+ * In: fn_compression: pointer to a function implementing the compression function;
+ * passing NULL restores the default implementation.
+ */
+SECP256K1_API void secp256k1_context_set_sha256_compression(
+ secp256k1_context *ctx,
+ secp256k1_sha256_compression_function fn_compression
+) SECP256K1_ARG_NONNULL(1);
+
/** Parse a variable-length public key into the pubkey object.
*
* Returns: 1 if the public key was fully valid.
@@ -448,6 +504,20 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
const secp256k1_pubkey *pubkey2
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+/** Sort public keys using lexicographic (of compressed serialization) order
+ *
+ * Returns: 0 if the arguments are invalid. 1 otherwise.
+ *
+ * Args: ctx: pointer to a context object
+ * In: pubkeys: array of pointers to pubkeys to sort
+ * n_pubkeys: number of elements in the pubkeys array
+ */
+SECP256K1_API int secp256k1_ec_pubkey_sort(
+ const secp256k1_context *ctx,
+ const secp256k1_pubkey **pubkeys,
+ size_t n_pubkeys
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
+
/** Parse an ECDSA signature in compact (64 bytes) format.
*
* Returns: 1 when the signature could be parsed, 0 otherwise.
@@ -687,21 +757,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
-/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in
- * future versions. */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
- const secp256k1_context *ctx,
- unsigned char *seckey
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
- SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead");
-
/** Negates a public key in place.
*
* Returns: 1 always
* Args: ctx: pointer to a context object
* In/Out: pubkey: pointer to the public key to be negated.
*/
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
+SECP256K1_API int secp256k1_ec_pubkey_negate(
const secp256k1_context *ctx,
secp256k1_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
@@ -727,15 +789,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in
- * future versions. */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
- const secp256k1_context *ctx,
- unsigned char *seckey,
- const unsigned char *tweak32
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
- SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_add instead");
-
/** Tweak a public key by adding tweak times the generator to it.
*
* Returns: 0 if the arguments are invalid or the resulting public key would be
@@ -774,15 +827,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in
- * future versions. */
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
- const secp256k1_context *ctx,
- unsigned char *seckey,
- const unsigned char *tweak32
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
- SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_mul instead");
-
/** Tweak a public key by multiplying it by a tweak value.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
@@ -869,7 +913,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
* msg: pointer to an array containing the message
* msglen: length of the message array
*/
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256(
+SECP256K1_API int secp256k1_tagged_sha256(
const secp256k1_context *ctx,
unsigned char *hash32,
const unsigned char *tag,
diff --git a/src/secp256k1/include/secp256k1_ecdsa_s2c.h b/src/secp256k1/include/secp256k1_ecdsa_s2c.h
index ea4219f..c931457 100644
--- a/src/secp256k1/include/secp256k1_ecdsa_s2c.h
+++ b/src/secp256k1/include/secp256k1_ecdsa_s2c.h
@@ -25,7 +25,7 @@ extern "C" {
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use secp256k1_ecdsa_s2c_opening_serialize and secp256k1_ecdsa_s2c_opening_parse.
*/
-typedef struct {
+typedef struct secp256k1_ecdsa_s2c_opening {
unsigned char data[64];
} secp256k1_ecdsa_s2c_opening;
diff --git a/src/secp256k1/include/secp256k1_ellswift.h b/src/secp256k1/include/secp256k1_ellswift.h
index 0d1293e..4cda5d5 100644
--- a/src/secp256k1/include/secp256k1_ellswift.h
+++ b/src/secp256k1/include/secp256k1_ellswift.h
@@ -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
diff --git a/src/secp256k1/include/secp256k1_extrakeys.h b/src/secp256k1/include/secp256k1_extrakeys.h
index e3fb7ae..1a517de 100644
--- a/src/secp256k1/include/secp256k1_extrakeys.h
+++ b/src/secp256k1/include/secp256k1_extrakeys.h
@@ -90,7 +90,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_cmp(
* the negation of the pubkey and set to 0 otherwise.
* In: pubkey: pointer to a public key that is converted.
*/
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey(
+SECP256K1_API int secp256k1_xonly_pubkey_from_pubkey(
const secp256k1_context *ctx,
secp256k1_xonly_pubkey *xonly_pubkey,
int *pk_parity,
@@ -179,7 +179,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
* Out: seckey: pointer to a 32-byte buffer for the secret key.
* In: keypair: pointer to a keypair.
*/
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
+SECP256K1_API int secp256k1_keypair_sec(
const secp256k1_context *ctx,
unsigned char *seckey,
const secp256k1_keypair *keypair
@@ -192,7 +192,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
* Out: pubkey: pointer to a pubkey object, set to the keypair public key.
* In: keypair: pointer to a keypair.
*/
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
+SECP256K1_API int secp256k1_keypair_pub(
const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const secp256k1_keypair *keypair
@@ -211,7 +211,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
* pk_parity argument of secp256k1_xonly_pubkey_from_pubkey.
* In: keypair: pointer to a keypair.
*/
-SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
+SECP256K1_API int secp256k1_keypair_xonly_pub(
const secp256k1_context *ctx,
secp256k1_xonly_pubkey *pubkey,
int *pk_parity,
@@ -243,21 +243,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Sort public keys using lexicographic order of their compressed
- * serialization.
- *
- * Returns: 0 if the arguments are invalid. 1 otherwise.
- *
- * Args: ctx: pointer to a context object
- * In: pubkeys: array of pointers to pubkeys to sort
- * n_pubkeys: number of elements in the pubkeys array
- */
-SECP256K1_API int secp256k1_pubkey_sort(
- const secp256k1_context *ctx,
- const secp256k1_pubkey **pubkeys,
- size_t n_pubkeys
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/secp256k1/include/secp256k1_generator.h b/src/secp256k1/include/secp256k1_generator.h
index 0a59c36..7bf3231 100644
--- a/src/secp256k1/include/secp256k1_generator.h
+++ b/src/secp256k1/include/secp256k1_generator.h
@@ -17,7 +17,7 @@ extern "C" {
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use secp256k1_generator_serialize and secp256k1_generator_parse.
*/
-typedef struct {
+typedef struct secp256k1_generator {
unsigned char data[64];
} secp256k1_generator;
@@ -100,7 +100,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate_blin
* comparison, use secp256k1_pedersen_commitment_serialize and
* secp256k1_pedersen_commitment_parse.
*/
-typedef struct {
+typedef struct secp256k1_pedersen_commitment {
unsigned char data[64];
} secp256k1_pedersen_commitment;
diff --git a/src/secp256k1/include/secp256k1_musig.h b/src/secp256k1/include/secp256k1_musig.h
index 28ecf1e..43836a6 100644
--- a/src/secp256k1/include/secp256k1_musig.h
+++ b/src/secp256k1/include/secp256k1_musig.h
@@ -8,38 +8,39 @@ extern "C" {
#endif
#include <stddef.h>
+#include <stdint.h>
/** This module implements BIP 327 "MuSig2 for BIP340-compatible
- * Multi-Signatures"
- * (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki)
- * v1.0.0. You can find an example demonstrating the musig module in
- * examples/musig.c.
+ * Multi-Signatures"
+ * (https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki)
+ * v1.0.0. You can find an example demonstrating the musig module in
+ * examples/musig.c.
*
- * The module also supports BIP-341 ("Taproot") public key tweaking and adaptor
- * signatures as described in
- * https://github.com/ElementsProject/scriptless-scripts/pull/24.
+ * The module also supports BIP 341 ("Taproot") public key tweaking and adaptor signatures.
*
- * It is recommended to read the documentation in this include file carefully.
- * Further notes on API usage can be found in src/modules/musig/musig.md
+ * It is recommended to read the documentation in this include file carefully.
+ * Further notes on API usage can be found in doc/musig.md
*
- * Since the first version of MuSig is essentially replaced by MuSig2, we use
- * MuSig, musig and MuSig2 synonymously unless noted otherwise.
+ * Since the first version of MuSig is essentially replaced by MuSig2, we use
+ * MuSig, musig and MuSig2 synonymously unless noted otherwise.
*/
/** Opaque data structures
*
- * The exact representation of data inside is implementation defined and not
- * guaranteed to be portable between different platforms or versions. If you
- * need to convert to a format suitable for storage, transmission, or
- * comparison, use the corresponding serialization and parsing functions.
+ * The exact representation of data inside the opaque data structures is
+ * implementation defined and not guaranteed to be portable between different
+ * platforms or versions. With the exception of `secp256k1_musig_secnonce`, the
+ * data structures can be safely copied/moved. If you need to convert to a
+ * format suitable for storage, transmission, or comparison, use the
+ * corresponding serialization and parsing functions.
*/
/** Opaque data structure that caches information about public key aggregation.
*
- * Guaranteed to be 197 bytes in size. It can be safely copied/moved. No
- * serialization and parsing functions (yet).
+ * Guaranteed to be 197 bytes in size. No serialization and parsing functions
+ * (yet).
*/
-typedef struct {
+typedef struct secp256k1_musig_keyagg_cache {
unsigned char data[197];
} secp256k1_musig_keyagg_cache;
@@ -50,44 +51,40 @@ typedef struct {
* WARNING: This structure MUST NOT be copied or read or written to directly. A
* signer who is online throughout the whole process and can keep this
* structure in memory can use the provided API functions for a safe standard
- * workflow. See
- * https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/ for
- * more details about the risks associated with serializing or deserializing
- * this structure.
+ * workflow.
*
- * We repeat, copying this data structure can result in nonce reuse which will
- * leak the secret signing key.
+ * Copying this data structure can result in nonce reuse which will leak the
+ * secret signing key.
*/
-typedef struct {
+typedef struct secp256k1_musig_secnonce {
unsigned char data[132];
} secp256k1_musig_secnonce;
/** Opaque data structure that holds a signer's public nonce.
-*
-* Guaranteed to be 132 bytes in size. It can be safely copied/moved. Serialized
-* and parsed with `musig_pubnonce_serialize` and `musig_pubnonce_parse`.
-*/
-typedef struct {
+ *
+ * Guaranteed to be 132 bytes in size. Serialized and parsed with
+ * `musig_pubnonce_serialize` and `musig_pubnonce_parse`.
+ */
+typedef struct secp256k1_musig_pubnonce {
unsigned char data[132];
} secp256k1_musig_pubnonce;
/** Opaque data structure that holds an aggregate public nonce.
*
- * Guaranteed to be 132 bytes in size. It can be safely copied/moved.
- * Serialized and parsed with `musig_aggnonce_serialize` and
- * `musig_aggnonce_parse`.
+ * Guaranteed to be 132 bytes in size. Serialized and parsed with
+ * `musig_aggnonce_serialize` and `musig_aggnonce_parse`.
*/
-typedef struct {
+typedef struct secp256k1_musig_aggnonce {
unsigned char data[132];
} secp256k1_musig_aggnonce;
/** Opaque data structure that holds a MuSig session.
*
* This structure is not required to be kept secret for the signing protocol to
- * be secure. Guaranteed to be 133 bytes in size. It can be safely
- * copied/moved. No serialization and parsing functions (yet).
+ * be secure. Guaranteed to be 133 bytes in size. No serialization and parsing
+ * functions (yet).
*/
-typedef struct {
+typedef struct secp256k1_musig_session {
unsigned char data[133];
} secp256k1_musig_session;
@@ -96,7 +93,7 @@ typedef struct {
* Guaranteed to be 36 bytes in size. Serialized and parsed with
* `musig_partial_sig_serialize` and `musig_partial_sig_parse`.
*/
-typedef struct {
+typedef struct secp256k1_musig_partial_sig {
unsigned char data[36];
} secp256k1_musig_partial_sig;
@@ -107,7 +104,7 @@ typedef struct {
* Out: nonce: pointer to a nonce object
* In: in66: pointer to the 66-byte nonce to be parsed
*/
-SECP256K1_API int secp256k1_musig_pubnonce_parse(
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubnonce_parse(
const secp256k1_context *ctx,
secp256k1_musig_pubnonce *nonce,
const unsigned char *in66
@@ -115,7 +112,7 @@ SECP256K1_API int secp256k1_musig_pubnonce_parse(
/** Serialize a signer's public nonce
*
- * Returns: 1 when the nonce could be serialized, 0 otherwise
+ * Returns: 1 always
* Args: ctx: pointer to a context object
* Out: out66: pointer to a 66-byte array to store the serialized nonce
* In: nonce: pointer to the nonce
@@ -133,7 +130,7 @@ SECP256K1_API int secp256k1_musig_pubnonce_serialize(
* Out: nonce: pointer to a nonce object
* In: in66: pointer to the 66-byte nonce to be parsed
*/
-SECP256K1_API int secp256k1_musig_aggnonce_parse(
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_aggnonce_parse(
const secp256k1_context *ctx,
secp256k1_musig_aggnonce *nonce,
const unsigned char *in66
@@ -141,7 +138,7 @@ SECP256K1_API int secp256k1_musig_aggnonce_parse(
/** Serialize an aggregate public nonce
*
- * Returns: 1 when the nonce could be serialized, 0 otherwise
+ * Returns: 1 always
* Args: ctx: pointer to a context object
* Out: out66: pointer to a 66-byte array to store the serialized nonce
* In: nonce: pointer to the nonce
@@ -152,54 +149,43 @@ SECP256K1_API int secp256k1_musig_aggnonce_serialize(
const secp256k1_musig_aggnonce *nonce
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Serialize a MuSig partial signature
- *
- * Returns: 1 when the signature could be serialized, 0 otherwise
- * Args: ctx: pointer to a context object
- * Out: out32: pointer to a 32-byte array to store the serialized signature
- * In: sig: pointer to the signature
- */
-SECP256K1_API int secp256k1_musig_partial_sig_serialize(
- const secp256k1_context *ctx,
- unsigned char *out32,
- const secp256k1_musig_partial_sig *sig
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-
/** Parse a MuSig partial signature.
*
* Returns: 1 when the signature could be parsed, 0 otherwise.
* Args: ctx: pointer to a context object
* Out: sig: pointer to a signature object
* In: in32: pointer to the 32-byte signature to be parsed
- *
- * After the call, sig will always be initialized. If parsing failed or the
- * encoded numbers are out of range, signature verification with it is
- * guaranteed to fail for every message and public key.
*/
-SECP256K1_API int secp256k1_musig_partial_sig_parse(
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_parse(
const secp256k1_context *ctx,
secp256k1_musig_partial_sig *sig,
const unsigned char *in32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+/** Serialize a MuSig partial signature
+ *
+ * Returns: 1 always
+ * Args: ctx: pointer to a context object
+ * Out: out32: pointer to a 32-byte array to store the serialized signature
+ * In: sig: pointer to the signature
+ */
+SECP256K1_API int secp256k1_musig_partial_sig_serialize(
+ const secp256k1_context *ctx,
+ unsigned char *out32,
+ const secp256k1_musig_partial_sig *sig
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
+
/** Computes an aggregate public key and uses it to initialize a keyagg_cache
*
* Different orders of `pubkeys` result in different `agg_pk`s.
*
- * Before aggregating, the pubkeys can be sorted with `secp256k1_pubkey_sort`
+ * Before aggregating, the pubkeys can be sorted with `secp256k1_ec_pubkey_sort`
* which ensures the same `agg_pk` result for the same multiset of pubkeys.
* This is useful to do before `pubkey_agg`, such that the order of pubkeys
* does not affect the aggregate public key.
*
* Returns: 0 if the arguments are invalid, 1 otherwise
* Args: ctx: pointer to a context object
- * scratch: should be NULL because it is not yet implemented. If it
- * was implemented then the scratch space would be used to
- * compute the aggregate pubkey by multiexponentiation.
- * Generally, the larger the scratch space, the faster this
- * function. However, the returns of providing a larger
- * scratch space are diminishing. If NULL, an inefficient
- * algorithm is used.
* Out: agg_pk: the MuSig-aggregated x-only public key. If you do not need it,
* this arg can be NULL.
* keyagg_cache: if non-NULL, pointer to a musig_keyagg_cache struct that
@@ -210,14 +196,13 @@ SECP256K1_API int secp256k1_musig_partial_sig_parse(
* aggregate public key.
* n_pubkeys: length of pubkeys array. Must be greater than 0.
*/
-SECP256K1_API int secp256k1_musig_pubkey_agg(
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_agg(
const secp256k1_context *ctx,
- secp256k1_scratch_space *scratch,
secp256k1_xonly_pubkey *agg_pk,
secp256k1_musig_keyagg_cache *keyagg_cache,
const secp256k1_pubkey * const *pubkeys,
size_t n_pubkeys
-) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5);
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(4);
/** Obtain the aggregate public key from a keyagg_cache.
*
@@ -237,9 +222,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(
const secp256k1_musig_keyagg_cache *keyagg_cache
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by
- * adding the generator multiplied with `tweak32` to it. This is useful for
- * deriving child keys from an aggregate public key via BIP32.
+/** Apply plain "EC" tweaking to a public key in a given keyagg_cache by adding
+ * the generator multiplied with `tweak32` to it. This is useful for deriving
+ * child keys from an aggregate public key via BIP 32 where `tweak32` is set to
+ * a hash as defined in BIP 32.
+ *
+ * Callers are responsible for deriving `tweak32` in a way that does not reduce
+ * the security of MuSig (for example, by following BIP 32).
*
* The tweaking method is the same as `secp256k1_ec_pubkey_tweak_add`. So after
* the following pseudocode buf and buf2 have identical contents (absent
@@ -248,29 +237,27 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(
* secp256k1_musig_pubkey_agg(..., keyagg_cache, pubkeys, ...)
* secp256k1_musig_pubkey_get(..., agg_pk, keyagg_cache)
* secp256k1_musig_pubkey_ec_tweak_add(..., output_pk, tweak32, keyagg_cache)
- * secp256k1_ec_pubkey_serialize(..., buf, output_pk)
+ * secp256k1_ec_pubkey_serialize(..., buf, ..., output_pk, ...)
* secp256k1_ec_pubkey_tweak_add(..., agg_pk, tweak32)
- * secp256k1_ec_pubkey_serialize(..., buf2, agg_pk)
+ * secp256k1_ec_pubkey_serialize(..., buf2, ..., agg_pk, ...)
*
* This function is required if you want to _sign_ for a tweaked aggregate key.
- * On the other hand, if you are only computing a public key, but not intending
- * to create a signature for it, you can just use
- * `secp256k1_ec_pubkey_tweak_add`.
+ * If you are only computing a public key but not intending to create a
+ * signature for it, use `secp256k1_ec_pubkey_tweak_add` instead.
*
- * Returns: 0 if the arguments are invalid or the resulting public key would be
- * invalid (only when the tweak is the negation of the corresponding
- * secret key). 1 otherwise.
+ * Returns: 0 if the arguments are invalid, 1 otherwise
* Args: ctx: pointer to a context object
* Out: output_pubkey: pointer to a public key to store the result. Will be set
* to an invalid value if this function returns 0. If you
* do not need it, this arg can be NULL.
* In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
* `musig_pubkey_agg`
- * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid
- * according to `secp256k1_ec_seckey_verify`, this function
- * returns 0. For uniformly random 32-byte arrays the
- * chance of being invalid is negligible (around 1 in
- * 2^128).
+ * In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes
+ * `secp256k1_ec_seckey_verify` and is not equal to the
+ * secret key corresponding to the public key represented
+ * by keyagg_cache or its negation. For uniformly random
+ * 32-byte arrays the chance of being invalid is
+ * negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_add(
const secp256k1_context *ctx,
@@ -281,36 +268,38 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_a
/** Apply x-only tweaking to a public key in a given keyagg_cache by adding the
* generator multiplied with `tweak32` to it. This is useful for creating
- * Taproot outputs.
+ * Taproot outputs where `tweak32` is set to a TapTweak hash as defined in BIP
+ * 341.
+ *
+ * Callers are responsible for deriving `tweak32` in a way that does not reduce
+ * the security of MuSig (for example, by following Taproot BIP 341).
*
* The tweaking method is the same as `secp256k1_xonly_pubkey_tweak_add`. So in
* the following pseudocode xonly_pubkey_tweak_add_check (absent earlier
* failures) returns 1.
*
* secp256k1_musig_pubkey_agg(..., agg_pk, keyagg_cache, pubkeys, ...)
- * secp256k1_musig_pubkey_xonly_tweak_add(..., output_pk, tweak32, keyagg_cache)
+ * secp256k1_musig_pubkey_xonly_tweak_add(..., output_pk, keyagg_cache, tweak32)
* secp256k1_xonly_pubkey_serialize(..., buf, output_pk)
* secp256k1_xonly_pubkey_tweak_add_check(..., buf, ..., agg_pk, tweak32)
*
* This function is required if you want to _sign_ for a tweaked aggregate key.
- * On the other hand, if you are only computing a public key, but not intending
- * to create a signature for it, you can just use
- * `secp256k1_xonly_pubkey_tweak_add`.
+ * If you are only computing a public key but not intending to create a
+ * signature for it, use `secp256k1_xonly_pubkey_tweak_add` instead.
*
- * Returns: 0 if the arguments are invalid or the resulting public key would be
- * invalid (only when the tweak is the negation of the corresponding
- * secret key). 1 otherwise.
+ * Returns: 0 if the arguments are invalid, 1 otherwise
* Args: ctx: pointer to a context object
* Out: output_pubkey: pointer to a public key to store the result. Will be set
* to an invalid value if this function returns 0. If you
* do not need it, this arg can be NULL.
* In/Out: keyagg_cache: pointer to a `musig_keyagg_cache` struct initialized by
* `musig_pubkey_agg`
- * In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid
- * according to secp256k1_ec_seckey_verify, this function
- * returns 0. For uniformly random 32-byte arrays the
- * chance of being invalid is negligible (around 1 in
- * 2^128).
+ * In: tweak32: pointer to a 32-byte tweak. The tweak is valid if it passes
+ * `secp256k1_ec_seckey_verify` and is not equal to the
+ * secret key corresponding to the public key represented
+ * by keyagg_cache or its negation. For uniformly random
+ * 32-byte arrays the chance of being invalid is
+ * negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_tweak_add(
const secp256k1_context *ctx,
@@ -327,12 +316,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea
* MuSig differs from regular Schnorr signing in that implementers _must_ take
* special care to not reuse a nonce. This can be ensured by following these rules:
*
- * 1. Each call to this function must have a UNIQUE session_id32 that must NOT BE
- * REUSED in subsequent calls to this function.
- * If you do not provide a seckey, session_id32 _must_ be UNIFORMLY RANDOM
- * AND KEPT SECRET (even from other signers). If you do provide a seckey,
- * session_id32 can instead be a counter (that must never repeat!). However,
- * it is recommended to always choose session_id32 uniformly at random.
+ * 1. Each call to this function must have a UNIQUE session_secrand32 that must
+ * NOT BE REUSED in subsequent calls to this function and must be KEPT
+ * SECRET (even from other signers).
* 2. If you already know the seckey, message or aggregate public key
* cache, they can be optionally provided to derive the nonce and increase
* misuse-resistance. The extra_input32 argument can be used to provide
@@ -341,6 +327,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea
* 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
* that it is used more than once for signing.
*
+ * If you don't have access to good randomness for session_secrand32, but you
+ * have access to a non-repeating counter, then see
+ * secp256k1_musig_nonce_gen_counter.
+ *
* Remember that nonce reuse will leak the secret key!
* Note that using the same seckey for multiple MuSig sessions is fine.
*
@@ -348,14 +338,19 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea
* Args: ctx: pointer to a context object (not secp256k1_context_static)
* Out: secnonce: pointer to a structure to store the secret nonce
* pubnonce: pointer to a structure to store the public nonce
- * In: session_id32: a 32-byte session_id32 as explained above. Must be unique to this
- * call to secp256k1_musig_nonce_gen and must be uniformly random
- * unless you really know what you are doing.
+ * In/Out:
+ * session_secrand32: a 32-byte session_secrand32 as explained above. Must be unique to this
+ * call to secp256k1_musig_nonce_gen and must be uniformly
+ * random. If the function call is successful, the
+ * session_secrand32 buffer is invalidated to prevent reuse.
+ * In:
* seckey: the 32-byte secret key that will later be used for signing, if
* already known (can be NULL)
* pubkey: public key of the signer creating the nonce. The secnonce
* output of this function cannot be used to sign for any
- * other public key.
+ * other public key. While the public key should correspond
+ * to the provided seckey, a mismatch will not cause the
+ * function to return 0.
* msg32: the 32-byte message that will later be signed, if already known
* (can be NULL)
* keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
@@ -364,11 +359,11 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea
* extra_input32: an optional 32-byte array that is input to the nonce
* derivation function (can be NULL)
*/
-SECP256K1_API int secp256k1_musig_nonce_gen(
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen(
const secp256k1_context *ctx,
secp256k1_musig_secnonce *secnonce,
secp256k1_musig_pubnonce *pubnonce,
- const unsigned char *session_id32,
+ unsigned char *session_secrand32,
const unsigned char *seckey,
const secp256k1_pubkey *pubkey,
const unsigned char *msg32,
@@ -376,6 +371,68 @@ SECP256K1_API int secp256k1_musig_nonce_gen(
const unsigned char *extra_input32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6);
+
+/** Alternative way to generate a nonce and start a signing session
+ *
+ * This function outputs a secret nonce that will be required for signing and a
+ * corresponding public nonce that is intended to be sent to other signers.
+ *
+ * This function differs from `secp256k1_musig_nonce_gen` by accepting a
+ * non-repeating counter value instead of a secret random value. This requires
+ * that a secret key is provided to `secp256k1_musig_nonce_gen_counter`
+ * (through the keypair argument), as opposed to `secp256k1_musig_nonce_gen`
+ * where the seckey argument is optional.
+ *
+ * MuSig differs from regular Schnorr signing in that implementers _must_ take
+ * special care to not reuse a nonce. This can be ensured by following these rules:
+ *
+ * 1. The nonrepeating_cnt argument must be a counter value that never repeats,
+ * i.e., you must never call `secp256k1_musig_nonce_gen_counter` twice with
+ * the same keypair and nonrepeating_cnt value. For example, this implies
+ * that if the same keypair is used with `secp256k1_musig_nonce_gen_counter`
+ * on multiple devices, none of the devices should have the same counter
+ * value as any other device.
+ * 2. If the seckey, message or aggregate public key cache is already available
+ * at this stage, any of these can be optionally provided, in which case
+ * they will be used in the derivation of the nonce and increase
+ * misuse-resistance. The extra_input32 argument can be used to provide
+ * additional data that does not repeat in normal scenarios, such as the
+ * current time.
+ * 3. Avoid copying (or serializing) the secnonce. This reduces the possibility
+ * that it is used more than once for signing.
+ *
+ * Remember that nonce reuse will leak the secret key!
+ * Note that using the same keypair for multiple MuSig sessions is fine.
+ *
+ * Returns: 0 if the arguments are invalid and 1 otherwise
+ * Args: ctx: pointer to a context object (not secp256k1_context_static)
+ * Out: secnonce: pointer to a structure to store the secret nonce
+ * pubnonce: pointer to a structure to store the public nonce
+ * In:
+ * nonrepeating_cnt: the value of a counter as explained above. Must be
+ * unique to this call to secp256k1_musig_nonce_gen.
+ * keypair: keypair of the signer creating the nonce. The secnonce
+ * output of this function cannot be used to sign for any
+ * other keypair.
+ * msg32: the 32-byte message that will later be signed, if already known
+ * (can be NULL)
+ * keyagg_cache: pointer to the keyagg_cache that was used to create the aggregate
+ * (and potentially tweaked) public key if already known
+ * (can be NULL)
+ * extra_input32: an optional 32-byte array that is input to the nonce
+ * derivation function (can be NULL)
+ */
+SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_gen_counter(
+ const secp256k1_context *ctx,
+ secp256k1_musig_secnonce *secnonce,
+ secp256k1_musig_pubnonce *pubnonce,
+ uint64_t nonrepeating_cnt,
+ const secp256k1_keypair *keypair,
+ const unsigned char *msg32,
+ const secp256k1_musig_keyagg_cache *keyagg_cache,
+ const unsigned char *extra_input32
+) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
+
/** Aggregates the nonces of all signers into a single nonce
*
* This can be done by an untrusted party to reduce the communication
@@ -383,6 +440,9 @@ SECP256K1_API int secp256k1_musig_nonce_gen(
* can be one party receiving all nonces, aggregating the nonces with this
* function and then sending only the aggregate nonce back to the signers.
*
+ * If the aggregator does not compute the aggregate nonce correctly, the final
+ * signature will be invalid.
+ *
* Returns: 0 if the arguments are invalid, 1 otherwise
* Args: ctx: pointer to a context object
* Out: aggnonce: pointer to an aggregate public nonce object for
@@ -394,21 +454,20 @@ SECP256K1_API int secp256k1_musig_nonce_gen(
*/
SECP256K1_API int secp256k1_musig_nonce_agg(
const secp256k1_context *ctx,
- secp256k1_musig_aggnonce *aggnonce,
+ secp256k1_musig_aggnonce *aggnonce,
const secp256k1_musig_pubnonce * const *pubnonces,
size_t n_pubnonces
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
-/** Takes the public nonces of all signers and computes a session that is
- * required for signing and verification of partial signatures.
+/** Takes the aggregate nonce and creates a session that is required for signing
+ * and verification of partial signatures.
*
* If the adaptor argument is non-NULL, then the output of
* musig_partial_sig_agg will be a pre-signature which is not a valid Schnorr
* signature. In order to create a valid signature, the pre-signature and the
* secret adaptor must be provided to `musig_adapt`.
*
- * Returns: 0 if the arguments are invalid or if some signer sent invalid
- * pubnonces, 1 otherwise
+ * Returns: 0 if the arguments are invalid, 1 otherwise
* Args: ctx: pointer to a context object
* Out: session: pointer to a struct to store the session
* In: aggnonce: pointer to an aggregate public nonce object that is the
@@ -423,7 +482,7 @@ SECP256K1_API int secp256k1_musig_nonce_agg(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process(
const secp256k1_context *ctx,
secp256k1_musig_session *session,
- const secp256k1_musig_aggnonce *aggnonce,
+ const secp256k1_musig_aggnonce *aggnonce,
const unsigned char *msg32,
const secp256k1_musig_keyagg_cache *keyagg_cache,
const secp256k1_pubkey *adaptor
@@ -485,10 +544,11 @@ SECP256K1_API int secp256k1_musig_partial_sign(
* create the `session` with `musig_nonce_process`.
*
* This function is essential when using protocols with adaptor signatures.
- * However, it is not essential for regular MuSig sessions, in the sense that if any
- * partial signature does not verify, the full signature will not verify either, so the
- * problem will be caught. But this function allows determining the specific party
- * who produced an invalid signature.
+ * Without adaptor signatures, it is not required to call this function in regular MuSig sessions, because
+ * if any partial signature does not verify, the final signature will not
+ * verify either, so the problem will be caught. However, this function
+ * provides the ability to identify which specific partial signature fails
+ * verification.
*
* Returns: 0 if the arguments are invalid or the partial signature does not
* verify, 1 otherwise
diff --git a/src/secp256k1/include/secp256k1_rangeproof.h b/src/secp256k1/include/secp256k1_rangeproof.h
index 0331527..0224972 100644
--- a/src/secp256k1/include/secp256k1_rangeproof.h
+++ b/src/secp256k1/include/secp256k1_rangeproof.h
@@ -10,6 +10,41 @@ extern "C" {
#include <stdint.h>
+/** This module implements a variant of Back-Maxwell range proofs as described
+ * in the Confidential Assets paper (https://blockstream.com/bitcoin17-final41.pdf).
+ * The construction is based on Borromean ring signatures.
+ * (https://nt4tn.net/papers/borromean_draft_0.01_34241bb.pdf)
+ *
+ * This implementation differs from the variant in the paper mainly in that it
+ * omits an optimization that saves one scalar per ring. This optimization complicates
+ * the protocol and security analysis, as it requires differentiating cases where
+ * the i-th bit v_i = 0 versus otherwise, and makes calculating response points R_i less
+ * straightforward. The implemented version uses Borromean ring signatures in
+ * an unmodified way.
+ *
+ * Another difference is that the implementation omits the last ring's commitment
+ * from the proof, which is recovered by the verifier by subtracting all other digit
+ * commitments from the total, reducing proof size by one group element.
+ *
+ * Furthermore, in the implementation every hash calculation includes a message
+ * m=SHA256(C||H||header||C_0||...||C_(n-2)||extra_commit), binding the commitment C,
+ * generator H, proof header, the n-1 explicit digit commitments, and any extra data.
+ * This prevents an attack that would compromise non-malleability. In the paper's
+ * version of the protocol, a prover could pick distinct indices i, j and a scalar y,
+ * and modify digit commitments in the original proof by setting C'_i = C_i + yG and
+ * C'_j = C_j - yG, obtaining a different valid proof for the same commitment and
+ * witness.
+ *
+ * In the current implementation, up to 3968 bytes of message data can be
+ * embedded and recovered within maximally-sized proofs. The implemented embedding
+ * method using the forged parts of ring signatures could also be applied to the
+ * construction in the paper, but is not mentioned there. Message embedding is used
+ * in Confidential Assets to transmit values and blinding factors of the corresponding
+ * commitments. This is possible because randomness is generated by seeding HMAC-DRBG
+ * with the shared ECDH key, allowing the receiver to rewind the proof using the same
+ * random values the sender used.
+ */
+
/** Length of a message that can be embedded into a maximally-sized rangeproof
*
* It is not be possible to fit a message of this size into a non-maximally-sized
diff --git a/src/secp256k1/include/secp256k1_recovery.h b/src/secp256k1/include/secp256k1_recovery.h
index 93a2e4c..2430f99 100644
--- a/src/secp256k1/include/secp256k1_recovery.h
+++ b/src/secp256k1/include/secp256k1_recovery.h
@@ -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.
diff --git a/src/secp256k1/include/secp256k1_surjectionproof.h b/src/secp256k1/include/secp256k1_surjectionproof.h
index c9a4aae..95c5838 100644
--- a/src/secp256k1/include/secp256k1_surjectionproof.h
+++ b/src/secp256k1/include/secp256k1_surjectionproof.h
@@ -39,7 +39,7 @@ extern "C" {
* The representation is exposed to allow creation of these objects on the
* stack; please *do not* use these internals directly.
*/
-typedef struct {
+typedef struct secp256k1_surjectionproof {
#ifdef VERIFY
/** Mark whether this proof has gone through `secp256k1_surjectionproof_initialize` */
int initialized;
@@ -100,7 +100,7 @@ SECP256K1_API int secp256k1_surjectionproof_serialize(
* data the API user wants to use as an asset tag. Its contents have no
* semantic meaning to libsecp whatsoever.
*/
-typedef struct {
+typedef struct secp256k1_fixed_asset_tag {
unsigned char data[32];
} secp256k1_fixed_asset_tag;
diff --git a/src/secp256k1/include/secp256k1_whitelist.h b/src/secp256k1/include/secp256k1_whitelist.h
index 9f9decc..20d495d 100644
--- a/src/secp256k1/include/secp256k1_whitelist.h
+++ b/src/secp256k1/include/secp256k1_whitelist.h
@@ -31,7 +31,7 @@ extern "C" {
* stack; please *do not* use these internals directly. To learn the number
* of keys for a signature, use `secp256k1_whitelist_signature_n_keys`.
*/
-typedef struct {
+typedef struct secp256k1_whitelist_signature {
size_t n_keys;
/* e0, scalars */
unsigned char data[32 * (1 + SECP256K1_WHITELIST_MAX_N_KEYS)];
diff --git a/src/secp256k1/sage/gen_split_lambda_constants.sage b/src/secp256k1/sage/gen_split_lambda_constants.sage
index 7d4359e..7a5761a 100644
--- a/src/secp256k1/sage/gen_split_lambda_constants.sage
+++ b/src/secp256k1/sage/gen_split_lambda_constants.sage
@@ -81,6 +81,15 @@ assert (A1 + A2)/2 < sqrt(N)
assert B1 < sqrt(N)
assert B2 < sqrt(N)
+# Verify connection to Eisenstein integers Z[w] where w = (-1 + sqrt(-3))/2.
+# The group order N factors as N = pi * conj(pi) in Z[w], where pi = A - B*w
+# is an Eisenstein prime with norm A^2 + A*B + B^2. The GLV endomorphism
+# eigenvalue LAMBDA equals B/A mod N, which is the image of w^2 under the
+# isomorphism Z[w]/(pi) -> Z/NZ (since w -> A/B and (A/B)^2 = B/A in Z/NZ).
+A_EIS, B_EIS = -B1, A1
+assert A_EIS**2 + A_EIS*B_EIS + B_EIS**2 == N
+assert Z(B_EIS / A_EIS) == LAMBDA
+
G1 = round((2**384)*B2/N)
G2 = round((2**384)*(-B1)/N)
diff --git a/src/secp256k1/src/CMakeLists.txt b/src/secp256k1/src/CMakeLists.txt
index 6c471af..ddd5d31 100644
--- a/src/secp256k1/src/CMakeLists.txt
+++ b/src/secp256k1/src/CMakeLists.txt
@@ -1,5 +1,110 @@
-# Must be included before CMAKE_INSTALL_INCLUDEDIR is used.
-include(GNUInstallDirs)
+add_library(secp256k1)
+
+set_property(TARGET secp256k1 PROPERTY PUBLIC_HEADER
+ ${PROJECT_SOURCE_DIR}/include/secp256k1.h
+ ${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h
+)
+
+# Processing must be done in a topological sorting of the dependency graph
+# (dependent module first).
+if(SECP256K1_ENABLE_MODULE_SCHNORRSIG_HALFAGG)
+ if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG)
+ message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the schnorrsig_halfagg module.")
+ endif()
+ set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON)
+ add_compile_definitions(ENABLE_MODULE_SCHNORRSIG_HALFAGG=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig_halfagg.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_BPPP)
+ if(DEFINED SECP256K1_ENABLE_MODULE_GENERATOR AND NOT SECP256K1_ENABLE_MODULE_GENERATOR)
+ message(FATAL_ERROR "Module dependency error: You have disabled the generator module explicitly, but it is required by the bppp module.")
+ endif()
+ set(SECP256K1_ENABLE_MODULE_GENERATOR ON)
+ add_compile_definitions(ENABLE_MODULE_BPPP=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_bppp.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_ECDSA_S2C)
+ add_compile_definitions(ENABLE_MODULE_ECDSA_S2C=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_ecdsa_s2c.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR)
+ add_compile_definitions(ENABLE_MODULE_ECDSA_ADAPTOR=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_ecdsa_adaptor.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_WHITELIST)
+ if(DEFINED SECP256K1_ENABLE_MODULE_RANGEPROOF AND NOT SECP256K1_ENABLE_MODULE_RANGEPROOF)
+ message(FATAL_ERROR "Module dependency error: You have disabled the rangeproof module explicitly, but it is required by the whitelist module.")
+ endif()
+ set(SECP256K1_ENABLE_MODULE_RANGEPROOF ON)
+ add_compile_definitions(ENABLE_MODULE_WHITELIST=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_whitelist.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_SURJECTIONPROOF)
+ if(DEFINED SECP256K1_ENABLE_MODULE_RANGEPROOF AND NOT SECP256K1_ENABLE_MODULE_RANGEPROOF)
+ message(FATAL_ERROR "Module dependency error: You have disabled the rangeproof module explicitly, but it is required by the surjectionproof module.")
+ endif()
+ set(SECP256K1_ENABLE_MODULE_RANGEPROOF ON)
+ add_compile_definitions(ENABLE_MODULE_SURJECTIONPROOF=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_surjectionproof.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_RANGEPROOF)
+ if(DEFINED SECP256K1_ENABLE_MODULE_GENERATOR AND NOT SECP256K1_ENABLE_MODULE_GENERATOR)
+ message(FATAL_ERROR "Module dependency error: You have disabled the generator module explicitly, but it is required by the rangeproof module.")
+ endif()
+ set(SECP256K1_ENABLE_MODULE_GENERATOR ON)
+ add_compile_definitions(ENABLE_MODULE_RANGEPROOF=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_rangeproof.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_GENERATOR)
+ add_compile_definitions(ENABLE_MODULE_GENERATOR=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_generator.h)
+endif()
+
+
+if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
+ add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_MUSIG)
+ if(DEFINED SECP256K1_ENABLE_MODULE_SCHNORRSIG AND NOT SECP256K1_ENABLE_MODULE_SCHNORRSIG)
+ message(FATAL_ERROR "Module dependency error: You have disabled the schnorrsig module explicitly, but it is required by the musig module.")
+ endif()
+ set(SECP256K1_ENABLE_MODULE_SCHNORRSIG ON)
+ add_compile_definitions(ENABLE_MODULE_MUSIG=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
+ if(DEFINED SECP256K1_ENABLE_MODULE_EXTRAKEYS AND NOT SECP256K1_ENABLE_MODULE_EXTRAKEYS)
+ message(FATAL_ERROR "Module dependency error: You have disabled the extrakeys module explicitly, but it is required by the schnorrsig module.")
+ endif()
+ set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
+ add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
+ add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_RECOVERY)
+ add_compile_definitions(ENABLE_MODULE_RECOVERY=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h)
+endif()
+
+if(SECP256K1_ENABLE_MODULE_ECDH)
+ add_compile_definitions(ENABLE_MODULE_ECDH=1)
+ set_property(TARGET secp256k1 APPEND PROPERTY PUBLIC_HEADER ${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h)
+endif()
add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL
precomputed_ecmult.c
@@ -8,7 +113,16 @@ add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL
# Add objects explicitly rather than linking to the object libs to keep them
# from being exported.
-add_library(secp256k1 secp256k1.c $<TARGET_OBJECTS:secp256k1_precomputed>)
+target_sources(secp256k1 PRIVATE secp256k1.c $<TARGET_OBJECTS:secp256k1_precomputed>)
+
+if(NOT SECP256K1_ENABLE_API_VISIBILITY_ATTRIBUTES)
+ target_compile_definitions(secp256k1 PRIVATE SECP256K1_NO_API_VISIBILITY_ATTRIBUTES)
+endif()
+
+# Create a helper lib that parent projects can use to link secp256k1 into a
+# static lib.
+add_library(secp256k1_objs INTERFACE)
+target_sources(secp256k1_objs INTERFACE $<TARGET_OBJECTS:secp256k1> $<TARGET_OBJECTS:secp256k1_precomputed>)
add_library(secp256k1_asm INTERFACE)
if(SECP256K1_ASM STREQUAL "arm32")
@@ -17,6 +131,7 @@ if(SECP256K1_ASM STREQUAL "arm32")
asm/field_10x26_arm.s
)
target_sources(secp256k1 PRIVATE $<TARGET_OBJECTS:secp256k1_asm_arm>)
+ target_sources(secp256k1_objs INTERFACE $<TARGET_OBJECTS:secp256k1_asm_arm>)
target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm)
endif()
@@ -31,37 +146,32 @@ endif()
get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE)
set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic})
+# Add the include path for parent projects so that they don't have to manually add it.
target_include_directories(secp256k1 INTERFACE
- # Add the include path for parent projects so that they don't have to manually add it.
$<BUILD_INTERFACE:$<$<NOT:$<BOOL:${PROJECT_IS_TOP_LEVEL}>>:${PROJECT_SOURCE_DIR}/include>>
- $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+set_target_properties(secp256k1_objs PROPERTIES
+ INTERFACE_COMPILE_DEFINITIONS "$<TARGET_PROPERTY:secp256k1,INTERFACE_COMPILE_DEFINITIONS>"
+ INTERFACE_INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:secp256k1,INTERFACE_INCLUDE_DIRECTORIES>"
)
# This emulates Libtool to make sure Libtool and CMake agree on the ABI version,
-# see below "Calculate the version variables" in build-aux/ltmain.sh.
+# see below "Calculate the version variables" in autotools-aux/ltmain.sh.
math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}")
set_target_properties(secp256k1 PROPERTIES
SOVERSION ${${PROJECT_NAME}_soversion}
)
-if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+if(CMAKE_SYSTEM_NAME MATCHES "^(Linux|FreeBSD)$")
set_target_properties(secp256k1 PROPERTIES
VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
)
elseif(APPLE)
- if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17)
- math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1")
- set_target_properties(secp256k1 PROPERTIES
- MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version}
- MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
- )
- unset(${PROJECT_NAME}_compatibility_version)
- elseif(BUILD_SHARED_LIBS)
- message(WARNING
- "The 'compatibility version' and 'current version' values of the DYLIB "
- "will diverge from the values set by the GNU Libtool. To ensure "
- "compatibility, it is recommended to upgrade CMake to at least version 3.17."
- )
- endif()
+ math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1")
+ set_target_properties(secp256k1 PROPERTIES
+ MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version}
+ MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
+ )
+ unset(${PROJECT_NAME}_compatibility_version)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(${PROJECT_NAME}_windows "secp256k1")
if(MSVC)
@@ -85,15 +195,36 @@ if(SECP256K1_BUILD_BENCHMARK)
endif()
if(SECP256K1_BUILD_TESTS)
- add_executable(noverify_tests tests.c)
- target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm)
- add_test(NAME secp256k1_noverify_tests COMMAND noverify_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()
+
+ function(add_executable_and_tests exe_name verify_definition)
+ add_executable(${exe_name} tests.c)
+ target_link_libraries(${exe_name} secp256k1_precomputed secp256k1_asm)
+ target_compile_definitions(${exe_name} PRIVATE ${verify_definition} ${TEST_DEFINITIONS})
+ include(DiscoverTests)
+ discover_tests(${exe_name}
+ DISCOVERY_ARGS "--list_tests"
+ DISCOVERY_MATCH "^\\t\\\\[ *[0-9]+\\\\] ([^ ].*)$"
+ TEST_NAME_REPLACEMENT "secp256k1.${exe_name}.\\\\1"
+ TEST_ARGS_REPLACEMENT "--target=\\\\1 --log=1"
+ PROPERTIES
+ LABELS "secp256k1_${exe_name}"
+ )
+ endfunction()
+
+ add_executable_and_tests(noverify_tests "")
if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
- add_executable(tests tests.c)
- target_compile_definitions(tests PRIVATE VERIFY)
- target_link_libraries(tests secp256k1_precomputed secp256k1_asm)
- add_test(NAME secp256k1_tests COMMAND tests)
+ add_executable_and_tests(tests VERIFY)
endif()
+ unset(TEST_DEFINITIONS)
endif()
if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
@@ -101,7 +232,10 @@ if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
add_executable(exhaustive_tests tests_exhaustive.c)
target_link_libraries(exhaustive_tests secp256k1_asm)
target_compile_definitions(exhaustive_tests PRIVATE $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
- add_test(NAME secp256k1_exhaustive_tests COMMAND exhaustive_tests)
+ add_test(NAME secp256k1.exhaustive_tests COMMAND exhaustive_tests)
+ set_tests_properties(secp256k1.exhaustive_tests PROPERTIES
+ LABELS secp256k1_exhaustive
+ )
endif()
if(SECP256K1_BUILD_CTIME_TESTS)
@@ -110,61 +244,16 @@ if(SECP256K1_BUILD_CTIME_TESTS)
endif()
if(SECP256K1_INSTALL)
+ include(GNUInstallDirs)
+ target_include_directories(secp256k1 INTERFACE
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+ )
install(TARGETS secp256k1
EXPORT ${PROJECT_NAME}-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
- )
- set(${PROJECT_NAME}_headers
- "${PROJECT_SOURCE_DIR}/include/secp256k1.h"
- "${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h"
- )
- if(SECP256K1_ENABLE_MODULE_BPPP)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_bppp.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_ECDSA_S2C)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdsa_s2c.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_ECDSA_ADAPTOR)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdsa_adaptor.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_MUSIG)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_WHITELIST)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_whitelist.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_SURJECTIONPROOF)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_surjectionproof.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_RANGEPROOF)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_rangeproof.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_GENERATOR)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_generator.h")
- endif()
-
- if(SECP256K1_ENABLE_MODULE_ECDH)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_RECOVERY)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_MUSIG)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_musig.h")
- endif()
- if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
- list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h")
- endif()
- install(FILES ${${PROJECT_NAME}_headers}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+ PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(EXPORT ${PROJECT_NAME}-targets
diff --git a/src/secp256k1/src/bench.c b/src/secp256k1/src/bench.c
index 1127df6..f561ad1 100644
--- a/src/secp256k1/src/bench.c
+++ b/src/secp256k1/src/bench.c
@@ -5,33 +5,38 @@
***********************************************************************/
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include "../include/secp256k1.h"
#include "util.h"
#include "bench.h"
-static void help(int default_iters) {
+static void help(const char *executable_path, int default_iters) {
printf("Benchmarks the following algorithms:\n");
printf(" - ECDSA signing/verification\n");
-#ifdef ENABLE_MODULE_ECDH
- printf(" - ECDH key exchange (optional module)\n");
-#endif
-
#ifdef ENABLE_MODULE_RECOVERY
printf(" - Public key recovery (optional module)\n");
#endif
+#ifdef ENABLE_MODULE_ECDH
+ printf(" - ECDH key exchange (optional module)\n");
+#endif
+
#ifdef ENABLE_MODULE_SCHNORRSIG
printf(" - Schnorr signatures (optional module)\n");
#endif
+#ifdef ENABLE_MODULE_ELLSWIFT
+ printf(" - ElligatorSwift (optional module)\n");
+#endif
+
printf("\n");
printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters);
printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n");
printf("\n");
- printf("Usage: ./bench [args]\n");
+ printf("Usage: %s [args]\n", executable_path);
printf("By default, all benchmarks will be run.\n");
printf("args:\n");
printf(" help : display this help and exit\n");
@@ -172,27 +177,31 @@ int main(int argc, char** argv) {
bench_data data;
int d = argc == 1;
- int default_iters = 20000;
- int iters = get_iters(default_iters);
/* Check for invalid user arguments */
char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover",
"ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec",
"keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode",
"ellswift_decode", "ellswift_keygen", "ellswift_ecdh"};
- size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]);
- int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size);
+ int invalid_args = have_invalid_args(argc, argv, valid_args, ARRAY_SIZE(valid_args));
+
+ int default_iters = 20000;
+ int iters = get_iters(default_iters);
+ if (iters == 0) {
+ help(argv[0], default_iters);
+ return EXIT_FAILURE;
+ }
if (argc > 1) {
if (have_flag(argc, argv, "-h")
|| have_flag(argc, argv, "--help")
|| have_flag(argc, argv, "help")) {
- help(default_iters);
- return 0;
+ help(argv[0], default_iters);
+ return EXIT_SUCCESS;
} else if (invalid_args) {
fprintf(stderr, "./bench: unrecognized argument.\n\n");
- help(default_iters);
- return 1;
+ help(argv[0], default_iters);
+ return EXIT_FAILURE;
}
}
@@ -200,24 +209,24 @@ int main(int argc, char** argv) {
#ifndef ENABLE_MODULE_ECDH
if (have_flag(argc, argv, "ecdh")) {
fprintf(stderr, "./bench: ECDH module not enabled.\n");
- fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n");
- return 1;
+ fprintf(stderr, "See README.md for configuration instructions.\n\n");
+ return EXIT_FAILURE;
}
#endif
#ifndef ENABLE_MODULE_RECOVERY
if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) {
fprintf(stderr, "./bench: Public key recovery module not enabled.\n");
- fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n");
- return 1;
+ fprintf(stderr, "See README.md for configuration instructions.\n\n");
+ return EXIT_FAILURE;
}
#endif
#ifndef ENABLE_MODULE_SCHNORRSIG
if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) {
fprintf(stderr, "./bWhy this scored 44/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.