mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-13 12:33:42 +02:00
Update src/secp256k1 to latest BlockstreamResearch/secp256k1-zkp master
This commit is contained in:
parent
13398037b6
commit
60fba755b5
159 changed files with 19301 additions and 14982 deletions
|
|
@ -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
|
||||
|
|
@ -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 }}
|
||||
|
|
|
|||
34
src/secp256k1/.github/actions/print-logs/action.yml
vendored
Normal file
34
src/secp256k1/.github/actions/print-logs/action.yml
vendored
Normal file
|
|
@ -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
|
||||
|
|
@ -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 }}
|
||||
"
|
||||
|
|
|
|||
637
src/secp256k1/.github/workflows/ci.yml
vendored
637
src/secp256k1/.github/workflows/ci.yml
vendored
|
|
@ -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
|
||||
scope: ${{ runner.arch }}-${{ needs.docker_cache.outputs.cache_scope }}
|
||||
command: ./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() }}
|
||||
- &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
|
||||
|
||||
|
|
|
|||
61
src/secp256k1/.github/workflows/sync.yml
vendored
Normal file
61
src/secp256k1/.github/workflows/sync.yml
vendored
Normal file
|
|
@ -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
|
||||
28
src/secp256k1/.gitignore
vendored
28
src/secp256k1/.gitignore
vendored
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
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()
|
||||
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".
|
||||
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"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0},
|
||||
"version": 3,
|
||||
"configurePresets": [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
------------
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ AC_DEFUN([SECP_X86_64_ASM_CHECK],[
|
|||
AC_MSG_CHECKING(for x86_64 assembly availability)
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <stdint.h>]],[[
|
||||
uint64_t a = 11, tmp;
|
||||
uint64_t a = 11, tmp = 0;
|
||||
__asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
|
||||
]])], [has_x86_64_asm=yes], [has_x86_64_asm=no])
|
||||
AC_MSG_RESULT([$has_x86_64_asm])
|
||||
|
|
@ -45,6 +45,22 @@ 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], [
|
||||
|
|
@ -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"
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
18
src/secp256k1/cmake/CheckMemorySanitizer.cmake
Normal file
18
src/secp256k1/cmake/CheckMemorySanitizer.cmake
Normal file
|
|
@ -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()
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
71
src/secp256k1/cmake/DiscoverTests.cmake
Normal file
71
src/secp256k1/cmake/DiscoverTests.cmake
Normal file
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
||||
Usage:
|
||||
$0 [--switch] <base-branch> <upstream-ref>
|
||||
|
||||
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>.
|
||||
|
||||
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>: ...".)
|
||||
|
||||
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>
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
# Process -b <branch> argument
|
||||
while getopts "b:" opt; do
|
||||
case $opt in
|
||||
b)
|
||||
LOCAL_BRANCH=$OPTARG
|
||||
;;
|
||||
\?)
|
||||
echo "Invalid option: -$OPTARG" >&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Shift off the processed options
|
||||
shift $((OPTIND -1))
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
help
|
||||
### 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
|
||||
|
|
|
|||
|
|
@ -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].
|
||||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
secure_erase(seckey, sizeof(seckey));
|
||||
}
|
||||
|
||||
/* 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");
|
||||
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)) {
|
||||
|
||||
/* 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 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("ok\n");
|
||||
|
||||
printf("Combining public keys...");
|
||||
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 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
* such mistakes, and the default (crashing) may be inadvisable. Should this
|
||||
* callback return instead of crashing, the return value and output arguments
|
||||
* of the API function call are undefined. Moreover, the same API call may
|
||||
* trigger the callback again in this case.
|
||||
*
|
||||
* When this function has not been called (or called with fn==NULL), then the
|
||||
* default handler will be used. The library provides a default handler which
|
||||
* writes the message to stderr and calls abort. This default handler can be
|
||||
* When this function has not been called (or called with fun==NULL), then the
|
||||
* default callback will be used. The library provides a default callback which
|
||||
* writes the message to stderr and calls abort. This default callback can be
|
||||
* replaced at link time if the preprocessor macro
|
||||
* USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build
|
||||
* has been configured with --enable-external-default-callbacks. Then the
|
||||
* 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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,9 +149,22 @@ SECP256K1_API int secp256k1_musig_aggnonce_serialize(
|
|||
const secp256k1_musig_aggnonce *nonce
|
||||
) 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
|
||||
*/
|
||||
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 when the signature could be serialized, 0 otherwise
|
||||
* 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
|
||||
|
|
@ -165,41 +175,17 @@ SECP256K1_API int secp256k1_musig_partial_sig_serialize(
|
|||
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(
|
||||
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);
|
||||
|
||||
/** 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)];
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
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)
|
||||
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_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
|
||||
|
|
|
|||
|
|
@ -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, "./bench: Schnorr signatures module not enabled.\n");
|
||||
fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n");
|
||||
return 1;
|
||||
fprintf(stderr, "See README.md for configuration instructions.\n\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -226,8 +235,8 @@ int main(int argc, char** argv) {
|
|||
have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") ||
|
||||
have_flag(argc, argv, "ellswift_ecdh")) {
|
||||
fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n");
|
||||
fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n");
|
||||
return 1;
|
||||
fprintf(stderr, "See README.md for configuration instructions.\n\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -275,5 +284,5 @@ int main(int argc, char** argv) {
|
|||
run_ellswift_bench(iters, argc, argv);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,27 +12,7 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
# include <time.h>
|
||||
#else
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
static int64_t gettime_i64(void) {
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
/* C11 way to get wallclock time */
|
||||
struct timespec tv;
|
||||
if (!timespec_get(&tv, TIME_UTC)) {
|
||||
fputs("timespec_get failed!", stderr);
|
||||
exit(1);
|
||||
}
|
||||
return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
|
||||
#endif
|
||||
}
|
||||
#include "tests_common.h"
|
||||
|
||||
#define FP_EXP (6)
|
||||
#define FP_MULT (1000000LL)
|
||||
|
|
@ -79,7 +59,7 @@ static void print_number(const int64_t x) {
|
|||
y /= 10;
|
||||
}
|
||||
} else if (c == 0) { /* fractional part is 0 */
|
||||
buffer[--ptr] = '0';
|
||||
buffer[--ptr] = '0';
|
||||
}
|
||||
buffer[--ptr] = '.';
|
||||
do {
|
||||
|
|
@ -170,7 +150,13 @@ static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n)
|
|||
static int get_iters(int default_iters) {
|
||||
char* env = getenv("SECP256K1_BENCH_ITERS");
|
||||
if (env) {
|
||||
return strtol(env, NULL, 0);
|
||||
char* endptr;
|
||||
long int iters = strtol(env, &endptr, 0);
|
||||
if (*endptr != '\0' || iters <= 0) {
|
||||
printf("Error: Value of SECP256K1_BENCH_ITERS is not a positive integer: %s\n\n", env);
|
||||
return 0;
|
||||
}
|
||||
return iters;
|
||||
} else {
|
||||
return default_iters;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
**********************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../include/secp256k1_bppp.h"
|
||||
#include "util.h"
|
||||
|
|
@ -28,11 +29,14 @@ static void bench_bppp(void* arg, int iters) {
|
|||
int main(void) {
|
||||
bench_bppp_data data;
|
||||
int iters = get_iters(32);
|
||||
if (iters == 0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
|
||||
run_benchmark("bppp_verify_bit", bench_bppp, bench_bppp_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "secp256k1.c"
|
||||
#include "../include/secp256k1.h"
|
||||
|
|
@ -18,10 +19,13 @@
|
|||
|
||||
#define POINTS 32768
|
||||
|
||||
static void help(char **argv) {
|
||||
static void help(const char *executable_path, int default_iters) {
|
||||
printf("Benchmark EC multiplication algorithms\n");
|
||||
printf("\n");
|
||||
printf("Usage: %s <help|pippenger_wnaf|strauss_wnaf|simple>\n", argv[0]);
|
||||
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: %s [args]\n", executable_path);
|
||||
printf("The output shows the number of multiplied and summed points right after the\n");
|
||||
printf("function name. The letter 'g' indicates that one of the points is the generator.\n");
|
||||
printf("The benchmarks are divided by the number of points.\n");
|
||||
|
|
@ -55,6 +59,7 @@ typedef struct {
|
|||
|
||||
/* Benchmark output. */
|
||||
secp256k1_gej* output;
|
||||
secp256k1_fe* output_xonly;
|
||||
} bench_data;
|
||||
|
||||
/* Hashes x into [0, POINTS) twice and store the result in offset1 and offset2. */
|
||||
|
|
@ -122,6 +127,32 @@ static void bench_ecmult_const_teardown(void* arg, int iters) {
|
|||
bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters);
|
||||
}
|
||||
|
||||
static void bench_ecmult_const_xonly(void* arg, int iters) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < iters; ++i) {
|
||||
const secp256k1_ge* pubkey = &data->pubkeys[(data->offset1+i) % POINTS];
|
||||
const secp256k1_scalar* scalar = &data->scalars[(data->offset2+i) % POINTS];
|
||||
int known_on_curve = 1;
|
||||
secp256k1_ecmult_const_xonly(&data->output_xonly[i], &pubkey->x, NULL, scalar, known_on_curve);
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_ecmult_const_xonly_teardown(void* arg, int iters) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
int i;
|
||||
|
||||
/* verify by comparing with x coordinate of regular ecmult result */
|
||||
for (i = 0; i < iters; ++i) {
|
||||
const secp256k1_gej* pubkey_gej = &data->pubkeys_gej[(data->offset1+i) % POINTS];
|
||||
const secp256k1_scalar* scalar = &data->scalars[(data->offset2+i) % POINTS];
|
||||
secp256k1_gej expected_gej;
|
||||
secp256k1_ecmult(&expected_gej, pubkey_gej, scalar, NULL);
|
||||
CHECK(secp256k1_gej_eq_x_var(&data->output_xonly[i], &expected_gej));
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_ecmult_1p(void* arg, int iters) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
int i;
|
||||
|
|
@ -170,6 +201,8 @@ static void run_ecmult_bench(bench_data* data, int iters) {
|
|||
run_benchmark(str, bench_ecmult_gen, bench_ecmult_setup, bench_ecmult_gen_teardown, data, 10, iters);
|
||||
sprintf(str, "ecmult_const");
|
||||
run_benchmark(str, bench_ecmult_const, bench_ecmult_setup, bench_ecmult_const_teardown, data, 10, iters);
|
||||
sprintf(str, "ecmult_const_xonly");
|
||||
run_benchmark(str, bench_ecmult_const_xonly, bench_ecmult_setup, bench_ecmult_const_xonly_teardown, data, 10, iters);
|
||||
/* ecmult with non generator point */
|
||||
sprintf(str, "ecmult_1p");
|
||||
run_benchmark(str, bench_ecmult_1p, bench_ecmult_setup, bench_ecmult_1p_teardown, data, 10, iters);
|
||||
|
|
@ -226,7 +259,7 @@ static void bench_ecmult_multi_teardown(void* arg, int iters) {
|
|||
}
|
||||
}
|
||||
|
||||
static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
|
||||
static void generate_scalar(const secp256k1_context *ctx, uint32_t num, secp256k1_scalar* scalar) {
|
||||
secp256k1_sha256 sha256;
|
||||
unsigned char c[10] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0};
|
||||
unsigned char buf[32];
|
||||
|
|
@ -236,8 +269,8 @@ static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
|
|||
c[8] = num >> 16;
|
||||
c[9] = num >> 24;
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&sha256, c, sizeof(c));
|
||||
secp256k1_sha256_finalize(&sha256, buf);
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &sha256, c, sizeof(c));
|
||||
secp256k1_sha256_finalize(secp256k1_get_hash_context(ctx), &sha256, buf);
|
||||
secp256k1_scalar_set_b32(scalar, buf, &overflow);
|
||||
CHECK(!overflow);
|
||||
}
|
||||
|
|
@ -278,7 +311,12 @@ int main(int argc, char **argv) {
|
|||
int i, p;
|
||||
size_t scratch_size;
|
||||
|
||||
int iters = get_iters(10000);
|
||||
int default_iters = 10000;
|
||||
int iters = get_iters(default_iters);
|
||||
if (iters == 0) {
|
||||
help(argv[0], default_iters);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
data.ecmult_multi = secp256k1_ecmult_multi_var;
|
||||
|
||||
|
|
@ -286,8 +324,8 @@ int main(int argc, char **argv) {
|
|||
if(have_flag(argc, argv, "-h")
|
||||
|| have_flag(argc, argv, "--help")
|
||||
|| have_flag(argc, argv, "help")) {
|
||||
help(argv);
|
||||
return 0;
|
||||
help(argv[0], default_iters);
|
||||
return EXIT_SUCCESS;
|
||||
} else if(have_flag(argc, argv, "pippenger_wnaf")) {
|
||||
printf("Using pippenger_wnaf:\n");
|
||||
data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single;
|
||||
|
|
@ -298,13 +336,13 @@ int main(int argc, char **argv) {
|
|||
printf("Using simple algorithm:\n");
|
||||
} else {
|
||||
fprintf(stderr, "%s: unrecognized argument '%s'.\n\n", argv[0], argv[1]);
|
||||
help(argv);
|
||||
return 1;
|
||||
help(argv[0], default_iters);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
|
||||
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT;
|
||||
if (!have_flag(argc, argv, "simple")) {
|
||||
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
|
||||
} else {
|
||||
|
|
@ -318,12 +356,13 @@ int main(int argc, char **argv) {
|
|||
data.pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS);
|
||||
data.expected_output = malloc(sizeof(secp256k1_gej) * (iters + 1));
|
||||
data.output = malloc(sizeof(secp256k1_gej) * (iters + 1));
|
||||
data.output_xonly = malloc(sizeof(secp256k1_fe) * (iters + 1));
|
||||
|
||||
/* Generate a set of scalars, and private/public keypairs. */
|
||||
secp256k1_gej_set_ge(&data.pubkeys_gej[0], &secp256k1_ge_const_g);
|
||||
secp256k1_scalar_set_int(&data.seckeys[0], 1);
|
||||
for (i = 0; i < POINTS; ++i) {
|
||||
generate_scalar(i, &data.scalars[i]);
|
||||
generate_scalar(data.ctx, i, &data.scalars[i]);
|
||||
if (i) {
|
||||
secp256k1_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL);
|
||||
secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]);
|
||||
|
|
@ -350,6 +389,8 @@ int main(int argc, char **argv) {
|
|||
run_ecmult_multi_bench(&data, i << p, 1, iters);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printf("Skipping some benchmarks due to SECP256K1_BENCH_ITERS <= 2\n");
|
||||
}
|
||||
|
||||
if (data.scratch != NULL) {
|
||||
|
|
@ -360,8 +401,9 @@ int main(int argc, char **argv) {
|
|||
free(data.pubkeys);
|
||||
free(data.pubkeys_gej);
|
||||
free(data.seckeys);
|
||||
free(data.output_xonly);
|
||||
free(data.output);
|
||||
free(data.expected_output);
|
||||
|
||||
return(0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
**********************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../include/secp256k1_generator.h"
|
||||
|
|
@ -49,6 +50,9 @@ static void bench_generator_generate_blinded(void* arg, int iters) {
|
|||
int main(void) {
|
||||
bench_generator_t data;
|
||||
int iters = get_iters(20000);
|
||||
if (iters == 0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
|
||||
|
|
@ -56,5 +60,5 @@ int main(void) {
|
|||
run_benchmark("generator_generate_blinded", bench_generator_generate_blinded, bench_generator_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "secp256k1.c"
|
||||
#include "../include/secp256k1.h"
|
||||
|
|
@ -17,13 +18,13 @@
|
|||
#include "ecmult_impl.h"
|
||||
#include "bench.h"
|
||||
|
||||
static void help(int default_iters) {
|
||||
static void help(const char *executable_path, int default_iters) {
|
||||
printf("Benchmarks various internal routines.\n");
|
||||
printf("\n");
|
||||
printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters);
|
||||
printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n");
|
||||
printf("\n");
|
||||
printf("Usage: ./bench_internal [args]\n");
|
||||
printf("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");
|
||||
|
|
@ -37,6 +38,7 @@ static void help(int default_iters) {
|
|||
}
|
||||
|
||||
typedef struct {
|
||||
const secp256k1_context* ctx;
|
||||
secp256k1_scalar scalar[2];
|
||||
secp256k1_fe fe[4];
|
||||
secp256k1_ge ge[2];
|
||||
|
|
@ -81,6 +83,9 @@ static void bench_setup(void* arg) {
|
|||
}
|
||||
};
|
||||
|
||||
/* Customize context if needed */
|
||||
data->ctx = secp256k1_context_static;
|
||||
|
||||
secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL);
|
||||
secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL);
|
||||
secp256k1_fe_set_b32_limit(&data->fe[0], init[0]);
|
||||
|
|
@ -370,11 +375,12 @@ static void bench_sha256(void* arg, int iters) {
|
|||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
secp256k1_sha256 sha;
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(data->ctx);
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, data->data, 32);
|
||||
secp256k1_sha256_finalize(&sha, data->data);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, data->data, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, data->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -382,11 +388,12 @@ static void bench_hmac_sha256(void* arg, int iters) {
|
|||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(data->ctx);
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_hmac_sha256_initialize(&hmac, data->data, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, data->data, 32);
|
||||
secp256k1_hmac_sha256_finalize(&hmac, data->data);
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, data->data, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, data->data, 32);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, data->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -394,10 +401,11 @@ static void bench_rfc6979_hmac_sha256(void* arg, int iters) {
|
|||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
secp256k1_rfc6979_hmac_sha256 rng;
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(data->ctx);
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64);
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32);
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, data->data, 64);
|
||||
secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, data->data, 32);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -411,16 +419,20 @@ static void bench_context(void* arg, int iters) {
|
|||
|
||||
int main(int argc, char **argv) {
|
||||
bench_inv data;
|
||||
int d = argc == 1; /* default */
|
||||
int default_iters = 20000;
|
||||
int iters = get_iters(default_iters);
|
||||
int d = argc == 1; /* default */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -461,5 +473,5 @@ int main(int argc, char **argv) {
|
|||
|
||||
if (d || have_flag(argc, argv, "context")) run_benchmark("context_create", bench_context, bench_setup, NULL, &data, 10, iters);
|
||||
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
**********************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../include/secp256k1_rangeproof.h"
|
||||
#include "util.h"
|
||||
|
|
@ -57,9 +58,12 @@ int main(void) {
|
|||
|
||||
data.min_bits = 32;
|
||||
iters = data.min_bits*get_iters(32);
|
||||
if (iters == 0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../include/secp256k1.h"
|
||||
|
||||
|
|
@ -13,7 +14,6 @@
|
|||
#include "hash_impl.h"
|
||||
#include "int128_impl.h"
|
||||
#include "scalar_impl.h"
|
||||
#include "testrand_impl.h"
|
||||
|
||||
#define MAX_N_KEYS 30
|
||||
|
||||
|
|
@ -49,17 +49,21 @@ static void run_test(bench_data* data, int iters) {
|
|||
run_benchmark(str, bench_whitelist, bench_whitelist_setup, NULL, data, 100, iters);
|
||||
}
|
||||
|
||||
static void random_scalar_order(secp256k1_scalar *num) {
|
||||
do {
|
||||
unsigned char b32[32];
|
||||
int overflow = 0;
|
||||
secp256k1_testrand256(b32);
|
||||
secp256k1_scalar_set_b32(num, b32, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(num)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} while(1);
|
||||
static void generate_scalar(secp256k1_scalar *scalar, unsigned char *seckey, uint32_t num) {
|
||||
secp256k1_sha256 sha256;
|
||||
secp256k1_hash_ctx hash_ctx;
|
||||
unsigned char c[13] = {'w','h','i','t','e','l','i','s','t', 0, 0, 0, 0};
|
||||
int is_valid;
|
||||
secp256k1_hash_ctx_init(&hash_ctx);
|
||||
c[9] = num;
|
||||
c[10] = num >> 8;
|
||||
c[11] = num >> 16;
|
||||
c[12] = num >> 24;
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&hash_ctx, &sha256, c, sizeof(c));
|
||||
secp256k1_sha256_finalize(&hash_ctx, &sha256, seckey);
|
||||
is_valid = secp256k1_scalar_set_b32_seckey(scalar, seckey);
|
||||
CHECK(is_valid);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
|
@ -68,26 +72,26 @@ int main(void) {
|
|||
size_t n_keys = 30;
|
||||
secp256k1_scalar ssub;
|
||||
int iters = get_iters(5);
|
||||
if (iters == 0) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
|
||||
/* Start with subkey */
|
||||
random_scalar_order(&ssub);
|
||||
secp256k1_scalar_get_b32(data.csub, &ssub);
|
||||
generate_scalar(&ssub, data.csub, 0);
|
||||
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.csub) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(data.ctx, &data.sub_pubkey, data.csub) == 1);
|
||||
/* Then offline and online whitelist keys */
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
secp256k1_scalar son, soff;
|
||||
|
||||
/* Create two keys */
|
||||
random_scalar_order(&son);
|
||||
secp256k1_scalar_get_b32(data.online_seckey[i], &son);
|
||||
/* Create two keys using different counter values to ensure different keys */
|
||||
generate_scalar(&son, data.online_seckey[i], i + 1);
|
||||
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.online_seckey[i]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(data.ctx, &data.online_pubkeys[i], data.online_seckey[i]) == 1);
|
||||
|
||||
random_scalar_order(&soff);
|
||||
secp256k1_scalar_get_b32(data.summed_seckey[i], &soff);
|
||||
generate_scalar(&soff, data.summed_seckey[i], i + 1 + n_keys);
|
||||
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.summed_seckey[i]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(data.ctx, &data.offline_pubkeys[i], data.summed_seckey[i]) == 1);
|
||||
|
||||
|
|
@ -104,5 +108,5 @@ int main(void) {
|
|||
}
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return(0);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,17 @@
|
|||
# if __has_feature(memory_sanitizer)
|
||||
# include <sanitizer/msan_interface.h>
|
||||
# define SECP256K1_CHECKMEM_ENABLED 1
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len))
|
||||
# if defined(__clang__) && ((__clang_major__ == 21 && __clang_minor__ >= 1) || __clang_major__ >= 22)
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) do { \
|
||||
/* Work around https://github.com/llvm/llvm-project/issues/160094 */ \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wuninitialized-const-pointer\"") \
|
||||
__msan_allocated_memory((p), (len)); \
|
||||
_Pragma("clang diagnostic pop") \
|
||||
} while(0)
|
||||
# else
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len))
|
||||
# endif
|
||||
# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len))
|
||||
# define SECP256K1_CHECKMEM_MSAN_DEFINE(p, len) __msan_unpoison((p), (len))
|
||||
# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len))
|
||||
|
|
@ -68,10 +78,15 @@
|
|||
# if defined(__clang__) && defined(__APPLE__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 15)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wtrailing-whitespace"
|
||||
# endif
|
||||
# include <valgrind/memcheck.h>
|
||||
# if defined(__clang__) && defined(__APPLE__)
|
||||
# pragma clang diagnostic pop
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 15)
|
||||
# pragma GCC diagnostic pop
|
||||
# endif
|
||||
# define SECP256K1_CHECKMEM_ENABLED 1
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len))
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
***********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../include/secp256k1.h"
|
||||
|
|
@ -47,10 +48,6 @@
|
|||
#include "../include/secp256k1_ecdsa_adaptor.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
#include "../include/secp256k1_musig.h"
|
||||
#endif
|
||||
|
||||
static void run_tests(secp256k1_context *ctx, unsigned char *key);
|
||||
|
||||
int main(void) {
|
||||
|
|
@ -60,8 +57,8 @@ int main(void) {
|
|||
|
||||
if (!SECP256K1_CHECKMEM_RUNNING()) {
|
||||
fprintf(stderr, "This test can only usefully be run inside valgrind because it was not compiled under msan.\n");
|
||||
fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n");
|
||||
return 1;
|
||||
fprintf(stderr, "Usage: valgrind ./ctime_tests (or with Autotools: libtool --mode=execute valgrind ./ctime_tests)\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY);
|
||||
/** In theory, testing with a single secret input should be sufficient:
|
||||
|
|
@ -81,7 +78,7 @@ int main(void) {
|
|||
CHECK(ret);
|
||||
|
||||
secp256k1_context_destroy(ctx);
|
||||
return 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
||||
|
|
@ -211,7 +208,12 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||
secp256k1_musig_keyagg_cache cache;
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_partial_sig partial_sig;
|
||||
const secp256k1_musig_partial_sig *partial_sig_ptr[1];
|
||||
unsigned char extra_input[32];
|
||||
unsigned char sec_adaptor[32];
|
||||
secp256k1_pubkey adaptor;
|
||||
unsigned char pre_sig[64];
|
||||
int nonce_parity;
|
||||
|
||||
pk_ptr[0] = &pk;
|
||||
pubnonce_ptr[0] = &pubnonce;
|
||||
|
|
@ -220,14 +222,19 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||
session_secrand[0] = session_secrand[0] + 1;
|
||||
memcpy(extra_input, key, sizeof(extra_input));
|
||||
extra_input[0] = extra_input[0] + 2;
|
||||
memcpy(sec_adaptor, key, sizeof(sec_adaptor));
|
||||
sec_adaptor[0] = extra_input[0] + 3;
|
||||
partial_sig_ptr[0] = &partial_sig;
|
||||
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, key));
|
||||
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair));
|
||||
CHECK(secp256k1_musig_pubkey_agg(ctx, &agg_pk, &cache, pk_ptr, 1));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor));
|
||||
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
SECP256K1_CHECKMEM_UNDEFINE(session_secrand, sizeof(session_secrand));
|
||||
SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input));
|
||||
SECP256K1_CHECKMEM_UNDEFINE(sec_adaptor, sizeof(sec_adaptor));
|
||||
ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_secrand, key, &pk, msg, &cache, extra_input);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
|
@ -238,7 +245,7 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1));
|
||||
/* Make sure that previous tests don't undefine msg. It's not used as a secret here. */
|
||||
SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg));
|
||||
CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache) == 1);
|
||||
CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache, &adaptor) == 1);
|
||||
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
|
|
@ -246,6 +253,18 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||
ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
SECP256K1_CHECKMEM_DEFINE(&partial_sig, sizeof(partial_sig));
|
||||
CHECK(secp256k1_musig_partial_sig_agg(ctx, pre_sig, &session, partial_sig_ptr, 1));
|
||||
SECP256K1_CHECKMEM_DEFINE(pre_sig, sizeof(pre_sig));
|
||||
|
||||
CHECK(secp256k1_musig_nonce_parity(ctx, &nonce_parity, &session));
|
||||
ret = secp256k1_musig_adapt(ctx, sig, pre_sig, sec_adaptor, nonce_parity);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
ret = secp256k1_musig_extract_adaptor(ctx, sec_adaptor, sig, pre_sig, nonce_parity);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -337,72 +356,4 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||
CHECK(ret == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_MUSIG
|
||||
{
|
||||
secp256k1_pubkey pk;
|
||||
const secp256k1_pubkey *pk_ptr[1];
|
||||
secp256k1_xonly_pubkey agg_pk;
|
||||
unsigned char session_id[32];
|
||||
secp256k1_musig_secnonce secnonce;
|
||||
secp256k1_musig_pubnonce pubnonce;
|
||||
const secp256k1_musig_pubnonce *pubnonce_ptr[1];
|
||||
secp256k1_musig_aggnonce aggnonce;
|
||||
secp256k1_musig_keyagg_cache cache;
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_partial_sig partial_sig;
|
||||
const secp256k1_musig_partial_sig *partial_sig_ptr[1];
|
||||
unsigned char extra_input[32];
|
||||
unsigned char sec_adaptor[32];
|
||||
secp256k1_pubkey adaptor;
|
||||
unsigned char pre_sig[64];
|
||||
int nonce_parity;
|
||||
|
||||
pk_ptr[0] = &pk;
|
||||
pubnonce_ptr[0] = &pubnonce;
|
||||
SECP256K1_CHECKMEM_DEFINE(key, 32);
|
||||
memcpy(session_id, key, sizeof(session_id));
|
||||
session_id[0] = session_id[0] + 1;
|
||||
memcpy(extra_input, key, sizeof(extra_input));
|
||||
extra_input[0] = extra_input[0] + 2;
|
||||
memcpy(sec_adaptor, key, sizeof(sec_adaptor));
|
||||
sec_adaptor[0] = extra_input[0] + 3;
|
||||
partial_sig_ptr[0] = &partial_sig;
|
||||
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, key));
|
||||
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair));
|
||||
CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pk_ptr, 1));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor));
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
SECP256K1_CHECKMEM_UNDEFINE(session_id, sizeof(session_id));
|
||||
SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input));
|
||||
SECP256K1_CHECKMEM_UNDEFINE(sec_adaptor, sizeof(sec_adaptor));
|
||||
ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id, key, &pk, msg, &cache, extra_input);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1));
|
||||
/* Make sure that previous tests don't undefine msg. It's not used as a secret here. */
|
||||
SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg));
|
||||
CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache, &adaptor) == 1);
|
||||
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
SECP256K1_CHECKMEM_DEFINE(&partial_sig, sizeof(partial_sig));
|
||||
CHECK(secp256k1_musig_partial_sig_agg(ctx, pre_sig, &session, partial_sig_ptr, 1));
|
||||
SECP256K1_CHECKMEM_DEFINE(pre_sig, sizeof(pre_sig));
|
||||
|
||||
CHECK(secp256k1_musig_nonce_parity(ctx, &nonce_parity, &session));
|
||||
ret = secp256k1_musig_adapt(ctx, sig, pre_sig, sec_adaptor, nonce_parity);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
ret = secp256k1_musig_extract_adaptor(ctx, sec_adaptor, sig, pre_sig, nonce_parity);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ static int secp256k1_ec_pubkey_tweak_add_helper(const secp256k1_ecmult_context*
|
|||
* pubp->infinity before calling this function. */
|
||||
static int secp256k1_ec_commit_pubkey_serialize_const(secp256k1_ge *pubp, unsigned char *buf33);
|
||||
/** Compute an ec commitment tweak as hash(pubkey, data). */
|
||||
static int secp256k1_ec_commit_tweak(unsigned char *tweak32, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
|
||||
static int secp256k1_ec_commit_tweak(const secp256k1_hash_ctx *hash_ctx, unsigned char *tweak32, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
|
||||
/** Compute an ec commitment as pubkey + hash(pubkey, data)*G. */
|
||||
static int secp256k1_ec_commit(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
|
||||
/** Compute a secret key commitment as seckey + hash(pubkey, data). */
|
||||
|
|
|
|||
|
|
@ -25,42 +25,42 @@ static int secp256k1_ec_commit_pubkey_serialize_const(secp256k1_ge *pubp, unsign
|
|||
}
|
||||
|
||||
/* Compute an ec commitment tweak as hash(pubp, data). */
|
||||
static int secp256k1_ec_commit_tweak(unsigned char *tweak32, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size)
|
||||
static int secp256k1_ec_commit_tweak(const secp256k1_hash_ctx *hash_ctx, unsigned char *tweak32, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size)
|
||||
{
|
||||
unsigned char rbuf[33];
|
||||
|
||||
if (!secp256k1_ec_commit_pubkey_serialize_const(pubp, rbuf)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(sha, rbuf, sizeof(rbuf));
|
||||
secp256k1_sha256_write(sha, data, data_size);
|
||||
secp256k1_sha256_finalize(sha, tweak32);
|
||||
secp256k1_sha256_write(hash_ctx, sha, rbuf, sizeof(rbuf));
|
||||
secp256k1_sha256_write(hash_ctx, sha, data, data_size);
|
||||
secp256k1_sha256_finalize(hash_ctx, sha, tweak32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute an ec commitment as pubp + hash(pubp, data)*G. */
|
||||
static int secp256k1_ec_commit(secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
|
||||
static int secp256k1_ec_commit(const secp256k1_hash_ctx *hash_ctx, secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
|
||||
unsigned char tweak[32];
|
||||
|
||||
*commitp = *pubp;
|
||||
return secp256k1_ec_commit_tweak(tweak, commitp, sha, data, data_size)
|
||||
return secp256k1_ec_commit_tweak(hash_ctx, tweak, commitp, sha, data, data_size)
|
||||
&& secp256k1_ec_pubkey_tweak_add_helper(commitp, tweak);
|
||||
}
|
||||
|
||||
/* Compute the seckey of an ec commitment from the original secret key of the pubkey as seckey +
|
||||
* hash(pubp, data). */
|
||||
static int secp256k1_ec_commit_seckey(secp256k1_scalar* seckey, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
|
||||
static int secp256k1_ec_commit_seckey(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar* seckey, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
|
||||
unsigned char tweak[32];
|
||||
return secp256k1_ec_commit_tweak(tweak, pubp, sha, data, data_size)
|
||||
return secp256k1_ec_commit_tweak(hash_ctx, tweak, pubp, sha, data, data_size)
|
||||
&& secp256k1_ec_seckey_tweak_add_helper(seckey, tweak);
|
||||
}
|
||||
|
||||
/* Verify an ec commitment as pubp + hash(pubp, data)*G ?= commitment. */
|
||||
static int secp256k1_ec_commit_verify(const secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
|
||||
static int secp256k1_ec_commit_verify(const secp256k1_hash_ctx *hash_ctx, const secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
|
||||
secp256k1_gej pj;
|
||||
secp256k1_ge p;
|
||||
|
||||
if (!secp256k1_ec_commit(&p, pubp, sha, data, data_size)) {
|
||||
if (!secp256k1_ec_commit(hash_ctx, &p, pubp, sha, data, data_size)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
|
|||
unsigned char c[32];
|
||||
secp256k1_scalar sn, u1, u2;
|
||||
#if !defined(EXHAUSTIVE_TEST_ORDER)
|
||||
int range;
|
||||
secp256k1_fe xr;
|
||||
#endif
|
||||
secp256k1_gej pubkeyj;
|
||||
|
|
@ -226,9 +227,16 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
|
|||
return secp256k1_scalar_eq(sigr, &computed_r);
|
||||
}
|
||||
#else
|
||||
|
||||
/* Interpret sigr as a field element xr */
|
||||
secp256k1_scalar_get_b32(c, sigr);
|
||||
/* we can ignore the fe_set_b32_limit return value, because we know the input is in range */
|
||||
(void)secp256k1_fe_set_b32_limit(&xr, c);
|
||||
range = secp256k1_fe_set_b32_limit(&xr, c);
|
||||
#ifdef VERIFY
|
||||
/* We know that c is in range; it comes from a scalar. */
|
||||
VERIFY_CHECK(range);
|
||||
#else
|
||||
(void)range;
|
||||
#endif
|
||||
|
||||
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
|
||||
* in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),
|
||||
|
|
|
|||
|
|
@ -15,7 +15,10 @@
|
|||
#include "ecmult_gen.h"
|
||||
|
||||
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size);
|
||||
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed);
|
||||
/** Serialize a group element (that is not allowed to be infinity) to a compressed public key (33 bytes). */
|
||||
static void secp256k1_eckey_pubkey_serialize33(secp256k1_ge *elem, unsigned char *pub33);
|
||||
/** Serialize a group element (that is not allowed to be infinity) to an uncompressed public key (65 bytes). */
|
||||
static void secp256k1_eckey_pubkey_serialize65(secp256k1_ge *elem, unsigned char *pub65);
|
||||
|
||||
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak);
|
||||
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "eckey.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "scalar.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
|
|
@ -34,22 +35,23 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char
|
|||
}
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) {
|
||||
if (secp256k1_ge_is_infinity(elem)) {
|
||||
return 0;
|
||||
}
|
||||
static void secp256k1_eckey_pubkey_serialize33(secp256k1_ge *elem, unsigned char *pub33) {
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(elem));
|
||||
|
||||
secp256k1_fe_normalize_var(&elem->x);
|
||||
secp256k1_fe_normalize_var(&elem->y);
|
||||
secp256k1_fe_get_b32(&pub[1], &elem->x);
|
||||
if (compressed) {
|
||||
*size = 33;
|
||||
pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
|
||||
} else {
|
||||
*size = 65;
|
||||
pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED;
|
||||
secp256k1_fe_get_b32(&pub[33], &elem->y);
|
||||
}
|
||||
return 1;
|
||||
pub33[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
|
||||
secp256k1_fe_get_b32(&pub33[1], &elem->x);
|
||||
}
|
||||
|
||||
static void secp256k1_eckey_pubkey_serialize65(secp256k1_ge *elem, unsigned char *pub65) {
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(elem));
|
||||
|
||||
secp256k1_fe_normalize_var(&elem->x);
|
||||
secp256k1_fe_normalize_var(&elem->y);
|
||||
pub65[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED;
|
||||
secp256k1_fe_get_b32(&pub65[1], &elem->x);
|
||||
secp256k1_fe_get_b32(&pub65[33], &elem->y);
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
|
||||
|
|
@ -84,7 +86,7 @@ static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_s
|
|||
}
|
||||
|
||||
secp256k1_gej_set_ge(&pt, key);
|
||||
secp256k1_ecmult(&pt, &pt, tweak, &secp256k1_scalar_zero);
|
||||
secp256k1_ecmult(&pt, &pt, tweak, NULL);
|
||||
secp256k1_ge_set_gej(key, &pt);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,9 +38,12 @@
|
|||
#endif
|
||||
|
||||
/** The number of entries a table with precomputed multiples needs to have. */
|
||||
#define ECMULT_TABLE_SIZE(w) (1L << ((w)-2))
|
||||
#define ECMULT_TABLE_SIZE(w) ((size_t)1 << ((w)-2))
|
||||
|
||||
/** Double multiply: R = na*A + ng*G */
|
||||
/** Double multiply: R = na*A + ng*G
|
||||
*
|
||||
* Passing NULL as ng is equivalent to the zero scalar but a tiny bit faster.
|
||||
*/
|
||||
static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
|
||||
|
||||
typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
static void secp256k1_ecmult_compute_table(secp256k1_ge_storage* table, int window_g, const secp256k1_gej* gen) {
|
||||
secp256k1_gej gj;
|
||||
secp256k1_ge ge, dgen;
|
||||
int j;
|
||||
size_t j;
|
||||
|
||||
gj = *gen;
|
||||
secp256k1_ge_set_gej_var(&ge, &gj);
|
||||
|
|
|
|||
|
|
@ -87,17 +87,15 @@ static void secp256k1_ecmult_const_odd_multiples_table_globalz(secp256k1_ge *pre
|
|||
secp256k1_fe neg_y; \
|
||||
VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \
|
||||
VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \
|
||||
/* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one
|
||||
/* Unconditionally set r->x = (pre)[m].x and r->y = (pre)[m].y because it's either the correct one
|
||||
* or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \
|
||||
(r)->x = (pre)[m].x; \
|
||||
(r)->y = (pre)[m].y; \
|
||||
secp256k1_ge_set_xy((r), &(pre)[m].x, &(pre)[m].y); \
|
||||
for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \
|
||||
/* This loop is used to avoid secret data in array indices. See
|
||||
* the comment in ecmult_gen_impl.h for rationale. */ \
|
||||
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \
|
||||
secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \
|
||||
} \
|
||||
(r)->infinity = 0; \
|
||||
secp256k1_fe_negate(&neg_y, &(r)->y, 1); \
|
||||
secp256k1_fe_cmov(&(r)->y, &neg_y, negative); \
|
||||
} while(0)
|
||||
|
|
@ -214,8 +212,8 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
|||
#ifdef VERIFY
|
||||
/* Verify that v1 and v2 are in range [0, 2^129-1]. */
|
||||
for (i = 129; i < 256; ++i) {
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits(&v1, i, 1) == 0);
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits(&v2, i, 1) == 0);
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v1, i, 1) == 0);
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&v2, i, 1) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -373,11 +371,16 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n,
|
|||
}
|
||||
}
|
||||
|
||||
/* Compute base point P = (n*g, g^2), the effective affine version of (n*g, g^2, v), which has
|
||||
* corresponding affine X coordinate n/d. */
|
||||
secp256k1_fe_mul(&p.x, &g, n);
|
||||
secp256k1_fe_sqr(&p.y, &g);
|
||||
p.infinity = 0;
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&g, 2);
|
||||
|
||||
/* Compute base point P = (n*g, g^2), the effective affine version of
|
||||
* (n*g, g^2, v), which has corresponding affine X coordinate n/d. */
|
||||
{
|
||||
secp256k1_fe x, y;
|
||||
secp256k1_fe_mul(&x, &g, n);
|
||||
secp256k1_fe_sqr(&y, &g);
|
||||
secp256k1_ge_set_xy(&p, &x, &y);
|
||||
}
|
||||
|
||||
/* Perform x-only EC multiplication of P with q. */
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(q));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Copyright (c) Pieter Wuille, Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
|
@ -7,42 +7,138 @@
|
|||
#ifndef SECP256K1_ECMULT_GEN_H
|
||||
#define SECP256K1_ECMULT_GEN_H
|
||||
|
||||
#include "hash.h"
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
#ifndef ECMULT_GEN_PREC_BITS
|
||||
# define ECMULT_GEN_PREC_BITS 4
|
||||
# ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_MSG("ECMULT_GEN_PREC_BITS undefined, assuming default value")
|
||||
|
||||
/* Configuration parameters for the signed-digit multi-comb algorithm:
|
||||
*
|
||||
* - COMB_BLOCKS is the number of blocks the input is split into. Each
|
||||
* has a corresponding table.
|
||||
* - COMB_TEETH is the number of bits simultaneously covered by one table.
|
||||
* - COMB_RANGE is the number of bits in supported scalars. For production
|
||||
* purposes, only 256 is reasonable, but smaller numbers are supported for
|
||||
* exhaustive test mode.
|
||||
*
|
||||
* The comb's spacing (COMB_SPACING), or the distance between the teeth,
|
||||
* is defined as ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)). Each block covers
|
||||
* COMB_SPACING * COMB_TEETH consecutive bits in the input.
|
||||
*
|
||||
* The size of the precomputed table is COMB_BLOCKS * (1 << (COMB_TEETH - 1))
|
||||
* secp256k1_ge_storages.
|
||||
*
|
||||
* The number of point additions equals COMB_BLOCKS * COMB_SPACING. Each point
|
||||
* addition involves a cmov from (1 << (COMB_TEETH - 1)) table entries and a
|
||||
* conditional negation.
|
||||
*
|
||||
* The number of point doublings is COMB_SPACING - 1. */
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
/* We need to control these values for exhaustive tests because
|
||||
* the table cannot have infinities in them (secp256k1_ge_storage
|
||||
* doesn't support infinities) */
|
||||
# undef COMB_BLOCKS
|
||||
# undef COMB_TEETH
|
||||
# if EXHAUSTIVE_TEST_ORDER == 7
|
||||
# define COMB_RANGE 3
|
||||
# define COMB_BLOCKS 1
|
||||
# define COMB_TEETH 2
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 13
|
||||
# define COMB_RANGE 4
|
||||
# define COMB_BLOCKS 1
|
||||
# define COMB_TEETH 2
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 199
|
||||
# define COMB_RANGE 8
|
||||
# define COMB_BLOCKS 2
|
||||
# define COMB_TEETH 3
|
||||
# else
|
||||
# error "Unknown exhaustive test order"
|
||||
# endif
|
||||
# if (COMB_RANGE >= 32) || ((EXHAUSTIVE_TEST_ORDER >> (COMB_RANGE - 1)) != 1)
|
||||
# error "COMB_RANGE != ceil(log2(EXHAUSTIVE_TEST_ORDER+1))"
|
||||
# endif
|
||||
#else /* !defined(EXHAUSTIVE_TEST_ORDER) */
|
||||
# define COMB_RANGE 256
|
||||
#endif /* defined(EXHAUSTIVE_TEST_ORDER) */
|
||||
|
||||
/* Use (11, 6) as default configuration, which results in a 22 kB table. */
|
||||
#ifndef COMB_BLOCKS
|
||||
# define COMB_BLOCKS 11
|
||||
# ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_MSG("COMB_BLOCKS undefined, assuming default value")
|
||||
# endif
|
||||
#endif
|
||||
#ifndef COMB_TEETH
|
||||
# define COMB_TEETH 6
|
||||
# ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_MSG("COMB_TEETH undefined, assuming default value")
|
||||
# endif
|
||||
#endif
|
||||
/* Use ceil(COMB_RANGE / (COMB_BLOCKS * COMB_TEETH)) as COMB_SPACING. */
|
||||
#define COMB_SPACING CEIL_DIV(COMB_RANGE, COMB_BLOCKS * COMB_TEETH)
|
||||
|
||||
/* Range checks on the parameters. */
|
||||
|
||||
/* The remaining COMB_* parameters are derived values, don't modify these. */
|
||||
/* - The number of bits covered by all the blocks; must be at least COMB_RANGE. */
|
||||
#define COMB_BITS (COMB_BLOCKS * COMB_TEETH * COMB_SPACING)
|
||||
/* - The number of entries per table. */
|
||||
#define COMB_POINTS (1 << (COMB_TEETH - 1))
|
||||
|
||||
/* Sanity checks. */
|
||||
#if !(1 <= COMB_BLOCKS && COMB_BLOCKS <= 256)
|
||||
# error "COMB_BLOCKS must be in the range [1, 256]"
|
||||
#endif
|
||||
#if !(1 <= COMB_TEETH && COMB_TEETH <= 8)
|
||||
# error "COMB_TEETH must be in the range [1, 8]"
|
||||
#endif
|
||||
#if COMB_BITS < COMB_RANGE
|
||||
# error "COMB_BLOCKS * COMB_TEETH * COMB_SPACING is too low"
|
||||
#endif
|
||||
|
||||
/* These last 2 checks are not strictly required, but prevent gratuitously inefficient
|
||||
* configurations. Note that they compare with 256 rather than COMB_RANGE, so they do
|
||||
* permit somewhat excessive values for the exhaustive test case, where testing with
|
||||
* suboptimal parameters may be desirable. */
|
||||
#if (COMB_BLOCKS - 1) * COMB_TEETH * COMB_SPACING >= 256
|
||||
# error "COMB_BLOCKS can be reduced"
|
||||
#endif
|
||||
#if COMB_BLOCKS * (COMB_TEETH - 1) * COMB_SPACING >= 256
|
||||
# error "COMB_TEETH can be reduced"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_CONFIG
|
||||
# pragma message DEBUG_CONFIG_DEF(ECMULT_GEN_PREC_BITS)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_RANGE)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_BLOCKS)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_TEETH)
|
||||
# pragma message DEBUG_CONFIG_DEF(COMB_SPACING)
|
||||
#endif
|
||||
|
||||
#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8
|
||||
# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8."
|
||||
#endif
|
||||
|
||||
#define ECMULT_GEN_PREC_G(bits) (1 << bits)
|
||||
#define ECMULT_GEN_PREC_N(bits) (256 / bits)
|
||||
|
||||
typedef struct {
|
||||
/* Whether the context has been built. */
|
||||
int built;
|
||||
|
||||
/* Blinding values used when computing (n-b)G + bG. */
|
||||
secp256k1_scalar blind; /* -b */
|
||||
secp256k1_gej initial; /* bG */
|
||||
/* Values chosen such that
|
||||
*
|
||||
* n*G == comb(n + scalar_offset, G/2) + ge_offset.
|
||||
*
|
||||
* This expression lets us use scalar blinding and optimize the comb precomputation. See
|
||||
* ecmult_gen_impl.h for more details. */
|
||||
secp256k1_scalar scalar_offset;
|
||||
secp256k1_ge ge_offset;
|
||||
|
||||
/* Factor used for projective blinding. This value is used to rescale the Z
|
||||
* coordinate of the first table lookup. */
|
||||
secp256k1_fe proj_blind;
|
||||
} secp256k1_ecmult_gen_context;
|
||||
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx);
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_hash_ctx *hash_ctx);
|
||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);
|
||||
|
||||
/** Multiply with the generator: R = a*G */
|
||||
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a);
|
||||
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32);
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32);
|
||||
|
||||
#endif /* SECP256K1_ECMULT_GEN_H */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Copyright (c) Pieter Wuille, Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits);
|
||||
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing);
|
||||
|
||||
#endif /* SECP256K1_ECMULT_GEN_COMPUTE_TABLE_H */
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
|
@ -10,74 +10,98 @@
|
|||
#include "ecmult_gen_compute_table.h"
|
||||
#include "group_impl.h"
|
||||
#include "field_impl.h"
|
||||
#include "scalar_impl.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "util.h"
|
||||
|
||||
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int bits) {
|
||||
int g = ECMULT_GEN_PREC_G(bits);
|
||||
int n = ECMULT_GEN_PREC_N(bits);
|
||||
static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, const secp256k1_ge* gen, int blocks, int teeth, int spacing) {
|
||||
size_t points = ((size_t)1) << (teeth - 1);
|
||||
size_t points_total = points * blocks;
|
||||
secp256k1_ge* prec = checked_malloc(&default_error_callback, points_total * sizeof(*prec));
|
||||
secp256k1_gej* ds = checked_malloc(&default_error_callback, teeth * sizeof(*ds));
|
||||
secp256k1_gej* vs = checked_malloc(&default_error_callback, points_total * sizeof(*vs));
|
||||
secp256k1_gej u;
|
||||
size_t vs_pos = 0;
|
||||
secp256k1_scalar half;
|
||||
int block, i;
|
||||
|
||||
secp256k1_ge* prec = checked_malloc(&default_error_callback, n * g * sizeof(*prec));
|
||||
secp256k1_gej gj;
|
||||
secp256k1_gej nums_gej;
|
||||
int i, j;
|
||||
VERIFY_CHECK(points_total > 0);
|
||||
|
||||
VERIFY_CHECK(g > 0);
|
||||
VERIFY_CHECK(n > 0);
|
||||
|
||||
/* get the generator */
|
||||
secp256k1_gej_set_ge(&gj, gen);
|
||||
|
||||
/* Construct a group element with no known corresponding scalar (nothing up my sleeve). */
|
||||
{
|
||||
static const unsigned char nums_b32[33] = "The scalar for this x is unknown";
|
||||
secp256k1_fe nums_x;
|
||||
secp256k1_ge nums_ge;
|
||||
int r;
|
||||
r = secp256k1_fe_set_b32_limit(&nums_x, nums_b32);
|
||||
(void)r;
|
||||
VERIFY_CHECK(r);
|
||||
r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);
|
||||
(void)r;
|
||||
VERIFY_CHECK(r);
|
||||
secp256k1_gej_set_ge(&nums_gej, &nums_ge);
|
||||
/* Add G to make the bits in x uniformly distributed. */
|
||||
secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, gen, NULL);
|
||||
}
|
||||
|
||||
/* compute prec. */
|
||||
{
|
||||
secp256k1_gej gbase;
|
||||
secp256k1_gej numsbase;
|
||||
secp256k1_gej* precj = checked_malloc(&default_error_callback, n * g * sizeof(*precj)); /* Jacobian versions of prec. */
|
||||
gbase = gj; /* PREC_G^j * G */
|
||||
numsbase = nums_gej; /* 2^j * nums. */
|
||||
for (j = 0; j < n; j++) {
|
||||
/* Set precj[j*PREC_G .. j*PREC_G+(PREC_G-1)] to (numsbase, numsbase + gbase, ..., numsbase + (PREC_G-1)*gbase). */
|
||||
precj[j*g] = numsbase;
|
||||
for (i = 1; i < g; i++) {
|
||||
secp256k1_gej_add_var(&precj[j*g + i], &precj[j*g + i - 1], &gbase, NULL);
|
||||
}
|
||||
/* Multiply gbase by PREC_G. */
|
||||
for (i = 0; i < bits; i++) {
|
||||
secp256k1_gej_double_var(&gbase, &gbase, NULL);
|
||||
}
|
||||
/* Multiply numbase by 2. */
|
||||
secp256k1_gej_double_var(&numsbase, &numsbase, NULL);
|
||||
if (j == n - 2) {
|
||||
/* In the last iteration, numsbase is (1 - 2^j) * nums instead. */
|
||||
secp256k1_gej_neg(&numsbase, &numsbase);
|
||||
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
|
||||
}
|
||||
}
|
||||
secp256k1_ge_set_all_gej_var(prec, precj, n * g);
|
||||
free(precj);
|
||||
}
|
||||
for (j = 0; j < n; j++) {
|
||||
for (i = 0; i < g; i++) {
|
||||
secp256k1_ge_to_storage(&table[j*g + i], &prec[j*g + i]);
|
||||
/* u is the running power of two times gen we're working with, initially gen/2. */
|
||||
secp256k1_scalar_half(&half, &secp256k1_scalar_one);
|
||||
secp256k1_gej_set_infinity(&u);
|
||||
for (i = 255; i >= 0; --i) {
|
||||
/* Use a very simple multiplication ladder to avoid dependency on ecmult. */
|
||||
secp256k1_gej_double_var(&u, &u, NULL);
|
||||
if (secp256k1_scalar_get_bits_limb32(&half, i, 1)) {
|
||||
secp256k1_gej_add_ge_var(&u, &u, gen, NULL);
|
||||
}
|
||||
}
|
||||
#ifdef VERIFY
|
||||
{
|
||||
/* Verify that u*2 = gen. */
|
||||
secp256k1_gej double_u;
|
||||
secp256k1_gej_double_var(&double_u, &u, NULL);
|
||||
VERIFY_CHECK(secp256k1_gej_eq_ge_var(&double_u, gen));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (block = 0; block < blocks; ++block) {
|
||||
int tooth;
|
||||
/* Here u = 2^(block*teeth*spacing) * gen/2. */
|
||||
secp256k1_gej sum;
|
||||
secp256k1_gej_set_infinity(&sum);
|
||||
for (tooth = 0; tooth < teeth; ++tooth) {
|
||||
/* Here u = 2^((block*teeth + tooth)*spacing) * gen/2. */
|
||||
/* Make sum = sum(2^((block*teeth + t)*spacing), t=0..tooth) * gen/2. */
|
||||
secp256k1_gej_add_var(&sum, &sum, &u, NULL);
|
||||
/* Make u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */
|
||||
secp256k1_gej_double_var(&u, &u, NULL);
|
||||
/* Make ds[tooth] = u = 2^((block*teeth + tooth)*spacing + 1) * gen/2. */
|
||||
ds[tooth] = u;
|
||||
/* Make u = 2^((block*teeth + tooth + 1)*spacing) * gen/2, unless at the end. */
|
||||
if (block + tooth != blocks + teeth - 2) {
|
||||
int bit_off;
|
||||
for (bit_off = 1; bit_off < spacing; ++bit_off) {
|
||||
secp256k1_gej_double_var(&u, &u, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Now u = 2^((block*teeth + teeth)*spacing) * gen/2
|
||||
* = 2^((block+1)*teeth*spacing) * gen/2 */
|
||||
|
||||
/* Next, compute the table entries for block number block in Jacobian coordinates.
|
||||
* The entries will occupy vs[block*points + i] for i=0..points-1.
|
||||
* We start by computing the first (i=0) value corresponding to all summed
|
||||
* powers of two times G being negative. */
|
||||
secp256k1_gej_neg(&vs[vs_pos++], &sum);
|
||||
/* And then teeth-1 times "double" the range of i values for which the table
|
||||
* is computed: in each iteration, double the table by taking an existing
|
||||
* table entry and adding ds[tooth]. */
|
||||
for (tooth = 0; tooth < teeth - 1; ++tooth) {
|
||||
size_t stride = ((size_t)1) << tooth;
|
||||
size_t index;
|
||||
for (index = 0; index < stride; ++index, ++vs_pos) {
|
||||
secp256k1_gej_add_var(&vs[vs_pos], &vs[vs_pos - stride], &ds[tooth], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY_CHECK(vs_pos == points_total);
|
||||
|
||||
/* Convert all points simultaneously from secp256k1_gej to secp256k1_ge. */
|
||||
secp256k1_ge_set_all_gej_var(prec, vs, points_total);
|
||||
/* Convert all points from secp256k1_ge to secp256k1_ge_storage output. */
|
||||
for (block = 0; block < blocks; ++block) {
|
||||
size_t index;
|
||||
for (index = 0; index < points; ++index) {
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(&prec[block * points + index]));
|
||||
secp256k1_ge_to_storage(&table[block * points + index], &prec[block * points + index]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free memory. */
|
||||
free(vs);
|
||||
free(ds);
|
||||
free(prec);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***********************************************************************
|
||||
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Copyright (c) Pieter Wuille, Gregory Maxwell, Peter Dettman *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
|
@ -14,8 +14,8 @@
|
|||
#include "hash_impl.h"
|
||||
#include "precomputed_ecmult_gen.h"
|
||||
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx) {
|
||||
secp256k1_ecmult_gen_blind(ctx, NULL);
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx) {
|
||||
secp256k1_ecmult_gen_blind(ctx, hash_ctx, NULL);
|
||||
ctx->built = 1;
|
||||
}
|
||||
|
||||
|
|
@ -25,41 +25,215 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont
|
|||
|
||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
|
||||
ctx->built = 0;
|
||||
secp256k1_scalar_clear(&ctx->blind);
|
||||
secp256k1_gej_clear(&ctx->initial);
|
||||
secp256k1_scalar_clear(&ctx->scalar_offset);
|
||||
secp256k1_ge_clear(&ctx->ge_offset);
|
||||
secp256k1_fe_clear(&ctx->proj_blind);
|
||||
}
|
||||
|
||||
/* For accelerating the computation of a*G:
|
||||
* To harden against timing attacks, use the following mechanism:
|
||||
* * Break up the multiplicand into groups of PREC_BITS bits, called n_0, n_1, n_2, ..., n_(PREC_N-1).
|
||||
* * Compute sum(n_i * (PREC_G)^i * G + U_i, i=0 ... PREC_N-1), where:
|
||||
* * U_i = U * 2^i, for i=0 ... PREC_N-2
|
||||
* * U_i = U * (1-2^(PREC_N-1)), for i=PREC_N-1
|
||||
* where U is a point with no known corresponding scalar. Note that sum(U_i, i=0 ... PREC_N-1) = 0.
|
||||
* For each i, and each of the PREC_G possible values of n_i, (n_i * (PREC_G)^i * G + U_i) is
|
||||
* precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0 ... PREC_N-1).
|
||||
* None of the resulting prec group elements have a known scalar, and neither do any of
|
||||
* the intermediate sums while computing a*G.
|
||||
* The prec values are stored in secp256k1_ecmult_gen_prec_table[i][n_i] = n_i * (PREC_G)^i * G + U_i.
|
||||
*/
|
||||
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) {
|
||||
int bits = ECMULT_GEN_PREC_BITS;
|
||||
int g = ECMULT_GEN_PREC_G(bits);
|
||||
int n = ECMULT_GEN_PREC_N(bits);
|
||||
/* Compute the scalar (2^COMB_BITS - 1) / 2, the difference between the gn argument to
|
||||
* secp256k1_ecmult_gen, and the scalar whose encoding the table lookup bits are drawn
|
||||
* from (before applying blinding). */
|
||||
static void secp256k1_ecmult_gen_scalar_diff(secp256k1_scalar* diff) {
|
||||
int i;
|
||||
|
||||
/* Compute scalar -1/2. */
|
||||
secp256k1_scalar neghalf;
|
||||
secp256k1_scalar_half(&neghalf, &secp256k1_scalar_one);
|
||||
secp256k1_scalar_negate(&neghalf, &neghalf);
|
||||
|
||||
/* Compute offset = 2^(COMB_BITS - 1). */
|
||||
*diff = secp256k1_scalar_one;
|
||||
for (i = 0; i < COMB_BITS - 1; ++i) {
|
||||
secp256k1_scalar_add(diff, diff, diff);
|
||||
}
|
||||
|
||||
/* The result is the sum 2^(COMB_BITS - 1) + (-1/2). */
|
||||
secp256k1_scalar_add(diff, diff, &neghalf);
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) {
|
||||
uint32_t comb_off;
|
||||
secp256k1_ge add;
|
||||
secp256k1_fe neg;
|
||||
secp256k1_ge_storage adds;
|
||||
secp256k1_scalar gnb;
|
||||
int i, j, n_i;
|
||||
|
||||
secp256k1_scalar d;
|
||||
/* Array of uint32_t values large enough to store COMB_BITS bits. Only the bottom
|
||||
* 8 are ever nonzero, but having the zero padding at the end if COMB_BITS>256
|
||||
* avoids the need to deal with out-of-bounds reads from a scalar. */
|
||||
uint32_t recoded[(COMB_BITS + 31) >> 5] = {0};
|
||||
int first = 1, i;
|
||||
|
||||
memset(&adds, 0, sizeof(adds));
|
||||
*r = ctx->initial;
|
||||
/* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */
|
||||
secp256k1_scalar_add(&gnb, gn, &ctx->blind);
|
||||
add.infinity = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
n_i = secp256k1_scalar_get_bits(&gnb, i * bits, bits);
|
||||
for (j = 0; j < g; j++) {
|
||||
|
||||
/* We want to compute R = gn*G.
|
||||
*
|
||||
* To blind the scalar used in the computation, we rewrite this to be
|
||||
* R = (gn - b)*G + b*G, with a blinding value b determined by the context.
|
||||
*
|
||||
* The multiplication (gn-b)*G will be performed using a signed-digit multi-comb (see Section
|
||||
* 3.3 of "Fast and compact elliptic-curve cryptography" by Mike Hamburg,
|
||||
* https://eprint.iacr.org/2012/309).
|
||||
*
|
||||
* Let comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1), where s[i] is the i'th bit of
|
||||
* the binary representation of scalar s. So the s[i] values determine whether -2^i*P (s[i]=0)
|
||||
* or +2^i*P (s[i]=1) are added together. COMB_BITS is at least 256, so all bits of s are
|
||||
* covered. By manipulating:
|
||||
*
|
||||
* comb(s, P) = sum((2*s[i]-1)*2^i*P for i=0..COMB_BITS-1)
|
||||
* <=> comb(s, P) = sum((2*s[i]-1)*2^i for i=0..COMB_BITS-1) * P
|
||||
* <=> comb(s, P) = (2*sum(s[i]*2^i for i=0..COMB_BITS-1) - sum(2^i for i=0..COMB_BITS-1)) * P
|
||||
* <=> comb(s, P) = (2*s - (2^COMB_BITS - 1)) * P
|
||||
*
|
||||
* If we wanted to compute (gn-b)*G as comb(s, G), it would need to hold that
|
||||
*
|
||||
* (gn - b) * G = (2*s - (2^COMB_BITS - 1)) * G
|
||||
* <=> s = (gn - b + (2^COMB_BITS - 1))/2 (mod order)
|
||||
*
|
||||
* We use an alternative here that avoids the modular division by two: instead we compute
|
||||
* (gn-b)*G as comb(d, G/2). For that to hold it must be the case that
|
||||
*
|
||||
* (gn - b) * G = (2*d - (2^COMB_BITS - 1)) * (G/2)
|
||||
* <=> d = gn - b + (2^COMB_BITS - 1)/2 (mod order)
|
||||
*
|
||||
* Adding precomputation, our final equations become:
|
||||
*
|
||||
* ctx->scalar_offset = (2^COMB_BITS - 1)/2 - b (mod order)
|
||||
* ctx->ge_offset = b*G
|
||||
* d = gn + ctx->scalar_offset (mod order)
|
||||
* R = comb(d, G/2) + ctx->ge_offset
|
||||
*
|
||||
* comb(d, G/2) function is then computed by summing + or - 2^(i-1)*G, for i=0..COMB_BITS-1,
|
||||
* depending on the value of the bits d[i] of the binary representation of scalar d.
|
||||
*/
|
||||
|
||||
/* Compute the scalar d = (gn + ctx->scalar_offset). */
|
||||
secp256k1_scalar_add(&d, &ctx->scalar_offset, gn);
|
||||
/* Convert to recoded array. */
|
||||
for (i = 0; i < 8 && i < ((COMB_BITS + 31) >> 5); ++i) {
|
||||
recoded[i] = secp256k1_scalar_get_bits_limb32(&d, 32 * i, 32);
|
||||
}
|
||||
secp256k1_scalar_clear(&d);
|
||||
|
||||
/* In secp256k1_ecmult_gen_prec_table we have precomputed sums of the
|
||||
* (2*d[i]-1) * 2^(i-1) * G points, for various combinations of i positions.
|
||||
* We rewrite our equation in terms of these table entries.
|
||||
*
|
||||
* Let mask(b) = sum(2^((b*COMB_TEETH + t)*COMB_SPACING) for t=0..COMB_TEETH-1),
|
||||
* with b ranging from 0 to COMB_BLOCKS-1. So for example with COMB_BLOCKS=11,
|
||||
* COMB_TEETH=6, COMB_SPACING=4, we would have:
|
||||
* mask(0) = 2^0 + 2^4 + 2^8 + 2^12 + 2^16 + 2^20,
|
||||
* mask(1) = 2^24 + 2^28 + 2^32 + 2^36 + 2^40 + 2^44,
|
||||
* mask(2) = 2^48 + 2^52 + 2^56 + 2^60 + 2^64 + 2^68,
|
||||
* ...
|
||||
* mask(10) = 2^240 + 2^244 + 2^248 + 2^252 + 2^256 + 2^260
|
||||
*
|
||||
* We will split up the bits d[i] using these masks. Specifically, each mask is
|
||||
* used COMB_SPACING times, with different shifts:
|
||||
*
|
||||
* d = (d & mask(0)<<0) + (d & mask(1)<<0) + ... + (d & mask(COMB_BLOCKS-1)<<0) +
|
||||
* (d & mask(0)<<1) + (d & mask(1)<<1) + ... + (d & mask(COMB_BLOCKS-1)<<1) +
|
||||
* ...
|
||||
* (d & mask(0)<<(COMB_SPACING-1)) + ...
|
||||
*
|
||||
* Now define table(b, m) = (m - mask(b)/2) * G, and we will precompute these values for
|
||||
* b=0..COMB_BLOCKS-1, and for all values m which (d & mask(b)) can take (so m can take on
|
||||
* 2^COMB_TEETH distinct values).
|
||||
*
|
||||
* If m=(d & mask(b)), then table(b, m) is the sum of 2^i * (2*d[i]-1) * G/2, with i
|
||||
* iterating over the set bits in mask(b). In our example, table(2, 2^48 + 2^56 + 2^68)
|
||||
* would equal (2^48 - 2^52 + 2^56 - 2^60 - 2^64 + 2^68) * G/2.
|
||||
*
|
||||
* With that, we can rewrite comb(d, G/2) as:
|
||||
*
|
||||
* 2^0 * (table(0, d>>0 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>0 & mask(COMP_BLOCKS-1)))
|
||||
* + 2^1 * (table(0, d>>1 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>1 & mask(COMP_BLOCKS-1)))
|
||||
* + 2^2 * (table(0, d>>2 & mask(0)) + ... + table(COMB_BLOCKS-1, d>>2 & mask(COMP_BLOCKS-1)))
|
||||
* + ...
|
||||
* + 2^(COMB_SPACING-1) * (table(0, d>>(COMB_SPACING-1) & mask(0)) + ...)
|
||||
*
|
||||
* Or more generically as
|
||||
*
|
||||
* sum(2^i * sum(table(b, d>>i & mask(b)), b=0..COMB_BLOCKS-1), i=0..COMB_SPACING-1)
|
||||
*
|
||||
* This is implemented using an outer loop that runs in reverse order over the lines of this
|
||||
* equation, which in each iteration runs an inner loop that adds the terms of that line and
|
||||
* then doubles the result before proceeding to the next line.
|
||||
*
|
||||
* In pseudocode:
|
||||
* c = infinity
|
||||
* for comb_off in range(COMB_SPACING - 1, -1, -1):
|
||||
* for block in range(COMB_BLOCKS):
|
||||
* c += table(block, (d >> comb_off) & mask(block))
|
||||
* if comb_off > 0:
|
||||
* c = 2*c
|
||||
* return c
|
||||
*
|
||||
* This computes c = comb(d, G/2), and thus finally R = c + ctx->ge_offset. Note that it would
|
||||
* be possible to apply an initial offset instead of a final offset (moving ge_offset to take
|
||||
* the place of infinity above), but the chosen approach allows using (in a future improvement)
|
||||
* an incomplete addition formula for most of the multiplication.
|
||||
*
|
||||
* The last question is how to implement the table(b, m) function. For any value of b,
|
||||
* m=(d & mask(b)) can only take on at most 2^COMB_TEETH possible values (the last one may have
|
||||
* fewer as there mask(b) may exceed the curve order). So we could create COMB_BLOCK tables
|
||||
* which contain a value for each such m value.
|
||||
*
|
||||
* Now note that if m=(d & mask(b)), then flipping the relevant bits of m results in negating
|
||||
* the result of table(b, m). This is because table(b,m XOR mask(b)) = table(b, mask(b) - m) =
|
||||
* (mask(b) - m - mask(b)/2)*G = (-m + mask(b)/2)*G = -(m - mask(b)/2)*G = -table(b, m).
|
||||
* Because of this it suffices to only store the first half of the m values for every b. If an
|
||||
* entry from the second half is needed, we look up its bit-flipped version instead, and negate
|
||||
* it.
|
||||
*
|
||||
* secp256k1_ecmult_gen_prec_table[b][index] stores the table(b, m) entries. Index
|
||||
* is the relevant mask(b) bits of m packed together without gaps. */
|
||||
|
||||
/* Outer loop: iterate over comb_off from COMB_SPACING - 1 down to 0. */
|
||||
comb_off = COMB_SPACING - 1;
|
||||
while (1) {
|
||||
uint32_t block;
|
||||
uint32_t bit_pos = comb_off;
|
||||
/* Inner loop: for each block, add table entries to the result. */
|
||||
for (block = 0; block < COMB_BLOCKS; ++block) {
|
||||
/* Gather the mask(block)-selected bits of d into bits. They're packed:
|
||||
* bits[tooth] = d[(block*COMB_TEETH + tooth)*COMB_SPACING + comb_off]. */
|
||||
uint32_t bits = 0, sign, abs, index, tooth;
|
||||
/* Instead of reading individual bits here to construct the bits variable,
|
||||
* build up the result by xoring rotated reads together. In every iteration,
|
||||
* one additional bit is made correct, starting at the bottom. The bits
|
||||
* above that contain junk. This reduces leakage by avoiding computations
|
||||
* on variables that can have only a low number of possible values (e.g.,
|
||||
* just two values when reading a single bit into a variable.) See:
|
||||
* https://www.usenix.org/system/files/conference/usenixsecurity18/sec18-alam.pdf
|
||||
*/
|
||||
for (tooth = 0; tooth < COMB_TEETH; ++tooth) {
|
||||
/* Construct bitdata s.t. the bottom bit is the bit we'd like to read.
|
||||
*
|
||||
* We could just set bitdata = recoded[bit_pos >> 5] >> (bit_pos & 0x1f)
|
||||
* but this would simply discard the bits that fall off at the bottom,
|
||||
* and thus, for example, bitdata could still have only two values if we
|
||||
* happen to shift by exactly 31 positions. We use a rotation instead,
|
||||
* which ensures that bitdata doesn't lose entropy. This relies on the
|
||||
* rotation being atomic, i.e., the compiler emitting an actual rot
|
||||
* instruction. */
|
||||
uint32_t bitdata = secp256k1_rotr32(recoded[bit_pos >> 5], bit_pos & 0x1f);
|
||||
|
||||
/* Clear the bit at position tooth, but sssh, don't tell clang. */
|
||||
uint32_t volatile vmask = ~(1 << tooth);
|
||||
bits &= vmask;
|
||||
|
||||
/* Write the bit into position tooth (and junk into higher bits). */
|
||||
bits ^= bitdata << tooth;
|
||||
bit_pos += COMB_SPACING;
|
||||
}
|
||||
|
||||
/* If the top bit of bits is 1, flip them all (corresponding to looking up
|
||||
* the negated table value), and remember to negate the result in sign. */
|
||||
sign = (bits >> (COMB_TEETH - 1)) & 1;
|
||||
abs = (bits ^ -sign) & (COMB_POINTS - 1);
|
||||
VERIFY_CHECK(sign == 0 || sign == 1);
|
||||
VERIFY_CHECK(abs < COMB_POINTS);
|
||||
|
||||
/** This uses a conditional move to avoid any secret data in array indexes.
|
||||
* _Any_ use of secret indexes has been demonstrated to result in timing
|
||||
* sidechannels, even when the cache-line access patterns are uniform.
|
||||
|
|
@ -68,63 +242,100 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
|
|||
* (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and
|
||||
* "Cache Attacks and Countermeasures: the Case of AES", RSA 2006,
|
||||
* by Dag Arne Osvik, Adi Shamir, and Eran Tromer
|
||||
* (https://www.tau.ac.il/~tromer/papers/cache.pdf)
|
||||
* (https://eprint.iacr.org/2005/271.pdf)
|
||||
*/
|
||||
secp256k1_ge_storage_cmov(&adds, &secp256k1_ecmult_gen_prec_table[i][j], j == n_i);
|
||||
for (index = 0; index < COMB_POINTS; ++index) {
|
||||
secp256k1_ge_storage_cmov(&adds, &secp256k1_ecmult_gen_prec_table[block][index], index == abs);
|
||||
}
|
||||
|
||||
/* Set add=adds or add=-adds, in constant time, based on sign. */
|
||||
secp256k1_ge_from_storage(&add, &adds);
|
||||
secp256k1_fe_negate(&neg, &add.y, 1);
|
||||
secp256k1_fe_cmov(&add.y, &neg, sign);
|
||||
|
||||
/* Add the looked up and conditionally negated value to r. */
|
||||
if (EXPECT(first, 0)) {
|
||||
/* If this is the first table lookup, we can skip addition. */
|
||||
secp256k1_gej_set_ge(r, &add);
|
||||
/* Give the entry a random Z coordinate to blind intermediary results. */
|
||||
secp256k1_gej_rescale(r, &ctx->proj_blind);
|
||||
first = 0;
|
||||
} else {
|
||||
secp256k1_gej_add_ge(r, r, &add);
|
||||
}
|
||||
}
|
||||
secp256k1_ge_from_storage(&add, &adds);
|
||||
secp256k1_gej_add_ge(r, r, &add);
|
||||
|
||||
/* Double the result, except in the last iteration. */
|
||||
if (comb_off-- == 0) break;
|
||||
secp256k1_gej_double(r, r);
|
||||
}
|
||||
n_i = 0;
|
||||
|
||||
/* Correct for the scalar_offset added at the start (ge_offset = b*G, while b was
|
||||
* subtracted from the input scalar gn). */
|
||||
secp256k1_gej_add_ge(r, r, &ctx->ge_offset);
|
||||
|
||||
/* Cleanup. */
|
||||
secp256k1_fe_clear(&neg);
|
||||
secp256k1_ge_clear(&add);
|
||||
secp256k1_scalar_clear(&gnb);
|
||||
secp256k1_memclear_explicit(&adds, sizeof(adds));
|
||||
secp256k1_memclear_explicit(&recoded, sizeof(recoded));
|
||||
}
|
||||
|
||||
/* Setup blinding values for secp256k1_ecmult_gen. */
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) {
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const secp256k1_hash_ctx *hash_ctx, const unsigned char *seed32) {
|
||||
secp256k1_scalar b;
|
||||
secp256k1_scalar diff;
|
||||
secp256k1_gej gb;
|
||||
secp256k1_fe s;
|
||||
secp256k1_fe f;
|
||||
unsigned char nonce32[32];
|
||||
secp256k1_rfc6979_hmac_sha256 rng;
|
||||
unsigned char keydata[64];
|
||||
|
||||
/* Compute the (2^COMB_BITS - 1)/2 term once. */
|
||||
secp256k1_ecmult_gen_scalar_diff(&diff);
|
||||
|
||||
if (seed32 == NULL) {
|
||||
/* When seed is NULL, reset the initial point and blinding value. */
|
||||
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
|
||||
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
|
||||
secp256k1_scalar_set_int(&ctx->blind, 1);
|
||||
/* When seed is NULL, reset the final point and blinding value. */
|
||||
secp256k1_ge_neg(&ctx->ge_offset, &secp256k1_ge_const_g);
|
||||
secp256k1_scalar_add(&ctx->scalar_offset, &secp256k1_scalar_one, &diff);
|
||||
ctx->proj_blind = secp256k1_fe_one;
|
||||
return;
|
||||
}
|
||||
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
|
||||
secp256k1_scalar_get_b32(keydata, &ctx->blind);
|
||||
secp256k1_scalar_get_b32(keydata, &ctx->scalar_offset);
|
||||
/** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,
|
||||
* and guards against weak or adversarial seeds. This is a simpler and safer interface than
|
||||
* asking the caller for blinding values directly and expecting them to retry on failure.
|
||||
*/
|
||||
VERIFY_CHECK(seed32 != NULL);
|
||||
memcpy(keydata + 32, seed32, 32);
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
|
||||
memset(keydata, 0, sizeof(keydata));
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
secp256k1_fe_set_b32_mod(&s, nonce32);
|
||||
secp256k1_fe_cmov(&s, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&s));
|
||||
/* Randomize the projection to defend against multiplier sidechannels.
|
||||
Do this before our own call to secp256k1_ecmult_gen below. */
|
||||
secp256k1_gej_rescale(&ctx->initial, &s);
|
||||
secp256k1_fe_clear(&s);
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, keydata, 64);
|
||||
secp256k1_memclear_explicit(keydata, sizeof(keydata));
|
||||
|
||||
/* Compute projective blinding factor (cannot be 0). */
|
||||
secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, nonce32, 32);
|
||||
secp256k1_fe_set_b32_mod(&f, nonce32);
|
||||
secp256k1_fe_cmov(&f, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&f));
|
||||
ctx->proj_blind = f;
|
||||
|
||||
/* For a random blinding value b, set scalar_offset=diff-b, ge_offset=bG */
|
||||
secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, nonce32, 32);
|
||||
secp256k1_scalar_set_b32(&b, nonce32, NULL);
|
||||
/* A blinding value of 0 works, but would undermine the projection hardening. */
|
||||
/* The blinding value cannot be zero, as that would mean ge_offset = infinity,
|
||||
* which secp256k1_gej_add_ge cannot handle. */
|
||||
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
|
||||
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||
memset(nonce32, 0, 32);
|
||||
/* The random projection in ctx->initial ensures that gb will have a random projection. */
|
||||
secp256k1_ecmult_gen(ctx, &gb, &b);
|
||||
secp256k1_scalar_negate(&b, &b);
|
||||
ctx->blind = b;
|
||||
ctx->initial = gb;
|
||||
secp256k1_scalar_add(&ctx->scalar_offset, &b, &diff);
|
||||
secp256k1_ge_set_gej(&ctx->ge_offset, &gb);
|
||||
|
||||
/* Clean up. */
|
||||
secp256k1_memclear_explicit(nonce32, sizeof(nonce32));
|
||||
secp256k1_scalar_clear(&b);
|
||||
secp256k1_gej_clear(&gb);
|
||||
secp256k1_fe_clear(&f);
|
||||
secp256k1_rfc6979_hmac_sha256_clear(&rng);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_ECMULT_GEN_IMPL_H */
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
#endif
|
||||
|
||||
#define WNAF_BITS 128
|
||||
#define WNAF_SIZE_BITS(bits, w) (((bits) + (w) - 1) / (w))
|
||||
#define WNAF_SIZE_BITS(bits, w) CEIL_DIV(bits, w)
|
||||
#define WNAF_SIZE(w) WNAF_SIZE_BITS(WNAF_BITS, w)
|
||||
|
||||
/* The number of objects allocated on the scratch space for ecmult_multi algorithms */
|
||||
|
|
@ -70,12 +70,12 @@
|
|||
* Lastly the zr[0] value, which isn't used above, is set so that:
|
||||
* - a.z = z(pre_a[0]) / zr[0]
|
||||
*/
|
||||
static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) {
|
||||
static void secp256k1_ecmult_odd_multiples_table(size_t n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) {
|
||||
secp256k1_gej d, ai;
|
||||
secp256k1_ge d_ge;
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
VERIFY_CHECK(!secp256k1_gej_is_infinity(a));
|
||||
|
||||
secp256k1_gej_double_var(&d, a, NULL);
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
|||
}
|
||||
|
||||
s = *a;
|
||||
if (secp256k1_scalar_get_bits(&s, 255, 1)) {
|
||||
if (secp256k1_scalar_get_bits_limb32(&s, 255, 1)) {
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
sign = -1;
|
||||
}
|
||||
|
|
@ -185,7 +185,7 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
|||
while (bit < len) {
|
||||
int now;
|
||||
int word;
|
||||
if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) {
|
||||
if (secp256k1_scalar_get_bits_limb32(&s, bit, 1) == (unsigned int)carry) {
|
||||
bit++;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -212,7 +212,7 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
|||
VERIFY_CHECK(carry == 0);
|
||||
|
||||
while (verify_bit < 256) {
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits(&s, verify_bit, 1) == 0);
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits_limb32(&s, verify_bit, 1) == 0);
|
||||
verify_bit++;
|
||||
}
|
||||
}
|
||||
|
|
@ -220,9 +220,24 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
|||
return last_set_bit + 1;
|
||||
}
|
||||
|
||||
/* Same as secp256k1_ecmult_wnaf, but stores to int8_t array. Requires w <= 8. */
|
||||
static int secp256k1_ecmult_wnaf_small(int8_t *wnaf, int len, const secp256k1_scalar *a, int w) {
|
||||
int wnaf_tmp[256];
|
||||
int ret, i;
|
||||
|
||||
VERIFY_CHECK(2 <= w && w <= 8);
|
||||
ret = secp256k1_ecmult_wnaf(wnaf_tmp, len, a, w);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
wnaf[i] = (int8_t)wnaf_tmp[i];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct secp256k1_strauss_point_state {
|
||||
int wnaf_na_1[129];
|
||||
int wnaf_na_lam[129];
|
||||
int8_t wnaf_na_1[129];
|
||||
int8_t wnaf_na_lam[129];
|
||||
int bits_na_1;
|
||||
int bits_na_lam;
|
||||
};
|
||||
|
|
@ -259,8 +274,8 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
|
|||
secp256k1_scalar_split_lambda(&na_1, &na_lam, &na[np]);
|
||||
|
||||
/* build wnaf representation for na_1 and na_lam. */
|
||||
state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A);
|
||||
state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A);
|
||||
state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf_small(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A);
|
||||
state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf_small(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A);
|
||||
VERIFY_CHECK(state->ps[no].bits_na_1 <= 129);
|
||||
VERIFY_CHECK(state->ps[no].bits_na_lam <= 129);
|
||||
if (state->ps[no].bits_na_1 > bits) {
|
||||
|
|
@ -296,8 +311,9 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
|
|||
}
|
||||
|
||||
for (np = 0; np < no; ++np) {
|
||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||
secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i].x, &secp256k1_const_beta);
|
||||
size_t j;
|
||||
for (j = 0; j < ECMULT_TABLE_SIZE(WINDOW_A); j++) {
|
||||
secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + j], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + j].x, &secp256k1_const_beta);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -341,7 +357,7 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
|
|||
}
|
||||
}
|
||||
|
||||
if (!r->infinity) {
|
||||
if (!secp256k1_gej_is_infinity(r)) {
|
||||
secp256k1_fe_mul(&r->z, &r->z, &Z);
|
||||
}
|
||||
}
|
||||
|
|
@ -502,7 +518,6 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi
|
|||
size_t np;
|
||||
size_t no = 0;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (np = 0; np < num; ++np) {
|
||||
if (secp256k1_scalar_is_zero(&sc[np]) || secp256k1_ge_is_infinity(&pt[np])) {
|
||||
|
|
@ -520,16 +535,17 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi
|
|||
|
||||
for (i = n_wnaf - 1; i >= 0; i--) {
|
||||
secp256k1_gej running_sum;
|
||||
int j;
|
||||
size_t buc;
|
||||
|
||||
for(j = 0; j < ECMULT_TABLE_SIZE(bucket_window+2); j++) {
|
||||
secp256k1_gej_set_infinity(&buckets[j]);
|
||||
for (buc = 0; buc < ECMULT_TABLE_SIZE(bucket_window+2); buc++) {
|
||||
secp256k1_gej_set_infinity(&buckets[buc]);
|
||||
}
|
||||
|
||||
for (np = 0; np < no; ++np) {
|
||||
int n = state->wnaf_na[np*n_wnaf + i];
|
||||
struct secp256k1_pippenger_point_state point_state = state->ps[np];
|
||||
secp256k1_ge tmp;
|
||||
int idx;
|
||||
|
||||
if (i == 0) {
|
||||
/* correct for wnaf skew */
|
||||
|
|
@ -540,16 +556,16 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi
|
|||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
idx = (n - 1)/2;
|
||||
secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &pt[point_state.input_pos], NULL);
|
||||
buc = (n - 1)/2;
|
||||
secp256k1_gej_add_ge_var(&buckets[buc], &buckets[buc], &pt[point_state.input_pos], NULL);
|
||||
} else if (n < 0) {
|
||||
idx = -(n + 1)/2;
|
||||
buc = -(n + 1)/2;
|
||||
secp256k1_ge_neg(&tmp, &pt[point_state.input_pos]);
|
||||
secp256k1_gej_add_ge_var(&buckets[idx], &buckets[idx], &tmp, NULL);
|
||||
secp256k1_gej_add_ge_var(&buckets[buc], &buckets[buc], &tmp, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
for(j = 0; j < bucket_window; j++) {
|
||||
for (j = 0; j < bucket_window; j++) {
|
||||
secp256k1_gej_double_var(r, r, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -562,8 +578,8 @@ static int secp256k1_ecmult_pippenger_wnaf(secp256k1_gej *buckets, int bucket_wi
|
|||
*
|
||||
* The doubling is done implicitly by deferring the final window doubling (of 'r').
|
||||
*/
|
||||
for(j = ECMULT_TABLE_SIZE(bucket_window+2) - 1; j > 0; j--) {
|
||||
secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[j], NULL);
|
||||
for (buc = ECMULT_TABLE_SIZE(bucket_window+2) - 1; buc > 0; buc--) {
|
||||
secp256k1_gej_add_var(&running_sum, &running_sum, &buckets[buc], NULL);
|
||||
secp256k1_gej_add_var(r, r, &running_sum, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -798,8 +814,8 @@ static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n
|
|||
return 1;
|
||||
}
|
||||
/* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */
|
||||
*n_batches = 1 + (n - 1) / max_n_batch_points;
|
||||
*n_batch_points = 1 + (n - 1) / *n_batches;
|
||||
*n_batches = CEIL_DIV(n, max_n_batch_points);
|
||||
*n_batch_points = CEIL_DIV(n, *n_batches);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -233,7 +233,7 @@ static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
|
|||
#define secp256k1_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, secp256k1_fe_mul_int_unchecked(r, a))
|
||||
|
||||
/** Like secp256k1_fe_mul_int but a is not checked to be an integer constant expression.
|
||||
*
|
||||
*
|
||||
* Should not be called directly outside of tests.
|
||||
*/
|
||||
static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a);
|
||||
|
|
@ -307,7 +307,8 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe
|
|||
*/
|
||||
static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
|
||||
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
|
||||
/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time.
|
||||
* Both *r and *a must be initialized. Flag must be 0 or 1. */
|
||||
static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
|
||||
|
||||
/** Conditionally move a field element in constant time.
|
||||
|
|
|
|||
|
|
@ -1014,6 +1014,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp25
|
|||
SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
|
||||
uint32_t mask0, mask1;
|
||||
volatile int vflag = flag;
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||
mask0 = vflag + ~((uint32_t)0);
|
||||
mask1 = ~mask0;
|
||||
|
|
@ -1097,6 +1098,7 @@ static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
|
|||
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
|
||||
uint32_t mask0, mask1;
|
||||
volatile int vflag = flag;
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||
mask0 = vflag + ~((uint32_t)0);
|
||||
mask1 = ~mask0;
|
||||
|
|
|
|||
|
|
@ -349,6 +349,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp25
|
|||
SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
|
||||
uint64_t mask0, mask1;
|
||||
volatile int vflag = flag;
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||
mask0 = vflag + ~((uint64_t)0);
|
||||
mask1 = ~mask0;
|
||||
|
|
@ -416,6 +417,7 @@ static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
|
|||
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
|
||||
uint64_t mask0, mask1;
|
||||
volatile int vflag = flag;
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||
mask0 = vflag + ~((uint64_t)0);
|
||||
mask1 = ~mask0;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
|
||||
secp256k1_memclear(a, sizeof(secp256k1_fe));
|
||||
secp256k1_memclear_explicit(a, sizeof(secp256k1_fe));
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,11 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);
|
|||
/** Set a group element equal to another which is given in jacobian coordinates. */
|
||||
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a);
|
||||
|
||||
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
|
||||
/** Set group elements r[0:len] (affine) equal to group elements a[0:len] (jacobian).
|
||||
* None of the group elements in a[0:len] may be infinity. Constant time. */
|
||||
static void secp256k1_ge_set_all_gej(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
|
||||
|
||||
/** Set group elements r[0:len] (affine) equal to group elements a[0:len] (jacobian). */
|
||||
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
|
||||
|
||||
/** Bring a batch of inputs to the same global z "denominator", based on ratios between
|
||||
|
|
@ -174,10 +178,12 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge
|
|||
/** Convert a group element back from the storage type. */
|
||||
static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a);
|
||||
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
|
||||
/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time.
|
||||
* Both *r and *a must be initialized. Flag must be 0 or 1. */
|
||||
static void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag);
|
||||
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
|
||||
/** If flag is 1, set *r equal to *a; if flag is 0, leave it. Constant-time.
|
||||
* Both *r and *a must be initialized. Flag must be 0 or 1. */
|
||||
static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag);
|
||||
|
||||
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
|
||||
|
|
@ -185,12 +191,20 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
|
|||
|
||||
/** Convert a group element that is not infinity to a 64-byte array. The output
|
||||
* array is platform-dependent. */
|
||||
static void secp256k1_ge_to_bytes(unsigned char *buf, secp256k1_ge *a);
|
||||
static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a);
|
||||
|
||||
/** Convert a 64-byte array into group element. This function assumes that the
|
||||
* provided buffer correctly encodes a group element. */
|
||||
static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf);
|
||||
|
||||
/** Convert a group element (that is allowed to be infinity) to a 64-byte
|
||||
* array. The output array is platform-dependent. */
|
||||
static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge);
|
||||
|
||||
/** Convert a 64-byte array into a group element. This function assumes that the
|
||||
* provided buffer is the output of secp256k1_ge_to_bytes_ext. */
|
||||
static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data);
|
||||
|
||||
/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve.
|
||||
*
|
||||
* In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the
|
||||
|
|
|
|||
|
|
@ -195,6 +195,44 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
|
|||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_all_gej(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
|
||||
secp256k1_fe u;
|
||||
size_t i;
|
||||
#ifdef VERIFY
|
||||
for (i = 0; i < len; i++) {
|
||||
SECP256K1_GEJ_VERIFY(&a[i]);
|
||||
VERIFY_CHECK(!secp256k1_gej_is_infinity(&a[i]));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use destination's x coordinates as scratch space */
|
||||
r[0].x = a[0].z;
|
||||
for (i = 1; i < len; i++) {
|
||||
secp256k1_fe_mul(&r[i].x, &r[i - 1].x, &a[i].z);
|
||||
}
|
||||
secp256k1_fe_inv(&u, &r[len - 1].x);
|
||||
|
||||
for (i = len - 1; i > 0; i--) {
|
||||
secp256k1_fe_mul(&r[i].x, &r[i - 1].x, &u);
|
||||
secp256k1_fe_mul(&u, &u, &a[i].z);
|
||||
}
|
||||
r[0].x = u;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
|
||||
}
|
||||
|
||||
#ifdef VERIFY
|
||||
for (i = 0; i < len; i++) {
|
||||
SECP256K1_GE_VERIFY(&r[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
|
||||
secp256k1_fe u;
|
||||
size_t i;
|
||||
|
|
@ -283,36 +321,27 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se
|
|||
|
||||
static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
|
||||
r->infinity = 1;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_fe_clear(&r->z);
|
||||
secp256k1_fe_set_int(&r->x, 0);
|
||||
secp256k1_fe_set_int(&r->y, 0);
|
||||
secp256k1_fe_set_int(&r->z, 0);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
|
||||
r->infinity = 1;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_fe_set_int(&r->x, 0);
|
||||
secp256k1_fe_set_int(&r->y, 0);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_clear(secp256k1_gej *r) {
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_fe_clear(&r->z);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
secp256k1_memclear_explicit(r, sizeof(secp256k1_gej));
|
||||
}
|
||||
|
||||
static void secp256k1_ge_clear(secp256k1_ge *r) {
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
secp256k1_memclear_explicit(r, sizeof(secp256k1_ge));
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
|
||||
|
|
@ -877,6 +906,7 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag
|
|||
static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) {
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
|
||||
secp256k1_fe_cmov(&r->x, &a->x, flag);
|
||||
secp256k1_fe_cmov(&r->y, &a->y, flag);
|
||||
|
|
@ -887,6 +917,7 @@ static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k
|
|||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
secp256k1_fe_storage_cmov(&r->x, &a->x, flag);
|
||||
secp256k1_fe_storage_cmov(&r->y, &a->y, flag);
|
||||
}
|
||||
|
|
@ -965,7 +996,7 @@ static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp25
|
|||
return secp256k1_fe_is_square_var(&r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_to_bytes(unsigned char *buf, secp256k1_ge *a) {
|
||||
static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a) {
|
||||
secp256k1_ge_storage s;
|
||||
|
||||
/* We require that the secp256k1_ge_storage type is exactly 64 bytes.
|
||||
|
|
@ -985,4 +1016,21 @@ static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf) {
|
|||
secp256k1_ge_from_storage(r, &s);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge) {
|
||||
if (secp256k1_ge_is_infinity(ge)) {
|
||||
memset(data, 0, 64);
|
||||
} else {
|
||||
secp256k1_ge_to_bytes(data, ge);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data) {
|
||||
static const unsigned char zeros[64] = { 0 };
|
||||
if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) {
|
||||
secp256k1_ge_set_infinity(ge);
|
||||
} else {
|
||||
secp256k1_ge_from_bytes(ge, data);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_GROUP_IMPL_H */
|
||||
|
|
|
|||
|
|
@ -10,6 +10,12 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
secp256k1_sha256_compression_function fn_sha256_compression;
|
||||
} secp256k1_hash_ctx;
|
||||
|
||||
static void secp256k1_hash_ctx_init(secp256k1_hash_ctx *hash_ctx);
|
||||
|
||||
typedef struct {
|
||||
uint32_t s[8];
|
||||
unsigned char buf[64];
|
||||
|
|
@ -17,17 +23,21 @@ typedef struct {
|
|||
} secp256k1_sha256;
|
||||
|
||||
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
|
||||
static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32);
|
||||
/* Initialize a SHA256 hash state with a precomputed midstate.
|
||||
* The byte counter must be a multiple of 64, i.e., there must be no unwritten
|
||||
* bytes in the buffer. */
|
||||
static void secp256k1_sha256_initialize_midstate(secp256k1_sha256 *hash, uint64_t bytes, const uint32_t state[8]);
|
||||
static void secp256k1_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, unsigned char *out32);
|
||||
static void secp256k1_sha256_clear(secp256k1_sha256 *hash);
|
||||
|
||||
typedef struct {
|
||||
secp256k1_sha256 inner, outer;
|
||||
} secp256k1_hmac_sha256;
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size);
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32);
|
||||
static void secp256k1_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size);
|
||||
static void secp256k1_hmac_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_hmac_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, unsigned char *out32);
|
||||
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash);
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -36,8 +46,8 @@ typedef struct {
|
|||
int retry;
|
||||
} secp256k1_rfc6979_hmac_sha256;
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||
|
||||
|
|
|
|||
|
|
@ -40,8 +40,15 @@ static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
|
|||
hash->bytes = 0;
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_initialize_midstate(secp256k1_sha256 *hash, uint64_t bytes, const uint32_t state[8]) {
|
||||
VERIFY_CHECK((bytes & 0x3F) == 0);
|
||||
VERIFY_CHECK(state != NULL);
|
||||
memcpy(hash->s, state, sizeof(hash->s));
|
||||
hash->bytes = bytes;
|
||||
}
|
||||
|
||||
/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */
|
||||
static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) {
|
||||
static void secp256k1_sha256_transform_impl(uint32_t* s, const unsigned char* buf) {
|
||||
uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
|
||||
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
|
||||
|
||||
|
|
@ -123,26 +130,52 @@ static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) {
|
|||
s[7] += h;
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) {
|
||||
static void secp256k1_sha256_transform(uint32_t *state, const unsigned char *blocks64, size_t n_blocks) {
|
||||
while (n_blocks--) {
|
||||
secp256k1_sha256_transform_impl(state, blocks64);
|
||||
blocks64 += 64;
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_hash_ctx_init(secp256k1_hash_ctx *hash_ctx) {
|
||||
VERIFY_CHECK(hash_ctx != NULL);
|
||||
hash_ctx->fn_sha256_compression = secp256k1_sha256_transform;
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *data, size_t len) {
|
||||
size_t chunk_len;
|
||||
size_t bufsize = hash->bytes & 0x3F;
|
||||
hash->bytes += len;
|
||||
VERIFY_CHECK(hash->bytes >= len);
|
||||
while (len >= 64 - bufsize) {
|
||||
/* Fill the buffer, and process it. */
|
||||
size_t chunk_len = 64 - bufsize;
|
||||
VERIFY_CHECK(hash_ctx != NULL);
|
||||
VERIFY_CHECK(hash_ctx->fn_sha256_compression != NULL);
|
||||
|
||||
/* If we exceed the 64-byte block size with this input, process it and wipe the buffer */
|
||||
chunk_len = 64 - bufsize;
|
||||
if (bufsize && len >= chunk_len) {
|
||||
memcpy(hash->buf + bufsize, data, chunk_len);
|
||||
data += chunk_len;
|
||||
len -= chunk_len;
|
||||
secp256k1_sha256_transform(hash->s, hash->buf);
|
||||
hash_ctx->fn_sha256_compression(hash->s, hash->buf, 1);
|
||||
bufsize = 0;
|
||||
}
|
||||
|
||||
/* If we still have data to process, invoke compression directly on the input */
|
||||
if (len >= 64) {
|
||||
const size_t n_blocks = len / 64;
|
||||
const size_t advance = n_blocks * 64;
|
||||
hash_ctx->fn_sha256_compression(hash->s, data, n_blocks);
|
||||
data += advance;
|
||||
len -= advance;
|
||||
}
|
||||
|
||||
/* Fill the buffer with what remains */
|
||||
if (len) {
|
||||
/* Fill the buffer with what remains. */
|
||||
memcpy(hash->buf + bufsize, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
|
||||
static void secp256k1_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, unsigned char *out32) {
|
||||
static const unsigned char pad[64] = {0x80};
|
||||
unsigned char sizedesc[8];
|
||||
int i;
|
||||
|
|
@ -150,8 +183,8 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out
|
|||
VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61));
|
||||
secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29);
|
||||
secp256k1_write_be32(&sizedesc[4], hash->bytes << 3);
|
||||
secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
|
||||
secp256k1_sha256_write(hash, sizedesc, 8);
|
||||
secp256k1_sha256_write(hash_ctx, hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
|
||||
secp256k1_sha256_write(hash_ctx, hash, sizedesc, 8);
|
||||
for (i = 0; i < 8; i++) {
|
||||
secp256k1_write_be32(&out32[4*i], hash->s[i]);
|
||||
hash->s[i] = 0;
|
||||
|
|
@ -160,22 +193,22 @@ static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out
|
|||
|
||||
/* Initializes a sha256 struct and writes the 64 byte string
|
||||
* SHA256(tag)||SHA256(tag) into it. */
|
||||
static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) {
|
||||
static void secp256k1_sha256_initialize_tagged(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256_initialize(hash);
|
||||
secp256k1_sha256_write(hash, tag, taglen);
|
||||
secp256k1_sha256_finalize(hash, buf);
|
||||
secp256k1_sha256_write(hash_ctx, hash, tag, taglen);
|
||||
secp256k1_sha256_finalize(hash_ctx, hash, buf);
|
||||
|
||||
secp256k1_sha256_initialize(hash);
|
||||
secp256k1_sha256_write(hash, buf, 32);
|
||||
secp256k1_sha256_write(hash, buf, 32);
|
||||
secp256k1_sha256_write(hash_ctx, hash, buf, 32);
|
||||
secp256k1_sha256_write(hash_ctx, hash, buf, 32);
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_clear(secp256k1_sha256 *hash) {
|
||||
secp256k1_memclear(hash, sizeof(*hash));
|
||||
secp256k1_memclear_explicit(hash, sizeof(*hash));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
|
||||
static void secp256k1_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
|
||||
size_t n;
|
||||
unsigned char rkey[64];
|
||||
if (keylen <= sizeof(rkey)) {
|
||||
|
|
@ -184,8 +217,8 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const
|
|||
} else {
|
||||
secp256k1_sha256 sha256;
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&sha256, key, keylen);
|
||||
secp256k1_sha256_finalize(&sha256, rkey);
|
||||
secp256k1_sha256_write(hash_ctx, &sha256, key, keylen);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha256, rkey);
|
||||
memset(rkey + 32, 0, 32);
|
||||
}
|
||||
|
||||
|
|
@ -193,33 +226,33 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const
|
|||
for (n = 0; n < sizeof(rkey); n++) {
|
||||
rkey[n] ^= 0x5c;
|
||||
}
|
||||
secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey));
|
||||
secp256k1_sha256_write(hash_ctx, &hash->outer, rkey, sizeof(rkey));
|
||||
|
||||
secp256k1_sha256_initialize(&hash->inner);
|
||||
for (n = 0; n < sizeof(rkey); n++) {
|
||||
rkey[n] ^= 0x5c ^ 0x36;
|
||||
}
|
||||
secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey));
|
||||
secp256k1_memclear(rkey, sizeof(rkey));
|
||||
secp256k1_sha256_write(hash_ctx, &hash->inner, rkey, sizeof(rkey));
|
||||
secp256k1_memclear_explicit(rkey, sizeof(rkey));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
|
||||
secp256k1_sha256_write(&hash->inner, data, size);
|
||||
static void secp256k1_hmac_sha256_write(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
|
||||
secp256k1_sha256_write(hash_ctx, &hash->inner, data, size);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) {
|
||||
static void secp256k1_hmac_sha256_finalize(const secp256k1_hash_ctx *hash_ctx, secp256k1_hmac_sha256 *hash, unsigned char *out32) {
|
||||
unsigned char temp[32];
|
||||
secp256k1_sha256_finalize(&hash->inner, temp);
|
||||
secp256k1_sha256_write(&hash->outer, temp, 32);
|
||||
secp256k1_memclear(temp, sizeof(temp));
|
||||
secp256k1_sha256_finalize(&hash->outer, out32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &hash->inner, temp);
|
||||
secp256k1_sha256_write(hash_ctx, &hash->outer, temp, 32);
|
||||
secp256k1_memclear_explicit(temp, sizeof(temp));
|
||||
secp256k1_sha256_finalize(hash_ctx, &hash->outer, out32);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_clear(secp256k1_hmac_sha256 *hash) {
|
||||
secp256k1_memclear(hash, sizeof(*hash));
|
||||
secp256k1_memclear_explicit(hash, sizeof(*hash));
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
static const unsigned char zero[1] = {0x00};
|
||||
static const unsigned char one[1] = {0x01};
|
||||
|
|
@ -228,47 +261,47 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2
|
|||
memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */
|
||||
|
||||
/* RFC6979 3.2.d. */
|
||||
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, zero, 1);
|
||||
secp256k1_hmac_sha256_write(&hmac, key, keylen);
|
||||
secp256k1_hmac_sha256_finalize(&hmac, rng->k);
|
||||
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(&hmac, rng->v);
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, zero, 1);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, key, keylen);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k);
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
|
||||
|
||||
/* RFC6979 3.2.f. */
|
||||
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, one, 1);
|
||||
secp256k1_hmac_sha256_write(&hmac, key, keylen);
|
||||
secp256k1_hmac_sha256_finalize(&hmac, rng->k);
|
||||
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(&hmac, rng->v);
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, one, 1);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, key, keylen);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k);
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
|
||||
rng->retry = 0;
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) {
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(const secp256k1_hash_ctx *hash_ctx, secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) {
|
||||
/* RFC6979 3.2.h. */
|
||||
static const unsigned char zero[1] = {0x00};
|
||||
if (rng->retry) {
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, zero, 1);
|
||||
secp256k1_hmac_sha256_finalize(&hmac, rng->k);
|
||||
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(&hmac, rng->v);
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, zero, 1);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->k);
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
|
||||
}
|
||||
|
||||
while (outlen > 0) {
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
int now = outlen;
|
||||
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(&hmac, rng->v);
|
||||
size_t now = outlen;
|
||||
secp256k1_hmac_sha256_initialize(hash_ctx, &hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(hash_ctx, &hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_finalize(hash_ctx, &hmac, rng->v);
|
||||
if (now > 32) {
|
||||
now = 32;
|
||||
}
|
||||
|
|
@ -285,7 +318,7 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
|
|||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_clear(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||
secp256k1_memclear(rng, sizeof(*rng));
|
||||
secp256k1_memclear_explicit(rng, sizeof(*rng));
|
||||
}
|
||||
|
||||
#undef Round
|
||||
|
|
|
|||
|
|
@ -13,8 +13,19 @@
|
|||
/* In-place, iterative heapsort with an interface matching glibc's qsort_r. This
|
||||
* is preferred over standard library implementations because they generally
|
||||
* make no guarantee about being fast for malicious inputs.
|
||||
* Remember that heapsort is unstable.
|
||||
*
|
||||
* See the qsort_r manpage for a description of the interface.
|
||||
* In/Out: ptr: pointer to the array to sort. The contents of the array are
|
||||
* sorted in ascending order according to the comparison function.
|
||||
* In: count: number of elements in the array.
|
||||
* size: size in bytes of each element.
|
||||
* cmp: pointer to a comparison function that is called with two
|
||||
* arguments that point to the objects being compared. The cmp_data
|
||||
* argument of secp256k1_hsort is passed as third argument. The
|
||||
* function must return an integer less than, equal to, or greater
|
||||
* than zero if the first argument is considered to be respectively
|
||||
* less than, equal to, or greater than the second.
|
||||
* cmp_data: pointer passed as third argument to cmp.
|
||||
*/
|
||||
static void secp256k1_hsort(void *ptr, size_t count, size_t size,
|
||||
int (*cmp)(const void *, const void *, void *),
|
||||
|
|
@ -13,33 +13,42 @@
|
|||
* compares as less than or equal to the element at index parent(i) = (i-1)/2.
|
||||
*/
|
||||
|
||||
static SECP256K1_INLINE size_t child1(size_t i) {
|
||||
static SECP256K1_INLINE size_t secp256k1_heap_child1(size_t i) {
|
||||
VERIFY_CHECK(i <= (SIZE_MAX - 1)/2);
|
||||
return 2*i + 1;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE size_t child2(size_t i) {
|
||||
static SECP256K1_INLINE size_t secp256k1_heap_child2(size_t i) {
|
||||
VERIFY_CHECK(i <= SIZE_MAX/2 - 1);
|
||||
return child1(i)+1;
|
||||
return secp256k1_heap_child1(i)+1;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void heap_swap64(unsigned char *a, size_t i, size_t j, size_t stride) {
|
||||
static SECP256K1_INLINE void secp256k1_heap_swap64(unsigned char *a, unsigned char *b, size_t len) {
|
||||
unsigned char tmp[64];
|
||||
VERIFY_CHECK(stride <= 64);
|
||||
memcpy(tmp, a + i*stride, stride);
|
||||
memmove(a + i*stride, a + j*stride, stride);
|
||||
memcpy(a + j*stride, tmp, stride);
|
||||
VERIFY_CHECK(len <= 64);
|
||||
memcpy(tmp, a, len);
|
||||
memmove(a, b, len);
|
||||
memcpy(b, tmp, len);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void heap_swap(unsigned char *a, size_t i, size_t j, size_t stride) {
|
||||
while (64 < stride) {
|
||||
heap_swap64(a + (stride - 64), i, j, 64);
|
||||
stride -= 64;
|
||||
static SECP256K1_INLINE void secp256k1_heap_swap(unsigned char *arr, size_t i, size_t j, size_t stride) {
|
||||
unsigned char *a = arr + i*stride;
|
||||
unsigned char *b = arr + j*stride;
|
||||
size_t len = stride;
|
||||
while (64 < len) {
|
||||
secp256k1_heap_swap64(a + (len - 64), b + (len - 64), 64);
|
||||
len -= 64;
|
||||
}
|
||||
heap_swap64(a, i, j, stride);
|
||||
secp256k1_heap_swap64(a, b, len);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void heap_down(unsigned char *a, size_t i, size_t heap_size, size_t stride,
|
||||
/* This function accepts an array arr containing heap_size elements, each of
|
||||
* size stride. The elements in the array at indices >i satisfy the max-heap
|
||||
* property, i.e., for any element at index j (where j > i), all of its children
|
||||
* are smaller than the element itself. The purpose of the function is to update
|
||||
* the array so that all elements at indices >=i satisfy the max-heap
|
||||
* property. */
|
||||
static SECP256K1_INLINE void secp256k1_heap_down(unsigned char *arr, size_t i, size_t heap_size, size_t stride,
|
||||
int (*cmp)(const void *, const void *, void *), void *cmp_data) {
|
||||
while (i < heap_size/2) {
|
||||
VERIFY_CHECK(i <= SIZE_MAX/2 - 1);
|
||||
|
|
@ -50,7 +59,7 @@ static SECP256K1_INLINE void heap_down(unsigned char *a, size_t i, size_t heap_s
|
|||
* 2*i <= SIZE_MAX - 2
|
||||
*/
|
||||
|
||||
VERIFY_CHECK(child1(i) < heap_size);
|
||||
VERIFY_CHECK(secp256k1_heap_child1(i) < heap_size);
|
||||
/* Proof:
|
||||
* i < heap_size/2
|
||||
* i + 1 <= heap_size/2
|
||||
|
|
@ -59,7 +68,7 @@ static SECP256K1_INLINE void heap_down(unsigned char *a, size_t i, size_t heap_s
|
|||
* child1(i) < heap_size
|
||||
*/
|
||||
|
||||
/* Let [x] be notation for the contents at a[x*stride].
|
||||
/* Let [x] be notation for the contents at arr[x*stride].
|
||||
*
|
||||
* If [child1(i)] > [i] and [child2(i)] > [i],
|
||||
* swap [i] with the larger child to ensure the new parent is larger
|
||||
|
|
@ -68,20 +77,20 @@ static SECP256K1_INLINE void heap_down(unsigned char *a, size_t i, size_t heap_s
|
|||
* Else if [child1(i)] > [i], swap [i] with [child1(i)].
|
||||
* Else if [child2(i)] > [i], swap [i] with [child2(i)].
|
||||
*/
|
||||
if (child2(i) < heap_size
|
||||
&& 0 <= cmp(a + child2(i)*stride, a + child1(i)*stride, cmp_data)) {
|
||||
if (0 < cmp(a + child2(i)*stride, a + i*stride, cmp_data)) {
|
||||
heap_swap(a, i, child2(i), stride);
|
||||
i = child2(i);
|
||||
if (secp256k1_heap_child2(i) < heap_size
|
||||
&& 0 <= cmp(arr + secp256k1_heap_child2(i)*stride, arr + secp256k1_heap_child1(i)*stride, cmp_data)) {
|
||||
if (0 < cmp(arr + secp256k1_heap_child2(i)*stride, arr + i*stride, cmp_data)) {
|
||||
secp256k1_heap_swap(arr, i, secp256k1_heap_child2(i), stride);
|
||||
i = secp256k1_heap_child2(i);
|
||||
} else {
|
||||
/* At this point we have [child2(i)] >= [child1(i)] and we have
|
||||
* [child2(i)] <= [i], and thus [child1(i)] <= [i] which means
|
||||
* that the next comparison can be skipped. */
|
||||
return;
|
||||
}
|
||||
} else if (0 < cmp(a + child1(i)*stride, a + i*stride, cmp_data)) {
|
||||
heap_swap(a, i, child1(i), stride);
|
||||
i = child1(i);
|
||||
} else if (0 < cmp(arr + secp256k1_heap_child1(i)*stride, arr + i*stride, cmp_data)) {
|
||||
secp256k1_heap_swap(arr, i, secp256k1_heap_child1(i), stride);
|
||||
i = secp256k1_heap_child1(i);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
|
@ -98,18 +107,18 @@ static SECP256K1_INLINE void heap_down(unsigned char *a, size_t i, size_t heap_s
|
|||
/* In-place heap sort. */
|
||||
static void secp256k1_hsort(void *ptr, size_t count, size_t size,
|
||||
int (*cmp)(const void *, const void *, void *),
|
||||
void *cmp_data ) {
|
||||
void *cmp_data) {
|
||||
size_t i;
|
||||
|
||||
for(i = count/2; 0 < i; --i) {
|
||||
heap_down(ptr, i-1, count, size, cmp, cmp_data);
|
||||
for (i = count/2; 0 < i; --i) {
|
||||
secp256k1_heap_down(ptr, i-1, count, size, cmp, cmp_data);
|
||||
}
|
||||
for(i = count; 1 < i; --i) {
|
||||
for (i = count; 1 < i; --i) {
|
||||
/* Extract the largest value from the heap */
|
||||
heap_swap(ptr, 0, i-1, size);
|
||||
secp256k1_heap_swap(ptr, 0, i-1, size);
|
||||
|
||||
/* Repair the heap condition */
|
||||
heap_down(ptr, 0, i-1, size, cmp, cmp_data);
|
||||
secp256k1_heap_down(ptr, 0, i-1, size, cmp, cmp_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -236,6 +236,7 @@ static int secp256k1_bppp_rangeproof_norm_product_prove(
|
|||
secp256k1_scalar* c_vec,
|
||||
size_t c_vec_len
|
||||
) {
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
secp256k1_scalar mu_f, rho_f = *rho;
|
||||
size_t proof_idx = 0;
|
||||
ecmult_x_cb_data x_cb_data;
|
||||
|
|
@ -316,8 +317,8 @@ static int secp256k1_bppp_rangeproof_norm_product_prove(
|
|||
proof_idx += 65;
|
||||
|
||||
/* Obtain challenge gamma for the the next round */
|
||||
secp256k1_sha256_write(transcript, &proof[proof_idx - 65], 65);
|
||||
secp256k1_bppp_challenge_scalar(&gamma, transcript, 0);
|
||||
secp256k1_sha256_write(hash_ctx, transcript, &proof[proof_idx - 65], 65);
|
||||
secp256k1_bppp_challenge_scalar(hash_ctx, &gamma, transcript, 0);
|
||||
|
||||
if (g_len > 1) {
|
||||
for (i = 0; i < g_len; i = i + 2) {
|
||||
|
|
@ -434,6 +435,7 @@ static int secp256k1_bppp_rangeproof_norm_product_verify(
|
|||
size_t c_vec_len,
|
||||
const secp256k1_ge* commit
|
||||
) {
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
secp256k1_scalar rho_f, mu_f, v, n, l, rho_inv, h_c;
|
||||
secp256k1_scalar *gammas, *s_g, *s_h, *rho_inv_pows;
|
||||
secp256k1_gej res1, res2;
|
||||
|
|
@ -487,8 +489,8 @@ static int secp256k1_bppp_rangeproof_norm_product_verify(
|
|||
|
||||
for (i = 0; i < n_rounds; i++) {
|
||||
secp256k1_scalar gamma;
|
||||
secp256k1_sha256_write(transcript, &proof[i * 65], 65);
|
||||
secp256k1_bppp_challenge_scalar(&gamma, transcript, 0);
|
||||
secp256k1_sha256_write(hash_ctx, transcript, &proof[i * 65], 65);
|
||||
secp256k1_bppp_challenge_scalar(hash_ctx, &gamma, transcript, 0);
|
||||
gammas[i] = gamma;
|
||||
}
|
||||
/* s_g[0] = n * \prod_{j=0}^{log_g_len - 1} rho^(2^j)
|
||||
|
|
|
|||
|
|
@ -14,26 +14,21 @@
|
|||
* SHA256 to SHA256("Bulletproofs_pp/v0/commitment")||SHA256("Bulletproofs_pp/v0/commitment").
|
||||
*/
|
||||
static void secp256k1_bppp_sha256_tagged_commitment_init(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x52fc8185ul;
|
||||
sha->s[1] = 0x0e7debf0ul;
|
||||
sha->s[2] = 0xb0967270ul;
|
||||
sha->s[3] = 0x6f5abfe1ul;
|
||||
sha->s[4] = 0x822bdec0ul;
|
||||
sha->s[5] = 0x36db8beful;
|
||||
sha->s[6] = 0x03d9e1f1ul;
|
||||
sha->s[7] = 0x8a5cef6ful;
|
||||
|
||||
sha->bytes = 64;
|
||||
static const uint32_t midstate[8] = {
|
||||
0x52fc8185ul, 0x0e7debf0ul, 0xb0967270ul, 0x6f5abfe1ul,
|
||||
0x822bdec0ul, 0x36db8beful, 0x03d9e1f1ul, 0x8a5cef6ful
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* Obtain a challenge scalar from the current transcript.*/
|
||||
static void secp256k1_bppp_challenge_scalar(secp256k1_scalar* ch, const secp256k1_sha256 *transcript, uint64_t idx) {
|
||||
static void secp256k1_bppp_challenge_scalar(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar* ch, const secp256k1_sha256 *transcript, uint64_t idx) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256 sha = *transcript;
|
||||
secp256k1_bppp_le64(buf, idx);
|
||||
secp256k1_sha256_write(&sha, buf, 8);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, buf, 8);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, buf);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
secp256k1_scalar_set_b32(ch, buf, NULL);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,8 +47,11 @@ static int secp256k1_bppp_parse_one_of_points(secp256k1_ge *pt, const unsigned c
|
|||
/* Outputs a serialized point in compressed form. Returns 0 at point at infinity.
|
||||
*/
|
||||
static int secp256k1_bppp_serialize_pt(unsigned char *output, secp256k1_ge *lpt) {
|
||||
size_t size;
|
||||
return secp256k1_eckey_pubkey_serialize(lpt, output, &size, 1 /*compressed*/);
|
||||
if (secp256k1_ge_is_infinity(lpt)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_eckey_pubkey_serialize33(lpt, output);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* little-endian encodes a uint64 */
|
||||
|
|
|
|||
|
|
@ -18,16 +18,17 @@
|
|||
secp256k1_bppp_generators *secp256k1_bppp_generators_create(const secp256k1_context *ctx, size_t n) {
|
||||
secp256k1_bppp_generators *ret;
|
||||
secp256k1_rfc6979_hmac_sha256 rng;
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
unsigned char seed[64];
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
|
||||
ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
|
||||
ret = checked_malloc(&ctx->error_callback, sizeof(*ret));
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
|
||||
ret->gens = checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
|
||||
if (ret->gens == NULL) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
|
|
@ -37,11 +38,11 @@ secp256k1_bppp_generators *secp256k1_bppp_generators_create(const secp256k1_cont
|
|||
secp256k1_fe_get_b32(&seed[0], &secp256k1_ge_const_g.x);
|
||||
secp256k1_fe_get_b32(&seed[32], &secp256k1_ge_const_g.y);
|
||||
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed, 64);
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(hash_ctx, &rng, seed, 64);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_generator gen;
|
||||
unsigned char tmp[32] = { 0 };
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32);
|
||||
secp256k1_rfc6979_hmac_sha256_generate(hash_ctx, &rng, tmp, 32);
|
||||
CHECK(secp256k1_generator_generate(ctx, &gen, tmp));
|
||||
secp256k1_generator_load(&ret->gens[i], &gen);
|
||||
}
|
||||
|
|
@ -60,12 +61,12 @@ secp256k1_bppp_generators* secp256k1_bppp_generators_parse(const secp256k1_conte
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
|
||||
ret = checked_malloc(&ctx->error_callback, sizeof(*ret));
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret->n = n;
|
||||
ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
|
||||
ret->gens = checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
|
||||
if (ret->gens == NULL) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "bppp_transcript_impl.h"
|
||||
#include "test_vectors/verify.h"
|
||||
#include "test_vectors/prove.h"
|
||||
#include "../../unit_test.h"
|
||||
|
||||
static void test_bppp_generators_api(void) {
|
||||
secp256k1_bppp_generators *gens;
|
||||
|
|
@ -103,17 +104,18 @@ static void test_bppp_generators_fixed(void) {
|
|||
}
|
||||
|
||||
static void test_bppp_tagged_hash(void) {
|
||||
unsigned char tag_data[29] = "Bulletproofs_pp/v0/commitment";
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
|
||||
unsigned char tag_data[] = {'B', 'u', 'l', 'l', 'e', 't', 'p', 'r', 'o', 'o', 'f', 's', '_', 'p', 'p', '/', 'v', '0', '/', 'c', 'o', 'm', 'm', 'i', 't', 'm', 'e', 'n', 't'};
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256 sha_cached;
|
||||
unsigned char output[32];
|
||||
unsigned char output_cached[32];
|
||||
secp256k1_scalar s;
|
||||
|
||||
secp256k1_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data));
|
||||
secp256k1_sha256_initialize_tagged(hash_ctx, &sha, tag_data, sizeof(tag_data));
|
||||
secp256k1_bppp_sha256_tagged_commitment_init(&sha_cached);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
secp256k1_sha256_finalize(&sha_cached, output_cached);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, output);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha_cached, output_cached);
|
||||
CHECK(secp256k1_memcmp_var(output, output_cached, 32) == 0);
|
||||
|
||||
{
|
||||
|
|
@ -122,7 +124,7 @@ static void test_bppp_tagged_hash(void) {
|
|||
0x8A, 0x41, 0xC6, 0x85, 0x1A, 0x79, 0x14, 0xFC,
|
||||
0x48, 0x15, 0xC7, 0x2D, 0xF8, 0x63, 0x8F, 0x1B };
|
||||
secp256k1_bppp_sha256_tagged_commitment_init(&sha);
|
||||
secp256k1_bppp_challenge_scalar(&s, &sha, 0);
|
||||
secp256k1_bppp_challenge_scalar(hash_ctx, &s, &sha, 0);
|
||||
secp256k1_scalar_get_b32(output, &s);
|
||||
CHECK(secp256k1_memcmp_var(output, expected, sizeof(output)) == 0);
|
||||
}
|
||||
|
|
@ -133,8 +135,8 @@ static void test_bppp_tagged_hash(void) {
|
|||
0x72, 0x7E, 0x3E, 0xB7, 0x10, 0x03, 0xF0, 0xE9,
|
||||
0x69, 0x4D, 0xAA, 0x96, 0xCE, 0x98, 0xBB, 0x39,
|
||||
0x1C, 0x2F, 0x7C, 0x2E, 0x1C, 0x17, 0x78, 0x6D };
|
||||
secp256k1_sha256_write(&sha, tmp, sizeof(tmp));
|
||||
secp256k1_bppp_challenge_scalar(&s, &sha, 0);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, tmp, sizeof(tmp));
|
||||
secp256k1_bppp_challenge_scalar(hash_ctx, &s, &sha, 0);
|
||||
secp256k1_scalar_get_b32(output, &s);
|
||||
CHECK(secp256k1_memcmp_var(output, expected, sizeof(output)) == 0);
|
||||
}
|
||||
|
|
@ -208,20 +210,20 @@ static void test_serialize_two_points(void) {
|
|||
int i;
|
||||
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
random_group_element_test(&X);
|
||||
random_group_element_test(&R);
|
||||
testutil_random_ge_test(&X);
|
||||
testutil_random_ge_test(&R);
|
||||
test_serialize_two_points_roundtrip(&X, &R);
|
||||
}
|
||||
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
random_group_element_test(&X);
|
||||
testutil_random_ge_test(&X);
|
||||
secp256k1_ge_set_infinity(&R);
|
||||
test_serialize_two_points_roundtrip(&X, &R);
|
||||
}
|
||||
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
secp256k1_ge_set_infinity(&X);
|
||||
random_group_element_test(&R);
|
||||
testutil_random_ge_test(&R);
|
||||
test_serialize_two_points_roundtrip(&X, &R);
|
||||
}
|
||||
|
||||
|
|
@ -233,12 +235,12 @@ static void test_serialize_two_points(void) {
|
|||
{
|
||||
secp256k1_ge X_tmp, R_tmp;
|
||||
unsigned char buf[65];
|
||||
random_group_element_test(&X);
|
||||
random_group_element_test(&R);
|
||||
testutil_random_ge_test(&X);
|
||||
testutil_random_ge_test(&R);
|
||||
secp256k1_bppp_serialize_points(buf, &X, &R);
|
||||
|
||||
/* buf is valid if 0 <= buf[0] < 4. */
|
||||
buf[0] = (unsigned char)secp256k1_testrandi64(4, 255);
|
||||
buf[0] = (unsigned char)testrandi64(4, 255);
|
||||
CHECK(!secp256k1_bppp_parse_one_of_points(&X_tmp, buf, 0));
|
||||
CHECK(!secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 0));
|
||||
}
|
||||
|
|
@ -247,8 +249,8 @@ static void test_serialize_two_points(void) {
|
|||
secp256k1_ge X_tmp, R_tmp;
|
||||
unsigned char buf[65];
|
||||
int expect;
|
||||
random_group_element_test(&X);
|
||||
random_group_element_test(&R);
|
||||
testutil_random_ge_test(&X);
|
||||
testutil_random_ge_test(&R);
|
||||
secp256k1_bppp_serialize_points(buf, &X, &R);
|
||||
memset(&buf[1], 0, 32);
|
||||
if ((buf[0] & 2) == 0) {
|
||||
|
|
@ -278,6 +280,7 @@ static void secp256k1_norm_arg_commit_initial_data(
|
|||
const secp256k1_ge* commit
|
||||
) {
|
||||
/* Commit to the initial public values */
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
|
||||
unsigned char ser_commit[33], ser_scalar[32], ser_le64[8];
|
||||
size_t i;
|
||||
secp256k1_ge comm = *commit;
|
||||
|
|
@ -286,24 +289,24 @@ static void secp256k1_norm_arg_commit_initial_data(
|
|||
secp256k1_fe_normalize(&comm.y);
|
||||
CHECK(secp256k1_ge_is_infinity(&comm) == 0);
|
||||
CHECK(secp256k1_bppp_serialize_pt(&ser_commit[0], &comm));
|
||||
secp256k1_sha256_write(transcript, ser_commit, 33);
|
||||
secp256k1_sha256_write(hash_ctx, transcript, ser_commit, 33);
|
||||
secp256k1_scalar_get_b32(ser_scalar, rho);
|
||||
secp256k1_sha256_write(transcript, ser_scalar, 32);
|
||||
secp256k1_sha256_write(hash_ctx, transcript, ser_scalar, 32);
|
||||
secp256k1_bppp_le64(ser_le64, g_len);
|
||||
secp256k1_sha256_write(transcript, ser_le64, 8);
|
||||
secp256k1_sha256_write(hash_ctx, transcript, ser_le64, 8);
|
||||
secp256k1_bppp_le64(ser_le64, gens_vec->n);
|
||||
secp256k1_sha256_write(transcript, ser_le64, 8);
|
||||
secp256k1_sha256_write(hash_ctx, transcript, ser_le64, 8);
|
||||
for (i = 0; i < gens_vec->n; i++) {
|
||||
secp256k1_fe_normalize(&gens_vec->gens[i].x);
|
||||
secp256k1_fe_normalize(&gens_vec->gens[i].y);
|
||||
CHECK(secp256k1_bppp_serialize_pt(&ser_commit[0], &gens_vec->gens[i]));
|
||||
secp256k1_sha256_write(transcript, ser_commit, 33);
|
||||
secp256k1_sha256_write(hash_ctx, transcript, ser_commit, 33);
|
||||
}
|
||||
secp256k1_bppp_le64(ser_le64, c_vec_len);
|
||||
secp256k1_sha256_write(transcript, ser_le64, 8);
|
||||
secp256k1_sha256_write(hash_ctx, transcript, ser_le64, 8);
|
||||
for (i = 0; i < c_vec_len; i++) {
|
||||
secp256k1_scalar_get_b32(ser_scalar, &c_vec[i]);
|
||||
secp256k1_sha256_write(transcript, ser_scalar, 32);
|
||||
secp256k1_sha256_write(hash_ctx, transcript, ser_scalar, 32);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -446,12 +449,12 @@ static void norm_arg_verify_zero_len(void) {
|
|||
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(CTX, n_vec_len + c_vec_len);
|
||||
size_t plen = sizeof(proof);
|
||||
|
||||
random_scalar_order(&rho);
|
||||
testutil_random_scalar_order(&rho);
|
||||
secp256k1_scalar_sqr(&mu, &rho);
|
||||
|
||||
random_scalar_order(&n_vec[0]);
|
||||
random_scalar_order(&c_vec[0]);
|
||||
random_scalar_order(&l_vec[0]);
|
||||
testutil_random_scalar_order(&n_vec[0]);
|
||||
testutil_random_scalar_order(&c_vec[0]);
|
||||
testutil_random_scalar_order(&l_vec[0]);
|
||||
CHECK(secp256k1_bppp_commit(CTX, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
|
||||
CHECK(secp256k1_norm_arg_prove(scratch, proof, &plen, &rho, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit));
|
||||
CHECK(secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit));
|
||||
|
|
@ -472,16 +475,16 @@ static void norm_arg_test(unsigned int n, unsigned int m) {
|
|||
secp256k1_scratch *scratch = secp256k1_scratch_space_create(CTX, 1000*1000); /* shouldn't need much */
|
||||
unsigned char proof[1000];
|
||||
plen = 1000;
|
||||
random_scalar_order(&rho);
|
||||
testutil_random_scalar_order(&rho);
|
||||
secp256k1_scalar_sqr(&mu, &rho);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
random_scalar_order(&n_vec[i]);
|
||||
testutil_random_scalar_order(&n_vec[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < m; i++) {
|
||||
random_scalar_order(&l_vec[i]);
|
||||
random_scalar_order(&c_vec[i]);
|
||||
testutil_random_scalar_order(&l_vec[i]);
|
||||
testutil_random_scalar_order(&c_vec[i]);
|
||||
}
|
||||
|
||||
res = secp256k1_bppp_commit(CTX, scratch, &commit, gs, n_vec, n, l_vec, m, c_vec, m, &mu);
|
||||
|
|
@ -513,12 +516,12 @@ secp256k1_bppp_generators* bppp_generators_parse_regular(const unsigned char* da
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ret = (secp256k1_bppp_generators *)checked_malloc(&CTX->error_callback, sizeof(*ret));
|
||||
ret = checked_malloc(&CTX->error_callback, sizeof(*ret));
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ret->n = n;
|
||||
ret->gens = (secp256k1_ge*)checked_malloc(&CTX->error_callback, n * sizeof(*ret->gens));
|
||||
ret->gens = checked_malloc(&CTX->error_callback, n * sizeof(*ret->gens));
|
||||
if (ret->gens == NULL) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
|
|
@ -560,7 +563,7 @@ int norm_arg_verify_vectors_helper(secp256k1_scratch *scratch, const unsigned ch
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define IDX_TO_TEST(i) (norm_arg_verify_vectors_helper(scratch, verify_vector_gens, verify_vector_##i##_proof, sizeof(verify_vector_##i##_proof), verify_vector_##i##_r32, verify_vector_##i##_n_vec_len, verify_vector_##i##_c_vec32, verify_vector_##i##_c_vec, sizeof(verify_vector_##i##_c_vec)/sizeof(secp256k1_scalar), verify_vector_##i##_commit33) == verify_vector_##i##_result)
|
||||
#define IDX_TO_TEST(i) (norm_arg_verify_vectors_helper(scratch, verify_vector_gens, verify_vector_##i##_proof, sizeof(verify_vector_##i##_proof), verify_vector_##i##_r32, verify_vector_##i##_n_vec_len, verify_vector_##i##_c_vec32, verify_vector_##i##_c_vec, ARRAY_SIZE(verify_vector_##i##_c_vec), verify_vector_##i##_commit33) == verify_vector_##i##_result)
|
||||
|
||||
static void norm_arg_verify_vectors(void) {
|
||||
secp256k1_scratch *scratch = secp256k1_scratch_space_create(CTX, 1000*1000); /* shouldn't need much */
|
||||
|
|
@ -628,9 +631,9 @@ static void norm_arg_prove_vectors_helper(secp256k1_scratch *scratch, const unsi
|
|||
|
||||
|
||||
#define IDX_TO_TEST(i) (norm_arg_prove_vectors_helper(scratch, prove_vector_gens, prove_vector_##i##_proof, sizeof(prove_vector_##i##_proof), prove_vector_##i##_r32,\
|
||||
prove_vector_##i##_n_vec32, prove_vector_##i##_n_vec, sizeof(prove_vector_##i##_n_vec)/sizeof(secp256k1_scalar),\
|
||||
prove_vector_##i##_n_vec32, prove_vector_##i##_n_vec, ARRAY_SIZE(prove_vector_##i##_n_vec),\
|
||||
prove_vector_##i##_l_vec32, prove_vector_##i##_l_vec,\
|
||||
prove_vector_##i##_c_vec32, prove_vector_##i##_c_vec, sizeof(prove_vector_##i##_c_vec)/sizeof(secp256k1_scalar), \
|
||||
prove_vector_##i##_c_vec32, prove_vector_##i##_c_vec, ARRAY_SIZE(prove_vector_##i##_c_vec), \
|
||||
prove_vector_##i##_result))
|
||||
|
||||
static void norm_arg_prove_vectors(void) {
|
||||
|
|
@ -649,15 +652,7 @@ static void norm_arg_prove_vectors(void) {
|
|||
|
||||
#undef IDX_TO_TEST
|
||||
|
||||
static void run_bppp_tests(void) {
|
||||
test_log_exp();
|
||||
test_norm_util_helpers();
|
||||
test_serialize_two_points();
|
||||
test_bppp_generators_api();
|
||||
test_bppp_generators_fixed();
|
||||
test_bppp_tagged_hash();
|
||||
|
||||
norm_arg_verify_zero_len();
|
||||
static void norm_arg_test_all(void) {
|
||||
norm_arg_test(1, 1);
|
||||
norm_arg_test(1, 64);
|
||||
norm_arg_test(64, 1);
|
||||
|
|
@ -665,9 +660,20 @@ static void run_bppp_tests(void) {
|
|||
norm_arg_test(32, 64);
|
||||
norm_arg_test(64, 32);
|
||||
norm_arg_test(64, 64);
|
||||
|
||||
norm_arg_verify_vectors();
|
||||
norm_arg_prove_vectors();
|
||||
}
|
||||
|
||||
/* --- Test registry --- */
|
||||
static const struct tf_test_entry tests_bppp[] = {
|
||||
CASE1(test_log_exp),
|
||||
CASE1(test_norm_util_helpers),
|
||||
CASE1(test_serialize_two_points),
|
||||
CASE1(test_bppp_generators_api),
|
||||
CASE1(test_bppp_generators_fixed),
|
||||
CASE1(test_bppp_tagged_hash),
|
||||
CASE1(norm_arg_verify_zero_len),
|
||||
CASE1(norm_arg_test_all),
|
||||
CASE1(norm_arg_verify_vectors),
|
||||
CASE1(norm_arg_prove_vectors),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ include_HEADERS += include/secp256k1_ecdh.h
|
|||
noinst_HEADERS += src/modules/ecdh/main_impl.h
|
||||
noinst_HEADERS += src/modules/ecdh/tests_impl.h
|
||||
noinst_HEADERS += src/modules/ecdh/bench_impl.h
|
||||
noinst_HEADERS += src/wycheproof/ecdh_secp256k1_test.h
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include "../../../include/secp256k1_ecdh.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
const secp256k1_context *ctx;
|
||||
secp256k1_pubkey point;
|
||||
unsigned char scalar[32];
|
||||
} bench_ecdh_data;
|
||||
|
|
@ -46,12 +46,9 @@ static void run_ecdh_bench(int iters, int argc, char** argv) {
|
|||
bench_ecdh_data data;
|
||||
int d = argc == 1;
|
||||
|
||||
/* create a context with no capabilities */
|
||||
data.ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
|
||||
data.ctx = secp256k1_context_static;
|
||||
|
||||
if (d || have_flag(argc, argv, "ecdh")) run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_MODULE_ECDH_BENCH_H */
|
||||
|
|
|
|||
|
|
@ -10,20 +10,24 @@
|
|||
#include "../../../include/secp256k1_ecdh.h"
|
||||
#include "../../ecmult_const_impl.h"
|
||||
|
||||
static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
|
||||
static int ecdh_hash_function_sha256_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
|
||||
unsigned char version = (y32[31] & 0x01) | 0x02;
|
||||
secp256k1_sha256 sha;
|
||||
(void)data;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, &version, 1);
|
||||
secp256k1_sha256_write(&sha, x32, 32);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, &version, 1);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, x32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, output);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
|
||||
return ecdh_hash_function_sha256_impl(secp256k1_get_hash_context(secp256k1_context_static), output, x32, y32, data);
|
||||
}
|
||||
|
||||
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256;
|
||||
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256;
|
||||
|
||||
|
|
@ -41,10 +45,6 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
|
|||
ARG_CHECK(point != NULL);
|
||||
ARG_CHECK(scalar != NULL);
|
||||
|
||||
if (hashfp == NULL) {
|
||||
hashfp = secp256k1_ecdh_hash_function_default;
|
||||
}
|
||||
|
||||
secp256k1_pubkey_load(ctx, &pt, point);
|
||||
secp256k1_scalar_set_b32(&s, scalar, &overflow);
|
||||
|
||||
|
|
@ -60,10 +60,15 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
|
|||
secp256k1_fe_get_b32(x, &pt.x);
|
||||
secp256k1_fe_get_b32(y, &pt.y);
|
||||
|
||||
ret = hashfp(output, x, y, data);
|
||||
if (hashfp == NULL) {
|
||||
/* Use ctx-aware function by default */
|
||||
ret = ecdh_hash_function_sha256_impl(secp256k1_get_hash_context(ctx), output, x, y, data);
|
||||
} else {
|
||||
ret = hashfp(output, x, y, data);
|
||||
}
|
||||
|
||||
secp256k1_memclear(x, sizeof(x));
|
||||
secp256k1_memclear(y, sizeof(y));
|
||||
secp256k1_memclear_explicit(x, sizeof(x));
|
||||
secp256k1_memclear_explicit(y, sizeof(y));
|
||||
secp256k1_scalar_clear(&s);
|
||||
secp256k1_ge_clear(&pt);
|
||||
secp256k1_gej_clear(&res);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,16 @@
|
|||
#ifndef SECP256K1_MODULE_ECDH_TESTS_H
|
||||
#define SECP256K1_MODULE_ECDH_TESTS_H
|
||||
|
||||
#include "../../unit_test.h"
|
||||
#include "../../testutil.h"
|
||||
|
||||
static int ecdh_hash_function_test_xpassthru(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||
(void)y;
|
||||
(void)data;
|
||||
memcpy(output, x, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||
(void)output;
|
||||
(void)x;
|
||||
|
|
@ -56,7 +66,7 @@ static void test_ecdh_generator_basepoint(void) {
|
|||
size_t point_ser_len = sizeof(point_ser);
|
||||
secp256k1_scalar s;
|
||||
|
||||
random_scalar_order(&s);
|
||||
testutil_random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(s_b32, &s);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1);
|
||||
|
|
@ -74,32 +84,52 @@ static void test_ecdh_generator_basepoint(void) {
|
|||
/* compute "explicitly" */
|
||||
CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, point_ser, point_ser_len);
|
||||
secp256k1_sha256_finalize(&sha, output_ser);
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(CTX), &sha, point_ser, point_ser_len);
|
||||
secp256k1_sha256_finalize(secp256k1_get_hash_context(CTX), &sha, output_ser);
|
||||
/* compare */
|
||||
CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_SHA256_TRANSFORM_PROBE(sha256_ecdh)
|
||||
static void test_ecdh_ctx_sha256(void) {
|
||||
/* Check ctx-provided SHA256 compression override takes effect */
|
||||
secp256k1_context *ctx = secp256k1_context_clone(CTX);
|
||||
unsigned char out_default[65], out_custom[65];
|
||||
const unsigned char sk[32] = {1};
|
||||
secp256k1_pubkey pubkey;
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, sk) == 1);
|
||||
|
||||
/* Default behavior */
|
||||
CHECK(secp256k1_ecdh(ctx, out_default, &pubkey, sk, NULL, NULL) == 1);
|
||||
CHECK(!sha256_ecdh_called);
|
||||
|
||||
/* Override SHA256 compression directly, bypassing the ctx setter sanity checks */
|
||||
ctx->hash_ctx.fn_sha256_compression = sha256_ecdh;
|
||||
CHECK(secp256k1_ecdh(ctx, out_custom, &pubkey, sk, NULL, NULL) == 1);
|
||||
|
||||
/* Outputs must differ if custom compression was used */
|
||||
CHECK(secp256k1_memcmp_var(out_default, out_custom, 32) != 0);
|
||||
CHECK(sha256_ecdh_called);
|
||||
|
||||
secp256k1_context_destroy(ctx);
|
||||
}
|
||||
|
||||
static void test_bad_scalar(void) {
|
||||
unsigned char s_zero[32] = { 0 };
|
||||
unsigned char s_overflow[32] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
|
||||
0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b,
|
||||
0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41
|
||||
};
|
||||
unsigned char s_overflow[32] = { 0 };
|
||||
unsigned char s_rand[32] = { 0 };
|
||||
unsigned char output[32];
|
||||
secp256k1_scalar rand;
|
||||
secp256k1_pubkey point;
|
||||
|
||||
/* Create random point */
|
||||
random_scalar_order(&rand);
|
||||
testutil_random_scalar_order(&rand);
|
||||
secp256k1_scalar_get_b32(s_rand, &rand);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1);
|
||||
|
||||
/* Try to multiply it by bad values */
|
||||
memcpy(s_overflow, secp256k1_group_order_bytes, 32);
|
||||
CHECK(secp256k1_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 0);
|
||||
/* ...and a good one */
|
||||
|
|
@ -127,7 +157,7 @@ static void test_result_basepoint(void) {
|
|||
CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1);
|
||||
|
||||
for (i = 0; i < 2 * COUNT; i++) {
|
||||
random_scalar_order(&rand);
|
||||
testutil_random_scalar_order(&rand);
|
||||
secp256k1_scalar_get_b32(s, &rand);
|
||||
secp256k1_scalar_inverse(&rand, &rand);
|
||||
secp256k1_scalar_get_b32(s_inv, &rand);
|
||||
|
|
@ -142,11 +172,47 @@ static void test_result_basepoint(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void run_ecdh_tests(void) {
|
||||
test_ecdh_api();
|
||||
test_ecdh_generator_basepoint();
|
||||
test_bad_scalar();
|
||||
test_result_basepoint();
|
||||
static void test_ecdh_wycheproof(void) {
|
||||
#include "../../wycheproof/ecdh_secp256k1_test.h"
|
||||
int t;
|
||||
for (t = 0; t < SECP256K1_ECDH_WYCHEPROOF_NUMBER_TESTVECTORS; t++) {
|
||||
int parsed_ok;
|
||||
secp256k1_pubkey point;
|
||||
const unsigned char *pk;
|
||||
const unsigned char *sk;
|
||||
const unsigned char *expected_shared_secret;
|
||||
unsigned char output_ecdh[65] = { 0 };
|
||||
|
||||
int expected_result;
|
||||
|
||||
memset(&point, 0, sizeof(point));
|
||||
pk = &wycheproof_ecdh_public_keys[testvectors[t].pk_offset];
|
||||
parsed_ok = secp256k1_ec_pubkey_parse(CTX, &point, pk, testvectors[t].pk_len);
|
||||
|
||||
expected_result = testvectors[t].expected_result;
|
||||
CHECK(parsed_ok == expected_result);
|
||||
if (!parsed_ok) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sk = &wycheproof_ecdh_private_keys[testvectors[t].sk_offset];
|
||||
CHECK(testvectors[t].sk_len == 32);
|
||||
|
||||
CHECK(secp256k1_ecdh(CTX, output_ecdh, &point, sk, ecdh_hash_function_test_xpassthru, NULL) == 1);
|
||||
expected_shared_secret = &wycheproof_ecdh_shared_secrets[testvectors[t].shared_offset];
|
||||
|
||||
CHECK(secp256k1_memcmp_var(output_ecdh, expected_shared_secret, testvectors[t].shared_len) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Test registry --- */
|
||||
static const struct tf_test_entry tests_ecdh[] = {
|
||||
CASE1(test_ecdh_api),
|
||||
CASE1(test_ecdh_generator_basepoint),
|
||||
CASE1(test_bad_scalar),
|
||||
CASE1(test_result_basepoint),
|
||||
CASE1(test_ecdh_wycheproof),
|
||||
CASE1(test_ecdh_ctx_sha256),
|
||||
};
|
||||
|
||||
#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
|
||||
|
|
|
|||
|
|
@ -1,56 +1,58 @@
|
|||
#ifndef SECP256K1_DLEQ_IMPL_H
|
||||
#define SECP256K1_DLEQ_IMPL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../../../include/secp256k1_ecdsa_adaptor.h"
|
||||
|
||||
#include "../../../src/eckey.h"
|
||||
#include "../../../src/ecmult_const.h"
|
||||
#include "../../../src/group.h"
|
||||
#include "../../../src/hash.h"
|
||||
#include "../../../src/scalar.h"
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("DLEQ")||SHA256("DLEQ"). */
|
||||
static void secp256k1_nonce_function_dleq_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x8cc4beacul;
|
||||
sha->s[1] = 0x2e011f3ful;
|
||||
sha->s[2] = 0x355c75fbul;
|
||||
sha->s[3] = 0x3ba6a2c5ul;
|
||||
sha->s[4] = 0xe96f3aeful;
|
||||
sha->s[5] = 0x180530fdul;
|
||||
sha->s[6] = 0x94582499ul;
|
||||
sha->s[7] = 0x577fd564ul;
|
||||
|
||||
sha->bytes = 64;
|
||||
static const uint32_t midstate[8] = {
|
||||
0x8cc4beacul, 0x2e011f3ful, 0x355c75fbul, 0x3ba6a2c5ul,
|
||||
0xe96f3aeful, 0x180530fdul, 0x94582499ul, 0x577fd564ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */
|
||||
static const unsigned char dleq_algo[4] = "DLEQ";
|
||||
static const unsigned char dleq_algo[] = {'D','L','E','Q'};
|
||||
|
||||
static int secp256k1_dleq_hash_point(secp256k1_sha256 *sha, secp256k1_ge *p) {
|
||||
static int nonce_function_ecdsa_adaptor_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *pk33, const unsigned char *algo, size_t algolen, void *data);
|
||||
|
||||
static void secp256k1_dleq_hash_point(const secp256k1_hash_ctx *hash_ctx, secp256k1_sha256 *sha, secp256k1_ge *p) {
|
||||
unsigned char buf[33];
|
||||
size_t size = 33;
|
||||
|
||||
if (!secp256k1_eckey_pubkey_serialize(p, buf, &size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_sha256_write(sha, buf, size);
|
||||
return 1;
|
||||
secp256k1_eckey_pubkey_serialize33(p, buf);
|
||||
secp256k1_sha256_write(hash_ctx, sha, buf, 33);
|
||||
}
|
||||
|
||||
static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *sk32, const unsigned char *gen2_33, const unsigned char *p1_33, const unsigned char *p2_33, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
|
||||
static int secp256k1_dleq_nonce(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *k, const unsigned char *sk32, const unsigned char *gen2_33, const unsigned char *p1_33, const unsigned char *p2_33, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char buf[32];
|
||||
unsigned char nonce[32];
|
||||
size_t size = 33;
|
||||
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_ecdsa_adaptor;
|
||||
}
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, p1_33, size);
|
||||
secp256k1_sha256_write(&sha, p2_33, size);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, p1_33, 33);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, p2_33, 33);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, buf);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
if (!noncefp(nonce, buf, sk32, gen2_33, dleq_algo, sizeof(dleq_algo), ndata)) {
|
||||
if (noncefp == NULL || noncefp == secp256k1_nonce_function_ecdsa_adaptor) {
|
||||
if (!nonce_function_ecdsa_adaptor_impl(hash_ctx, nonce, buf, sk32, gen2_33, dleq_algo, sizeof(dleq_algo), ndata)) {
|
||||
return 0;
|
||||
}
|
||||
} else if (!noncefp(nonce, buf, sk32, gen2_33, dleq_algo, sizeof(dleq_algo), ndata)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(k, nonce, NULL);
|
||||
secp256k1_memclear_explicit(nonce, sizeof(nonce));
|
||||
if (secp256k1_scalar_is_zero(k)) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -60,79 +62,82 @@ static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *sk32,
|
|||
|
||||
/* Generates a challenge as defined in the DLC Specification at
|
||||
* https://github.com/discreetlogcontracts/dlcspecs */
|
||||
static void secp256k1_dleq_challenge(secp256k1_scalar *e, secp256k1_ge *gen2, secp256k1_ge *r1, secp256k1_ge *r2, secp256k1_ge *p1, secp256k1_ge *p2) {
|
||||
static void secp256k1_dleq_challenge(const secp256k1_hash_ctx *hash_ctx, secp256k1_scalar *e, secp256k1_ge *gen2, secp256k1_ge *r1, secp256k1_ge *r2, secp256k1_ge *p1, secp256k1_ge *p2) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
secp256k1_nonce_function_dleq_sha256_tagged(&sha);
|
||||
secp256k1_dleq_hash_point(&sha, p1);
|
||||
secp256k1_dleq_hash_point(&sha, gen2);
|
||||
secp256k1_dleq_hash_point(&sha, p2);
|
||||
secp256k1_dleq_hash_point(&sha, r1);
|
||||
secp256k1_dleq_hash_point(&sha, r2);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_dleq_hash_point(hash_ctx, &sha, p1);
|
||||
secp256k1_dleq_hash_point(hash_ctx, &sha, gen2);
|
||||
secp256k1_dleq_hash_point(hash_ctx, &sha, p2);
|
||||
secp256k1_dleq_hash_point(hash_ctx, &sha, r1);
|
||||
secp256k1_dleq_hash_point(hash_ctx, &sha, r2);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, buf);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
secp256k1_scalar_set_b32(e, buf, NULL);
|
||||
}
|
||||
|
||||
/* P1 = x*G, P2 = x*Y */
|
||||
static void secp256k1_dleq_pair(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_ge *p1, secp256k1_ge *p2, const secp256k1_scalar *sk, const secp256k1_ge *gen2) {
|
||||
secp256k1_gej p1j, p2j;
|
||||
/* p[0] = x*G, p[1] = x*Y */
|
||||
static void secp256k1_dleq_pair(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_ge *p, const secp256k1_scalar *sk, const secp256k1_ge *gen2) {
|
||||
secp256k1_gej pj[2];
|
||||
|
||||
secp256k1_ecmult_gen(ecmult_gen_ctx, &p1j, sk);
|
||||
secp256k1_ge_set_gej(p1, &p1j);
|
||||
secp256k1_ecmult_const(&p2j, gen2, sk);
|
||||
secp256k1_ge_set_gej(p2, &p2j);
|
||||
secp256k1_ecmult_gen(ecmult_gen_ctx, &pj[0], sk);
|
||||
secp256k1_ecmult_const(&pj[1], gen2, sk);
|
||||
secp256k1_ge_set_all_gej(p, pj, 2);
|
||||
}
|
||||
|
||||
/* Generates a proof that the discrete logarithm of P1 to the secp256k1 base G is the
|
||||
* same as the discrete logarithm of P2 to the base Y */
|
||||
static int secp256k1_dleq_prove(const secp256k1_context* ctx, secp256k1_scalar *s, secp256k1_scalar *e, const secp256k1_scalar *sk, secp256k1_ge *gen2, secp256k1_ge *p1, secp256k1_ge *p2, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
|
||||
secp256k1_ge r1, r2;
|
||||
static int secp256k1_dleq_prove(const secp256k1_context* ctx, secp256k1_scalar *s, secp256k1_scalar *e, const secp256k1_scalar *sk, secp256k1_ge *p1, secp256k1_ge *gen2, secp256k1_ge *p2, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
|
||||
/* Note: r[2] and k are local to the DLEQ proof, and they differ from the
|
||||
* values with the same identifiers in main_impl.h. */
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
secp256k1_ge r[2];
|
||||
secp256k1_scalar k = { 0 };
|
||||
unsigned char sk32[32];
|
||||
unsigned char gen2_33[33];
|
||||
unsigned char p1_33[33];
|
||||
unsigned char p2_33[33];
|
||||
int ret = 1;
|
||||
size_t pubkey_size = 33;
|
||||
int ret;
|
||||
|
||||
secp256k1_eckey_pubkey_serialize33(gen2, gen2_33);
|
||||
secp256k1_eckey_pubkey_serialize33(p1, p1_33);
|
||||
secp256k1_eckey_pubkey_serialize33(p2, p2_33);
|
||||
|
||||
secp256k1_scalar_get_b32(sk32, sk);
|
||||
if (!secp256k1_eckey_pubkey_serialize(gen2, gen2_33, &pubkey_size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_eckey_pubkey_serialize(p1, p1_33, &pubkey_size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_eckey_pubkey_serialize(p2, p2_33, &pubkey_size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret &= secp256k1_dleq_nonce(&k, sk32, gen2_33, p1_33, p2_33, noncefp, ndata);
|
||||
ret = secp256k1_dleq_nonce(hash_ctx, &k, sk32, gen2_33, p1_33, p2_33, noncefp, ndata);
|
||||
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
||||
if (!ret) {
|
||||
secp256k1_memclear_explicit(sk32, sizeof(sk32));
|
||||
return 0;
|
||||
}
|
||||
/* R1 = k*G, R2 = k*Y */
|
||||
secp256k1_dleq_pair(&ctx->ecmult_gen_ctx, &r1, &r2, &k, gen2);
|
||||
/* We declassify the non-secret values r1 and r2 to allow using them as
|
||||
secp256k1_dleq_pair(&ctx->ecmult_gen_ctx, r, &k, gen2);
|
||||
/* We declassify the non-secret values r[0] and r[1] to allow using them as
|
||||
* branch points. */
|
||||
secp256k1_declassify(ctx, &r1, sizeof(r1));
|
||||
secp256k1_declassify(ctx, &r2, sizeof(r2));
|
||||
secp256k1_declassify(ctx, &r[0], sizeof(r[0]));
|
||||
secp256k1_declassify(ctx, &r[1], sizeof(r[1]));
|
||||
|
||||
/* e = tagged hash(p1, gen2, p2, r1, r2) */
|
||||
/* e = tagged hash(p1, gen2, p2, r[0], r[1]) */
|
||||
/* s = k + e * sk */
|
||||
secp256k1_dleq_challenge(e, gen2, &r1, &r2, p1, p2);
|
||||
secp256k1_dleq_challenge(hash_ctx, e, gen2, &r[0], &r[1], p1, p2);
|
||||
secp256k1_scalar_mul(s, e, sk);
|
||||
secp256k1_scalar_add(s, s, &k);
|
||||
|
||||
secp256k1_scalar_clear(&k);
|
||||
return ret;
|
||||
secp256k1_memclear_explicit(sk32, sizeof(sk32));
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_dleq_verify(const secp256k1_scalar *s, const secp256k1_scalar *e, secp256k1_ge *p1, secp256k1_ge *gen2, secp256k1_ge *p2) {
|
||||
static int secp256k1_dleq_verify(const secp256k1_hash_ctx *hash_ctx, const secp256k1_scalar *s, const secp256k1_scalar *e, secp256k1_ge *p1, secp256k1_ge *gen2, secp256k1_ge *p2) {
|
||||
secp256k1_scalar e_neg;
|
||||
secp256k1_scalar e_expected;
|
||||
secp256k1_gej gen2j;
|
||||
secp256k1_gej p1j, p2j;
|
||||
secp256k1_gej r1j, r2j;
|
||||
secp256k1_ge r1, r2;
|
||||
secp256k1_gej rj[2];
|
||||
secp256k1_ge r[2];
|
||||
secp256k1_gej tmpj;
|
||||
|
||||
secp256k1_gej_set_ge(&p1j, p1);
|
||||
|
|
@ -140,16 +145,20 @@ static int secp256k1_dleq_verify(const secp256k1_scalar *s, const secp256k1_scal
|
|||
|
||||
secp256k1_scalar_negate(&e_neg, e);
|
||||
/* R1 = s*G - e*P1 */
|
||||
secp256k1_ecmult(&r1j, &p1j, &e_neg, s);
|
||||
secp256k1_ecmult(&rj[0], &p1j, &e_neg, s);
|
||||
/* R2 = s*gen2 - e*P2 */
|
||||
secp256k1_ecmult(&tmpj, &p2j, &e_neg, &secp256k1_scalar_zero);
|
||||
secp256k1_gej_set_ge(&gen2j, gen2);
|
||||
secp256k1_ecmult(&r2j, &gen2j, s, &secp256k1_scalar_zero);
|
||||
secp256k1_gej_add_var(&r2j, &r2j, &tmpj, NULL);
|
||||
secp256k1_ecmult(&rj[1], &gen2j, s, &secp256k1_scalar_zero);
|
||||
secp256k1_gej_add_var(&rj[1], &rj[1], &tmpj, NULL);
|
||||
|
||||
secp256k1_ge_set_gej(&r1, &r1j);
|
||||
secp256k1_ge_set_gej(&r2, &r2j);
|
||||
secp256k1_dleq_challenge(&e_expected, gen2, &r1, &r2, p1, p2);
|
||||
if (secp256k1_gej_is_infinity(&rj[0]) || secp256k1_gej_is_infinity(&rj[1])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_ge_set_all_gej_var(r, rj, 2);
|
||||
|
||||
secp256k1_dleq_challenge(hash_ctx, &e_expected, gen2, &r[0], &r[1], p1, p2);
|
||||
|
||||
secp256k1_scalar_add(&e_expected, &e_expected, &e_neg);
|
||||
return secp256k1_scalar_is_zero(&e_expected);
|
||||
|
|
|
|||
|
|
@ -7,24 +7,25 @@
|
|||
#ifndef SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H
|
||||
#define SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../../../include/secp256k1_ecdsa_adaptor.h"
|
||||
#include "dleq_impl.h"
|
||||
|
||||
/* (R, R', s', dleq_proof) */
|
||||
static int secp256k1_ecdsa_adaptor_sig_serialize(unsigned char *adaptor_sig162, secp256k1_ge *r, secp256k1_ge *rp, const secp256k1_scalar *sp, const secp256k1_scalar *dleq_proof_e, const secp256k1_scalar *dleq_proof_s) {
|
||||
size_t size = 33;
|
||||
#include "../../../src/eckey.h"
|
||||
#include "../../../src/ecmult.h"
|
||||
#include "../../../src/ecmult_const.h"
|
||||
#include "../../../src/group.h"
|
||||
#include "../../../src/hash.h"
|
||||
#include "../../../src/scalar.h"
|
||||
|
||||
if (!secp256k1_eckey_pubkey_serialize(r, adaptor_sig162, &size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_eckey_pubkey_serialize(rp, &adaptor_sig162[33], &size, 1)) {
|
||||
return 0;
|
||||
}
|
||||
/* (R, R', s', dleq_proof) */
|
||||
static void secp256k1_ecdsa_adaptor_sig_serialize(unsigned char *adaptor_sig162, secp256k1_ge *r, secp256k1_ge *rp, const secp256k1_scalar *sp, const secp256k1_scalar *dleq_proof_e, const secp256k1_scalar *dleq_proof_s) {
|
||||
secp256k1_eckey_pubkey_serialize33(r, adaptor_sig162);
|
||||
secp256k1_eckey_pubkey_serialize33(rp, &adaptor_sig162[33]);
|
||||
secp256k1_scalar_get_b32(&adaptor_sig162[66], sp);
|
||||
secp256k1_scalar_get_b32(&adaptor_sig162[98], dleq_proof_e);
|
||||
secp256k1_scalar_get_b32(&adaptor_sig162[130], dleq_proof_s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_ecdsa_adaptor_sig_deserialize(secp256k1_ge *r, secp256k1_scalar *sigr, secp256k1_ge *rp, secp256k1_scalar *sp, secp256k1_scalar *dleq_proof_e, secp256k1_scalar *dleq_proof_s, const unsigned char *adaptor_sig162) {
|
||||
|
|
@ -68,40 +69,28 @@ static int secp256k1_ecdsa_adaptor_sig_deserialize(secp256k1_ge *r, secp256k1_sc
|
|||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("ECDSAadaptor/non")||SHA256("ECDSAadaptor/non"). */
|
||||
static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x791dae43ul;
|
||||
sha->s[1] = 0xe52d3b44ul;
|
||||
sha->s[2] = 0x37f9edeaul;
|
||||
sha->s[3] = 0x9bfd2ab1ul;
|
||||
sha->s[4] = 0xcfb0f44dul;
|
||||
sha->s[5] = 0xccf1d880ul;
|
||||
sha->s[6] = 0xd18f2c13ul;
|
||||
sha->s[7] = 0xa37b9024ul;
|
||||
|
||||
sha->bytes = 64;
|
||||
static const uint32_t midstate[8] = {
|
||||
0x791dae43ul, 0xe52d3b44ul, 0x37f9edeaul, 0x9bfd2ab1ul,
|
||||
0xcfb0f44dul, 0xccf1d880ul, 0xd18f2c13ul, 0xa37b9024ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("ECDSAadaptor/aux")||SHA256("ECDSAadaptor/aux"). */
|
||||
static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0xd14c7bd9ul;
|
||||
sha->s[1] = 0x095d35e6ul;
|
||||
sha->s[2] = 0xb8490a88ul;
|
||||
sha->s[3] = 0xfb00ef74ul;
|
||||
sha->s[4] = 0x0baa488ful;
|
||||
sha->s[5] = 0x69366693ul;
|
||||
sha->s[6] = 0x1c81c5baul;
|
||||
sha->s[7] = 0xc33b296aul;
|
||||
|
||||
sha->bytes = 64;
|
||||
static const uint32_t midstate[8] = {
|
||||
0xd14c7bd9ul, 0x095d35e6ul, 0xb8490a88ul, 0xfb00ef74ul,
|
||||
0x0baa488ful, 0x69366693ul, 0x1c81c5baul, 0xc33b296aul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */
|
||||
static const unsigned char ecdsa_adaptor_algo[16] = "ECDSAadaptor/non";
|
||||
static const unsigned char ecdsa_adaptor_algo[] = {'E', 'C', 'D', 'S', 'A', 'a', 'd', 'a', 'p', 't', 'o', 'r', '/', 'n', 'o', 'n'};
|
||||
|
||||
/* Modified BIP-340 nonce function */
|
||||
static int nonce_function_ecdsa_adaptor(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *pk33, const unsigned char *algo, size_t algolen, void *data) {
|
||||
static int nonce_function_ecdsa_adaptor_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *pk33, const unsigned char *algo, size_t algolen, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char masked_key[32];
|
||||
int i;
|
||||
|
|
@ -112,8 +101,9 @@ static int nonce_function_ecdsa_adaptor(unsigned char *nonce32, const unsigned c
|
|||
|
||||
if (data != NULL) {
|
||||
secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux(&sha);
|
||||
secp256k1_sha256_write(&sha, data, 32);
|
||||
secp256k1_sha256_finalize(&sha, masked_key);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, data, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, masked_key);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
for (i = 0; i < 32; i++) {
|
||||
masked_key[i] ^= key32[i];
|
||||
}
|
||||
|
|
@ -129,28 +119,42 @@ static int nonce_function_ecdsa_adaptor(unsigned char *nonce32, const unsigned c
|
|||
&& secp256k1_memcmp_var(algo, dleq_algo, algolen) == 0) {
|
||||
secp256k1_nonce_function_dleq_sha256_tagged(&sha);
|
||||
} else {
|
||||
secp256k1_sha256_initialize_tagged(&sha, algo, algolen);
|
||||
secp256k1_sha256_initialize_tagged(hash_ctx, &sha, algo, algolen);
|
||||
}
|
||||
|
||||
/* Hash (masked-)key||pk||msg using the tagged hash as per BIP-340 */
|
||||
if (data != NULL) {
|
||||
secp256k1_sha256_write(&sha, masked_key, 32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, masked_key, 32);
|
||||
} else {
|
||||
secp256k1_sha256_write(&sha, key32, 32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, key32, 32);
|
||||
}
|
||||
secp256k1_sha256_write(&sha, pk33, 33);
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
secp256k1_sha256_finalize(&sha, nonce32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, pk33, 33);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, msg32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, nonce32);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nonce_function_ecdsa_adaptor(
|
||||
unsigned char *nonce32,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *key32,
|
||||
const unsigned char *pk33,
|
||||
const unsigned char *algo,
|
||||
size_t algolen,
|
||||
void *data)
|
||||
{
|
||||
return nonce_function_ecdsa_adaptor_impl(secp256k1_get_hash_context(secp256k1_context_static),nonce32, msg32, key32, pk33, algo, algolen, data);
|
||||
}
|
||||
|
||||
const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor = nonce_function_ecdsa_adaptor;
|
||||
|
||||
int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char *adaptor_sig162, unsigned char *seckey32, const secp256k1_pubkey *enckey, const unsigned char *msg32, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
|
||||
const secp256k1_hash_ctx *hash_ctx;
|
||||
secp256k1_scalar k;
|
||||
secp256k1_gej rj, rpj;
|
||||
secp256k1_ge r, rp;
|
||||
secp256k1_ge enckey_ge;
|
||||
secp256k1_ge r[2]; /* R, R' */
|
||||
secp256k1_gej rj[2]; /* R, R' */
|
||||
secp256k1_ge enckey_ge; /* Y */
|
||||
secp256k1_scalar dleq_proof_s;
|
||||
secp256k1_scalar dleq_proof_e;
|
||||
secp256k1_scalar sk;
|
||||
|
|
@ -160,7 +164,6 @@ int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char
|
|||
secp256k1_scalar n;
|
||||
unsigned char nonce32[32] = { 0 };
|
||||
unsigned char buf33[33];
|
||||
size_t size = 33;
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
|
|
@ -173,36 +176,46 @@ int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char
|
|||
secp256k1_scalar_clear(&dleq_proof_e);
|
||||
secp256k1_scalar_clear(&dleq_proof_s);
|
||||
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_ecdsa_adaptor;
|
||||
if (!secp256k1_pubkey_load(ctx, &enckey_ge, enckey)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
|
||||
secp256k1_eckey_pubkey_serialize33(&enckey_ge, buf33);
|
||||
if (noncefp == NULL || noncefp == secp256k1_nonce_function_ecdsa_adaptor) {
|
||||
ret &= nonce_function_ecdsa_adaptor_impl(hash_ctx, nonce32, msg32, seckey32, buf33, ecdsa_adaptor_algo, sizeof(ecdsa_adaptor_algo), ndata);
|
||||
} else {
|
||||
ret &= !!noncefp(nonce32, msg32, seckey32, buf33, ecdsa_adaptor_algo, sizeof(ecdsa_adaptor_algo), ndata);
|
||||
}
|
||||
|
||||
ret &= secp256k1_pubkey_load(ctx, &enckey_ge, enckey);
|
||||
ret &= secp256k1_eckey_pubkey_serialize(&enckey_ge, buf33, &size, 1);
|
||||
ret &= !!noncefp(nonce32, msg32, seckey32, buf33, ecdsa_adaptor_algo, sizeof(ecdsa_adaptor_algo), ndata);
|
||||
secp256k1_scalar_set_b32(&k, nonce32, NULL);
|
||||
ret &= !secp256k1_scalar_is_zero(&k);
|
||||
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
|
||||
|
||||
/* R := k*Y */
|
||||
secp256k1_ecmult_const(&rj[0], &enckey_ge, &k);
|
||||
/* R' := k*G */
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rpj, &k);
|
||||
secp256k1_ge_set_gej(&rp, &rpj);
|
||||
/* R = k*Y; */
|
||||
secp256k1_ecmult_const(&rj, &enckey_ge, &k);
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
/* We declassify the non-secret values rp and r to allow using them
|
||||
* as branch points. */
|
||||
secp256k1_declassify(ctx, &rp, sizeof(rp));
|
||||
secp256k1_declassify(ctx, &r, sizeof(r));
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj[1], &k);
|
||||
|
||||
secp256k1_ge_set_all_gej(r, rj, 2);
|
||||
|
||||
/* We declassify the non-secret nonce values to allow using them as branch points. */
|
||||
secp256k1_declassify(ctx, &r[0], sizeof(r[0]));
|
||||
secp256k1_declassify(ctx, &r[1], sizeof(r[1]));
|
||||
|
||||
/* dleq_proof = DLEQ_prove(k, (R', Y, R)) */
|
||||
ret &= secp256k1_dleq_prove(ctx, &dleq_proof_s, &dleq_proof_e, &k, &enckey_ge, &rp, &r, noncefp, ndata);
|
||||
|
||||
if (!secp256k1_dleq_prove(ctx, &dleq_proof_s, &dleq_proof_e, &k, &r[1], &enckey_ge, &r[0], noncefp, ndata)) {
|
||||
memset(adaptor_sig162, 0, 162);
|
||||
secp256k1_memclear_explicit(nonce32, sizeof(nonce32));
|
||||
secp256k1_scalar_clear(&k);
|
||||
return 0;
|
||||
}
|
||||
ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey32);
|
||||
secp256k1_scalar_cmov(&sk, &secp256k1_scalar_one, !ret);
|
||||
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||
secp256k1_fe_normalize(&r.x);
|
||||
secp256k1_fe_get_b32(buf33, &r.x);
|
||||
secp256k1_fe_normalize(&r[0].x);
|
||||
secp256k1_fe_get_b32(buf33, &r[0].x);
|
||||
secp256k1_scalar_set_b32(&sigr, buf33, NULL);
|
||||
ret &= !secp256k1_scalar_is_zero(&sigr);
|
||||
/* s' = k⁻¹(m + R.x * x) */
|
||||
|
|
@ -213,9 +226,10 @@ int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char
|
|||
ret &= !secp256k1_scalar_is_zero(&sp);
|
||||
|
||||
/* return (R, R', s', dleq_proof) */
|
||||
ret &= secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig162, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s);
|
||||
secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig162, &r[0], &r[1], &sp, &dleq_proof_e, &dleq_proof_s);
|
||||
|
||||
secp256k1_memczero(adaptor_sig162, 162, !ret);
|
||||
secp256k1_memclear_explicit(nonce32, sizeof(nonce32));
|
||||
secp256k1_scalar_clear(&n);
|
||||
secp256k1_scalar_clear(&k);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
|
|
@ -234,6 +248,7 @@ int secp256k1_ecdsa_adaptor_verify(const secp256k1_context* ctx, const unsigned
|
|||
secp256k1_gej derived_rp;
|
||||
secp256k1_scalar sn, u1, u2;
|
||||
secp256k1_gej pubkeyj;
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(adaptor_sig162 != NULL);
|
||||
|
|
@ -248,7 +263,7 @@ int secp256k1_ecdsa_adaptor_verify(const secp256k1_context* ctx, const unsigned
|
|||
return 0;
|
||||
}
|
||||
/* DLEQ_verify((R', Y, R), dleq_proof) */
|
||||
if(!secp256k1_dleq_verify(&dleq_proof_s, &dleq_proof_e, &rp, &enckey_ge, &r)) {
|
||||
if(!secp256k1_dleq_verify(hash_ctx, &dleq_proof_s, &dleq_proof_e, &rp, &enckey_ge, &r)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||
|
|
@ -309,10 +324,10 @@ int secp256k1_ecdsa_adaptor_recover(const secp256k1_context* ctx, unsigned char
|
|||
secp256k1_scalar s, r;
|
||||
secp256k1_scalar deckey;
|
||||
secp256k1_ge enckey_expected_ge;
|
||||
secp256k1_ge enckey_ge;
|
||||
secp256k1_gej enckey_expected_gej;
|
||||
unsigned char enckey33[33];
|
||||
unsigned char enckey_expected33[33];
|
||||
size_t size = 33;
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
|
|
@ -339,23 +354,21 @@ int secp256k1_ecdsa_adaptor_recover(const secp256k1_context* ctx, unsigned char
|
|||
/* We declassify non-secret enckey_expected_ge to allow using it as a
|
||||
* branch point. */
|
||||
secp256k1_declassify(ctx, &enckey_expected_ge, sizeof(enckey_expected_ge));
|
||||
if (!secp256k1_eckey_pubkey_serialize(&enckey_expected_ge, enckey_expected33, &size, SECP256K1_EC_COMPRESSED)) {
|
||||
/* Unreachable from tests (and other VERIFY builds) and therefore this
|
||||
* branch should be ignored in test coverage analysis.
|
||||
*
|
||||
* Proof:
|
||||
* eckey_pubkey_serialize fails <=> deckey = 0
|
||||
* deckey = 0 <=> s^-1 = 0 or sp = 0
|
||||
* case 1: s^-1 = 0 impossible by the definition of multiplicative
|
||||
* inverse and because the scalar_inverse implementation
|
||||
* VERIFY_CHECKs that the inputs are valid scalars.
|
||||
* case 2: sp = 0 impossible because ecdsa_adaptor_sig_deserialize would have already failed
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ec_pubkey_serialize(ctx, enckey33, &size, enckey, SECP256K1_EC_COMPRESSED)) {
|
||||
/* enckey_expected_ge cannot be infinity:
|
||||
*
|
||||
* Proof:
|
||||
* enckey_expected_ge is infinity <=> deckey = 0
|
||||
* deckey = 0 <=> s^-1 = 0 or sp = 0
|
||||
* case 1: s^-1 = 0 impossible by the definition of multiplicative
|
||||
* inverse and because the scalar_inverse implementation
|
||||
* VERIFY_CHECKs that the inputs are valid scalars.
|
||||
* case 2: sp = 0 impossible because ecdsa_adaptor_sig_deserialize would have already failed
|
||||
*/
|
||||
secp256k1_eckey_pubkey_serialize33(&enckey_expected_ge, enckey_expected33);
|
||||
if (!secp256k1_pubkey_load(ctx, &enckey_ge, enckey)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_eckey_pubkey_serialize33(&enckey_ge, enckey33);
|
||||
if (secp256k1_memcmp_var(&enckey_expected33[1], &enckey33[1], 32) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@
|
|||
#define SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H
|
||||
|
||||
#include "../../../include/secp256k1_ecdsa_adaptor.h"
|
||||
#include "../../unit_test.h"
|
||||
|
||||
static void rand_scalar(secp256k1_scalar *scalar) {
|
||||
unsigned char buf32[32];
|
||||
secp256k1_testrand256(buf32);
|
||||
testrand256(buf32);
|
||||
secp256k1_scalar_set_b32(scalar, buf32, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -19,17 +20,20 @@ static void rand_point(secp256k1_ge *point) {
|
|||
}
|
||||
|
||||
static void dleq_nonce_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) {
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
|
||||
secp256k1_scalar k1, k2;
|
||||
|
||||
CHECK(secp256k1_dleq_nonce(&k1, args[0], args[1], args[2], args[3], NULL, args[4]) == 1);
|
||||
secp256k1_testrand_flip(args[n_flip], n_bytes);
|
||||
CHECK(secp256k1_dleq_nonce(&k2, args[0], args[1], args[2], args[3], NULL, args[4]) == 1);
|
||||
CHECK(secp256k1_dleq_nonce(hash_ctx, &k1, args[0], args[1], args[2], args[3], NULL, args[4]) == 1);
|
||||
testrand_flip(args[n_flip], n_bytes);
|
||||
CHECK(secp256k1_dleq_nonce(hash_ctx, &k2, args[0], args[1], args[2], args[3], NULL, args[4]) == 1);
|
||||
CHECK(secp256k1_scalar_eq(&k1, &k2) == 0);
|
||||
}
|
||||
|
||||
static void dleq_tests(void) {
|
||||
static void dleq_tests_internal(void) {
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
|
||||
secp256k1_scalar s, e, sk, k;
|
||||
secp256k1_ge gen2, p1, p2;
|
||||
secp256k1_ge p[2];
|
||||
unsigned char *args[5];
|
||||
unsigned char sk32[32];
|
||||
unsigned char gen2_33[33];
|
||||
|
|
@ -37,47 +41,41 @@ static void dleq_tests(void) {
|
|||
unsigned char p2_33[33];
|
||||
unsigned char aux_rand[32];
|
||||
int i;
|
||||
size_t pubkey_size = 33;
|
||||
|
||||
rand_point(&gen2);
|
||||
rand_scalar(&sk);
|
||||
secp256k1_dleq_pair(&CTX->ecmult_gen_ctx, &p1, &p2, &sk, &gen2);
|
||||
CHECK(secp256k1_dleq_prove(CTX, &s, &e, &sk, &gen2, &p1, &p2, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_dleq_verify(&s, &e, &p1, &gen2, &p2) == 1);
|
||||
secp256k1_dleq_pair(&CTX->ecmult_gen_ctx, p, &sk, &gen2);
|
||||
p1 = p[0];
|
||||
p2 = p[1];
|
||||
CHECK(secp256k1_dleq_prove(CTX, &s, &e, &sk, &p1, &gen2, &p2, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_dleq_verify(hash_ctx, &s, &e, &p1, &gen2, &p2) == 1);
|
||||
|
||||
{
|
||||
secp256k1_scalar tmp;
|
||||
secp256k1_scalar_set_int(&tmp, 1);
|
||||
CHECK(secp256k1_dleq_verify(&tmp, &e, &p1, &gen2, &p2) == 0);
|
||||
CHECK(secp256k1_dleq_verify(&s, &tmp, &p1, &gen2, &p2) == 0);
|
||||
CHECK(secp256k1_dleq_verify(hash_ctx, &tmp, &e, &p1, &gen2, &p2) == 0);
|
||||
CHECK(secp256k1_dleq_verify(hash_ctx, &s, &tmp, &p1, &gen2, &p2) == 0);
|
||||
}
|
||||
{
|
||||
secp256k1_ge p_tmp;
|
||||
rand_point(&p_tmp);
|
||||
CHECK(secp256k1_dleq_verify(&s, &e, &p_tmp, &gen2, &p2) == 0);
|
||||
CHECK(secp256k1_dleq_verify(&s, &e, &p1, &p_tmp, &p2) == 0);
|
||||
CHECK(secp256k1_dleq_verify(&s, &e, &p1, &gen2, &p_tmp) == 0);
|
||||
}
|
||||
{
|
||||
secp256k1_ge p_inf;
|
||||
secp256k1_ge_set_infinity(&p_inf);
|
||||
CHECK(secp256k1_dleq_prove(CTX, &s, &e, &sk, &p_inf, &p1, &p2, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_dleq_prove(CTX, &s, &e, &sk, &gen2, &p_inf, &p2, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_dleq_prove(CTX, &s, &e, &sk, &gen2, &p1, &p_inf, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_dleq_verify(hash_ctx, &s, &e, &p_tmp, &gen2, &p2) == 0);
|
||||
CHECK(secp256k1_dleq_verify(hash_ctx, &s, &e, &p1, &p_tmp, &p2) == 0);
|
||||
CHECK(secp256k1_dleq_verify(hash_ctx, &s, &e, &p1, &gen2, &p_tmp) == 0);
|
||||
}
|
||||
|
||||
/* Nonce tests */
|
||||
secp256k1_scalar_get_b32(sk32, &sk);
|
||||
CHECK(secp256k1_eckey_pubkey_serialize(&gen2, gen2_33, &pubkey_size, 1));
|
||||
CHECK(secp256k1_eckey_pubkey_serialize(&p1, p1_33, &pubkey_size, 1));
|
||||
CHECK(secp256k1_eckey_pubkey_serialize(&p2, p2_33, &pubkey_size, 1));
|
||||
CHECK(secp256k1_dleq_nonce(&k, sk32, gen2_33, p1_33, p2_33, NULL, NULL) == 1);
|
||||
secp256k1_eckey_pubkey_serialize33(&gen2, gen2_33);
|
||||
secp256k1_eckey_pubkey_serialize33(&p1, p1_33);
|
||||
secp256k1_eckey_pubkey_serialize33(&p2, p2_33);
|
||||
CHECK(secp256k1_dleq_nonce(hash_ctx, &k, sk32, gen2_33, p1_33, p2_33, NULL, NULL) == 1);
|
||||
|
||||
secp256k1_testrand_bytes_test(sk32, sizeof(sk32));
|
||||
secp256k1_testrand_bytes_test(gen2_33, sizeof(gen2_33));
|
||||
secp256k1_testrand_bytes_test(p1_33, sizeof(p1_33));
|
||||
secp256k1_testrand_bytes_test(p2_33, sizeof(p2_33));
|
||||
secp256k1_testrand_bytes_test(aux_rand, sizeof(aux_rand));
|
||||
testrand_bytes_test(sk32, sizeof(sk32));
|
||||
testrand_bytes_test(gen2_33, sizeof(gen2_33));
|
||||
testrand_bytes_test(p1_33, sizeof(p1_33));
|
||||
testrand_bytes_test(p2_33, sizeof(p2_33));
|
||||
testrand_bytes_test(aux_rand, sizeof(aux_rand));
|
||||
|
||||
/* Check that a bitflip in an argument results in different nonces. */
|
||||
args[0] = sk32;
|
||||
|
|
@ -97,11 +95,11 @@ static void dleq_tests(void) {
|
|||
}
|
||||
|
||||
/* NULL aux_rand argument is allowed. */
|
||||
CHECK(secp256k1_dleq_nonce(&k, sk32, gen2_33, p1_33, p2_33, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_dleq_nonce(hash_ctx, &k, sk32, gen2_33, p1_33, p2_33, NULL, NULL) == 1);
|
||||
}
|
||||
|
||||
static void rand_flip_bit(unsigned char *array, size_t n) {
|
||||
array[secp256k1_testrand_int(n)] ^= 1 << secp256k1_testrand_int(8);
|
||||
array[testrand_int(n)] ^= 1 << testrand_int(8);
|
||||
}
|
||||
|
||||
/* Helper function for test_ecdsa_adaptor_spec_vectors
|
||||
|
|
@ -161,7 +159,7 @@ static void test_ecdsa_adaptor_spec_vectors_check_serialization(const unsigned c
|
|||
|
||||
CHECK(expected == secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig162));
|
||||
if (expected == 1) {
|
||||
CHECK(secp256k1_ecdsa_adaptor_sig_serialize(buf, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s) == 1);
|
||||
secp256k1_ecdsa_adaptor_sig_serialize(buf, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s);
|
||||
CHECK(secp256k1_memcmp_var(buf, adaptor_sig162, 162) == 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -713,29 +711,18 @@ static int ecdsa_adaptor_nonce_function_overflowing(unsigned char *nonce32, cons
|
|||
static void nonce_function_ecdsa_adaptor_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t algolen) {
|
||||
unsigned char nonces[2][32];
|
||||
CHECK(nonce_function_ecdsa_adaptor(nonces[0], args[0], args[1], args[2], args[3], algolen, args[4]) == 1);
|
||||
secp256k1_testrand_flip(args[n_flip], n_bytes);
|
||||
testrand_flip(args[n_flip], n_bytes);
|
||||
CHECK(nonce_function_ecdsa_adaptor(nonces[1], args[0], args[1], args[2], args[3], algolen, args[4]) == 1);
|
||||
CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0);
|
||||
}
|
||||
|
||||
/* Tests for the equality of two sha256 structs. This function only produces a
|
||||
* correct result if an integer multiple of 64 many bytes have been written
|
||||
* into the hash functions. */
|
||||
static void ecdsa_adaptor_test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) {
|
||||
/* Is buffer fully consumed? */
|
||||
CHECK((sha1->bytes & 0x3F) == 0);
|
||||
|
||||
CHECK(sha1->bytes == sha2->bytes);
|
||||
CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
|
||||
}
|
||||
|
||||
static void run_nonce_function_ecdsa_adaptor_tests(void) {
|
||||
unsigned char tag[16] = "ECDSAadaptor/non";
|
||||
unsigned char aux_tag[16] = "ECDSAadaptor/aux";
|
||||
unsigned char algo[16] = "ECDSAadaptor/non";
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
|
||||
static const unsigned char tag[] = {'E', 'C', 'D', 'S', 'A', 'a', 'd', 'a', 'p', 't', 'o', 'r', '/', 'n', 'o', 'n'};
|
||||
static const unsigned char aux_tag[] = {'E', 'C', 'D', 'S', 'A', 'a', 'd', 'a', 'p', 't', 'o', 'r', '/', 'a', 'u', 'x'};
|
||||
unsigned char algo[] = {'E', 'C', 'D', 'S', 'A', 'a', 'd', 'a', 'p', 't', 'o', 'r', '/', 'n', 'o', 'n'};
|
||||
size_t algolen = sizeof(algo);
|
||||
unsigned char dleq_tag[4] = "DLEQ";
|
||||
secp256k1_sha256 sha;
|
||||
static const unsigned char dleq_tag[] = {'D', 'L', 'E', 'Q'};
|
||||
secp256k1_sha256 sha_optimized;
|
||||
unsigned char nonce[32];
|
||||
unsigned char msg[32];
|
||||
|
|
@ -748,28 +735,25 @@ static void run_nonce_function_ecdsa_adaptor_tests(void) {
|
|||
/* Check that hash initialized by
|
||||
* secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, tag, sizeof(tag));
|
||||
secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(&sha_optimized);
|
||||
ecdsa_adaptor_test_sha256_eq(&sha, &sha_optimized);
|
||||
test_sha256_tag_midstate(hash_ctx, &sha_optimized, tag, sizeof(tag));
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag));
|
||||
secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux(&sha_optimized);
|
||||
ecdsa_adaptor_test_sha256_eq(&sha, &sha_optimized);
|
||||
test_sha256_tag_midstate(hash_ctx, &sha_optimized, aux_tag, sizeof(aux_tag));
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_nonce_function_dleq_sha256_tagged_aux has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, dleq_tag, sizeof(dleq_tag));
|
||||
secp256k1_nonce_function_dleq_sha256_tagged(&sha_optimized);
|
||||
ecdsa_adaptor_test_sha256_eq(&sha, &sha_optimized);
|
||||
test_sha256_tag_midstate(hash_ctx, &sha_optimized, dleq_tag, sizeof(dleq_tag));
|
||||
|
||||
secp256k1_testrand_bytes_test(msg, sizeof(msg));
|
||||
secp256k1_testrand_bytes_test(key, sizeof(key));
|
||||
secp256k1_testrand_bytes_test(pk, sizeof(pk));
|
||||
secp256k1_testrand_bytes_test(aux_rand, sizeof(aux_rand));
|
||||
testrand_bytes_test(msg, sizeof(msg));
|
||||
testrand_bytes_test(key, sizeof(key));
|
||||
testrand_bytes_test(pk, sizeof(pk));
|
||||
testrand_bytes_test(aux_rand, sizeof(aux_rand));
|
||||
|
||||
/* Check that a bitflip in an argument results in different nonces. */
|
||||
args[0] = msg;
|
||||
|
|
@ -802,7 +786,7 @@ static void run_nonce_function_ecdsa_adaptor_tests(void) {
|
|||
/* Different algolen gives different nonce */
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
unsigned char nonce2[32];
|
||||
uint32_t offset = secp256k1_testrand_int(algolen - 1);
|
||||
uint32_t offset = testrand_int(algolen - 1);
|
||||
size_t algolen_tmp = (algolen + offset) % algolen;
|
||||
|
||||
CHECK(nonce_function_ecdsa_adaptor(nonce2, msg, key, pk, algo, algolen_tmp, NULL) == 1);
|
||||
|
|
@ -822,11 +806,12 @@ static void test_ecdsa_adaptor_api(void) {
|
|||
unsigned char msg[32];
|
||||
unsigned char asig[162];
|
||||
unsigned char deckey[32];
|
||||
unsigned char zeros162[162] = { 0 };
|
||||
|
||||
/** setup **/
|
||||
secp256k1_testrand256(sk);
|
||||
secp256k1_testrand256(msg);
|
||||
secp256k1_testrand256(deckey);
|
||||
testrand256(sk);
|
||||
testrand256(msg);
|
||||
testrand256(deckey);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, sk) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &enckey, deckey) == 1);
|
||||
memset(&zero_pk, 0, sizeof(zero_pk));
|
||||
|
|
@ -840,6 +825,14 @@ static void test_ecdsa_adaptor_api(void) {
|
|||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, NULL, msg, NULL, NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, &zero_pk, msg, NULL, NULL));
|
||||
|
||||
/* Test bad nonce functions */
|
||||
memset(asig, 1, sizeof(asig));
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, &enckey, msg, ecdsa_adaptor_nonce_function_failing, NULL) == 0);
|
||||
CHECK(secp256k1_memcmp_var(asig, zeros162, sizeof(asig)) == 0);
|
||||
memset(asig, 1, sizeof(asig));
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, &enckey, msg, ecdsa_adaptor_nonce_function_0, NULL) == 0);
|
||||
CHECK(secp256k1_memcmp_var(asig, zeros162, sizeof(asig)) == 0);
|
||||
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, asig, sk, &enckey, msg, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_ecdsa_adaptor_verify(CTX, asig, &pubkey, msg, &enckey) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_verify(CTX, NULL, &pubkey, msg, &enckey));
|
||||
|
|
@ -865,7 +858,7 @@ static void test_ecdsa_adaptor_api(void) {
|
|||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_adaptor_recover(CTX, deckey, &sig, asig, &zero_pk));
|
||||
}
|
||||
|
||||
static void adaptor_tests(void) {
|
||||
static void adaptor_tests_internal_impl(secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void* ndata) {
|
||||
unsigned char seckey[32];
|
||||
secp256k1_pubkey pubkey;
|
||||
unsigned char msg[32];
|
||||
|
|
@ -877,29 +870,21 @@ static void adaptor_tests(void) {
|
|||
unsigned char zeros64[64] = { 0 };
|
||||
unsigned char big[32];
|
||||
|
||||
secp256k1_testrand256(seckey);
|
||||
secp256k1_testrand256(msg);
|
||||
secp256k1_testrand256(deckey);
|
||||
testrand256(seckey);
|
||||
testrand256(msg);
|
||||
testrand256(deckey);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, seckey) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &enckey, deckey) == 1);
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, adaptor_sig, seckey, &enckey, msg, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, adaptor_sig, seckey, &enckey, msg, noncefp, ndata) == 1);
|
||||
|
||||
{
|
||||
unsigned char adaptor_sig_tmp[162] = { 0 };
|
||||
|
||||
/* Test overflowing seckey */
|
||||
memset(big, 0xFF, 32);
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, adaptor_sig, big, &enckey, msg, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) == 0);
|
||||
|
||||
/* Test different nonce functions */
|
||||
memset(adaptor_sig, 1, sizeof(adaptor_sig));
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, adaptor_sig, seckey, &enckey, msg, ecdsa_adaptor_nonce_function_failing, NULL) == 0);
|
||||
CHECK(secp256k1_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) == 0);
|
||||
memset(&adaptor_sig, 1, sizeof(adaptor_sig));
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, adaptor_sig, seckey, &enckey, msg, ecdsa_adaptor_nonce_function_0, NULL) == 0);
|
||||
CHECK(secp256k1_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) == 0);
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, adaptor_sig, seckey, &enckey, msg, ecdsa_adaptor_nonce_function_overflowing, NULL) == 1);
|
||||
CHECK(secp256k1_memcmp_var(adaptor_sig, zeros162, sizeof(adaptor_sig)) != 0);
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, adaptor_sig_tmp, big, &enckey, msg, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_memcmp_var(adaptor_sig_tmp, zeros162, sizeof(adaptor_sig)) == 0);
|
||||
}
|
||||
{
|
||||
/* Test adaptor_sig_serialize roundtrip */
|
||||
|
|
@ -907,18 +892,12 @@ static void adaptor_tests(void) {
|
|||
secp256k1_scalar sigr;
|
||||
secp256k1_scalar sp;
|
||||
secp256k1_scalar dleq_proof_s, dleq_proof_e;
|
||||
secp256k1_ge p_inf;
|
||||
unsigned char adaptor_sig_tmp[162];
|
||||
|
||||
CHECK(secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig) == 1);
|
||||
|
||||
CHECK(secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s) == 1);
|
||||
secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s);
|
||||
CHECK(secp256k1_memcmp_var(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig_tmp)) == 0);
|
||||
|
||||
/* Test adaptor_sig_serialize points at infinity */
|
||||
secp256k1_ge_set_infinity(&p_inf);
|
||||
CHECK(secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &p_inf, &rp, &sp, &dleq_proof_e, &dleq_proof_s) == 0);
|
||||
CHECK(secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig_tmp, &r, &p_inf, &sp, &dleq_proof_e, &dleq_proof_s) == 0);
|
||||
}
|
||||
{
|
||||
/* Test adaptor_sig_deserialize */
|
||||
|
|
@ -1065,7 +1044,17 @@ static void adaptor_tests(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void multi_hop_lock_tests(void) {
|
||||
static void adaptor_tests_internal(void) {
|
||||
adaptor_tests_internal_impl(NULL, NULL);
|
||||
/* Since the same nonce function with different algo arguments is used
|
||||
* both for the adaptor sig secret nonce and the dleq secret nonce,
|
||||
* but ecdsa_adaptor_nonce_function_overflowing ignores the algo arg
|
||||
* (in violation of the documented API contract), the resulting secret
|
||||
* nonces will be the same. */
|
||||
adaptor_tests_internal_impl(ecdsa_adaptor_nonce_function_overflowing, NULL);
|
||||
}
|
||||
|
||||
static void multi_hop_lock_tests_internal(void) {
|
||||
unsigned char seckey_a[32];
|
||||
unsigned char seckey_b[32];
|
||||
unsigned char pop[32];
|
||||
|
|
@ -1082,19 +1071,19 @@ static void multi_hop_lock_tests(void) {
|
|||
secp256k1_scalar deckey;
|
||||
secp256k1_ecdsa_signature sig_ab, sig_bc;
|
||||
|
||||
secp256k1_testrand256(seckey_a);
|
||||
secp256k1_testrand256(seckey_b);
|
||||
testrand256(seckey_a);
|
||||
testrand256(seckey_b);
|
||||
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey_a, seckey_a));
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey_b, seckey_b));
|
||||
|
||||
/* Carol setup */
|
||||
/* Proof of payment */
|
||||
secp256k1_testrand256(pop);
|
||||
testrand256(pop);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey_pop, pop));
|
||||
|
||||
/* Alice setup */
|
||||
secp256k1_testrand256(tx_ab);
|
||||
testrand256(tx_ab);
|
||||
rand_scalar(&t1);
|
||||
rand_scalar(&t2);
|
||||
secp256k1_scalar_add(&tp, &t1, &t2);
|
||||
|
|
@ -1110,7 +1099,7 @@ static void multi_hop_lock_tests(void) {
|
|||
|
||||
/* Bob setup */
|
||||
CHECK(secp256k1_ecdsa_adaptor_verify(CTX, asig_ab, &pubkey_a, tx_ab, &l));
|
||||
secp256k1_testrand256(tx_bc);
|
||||
testrand256(tx_bc);
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, asig_bc, seckey_b, &r, tx_bc, NULL, NULL));
|
||||
|
||||
/* Carol decrypt */
|
||||
|
|
@ -1139,21 +1128,75 @@ static void multi_hop_lock_tests(void) {
|
|||
CHECK(secp256k1_memcmp_var(buf, pop, 32) == 0);
|
||||
}
|
||||
|
||||
static void run_ecdsa_adaptor_tests(void) {
|
||||
int i;
|
||||
run_nonce_function_ecdsa_adaptor_tests();
|
||||
static void adaptor_test_issue335(void) {
|
||||
/* Inputs that will trigger R1==infinity in secp256k1_dleq_verify. */
|
||||
unsigned char adaptor_sig[162] = {
|
||||
0x03, 0x63, 0x3D, 0x56, 0xAB, 0xEE, 0x6F, 0x36, 0xE6, 0x07, 0xC6, 0x04,
|
||||
0x2C, 0x68, 0xB4, 0x09, 0xBE, 0x4F, 0x3D, 0x56, 0x3A, 0x51, 0x7B, 0xCA,
|
||||
0x95, 0xE6, 0xD9, 0x48, 0x1E, 0x95, 0xD0, 0xD6, 0xC6, 0x03, 0x91, 0x66,
|
||||
0xC2, 0x89, 0xB9, 0xF9, 0x05, 0xE5, 0x5F, 0x9E, 0x3D, 0xF9, 0xF6, 0x9D,
|
||||
0x7F, 0x35, 0x6B, 0x4A, 0x22, 0x09, 0x5F, 0x89, 0x4F, 0x47, 0x15, 0x71,
|
||||
0x4A, 0xA4, 0xB5, 0x66, 0x06, 0xAF, 0x84, 0x40, 0xB2, 0x83, 0x34, 0xF6,
|
||||
0x74, 0x18, 0xD8, 0x3D, 0x5C, 0xDC, 0x14, 0x0A, 0xAB, 0x22, 0x2B, 0x19,
|
||||
0x15, 0x13, 0xC3, 0x5D, 0x9C, 0xBC, 0x6D, 0x89, 0x1C, 0xB5, 0x38, 0x74,
|
||||
0xB0, 0xCE, 0x5F, 0x34, 0xD7, 0xA0, 0xA9, 0x89, 0x7A, 0x19, 0x45, 0x77,
|
||||
0xBD, 0x5F, 0x0F, 0x31, 0xD8, 0x3B, 0x50, 0xC6, 0x2A, 0x4D, 0xCF, 0x4D,
|
||||
0xCB, 0x91, 0x71, 0x8C, 0x66, 0xAE, 0xB8, 0xE2, 0x1A, 0x01, 0x65, 0x05,
|
||||
0x2D, 0x93, 0x73, 0x97, 0xB7, 0x66, 0xC4, 0xEB, 0x23, 0x8D, 0x3B, 0x55,
|
||||
0xA2, 0x3D, 0xF8, 0x8E, 0x56, 0x84, 0x87, 0x10, 0x76, 0x18, 0xC2, 0xE8,
|
||||
0x35, 0xF9, 0x4E, 0x2A, 0x29, 0xB2
|
||||
};
|
||||
unsigned char msg[32] = {
|
||||
0x38, 0x9C, 0x43, 0x7B, 0x37, 0xBB, 0x6F, 0x74, 0x09, 0x3D, 0x69,
|
||||
0x3E, 0x3D, 0x9B, 0x4F, 0xC7, 0x9D, 0xDF, 0xA9, 0x33, 0x39, 0x8C,
|
||||
0x90, 0x03, 0x95, 0x2D, 0x67, 0xCD, 0xD9, 0x99, 0xDC, 0x55
|
||||
};
|
||||
unsigned char deckey[32] = {
|
||||
0x4A, 0x0B, 0x45, 0xA7, 0x4F, 0xBF, 0x49, 0xC3, 0x4B, 0x7C, 0xE0,
|
||||
0x8E, 0x34, 0x89, 0xFB, 0xEA, 0xD5, 0x41, 0xA1, 0x2E, 0xBE, 0x13,
|
||||
0x3F, 0xD6, 0x8E, 0x24, 0x86, 0x60, 0x1B, 0x19, 0xC1, 0xB5
|
||||
};
|
||||
unsigned char seckey[32] = {
|
||||
0x12, 0xDB, 0x27, 0x33, 0x51, 0x3D, 0xD9, 0xDF, 0x6A, 0x3C, 0x5A,
|
||||
0xEC, 0x3C, 0xA9, 0xF5, 0xDA, 0xA7, 0x3E, 0xB4, 0x61, 0xC8, 0xBB,
|
||||
0x12, 0xB7, 0xD4, 0xAA, 0xF5, 0x9A, 0xE9, 0xE5, 0x8B, 0xB7
|
||||
};
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_pubkey enckey;
|
||||
|
||||
test_ecdsa_adaptor_api();
|
||||
test_ecdsa_adaptor_spec_vectors();
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
dleq_tests();
|
||||
}
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
adaptor_tests();
|
||||
}
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
multi_hop_lock_tests();
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, seckey) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &enckey, deckey) == 1);
|
||||
CHECK(secp256k1_ecdsa_adaptor_verify(CTX, adaptor_sig, &pubkey, msg, &enckey) == 0);
|
||||
|
||||
/* This explains how the inputs were obtained. */
|
||||
{
|
||||
unsigned char adaptor_sig_tmp[sizeof(adaptor_sig)];
|
||||
/* Since the same nonce function with different algo arguments is used
|
||||
* both for the adaptor sig secret nonce and the dleq secret nonce,
|
||||
* but ecdsa_adaptor_nonce_function_overflowing ignores the algo arg
|
||||
* (in violation of the documented API contract), the resulting secret
|
||||
* nonces will be the same. */
|
||||
CHECK(secp256k1_ecdsa_adaptor_encrypt(CTX, adaptor_sig_tmp, seckey, &enckey, msg, ecdsa_adaptor_nonce_function_overflowing, NULL) == 1);
|
||||
CHECK(secp256k1_ecdsa_adaptor_verify(CTX, adaptor_sig_tmp, &pubkey, msg, &enckey) == 1);
|
||||
/* Increment the last least significant bit of e. */
|
||||
adaptor_sig_tmp[129] = 0x01;
|
||||
CHECK(secp256k1_memcmp_var(adaptor_sig_tmp, adaptor_sig, sizeof(adaptor_sig)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Test registry --- */
|
||||
REPEAT_TEST(dleq_tests)
|
||||
REPEAT_TEST(adaptor_tests)
|
||||
REPEAT_TEST(multi_hop_lock_tests)
|
||||
|
||||
static const struct tf_test_entry tests_ecdsa_adaptor[] = {
|
||||
CASE1(run_nonce_function_ecdsa_adaptor_tests),
|
||||
CASE1(test_ecdsa_adaptor_api),
|
||||
CASE1(test_ecdsa_adaptor_spec_vectors),
|
||||
CASE1(dleq_tests),
|
||||
CASE1(adaptor_tests),
|
||||
CASE1(multi_hop_lock_tests),
|
||||
CASE1(adaptor_test_issue335),
|
||||
};
|
||||
|
||||
#endif /* SECP256K1_MODULE_ECDSA_ADAPTOR_TESTS_H */
|
||||
|
|
|
|||
|
|
@ -36,37 +36,26 @@ int secp256k1_ecdsa_s2c_opening_serialize(const secp256k1_context* ctx, unsigned
|
|||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("s2c/ecdsa/point")||SHA256("s2c/ecdsa/point"). */
|
||||
static void secp256k1_s2c_ecdsa_point_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0xa9b21c7bul;
|
||||
sha->s[1] = 0x358c3e3eul;
|
||||
sha->s[2] = 0x0b6863d1ul;
|
||||
sha->s[3] = 0xc62b2035ul;
|
||||
sha->s[4] = 0xb44b40ceul;
|
||||
sha->s[5] = 0x254a8912ul;
|
||||
sha->s[6] = 0x0f85d0d4ul;
|
||||
sha->s[7] = 0x8a5bf91cul;
|
||||
|
||||
sha->bytes = 64;
|
||||
static const uint32_t midstate[8] = {
|
||||
0xa9b21c7bul, 0x358c3e3eul, 0x0b6863d1ul, 0xc62b2035ul,
|
||||
0xb44b40ceul, 0x254a8912ul, 0x0f85d0d4ul, 0x8a5bf91cul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("s2c/ecdsa/data")||SHA256("s2c/ecdsa/data"). */
|
||||
static void secp256k1_s2c_ecdsa_data_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0xfeefd675ul;
|
||||
sha->s[1] = 0x73166c99ul;
|
||||
sha->s[2] = 0xe2309cb8ul;
|
||||
sha->s[3] = 0x6d458113ul;
|
||||
sha->s[4] = 0x01d3a512ul;
|
||||
sha->s[5] = 0x00e18112ul;
|
||||
sha->s[6] = 0x37ee0874ul;
|
||||
sha->s[7] = 0x421fc55ful;
|
||||
|
||||
sha->bytes = 64;
|
||||
static const uint32_t midstate[8] = {
|
||||
0xfeefd675ul, 0x73166c99ul, 0xe2309cb8ul, 0x6d458113ul,
|
||||
0x01d3a512ul, 0x00e18112ul, 0x37ee0874ul, 0x421fc55ful
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(sha, 64, midstate);
|
||||
}
|
||||
|
||||
int secp256k1_ecdsa_s2c_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature* signature, secp256k1_ecdsa_s2c_opening* s2c_opening, const unsigned char
|
||||
*msg32, const unsigned char *seckey, const unsigned char* s2c_data32) {
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
secp256k1_scalar r, s;
|
||||
int ret;
|
||||
unsigned char ndata[32];
|
||||
|
|
@ -84,8 +73,9 @@ int secp256k1_ecdsa_s2c_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signa
|
|||
* to derive nonces even if only a SHA256 commitment to the data is
|
||||
* known. This is important in the ECDSA anti-exfil protocol. */
|
||||
secp256k1_s2c_ecdsa_data_sha256_tagged(&s2c_sha);
|
||||
secp256k1_sha256_write(&s2c_sha, s2c_data32, 32);
|
||||
secp256k1_sha256_finalize(&s2c_sha, ndata);
|
||||
secp256k1_sha256_write(hash_ctx, &s2c_sha, s2c_data32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &s2c_sha, ndata);
|
||||
secp256k1_sha256_clear(&s2c_sha);
|
||||
|
||||
secp256k1_s2c_ecdsa_point_sha256_tagged(&s2c_sha);
|
||||
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, &s2c_sha, s2c_opening, s2c_data32, msg32, seckey, NULL, ndata);
|
||||
|
|
@ -96,6 +86,7 @@ int secp256k1_ecdsa_s2c_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signa
|
|||
}
|
||||
|
||||
int secp256k1_ecdsa_s2c_verify_commit(const secp256k1_context* ctx, const secp256k1_ecdsa_signature* sig, const unsigned char* data32, const secp256k1_ecdsa_s2c_opening* opening) {
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
secp256k1_ge commitment_ge;
|
||||
secp256k1_ge original_pubnonce_ge;
|
||||
unsigned char x_bytes[32];
|
||||
|
|
@ -111,7 +102,7 @@ int secp256k1_ecdsa_s2c_verify_commit(const secp256k1_context* ctx, const secp25
|
|||
return 0;
|
||||
}
|
||||
secp256k1_s2c_ecdsa_point_sha256_tagged(&s2c_sha);
|
||||
if (!secp256k1_ec_commit(&commitment_ge, &original_pubnonce_ge, &s2c_sha, data32, 32)) {
|
||||
if (!secp256k1_ec_commit(hash_ctx, &commitment_ge, &original_pubnonce_ge, &s2c_sha, data32, 32)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -139,14 +130,16 @@ int secp256k1_ecdsa_s2c_verify_commit(const secp256k1_context* ctx, const secp25
|
|||
/*** anti-exfil ***/
|
||||
int secp256k1_ecdsa_anti_exfil_host_commit(const secp256k1_context* ctx, unsigned char* rand_commitment32, const unsigned char* rand32) {
|
||||
secp256k1_sha256 sha;
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(rand_commitment32 != NULL);
|
||||
ARG_CHECK(rand32 != NULL);
|
||||
|
||||
secp256k1_s2c_ecdsa_data_sha256_tagged(&sha);
|
||||
secp256k1_sha256_write(&sha, rand32, 32);
|
||||
secp256k1_sha256_finalize(&sha, rand_commitment32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, rand32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, rand_commitment32);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +173,7 @@ int secp256k1_ecdsa_anti_exfil_signer_commit(const secp256k1_context* ctx, secp2
|
|||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k);
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
secp256k1_ecdsa_s2c_opening_save(opening, &r);
|
||||
memset(nonce32, 0, 32);
|
||||
secp256k1_memclear_explicit(nonce32, 32);
|
||||
secp256k1_scalar_clear(&k);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,25 +8,27 @@
|
|||
#define SECP256K1_MODULE_ECDSA_S2C_TESTS_H
|
||||
|
||||
#include "../../../include/secp256k1_ecdsa_s2c.h"
|
||||
#include "../../unit_test.h"
|
||||
|
||||
static void test_ecdsa_s2c_tagged_hash(void) {
|
||||
unsigned char tag_data[14] = "s2c/ecdsa/data";
|
||||
unsigned char tag_point[15] = "s2c/ecdsa/point";
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
|
||||
unsigned char tag_data[] = {'s', '2', 'c', '/', 'e', 'c', 'd', 's', 'a', '/', 'd', 'a', 't', 'a'};
|
||||
unsigned char tag_point[] = {'s', '2', 'c', '/', 'e', 'c', 'd', 's', 'a', '/', 'p', 'o', 'i', 'n', 't'};
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256 sha_optimized;
|
||||
unsigned char output[32];
|
||||
unsigned char output_optimized[32];
|
||||
|
||||
secp256k1_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data));
|
||||
secp256k1_sha256_initialize_tagged(hash_ctx, &sha, tag_data, sizeof(tag_data));
|
||||
secp256k1_s2c_ecdsa_data_sha256_tagged(&sha_optimized);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
secp256k1_sha256_finalize(&sha_optimized, output_optimized);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, output);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha_optimized, output_optimized);
|
||||
CHECK(secp256k1_memcmp_var(output, output_optimized, 32) == 0);
|
||||
|
||||
secp256k1_sha256_initialize_tagged(&sha, tag_point, sizeof(tag_point));
|
||||
secp256k1_sha256_initialize_tagged(hash_ctx, &sha, tag_point, sizeof(tag_point));
|
||||
secp256k1_s2c_ecdsa_point_sha256_tagged(&sha_optimized);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
secp256k1_sha256_finalize(&sha_optimized, output_optimized);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, output);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha_optimized, output_optimized);
|
||||
CHECK(secp256k1_memcmp_var(output, output_optimized, 32) == 0);
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +71,7 @@ static void run_s2c_opening_test(void) {
|
|||
CHECK(secp256k1_ecdsa_s2c_opening_serialize(CTX, output, &opening) == 1);
|
||||
CHECK(secp256k1_memcmp_var(output, input, sizeof(output)) == 0);
|
||||
}
|
||||
secp256k1_testrand256(&input[1]);
|
||||
testrand256(&input[1]);
|
||||
/* Set pubkey oddness tag to first bit of input[1] */
|
||||
input[0] = (input[1] & 1) + 2;
|
||||
}
|
||||
|
|
@ -78,10 +80,10 @@ static void run_s2c_opening_test(void) {
|
|||
static void test_ecdsa_s2c_api(void) {
|
||||
secp256k1_ecdsa_s2c_opening s2c_opening;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
const unsigned char msg[32] = "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm";
|
||||
const unsigned char sec[32] = "ssssssssssssssssssssssssssssssss";
|
||||
const unsigned char s2c_data[32] = "dddddddddddddddddddddddddddddddd";
|
||||
const unsigned char hostrand[32] = "hrhrhrhrhrhrhrhrhrhrhrhrhrhrhrhr";
|
||||
const unsigned char msg[] = {'m', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm', 'm'};
|
||||
const unsigned char sec[] = {'s', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's', 's'};
|
||||
const unsigned char s2c_data[] = {'d', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd'};
|
||||
const unsigned char hostrand[] = {'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r', 'h', 'r'};
|
||||
unsigned char hostrand_commitment[32];
|
||||
secp256k1_pubkey pk;
|
||||
|
||||
|
|
@ -148,14 +150,14 @@ typedef struct {
|
|||
|
||||
static ecdsa_s2c_test ecdsa_s2c_tests[] = {
|
||||
{
|
||||
"\x1b\xf6\xfb\x42\xf4\x1e\xb8\x76\xc4\xd7\xaa\x0d\x67\x24\x2b\x00\xba\xab\x99\xdc\x20\x84\x49\x3e\x4e\x63\x27\x7f\xa1\xf7\x7f\x22",
|
||||
"\x03\xf0\x30\xde\xf3\x18\x8c\x0f\x56\xfc\xea\x87\x43\x5b\x30\x76\x43\xf4\x5d\xaf\xe2\x2c\xbc\x82\xfd\x56\x03\x4f\xae\x97\x41\x7d\x3a",
|
||||
"\x02\xdf\x63\x75\x5d\x1f\x32\x92\xbf\xfe\xd8\x29\x86\xb1\x06\x49\x7c\x93\xb1\xf8\xbd\xc0\x45\x4b\x6b\x0b\x0a\x47\x79\xc0\xef\x71\x88",
|
||||
{0x1b, 0xf6, 0xfb, 0x42, 0xf4, 0x1e, 0xb8, 0x76, 0xc4, 0xd7, 0xaa, 0x0d, 0x67, 0x24, 0x2b, 0x00, 0xba, 0xab, 0x99, 0xdc, 0x20, 0x84, 0x49, 0x3e, 0x4e, 0x63, 0x27, 0x7f, 0xa1, 0xf7, 0x7f, 0x22},
|
||||
{0x03, 0xf0, 0x30, 0xde, 0xf3, 0x18, 0x8c, 0x0f, 0x56, 0xfc, 0xea, 0x87, 0x43, 0x5b, 0x30, 0x76, 0x43, 0xf4, 0x5d, 0xaf, 0xe2, 0x2c, 0xbc, 0x82, 0xfd, 0x56, 0x03, 0x4f, 0xae, 0x97, 0x41, 0x7d, 0x3a},
|
||||
{0x02, 0xdf, 0x63, 0x75, 0x5d, 0x1f, 0x32, 0x92, 0xbf, 0xfe, 0xd8, 0x29, 0x86, 0xb1, 0x06, 0x49, 0x7c, 0x93, 0xb1, 0xf8, 0xbd, 0xc0, 0x45, 0x4b, 0x6b, 0x0b, 0x0a, 0x47, 0x79, 0xc0, 0xef, 0x71, 0x88},
|
||||
},
|
||||
{
|
||||
"\x35\x19\x9a\x8f\xbf\x84\xad\x6e\xf6\x9a\x18\x4c\x1b\x19\x28\x5b\xef\xbe\x06\xe6\x0b\x62\x64\xe6\xd3\x73\x89\x3f\x68\x55\xe2\x4a",
|
||||
"\x03\x90\x17\x17\xce\x7c\x74\x84\xa2\xce\x1b\x7d\xc7\x40\x3b\x14\xe0\x35\x49\x71\x39\x3e\xc0\x92\xa7\xf3\xe0\xc8\xe4\xe2\xd2\x63\x9d",
|
||||
"\x02\xc0\x4a\xc7\xf7\x71\xe8\xeb\xdb\xf3\x15\xff\x5e\x58\xb7\xfe\x95\x16\x10\x21\x03\x50\x00\x66\x17\x2c\x4f\xac\x5b\x20\xf9\xe0\xea",
|
||||
{0x35, 0x19, 0x9a, 0x8f, 0xbf, 0x84, 0xad, 0x6e, 0xf6, 0x9a, 0x18, 0x4c, 0x1b, 0x19, 0x28, 0x5b, 0xef, 0xbe, 0x06, 0xe6, 0x0b, 0x62, 0x64, 0xe6, 0xd3, 0x73, 0x89, 0x3f, 0x68, 0x55, 0xe2, 0x4a},
|
||||
{0x03, 0x90, 0x17, 0x17, 0xce, 0x7c, 0x74, 0x84, 0xa2, 0xce, 0x1b, 0x7d, 0xc7, 0x40, 0x3b, 0x14, 0xe0, 0x35, 0x49, 0x71, 0x39, 0x3e, 0xc0, 0x92, 0xa7, 0xf3, 0xe0, 0xc8, 0xe4, 0xe2, 0xd2, 0x63, 0x9d},
|
||||
{0x02, 0xc0, 0x4a, 0xc7, 0xf7, 0x71, 0xe8, 0xeb, 0xdb, 0xf3, 0x15, 0xff, 0x5e, 0x58, 0xb7, 0xfe, 0x95, 0x16, 0x10, 0x21, 0x03, 0x50, 0x00, 0x66, 0x17, 0x2c, 0x4f, 0xac, 0x5b, 0x20, 0xf9, 0xe0, 0xea},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -170,7 +172,7 @@ static void test_ecdsa_s2c_fixed_vectors(void) {
|
|||
};
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(ecdsa_s2c_tests) / sizeof(ecdsa_s2c_tests[0]); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(ecdsa_s2c_tests); i++) {
|
||||
secp256k1_ecdsa_s2c_opening s2c_opening;
|
||||
unsigned char opening_ser[33];
|
||||
const ecdsa_s2c_test *test = &ecdsa_s2c_tests[i];
|
||||
|
|
@ -195,19 +197,19 @@ static void test_ecdsa_s2c_sign_verify(void) {
|
|||
/* Generate a random key, message, noncedata and s2c_data. */
|
||||
{
|
||||
secp256k1_scalar key;
|
||||
random_scalar_order_test(&key);
|
||||
testutil_random_scalar_order_test(&key);
|
||||
secp256k1_scalar_get_b32(privkey, &key);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1);
|
||||
|
||||
secp256k1_testrand256_test(message);
|
||||
secp256k1_testrand256_test(noncedata);
|
||||
secp256k1_testrand256_test(s2c_data);
|
||||
secp256k1_testrand256_test(s2c_data2);
|
||||
testrand256_test(message);
|
||||
testrand256_test(noncedata);
|
||||
testrand256_test(s2c_data);
|
||||
testrand256_test(s2c_data2);
|
||||
}
|
||||
|
||||
{ /* invalid privkeys */
|
||||
unsigned char zero_privkey[32] = {0};
|
||||
unsigned char overflow_privkey[32] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
|
||||
unsigned char overflow_privkey[32] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
CHECK(secp256k1_ecdsa_s2c_sign(CTX, &signature, NULL, message, zero_privkey, s2c_data) == 0);
|
||||
CHECK(secp256k1_ecdsa_s2c_sign(CTX, &signature, NULL, message, overflow_privkey, s2c_data) == 0);
|
||||
}
|
||||
|
|
@ -247,7 +249,7 @@ static void test_ecdsa_anti_exfil_signer_commit(void) {
|
|||
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
|
||||
};
|
||||
/* Check that original pubnonce is derived from s2c_data */
|
||||
for (i = 0; i < sizeof(ecdsa_s2c_tests) / sizeof(ecdsa_s2c_tests[0]); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(ecdsa_s2c_tests); i++) {
|
||||
secp256k1_ecdsa_s2c_opening s2c_opening;
|
||||
unsigned char buf[33];
|
||||
const ecdsa_s2c_test *test = &ecdsa_s2c_tests[i];
|
||||
|
|
@ -270,11 +272,11 @@ static void test_ecdsa_anti_exfil(void) {
|
|||
/* Generate a random key, message. */
|
||||
{
|
||||
secp256k1_scalar key;
|
||||
random_scalar_order_test(&key);
|
||||
testutil_random_scalar_order_test(&key);
|
||||
secp256k1_scalar_get_b32(signer_privkey, &key);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &signer_pubkey, signer_privkey) == 1);
|
||||
secp256k1_testrand256_test(host_msg);
|
||||
secp256k1_testrand256_test(host_nonce_contribution);
|
||||
testrand256_test(host_msg);
|
||||
testrand256_test(host_nonce_contribution);
|
||||
}
|
||||
|
||||
/* Protocol step 1. */
|
||||
|
|
@ -307,7 +309,7 @@ static void test_ecdsa_anti_exfil(void) {
|
|||
}
|
||||
{ /* host_verify: message does not match */
|
||||
unsigned char bad_msg[32];
|
||||
secp256k1_testrand256_test(bad_msg);
|
||||
testrand256_test(bad_msg);
|
||||
CHECK(secp256k1_anti_exfil_host_verify(CTX, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 1);
|
||||
CHECK(secp256k1_anti_exfil_host_verify(CTX, &signature, bad_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0);
|
||||
}
|
||||
|
|
@ -323,15 +325,15 @@ static void test_ecdsa_anti_exfil(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void run_ecdsa_s2c_tests(void) {
|
||||
run_s2c_opening_test();
|
||||
test_ecdsa_s2c_tagged_hash();
|
||||
test_ecdsa_s2c_api();
|
||||
test_ecdsa_s2c_fixed_vectors();
|
||||
test_ecdsa_s2c_sign_verify();
|
||||
|
||||
test_ecdsa_anti_exfil_signer_commit();
|
||||
test_ecdsa_anti_exfil();
|
||||
}
|
||||
/* --- Test registry --- */
|
||||
static const struct tf_test_entry tests_ecdsa_s2c[] = {
|
||||
CASE1(run_s2c_opening_test),
|
||||
CASE1(test_ecdsa_s2c_tagged_hash),
|
||||
CASE1(test_ecdsa_s2c_api),
|
||||
CASE1(test_ecdsa_s2c_fixed_vectors),
|
||||
CASE1(test_ecdsa_s2c_sign_verify),
|
||||
CASE1(test_ecdsa_anti_exfil_signer_commit),
|
||||
CASE1(test_ecdsa_anti_exfil)
|
||||
};
|
||||
|
||||
#endif /* SECP256K1_MODULE_ECDSA_S2C_TESTS_H */
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_
|
|||
* hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness.
|
||||
* Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a
|
||||
* 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */
|
||||
static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) {
|
||||
static void secp256k1_ellswift_prng(const secp256k1_hash_ctx *hash_ctx, unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) {
|
||||
secp256k1_sha256 hash = *hasher;
|
||||
unsigned char buf4[4];
|
||||
#ifdef VERIFY
|
||||
|
|
@ -317,8 +317,8 @@ static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256
|
|||
buf4[1] = cnt >> 8;
|
||||
buf4[2] = cnt >> 16;
|
||||
buf4[3] = cnt >> 24;
|
||||
secp256k1_sha256_write(&hash, buf4, 4);
|
||||
secp256k1_sha256_finalize(&hash, out32);
|
||||
secp256k1_sha256_write(hash_ctx, &hash, buf4, 4);
|
||||
secp256k1_sha256_finalize(hash_ctx, &hash, out32);
|
||||
|
||||
/* Writing and finalizing together should trigger exactly one SHA256 compression. */
|
||||
VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1));
|
||||
|
|
@ -330,7 +330,7 @@ static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256
|
|||
* needs encoding.
|
||||
*
|
||||
* hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */
|
||||
static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) {
|
||||
static void secp256k1_ellswift_xelligatorswift_var(const secp256k1_context *ctx, unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) {
|
||||
/* Pool of 3-bit branch values. */
|
||||
unsigned char branch_hash[32];
|
||||
/* Number of 3-bit values in branch_hash left. */
|
||||
|
|
@ -346,14 +346,14 @@ static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1
|
|||
secp256k1_fe u;
|
||||
/* If the pool of branch values is empty, populate it. */
|
||||
if (branches_left == 0) {
|
||||
secp256k1_ellswift_prng(branch_hash, hasher, cnt++);
|
||||
secp256k1_ellswift_prng(secp256k1_get_hash_context(ctx), branch_hash, hasher, cnt++);
|
||||
branches_left = 64;
|
||||
}
|
||||
/* Take a 3-bit branch value from the branch pool (top bit is discarded). */
|
||||
--branches_left;
|
||||
branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7;
|
||||
/* Compute a new u value by hashing. */
|
||||
secp256k1_ellswift_prng(u32, hasher, cnt++);
|
||||
secp256k1_ellswift_prng(secp256k1_get_hash_context(ctx), u32, hasher, cnt++);
|
||||
/* overflow is not a problem (we prefer uniform u32 over uniform u). */
|
||||
secp256k1_fe_set_b32_mod(&u, u32);
|
||||
/* Since u is the output of a hash, it should practically never be 0. We could apply the
|
||||
|
|
@ -372,8 +372,8 @@ static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1
|
|||
* as input, and returns an encoding that matches the provided Y coordinate rather than a random
|
||||
* one.
|
||||
*/
|
||||
static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) {
|
||||
secp256k1_ellswift_xelligatorswift_var(u32, t, &p->x, hasher);
|
||||
static void secp256k1_ellswift_elligatorswift_var(const secp256k1_context *ctx, unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) {
|
||||
secp256k1_ellswift_xelligatorswift_var(ctx, u32, t, &p->x, hasher);
|
||||
secp256k1_fe_normalize_var(t);
|
||||
if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) {
|
||||
secp256k1_fe_negate(t, t, 1);
|
||||
|
|
@ -383,17 +383,11 @@ static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_
|
|||
|
||||
/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_encode". */
|
||||
static void secp256k1_ellswift_sha256_init_encode(secp256k1_sha256* hash) {
|
||||
secp256k1_sha256_initialize(hash);
|
||||
hash->s[0] = 0xd1a6524bul;
|
||||
hash->s[1] = 0x028594b3ul;
|
||||
hash->s[2] = 0x96e42f4eul;
|
||||
hash->s[3] = 0x1037a177ul;
|
||||
hash->s[4] = 0x1b8fcb8bul;
|
||||
hash->s[5] = 0x56023885ul;
|
||||
hash->s[6] = 0x2560ede1ul;
|
||||
hash->s[7] = 0xd626b715ul;
|
||||
|
||||
hash->bytes = 64;
|
||||
static const uint32_t midstate[8] = {
|
||||
0xd1a6524bul, 0x028594b3ul, 0x96e42f4eul, 0x1037a177ul,
|
||||
0x1b8fcb8bul, 0x56023885ul, 0x2560ede1ul, 0xd626b715ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(hash, 64, midstate);
|
||||
}
|
||||
|
||||
int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) {
|
||||
|
|
@ -406,24 +400,17 @@ int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64
|
|||
if (secp256k1_pubkey_load(ctx, &p, pubkey)) {
|
||||
secp256k1_fe t;
|
||||
unsigned char p64[64] = {0};
|
||||
size_t ser_size;
|
||||
int ser_ret;
|
||||
secp256k1_sha256 hash;
|
||||
|
||||
/* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using
|
||||
* BIP340 tagged hash with tag "secp256k1_ellswift_encode". */
|
||||
secp256k1_ellswift_sha256_init_encode(&hash);
|
||||
ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1);
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(ser_ret && ser_size == 33);
|
||||
#else
|
||||
(void)ser_ret;
|
||||
#endif
|
||||
secp256k1_sha256_write(&hash, p64, sizeof(p64));
|
||||
secp256k1_sha256_write(&hash, rnd32, 32);
|
||||
secp256k1_eckey_pubkey_serialize33(&p, p64);
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, p64, sizeof(p64));
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, rnd32, 32);
|
||||
|
||||
/* Compute ElligatorSwift encoding and construct output. */
|
||||
secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
|
||||
secp256k1_ellswift_elligatorswift_var(ctx, ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
|
||||
secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -434,17 +421,11 @@ int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64
|
|||
|
||||
/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_create". */
|
||||
static void secp256k1_ellswift_sha256_init_create(secp256k1_sha256* hash) {
|
||||
secp256k1_sha256_initialize(hash);
|
||||
hash->s[0] = 0xd29e1bf5ul;
|
||||
hash->s[1] = 0xf7025f42ul;
|
||||
hash->s[2] = 0x9b024773ul;
|
||||
hash->s[3] = 0x094cb7d5ul;
|
||||
hash->s[4] = 0xe59ed789ul;
|
||||
hash->s[5] = 0x03bc9786ul;
|
||||
hash->s[6] = 0x68335b35ul;
|
||||
hash->s[7] = 0x4e363b53ul;
|
||||
|
||||
hash->bytes = 64;
|
||||
static const uint32_t midstate[8] = {
|
||||
0xd29e1bf5ul, 0xf7025f42ul, 0x9b024773ul, 0x094cb7d5ul,
|
||||
0xe59ed789ul, 0x03bc9786ul, 0x68335b35ul, 0x4e363b53ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(hash, 64, midstate);
|
||||
}
|
||||
|
||||
int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *auxrnd32) {
|
||||
|
|
@ -471,13 +452,13 @@ int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64
|
|||
/* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++),
|
||||
* using BIP340 tagged hash with tag "secp256k1_ellswift_create". */
|
||||
secp256k1_ellswift_sha256_init_create(&hash);
|
||||
secp256k1_sha256_write(&hash, seckey32, 32);
|
||||
secp256k1_sha256_write(&hash, zero32, sizeof(zero32));
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, seckey32, 32);
|
||||
secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, zero32, sizeof(zero32));
|
||||
secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */
|
||||
if (auxrnd32) secp256k1_sha256_write(&hash, auxrnd32, 32);
|
||||
if (auxrnd32) secp256k1_sha256_write(secp256k1_get_hash_context(ctx), &hash, auxrnd32, 32);
|
||||
|
||||
/* Compute ElligatorSwift encoding and construct output. */
|
||||
secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
|
||||
secp256k1_ellswift_elligatorswift_var(ctx, ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
|
||||
secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
|
||||
|
||||
secp256k1_memczero(ell64, 64, !ret);
|
||||
|
|
@ -501,50 +482,52 @@ int secp256k1_ellswift_decode(const secp256k1_context *ctx, secp256k1_pubkey *pu
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
static int ellswift_xdh_hash_function_prefix_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, data, 64);
|
||||
secp256k1_sha256_write(&sha, ell_a64, 64);
|
||||
secp256k1_sha256_write(&sha, ell_b64, 64);
|
||||
secp256k1_sha256_write(&sha, x32, 32);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, data, 64);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, ell_a64, 64);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, ell_b64, 64);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, x32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, output);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */
|
||||
static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) {
|
||||
secp256k1_sha256_initialize(hash);
|
||||
hash->s[0] = 0x8c12d730ul;
|
||||
hash->s[1] = 0x827bd392ul;
|
||||
hash->s[2] = 0x9e4fb2eeul;
|
||||
hash->s[3] = 0x207b373eul;
|
||||
hash->s[4] = 0x2292bd7aul;
|
||||
hash->s[5] = 0xaa5441bcul;
|
||||
hash->s[6] = 0x15c3779ful;
|
||||
hash->s[7] = 0xcfb52549ul;
|
||||
|
||||
hash->bytes = 64;
|
||||
static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
return ellswift_xdh_hash_function_prefix_impl(secp256k1_get_hash_context(secp256k1_context_static), output, x32, ell_a64, ell_b64, data);
|
||||
}
|
||||
|
||||
static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
/** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */
|
||||
static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) {
|
||||
static const uint32_t midstate[8] = {
|
||||
0x8c12d730ul, 0x827bd392ul, 0x9e4fb2eeul, 0x207b373eul,
|
||||
0x2292bd7aul, 0xaa5441bcul, 0x15c3779ful, 0xcfb52549ul
|
||||
};
|
||||
secp256k1_sha256_initialize_midstate(hash, 64, midstate);
|
||||
}
|
||||
|
||||
static int ellswift_xdh_hash_function_bip324_impl(const secp256k1_hash_ctx *hash_ctx, unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
(void)data;
|
||||
|
||||
secp256k1_ellswift_sha256_init_bip324(&sha);
|
||||
secp256k1_sha256_write(&sha, ell_a64, 64);
|
||||
secp256k1_sha256_write(&sha, ell_b64, 64);
|
||||
secp256k1_sha256_write(&sha, x32, 32);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, ell_a64, 64);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, ell_b64, 64);
|
||||
secp256k1_sha256_write(hash_ctx, &sha, x32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha, output);
|
||||
secp256k1_sha256_clear(&sha);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
return ellswift_xdh_hash_function_bip324_impl(secp256k1_get_hash_context(secp256k1_context_static), output, x32, ell_a64, ell_b64, data);
|
||||
}
|
||||
|
||||
const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix;
|
||||
const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324;
|
||||
|
||||
|
|
@ -571,7 +554,7 @@ int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output,
|
|||
|
||||
/* Load private key (using one if invalid). */
|
||||
secp256k1_scalar_set_b32(&s, seckey32, &overflow);
|
||||
overflow = secp256k1_scalar_is_zero(&s);
|
||||
overflow |= secp256k1_scalar_is_zero(&s);
|
||||
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
|
||||
|
||||
/* Compute shared X coordinate. */
|
||||
|
|
@ -579,10 +562,16 @@ int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output,
|
|||
secp256k1_fe_normalize(&px);
|
||||
secp256k1_fe_get_b32(sx, &px);
|
||||
|
||||
/* Invoke hasher */
|
||||
ret = hashfp(output, sx, ell_a64, ell_b64, data);
|
||||
/* Invoke hasher. Use ctx-aware function by default */
|
||||
if (hashfp == secp256k1_ellswift_xdh_hash_function_bip324) {
|
||||
ret = ellswift_xdh_hash_function_bip324_impl(secp256k1_get_hash_context(ctx), output, sx, ell_a64, ell_b64, data);
|
||||
} else if (hashfp == secp256k1_ellswift_xdh_hash_function_prefix) {
|
||||
ret = ellswift_xdh_hash_function_prefix_impl(secp256k1_get_hash_context(ctx), output, sx, ell_a64, ell_b64, data);
|
||||
} else {
|
||||
ret = hashfp(output, sx, ell_a64, ell_b64, data);
|
||||
}
|
||||
|
||||
secp256k1_memclear(sx, sizeof(sx));
|
||||
secp256k1_memclear_explicit(sx, sizeof(sx));
|
||||
secp256k1_fe_clear(&px);
|
||||
secp256k1_scalar_clear(&s);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#define SECP256K1_MODULE_ELLSWIFT_TESTS_H
|
||||
|
||||
#include "../../../include/secp256k1_ellswift.h"
|
||||
#include "../../unit_test.h"
|
||||
#include "../../util.h"
|
||||
|
||||
struct ellswift_xswiftec_inv_test {
|
||||
int enc_bitmap;
|
||||
|
|
@ -176,10 +178,10 @@ static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32
|
|||
return 1;
|
||||
}
|
||||
|
||||
void run_ellswift_tests(void) {
|
||||
int i = 0;
|
||||
/* Test vectors. */
|
||||
for (i = 0; (unsigned)i < sizeof(ellswift_xswiftec_inv_tests) / sizeof(ellswift_xswiftec_inv_tests[0]); ++i) {
|
||||
/* Run the test vectors for ellswift encoding */
|
||||
void ellswift_encoding_test_vectors_tests(void) {
|
||||
int i;
|
||||
for (i = 0; (unsigned)i < ARRAY_SIZE(ellswift_xswiftec_inv_tests); ++i) {
|
||||
const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i];
|
||||
int c;
|
||||
for (c = 0; c < 8; ++c) {
|
||||
|
|
@ -194,7 +196,12 @@ void run_ellswift_tests(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; (unsigned)i < sizeof(ellswift_decode_tests) / sizeof(ellswift_decode_tests[0]); ++i) {
|
||||
}
|
||||
|
||||
/* Run the test vectors for ellswift decoding */
|
||||
void ellswift_decoding_test_vectors_tests(void) {
|
||||
int i;
|
||||
for (i = 0; (unsigned)i < ARRAY_SIZE(ellswift_decode_tests); ++i) {
|
||||
const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i];
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ge ge;
|
||||
|
|
@ -206,7 +213,12 @@ void run_ellswift_tests(void) {
|
|||
CHECK(fe_equal(&testcase->x, &ge.x));
|
||||
CHECK(secp256k1_fe_is_odd(&ge.y) == testcase->odd_y);
|
||||
}
|
||||
for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) {
|
||||
}
|
||||
|
||||
/* Run the test vectors for ellswift expected xdh BIP324 shared secrets */
|
||||
void ellswift_xdh_test_vectors_tests(void) {
|
||||
int i;
|
||||
for (i = 0; (unsigned)i < ARRAY_SIZE(ellswift_xdh_tests_bip324); ++i) {
|
||||
const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i];
|
||||
unsigned char shared_secret[32];
|
||||
int ret;
|
||||
|
|
@ -222,16 +234,20 @@ void run_ellswift_tests(void) {
|
|||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(shared_secret, test->shared_secret, 32) == 0);
|
||||
}
|
||||
/* Verify that secp256k1_ellswift_encode + decode roundtrips. */
|
||||
}
|
||||
|
||||
/* Verify that secp256k1_ellswift_encode + decode roundtrips */
|
||||
void ellswift_encode_decode_roundtrip_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < 1000 * COUNT; i++) {
|
||||
unsigned char rnd32[32];
|
||||
unsigned char ell64[64];
|
||||
secp256k1_ge g, g2;
|
||||
secp256k1_pubkey pubkey, pubkey2;
|
||||
/* Generate random public key and random randomizer. */
|
||||
random_group_element_test(&g);
|
||||
testutil_random_ge_test(&g);
|
||||
secp256k1_pubkey_save(&pubkey, &g);
|
||||
secp256k1_testrand256(rnd32);
|
||||
testrand256(rnd32);
|
||||
/* Convert the public key to ElligatorSwift and back. */
|
||||
secp256k1_ellswift_encode(CTX, ell64, &pubkey, rnd32);
|
||||
secp256k1_ellswift_decode(CTX, &pubkey2, ell64);
|
||||
|
|
@ -239,7 +255,11 @@ void run_ellswift_tests(void) {
|
|||
/* Compare with original. */
|
||||
CHECK(secp256k1_ge_eq_var(&g, &g2));
|
||||
}
|
||||
/* Verify the behavior of secp256k1_ellswift_create */
|
||||
}
|
||||
|
||||
/* Verify the behavior of secp256k1_ellswift_create */
|
||||
void ellswift_create_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < 400 * COUNT; i++) {
|
||||
unsigned char auxrnd32[32], sec32[32];
|
||||
secp256k1_scalar sec;
|
||||
|
|
@ -249,8 +269,8 @@ void run_ellswift_tests(void) {
|
|||
unsigned char ell64[64];
|
||||
int ret;
|
||||
/* Generate random secret key and random randomizer. */
|
||||
if (i & 1) secp256k1_testrand256_test(auxrnd32);
|
||||
random_scalar_order_test(&sec);
|
||||
if (i & 1) testrand256_test(auxrnd32);
|
||||
testutil_random_scalar_order_test(&sec);
|
||||
secp256k1_scalar_get_b32(sec32, &sec);
|
||||
/* Construct ElligatorSwift-encoded public keys for that key. */
|
||||
ret = secp256k1_ellswift_create(CTX, ell64, sec32, (i & 1) ? auxrnd32 : NULL);
|
||||
|
|
@ -261,7 +281,11 @@ void run_ellswift_tests(void) {
|
|||
secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&res, &dec));
|
||||
}
|
||||
/* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */
|
||||
}
|
||||
|
||||
/* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate */
|
||||
void ellswift_compute_shared_secret_tests(void) {
|
||||
int i;
|
||||
for (i = 0; i < 800 * COUNT; i++) {
|
||||
unsigned char ell64[64], sec32[32], share32[32];
|
||||
secp256k1_scalar sec;
|
||||
|
|
@ -271,11 +295,11 @@ void run_ellswift_tests(void) {
|
|||
secp256k1_pubkey pub;
|
||||
int ret;
|
||||
/* Generate random secret key. */
|
||||
random_scalar_order_test(&sec);
|
||||
testutil_random_scalar_order_test(&sec);
|
||||
secp256k1_scalar_get_b32(sec32, &sec);
|
||||
/* Generate random ElligatorSwift encoding for the remote key and decode it. */
|
||||
secp256k1_testrand256_test(ell64);
|
||||
secp256k1_testrand256_test(ell64 + 32);
|
||||
testrand256_test(ell64);
|
||||
testrand256_test(ell64 + 32);
|
||||
secp256k1_ellswift_decode(CTX, &pub, ell64);
|
||||
secp256k1_pubkey_load(CTX, &dec, &pub);
|
||||
secp256k1_gej_set_ge(&decj, &dec);
|
||||
|
|
@ -292,6 +316,10 @@ void run_ellswift_tests(void) {
|
|||
/* Compare. */
|
||||
CHECK(fe_equal(&res.x, &share_x));
|
||||
}
|
||||
}
|
||||
|
||||
void ellswift_xdh_correctness_tests(void) {
|
||||
int i;
|
||||
/* Verify the joint behavior of secp256k1_ellswift_xdh */
|
||||
for (i = 0; i < 200 * COUNT; i++) {
|
||||
unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32];
|
||||
|
|
@ -313,18 +341,18 @@ void run_ellswift_tests(void) {
|
|||
data = NULL;
|
||||
} else {
|
||||
hash_function = secp256k1_ellswift_xdh_hash_function_prefix;
|
||||
secp256k1_testrand256_test(prefix64);
|
||||
secp256k1_testrand256_test(prefix64 + 32);
|
||||
testrand256_test(prefix64);
|
||||
testrand256_test(prefix64 + 32);
|
||||
data = prefix64;
|
||||
}
|
||||
|
||||
/* Generate random secret keys and random randomizers. */
|
||||
secp256k1_testrand256_test(auxrnd32a);
|
||||
secp256k1_testrand256_test(auxrnd32b);
|
||||
random_scalar_order_test(&seca);
|
||||
testrand256_test(auxrnd32a);
|
||||
testrand256_test(auxrnd32b);
|
||||
testutil_random_scalar_order_test(&seca);
|
||||
/* Draw secb uniformly at random to make sure that the secret keys
|
||||
* differ */
|
||||
random_scalar_order(&secb);
|
||||
testutil_random_scalar_order(&secb);
|
||||
secp256k1_scalar_get_b32(sec32a, &seca);
|
||||
secp256k1_scalar_get_b32(sec32b, &secb);
|
||||
|
||||
|
|
@ -349,13 +377,13 @@ void run_ellswift_tests(void) {
|
|||
/* Verify that the shared secret doesn't match if other side's public key is incorrect. */
|
||||
/* For A (using a bad public key for B): */
|
||||
memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad));
|
||||
secp256k1_testrand_flip(ell64b_bad, sizeof(ell64b_bad));
|
||||
testrand_flip(ell64b_bad, sizeof(ell64b_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data);
|
||||
CHECK(ret); /* Mismatching encodings don't get detected by secp256k1_ellswift_xdh. */
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B (using a bad public key for A): */
|
||||
memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad));
|
||||
secp256k1_testrand_flip(ell64a_bad, sizeof(ell64a_bad));
|
||||
testrand_flip(ell64a_bad, sizeof(ell64a_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
|
|
@ -363,12 +391,12 @@ void run_ellswift_tests(void) {
|
|||
/* Verify that the shared secret doesn't match if the private key is incorrect. */
|
||||
/* For A: */
|
||||
memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad));
|
||||
secp256k1_testrand_flip(sec32a_bad, sizeof(sec32a_bad));
|
||||
testrand_flip(sec32a_bad, sizeof(sec32a_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data);
|
||||
CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B: */
|
||||
memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad));
|
||||
secp256k1_testrand_flip(sec32b_bad, sizeof(sec32b_bad));
|
||||
testrand_flip(sec32b_bad, sizeof(sec32b_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data);
|
||||
CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
|
||||
|
|
@ -376,7 +404,7 @@ void run_ellswift_tests(void) {
|
|||
/* Verify that the shared secret doesn't match when a different encoding of the same public key is used. */
|
||||
/* For A (changing B's public key): */
|
||||
memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad));
|
||||
secp256k1_testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad));
|
||||
testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad));
|
||||
ret = secp256k1_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad);
|
||||
CHECK(ret);
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data);
|
||||
|
|
@ -384,7 +412,7 @@ void run_ellswift_tests(void) {
|
|||
CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B (changing A's public key): */
|
||||
memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad));
|
||||
secp256k1_testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad));
|
||||
testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad));
|
||||
ret = secp256k1_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad);
|
||||
CHECK(ret);
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data);
|
||||
|
|
@ -402,35 +430,115 @@ void run_ellswift_tests(void) {
|
|||
CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test hash initializers. */
|
||||
{
|
||||
secp256k1_sha256 sha, sha_optimized;
|
||||
static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'};
|
||||
static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'};
|
||||
static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'};
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_encode has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, encode_tag, sizeof(encode_tag));
|
||||
secp256k1_ellswift_sha256_init_encode(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_create has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, create_tag, sizeof(create_tag));
|
||||
secp256k1_ellswift_sha256_init_create(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_bip324 has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, bip324_tag, sizeof(bip324_tag));
|
||||
secp256k1_ellswift_sha256_init_bip324(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_SHA256_TRANSFORM_PROBE(sha256_ellswift_xdh)
|
||||
void ellswift_xdh_ctx_sha256_tests(void) {
|
||||
/* Check ctx-provided SHA256 compression override takes effect */
|
||||
secp256k1_context *ctx = secp256k1_context_clone(CTX);
|
||||
unsigned char out_default[65], out_custom[65];
|
||||
const unsigned char skA[32] = {1}, skB[32] = {2};
|
||||
unsigned char keyA[64], keyB[64], data[64] = {0};
|
||||
secp256k1_ellswift_xdh_hash_function hash_fn;
|
||||
int i;
|
||||
|
||||
CHECK(secp256k1_ellswift_create(ctx, keyA, skA, NULL));
|
||||
CHECK(secp256k1_ellswift_create(ctx, keyB, skB, NULL));
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (i == 0) {
|
||||
hash_fn = secp256k1_ellswift_xdh_hash_function_bip324;
|
||||
} else {
|
||||
hash_fn = secp256k1_ellswift_xdh_hash_function_prefix;
|
||||
}
|
||||
/* Default behavior. No ctx-provided SHA256 compression */
|
||||
CHECK(secp256k1_ellswift_xdh(ctx, out_default, keyA, keyB, skA, 0, hash_fn, data));
|
||||
CHECK(!sha256_ellswift_xdh_called);
|
||||
|
||||
/* Override SHA256 compression directly, bypassing the ctx setter sanity checks */
|
||||
ctx->hash_ctx.fn_sha256_compression = sha256_ellswift_xdh;
|
||||
CHECK(secp256k1_ellswift_xdh(ctx, out_custom, keyA, keyB, skA, 0, hash_fn, data));
|
||||
CHECK(sha256_ellswift_xdh_called);
|
||||
/* Outputs must differ if custom compression was used */
|
||||
CHECK(secp256k1_memcmp_var(out_default, out_custom, 32) != 0);
|
||||
|
||||
/* Restore defaults */
|
||||
sha256_ellswift_xdh_called = 0;
|
||||
secp256k1_context_set_sha256_compression(ctx, NULL);
|
||||
}
|
||||
|
||||
secp256k1_context_destroy(ctx);
|
||||
}
|
||||
|
||||
/* Test hash initializers */
|
||||
void ellswift_hash_init_tests(void) {
|
||||
secp256k1_sha256 sha_optimized;
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(CTX);
|
||||
/* "secp256k1_ellswift_encode" */
|
||||
static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'};
|
||||
/* "secp256k1_ellswift_create" */
|
||||
static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'};
|
||||
/* "bip324_ellswift_xonly_ecdh" */
|
||||
static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'};
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_encode has the expected
|
||||
* state. */
|
||||
secp256k1_ellswift_sha256_init_encode(&sha_optimized);
|
||||
test_sha256_tag_midstate(hash_ctx, &sha_optimized, encode_tag, sizeof(encode_tag));
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_create has the expected
|
||||
* state. */
|
||||
secp256k1_ellswift_sha256_init_create(&sha_optimized);
|
||||
test_sha256_tag_midstate(hash_ctx, &sha_optimized, create_tag, sizeof(create_tag));
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_bip324 has the expected
|
||||
* state. */
|
||||
secp256k1_ellswift_sha256_init_bip324(&sha_optimized);
|
||||
test_sha256_tag_midstate(hash_ctx, &sha_optimized, bip324_tag, sizeof(bip324_tag));
|
||||
}
|
||||
|
||||
void ellswift_xdh_bad_scalar_tests(void) {
|
||||
unsigned char s_zero[32] = { 0 };
|
||||
unsigned char s_overflow_minus1[32] = { 0 };
|
||||
unsigned char s_overflow_plus1[32] = { 0 };
|
||||
unsigned char s_good[32] = { 0 };
|
||||
unsigned char ell_a64[64], ell_b64[64];
|
||||
unsigned char output[32];
|
||||
secp256k1_scalar rand_scalar;
|
||||
|
||||
testutil_random_scalar_order(&rand_scalar);
|
||||
secp256k1_scalar_get_b32(s_good, &rand_scalar);
|
||||
|
||||
CHECK(secp256k1_ellswift_create(CTX, ell_a64, s_good, NULL) == 1);
|
||||
|
||||
testrand256_test(ell_b64);
|
||||
testrand256_test(ell_b64 + 32);
|
||||
|
||||
memcpy(s_overflow_minus1, secp256k1_group_order_bytes, 32);
|
||||
s_overflow_minus1[31] -= 1;
|
||||
memcpy(s_overflow_plus1, secp256k1_group_order_bytes, 32);
|
||||
s_overflow_plus1[31] += 1;
|
||||
CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, s_zero, 0, &ellswift_xdh_hash_x32, NULL) == 0);
|
||||
CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, secp256k1_group_order_bytes, 0, &ellswift_xdh_hash_x32, NULL) == 0);
|
||||
CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, s_overflow_plus1, 0, &ellswift_xdh_hash_x32, NULL) == 0);
|
||||
CHECK(secp256k1_ellswift_xdh(CTX, output, ell_a64, ell_b64, s_overflow_minus1, 0, &ellswift_xdh_hash_x32, NULL) == 1);
|
||||
}
|
||||
|
||||
/* --- Test registry --- */
|
||||
static const struct tf_test_entry tests_ellswift[] = {
|
||||
CASE1(ellswift_encoding_test_vectors_tests),
|
||||
CASE1(ellswift_decoding_test_vectors_tests),
|
||||
CASE1(ellswift_xdh_test_vectors_tests),
|
||||
CASE1(ellswift_encode_decode_roundtrip_tests),
|
||||
CASE1(ellswift_create_tests),
|
||||
CASE1(ellswift_compute_shared_secret_tests),
|
||||
CASE1(ellswift_xdh_correctness_tests),
|
||||
CASE1(ellswift_hash_init_tests),
|
||||
CASE1(ellswift_xdh_bad_scalar_tests),
|
||||
CASE1(ellswift_xdh_ctx_sha256_tests),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
include_HEADERS += include/secp256k1_extrakeys.h
|
||||
noinst_HEADERS += src/modules/extrakeys/tests_impl.h
|
||||
noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h
|
||||
noinst_HEADERS += src/modules/extrakeys/main_impl.h
|
||||
noinst_HEADERS += src/modules/extrakeys/hsort.h
|
||||
noinst_HEADERS += src/modules/extrakeys/hsort_impl.h
|
||||
noinst_HEADERS += src/modules/extrakeys/main_impl.h
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_extrakeys.h"
|
||||
#include "hsort_impl.h"
|
||||
#include "../../util.h"
|
||||
|
||||
static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) {
|
||||
|
|
@ -283,38 +282,4 @@ int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_ke
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* This struct wraps a const context pointer to satisfy the secp256k1_hsort api
|
||||
* which expects a non-const cmp_data pointer. */
|
||||
typedef struct {
|
||||
const secp256k1_context *ctx;
|
||||
} secp256k1_pubkey_sort_cmp_data;
|
||||
|
||||
static int secp256k1_pubkey_sort_cmp(const void* pk1, const void* pk2, void *cmp_data) {
|
||||
return secp256k1_ec_pubkey_cmp(((secp256k1_pubkey_sort_cmp_data*)cmp_data)->ctx,
|
||||
*(secp256k1_pubkey **)pk1,
|
||||
*(secp256k1_pubkey **)pk2);
|
||||
}
|
||||
|
||||
int secp256k1_pubkey_sort(const secp256k1_context* ctx, const secp256k1_pubkey **pubkeys, size_t n_pubkeys) {
|
||||
secp256k1_pubkey_sort_cmp_data cmp_data;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkeys != NULL);
|
||||
|
||||
cmp_data.ctx = ctx;
|
||||
|
||||
/* Suppress wrong warning (fixed in MSVC 19.33) */
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1933)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4090)
|
||||
#endif
|
||||
|
||||
secp256k1_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), secp256k1_pubkey_sort_cmp, &cmp_data);
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER < 1933)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#define SECP256K1_MODULE_EXTRAKEYS_TESTS_H
|
||||
|
||||
#include "../../../include/secp256k1_extrakeys.h"
|
||||
#include "../../unit_test.h"
|
||||
|
||||
static void test_xonly_pubkey(void) {
|
||||
secp256k1_pubkey pk;
|
||||
|
|
@ -23,9 +24,9 @@ static void test_xonly_pubkey(void) {
|
|||
int pk_parity;
|
||||
int i;
|
||||
|
||||
secp256k1_testrand256(sk);
|
||||
testrand256(sk);
|
||||
memset(ones32, 0xFF, 32);
|
||||
secp256k1_testrand256(xy_sk);
|
||||
testrand256(xy_sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
|
||||
|
|
@ -95,7 +96,7 @@ static void test_xonly_pubkey(void) {
|
|||
* the curve) then xonly_pubkey_parse should fail as well. */
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
unsigned char rand33[33];
|
||||
secp256k1_testrand256(&rand33[1]);
|
||||
testrand256(&rand33[1]);
|
||||
rand33[0] = SECP256K1_TAG_PUBKEY_EVEN;
|
||||
if (!secp256k1_ec_pubkey_parse(CTX, &pk, rand33, 33)) {
|
||||
memset(&xonly_pk, 1, sizeof(xonly_pk));
|
||||
|
|
@ -152,8 +153,8 @@ static void test_xonly_pubkey_tweak(void) {
|
|||
int i;
|
||||
|
||||
memset(overflows, 0xff, sizeof(overflows));
|
||||
secp256k1_testrand256(tweak);
|
||||
secp256k1_testrand256(sk);
|
||||
testrand256(tweak);
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
|
||||
|
||||
|
|
@ -190,7 +191,7 @@ static void test_xonly_pubkey_tweak(void) {
|
|||
|
||||
/* Invalid pk with a valid tweak */
|
||||
memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk));
|
||||
secp256k1_testrand256(tweak);
|
||||
testrand256(tweak);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak));
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
}
|
||||
|
|
@ -209,8 +210,8 @@ static void test_xonly_pubkey_tweak_check(void) {
|
|||
unsigned char tweak[32];
|
||||
|
||||
memset(overflows, 0xff, sizeof(overflows));
|
||||
secp256k1_testrand256(tweak);
|
||||
secp256k1_testrand256(sk);
|
||||
testrand256(tweak);
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
|
||||
|
||||
|
|
@ -256,7 +257,7 @@ static void test_xonly_pubkey_tweak_recursive(void) {
|
|||
unsigned char tweak[N_PUBKEYS - 1][32];
|
||||
int i;
|
||||
|
||||
secp256k1_testrand256(sk);
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pk[0], sk) == 1);
|
||||
/* Add tweaks */
|
||||
for (i = 0; i < N_PUBKEYS - 1; i++) {
|
||||
|
|
@ -292,7 +293,7 @@ static void test_keypair(void) {
|
|||
memset(overflows, 0xFF, sizeof(overflows));
|
||||
|
||||
/* Test keypair_create */
|
||||
secp256k1_testrand256(sk);
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
|
|
@ -311,7 +312,7 @@ static void test_keypair(void) {
|
|||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
|
||||
/* Test keypair_pub */
|
||||
secp256k1_testrand256(sk);
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, NULL, &keypair));
|
||||
|
|
@ -330,7 +331,7 @@ static void test_keypair(void) {
|
|||
CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0);
|
||||
|
||||
/** Test keypair_xonly_pub **/
|
||||
secp256k1_testrand256(sk);
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair));
|
||||
|
|
@ -353,7 +354,7 @@ static void test_keypair(void) {
|
|||
CHECK(pk_parity == pk_parity_tmp);
|
||||
|
||||
/* Test keypair_seckey */
|
||||
secp256k1_testrand256(sk);
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, NULL, &keypair));
|
||||
|
|
@ -381,8 +382,8 @@ static void test_keypair_add(void) {
|
|||
int i;
|
||||
|
||||
CHECK(sizeof(zeros96) == sizeof(keypair));
|
||||
secp256k1_testrand256(sk);
|
||||
secp256k1_testrand256(tweak);
|
||||
testrand256(sk);
|
||||
testrand256(tweak);
|
||||
memset(overflows, 0xFF, 32);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
|
||||
|
|
@ -407,7 +408,7 @@ static void test_keypair_add(void) {
|
|||
for (i = 0; i < COUNT; i++) {
|
||||
secp256k1_scalar scalar_tweak;
|
||||
secp256k1_keypair keypair_tmp;
|
||||
secp256k1_testrand256(sk);
|
||||
testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
memcpy(&keypair_tmp, &keypair, sizeof(keypair));
|
||||
/* Because sk may be negated before adding, we need to try with tweak =
|
||||
|
|
@ -423,7 +424,7 @@ static void test_keypair_add(void) {
|
|||
|
||||
/* Invalid keypair with a valid tweak */
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
secp256k1_testrand256(tweak);
|
||||
testrand256(tweak);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak));
|
||||
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
|
||||
/* Only seckey part of keypair invalid */
|
||||
|
|
@ -446,7 +447,7 @@ static void test_keypair_add(void) {
|
|||
unsigned char sk32[32];
|
||||
int pk_parity;
|
||||
|
||||
secp256k1_testrand256(tweak);
|
||||
testrand256(tweak);
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1);
|
||||
|
|
@ -467,210 +468,17 @@ static void test_keypair_add(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void test_hsort_is_sorted(int *ints, size_t n) {
|
||||
size_t i;
|
||||
for (i = 1; i < n; i++) {
|
||||
CHECK(ints[i-1] <= ints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int test_hsort_cmp(const void *i1, const void *i2, void *counter) {
|
||||
*(size_t*)counter += 1;
|
||||
return *(int*)i1 - *(int*)i2;
|
||||
}
|
||||
|
||||
#define NUM 64
|
||||
static void test_hsort(void) {
|
||||
int ints[NUM] = { 0 };
|
||||
size_t counter = 0;
|
||||
int i, j;
|
||||
|
||||
secp256k1_hsort(ints, 0, sizeof(ints[0]), test_hsort_cmp, &counter);
|
||||
CHECK(counter == 0);
|
||||
secp256k1_hsort(ints, 1, sizeof(ints[0]), test_hsort_cmp, &counter);
|
||||
CHECK(counter == 0);
|
||||
secp256k1_hsort(ints, NUM, sizeof(ints[0]), test_hsort_cmp, &counter);
|
||||
CHECK(counter > 0);
|
||||
test_hsort_is_sorted(ints, NUM);
|
||||
|
||||
/* Test hsort with length n array and random elements in
|
||||
* [-interval/2, interval/2] */
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
int n = secp256k1_testrand_int(NUM);
|
||||
int interval = secp256k1_testrand_int(63) + 1;
|
||||
for (j = 0; j < n; j++) {
|
||||
ints[j] = secp256k1_testrand_int(interval) - interval/2;
|
||||
}
|
||||
secp256k1_hsort(ints, n, sizeof(ints[0]), test_hsort_cmp, &counter);
|
||||
test_hsort_is_sorted(ints, n);
|
||||
}
|
||||
}
|
||||
#undef NUM
|
||||
|
||||
static void test_sort_helper(secp256k1_pubkey *pk, size_t *pk_order, size_t n_pk) {
|
||||
size_t i;
|
||||
const secp256k1_pubkey *pk_test[5];
|
||||
|
||||
for (i = 0; i < n_pk; i++) {
|
||||
pk_test[i] = &pk[pk_order[i]];
|
||||
}
|
||||
secp256k1_pubkey_sort(CTX, pk_test, n_pk);
|
||||
for (i = 0; i < n_pk; i++) {
|
||||
CHECK(secp256k1_memcmp_var(pk_test[i], &pk[i], sizeof(*pk_test[i])) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void permute(size_t *arr, size_t n) {
|
||||
size_t i;
|
||||
for (i = n - 1; i >= 1; i--) {
|
||||
size_t tmp, j;
|
||||
j = secp256k1_testrand_int(i + 1);
|
||||
tmp = arr[i];
|
||||
arr[i] = arr[j];
|
||||
arr[j] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
static void rand_pk(secp256k1_pubkey *pk) {
|
||||
unsigned char seckey[32];
|
||||
secp256k1_keypair keypair;
|
||||
secp256k1_testrand256(seckey);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, seckey) == 1);
|
||||
CHECK(secp256k1_keypair_pub(CTX, pk, &keypair) == 1);
|
||||
}
|
||||
|
||||
static void test_sort_api(void) {
|
||||
secp256k1_pubkey pks[2];
|
||||
const secp256k1_pubkey *pks_ptr[2];
|
||||
|
||||
pks_ptr[0] = &pks[0];
|
||||
pks_ptr[1] = &pks[1];
|
||||
|
||||
rand_pk(&pks[0]);
|
||||
rand_pk(&pks[1]);
|
||||
|
||||
CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, 2) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_pubkey_sort(CTX, NULL, 2));
|
||||
CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, 0) == 1);
|
||||
/* Test illegal public keys */
|
||||
memset(&pks[0], 0, sizeof(pks[0]));
|
||||
CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, 2) == 1));
|
||||
memset(&pks[1], 0, sizeof(pks[1]));
|
||||
{
|
||||
int32_t ecount = 0;
|
||||
secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount);
|
||||
CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, 2) == 1);
|
||||
CHECK(ecount == 2);
|
||||
secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_sort(void) {
|
||||
secp256k1_pubkey pk[5];
|
||||
unsigned char pk_ser[5][33] = {
|
||||
{ 0x02, 0x08 },
|
||||
{ 0x02, 0x0b },
|
||||
{ 0x02, 0x0c },
|
||||
{ 0x03, 0x05 },
|
||||
{ 0x03, 0x0a },
|
||||
};
|
||||
int i;
|
||||
size_t pk_order[5] = { 0, 1, 2, 3, 4 };
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
CHECK(secp256k1_ec_pubkey_parse(CTX, &pk[i], pk_ser[i], sizeof(pk_ser[i])));
|
||||
}
|
||||
|
||||
permute(pk_order, 1);
|
||||
test_sort_helper(pk, pk_order, 1);
|
||||
permute(pk_order, 2);
|
||||
test_sort_helper(pk, pk_order, 2);
|
||||
permute(pk_order, 3);
|
||||
test_sort_helper(pk, pk_order, 3);
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
permute(pk_order, 4);
|
||||
test_sort_helper(pk, pk_order, 4);
|
||||
}
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
permute(pk_order, 5);
|
||||
test_sort_helper(pk, pk_order, 5);
|
||||
}
|
||||
/* Check that sorting also works for random pubkeys */
|
||||
for (i = 0; i < COUNT; i++) {
|
||||
int j;
|
||||
const secp256k1_pubkey *pk_ptr[5];
|
||||
for (j = 0; j < 5; j++) {
|
||||
rand_pk(&pk[j]);
|
||||
pk_ptr[j] = &pk[j];
|
||||
}
|
||||
secp256k1_pubkey_sort(CTX, pk_ptr, 5);
|
||||
for (j = 1; j < 5; j++) {
|
||||
CHECK(secp256k1_pubkey_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], CTX) <= 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Test vectors from BIP-MuSig2 */
|
||||
static void test_sort_vectors(void) {
|
||||
enum { N_PUBKEYS = 6 };
|
||||
unsigned char pk_ser[N_PUBKEYS][33] = {
|
||||
{ 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F,
|
||||
0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09,
|
||||
0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 },
|
||||
{ 0x02, 0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10, 0x49, 0x34,
|
||||
0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29, 0xB5, 0x31, 0xC8, 0x45, 0x83,
|
||||
0x6F, 0x99, 0xB0, 0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9 },
|
||||
{ 0x03, 0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F, 0x36, 0x18,
|
||||
0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE, 0x58, 0xFE, 0xAE, 0x1D, 0xA2,
|
||||
0xDE, 0xCE, 0xD8, 0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59 },
|
||||
{ 0x02, 0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18, 0x15, 0xC2,
|
||||
0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3, 0x14, 0x93, 0x16, 0xC3, 0x51,
|
||||
0x8C, 0xE7, 0xB7, 0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66 },
|
||||
{ 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F,
|
||||
0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09,
|
||||
0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xFF },
|
||||
{ 0x02, 0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13, 0x12, 0x1F,
|
||||
0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC, 0x01, 0x39, 0x71, 0x53, 0x09,
|
||||
0xB0, 0x86, 0xC9, 0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8 }
|
||||
};
|
||||
secp256k1_pubkey pubkeys[N_PUBKEYS];
|
||||
secp256k1_pubkey *sorted[N_PUBKEYS];
|
||||
const secp256k1_pubkey *pks_ptr[N_PUBKEYS];
|
||||
int i;
|
||||
|
||||
sorted[0] = &pubkeys[3];
|
||||
sorted[1] = &pubkeys[0];
|
||||
sorted[2] = &pubkeys[0];
|
||||
sorted[3] = &pubkeys[4];
|
||||
sorted[4] = &pubkeys[1];
|
||||
sorted[5] = &pubkeys[2];
|
||||
|
||||
for (i = 0; i < N_PUBKEYS; i++) {
|
||||
CHECK(secp256k1_ec_pubkey_parse(CTX, &pubkeys[i], pk_ser[i], sizeof(pk_ser[i])));
|
||||
pks_ptr[i] = &pubkeys[i];
|
||||
}
|
||||
CHECK(secp256k1_pubkey_sort(CTX, pks_ptr, N_PUBKEYS) == 1);
|
||||
for (i = 0; i < N_PUBKEYS; i++) {
|
||||
CHECK(secp256k1_memcmp_var(pks_ptr[i], sorted[i], sizeof(secp256k1_pubkey)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void run_extrakeys_tests(void) {
|
||||
/* --- Test registry --- */
|
||||
static const struct tf_test_entry tests_extrakeys[] = {
|
||||
/* xonly key test cases */
|
||||
test_xonly_pubkey();
|
||||
test_xonly_pubkey_tweak();
|
||||
test_xonly_pubkey_tweak_check();
|
||||
test_xonly_pubkey_tweak_recursive();
|
||||
test_xonly_pubkey_comparison();
|
||||
|
||||
CASE1(test_xonly_pubkey),
|
||||
CASE1(test_xonly_pubkey_tweak),
|
||||
CASE1(test_xonly_pubkey_tweak_check),
|
||||
CASE1(test_xonly_pubkey_tweak_recursive),
|
||||
CASE1(test_xonly_pubkey_comparison),
|
||||
/* keypair tests */
|
||||
test_keypair();
|
||||
test_keypair_add();
|
||||
|
||||
test_hsort();
|
||||
test_sort_api();
|
||||
test_sort();
|
||||
test_sort_vectors();
|
||||
}
|
||||
CASE1(test_keypair),
|
||||
CASE1(test_keypair_add),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -38,12 +38,13 @@ const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_intern
|
|||
|
||||
|
||||
static void secp256k1_generator_load(secp256k1_ge* ge, const secp256k1_generator* gen) {
|
||||
secp256k1_fe x, y;
|
||||
int succeed;
|
||||
succeed = secp256k1_fe_set_b32_limit(&ge->x, &gen->data[0]);
|
||||
succeed = secp256k1_fe_set_b32_limit(&x, &gen->data[0]);
|
||||
VERIFY_CHECK(succeed != 0);
|
||||
succeed = secp256k1_fe_set_b32_limit(&ge->y, &gen->data[32]);
|
||||
succeed = secp256k1_fe_set_b32_limit(&y, &gen->data[32]);
|
||||
VERIFY_CHECK(succeed != 0);
|
||||
ge->infinity = 0;
|
||||
secp256k1_ge_set_xy(ge, &x, &y);
|
||||
(void) succeed;
|
||||
}
|
||||
|
||||
|
|
@ -210,6 +211,7 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s
|
|||
secp256k1_sha256 sha256;
|
||||
unsigned char b32[32];
|
||||
int ret = 1;
|
||||
const secp256k1_hash_ctx *hash_ctx = secp256k1_get_hash_context(ctx);
|
||||
|
||||
if (blind32) {
|
||||
secp256k1_scalar blind;
|
||||
|
|
@ -219,9 +221,10 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s
|
|||
}
|
||||
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&sha256, prefix1, 16);
|
||||
secp256k1_sha256_write(&sha256, key32, 32);
|
||||
secp256k1_sha256_finalize(&sha256, b32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha256, prefix1, 16);
|
||||
secp256k1_sha256_write(hash_ctx, &sha256, key32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha256, b32);
|
||||
secp256k1_sha256_clear(&sha256);
|
||||
ret &= secp256k1_fe_set_b32_limit(&t, b32);
|
||||
shallue_van_de_woestijne(&add, &t);
|
||||
if (blind32) {
|
||||
|
|
@ -231,9 +234,10 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s
|
|||
}
|
||||
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&sha256, prefix2, 16);
|
||||
secp256k1_sha256_write(&sha256, key32, 32);
|
||||
secp256k1_sha256_finalize(&sha256, b32);
|
||||
secp256k1_sha256_write(hash_ctx, &sha256, prefix2, 16);
|
||||
secp256k1_sha256_write(hash_ctx, &sha256, key32, 32);
|
||||
secp256k1_sha256_finalize(hash_ctx, &sha256, b32);
|
||||
secp256k1_sha256_clear(&sha256);
|
||||
ret &= secp256k1_fe_set_b32_limit(&t, b32);
|
||||
shallue_van_de_woestijne(&add, &t);
|
||||
secp256k1_gej_add_ge(&accum, &accum, &add);
|
||||
|
|
@ -341,6 +345,9 @@ int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *bl
|
|||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(blind_out != NULL);
|
||||
ARG_CHECK(blinds != NULL);
|
||||
for (i = 0; i < n; i++) {
|
||||
ARG_CHECK(blinds[i] != NULL);
|
||||
}
|
||||
ARG_CHECK(npositive <= n);
|
||||
(void) ctx;
|
||||
secp256k1_scalar_set_int(&acc, 0);
|
||||
|
|
@ -368,6 +375,12 @@ int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k
|
|||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(!pcnt || (commits != NULL));
|
||||
ARG_CHECK(!ncnt || (ncommits != NULL));
|
||||
for (i = 0; i < pcnt; i++) {
|
||||
ARG_CHECK(commits[i] != NULL);
|
||||
}
|
||||
for (i = 0; i < ncnt; i++) {
|
||||
ARG_CHECK(ncommits[i] != NULL);
|
||||
}
|
||||
(void) ctx;
|
||||
secp256k1_gej_set_infinity(&accj);
|
||||
for (i = 0; i < ncnt; i++) {
|
||||
|
|
@ -392,6 +405,10 @@ int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, c
|
|||
ARG_CHECK(n_total == 0 || generator_blind != NULL);
|
||||
ARG_CHECK(n_total == 0 || blinding_factor != NULL);
|
||||
ARG_CHECK(n_total > n_inputs);
|
||||
for (i = 0; i < n_total; i++) {
|
||||
ARG_CHECK(generator_blind[i] != NULL);
|
||||
ARG_CHECK(blinding_factor[i] != NULL);
|
||||
}
|
||||
(void) ctx;
|
||||
|
||||
if (n_total == 0) {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ static void secp256k1_pedersen_scalar_set_u64(secp256k1_scalar *sec, uint64_t va
|
|||
value <<= 8;
|
||||
}
|
||||
secp256k1_scalar_set_b32(sec, data, NULL);
|
||||
memset(data, 0, 32);
|
||||
secp256k1_memclear_explicit(data, 32);
|
||||
}
|
||||
|
||||
static void secp256k1_pedersen_ecmult_small(secp256k1_gej *r, uint64_t gn, const secp256k1_ge* genp) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "../../scalar.h"
|
||||
#include "../../testrand.h"
|
||||
#include "../../util.h"
|
||||
#include "../../unit_test.h"
|
||||
|
||||
#include "../../../include/secp256k1_generator.h"
|
||||
|
||||
|
|
@ -23,8 +24,8 @@ static void test_generator_api(void) {
|
|||
unsigned char sergen[33];
|
||||
secp256k1_generator gen;
|
||||
|
||||
secp256k1_testrand256(key);
|
||||
secp256k1_testrand256(blind);
|
||||
testrand256(key);
|
||||
testrand256(blind);
|
||||
|
||||
CHECK(secp256k1_generator_generate(CTX, &gen, key) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_generator_generate(CTX, NULL, key));
|
||||
|
|
@ -196,9 +197,9 @@ static void test_pedersen_api(void) {
|
|||
unsigned char blind_out[32];
|
||||
const unsigned char *blind_ptr = blind;
|
||||
unsigned char *blind_out_ptr = blind_out;
|
||||
uint64_t val = secp256k1_testrand32();
|
||||
uint64_t val = testrand32();
|
||||
|
||||
secp256k1_testrand256(blind);
|
||||
testrand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(CTX, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK_ILLEGAL(STATIC_CTX, secp256k1_pedersen_commit(STATIC_CTX, &commit, blind, val, secp256k1_generator_h));
|
||||
|
||||
|
|
@ -226,9 +227,16 @@ static void test_pedersen_api(void) {
|
|||
CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, NULL, &blind_ptr, &blind_out_ptr, 1, 0));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, NULL, &blind_out_ptr, 1, 0));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, NULL, 1, 0));
|
||||
/* check that NULL in array of generator_blind pointers is not allowed */
|
||||
blind_ptr = NULL;
|
||||
CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, &blind_out_ptr, 1, 0));
|
||||
blind_ptr = blind;
|
||||
/* check that NULL in array of blinding_factor pointers is not allowed */
|
||||
blind_out_ptr = NULL;
|
||||
CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_generator_blind_sum(CTX, &val, &blind_ptr, &blind_out_ptr, 1, 0));
|
||||
}
|
||||
|
||||
static void test_pedersen(void) {
|
||||
static void test_pedersen_internal(void) {
|
||||
secp256k1_pedersen_commitment commits[19];
|
||||
const secp256k1_pedersen_commitment *cptr[19];
|
||||
unsigned char blinds[32*19];
|
||||
|
|
@ -240,8 +248,8 @@ static void test_pedersen(void) {
|
|||
int inputs;
|
||||
int outputs;
|
||||
int total;
|
||||
inputs = (secp256k1_testrand32() & 7) + 1;
|
||||
outputs = (secp256k1_testrand32() & 7) + 2;
|
||||
inputs = (testrand32() & 7) + 1;
|
||||
outputs = (testrand32() & 7) + 2;
|
||||
total = inputs + outputs;
|
||||
for (i = 0; i < 19; i++) {
|
||||
cptr[i] = &commits[i];
|
||||
|
|
@ -249,20 +257,28 @@ static void test_pedersen(void) {
|
|||
}
|
||||
totalv = 0;
|
||||
for (i = 0; i < inputs; i++) {
|
||||
values[i] = secp256k1_testrandi64(0, INT64_MAX - totalv);
|
||||
values[i] = testrandi64(0, INT64_MAX - totalv);
|
||||
totalv += values[i];
|
||||
}
|
||||
for (i = 0; i < outputs - 1; i++) {
|
||||
values[i + inputs] = secp256k1_testrandi64(0, totalv);
|
||||
values[i + inputs] = testrandi64(0, totalv);
|
||||
totalv -= values[i + inputs];
|
||||
}
|
||||
values[total - 1] = totalv;
|
||||
|
||||
for (i = 0; i < total - 1; i++) {
|
||||
random_scalar_order(&s);
|
||||
testutil_random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
|
||||
}
|
||||
CHECK(secp256k1_pedersen_blind_sum(CTX, &blinds[(total - 1) * 32], bptr, total - 1, inputs));
|
||||
/* check that NULL in array of blind pointers is not allowed */
|
||||
for (i = 0; i < total - 1; i++) {
|
||||
unsigned char blind_out[32];
|
||||
const unsigned char *original_ptr = bptr[i];
|
||||
bptr[i] = NULL;
|
||||
CHECK_ILLEGAL(CTX, secp256k1_pedersen_blind_sum(CTX, blind_out, bptr, total - 1, inputs));
|
||||
bptr[i] = original_ptr;
|
||||
}
|
||||
for (i = 0; i < total; i++) {
|
||||
unsigned char result[33];
|
||||
secp256k1_pedersen_commitment parse;
|
||||
|
|
@ -274,10 +290,24 @@ static void test_pedersen(void) {
|
|||
}
|
||||
CHECK(secp256k1_pedersen_verify_tally(CTX, cptr, inputs, &cptr[inputs], outputs));
|
||||
CHECK(secp256k1_pedersen_verify_tally(CTX, &cptr[inputs], outputs, cptr, inputs));
|
||||
/* check that NULL in array of commits pointers is not allowed */
|
||||
for (i = 0; i < inputs; i++) {
|
||||
const secp256k1_pedersen_commitment *original_ptr = cptr[i];
|
||||
cptr[i] = NULL;
|
||||
CHECK_ILLEGAL(CTX, secp256k1_pedersen_verify_tally(CTX, cptr, inputs, &cptr[inputs], outputs));
|
||||
cptr[i] = original_ptr;
|
||||
}
|
||||
/* check that NULL in array of ncommits pointers is not allowed */
|
||||
for (i = 0; i < outputs; i++) {
|
||||
const secp256k1_pedersen_commitment *original_ptr = cptr[inputs + i];
|
||||
cptr[inputs + i] = NULL;
|
||||
CHECK_ILLEGAL(CTX, secp256k1_pedersen_verify_tally(CTX, cptr, inputs, &cptr[inputs], outputs));
|
||||
cptr[inputs + i] = original_ptr;
|
||||
}
|
||||
if (inputs > 0 && values[0] > 0) {
|
||||
CHECK(!secp256k1_pedersen_verify_tally(CTX, cptr, inputs - 1, &cptr[inputs], outputs));
|
||||
}
|
||||
random_scalar_order(&s);
|
||||
testutil_random_scalar_order(&s);
|
||||
for (i = 0; i < 4; i++) {
|
||||
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
|
||||
}
|
||||
|
|
@ -310,19 +340,17 @@ static void test_pedersen_commitment_fixed_vector(void) {
|
|||
CHECK(!secp256k1_pedersen_commitment_parse(CTX, &parse, result));
|
||||
}
|
||||
|
||||
/* --- Test registry --- */
|
||||
REPEAT_TEST(test_pedersen)
|
||||
|
||||
static void run_generator_tests(void) {
|
||||
int i;
|
||||
|
||||
test_shallue_van_de_woestijne();
|
||||
test_generator_fixed_vector();
|
||||
test_generator_api();
|
||||
test_generator_generate();
|
||||
test_pedersen_api();
|
||||
test_pedersen_commitment_fixed_vector();
|
||||
for (i = 0; i < COUNT / 2 + 1; i++) {
|
||||
test_pedersen();
|
||||
}
|
||||
}
|
||||
static const struct tf_test_entry tests_generator[] = {
|
||||
CASE1(test_shallue_van_de_woestijne),
|
||||
CASE1(test_generator_fixed_vector),
|
||||
CASE1(test_generator_api),
|
||||
CASE1(test_generator_generate),
|
||||
CASE1(test_pedersen),
|
||||
CASE1(test_pedersen_api),
|
||||
CASE1(test_pedersen_commitment_fixed_vector),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue