0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-09 10:43:19 -05:00

Squashed 'src/secp256k1/' changes from 21ffe4b22a9..bdf39000b9c

bdf39000b9c Merge bitcoin-core/secp256k1#1223: release: prepare for 0.3.0
b40adf23604 release: prepare for 0.3.0
90b513aadad Merge bitcoin-core/secp256k1#1229: cmake: Rename project to "libsecp256k1"
8be82d43628 cmake: Rename project to "libsecp256k1"
ef4f8bd0259 Merge bitcoin-core/secp256k1#1227: readme: Use correct build type in CMake/Windows build instructions
756b61d451d readme: Use correct build type in CMake/Windows build instructions
3295aa149bd Merge bitcoin-core/secp256k1#1225: changelog: Add entry for CMake
92098d84cf7 changelog: Add entry for CMake
df323b5c146 Merge bitcoin-core/secp256k1#1113: build: Add CMake-based build system
e1eb33724c2 ci: Add "x86_64: Windows (VS 2022)" task
10602b0030e cmake: Export config files
5468d709644 build: Add CMake-based build system
6048e6c03e4 Merge bitcoin-core/secp256k1#1222: Remove redundant checks.
eb8749fcd0f Merge bitcoin-core/secp256k1#1221: Update Changelog
5d8f53e3129 Remove redudent checks.
9d1b458d5fb Merge bitcoin-core/secp256k1#1217: Add secp256k1_fe_add_int function
d232112fa7e Update Changelog
8962fc95bb0 Merge bitcoin-core/secp256k1#1218: Update overflow check
2ef1c9b3870 Update overflow check
57573187826 Merge bitcoin-core/secp256k1#1212: Prevent dead-store elimination when clearing secrets in examples
b081f7e4cbf Add secp256k1_fe_add_int function
5660c137552 prevent optimization in algorithms
09b1d466db7 Merge bitcoin-core/secp256k1#979: Native jacobi symbol algorithm
ce3cfc78a60 doc: Describe Jacobi calculation in safegcd_implementation.md
6be01036c8a Add secp256k1_fe_is_square_var function
1de2a01c2b2 Native jacobi symbol algorithm
04c6c1b1816 Make secp256k1_modinv64_det_check_pow2 support abs val
5fffb2c7af5 Make secp256k1_i128_check_pow2 support -(2^n)
cbd25559343 Merge bitcoin-core/secp256k1#1209: build: Add SECP256K1_API_VAR to fix importing variables from DLLs
1b21aa51752 Merge bitcoin-core/secp256k1#1078: group: Save a normalize_to_zero in gej_add_ge
e4330341bd6 ci: Shutdown wineserver whenever CI script exits
9a5a611a21f build: Suppress stupid MSVC linker warning
739c53b19a2 examples: Extend sig examples by call that uses static context
914276e4d27 build: Add SECP256K1_API_VAR to fix importing variables from DLLs
1cca7c1744b Merge bitcoin-core/secp256k1#1206: build: Add -Wreserved-identifier supported by clang
8c7e0fc1de0 build: Add -Wreserved-identifier supported by clang
8ebe5c52050 Merge bitcoin-core/secp256k1#1201: ci: Do not set git's `user.{email,name}` config options
5596ec5c2cf Merge bitcoin-core/secp256k1#1203: Do not link `bench` and `ctime_tests` to `COMMON_LIB`
ef39721ccce Do not link `bench` and `ctime_tests` to `COMMON_LIB`
9b60e3148d8 ci: Do not set git's `user.{email,name}` config options
e1817a6f54f Merge bitcoin-core/secp256k1#1199: ci: Minor improvements inspired by Bitcoin Core
1bff2005885 Merge bitcoin-core/secp256k1#1200: Drop no longer used Autoheader macros
9b7d18669dc Drop no longer used Autoheader macros
c2415866c7a ci: Don't fetch git history
0ecf3188515 ci: Use remote pull/merge ref instead of local git merge
2b77240b3ba Merge bitcoin-core/secp256k1#1172: benchmarks: fix bench_scalar_split
eb6bebaee39 scalar: restrict split_lambda args, improve doc and VERIFY_CHECKs
7f49aa7f2dc ci: add test job with -DVERIFY
620ba3d74be benchmarks: fix bench_scalar_split
5fbff5d348f Merge bitcoin-core/secp256k1#1170: contexts: Forbid destroying, cloning and randomizing the static context
233822d849d Merge bitcoin-core/secp256k1#1195: ctime_tests: improve output when CHECKMEM_RUNNING is not defined
ad7433b1409 Merge bitcoin-core/secp256k1#1196: Drop no longer used variables from the build system
e39d954f118 tests: Add CHECK_ILLEGAL(_VOID) macros and use in static ctx tests
2cd4e3c0a97 Drop no longer used `SECP_{LIBS,INCLUDE}` variables
613626f94c7 Drop no longer used `SECP_TEST_{LIBS,INCLUDE}` variables
61841fc9ee5 contexts: Forbid randomizing secp256k1_context_static
4b6df5e33e1 contexts: Forbid cloning/destroying secp256k1_context_static
b1579cf5fb4 Merge bitcoin-core/secp256k1#1194: Ensure safety of ctz_debruijn implementation.
8f51229e034 ctime_tests: improve output when CHECKMEM_RUNNING is not defined
d6ff738d5bb Ensure safety of ctz_debruijn implementation.
a01a7d86dc2 Merge bitcoin-core/secp256k1#1192: Switch to exhaustive groups with small B coefficient
a7a7bfaf3dc Merge bitcoin-core/secp256k1#1190: Make all non-API functions (except main) static
f29a3270923 Merge bitcoin-core/secp256k1#1169: Add support for msan instead of valgrind (for memcheck and ctime test)
ff8edf89e2e Merge bitcoin-core/secp256k1#1193: Add `noverify_tests` to `.gitignore`
ce60785b265 Introduce SECP256K1_B macro for curve b coefficient
4934aa79958 Switch to exhaustive groups with small B coefficient
d4a6b58df74 Add `noverify_tests` to `.gitignore`
88e80722d2a Merge bitcoin-core/secp256k1#1160: Makefile: add `-I$(top_srcdir)/{include,src}` to `CPPFLAGS` for precomputed
0f088ec1126 Rename CTIMETEST -> CTIMETESTS
74b026f05d5 Add runtime checking for DECLASSIFY flag
5e2e6fcfc0e Run ctime test in Linux MSan CI job
18974061a3f Make ctime tests building configurable
5048be17e93 Rename valgrind_ctime_test -> ctime_tests
6eed6c18ded Update error messages to suggest msan as well
8e11f89a685 Add support for msan integration to checkmem.h
8dc64079eb1 Add compile-time error to valgrind_ctime_test
0db05a770eb Abstract interactions with valgrind behind new checkmem.h
4f1a54e41d8 Move valgrind CPPFLAGS into SECP_CONFIG_DEFINES
cc3b8a4f404 Merge bitcoin-core/secp256k1#1187: refactor: Rename global variables in tests
9a93f48f502 refactor: Rename STTC to STATIC_CTX in tests
3385a2648d7 refactor: Rename global variables to uppercase in tests
e03ef865593 Make all non-API functions (except main) static
cbe41ac138b Merge bitcoin-core/secp256k1#1188: tests: Add noverify_tests which is like tests but without VERIFY
203760023c6 tests: Add noverify_tests which is like tests but without VERIFY
e862c4af0c5 Makefile: add -I$(top_srcdir)/src to CPPFLAGS for precomputed
0eb3000417f Merge bitcoin-core/secp256k1#1186: tests: Tidy context tests
39e8f0e3d7b refactor: Separate run_context_tests into static vs proper contexts
a4a09379b1a tests: Clean up and improve run_context_tests() further
fc90bb56956 refactor: Tidy up main()
f32a36f620e tests: Don't use global context for context tests
ce4f936c4fa tests: Tidy run_context_tests() by extracting functions
18e0db30cb4 tests: Don't recreate global context in scratch space test
b19806122e9 tests: Use global copy of secp256k1_context_static instead of clone
2a39ac162e0 Merge bitcoin-core/secp256k1#1185: Drop `SECP_CONFIG_DEFINES` from examples
2f9ca284e2a Drop `SECP_CONFIG_DEFINES` from examples
31ed5386e84 Merge bitcoin-core/secp256k1#1183: Bugfix: pass SECP_CONFIG_DEFINES to bench compilation
c0a555b2ae3 Bugfix: pass SECP_CONFIG_DEFINES to bench compilation
01b819a8c7d Merge bitcoin-core/secp256k1#1158: Add a secp256k1_i128_to_u64 function.
eacad90f699 Merge bitcoin-core/secp256k1#1171: Change ARG_CHECK_NO_RETURN to ARG_CHECK_VOID which returns (void)
3f57b9f7749 Merge bitcoin-core/secp256k1#1177: Some improvements to the changelog
c30b889f17e Clarify that the ABI-incompatible versions are earlier
881fc33d0c1 Consistency in naming of modules
665ba77e793 Merge bitcoin-core/secp256k1#1178: Drop `src/libsecp256k1-config.h`
75d7b7f5bae Merge bitcoin-core/secp256k1#1154: ci: set -u in cirrus.sh to treat unset variables as an error
7a746882013 ci: add missing CFLAGS & CPPFLAGS variable to print_environment
c2e0fdadebd ci: set -u in cirrus.sh to treat unset variables as an error
9c5a4d21bbe Do not define unused `HAVE_VALGRIND` macro
ad8647f548c Drop no longer relevant files from `.gitignore`
b627ba7050b Remove dependency on `src/libsecp256k1-config.h`
9ecf8149a19 Reduce font size in changelog
2dc133a67ff Add more changelog entries
ac233e181a5 Add links to diffs to changelog
cee8223ef6d Mention semantic versioning in changelog
9a8d65f07f1 Merge bitcoin-core/secp256k1#1174: release cleanup: bump version after 0.2.0
02ebc290f74 release cleanup: bump version after 0.2.0
b6b360efafc doc: improve message of cleanup commit
a49e0940ad6 docs: Fix typo
2551cdac903 tests: Fix code formatting
c635c1bfd54 Change ARG_CHECK_NO_RETURN to ARG_CHECK_VOID which returns (void)
cf66f2357c6 refactor: Add helper function secp256k1_context_is_proper()
d2164752053 test secp256k1_i128_to_i64
4bc429019dc Add a secp256k1_i128_to_u64 function.
e089eecc1e5 group: Further simply gej_add_ge
ac71020ebe0 group: Save a normalize_to_zero in gej_add_ge

git-subtree-dir: src/secp256k1
git-subtree-split: bdf39000b9c6a0818e7149ccb500873d079e6e85
This commit is contained in:
Pieter Wuille 2023-03-08 17:41:24 -05:00
parent 9d47e7b71b
commit 763079a3f1
72 changed files with 3236 additions and 1682 deletions

View file

@ -1,6 +1,9 @@
env: env:
### cirrus config
CIRRUS_CLONE_DEPTH: 1
### compiler options ### compiler options
HOST: HOST:
WRAPPER_CMD:
# Specific warnings can be disabled with -Wno-error=foo. # 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. # -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual.
WERROR_CFLAGS: -Werror -pedantic-errors WERROR_CFLAGS: -Werror -pedantic-errors
@ -22,7 +25,7 @@ env:
SECP256K1_TEST_ITERS: SECP256K1_TEST_ITERS:
BENCH: yes BENCH: yes
SECP256K1_BENCH_ITERS: 2 SECP256K1_BENCH_ITERS: 2
CTIMETEST: yes CTIMETESTS: yes
# Compile and run the tests # Compile and run the tests
EXAMPLES: yes EXAMPLES: yes
@ -35,10 +38,12 @@ cat_logs_snippet: &CAT_LOGS
always: always:
cat_tests_log_script: cat_tests_log_script:
- cat tests.log || true - cat tests.log || true
cat_noverify_tests_log_script:
- cat noverify_tests.log || true
cat_exhaustive_tests_log_script: cat_exhaustive_tests_log_script:
- cat exhaustive_tests.log || true - cat exhaustive_tests.log || true
cat_valgrind_ctime_test_log_script: cat_ctime_tests_log_script:
- cat valgrind_ctime_test.log || true - cat ctime_tests.log || true
cat_bench_log_script: cat_bench_log_script:
- cat bench.log || true - cat bench.log || true
cat_config_log_script: cat_config_log_script:
@ -51,10 +56,8 @@ cat_logs_snippet: &CAT_LOGS
merge_base_script_snippet: &MERGE_BASE merge_base_script_snippet: &MERGE_BASE
merge_base_script: merge_base_script:
- if [ "$CIRRUS_PR" = "" ]; then exit 0; fi - if [ "$CIRRUS_PR" = "" ]; then exit 0; fi
- git fetch $CIRRUS_REPO_CLONE_URL $CIRRUS_BASE_BRANCH - git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge"
- git config --global user.email "ci@ci.ci" - git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts
- git config --global user.name "ci"
- git merge FETCH_HEAD # Merge base to detect silent merge conflicts
linux_container_snippet: &LINUX_CONTAINER linux_container_snippet: &LINUX_CONTAINER
container: container:
@ -78,9 +81,10 @@ task:
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes} - env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, ASM: x86_64} - env: {WIDEMUL: int128, ASM: x86_64}
- env: { RECOVERY: yes, SCHNORRSIG: yes} - env: { RECOVERY: yes, SCHNORRSIG: yes}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no} - env: {CTIMETESTS: no, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, CPPFLAGS: -DVERIFY}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no}
- env: {CPPFLAGS: -DDETERMINISTIC} - env: {CPPFLAGS: -DDETERMINISTIC}
- env: {CFLAGS: -O0, CTIMETEST: no} - env: {CFLAGS: -O0, CTIMETESTS: no}
- env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 } - env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
- env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 } - env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 }
matrix: matrix:
@ -125,7 +129,7 @@ task:
env: env:
ASM: no ASM: no
WITH_VALGRIND: no WITH_VALGRIND: no
CTIMETEST: no CTIMETESTS: no
matrix: matrix:
- env: - env:
CC: gcc CC: gcc
@ -150,7 +154,7 @@ task:
ECDH: yes ECDH: yes
RECOVERY: yes RECOVERY: yes
SCHNORRSIG: yes SCHNORRSIG: yes
CTIMETEST: no CTIMETESTS: no
<< : *MERGE_BASE << : *MERGE_BASE
test_script: test_script:
# https://sourceware.org/bugzilla/show_bug.cgi?id=27008 # https://sourceware.org/bugzilla/show_bug.cgi?id=27008
@ -169,7 +173,7 @@ task:
ECDH: yes ECDH: yes
RECOVERY: yes RECOVERY: yes
SCHNORRSIG: yes SCHNORRSIG: yes
CTIMETEST: no CTIMETESTS: no
matrix: matrix:
- env: {} - env: {}
- env: {EXPERIMENTAL: yes, ASM: arm} - env: {EXPERIMENTAL: yes, ASM: arm}
@ -189,7 +193,7 @@ task:
ECDH: yes ECDH: yes
RECOVERY: yes RECOVERY: yes
SCHNORRSIG: yes SCHNORRSIG: yes
CTIMETEST: no CTIMETESTS: no
<< : *MERGE_BASE << : *MERGE_BASE
test_script: test_script:
- ./ci/cirrus.sh - ./ci/cirrus.sh
@ -206,7 +210,7 @@ task:
ECDH: yes ECDH: yes
RECOVERY: yes RECOVERY: yes
SCHNORRSIG: yes SCHNORRSIG: yes
CTIMETEST: no CTIMETESTS: no
<< : *MERGE_BASE << : *MERGE_BASE
test_script: test_script:
- ./ci/cirrus.sh - ./ci/cirrus.sh
@ -220,7 +224,7 @@ task:
ECDH: yes ECDH: yes
RECOVERY: yes RECOVERY: yes
SCHNORRSIG: yes SCHNORRSIG: yes
CTIMETEST: no CTIMETESTS: no
matrix: matrix:
- name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)" - name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
env: env:
@ -243,7 +247,7 @@ task:
RECOVERY: yes RECOVERY: yes
EXPERIMENTAL: yes EXPERIMENTAL: yes
SCHNORRSIG: yes SCHNORRSIG: yes
CTIMETEST: no CTIMETESTS: no
# Use a MinGW-w64 host to tell ./configure we're building for Windows. # Use a MinGW-w64 host to tell ./configure we're building for Windows.
# This will detect some MinGW-w64 tools but then make will need only # This will detect some MinGW-w64 tools but then make will need only
# the MSVC tools CC, AR and NM as specified below. # the MSVC tools CC, AR and NM as specified below.
@ -254,7 +258,7 @@ task:
# Set non-essential options that affect the CLI messages here. # Set non-essential options that affect the CLI messages here.
# (They depend on the user's taste, so we don't want to set them automatically in configure.ac.) # (They depend on the user's taste, so we don't want to set them automatically in configure.ac.)
CFLAGS: -nologo -diagnostics:caret CFLAGS: -nologo -diagnostics:caret
LDFLAGS: -XCClinker -nologo -XCClinker -diagnostics:caret LDFLAGS: -Xlinker -Xlinker -Xlinker -nologo
matrix: matrix:
- name: "x86_64 (MSVC): Windows (Debian stable, Wine)" - name: "x86_64 (MSVC): Windows (Debian stable, Wine)"
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)" - name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)"
@ -282,7 +286,7 @@ task:
ECDH: yes ECDH: yes
RECOVERY: yes RECOVERY: yes
SCHNORRSIG: yes SCHNORRSIG: yes
CTIMETEST: no CTIMETESTS: no
matrix: matrix:
- name: "Valgrind (memcheck)" - name: "Valgrind (memcheck)"
container: container:
@ -327,10 +331,11 @@ task:
ECDH: yes ECDH: yes
RECOVERY: yes RECOVERY: yes
SCHNORRSIG: yes SCHNORRSIG: yes
CTIMETEST: no CTIMETESTS: yes
CC: clang CC: clang
SECP256K1_TEST_ITERS: 32 SECP256K1_TEST_ITERS: 32
ASM: no ASM: no
WITH_VALGRIND: no
container: container:
memory: 2G memory: 2G
matrix: matrix:
@ -375,3 +380,30 @@ task:
test_script: test_script:
- cd sage - cd sage
- sage prove_group_implementations.sage - sage prove_group_implementations.sage
task:
name: "x86_64: Windows (VS 2022)"
windows_container:
image: cirrusci/windowsservercore:visualstudio2022
cpu: 4
memory: 3840MB
env:
PATH: '%CIRRUS_WORKING_DIR%\build\src\RelWithDebInfo;%PATH%'
x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"'
# Ignore MSBuild warning MSB8029.
# See: https://learn.microsoft.com/en-us/visualstudio/msbuild/errors/msb8029?view=vs-2022
IgnoreWarnIntDirInTempDetected: 'true'
merge_script:
- PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL pull/$env:CIRRUS_PR/merge; git reset --hard FETCH_HEAD; }
configure_script:
- '%x64_NATIVE_TOOLS%'
- cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
build_script:
- '%x64_NATIVE_TOOLS%'
- cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5
check_script:
- '%x64_NATIVE_TOOLS%'
- ctest --test-dir build -j 5
- build\src\RelWithDebInfo\bench_ecmult.exe
- build\src\RelWithDebInfo\bench_internal.exe
- build\src\RelWithDebInfo\bench.exe

9
.gitignore vendored
View file

@ -1,11 +1,12 @@
bench bench
bench_ecmult bench_ecmult
bench_internal bench_internal
noverify_tests
tests tests
exhaustive_tests exhaustive_tests
precompute_ecmult_gen precompute_ecmult_gen
precompute_ecmult precompute_ecmult
valgrind_ctime_test ctime_tests
ecdh_example ecdh_example
ecdsa_example ecdsa_example
schnorr_example schnorr_example
@ -42,8 +43,6 @@ coverage.*.html
*.gcno *.gcno
*.gcov *.gcov
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
build-aux/ar-lib build-aux/ar-lib
build-aux/config.guess build-aux/config.guess
build-aux/config.sub build-aux/config.sub
@ -58,5 +57,7 @@ build-aux/m4/ltversion.m4
build-aux/missing build-aux/missing
build-aux/compile build-aux/compile
build-aux/test-driver build-aux/test-driver
src/stamp-h1
libsecp256k1.pc libsecp256k1.pc
# Default CMake build directory.
/build

View file

@ -1,28 +1,61 @@
# Changelog # Changelog
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). 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] ## [Unreleased]
## [0.3.0] - 2023-03-08
#### Added
- Added experimental support for CMake builds. Traditional GNU Autotools builds (`./configure` and `make`) remain fully supported.
- Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory.
- Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target.
#### Fixed
- Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning.
#### Changed
- Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.)
- Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization.
#### Removed
- Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags).
#### ABI Compatibility
Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is *not* compatible with previous versions.
## [0.2.0] - 2022-12-12 ## [0.2.0] - 2022-12-12
### Added #### Added
- Added usage examples for common use cases in a new `examples/` directory.
- Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`. - Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`.
- Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms.
### Changed #### Changed
- Enabled modules schnorrsig, extrakeys and ECDH by default in `./configure`. - Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`.
- The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API.
### Deprecated #### Deprecated
- Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead. - Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead.
- Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`. - Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`.
- Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`.
### ABI Compatibility #### ABI Compatibility
Since this is the first release, we do not compare application binary interfaces. Since this is the first release, we do not compare application binary interfaces.
However, there are unreleased versions of libsecp256k1 that are *not* ABI compatible with this version. However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version.
## [0.1.0] - 2013-03-05 to 2021-12-25 ## [0.1.0] - 2013-03-05 to 2021-12-25
This version was in fact never released. This version was in fact never released.
The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6). 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. Therefore, this version number does not uniquely identify a set of source files.
[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...HEAD
[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0
[0.1.0]: https://github.com/bitcoin-core/secp256k1/commit/423b6d19d373f1224fd671a982584d7e7900bc93

302
CMakeLists.txt Normal file
View file

@ -0,0 +1,302 @@
cmake_minimum_required(VERSION 3.1)
if(CMAKE_VERSION VERSION_GREATER 3.14)
# MSVC runtime library flags are selected by the CMAKE_MSVC_RUNTIME_LIBRARY abstraction.
cmake_policy(SET CMP0091 NEW)
# MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.
cmake_policy(SET CMP0092 NEW)
endif()
# 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.
project(libsecp256k1 VERSION 0.3.0 LANGUAGES C)
# 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 2)
set(${PROJECT_NAME}_LIB_VERSION_REVISION 0)
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
set(CMAKE_C_STANDARD 90)
set(CMAKE_C_EXTENSIONS OFF)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
# We do not use CMake's BUILD_SHARED_LIBS option.
option(SECP256K1_BUILD_SHARED "Build shared library." ON)
option(SECP256K1_BUILD_STATIC "Build static library." ON)
if(NOT SECP256K1_BUILD_SHARED AND NOT SECP256K1_BUILD_STATIC)
message(FATAL_ERROR "At least one of SECP256K1_BUILD_SHARED and SECP256K1_BUILD_STATIC must be enabled.")
endif()
option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
if(SECP256K1_ENABLE_MODULE_ECDH)
add_definitions(-DENABLE_MODULE_ECDH=1)
endif()
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
if(SECP256K1_ENABLE_MODULE_RECOVERY)
add_definitions(-DENABLE_MODULE_RECOVERY=1)
endif()
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
add_definitions(-DENABLE_MODULE_SCHNORRSIG=1)
endif()
if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
add_definitions(-DENABLE_MODULE_EXTRAKEYS=1)
endif()
option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
add_definitions(-DUSE_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)
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_definitions(-DECMULT_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)
endif()
add_definitions(-DECMULT_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")
check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value)
add_definitions(-DUSE_FORCE_WIDEMUL_${widemul_upper_value}=1)
endif()
mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm\" (experimental). [default=AUTO]")
set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm")
check_string_option_value(SECP256K1_ASM)
if(SECP256K1_ASM STREQUAL "arm")
enable_language(ASM)
add_definitions(-DUSE_EXTERNAL_ASM=1)
elseif(SECP256K1_ASM)
include(Check64bitAssembly)
check_64bit_assembly()
if(HAS_64BIT_ASM)
set(SECP256K1_ASM "x86_64")
add_definitions(-DUSE_ASM_X86_64=1)
elseif(SECP256K1_ASM STREQUAL "AUTO")
set(SECP256K1_ASM "OFF")
else()
message(FATAL_ERROR "x86_64 assembly optimization requested but not available.")
endif()
endif()
option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
if(NOT SECP256K1_EXPERIMENTAL)
if(SECP256K1_ASM STREQUAL "arm")
message(FATAL_ERROR "ARM assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
endif()
endif()
set(SECP256K1_VALGRIND "AUTO" CACHE STRING "Build with extra checks for running inside Valgrind. [default=AUTO]")
set_property(CACHE SECP256K1_VALGRIND PROPERTY STRINGS "AUTO" "OFF" "ON")
check_string_option_value(SECP256K1_VALGRIND)
if(SECP256K1_VALGRIND)
find_package(Valgrind MODULE)
if(Valgrind_FOUND)
set(SECP256K1_VALGRIND ON)
include_directories(${Valgrind_INCLUDE_DIR})
add_definitions(-DVALGRIND)
elseif(SECP256K1_VALGRIND STREQUAL "AUTO")
set(SECP256K1_VALGRIND OFF)
else()
message(FATAL_ERROR "Valgrind support requested but valgrind/memcheck.h header not available.")
endif()
endif()
option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON)
option(SECP256K1_BUILD_TESTS "Build tests." ON)
option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON)
option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND})
option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF)
# Redefine configuration flags.
# We leave assertions on, because they are only used in the examples, and we want them always on there.
if(MSVC)
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
else()
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
# Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.)
string(REGEX REPLACE "-O3[ \t\r\n]*" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
endif()
# Define custom "Coverage" build type.
set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage -Wno-unused-parameter" CACHE STRING
"Flags used by the C compiler during \"Coverage\" builds."
FORCE
)
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING
"Flags used for linking binaries during \"Coverage\" builds."
FORCE
)
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING
"Flags used by the shared libraries linker during \"Coverage\" builds."
FORCE
)
mark_as_advanced(
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE
)
if(CMAKE_CONFIGURATION_TYPES)
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage")
endif()
get_property(cached_cmake_build_type CACHE CMAKE_BUILD_TYPE PROPERTY TYPE)
if(cached_cmake_build_type)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
STRINGS "RelWithDebInfo" "Release" "Debug" "MinSizeRel" "Coverage"
)
endif()
set(default_build_type "RelWithDebInfo")
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
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()
include(TryAddCompileOption)
if(MSVC)
try_add_compile_option(/W2)
try_add_compile_option(/wd4146)
else()
try_add_compile_option(-pedantic)
try_add_compile_option(-Wall)
try_add_compile_option(-Wcast-align)
try_add_compile_option(-Wcast-align=strict)
try_add_compile_option(-Wconditional-uninitialized)
try_add_compile_option(-Wextra)
try_add_compile_option(-Wnested-externs)
try_add_compile_option(-Wno-long-long)
try_add_compile_option(-Wno-overlength-strings)
try_add_compile_option(-Wno-unused-function)
try_add_compile_option(-Wreserved-identifier)
try_add_compile_option(-Wshadow)
try_add_compile_option(-Wstrict-prototypes)
try_add_compile_option(-Wundef)
endif()
if(CMAKE_VERSION VERSION_GREATER 3.2)
# Honor visibility properties for all target types.
# See: https://cmake.org/cmake/help/latest/policy/CMP0063.html
cmake_policy(SET CMP0063 NEW)
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()
endif()
add_subdirectory(src)
if(SECP256K1_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
message("\n")
message("secp256k1 configure summary")
message("===========================")
message("Build artifacts:")
message(" shared library ...................... ${SECP256K1_BUILD_SHARED}")
message(" static library ...................... ${SECP256K1_BUILD_STATIC}")
message("Optional modules:")
message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}")
message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}")
message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
message("Parameters:")
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
message("Optional features:")
message(" assembly optimization ............... ${SECP256K1_ASM}")
message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}")
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}")
endif()
message("Optional binaries:")
message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}")
message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}")
set(tests_status "${SECP256K1_BUILD_TESTS}")
if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
set(tests_status OFF)
endif()
message(" tests ............................... ${tests_status}")
message(" exhaustive tests .................... ${SECP256K1_BUILD_EXHAUSTIVE_TESTS}")
message(" ctime_tests ......................... ${SECP256K1_BUILD_CTIME_TESTS}")
message(" examples ............................ ${SECP256K1_BUILD_EXAMPLES}")
message("")
if(CMAKE_CROSSCOMPILING)
set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}")
else()
set(cross_status "FALSE")
endif()
message("Cross compiling ....................... ${cross_status}")
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("CFLAGS ................................ ${CMAKE_C_FLAGS}")
get_directory_property(compile_options COMPILE_OPTIONS)
string(REPLACE ";" " " compile_options "${compile_options}")
message("Compile options ....................... " ${compile_options})
if(DEFINED CMAKE_BUILD_TYPE)
message("Build type:")
message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}")
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}")
else()
message("Available configurations .............. ${CMAKE_CONFIGURATION_TYPES}")
message("RelWithDebInfo configuration:")
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
message("Debug configuration:")
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
endif()
message("\n")
if(SECP256K1_EXPERIMENTAL)
message(
" ******\n"
" WARNING: experimental build\n"
" Experimental features do not have stable APIs or properties, and may not be safe for production use.\n"
" ******\n"
)
endif()

View file

@ -47,6 +47,7 @@ noinst_HEADERS += src/modinv64_impl.h
noinst_HEADERS += src/precomputed_ecmult.h noinst_HEADERS += src/precomputed_ecmult.h
noinst_HEADERS += src/precomputed_ecmult_gen.h noinst_HEADERS += src/precomputed_ecmult_gen.h
noinst_HEADERS += src/assumptions.h noinst_HEADERS += src/assumptions.h
noinst_HEADERS += src/checkmem.h
noinst_HEADERS += src/util.h noinst_HEADERS += src/util.h
noinst_HEADERS += src/int128.h noinst_HEADERS += src/int128.h
noinst_HEADERS += src/int128_impl.h noinst_HEADERS += src/int128_impl.h
@ -68,12 +69,14 @@ noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
noinst_HEADERS += examples/random.h noinst_HEADERS += examples/examples_util.h
PRECOMPUTED_LIB = libsecp256k1_precomputed.la PRECOMPUTED_LIB = libsecp256k1_precomputed.la
noinst_LTLIBRARIES = $(PRECOMPUTED_LIB) noinst_LTLIBRARIES = $(PRECOMPUTED_LIB)
libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c
libsecp256k1_precomputed_la_CPPFLAGS = $(SECP_INCLUDES) # We need `-I$(top_srcdir)/src` in VPATH builds if libsecp256k1_precomputed_la_SOURCES have been recreated in the build tree.
# This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo).
libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_CONFIG_DEFINES)
if USE_EXTERNAL_ASM if USE_EXTERNAL_ASM
COMMON_LIB = libsecp256k1_common.la COMMON_LIB = libsecp256k1_common.la
@ -92,55 +95,58 @@ endif
endif endif
libsecp256k1_la_SOURCES = src/secp256k1.c libsecp256k1_la_SOURCES = src/secp256k1.c
libsecp256k1_la_CPPFLAGS = $(SECP_INCLUDES) libsecp256k1_la_CPPFLAGS = $(SECP_CONFIG_DEFINES)
libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) libsecp256k1_la_LIBADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE) libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE)
if VALGRIND_ENABLED
libsecp256k1_la_CPPFLAGS += -DVALGRIND
endif
noinst_PROGRAMS = noinst_PROGRAMS =
if USE_BENCHMARK if USE_BENCHMARK
noinst_PROGRAMS += bench bench_internal bench_ecmult noinst_PROGRAMS += bench bench_internal bench_ecmult
bench_SOURCES = src/bench.c bench_SOURCES = src/bench.c
bench_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) bench_LDADD = libsecp256k1.la
bench_CPPFLAGS = $(SECP_CONFIG_DEFINES)
bench_internal_SOURCES = src/bench_internal.c bench_internal_SOURCES = src/bench_internal.c
bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) bench_internal_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
bench_internal_CPPFLAGS = $(SECP_INCLUDES) bench_internal_CPPFLAGS = $(SECP_CONFIG_DEFINES)
bench_ecmult_SOURCES = src/bench_ecmult.c bench_ecmult_SOURCES = src/bench_ecmult.c
bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB) bench_ecmult_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
bench_ecmult_CPPFLAGS = $(SECP_INCLUDES) bench_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES)
endif endif
TESTS = TESTS =
if USE_TESTS if USE_TESTS
noinst_PROGRAMS += tests TESTS += noverify_tests
tests_SOURCES = src/tests.c noinst_PROGRAMS += noverify_tests
tests_CPPFLAGS = $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) noverify_tests_SOURCES = src/tests.c
if VALGRIND_ENABLED noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
tests_CPPFLAGS += -DVALGRIND noverify_tests_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
noinst_PROGRAMS += valgrind_ctime_test noverify_tests_LDFLAGS = -static
valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c
valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
if !ENABLE_COVERAGE if !ENABLE_COVERAGE
tests_CPPFLAGS += -DVERIFY
endif
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
tests_LDFLAGS = -static
TESTS += tests TESTS += tests
noinst_PROGRAMS += tests
tests_SOURCES = $(noverify_tests_SOURCES)
tests_CPPFLAGS = $(noverify_tests_CPPFLAGS) -DVERIFY
tests_LDADD = $(noverify_tests_LDADD)
tests_LDFLAGS = $(noverify_tests_LDFLAGS)
endif
endif
if USE_CTIME_TESTS
noinst_PROGRAMS += ctime_tests
ctime_tests_SOURCES = src/ctime_tests.c
ctime_tests_LDADD = libsecp256k1.la
ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
endif endif
if USE_EXHAUSTIVE_TESTS if USE_EXHAUSTIVE_TESTS
noinst_PROGRAMS += exhaustive_tests noinst_PROGRAMS += exhaustive_tests
exhaustive_tests_SOURCES = src/tests_exhaustive.c exhaustive_tests_SOURCES = src/tests_exhaustive.c
exhaustive_tests_CPPFLAGS = $(SECP_INCLUDES) exhaustive_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
if !ENABLE_COVERAGE if !ENABLE_COVERAGE
exhaustive_tests_CPPFLAGS += -DVERIFY exhaustive_tests_CPPFLAGS += -DVERIFY
endif endif
# Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables). # Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables).
exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB) exhaustive_tests_LDADD = $(COMMON_LIB)
exhaustive_tests_LDFLAGS = -static exhaustive_tests_LDFLAGS = -static
TESTS += exhaustive_tests TESTS += exhaustive_tests
endif endif
@ -184,12 +190,12 @@ EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen
CLEANFILES = $(EXTRA_PROGRAMS) CLEANFILES = $(EXTRA_PROGRAMS)
precompute_ecmult_SOURCES = src/precompute_ecmult.c precompute_ecmult_SOURCES = src/precompute_ecmult.c
precompute_ecmult_CPPFLAGS = $(SECP_INCLUDES) precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES)
precompute_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) precompute_ecmult_LDADD = $(COMMON_LIB)
precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c
precompute_ecmult_gen_CPPFLAGS = $(SECP_INCLUDES) precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES)
precompute_ecmult_gen_LDADD = $(SECP_LIBS) $(COMMON_LIB) precompute_ecmult_gen_LDADD = $(COMMON_LIB)
# See Automake manual, Section "Errors with distclean". # See Automake manual, Section "Errors with distclean".
# We don't list any dependencies for the prebuilt files here because # We don't list any dependencies for the prebuilt files here because

View file

@ -60,10 +60,8 @@ Implementation details
* Optional runtime blinding which attempts to frustrate differential power analysis. * Optional runtime blinding which attempts to frustrate differential power analysis.
* The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally. * The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally.
Build steps Building with Autotools
----------- -----------------------
libsecp256k1 is built using autotools:
$ ./autogen.sh $ ./autogen.sh
$ ./configure $ ./configure
@ -73,6 +71,43 @@ libsecp256k1 is built using autotools:
To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags. 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.
Building with CMake (experimental)
----------------------------------
To maintain a pristine source tree, CMake encourages to perform an out-of-source build by using a separate dedicated build tree.
### Building on POSIX systems
$ mkdir build && cd build
$ cmake ..
$ make
$ make check # run the test suite
$ sudo make install # optional
To compile optional modules (such as Schnorr signatures), you need to run `cmake` with additional flags (such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG=ON`). Run `cmake .. -LH` to see the full list of available flags.
### Cross compiling
To alleviate issues with cross compiling, preconfigured toolchain files are available in the `cmake` directory.
For example, to cross compile for Windows:
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/x86_64-w64-mingw32.toolchain.cmake
To cross compile for Android with [NDK](https://developer.android.com/ndk/guides/cmake) (using NDK's toolchain file, and assuming the `ANDROID_NDK_ROOT` environment variable has been set):
$ cmake .. -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT}/build/cmake/android.toolchain.cmake" -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=28
### Building on Windows
To build on Windows with Visual Studio, a proper [generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#visual-studio-generators) must be specified for a new build tree.
The following example assumes using of Visual Studio 2022 and CMake v3.21+.
In "Developer Command Prompt for VS 2022":
>cmake -G "Visual Studio 17 2022" -A x64 -S . -B build
>cmake --build build --config RelWithDebInfo
Usage examples Usage examples
----------- -----------
Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`. Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.

View file

@ -20,7 +20,7 @@ if test x"$has_valgrind" != x"yes"; then
#if defined(NVALGRIND) #if defined(NVALGRIND)
# error "Valgrind does not support this platform." # error "Valgrind does not support this platform."
#endif #endif
]])], [has_valgrind=yes; AC_DEFINE(HAVE_VALGRIND,1,[Define this symbol if valgrind is installed, and it supports the host platform])]) ]])], [has_valgrind=yes])
fi fi
AC_MSG_RESULT($has_valgrind) AC_MSG_RESULT($has_valgrind)
]) ])

View file

@ -1,7 +1,6 @@
#!/bin/sh #!/bin/sh
set -e set -eux
set -x
export LC_ALL=C export LC_ALL=C
@ -11,14 +10,20 @@ print_environment() {
set +x set +x
# There are many ways to print variable names and their content. This one # There are many ways to print variable names and their content. This one
# does not rely on bash. # does not rely on bash.
for i in WERROR_CFLAGS MAKEFLAGS BUILD \ for var in WERROR_CFLAGS MAKEFLAGS BUILD \
ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \ ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
EXPERIMENTAL ECDH RECOVERY SCHNORRSIG \ EXPERIMENTAL ECDH RECOVERY SCHNORRSIG \
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETEST\ SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
EXAMPLES \ EXAMPLES \
WRAPPER_CMD CC AR NM HOST HOST WRAPPER_CMD \
CC CFLAGS CPPFLAGS AR NM
do do
eval 'printf "%s %s " "$i=\"${'"$i"'}\""' eval "isset=\${$var+x}"
if [ -n "$isset" ]; then
eval "val=\${$var}"
# shellcheck disable=SC2154
printf '%s="%s" ' "$var" "$val"
fi
done done
echo "$0" echo "$0"
set -x set -x
@ -29,6 +34,8 @@ print_environment
# This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously. # This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously.
case "$WRAPPER_CMD" in case "$WRAPPER_CMD" in
*wine*) *wine*)
# Make sure to shutdown wineserver whenever we exit.
trap "wineserver -k || true" EXIT INT HUP
# This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards. # This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards.
wineserver -p && wine hh.exe wineserver -p && wine hh.exe
;; ;;
@ -36,7 +43,7 @@ esac
env >> test_env.log env >> test_env.log
if [ -n "$CC" ]; then if [ -n "${CC+x}" ]; then
# The MSVC compiler "cl" doesn't understand "-v" # The MSVC compiler "cl" doesn't understand "-v"
$CC -v || true $CC -v || true
fi fi
@ -57,6 +64,7 @@ fi
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \ --enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
--enable-module-schnorrsig="$SCHNORRSIG" \ --enable-module-schnorrsig="$SCHNORRSIG" \
--enable-examples="$EXAMPLES" \ --enable-examples="$EXAMPLES" \
--enable-ctime-tests="$CTIMETESTS" \
--with-valgrind="$WITH_VALGRIND" \ --with-valgrind="$WITH_VALGRIND" \
--host="$HOST" $EXTRAFLAGS --host="$HOST" $EXTRAFLAGS
@ -73,14 +81,15 @@ export LOG_COMPILER="$WRAPPER_CMD"
make "$BUILD" make "$BUILD"
# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
EXEC='./libtool --mode=execute'
if [ -n "$WRAPPER_CMD" ]
then
EXEC="$EXEC $WRAPPER_CMD"
fi
if [ "$BENCH" = "yes" ] if [ "$BENCH" = "yes" ]
then then
# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
EXEC='./libtool --mode=execute'
if [ -n "$WRAPPER_CMD" ]
then
EXEC="$EXEC $WRAPPER_CMD"
fi
{ {
$EXEC ./bench_ecmult $EXEC ./bench_ecmult
$EXEC ./bench_internal $EXEC ./bench_internal
@ -88,9 +97,13 @@ then
} >> bench.log 2>&1 } >> bench.log 2>&1
fi fi
if [ "$CTIMETEST" = "yes" ] if [ "$CTIMETESTS" = "yes" ]
then then
./libtool --mode=execute valgrind --error-exitcode=42 ./valgrind_ctime_test > valgrind_ctime_test.log 2>&1 if [ "$WITH_VALGRIND" = "yes" ]; then
./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1
else
$EXEC ./ctime_tests > ctime_tests.log 2>&1
fi
fi fi
# Rebuild precomputed files (if not cross-compiling). # Rebuild precomputed files (if not cross-compiling).
@ -100,9 +113,6 @@ then
make precomp make precomp
fi fi
# Shutdown wineserver again
wineserver -k || true
# Check that no repo files have been modified by the build. # Check that no repo files have been modified by the build.
# (This fails for example if the precomp files need to be updated in the repo.) # (This fails for example if the precomp files need to be updated in the repo.)
git diff --exit-code git diff --exit-code

View file

@ -0,0 +1,14 @@
include(CheckCSourceCompiles)
function(check_64bit_assembly)
check_c_source_compiles("
#include <stdint.h>
int main()
{
uint64_t a = 11, tmp;
__asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\");
}
" HAS_64BIT_ASM)
set(HAS_64BIT_ASM ${HAS_64BIT_ASM} PARENT_SCOPE)
endfunction()

View file

@ -0,0 +1,12 @@
function(check_string_option_value option)
get_property(expected_values CACHE ${option} PROPERTY STRINGS)
if(expected_values)
foreach(value IN LISTS expected_values)
if(value STREQUAL "${${option}}")
return()
endif()
endforeach()
message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.")
endif()
message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.")
endfunction()

41
cmake/FindValgrind.cmake Normal file
View file

@ -0,0 +1,41 @@
if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
find_program(BREW_COMMAND brew)
execute_process(
COMMAND ${BREW_COMMAND} --prefix valgrind
OUTPUT_VARIABLE valgrind_brew_prefix
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
set(hints_paths)
if(valgrind_brew_prefix)
set(hints_paths ${valgrind_brew_prefix}/include)
endif()
find_path(Valgrind_INCLUDE_DIR
NAMES valgrind/memcheck.h
HINTS ${hints_paths}
)
if(Valgrind_INCLUDE_DIR)
include(CheckCSourceCompiles)
set(CMAKE_REQUIRED_INCLUDES ${Valgrind_INCLUDE_DIR})
check_c_source_compiles("
#include <valgrind/memcheck.h>
#if defined(NVALGRIND)
# error \"Valgrind does not support this platform.\"
#endif
int main() {}
" Valgrind_WORKS)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Valgrind
REQUIRED_VARS Valgrind_INCLUDE_DIR Valgrind_WORKS
)
mark_as_advanced(
Valgrind_INCLUDE_DIR
)

View file

@ -0,0 +1,23 @@
include(CheckCCompilerFlag)
function(try_add_compile_option option)
string(MAKE_C_IDENTIFIER ${option} result)
string(TOUPPER ${result} result)
set(result "C_SUPPORTS${result}")
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
if(NOT MSVC)
set(CMAKE_REQUIRED_FLAGS "-Werror")
endif()
check_c_compiler_flag(${option} ${result})
if(${result})
get_property(compile_options
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
PROPERTY COMPILE_OPTIONS
)
list(APPEND compile_options "${option}")
set_property(
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
PROPERTY COMPILE_OPTIONS "${compile_options}"
)
endif()
endfunction()

View file

@ -0,0 +1,3 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)

5
cmake/config.cmake.in Normal file
View file

@ -0,0 +1,5 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
check_required_components(@PROJECT_NAME@)

View file

@ -0,0 +1,3 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)

View file

@ -4,7 +4,7 @@ AC_PREREQ([2.60])
# the API. All changes in experimental modules are treated as # the API. All changes in experimental modules are treated as
# backwards-compatible and therefore at most increase the minor version. # backwards-compatible and therefore at most increase the minor version.
define(_PKG_VERSION_MAJOR, 0) define(_PKG_VERSION_MAJOR, 0)
define(_PKG_VERSION_MINOR, 2) define(_PKG_VERSION_MINOR, 3)
define(_PKG_VERSION_PATCH, 0) define(_PKG_VERSION_PATCH, 0)
define(_PKG_VERSION_IS_RELEASE, true) define(_PKG_VERSION_IS_RELEASE, true)
@ -13,7 +13,7 @@ define(_PKG_VERSION_IS_RELEASE, true)
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html # 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 # All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision. # interface and therefore only increase the revision.
define(_LIB_VERSION_CURRENT, 1) define(_LIB_VERSION_CURRENT, 2)
define(_LIB_VERSION_REVISION, 0) define(_LIB_VERSION_REVISION, 0)
define(_LIB_VERSION_AGE, 0) define(_LIB_VERSION_AGE, 0)
@ -22,9 +22,6 @@ AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG
AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4]) AC_CONFIG_MACRO_DIR([build-aux/m4])
AC_CANONICAL_HOST AC_CANONICAL_HOST
AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
AH_TOP([#define LIBSECP256K1_CONFIG_H])
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
# Require Automake 1.11.2 for AM_PROG_AR # Require Automake 1.11.2 for AM_PROG_AR
AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects]) AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
@ -105,6 +102,7 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95 SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0 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([-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([-fvisibility=hidden], $1) # GCC >= 4.0
CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS" CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
@ -117,6 +115,12 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then
SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned" SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned"
SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files SECP_TRY_APPEND_CFLAGS([-external:anglebrackets -external:W0], $1) # Suppress warnings from #include <...> files
# We pass -ignore:4217 to the MSVC linker to suppress warning 4217 when
# importing variables from a statically linked secp256k1.
# (See the libtool manual, section "Windows DLLs" for background.)
# Unfortunately, libtool tries to be too clever and strips "-Xlinker arg"
# into "arg", so this will be " -Xlinker -ignore:4217" after stripping.
LDFLAGS="-Xlinker -Xlinker -Xlinker -ignore:4217 $LDFLAGS"
fi fi
]) ])
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS) SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
@ -142,6 +146,10 @@ AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [], AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [],
[SECP_SET_DEFAULT([enable_tests], [yes], [yes])]) [SECP_SET_DEFAULT([enable_tests], [yes], [yes])])
AC_ARG_ENABLE(ctime_tests,
AS_HELP_STRING([--enable-ctime-tests],[compile constant-time tests [default=yes if valgrind enabled]]), [],
[SECP_SET_DEFAULT([enable_ctime_tests], [auto], [auto])])
AC_ARG_ENABLE(experimental, AC_ARG_ENABLE(experimental,
AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [], AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [],
[SECP_SET_DEFAULT([enable_experimental], [no], [yes])]) [SECP_SET_DEFAULT([enable_experimental], [no], [yes])])
@ -225,10 +233,13 @@ else
enable_valgrind=yes enable_valgrind=yes
fi fi
fi fi
AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
if test x"$enable_ctime_tests" = x"auto"; then
enable_ctime_tests=$enable_valgrind
fi
if test x"$enable_coverage" = x"yes"; then if test x"$enable_coverage" = x"yes"; then
AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1"
SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS" SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS"
LDFLAGS="--coverage $LDFLAGS" LDFLAGS="--coverage $LDFLAGS"
else else
@ -270,7 +281,7 @@ enable_external_asm=no
case $set_asm in case $set_asm in
x86_64) x86_64)
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1"
;; ;;
arm) arm)
enable_external_asm=yes enable_external_asm=yes
@ -283,20 +294,20 @@ no)
esac esac
if test x"$enable_external_asm" = x"yes"; then if test x"$enable_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_ASM=1"
fi fi
# Select wide multiplication implementation # Select wide multiplication implementation
case $set_widemul in case $set_widemul in
int128_struct) int128_struct)
AC_DEFINE(USE_FORCE_WIDEMUL_INT128_STRUCT, 1, [Define this symbol to force the use of the structure for simulating (unsigned) int128 based wide multiplication]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128_STRUCT=1"
;; ;;
int128) int128)
AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128=1"
;; ;;
int64) int64)
AC_DEFINE(USE_FORCE_WIDEMUL_INT64, 1, [Define this symbol to force the use of the (u)int64_t based wide multiplication implementation]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT64=1"
;; ;;
auto) auto)
;; ;;
@ -323,7 +334,7 @@ case $set_ecmult_window in
# not in range # not in range
AC_MSG_ERROR($error_window_size) AC_MSG_ERROR($error_window_size)
fi fi
AC_DEFINE_UNQUOTED(ECMULT_WINDOW_SIZE, $set_ecmult_window, [Set window size for ecmult precomputation]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_WINDOW_SIZE=$set_ecmult_window"
;; ;;
esac esac
@ -336,7 +347,7 @@ fi
case $set_ecmult_gen_precision in case $set_ecmult_gen_precision in
2|4|8) 2|4|8)
AC_DEFINE_UNQUOTED(ECMULT_GEN_PREC_BITS, $set_ecmult_gen_precision, [Set ecmult gen precision bits]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_GEN_PREC_BITS=$set_ecmult_gen_precision"
;; ;;
*) *)
AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"']) AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"'])
@ -344,7 +355,7 @@ case $set_ecmult_gen_precision in
esac esac
if test x"$enable_valgrind" = x"yes"; then if test x"$enable_valgrind" = x"yes"; then
SECP_INCLUDES="$SECP_INCLUDES $VALGRIND_CPPFLAGS" SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES $VALGRIND_CPPFLAGS -DVALGRIND"
fi fi
# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI). # Add -Werror and similar flags passed from the outside (for testing, e.g., in CI).
@ -357,26 +368,26 @@ SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
### ###
if test x"$enable_module_ecdh" = x"yes"; then if test x"$enable_module_ecdh" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1"
fi fi
if test x"$enable_module_recovery" = x"yes"; then if test x"$enable_module_recovery" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1"
fi fi
if test x"$enable_module_schnorrsig" = x"yes"; then if test x"$enable_module_schnorrsig" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1"
enable_module_extrakeys=yes enable_module_extrakeys=yes
fi fi
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig # Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
# module to set enable_module_extrakeys=yes # module to set enable_module_extrakeys=yes
if test x"$enable_module_extrakeys" = x"yes"; then if test x"$enable_module_extrakeys" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=1"
fi fi
if test x"$enable_external_default_callbacks" = x"yes"; then if test x"$enable_external_default_callbacks" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used]) SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1"
fi fi
### ###
@ -398,15 +409,12 @@ fi
### Generate output ### Generate output
### ###
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
AC_CONFIG_FILES([Makefile libsecp256k1.pc]) AC_CONFIG_FILES([Makefile libsecp256k1.pc])
AC_SUBST(SECP_INCLUDES)
AC_SUBST(SECP_LIBS)
AC_SUBST(SECP_TEST_LIBS)
AC_SUBST(SECP_TEST_INCLUDES)
AC_SUBST(SECP_CFLAGS) AC_SUBST(SECP_CFLAGS)
AC_SUBST(SECP_CONFIG_DEFINES)
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"]) AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"])
AM_CONDITIONAL([USE_CTIME_TESTS], [test x"$enable_ctime_tests" = x"yes"])
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"])
AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"]) AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"])
@ -428,6 +436,7 @@ echo "Build Options:"
echo " with external callbacks = $enable_external_default_callbacks" echo " with external callbacks = $enable_external_default_callbacks"
echo " with benchmarks = $enable_benchmark" echo " with benchmarks = $enable_benchmark"
echo " with tests = $enable_tests" echo " with tests = $enable_tests"
echo " with ctime tests = $enable_ctime_tests"
echo " with coverage = $enable_coverage" echo " with coverage = $enable_coverage"
echo " with examples = $enable_examples" echo " with examples = $enable_examples"
echo " module ecdh = $enable_module_ecdh" echo " module ecdh = $enable_module_ecdh"

View file

@ -23,7 +23,7 @@ This process also assumes that there will be no minor releases for old major rel
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
``` ```
3. Open a PR to the master branch with a commit (using message `"release: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that sets `_PKG_VERSION_IS_RELEASE` to `false` and `_PKG_VERSION_PATCH` to `$PATCH + 1` and increases `_LIB_VERSION_REVISION`. If other maintainers are not present to approve the PR, it can be merged without ACKs. 3. 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 `_PKG_VERSION_PATCH` to `$PATCH + 1` and increases `_LIB_VERSION_REVISION`. If other maintainers are not present to approve the PR, it can be merged without ACKs.
4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md). 4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
## Maintenance release ## Maintenance release

View file

@ -1,7 +1,7 @@
# The safegcd implementation in libsecp256k1 explained # The safegcd implementation in libsecp256k1 explained
This document explains the modular inverse implementation in the `src/modinv*.h` files. It is based This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files.
on the paper It is based on the paper
["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd) ["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd)
by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version. by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version.
@ -410,7 +410,7 @@ sufficient even. Given that every loop iteration performs *N* divsteps, it will
To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise
operations (and hope the C compiler isn't smart enough to turn them back into branches; see operations (and hope the C compiler isn't smart enough to turn them back into branches; see
`valgrind_ctime_test.c` for automated tests that this isn't the case). To do so, observe that a `ctime_tests.c` for automated tests that this isn't the case). To do so, observe that a
divstep can be written instead as (compare to the inner loop of `gcd` in section 1). divstep can be written instead as (compare to the inner loop of `gcd` in section 1).
```python ```python
@ -769,3 +769,51 @@ def modinv_var(M, Mi, x):
d, e = update_de(d, e, t, M, Mi) d, e = update_de(d, e, t, M, Mi)
return normalize(f, d, Mi) return normalize(f, d, Mi)
``` ```
## 8. From GCDs to Jacobi symbol
We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an
extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we
make corresponding updates to *j* using
[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties):
* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*).
* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*).
These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied
very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this
calculation is slightly simpler than the one for the modular inverse because we no longer need to
keep track of *d* and *e*.
However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for
positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative
values. We resolve this by using the following modified steps:
```python
# Before
if delta > 0 and g & 1:
delta, f, g = 1 - delta, g, (g - f) // 2
# After
if delta > 0 and g & 1:
delta, f, g = 1 - delta, g, (g + f) // 2
```
The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4
and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm
will converge. The justification for posdivsteps is completely empirical: in practice, it appears
that the vast majority of nonzero inputs converge to *f=g=gcd(f<sub>0</sub>, g<sub>0</sub>)* in a
number of steps proportional to their logarithm.
Note that:
- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached.
- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect.
- We need to update the termination condition from *g=0* to *f=1*.
We account for the possibility of nonconvergence by only performing a bounded number of
posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not
yet been found.
The optimizations in sections 3-7 above are described in the context of the original divsteps, but
in the C implementation we also adapt most of them (not including "avoiding modulus operations",
since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate
Jacobi symbols for secret data) to the posdivsteps version.

34
examples/CMakeLists.txt Normal file
View file

@ -0,0 +1,34 @@
add_library(example INTERFACE)
target_include_directories(example INTERFACE
${PROJECT_SOURCE_DIR}/include
)
target_compile_options(example INTERFACE
$<$<C_COMPILER_ID:MSVC>:/wd4005>
)
target_link_libraries(example INTERFACE
$<$<PLATFORM_ID:Windows>:bcrypt>
)
if(SECP256K1_BUILD_SHARED)
target_link_libraries(example INTERFACE secp256k1)
elseif(SECP256K1_BUILD_STATIC)
target_link_libraries(example INTERFACE secp256k1_static)
if(MSVC)
target_link_options(example INTERFACE /IGNORE:4217)
endif()
endif()
add_executable(ecdsa_example ecdsa.c)
target_link_libraries(ecdsa_example example)
add_test(ecdsa_example ecdsa_example)
if(SECP256K1_ENABLE_MODULE_ECDH)
add_executable(ecdh_example ecdh.c)
target_link_libraries(ecdh_example example)
add_test(ecdh_example ecdh_example)
endif()
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
add_executable(schnorr_example schnorr.c)
target_link_libraries(schnorr_example example)
add_test(schnorr_example schnorr_example)
endif()

View file

@ -14,8 +14,7 @@
#include <secp256k1.h> #include <secp256k1.h>
#include <secp256k1_ecdh.h> #include <secp256k1_ecdh.h>
#include "random.h" #include "examples_util.h"
int main(void) { int main(void) {
unsigned char seckey1[32]; unsigned char seckey1[32];
@ -112,12 +111,12 @@ int main(void) {
* example through "out of bounds" array access (see Heartbleed), Or the OS * example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros. * swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
* *
* TODO: Prevent these writes from being optimized out, as any good compiler * Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */ * will remove any writes that aren't used. */
memset(seckey1, 0, sizeof(seckey1)); secure_erase(seckey1, sizeof(seckey1));
memset(seckey2, 0, sizeof(seckey2)); secure_erase(seckey2, sizeof(seckey2));
memset(shared_secret1, 0, sizeof(shared_secret1)); secure_erase(shared_secret1, sizeof(shared_secret1));
memset(shared_secret2, 0, sizeof(shared_secret2)); secure_erase(shared_secret2, sizeof(shared_secret2));
return 0; return 0;
} }

View file

@ -13,9 +13,7 @@
#include <secp256k1.h> #include <secp256k1.h>
#include "random.h" #include "examples_util.h"
int main(void) { int main(void) {
/* Instead of signing the message directly, we must sign a 32-byte hash. /* Instead of signing the message directly, we must sign a 32-byte hash.
@ -34,7 +32,7 @@ int main(void) {
unsigned char compressed_pubkey[33]; unsigned char compressed_pubkey[33];
unsigned char serialized_signature[64]; unsigned char serialized_signature[64];
size_t len; size_t len;
int is_signature_valid; int is_signature_valid, is_signature_valid2;
int return_val; int return_val;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig; secp256k1_ecdsa_signature sig;
@ -116,18 +114,26 @@ int main(void) {
printf("Signature: "); printf("Signature: ");
print_hex(serialized_signature, sizeof(serialized_signature)); print_hex(serialized_signature, sizeof(serialized_signature));
/* This will clear everything from the context and free the memory */ /* This will clear everything from the context and free the memory */
secp256k1_context_destroy(ctx); secp256k1_context_destroy(ctx);
/* Bonus example: if all we need is signature verification (and no key
generation or signing), we don't need to use a context created via
secp256k1_context_create(). We can simply use the static (i.e., global)
context secp256k1_context_static. See its description in
include/secp256k1.h for details. */
is_signature_valid2 = secp256k1_ecdsa_verify(secp256k1_context_static,
&sig, msg_hash, &pubkey);
assert(is_signature_valid2 == is_signature_valid);
/* It's best practice to try to clear secrets from memory after using them. /* 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 * 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 * example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros. * swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
* *
* TODO: Prevent these writes from being optimized out, as any good compiler * Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */ * will remove any writes that aren't used. */
memset(seckey, 0, sizeof(seckey)); secure_erase(seckey, sizeof(seckey));
return 0; return 0;
} }

View file

@ -71,3 +71,32 @@ static void print_hex(unsigned char* data, size_t size) {
} }
printf("\n"); printf("\n");
} }
#if defined(_MSC_VER)
// For SecureZeroMemory
#include <Windows.h>
#endif
/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
static SECP256K1_INLINE void secure_erase(void *ptr, size_t len) {
#if defined(_MSC_VER)
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
SecureZeroMemory(ptr, len);
#elif defined(__GNUC__)
/* We use a memory barrier that scares the compiler away from optimizing out the memset.
*
* Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
* in BoringSSL (ISC License):
* As best as we can tell, this is sufficient to break any optimisations that
* might try to eliminate "superfluous" memsets.
* This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is
* pretty efficient, because the compiler can still implement the memset() efficently,
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
* Yang et al. (USENIX Security 2017) for more background.
*/
memset(ptr, 0, len);
__asm__ __volatile__("" : : "r"(ptr) : "memory");
#else
void *(*volatile const volatile_memset)(void *, int, size_t) = memset;
volatile_memset(ptr, 0, len);
#endif
}

View file

@ -15,7 +15,7 @@
#include <secp256k1_extrakeys.h> #include <secp256k1_extrakeys.h>
#include <secp256k1_schnorrsig.h> #include <secp256k1_schnorrsig.h>
#include "random.h" #include "examples_util.h"
int main(void) { int main(void) {
unsigned char msg[12] = "Hello World!"; unsigned char msg[12] = "Hello World!";
@ -26,7 +26,7 @@ int main(void) {
unsigned char auxiliary_rand[32]; unsigned char auxiliary_rand[32];
unsigned char serialized_pubkey[32]; unsigned char serialized_pubkey[32];
unsigned char signature[64]; unsigned char signature[64];
int is_signature_valid; int is_signature_valid, is_signature_valid2;
int return_val; int return_val;
secp256k1_xonly_pubkey pubkey; secp256k1_xonly_pubkey pubkey;
secp256k1_keypair keypair; secp256k1_keypair keypair;
@ -135,14 +135,22 @@ int main(void) {
/* This will clear everything from the context and free the memory */ /* This will clear everything from the context and free the memory */
secp256k1_context_destroy(ctx); secp256k1_context_destroy(ctx);
/* Bonus example: if all we need is signature verification (and no key
generation or signing), we don't need to use a context created via
secp256k1_context_create(). We can simply use the static (i.e., global)
context secp256k1_context_static. See its description in
include/secp256k1.h for details. */
is_signature_valid2 = secp256k1_schnorrsig_verify(secp256k1_context_static,
signature, msg_hash, 32, &pubkey);
assert(is_signature_valid2 == is_signature_valid);
/* It's best practice to try to clear secrets from memory after using them. /* 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 * 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 * example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros. * swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
* *
* TODO: Prevent these writes from being optimized out, as any good compiler * Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */ * will remove any writes that aren't used. */
memset(seckey, 0, sizeof(seckey)); secure_erase(seckey, sizeof(seckey));
return 0; return 0;
} }

View file

@ -145,21 +145,28 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_NO_BUILD # define SECP256K1_NO_BUILD
#endif #endif
/** At secp256k1 build-time DLL_EXPORT is defined when building objects destined /* Symbol visibility. See libtool manual, section "Windows DLLs". */
* for a shared library, but not for those intended for static libraries. #if defined(_WIN32) && !defined(__GNUC__)
*/ # ifdef SECP256K1_BUILD
# ifdef DLL_EXPORT
#ifndef SECP256K1_API # define SECP256K1_API __declspec (dllexport)
# if defined(_WIN32) # define SECP256K1_API_VAR extern __declspec (dllexport)
# if defined(SECP256K1_BUILD) && defined(DLL_EXPORT)
# define SECP256K1_API __declspec(dllexport)
# else
# define SECP256K1_API
# endif # endif
# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD) # elif defined _MSC_VER
# define SECP256K1_API __attribute__ ((visibility ("default"))) # define SECP256K1_API
# define SECP256K1_API_VAR extern __declspec (dllimport)
# elif defined DLL_EXPORT
# define SECP256K1_API __declspec (dllimport)
# define SECP256K1_API_VAR extern __declspec (dllimport)
# endif
#endif
#ifndef SECP256K1_API
# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
# define SECP256K1_API __attribute__ ((visibility ("default")))
# define SECP256K1_API_VAR extern __attribute__ ((visibility ("default")))
# else # else
# define SECP256K1_API # define SECP256K1_API
# define SECP256K1_API_VAR extern
# endif # endif
#endif #endif
@ -231,10 +238,10 @@ typedef int (*secp256k1_nonce_function)(
* *
* It is highly recommended to call secp256k1_selftest before using this context. * It is highly recommended to call secp256k1_selftest before using this context.
*/ */
SECP256K1_API extern const secp256k1_context *secp256k1_context_static; SECP256K1_API_VAR const secp256k1_context *secp256k1_context_static;
/** Deprecated alias for secp256k1_context_static. */ /** Deprecated alias for secp256k1_context_static. */
SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp SECP256K1_API_VAR const secp256k1_context *secp256k1_context_no_precomp
SECP256K1_DEPRECATED("Use secp256k1_context_static instead"); SECP256K1_DEPRECATED("Use secp256k1_context_static instead");
/** Perform basic self tests (to be used in conjunction with secp256k1_context_static) /** Perform basic self tests (to be used in conjunction with secp256k1_context_static)
@ -291,8 +298,11 @@ SECP256K1_API secp256k1_context* secp256k1_context_create(
* called at most once for every call of this function. If you need to avoid dynamic * called at most once for every call of this function. If you need to avoid dynamic
* memory allocation entirely, see the functions in secp256k1_preallocated.h. * memory allocation entirely, see the functions in secp256k1_preallocated.h.
* *
* Cloning secp256k1_context_static is not possible, and should not be emulated by
* the caller (e.g., using memcpy). Create a new context instead.
*
* Returns: a newly created context object. * Returns: a newly created context object.
* Args: ctx: an existing context to copy * Args: ctx: an existing context to copy (not secp256k1_context_static)
*/ */
SECP256K1_API secp256k1_context* secp256k1_context_clone( SECP256K1_API secp256k1_context* secp256k1_context_clone(
const secp256k1_context* ctx const secp256k1_context* ctx
@ -310,6 +320,7 @@ SECP256K1_API secp256k1_context* secp256k1_context_clone(
* *
* Args: ctx: an existing context to destroy, constructed using * Args: ctx: an existing context to destroy, constructed using
* secp256k1_context_create or secp256k1_context_clone * secp256k1_context_create or secp256k1_context_clone
* (i.e., not secp256k1_context_static).
*/ */
SECP256K1_API void secp256k1_context_destroy( SECP256K1_API void secp256k1_context_destroy(
secp256k1_context* ctx secp256k1_context* ctx
@ -627,10 +638,10 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize(
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
* extra entropy. * extra entropy.
*/ */
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_default;
/** Create an ECDSA signature. /** Create an ECDSA signature.
* *
@ -820,10 +831,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
/** Randomizes the context to provide enhanced protection against side-channel leakage. /** Randomizes the context to provide enhanced protection against side-channel leakage.
* *
* Returns: 1: randomization successful (or called on copy of secp256k1_context_static) * Returns: 1: randomization successful
* 0: error * 0: error
* Args: ctx: pointer to a context object. * Args: ctx: pointer to a context object (not secp256k1_context_static).
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state).
* *
* While secp256k1 code is written and tested to be constant-time no matter what * While secp256k1 code is written and tested to be constant-time no matter what
* secret values are, it is possible that a compiler may output code which is not, * secret values are, it is possible that a compiler may output code which is not,
@ -838,21 +849,17 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
* functions that perform computations involving secret keys, e.g., signing and * functions that perform computations involving secret keys, e.g., signing and
* public key generation. It is possible to call this function more than once on * public key generation. It is possible to call this function more than once on
* the same context, and doing so before every few computations involving secret * the same context, and doing so before every few computations involving secret
* keys is recommended as a defense-in-depth measure. * keys is recommended as a defense-in-depth measure. Randomization of the static
* context secp256k1_context_static is not supported.
* *
* Currently, the random seed is mainly used for blinding multiplications of a * Currently, the random seed is mainly used for blinding multiplications of a
* secret scalar with the elliptic curve base point. Multiplications of this * secret scalar with the elliptic curve base point. Multiplications of this
* kind are performed by exactly those API functions which are documented to * kind are performed by exactly those API functions which are documented to
* require a context that is not the secp256k1_context_static. As a rule of thumb, * require a context that is not secp256k1_context_static. As a rule of thumb,
* these are all functions which take a secret key (or a keypair) as an input. * these are all functions which take a secret key (or a keypair) as an input.
* A notable exception to that rule is the ECDH module, which relies on a different * A notable exception to that rule is the ECDH module, which relies on a different
* kind of elliptic curve point multiplication and thus does not benefit from * kind of elliptic curve point multiplication and thus does not benefit from
* enhanced protection against side-channel leakage currently. * enhanced protection against side-channel leakage currently.
*
* It is safe call this function on a copy of secp256k1_context_static in writable
* memory (e.g., obtained via secp256k1_context_clone). In that case, this
* function is guaranteed to return 1, but the call will have no effect because
* the static context (or a copy thereof) is not meant to be randomized.
*/ */
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
secp256k1_context* ctx, secp256k1_context* ctx,

View file

@ -27,11 +27,11 @@ typedef int (*secp256k1_ecdh_hash_function)(
/** An implementation of SHA256 hash function that applies to compressed public key. /** An implementation of SHA256 hash function that applies to compressed public key.
* Populates the output parameter with 32 bytes. */ * Populates the output parameter with 32 bytes. */
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256; SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256). /** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256).
* Populates the output parameter with 32 bytes. */ * Populates the output parameter with 32 bytes. */
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default; SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
/** Compute an EC Diffie-Hellman secret in constant time /** Compute an EC Diffie-Hellman secret in constant time
* *

View file

@ -88,8 +88,11 @@ SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
* the lifetime of this context object, see the description of * the lifetime of this context object, see the description of
* secp256k1_context_preallocated_create for details. * secp256k1_context_preallocated_create for details.
* *
* Cloning secp256k1_context_static is not possible, and should not be emulated by
* the caller (e.g., using memcpy). Create a new context instead.
*
* Returns: a newly created context object. * Returns: a newly created context object.
* Args: ctx: an existing context to copy. * Args: ctx: an existing context to copy (not secp256k1_context_static).
* In: prealloc: a pointer to a rewritable contiguous block of memory of * In: prealloc: a pointer to a rewritable contiguous block of memory of
* size at least secp256k1_context_preallocated_size(flags) * size at least secp256k1_context_preallocated_size(flags)
* bytes, as detailed above. * bytes, as detailed above.
@ -117,7 +120,8 @@ SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
* *
* Args: ctx: an existing context to destroy, constructed using * Args: ctx: an existing context to destroy, constructed using
* secp256k1_context_preallocated_create or * secp256k1_context_preallocated_create or
* secp256k1_context_preallocated_clone. * secp256k1_context_preallocated_clone
* (i.e., not secp256k1_context_static).
*/ */
SECP256K1_API void secp256k1_context_preallocated_destroy( SECP256K1_API void secp256k1_context_preallocated_destroy(
secp256k1_context* ctx secp256k1_context* ctx

View file

@ -61,7 +61,7 @@ typedef int (*secp256k1_nonce_function_hardened)(
* Therefore, to create BIP-340 compliant signatures, algo must be set to * Therefore, to create BIP-340 compliant signatures, algo must be set to
* "BIP0340/nonce" and algolen to 13. * "BIP0340/nonce" and algolen to 13.
*/ */
SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340; SECP256K1_API_VAR const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
/** Data structure that contains additional arguments for schnorrsig_sign_custom. /** Data structure that contains additional arguments for schnorrsig_sign_custom.
* *

View file

@ -9,5 +9,4 @@ URL: https://github.com/bitcoin-core/secp256k1
Version: @PACKAGE_VERSION@ Version: @PACKAGE_VERSION@
Cflags: -I${includedir} Cflags: -I${includedir}
Libs: -L${libdir} -lsecp256k1 Libs: -L${libdir} -lsecp256k1
Libs.private: @SECP_LIBS@

View file

@ -1,124 +1,156 @@
load("secp256k1_params.sage") load("secp256k1_params.sage")
MAX_ORDER = 1000
# Set of (curve) orders we have encountered so far.
orders_done = set() orders_done = set()
results = {}
first = True # Map from (subgroup) orders to [b, int(gen.x), int(gen.y), gen, lambda] for those subgroups.
solutions = {}
# Iterate over curves of the form y^2 = x^3 + B.
for b in range(1, P): for b in range(1, P):
# There are only 6 curves (up to isomorphism) of the form y^2=x^3+B. Stop once we have tried all. # There are only 6 curves (up to isomorphism) of the form y^2 = x^3 + B. Stop once we have tried all.
if len(orders_done) == 6: if len(orders_done) == 6:
break break
E = EllipticCurve(F, [0, b]) E = EllipticCurve(F, [0, b])
print("Analyzing curve y^2 = x^3 + %i" % b) print("Analyzing curve y^2 = x^3 + %i" % b)
n = E.order() n = E.order()
# Skip curves with an order we've already tried # Skip curves with an order we've already tried
if n in orders_done: if n in orders_done:
print("- Isomorphic to earlier curve") print("- Isomorphic to earlier curve")
print()
continue continue
orders_done.add(n) orders_done.add(n)
# Skip curves isomorphic to the real secp256k1 # Skip curves isomorphic to the real secp256k1
if n.is_pseudoprime(): if n.is_pseudoprime():
print(" - Isomorphic to secp256k1") assert E.is_isomorphic(C)
print("- Isomorphic to secp256k1")
print()
continue continue
print("- Finding subgroups") print("- Finding prime subgroups")
# Find what prime subgroups exist # Map from group_order to a set of independent generators for that order.
for f, _ in n.factor(): curve_gens = {}
print("- Analyzing subgroup of order %i" % f)
# Skip subgroups of order >1000
if f < 4 or f > 1000:
print(" - Bad size")
continue
# Iterate over X coordinates until we find one that is on the curve, has order f, for g in E.gens():
# and for which curve isomorphism exists that maps it to X coordinate 1. # Find what prime subgroups of group generated by g exist.
for x in range(1, P): g_order = g.order()
# Skip X coordinates not on the curve, and construct the full point otherwise. for f, _ in g.order().factor():
if not E.is_x_coord(x): # Skip subgroups that have bad size.
if f < 4:
print(f" - Subgroup of size {f}: too small")
continue continue
G = E.lift_x(F(x)) if f > MAX_ORDER:
print(f" - Subgroup of size {f}: too large")
print(" - Analyzing (multiples of) point with X=%i" % x)
# Skip points whose order is not a multiple of f. Project the point to have
# order f otherwise.
if (G.order() % f):
print(" - Bad order")
continue continue
G = G * (G.order() // f)
# Construct a generator for that subgroup.
gen = g * (g_order // f)
assert(gen.order() == f)
# Add to set the minimal multiple of gen.
curve_gens.setdefault(f, set()).add(min([j*gen for j in range(1, f)]))
print(f" - Subgroup of size {f}: ok")
for f in sorted(curve_gens.keys()):
print(f"- Constructing group of order {f}")
cbrts = sorted([int(c) for c in Integers(f)(1).nth_root(3, all=true) if c != 1])
gens = list(curve_gens[f])
sol_count = 0
no_endo_count = 0
# Consider all non-zero linear combinations of the independent generators.
for j in range(1, f**len(gens)):
gen = sum(gens[k] * ((j // f**k) % f) for k in range(len(gens)))
assert not gen.is_zero()
assert (f*gen).is_zero()
# Find lambda for endomorphism. Skip if none can be found. # Find lambda for endomorphism. Skip if none can be found.
lam = None lam = None
for l in Integers(f)(1).nth_root(3, all=True): for l in cbrts:
if int(l)*G == E(BETA*G[0], G[1]): if l*gen == E(BETA*gen[0], gen[1]):
lam = int(l) lam = l
break break
if lam is None: if lam is None:
print(" - No endomorphism for this subgroup") no_endo_count += 1
break else:
sol_count += 1
solutions.setdefault(f, []).append((b, int(gen[0]), int(gen[1]), gen, lam))
# Now look for an isomorphism of the curve that gives this point an X print(f" - Found {sol_count} generators (plus {no_endo_count} without endomorphism)")
# coordinate equal to 1.
# If (x,y) is on y^2 = x^3 + b, then (a^2*x, a^3*y) is on y^2 = x^3 + a^6*b.
# So look for m=a^2=1/x.
m = F(1)/G[0]
if not m.is_square():
print(" - No curve isomorphism maps it to a point with X=1")
continue
a = m.sqrt()
rb = a^6*b
RE = EllipticCurve(F, [0, rb])
# Use as generator twice the image of G under the above isormorphism. print()
# This means that generator*(1/2 mod f) will have X coordinate 1.
RG = RE(1, a^3*G[1]) * 2
# And even Y coordinate.
if int(RG[1]) % 2:
RG = -RG
assert(RG.order() == f)
assert(lam*RG == RE(BETA*RG[0], RG[1]))
# We have found curve RE:y^2=x^3+rb with generator RG of order f. Remember it def output_generator(g, name):
results[f] = {"b": rb, "G": RG, "lambda": lam} print(f"#define {name} SECP256K1_GE_CONST(\\")
print(" - Found solution") print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
break print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x,\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x\\" % tuple((int(g[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
print(")")
print("") def output_b(b):
print(f"#define SECP256K1_B {int(b)}")
print("") print()
print("") print("To be put in src/group_impl.h:")
print("/* To be put in src/group_impl.h: */") print()
print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */")
for f in sorted(solutions.keys()):
# Use as generator/2 the one with lowest b, and lowest (x, y) generator (interpreted as non-negative integers).
b, _, _, HALF_G, lam = min(solutions[f])
output_generator(2 * HALF_G, f"SECP256K1_G_ORDER_{f}")
print("/** Generator for secp256k1, value 'g' defined in")
print(" * \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.")
print(" */")
output_generator(G, "SECP256K1_G")
print("/* These exhaustive group test orders and generators are chosen such that:")
print(" * - The field size is equal to that of secp256k1, so field code is the same.")
print(" * - The curve equation is of the form y^2=x^3+B for some small constant B.")
print(" * - The subgroup has a generator 2*P, where P.x is as small as possible.")
print(f" * - The subgroup has size less than {MAX_ORDER} to permit exhaustive testing.")
print(" * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).")
print(" */")
print("#if defined(EXHAUSTIVE_TEST_ORDER)")
first = True first = True
for f in sorted(results.keys()): for f in sorted(solutions.keys()):
b = results[f]["b"] b, _, _, _, lam = min(solutions[f])
G = results[f]["G"] print(f"# {'if' if first else 'elif'} EXHAUSTIVE_TEST_ORDER == {f}")
print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f))
first = False first = False
print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(") print()
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) print(f"static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_{f};")
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) output_b(b)
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) print()
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
print(");")
print("static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(")
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
print(");")
print("# else") print("# else")
print("# error No known generator for the specified exhaustive test group order.") print("# error No known generator for the specified exhaustive test group order.")
print("# endif") print("# endif")
print("#else")
print()
print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;")
output_b(7)
print()
print("#endif")
print("/* End of section generated by sage/gen_exhaustive_groups.sage. */")
print("")
print("") print()
print("/* To be put in src/scalar_impl.h: */") print()
print("To be put in src/scalar_impl.h:")
print()
print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */")
first = True first = True
for f in sorted(results.keys()): for f in sorted(solutions.keys()):
lam = results[f]["lambda"] _, _, _, _, lam = min(solutions[f])
print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f))
first = False first = False
print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam) print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam)
print("# else") print("# else")
print("# error No known lambda for the specified exhaustive test group order.") print("# error No known lambda for the specified exhaustive test group order.")
print("# endif") print("# endif")
print("") print("/* End of section generated by sage/gen_exhaustive_groups.sage. */")

View file

@ -148,7 +148,7 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
zeroes = {} zeroes = {}
nonzeroes = {} nonzeroes = {}
a_infinity = False a_infinity = False
if (branch & 4) != 0: if (branch & 2) != 0:
nonzeroes.update({a.Infinity : 'a_infinite'}) nonzeroes.update({a.Infinity : 'a_infinite'})
a_infinity = True a_infinity = True
else: else:
@ -167,15 +167,11 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
m_alt = -u2 m_alt = -u2
tt = u1 * m_alt tt = u1 * m_alt
rr = rr + tt rr = rr + tt
degenerate = (branch & 3) == 3 degenerate = (branch & 1) != 0
if (branch & 1) != 0: if degenerate:
zeroes.update({m : 'm_zero'}) zeroes.update({m : 'm_zero'})
else: else:
nonzeroes.update({m : 'm_nonzero'}) nonzeroes.update({m : 'm_nonzero'})
if (branch & 2) != 0:
zeroes.update({rr : 'rr_zero'})
else:
nonzeroes.update({rr : 'rr_nonzero'})
rr_alt = s1 rr_alt = s1
rr_alt = rr_alt * 2 rr_alt = rr_alt * 2
m_alt = m_alt + u1 m_alt = m_alt + u1
@ -190,13 +186,6 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
n = m n = m
t = rr_alt^2 t = rr_alt^2
rz = a.Z * m_alt rz = a.Z * m_alt
infinity = False
if (branch & 8) != 0:
if not a_infinity:
infinity = True
zeroes.update({rz : 'r.z=0'})
else:
nonzeroes.update({rz : 'r.z!=0'})
t = t + q t = t + q
rx = t rx = t
t = t * 2 t = t * 2
@ -209,8 +198,11 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
rx = b.X rx = b.X
ry = b.Y ry = b.Y
rz = 1 rz = 1
if infinity: if (branch & 4) != 0:
zeroes.update({rz : 'r.z = 0'})
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity())
else:
nonzeroes.update({rz : 'r.z != 0'})
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz))
def formula_secp256k1_gej_add_ge_old(branch, a, b): def formula_secp256k1_gej_add_ge_old(branch, a, b):
@ -280,14 +272,14 @@ if __name__ == "__main__":
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge) success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge)
success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)) success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old))
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43) success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge, 43)
success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)) success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43))
sys.exit(int(not success)) sys.exit(int(not success))

151
src/CMakeLists.txt Normal file
View file

@ -0,0 +1,151 @@
# Must be included before CMAKE_INSTALL_INCLUDEDIR is used.
include(GNUInstallDirs)
set(${PROJECT_NAME}_installables "")
if(SECP256K1_ASM STREQUAL "arm")
add_library(common OBJECT
asm/field_10x26_arm.s
)
set(common_obj "$<TARGET_OBJECTS:common>")
else()
set(common_obj "")
endif()
add_library(precomputed OBJECT
precomputed_ecmult.c
precomputed_ecmult_gen.c
)
set(internal_obj "$<TARGET_OBJECTS:precomputed>" "${common_obj}")
add_library(secp256k1 SHARED EXCLUDE_FROM_ALL
secp256k1.c
${internal_obj}
)
target_include_directories(secp256k1 INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_compile_definitions(secp256k1 PRIVATE
$<$<PLATFORM_ID:Windows>:DLL_EXPORT>
)
set_target_properties(secp256k1 PROPERTIES
VERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}"
SOVERSION "${${PROJECT_NAME}_LIB_VERSION_CURRENT}"
)
if(SECP256K1_BUILD_SHARED)
get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE)
set_target_properties(precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic})
set_target_properties(secp256k1 PROPERTIES EXCLUDE_FROM_ALL FALSE)
list(APPEND ${PROJECT_NAME}_installables secp256k1)
endif()
add_library(secp256k1_static STATIC EXCLUDE_FROM_ALL
secp256k1.c
${internal_obj}
)
target_include_directories(secp256k1_static INTERFACE
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
if(NOT MSVC)
set_target_properties(secp256k1_static PROPERTIES
OUTPUT_NAME secp256k1
)
endif()
if(SECP256K1_BUILD_STATIC)
set_target_properties(secp256k1_static PROPERTIES EXCLUDE_FROM_ALL FALSE)
list(APPEND ${PROJECT_NAME}_installables secp256k1_static)
endif()
add_library(binary_interface INTERFACE)
target_compile_definitions(binary_interface INTERFACE
$<$<C_COMPILER_ID:MSVC>:_CRT_SECURE_NO_WARNINGS>
)
add_library(link_library INTERFACE)
if(SECP256K1_BUILD_SHARED)
target_link_libraries(link_library INTERFACE secp256k1)
elseif(SECP256K1_BUILD_STATIC)
target_link_libraries(link_library INTERFACE secp256k1_static)
endif()
if(SECP256K1_BUILD_BENCHMARK)
add_executable(bench bench.c)
target_link_libraries(bench binary_interface link_library)
add_executable(bench_internal bench_internal.c ${internal_obj})
target_link_libraries(bench_internal binary_interface)
add_executable(bench_ecmult bench_ecmult.c ${internal_obj})
target_link_libraries(bench_ecmult binary_interface)
endif()
if(SECP256K1_BUILD_TESTS)
add_executable(noverify_tests tests.c ${internal_obj})
target_link_libraries(noverify_tests binary_interface)
add_test(noverify_tests noverify_tests)
if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
add_executable(tests tests.c ${internal_obj})
target_compile_definitions(tests PRIVATE VERIFY)
target_link_libraries(tests binary_interface)
add_test(tests tests)
endif()
endif()
if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
# Note: do not include $<TARGET_OBJECTS:precomputed> in exhaustive_tests (it uses runtime-generated tables).
add_executable(exhaustive_tests tests_exhaustive.c ${common_obj})
target_compile_definitions(exhaustive_tests PRIVATE $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
target_link_libraries(exhaustive_tests binary_interface)
add_test(exhaustive_tests exhaustive_tests)
endif()
if(SECP256K1_BUILD_CTIME_TESTS)
add_executable(ctime_tests ctime_tests.c)
target_link_libraries(ctime_tests binary_interface link_library)
endif()
install(TARGETS ${${PROJECT_NAME}_installables}
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_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()
install(FILES ${${PROJECT_NAME}_headers}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(EXPORT ${PROJECT_NAME}-targets
FILE ${PROJECT_NAME}-targets.cmake
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
include(CMakePackageConfigHelpers)
configure_package_config_file(
${PROJECT_SOURCE_DIR}/cmake/config.cmake.in
${PROJECT_NAME}-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
NO_SET_AND_CHECK_MACRO
)
write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake
COMPATIBILITY SameMajorVersion
)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)

View file

@ -11,7 +11,7 @@
#include "util.h" #include "util.h"
#include "bench.h" #include "bench.h"
void help(int default_iters) { static void help(int default_iters) {
printf("Benchmarks the following algorithms:\n"); printf("Benchmarks the following algorithms:\n");
printf(" - ECDSA signing/verification\n"); printf(" - ECDSA signing/verification\n");

View file

@ -38,7 +38,7 @@ static int64_t gettime_i64(void) {
#define FP_MULT (1000000LL) #define FP_MULT (1000000LL)
/* Format fixed point number. */ /* Format fixed point number. */
void print_number(const int64_t x) { static void print_number(const int64_t x) {
int64_t x_abs, y; int64_t x_abs, y;
int c, i, rounding, g; /* g = integer part size, c = fractional part size */ int c, i, rounding, g; /* g = integer part size, c = fractional part size */
size_t ptr; size_t ptr;
@ -95,7 +95,7 @@ void print_number(const int64_t x) {
printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */ printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */
} }
void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) { static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
int i; int i;
int64_t min = INT64_MAX; int64_t min = INT64_MAX;
int64_t sum = 0; int64_t sum = 0;
@ -129,7 +129,7 @@ void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void
printf("\n"); printf("\n");
} }
int have_flag(int argc, char** argv, char *flag) { static int have_flag(int argc, char** argv, char *flag) {
char** argm = argv + argc; char** argm = argv + argc;
argv++; argv++;
while (argv != argm) { while (argv != argm) {
@ -145,7 +145,7 @@ int have_flag(int argc, char** argv, char *flag) {
returns: returns:
- 1 if the user entered an invalid argument - 1 if the user entered an invalid argument
- 0 if all the user entered arguments are valid */ - 0 if all the user entered arguments are valid */
int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
size_t i; size_t i;
int found_valid; int found_valid;
char** argm = argv + argc; char** argm = argv + argc;
@ -167,7 +167,7 @@ int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
return 0; return 0;
} }
int get_iters(int default_iters) { static int get_iters(int default_iters) {
char* env = getenv("SECP256K1_BENCH_ITERS"); char* env = getenv("SECP256K1_BENCH_ITERS");
if (env) { if (env) {
return strtol(env, NULL, 0); return strtol(env, NULL, 0);
@ -176,7 +176,7 @@ int get_iters(int default_iters) {
} }
} }
void print_output_table_header_row(void) { static void print_output_table_header_row(void) {
char* bench_str = "Benchmark"; /* left justified */ char* bench_str = "Benchmark"; /* left justified */
char* min_str = " Min(us) "; /* center alignment */ char* min_str = " Min(us) "; /* center alignment */
char* avg_str = " Avg(us) "; char* avg_str = " Avg(us) ";

View file

@ -18,7 +18,7 @@
#define POINTS 32768 #define POINTS 32768
void help(char **argv) { static void help(char **argv) {
printf("Benchmark EC multiplication algorithms\n"); printf("Benchmark EC multiplication algorithms\n");
printf("\n"); printf("\n");
printf("Usage: %s <help|pippenger_wnaf|strauss_wnaf|simple>\n", argv[0]); printf("Usage: %s <help|pippenger_wnaf|strauss_wnaf|simple>\n", argv[0]);

View file

@ -27,7 +27,7 @@ typedef struct {
int wnaf[256]; int wnaf[256];
} bench_inv; } bench_inv;
void bench_setup(void* arg) { static void bench_setup(void* arg) {
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
static const unsigned char init[4][32] = { static const unsigned char init[4][32] = {
@ -79,7 +79,7 @@ void bench_setup(void* arg) {
memcpy(data->data + 32, init[1], 32); memcpy(data->data + 32, init[1], 32);
} }
void bench_scalar_add(void* arg, int iters) { static void bench_scalar_add(void* arg, int iters) {
int i, j = 0; int i, j = 0;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -89,7 +89,7 @@ void bench_scalar_add(void* arg, int iters) {
CHECK(j <= iters); CHECK(j <= iters);
} }
void bench_scalar_negate(void* arg, int iters) { static void bench_scalar_negate(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -98,7 +98,7 @@ void bench_scalar_negate(void* arg, int iters) {
} }
} }
void bench_scalar_mul(void* arg, int iters) { static void bench_scalar_mul(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -107,18 +107,19 @@ void bench_scalar_mul(void* arg, int iters) {
} }
} }
void bench_scalar_split(void* arg, int iters) { static void bench_scalar_split(void* arg, int iters) {
int i, j = 0; int i, j = 0;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
secp256k1_scalar tmp;
for (i = 0; i < iters; i++) { for (i = 0; i < iters; i++) {
secp256k1_scalar_split_lambda(&data->scalar[0], &data->scalar[1], &data->scalar[0]); secp256k1_scalar_split_lambda(&tmp, &data->scalar[1], &data->scalar[0]);
j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]); j += secp256k1_scalar_add(&data->scalar[0], &tmp, &data->scalar[1]);
} }
CHECK(j <= iters); CHECK(j <= iters);
} }
void bench_scalar_inverse(void* arg, int iters) { static void bench_scalar_inverse(void* arg, int iters) {
int i, j = 0; int i, j = 0;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -129,7 +130,7 @@ void bench_scalar_inverse(void* arg, int iters) {
CHECK(j <= iters); CHECK(j <= iters);
} }
void bench_scalar_inverse_var(void* arg, int iters) { static void bench_scalar_inverse_var(void* arg, int iters) {
int i, j = 0; int i, j = 0;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -140,7 +141,7 @@ void bench_scalar_inverse_var(void* arg, int iters) {
CHECK(j <= iters); CHECK(j <= iters);
} }
void bench_field_half(void* arg, int iters) { static void bench_field_half(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -149,7 +150,7 @@ void bench_field_half(void* arg, int iters) {
} }
} }
void bench_field_normalize(void* arg, int iters) { static void bench_field_normalize(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -158,7 +159,7 @@ void bench_field_normalize(void* arg, int iters) {
} }
} }
void bench_field_normalize_weak(void* arg, int iters) { static void bench_field_normalize_weak(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -167,7 +168,7 @@ void bench_field_normalize_weak(void* arg, int iters) {
} }
} }
void bench_field_mul(void* arg, int iters) { static void bench_field_mul(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -176,7 +177,7 @@ void bench_field_mul(void* arg, int iters) {
} }
} }
void bench_field_sqr(void* arg, int iters) { static void bench_field_sqr(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -185,7 +186,7 @@ void bench_field_sqr(void* arg, int iters) {
} }
} }
void bench_field_inverse(void* arg, int iters) { static void bench_field_inverse(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -195,7 +196,7 @@ void bench_field_inverse(void* arg, int iters) {
} }
} }
void bench_field_inverse_var(void* arg, int iters) { static void bench_field_inverse_var(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -205,7 +206,7 @@ void bench_field_inverse_var(void* arg, int iters) {
} }
} }
void bench_field_sqrt(void* arg, int iters) { static void bench_field_sqrt(void* arg, int iters) {
int i, j = 0; int i, j = 0;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
secp256k1_fe t; secp256k1_fe t;
@ -218,7 +219,20 @@ void bench_field_sqrt(void* arg, int iters) {
CHECK(j <= iters); CHECK(j <= iters);
} }
void bench_group_double_var(void* arg, int iters) { static void bench_field_is_square_var(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
secp256k1_fe t = data->fe[0];
for (i = 0; i < iters; i++) {
j += secp256k1_fe_is_square_var(&t);
secp256k1_fe_add(&t, &data->fe[1]);
secp256k1_fe_normalize_var(&t);
}
CHECK(j <= iters);
}
static void bench_group_double_var(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -227,7 +241,7 @@ void bench_group_double_var(void* arg, int iters) {
} }
} }
void bench_group_add_var(void* arg, int iters) { static void bench_group_add_var(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -236,7 +250,7 @@ void bench_group_add_var(void* arg, int iters) {
} }
} }
void bench_group_add_affine(void* arg, int iters) { static void bench_group_add_affine(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -245,7 +259,7 @@ void bench_group_add_affine(void* arg, int iters) {
} }
} }
void bench_group_add_affine_var(void* arg, int iters) { static void bench_group_add_affine_var(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -254,7 +268,7 @@ void bench_group_add_affine_var(void* arg, int iters) {
} }
} }
void bench_group_add_zinv_var(void* arg, int iters) { static void bench_group_add_zinv_var(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -263,7 +277,7 @@ void bench_group_add_zinv_var(void* arg, int iters) {
} }
} }
void bench_group_to_affine_var(void* arg, int iters) { static void bench_group_to_affine_var(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -283,7 +297,7 @@ void bench_group_to_affine_var(void* arg, int iters) {
} }
} }
void bench_ecmult_wnaf(void* arg, int iters) { static void bench_ecmult_wnaf(void* arg, int iters) {
int i, bits = 0, overflow = 0; int i, bits = 0, overflow = 0;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -295,7 +309,7 @@ void bench_ecmult_wnaf(void* arg, int iters) {
CHECK(bits <= 256*iters); CHECK(bits <= 256*iters);
} }
void bench_wnaf_const(void* arg, int iters) { static void bench_wnaf_const(void* arg, int iters) {
int i, bits = 0, overflow = 0; int i, bits = 0, overflow = 0;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
@ -307,8 +321,7 @@ void bench_wnaf_const(void* arg, int iters) {
CHECK(bits <= 256*iters); CHECK(bits <= 256*iters);
} }
static void bench_sha256(void* arg, int iters) {
void bench_sha256(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
secp256k1_sha256 sha; secp256k1_sha256 sha;
@ -320,7 +333,7 @@ void bench_sha256(void* arg, int iters) {
} }
} }
void bench_hmac_sha256(void* arg, int iters) { static void bench_hmac_sha256(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
secp256k1_hmac_sha256 hmac; secp256k1_hmac_sha256 hmac;
@ -332,7 +345,7 @@ void bench_hmac_sha256(void* arg, int iters) {
} }
} }
void bench_rfc6979_hmac_sha256(void* arg, int iters) { static void bench_rfc6979_hmac_sha256(void* arg, int iters) {
int i; int i;
bench_inv *data = (bench_inv*)arg; bench_inv *data = (bench_inv*)arg;
secp256k1_rfc6979_hmac_sha256 rng; secp256k1_rfc6979_hmac_sha256 rng;
@ -343,7 +356,7 @@ void bench_rfc6979_hmac_sha256(void* arg, int iters) {
} }
} }
void bench_context(void* arg, int iters) { static void bench_context(void* arg, int iters) {
int i; int i;
(void)arg; (void)arg;
for (i = 0; i < iters; i++) { for (i = 0; i < iters; i++) {
@ -371,6 +384,7 @@ int main(int argc, char **argv) {
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "issquare")) run_benchmark("field_is_square_var", bench_field_is_square_var, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters); if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10); if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10);

88
src/checkmem.h Normal file
View file

@ -0,0 +1,88 @@
/***********************************************************************
* Copyright (c) 2022 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
/* The code here is inspired by Kris Kwiatkowski's approach in
* https://github.com/kriskwiatkowski/pqc/blob/main/src/common/ct_check.h
* to provide a general interface for memory-checking mechanisms, primarily
* for constant-time checking.
*/
/* These macros are defined by this header file:
*
* - SECP256K1_CHECKMEM_ENABLED:
* - 1 if memory-checking integration is available, 0 otherwise.
* This is just a compile-time macro. Use the next macro to check it is actually
* available at runtime.
* - SECP256K1_CHECKMEM_RUNNING():
* - Acts like a function call, returning 1 if memory checking is available
* at runtime.
* - SECP256K1_CHECKMEM_CHECK(p, len):
* - Assert or otherwise fail in case the len-byte memory block pointed to by p is
* not considered entirely defined.
* - SECP256K1_CHECKMEM_CHECK_VERIFY(p, len):
* - Like SECP256K1_CHECKMEM_CHECK, but only works in VERIFY mode.
* - SECP256K1_CHECKMEM_UNDEFINE(p, len):
* - marks the len-byte memory block pointed to by p as undefined data (secret data,
* in the context of constant-time checking).
* - SECP256K1_CHECKMEM_DEFINE(p, len):
* - marks the len-byte memory pointed to by p as defined data (public data, in the
* context of constant-time checking).
*
*/
#ifndef SECP256K1_CHECKMEM_H
#define SECP256K1_CHECKMEM_H
/* Define a statement-like macro that ignores the arguments. */
#define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0)
/* If compiling under msan, map the SECP256K1_CHECKMEM_* functionality to msan.
* Choose this preferentially, even when VALGRIND is defined, as msan-compiled
* binaries can't be run under valgrind anyway. */
#if defined(__has_feature)
# 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))
# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len))
# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len))
# define SECP256K1_CHECKMEM_RUNNING() (1)
# endif
#endif
/* If valgrind integration is desired (through the VALGRIND define), implement the
* SECP256K1_CHECKMEM_* macros using valgrind. */
#if !defined SECP256K1_CHECKMEM_ENABLED
# if defined VALGRIND
# include <stddef.h>
# include <valgrind/memcheck.h>
# define SECP256K1_CHECKMEM_ENABLED 1
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len))
# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len))
# define SECP256K1_CHECKMEM_CHECK(p, len) VALGRIND_CHECK_MEM_IS_DEFINED((p), (len))
/* VALGRIND_MAKE_MEM_DEFINED returns 0 iff not running on memcheck.
* This is more precise than the RUNNING_ON_VALGRIND macro, which
* checks for valgrind in general instead of memcheck specifically. */
# define SECP256K1_CHECKMEM_RUNNING() (VALGRIND_MAKE_MEM_DEFINED(NULL, 0) != 0)
# endif
#endif
/* As a fall-back, map these macros to dummy statements. */
#if !defined SECP256K1_CHECKMEM_ENABLED
# define SECP256K1_CHECKMEM_ENABLED 0
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
# define SECP256K1_CHECKMEM_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
# define SECP256K1_CHECKMEM_CHECK(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
# define SECP256K1_CHECKMEM_RUNNING() (0)
#endif
#if defined VERIFY
#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_CHECK((p), (len))
#else
#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
#endif
#endif /* SECP256K1_CHECKMEM_H */

View file

@ -4,12 +4,15 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.* * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/ ***********************************************************************/
#include <valgrind/memcheck.h>
#include <stdio.h> #include <stdio.h>
#include "../include/secp256k1.h" #include "../include/secp256k1.h"
#include "assumptions.h" #include "assumptions.h"
#include "util.h" #include "checkmem.h"
#if !SECP256K1_CHECKMEM_ENABLED
# error "This tool cannot be compiled without memory-checking interface (valgrind or msan)"
#endif
#ifdef ENABLE_MODULE_ECDH #ifdef ENABLE_MODULE_ECDH
# include "../include/secp256k1_ecdh.h" # include "../include/secp256k1_ecdh.h"
@ -27,16 +30,16 @@
#include "../include/secp256k1_schnorrsig.h" #include "../include/secp256k1_schnorrsig.h"
#endif #endif
void run_tests(secp256k1_context *ctx, unsigned char *key); static void run_tests(secp256k1_context *ctx, unsigned char *key);
int main(void) { int main(void) {
secp256k1_context* ctx; secp256k1_context* ctx;
unsigned char key[32]; unsigned char key[32];
int ret, i; int ret, i;
if (!RUNNING_ON_VALGRIND) { if (!SECP256K1_CHECKMEM_RUNNING()) {
fprintf(stderr, "This test can only usefully be run inside valgrind.\n"); 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 ./valgrind_ctime_test\n"); fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n");
return 1; return 1;
} }
ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY); ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY);
@ -51,16 +54,16 @@ int main(void) {
/* Test context randomisation. Do this last because it leaves the context /* Test context randomisation. Do this last because it leaves the context
* tainted. */ * tainted. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_context_randomize(ctx, key); ret = secp256k1_context_randomize(ctx, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret); CHECK(ret);
secp256k1_context_destroy(ctx); secp256k1_context_destroy(ctx);
return 0; return 0;
} }
void run_tests(secp256k1_context *ctx, unsigned char *key) { static void run_tests(secp256k1_context *ctx, unsigned char *key) {
secp256k1_ecdsa_signature signature; secp256k1_ecdsa_signature signature;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
size_t siglen = 74; size_t siglen = 74;
@ -83,89 +86,89 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
} }
/* Test keygen. */ /* Test keygen. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key); ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key);
VALGRIND_MAKE_MEM_DEFINED(&pubkey, sizeof(secp256k1_pubkey)); SECP256K1_CHECKMEM_DEFINE(&pubkey, sizeof(secp256k1_pubkey));
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret); CHECK(ret);
CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
/* Test signing. */ /* Test signing. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL); ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL);
VALGRIND_MAKE_MEM_DEFINED(&signature, sizeof(secp256k1_ecdsa_signature)); SECP256K1_CHECKMEM_DEFINE(&signature, sizeof(secp256k1_ecdsa_signature));
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret); CHECK(ret);
CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature)); CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature));
#ifdef ENABLE_MODULE_ECDH #ifdef ENABLE_MODULE_ECDH
/* Test ECDH. */ /* Test ECDH. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL); ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1); CHECK(ret == 1);
#endif #endif
#ifdef ENABLE_MODULE_RECOVERY #ifdef ENABLE_MODULE_RECOVERY
/* Test signing a recoverable signature. */ /* Test signing a recoverable signature. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL); ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL);
VALGRIND_MAKE_MEM_DEFINED(&recoverable_signature, sizeof(recoverable_signature)); SECP256K1_CHECKMEM_DEFINE(&recoverable_signature, sizeof(recoverable_signature));
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret); CHECK(ret);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature)); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature));
CHECK(recid >= 0 && recid <= 3); CHECK(recid >= 0 && recid <= 3);
#endif #endif
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ec_seckey_verify(ctx, key); ret = secp256k1_ec_seckey_verify(ctx, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1); CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ec_seckey_negate(ctx, key); ret = secp256k1_ec_seckey_negate(ctx, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1); CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
VALGRIND_MAKE_MEM_UNDEFINED(msg, 32); SECP256K1_CHECKMEM_UNDEFINE(msg, 32);
ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg); ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1); CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
VALGRIND_MAKE_MEM_UNDEFINED(msg, 32); SECP256K1_CHECKMEM_UNDEFINE(msg, 32);
ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg); ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1); CHECK(ret == 1);
/* Test keypair_create and keypair_xonly_tweak_add. */ /* Test keypair_create and keypair_xonly_tweak_add. */
#ifdef ENABLE_MODULE_EXTRAKEYS #ifdef ENABLE_MODULE_EXTRAKEYS
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_keypair_create(ctx, &keypair, key); ret = secp256k1_keypair_create(ctx, &keypair, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1); CHECK(ret == 1);
/* The tweak is not treated as a secret in keypair_tweak_add */ /* The tweak is not treated as a secret in keypair_tweak_add */
VALGRIND_MAKE_MEM_DEFINED(msg, 32); SECP256K1_CHECKMEM_DEFINE(msg, 32);
ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg); ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1); CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
VALGRIND_MAKE_MEM_UNDEFINED(&keypair, sizeof(keypair)); SECP256K1_CHECKMEM_UNDEFINE(&keypair, sizeof(keypair));
ret = secp256k1_keypair_sec(ctx, key, &keypair); ret = secp256k1_keypair_sec(ctx, key, &keypair);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1); CHECK(ret == 1);
#endif #endif
#ifdef ENABLE_MODULE_SCHNORRSIG #ifdef ENABLE_MODULE_SCHNORRSIG
VALGRIND_MAKE_MEM_UNDEFINED(key, 32); SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_keypair_create(ctx, &keypair, key); ret = secp256k1_keypair_create(ctx, &keypair, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1); CHECK(ret == 1);
ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL); ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1); CHECK(ret == 1);
#endif #endif
} }

View file

@ -18,10 +18,6 @@
* imply normality. * imply normality.
*/ */
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h" #include "util.h"
#if defined(SECP256K1_WIDEMUL_INT128) #if defined(SECP256K1_WIDEMUL_INT128)
@ -89,6 +85,9 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
* as an argument. The magnitude of the output is one higher. */ * as an argument. The magnitude of the output is one higher. */
static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
/** Adds a small integer (up to 0x7FFF) to r. The resulting magnitude increases by one. */
static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that /** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
* small integer. */ * small integer. */
static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
@ -139,4 +138,7 @@ static void secp256k1_fe_half(secp256k1_fe *r);
* magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */ * magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m); static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
/** Determine whether a is a square (modulo p). */
static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
#endif /* SECP256K1_FIELD_H */ #endif /* SECP256K1_FIELD_H */

View file

@ -7,6 +7,7 @@
#ifndef SECP256K1_FIELD_REPR_IMPL_H #ifndef SECP256K1_FIELD_REPR_IMPL_H
#define SECP256K1_FIELD_REPR_IMPL_H #define SECP256K1_FIELD_REPR_IMPL_H
#include "checkmem.h"
#include "util.h" #include "util.h"
#include "field.h" #include "field.h"
#include "modinv32_impl.h" #include "modinv32_impl.h"
@ -481,6 +482,20 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f
#endif #endif
} }
SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
#ifdef VERIFY
secp256k1_fe_verify(r);
VERIFY_CHECK(a >= 0);
VERIFY_CHECK(a <= 0x7FFF);
#endif
r->n[0] += a;
#ifdef VERIFY
r->magnitude += 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
#if defined(USE_EXTERNAL_ASM) #if defined(USE_EXTERNAL_ASM)
/* External assembler implementation */ /* External assembler implementation */
@ -1132,7 +1147,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint32_t mask0, mask1; uint32_t mask0, mask1;
VG_CHECK_VERIFY(r->n, sizeof(r->n)); SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = flag + ~((uint32_t)0); mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0; mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@ -1231,7 +1246,7 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint32_t mask0, mask1; uint32_t mask0, mask1;
VG_CHECK_VERIFY(r->n, sizeof(r->n)); SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = flag + ~((uint32_t)0); mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0; mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@ -1364,4 +1379,31 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp)); VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
} }
static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv32_signed30 s;
int jac, ret;
tmp = *x;
secp256k1_fe_normalize_var(&tmp);
/* secp256k1_jacobi32_maybe_var cannot deal with input 0. */
if (secp256k1_fe_is_zero(&tmp)) return 1;
secp256k1_fe_to_signed30(&s, &tmp);
jac = secp256k1_jacobi32_maybe_var(&s, &secp256k1_const_modinfo_fe);
if (jac == 0) {
/* secp256k1_jacobi32_maybe_var failed to compute the Jacobi symbol. Fall back
* to computing a square root. This should be extremely rare with random
* input (except in VERIFY mode, where a lower iteration count is used). */
secp256k1_fe dummy;
ret = secp256k1_fe_sqrt(&dummy, &tmp);
} else {
#ifdef VERIFY
secp256k1_fe dummy;
VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
#endif
ret = jac >= 0;
}
return ret;
}
#endif /* SECP256K1_FIELD_REPR_IMPL_H */ #endif /* SECP256K1_FIELD_REPR_IMPL_H */

View file

@ -7,10 +7,7 @@
#ifndef SECP256K1_FIELD_REPR_IMPL_H #ifndef SECP256K1_FIELD_REPR_IMPL_H
#define SECP256K1_FIELD_REPR_IMPL_H #define SECP256K1_FIELD_REPR_IMPL_H
#if defined HAVE_CONFIG_H #include "checkmem.h"
#include "libsecp256k1-config.h"
#endif
#include "util.h" #include "util.h"
#include "field.h" #include "field.h"
#include "modinv64_impl.h" #include "modinv64_impl.h"
@ -428,6 +425,20 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
#endif #endif
} }
SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
#ifdef VERIFY
secp256k1_fe_verify(r);
VERIFY_CHECK(a >= 0);
VERIFY_CHECK(a <= 0x7FFF);
#endif
r->n[0] += a;
#ifdef VERIFY
r->magnitude += 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY #ifdef VERIFY
secp256k1_fe_verify(a); secp256k1_fe_verify(a);
@ -476,7 +487,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint64_t mask0, mask1; uint64_t mask0, mask1;
VG_CHECK_VERIFY(r->n, sizeof(r->n)); SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = flag + ~((uint64_t)0); mask0 = flag + ~((uint64_t)0);
mask1 = ~mask0; mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@ -559,7 +570,7 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint64_t mask0, mask1; uint64_t mask0, mask1;
VG_CHECK_VERIFY(r->n, sizeof(r->n)); SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = flag + ~((uint64_t)0); mask0 = flag + ~((uint64_t)0);
mask1 = ~mask0; mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@ -667,4 +678,31 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
#endif #endif
} }
static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv64_signed62 s;
int jac, ret;
tmp = *x;
secp256k1_fe_normalize_var(&tmp);
/* secp256k1_jacobi64_maybe_var cannot deal with input 0. */
if (secp256k1_fe_is_zero(&tmp)) return 1;
secp256k1_fe_to_signed62(&s, &tmp);
jac = secp256k1_jacobi64_maybe_var(&s, &secp256k1_const_modinfo_fe);
if (jac == 0) {
/* secp256k1_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back
* to computing a square root. This should be extremely rare with random
* input (except in VERIFY mode, where a lower iteration count is used). */
secp256k1_fe dummy;
ret = secp256k1_fe_sqrt(&dummy, &tmp);
} else {
#ifdef VERIFY
secp256k1_fe dummy;
VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
#endif
ret = jac >= 0;
}
return ret;
}
#endif /* SECP256K1_FIELD_REPR_IMPL_H */ #endif /* SECP256K1_FIELD_REPR_IMPL_H */

View file

@ -7,10 +7,6 @@
#ifndef SECP256K1_FIELD_IMPL_H #ifndef SECP256K1_FIELD_IMPL_H
#define SECP256K1_FIELD_IMPL_H #define SECP256K1_FIELD_IMPL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h" #include "util.h"
#if defined(SECP256K1_WIDEMUL_INT128) #if defined(SECP256K1_WIDEMUL_INT128)

View file

@ -10,59 +10,69 @@
#include "field.h" #include "field.h"
#include "group.h" #include "group.h"
/* Begin of section generated by sage/gen_exhaustive_groups.sage. */
#define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\
0x66625d13, 0x317ffe44, 0x63d32cff, 0x1ca02b9b,\
0xe5c6d070, 0x50b4b05e, 0x81cc30db, 0xf5166f0a,\
0x1e60e897, 0xa7c00c7c, 0x2df53eb6, 0x98274ff4,\
0x64252f42, 0x8ca44e17, 0x3b25418c, 0xff4ab0cf\
)
#define SECP256K1_G_ORDER_13 SECP256K1_GE_CONST(\ #define SECP256K1_G_ORDER_13 SECP256K1_GE_CONST(\
0xc3459c3d, 0x35326167, 0xcd86cce8, 0x07a2417f,\ 0xa2482ff8, 0x4bf34edf, 0xa51262fd, 0xe57921db,\
0x5b8bd567, 0xde8538ee, 0x0d507b0c, 0xd128f5bb,\ 0xe0dd2cb7, 0xa5914790, 0xbc71631f, 0xc09704fb,\
0x8e467fec, 0xcd30000a, 0x6cc1184e, 0x25d382c2,\ 0x942536cb, 0xa3e49492, 0x3a701cc3, 0xee3e443f,\
0xa2f4494e, 0x2fbe9abc, 0x8b64abac, 0xd005fb24\ 0xdf182aa9, 0x15b8aa6a, 0x166d3b19, 0xba84b045\
) )
#define SECP256K1_G_ORDER_199 SECP256K1_GE_CONST(\ #define SECP256K1_G_ORDER_199 SECP256K1_GE_CONST(\
0x226e653f, 0xc8df7744, 0x9bacbf12, 0x7d1dcbf9,\ 0x7fb07b5c, 0xd07c3bda, 0x553902e2, 0x7a87ea2c,\
0x87f05b2a, 0xe7edbd28, 0x1f564575, 0xc48dcf18,\ 0x35108a7f, 0x051f41e5, 0xb76abad5, 0x1f2703ad,\
0xa13872c2, 0xe933bb17, 0x5d9ffd5b, 0xb5b6e10c,\ 0x0a251539, 0x5b4c4438, 0x952a634f, 0xac10dd4d,\
0x57fe3c00, 0xbaaaa15a, 0xe003ec3e, 0x9c269bae\ 0x6d6f4745, 0x98990c27, 0x3a4f3116, 0xd32ff969\
) )
/** Generator for secp256k1, value 'g' defined in /** Generator for secp256k1, value 'g' defined in
* "Standards for Efficient Cryptography" (SEC2) 2.7.1. * "Standards for Efficient Cryptography" (SEC2) 2.7.1.
*/ */
#define SECP256K1_G SECP256K1_GE_CONST(\ #define SECP256K1_G SECP256K1_GE_CONST(\
0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL,\ 0x79be667e, 0xf9dcbbac, 0x55a06295, 0xce870b07,\
0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL,\ 0x029bfcdb, 0x2dce28d9, 0x59f2815b, 0x16f81798,\
0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL,\ 0x483ada77, 0x26a3c465, 0x5da4fbfc, 0x0e1108a8,\
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL\ 0xfd17b448, 0xa6855419, 0x9c47d08f, 0xfb10d4b8\
) )
/* These exhaustive group test orders and generators are chosen such that: /* These exhaustive group test orders and generators are chosen such that:
* - The field size is equal to that of secp256k1, so field code is the same. * - The field size is equal to that of secp256k1, so field code is the same.
* - The curve equation is of the form y^2=x^3+B for some constant B. * - The curve equation is of the form y^2=x^3+B for some small constant B.
* - The subgroup has a generator 2*P, where P.x=1. * - The subgroup has a generator 2*P, where P.x is as small as possible.
* - The subgroup has size less than 1000 to permit exhaustive testing. * - The subgroup has size less than 1000 to permit exhaustive testing.
* - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y). * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).
*
* These parameters are generated using sage/gen_exhaustive_groups.sage.
*/ */
#if defined(EXHAUSTIVE_TEST_ORDER) #if defined(EXHAUSTIVE_TEST_ORDER)
# if EXHAUSTIVE_TEST_ORDER == 13 # if EXHAUSTIVE_TEST_ORDER == 7
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_7;
#define SECP256K1_B 6
# elif EXHAUSTIVE_TEST_ORDER == 13
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_13; static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_13;
#define SECP256K1_B 2
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(
0x3d3486b2, 0x159a9ca5, 0xc75638be, 0xb23a69bc,
0x946a45ab, 0x24801247, 0xb4ed2b8e, 0x26b6a417
);
# elif EXHAUSTIVE_TEST_ORDER == 199 # elif EXHAUSTIVE_TEST_ORDER == 199
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_199;
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST( static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_199;
0x2cca28fa, 0xfc614b80, 0x2a3db42b, 0x00ba00b1, #define SECP256K1_B 4
0xbea8d943, 0xdace9ab2, 0x9536daea, 0x0074defb
);
# else # else
# error No known generator for the specified exhaustive test group order. # error No known generator for the specified exhaustive test group order.
# endif # endif
#else #else
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7); static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;
#define SECP256K1_B 7
#endif #endif
/* End of section generated by sage/gen_exhaustive_groups.sage. */
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, SECP256K1_B);
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
secp256k1_fe zi2; secp256k1_fe zi2;
@ -217,7 +227,7 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o
secp256k1_fe_sqr(&x2, x); secp256k1_fe_sqr(&x2, x);
secp256k1_fe_mul(&x3, x, &x2); secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0; r->infinity = 0;
secp256k1_fe_add(&x3, &secp256k1_fe_const_b); secp256k1_fe_add_int(&x3, SECP256K1_B);
if (!secp256k1_fe_sqrt(&r->y, &x3)) { if (!secp256k1_fe_sqrt(&r->y, &x3)) {
return 0; return 0;
} }
@ -272,7 +282,7 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
/* y^2 = x^3 + 7 */ /* y^2 = x^3 + 7 */
secp256k1_fe_sqr(&y2, &a->y); secp256k1_fe_sqr(&y2, &a->y);
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
secp256k1_fe_add(&x3, &secp256k1_fe_const_b); secp256k1_fe_add_int(&x3, SECP256K1_B);
secp256k1_fe_normalize_weak(&x3); secp256k1_fe_normalize_weak(&x3);
return secp256k1_fe_equal_var(&y2, &x3); return secp256k1_fe_equal_var(&y2, &x3);
} }
@ -522,11 +532,11 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
/* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */ /* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
secp256k1_fe m_alt, rr_alt; secp256k1_fe m_alt, rr_alt;
int infinity, degenerate; int degenerate;
VERIFY_CHECK(!b->infinity); VERIFY_CHECK(!b->infinity);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
/** In: /* In:
* Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks.
* In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002.
* we find as solution for a unified addition/doubling formula: * we find as solution for a unified addition/doubling formula:
@ -588,10 +598,9 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */
secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */
secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */
/** If lambda = R/M = 0/0 we have a problem (except in the "trivial" /* If lambda = R/M = R/0 we have a problem (except in the "trivial"
* case that Z = z1z2 = 0, and this is special-cased later on). */ * case that Z = z1z2 = 0, and this is special-cased later on). */
degenerate = secp256k1_fe_normalizes_to_zero(&m) & degenerate = secp256k1_fe_normalizes_to_zero(&m);
secp256k1_fe_normalizes_to_zero(&rr);
/* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2.
* This means either x1 == beta*x2 or beta*x1 == x2, where beta is * This means either x1 == beta*x2 or beta*x1 == x2, where beta is
* a nontrivial cube root of one. In either case, an alternate * a nontrivial cube root of one. In either case, an alternate
@ -603,7 +612,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); secp256k1_fe_cmov(&rr_alt, &rr, !degenerate);
secp256k1_fe_cmov(&m_alt, &m, !degenerate); secp256k1_fe_cmov(&m_alt, &m, !degenerate);
/* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. /* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0.
* From here on out Ralt and Malt represent the numerator * From here on out Ralt and Malt represent the numerator
* and denominator of lambda; R and M represent the explicit * and denominator of lambda; R and M represent the explicit
* expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
@ -618,7 +627,6 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */ secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */
infinity = secp256k1_fe_normalizes_to_zero(&r->z) & ~a->infinity;
secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */ secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */
r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */ r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */
secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */ secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */
@ -628,11 +636,28 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */ secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */
secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */ secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */
/** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ /* In case a->infinity == 1, replace r with (b->x, b->y, 1). */
secp256k1_fe_cmov(&r->x, &b->x, a->infinity); secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
secp256k1_fe_cmov(&r->y, &b->y, a->infinity); secp256k1_fe_cmov(&r->y, &b->y, a->infinity);
secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity); secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity);
r->infinity = infinity;
/* Set r->infinity if r->z is 0.
*
* If a->infinity is set, then r->infinity = (r->z == 0) = (1 == 0) = false,
* which is correct because the function assumes that b is not infinity.
*
* Now assume !a->infinity. This implies Z = Z1 != 0.
*
* Case y1 = -y2:
* In this case we could have a = -b, namely if x1 = x2.
* We have degenerate = true, r->z = (x1 - x2) * Z.
* Then r->infinity = ((x1 - x2)Z == 0) = (x1 == x2) = (a == -b).
*
* Case y1 != -y2:
* In this case, we can't have a = -b.
* We have degenerate = false, r->z = (y1 + y2) * Z.
* Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */
r->infinity = secp256k1_fe_normalizes_to_zero(&r->z);
} }
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {

View file

@ -66,7 +66,12 @@ static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a,
*/ */
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b); static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b);
/* Return the low 64-bits of a 128-bit value interpreted as an signed 64-bit value. */ /* Return the input value modulo 2^64. */
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a);
/* Return the value as a signed 64-bit value.
* Requires the input to be between INT64_MIN and INT64_MAX.
*/
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a); static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a);
/* Write a signed 64-bit value to r. */ /* Write a signed 64-bit value to r. */
@ -75,10 +80,10 @@ static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_
/* Compare two 128-bit values for equality. */ /* Compare two 128-bit values for equality. */
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b); static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b);
/* Tests if r is equal to 2^n. /* Tests if r is equal to sign*2^n (sign must be 1 or -1).
* n must be strictly less than 127. * n must be strictly less than 127.
*/ */
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n); static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign);
#endif #endif

View file

@ -67,7 +67,12 @@ static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned
*r >>= n; *r >>= n;
} }
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
return (uint64_t)*a;
}
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) { static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX);
return *a; return *a;
} }
@ -79,9 +84,10 @@ static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, con
return *a == *b; return *a == *b;
} }
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n) { static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) {
VERIFY_CHECK(n < 127); VERIFY_CHECK(n < 127);
return (*r == (int128_t)1 << n); VERIFY_CHECK(sign == 1 || sign == -1);
return (*r == (int128_t)((uint128_t)sign << n));
} }
#endif #endif

View file

@ -170,8 +170,14 @@ static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned
} }
} }
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
return a->lo;
}
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) { static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
return (int64_t)a->lo; /* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */
VERIFY_CHECK(a->hi == -(a->lo >> 63));
return (int64_t)secp256k1_i128_to_u64(a);
} }
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) { static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {
@ -183,10 +189,11 @@ static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, con
return a->hi == b->hi && a->lo == b->lo; return a->hi == b->hi && a->lo == b->lo;
} }
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n) { static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) {
VERIFY_CHECK(n < 127); VERIFY_CHECK(n < 127);
return n >= 64 ? r->hi == (uint64_t)1 << (n - 64) && r->lo == 0 VERIFY_CHECK(sign == 1 || sign == -1);
: r->hi == 0 && r->lo == (uint64_t)1 << n; return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0
: r->hi == (uint64_t)((sign - 1) >> 1) && r->lo == (uint64_t)sign << n;
} }
#endif #endif

View file

@ -7,10 +7,6 @@
#ifndef SECP256K1_MODINV32_H #ifndef SECP256K1_MODINV32_H
#define SECP256K1_MODINV32_H #define SECP256K1_MODINV32_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h" #include "util.h"
/* A signed 30-bit limb representation of integers. /* A signed 30-bit limb representation of integers.
@ -39,4 +35,9 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
/* Same as secp256k1_modinv32_var, but constant time in x (not in the modulus). */ /* Same as secp256k1_modinv32_var, but constant time in x (not in the modulus). */
static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo); static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus
* cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result
* cannot be computed. */
static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
#endif /* SECP256K1_MODINV32_H */ #endif /* SECP256K1_MODINV32_H */

View file

@ -232,6 +232,21 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
return zeta; return zeta;
} }
/* inv256[i] = -(2*i+1)^-1 (mod 256) */
static const uint8_t secp256k1_modinv32_inv256[128] = {
0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59,
0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31,
0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89,
0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61,
0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9,
0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91,
0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9,
0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1,
0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19,
0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1,
0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01
};
/* Compute the transition matrix and eta for 30 divsteps (variable time). /* Compute the transition matrix and eta for 30 divsteps (variable time).
* *
* Input: eta: initial eta * Input: eta: initial eta
@ -243,21 +258,6 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
* Implements the divsteps_n_matrix_var function from the explanation. * Implements the divsteps_n_matrix_var function from the explanation.
*/ */
static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) { static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) {
/* inv256[i] = -(2*i+1)^-1 (mod 256) */
static const uint8_t inv256[128] = {
0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59,
0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31,
0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89,
0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61,
0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9,
0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91,
0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9,
0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1,
0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19,
0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1,
0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01
};
/* Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. */ /* Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. */
uint32_t u = 1, v = 0, q = 0, r = 1; uint32_t u = 1, v = 0, q = 0, r = 1;
uint32_t f = f0, g = g0, m; uint32_t f = f0, g = g0, m;
@ -297,7 +297,7 @@ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint
VERIFY_CHECK(limit > 0 && limit <= 30); VERIFY_CHECK(limit > 0 && limit <= 30);
m = (UINT32_MAX >> (32 - limit)) & 255U; m = (UINT32_MAX >> (32 - limit)) & 255U;
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */ /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
w = (g * inv256[(f >> 1) & 127]) & m; w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m;
/* Do so. */ /* Do so. */
g += f * w; g += f * w;
q += u * w; q += u * w;
@ -317,6 +317,86 @@ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint
return eta; return eta;
} }
/* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track
* of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because
* Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
*
* Input: eta: initial eta
* f0: bottom limb of initial f
* g0: bottom limb of initial g
* Output: t: transition matrix
* Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign
* by applying the returned transformation matrix to it. The other bits of *jacp may
* change, but are meaningless.
* Return: final eta
*/
static int32_t secp256k1_modinv32_posdivsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t, int *jacp) {
/* Transformation matrix. */
uint32_t u = 1, v = 0, q = 0, r = 1;
uint32_t f = f0, g = g0, m;
uint16_t w;
int i = 30, limit, zeros;
int jac = *jacp;
for (;;) {
/* Use a sentinel bit to count zeros only up to i. */
zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i));
/* Perform zeros divsteps at once; they all just divide g by two. */
g >>= zeros;
u <<= zeros;
v <<= zeros;
eta -= zeros;
i -= zeros;
/* Update the bottom bit of jac: when dividing g by an odd power of 2,
* if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
jac ^= (zeros & ((f >> 1) ^ (f >> 2)));
/* We're done once we've done 30 posdivsteps. */
if (i == 0) break;
VERIFY_CHECK((f & 1) == 1);
VERIFY_CHECK((g & 1) == 1);
VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i));
VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i));
/* If eta is negative, negate it and replace f,g with g,f. */
if (eta < 0) {
uint32_t tmp;
eta = -eta;
/* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
* if both f and g are 3 mod 4. */
jac ^= ((f & g) >> 1);
tmp = f; f = g; g = tmp;
tmp = u; u = q; q = tmp;
tmp = v; v = r; r = tmp;
}
/* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more
* than i can be cancelled out (as we'd be done before that point), and no more than eta+1
* can be done as its sign will flip once that happens. */
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
/* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */
VERIFY_CHECK(limit > 0 && limit <= 30);
m = (UINT32_MAX >> (32 - limit)) & 255U;
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m;
/* Do so. */
g += f * w;
q += u * w;
r += v * w;
VERIFY_CHECK((g & m) == 0);
}
/* Return data in t and return value. */
t->u = (int32_t)u;
t->v = (int32_t)v;
t->q = (int32_t)q;
t->r = (int32_t)r;
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
* the aggregate of 30 of them will have determinant 2^30 or -2^30. */
VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30 ||
(int64_t)t->u * t->r - (int64_t)t->v * t->q == -(((int64_t)1) << 30));
*jacp = jac;
return eta;
}
/* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps. /* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps.
* *
* On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range
@ -335,10 +415,8 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */ VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
VERIFY_CHECK((labs(u) + labs(v)) >= 0); /* |u|+|v| doesn't overflow */ VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */
VERIFY_CHECK((labs(q) + labs(r)) >= 0); /* |q|+|r| doesn't overflow */ VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */
VERIFY_CHECK((labs(u) + labs(v)) <= M30 + 1); /* |u|+|v| <= 2^30 */
VERIFY_CHECK((labs(q) + labs(r)) <= M30 + 1); /* |q|+|r| <= 2^30 */
#endif #endif
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d->v[8] >> 31; sd = d->v[8] >> 31;
@ -584,4 +662,74 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
*x = d; *x = d;
} }
/* Do up to 50 iterations of 30 posdivsteps (up to 1500 steps; more is extremely rare) each until f=1.
* In VERIFY mode use a lower number of iterations (750, close to the median 756), so failure actually occurs. */
#ifdef VERIFY
#define JACOBI32_ITERATIONS 25
#else
#define JACOBI32_ITERATIONS 50
#endif
/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */
static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) {
/* Start with f=modulus, g=x, eta=-1. */
secp256k1_modinv32_signed30 f = modinfo->modulus;
secp256k1_modinv32_signed30 g = *x;
int j, len = 9;
int32_t eta = -1; /* eta = -delta; delta is initially 1 */
int32_t cond, fn, gn;
int jac = 0;
int count;
/* The input limbs must all be non-negative. */
VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0 && g.v[5] >= 0 && g.v[6] >= 0 && g.v[7] >= 0 && g.v[8] >= 0);
/* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we
* require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or
* time out). */
VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4] | g.v[5] | g.v[6] | g.v[7] | g.v[8]) != 0);
for (count = 0; count < JACOBI32_ITERATIONS; ++count) {
/* Compute transition matrix and new eta after 30 posdivsteps. */
secp256k1_modinv32_trans2x2 t;
eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac);
/* Update f,g using that transition matrix. */
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
/* If the bottom limb of f is 1, there is a chance that f=1. */
if (f.v[0] == 1) {
cond = 0;
/* Check if the other limbs are also 0. */
for (j = 1; j < len; ++j) {
cond |= f.v[j];
}
/* If so, we're done. If f=1, the Jacobi symbol (g | f)=1. */
if (cond == 0) return 1 - 2*(jac & 1);
}
/* Determine if len>1 and limb (len-1) of both f and g is 0. */
fn = f.v[len - 1];
gn = g.v[len - 1];
cond = ((int32_t)len - 2) >> 31;
cond |= fn;
cond |= gn;
/* If so, reduce length. */
if (cond == 0) --len;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
}
/* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */
return 0;
}
#endif /* SECP256K1_MODINV32_IMPL_H */ #endif /* SECP256K1_MODINV32_IMPL_H */

View file

@ -7,10 +7,6 @@
#ifndef SECP256K1_MODINV64_H #ifndef SECP256K1_MODINV64_H
#define SECP256K1_MODINV64_H #define SECP256K1_MODINV64_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h" #include "util.h"
#ifndef SECP256K1_WIDEMUL_INT128 #ifndef SECP256K1_WIDEMUL_INT128
@ -43,4 +39,9 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
/* Same as secp256k1_modinv64_var, but constant time in x (not in the modulus). */ /* Same as secp256k1_modinv64_var, but constant time in x (not in the modulus). */
static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo); static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus
* cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result
* cannot be computed. */
static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
#endif /* SECP256K1_MODINV64_H */ #endif /* SECP256K1_MODINV64_H */

View file

@ -39,13 +39,13 @@ static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}};
/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */ /* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */
static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) { static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2); const uint64_t M62 = UINT64_MAX >> 2;
secp256k1_int128 c, d; secp256k1_int128 c, d;
int i; int i;
secp256k1_i128_from_i64(&c, 0); secp256k1_i128_from_i64(&c, 0);
for (i = 0; i < 4; ++i) { for (i = 0; i < 4; ++i) {
if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor); if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor);
r->v[i] = secp256k1_i128_to_i64(&c) & M62; secp256k1_i128_rshift(&c, 62); r->v[i] = secp256k1_i128_to_u64(&c) & M62; secp256k1_i128_rshift(&c, 62);
} }
if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor); if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor);
secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c)); secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c));
@ -71,11 +71,13 @@ static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, i
return 0; return 0;
} }
/* Check if the determinant of t is equal to 1 << n. */ /* Check if the determinant of t is equal to 1 << n. If abs, check if |det t| == 1 << n. */
static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n) { static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n, int abs) {
secp256k1_int128 a; secp256k1_int128 a;
secp256k1_i128_det(&a, t->u, t->v, t->q, t->r); secp256k1_i128_det(&a, t->u, t->v, t->q, t->r);
return secp256k1_i128_check_pow2(&a, n); if (secp256k1_i128_check_pow2(&a, n, 1)) return 1;
if (abs && secp256k1_i128_check_pow2(&a, n, -1)) return 1;
return 0;
} }
#endif #endif
@ -218,7 +220,7 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
* aggregate of 59 of them will have determinant 2^59. Multiplying with the initial * aggregate of 59 of them will have determinant 2^59. Multiplying with the initial
* 8*identity (which has determinant 2^6) means the overall outputs has determinant * 8*identity (which has determinant 2^6) means the overall outputs has determinant
* 2^65. */ * 2^65. */
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65)); VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0));
#endif #endif
return zeta; return zeta;
} }
@ -266,7 +268,7 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
tmp = v; v = r; r = -tmp; tmp = v; v = r; r = -tmp;
/* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled /* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled
* out (as we'd be done before that point), and no more than eta+1 can be done as its * out (as we'd be done before that point), and no more than eta+1 can be done as its
* will flip again once that happens. */ * sign will flip again once that happens. */
limit = ((int)eta + 1) > i ? i : ((int)eta + 1); limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
VERIFY_CHECK(limit > 0 && limit <= 62); VERIFY_CHECK(limit > 0 && limit <= 62);
/* m is a mask for the bottom min(limit, 6) bits. */ /* m is a mask for the bottom min(limit, 6) bits. */
@ -301,11 +303,103 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the * will be divided out again). As each divstep's individual matrix has determinant 2, the
* aggregate of 62 of them will have determinant 2^62. */ * aggregate of 62 of them will have determinant 2^62. */
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62)); VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0));
#endif #endif
return eta; return eta;
} }
/* Compute the transition matrix and eta for 62 posdivsteps (variable time, eta=-delta), and keeps track
* of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^64 rather than 2^62, because
* Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
*
* Input: eta: initial eta
* f0: bottom limb of initial f
* g0: bottom limb of initial g
* Output: t: transition matrix
* Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign
* by applying the returned transformation matrix to it. The other bits of *jacp may
* change, but are meaningless.
* Return: final eta
*/
static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t, int *jacp) {
/* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */
uint64_t u = 1, v = 0, q = 0, r = 1;
uint64_t f = f0, g = g0, m;
uint32_t w;
int i = 62, limit, zeros;
int jac = *jacp;
for (;;) {
/* Use a sentinel bit to count zeros only up to i. */
zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i));
/* Perform zeros divsteps at once; they all just divide g by two. */
g >>= zeros;
u <<= zeros;
v <<= zeros;
eta -= zeros;
i -= zeros;
/* Update the bottom bit of jac: when dividing g by an odd power of 2,
* if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
jac ^= (zeros & ((f >> 1) ^ (f >> 2)));
/* We're done once we've done 62 posdivsteps. */
if (i == 0) break;
VERIFY_CHECK((f & 1) == 1);
VERIFY_CHECK((g & 1) == 1);
VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i));
VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i));
/* If eta is negative, negate it and replace f,g with g,f. */
if (eta < 0) {
uint64_t tmp;
eta = -eta;
tmp = f; f = g; g = tmp;
tmp = u; u = q; q = tmp;
tmp = v; v = r; r = tmp;
/* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
* if both f and g are 3 mod 4. */
jac ^= ((f & g) >> 1);
/* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled
* out (as we'd be done before that point), and no more than eta+1 can be done as its
* sign will flip again once that happens. */
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
VERIFY_CHECK(limit > 0 && limit <= 62);
/* m is a mask for the bottom min(limit, 6) bits. */
m = (UINT64_MAX >> (64 - limit)) & 63U;
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 6)
* bits. */
w = (f * g * (f * f - 2)) & m;
} else {
/* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as
* eta tends to be smaller here. */
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
VERIFY_CHECK(limit > 0 && limit <= 62);
/* m is a mask for the bottom min(limit, 4) bits. */
m = (UINT64_MAX >> (64 - limit)) & 15U;
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 4)
* bits. */
w = f + (((f + 1) & 4) << 1);
w = (-w * g) & m;
}
g += f * w;
q += u * w;
r += v * w;
VERIFY_CHECK((g & m) == 0);
}
/* Return data in t and return value. */
t->u = (int64_t)u;
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
#ifdef VERIFY
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
* the aggregate of 62 of them will have determinant 2^62 or -2^62. */
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1));
#endif
*jacp = jac;
return eta;
}
/* Compute (t/2^62) * [d, e] mod modulus, where t is a transition matrix scaled by 2^62. /* Compute (t/2^62) * [d, e] mod modulus, where t is a transition matrix scaled by 2^62.
* *
* On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range * On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range
@ -314,7 +408,7 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
* This implements the update_de function from the explanation. * This implements the update_de function from the explanation.
*/ */
static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp256k1_modinv64_signed62 *e, const secp256k1_modinv64_trans2x2 *t, const secp256k1_modinv64_modinfo* modinfo) { static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp256k1_modinv64_signed62 *e, const secp256k1_modinv64_trans2x2 *t, const secp256k1_modinv64_modinfo* modinfo) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2); const uint64_t M62 = UINT64_MAX >> 2;
const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4]; const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4];
const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4]; const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4];
const int64_t u = t->u, v = t->v, q = t->q, r = t->r; const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
@ -325,10 +419,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */ VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) >= 0); /* |u|+|v| doesn't overflow */ VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) >= 0); /* |q|+|r| doesn't overflow */ VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) <= M62 + 1); /* |u|+|v| <= 2^62 */
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) <= M62 + 1); /* |q|+|r| <= 2^62 */
#endif #endif
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */ /* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d4 >> 63; sd = d4 >> 63;
@ -341,14 +433,14 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
secp256k1_i128_mul(&ce, q, d0); secp256k1_i128_mul(&ce, q, d0);
secp256k1_i128_accum_mul(&ce, r, e0); secp256k1_i128_accum_mul(&ce, r, e0);
/* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */ /* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */
md -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&cd) + md) & M62; md -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&cd) + md) & M62;
me -= (modinfo->modulus_inv62 * (uint64_t)secp256k1_i128_to_i64(&ce) + me) & M62; me -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&ce) + me) & M62;
/* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */ /* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md); secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me); secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me);
/* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */ /* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */
VERIFY_CHECK((secp256k1_i128_to_i64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62); VERIFY_CHECK((secp256k1_i128_to_u64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
VERIFY_CHECK((secp256k1_i128_to_i64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62); VERIFY_CHECK((secp256k1_i128_to_u64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
/* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */ /* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */
secp256k1_i128_accum_mul(&cd, u, d1); secp256k1_i128_accum_mul(&cd, u, d1);
secp256k1_i128_accum_mul(&cd, v, e1); secp256k1_i128_accum_mul(&cd, v, e1);
@ -358,8 +450,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md); secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me); secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me);
} }
d->v[0] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); d->v[0] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[0] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); e->v[0] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */ /* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */
secp256k1_i128_accum_mul(&cd, u, d2); secp256k1_i128_accum_mul(&cd, u, d2);
secp256k1_i128_accum_mul(&cd, v, e2); secp256k1_i128_accum_mul(&cd, v, e2);
@ -369,8 +461,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md); secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me); secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me);
} }
d->v[1] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); d->v[1] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[1] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); e->v[1] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */ /* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */
secp256k1_i128_accum_mul(&cd, u, d3); secp256k1_i128_accum_mul(&cd, u, d3);
secp256k1_i128_accum_mul(&cd, v, e3); secp256k1_i128_accum_mul(&cd, v, e3);
@ -380,8 +472,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md); secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me); secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me);
} }
d->v[2] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); d->v[2] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[2] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); e->v[2] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */ /* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */
secp256k1_i128_accum_mul(&cd, u, d4); secp256k1_i128_accum_mul(&cd, u, d4);
secp256k1_i128_accum_mul(&cd, v, e4); secp256k1_i128_accum_mul(&cd, v, e4);
@ -389,8 +481,8 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
secp256k1_i128_accum_mul(&ce, r, e4); secp256k1_i128_accum_mul(&ce, r, e4);
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md); secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me); secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me);
d->v[3] = secp256k1_i128_to_i64(&cd) & M62; secp256k1_i128_rshift(&cd, 62); d->v[3] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[3] = secp256k1_i128_to_i64(&ce) & M62; secp256k1_i128_rshift(&ce, 62); e->v[3] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */ /* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
d->v[4] = secp256k1_i128_to_i64(&cd); d->v[4] = secp256k1_i128_to_i64(&cd);
e->v[4] = secp256k1_i128_to_i64(&ce); e->v[4] = secp256k1_i128_to_i64(&ce);
@ -407,7 +499,7 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
* This implements the update_fg function from the explanation. * This implements the update_fg function from the explanation.
*/ */
static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) { static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2); const uint64_t M62 = UINT64_MAX >> 2;
const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4]; const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4];
const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4]; const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4];
const int64_t u = t->u, v = t->v, q = t->q, r = t->r; const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
@ -418,36 +510,36 @@ static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp
secp256k1_i128_mul(&cg, q, f0); secp256k1_i128_mul(&cg, q, f0);
secp256k1_i128_accum_mul(&cg, r, g0); secp256k1_i128_accum_mul(&cg, r, g0);
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62); VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62); VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
/* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */ /* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */
secp256k1_i128_accum_mul(&cf, u, f1); secp256k1_i128_accum_mul(&cf, u, f1);
secp256k1_i128_accum_mul(&cf, v, g1); secp256k1_i128_accum_mul(&cf, v, g1);
secp256k1_i128_accum_mul(&cg, q, f1); secp256k1_i128_accum_mul(&cg, q, f1);
secp256k1_i128_accum_mul(&cg, r, g1); secp256k1_i128_accum_mul(&cg, r, g1);
f->v[0] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); f->v[0] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[0] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); g->v[0] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 2 of t*[f,g], and store it as output limb 1. */ /* Compute limb 2 of t*[f,g], and store it as output limb 1. */
secp256k1_i128_accum_mul(&cf, u, f2); secp256k1_i128_accum_mul(&cf, u, f2);
secp256k1_i128_accum_mul(&cf, v, g2); secp256k1_i128_accum_mul(&cf, v, g2);
secp256k1_i128_accum_mul(&cg, q, f2); secp256k1_i128_accum_mul(&cg, q, f2);
secp256k1_i128_accum_mul(&cg, r, g2); secp256k1_i128_accum_mul(&cg, r, g2);
f->v[1] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); f->v[1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[1] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); g->v[1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 3 of t*[f,g], and store it as output limb 2. */ /* Compute limb 3 of t*[f,g], and store it as output limb 2. */
secp256k1_i128_accum_mul(&cf, u, f3); secp256k1_i128_accum_mul(&cf, u, f3);
secp256k1_i128_accum_mul(&cf, v, g3); secp256k1_i128_accum_mul(&cf, v, g3);
secp256k1_i128_accum_mul(&cg, q, f3); secp256k1_i128_accum_mul(&cg, q, f3);
secp256k1_i128_accum_mul(&cg, r, g3); secp256k1_i128_accum_mul(&cg, r, g3);
f->v[2] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); f->v[2] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[2] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); g->v[2] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 4 of t*[f,g], and store it as output limb 3. */ /* Compute limb 4 of t*[f,g], and store it as output limb 3. */
secp256k1_i128_accum_mul(&cf, u, f4); secp256k1_i128_accum_mul(&cf, u, f4);
secp256k1_i128_accum_mul(&cf, v, g4); secp256k1_i128_accum_mul(&cf, v, g4);
secp256k1_i128_accum_mul(&cg, q, f4); secp256k1_i128_accum_mul(&cg, q, f4);
secp256k1_i128_accum_mul(&cg, r, g4); secp256k1_i128_accum_mul(&cg, r, g4);
f->v[3] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); f->v[3] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[3] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); g->v[3] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* What remains is limb 5 of t*[f,g]; store it as output limb 4. */ /* What remains is limb 5 of t*[f,g]; store it as output limb 4. */
f->v[4] = secp256k1_i128_to_i64(&cf); f->v[4] = secp256k1_i128_to_i64(&cf);
g->v[4] = secp256k1_i128_to_i64(&cg); g->v[4] = secp256k1_i128_to_i64(&cg);
@ -460,7 +552,7 @@ static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp
* This implements the update_fg function from the explanation. * This implements the update_fg function from the explanation.
*/ */
static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) { static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2); const uint64_t M62 = UINT64_MAX >> 2;
const int64_t u = t->u, v = t->v, q = t->q, r = t->r; const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int64_t fi, gi; int64_t fi, gi;
secp256k1_int128 cf, cg; secp256k1_int128 cf, cg;
@ -474,8 +566,8 @@ static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_sign
secp256k1_i128_mul(&cg, q, fi); secp256k1_i128_mul(&cg, q, fi);
secp256k1_i128_accum_mul(&cg, r, gi); secp256k1_i128_accum_mul(&cg, r, gi);
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */ /* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
VERIFY_CHECK((secp256k1_i128_to_i64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62); VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
VERIFY_CHECK((secp256k1_i128_to_i64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62); VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
/* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting /* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
* down by 62 bits). */ * down by 62 bits). */
for (i = 1; i < len; ++i) { for (i = 1; i < len; ++i) {
@ -485,8 +577,8 @@ static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_sign
secp256k1_i128_accum_mul(&cf, v, gi); secp256k1_i128_accum_mul(&cf, v, gi);
secp256k1_i128_accum_mul(&cg, q, fi); secp256k1_i128_accum_mul(&cg, q, fi);
secp256k1_i128_accum_mul(&cg, r, gi); secp256k1_i128_accum_mul(&cg, r, gi);
f->v[i - 1] = secp256k1_i128_to_i64(&cf) & M62; secp256k1_i128_rshift(&cf, 62); f->v[i - 1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[i - 1] = secp256k1_i128_to_i64(&cg) & M62; secp256k1_i128_rshift(&cg, 62); g->v[i - 1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
} }
/* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */ /* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */
f->v[len - 1] = secp256k1_i128_to_i64(&cf); f->v[len - 1] = secp256k1_i128_to_i64(&cf);
@ -626,4 +718,74 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
*x = d; *x = d;
} }
/* Do up to 25 iterations of 62 posdivsteps (up to 1550 steps; more is extremely rare) each until f=1.
* In VERIFY mode use a lower number of iterations (744, close to the median 756), so failure actually occurs. */
#ifdef VERIFY
#define JACOBI64_ITERATIONS 12
#else
#define JACOBI64_ITERATIONS 25
#endif
/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */
static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) {
/* Start with f=modulus, g=x, eta=-1. */
secp256k1_modinv64_signed62 f = modinfo->modulus;
secp256k1_modinv64_signed62 g = *x;
int j, len = 5;
int64_t eta = -1; /* eta = -delta; delta is initially 1 */
int64_t cond, fn, gn;
int jac = 0;
int count;
/* The input limbs must all be non-negative. */
VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0);
/* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we
* require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or
* time out). */
VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4]) != 0);
for (count = 0; count < JACOBI64_ITERATIONS; ++count) {
/* Compute transition matrix and new eta after 62 posdivsteps. */
secp256k1_modinv64_trans2x2 t;
eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac);
/* Update f,g using that transition matrix. */
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
/* If the bottom limb of f is 1, there is a chance that f=1. */
if (f.v[0] == 1) {
cond = 0;
/* Check if the other limbs are also 0. */
for (j = 1; j < len; ++j) {
cond |= f.v[j];
}
/* If so, we're done. When f=1, the Jacobi symbol (g | f)=1. */
if (cond == 0) return 1 - 2*(jac & 1);
}
/* Determine if len>1 and limb (len-1) of both f and g is 0. */
fn = f.v[len - 1];
gn = g.v[len - 1];
cond = ((int64_t)len - 2) >> 63;
cond |= fn;
cond |= gn;
/* If so, reduce length. */
if (cond == 0) --len;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
}
/* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */
return 0;
}
#endif /* SECP256K1_MODINV64_IMPL_H */ #endif /* SECP256K1_MODINV64_IMPL_H */

View file

@ -42,7 +42,7 @@ static void bench_ecdh(void* arg, int iters) {
} }
} }
void run_ecdh_bench(int iters, int argc, char** argv) { static void run_ecdh_bench(int iters, int argc, char** argv) {
bench_ecdh_data data; bench_ecdh_data data;
int d = argc == 1; int d = argc == 1;

View file

@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_ECDH_TESTS_H #ifndef SECP256K1_MODULE_ECDH_TESTS_H
#define SECP256K1_MODULE_ECDH_TESTS_H #define SECP256K1_MODULE_ECDH_TESTS_H
int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { static int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
(void)output; (void)output;
(void)x; (void)x;
(void)y; (void)y;
@ -15,7 +15,7 @@ int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x,
return 0; return 0;
} }
int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) { static int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
(void)data; (void)data;
/* Save x and y as uncompressed public key */ /* Save x and y as uncompressed public key */
output[0] = 0x04; output[0] = 0x04;
@ -24,7 +24,7 @@ int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, con
return 1; return 1;
} }
void test_ecdh_api(void) { static void test_ecdh_api(void) {
/* Setup context that just counts errors */ /* Setup context that just counts errors */
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_pubkey point; secp256k1_pubkey point;
@ -53,14 +53,14 @@ void test_ecdh_api(void) {
secp256k1_context_destroy(tctx); secp256k1_context_destroy(tctx);
} }
void test_ecdh_generator_basepoint(void) { static void test_ecdh_generator_basepoint(void) {
unsigned char s_one[32] = { 0 }; unsigned char s_one[32] = { 0 };
secp256k1_pubkey point[2]; secp256k1_pubkey point[2];
int i; int i;
s_one[31] = 1; s_one[31] = 1;
/* Check against pubkey creation when the basepoint is the generator */ /* Check against pubkey creation when the basepoint is the generator */
for (i = 0; i < 2 * count; ++i) { for (i = 0; i < 2 * COUNT; ++i) {
secp256k1_sha256 sha; secp256k1_sha256 sha;
unsigned char s_b32[32]; unsigned char s_b32[32];
unsigned char output_ecdh[65]; unsigned char output_ecdh[65];
@ -72,20 +72,20 @@ void test_ecdh_generator_basepoint(void) {
random_scalar_order(&s); random_scalar_order(&s);
secp256k1_scalar_get_b32(s_b32, &s); secp256k1_scalar_get_b32(s_b32, &s);
CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &point[1], s_b32) == 1);
/* compute using ECDH function with custom hash function */ /* compute using ECDH function with custom hash function */
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1); CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1);
/* compute "explicitly" */ /* compute "explicitly" */
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1); CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1);
/* compare */ /* compare */
CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0); CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0);
/* compute using ECDH function with default hash function */ /* compute using ECDH function with default hash function */
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1); CHECK(secp256k1_ecdh(CTX, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
/* compute "explicitly" */ /* compute "explicitly" */
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); CHECK(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
secp256k1_sha256_initialize(&sha); secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, point_ser, point_ser_len); secp256k1_sha256_write(&sha, point_ser, point_ser_len);
secp256k1_sha256_finalize(&sha, output_ser); secp256k1_sha256_finalize(&sha, output_ser);
@ -94,7 +94,7 @@ void test_ecdh_generator_basepoint(void) {
} }
} }
void test_bad_scalar(void) { static void test_bad_scalar(void) {
unsigned char s_zero[32] = { 0 }; unsigned char s_zero[32] = { 0 };
unsigned char s_overflow[32] = { unsigned char s_overflow[32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@ -110,21 +110,21 @@ void test_bad_scalar(void) {
/* Create random point */ /* Create random point */
random_scalar_order(&rand); random_scalar_order(&rand);
secp256k1_scalar_get_b32(s_rand, &rand); secp256k1_scalar_get_b32(s_rand, &rand);
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_rand) == 1);
/* Try to multiply it by bad values */ /* Try to multiply it by bad values */
CHECK(secp256k1_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0); CHECK(secp256k1_ecdh(CTX, output, &point, s_zero, NULL, NULL) == 0);
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0); CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 0);
/* ...and a good one */ /* ...and a good one */
s_overflow[31] -= 1; s_overflow[31] -= 1;
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1); CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, NULL, NULL) == 1);
/* Hash function failure results in ecdh failure */ /* Hash function failure results in ecdh failure */
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0); CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
} }
/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */ /** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */
void test_result_basepoint(void) { static void test_result_basepoint(void) {
secp256k1_pubkey point; secp256k1_pubkey point;
secp256k1_scalar rand; secp256k1_scalar rand;
unsigned char s[32]; unsigned char s[32];
@ -136,26 +136,26 @@ void test_result_basepoint(void) {
unsigned char s_one[32] = { 0 }; unsigned char s_one[32] = { 0 };
s_one[31] = 1; s_one[31] = 1;
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_one) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1);
CHECK(secp256k1_ecdh(ctx, out_base, &point, s_one, NULL, NULL) == 1); CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1);
for (i = 0; i < 2 * count; i++) { for (i = 0; i < 2 * COUNT; i++) {
random_scalar_order(&rand); random_scalar_order(&rand);
secp256k1_scalar_get_b32(s, &rand); secp256k1_scalar_get_b32(s, &rand);
secp256k1_scalar_inverse(&rand, &rand); secp256k1_scalar_inverse(&rand, &rand);
secp256k1_scalar_get_b32(s_inv, &rand); secp256k1_scalar_get_b32(s_inv, &rand);
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &point, s) == 1);
CHECK(secp256k1_ecdh(ctx, out, &point, s_inv, NULL, NULL) == 1); CHECK(secp256k1_ecdh(CTX, out, &point, s_inv, NULL, NULL) == 1);
CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0); CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0);
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_inv) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_inv) == 1);
CHECK(secp256k1_ecdh(ctx, out_inv, &point, s, NULL, NULL) == 1); CHECK(secp256k1_ecdh(CTX, out_inv, &point, s, NULL, NULL) == 1);
CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0); CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0);
} }
} }
void run_ecdh_tests(void) { static void run_ecdh_tests(void) {
test_ecdh_api(); test_ecdh_api();
test_ecdh_generator_basepoint(); test_ecdh_generator_basepoint();
test_bad_scalar(); test_bad_scalar();

View file

@ -14,7 +14,7 @@ static void set_counting_callbacks(secp256k1_context *ctx0, int *ecount) {
secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount); secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount);
} }
void test_xonly_pubkey(void) { static void test_xonly_pubkey(void) {
secp256k1_pubkey pk; secp256k1_pubkey pk;
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
secp256k1_ge pk1; secp256k1_ge pk1;
@ -30,52 +30,52 @@ void test_xonly_pubkey(void) {
int ecount; int ecount;
set_counting_callbacks(ctx, &ecount); set_counting_callbacks(CTX, &ecount);
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
memset(ones32, 0xFF, 32); memset(ones32, 0xFF, 32);
secp256k1_testrand256(xy_sk); secp256k1_testrand256(xy_sk);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
/* Test xonly_pubkey_from_pubkey */ /* Test xonly_pubkey_from_pubkey */
ecount = 0; ecount = 0;
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, NULL, &pk_parity, &pk) == 0); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, NULL) == 0); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
memset(&pk, 0, sizeof(pk)); memset(&pk, 0, sizeof(pk));
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 0); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
/* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */ /* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */
memset(sk, 0, sizeof(sk)); memset(sk, 0, sizeof(sk));
sk[0] = 1; sk[0] = 1;
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0); CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0);
CHECK(pk_parity == 0); CHECK(pk_parity == 0);
/* Choose a secret key such that pubkey and xonly_pubkey are each others /* Choose a secret key such that pubkey and xonly_pubkey are each others
* negation. */ * negation. */
sk[0] = 2; sk[0] = 2;
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0); CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0);
CHECK(pk_parity == 1); CHECK(pk_parity == 1);
secp256k1_pubkey_load(ctx, &pk1, &pk); secp256k1_pubkey_load(CTX, &pk1, &pk);
secp256k1_pubkey_load(ctx, &pk2, (secp256k1_pubkey *) &xonly_pk); secp256k1_pubkey_load(CTX, &pk2, (secp256k1_pubkey *) &xonly_pk);
CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1); CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1);
secp256k1_fe_negate(&y, &pk2.y, 1); secp256k1_fe_negate(&y, &pk2.y, 1);
CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1); CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1);
/* Test xonly_pubkey_serialize and xonly_pubkey_parse */ /* Test xonly_pubkey_serialize and xonly_pubkey_parse */
ecount = 0; ecount = 0;
CHECK(secp256k1_xonly_pubkey_serialize(ctx, NULL, &xonly_pk) == 0); CHECK(secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, NULL) == 0); CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL) == 0);
CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0); CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
{ {
@ -83,52 +83,52 @@ void test_xonly_pubkey(void) {
* special casing. */ * special casing. */
secp256k1_xonly_pubkey pk_tmp; secp256k1_xonly_pubkey pk_tmp;
memset(&pk_tmp, 0, sizeof(pk_tmp)); memset(&pk_tmp, 0, sizeof(pk_tmp));
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &pk_tmp) == 0); CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp) == 0);
} }
/* pubkey_load called illegal callback */ /* pubkey_load called illegal callback */
CHECK(ecount == 3); CHECK(ecount == 3);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1);
ecount = 0; ecount = 0;
CHECK(secp256k1_xonly_pubkey_parse(ctx, NULL, buf32) == 0); CHECK(secp256k1_xonly_pubkey_parse(CTX, NULL, buf32) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, NULL) == 0); CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
/* Serialization and parse roundtrip */ /* Serialization and parse roundtrip */
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1); CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk_tmp, buf32) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0); CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0);
/* Test parsing invalid field elements */ /* Test parsing invalid field elements */
memset(&xonly_pk, 1, sizeof(xonly_pk)); memset(&xonly_pk, 1, sizeof(xonly_pk));
/* Overflowing field element */ /* Overflowing field element */
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, ones32) == 0); CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, ones32) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
memset(&xonly_pk, 1, sizeof(xonly_pk)); memset(&xonly_pk, 1, sizeof(xonly_pk));
/* There's no point with x-coordinate 0 on secp256k1 */ /* There's no point with x-coordinate 0 on secp256k1 */
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, zeros64) == 0); CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, zeros64) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
/* If a random 32-byte string can not be parsed with ec_pubkey_parse /* If a random 32-byte string can not be parsed with ec_pubkey_parse
* (because interpreted as X coordinate it does not correspond to a point on * (because interpreted as X coordinate it does not correspond to a point on
* the curve) then xonly_pubkey_parse should fail as well. */ * the curve) then xonly_pubkey_parse should fail as well. */
for (i = 0; i < count; i++) { for (i = 0; i < COUNT; i++) {
unsigned char rand33[33]; unsigned char rand33[33];
secp256k1_testrand256(&rand33[1]); secp256k1_testrand256(&rand33[1]);
rand33[0] = SECP256K1_TAG_PUBKEY_EVEN; rand33[0] = SECP256K1_TAG_PUBKEY_EVEN;
if (!secp256k1_ec_pubkey_parse(ctx, &pk, rand33, 33)) { if (!secp256k1_ec_pubkey_parse(CTX, &pk, rand33, 33)) {
memset(&xonly_pk, 1, sizeof(xonly_pk)); memset(&xonly_pk, 1, sizeof(xonly_pk));
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 0); CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 0);
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0); CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
} else { } else {
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 1); CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 1);
} }
} }
CHECK(ecount == 2); CHECK(ecount == 2);
} }
void test_xonly_pubkey_comparison(void) { static void test_xonly_pubkey_comparison(void) {
unsigned char pk1_ser[32] = { unsigned char pk1_ser[32] = {
0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11, 0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11,
0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23 0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23
@ -141,30 +141,30 @@ void test_xonly_pubkey_comparison(void) {
secp256k1_xonly_pubkey pk2; secp256k1_xonly_pubkey pk2;
int ecount = 0; int ecount = 0;
set_counting_callbacks(ctx, &ecount); set_counting_callbacks(CTX, &ecount);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk1, pk1_ser) == 1); CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk1, pk1_ser) == 1);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk2, pk2_ser) == 1); CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk2, pk2_ser) == 1);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, NULL, &pk2) < 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, NULL) > 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk2) < 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk2, &pk1) > 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk1) == 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk2, &pk2) == 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk2) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */ memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk2) < 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0);
CHECK(ecount == 3); CHECK(ecount == 3);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk1, &pk1) == 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
CHECK(ecount == 5); CHECK(ecount == 5);
CHECK(secp256k1_xonly_pubkey_cmp(ctx, &pk2, &pk1) > 0); CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0);
CHECK(ecount == 6); CHECK(ecount == 6);
} }
void test_xonly_pubkey_tweak(void) { static void test_xonly_pubkey_tweak(void) {
unsigned char zeros64[64] = { 0 }; unsigned char zeros64[64] = { 0 };
unsigned char overflows[32]; unsigned char overflows[32];
unsigned char sk[32]; unsigned char sk[32];
@ -177,48 +177,48 @@ void test_xonly_pubkey_tweak(void) {
int ecount; int ecount;
set_counting_callbacks(ctx, &ecount); set_counting_callbacks(CTX, &ecount);
memset(overflows, 0xff, sizeof(overflows)); memset(overflows, 0xff, sizeof(overflows));
secp256k1_testrand256(tweak); secp256k1_testrand256(tweak);
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1); 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); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
ecount = 0; ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, NULL, &internal_xonly_pk, tweak) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, NULL, tweak) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
/* NULL internal_xonly_pk zeroes the output_pk */ /* NULL internal_xonly_pk zeroes the output_pk */
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, NULL) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
/* NULL tweak zeroes the output_pk */ /* NULL tweak zeroes the output_pk */
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
/* Invalid tweak zeroes the output_pk */ /* Invalid tweak zeroes the output_pk */
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
/* A zero tweak is fine */ /* A zero tweak is fine */
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, zeros64) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, zeros64) == 1);
/* Fails if the resulting key was infinity */ /* Fails if the resulting key was infinity */
for (i = 0; i < count; i++) { for (i = 0; i < COUNT; i++) {
secp256k1_scalar scalar_tweak; secp256k1_scalar scalar_tweak;
/* Because sk may be negated before adding, we need to try with tweak = /* Because sk may be negated before adding, we need to try with tweak =
* sk as well as tweak = -sk. */ * sk as well as tweak = -sk. */
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL); secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak); secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
secp256k1_scalar_get_b32(tweak, &scalar_tweak); secp256k1_scalar_get_b32(tweak, &scalar_tweak);
CHECK((secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, sk) == 0) CHECK((secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, sk) == 0)
|| (secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 0)); || (secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0));
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
} }
@ -226,12 +226,12 @@ void test_xonly_pubkey_tweak(void) {
memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk)); memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk));
secp256k1_testrand256(tweak); secp256k1_testrand256(tweak);
ecount = 0; ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
} }
void test_xonly_pubkey_tweak_check(void) { static void test_xonly_pubkey_tweak_check(void) {
unsigned char zeros64[64] = { 0 }; unsigned char zeros64[64] = { 0 };
unsigned char overflows[32]; unsigned char overflows[32];
unsigned char sk[32]; unsigned char sk[32];
@ -246,49 +246,49 @@ void test_xonly_pubkey_tweak_check(void) {
int ecount; int ecount;
set_counting_callbacks(ctx, &ecount); set_counting_callbacks(CTX, &ecount);
memset(overflows, 0xff, sizeof(overflows)); memset(overflows, 0xff, sizeof(overflows));
secp256k1_testrand256(tweak); secp256k1_testrand256(tweak);
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
CHECK(secp256k1_ec_pubkey_create(ctx, &internal_pk, sk) == 1); 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); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
ecount = 0; ecount = 0;
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &output_xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &output_xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, NULL, pk_parity, &internal_xonly_pk, tweak) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
/* invalid pk_parity value */ /* invalid pk_parity value */
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, 2, &internal_xonly_pk, tweak) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, 2, &internal_xonly_pk, tweak) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, NULL, tweak) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, NULL) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
memset(tweak, 1, sizeof(tweak)); memset(tweak, 1, sizeof(tweak));
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, NULL, &internal_pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, NULL, &internal_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk32, &output_xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk32, &output_xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1);
/* Wrong pk_parity */ /* Wrong pk_parity */
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0);
/* Wrong public key */ /* Wrong public key */
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &internal_xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &internal_xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
/* Overflowing tweak not allowed */ /* Overflowing tweak not allowed */
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0);
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0); CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
} }
@ -297,7 +297,7 @@ void test_xonly_pubkey_tweak_check(void) {
* additional pubkeys by calling tweak_add. Then verifies every tweak starting * additional pubkeys by calling tweak_add. Then verifies every tweak starting
* from the last pubkey. */ * from the last pubkey. */
#define N_PUBKEYS 32 #define N_PUBKEYS 32
void test_xonly_pubkey_tweak_recursive(void) { static void test_xonly_pubkey_tweak_recursive(void) {
unsigned char sk[32]; unsigned char sk[32];
secp256k1_pubkey pk[N_PUBKEYS]; secp256k1_pubkey pk[N_PUBKEYS];
unsigned char pk_serialized[32]; unsigned char pk_serialized[32];
@ -305,28 +305,28 @@ void test_xonly_pubkey_tweak_recursive(void) {
int i; int i;
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &pk[0], sk) == 1);
/* Add tweaks */ /* Add tweaks */
for (i = 0; i < N_PUBKEYS - 1; i++) { for (i = 0; i < N_PUBKEYS - 1; i++) {
secp256k1_xonly_pubkey xonly_pk; secp256k1_xonly_pubkey xonly_pk;
memset(tweak[i], i + 1, sizeof(tweak[i])); memset(tweak[i], i + 1, sizeof(tweak[i]));
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i]) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i]) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &xonly_pk, tweak[i]) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &pk[i + 1], &xonly_pk, tweak[i]) == 1);
} }
/* Verify tweaks */ /* Verify tweaks */
for (i = N_PUBKEYS - 1; i > 0; i--) { for (i = N_PUBKEYS - 1; i > 0; i--) {
secp256k1_xonly_pubkey xonly_pk; secp256k1_xonly_pubkey xonly_pk;
int pk_parity; int pk_parity;
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk[i]) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk[i]) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_serialized, &xonly_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk_serialized, &xonly_pk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i - 1]) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk[i - 1]) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1);
} }
} }
#undef N_PUBKEYS #undef N_PUBKEYS
void test_keypair(void) { static void test_keypair(void) {
unsigned char sk[32]; unsigned char sk[32];
unsigned char sk_tmp[32]; unsigned char sk_tmp[32];
unsigned char zeros96[96] = { 0 }; unsigned char zeros96[96] = { 0 };
@ -336,10 +336,9 @@ void test_keypair(void) {
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp; secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
int pk_parity, pk_parity_tmp; int pk_parity, pk_parity_tmp;
int ecount; int ecount;
secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static);
set_counting_callbacks(ctx, &ecount); set_counting_callbacks(CTX, &ecount);
set_counting_callbacks(sttc, &ecount); set_counting_callbacks(STATIC_CTX, &ecount);
CHECK(sizeof(zeros96) == sizeof(keypair)); CHECK(sizeof(zeros96) == sizeof(keypair));
memset(overflows, 0xFF, sizeof(overflows)); memset(overflows, 0xFF, sizeof(overflows));
@ -347,103 +346,105 @@ void test_keypair(void) {
/* Test keypair_create */ /* Test keypair_create */
ecount = 0; ecount = 0;
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_keypair_create(ctx, NULL, sk) == 0); CHECK(secp256k1_keypair_create(CTX, NULL, sk) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_keypair_create(ctx, &keypair, NULL) == 0); CHECK(secp256k1_keypair_create(CTX, &keypair, NULL) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_keypair_create(sttc, &keypair, sk) == 0); CHECK(secp256k1_keypair_create(STATIC_CTX, &keypair, sk) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
/* Invalid secret key */ /* Invalid secret key */
CHECK(secp256k1_keypair_create(ctx, &keypair, zeros96) == 0); CHECK(secp256k1_keypair_create(CTX, &keypair, zeros96) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
CHECK(secp256k1_keypair_create(ctx, &keypair, overflows) == 0); CHECK(secp256k1_keypair_create(CTX, &keypair, overflows) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0); CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
/* Test keypair_pub */ /* Test keypair_pub */
ecount = 0; ecount = 0;
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair) == 1); CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1);
CHECK(secp256k1_keypair_pub(ctx, NULL, &keypair) == 0); CHECK(secp256k1_keypair_pub(CTX, NULL, &keypair) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_keypair_pub(ctx, &pk, NULL) == 0); CHECK(secp256k1_keypair_pub(CTX, &pk, NULL) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
/* Using an invalid keypair is fine for keypair_pub */ /* Using an invalid keypair is fine for keypair_pub */
memset(&keypair, 0, sizeof(keypair)); memset(&keypair, 0, sizeof(keypair));
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair) == 1); CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1);
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0); CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
/* keypair holds the same pubkey as pubkey_create */ /* keypair holds the same pubkey as pubkey_create */
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_pub(ctx, &pk_tmp, &keypair) == 1); CHECK(secp256k1_keypair_pub(CTX, &pk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0); CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0);
/** Test keypair_xonly_pub **/ /** Test keypair_xonly_pub **/
ecount = 0; ecount = 0;
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, NULL, &pk_parity, &keypair) == 0); CHECK(secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, NULL, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, NULL, &keypair) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, NULL) == 0); CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
/* Using an invalid keypair will set the xonly_pk to 0 (first reset /* Using an invalid keypair will set the xonly_pk to 0 (first reset
* xonly_pk). */ * xonly_pk). */
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
memset(&keypair, 0, sizeof(keypair)); memset(&keypair, 0, sizeof(keypair));
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk, &pk_parity, &keypair) == 0); CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 0);
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0); CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
/** keypair holds the same xonly pubkey as pubkey_create **/ /** keypair holds the same xonly pubkey as pubkey_create **/
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1); CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0); CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
CHECK(pk_parity == pk_parity_tmp); CHECK(pk_parity == pk_parity_tmp);
/* Test keypair_seckey */ /* Test keypair_seckey */
ecount = 0; ecount = 0;
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_sec(ctx, sk_tmp, &keypair) == 1); CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
CHECK(secp256k1_keypair_sec(ctx, NULL, &keypair) == 0); CHECK(secp256k1_keypair_sec(CTX, NULL, &keypair) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_keypair_sec(ctx, sk_tmp, NULL) == 0); CHECK(secp256k1_keypair_sec(CTX, sk_tmp, NULL) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
/* keypair returns the same seckey it got */ /* keypair returns the same seckey it got */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_sec(ctx, sk_tmp, &keypair) == 1); CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0); CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0);
/* Using an invalid keypair is fine for keypair_seckey */ /* Using an invalid keypair is fine for keypair_seckey */
memset(&keypair, 0, sizeof(keypair)); memset(&keypair, 0, sizeof(keypair));
CHECK(secp256k1_keypair_sec(ctx, sk_tmp, &keypair) == 1); CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0); CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
secp256k1_context_destroy(sttc);
secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
} }
void test_keypair_add(void) { static void test_keypair_add(void) {
unsigned char sk[32]; unsigned char sk[32];
secp256k1_keypair keypair; secp256k1_keypair keypair;
unsigned char overflows[32]; unsigned char overflows[32];
@ -452,49 +453,49 @@ void test_keypair_add(void) {
int i; int i;
int ecount = 0; int ecount = 0;
set_counting_callbacks(ctx, &ecount); set_counting_callbacks(CTX, &ecount);
CHECK(sizeof(zeros96) == sizeof(keypair)); CHECK(sizeof(zeros96) == sizeof(keypair));
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
secp256k1_testrand256(tweak); secp256k1_testrand256(tweak);
memset(overflows, 0xFF, 32); memset(overflows, 0xFF, 32);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, NULL, tweak) == 0); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, NULL) == 0); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
/* This does not set the keypair to zeroes */ /* This does not set the keypair to zeroes */
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0); CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0);
/* Invalid tweak zeroes the keypair */ /* Invalid tweak zeroes the keypair */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, overflows) == 0); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, overflows) == 0);
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
/* A zero tweak is fine */ /* A zero tweak is fine */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, zeros96) == 1); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, zeros96) == 1);
/* Fails if the resulting keypair was (sk=0, pk=infinity) */ /* Fails if the resulting keypair was (sk=0, pk=infinity) */
for (i = 0; i < count; i++) { for (i = 0; i < COUNT; i++) {
secp256k1_scalar scalar_tweak; secp256k1_scalar scalar_tweak;
secp256k1_keypair keypair_tmp; secp256k1_keypair keypair_tmp;
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
memcpy(&keypair_tmp, &keypair, sizeof(keypair)); memcpy(&keypair_tmp, &keypair, sizeof(keypair));
/* Because sk may be negated before adding, we need to try with tweak = /* Because sk may be negated before adding, we need to try with tweak =
* sk as well as tweak = -sk. */ * sk as well as tweak = -sk. */
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL); secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak); secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
secp256k1_scalar_get_b32(tweak, &scalar_tweak); secp256k1_scalar_get_b32(tweak, &scalar_tweak);
CHECK((secp256k1_keypair_xonly_tweak_add(ctx, &keypair, sk) == 0) CHECK((secp256k1_keypair_xonly_tweak_add(CTX, &keypair, sk) == 0)
|| (secp256k1_keypair_xonly_tweak_add(ctx, &keypair_tmp, tweak) == 0)); || (secp256k1_keypair_xonly_tweak_add(CTX, &keypair_tmp, tweak) == 0));
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0 CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0
|| secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0); || secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0);
} }
@ -503,23 +504,23 @@ void test_keypair_add(void) {
memset(&keypair, 0, sizeof(keypair)); memset(&keypair, 0, sizeof(keypair));
secp256k1_testrand256(tweak); secp256k1_testrand256(tweak);
ecount = 0; ecount = 0;
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 0); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0); CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
/* Only seckey part of keypair invalid */ /* Only seckey part of keypair invalid */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
memset(&keypair, 0, 32); memset(&keypair, 0, 32);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 0); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
/* Only pubkey part of keypair invalid */ /* Only pubkey part of keypair invalid */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
memset(&keypair.data[32], 0, 64); memset(&keypair.data[32], 0, 64);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 0); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
/* Check that the keypair_tweak_add implementation is correct */ /* Check that the keypair_tweak_add implementation is correct */
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
for (i = 0; i < count; i++) { for (i = 0; i < COUNT; i++) {
secp256k1_xonly_pubkey internal_pk; secp256k1_xonly_pubkey internal_pk;
secp256k1_xonly_pubkey output_pk; secp256k1_xonly_pubkey output_pk;
secp256k1_pubkey output_pk_xy; secp256k1_pubkey output_pk_xy;
@ -529,27 +530,27 @@ void test_keypair_add(void) {
int pk_parity; int pk_parity;
secp256k1_testrand256(tweak); secp256k1_testrand256(tweak);
CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1); 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_tweak_add(CTX, &keypair, tweak) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1);
/* Check that it passes xonly_pubkey_tweak_add_check */ /* Check that it passes xonly_pubkey_tweak_add_check */
CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk32, &output_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, pk32, &output_pk) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk32, pk_parity, &internal_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, pk32, pk_parity, &internal_pk, tweak) == 1);
/* Check that the resulting pubkey matches xonly_pubkey_tweak_add */ /* Check that the resulting pubkey matches xonly_pubkey_tweak_add */
CHECK(secp256k1_keypair_pub(ctx, &output_pk_xy, &keypair) == 1); CHECK(secp256k1_keypair_pub(CTX, &output_pk_xy, &keypair) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk_expected, &internal_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk_expected, &internal_pk, tweak) == 1);
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
/* Check that the secret key in the keypair is tweaked correctly */ /* Check that the secret key in the keypair is tweaked correctly */
CHECK(secp256k1_keypair_sec(ctx, sk32, &keypair) == 1); CHECK(secp256k1_keypair_sec(CTX, sk32, &keypair) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, sk32) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &output_pk_expected, sk32) == 1);
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0); CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
} }
} }
void run_extrakeys_tests(void) { static void run_extrakeys_tests(void) {
/* xonly key test cases */ /* xonly key test cases */
test_xonly_pubkey(); test_xonly_pubkey();
test_xonly_pubkey_tweak(); test_xonly_pubkey_tweak();

View file

@ -15,7 +15,7 @@ typedef struct {
unsigned char sig[64]; unsigned char sig[64];
} bench_recover_data; } bench_recover_data;
void bench_recover(void* arg, int iters) { static void bench_recover(void* arg, int iters) {
int i; int i;
bench_recover_data *data = (bench_recover_data*)arg; bench_recover_data *data = (bench_recover_data*)arg;
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
@ -36,7 +36,7 @@ void bench_recover(void* arg, int iters) {
} }
} }
void bench_recover_setup(void* arg) { static void bench_recover_setup(void* arg) {
int i; int i;
bench_recover_data *data = (bench_recover_data*)arg; bench_recover_data *data = (bench_recover_data*)arg;
@ -48,7 +48,7 @@ void bench_recover_setup(void* arg) {
} }
} }
void run_recovery_bench(int iters, int argc, char** argv) { static void run_recovery_bench(int iters, int argc, char** argv) {
bench_recover_data data; bench_recover_data data;
int d = argc == 1; int d = argc == 1;

View file

@ -10,7 +10,7 @@
#include "main_impl.h" #include "main_impl.h"
#include "../../../include/secp256k1_recovery.h" #include "../../../include/secp256k1_recovery.h"
void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { static void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
int i, j, k; int i, j, k;
uint64_t iter = 0; uint64_t iter = 0;
@ -43,8 +43,7 @@ void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1
(k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER); (k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER);
/* The recid's second bit is for conveying overflow (R.x value >= group order). /* The recid's second bit is for conveying overflow (R.x value >= group order).
* In the actual secp256k1 this is an astronomically unlikely event, but in the * In the actual secp256k1 this is an astronomically unlikely event, but in the
* small group used here, it will be the case for all points except the ones where * small group used here, it will almost certainly be the case for all points.
* R.x=1 (which the group is specifically selected to have).
* Note that this isn't actually useful; full recovery would need to convey * Note that this isn't actually useful; full recovery would need to convey
* floor(R.x / group_order), but only one bit is used as that is sufficient * floor(R.x / group_order), but only one bit is used as that is sufficient
* in the real group. */ * in the real group. */
@ -79,7 +78,7 @@ void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1
} }
} }
void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { static void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) {
/* This is essentially a copy of test_exhaustive_verify, with recovery added */ /* This is essentially a copy of test_exhaustive_verify, with recovery added */
int s, r, msg, key; int s, r, msg, key;
uint64_t iter = 0; uint64_t iter = 0;

View file

@ -28,9 +28,8 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c
return secp256k1_testrand_bits(1); return secp256k1_testrand_bits(1);
} }
void test_ecdsa_recovery_api(void) { static void test_ecdsa_recovery_api(void) {
/* Setup contexts that just count errors */ /* Setup contexts that just count errors */
secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static);
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
secp256k1_pubkey recpubkey; secp256k1_pubkey recpubkey;
secp256k1_ecdsa_signature normal_sig; secp256k1_ecdsa_signature normal_sig;
@ -46,88 +45,89 @@ void test_ecdsa_recovery_api(void) {
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 };
secp256k1_context_set_error_callback(ctx, counting_illegal_callback_fn, &ecount); secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
/* Construct and verify corresponding public key. */ /* Construct and verify corresponding public key. */
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1);
/* Check bad contexts and NULLs for signing */ /* Check bad contexts and NULLs for signing */
ecount = 0; ecount = 0;
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, NULL, message, privkey, NULL, NULL) == 0); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, NULL, privkey, NULL, NULL) == 0); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, NULL, NULL, NULL) == 0); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_sign_recoverable(sttc, &recsig, message, privkey, NULL, NULL) == 0); CHECK(secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL) == 0);
CHECK(ecount == 4); CHECK(ecount == 4);
/* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, recovery_test_nonce_function, NULL); secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, recovery_test_nonce_function, NULL);
CHECK(ecount == 4); CHECK(ecount == 4);
/* These will all fail, but not in ARG_CHECK way */ /* These will all fail, but not in ARG_CHECK way */
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, zero_privkey, NULL, NULL) == 0); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, zero_privkey, NULL, NULL) == 0);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, over_privkey, NULL, NULL) == 0); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, over_privkey, NULL, NULL) == 0);
/* This one will succeed. */ /* This one will succeed. */
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
CHECK(ecount == 4); CHECK(ecount == 4);
/* Check signing with a goofy nonce function */ /* Check signing with a goofy nonce function */
/* Check bad contexts and NULLs for recovery */ /* Check bad contexts and NULLs for recovery */
ecount = 0; ecount = 0;
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &recsig, message) == 1); CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, message) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_recover(ctx, NULL, &recsig, message) == 0); CHECK(secp256k1_ecdsa_recover(CTX, NULL, &recsig, message) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, NULL, message) == 0); CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &recsig, NULL) == 0); CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
/* Check NULLs for conversion */ /* Check NULLs for conversion */
CHECK(secp256k1_ecdsa_sign(ctx, &normal_sig, message, privkey, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_sign(CTX, &normal_sig, message, privkey, NULL, NULL) == 1);
ecount = 0; ecount = 0;
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, NULL, &recsig) == 0); CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &normal_sig, NULL) == 0); CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &normal_sig, &recsig) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, &recsig) == 1);
/* Check NULLs for de/serialization */ /* Check NULLs for de/serialization */
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &recsig, message, privkey, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
ecount = 0; ecount = 0;
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, NULL, &recid, &recsig) == 0); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, NULL, &recsig) == 0); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, NULL) == 0); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recsig) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &recsig) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, NULL, sig, recid) == 0); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid) == 0);
CHECK(ecount == 4); CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, NULL, recid) == 0); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid) == 0);
CHECK(ecount == 5); CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, sig, -1) == 0); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1) == 0);
CHECK(ecount == 6); CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, sig, 5) == 0); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5) == 0);
CHECK(ecount == 7); CHECK(ecount == 7);
/* overflow in signature will fail but not affect ecount */ /* overflow in signature will fail but not affect ecount */
memcpy(sig, over_privkey, 32); memcpy(sig, over_privkey, 32);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &recsig, sig, recid) == 0); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0);
CHECK(ecount == 7); CHECK(ecount == 7);
/* cleanup */ /* cleanup */
secp256k1_context_destroy(sttc); secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
} }
void test_ecdsa_recovery_end_to_end(void) { static void test_ecdsa_recovery_end_to_end(void) {
unsigned char extra[32] = {0x00}; unsigned char extra[32] = {0x00};
unsigned char privkey[32]; unsigned char privkey[32];
unsigned char message[32]; unsigned char message[32];
@ -148,45 +148,45 @@ void test_ecdsa_recovery_end_to_end(void) {
} }
/* Construct and verify corresponding public key. */ /* Construct and verify corresponding public key. */
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1);
/* Serialize/parse compact and verify/recover. */ /* Serialize/parse compact and verify/recover. */
extra[0] = 0; extra[0] = 0;
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[0], message, privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_sign(CTX, &signature[0], message, privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[4], message, privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[1], message, privkey, NULL, extra) == 1);
extra[31] = 1; extra[31] = 1;
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[2], message, privkey, NULL, extra) == 1);
extra[31] = 0; extra[31] = 0;
extra[0] = 1; extra[0] = 1;
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &rsignature[3], message, privkey, NULL, extra) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1);
CHECK(secp256k1_memcmp_var(&signature[4], &signature[0], 64) == 0); CHECK(secp256k1_memcmp_var(&signature[4], &signature[0], 64) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1);
memset(&rsignature[4], 0, sizeof(rsignature[4])); memset(&rsignature[4], 0, sizeof(rsignature[4]));
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 1);
/* Parse compact (with recovery id) and recover. */ /* Parse compact (with recovery id) and recover. */
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 1);
CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0); CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
/* Serialize/destroy/parse signature and verify again. */ /* Serialize/destroy/parse signature and verify again. */
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &rsignature[4]) == 1);
sig[secp256k1_testrand_bits(6)] += 1 + secp256k1_testrand_int(255); sig[secp256k1_testrand_bits(6)] += 1 + secp256k1_testrand_int(255);
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsignature[4], sig, recid) == 1);
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &signature[4], &rsignature[4]) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); CHECK(secp256k1_ecdsa_verify(CTX, &signature[4], message, &pubkey) == 0);
/* Recover again */ /* Recover again */
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &rsignature[4], message) == 0 ||
secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0); secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
} }
/* Tests several edge cases. */ /* Tests several edge cases. */
void test_ecdsa_recovery_edge_cases(void) { static void test_ecdsa_recovery_edge_cases(void) {
const unsigned char msg32[32] = { const unsigned char msg32[32] = {
'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's',
@ -222,14 +222,14 @@ void test_ecdsa_recovery_edge_cases(void) {
secp256k1_ecdsa_signature sig; secp256k1_ecdsa_signature sig;
int recid; int recid;
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0)); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 0));
CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 1));
CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); CHECK(secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 2));
CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sig64, 3));
CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); CHECK(!secp256k1_ecdsa_recover(CTX, &pubkey, &rsig, msg32));
for (recid = 0; recid < 4; recid++) { for (recid = 0; recid < 4; recid++) {
int i; int i;
@ -274,40 +274,40 @@ void test_ecdsa_recovery_edge_cases(void) {
0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,
0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04
}; };
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1); CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 1);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 1);
for (recid2 = 0; recid2 < 4; recid2++) { for (recid2 = 0; recid2 < 4; recid2++) {
secp256k1_pubkey pubkey2b; secp256k1_pubkey pubkey2b;
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigb64, recid2) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); CHECK(secp256k1_ecdsa_recover(CTX, &pubkey2b, &rsig, msg32) == 1);
/* Verifying with (order + r,4) should always fail. */ /* Verifying with (order + r,4) should always fail. */
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderlong, sizeof(sigbderlong)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
} }
/* DER parsing tests. */ /* DER parsing tests. */
/* Zero length r/s. */ /* Zero length r/s. */
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
/* Leading zeros. */ /* Leading zeros. */
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
sigbderalt3[4] = 1; sigbderalt3[4] = 1;
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
sigbderalt4[7] = 1; sigbderalt4[7] = 1;
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
/* Damage signature. */ /* Damage signature. */
sigbder[7]++; sigbder[7]++;
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
sigbder[7]--; sigbder[7]--;
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, 6) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder) - 1) == 0);
for(i = 0; i < 8; i++) { for(i = 0; i < 8; i++) {
int c; int c;
unsigned char orig = sigbder[i]; unsigned char orig = sigbder[i];
@ -317,7 +317,7 @@ void test_ecdsa_recovery_edge_cases(void) {
continue; continue;
} }
sigbder[i] = c; sigbder[i] = c;
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyb) == 0);
} }
sigbder[i] = orig; sigbder[i] = orig;
} }
@ -338,33 +338,33 @@ void test_ecdsa_recovery_edge_cases(void) {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
}; };
secp256k1_pubkey pubkeyc; secp256k1_pubkey pubkeyc;
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1); CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyc, &rsig, msg32) == 1);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1); CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 1);
sigcder[4] = 0; sigcder[4] = 0;
sigc64[31] = 0; sigc64[31] = 0;
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0);
sigcder[4] = 1; sigcder[4] = 1;
sigcder[7] = 0; sigcder[7] = 0;
sigc64[31] = 1; sigc64[31] = 1;
sigc64[63] = 0; sigc64[63] = 0;
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &rsig, sigc64, 0) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); CHECK(secp256k1_ecdsa_recover(CTX, &pubkeyb, &rsig, msg32) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(CTX, &sig, sigcder, sizeof(sigcder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); CHECK(secp256k1_ecdsa_verify(CTX, &sig, msg32, &pubkeyc) == 0);
} }
} }
void run_recovery_tests(void) { static void run_recovery_tests(void) {
int i; int i;
for (i = 0; i < count; i++) { for (i = 0; i < COUNT; i++) {
test_ecdsa_recovery_api(); test_ecdsa_recovery_api();
} }
for (i = 0; i < 64*count; i++) { for (i = 0; i < 64*COUNT; i++) {
test_ecdsa_recovery_end_to_end(); test_ecdsa_recovery_end_to_end();
} }
test_ecdsa_recovery_edge_cases(); test_ecdsa_recovery_edge_cases();

View file

@ -21,7 +21,7 @@ typedef struct {
const unsigned char **msgs; const unsigned char **msgs;
} bench_schnorrsig_data; } bench_schnorrsig_data;
void bench_schnorrsig_sign(void* arg, int iters) { static void bench_schnorrsig_sign(void* arg, int iters) {
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
int i; int i;
unsigned char msg[MSGLEN] = {0}; unsigned char msg[MSGLEN] = {0};
@ -34,7 +34,7 @@ void bench_schnorrsig_sign(void* arg, int iters) {
} }
} }
void bench_schnorrsig_verify(void* arg, int iters) { static void bench_schnorrsig_verify(void* arg, int iters) {
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg; bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
int i; int i;
@ -45,7 +45,7 @@ void bench_schnorrsig_verify(void* arg, int iters) {
} }
} }
void run_schnorrsig_bench(int iters, int argc, char** argv) { static void run_schnorrsig_bench(int iters, int argc, char** argv) {
int i; int i;
bench_schnorrsig_data data; bench_schnorrsig_data data;
int d = argc == 1; int d = argc == 1;

View file

@ -12,7 +12,7 @@
/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many /* Checks that a bit flip in the n_flip-th argument (that has n_bytes many
* bytes) changes the hash function * bytes) changes the hash function
*/ */
void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) { static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t msglen, size_t algolen) {
unsigned char nonces[2][32]; unsigned char nonces[2][32];
CHECK(nonce_function_bip340(nonces[0], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1); CHECK(nonce_function_bip340(nonces[0], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1);
secp256k1_testrand_flip(args[n_flip], n_bytes); secp256k1_testrand_flip(args[n_flip], n_bytes);
@ -23,7 +23,7 @@ void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n
/* Tests for the equality of two sha256 structs. This function only produces a /* 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 * correct result if an integer multiple of 64 many bytes have been written
* into the hash functions. */ * into the hash functions. */
void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) { static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) {
/* Is buffer fully consumed? */ /* Is buffer fully consumed? */
CHECK((sha1->bytes & 0x3F) == 0); CHECK((sha1->bytes & 0x3F) == 0);
@ -31,7 +31,7 @@ void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2)
CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0); CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
} }
void run_nonce_function_bip340_tests(void) { static void run_nonce_function_bip340_tests(void) {
unsigned char tag[13] = "BIP0340/nonce"; unsigned char tag[13] = "BIP0340/nonce";
unsigned char aux_tag[11] = "BIP0340/aux"; unsigned char aux_tag[11] = "BIP0340/aux";
unsigned char algo[13] = "BIP0340/nonce"; unsigned char algo[13] = "BIP0340/nonce";
@ -72,7 +72,7 @@ void run_nonce_function_bip340_tests(void) {
args[2] = pk; args[2] = pk;
args[3] = algo; args[3] = algo;
args[4] = aux_rand; args[4] = aux_rand;
for (i = 0; i < count; i++) { for (i = 0; i < COUNT; i++) {
nonce_function_bip340_bitflip(args, 0, 32, msglen, algolen); nonce_function_bip340_bitflip(args, 0, 32, msglen, algolen);
nonce_function_bip340_bitflip(args, 1, 32, msglen, algolen); nonce_function_bip340_bitflip(args, 1, 32, msglen, algolen);
nonce_function_bip340_bitflip(args, 2, 32, msglen, algolen); nonce_function_bip340_bitflip(args, 2, 32, msglen, algolen);
@ -90,7 +90,7 @@ void run_nonce_function_bip340_tests(void) {
secp256k1_testrand_bytes_test(algo, algolen); secp256k1_testrand_bytes_test(algo, algolen);
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1); CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1);
for (i = 0; i < count; i++) { for (i = 0; i < COUNT; i++) {
unsigned char nonce2[32]; unsigned char nonce2[32];
uint32_t offset = secp256k1_testrand_int(msglen - 1); uint32_t offset = secp256k1_testrand_int(msglen - 1);
size_t msglen_tmp = (msglen + offset) % msglen; size_t msglen_tmp = (msglen + offset) % msglen;
@ -114,7 +114,7 @@ void run_nonce_function_bip340_tests(void) {
CHECK(secp256k1_memcmp_var(nonce_z, nonce, 32) == 0); CHECK(secp256k1_memcmp_var(nonce_z, nonce, 32) == 0);
} }
void test_schnorrsig_api(void) { static void test_schnorrsig_api(void) {
unsigned char sk1[32]; unsigned char sk1[32];
unsigned char sk2[32]; unsigned char sk2[32];
unsigned char sk3[32]; unsigned char sk3[32];
@ -128,82 +128,82 @@ void test_schnorrsig_api(void) {
secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL}; secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL};
/** setup **/ /** setup **/
secp256k1_context *sttc = secp256k1_context_clone(secp256k1_context_static); int ecount = 0;
int ecount;
secp256k1_context_set_error_callback(ctx, counting_illegal_callback_fn, &ecount); secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(sttc, counting_illegal_callback_fn, &ecount); secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sttc, counting_illegal_callback_fn, &ecount); secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
secp256k1_testrand256(sk1); secp256k1_testrand256(sk1);
secp256k1_testrand256(sk2); secp256k1_testrand256(sk2);
secp256k1_testrand256(sk3); secp256k1_testrand256(sk3);
secp256k1_testrand256(msg); secp256k1_testrand256(msg);
CHECK(secp256k1_keypair_create(ctx, &keypairs[0], sk1) == 1); CHECK(secp256k1_keypair_create(CTX, &keypairs[0], sk1) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypairs[1], sk2) == 1); CHECK(secp256k1_keypair_create(CTX, &keypairs[1], sk2) == 1);
CHECK(secp256k1_keypair_create(ctx, &keypairs[2], sk3) == 1); CHECK(secp256k1_keypair_create(CTX, &keypairs[2], sk3) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[0], NULL, &keypairs[0]) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[0], NULL, &keypairs[0]) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[1], NULL, &keypairs[1]) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[1], NULL, &keypairs[1]) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[2], NULL, &keypairs[2]) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &pk[2], NULL, &keypairs[2]) == 1);
memset(&zero_pk, 0, sizeof(zero_pk)); memset(&zero_pk, 0, sizeof(zero_pk));
/** main test body **/ /** main test body **/
ecount = 0; ecount = 0;
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypairs[0], NULL) == 1); CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign32(ctx, NULL, msg, &keypairs[0], NULL) == 0); CHECK(secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, NULL, &keypairs[0], NULL) == 0); CHECK(secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, NULL, NULL) == 0); CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &invalid_keypair, NULL) == 0); CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL) == 0);
CHECK(ecount == 4); CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_sign32(sttc, sig, msg, &keypairs[0], NULL) == 0); CHECK(secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 5); CHECK(ecount == 5);
ecount = 0; ecount = 0;
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0); CHECK(secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, NULL, 0, &keypairs[0], &extraparams) == 1); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, 0, &keypairs[0], &extraparams) == 1);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), NULL, &extraparams) == 0); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0);
CHECK(ecount == 4); CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1);
CHECK(ecount == 4); CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0);
CHECK(ecount == 5); CHECK(ecount == 5);
CHECK(secp256k1_schnorrsig_sign_custom(sttc, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0); CHECK(secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 6); CHECK(ecount == 6);
ecount = 0; ecount = 0;
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypairs[0], NULL) == 1); CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk[0]) == 1); CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk[0]) == 1);
CHECK(ecount == 0); CHECK(ecount == 0);
CHECK(secp256k1_schnorrsig_verify(ctx, NULL, msg, sizeof(msg), &pk[0]) == 0); CHECK(secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0]) == 0);
CHECK(ecount == 1); CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, NULL, sizeof(msg), &pk[0]) == 0); CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0]) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, NULL, 0, &pk[0]) == 0); CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, 0, &pk[0]) == 0);
CHECK(ecount == 2); CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), NULL) == 0); CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL) == 0);
CHECK(ecount == 3); CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &zero_pk) == 0); CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk) == 0);
CHECK(ecount == 4); CHECK(ecount == 4);
secp256k1_context_destroy(sttc); secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
} }
/* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the /* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the
* expected state. */ * expected state. */
void test_schnorrsig_sha256_tagged(void) { static void test_schnorrsig_sha256_tagged(void) {
unsigned char tag[17] = "BIP0340/challenge"; unsigned char tag[17] = "BIP0340/challenge";
secp256k1_sha256 sha; secp256k1_sha256 sha;
secp256k1_sha256 sha_optimized; secp256k1_sha256 sha_optimized;
@ -215,33 +215,33 @@ void test_schnorrsig_sha256_tagged(void) {
/* Helper function for schnorrsig_bip_vectors /* Helper function for schnorrsig_bip_vectors
* Signs the message and checks that it's the same as expected_sig. */ * Signs the message and checks that it's the same as expected_sig. */
void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg32, const unsigned char *expected_sig) { static void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, const unsigned char *aux_rand, const unsigned char *msg32, const unsigned char *expected_sig) {
unsigned char sig[64]; unsigned char sig[64];
secp256k1_keypair keypair; secp256k1_keypair keypair;
secp256k1_xonly_pubkey pk, pk_expected; secp256k1_xonly_pubkey pk, pk_expected;
CHECK(secp256k1_keypair_create(ctx, &keypair, sk)); CHECK(secp256k1_keypair_create(CTX, &keypair, sk));
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg32, &keypair, aux_rand)); CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg32, &keypair, aux_rand));
CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0); CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized)); CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk_expected, pk_serialized));
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair));
CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0); CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg32, 32, &pk)); CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk));
} }
/* Helper function for schnorrsig_bip_vectors /* Helper function for schnorrsig_bip_vectors
* Checks that both verify and verify_batch (TODO) return the same value as expected. */ * Checks that both verify and verify_batch (TODO) return the same value as expected. */
void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) { static void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) {
secp256k1_xonly_pubkey pk; secp256k1_xonly_pubkey pk;
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk, pk_serialized)); CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk, pk_serialized));
CHECK(expected == secp256k1_schnorrsig_verify(ctx, sig, msg32, 32, &pk)); CHECK(expected == secp256k1_schnorrsig_verify(CTX, sig, msg32, 32, &pk));
} }
/* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See /* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See
* https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv. */ * https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv. */
void test_schnorrsig_bip_vectors(void) { static void test_schnorrsig_bip_vectors(void) {
{ {
/* Test vector 0 */ /* Test vector 0 */
const unsigned char sk[32] = { const unsigned char sk[32] = {
@ -434,7 +434,7 @@ void test_schnorrsig_bip_vectors(void) {
}; };
secp256k1_xonly_pubkey pk_parsed; secp256k1_xonly_pubkey pk_parsed;
/* No need to check the signature of the test vector as parsing the pubkey already fails */ /* No need to check the signature of the test vector as parsing the pubkey already fails */
CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk_parsed, pk)); CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk));
} }
{ {
/* Test vector 6 */ /* Test vector 6 */
@ -654,7 +654,7 @@ void test_schnorrsig_bip_vectors(void) {
}; };
secp256k1_xonly_pubkey pk_parsed; secp256k1_xonly_pubkey pk_parsed;
/* No need to check the signature of the test vector as parsing the pubkey already fails */ /* No need to check the signature of the test vector as parsing the pubkey already fails */
CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk_parsed, pk)); CHECK(!secp256k1_xonly_pubkey_parse(CTX, &pk_parsed, pk));
} }
} }
@ -699,7 +699,7 @@ static int nonce_function_overflowing(unsigned char *nonce32, const unsigned cha
return 1; return 1;
} }
void test_schnorrsig_sign(void) { static void test_schnorrsig_sign(void) {
unsigned char sk[32]; unsigned char sk[32];
secp256k1_xonly_pubkey pk; secp256k1_xonly_pubkey pk;
secp256k1_keypair keypair; secp256k1_keypair keypair;
@ -712,36 +712,36 @@ void test_schnorrsig_sign(void) {
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
secp256k1_testrand256(aux_rand); secp256k1_testrand256(aux_rand);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk)); CHECK(secp256k1_keypair_create(CTX, &keypair, sk));
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair));
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1); CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk)); CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk));
/* Check that deprecated alias gives the same result */ /* Check that deprecated alias gives the same result */
CHECK(secp256k1_schnorrsig_sign(ctx, sig2, msg, &keypair, NULL) == 1); CHECK(secp256k1_schnorrsig_sign(CTX, sig2, msg, &keypair, NULL) == 1);
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
/* Test different nonce functions */ /* Test different nonce functions */
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk)); CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk));
memset(sig, 1, sizeof(sig)); memset(sig, 1, sizeof(sig));
extraparams.noncefp = nonce_function_failing; extraparams.noncefp = nonce_function_failing;
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0);
CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0);
memset(&sig, 1, sizeof(sig)); memset(&sig, 1, sizeof(sig));
extraparams.noncefp = nonce_function_0; extraparams.noncefp = nonce_function_0;
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 0); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 0);
CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0); CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0);
memset(&sig, 1, sizeof(sig)); memset(&sig, 1, sizeof(sig));
extraparams.noncefp = nonce_function_overflowing; extraparams.noncefp = nonce_function_overflowing;
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk)); CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk));
/* When using the default nonce function, schnorrsig_sign_custom produces /* When using the default nonce function, schnorrsig_sign_custom produces
* the same result as schnorrsig_sign with aux_rand = extraparams.ndata */ * the same result as schnorrsig_sign with aux_rand = extraparams.ndata */
extraparams.noncefp = NULL; extraparams.noncefp = NULL;
extraparams.ndata = aux_rand; extraparams.ndata = aux_rand;
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig2, msg, &keypair, extraparams.ndata) == 1); CHECK(secp256k1_schnorrsig_sign32(CTX, sig2, msg, &keypair, extraparams.ndata) == 1);
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0); CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
} }
@ -749,7 +749,7 @@ void test_schnorrsig_sign(void) {
/* Creates N_SIGS valid signatures and verifies them with verify and /* Creates N_SIGS valid signatures and verifies them with verify and
* verify_batch (TODO). Then flips some bits and checks that verification now * verify_batch (TODO). Then flips some bits and checks that verification now
* fails. */ * fails. */
void test_schnorrsig_sign_verify(void) { static void test_schnorrsig_sign_verify(void) {
unsigned char sk[32]; unsigned char sk[32];
unsigned char msg[N_SIGS][32]; unsigned char msg[N_SIGS][32];
unsigned char sig[N_SIGS][64]; unsigned char sig[N_SIGS][64];
@ -759,13 +759,13 @@ void test_schnorrsig_sign_verify(void) {
secp256k1_scalar s; secp256k1_scalar s;
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk)); CHECK(secp256k1_keypair_create(CTX, &keypair, sk));
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair)); CHECK(secp256k1_keypair_xonly_pub(CTX, &pk, NULL, &keypair));
for (i = 0; i < N_SIGS; i++) { for (i = 0; i < N_SIGS; i++) {
secp256k1_testrand256(msg[i]); secp256k1_testrand256(msg[i]);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig[i], msg[i], &keypair, NULL)); CHECK(secp256k1_schnorrsig_sign32(CTX, sig[i], msg[i], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], sizeof(msg[i]), &pk)); CHECK(secp256k1_schnorrsig_verify(CTX, sig[i], msg[i], sizeof(msg[i]), &pk));
} }
{ {
@ -775,40 +775,40 @@ void test_schnorrsig_sign_verify(void) {
size_t byte_idx = secp256k1_testrand_bits(5); size_t byte_idx = secp256k1_testrand_bits(5);
unsigned char xorbyte = secp256k1_testrand_int(254)+1; unsigned char xorbyte = secp256k1_testrand_int(254)+1;
sig[sig_idx][byte_idx] ^= xorbyte; sig[sig_idx][byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
sig[sig_idx][byte_idx] ^= xorbyte; sig[sig_idx][byte_idx] ^= xorbyte;
byte_idx = secp256k1_testrand_bits(5); byte_idx = secp256k1_testrand_bits(5);
sig[sig_idx][32+byte_idx] ^= xorbyte; sig[sig_idx][32+byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
sig[sig_idx][32+byte_idx] ^= xorbyte; sig[sig_idx][32+byte_idx] ^= xorbyte;
byte_idx = secp256k1_testrand_bits(5); byte_idx = secp256k1_testrand_bits(5);
msg[sig_idx][byte_idx] ^= xorbyte; msg[sig_idx][byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); CHECK(!secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
msg[sig_idx][byte_idx] ^= xorbyte; msg[sig_idx][byte_idx] ^= xorbyte;
/* Check that above bitflips have been reversed correctly */ /* Check that above bitflips have been reversed correctly */
CHECK(secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk)); CHECK(secp256k1_schnorrsig_verify(CTX, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
} }
/* Test overflowing s */ /* Test overflowing s */
CHECK(secp256k1_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL)); CHECK(secp256k1_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk)); CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk));
memset(&sig[0][32], 0xFF, 32); memset(&sig[0][32], 0xFF, 32);
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk)); CHECK(!secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk));
/* Test negative s */ /* Test negative s */
CHECK(secp256k1_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL)); CHECK(secp256k1_schnorrsig_sign32(CTX, sig[0], msg[0], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk)); CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk));
secp256k1_scalar_set_b32(&s, &sig[0][32], NULL); secp256k1_scalar_set_b32(&s, &sig[0][32], NULL);
secp256k1_scalar_negate(&s, &s); secp256k1_scalar_negate(&s, &s);
secp256k1_scalar_get_b32(&sig[0][32], &s); secp256k1_scalar_get_b32(&sig[0][32], &s);
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk)); CHECK(!secp256k1_schnorrsig_verify(CTX, sig[0], msg[0], sizeof(msg[0]), &pk));
/* The empty message can be signed & verified */ /* The empty message can be signed & verified */
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig[0], NULL, 0, &keypair, NULL) == 1); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], NULL, 0, &keypair, NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], NULL, 0, &pk) == 1); CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], NULL, 0, &pk) == 1);
{ {
/* Test varying message lengths */ /* Test varying message lengths */
@ -817,16 +817,16 @@ void test_schnorrsig_sign_verify(void) {
for (i = 0; i < sizeof(msg_large); i += 32) { for (i = 0; i < sizeof(msg_large); i += 32) {
secp256k1_testrand256(&msg_large[i]); secp256k1_testrand256(&msg_large[i]);
} }
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig[0], msg_large, msglen, &keypair, NULL) == 1); CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig[0], msg_large, msglen, &keypair, NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg_large, msglen, &pk) == 1); CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 1);
/* Verification for a random wrong message length fails */ /* Verification for a random wrong message length fails */
msglen = (msglen + (sizeof(msg_large) - 1)) % sizeof(msg_large); msglen = (msglen + (sizeof(msg_large) - 1)) % sizeof(msg_large);
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg_large, msglen, &pk) == 0); CHECK(secp256k1_schnorrsig_verify(CTX, sig[0], msg_large, msglen, &pk) == 0);
} }
} }
#undef N_SIGS #undef N_SIGS
void test_schnorrsig_taproot(void) { static void test_schnorrsig_taproot(void) {
unsigned char sk[32]; unsigned char sk[32];
secp256k1_keypair keypair; secp256k1_keypair keypair;
secp256k1_xonly_pubkey internal_pk; secp256k1_xonly_pubkey internal_pk;
@ -840,36 +840,36 @@ void test_schnorrsig_taproot(void) {
/* Create output key */ /* Create output key */
secp256k1_testrand256(sk); secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1); CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &internal_pk, NULL, &keypair) == 1);
/* In actual taproot the tweak would be hash of internal_pk */ /* In actual taproot the tweak would be hash of internal_pk */
CHECK(secp256k1_xonly_pubkey_serialize(ctx, tweak, &internal_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, tweak, &internal_pk) == 1);
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1); CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1); CHECK(secp256k1_keypair_xonly_pub(CTX, &output_pk, &pk_parity, &keypair) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk_bytes, &output_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, output_pk_bytes, &output_pk) == 1);
/* Key spend */ /* Key spend */
secp256k1_testrand256(msg); secp256k1_testrand256(msg);
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1); CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypair, NULL) == 1);
/* Verify key spend */ /* Verify key spend */
CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1); CHECK(secp256k1_xonly_pubkey_parse(CTX, &output_pk, output_pk_bytes) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &output_pk) == 1); CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &output_pk) == 1);
/* Script spend */ /* Script spend */
CHECK(secp256k1_xonly_pubkey_serialize(ctx, internal_pk_bytes, &internal_pk) == 1); CHECK(secp256k1_xonly_pubkey_serialize(CTX, internal_pk_bytes, &internal_pk) == 1);
/* Verify script spend */ /* Verify script spend */
CHECK(secp256k1_xonly_pubkey_parse(ctx, &internal_pk, internal_pk_bytes) == 1); CHECK(secp256k1_xonly_pubkey_parse(CTX, &internal_pk, internal_pk_bytes) == 1);
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1); CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1);
} }
void run_schnorrsig_tests(void) { static void run_schnorrsig_tests(void) {
int i; int i;
run_nonce_function_bip340_tests(); run_nonce_function_bip340_tests();
test_schnorrsig_api(); test_schnorrsig_api();
test_schnorrsig_sha256_tagged(); test_schnorrsig_sha256_tagged();
test_schnorrsig_bip_vectors(); test_schnorrsig_bip_vectors();
for (i = 0; i < count; i++) { for (i = 0; i < COUNT; i++) {
test_schnorrsig_sign(); test_schnorrsig_sign();
test_schnorrsig_sign_verify(); test_schnorrsig_sign_verify();
} }

View file

@ -7,12 +7,6 @@
#include <inttypes.h> #include <inttypes.h>
#include <stdio.h> #include <stdio.h>
/* Autotools creates libsecp256k1-config.h, of which ECMULT_WINDOW_SIZE is needed.
ifndef guard so downstream users can define their own if they do not use autotools. */
#if !defined(ECMULT_WINDOW_SIZE)
#include "libsecp256k1-config.h"
#endif
#include "../include/secp256k1.h" #include "../include/secp256k1.h"
#include "assumptions.h" #include "assumptions.h"
@ -74,9 +68,6 @@ int main(void) {
fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n"); fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n");
fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n"); fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n");
fprintf(fp, " */\n"); fprintf(fp, " */\n");
fprintf(fp, "#if defined HAVE_CONFIG_H\n");
fprintf(fp, "# include \"libsecp256k1-config.h\"\n");
fprintf(fp, "#endif\n");
fprintf(fp, "#include \"../include/secp256k1.h\"\n"); fprintf(fp, "#include \"../include/secp256k1.h\"\n");
fprintf(fp, "#include \"group.h\"\n"); fprintf(fp, "#include \"group.h\"\n");
fprintf(fp, "#include \"ecmult.h\"\n"); fprintf(fp, "#include \"ecmult.h\"\n");

View file

@ -33,9 +33,6 @@ int main(int argc, char **argv) {
fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n"); fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n");
fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n"); fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n");
fprintf(fp, "#if defined HAVE_CONFIG_H\n");
fprintf(fp, "# include \"libsecp256k1-config.h\"\n");
fprintf(fp, "#endif\n");
fprintf(fp, "#include \"../include/secp256k1.h\"\n"); fprintf(fp, "#include \"../include/secp256k1.h\"\n");
fprintf(fp, "#include \"group.h\"\n"); fprintf(fp, "#include \"group.h\"\n");
fprintf(fp, "#include \"ecmult_gen.h\"\n"); fprintf(fp, "#include \"ecmult_gen.h\"\n");

View file

@ -2,9 +2,6 @@
/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and /* This file contains an array secp256k1_pre_g with odd multiples of the base point G and
* an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G. * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.
*/ */
#if defined HAVE_CONFIG_H
# include "libsecp256k1-config.h"
#endif
#include "../include/secp256k1.h" #include "../include/secp256k1.h"
#include "group.h" #include "group.h"
#include "ecmult.h" #include "ecmult.h"

View file

@ -13,7 +13,9 @@ extern "C" {
#include "group.h" #include "group.h"
#if defined(EXHAUSTIVE_TEST_ORDER) #if defined(EXHAUSTIVE_TEST_ORDER)
#if EXHAUSTIVE_TEST_ORDER == 13 # if EXHAUSTIVE_TEST_ORDER == 7
# define WINDOW_G 3
# elif EXHAUSTIVE_TEST_ORDER == 13
# define WINDOW_G 4 # define WINDOW_G 4
# elif EXHAUSTIVE_TEST_ORDER == 199 # elif EXHAUSTIVE_TEST_ORDER == 199
# define WINDOW_G 8 # define WINDOW_G 8

View file

@ -1,8 +1,5 @@
/* This file was automatically generated by precompute_ecmult_gen. */ /* This file was automatically generated by precompute_ecmult_gen. */
/* See ecmult_gen_impl.h for details about the contents of this file. */ /* See ecmult_gen_impl.h for details about the contents of this file. */
#if defined HAVE_CONFIG_H
# include "libsecp256k1-config.h"
#endif
#include "../include/secp256k1.h" #include "../include/secp256k1.h"
#include "group.h" #include "group.h"
#include "ecmult_gen.h" #include "ecmult_gen.h"

View file

@ -9,10 +9,6 @@
#include "util.h" #include "util.h"
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#if defined(EXHAUSTIVE_TEST_ORDER) #if defined(EXHAUSTIVE_TEST_ORDER)
#include "scalar_low.h" #include "scalar_low.h"
#elif defined(SECP256K1_WIDEMUL_INT128) #elif defined(SECP256K1_WIDEMUL_INT128)
@ -92,9 +88,10 @@ static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar
/** Find r1 and r2 such that r1+r2*2^128 = k. */ /** Find r1 and r2 such that r1+r2*2^128 = k. */
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k); static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k);
/** Find r1 and r2 such that r1+r2*lambda = k, /** Find r1 and r2 such that r1+r2*lambda = k, where r1 and r2 or their
* where r1 and r2 or their negations are maximum 128 bits long (see secp256k1_ge_mul_lambda). */ * negations are maximum 128 bits long (see secp256k1_ge_mul_lambda). It is
static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k); * required that r1, r2, and k all point to different objects. */
static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k);
/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */
static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift);

View file

@ -7,6 +7,7 @@
#ifndef SECP256K1_SCALAR_REPR_IMPL_H #ifndef SECP256K1_SCALAR_REPR_IMPL_H
#define SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H
#include "checkmem.h"
#include "int128.h" #include "int128.h"
#include "modinv64_impl.h" #include "modinv64_impl.h"
@ -810,7 +811,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint64_t mask0, mask1; uint64_t mask0, mask1;
VG_CHECK_VERIFY(r->d, sizeof(r->d)); SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d));
mask0 = flag + ~((uint64_t)0); mask0 = flag + ~((uint64_t)0);
mask1 = ~mask0; mask1 = ~mask0;
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);

View file

@ -7,6 +7,7 @@
#ifndef SECP256K1_SCALAR_REPR_IMPL_H #ifndef SECP256K1_SCALAR_REPR_IMPL_H
#define SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H
#include "checkmem.h"
#include "modinv32_impl.h" #include "modinv32_impl.h"
/* Limbs of the secp256k1 order. */ /* Limbs of the secp256k1 order. */
@ -631,7 +632,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint32_t mask0, mask1; uint32_t mask0, mask1;
VG_CHECK_VERIFY(r->d, sizeof(r->d)); SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d));
mask0 = flag + ~((uint32_t)0); mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0; mask1 = ~mask0;
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1); r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);

View file

@ -14,10 +14,6 @@
#include "scalar.h" #include "scalar.h"
#include "util.h" #include "util.h"
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#if defined(EXHAUSTIVE_TEST_ORDER) #if defined(EXHAUSTIVE_TEST_ORDER)
#include "scalar_low_impl.h" #include "scalar_low_impl.h"
#elif defined(SECP256K1_WIDEMUL_INT128) #elif defined(SECP256K1_WIDEMUL_INT128)
@ -37,15 +33,18 @@ static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned c
return (!overflow) & (!secp256k1_scalar_is_zero(r)); return (!overflow) & (!secp256k1_scalar_is_zero(r));
} }
/* These parameters are generated using sage/gen_exhaustive_groups.sage. */
#if defined(EXHAUSTIVE_TEST_ORDER) #if defined(EXHAUSTIVE_TEST_ORDER)
# if EXHAUSTIVE_TEST_ORDER == 13 /* Begin of section generated by sage/gen_exhaustive_groups.sage. */
# if EXHAUSTIVE_TEST_ORDER == 7
# define EXHAUSTIVE_TEST_LAMBDA 2
# elif EXHAUSTIVE_TEST_ORDER == 13
# define EXHAUSTIVE_TEST_LAMBDA 9 # define EXHAUSTIVE_TEST_LAMBDA 9
# elif EXHAUSTIVE_TEST_ORDER == 199 # elif EXHAUSTIVE_TEST_ORDER == 199
# define EXHAUSTIVE_TEST_LAMBDA 92 # define EXHAUSTIVE_TEST_LAMBDA 92
# else # else
# error No known lambda for the specified exhaustive test group order. # error No known lambda for the specified exhaustive test group order.
# endif # endif
/* End of section generated by sage/gen_exhaustive_groups.sage. */
/** /**
* Find r1 and r2 given k, such that r1 + r2 * lambda == k mod n; unlike in the * Find r1 and r2 given k, such that r1 + r2 * lambda == k mod n; unlike in the
@ -53,7 +52,10 @@ static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned c
* nontrivial to get full test coverage for the exhaustive tests. We therefore * nontrivial to get full test coverage for the exhaustive tests. We therefore
* (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n). * (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n).
*/ */
static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) {
VERIFY_CHECK(r1 != k);
VERIFY_CHECK(r2 != k);
VERIFY_CHECK(r1 != r2);
*r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER; *r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER;
*r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; *r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER;
} }
@ -120,7 +122,7 @@ static void secp256k1_scalar_split_lambda_verify(const secp256k1_scalar *r1, con
* *
* See proof below. * See proof below.
*/ */
static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) { static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) {
secp256k1_scalar c1, c2; secp256k1_scalar c1, c2;
static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST(
0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL,
@ -140,6 +142,7 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar
); );
VERIFY_CHECK(r1 != k); VERIFY_CHECK(r1 != k);
VERIFY_CHECK(r2 != k); VERIFY_CHECK(r2 != k);
VERIFY_CHECK(r1 != r2);
/* these _var calls are constant time since the shift amount is constant */ /* these _var calls are constant time since the shift amount is constant */
secp256k1_scalar_mul_shift_var(&c1, k, &g1, 384); secp256k1_scalar_mul_shift_var(&c1, k, &g1, 384);
secp256k1_scalar_mul_shift_var(&c2, k, &g2, 384); secp256k1_scalar_mul_shift_var(&c2, k, &g2, 384);

View file

@ -7,6 +7,7 @@
#ifndef SECP256K1_SCALAR_REPR_IMPL_H #ifndef SECP256K1_SCALAR_REPR_IMPL_H
#define SECP256K1_SCALAR_REPR_IMPL_H #define SECP256K1_SCALAR_REPR_IMPL_H
#include "checkmem.h"
#include "scalar.h" #include "scalar.h"
#include <string.h> #include <string.h>
@ -115,7 +116,7 @@ SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) { static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
uint32_t mask0, mask1; uint32_t mask0, mask1;
VG_CHECK_VERIFY(r, sizeof(*r)); SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r));
mask0 = flag + ~((uint32_t)0); mask0 = flag + ~((uint32_t)0);
mask1 = ~mask0; mask1 = ~mask0;
*r = (*r & mask0) | (*a & mask1); *r = (*r & mask0) | (*a & mask1);

View file

@ -21,6 +21,7 @@
#include "../include/secp256k1_preallocated.h" #include "../include/secp256k1_preallocated.h"
#include "assumptions.h" #include "assumptions.h"
#include "checkmem.h"
#include "util.h" #include "util.h"
#include "field_impl.h" #include "field_impl.h"
@ -40,10 +41,6 @@
# error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c" # error "secp256k1.h processed without SECP256K1_BUILD defined while building secp256k1.c"
#endif #endif
#if defined(VALGRIND)
# include <valgrind/memcheck.h>
#endif
#define ARG_CHECK(cond) do { \ #define ARG_CHECK(cond) do { \
if (EXPECT(!(cond), 0)) { \ if (EXPECT(!(cond), 0)) { \
secp256k1_callback_call(&ctx->illegal_callback, #cond); \ secp256k1_callback_call(&ctx->illegal_callback, #cond); \
@ -51,9 +48,10 @@
} \ } \
} while(0) } while(0)
#define ARG_CHECK_NO_RETURN(cond) do { \ #define ARG_CHECK_VOID(cond) do { \
if (EXPECT(!(cond), 0)) { \ if (EXPECT(!(cond), 0)) { \
secp256k1_callback_call(&ctx->illegal_callback, #cond); \ secp256k1_callback_call(&ctx->illegal_callback, #cond); \
return; \
} \ } \
} while(0) } while(0)
@ -75,6 +73,15 @@ static const secp256k1_context secp256k1_context_static_ = {
const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_; const secp256k1_context *secp256k1_context_static = &secp256k1_context_static_;
const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_; const secp256k1_context *secp256k1_context_no_precomp = &secp256k1_context_static_;
/* Helper function that determines if a context is proper, i.e., is not the static context or a copy thereof.
*
* This is intended for "context" functions such as secp256k1_context_clone. Function which need specific
* features of a context should still check for these features directly. For example, a function that needs
* ecmult_gen should directly check for the existence of the ecmult_gen context. */
static int secp256k1_context_is_proper(const secp256k1_context* ctx) {
return secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx);
}
void secp256k1_selftest(void) { void secp256k1_selftest(void) {
if (!secp256k1_selftest_passes()) { if (!secp256k1_selftest_passes()) {
secp256k1_callback_call(&default_error_callback, "self test failed"); secp256k1_callback_call(&default_error_callback, "self test failed");
@ -92,13 +99,19 @@ size_t secp256k1_context_preallocated_size(unsigned int flags) {
return 0; return 0;
} }
if (EXPECT(!SECP256K1_CHECKMEM_RUNNING() && (flags & SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY), 0)) {
secp256k1_callback_call(&default_illegal_callback,
"Declassify flag requires running with memory checking");
return 0;
}
return ret; return ret;
} }
size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) { size_t secp256k1_context_preallocated_clone_size(const secp256k1_context* ctx) {
size_t ret = sizeof(secp256k1_context);
VERIFY_CHECK(ctx != NULL); VERIFY_CHECK(ctx != NULL);
return ret; ARG_CHECK(secp256k1_context_is_proper(ctx));
return sizeof(secp256k1_context);
} }
secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) { secp256k1_context* secp256k1_context_preallocated_create(void* prealloc, unsigned int flags) {
@ -139,6 +152,7 @@ secp256k1_context* secp256k1_context_preallocated_clone(const secp256k1_context*
secp256k1_context* ret; secp256k1_context* ret;
VERIFY_CHECK(ctx != NULL); VERIFY_CHECK(ctx != NULL);
ARG_CHECK(prealloc != NULL); ARG_CHECK(prealloc != NULL);
ARG_CHECK(secp256k1_context_is_proper(ctx));
ret = (secp256k1_context*)prealloc; ret = (secp256k1_context*)prealloc;
*ret = *ctx; *ret = *ctx;
@ -150,6 +164,8 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
size_t prealloc_size; size_t prealloc_size;
VERIFY_CHECK(ctx != NULL); VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_context_is_proper(ctx));
prealloc_size = secp256k1_context_preallocated_clone_size(ctx); prealloc_size = secp256k1_context_preallocated_clone_size(ctx);
ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size); ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, prealloc_size);
ret = secp256k1_context_preallocated_clone(ctx, ret); ret = secp256k1_context_preallocated_clone(ctx, ret);
@ -157,21 +173,33 @@ secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) {
} }
void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) { void secp256k1_context_preallocated_destroy(secp256k1_context* ctx) {
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static); ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
if (ctx != NULL) {
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); /* Defined as noop */
if (ctx == NULL) {
return;
} }
secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx);
} }
void secp256k1_context_destroy(secp256k1_context* ctx) { void secp256k1_context_destroy(secp256k1_context* ctx) {
if (ctx != NULL) { ARG_CHECK_VOID(ctx == NULL || secp256k1_context_is_proper(ctx));
secp256k1_context_preallocated_destroy(ctx);
free(ctx); /* Defined as noop */
if (ctx == NULL) {
return;
} }
secp256k1_context_preallocated_destroy(ctx);
free(ctx);
} }
void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static); /* We compare pointers instead of checking secp256k1_context_is_proper() here
because setting callbacks is allowed on *copies* of the static context:
it's harmless and makes testing easier. */
ARG_CHECK_VOID(ctx != secp256k1_context_static);
if (fun == NULL) { if (fun == NULL) {
fun = secp256k1_default_illegal_callback_fn; fun = secp256k1_default_illegal_callback_fn;
} }
@ -180,7 +208,10 @@ void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(
} }
void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) {
ARG_CHECK_NO_RETURN(ctx != secp256k1_context_static); /* We compare pointers instead of checking secp256k1_context_is_proper() here
because setting callbacks is allowed on *copies* of the static context:
it's harmless and makes testing easier. */
ARG_CHECK_VOID(ctx != secp256k1_context_static);
if (fun == NULL) { if (fun == NULL) {
fun = secp256k1_default_error_callback_fn; fun = secp256k1_default_error_callback_fn;
} }
@ -199,17 +230,10 @@ void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scr
} }
/* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour /* Mark memory as no-longer-secret for the purpose of analysing constant-time behaviour
* of the software. This is setup for use with valgrind but could be substituted with * of the software.
* the appropriate instrumentation for other analysis tools.
*/ */
static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, const void *p, size_t len) { static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, const void *p, size_t len) {
#if defined(VALGRIND) if (EXPECT(ctx->declassify, 0)) SECP256K1_CHECKMEM_DEFINE(p, len);
if (EXPECT(ctx->declassify,0)) VALGRIND_MAKE_MEM_DEFINED(p, len);
#else
(void)ctx;
(void)p;
(void)len;
#endif
} }
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
@ -725,6 +749,8 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey
int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) {
VERIFY_CHECK(ctx != NULL); VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_context_is_proper(ctx));
if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) { if (secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)) {
secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32);
} }

View file

@ -7,10 +7,6 @@
#ifndef SECP256K1_TESTRAND_H #ifndef SECP256K1_TESTRAND_H
#define SECP256K1_TESTRAND_H #define SECP256K1_TESTRAND_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
/* A non-cryptographic RNG used only for test infrastructure. */ /* A non-cryptographic RNG used only for test infrastructure. */
/** Seed the pseudorandom number generator for testing. */ /** Seed the pseudorandom number generator for testing. */

File diff suppressed because it is too large Load diff

View file

@ -4,10 +4,6 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.* * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/ ***********************************************************************/
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
@ -28,7 +24,7 @@
static int count = 2; static int count = 2;
/** stolen from tests.c */ /** stolen from tests.c */
void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
CHECK(a->infinity == b->infinity); CHECK(a->infinity == b->infinity);
if (a->infinity) { if (a->infinity) {
return; return;
@ -37,7 +33,7 @@ void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); CHECK(secp256k1_fe_equal_var(&a->y, &b->y));
} }
void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
secp256k1_fe z2s; secp256k1_fe z2s;
secp256k1_fe u1, u2, s1, s2; secp256k1_fe u1, u2, s1, s2;
CHECK(a->infinity == b->infinity); CHECK(a->infinity == b->infinity);
@ -54,7 +50,7 @@ void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
CHECK(secp256k1_fe_equal_var(&s1, &s2)); CHECK(secp256k1_fe_equal_var(&s1, &s2));
} }
void random_fe(secp256k1_fe *x) { static void random_fe(secp256k1_fe *x) {
unsigned char bin[32]; unsigned char bin[32];
do { do {
secp256k1_testrand256(bin); secp256k1_testrand256(bin);
@ -74,7 +70,7 @@ SECP256K1_INLINE static int skip_section(uint64_t* iter) {
return ((((uint32_t)*iter ^ (*iter >> 32)) * num_cores) >> 32) != this_core; return ((((uint32_t)*iter ^ (*iter >> 32)) * num_cores) >> 32) != this_core;
} }
int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, static int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,
const unsigned char *key32, const unsigned char *algo16, const unsigned char *key32, const unsigned char *algo16,
void *data, unsigned int attempt) { void *data, unsigned int attempt) {
secp256k1_scalar s; secp256k1_scalar s;
@ -94,7 +90,7 @@ int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned cha
return 1; return 1;
} }
void test_exhaustive_endomorphism(const secp256k1_ge *group) { static void test_exhaustive_endomorphism(const secp256k1_ge *group) {
int i; int i;
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) { for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) {
secp256k1_ge res; secp256k1_ge res;
@ -103,7 +99,7 @@ void test_exhaustive_endomorphism(const secp256k1_ge *group) {
} }
} }
void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj) { static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj) {
int i, j; int i, j;
uint64_t iter = 0; uint64_t iter = 0;
@ -163,7 +159,7 @@ void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *gr
} }
} }
void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_gej *groupj) { static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_gej *groupj) {
int i, j, r_log; int i, j, r_log;
uint64_t iter = 0; uint64_t iter = 0;
for (r_log = 1; r_log < EXHAUSTIVE_TEST_ORDER; r_log++) { for (r_log = 1; r_log < EXHAUSTIVE_TEST_ORDER; r_log++) {
@ -199,7 +195,7 @@ static int ecmult_multi_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t
return 1; return 1;
} }
void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group) { static void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_ge *group) {
int i, j, k, x, y; int i, j, k, x, y;
uint64_t iter = 0; uint64_t iter = 0;
secp256k1_scratch *scratch = secp256k1_scratch_create(&ctx->error_callback, 4096); secp256k1_scratch *scratch = secp256k1_scratch_create(&ctx->error_callback, 4096);
@ -229,7 +225,7 @@ void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_
secp256k1_scratch_destroy(&ctx->error_callback, scratch); secp256k1_scratch_destroy(&ctx->error_callback, scratch);
} }
void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overflow) { static void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overflow) {
secp256k1_fe x; secp256k1_fe x;
unsigned char x_bin[32]; unsigned char x_bin[32];
k %= EXHAUSTIVE_TEST_ORDER; k %= EXHAUSTIVE_TEST_ORDER;
@ -239,7 +235,7 @@ void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k, int* overfl
secp256k1_scalar_set_b32(r, x_bin, overflow); secp256k1_scalar_set_b32(r, x_bin, overflow);
} }
void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group) { static void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group) {
int s, r, msg, key; int s, r, msg, key;
uint64_t iter = 0; uint64_t iter = 0;
for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) { for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) {
@ -292,7 +288,7 @@ void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *gr
} }
} }
void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group) { static void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
int i, j, k; int i, j, k;
uint64_t iter = 0; uint64_t iter = 0;

View file

@ -7,10 +7,6 @@
#ifndef SECP256K1_UTIL_H #ifndef SECP256K1_UTIL_H
#define SECP256K1_UTIL_H #define SECP256K1_UTIL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@ -101,25 +97,6 @@ static const secp256k1_callback default_error_callback = {
#define VERIFY_SETUP(stmt) #define VERIFY_SETUP(stmt)
#endif #endif
/* Define `VG_UNDEF` and `VG_CHECK` when VALGRIND is defined */
#if !defined(VG_CHECK)
# if defined(VALGRIND)
# include <valgrind/memcheck.h>
# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y))
# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y))
# else
# define VG_UNDEF(x,y)
# define VG_CHECK(x,y)
# endif
#endif
/* Like `VG_CHECK` but on VERIFY only */
#if defined(VERIFY)
#define VG_CHECK_VERIFY(x,y) VG_CHECK((x), (y))
#else
#define VG_CHECK_VERIFY(x,y)
#endif
static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) {
void *ret = malloc(size); void *ret = malloc(size);
if (ret == NULL) { if (ret == NULL) {
@ -274,7 +251,7 @@ static SECP256K1_INLINE int secp256k1_ctz32_var_debruijn(uint32_t x) {
0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B, 0x10, 0x07, 0x0C, 0x1A, 0x1F, 0x17, 0x12, 0x05, 0x15, 0x09, 0x0F, 0x0B,
0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B 0x1E, 0x11, 0x08, 0x0E, 0x1D, 0x0D, 0x1C, 0x1B
}; };
return debruijn[((x & -x) * 0x04D7651F) >> 27]; return debruijn[(uint32_t)((x & -x) * 0x04D7651FU) >> 27];
} }
/* Determine the number of trailing zero bits in a (non-zero) 64-bit x. /* Determine the number of trailing zero bits in a (non-zero) 64-bit x.
@ -287,7 +264,7 @@ static SECP256K1_INLINE int secp256k1_ctz64_var_debruijn(uint64_t x) {
63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10,
51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12
}; };
return debruijn[((x & -x) * 0x022FDD63CC95386D) >> 58]; return debruijn[(uint64_t)((x & -x) * 0x022FDD63CC95386DU) >> 58];
} }
/* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */ /* Determine the number of trailing zero bits in a (non-zero) 32-bit x. */