Squashed 'src/secp256k1/' changes from 0129b77767e..90580edcc98

90580edcc98 Merge pull request #140 from apoelstra/2021-07--resync
6ad66de6802 rangeproof: add an (unnecessary) variable initialization to shut up CI
2979e4d9d46 Merge commits '8ae56e33 75ce488c 4866178d 446d28d9 253f90cd ec3aaa50 0440945f 7688a4f1 be8d9c26 ' into temp-merge-965
5d2df054196 Merge elementsproject/secp256k1-zkp#120: Add MuSig Key Aggregation spec
fc26ca8ddef musig: remove unnecessary constant time normalize in combine
48f63efe683 musig: remove unnecessary branch in pubkey_tweak_add
5860b5e0fe7 musig: do not also require schnorrsig module config flag
f27fd1d5e75 musig: improve test coverage of pubkey_combine
56014e8ca01 musig: change pubkey_combine arg to array of pointers to pks
08fa02d5791 musig: add key aggregation spec draft
4a9b059b16d musig: rename Musig coefficient to KeyAgg coefficient
4bc46d836e7 musig: optimize key aggregation using const 1 for 2nd key
2310849f50f musig: compute musig coefficient by hashing key instead of index
9683c8a7eb6 musig: add static test vectors for key aggregation
9b3d7bf5361 extrakeys: add xonly_sort function
f31affd8a61 extrakeys: add hsort, in-place, iterative heapsort
be8d9c262f4 Merge bitcoin-core/secp256k1#965: gen_context: Don't use any ASM
d9560e0af78 Merge elementsproject/secp256k1-zkp#136: Eliminate a wrong -Wmaybe-uninitialized warning in GCC
aeece445997 gen_context: Don't use any ASM
6db00f5b2e0 Merge elementsproject/secp256k1-zkp#132: Upstream PRs 831, 907, 903, 889, 918, 906, 928, 922, 933, Merge bitcoin-core/secp256k1#936: Fix gen_context/ASM build on ARM, 925, 937, 926, Merge bitcoin-core/secp256k1#940: contrib: Explain explicit header guards, 850, 930, 941, 846, 947, 662, 950
cc0b279568d Eliminate a wrong -Wmaybe-uninitialized warning in GCC
f09497ea3e0 CI: tweak cirrus.yml to prevent OOM and timeout w sanitizer/valgrind
7226cf215aa ecdsa_adaptor: fix too small buffer in tests
b053e853d4f ecdsa_adaptor: fix test case with invalid signature
91b64770c3b Merge elementsproject/secp256k1-zkp#135: sync-upstream: fix "end" parameter for specifying range
907633e2e9a sync-upstream: fix "end" parameter for specifying range
394f49fd1a6 sync-upstream: quote variables
1bb5db3d602 Merge elementsproject/secp256k1-zkp#134: sync-upstream: parse merge commits w/ and w/o repo identifier
9321d42f751 sync-upstream: parse merge commits w/ and w/o repo identifier
7688a4f13a3 Merge bitcoin-core/secp256k1#963: "Schnorrsig API overhaul" fixups
90e83449b2c ci: Add C++ test
f698caaff6a Use unsigned char consistently for byte arrays
b5b8e7b7190 Don't declare constants twice
769528f3071 Don't use string literals for char arrays without NUL termination
2cc3cfa5838 Fix -Wmissing-braces warning in clang
0440945fb5c Merge #844: schnorrsig API overhaul
ec3aaa5014f Merge #960: tests_exhaustive: check the result of secp256k1_ecdsa_sign
a1ee83c6546 tests_exhaustive: check the result of secp256k1_ecdsa_sign
253f90cdeb1 Merge bitcoin-core/secp256k1#951: configure: replace AC_PATH_PROG to AC_CHECK_PROG
446d28d9de3 Merge bitcoin-core/secp256k1#944: Various improvements related to CFLAGS
0302138f750 ci: Make compiler warning into errors on CI
b924e1e605d build: Ensure that configure's compile checks default to -O2
7939cd571c7 build: List *CPPFLAGS before *CFLAGS like on the compiler command line
595e8a35d80 build: Enable -Wcast-align=strict warning
07256267ffa build: Use own variable SECP_CFLAGS instead of touching user CFLAGS
4866178dfc9 Merge bitcoin-core/secp256k1#955: Add random field multiply/square tests
75ce488c2a6 Merge bitcoin-core/secp256k1#959: tests: really test the non-var scalar inverse
41ed13942bd tests: really test the non-var scalar inverse
5f6ceafcfa4 schnorrsig: allow setting MSGLEN != 32 in benchmark
fdd06b79671 schnorrsig: add tests for sign_custom and varlen msg verification
d8d806aaf38 schnorrsig: add extra parameter struct for sign_custom
a0c3fc177f7 schnorrsig: allow signing and verification of variable length msgs
5a8e4991ad4 Add secp256k1_tagged_sha256 as defined in BIP-340
b6c0b72fb06 schnorrsig: remove noncefp args from sign; add sign_custom function
bdf19f105c6 Add random field multiply/square tests
8ae56e33e74 Merge #879: Avoid passing out-of-bound pointers to 0-size memcpy
a4642fa15ee configure: replace AC_PATH_PROG to AC_CHECK_PROG
d27e4598610 Revert "Remove unused Jacobi symbol support"
edcacc2b2ec Merge commits '26de4dfe 6e898534 c083cc6e 1e5d50fa cc2c09e3 efad3506 7012a188 34388af6 98e0358d d0bd2693 185a6af2 6c52ae87 69394879 1e78c18d 202a030f bf0ac460 399722a6 3dc8c072 50f33677 7973576f 1758a92f ' into temp-merge-950
1758a92ffd8 Merge #950: ci: Add ppc64le build
c58c4ea4707 ci: Add ppc64le build
7973576f6e3 Merge #662: Add ecmult_gen, ecmult_const and ecmult to benchmark
8f879c2887e Fix array size in bench_ecmult
2fe1b50df16 Add ecmult_gen, ecmult_const and ecmult to benchmark
593e6bad9c5 Clean up ecmult_bench to make space for more benchmarks
50f33677122 Merge #947: ci: Run PRs on merge result even for i686
a35fdd3478f ci: Run PRs on merge result even for i686
442cee5bafb schnorrsig: add algolen argument to nonce_function_hardened
df3bfa12c3b schnorrsig: clarify result of calling nonce_function_bip340 without data
99e8614812b README: mention schnorrsig module
3dc8c072b6d Merge #846: ci: Run ASan/LSan and reorganize sanitizer and Valgrind jobs
02dcea1ad94 ci: Make test iterations configurable and tweak for sanitizer builds
489ff5c20a1 tests: Treat empty SECP2561_TEST_ITERS as if it was unset
fcfcb97e74b ci: Simplify to use generic wrapper for QEMU, Valgrind, etc
de4157f13ac ci: Run ASan/LSan and reorganize sanitizer and Valgrind jobs
399722a63ad Merge #941: Clean up git tree
09b3bb8648f Clean up git tree
bf0ac460661 Merge #930: Add ARM32/ARM64 CI
202a030f7d1 Merge #850: add `secp256k1_ec_pubkey_cmp` method
1e78c18d5b8 Merge bitcoin-core/secp256k1#940: contrib: Explain explicit header guards
69394879b64 Merge #926: secp256k1.h: clarify that by default arguments must be != NULL
6eceec6d566 add `secp256k1_xonly_pubkey_cmp` method
0d9561ae879 add `secp256k1_ec_pubkey_cmp` method
22a9ea154a2 contrib: Explain explicit header guards
6c52ae87247 Merge #937: Have ge_set_gej_var, gej_double_var and ge_set_all_gej_var initialize all fields of their outputs.
185a6af2279 Merge #925: changed include statements without prefix 'include/'
14c9739a1fb tests: Improve secp256k1_ge_set_all_gej_var for some infinity inputs
4a19668c37b tests: Test secp256k1_ge_set_all_gej_var for all infinity inputs
3c90bdda95a change local lib headers to be relative for those pointing at "include/" dir
45b6468d7e3 Have secp256k1_ge_set_all_gej_var initialize all fields. Previous behaviour would not initialize r->y values in the case where infinity is passed in. Furthermore, the previous behaviour wouldn't initialize anything in the case where all inputs were infinity.
31c0f6de413 Have secp256k1_gej_double_var initialize all fields. Previous behaviour would not initialize r->x and r->y values in the case where infinity is passed in.
dd6c3de3227 Have secp256k1_ge_set_gej_var initialize all fields. Previous behaviour would not initialize r->x and r->y values in the case where infinity is passed in.
d0bd2693e30 Merge bitcoin-core/secp256k1#936: Fix gen_context/ASM build on ARM
8bbad7a18e5 Add asm build to ARM32 CI
7d65ed52142 Add ARM32/ARM64 CI
c8483520c90 Makefile.am: Don't pass a variable twice
2161f31785e Makefile.am: Honor config when building gen_context
99f47c20ec4 gen_context: Don't use external ASM because it complicates the build
98e0358d297 Merge #933: Avoids a missing brace warning in schnorrsig/tests_impl.h on old compilers
99e2d5be0db Avoids a missing brace warning in schnorrsig/tests_impl.h on old compilers.
34388af6b6a Merge #922: Add mingw32-w64/wine CI build
7012a188e6e Merge #928: Define SECP256K1_BUILD in secp256k1.c directly.
ed5a199bed6 tests: fopen /dev/urandom in binary mode
ae9e648526c Define SECP256K1_BUILD in secp256k1.c directly.
4dc37bf81b5 Add mingw32-w64/wine CI build
0881633dfd0 secp256k1.h: clarify that by default arguments must be != NULL
efad3506a89 Merge #906: Use modified divsteps with initial delta=1/2 for constant-time
cc2c09e3a78 Merge #918: Clean up configuration in gen_context
07067967ee9 add ECMULT_GEN_PREC_BITS to basic_config.h
a3aa2628c7b gen_context: Don't include basic-config.h
be0609fd54a Add unit tests for edge cases with delta=1/2 variant of divsteps
cd393ce2283 Optimization: only do 59 hddivsteps per iteration instead of 62
277b224b6ab Use modified divsteps with initial delta=1/2 for constant-time
376ca366db0 Fix typo in explanation
1e5d50fa93d Merge #889: fix uninitialized read in tests
f3708a1ecb4 Merge #117: Add ECDSA adaptor signatures module
5710ebacb9e Merge #128: Make function argument name consistent with doc
b0ffa923199 ecdsa_adaptor: add tests
6955af5ca89 ecdsa_adaptor: add ECDSA adaptor signature APIs
c083cc6e52a Merge #903: Make argument of fe_normalizes_to_zero{_var} const
6e898534ff4 Merge #907: changed import to use brackets <> for openssl
cc82ad5ab74 Make function argument name consistent with doc
4504472269d changed import to use brackets <> for openssl as they are not local to the project
26de4dfeb1f Merge #831: Safegcd inverses, drop Jacobi symbols, remove libgmp
b508e5dd9b1 ecdsa_adaptor: add support for proof of discrete logarithm equality
d8f336564fe ecdsa_adaptor: add nonce function and tags
654cd633f50 ecdsa_adaptor: initialize project
23c3fb629b9 Make argument of fe_normalizes_to_zero{_var} const
24ad04fc064 Make scalar_inverse{,_var} benchmark scale with SECP256K1_BENCH_ITERS
ebc1af700f9 Optimization: track f,g limb count and pass to new variable-time update_fg_var
b306935ac12 Optimization: use formulas instead of lookup tables for cancelling g bits
9164a1b6582 Optimization: special-case zero modulus limbs in modinv64
1f233b3fa05 Remove num/gmp support
fac477f822a Merge #126: Upstream PRs  #854 #852 #857 #858 #860 #845 #862 #875 #878 #874 #877 #880 #864 #882 #894 #891 #901
20448b8d09a Remove unused Jacobi symbol support
5437e7bdfbf Remove unused scalar_sqr
aa9cc521800 Improve field/scalar inverse tests
1e0e885c8ac Make field/scalar code use the new modinv modules for inverses
436281afdcb Move secp256k1_fe_inverse{_var} to per-impl files
aa404d53bef Move secp256k1_scalar_{inverse{_var},is_even} to per-impl files
08d54964e51 Improve bounds checks in modinv modules
6a7861f646f Merge #127: sync-upstream: Create proper links to upstream PRs
4091e619248 cirrus: increase timeout for macOS tasks
136ed8f84d9 sync-upstream: Fix output of command to reproduce
38f1e777d49 sync-upstream: Create proper links to upstream PRs
79d4c3ac681 whitelist: add SECP_INCLUDES to bench_whitelist CPPFLAGS
649bf201d85 musig: fix tests for 32-bit
151aac00d31 Add tests for modinv modules
d8a92fcc4c6 Add extensive comments on the safegcd algorithm and implementation
8e415acba25 Add safegcd based modular inverse modules
de0a643c3dc Add secp256k1_ctz{32,64}_var functions
d4ca81f48e9 Merge commits 'dc6e5c3a 2d9e7175 b61f9da5 98dac878 8c727b90 328aaef2 f2d9aeae b732701f db726782 5671e5f3 a4abaab7 659d0d47 f8c0b57e 24d1656c 3a8b47bc ebdba03c 4c3ba88c ' into temp-merge-901
4c3ba88c3a8 Merge #901: ci: Switch all Linux builds to Debian and more improvements
9361f360bb0 ci: Select number of parallel make jobs depending on CI environment
28eccdf8064 ci: Split output of logs into multiple sections
c7f754fe4d5 ci: Run PRs on merge result instead of on the source branch
b994a8be3cf ci: Print information about binaries using "file"
f24e122d13d ci: Switch all Linux builds to Debian
ebdba03cb56 Merge #891: build: Add workaround for automake 1.13 and older
3a8b47bc6d1 Merge #894: ctime_test: move context randomization test to the end
6da00ec6245 Merge pull request #124 from apoelstra/2021-02--rename-klepto
e354c5751d6 ecdsa_s2c: rename anti-klepto to anti-exfil
7d3497cdc4c ctime_test: move context randomization test to the end
99a1cfec174 print warnings for conditional-uninitialized
3d2cf6c5bd3 initialize variable in tests
f329bba2442 build: Add workaround for automake 1.13 and older
24d1656c328 Merge #882: Use bit ops instead of int mult for constant-time logic in gej_add_ge
e491d06b98c Use bit ops instead of int mult for constant-time logic in gej_add_ge
f8c0b57e6ba Merge #864: Add support for Cirrus CI
cc2a5451dc8 ci: Refactor Nix shell files
2480e55c8f3 ci: Remove support for Travis CI
2b359f1c1d8 ci: Enable simple cache for brewing valgrind on macOS
8c02e465c5a ci: Add support for Cirrus CI
659d0d47989 Merge #880: Add parens around ROUND_TO_ALIGN's parameter.
b6f649889ae Add parens around ROUND_TO_ALIGN's parameter. This makes the macro robust against a hypothetical ROUND_TO_ALIGN(foo ? sizeA : size B) invocation.
a4abaab7931 Merge #877: Add missing secp256k1_ge_set_gej_var decl.
5671e5f3fd0 Merge #874: Remove underscores from header defs.
db726782fa2 Merge #878: Remove unused secp256k1_fe_inv_all_var
b732701faa7 Merge #875: Avoid casting (void**) values.
9570f674cc7 Avoid passing out-of-bound pointers to 0-size memcpy
75d2ae149ef Remove unused secp256k1_fe_inv_all_var
482e4a9cfce Add missing secp256k1_ge_set_gej_var decl.
27306186045 Avoid casting (void**) values. Replaced with an expression that only casts (void*) values.
fb390c5299e Remove underscores from header defs. This makes them consistent with other files and avoids reserved identifiers.
ed69ea79b42 Merge #98: Add contrib/sync-upstream.sh script to automate syncing PRs
7eeacd7725f Add contrib/sync-upstream.sh script to automate merging upstream PRs
f2d9aeae6d5 Merge #862: Autoconf improvements
328aaef22a4 Merge #845: Extract the secret key from a keypair
3c15130709d Improve CC_FOR_BUILD detection
47802a47624 Restructure and tidy configure.ac
252c19dfc65 Ask brew for valgrind include path
8c727b9087a Merge #860: fixed trivial typo
cfac088e1b2 Merge #119: Remove repeated schnorr flag from travis config
96c83a83dcf Remove repeated schnorr flag from travis config
d2b6740688f Merge pull request #118 from jonasnick/clarify-rangeproof-rewind
41d6963bc1c rangeproof: clarify rewind outlen argument
673e551f4d1 Merge #111: Add ECDSA sign-to-contract module
b7bc3a4aaa5 fixed typo
47efb5e39a1 ecdsa-s2c: add ctime tests
396b558273c ecdsa-s2c: add anti-klepto protocol
290dee566e1 ecdsa-s2c: add actual sign-to-contract functionality
8e46cac5b31 ecdsa-s2c: block in module
826bd04b43f add eccommit functionality
33cb3c2b1fc Add secret key extraction from keypair to constant time tests
36d9dc1e8e6 Add seckey extraction from keypair to the extrakeys tests
fc96aa73f5c Add a function to extract the secretkey from a keypair
98dac878398 Merge #858: Fix insecure links
07aa4c70ffb Fix insecure links
b61f9da54ef Merge #857: docs: fix simple typo, dependecy -> dependency
18aadf9d288 docs: fix simple typo, dependecy -> dependency
2d9e7175c6e Merge #852: Add sage script for generating scalar_split_lambda constants
dc6e5c3a5c4 Merge #854: Rename msg32 to msghash32 in ecdsa_sign/verify and add explanation
6e85d675aaf Rename tweak to tweak32 in public API
f587f04e357 Rename msg32 to msghash32 in ecdsa_sign/verify and add explanation
329a2e0a3f2 sage: Add script for generating scalar_split_lambda constants
f554dfc7088 sage: Reorganize files

git-subtree-dir: src/secp256k1
git-subtree-split: 90580edcc98350c9df9bebee58d2f9616d801849
This commit is contained in:
Andrew Poelstra 2021-07-28 22:05:08 +00:00
parent 5fbc67e108
commit 196c993d1f
122 changed files with 9971 additions and 2725 deletions

368
.cirrus.yml Normal file
View file

@ -0,0 +1,368 @@
env:
### compiler options
HOST:
# Specific warnings can be disabled with -Wno-error=foo.
# -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual.
WERROR_CFLAGS: -Werror -pedantic-errors
MAKEFLAGS: -j2
BUILD: check
### secp256k1 config
STATICPRECOMPUTATION: yes
ECMULTGENPRECISION: auto
ASM: no
WIDEMUL: auto
WITH_VALGRIND: yes
EXTRAFLAGS:
### secp256k1 modules
ECDH: no
RECOVERY: no
SCHNORRSIG: no
ECDSA_S2C: no
GENERATOR: no
RANGEPROOF: no
WHITELIST: no
MUSIG: no
ECDSAADAPTOR: no
### test options
TEST_ITERS:
BENCH: yes
BENCH_ITERS: 2
CTIMETEST: yes
cat_logs_snippet: &CAT_LOGS
always:
cat_tests_log_script:
- cat tests.log || true
cat_exhaustive_tests_log_script:
- cat exhaustive_tests.log || true
cat_valgrind_ctime_test_log_script:
- cat valgrind_ctime_test.log || true
cat_bench_log_script:
- cat bench.log || true
on_failure:
cat_config_log_script:
- cat config.log || true
cat_test_env_script:
- cat test_env.log || true
cat_ci_env_script:
- env
merge_base_script_snippet: &MERGE_BASE
merge_base_script:
- if [ "$CIRRUS_PR" = "" ]; then exit 0; fi
- git fetch $CIRRUS_REPO_CLONE_URL $CIRRUS_BASE_BRANCH
- git config --global user.email "ci@ci.ci"
- git config --global user.name "ci"
- git merge FETCH_HEAD # Merge base to detect silent merge conflicts
task:
name: "x86_64: Linux (Debian stable)"
container:
dockerfile: ci/linux-debian.Dockerfile
# Reduce number of CPUs to be able to do more builds in parallel.
cpu: 1
# More than enough for our scripts.
memory: 1G
matrix: &ENV_MATRIX
- env: {WIDEMUL: int64, RECOVERY: yes}
- env: {WIDEMUL: int64, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
- env: {WIDEMUL: int128}
- env: {WIDEMUL: int128, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, ECDH: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
- env: {WIDEMUL: int128, ASM: x86_64}
- env: { RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
- env: { STATICPRECOMPUTATION: no}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
- env: {CPPFLAGS: -DDETERMINISTIC}
- env: {CFLAGS: -O0, CTIMETEST: no}
- env: { ECMULTGENPRECISION: 2 }
- env: { ECMULTGENPRECISION: 8 }
matrix:
- env:
CC: gcc
- env:
CC: clang
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "i686: Linux (Debian stable)"
container:
dockerfile: ci/linux-debian.Dockerfile
cpu: 1
memory: 1G
env:
HOST: i686-linux-gnu
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
ECDSA_S2C: yes
RANGEPROOF: yes
WHITELIST: yes
GENERATOR: yes
MUSIG: yes
ECDSAADAPTOR: yes
matrix:
- env:
CC: i686-linux-gnu-gcc
- env:
CC: clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "x86_64: macOS Catalina"
macos_instance:
image: catalina-base
# As of d4ca81f48e tasks with valgrind enabled take about 60 minutes
timeout_in: 90m
env:
HOMEBREW_NO_AUTO_UPDATE: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
# Cirrus gives us a fixed number of 12 virtual CPUs. Not that we even have that many jobs at the moment...
MAKEFLAGS: -j13
matrix:
<< : *ENV_MATRIX
matrix:
- env:
CC: gcc-9
- env:
CC: clang
# Update Command Line Tools
# Uncomment this if the Command Line Tools on the CirrusCI macOS image are too old to brew valgrind.
# See https://apple.stackexchange.com/a/195963 for the implementation.
## update_clt_script:
## - system_profiler SPSoftwareDataType
## - touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
## - |-
## PROD=$(softwareupdate -l | grep "*.*Command Line" | tail -n 1 | awk -F"*" '{print $2}' | sed -e 's/^ *//' | sed 's/Label: //g' | tr -d '\n')
## # For debugging
## - softwareupdate -l && echo "PROD: $PROD"
## - softwareupdate -i "$PROD" --verbose
## - rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
##
brew_valgrind_pre_script:
- brew config
- brew tap --shallow LouisBrunner/valgrind
# Fetch valgrind source but don't build it yet.
- brew fetch --HEAD LouisBrunner/valgrind/valgrind
brew_valgrind_cache:
# This is $(brew --cellar valgrind) but command substition does not work here.
folder: /usr/local/Cellar/valgrind
# Rebuild cache if ...
fingerprint_script:
# ... macOS version changes:
- sw_vers
# ... brew changes:
- brew config
# ... valgrind changes:
- git -C "$(brew --cache)/valgrind--git" rev-parse HEAD
populate_script:
# If there's no hit in the cache, build and install valgrind.
- brew install --HEAD LouisBrunner/valgrind/valgrind
brew_valgrind_post_script:
# If we have restored valgrind from the cache, tell brew to create symlink to the PATH.
# If we haven't restored from cached (and just run brew install), this is a no-op.
- brew link valgrind
brew_script:
- brew install automake libtool gcc@9
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "s390x (big-endian): Linux (Debian stable, QEMU)"
container:
dockerfile: ci/linux-debian.Dockerfile
cpu: 1
memory: 1G
env:
WRAPPER_CMD: qemu-s390x
TEST_ITERS: 16
HOST: s390x-linux-gnu
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
ECDSA_S2C: yes
RANGEPROOF: yes
WHITELIST: yes
GENERATOR: yes
MUSIG: yes
ECDSAADAPTOR: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
# https://sourceware.org/bugzilla/show_bug.cgi?id=27008
- rm /etc/ld.so.cache
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "ARM32: Linux (Debian stable, QEMU)"
container:
dockerfile: ci/linux-debian.Dockerfile
cpu: 1
memory: 1G
env:
WRAPPER_CMD: qemu-arm
TEST_ITERS: 16
HOST: arm-linux-gnueabihf
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
matrix:
- env: {}
- env: {ASM: arm}
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "ARM64: Linux (Debian stable, QEMU)"
container:
dockerfile: ci/linux-debian.Dockerfile
cpu: 1
memory: 1G
env:
WRAPPER_CMD: qemu-aarch64
TEST_ITERS: 16
HOST: aarch64-linux-gnu
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "ppc64le: Linux (Debian stable, QEMU)"
container:
dockerfile: ci/linux-debian.Dockerfile
cpu: 1
memory: 1G
env:
WRAPPER_CMD: qemu-ppc64le
TEST_ITERS: 16
HOST: powerpc64le-linux-gnu
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
container:
dockerfile: ci/linux-debian.Dockerfile
cpu: 1
memory: 1G
env:
WRAPPER_CMD: wine64-stable
TEST_ITERS: 16
HOST: x86_64-w64-mingw32
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
# Sanitizers
task:
timeout_in: 120m
container:
dockerfile: ci/linux-debian.Dockerfile
cpu: 1
memory: 2G
env:
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
ECDSA_S2C: yes
RANGEPROOF: yes
WHITELIST: yes
GENERATOR: yes
MUSIG: yes
ECDSAADAPTOR: yes
CTIMETEST: no
EXTRAFLAGS: "--disable-openssl-tests"
matrix:
- name: "Valgrind (memcheck)"
env:
# The `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (https://www.valgrind.org/docs/manual/manual-core.html)
WRAPPER_CMD: "valgrind --error-exitcode=42"
TEST_ITERS: 8
- name: "UBSan, ASan, LSan"
env:
CFLAGS: "-fsanitize=undefined,address"
CFLAGS_FOR_BUILD: "-fsanitize=undefined,address"
UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1"
ASAN_OPTIONS: "strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1"
LSAN_OPTIONS: "use_unaligned=1"
TEST_ITERS: 32
# Try to cover many configurations with just a tiny matrix.
matrix:
- env:
ASM: auto
STATICPRECOMPUTATION: yes
- env:
ASM: no
STATICPRECOMPUTATION: no
ECMULTGENPRECISION: 2
matrix:
- env:
CC: clang
- env:
HOST: i686-linux-gnu
CC: i686-linux-gnu-gcc
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "C++ -fpermissive"
container:
dockerfile: ci/linux-debian.Dockerfile
cpu: 1
memory: 1G
env:
# ./configure correctly errors out when given CC=g++.
# We hack around this by passing CC=g++ only to make.
CC: gcc
MAKEFLAGS: -j2 CC=g++ CFLAGS=-fpermissive
WERROR_CFLAGS:
EXPERIMENTAL: yes
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS

10
.gitignore vendored
View file

@ -25,6 +25,7 @@ aclocal.m4
autom4te.cache/
config.log
config.status
conftest*
*.tar.gz
*.la
libtool
@ -35,6 +36,14 @@ libtool
*~
*.log
*.trs
coverage/
coverage.html
coverage.*.html
*.gcda
*.gcno
*.gcov
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
src/ecmult_static_context.h
@ -53,3 +62,4 @@ build-aux/compile
build-aux/test-driver
src/stamp-h1
libsecp256k1.pc
contrib/gh-pr-create.sh

View file

@ -1,111 +0,0 @@
language: c
os:
- linux
- osx
dist: bionic
# Valgrind currently supports upto macOS 10.13, the latest xcode of that version is 10.1
osx_image: xcode10.1
addons:
apt:
packages:
- libgmp-dev
- valgrind
- libtool-bin
compiler:
- clang
- gcc
env:
global:
- WIDEMUL=auto BIGNUM=auto STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check WITH_VALGRIND=yes RUN_VALGRIND=no EXTRAFLAGS= HOST= ECDH=no RECOVERY=no SCHNORRSIG=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2 GENERATOR=no RANGEPROOF=no WHITELIST=no SCHNORRSIG=no MUSIG=no
matrix:
- WIDEMUL=int64 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
- WIDEMUL=int128 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
- WIDEMUL=int64 RECOVERY=yes
- WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
- WIDEMUL=int128
- WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
- WIDEMUL=int128 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
- WIDEMUL=int128 ASM=x86_64
- BIGNUM=no
- BIGNUM=no RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
- BIGNUM=no STATICPRECOMPUTATION=no
- BUILD=distcheck WITH_VALGRIND=no CTIMETEST=no BENCH=no
- CPPFLAGS=-DDETERMINISTIC
- CFLAGS=-O0 CTIMETEST=no
- CFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=no
- ECMULTGENPRECISION=2
- ECMULTGENPRECISION=8
- RUN_VALGRIND=yes BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes EXTRAFLAGS="--disable-openssl-tests" BUILD=
matrix:
fast_finish: true
include:
- compiler: clang
os: linux
env: HOST=i686-linux-gnu
addons:
apt:
packages:
- gcc-multilib
- libgmp-dev:i386
- valgrind
- libtool-bin
- libc6-dbg:i386
- compiler: clang
env: HOST=i686-linux-gnu
os: linux
addons:
apt:
packages:
- gcc-multilib
- valgrind
- libtool-bin
- libc6-dbg:i386
- compiler: gcc
env: HOST=i686-linux-gnu
os: linux
addons:
apt:
packages:
- gcc-multilib
- valgrind
- libtool-bin
- libc6-dbg:i386
- compiler: gcc
os: linux
env: HOST=i686-linux-gnu
addons:
apt:
packages:
- gcc-multilib
- libgmp-dev:i386
- valgrind
- libtool-bin
- libc6-dbg:i386
# S390x build (big endian system)
- compiler: gcc
env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=
arch: s390x
# We use this to install macOS dependencies instead of the built in `homebrew` plugin,
# because in xcode earlier than 11 they have a bug requiring updating the system which overall takes ~8 minutes.
# https://travis-ci.community/t/macos-build-fails-because-of-homebrew-bundle-unknown-command/7296
before_install:
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then HOMEBREW_NO_AUTO_UPDATE=1 brew install gmp valgrind gcc@9; fi
before_script: ./autogen.sh
# travis auto terminates jobs that go for 10 minutes without printing to stdout, but travis_wait doesn't work well with forking programs like valgrind (https://docs.travis-ci.com/user/common-build-problems/#build-times-out-because-no-output-was-received https://github.com/bitcoin-core/secp256k1/pull/750#issuecomment-623476860)
script:
- function keep_alive() { while true; do echo -en "\a"; sleep 60; done }
- keep_alive &
- ./contrib/travis.sh
- kill %keep_alive
after_script:
- cat ./tests.log
- cat ./exhaustive_tests.log
- cat ./valgrind_ctime_test.log
- cat ./bench.log
- $CC --version
- valgrind --version

View file

@ -1,5 +1,9 @@
ACLOCAL_AMFLAGS = -I build-aux/m4
# AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo
# which does not have an explicit foo_CFLAGS variable set.
AM_CFLAGS = $(SECP_CFLAGS)
lib_LTLIBRARIES = libsecp256k1.la
include_HEADERS = include/secp256k1.h
include_HEADERS += include/secp256k1_preallocated.h
@ -14,8 +18,8 @@ noinst_HEADERS += src/scalar_8x32_impl.h
noinst_HEADERS += src/scalar_low_impl.h
noinst_HEADERS += src/group.h
noinst_HEADERS += src/group_impl.h
noinst_HEADERS += src/num_gmp.h
noinst_HEADERS += src/num_gmp_impl.h
noinst_HEADERS += src/eccommit.h
noinst_HEADERS += src/eccommit_impl.h
noinst_HEADERS += src/ecdsa.h
noinst_HEADERS += src/ecdsa_impl.h
noinst_HEADERS += src/eckey.h
@ -26,14 +30,16 @@ noinst_HEADERS += src/ecmult_const.h
noinst_HEADERS += src/ecmult_const_impl.h
noinst_HEADERS += src/ecmult_gen.h
noinst_HEADERS += src/ecmult_gen_impl.h
noinst_HEADERS += src/num.h
noinst_HEADERS += src/num_impl.h
noinst_HEADERS += src/field_10x26.h
noinst_HEADERS += src/field_10x26_impl.h
noinst_HEADERS += src/field_5x52.h
noinst_HEADERS += src/field_5x52_impl.h
noinst_HEADERS += src/field_5x52_int128_impl.h
noinst_HEADERS += src/field_5x52_asm_impl.h
noinst_HEADERS += src/modinv32.h
noinst_HEADERS += src/modinv32_impl.h
noinst_HEADERS += src/modinv64.h
noinst_HEADERS += src/modinv64_impl.h
noinst_HEADERS += src/assumptions.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/scratch.h
@ -68,7 +74,7 @@ endif
endif
libsecp256k1_la_SOURCES = src/secp256k1.c
libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB)
if VALGRIND_ENABLED
@ -81,27 +87,27 @@ noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_ecmult
bench_verify_SOURCES = src/bench_verify.c
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
# SECP_TEST_INCLUDES are only used here for CRYPTO_CPPFLAGS
bench_verify_CPPFLAGS = -DSECP256K1_BUILD $(SECP_TEST_INCLUDES)
bench_verify_CPPFLAGS = $(SECP_TEST_INCLUDES)
bench_sign_SOURCES = src/bench_sign.c
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_internal_SOURCES = src/bench_internal.c
bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
bench_internal_CPPFLAGS = $(SECP_INCLUDES)
bench_ecmult_SOURCES = src/bench_ecmult.c
bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB)
bench_ecmult_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
bench_ecmult_CPPFLAGS = $(SECP_INCLUDES)
endif
TESTS =
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
tests_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
if VALGRIND_ENABLED
tests_CPPFLAGS += -DVALGRIND
noinst_PROGRAMS += valgrind_ctime_test
valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c
valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_LIBS) $(COMMON_LIB)
valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
if !ENABLE_COVERAGE
tests_CPPFLAGS += -DVERIFY
@ -114,7 +120,7 @@ endif
if USE_EXHAUSTIVE_TESTS
noinst_PROGRAMS += exhaustive_tests
exhaustive_tests_SOURCES = src/tests_exhaustive.c
exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES)
exhaustive_tests_CPPFLAGS = -I$(top_srcdir)/src $(SECP_INCLUDES)
if !ENABLE_COVERAGE
exhaustive_tests_CPPFLAGS += -DVERIFY
endif
@ -129,10 +135,10 @@ CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) -I$(builddir)/src
gen_context_OBJECTS = gen_context.o
gen_context_BIN = gen_context$(BUILD_EXEEXT)
gen_%.o: src/gen_%.c src/libsecp256k1-config.h
$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@
$(CC_FOR_BUILD) $(DEFS) $(CPPFLAGS_FOR_BUILD) $(SECP_CFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@
$(gen_context_BIN): $(gen_context_OBJECTS)
$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) $^ -o $@
$(CC_FOR_BUILD) $(SECP_CFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) $^ -o $@
$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h
$(tests_OBJECTS): src/ecmult_static_context.h
@ -182,3 +188,11 @@ endif
if ENABLE_MODULE_SCHNORRSIG
include src/modules/schnorrsig/Makefile.am.include
endif
if ENABLE_MODULE_ECDSA_S2C
include src/modules/ecdsa_s2c/Makefile.am.include
endif
if ENABLE_MODULE_ECDSA_ADAPTOR
include src/modules/ecdsa_adaptor/Makefile.am.include
endif

View file

@ -1,7 +1,7 @@
libsecp256k1
============
[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1)
[![Build Status](https://api.cirrus-ci.com/github/bitcoin-core/secp256k1.svg?branch=master)](https://cirrus-ci.com/github/bitcoin-core/secp256k1)
Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.
@ -17,6 +17,8 @@ Features:
* Suitable for embedded systems.
* Optional module for public key recovery.
* Optional module for ECDH key exchange.
* Optional module for Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) (experimental).
* Optional module for ECDSA adaptor signatures (experimental).
Experimental features have not received enough scrutiny to satisfy the standard of quality of this library but are made available for testing and review by the community. The APIs of these features should not be considered stable.
@ -34,11 +36,11 @@ Implementation details
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
* Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys).
* Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan).
* Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman).
* Scalar operations
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
* Using 4 64-bit limbs (relying on __int128 support in the compiler).
* Using 8 32-bit limbs.
* Modular inverses (both field elements and scalars) based on [safegcd](https://gcd.cr.yp.to/index.html) with some modifications, and a variable-time variant (by Peter Dettman).
* Group operations
* Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7).
* Use addition between points in Jacobian and affine coordinates where possible.
@ -96,7 +98,8 @@ To create a report, `gcovr` is recommended, as it includes branch coverage repor
To create a HTML report with coloured and annotated source code:
$ gcovr --exclude 'src/bench*' --html --html-details -o coverage.html
$ mkdir -p coverage
$ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html
Reporting a vulnerability
------------

View file

@ -1,5 +1,5 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html
# https://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html
# ===========================================================================
#
# SYNOPSIS

View file

@ -75,15 +75,26 @@ if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
fi
])
dnl
AC_DEFUN([SECP_GMP_CHECK],[
if test x"$has_gmp" != x"yes"; then
AC_DEFUN([SECP_VALGRIND_CHECK],[
if test x"$has_valgrind" != x"yes"; then
CPPFLAGS_TEMP="$CPPFLAGS"
CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS"
LIBS_TEMP="$LIBS"
LIBS="$GMP_LIBS $LIBS"
AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])])
CPPFLAGS="$CPPFLAGS_TEMP"
LIBS="$LIBS_TEMP"
CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS"
AC_CHECK_HEADER([valgrind/memcheck.h], [has_valgrind=yes; AC_DEFINE(HAVE_VALGRIND,1,[Define this symbol if valgrind is installed])])
fi
])
dnl SECP_TRY_APPEND_CFLAGS(flags, VAR)
dnl Append flags to VAR if CC accepts them.
AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [
AC_MSG_CHECKING([if ${CC} supports $1])
SECP_TRY_APPEND_CFLAGS_saved_CFLAGS="$CFLAGS"
CFLAGS="$1 $CFLAGS"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], [flag_works=yes], [flag_works=no])
AC_MSG_RESULT($flag_works)
CFLAGS="$SECP_TRY_APPEND_CFLAGS_saved_CFLAGS"
if test x"$flag_works" = x"yes"; then
$2="$$2 $1"
fi
unset flag_works
AC_SUBST($2)
])

View file

@ -3,47 +3,51 @@
set -e
set -x
if [ "$HOST" = "i686-linux-gnu" ]
then
export CC="$CC -m32"
fi
if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$TRAVIS_COMPILER" = "gcc" ]
then
export CC="gcc-9"
fi
export LC_ALL=C
env >> test_env.log
$CC -v || true
valgrind --version || true
./autogen.sh
./configure \
--enable-experimental="$EXPERIMENTAL" \
--with-test-override-wide-multiply="$WIDEMUL" --with-bignum="$BIGNUM" --with-asm="$ASM" \
--with-test-override-wide-multiply="$WIDEMUL" --with-asm="$ASM" \
--enable-ecmult-static-precomputation="$STATICPRECOMPUTATION" --with-ecmult-gen-precision="$ECMULTGENPRECISION" \
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG"\
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
--with-valgrind="$WITH_VALGRIND" \
--host="$HOST" $EXTRAFLAGS
if [ -n "$BUILD" ]
then
make -j2 "$BUILD"
fi
if [ "$RUN_VALGRIND" = "yes" ]
then
make -j2
# the `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (http://valgrind.org/docs/manual/manual-core.html)
valgrind --error-exitcode=42 ./tests 16
valgrind --error-exitcode=42 ./exhaustive_tests
fi
# We have set "-j<n>" in MAKEFLAGS.
make
# Print information about binaries so that we can see that the architecture is correct
file *tests* || true
file bench_* || true
file .libs/* || true
# This tells `make check` to wrap test invocations.
export LOG_COMPILER="$WRAPPER_CMD"
# This limits the iterations in the tests and benchmarks.
export SECP256K1_TEST_ITERS="$TEST_ITERS"
export SECP256K1_BENCH_ITERS="$BENCH_ITERS"
make "$BUILD"
if [ "$BENCH" = "yes" ]
then
if [ "$RUN_VALGRIND" = "yes" ]
# 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
# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
EXEC='./libtool --mode=execute valgrind --error-exitcode=42'
else
EXEC=
EXEC="$EXEC $WRAPPER_CMD"
fi
# This limits the iterations in the benchmarks below to ITER(set in .travis.yml) iterations.
export SECP256K1_BENCH_ITERS="$ITERS"
{
$EXEC ./bench_ecmult
$EXEC ./bench_internal

View file

@ -0,0 +1,25 @@
FROM debian:stable
RUN dpkg --add-architecture i386
RUN dpkg --add-architecture s390x
RUN dpkg --add-architecture armhf
RUN dpkg --add-architecture arm64
RUN dpkg --add-architecture ppc64el
RUN apt-get update
# dkpg-dev: to make pkg-config work in cross-builds
# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces
RUN apt-get install --no-install-recommends --no-upgrade -y \
git ca-certificates \
make automake libtool pkg-config dpkg-dev valgrind qemu-user \
gcc clang llvm libc6-dbg \
g++ \
gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan5:i386 \
gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
wine gcc-mingw-w64-x86-64
# Run a dummy command in wine to make it set up configuration
RUN wine64-stable xcopy || true

View file

@ -8,13 +8,9 @@ AH_TOP([#define LIBSECP256K1_CONFIG_H])
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
AM_INIT_AUTOMAKE([foreign subdir-objects])
# Set -g if CFLAGS are not already set, which matches the default autoconf
# behavior (see PROG_CC in the Autoconf manual) with the exception that we don't
# set -O2 here because we set it in any case (see further down).
: ${CFLAGS="-g"}
LT_INIT
dnl make the compilation flags quiet unless V=1 is used
# Make the compilation flags quiet unless V=1 is used.
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
PKG_PROG_PKG_CONFIG
@ -22,9 +18,16 @@ PKG_PROG_PKG_CONFIG
AC_PATH_TOOL(AR, ar)
AC_PATH_TOOL(RANLIB, ranlib)
AC_PATH_TOOL(STRIP, strip)
AX_PROG_CC_FOR_BUILD
# Save definition of AC_PROG_CC because AM_PROG_CC_C_O in automake<=1.13 will
# redefine AC_PROG_CC to exit with an error, which avoids the user calling it
# accidently and screwing up the effect of AM_PROG_CC_C_O. However, we'll need
# AC_PROG_CC later on in AX_PROG_CC_FOR_BUILD, where its usage is fine, and
# we'll carefully make sure not to call AC_PROG_CC anywhere else.
m4_copy([AC_PROG_CC], [saved_AC_PROG_CC])
AM_PROG_CC_C_O
# Restore AC_PROG_CC
m4_rename_force([saved_AC_PROG_CC], [AC_PROG_CC])
AC_PROG_CC_C89
if test x"$ac_cv_prog_cc_c89" = x"no"; then
@ -35,28 +38,26 @@ AM_PROG_AS
case $host_os in
*darwin*)
if test x$cross_compiling != xyes; then
AC_PATH_PROG([BREW],brew,)
if test x$BREW != x; then
dnl These Homebrew packages may be keg-only, meaning that they won't be found
dnl in expected paths because they may conflict with system files. Ask
dnl Homebrew where each one is located, then adjust paths accordingly.
AC_CHECK_PROG([BREW], brew, brew)
if test x$BREW = xbrew; then
# These Homebrew packages may be keg-only, meaning that they won't be found
# in expected paths because they may conflict with system files. Ask
# Homebrew where each one is located, then adjust paths accordingly.
openssl_prefix=`$BREW --prefix openssl 2>/dev/null`
gmp_prefix=`$BREW --prefix gmp 2>/dev/null`
valgrind_prefix=`$BREW --prefix valgrind 2>/dev/null`
if test x$openssl_prefix != x; then
PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
export PKG_CONFIG_PATH
CRYPTO_CPPFLAGS="-I$openssl_prefix/include"
fi
if test x$gmp_prefix != x; then
GMP_CPPFLAGS="-I$gmp_prefix/include"
GMP_LIBS="-L$gmp_prefix/lib"
if test x$valgrind_prefix != x; then
VALGRIND_CPPFLAGS="-I$valgrind_prefix/include"
fi
else
AC_PATH_PROG([PORT],port,)
dnl if homebrew isn't installed and macports is, add the macports default paths
dnl as a last resort.
if test x$PORT != x; then
AC_CHECK_PROG([PORT], port, port)
# If homebrew isn't installed and macports is, add the macports default paths
# as a last resort.
if test x$PORT = xport; then
CPPFLAGS="$CPPFLAGS -isystem /opt/local/include"
LDFLAGS="$LDFLAGS -L/opt/local/lib"
fi
@ -65,26 +66,45 @@ case $host_os in
;;
esac
CFLAGS="-W $CFLAGS"
# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS.
#
# These are our own flags, so we append them to our own SECP_CFLAGS variable (instead of CFLAGS) as
# recommended in the automake manual (Section "Flag Variables Ordering"). CFLAGS belongs to the user
# and we are not supposed to touch it. In the Makefile, we will need to ensure that SECP_CFLAGS
# is prepended to CFLAGS when invoking the compiler so that the user always has the last word (flag).
#
# Another advantage of not touching CFLAGS is that the contents of CFLAGS will be picked up by
# libtool for compiling helper executables. For example, when compiling for Windows, libtool will
# generate entire wrapper executables (instead of simple wrapper scripts as on Unix) to ensure
# proper operation of uninstalled programs linked by libtool against the uninstalled shared library.
# These executables are compiled from C source file for which our flags may not be appropriate,
# e.g., -std=c89 flag has lead to undesirable warnings in the past.
#
# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues.
AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
# Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
# not error out if it gets unknown warning flags and the checks here will always succeed
# no matter if clang knows the flag or not.
SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef -Wno-unused-function -Wno-long-long -Wno-overlength-strings"
saved_CFLAGS="$CFLAGS"
CFLAGS="$warn_CFLAGS $CFLAGS"
AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
CFLAGS="$saved_CFLAGS"
])
SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
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([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
saved_CFLAGS="$CFLAGS"
CFLAGS="-fvisibility=hidden $CFLAGS"
AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
CFLAGS="$saved_CFLAGS"
])
CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
])
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
###
### Define config arguments
###
AC_ARG_ENABLE(benchmark,
AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]),
@ -161,6 +181,16 @@ AC_ARG_ENABLE(module_schnorrsig,
[enable_module_schnorrsig=$enableval],
[enable_module_schnorrsig=no])
AC_ARG_ENABLE(module_ecdsa_s2c,
AS_HELP_STRING([--enable-module-ecdsa-s2c],[enable ECDSA sign-to-contract module [default=no]]),
[enable_module_ecdsa_s2c=$enableval],
[enable_module_ecdsa_s2c=no])
AC_ARG_ENABLE(module_ecdsa-adaptor,
AS_HELP_STRING([--enable-module-ecdsa-adaptor],[enable ECDSA adaptor module [default=no]]),
[enable_module_ecdsa_adaptor=$enableval],
[enable_module_ecdsa_adaptor=no])
AC_ARG_ENABLE(external_default_callbacks,
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
[use_external_default_callbacks=$enableval],
@ -176,13 +206,10 @@ AC_ARG_ENABLE(reduced_surjection_proof_size,
[use_reduced_surjection_proof_size=$enableval],
[use_reduced_surjection_proof_size=no])
dnl Test-only override of the (autodetected by the C code) "widemul" setting.
dnl Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
# Test-only override of the (autodetected by the C code) "widemul" setting.
# Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
[bignum implementation to use [default=auto]])],[req_bignum=$withval], [req_bignum=auto])
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto])
@ -207,24 +234,35 @@ AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto],
)],
[req_valgrind=$withval], [req_valgrind=auto])
###
### Handle config options (except for modules)
###
if test x"$req_valgrind" = x"no"; then
enable_valgrind=no
else
AC_CHECK_HEADER([valgrind/memcheck.h], [enable_valgrind=yes], [
SECP_VALGRIND_CHECK
if test x"$has_valgrind" != x"yes"; then
if test x"$req_valgrind" = x"yes"; then
AC_MSG_ERROR([Valgrind support explicitly requested but valgrind/memcheck.h header not available])
fi
enable_valgrind=no
], [])
else
enable_valgrind=yes
fi
fi
AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
if test x"$enable_coverage" = x"yes"; then
AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
CFLAGS="-O0 --coverage $CFLAGS"
SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS"
LDFLAGS="--coverage $LDFLAGS"
else
CFLAGS="-O2 $CFLAGS"
# Most likely the CFLAGS already contain -O2 because that is autoconf's default.
# We still add it here because passing it twice is not an issue, and handling
# this case would just add unnecessary complexity (see #896).
SECP_CFLAGS="-O2 $SECP_CFLAGS"
SECP_CFLAGS_FOR_BUILD="-O2 $SECP_CFLAGS_FOR_BUILD"
fi
AC_MSG_CHECKING([for __builtin_popcount])
@ -233,61 +271,6 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_popcount(0);}]])],
[ AC_MSG_RESULT([no])
])
if test x"$use_ecmult_static_precomputation" != x"no"; then
# Temporarily switch to an environment for the native compiler
save_cross_compiling=$cross_compiling
cross_compiling=no
SAVE_CC="$CC"
CC="$CC_FOR_BUILD"
SAVE_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS_FOR_BUILD"
SAVE_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS_FOR_BUILD"
SAVE_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS_FOR_BUILD"
warn_CFLAGS_FOR_BUILD="-Wall -Wextra -Wno-unused-function"
saved_CFLAGS="$CFLAGS"
CFLAGS="$warn_CFLAGS_FOR_BUILD $CFLAGS"
AC_MSG_CHECKING([if native ${CC_FOR_BUILD} supports ${warn_CFLAGS_FOR_BUILD}])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
[ AC_MSG_RESULT([yes]) ],
[ AC_MSG_RESULT([no])
CFLAGS="$saved_CFLAGS"
])
AC_MSG_CHECKING([for working native compiler: ${CC_FOR_BUILD}])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([], [])],
[working_native_cc=yes],
[working_native_cc=no],[:])
CFLAGS_FOR_BUILD="$CFLAGS"
# Restore the environment
cross_compiling=$save_cross_compiling
CC="$SAVE_CC"
CFLAGS="$SAVE_CFLAGS"
CPPFLAGS="$SAVE_CPPFLAGS"
LDFLAGS="$SAVE_LDFLAGS"
if test x"$working_native_cc" = x"no"; then
AC_MSG_RESULT([no])
set_precomp=no
m4_define([please_set_for_build], [Please set CC_FOR_BUILD, CFLAGS_FOR_BUILD, CPPFLAGS_FOR_BUILD, and/or LDFLAGS_FOR_BUILD.])
if test x"$use_ecmult_static_precomputation" = x"yes"; then
AC_MSG_ERROR([native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
else
AC_MSG_WARN([Disabling statically generated ecmult table because the native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
fi
else
AC_MSG_RESULT([yes])
set_precomp=yes
fi
else
set_precomp=no
fi
AC_MSG_CHECKING([for __builtin_clzll])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() { __builtin_clzll(1);}]])],
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_CLZLL,1,[Define this symbol if __builtin_clzll is available]) ],
@ -321,33 +304,7 @@ else
esac
fi
if test x"$req_bignum" = x"auto"; then
SECP_GMP_CHECK
if test x"$has_gmp" = x"yes"; then
set_bignum=gmp
fi
if test x"$set_bignum" = x; then
set_bignum=no
fi
else
set_bignum=$req_bignum
case $set_bignum in
gmp)
SECP_GMP_CHECK
if test x"$has_gmp" != x"yes"; then
AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available])
fi
;;
no)
;;
*)
AC_MSG_ERROR([invalid bignum implementation selection])
;;
esac
fi
# select assembly optimization
# Select assembly optimization
use_external_asm=no
case $set_asm in
@ -364,7 +321,12 @@ no)
;;
esac
# select wide multiplication implementation
if test x"$use_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
fi
# Select wide multiplication implementation
case $set_widemul in
int128)
AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation])
@ -379,25 +341,7 @@ auto)
;;
esac
# select bignum implementation
case $set_bignum in
gmp)
AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed])
AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num])
AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation])
AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation])
;;
no)
AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation])
AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation])
AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation])
;;
*)
AC_MSG_ERROR([invalid bignum implementation])
;;
esac
#set ecmult window size
# Set ecmult window size
if test x"$req_ecmult_window" = x"auto"; then
set_ecmult_window=15
else
@ -419,7 +363,7 @@ case $set_ecmult_window in
;;
esac
#set ecmult gen precision
# Set ecmult gen precision
if test x"$req_ecmult_gen_precision" = x"auto"; then
set_ecmult_gen_precision=4
else
@ -461,21 +405,95 @@ else
enable_openssl_tests=no
fi
if test x"$set_bignum" = x"gmp"; then
SECP_LIBS="$SECP_LIBS $GMP_LIBS"
SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
if test x"$enable_valgrind" = x"yes"; then
SECP_INCLUDES="$SECP_INCLUDES $VALGRIND_CPPFLAGS"
fi
# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI)
SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
# Handle static precomputation (after everything which modifies CFLAGS and friends)
if test x"$use_ecmult_static_precomputation" != x"no"; then
if test x"$cross_compiling" = x"no"; then
set_precomp=yes
if test x"${CC_FOR_BUILD+x}${CFLAGS_FOR_BUILD+x}${CPPFLAGS_FOR_BUILD+x}${LDFLAGS_FOR_BUILD+x}" != x; then
AC_MSG_WARN([CC_FOR_BUILD, CFLAGS_FOR_BUILD, CPPFLAGS_FOR_BUILD, and/or LDFLAGS_FOR_BUILD is set but ignored because we are not cross-compiling.])
fi
# If we're not cross-compiling, simply use the same compiler for building the static precompation code.
CC_FOR_BUILD="$CC"
CPPFLAGS_FOR_BUILD="$CPPFLAGS"
SECP_CFLAGS_FOR_BUILD="$SECP_CFLAGS"
CFLAGS_FOR_BUILD="$CFLAGS"
LDFLAGS_FOR_BUILD="$LDFLAGS"
else
AX_PROG_CC_FOR_BUILD
# Temporarily switch to an environment for the native compiler
save_cross_compiling=$cross_compiling
cross_compiling=no
SAVE_CC="$CC"
CC="$CC_FOR_BUILD"
SAVE_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS_FOR_BUILD"
SAVE_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS_FOR_BUILD"
SAVE_LDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS_FOR_BUILD"
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS_FOR_BUILD)
AC_MSG_CHECKING([for working native compiler: ${CC_FOR_BUILD}])
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([], [])],
[working_native_cc=yes],
[working_native_cc=no],[:])
# Restore the environment
cross_compiling=$save_cross_compiling
CC="$SAVE_CC"
CPPFLAGS="$SAVE_CPPFLAGS"
CFLAGS="$SAVE_CFLAGS"
LDFLAGS="$SAVE_LDFLAGS"
if test x"$working_native_cc" = x"no"; then
AC_MSG_RESULT([no])
set_precomp=no
m4_define([please_set_for_build], [Please set CC_FOR_BUILD, CPPFLAGS_FOR_BUILD, CFLAGS_FOR_BUILD, and/or LDFLAGS_FOR_BUILD.])
if test x"$use_ecmult_static_precomputation" = x"yes"; then
AC_MSG_ERROR([native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
else
AC_MSG_WARN([Disabling statically generated ecmult table because the native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
fi
else
AC_MSG_RESULT([yes])
set_precomp=yes
fi
fi
AC_SUBST(CC_FOR_BUILD)
AC_SUBST(CPPFLAGS_FOR_BUILD)
AC_SUBST(SECP_CFLAGS_FOR_BUILD)
AC_SUBST(CFLAGS_FOR_BUILD)
AC_SUBST(LDFLAGS_FOR_BUILD)
else
set_precomp=no
fi
if test x"$set_precomp" = x"yes"; then
AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table])
fi
###
### Handle module options
###
if test x"$enable_module_ecdh" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
fi
if test x"$enable_module_musig" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_MUSIG, 1, [Define this symbol to enable the MuSig module])
enable_module_schnorrsig=yes
fi
if test x"$enable_module_recovery" = x"yes"; then
@ -497,7 +515,8 @@ fi
if test x"$enable_module_surjectionproof" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module])
fi
# Test if extrakeys is set _after_ the MuSig module to allow the MuSig
# module to set enable_module_schnorrsig=yes
if test x"$enable_module_schnorrsig" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module])
enable_module_extrakeys=yes
@ -509,8 +528,8 @@ if test x"$enable_module_extrakeys" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module])
fi
if test x"$use_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
if test x"$enable_module_ecdsa_s2c" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDSA_S2C, 1, [Define this symbol to enable the ECDSA sign-to-contract module])
fi
if test x"$use_external_default_callbacks" = x"yes"; then
@ -521,6 +540,14 @@ if test x"$use_reduced_surjection_proof_size" = x"yes"; then
AC_DEFINE(USE_REDUCED_SURJECTION_PROOF_SIZE, 1, [Define this symbol to reduce SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS to 16, disabling parsing and verification])
fi
if test x"$enable_module_ecdsa_adaptor" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDSA_ADAPTOR, 1, [Define this symbol to enable the ECDSA adaptor module])
fi
###
### Check for --enable-experimental if necessary
###
if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([******])
AC_MSG_NOTICE([WARNING: experimental build])
@ -532,6 +559,8 @@ if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([Building MuSig module: $enable_module_musig])
AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys])
AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig])
AC_MSG_NOTICE([Building ECDSA sign-to-contract module: $enable_module_ecdsa_s2c])
AC_MSG_NOTICE([Building ECDSA adaptor signatures module: $enable_module_ecdsa_adaptor])
AC_MSG_NOTICE([******])
@ -565,6 +594,12 @@ else
if test x"$enable_module_schnorrsig" = x"yes"; then
AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.])
fi
if test x"$enable_module_ecdsa_s2c" = x"yes"; then
AC_MSG_ERROR([ECDSA sign-to-contract module module is experimental. Use --enable-experimental to allow.])
fi
if test x"$enable_module_ecdsa_adaptor" = x"yes"; then
AC_MSG_ERROR([ecdsa adaptor signatures module is experimental. Use --enable-experimental to allow.])
fi
if test x"$set_asm" = x"arm"; then
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
fi
@ -582,12 +617,17 @@ else
fi
fi
###
### Generate output
###
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
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)
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
@ -601,12 +641,14 @@ AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" =
AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_S2C], [test x"$enable_module_ecdsa_s2c" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_ADAPTOR], [test x"$enable_module_ecdsa_adaptor" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"])
AM_CONDITIONAL([USE_REDUCED_SURJECTION_PROOF_SIZE], [test x"$use_reduced_surjection_proof_size" = x"yes"])
dnl make sure nothing new is exported so that we don't break the cache
# Make sure nothing new is exported so that we don't break the cache.
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
unset PKG_CONFIG_PATH
PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
@ -625,19 +667,29 @@ echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module extrakeys = $enable_module_extrakeys"
echo " module schnorrsig = $enable_module_schnorrsig"
echo " module musig = $enable_module_musig"
echo " module ecdsa-s2c = $enable_module_ecdsa_s2c"
echo " module ecdsa-adaptor = $enable_module_ecdsa_adaptor"
echo
echo " asm = $set_asm"
echo " bignum = $set_bignum"
echo " ecmult window size = $set_ecmult_window"
echo " ecmult gen prec. bits = $set_ecmult_gen_precision"
dnl Hide test-only options unless they're used.
# Hide test-only options unless they're used.
if test x"$set_widemul" != xauto; then
echo " wide multiplication = $set_widemul"
fi
echo
echo " valgrind = $enable_valgrind"
echo " CC = $CC"
echo " CFLAGS = $CFLAGS"
echo " CPPFLAGS = $CPPFLAGS"
echo " SECP_CFLAGS = $SECP_CFLAGS"
echo " CFLAGS = $CFLAGS"
echo " LDFLAGS = $LDFLAGS"
echo
if test x"$set_precomp" = x"yes"; then
echo " CC_FOR_BUILD = $CC_FOR_BUILD"
echo " CPPFLAGS_FOR_BUILD = $CPPFLAGS_FOR_BUILD"
echo " SECP_CFLAGS_FOR_BUILD = $SECP_CFLAGS_FOR_BUILD"
echo " CFLAGS_FOR_BUILD = $CFLAGS_FOR_BUILD"
echo " LDFLAGS_FOR_BUILD = $LDFLAGS_FOR_BUILD"
fi

View file

@ -1,11 +1,10 @@
/**********************************************************************
* Copyright (c) 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#include <string.h>
#include <secp256k1.h>
#include "lax_der_parsing.h"
@ -121,7 +120,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
/* Copy R value */
if (rlen > 32) {
overflow = 1;
} else {
} else if (rlen) {
memcpy(tmpsig + 32 - rlen, input + rpos, rlen);
}
@ -133,7 +132,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
/* Copy S value */
if (slen > 32) {
overflow = 1;
} else {
} else if (slen) {
memcpy(tmpsig + 64 - slen, input + spos, slen);
}

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
/****
* Please do not link this file directly. It is not part of the libsecp256k1
@ -51,7 +51,13 @@
#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H
#define SECP256K1_CONTRIB_LAX_DER_PARSING_H
/* #include secp256k1.h only when it hasn't been included yet.
This enables this file to be #included directly in other project
files (such as tests.c) without the need to set an explicit -I flag,
which would be necessary to locate secp256k1.h. */
#ifndef SECP256K1_H
#include <secp256k1.h>
#endif
#ifdef __cplusplus
extern "C" {

View file

@ -1,11 +1,10 @@
/**********************************************************************
* Copyright (c) 2014, 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2014, 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#include <string.h>
#include <secp256k1.h>
#include "lax_der_privatekey_parsing.h"
@ -45,7 +44,7 @@ int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, co
if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) {
return 0;
}
memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);
if (privkey[1]) memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]);
if (!secp256k1_ec_seckey_verify(ctx, out32)) {
memset(out32, 0, 32);
return 0;

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2014, 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2014, 2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
/****
* Please do not link this file directly. It is not part of the libsecp256k1
@ -28,7 +28,13 @@
#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H
#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H
/* #include secp256k1.h only when it hasn't been included yet.
This enables this file to be #included directly in other project
files (such as tests.c) without the need to set an explicit -I flag,
which would be necessary to locate secp256k1.h. */
#ifndef SECP256K1_H
#include <secp256k1.h>
#endif
#ifdef __cplusplus
extern "C" {

115
contrib/sync-upstream.sh Executable file
View file

@ -0,0 +1,115 @@
#!/bin/bash
set -eou pipefail
help() {
echo "$0 range [end]"
echo " merges every merge commit present in upstream and missing locally."
echo " If the optional [end] commit is provided, only merges up to [end]."
echo
echo "$0 select <commit> ... <commit>"
echo " merges every selected merge commit"
echo
echo "This tool creates a branch and a script that can be executed to create the"
echo "PR automatically. The script requires the github-cli tool (aka gh)."
echo ""
echo "Tip: \`git log --oneline upstream/master --merges\` shows merge commits."
exit 1
}
if [ "$#" -lt 1 ]; then
help
fi
REMOTE=upstream
REMOTE_BRANCH="$REMOTE/master"
# Makes sure you have a remote "upstream" that is up-to-date
setup() {
ret=0
git fetch "$REMOTE" &> /dev/null || ret="$?"
if [ ${ret} == 0 ]; then
return
fi
echo "Adding remote \"$REMOTE\" with URL git@github.com:bitcoin-core/secp256k1.git. Continue with y"
read -r yn
case $yn in
[Yy]* ) ;;
* ) exit 1;;
esac
git remote add "$REMOTE" git@github.com:bitcoin-core/secp256k1.git &> /dev/null
git fetch "$REMOTE" &> /dev/null
}
range() {
RANGESTART_COMMIT=$(git merge-base "$REMOTE_BRANCH" master)
RANGEEND_COMMIT=$(git rev-parse "$REMOTE_BRANCH")
if [ "$#" = 1 ]; then
RANGEEND_COMMIT=$1
fi
COMMITS=$(git --no-pager log --oneline --merges "$RANGESTART_COMMIT".."$RANGEEND_COMMIT")
COMMITS=$(echo "$COMMITS" | tac | awk '{ print $1 }' ORS=' ')
echo "Merging $COMMITS. Continue with y"
read -r yn
case $yn in
[Yy]* ) ;;
* ) exit 1;;
esac
}
case $1 in
range)
shift
setup
range "$@"
REPRODUCE_COMMAND="$0 range $RANGEEND_COMMIT"
;;
select)
shift
setup
COMMITS=$*
REPRODUCE_COMMAND="$0 $@"
;;
help)
help
;;
*)
help
esac
TITLE="Upstream PRs"
BODY=""
for COMMIT in $COMMITS
do
PRNUM=$(git log -1 "$COMMIT" --pretty=format:%s | sed s/'Merge \(bitcoin-core\/secp256k1\)\?#\([0-9]*\).*'/'\2'/)
TITLE="$TITLE $PRNUM,"
BODY=$(printf "%s\n%s" "$BODY" "$(git log -1 "$COMMIT" --pretty=format:%s | sed s/'Merge \(bitcoin-core\/secp256k1\)\?#\([0-9]*\)'/'[bitcoin-core\/secp256k1#\2]'/)")
done
# Remove trailing ","
TITLE=${TITLE%?}
BODY=$(printf "%s\n\n%s" "$BODY" "This PR can be recreated with \`$REPRODUCE_COMMAND\`.")
echo "-----------------------------------"
echo "$TITLE"
echo "-----------------------------------"
echo "$BODY"
echo "-----------------------------------"
# Create branch from PR commit and create PR
git checkout master
git pull
git checkout -b temp-merge-"$PRNUM"
BASEDIR=$(dirname "$0")
FNAME="$BASEDIR/gh-pr-create.sh"
cat <<EOT > "$FNAME"
#!/bin/sh
gh pr create -t "$TITLE" -b "$BODY" --web
# Remove temporary branch
git checkout master
git branch -D temp-merge-"$PRNUM"
EOT
chmod +x "$FNAME"
echo Run "$FNAME" after solving the merge conflicts
git merge --no-edit -m "Merge commits '$COMMITS' into temp-merge-$PRNUM" $COMMITS

View file

@ -0,0 +1,765 @@
# The safegcd implementation in libsecp256k1 explained
This document explains the modular inverse implementation in the `src/modinv*.h` files. It is based
on the paper
["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.
The actual implementation is in C of course, but for demonstration purposes Python3 is used here.
Most implementation aspects and optimizations are explained, except those that depend on the specific
number representation used in the C code.
## 1. Computing the Greatest Common Divisor (GCD) using divsteps
The algorithm from the paper (section 11), at a very high level, is this:
```python
def gcd(f, g):
"""Compute the GCD of an odd integer f and another integer g."""
assert f & 1 # require f to be odd
delta = 1 # additional state variable
while g != 0:
assert f & 1 # f will be odd in every iteration
if delta > 0 and g & 1:
delta, f, g = 1 - delta, g, (g - f) // 2
elif g & 1:
delta, f, g = 1 + delta, f, (g + f) // 2
else:
delta, f, g = 1 + delta, f, (g ) // 2
return abs(f)
```
It computes the greatest common divisor of an odd integer *f* and any integer *g*. Its inner loop
keeps rewriting the variables *f* and *g* alongside a state variable *&delta;* that starts at *1*, until
*g=0* is reached. At that point, *|f|* gives the GCD. Each of the transitions in the loop is called a
"division step" (referred to as divstep in what follows).
For example, *gcd(21, 14)* would be computed as:
- Start with *&delta;=1 f=21 g=14*
- Take the third branch: *&delta;=2 f=21 g=7*
- Take the first branch: *&delta;=-1 f=7 g=-7*
- Take the second branch: *&delta;=0 f=7 g=0*
- The answer *|f| = 7*.
Why it works:
- Divsteps can be decomposed into two steps (see paragraph 8.2 in the paper):
- (a) If *g* is odd, replace *(f,g)* with *(g,g-f)* or (f,g+f), resulting in an even *g*.
- (b) Replace *(f,g)* with *(f,g/2)* (where *g* is guaranteed to be even).
- Neither of those two operations change the GCD:
- For (a), assume *gcd(f,g)=c*, then it must be the case that *f=a&thinsp;c* and *g=b&thinsp;c* for some integers *a*
and *b*. As *(g,g-f)=(b&thinsp;c,(b-a)c)* and *(f,f+g)=(a&thinsp;c,(a+b)c)*, the result clearly still has
common factor *c*. Reasoning in the other direction shows that no common factor can be added by
doing so either.
- For (b), we know that *f* is odd, so *gcd(f,g)* clearly has no factor *2*, and we can remove
it from *g*.
- The algorithm will eventually converge to *g=0*. This is proven in the paper (see theorem G.3).
- It follows that eventually we find a final value *f'* for which *gcd(f,g) = gcd(f',0)*. As the
gcd of *f'* and *0* is *|f'|* by definition, that is our answer.
Compared to more [traditional GCD algorithms](https://en.wikipedia.org/wiki/Euclidean_algorithm), this one has the property of only ever looking at
the low-order bits of the variables to decide the next steps, and being easy to make
constant-time (in more low-level languages than Python). The *&delta;* parameter is necessary to
guide the algorithm towards shrinking the numbers' magnitudes without explicitly needing to look
at high order bits.
Properties that will become important later:
- Performing more divsteps than needed is not a problem, as *f* does not change anymore after *g=0*.
- Only even numbers are divided by *2*. This means that when reasoning about it algebraically we
do not need to worry about rounding.
- At every point during the algorithm's execution the next *N* steps only depend on the bottom *N*
bits of *f* and *g*, and on *&delta;*.
## 2. From GCDs to modular inverses
We want an algorithm to compute the inverse *a* of *x* modulo *M*, i.e. the number a such that *a&thinsp;x=1
mod M*. This inverse only exists if the GCD of *x* and *M* is *1*, but that is always the case if *M* is
prime and *0 < x < M*. In what follows, assume that the modular inverse exists.
It turns out this inverse can be computed as a side effect of computing the GCD by keeping track
of how the internal variables can be written as linear combinations of the inputs at every step
(see the [extended Euclidean algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm)).
Since the GCD is *1*, such an algorithm will compute numbers *a* and *b* such that a&thinsp;x + b&thinsp;M = 1*.
Taking that expression *mod M* gives *a&thinsp;x mod M = 1*, and we see that *a* is the modular inverse of *x
mod M*.
A similar approach can be used to calculate modular inverses using the divsteps-based GCD
algorithm shown above, if the modulus *M* is odd. To do so, compute *gcd(f=M,g=x)*, while keeping
track of extra variables *d* and *e*, for which at every step *d = f/x (mod M)* and *e = g/x (mod M)*.
*f/x* here means the number which multiplied with *x* gives *f mod M*. As *f* and *g* are initialized to *M*
and *x* respectively, *d* and *e* just start off being *0* (*M/x mod M = 0/x mod M = 0*) and *1* (*x/x mod M
= 1*).
```python
def div2(M, x):
"""Helper routine to compute x/2 mod M (where M is odd)."""
assert M & 1
if x & 1: # If x is odd, make it even by adding M.
x += M
# x must be even now, so a clean division by 2 is possible.
return x // 2
def modinv(M, x):
"""Compute the inverse of x mod M (given that it exists, and M is odd)."""
assert M & 1
delta, f, g, d, e = 1, M, x, 0, 1
while g != 0:
# Note that while division by two for f and g is only ever done on even inputs, this is
# not true for d and e, so we need the div2 helper function.
if delta > 0 and g & 1:
delta, f, g, d, e = 1 - delta, g, (g - f) // 2, e, div2(M, e - d)
elif g & 1:
delta, f, g, d, e = 1 + delta, f, (g + f) // 2, d, div2(M, e + d)
else:
delta, f, g, d, e = 1 + delta, f, (g ) // 2, d, div2(M, e )
# Verify that the invariants d=f/x mod M, e=g/x mod M are maintained.
assert f % M == (d * x) % M
assert g % M == (e * x) % M
assert f == 1 or f == -1 # |f| is the GCD, it must be 1
# Because of invariant d = f/x (mod M), 1/x = d/f (mod M). As |f|=1, d/f = d*f.
return (d * f) % M
```
Also note that this approach to track *d* and *e* throughout the computation to determine the inverse
is different from the paper. There (see paragraph 12.1 in the paper) a transition matrix for the
entire computation is determined (see section 3 below) and the inverse is computed from that.
The approach here avoids the need for 2x2 matrix multiplications of various sizes, and appears to
be faster at the level of optimization we're able to do in C.
## 3. Batching multiple divsteps
Every divstep can be expressed as a matrix multiplication, applying a transition matrix *(1/2 t)*
to both vectors *[f, g]* and *[d, e]* (see paragraph 8.1 in the paper):
```
t = [ u, v ]
[ q, r ]
[ out_f ] = (1/2 * t) * [ in_f ]
[ out_g ] = [ in_g ]
[ out_d ] = (1/2 * t) * [ in_d ] (mod M)
[ out_e ] [ in_e ]
```
where *(u, v, q, r)* is *(0, 2, -1, 1)*, *(2, 0, 1, 1)*, or *(2, 0, 0, 1)*, depending on which branch is
taken. As above, the resulting *f* and *g* are always integers.
Performing multiple divsteps corresponds to a multiplication with the product of all the
individual divsteps' transition matrices. As each transition matrix consists of integers
divided by *2*, the product of these matrices will consist of integers divided by *2<sup>N</sup>* (see also
theorem 9.2 in the paper). These divisions are expensive when updating *d* and *e*, so we delay
them: we compute the integer coefficients of the combined transition matrix scaled by *2<sup>N</sup>*, and
do one division by *2<sup>N</sup>* as a final step:
```python
def divsteps_n_matrix(delta, f, g):
"""Compute delta and transition matrix t after N divsteps (multiplied by 2^N)."""
u, v, q, r = 1, 0, 0, 1 # start with identity matrix
for _ in range(N):
if delta > 0 and g & 1:
delta, f, g, u, v, q, r = 1 - delta, g, (g - f) // 2, 2*q, 2*r, q-u, r-v
elif g & 1:
delta, f, g, u, v, q, r = 1 + delta, f, (g + f) // 2, 2*u, 2*v, q+u, r+v
else:
delta, f, g, u, v, q, r = 1 + delta, f, (g ) // 2, 2*u, 2*v, q , r
return delta, (u, v, q, r)
```
As the branches in the divsteps are completely determined by the bottom *N* bits of *f* and *g*, this
function to compute the transition matrix only needs to see those bottom bits. Furthermore all
intermediate results and outputs fit in *(N+1)*-bit numbers (unsigned for *f* and *g*; signed for *u*, *v*,
*q*, and *r*) (see also paragraph 8.3 in the paper). This means that an implementation using 64-bit
integers could set *N=62* and compute the full transition matrix for 62 steps at once without any
big integer arithmetic at all. This is the reason why this algorithm is efficient: it only needs
to update the full-size *f*, *g*, *d*, and *e* numbers once every *N* steps.
We still need functions to compute:
```
[ out_f ] = (1/2^N * [ u, v ]) * [ in_f ]
[ out_g ] ( [ q, r ]) [ in_g ]
[ out_d ] = (1/2^N * [ u, v ]) * [ in_d ] (mod M)
[ out_e ] ( [ q, r ]) [ in_e ]
```
Because the divsteps transformation only ever divides even numbers by two, the result of *t&thinsp;[f,g]* is always even. When *t* is a composition of *N* divsteps, it follows that the resulting *f*
and *g* will be multiple of *2<sup>N</sup>*, and division by *2<sup>N</sup>* is simply shifting them down:
```python
def update_fg(f, g, t):
"""Multiply matrix t/2^N with [f, g]."""
u, v, q, r = t
cf, cg = u*f + v*g, q*f + r*g
# (t / 2^N) should cleanly apply to [f,g] so the result of t*[f,g] should have N zero
# bottom bits.
assert cf % 2**N == 0
assert cg % 2**N == 0
return cf >> N, cg >> N
```
The same is not true for *d* and *e*, and we need an equivalent of the `div2` function for division by *2<sup>N</sup> mod M*.
This is easy if we have precomputed *1/M mod 2<sup>N</sup>* (which always exists for odd *M*):
```python
def div2n(M, Mi, x):
"""Compute x/2^N mod M, given Mi = 1/M mod 2^N."""
assert (M * Mi) % 2**N == 1
# Find a factor m such that m*M has the same bottom N bits as x. We want:
# (m * M) mod 2^N = x mod 2^N
# <=> m mod 2^N = (x / M) mod 2^N
# <=> m mod 2^N = (x * Mi) mod 2^N
m = (Mi * x) % 2**N
# Subtract that multiple from x, cancelling its bottom N bits.
x -= m * M
# Now a clean division by 2^N is possible.
assert x % 2**N == 0
return (x >> N) % M
def update_de(d, e, t, M, Mi):
"""Multiply matrix t/2^N with [d, e], modulo M."""
u, v, q, r = t
cd, ce = u*d + v*e, q*d + r*e
return div2n(M, Mi, cd), div2n(M, Mi, ce)
```
With all of those, we can write a version of `modinv` that performs *N* divsteps at once:
```python3
def modinv(M, Mi, x):
"""Compute the modular inverse of x mod M, given Mi=1/M mod 2^N."""
assert M & 1
delta, f, g, d, e = 1, M, x, 0, 1
while g != 0:
# Compute the delta and transition matrix t for the next N divsteps (this only needs
# (N+1)-bit signed integer arithmetic).
delta, t = divsteps_n_matrix(delta, f % 2**N, g % 2**N)
# Apply the transition matrix t to [f, g]:
f, g = update_fg(f, g, t)
# Apply the transition matrix t to [d, e]:
d, e = update_de(d, e, t, M, Mi)
return (d * f) % M
```
This means that in practice we'll always perform a multiple of *N* divsteps. This is not a problem
because once *g=0*, further divsteps do not affect *f*, *g*, *d*, or *e* anymore (only *&delta;* keeps
increasing). For variable time code such excess iterations will be mostly optimized away in later
sections.
## 4. Avoiding modulus operations
So far, there are two places where we compute a remainder of big numbers modulo *M*: at the end of
`div2n` in every `update_de`, and at the very end of `modinv` after potentially negating *d* due to the
sign of *f*. These are relatively expensive operations when done generically.
To deal with the modulus operation in `div2n`, we simply stop requiring *d* and *e* to be in range
*[0,M)* all the time. Let's start by inlining `div2n` into `update_de`, and dropping the modulus
operation at the end:
```python
def update_de(d, e, t, M, Mi):
"""Multiply matrix t/2^N with [d, e] mod M, given Mi=1/M mod 2^N."""
u, v, q, r = t
cd, ce = u*d + v*e, q*d + r*e
# Cancel out bottom N bits of cd and ce.
md = -((Mi * cd) % 2**N)
me = -((Mi * ce) % 2**N)
cd += md * M
ce += me * M
# And cleanly divide by 2**N.
return cd >> N, ce >> N
```
Let's look at bounds on the ranges of these numbers. It can be shown that *|u|+|v|* and *|q|+|r|*
never exceed *2<sup>N</sup>* (see paragraph 8.3 in the paper), and thus a multiplication with *t* will have
outputs whose absolute values are at most *2<sup>N</sup>* times the maximum absolute input value. In case the
inputs *d* and *e* are in *(-M,M)*, which is certainly true for the initial values *d=0* and *e=1* assuming
*M > 1*, the multiplication results in numbers in range *(-2<sup>N</sup>M,2<sup>N</sup>M)*. Subtracting less than *2<sup>N</sup>*
times *M* to cancel out *N* bits brings that up to *(-2<sup>N+1</sup>M,2<sup>N</sup>M)*, and
dividing by *2<sup>N</sup>* at the end takes it to *(-2M,M)*. Another application of `update_de` would take that
to *(-3M,2M)*, and so forth. This progressive expansion of the variables' ranges can be
counteracted by incrementing *d* and *e* by *M* whenever they're negative:
```python
...
if d < 0:
d += M
if e < 0:
e += M
cd, ce = u*d + v*e, q*d + r*e
# Cancel out bottom N bits of cd and ce.
...
```
With inputs in *(-2M,M)*, they will first be shifted into range *(-M,M)*, which means that the
output will again be in *(-2M,M)*, and this remains the case regardless of how many `update_de`
invocations there are. In what follows, we will try to make this more efficient.
Note that increasing *d* by *M* is equal to incrementing *cd* by *u&thinsp;M* and *ce* by *q&thinsp;M*. Similarly,
increasing *e* by *M* is equal to incrementing *cd* by *v&thinsp;M* and *ce* by *r&thinsp;M*. So we could instead write:
```python
...
cd, ce = u*d + v*e, q*d + r*e
# Perform the equivalent of incrementing d, e by M when they're negative.
if d < 0:
cd += u*M
ce += q*M
if e < 0:
cd += v*M
ce += r*M
# Cancel out bottom N bits of cd and ce.
md = -((Mi * cd) % 2**N)
me = -((Mi * ce) % 2**N)
cd += md * M
ce += me * M
...
```
Now note that we have two steps of corrections to *cd* and *ce* that add multiples of *M*: this
increment, and the decrement that cancels out bottom bits. The second one depends on the first
one, but they can still be efficiently combined by only computing the bottom bits of *cd* and *ce*
at first, and using that to compute the final *md*, *me* values:
```python
def update_de(d, e, t, M, Mi):
"""Multiply matrix t/2^N with [d, e], modulo M."""
u, v, q, r = t
md, me = 0, 0
# Compute what multiples of M to add to cd and ce.
if d < 0:
md += u
me += q
if e < 0:
md += v
me += r
# Compute bottom N bits of t*[d,e] + M*[md,me].
cd, ce = (u*d + v*e + md*M) % 2**N, (q*d + r*e + me*M) % 2**N
# Correct md and me such that the bottom N bits of t*[d,e] + M*[md,me] are zero.
md -= (Mi * cd) % 2**N
me -= (Mi * ce) % 2**N
# Do the full computation.
cd, ce = u*d + v*e + md*M, q*d + r*e + me*M
# And cleanly divide by 2**N.
return cd >> N, ce >> N
```
One last optimization: we can avoid the *md&thinsp;M* and *me&thinsp;M* multiplications in the bottom bits of *cd*
and *ce* by moving them to the *md* and *me* correction:
```python
...
# Compute bottom N bits of t*[d,e].
cd, ce = (u*d + v*e) % 2**N, (q*d + r*e) % 2**N
# Correct md and me such that the bottom N bits of t*[d,e]+M*[md,me] are zero.
# Note that this is not the same as {md = (-Mi * cd) % 2**N} etc. That would also result in N
# zero bottom bits, but isn't guaranteed to be a reduction of [0,2^N) compared to the
# previous md and me values, and thus would violate our bounds analysis.
md -= (Mi*cd + md) % 2**N
me -= (Mi*ce + me) % 2**N
...
```
The resulting function takes *d* and *e* in range *(-2M,M)* as inputs, and outputs values in the same
range. That also means that the *d* value at the end of `modinv` will be in that range, while we want
a result in *[0,M)*. To do that, we need a normalization function. It's easy to integrate the
conditional negation of *d* (based on the sign of *f*) into it as well:
```python
def normalize(sign, v, M):
"""Compute sign*v mod M, where v is in range (-2*M,M); output in [0,M)."""
assert sign == 1 or sign == -1
# v in (-2*M,M)
if v < 0:
v += M
# v in (-M,M). Now multiply v with sign (which can only be 1 or -1).
if sign == -1:
v = -v
# v in (-M,M)
if v < 0:
v += M
# v in [0,M)
return v
```
And calling it in `modinv` is simply:
```python
...
return normalize(f, d, M)
```
## 5. Constant-time operation
The primary selling point of the algorithm is fast constant-time operation. What code flow still
depends on the input data so far?
- the number of iterations of the while *g &ne; 0* loop in `modinv`
- the branches inside `divsteps_n_matrix`
- the sign checks in `update_de`
- the sign checks in `normalize`
To make the while loop in `modinv` constant time it can be replaced with a constant number of
iterations. The paper proves (Theorem 11.2) that *741* divsteps are sufficient for any *256*-bit
inputs, and [safegcd-bounds](https://github.com/sipa/safegcd-bounds) shows that the slightly better bound *724* is
sufficient even. Given that every loop iteration performs *N* divsteps, it will run a total of
*&lceil;724/N&rceil;* times.
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
`valgrind_ctime_test.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).
```python
x = -f if delta > 0 else f # set x equal to (input) -f or f
if g & 1:
g += x # set g to (input) g-f or g+f
if delta > 0:
delta = -delta
f += g # set f to (input) g (note that g was set to g-f before)
delta += 1
g >>= 1
```
To convert the above to bitwise operations, we rely on a trick to negate conditionally: per the
definition of negative numbers in two's complement, (*-v == ~v + 1*) holds for every number *v*. As
*-1* in two's complement is all *1* bits, bitflipping can be expressed as xor with *-1*. It follows
that *-v == (v ^ -1) - (-1)*. Thus, if we have a variable *c* that takes on values *0* or *-1*, then
*(v ^ c) - c* is *v* if *c=0* and *-v* if *c=-1*.
Using this we can write:
```python
x = -f if delta > 0 else f
```
in constant-time form as:
```python
c1 = (-delta) >> 63
# Conditionally negate f based on c1:
x = (f ^ c1) - c1
```
To use that trick, we need a helper mask variable *c1* that resolves the condition *&delta;>0* to *-1*
(if true) or *0* (if false). We compute *c1* using right shifting, which is equivalent to dividing by
the specified power of *2* and rounding down (in Python, and also in C under the assumption of a typical two's complement system; see
`assumptions.h` for tests that this is the case). Right shifting by *63* thus maps all
numbers in range *[-2<sup>63</sup>,0)* to *-1*, and numbers in range *[0,2<sup>63</sup>)* to *0*.
Using the facts that *x&0=0* and *x&(-1)=x* (on two's complement systems again), we can write:
```python
if g & 1:
g += x
```
as:
```python
# Compute c2=0 if g is even and c2=-1 if g is odd.
c2 = -(g & 1)
# This masks out x if g is even, and leaves x be if g is odd.
g += x & c2
```
Using the conditional negation trick again we can write:
```python
if g & 1:
if delta > 0:
delta = -delta
```
as:
```python
# Compute c3=-1 if g is odd and delta>0, and 0 otherwise.
c3 = c1 & c2
# Conditionally negate delta based on c3:
delta = (delta ^ c3) - c3
```
Finally:
```python
if g & 1:
if delta > 0:
f += g
```
becomes:
```python
f += g & c3
```
It turns out that this can be implemented more efficiently by applying the substitution
*&eta;=-&delta;*. In this representation, negating *&delta;* corresponds to negating *&eta;*, and incrementing
*&delta;* corresponds to decrementing *&eta;*. This allows us to remove the negation in the *c1*
computation:
```python
# Compute a mask c1 for eta < 0, and compute the conditional negation x of f:
c1 = eta >> 63
x = (f ^ c1) - c1
# Compute a mask c2 for odd g, and conditionally add x to g:
c2 = -(g & 1)
g += x & c2
# Compute a mask c for (eta < 0) and odd (input) g, and use it to conditionally negate eta,
# and add g to f:
c3 = c1 & c2
eta = (eta ^ c3) - c3
f += g & c3
# Incrementing delta corresponds to decrementing eta.
eta -= 1
g >>= 1
```
A variant of divsteps with better worst-case performance can be used instead: starting *&delta;* at
*1/2* instead of *1*. This reduces the worst case number of iterations to *590* for *256*-bit inputs
(which can be shown using convex hull analysis). In this case, the substitution *&zeta;=-(&delta;+1/2)*
is used instead to keep the variable integral. Incrementing *&delta;* by *1* still translates to
decrementing *&zeta;* by *1*, but negating *&delta;* now corresponds to going from *&zeta;* to *-(&zeta;+1)*, or
*~&zeta;*. Doing that conditionally based on *c3* is simply:
```python
...
c3 = c1 & c2
zeta ^= c3
...
```
By replacing the loop in `divsteps_n_matrix` with a variant of the divstep code above (extended to
also apply all *f* operations to *u*, *v* and all *g* operations to *q*, *r*), a constant-time version of
`divsteps_n_matrix` is obtained. The full code will be in section 7.
These bit fiddling tricks can also be used to make the conditional negations and additions in
`update_de` and `normalize` constant-time.
## 6. Variable-time optimizations
In section 5, we modified the `divsteps_n_matrix` function (and a few others) to be constant time.
Constant time operations are only necessary when computing modular inverses of secret data. In
other cases, it slows down calculations unnecessarily. In this section, we will construct a
faster non-constant time `divsteps_n_matrix` function.
To do so, first consider yet another way of writing the inner loop of divstep operations in
`gcd` from section 1. This decomposition is also explained in the paper in section 8.2. We use
the original version with initial *&delta;=1* and *&eta;=-&delta;* here.
```python
for _ in range(N):
if g & 1 and eta < 0:
eta, f, g = -eta, g, -f
if g & 1:
g += f
eta -= 1
g >>= 1
```
Whenever *g* is even, the loop only shifts *g* down and decreases *&eta;*. When *g* ends in multiple zero
bits, these iterations can be consolidated into one step. This requires counting the bottom zero
bits efficiently, which is possible on most platforms; it is abstracted here as the function
`count_trailing_zeros`.
```python
def count_trailing_zeros(v):
"""For a non-zero value v, find z such that v=(d<<z) for some odd d."""
return (v & -v).bit_length() - 1
i = N # divsteps left to do
while True:
# Get rid of all bottom zeros at once. In the first iteration, g may be odd and the following
# lines have no effect (until "if eta < 0").
zeros = min(i, count_trailing_zeros(g))
eta -= zeros
g >>= zeros
i -= zeros
if i == 0:
break
# We know g is odd now
if eta < 0:
eta, f, g = -eta, g, -f
g += f
# g is even now, and the eta decrement and g shift will happen in the next loop.
```
We can now remove multiple bottom *0* bits from *g* at once, but still need a full iteration whenever
there is a bottom *1* bit. In what follows, we will get rid of multiple *1* bits simultaneously as
well.
Observe that as long as *&eta; &geq; 0*, the loop does not modify *f*. Instead, it cancels out bottom
bits of *g* and shifts them out, and decreases *&eta;* and *i* accordingly - interrupting only when *&eta;*
becomes negative, or when *i* reaches *0*. Combined, this is equivalent to adding a multiple of *f* to
*g* to cancel out multiple bottom bits, and then shifting them out.
It is easy to find what that multiple is: we want a number *w* such that *g+w&thinsp;f* has a few bottom
zero bits. If that number of bits is *L*, we want *g+w&thinsp;f mod 2<sup>L</sup> = 0*, or *w = -g/f mod 2<sup>L</sup>*. Since *f*
is odd, such a *w* exists for any *L*. *L* cannot be more than *i* steps (as we'd finish the loop before
doing more) or more than *&eta;+1* steps (as we'd run `eta, f, g = -eta, g, f` at that point), but
apart from that, we're only limited by the complexity of computing *w*.
This code demonstrates how to cancel up to 4 bits per step:
```python
NEGINV16 = [15, 5, 3, 9, 7, 13, 11, 1] # NEGINV16[n//2] = (-n)^-1 mod 16, for odd n
i = N
while True:
zeros = min(i, count_trailing_zeros(g))
eta -= zeros
g >>= zeros
i -= zeros
if i == 0:
break
# We know g is odd now
if eta < 0:
eta, f, g = -eta, g, f
# Compute limit on number of bits to cancel
limit = min(min(eta + 1, i), 4)
# Compute w = -g/f mod 2**limit, using the table value for -1/f mod 2**4. Note that f is
# always odd, so its inverse modulo a power of two always exists.
w = (g * NEGINV16[(f & 15) // 2]) % (2**limit)
# As w = -g/f mod (2**limit), g+w*f mod 2**limit = 0 mod 2**limit.
g += w * f
assert g % (2**limit) == 0
# The next iteration will now shift out at least limit bottom zero bits from g.
```
By using a bigger table more bits can be cancelled at once. The table can also be implemented
as a formula. Several formulas are known for computing modular inverses modulo powers of two;
some can be found in Hacker's Delight second edition by Henry S. Warren, Jr. pages 245-247.
Here we need the negated modular inverse, which is a simple transformation of those:
- Instead of a 3-bit table:
- *-f* or *f ^ 6*
- Instead of a 4-bit table:
- *1 - f(f + 1)*
- *-(f + (((f + 1) & 4) << 1))*
- For larger tables the following technique can be used: if *w=-1/f mod 2<sup>L</sup>*, then *w(w&thinsp;f+2)* is
*-1/f mod 2<sup>2L</sup>*. This allows extending the previous formulas (or tables). In particular we
have this 6-bit function (based on the 3-bit function above):
- *f(f<sup>2</sup> - 2)*
This loop, again extended to also handle *u*, *v*, *q*, and *r* alongside *f* and *g*, placed in
`divsteps_n_matrix`, gives a significantly faster, but non-constant time version.
## 7. Final Python version
All together we need the following functions:
- A way to compute the transition matrix in constant time, using the `divsteps_n_matrix` function
from section 2, but with its loop replaced by a variant of the constant-time divstep from
section 5, extended to handle *u*, *v*, *q*, *r*:
```python
def divsteps_n_matrix(zeta, f, g):
"""Compute zeta and transition matrix t after N divsteps (multiplied by 2^N)."""
u, v, q, r = 1, 0, 0, 1 # start with identity matrix
for _ in range(N):
c1 = zeta >> 63
# Compute x, y, z as conditionally-negated versions of f, u, v.
x, y, z = (f ^ c1) - c1, (u ^ c1) - c1, (v ^ c1) - c1
c2 = -(g & 1)
# Conditionally add x, y, z to g, q, r.
g, q, r = g + (x & c2), q + (y & c2), r + (z & c2)
c1 &= c2 # reusing c1 here for the earlier c3 variable
zeta = (zeta ^ c1) - 1 # inlining the unconditional zeta decrement here
# Conditionally add g, q, r to f, u, v.
f, u, v = f + (g & c1), u + (q & c1), v + (r & c1)
# When shifting g down, don't shift q, r, as we construct a transition matrix multiplied
# by 2^N. Instead, shift f's coefficients u and v up.
g, u, v = g >> 1, u << 1, v << 1
return zeta, (u, v, q, r)
```
- The functions to update *f* and *g*, and *d* and *e*, from section 2 and section 4, with the constant-time
changes to `update_de` from section 5:
```python
def update_fg(f, g, t):
"""Multiply matrix t/2^N with [f, g]."""
u, v, q, r = t
cf, cg = u*f + v*g, q*f + r*g
return cf >> N, cg >> N
def update_de(d, e, t, M, Mi):
"""Multiply matrix t/2^N with [d, e], modulo M."""
u, v, q, r = t
d_sign, e_sign = d >> 257, e >> 257
md, me = (u & d_sign) + (v & e_sign), (q & d_sign) + (r & e_sign)
cd, ce = (u*d + v*e) % 2**N, (q*d + r*e) % 2**N
md -= (Mi*cd + md) % 2**N
me -= (Mi*ce + me) % 2**N
cd, ce = u*d + v*e + M*md, q*d + r*e + M*me
return cd >> N, ce >> N
```
- The `normalize` function from section 4, made constant time as well:
```python
def normalize(sign, v, M):
"""Compute sign*v mod M, where v in (-2*M,M); output in [0,M)."""
v_sign = v >> 257
# Conditionally add M to v.
v += M & v_sign
c = (sign - 1) >> 1
# Conditionally negate v.
v = (v ^ c) - c
v_sign = v >> 257
# Conditionally add M to v again.
v += M & v_sign
return v
```
- And finally the `modinv` function too, adapted to use *&zeta;* instead of *&delta;*, and using the fixed
iteration count from section 5:
```python
def modinv(M, Mi, x):
"""Compute the modular inverse of x mod M, given Mi=1/M mod 2^N."""
zeta, f, g, d, e = -1, M, x, 0, 1
for _ in range((590 + N - 1) // N):
zeta, t = divsteps_n_matrix(zeta, f % 2**N, g % 2**N)
f, g = update_fg(f, g, t)
d, e = update_de(d, e, t, M, Mi)
return normalize(f, d, M)
```
- To get a variable time version, replace the `divsteps_n_matrix` function with one that uses the
divsteps loop from section 5, and a `modinv` version that calls it without the fixed iteration
count:
```python
NEGINV16 = [15, 5, 3, 9, 7, 13, 11, 1] # NEGINV16[n//2] = (-n)^-1 mod 16, for odd n
def divsteps_n_matrix_var(eta, f, g):
"""Compute eta and transition matrix t after N divsteps (multiplied by 2^N)."""
u, v, q, r = 1, 0, 0, 1
i = N
while True:
zeros = min(i, count_trailing_zeros(g))
eta, i = eta - zeros, i - zeros
g, u, v = g >> zeros, u << zeros, v << zeros
if i == 0:
break
if eta < 0:
eta, f, u, v, g, q, r = -eta, g, q, r, -f, -u, -v
limit = min(min(eta + 1, i), 4)
w = (g * NEGINV16[(f & 15) // 2]) % (2**limit)
g, q, r = g + w*f, q + w*u, r + w*v
return eta, (u, v, q, r)
def modinv_var(M, Mi, x):
"""Compute the modular inverse of x mod M, given Mi = 1/M mod 2^N."""
eta, f, g, d, e = -1, M, x, 0, 1
while g != 0:
eta, t = divsteps_n_matrix_var(eta, f % 2**N, g % 2**N)
f, g = update_fg(f, g, t)
d, e = update_de(d, e, t, M, Mi)
return normalize(f, d, Mi)
```

View file

@ -7,11 +7,13 @@ extern "C" {
#include <stddef.h>
/* These rules specify the order of arguments in API calls:
/* Unless explicitly stated all pointer arguments must not be NULL.
*
* The following rules specify the order of arguments in API calls:
*
* 1. Context pointers go first, followed by output arguments, combined
* output/input arguments, and finally input-only arguments.
* 2. Array lengths always immediately the follow the argument whose length
* 2. Array lengths always immediately follow the argument whose length
* they describe, even if this violates rule 1.
* 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated
* later go first. This means: signatures, public nonces, secret nonces,
@ -61,8 +63,9 @@ typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse.
* If you need to convert to a format suitable for storage or transmission,
* use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. To
* compare keys, use secp256k1_ec_pubkey_cmp.
*/
typedef struct {
unsigned char data[64];
@ -127,6 +130,17 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_INLINE inline
# endif
/** When this header is used at build-time the SECP256K1_BUILD define needs to be set
* to correctly setup export attributes and nullness checks. This is normally done
* by secp256k1.c but to guard against this header being included before secp256k1.c
* has had a chance to set the define (e.g. via test harnesses that just includes
* secp256k1.c) we set SECP256K1_NO_BUILD when this header is processed without the
* BUILD define so this condition can be caught.
*/
#ifndef SECP256K1_BUILD
# define SECP256K1_NO_BUILD
#endif
#ifndef SECP256K1_API
# if defined(_WIN32)
# ifdef SECP256K1_BUILD
@ -370,6 +384,21 @@ SECP256K1_API int secp256k1_ec_pubkey_serialize(
unsigned int flags
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Compare two public keys using lexicographic (of compressed serialization) order
*
* Returns: <0 if the first public key is less than the second
* >0 if the first public key is greater than the second
* 0 if the two public keys are equal
* Args: ctx: a secp256k1 context object.
* In: pubkey1: first public key to compare
* pubkey2: second public key to compare
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
const secp256k1_context* ctx,
const secp256k1_pubkey* pubkey1,
const secp256k1_pubkey* pubkey2
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Parse an ECDSA signature in compact (64 bytes) format.
*
* Returns: 1 when the signature could be parsed, 0 otherwise.
@ -452,7 +481,14 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
* 0: incorrect or unparseable signature
* Args: ctx: a secp256k1 context object, initialized for verification.
* In: sig: the signature being verified (cannot be NULL)
* msg32: the 32-byte message hash being verified (cannot be NULL)
* msghash32: the 32-byte message hash being verified (cannot be NULL).
* The verifier must make sure to apply a cryptographic
* hash function to the message by itself and not accept an
* msghash32 value directly. Otherwise, it would be easy to
* create a "valid" signature without knowledge of the
* secret key. See also
* https://bitcoin.stackexchange.com/a/81116/35586 for more
* background on this topic.
* pubkey: pointer to an initialized public key to verify with (cannot be NULL)
*
* To avoid accepting malleable signatures, only ECDSA signatures in lower-S
@ -467,7 +503,7 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
const secp256k1_context* ctx,
const secp256k1_ecdsa_signature *sig,
const unsigned char *msg32,
const unsigned char *msghash32,
const secp256k1_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
@ -532,12 +568,12 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* In: msghash32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
*
* The created signature is always in lower-S form. See
* secp256k1_ecdsa_signature_normalize for more details.
@ -545,7 +581,7 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def
SECP256K1_API int secp256k1_ecdsa_sign(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature *sig,
const unsigned char *msg32,
const unsigned char *msghash32,
const unsigned char *seckey,
secp256k1_nonce_function noncefp,
const void *ndata
@ -626,7 +662,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
* invalid according to secp256k1_ec_seckey_verify, this
* function returns 0. seckey will be set to some unspecified
* value if this function returns 0. (cannot be NULL)
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128) (cannot be NULL).
@ -634,7 +670,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
const secp256k1_context* ctx,
unsigned char *seckey,
const unsigned char *tweak
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in
@ -642,7 +678,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
const secp256k1_context* ctx,
unsigned char *seckey,
const unsigned char *tweak
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a public key by adding tweak times the generator to it.
@ -654,7 +690,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
* (cannot be NULL).
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
* invalid value if this function returns 0 (cannot be NULL).
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128) (cannot be NULL).
@ -662,7 +698,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
const secp256k1_context* ctx,
secp256k1_pubkey *pubkey,
const unsigned char *tweak
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a secret key by multiplying it by a tweak.
@ -673,7 +709,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
* invalid according to secp256k1_ec_seckey_verify, this
* function returns 0. seckey will be set to some unspecified
* value if this function returns 0. (cannot be NULL)
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128) (cannot be NULL).
@ -681,7 +717,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
const secp256k1_context* ctx,
unsigned char *seckey,
const unsigned char *tweak
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in
@ -689,7 +725,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
const secp256k1_context* ctx,
unsigned char *seckey,
const unsigned char *tweak
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a public key by multiplying it by a tweak value.
@ -699,7 +735,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
* (cannot be NULL).
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
* invalid value if this function returns 0 (cannot be NULL).
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128) (cannot be NULL).
@ -707,7 +743,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
const secp256k1_context* ctx,
secp256k1_pubkey *pubkey,
const unsigned char *tweak
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Updates the context randomization to protect against side-channel leakage.
@ -757,6 +793,31 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
size_t n
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Compute a tagged hash as defined in BIP-340.
*
* This is useful for creating a message hash and achieving domain separation
* through an application-specific tag. This function returns
* SHA256(SHA256(tag)||SHA256(tag)||msg). Therefore, tagged hash
* implementations optimized for a specific tag can precompute the SHA256 state
* after hashing the tag hashes.
*
* Returns 0 if the arguments are invalid and 1 otherwise.
* Args: ctx: pointer to a context object
* Out: hash32: pointer to a 32-byte array to store the resulting hash
* In: tag: pointer to an array containing the tag
* taglen: length of the tag array
* msg: pointer to an array containing the message
* msglen: length of the message array
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256(
const secp256k1_context* ctx,
unsigned char *hash32,
const unsigned char *tag,
size_t taglen,
const unsigned char *msg,
size_t msglen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,162 @@
#ifndef SECP256K1_ECDSA_ADAPTOR_H
#define SECP256K1_ECDSA_ADAPTOR_H
#ifdef __cplusplus
extern "C" {
#endif
/** This module implements single signer ECDSA adaptor signatures following
* "One-Time Verifiably Encrypted Signatures A.K.A. Adaptor Signatures" by
* Lloyd Fournier
* (https://lists.linuxfoundation.org/pipermail/lightning-dev/2019-November/002316.html
* and https://github.com/LLFourn/one-time-VES/blob/master/main.pdf).
*
* WARNING! DANGER AHEAD!
* As mentioned in Lloyd Fournier's paper, the adaptor signature leaks the
* Elliptic-curve DiffieHellman (ECDH) key between the signing key and the
* encryption key. This is not a problem for ECDSA adaptor signatures
* themselves, but may result in a complete loss of security when they are
* composed with other schemes. More specifically, let us refer to the
* signer's public key as X = x*G, and to the encryption key as Y = y*G.
* Given X, Y and the adaptor signature, it is trivial to compute Y^x = X^y.
*
* A defense is to not reuse the signing key of ECDSA adaptor signatures in
* protocols that rely on the hardness of the CDH problem, e.g., Diffie-Hellman
* key exchange and ElGamal encryption. In general, it is a well-established
* cryptographic practice to seperate keys for different purposes whenever
* possible.
*/
/** A pointer to a function to deterministically generate a nonce.
*
* Same as secp256k1_nonce_function_hardened with the exception of using the
* compressed 33-byte encoding for the pubkey argument.
*
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to
* return an error.
* Out: nonce32: pointer to a 32-byte array to be filled by the function
* In: msg32: the 32-byte message hash being verified
* key32: pointer to a 32-byte secret key
* pk33: the 33-byte serialized pubkey corresponding to key32
* algo: pointer to an array describing the signature algorithm
* algolen: the length of the algo array
* data: arbitrary data pointer that is passed through
*
* Except for test cases, this function should compute some cryptographic hash of
* the message, the key, the pubkey, the algorithm description, and data.
*/
typedef int (*secp256k1_nonce_function_hardened_ecdsa_adaptor)(
unsigned char *nonce32,
const unsigned char *msg32,
const unsigned char *key32,
const unsigned char *pk33,
const unsigned char *algo,
size_t algolen,
void *data
);
/** A modified BIP-340 nonce generation function. If a data pointer is passed, it is
* assumed to be a pointer to 32 bytes of auxiliary random data as defined in BIP-340.
* The hash will be tagged with algo after removing all terminating null bytes.
*/
SECP256K1_API extern const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor;
/** Encrypted Signing
*
* Creates an adaptor signature, which includes a proof to verify the adaptor
* signature.
* WARNING: Make sure you have read and understood the WARNING at the top of
* this file and applied the suggested countermeasures.
*
* Returns: 1 on success, 0 on failure
* Args: ctx: a secp256k1 context object, initialized for signing
* Out: adaptor_sig162: pointer to 162 byte to store the returned signature
* In: seckey32: pointer to 32 byte secret key that will be used for
* signing
* enckey: pointer to the encryption public key
* msg32: pointer to the 32-byte message hash to sign
* noncefp: pointer to a nonce generation function. If NULL,
* secp256k1_nonce_function_ecdsa_adaptor is used
* ndata: pointer to arbitrary data used by the nonce generation
* function (can be NULL). If it is non-NULL and
* secp256k1_nonce_function_ecdsa_adaptor is used, then
* ndata must be a pointer to 32-byte auxiliary randomness
* as per BIP-340.
*/
SECP256K1_API int secp256k1_ecdsa_adaptor_encrypt(
const secp256k1_context* ctx,
unsigned char *adaptor_sig162,
unsigned char *seckey32,
const secp256k1_pubkey *enckey,
const unsigned char *msg32,
secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp,
void *ndata
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Encryption Verification
*
* Verifies that the adaptor decryption key can be extracted from the adaptor signature
* and the completed ECDSA signature.
*
* Returns: 1 on success, 0 on failure
* Args: ctx: a secp256k1 context object, initialized for verification
* In: adaptor_sig162: pointer to 162-byte signature to verify
* pubkey: pointer to the public key corresponding to the secret key
* used for signing
* msg32: pointer to the 32-byte message hash being verified
* enckey: pointer to the adaptor encryption public key
*/
SECP256K1_API int secp256k1_ecdsa_adaptor_verify(
const secp256k1_context* ctx,
const unsigned char *adaptor_sig162,
const secp256k1_pubkey *pubkey,
const unsigned char *msg32,
const secp256k1_pubkey *enckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Signature Decryption
*
* Derives an ECDSA signature from an adaptor signature and an adaptor decryption key.
*
* Returns: 1 on success, 0 on failure
* Args: ctx: a secp256k1 context object
* Out: sig: pointer to the ECDSA signature to create
* In: deckey32: pointer to 32-byte decryption secret key for the adaptor
* encryption public key
* adaptor_sig162: pointer to 162-byte adaptor sig
*/
SECP256K1_API int secp256k1_ecdsa_adaptor_decrypt(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature *sig,
const unsigned char *deckey32,
const unsigned char *adaptor_sig162
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Decryption Key Recovery
*
* Extracts the adaptor decryption key from the complete signature and the adaptor
* signature.
*
* Returns: 1 on success, 0 on failure
* Args: ctx: a secp256k1 context object, initialized for signing
* Out: deckey32: pointer to 32-byte adaptor decryption key for the adaptor
* encryption public key
* In: sig: pointer to ECDSA signature to recover the adaptor decryption
* key from
* adaptor_sig162: pointer to adaptor signature to recover the adaptor
* decryption key from
* enckey: pointer to the adaptor encryption public key
*/
SECP256K1_API int secp256k1_ecdsa_adaptor_recover(
const secp256k1_context* ctx,
unsigned char *deckey32,
const secp256k1_ecdsa_signature *sig,
const unsigned char *adaptor_sig162,
const secp256k1_pubkey *enckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
#ifdef __cplusplus
}
#endif
#endif /* SECP256K1_ECDSA_ADAPTOR_H */

View file

@ -0,0 +1,234 @@
#ifndef SECP256K1_ECDSA_S2C_H
#define SECP256K1_ECDSA_S2C_H
#include "secp256k1.h"
/** This module implements the sign-to-contract scheme for ECDSA signatures, as
* well as the "ECDSA Anti-Exfil Protocol" that is based on sign-to-contract
* and is specified further down. The sign-to-contract scheme allows creating a
* signature that also commits to some data. This works by offsetting the public
* nonce point of the signature R by hash(R, data)*G where G is the secp256k1
* group generator.
*/
#ifdef __cplusplus
extern "C" {
#endif
/** Data structure that holds a sign-to-contract ("s2c") opening information.
* Sign-to-contract allows a signer to commit to some data as part of a signature. It
* can be used as an Out-argument in certain signing functions.
*
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use secp256k1_ecdsa_s2c_opening_serialize and secp256k1_ecdsa_s2c_opening_parse.
*/
typedef struct {
unsigned char data[64];
} secp256k1_ecdsa_s2c_opening;
/** Parse a sign-to-contract opening.
*
* Returns: 1 if the opening could be parsed
* 0 if the opening could not be parsed
* Args: ctx: a secp256k1 context object.
* Out: opening: pointer to an opening object. If 1 is returned, it is set to a
* parsed version of input. If not, its value is unspecified.
* In: input33: pointer to 33-byte array with a serialized opening
*
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_parse(
const secp256k1_context* ctx,
secp256k1_ecdsa_s2c_opening* opening,
const unsigned char* input33
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize a sign-to-contract opening into a byte sequence.
*
* Returns: 1 if the opening was successfully serialized.
* 0 if the opening could not be serialized
* Args: ctx: a secp256k1 context object
* Out: output33: pointer to a 33-byte array to place the serialized opening in
* In: opening: a pointer to an initialized `secp256k1_ecdsa_s2c_opening`
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_serialize(
const secp256k1_context* ctx,
unsigned char* output33,
const secp256k1_ecdsa_s2c_opening* opening
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Same as secp256k1_ecdsa_sign, but s2c_data32 is committed to inside the nonce
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the private key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* s2c_opening: if non-NULL, pointer to an secp256k1_ecdsa_s2c_opening structure to populate
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* s2c_data32: pointer to a 32-byte data to commit to in the nonce (cannot be NULL)
*/
SECP256K1_API int secp256k1_ecdsa_s2c_sign(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
secp256k1_ecdsa_s2c_opening* s2c_opening,
const unsigned char* msg32,
const unsigned char* seckey,
const unsigned char* s2c_data32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
/** Verify a sign-to-contract commitment.
*
* Returns: 1: the signature contains a commitment to data32 (though it does
* not necessarily need to be a valid siganture!)
* 0: incorrect opening
* Args: ctx: a secp256k1 context object, initialized for verification.
* In: sig: the signature containing the sign-to-contract commitment (cannot be NULL)
* data32: the 32-byte data that was committed to (cannot be NULL)
* opening: pointer to the opening created during signing (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_verify_commit(
const secp256k1_context* ctx,
const secp256k1_ecdsa_signature *sig,
const unsigned char *data32,
const secp256k1_ecdsa_s2c_opening *opening
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** ECDSA Anti-Exfil Protocol
*
* The ecdsa_anti_exfil_* functions can be used to prevent a signing device from
* exfiltrating the secret signing keys through biased signature nonces. The general
* idea is that a host provides additional randomness to the signing device client
* and the client commits to the randomness in the nonce using sign-to-contract.
*
* The following scheme is described by Stepan Snigirev here:
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-February/017655.html
* and by Pieter Wuille (as "Scheme 6") here:
* https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2020-March/017667.html
*
* In order to ensure the host cannot trick the signing device into revealing its
* keys, or the signing device to bias the nonce despite the host's contributions,
* the host and client must engage in a commit-reveal protocol as follows:
* 1. The host draws randomness `rho` and computes a sha256 commitment to it using
* `secp256k1_ecdsa_anti_exfil_host_commit`. It sends this to the signing device.
* 2. The signing device computes a public nonce `R` using the host's commitment
* as auxiliary randomness, using `secp256k1_ecdsa_anti_exfil_signer_commit`.
* The signing device sends the resulting `R` to the host as a s2c_opening.
*
* If, at any point from this step onward, the hardware device fails, it is
* okay to restart the protocol using **exactly the same `rho`** and checking
* that the hardware device proposes **exactly the same** `R`. Otherwise, the
* hardware device may be selectively aborting and thereby biasing the set of
* nonces that are used in actual signatures.
*
* It takes many (>100) such aborts before there is a plausible attack, given
* current knowledge in 2020. However such aborts accumulate even across a total
* replacement of all relevant devices (but not across replacement of the actual
* signing keys with new independently random ones).
*
* In case the hardware device cannot be made to sign with the given `rho`, `R`
* pair, wallet authors should alert the user and present a very scary message
* implying that if this happens more than even a few times, say 20 or more times
* EVER, they should change hardware vendors and perhaps sweep their coins.
*
* 3. The host replies with `rho` generated in step 1.
* 4. The device signs with `secp256k1_anti_exfil_sign`, using `rho` as `host_data32`,
* and sends the signature to the host.
* 5. The host verifies that the signature's public nonce matches the opening from
* step 2 and its original randomness `rho`, using `secp256k1_anti_exfil_host_verify`.
*
* Rationale:
* - The reason for having a host commitment is to allow the signing device to
* deterministically derive a unique nonce even if the host restarts the protocol
* using the same message and keys. Otherwise the signer might reuse the original
* nonce in two iterations of the protocol with different `rho`, which leaks the
* the secret key.
* - The signer does not need to check that the host commitment matches the host's
* claimed `rho`. Instead it re-derives the commitment (and its original `R`) from
* the provided `rho`. If this differs from the original commitment, the result
* will be an invalid `s2c_opening`, but since `R` was unique there is no risk to
* the signer's secret keys. Because of this, the signing device does not need to
* maintain any state about the progress of the protocol.
*/
/** Create the initial host commitment to `rho`. Part of the ECDSA Anti-Exfil Protocol.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: rand_commitment32: pointer to 32-byte array to store the returned commitment (cannot be NULL)
* In: rand32: the 32-byte randomness to commit to (cannot be NULL). It must come from
* a cryptographically secure RNG. As per the protocol, this value must not
* be revealed to the client until after the host has received the client
* commitment.
*/
SECP256K1_API int secp256k1_ecdsa_anti_exfil_host_commit(
const secp256k1_context* ctx,
unsigned char* rand_commitment32,
const unsigned char* rand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Compute signer's original nonce. Part of the ECDSA Anti-Exfil Protocol.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: s2c_opening: pointer to an s2c_opening where the signer's public nonce will be
* placed. (cannot be NULL)
* In: msg32: the 32-byte message hash to be signed (cannot be NULL)
* seckey32: the 32-byte secret key used for signing (cannot be NULL)
* rand_commitment32: the 32-byte randomness commitment from the host (cannot be NULL)
*/
SECP256K1_API int secp256k1_ecdsa_anti_exfil_signer_commit(
const secp256k1_context* ctx,
secp256k1_ecdsa_s2c_opening* s2c_opening,
const unsigned char* msg32,
const unsigned char* seckey32,
const unsigned char* rand_commitment32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Same as secp256k1_ecdsa_sign, but commits to host randomness in the nonce. Part of the
* ECDSA Anti-Exfil Protocol.
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the private key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* host_data32: pointer to 32-byte host-provided randomness (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_anti_exfil_sign(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
const unsigned char* msg32,
const unsigned char* seckey,
const unsigned char* host_data32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Verify a signature was correctly constructed using the ECDSA Anti-Exfil Protocol.
*
* Returns: 1: the signature is valid and contains a commitment to host_data32
* 0: incorrect opening
* Args: ctx: a secp256k1 context object, initialized for verification.
* In: sig: the signature produced by the signer (cannot be NULL)
* msghash32: the 32-byte message hash being verified (cannot be NULL)
* pubkey: pointer to the signer's public key (cannot be NULL)
* host_data32: the 32-byte data provided by the host (cannot be NULL)
* opening: the s2c opening provided by the signer (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_anti_exfil_host_verify(
const secp256k1_context* ctx,
const secp256k1_ecdsa_signature *sig,
const unsigned char *msg32,
const secp256k1_pubkey *pubkey,
const unsigned char *host_data32,
const secp256k1_ecdsa_s2c_opening *opening
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
#ifdef __cplusplus
}
#endif
#endif /* SECP256K1_ECDSA_S2C_H */

View file

@ -15,9 +15,9 @@ extern "C" {
* The exact representation of data inside is implementation defined and not
* guaranteed to be portable between different platforms or versions. It is
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
* If you need to convert to a format suitable for storage, transmission, or
* comparison, use secp256k1_xonly_pubkey_serialize and
* secp256k1_xonly_pubkey_parse.
* If you need to convert to a format suitable for storage, transmission, use
* use secp256k1_xonly_pubkey_serialize and secp256k1_xonly_pubkey_parse. To
* compare keys, use secp256k1_xonly_pubkey_cmp.
*/
typedef struct {
unsigned char data[64];
@ -67,6 +67,21 @@ SECP256K1_API int secp256k1_xonly_pubkey_serialize(
const secp256k1_xonly_pubkey* pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Compare two x-only public keys using lexicographic order
*
* Returns: <0 if the first public key is less than the second
* >0 if the first public key is greater than the second
* 0 if the two public keys are equal
* Args: ctx: a secp256k1 context object.
* In: pubkey1: first public key to compare
* pubkey2: second public key to compare
*/
SECP256K1_API int secp256k1_xonly_pubkey_cmp(
const secp256k1_context* ctx,
const secp256k1_xonly_pubkey* pk1,
const secp256k1_xonly_pubkey* pk2
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
*
* Returns: 1 if the public key was successfully converted
@ -151,6 +166,20 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Sorts xonly public keys according to secp256k1_xonly_pubkey_cmp
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
*
* Args: ctx: pointer to a context object
* In: pubkeys: array of pointers to pubkeys to sort
* n_pubkeys: number of elements in the pubkeys array
*/
SECP256K1_API int secp256k1_xonly_sort(
const secp256k1_context* ctx,
const secp256k1_xonly_pubkey **pubkeys,
size_t n_pubkeys
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Compute the keypair for a secret key.
*
* Returns: 1: secret was valid, keypair is ready to use
@ -165,6 +194,19 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Get the secret key from a keypair.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
* Args: ctx: pointer to a context object (cannot be NULL)
* Out: seckey: pointer to a 32-byte buffer for the secret key (cannot be NULL)
* In: keypair: pointer to a keypair (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
const secp256k1_context* ctx,
unsigned char *seckey,
const secp256k1_keypair *keypair
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Get the public key from a keypair.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.

View file

@ -82,7 +82,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate(
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate_blinded(
const secp256k1_context* ctx,
secp256k1_generator* gen,
const unsigned char *key32,
const unsigned char *seed32,
const unsigned char *blind32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);

View file

@ -25,6 +25,8 @@ extern "C" {
* magic: Set during initialization in `pubkey_combine` to allow
* detecting an uninitialized object.
* pk_hash: The 32-byte hash of the original public keys
* second_pk: Serialized x-coordinate of the second public key in the list.
* Filled with zeros if there is none.
* pk_parity: Whether the MuSig-aggregated point was negated when
* converting it to the combined xonly pubkey.
* is_tweaked: Whether the combined pubkey was tweaked
@ -35,6 +37,7 @@ extern "C" {
typedef struct {
uint64_t magic;
unsigned char pk_hash[32];
unsigned char second_pk[32];
int pk_parity;
int is_tweaked;
unsigned char tweak[32];
@ -94,7 +97,7 @@ typedef struct {
* The workflow for this structure is as follows:
*
* 1. This structure is initialized with `musig_session_init` or
* `musig_session_init_verifier`, which set the `index` field, and zero out
* `musig_session_init_verifier`, which initializes
* all other fields. The public session is initialized with the signers'
* nonce_commitments.
*
@ -111,14 +114,12 @@ typedef struct {
*
* Fields:
* present: indicates whether the signer's nonce is set
* index: index of the signer in the MuSig key aggregation
* nonce: public nonce, must be a valid curvepoint if the signer is `present`
* nonce_commitment: commitment to the nonce, or all-bits zero if a commitment
* has not yet been set
*/
typedef struct {
int present;
uint32_t index;
secp256k1_xonly_pubkey nonce;
unsigned char nonce_commitment[32];
} secp256k1_musig_session_signer_data;
@ -137,8 +138,14 @@ typedef struct {
} secp256k1_musig_partial_signature;
/** Computes a combined public key and the hash of the given public keys.
*
* Different orders of `pubkeys` result in different `combined_pk`s.
*
* The pubkeys can be sorted before combining with `secp256k1_xonly_sort` which
* ensures the same resulting `combined_pk` for the same multiset of pubkeys.
* This is useful to do before pubkey_combine, such that the order of pubkeys
* does not affect the combined public key.
*
* Returns: 1 if the public keys were successfully combined, 0 otherwise
* Args: ctx: pointer to a context object initialized for verification
* (cannot be NULL)
@ -147,9 +154,9 @@ typedef struct {
* Out: combined_pk: the MuSig-combined xonly public key (cannot be NULL)
* pre_session: if non-NULL, pointer to a musig_pre_session struct to be used in
* `musig_session_init` or `musig_pubkey_tweak_add`.
* In: pubkeys: input array of public keys to combine. The order is important;
* a different order will result in a different combined public
* key (cannot be NULL)
* In: pubkeys: input array of pointers to public keys to combine. The order
* is important; a different order will result in a different
* combined public key (cannot be NULL)
* n_pubkeys: length of pubkeys array. Must be greater than 0.
*/
SECP256K1_API int secp256k1_musig_pubkey_combine(
@ -157,7 +164,7 @@ SECP256K1_API int secp256k1_musig_pubkey_combine(
secp256k1_scratch_space *scratch,
secp256k1_xonly_pubkey *combined_pk,
secp256k1_musig_pre_session *pre_session,
const secp256k1_xonly_pubkey *pubkeys,
const secp256k1_xonly_pubkey * const* pubkeys,
size_t n_pubkeys
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
@ -221,8 +228,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_tweak_add(
* `musig_pubkey_tweak_add` (cannot be NULL).
* n_signers: length of signers array. Number of signers participating in
* the MuSig. Must be greater than 0 and at most 2^32 - 1.
* my_index: index of this signer in the signers array. Must be less
* than `n_signers`.
* seckey: the signer's 32-byte secret key (cannot be NULL)
*/
SECP256K1_API int secp256k1_musig_session_init(
@ -235,7 +240,6 @@ SECP256K1_API int secp256k1_musig_session_init(
const secp256k1_xonly_pubkey *combined_pk,
const secp256k1_musig_pre_session *pre_session,
size_t n_signers,
size_t my_index,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(11);

View file

@ -197,7 +197,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
* In/Out: blind_out: storage for the 32-byte blinding factor used for the commitment
* value_out: pointer to an unsigned int64 which has the exact value of the commitment.
* message_out: pointer to a 4096 byte character array to receive message data from the proof author.
* outlen: length of message data written to message_out.
* outlen: length of message data written to message_out. This is generally not equal to the
* msg_len used by the signer. However, for all i with msg_len <= i < outlen, it is
* guaranteed that message_out[i] == 0.
* min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
* max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
*/

View file

@ -71,17 +71,17 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* In: msghash32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
*/
SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
const secp256k1_context* ctx,
secp256k1_ecdsa_recoverable_signature *sig,
const unsigned char *msg32,
const unsigned char *msghash32,
const unsigned char *seckey,
secp256k1_nonce_function noncefp,
const void *ndata
@ -91,16 +91,16 @@ SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
*
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
* 0: otherwise.
* Args: ctx: pointer to a context object, initialized for verification (cannot be NULL)
* Out: pubkey: pointer to the recovered public key (cannot be NULL)
* In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL)
* msg32: the 32-byte message hash assumed to be signed (cannot be NULL)
* Args: ctx: pointer to a context object, initialized for verification (cannot be NULL)
* Out: pubkey: pointer to the recovered public key (cannot be NULL)
* In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL)
* msghash32: the 32-byte message hash assumed to be signed (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
const secp256k1_context* ctx,
secp256k1_pubkey *pubkey,
const secp256k1_ecdsa_recoverable_signature *sig,
const unsigned char *msg32
const unsigned char *msghash32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
#ifdef __cplusplus

View file

@ -23,24 +23,29 @@ extern "C" {
*
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to
* return an error.
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
* In: msg32: the 32-byte message hash being verified (will not be NULL)
* key32: pointer to a 32-byte secret key (will not be NULL)
* xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
* (will not be NULL)
* algo16: pointer to a 16-byte array describing the signature
* algorithm (will not be NULL).
* data: Arbitrary data pointer that is passed through.
* Out: nonce32: pointer to a 32-byte array to be filled by the function
* In: msg: the message being verified. Is NULL if and only if msglen
* is 0.
* msglen: the length of the message
* key32: pointer to a 32-byte secret key (will not be NULL)
* xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
* (will not be NULL)
* algo: pointer to an array describing the signature
* algorithm (will not be NULL)
* algolen: the length of the algo array
* data: arbitrary data pointer that is passed through
*
* Except for test cases, this function should compute some cryptographic hash of
* the message, the key, the pubkey, the algorithm description, and data.
*/
typedef int (*secp256k1_nonce_function_hardened)(
unsigned char *nonce32,
const unsigned char *msg32,
const unsigned char *msg,
size_t msglen,
const unsigned char *key32,
const unsigned char *xonly_pk32,
const unsigned char *algo16,
const unsigned char *algo,
size_t algolen,
void *data
);
@ -50,59 +55,113 @@ typedef int (*secp256k1_nonce_function_hardened)(
*
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
* auxiliary random data as defined in BIP-340. If the data pointer is NULL,
* schnorrsig_sign does not produce BIP-340 compliant signatures. The algo16
* argument must be non-NULL, otherwise the function will fail and return 0.
* The hash will be tagged with algo16 after removing all terminating null
* bytes. Therefore, to create BIP-340 compliant signatures, algo16 must be set
* to "BIP0340/nonce\0\0\0"
* the nonce derivation procedure follows BIP-340 by setting the auxiliary
* random data to zero. The algo argument must be non-NULL, otherwise the
* function will fail and return 0. The hash will be tagged with algo.
* Therefore, to create BIP-340 compliant signatures, algo must be set to
* "BIP0340/nonce" and algolen to 13.
*/
SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
/** Data structure that contains additional arguments for schnorrsig_sign_custom.
*
* A schnorrsig_extraparams structure object can be initialized correctly by
* setting it to SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT.
*
* Members:
* magic: set to SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC at initialization
* and has no other function than making sure the object is
* initialized.
* noncefp: pointer to a nonce generation function. If NULL,
* secp256k1_nonce_function_bip340 is used
* ndata: pointer to arbitrary data used by the nonce generation function
* (can be NULL). If it is non-NULL and
* secp256k1_nonce_function_bip340 is used, then ndata must be a
* pointer to 32-byte auxiliary randomness as per BIP-340.
*/
typedef struct {
unsigned char magic[4];
secp256k1_nonce_function_hardened noncefp;
void* ndata;
} secp256k1_schnorrsig_extraparams;
#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC { 0xda, 0x6f, 0xb3, 0x8c }
#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT {\
SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC,\
NULL,\
NULL\
}
/** Create a Schnorr signature.
*
* Does _not_ strictly follow BIP-340 because it does not verify the resulting
* signature. Instead, you can manually use secp256k1_schnorrsig_verify and
* abort if it fails.
*
* Otherwise BIP-340 compliant if the noncefp argument is NULL or
* secp256k1_nonce_function_bip340 and the ndata argument is 32-byte auxiliary
* randomness.
* This function only signs 32-byte messages. If you have messages of a
* different size (or the same size but without a context-specific tag
* prefix), it is recommended to create a 32-byte message hash with
* secp256k1_tagged_sha256 and then sign the hash. Tagged hashing allows
* providing an context-specific tag for domain separation. This prevents
* signatures from being valid in multiple contexts by accident.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Out: sig64: pointer to a 64-byte array to store the serialized signature (cannot be NULL)
* In: msg32: the 32-byte message being signed (cannot be NULL)
* keypair: pointer to an initialized keypair (cannot be NULL)
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bip340 is used
* ndata: pointer to arbitrary data used by the nonce generation
* function (can be NULL). If it is non-NULL and
* secp256k1_nonce_function_bip340 is used, then ndata must be a
* pointer to 32-byte auxiliary randomness as per BIP-340.
* aux_rand32: 32 bytes of fresh randomness. While recommended to provide
* this, it is only supplemental to security and can be NULL. See
* BIP-340 "Default Signing" for a full explanation of this
* argument and for guidance if randomness is expensive.
*/
SECP256K1_API int secp256k1_schnorrsig_sign(
const secp256k1_context* ctx,
unsigned char *sig64,
const unsigned char *msg32,
const secp256k1_keypair *keypair,
secp256k1_nonce_function_hardened noncefp,
void *ndata
unsigned char *aux_rand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Create a Schnorr signature with a more flexible API.
*
* Same arguments as secp256k1_schnorrsig_sign except that it allows signing
* variable length messages and accepts a pointer to an extraparams object that
* allows customizing signing by passing additional arguments.
*
* Creates the same signatures as schnorrsig_sign if msglen is 32 and the
* extraparams.ndata is the same as aux_rand32.
*
* In: msg: the message being signed. Can only be NULL if msglen is 0.
* msglen: length of the message
* extraparams: pointer to a extraparams object (can be NULL)
*/
SECP256K1_API int secp256k1_schnorrsig_sign_custom(
const secp256k1_context* ctx,
unsigned char *sig64,
const unsigned char *msg,
size_t msglen,
const secp256k1_keypair *keypair,
secp256k1_schnorrsig_extraparams *extraparams
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5);
/** Verify a Schnorr signature.
*
* Returns: 1: correct signature
* 0: incorrect signature
* Args: ctx: a secp256k1 context object, initialized for verification.
* In: sig64: pointer to the 64-byte signature to verify (cannot be NULL)
* msg32: the 32-byte message being verified (cannot be NULL)
* msg: the message being verified. Can only be NULL if msglen is 0.
* msglen: length of the message
* pubkey: pointer to an x-only public key to verify with (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
const secp256k1_context* ctx,
const unsigned char *sig64,
const unsigned char *msg32,
const unsigned char *msg,
size_t msglen,
const secp256k1_xonly_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(5);
#ifdef __cplusplus
}

0
obj/.gitignore vendored
View file

View file

@ -1,9 +1,4 @@
# Define field size and field
P = 2^256 - 2^32 - 977
F = GF(P)
BETA = F(0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee)
assert(BETA != F(1) and BETA^3 == F(1))
load("secp256k1_params.sage")
orders_done = set()
results = {}

View file

@ -0,0 +1,114 @@
""" Generates the constants used in secp256k1_scalar_split_lambda.
See the comments for secp256k1_scalar_split_lambda in src/scalar_impl.h for detailed explanations.
"""
load("secp256k1_params.sage")
def inf_norm(v):
"""Returns the infinity norm of a vector."""
return max(map(abs, v))
def gauss_reduction(i1, i2):
v1, v2 = i1.copy(), i2.copy()
while True:
if inf_norm(v2) < inf_norm(v1):
v1, v2 = v2, v1
# This is essentially
# m = round((v1[0]*v2[0] + v1[1]*v2[1]) / (inf_norm(v1)**2))
# (rounding to the nearest integer) without relying on floating point arithmetic.
m = ((v1[0]*v2[0] + v1[1]*v2[1]) + (inf_norm(v1)**2) // 2) // (inf_norm(v1)**2)
if m == 0:
return v1, v2
v2[0] -= m*v1[0]
v2[1] -= m*v1[1]
def find_split_constants_gauss():
"""Find constants for secp256k1_scalar_split_lamdba using gauss reduction."""
(v11, v12), (v21, v22) = gauss_reduction([0, N], [1, int(LAMBDA)])
# We use related vectors in secp256k1_scalar_split_lambda.
A1, B1 = -v21, -v11
A2, B2 = v22, -v21
return A1, B1, A2, B2
def find_split_constants_explicit_tof():
"""Find constants for secp256k1_scalar_split_lamdba using the trace of Frobenius.
See Benjamin Smith: "Easy scalar decompositions for efficient scalar multiplication on
elliptic curves and genus 2 Jacobians" (https://eprint.iacr.org/2013/672), Example 2
"""
assert P % 3 == 1 # The paper says P % 3 == 2 but that appears to be a mistake, see [10].
assert C.j_invariant() == 0
t = C.trace_of_frobenius()
c = Integer(sqrt((4*P - t**2)/3))
A1 = Integer((t - c)/2 - 1)
B1 = c
A2 = Integer((t + c)/2 - 1)
B2 = Integer(1 - (t - c)/2)
# We use a negated b values in secp256k1_scalar_split_lambda.
B1, B2 = -B1, -B2
return A1, B1, A2, B2
A1, B1, A2, B2 = find_split_constants_explicit_tof()
# For extra fun, use an independent method to recompute the constants.
assert (A1, B1, A2, B2) == find_split_constants_gauss()
# PHI : Z[l] -> Z_n where phi(a + b*l) == a + b*lambda mod n.
def PHI(a,b):
return Z(a + LAMBDA*b)
# Check that (A1, B1) and (A2, B2) are in the kernel of PHI.
assert PHI(A1, B1) == Z(0)
assert PHI(A2, B2) == Z(0)
# Check that the parallelogram generated by (A1, A2) and (B1, B2)
# is a fundamental domain by containing exactly N points.
# Since the LHS is the determinant and N != 0, this also checks that
# (A1, A2) and (B1, B2) are linearly independent. By the previous
# assertions, (A1, A2) and (B1, B2) are a basis of the kernel.
assert A1*B2 - B1*A2 == N
# Check that their components are short enough.
assert (A1 + A2)/2 < sqrt(N)
assert B1 < sqrt(N)
assert B2 < sqrt(N)
G1 = round((2**384)*B2/N)
G2 = round((2**384)*(-B1)/N)
def rnddiv2(v):
if v & 1:
v += 1
return v >> 1
def scalar_lambda_split(k):
"""Equivalent to secp256k1_scalar_lambda_split()."""
c1 = rnddiv2((k * G1) >> 383)
c2 = rnddiv2((k * G2) >> 383)
c1 = (c1 * -B1) % N
c2 = (c2 * -B2) % N
r2 = (c1 + c2) % N
r1 = (k + r2 * -LAMBDA) % N
return (r1, r2)
# The result of scalar_lambda_split can depend on the representation of k (mod n).
SPECIAL = (2**383) // G2 + 1
assert scalar_lambda_split(SPECIAL) != scalar_lambda_split(SPECIAL + N)
print(' A1 =', hex(A1))
print(' -B1 =', hex(-B1))
print(' A2 =', hex(A2))
print(' -B2 =', hex(-B2))
print(' =', hex(Z(-B2)))
print(' -LAMBDA =', hex(-LAMBDA))
print(' G1 =', hex(G1))
print(' G2 =', hex(G2))

View file

@ -42,7 +42,7 @@
# as we assume that all constraints in it are complementary with each other.
#
# Based on the sage verification scripts used in the Explicit-Formulas Database
# by Tanja Lange and others, see http://hyperelliptic.org/EFD
# by Tanja Lange and others, see https://hyperelliptic.org/EFD
class fastfrac:
"""Fractions over rings."""

View file

@ -0,0 +1,36 @@
"""Prime order of finite field underlying secp256k1 (2^256 - 2^32 - 977)"""
P = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
"""Finite field underlying secp256k1"""
F = FiniteField(P)
"""Elliptic curve secp256k1: y^2 = x^3 + 7"""
C = EllipticCurve([F(0), F(7)])
"""Base point of secp256k1"""
G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798)
"""Prime order of secp256k1"""
N = C.order()
"""Finite field of scalars of secp256k1"""
Z = FiniteField(N)
""" Beta value of secp256k1 non-trivial endomorphism: lambda * (x, y) = (beta * x, y)"""
BETA = F(2)^((P-1)/3)
""" Lambda value of secp256k1 non-trivial endomorphism: lambda * (x, y) = (beta * x, y)"""
LAMBDA = Z(3)^((N-1)/3)
assert is_prime(P)
assert is_prime(N)
assert BETA != F(1)
assert BETA^3 == F(1)
assert BETA^2 + BETA + 1 == 0
assert LAMBDA != Z(1)
assert LAMBDA^3 == Z(1)
assert LAMBDA^2 + LAMBDA + 1 == 0
assert Integer(LAMBDA)*G == C(BETA*G[0], G[1])

View file

@ -1,9 +1,9 @@
@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm:
/**********************************************************************
* Copyright (c) 2014 Wladimir J. van der Laan *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2014 Wladimir J. van der Laan *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
/*
ARM implementation of field_10x26 inner loops.

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2020 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2020 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_ASSUMPTIONS_H
#define SECP256K1_ASSUMPTIONS_H

View file

@ -1,33 +1,16 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_BASIC_CONFIG_H
#define SECP256K1_BASIC_CONFIG_H
#ifdef USE_BASIC_CONFIG
#undef USE_ASM_X86_64
#undef USE_ECMULT_STATIC_PRECOMPUTATION
#undef USE_EXTERNAL_ASM
#undef USE_EXTERNAL_DEFAULT_CALLBACKS
#undef USE_FIELD_INV_BUILTIN
#undef USE_FIELD_INV_NUM
#undef USE_NUM_GMP
#undef USE_NUM_NONE
#undef USE_SCALAR_INV_BUILTIN
#undef USE_SCALAR_INV_NUM
#undef USE_FORCE_WIDEMUL_INT64
#undef USE_FORCE_WIDEMUL_INT128
#undef ECMULT_WINDOW_SIZE
#define USE_NUM_NONE 1
#define USE_FIELD_INV_BUILTIN 1
#define USE_SCALAR_INV_BUILTIN 1
#define USE_WIDEMUL_64 1
#define ECMULT_WINDOW_SIZE 15
#define ECMULT_GEN_PREC_BITS 4
#endif /* USE_BASIC_CONFIG */

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_BENCH_H
#define SECP256K1_BENCH_H

View file

@ -1,13 +1,13 @@
/**********************************************************************
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#include <string.h>
#include "include/secp256k1.h"
#include "include/secp256k1_ecdh.h"
#include "../include/secp256k1.h"
#include "../include/secp256k1_ecdh.h"
#include "util.h"
#include "bench.h"

View file

@ -1,47 +1,191 @@
/**********************************************************************
* Copyright (c) 2017 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2017 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#include <stdio.h>
#include "include/secp256k1.h"
#include "secp256k1.c"
#include "../include/secp256k1.h"
#include "util.h"
#include "hash_impl.h"
#include "num_impl.h"
#include "field_impl.h"
#include "group_impl.h"
#include "scalar_impl.h"
#include "ecmult_impl.h"
#include "bench.h"
#include "secp256k1.c"
#define POINTS 32768
void help(char **argv) {
printf("Benchmark EC multiplication algorithms\n");
printf("\n");
printf("Usage: %s <help|pippenger_wnaf|strauss_wnaf|simple>\n", argv[0]);
printf("The output shows the number of multiplied and summed points right after the\n");
printf("function name. The letter 'g' indicates that one of the points is the generator.\n");
printf("The benchmarks are divided by the number of points.\n");
printf("\n");
printf("default (ecmult_multi): picks pippenger_wnaf or strauss_wnaf depending on the\n");
printf(" batch size\n");
printf("pippenger_wnaf: for all batch sizes\n");
printf("strauss_wnaf: for all batch sizes\n");
printf("simple: multiply and sum each point individually\n");
}
typedef struct {
/* Setup once in advance */
secp256k1_context* ctx;
secp256k1_scratch_space* scratch;
secp256k1_scalar* scalars;
secp256k1_ge* pubkeys;
secp256k1_gej* pubkeys_gej;
secp256k1_scalar* seckeys;
secp256k1_gej* expected_output;
secp256k1_ecmult_multi_func ecmult_multi;
/* Changes per test */
/* Changes per benchmark */
size_t count;
int includes_g;
/* Changes per test iteration */
/* Changes per benchmark iteration, used to pick different scalars and pubkeys
* in each run. */
size_t offset1;
size_t offset2;
/* Test output. */
/* Benchmark output. */
secp256k1_gej* output;
} bench_data;
static int bench_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, void* arg) {
/* Hashes x into [0, POINTS) twice and store the result in offset1 and offset2. */
static void hash_into_offset(bench_data* data, size_t x) {
data->offset1 = (x * 0x537b7f6f + 0x8f66a481) % POINTS;
data->offset2 = (x * 0x7f6f537b + 0x6a1a8f49) % POINTS;
}
/* Check correctness of the benchmark by computing
* sum(outputs) ?= (sum(scalars_gen) + sum(seckeys)*sum(scalars))*G */
static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset, size_t* scalar_offset, size_t* scalar_gen_offset, int iters) {
int i;
secp256k1_gej sum_output, tmp;
secp256k1_scalar sum_scalars;
secp256k1_gej_set_infinity(&sum_output);
secp256k1_scalar_clear(&sum_scalars);
for (i = 0; i < iters; ++i) {
secp256k1_gej_add_var(&sum_output, &sum_output, &data->output[i], NULL);
if (scalar_gen_offset != NULL) {
secp256k1_scalar_add(&sum_scalars, &sum_scalars, &data->scalars[(*scalar_gen_offset+i) % POINTS]);
}
if (seckey_offset != NULL) {
secp256k1_scalar s = data->seckeys[(*seckey_offset+i) % POINTS];
secp256k1_scalar_mul(&s, &s, &data->scalars[(*scalar_offset+i) % POINTS]);
secp256k1_scalar_add(&sum_scalars, &sum_scalars, &s);
}
}
secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars);
secp256k1_gej_neg(&tmp, &tmp);
secp256k1_gej_add_var(&tmp, &tmp, &sum_output, NULL);
CHECK(secp256k1_gej_is_infinity(&tmp));
}
static void bench_ecmult_setup(void* arg) {
bench_data* data = (bench_data*)arg;
/* Re-randomize offset to ensure that we're using different scalars and
* group elements in each run. */
hash_into_offset(data, data->offset1);
}
static void bench_ecmult_gen(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
int i;
for (i = 0; i < iters; ++i) {
secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &data->output[i], &data->scalars[(data->offset1+i) % POINTS]);
}
}
static void bench_ecmult_gen_teardown(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
bench_ecmult_teardown_helper(data, NULL, NULL, &data->offset1, iters);
}
static void bench_ecmult_const(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
int i;
for (i = 0; i < iters; ++i) {
secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], 256);
}
}
static void bench_ecmult_const_teardown(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters);
}
static void bench_ecmult_1(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
int i;
for (i = 0; i < iters; ++i) {
secp256k1_ecmult(&data->ctx->ecmult_ctx, &data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], NULL);
}
}
static void bench_ecmult_1_teardown(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, NULL, iters);
}
static void bench_ecmult_1g(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
secp256k1_scalar zero;
int i;
secp256k1_scalar_set_int(&zero, 0);
for (i = 0; i < iters; ++i) {
secp256k1_ecmult(&data->ctx->ecmult_ctx, &data->output[i], NULL, &zero, &data->scalars[(data->offset1+i) % POINTS]);
}
}
static void bench_ecmult_1g_teardown(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
bench_ecmult_teardown_helper(data, NULL, NULL, &data->offset1, iters);
}
static void bench_ecmult_2g(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
int i;
for (i = 0; i < iters/2; ++i) {
secp256k1_ecmult(&data->ctx->ecmult_ctx, &data->output[i], &data->pubkeys_gej[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], &data->scalars[(data->offset1+i) % POINTS]);
}
}
static void bench_ecmult_2g_teardown(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
bench_ecmult_teardown_helper(data, &data->offset1, &data->offset2, &data->offset1, iters/2);
}
static void run_ecmult_bench(bench_data* data, int iters) {
char str[32];
sprintf(str, "ecmult_gen");
run_benchmark(str, bench_ecmult_gen, bench_ecmult_setup, bench_ecmult_gen_teardown, data, 10, iters);
sprintf(str, "ecmult_const");
run_benchmark(str, bench_ecmult_const, bench_ecmult_setup, bench_ecmult_const_teardown, data, 10, iters);
/* ecmult with non generator point */
sprintf(str, "ecmult 1");
run_benchmark(str, bench_ecmult_1, bench_ecmult_setup, bench_ecmult_1_teardown, data, 10, iters);
/* ecmult with generator point */
sprintf(str, "ecmult 1g");
run_benchmark(str, bench_ecmult_1g, bench_ecmult_setup, bench_ecmult_1g_teardown, data, 10, iters);
/* ecmult with generator and non-generator point. The reported time is per point. */
sprintf(str, "ecmult 2g");
run_benchmark(str, bench_ecmult_2g, bench_ecmult_setup, bench_ecmult_2g_teardown, data, 10, 2*iters);
}
static int bench_ecmult_multi_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, void* arg) {
bench_data* data = (bench_data*)arg;
if (data->includes_g) ++idx;
if (idx == 0) {
@ -54,7 +198,7 @@ static int bench_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, vo
return 1;
}
static void bench_ecmult(void* arg, int iters) {
static void bench_ecmult_multi(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
int includes_g = data->includes_g;
@ -63,19 +207,18 @@ static void bench_ecmult(void* arg, int iters) {
iters = iters / data->count;
for (iter = 0; iter < iters; ++iter) {
data->ecmult_multi(&data->ctx->error_callback, &data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g);
data->ecmult_multi(&data->ctx->error_callback, &data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_ecmult_multi_callback, arg, count - includes_g);
data->offset1 = (data->offset1 + count) % POINTS;
data->offset2 = (data->offset2 + count - 1) % POINTS;
}
}
static void bench_ecmult_setup(void* arg) {
static void bench_ecmult_multi_setup(void* arg) {
bench_data* data = (bench_data*)arg;
data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS;
data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS;
hash_into_offset(data, data->count);
}
static void bench_ecmult_teardown(void* arg, int iters) {
static void bench_ecmult_multi_teardown(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
int iter;
iters = iters / data->count;
@ -89,7 +232,7 @@ static void bench_ecmult_teardown(void* arg, int iters) {
static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
secp256k1_sha256 sha256;
unsigned char c[11] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0};
unsigned char c[10] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0};
unsigned char buf[32];
int overflow = 0;
c[6] = num;
@ -103,7 +246,7 @@ static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
CHECK(!overflow);
}
static void run_test(bench_data* data, size_t count, int includes_g, int num_iters) {
static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_g, int num_iters) {
char str[32];
static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
size_t iters = 1 + num_iters / count;
@ -113,8 +256,7 @@ static void run_test(bench_data* data, size_t count, int includes_g, int num_ite
data->includes_g = includes_g;
/* Compute (the negation of) the expected results directly. */
data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS;
data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS;
hash_into_offset(data, data->count);
for (iter = 0; iter < iters; ++iter) {
secp256k1_scalar tmp;
secp256k1_scalar total = data->scalars[(data->offset1++) % POINTS];
@ -128,25 +270,26 @@ static void run_test(bench_data* data, size_t count, int includes_g, int num_ite
}
/* Run the benchmark. */
sprintf(str, includes_g ? "ecmult_%ig" : "ecmult_%i", (int)count);
run_benchmark(str, bench_ecmult, bench_ecmult_setup, bench_ecmult_teardown, data, 10, count * iters);
sprintf(str, includes_g ? "ecmult_multi %ig" : "ecmult_multi %i", (int)count);
run_benchmark(str, bench_ecmult_multi, bench_ecmult_multi_setup, bench_ecmult_multi_teardown, data, 10, count * iters);
}
int main(int argc, char **argv) {
bench_data data;
int i, p;
secp256k1_gej* pubkeys_gej;
size_t scratch_size;
int iters = get_iters(10000);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
data.ecmult_multi = secp256k1_ecmult_multi_var;
if (argc > 1) {
if(have_flag(argc, argv, "pippenger_wnaf")) {
if(have_flag(argc, argv, "-h")
|| have_flag(argc, argv, "--help")
|| have_flag(argc, argv, "help")) {
help(argv);
return 1;
} else if(have_flag(argc, argv, "pippenger_wnaf")) {
printf("Using pippenger_wnaf:\n");
data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single;
} else if(have_flag(argc, argv, "strauss_wnaf")) {
@ -154,39 +297,48 @@ int main(int argc, char **argv) {
data.ecmult_multi = secp256k1_ecmult_strauss_batch_single;
} else if(have_flag(argc, argv, "simple")) {
printf("Using simple algorithm:\n");
data.ecmult_multi = secp256k1_ecmult_multi_var;
secp256k1_scratch_space_destroy(data.ctx, data.scratch);
data.scratch = NULL;
} else {
fprintf(stderr, "%s: unrecognized argument '%s'.\n", argv[0], argv[1]);
fprintf(stderr, "Use 'pippenger_wnaf', 'strauss_wnaf', 'simple' or no argument to benchmark a combined algorithm.\n");
fprintf(stderr, "%s: unrecognized argument '%s'.\n\n", argv[0], argv[1]);
help(argv);
return 1;
}
}
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
if (!have_flag(argc, argv, "simple")) {
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
} else {
data.scratch = NULL;
}
/* Allocate stuff */
data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS);
data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS);
data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS);
data.pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS);
data.expected_output = malloc(sizeof(secp256k1_gej) * (iters + 1));
data.output = malloc(sizeof(secp256k1_gej) * (iters + 1));
/* Generate a set of scalars, and private/public keypairs. */
pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS);
secp256k1_gej_set_ge(&pubkeys_gej[0], &secp256k1_ge_const_g);
secp256k1_gej_set_ge(&data.pubkeys_gej[0], &secp256k1_ge_const_g);
secp256k1_scalar_set_int(&data.seckeys[0], 1);
for (i = 0; i < POINTS; ++i) {
generate_scalar(i, &data.scalars[i]);
if (i) {
secp256k1_gej_double_var(&pubkeys_gej[i], &pubkeys_gej[i - 1], NULL);
secp256k1_gej_double_var(&data.pubkeys_gej[i], &data.pubkeys_gej[i - 1], NULL);
secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]);
}
}
secp256k1_ge_set_all_gej_var(data.pubkeys, pubkeys_gej, POINTS);
free(pubkeys_gej);
secp256k1_ge_set_all_gej_var(data.pubkeys, data.pubkeys_gej, POINTS);
/* Initialize offset1 and offset2 */
hash_into_offset(&data, 0);
run_ecmult_bench(&data, iters);
for (i = 1; i <= 8; ++i) {
run_test(&data, i, 1, iters);
run_ecmult_multi_bench(&data, i, 1, iters);
}
/* This is disabled with low count of iterations because the loop runs 77 times even with iters=1
@ -195,7 +347,7 @@ int main(int argc, char **argv) {
if (iters > 2) {
for (p = 0; p <= 11; ++p) {
for (i = 9; i <= 16; ++i) {
run_test(&data, i << p, 1, iters);
run_ecmult_multi_bench(&data, i << p, 1, iters);
}
}
}
@ -206,6 +358,7 @@ int main(int argc, char **argv) {
secp256k1_context_destroy(data.ctx);
free(data.scalars);
free(data.pubkeys);
free(data.pubkeys_gej);
free(data.seckeys);
free(data.output);
free(data.expected_output);

View file

@ -1,23 +1,22 @@
/**********************************************************************
* Copyright (c) 2014-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2014-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#include <stdio.h>
#include "include/secp256k1.h"
#include "secp256k1.c"
#include "../include/secp256k1.h"
#include "assumptions.h"
#include "util.h"
#include "hash_impl.h"
#include "num_impl.h"
#include "field_impl.h"
#include "group_impl.h"
#include "scalar_impl.h"
#include "ecmult_const_impl.h"
#include "ecmult_impl.h"
#include "bench.h"
#include "secp256k1.c"
typedef struct {
secp256k1_scalar scalar[2];
@ -99,15 +98,6 @@ void bench_scalar_negate(void* arg, int iters) {
}
}
void bench_scalar_sqr(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
secp256k1_scalar_sqr(&data->scalar[0], &data->scalar[0]);
}
}
void bench_scalar_mul(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -369,35 +359,16 @@ void bench_context_sign(void* arg, int iters) {
}
}
#ifndef USE_NUM_NONE
void bench_num_jacobi(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
secp256k1_num nx, na, norder;
secp256k1_scalar_get_num(&nx, &data->scalar[0]);
secp256k1_scalar_order_get_num(&norder);
secp256k1_scalar_get_num(&na, &data->scalar[1]);
for (i = 0; i < iters; i++) {
j += secp256k1_num_jacobi(&nx, &norder);
secp256k1_num_add(&nx, &nx, &na);
}
CHECK(j <= iters);
}
#endif
int main(int argc, char **argv) {
bench_inv data;
int iters = get_iters(20000);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, iters);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, iters*100);
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, iters*100);
@ -424,8 +395,5 @@ int main(int argc, char **argv) {
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 1 + iters/1000);
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 1 + iters/100);
#ifndef USE_NUM_NONE
if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, iters*10);
#endif
return 0;
}

View file

@ -1,11 +1,11 @@
/**********************************************************************
* Copyright (c) 2014-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2014-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#include "include/secp256k1.h"
#include "include/secp256k1_recovery.h"
#include "../include/secp256k1.h"
#include "../include/secp256k1_recovery.h"
#include "util.h"
#include "bench.h"

View file

@ -1,18 +1,20 @@
/**********************************************************************
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#include <string.h>
#include <stdlib.h>
#include "include/secp256k1.h"
#include "include/secp256k1_schnorrsig.h"
#include "../include/secp256k1.h"
#include "../include/secp256k1_schnorrsig.h"
#include "util.h"
#include "bench.h"
#define MSGLEN 32
typedef struct {
secp256k1_context *ctx;
int n;
@ -26,13 +28,13 @@ typedef struct {
void bench_schnorrsig_sign(void* arg, int iters) {
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
int i;
unsigned char msg[32] = "benchmarkexamplemessagetemplate";
unsigned char msg[MSGLEN] = {0};
unsigned char sig[64];
for (i = 0; i < iters; i++) {
msg[0] = i;
msg[1] = i >> 8;
CHECK(secp256k1_schnorrsig_sign(data->ctx, sig, msg, data->keypairs[i], NULL, NULL));
CHECK(secp256k1_schnorrsig_sign_custom(data->ctx, sig, msg, MSGLEN, data->keypairs[i], NULL));
}
}
@ -43,7 +45,7 @@ void bench_schnorrsig_verify(void* arg, int iters) {
for (i = 0; i < iters; i++) {
secp256k1_xonly_pubkey pk;
CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1);
CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], &pk));
CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], MSGLEN, &pk));
}
}
@ -58,9 +60,10 @@ int main(void) {
data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
CHECK(MSGLEN >= 4);
for (i = 0; i < iters; i++) {
unsigned char sk[32];
unsigned char *msg = (unsigned char *)malloc(32);
unsigned char *msg = (unsigned char *)malloc(MSGLEN);
unsigned char *sig = (unsigned char *)malloc(64);
secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair));
unsigned char *pk_char = (unsigned char *)malloc(32);
@ -69,7 +72,7 @@ int main(void) {
msg[1] = sk[1] = i >> 8;
msg[2] = sk[2] = i >> 16;
msg[3] = sk[3] = i >> 24;
memset(&msg[4], 'm', 28);
memset(&msg[4], 'm', MSGLEN - 4);
memset(&sk[4], 's', 28);
data.keypairs[i] = keypair;
@ -78,7 +81,7 @@ int main(void) {
data.sigs[i] = sig;
CHECK(secp256k1_keypair_create(data.ctx, keypair, sk));
CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, msg, keypair, NULL, NULL));
CHECK(secp256k1_schnorrsig_sign_custom(data.ctx, sig, msg, MSGLEN, keypair, NULL));
CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair));
CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1);
}

View file

@ -1,10 +1,10 @@
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#include "include/secp256k1.h"
#include "../include/secp256k1.h"
#include "util.h"
#include "bench.h"

View file

@ -1,13 +1,13 @@
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#include <stdio.h>
#include <string.h>
#include "include/secp256k1.h"
#include "../include/secp256k1.h"
#include "util.h"
#include "bench.h"

View file

@ -11,7 +11,6 @@
#include "util.h"
#include "bench.h"
#include "hash_impl.h"
#include "num_impl.h"
#include "scalar_impl.h"
#include "testrand_impl.h"

28
src/eccommit.h Normal file
View file

@ -0,0 +1,28 @@
/**********************************************************************
* Copyright (c) 2020 The libsecp256k1-zkp Developers *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_ECCOMMIT_H
#define SECP256K1_ECCOMMIT_H
/** Helper function to add a 32-byte value to a scalar */
static int secp256k1_ec_seckey_tweak_add_helper(secp256k1_scalar *sec, const unsigned char *tweak);
/** Helper function to add a 32-byte value, times G, to an EC point */
static int secp256k1_ec_pubkey_tweak_add_helper(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge *p, const unsigned char *tweak);
/** Serializes elem as a 33 byte array. This is non-constant time with respect to
* whether pubp is the point at infinity. Thus, you may need to declassify
* pubp->infinity before calling this function. */
static int secp256k1_ec_commit_pubkey_serialize_const(secp256k1_ge *pubp, unsigned char *buf33);
/** Compute an ec commitment tweak as hash(pubkey, data). */
static int secp256k1_ec_commit_tweak(unsigned char *tweak32, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
/** Compute an ec commitment as pubkey + hash(pubkey, data)*G. */
static int secp256k1_ec_commit(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
/** Compute a secret key commitment as seckey + hash(pubkey, data). */
static int secp256k1_ec_commit_seckey(const secp256k1_ecmult_gen_context* ecmult_gen_ctx, secp256k1_scalar* seckey, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
/** Verify an ec commitment as pubkey + hash(pubkey, data)*G ?= commitment. */
static int secp256k1_ec_commit_verify(const secp256k1_ecmult_context* ecmult_ctx, const secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size);
#endif /* SECP256K1_ECCOMMIT_H */

73
src/eccommit_impl.h Normal file
View file

@ -0,0 +1,73 @@
/**********************************************************************
* Copyright (c) 2020 The libsecp256k1 Developers *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#include <stddef.h>
#include "eckey.h"
#include "hash.h"
/* from secp256k1.c */
static int secp256k1_ec_seckey_tweak_add_helper(secp256k1_scalar *sec, const unsigned char *tweak);
static int secp256k1_ec_pubkey_tweak_add_helper(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge *pubp, const unsigned char *tweak);
static int secp256k1_ec_commit_pubkey_serialize_const(secp256k1_ge *pubp, unsigned char *buf33) {
if (secp256k1_ge_is_infinity(pubp)) {
return 0;
}
secp256k1_fe_normalize(&pubp->x);
secp256k1_fe_normalize(&pubp->y);
secp256k1_fe_get_b32(&buf33[1], &pubp->x);
buf33[0] = secp256k1_fe_is_odd(&pubp->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
return 1;
}
/* Compute an ec commitment tweak as hash(pubp, data). */
static int secp256k1_ec_commit_tweak(unsigned char *tweak32, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size)
{
unsigned char rbuf[33];
if (!secp256k1_ec_commit_pubkey_serialize_const(pubp, rbuf)) {
return 0;
}
secp256k1_sha256_write(sha, rbuf, sizeof(rbuf));
secp256k1_sha256_write(sha, data, data_size);
secp256k1_sha256_finalize(sha, tweak32);
return 1;
}
/* Compute an ec commitment as pubp + hash(pubp, data)*G. */
static int secp256k1_ec_commit(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
unsigned char tweak[32];
*commitp = *pubp;
return secp256k1_ec_commit_tweak(tweak, commitp, sha, data, data_size)
&& secp256k1_ec_pubkey_tweak_add_helper(ecmult_ctx, commitp, tweak);
}
/* Compute the seckey of an ec commitment from the original secret key of the pubkey as seckey +
* hash(pubp, data). */
static int secp256k1_ec_commit_seckey(secp256k1_scalar* seckey, secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
unsigned char tweak[32];
return secp256k1_ec_commit_tweak(tweak, pubp, sha, data, data_size)
&& secp256k1_ec_seckey_tweak_add_helper(seckey, tweak);
}
/* Verify an ec commitment as pubp + hash(pubp, data)*G ?= commitment. */
static int secp256k1_ec_commit_verify(const secp256k1_ecmult_context* ecmult_ctx, const secp256k1_ge* commitp, const secp256k1_ge* pubp, secp256k1_sha256* sha, const unsigned char *data, size_t data_size) {
secp256k1_gej pj;
secp256k1_ge p;
if (!secp256k1_ec_commit(ecmult_ctx, &p, pubp, sha, data, data_size)) {
return 0;
}
/* Return p == commitp */
secp256k1_ge_neg(&p, &p);
secp256k1_gej_set_ge(&pj, &p);
secp256k1_gej_add_ge_var(&pj, &pj, commitp, NULL);
return secp256k1_gej_is_infinity(&pj);
}

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_ECDSA_H
#define SECP256K1_ECDSA_H

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_ECDSA_IMPL_H
@ -140,7 +140,7 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char
overflow = 1;
}
if (!overflow) {
memcpy(ra + 32 - rlen, *sig, rlen);
if (rlen) memcpy(ra + 32 - rlen, *sig, rlen);
secp256k1_scalar_set_b32(r, ra, &overflow);
}
if (overflow) {

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_ECKEY_H
#define SECP256K1_ECKEY_H

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_ECKEY_IMPL_H
#define SECP256K1_ECKEY_IMPL_H

View file

@ -1,13 +1,12 @@
/**********************************************************************
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_ECMULT_H
#define SECP256K1_ECMULT_H
#include "num.h"
#include "group.h"
#include "scalar.h"
#include "scratch.h"
@ -18,7 +17,6 @@ typedef struct {
secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */
} secp256k1_ecmult_context;
static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE;
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx);
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void **prealloc);
static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src);

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_ECMULT_CONST_H
#define SECP256K1_ECMULT_CONST_H

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_ECMULT_CONST_IMPL_H
#define SECP256K1_ECMULT_CONST_IMPL_H

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_ECMULT_GEN_H
#define SECP256K1_ECMULT_GEN_H
@ -35,7 +35,6 @@ typedef struct {
secp256k1_gej initial;
} secp256k1_ecmult_gen_context;
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx);
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, void **prealloc);
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context* src);

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_ECMULT_GEN_IMPL_H
#define SECP256K1_ECMULT_GEN_IMPL_H
@ -144,7 +144,7 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
* (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and
* "Cache Attacks and Countermeasures: the Case of AES", RSA 2006,
* by Dag Arne Osvik, Adi Shamir, and Eran Tromer
* (http://www.tau.ac.il/~tromer/papers/cache.pdf)
* (https://www.tau.ac.il/~tromer/papers/cache.pdf)
*/
secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits);
}

View file

@ -1,8 +1,8 @@
/*****************************************************************************
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
*****************************************************************************/
/******************************************************************************
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php. *
******************************************************************************/
#ifndef SECP256K1_ECMULT_IMPL_H
#define SECP256K1_ECMULT_IMPL_H

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_FIELD_H
#define SECP256K1_FIELD_H
@ -43,13 +43,12 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
/** Normalize a field element, without constant-time guarantee. */
static void secp256k1_fe_normalize_var(secp256k1_fe *r);
/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field
* implementation may optionally normalize the input, but this should not be relied upon. */
static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r);
/** Verify whether a field element represents zero i.e. would normalize to a zero value. */
static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r);
/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field
* implementation may optionally normalize the input, but this should not be relied upon. */
static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r);
/** Verify whether a field element represents zero i.e. would normalize to a zero value,
* without constant-time guarantee. */
static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r);
/** Set a field element equal to a small integer. Resulting field element is normalized. */
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
@ -114,11 +113,6 @@ static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a);
/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);
/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be
* at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and
* outputs must not overlap in memory. */
static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len);
/** Convert a field element to the storage type. */
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_FIELD_REPR_H
#define SECP256K1_FIELD_REPR_H

View file

@ -1,14 +1,15 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_FIELD_REPR_IMPL_H
#define SECP256K1_FIELD_REPR_IMPL_H
#include "util.h"
#include "field.h"
#include "modinv32_impl.h"
#ifdef VERIFY
static void secp256k1_fe_verify(const secp256k1_fe *a) {
@ -181,7 +182,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
#endif
}
static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) {
static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@ -210,7 +211,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
}
static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) {
static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
uint32_t z0, z1;
uint32_t x;
@ -1164,4 +1165,92 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
#endif
}
static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) {
const uint32_t M26 = UINT32_MAX >> 6;
const uint32_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4],
a5 = a->v[5], a6 = a->v[6], a7 = a->v[7], a8 = a->v[8];
/* The output from secp256k1_modinv32{_var} should be normalized to range [0,modulus), and
* have limbs in [0,2^30). The modulus is < 2^256, so the top limb must be below 2^(256-30*8).
*/
VERIFY_CHECK(a0 >> 30 == 0);
VERIFY_CHECK(a1 >> 30 == 0);
VERIFY_CHECK(a2 >> 30 == 0);
VERIFY_CHECK(a3 >> 30 == 0);
VERIFY_CHECK(a4 >> 30 == 0);
VERIFY_CHECK(a5 >> 30 == 0);
VERIFY_CHECK(a6 >> 30 == 0);
VERIFY_CHECK(a7 >> 30 == 0);
VERIFY_CHECK(a8 >> 16 == 0);
r->n[0] = a0 & M26;
r->n[1] = (a0 >> 26 | a1 << 4) & M26;
r->n[2] = (a1 >> 22 | a2 << 8) & M26;
r->n[3] = (a2 >> 18 | a3 << 12) & M26;
r->n[4] = (a3 >> 14 | a4 << 16) & M26;
r->n[5] = (a4 >> 10 | a5 << 20) & M26;
r->n[6] = (a5 >> 6 | a6 << 24) & M26;
r->n[7] = (a6 >> 2 ) & M26;
r->n[8] = (a6 >> 28 | a7 << 2) & M26;
r->n[9] = (a7 >> 24 | a8 << 6);
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) {
const uint32_t M30 = UINT32_MAX >> 2;
const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4],
a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9];
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
#endif
r->v[0] = (a0 | a1 << 26) & M30;
r->v[1] = (a1 >> 4 | a2 << 22) & M30;
r->v[2] = (a2 >> 8 | a3 << 18) & M30;
r->v[3] = (a3 >> 12 | a4 << 14) & M30;
r->v[4] = (a4 >> 16 | a5 << 10) & M30;
r->v[5] = (a5 >> 20 | a6 << 6) & M30;
r->v[6] = (a6 >> 24 | a7 << 2
| a8 << 28) & M30;
r->v[7] = (a8 >> 2 | a9 << 24) & M30;
r->v[8] = a9 >> 6;
}
static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = {
{{-0x3D1, -4, 0, 0, 0, 0, 0, 0, 65536}},
0x2DDACACFL
};
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv32_signed30 s;
tmp = *x;
secp256k1_fe_normalize(&tmp);
secp256k1_fe_to_signed30(&s, &tmp);
secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed30(r, &s);
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
}
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv32_signed30 s;
tmp = *x;
secp256k1_fe_normalize_var(&tmp);
secp256k1_fe_to_signed30(&s, &tmp);
secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed30(r, &s);
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
}
#endif /* SECP256K1_FIELD_REPR_IMPL_H */

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_FIELD_REPR_H
#define SECP256K1_FIELD_REPR_H

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
/**
* Changelog:

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_FIELD_REPR_IMPL_H
#define SECP256K1_FIELD_REPR_IMPL_H
@ -13,6 +13,7 @@
#include "util.h"
#include "field.h"
#include "modinv64_impl.h"
#if defined(USE_ASM_X86_64)
#include "field_5x52_asm_impl.h"
@ -161,7 +162,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
#endif
}
static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) {
static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
@ -184,7 +185,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
}
static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) {
static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
uint64_t t0, t1, t2, t3, t4;
uint64_t z0, z1;
uint64_t x;
@ -498,4 +499,80 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
#endif
}
static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) {
const uint64_t M52 = UINT64_MAX >> 12;
const uint64_t a0 = a->v[0], a1 = a->v[1], a2 = a->v[2], a3 = a->v[3], a4 = a->v[4];
/* The output from secp256k1_modinv64{_var} should be normalized to range [0,modulus), and
* have limbs in [0,2^62). The modulus is < 2^256, so the top limb must be below 2^(256-62*4).
*/
VERIFY_CHECK(a0 >> 62 == 0);
VERIFY_CHECK(a1 >> 62 == 0);
VERIFY_CHECK(a2 >> 62 == 0);
VERIFY_CHECK(a3 >> 62 == 0);
VERIFY_CHECK(a4 >> 8 == 0);
r->n[0] = a0 & M52;
r->n[1] = (a0 >> 52 | a1 << 10) & M52;
r->n[2] = (a1 >> 42 | a2 << 20) & M52;
r->n[3] = (a2 >> 32 | a3 << 30) & M52;
r->n[4] = (a3 >> 22 | a4 << 40);
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) {
const uint64_t M62 = UINT64_MAX >> 2;
const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4];
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
#endif
r->v[0] = (a0 | a1 << 52) & M62;
r->v[1] = (a1 >> 10 | a2 << 42) & M62;
r->v[2] = (a2 >> 20 | a3 << 32) & M62;
r->v[3] = (a3 >> 30 | a4 << 22) & M62;
r->v[4] = a4 >> 40;
}
static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = {
{{-0x1000003D1LL, 0, 0, 0, 256}},
0x27C7F6E22DDACACFLL
};
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv64_signed62 s;
tmp = *x;
secp256k1_fe_normalize(&tmp);
secp256k1_fe_to_signed62(&s, &tmp);
secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed62(r, &s);
#ifdef VERIFY
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
#endif
}
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv64_signed62 s;
tmp = *x;
secp256k1_fe_normalize_var(&tmp);
secp256k1_fe_to_signed62(&s, &tmp);
secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed62(r, &s);
#ifdef VERIFY
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
#endif
}
#endif /* SECP256K1_FIELD_REPR_IMPL_H */

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
#define SECP256K1_FIELD_INNER5X52_IMPL_H

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_FIELD_IMPL_H
#define SECP256K1_FIELD_IMPL_H
@ -12,7 +12,6 @@
#endif
#include "util.h"
#include "num.h"
#if defined(SECP256K1_WIDEMUL_INT128)
#include "field_5x52_impl.h"
@ -136,183 +135,9 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
return secp256k1_fe_equal(&t1, a);
}
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
int j;
/** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in
* { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
* [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
*/
secp256k1_fe_sqr(&x2, a);
secp256k1_fe_mul(&x2, &x2, a);
secp256k1_fe_sqr(&x3, &x2);
secp256k1_fe_mul(&x3, &x3, a);
x6 = x3;
for (j=0; j<3; j++) {
secp256k1_fe_sqr(&x6, &x6);
}
secp256k1_fe_mul(&x6, &x6, &x3);
x9 = x6;
for (j=0; j<3; j++) {
secp256k1_fe_sqr(&x9, &x9);
}
secp256k1_fe_mul(&x9, &x9, &x3);
x11 = x9;
for (j=0; j<2; j++) {
secp256k1_fe_sqr(&x11, &x11);
}
secp256k1_fe_mul(&x11, &x11, &x2);
x22 = x11;
for (j=0; j<11; j++) {
secp256k1_fe_sqr(&x22, &x22);
}
secp256k1_fe_mul(&x22, &x22, &x11);
x44 = x22;
for (j=0; j<22; j++) {
secp256k1_fe_sqr(&x44, &x44);
}
secp256k1_fe_mul(&x44, &x44, &x22);
x88 = x44;
for (j=0; j<44; j++) {
secp256k1_fe_sqr(&x88, &x88);
}
secp256k1_fe_mul(&x88, &x88, &x44);
x176 = x88;
for (j=0; j<88; j++) {
secp256k1_fe_sqr(&x176, &x176);
}
secp256k1_fe_mul(&x176, &x176, &x88);
x220 = x176;
for (j=0; j<44; j++) {
secp256k1_fe_sqr(&x220, &x220);
}
secp256k1_fe_mul(&x220, &x220, &x44);
x223 = x220;
for (j=0; j<3; j++) {
secp256k1_fe_sqr(&x223, &x223);
}
secp256k1_fe_mul(&x223, &x223, &x3);
/* The final result is then assembled using a sliding window over the blocks. */
t1 = x223;
for (j=0; j<23; j++) {
secp256k1_fe_sqr(&t1, &t1);
}
secp256k1_fe_mul(&t1, &t1, &x22);
for (j=0; j<5; j++) {
secp256k1_fe_sqr(&t1, &t1);
}
secp256k1_fe_mul(&t1, &t1, a);
for (j=0; j<3; j++) {
secp256k1_fe_sqr(&t1, &t1);
}
secp256k1_fe_mul(&t1, &t1, &x2);
for (j=0; j<2; j++) {
secp256k1_fe_sqr(&t1, &t1);
}
secp256k1_fe_mul(r, a, &t1);
}
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) {
#if defined(USE_FIELD_INV_BUILTIN)
secp256k1_fe_inv(r, a);
#elif defined(USE_FIELD_INV_NUM)
secp256k1_num n, m;
static const secp256k1_fe negone = SECP256K1_FE_CONST(
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL,
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL
);
/* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
static const unsigned char prime[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
};
unsigned char b[32];
int res;
secp256k1_fe c = *a;
secp256k1_fe_normalize_var(&c);
secp256k1_fe_get_b32(b, &c);
secp256k1_num_set_bin(&n, b, 32);
secp256k1_num_set_bin(&m, prime, 32);
secp256k1_num_mod_inverse(&n, &n, &m);
secp256k1_num_get_bin(b, 32, &n);
res = secp256k1_fe_set_b32(r, b);
(void)res;
VERIFY_CHECK(res);
/* Verify the result is the (unique) valid inverse using non-GMP code. */
secp256k1_fe_mul(&c, &c, r);
secp256k1_fe_add(&c, &negone);
CHECK(secp256k1_fe_normalizes_to_zero_var(&c));
#else
#error "Please select field inverse implementation"
#endif
}
static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len) {
secp256k1_fe u;
size_t i;
if (len < 1) {
return;
}
VERIFY_CHECK((r + len <= a) || (a + len <= r));
r[0] = a[0];
i = 0;
while (++i < len) {
secp256k1_fe_mul(&r[i], &r[i - 1], &a[i]);
}
secp256k1_fe_inv_var(&u, &r[--i]);
while (i > 0) {
size_t j = i--;
secp256k1_fe_mul(&r[j], &r[i], &u);
secp256k1_fe_mul(&u, &u, &a[j]);
}
r[0] = u;
}
static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
#ifndef USE_NUM_NONE
unsigned char b[32];
secp256k1_num n;
secp256k1_num m;
/* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
static const unsigned char prime[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F
};
secp256k1_fe c = *a;
secp256k1_fe_normalize_var(&c);
secp256k1_fe_get_b32(b, &c);
secp256k1_num_set_bin(&n, b, 32);
secp256k1_num_set_bin(&m, prime, 32);
return secp256k1_num_jacobi(&n, &m) >= 0;
#else
secp256k1_fe r;
return secp256k1_fe_sqrt(&r, a);
#endif
}
static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);

View file

@ -1,18 +1,25 @@
/**********************************************************************
* Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
// Autotools creates libsecp256k1-config.h, of which ECMULT_GEN_PREC_BITS is needed.
// ifndef guard so downstream users can define their own if they do not use autotools.
/* Autotools creates libsecp256k1-config.h, of which ECMULT_GEN_PREC_BITS is needed.
ifndef guard so downstream users can define their own if they do not use autotools. */
#if !defined(ECMULT_GEN_PREC_BITS)
#include "libsecp256k1-config.h"
#endif
#define USE_BASIC_CONFIG 1
#include "basic-config.h"
#include "include/secp256k1.h"
/* We can't require the precomputed tables when creating them. */
#undef USE_ECMULT_STATIC_PRECOMPUTATION
/* In principle we could use ASM, but this yields only a minor speedup in
build time and it's very complicated. In particular when cross-compiling, we'd
need to build the ASM for the build and the host machine. */
#undef USE_EXTERNAL_ASM
#undef USE_ASM_X86_64
#include "../include/secp256k1.h"
#include "assumptions.h"
#include "util.h"
#include "field_impl.h"
@ -47,8 +54,8 @@ int main(int argc, char **argv) {
return -1;
}
fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
fprintf(fp, "#ifndef SECP256K1_ECMULT_STATIC_CONTEXT_H\n");
fprintf(fp, "#define SECP256K1_ECMULT_STATIC_CONTEXT_H\n");
fprintf(fp, "#include \"src/group.h\"\n");
fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n");
fprintf(fp, "#if ECMULT_GEN_PREC_N != %d || ECMULT_GEN_PREC_G != %d\n", ECMULT_GEN_PREC_N, ECMULT_GEN_PREC_G);

View file

@ -1,13 +1,12 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_GROUP_H
#define SECP256K1_GROUP_H
#include "num.h"
#include "field.h"
/** A group element of the secp256k1 curve, in affine coordinates. */
@ -62,9 +61,12 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a);
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);
/** Set a group element equal to another which is given in jacobian coordinates */
/** Set a group element equal to another which is given in jacobian coordinates. Constant time. */
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);
/** Set a group element equal to another which is given in jacobian coordinates. */
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a);
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len);

View file

@ -1,13 +1,12 @@
/**********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_GROUP_IMPL_H
#define SECP256K1_GROUP_IMPL_H
#include "num.h"
#include "field.h"
#include "group.h"
@ -101,8 +100,8 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3;
r->infinity = a->infinity;
if (a->infinity) {
secp256k1_ge_set_infinity(r);
return;
}
secp256k1_fe_inv_var(&a->z, &a->z);
@ -111,8 +110,7 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe_mul(&a->x, &a->x, &z2);
secp256k1_fe_mul(&a->y, &a->y, &z3);
secp256k1_fe_set_int(&a->z, 1);
r->x = a->x;
r->y = a->y;
secp256k1_ge_set_xy(r, &a->x, &a->y);
}
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
@ -121,7 +119,9 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
size_t last_i = SIZE_MAX;
for (i = 0; i < len; i++) {
if (!a[i].infinity) {
if (a[i].infinity) {
secp256k1_ge_set_infinity(&r[i]);
} else {
/* Use destination's x coordinates as scratch space */
if (last_i == SIZE_MAX) {
r[i].x = a[i].z;
@ -149,7 +149,6 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
r[last_i].x = u;
for (i = 0; i < len; i++) {
r[i].infinity = a[i].infinity;
if (!a[i].infinity) {
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
}
@ -316,7 +315,7 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
* point will be gibberish (z = 0 but infinity = 0).
*/
if (a->infinity) {
r->infinity = 1;
secp256k1_gej_set_infinity(r);
if (rzr != NULL) {
secp256k1_fe_set_int(rzr, 1);
}
@ -591,7 +590,7 @@ 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_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */
infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity);
infinity = secp256k1_fe_normalizes_to_zero(&r->z) & ~a->infinity;
secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */
secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */
secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */
@ -674,7 +673,7 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
secp256k1_gej out;
int i;
/* A very simple EC multiplication ladder that avoids a dependecy on ecmult. */
/* A very simple EC multiplication ladder that avoids a dependency on ecmult. */
secp256k1_gej_set_infinity(&out);
for (i = 0; i < 32; ++i) {
secp256k1_gej_double_var(&out, &out, NULL);

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_HASH_H
#define SECP256K1_HASH_H

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_HASH_IMPL_H
#define SECP256K1_HASH_IMPL_H

42
src/modinv32.h Normal file
View file

@ -0,0 +1,42 @@
/***********************************************************************
* Copyright (c) 2020 Peter Dettman *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODINV32_H
#define SECP256K1_MODINV32_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h"
/* A signed 30-bit limb representation of integers.
*
* Its value is sum(v[i] * 2^(30*i), i=0..8). */
typedef struct {
int32_t v[9];
} secp256k1_modinv32_signed30;
typedef struct {
/* The modulus in signed30 notation, must be odd and in [3, 2^256]. */
secp256k1_modinv32_signed30 modulus;
/* modulus^{-1} mod 2^30 */
uint32_t modulus_inv30;
} secp256k1_modinv32_modinfo;
/* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus).
* If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of
* x and modulus must be 1). These rules are automatically satisfied if the modulus is prime.
*
* On output, all of x's limbs will be in [0, 2^30).
*/
static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
/* 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);
#endif /* SECP256K1_MODINV32_H */

587
src/modinv32_impl.h Normal file
View file

@ -0,0 +1,587 @@
/***********************************************************************
* Copyright (c) 2020 Peter Dettman *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODINV32_IMPL_H
#define SECP256K1_MODINV32_IMPL_H
#include "modinv32.h"
#include "util.h"
#include <stdlib.h>
/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and
* modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
*
* For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an
* implementation for N=30, using 30-bit signed limbs represented as int32_t.
*/
#ifdef VERIFY
static const secp256k1_modinv32_signed30 SECP256K1_SIGNED30_ONE = {{1}};
/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^30). */
static void secp256k1_modinv32_mul_30(secp256k1_modinv32_signed30 *r, const secp256k1_modinv32_signed30 *a, int alen, int32_t factor) {
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
int64_t c = 0;
int i;
for (i = 0; i < 8; ++i) {
if (i < alen) c += (int64_t)a->v[i] * factor;
r->v[i] = (int32_t)c & M30; c >>= 30;
}
if (8 < alen) c += (int64_t)a->v[8] * factor;
VERIFY_CHECK(c == (int32_t)c);
r->v[8] = (int32_t)c;
}
/* Return -1 for a<b*factor, 0 for a==b*factor, 1 for a>b*factor. A consists of alen limbs; b has 9. */
static int secp256k1_modinv32_mul_cmp_30(const secp256k1_modinv32_signed30 *a, int alen, const secp256k1_modinv32_signed30 *b, int32_t factor) {
int i;
secp256k1_modinv32_signed30 am, bm;
secp256k1_modinv32_mul_30(&am, a, alen, 1); /* Normalize all but the top limb of a. */
secp256k1_modinv32_mul_30(&bm, b, 9, factor);
for (i = 0; i < 8; ++i) {
/* Verify that all but the top limb of a and b are normalized. */
VERIFY_CHECK(am.v[i] >> 30 == 0);
VERIFY_CHECK(bm.v[i] >> 30 == 0);
}
for (i = 8; i >= 0; --i) {
if (am.v[i] < bm.v[i]) return -1;
if (am.v[i] > bm.v[i]) return 1;
}
return 0;
}
#endif
/* Take as input a signed30 number in range (-2*modulus,modulus), and add a multiple of the modulus
* to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the
* process. The input must have limbs in range (-2^30,2^30). The output will have limbs in range
* [0,2^30). */
static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int32_t sign, const secp256k1_modinv32_modinfo *modinfo) {
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
int32_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4],
r5 = r->v[5], r6 = r->v[6], r7 = r->v[7], r8 = r->v[8];
int32_t cond_add, cond_negate;
#ifdef VERIFY
/* Verify that all limbs are in range (-2^30,2^30). */
int i;
for (i = 0; i < 9; ++i) {
VERIFY_CHECK(r->v[i] >= -M30);
VERIFY_CHECK(r->v[i] <= M30);
}
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, -2) > 0); /* r > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */
#endif
/* In a first step, add the modulus if the input is negative, and then negate if requested.
* This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input
* limbs are in range (-2^30,2^30), this cannot overflow an int32_t. Note that the right
* shifts below are signed sign-extending shifts (see assumptions.h for tests that that is
* indeed the behavior of the right shift operator). */
cond_add = r8 >> 31;
r0 += modinfo->modulus.v[0] & cond_add;
r1 += modinfo->modulus.v[1] & cond_add;
r2 += modinfo->modulus.v[2] & cond_add;
r3 += modinfo->modulus.v[3] & cond_add;
r4 += modinfo->modulus.v[4] & cond_add;
r5 += modinfo->modulus.v[5] & cond_add;
r6 += modinfo->modulus.v[6] & cond_add;
r7 += modinfo->modulus.v[7] & cond_add;
r8 += modinfo->modulus.v[8] & cond_add;
cond_negate = sign >> 31;
r0 = (r0 ^ cond_negate) - cond_negate;
r1 = (r1 ^ cond_negate) - cond_negate;
r2 = (r2 ^ cond_negate) - cond_negate;
r3 = (r3 ^ cond_negate) - cond_negate;
r4 = (r4 ^ cond_negate) - cond_negate;
r5 = (r5 ^ cond_negate) - cond_negate;
r6 = (r6 ^ cond_negate) - cond_negate;
r7 = (r7 ^ cond_negate) - cond_negate;
r8 = (r8 ^ cond_negate) - cond_negate;
/* Propagate the top bits, to bring limbs back to range (-2^30,2^30). */
r1 += r0 >> 30; r0 &= M30;
r2 += r1 >> 30; r1 &= M30;
r3 += r2 >> 30; r2 &= M30;
r4 += r3 >> 30; r3 &= M30;
r5 += r4 >> 30; r4 &= M30;
r6 += r5 >> 30; r5 &= M30;
r7 += r6 >> 30; r6 &= M30;
r8 += r7 >> 30; r7 &= M30;
/* In a second step add the modulus again if the result is still negative, bringing r to range
* [0,modulus). */
cond_add = r8 >> 31;
r0 += modinfo->modulus.v[0] & cond_add;
r1 += modinfo->modulus.v[1] & cond_add;
r2 += modinfo->modulus.v[2] & cond_add;
r3 += modinfo->modulus.v[3] & cond_add;
r4 += modinfo->modulus.v[4] & cond_add;
r5 += modinfo->modulus.v[5] & cond_add;
r6 += modinfo->modulus.v[6] & cond_add;
r7 += modinfo->modulus.v[7] & cond_add;
r8 += modinfo->modulus.v[8] & cond_add;
/* And propagate again. */
r1 += r0 >> 30; r0 &= M30;
r2 += r1 >> 30; r1 &= M30;
r3 += r2 >> 30; r2 &= M30;
r4 += r3 >> 30; r3 &= M30;
r5 += r4 >> 30; r4 &= M30;
r6 += r5 >> 30; r5 &= M30;
r7 += r6 >> 30; r6 &= M30;
r8 += r7 >> 30; r7 &= M30;
r->v[0] = r0;
r->v[1] = r1;
r->v[2] = r2;
r->v[3] = r3;
r->v[4] = r4;
r->v[5] = r5;
r->v[6] = r6;
r->v[7] = r7;
r->v[8] = r8;
#ifdef VERIFY
VERIFY_CHECK(r0 >> 30 == 0);
VERIFY_CHECK(r1 >> 30 == 0);
VERIFY_CHECK(r2 >> 30 == 0);
VERIFY_CHECK(r3 >> 30 == 0);
VERIFY_CHECK(r4 >> 30 == 0);
VERIFY_CHECK(r5 >> 30 == 0);
VERIFY_CHECK(r6 >> 30 == 0);
VERIFY_CHECK(r7 >> 30 == 0);
VERIFY_CHECK(r8 >> 30 == 0);
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 0) >= 0); /* r >= 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */
#endif
}
/* Data type for transition matrices (see section 3 of explanation).
*
* t = [ u v ]
* [ q r ]
*/
typedef struct {
int32_t u, v, q, r;
} secp256k1_modinv32_trans2x2;
/* Compute the transition matrix and zeta for 30 divsteps.
*
* Input: zeta: initial zeta
* f0: bottom limb of initial f
* g0: bottom limb of initial g
* Output: t: transition matrix
* Return: final zeta
*
* Implements the divsteps_n_matrix function from the explanation.
*/
static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) {
/* u,v,q,r are the elements of the transformation matrix being built up,
* starting with the identity matrix. Semantically they are signed integers
* in range [-2^30,2^30], but here represented as unsigned mod 2^32. This
* permits left shifting (which is UB for negative numbers). The range
* being inside [-2^31,2^31) means that casting to signed works correctly.
*/
uint32_t u = 1, v = 0, q = 0, r = 1;
uint32_t c1, c2, f = f0, g = g0, x, y, z;
int i;
for (i = 0; i < 30; ++i) {
VERIFY_CHECK((f & 1) == 1); /* f must always be odd */
VERIFY_CHECK((u * f0 + v * g0) == f << i);
VERIFY_CHECK((q * f0 + r * g0) == g << i);
/* Compute conditional masks for (zeta < 0) and for (g & 1). */
c1 = zeta >> 31;
c2 = -(g & 1);
/* Compute x,y,z, conditionally negated versions of f,u,v. */
x = (f ^ c1) - c1;
y = (u ^ c1) - c1;
z = (v ^ c1) - c1;
/* Conditionally add x,y,z to g,q,r. */
g += x & c2;
q += y & c2;
r += z & c2;
/* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
c1 &= c2;
/* Conditionally change zeta into -zeta-2 or zeta-1. */
zeta = (zeta ^ c1) - 1;
/* Conditionally add g,q,r to f,u,v. */
f += g & c1;
u += q & c1;
v += r & c1;
/* Shifts */
g >>= 1;
u <<= 1;
v <<= 1;
/* Bounds on zeta that follow from the bounds on iteration count (max 20*30 divsteps). */
VERIFY_CHECK(zeta >= -601 && zeta <= 601);
}
/* 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, the
* aggregate of 30 of them will have determinant 2^30. */
VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30);
return zeta;
}
/* Compute the transition matrix and eta for 30 divsteps (variable time).
*
* Input: eta: initial eta
* f0: bottom limb of initial f
* g0: bottom limb of initial g
* Output: t: transition matrix
* Return: final eta
*
* 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) {
/* 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. */
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;
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;
/* We're done once we've done 30 divsteps. */
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));
/* Bounds on eta that follow from the bounds on iteration count (max 25*30 divsteps). */
VERIFY_CHECK(eta >= -751 && eta <= 751);
/* If eta is negative, negate it and replace f,g with g,-f. */
if (eta < 0) {
uint32_t tmp;
eta = -eta;
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 * 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, the
* aggregate of 30 of them will have determinant 2^30. */
VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30);
return eta;
}
/* 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
* (-2^30,2^30).
*
* This implements the update_de function from the explanation.
*/
static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp256k1_modinv32_signed30 *e, const secp256k1_modinv32_trans2x2 *t, const secp256k1_modinv32_modinfo* modinfo) {
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
const int32_t u = t->u, v = t->v, q = t->q, r = t->r;
int32_t di, ei, md, me, sd, se;
int64_t cd, ce;
int i;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
VERIFY_CHECK((labs(u) + labs(v)) >= 0); /* |u|+|v| doesn't overflow */
VERIFY_CHECK((labs(q) + labs(r)) >= 0); /* |q|+|r| doesn't overflow */
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
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d->v[8] >> 31;
se = e->v[8] >> 31;
md = (u & sd) + (v & se);
me = (q & sd) + (r & se);
/* Begin computing t*[d,e]. */
di = d->v[0];
ei = e->v[0];
cd = (int64_t)u * di + (int64_t)v * ei;
ce = (int64_t)q * di + (int64_t)r * ei;
/* Correct md,me so that t*[d,e]+modulus*[md,me] has 30 zero bottom bits. */
md -= (modinfo->modulus_inv30 * (uint32_t)cd + md) & M30;
me -= (modinfo->modulus_inv30 * (uint32_t)ce + me) & M30;
/* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
cd += (int64_t)modinfo->modulus.v[0] * md;
ce += (int64_t)modinfo->modulus.v[0] * me;
/* Verify that the low 30 bits of the computation are indeed zero, and then throw them away. */
VERIFY_CHECK(((int32_t)cd & M30) == 0); cd >>= 30;
VERIFY_CHECK(((int32_t)ce & M30) == 0); ce >>= 30;
/* Now iteratively compute limb i=1..8 of t*[d,e]+modulus*[md,me], and store them in output
* limb i-1 (shifting down by 30 bits). */
for (i = 1; i < 9; ++i) {
di = d->v[i];
ei = e->v[i];
cd += (int64_t)u * di + (int64_t)v * ei;
ce += (int64_t)q * di + (int64_t)r * ei;
cd += (int64_t)modinfo->modulus.v[i] * md;
ce += (int64_t)modinfo->modulus.v[i] * me;
d->v[i - 1] = (int32_t)cd & M30; cd >>= 30;
e->v[i - 1] = (int32_t)ce & M30; ce >>= 30;
}
/* What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. */
d->v[8] = (int32_t)cd;
e->v[8] = (int32_t)ce;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
#endif
}
/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps.
*
* This implements the update_fg function from the explanation.
*/
static void secp256k1_modinv32_update_fg_30(secp256k1_modinv32_signed30 *f, secp256k1_modinv32_signed30 *g, const secp256k1_modinv32_trans2x2 *t) {
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
const int32_t u = t->u, v = t->v, q = t->q, r = t->r;
int32_t fi, gi;
int64_t cf, cg;
int i;
/* Start computing t*[f,g]. */
fi = f->v[0];
gi = g->v[0];
cf = (int64_t)u * fi + (int64_t)v * gi;
cg = (int64_t)q * fi + (int64_t)r * gi;
/* Verify that the bottom 30 bits of the result are zero, and then throw them away. */
VERIFY_CHECK(((int32_t)cf & M30) == 0); cf >>= 30;
VERIFY_CHECK(((int32_t)cg & M30) == 0); cg >>= 30;
/* Now iteratively compute limb i=1..8 of t*[f,g], and store them in output limb i-1 (shifting
* down by 30 bits). */
for (i = 1; i < 9; ++i) {
fi = f->v[i];
gi = g->v[i];
cf += (int64_t)u * fi + (int64_t)v * gi;
cg += (int64_t)q * fi + (int64_t)r * gi;
f->v[i - 1] = (int32_t)cf & M30; cf >>= 30;
g->v[i - 1] = (int32_t)cg & M30; cg >>= 30;
}
/* What remains is limb 9 of t*[f,g]; store it as output limb 8. */
f->v[8] = (int32_t)cf;
g->v[8] = (int32_t)cg;
}
/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps.
*
* Version that operates on a variable number of limbs in f and g.
*
* This implements the update_fg function from the explanation in modinv64_impl.h.
*/
static void secp256k1_modinv32_update_fg_30_var(int len, secp256k1_modinv32_signed30 *f, secp256k1_modinv32_signed30 *g, const secp256k1_modinv32_trans2x2 *t) {
const int32_t M30 = (int32_t)(UINT32_MAX >> 2);
const int32_t u = t->u, v = t->v, q = t->q, r = t->r;
int32_t fi, gi;
int64_t cf, cg;
int i;
VERIFY_CHECK(len > 0);
/* Start computing t*[f,g]. */
fi = f->v[0];
gi = g->v[0];
cf = (int64_t)u * fi + (int64_t)v * gi;
cg = (int64_t)q * fi + (int64_t)r * gi;
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
VERIFY_CHECK(((int32_t)cf & M30) == 0); cf >>= 30;
VERIFY_CHECK(((int32_t)cg & M30) == 0); cg >>= 30;
/* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
* down by 30 bits). */
for (i = 1; i < len; ++i) {
fi = f->v[i];
gi = g->v[i];
cf += (int64_t)u * fi + (int64_t)v * gi;
cg += (int64_t)q * fi + (int64_t)r * gi;
f->v[i - 1] = (int32_t)cf & M30; cf >>= 30;
g->v[i - 1] = (int32_t)cg & M30; cg >>= 30;
}
/* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */
f->v[len - 1] = (int32_t)cf;
g->v[len - 1] = (int32_t)cg;
}
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */
static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) {
/* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */
secp256k1_modinv32_signed30 d = {{0}};
secp256k1_modinv32_signed30 e = {{1}};
secp256k1_modinv32_signed30 f = modinfo->modulus;
secp256k1_modinv32_signed30 g = *x;
int i;
int32_t zeta = -1; /* zeta = -(delta+1/2); delta is initially 1/2. */
/* Do 20 iterations of 30 divsteps each = 600 divsteps. 590 suffices for 256-bit inputs. */
for (i = 0; i < 20; ++i) {
/* Compute transition matrix and new zeta after 30 divsteps. */
secp256k1_modinv32_trans2x2 t;
zeta = secp256k1_modinv32_divsteps_30(zeta, f.v[0], g.v[0], &t);
/* Update d,e using that transition matrix. */
secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo);
/* Update f,g using that transition matrix. */
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
secp256k1_modinv32_update_fg_30(&f, &g, &t);
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
}
/* At this point sufficient iterations have been performed that g must have reached 0
* and (if g was not originally 0) f must now equal +/- GCD of the initial f, g
* values i.e. +/- 1, and d now contains +/- the modular inverse. */
#ifdef VERIFY
/* g == 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0);
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, -1) == 0 ||
secp256k1_modinv32_mul_cmp_30(&f, 9, &SECP256K1_SIGNED30_ONE, 1) == 0 ||
(secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0 ||
secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) == 0)));
#endif
/* Optionally negate d, normalize to [0,modulus), and return it. */
secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo);
*x = d;
}
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */
static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) {
/* Start with d=0, e=1, f=modulus, g=x, eta=-1. */
secp256k1_modinv32_signed30 d = {{0, 0, 0, 0, 0, 0, 0, 0, 0}};
secp256k1_modinv32_signed30 e = {{1, 0, 0, 0, 0, 0, 0, 0, 0}};
secp256k1_modinv32_signed30 f = modinfo->modulus;
secp256k1_modinv32_signed30 g = *x;
#ifdef VERIFY
int i = 0;
#endif
int j, len = 9;
int32_t eta = -1; /* eta = -delta; delta is initially 1 (faster for the variable-time code) */
int32_t cond, fn, gn;
/* Do iterations of 30 divsteps each until g=0. */
while (1) {
/* Compute transition matrix and new eta after 30 divsteps. */
secp256k1_modinv32_trans2x2 t;
eta = secp256k1_modinv32_divsteps_30_var(eta, f.v[0], g.v[0], &t);
/* Update d,e using that transition matrix. */
secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo);
/* Update f,g using that transition matrix. */
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
/* If the bottom limb of g is 0, there is a chance g=0. */
if (g.v[0] == 0) {
cond = 0;
/* Check if all other limbs are also 0. */
for (j = 1; j < len; ++j) {
cond |= g.v[j];
}
/* If so, we're done. */
if (cond == 0) break;
}
/* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */
fn = f.v[len - 1];
gn = g.v[len - 1];
cond = ((int32_t)len - 2) >> 31;
cond |= fn ^ (fn >> 31);
cond |= gn ^ (gn >> 31);
/* If so, reduce length, propagating the sign of f and g's top limb into the one below. */
if (cond == 0) {
f.v[len - 2] |= (uint32_t)fn << 30;
g.v[len - 2] |= (uint32_t)gn << 30;
--len;
}
#ifdef VERIFY
VERIFY_CHECK(++i < 25); /* We should never need more than 25*30 = 750 divsteps */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
}
/* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of
* the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */
#ifdef VERIFY
/* g == 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0);
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, -1) == 0 ||
secp256k1_modinv32_mul_cmp_30(&f, len, &SECP256K1_SIGNED30_ONE, 1) == 0 ||
(secp256k1_modinv32_mul_cmp_30(x, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0 ||
secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) == 0)));
#endif
/* Optionally negate d, normalize to [0,modulus), and return it. */
secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo);
*x = d;
}
#endif /* SECP256K1_MODINV32_IMPL_H */

46
src/modinv64.h Normal file
View file

@ -0,0 +1,46 @@
/***********************************************************************
* Copyright (c) 2020 Peter Dettman *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODINV64_H
#define SECP256K1_MODINV64_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h"
#ifndef SECP256K1_WIDEMUL_INT128
#error "modinv64 requires 128-bit wide multiplication support"
#endif
/* A signed 62-bit limb representation of integers.
*
* Its value is sum(v[i] * 2^(62*i), i=0..4). */
typedef struct {
int64_t v[5];
} secp256k1_modinv64_signed62;
typedef struct {
/* The modulus in signed62 notation, must be odd and in [3, 2^256]. */
secp256k1_modinv64_signed62 modulus;
/* modulus^{-1} mod 2^62 */
uint64_t modulus_inv62;
} secp256k1_modinv64_modinfo;
/* Replace x with its modular inverse mod modinfo->modulus. x must be in range [0, modulus).
* If x is zero, the result will be zero as well. If not, the inverse must exist (i.e., the gcd of
* x and modulus must be 1). These rules are automatically satisfied if the modulus is prime.
*
* On output, all of x's limbs will be in [0, 2^62).
*/
static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
/* 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);
#endif /* SECP256K1_MODINV64_H */

593
src/modinv64_impl.h Normal file
View file

@ -0,0 +1,593 @@
/***********************************************************************
* Copyright (c) 2020 Peter Dettman *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODINV64_IMPL_H
#define SECP256K1_MODINV64_IMPL_H
#include "modinv64.h"
#include "util.h"
/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and
* modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
*
* For an explanation of the algorithm, see doc/safegcd_implementation.md. This file contains an
* implementation for N=62, using 62-bit signed limbs represented as int64_t.
*/
#ifdef VERIFY
/* Helper function to compute the absolute value of an int64_t.
* (we don't use abs/labs/llabs as it depends on the int sizes). */
static int64_t secp256k1_modinv64_abs(int64_t v) {
VERIFY_CHECK(v > INT64_MIN);
if (v < 0) return -v;
return v;
}
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). */
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);
int128_t c = 0;
int i;
for (i = 0; i < 4; ++i) {
if (i < alen) c += (int128_t)a->v[i] * factor;
r->v[i] = (int64_t)c & M62; c >>= 62;
}
if (4 < alen) c += (int128_t)a->v[4] * factor;
VERIFY_CHECK(c == (int64_t)c);
r->v[4] = (int64_t)c;
}
/* Return -1 for a<b*factor, 0 for a==b*factor, 1 for a>b*factor. A has alen limbs; b has 5. */
static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, int alen, const secp256k1_modinv64_signed62 *b, int64_t factor) {
int i;
secp256k1_modinv64_signed62 am, bm;
secp256k1_modinv64_mul_62(&am, a, alen, 1); /* Normalize all but the top limb of a. */
secp256k1_modinv64_mul_62(&bm, b, 5, factor);
for (i = 0; i < 4; ++i) {
/* Verify that all but the top limb of a and b are normalized. */
VERIFY_CHECK(am.v[i] >> 62 == 0);
VERIFY_CHECK(bm.v[i] >> 62 == 0);
}
for (i = 4; i >= 0; --i) {
if (am.v[i] < bm.v[i]) return -1;
if (am.v[i] > bm.v[i]) return 1;
}
return 0;
}
#endif
/* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus
* to it to bring it to range [0,modulus). If sign < 0, the input will also be negated in the
* process. The input must have limbs in range (-2^62,2^62). The output will have limbs in range
* [0,2^62). */
static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int64_t sign, const secp256k1_modinv64_modinfo *modinfo) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
int64_t r0 = r->v[0], r1 = r->v[1], r2 = r->v[2], r3 = r->v[3], r4 = r->v[4];
int64_t cond_add, cond_negate;
#ifdef VERIFY
/* Verify that all limbs are in range (-2^62,2^62). */
int i;
for (i = 0; i < 5; ++i) {
VERIFY_CHECK(r->v[i] >= -M62);
VERIFY_CHECK(r->v[i] <= M62);
}
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, -2) > 0); /* r > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */
#endif
/* In a first step, add the modulus if the input is negative, and then negate if requested.
* This brings r from range (-2*modulus,modulus) to range (-modulus,modulus). As all input
* limbs are in range (-2^62,2^62), this cannot overflow an int64_t. Note that the right
* shifts below are signed sign-extending shifts (see assumptions.h for tests that that is
* indeed the behavior of the right shift operator). */
cond_add = r4 >> 63;
r0 += modinfo->modulus.v[0] & cond_add;
r1 += modinfo->modulus.v[1] & cond_add;
r2 += modinfo->modulus.v[2] & cond_add;
r3 += modinfo->modulus.v[3] & cond_add;
r4 += modinfo->modulus.v[4] & cond_add;
cond_negate = sign >> 63;
r0 = (r0 ^ cond_negate) - cond_negate;
r1 = (r1 ^ cond_negate) - cond_negate;
r2 = (r2 ^ cond_negate) - cond_negate;
r3 = (r3 ^ cond_negate) - cond_negate;
r4 = (r4 ^ cond_negate) - cond_negate;
/* Propagate the top bits, to bring limbs back to range (-2^62,2^62). */
r1 += r0 >> 62; r0 &= M62;
r2 += r1 >> 62; r1 &= M62;
r3 += r2 >> 62; r2 &= M62;
r4 += r3 >> 62; r3 &= M62;
/* In a second step add the modulus again if the result is still negative, bringing
* r to range [0,modulus). */
cond_add = r4 >> 63;
r0 += modinfo->modulus.v[0] & cond_add;
r1 += modinfo->modulus.v[1] & cond_add;
r2 += modinfo->modulus.v[2] & cond_add;
r3 += modinfo->modulus.v[3] & cond_add;
r4 += modinfo->modulus.v[4] & cond_add;
/* And propagate again. */
r1 += r0 >> 62; r0 &= M62;
r2 += r1 >> 62; r1 &= M62;
r3 += r2 >> 62; r2 &= M62;
r4 += r3 >> 62; r3 &= M62;
r->v[0] = r0;
r->v[1] = r1;
r->v[2] = r2;
r->v[3] = r3;
r->v[4] = r4;
#ifdef VERIFY
VERIFY_CHECK(r0 >> 62 == 0);
VERIFY_CHECK(r1 >> 62 == 0);
VERIFY_CHECK(r2 >> 62 == 0);
VERIFY_CHECK(r3 >> 62 == 0);
VERIFY_CHECK(r4 >> 62 == 0);
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 0) >= 0); /* r >= 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */
#endif
}
/* Data type for transition matrices (see section 3 of explanation).
*
* t = [ u v ]
* [ q r ]
*/
typedef struct {
int64_t u, v, q, r;
} secp256k1_modinv64_trans2x2;
/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)).
* Note that the transformation matrix is scaled by 2^62 and not 2^59.
*
* Input: zeta: initial zeta
* f0: bottom limb of initial f
* g0: bottom limb of initial g
* Output: t: transition matrix
* Return: final zeta
*
* Implements the divsteps_n_matrix function from the explanation.
*/
static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t) {
/* u,v,q,r are the elements of the transformation matrix being built up,
* starting with the identity matrix times 8 (because the caller expects
* a result scaled by 2^62). Semantically they are signed integers
* in range [-2^62,2^62], but here represented as unsigned mod 2^64. This
* permits left shifting (which is UB for negative numbers). The range
* being inside [-2^63,2^63) means that casting to signed works correctly.
*/
uint64_t u = 8, v = 0, q = 0, r = 8;
uint64_t c1, c2, f = f0, g = g0, x, y, z;
int i;
for (i = 3; i < 62; ++i) {
VERIFY_CHECK((f & 1) == 1); /* f must always be odd */
VERIFY_CHECK((u * f0 + v * g0) == f << i);
VERIFY_CHECK((q * f0 + r * g0) == g << i);
/* Compute conditional masks for (zeta < 0) and for (g & 1). */
c1 = zeta >> 63;
c2 = -(g & 1);
/* Compute x,y,z, conditionally negated versions of f,u,v. */
x = (f ^ c1) - c1;
y = (u ^ c1) - c1;
z = (v ^ c1) - c1;
/* Conditionally add x,y,z to g,q,r. */
g += x & c2;
q += y & c2;
r += z & c2;
/* In what follows, c1 is a condition mask for (zeta < 0) and (g & 1). */
c1 &= c2;
/* Conditionally change zeta into -zeta-2 or zeta-1. */
zeta = (zeta ^ c1) - 1;
/* Conditionally add g,q,r to f,u,v. */
f += g & c1;
u += q & c1;
v += r & c1;
/* Shifts */
g >>= 1;
u <<= 1;
v <<= 1;
/* Bounds on zeta that follow from the bounds on iteration count (max 10*59 divsteps). */
VERIFY_CHECK(zeta >= -591 && zeta <= 591);
}
/* 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;
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the
* aggregate of 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
* 2^65. */
VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 65);
return zeta;
}
/* Compute the transition matrix and eta for 62 divsteps (variable time, eta=-delta).
*
* Input: eta: initial eta
* f0: bottom limb of initial f
* g0: bottom limb of initial g
* Output: t: transition matrix
* Return: final eta
*
* Implements the divsteps_n_matrix_var function from the explanation.
*/
static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t) {
/* 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;
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;
/* We're done once we've done 62 divsteps. */
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));
/* Bounds on eta that follow from the bounds on iteration count (max 12*62 divsteps). */
VERIFY_CHECK(eta >= -745 && eta <= 745);
/* 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;
/* 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
* 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;
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the
* aggregate of 62 of them will have determinant 2^62. */
VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 62);
return eta;
}
/* 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
* (-2^62,2^62).
*
* 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) {
const int64_t M62 = (int64_t)(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 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;
int64_t md, me, sd, se;
int128_t cd, ce;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) >= 0); /* |u|+|v| doesn't overflow */
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) >= 0); /* |q|+|r| doesn't overflow */
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
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d4 >> 63;
se = e4 >> 63;
md = (u & sd) + (v & se);
me = (q & sd) + (r & se);
/* Begin computing t*[d,e]. */
cd = (int128_t)u * d0 + (int128_t)v * e0;
ce = (int128_t)q * d0 + (int128_t)r * e0;
/* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */
md -= (modinfo->modulus_inv62 * (uint64_t)cd + md) & M62;
me -= (modinfo->modulus_inv62 * (uint64_t)ce + me) & M62;
/* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
cd += (int128_t)modinfo->modulus.v[0] * md;
ce += (int128_t)modinfo->modulus.v[0] * me;
/* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */
VERIFY_CHECK(((int64_t)cd & M62) == 0); cd >>= 62;
VERIFY_CHECK(((int64_t)ce & M62) == 0); ce >>= 62;
/* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */
cd += (int128_t)u * d1 + (int128_t)v * e1;
ce += (int128_t)q * d1 + (int128_t)r * e1;
if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */
cd += (int128_t)modinfo->modulus.v[1] * md;
ce += (int128_t)modinfo->modulus.v[1] * me;
}
d->v[0] = (int64_t)cd & M62; cd >>= 62;
e->v[0] = (int64_t)ce & M62; ce >>= 62;
/* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */
cd += (int128_t)u * d2 + (int128_t)v * e2;
ce += (int128_t)q * d2 + (int128_t)r * e2;
if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */
cd += (int128_t)modinfo->modulus.v[2] * md;
ce += (int128_t)modinfo->modulus.v[2] * me;
}
d->v[1] = (int64_t)cd & M62; cd >>= 62;
e->v[1] = (int64_t)ce & M62; ce >>= 62;
/* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */
cd += (int128_t)u * d3 + (int128_t)v * e3;
ce += (int128_t)q * d3 + (int128_t)r * e3;
if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */
cd += (int128_t)modinfo->modulus.v[3] * md;
ce += (int128_t)modinfo->modulus.v[3] * me;
}
d->v[2] = (int64_t)cd & M62; cd >>= 62;
e->v[2] = (int64_t)ce & M62; ce >>= 62;
/* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */
cd += (int128_t)u * d4 + (int128_t)v * e4;
ce += (int128_t)q * d4 + (int128_t)r * e4;
cd += (int128_t)modinfo->modulus.v[4] * md;
ce += (int128_t)modinfo->modulus.v[4] * me;
d->v[3] = (int64_t)cd & M62; cd >>= 62;
e->v[3] = (int64_t)ce & M62; ce >>= 62;
/* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
d->v[4] = (int64_t)cd;
e->v[4] = (int64_t)ce;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
#endif
}
/* Compute (t/2^62) * [f, g], where t is a transition matrix scaled by 2^62.
*
* 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) {
const int64_t M62 = (int64_t)(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 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;
int128_t cf, cg;
/* Start computing t*[f,g]. */
cf = (int128_t)u * f0 + (int128_t)v * g0;
cg = (int128_t)q * f0 + (int128_t)r * g0;
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62;
VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62;
/* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */
cf += (int128_t)u * f1 + (int128_t)v * g1;
cg += (int128_t)q * f1 + (int128_t)r * g1;
f->v[0] = (int64_t)cf & M62; cf >>= 62;
g->v[0] = (int64_t)cg & M62; cg >>= 62;
/* Compute limb 2 of t*[f,g], and store it as output limb 1. */
cf += (int128_t)u * f2 + (int128_t)v * g2;
cg += (int128_t)q * f2 + (int128_t)r * g2;
f->v[1] = (int64_t)cf & M62; cf >>= 62;
g->v[1] = (int64_t)cg & M62; cg >>= 62;
/* Compute limb 3 of t*[f,g], and store it as output limb 2. */
cf += (int128_t)u * f3 + (int128_t)v * g3;
cg += (int128_t)q * f3 + (int128_t)r * g3;
f->v[2] = (int64_t)cf & M62; cf >>= 62;
g->v[2] = (int64_t)cg & M62; cg >>= 62;
/* Compute limb 4 of t*[f,g], and store it as output limb 3. */
cf += (int128_t)u * f4 + (int128_t)v * g4;
cg += (int128_t)q * f4 + (int128_t)r * g4;
f->v[3] = (int64_t)cf & M62; cf >>= 62;
g->v[3] = (int64_t)cg & M62; cg >>= 62;
/* What remains is limb 5 of t*[f,g]; store it as output limb 4. */
f->v[4] = (int64_t)cf;
g->v[4] = (int64_t)cg;
}
/* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps.
*
* Version that operates on a variable number of limbs in f and g.
*
* 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) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int64_t fi, gi;
int128_t cf, cg;
int i;
VERIFY_CHECK(len > 0);
/* Start computing t*[f,g]. */
fi = f->v[0];
gi = g->v[0];
cf = (int128_t)u * fi + (int128_t)v * gi;
cg = (int128_t)q * fi + (int128_t)r * gi;
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62;
VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62;
/* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
* down by 62 bits). */
for (i = 1; i < len; ++i) {
fi = f->v[i];
gi = g->v[i];
cf += (int128_t)u * fi + (int128_t)v * gi;
cg += (int128_t)q * fi + (int128_t)r * gi;
f->v[i - 1] = (int64_t)cf & M62; cf >>= 62;
g->v[i - 1] = (int64_t)cg & M62; cg >>= 62;
}
/* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */
f->v[len - 1] = (int64_t)cf;
g->v[len - 1] = (int64_t)cg;
}
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */
static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) {
/* Start with d=0, e=1, f=modulus, g=x, zeta=-1. */
secp256k1_modinv64_signed62 d = {{0, 0, 0, 0, 0}};
secp256k1_modinv64_signed62 e = {{1, 0, 0, 0, 0}};
secp256k1_modinv64_signed62 f = modinfo->modulus;
secp256k1_modinv64_signed62 g = *x;
int i;
int64_t zeta = -1; /* zeta = -(delta+1/2); delta starts at 1/2. */
/* Do 10 iterations of 59 divsteps each = 590 divsteps. This suffices for 256-bit inputs. */
for (i = 0; i < 10; ++i) {
/* Compute transition matrix and new zeta after 59 divsteps. */
secp256k1_modinv64_trans2x2 t;
zeta = secp256k1_modinv64_divsteps_59(zeta, f.v[0], g.v[0], &t);
/* Update d,e using that transition matrix. */
secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo);
/* Update f,g using that transition matrix. */
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
secp256k1_modinv64_update_fg_62(&f, &g, &t);
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
}
/* At this point sufficient iterations have been performed that g must have reached 0
* and (if g was not originally 0) f must now equal +/- GCD of the initial f, g
* values i.e. +/- 1, and d now contains +/- the modular inverse. */
#ifdef VERIFY
/* g == 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0);
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, -1) == 0 ||
secp256k1_modinv64_mul_cmp_62(&f, 5, &SECP256K1_SIGNED62_ONE, 1) == 0 ||
(secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0 ||
secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) == 0)));
#endif
/* Optionally negate d, normalize to [0,modulus), and return it. */
secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo);
*x = d;
}
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (variable time). */
static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) {
/* Start with d=0, e=1, f=modulus, g=x, eta=-1. */
secp256k1_modinv64_signed62 d = {{0, 0, 0, 0, 0}};
secp256k1_modinv64_signed62 e = {{1, 0, 0, 0, 0}};
secp256k1_modinv64_signed62 f = modinfo->modulus;
secp256k1_modinv64_signed62 g = *x;
#ifdef VERIFY
int i = 0;
#endif
int j, len = 5;
int64_t eta = -1; /* eta = -delta; delta is initially 1 */
int64_t cond, fn, gn;
/* Do iterations of 62 divsteps each until g=0. */
while (1) {
/* Compute transition matrix and new eta after 62 divsteps. */
secp256k1_modinv64_trans2x2 t;
eta = secp256k1_modinv64_divsteps_62_var(eta, f.v[0], g.v[0], &t);
/* Update d,e using that transition matrix. */
secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo);
/* Update f,g using that transition matrix. */
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
/* If the bottom limb of g is zero, there is a chance that g=0. */
if (g.v[0] == 0) {
cond = 0;
/* Check if the other limbs are also 0. */
for (j = 1; j < len; ++j) {
cond |= g.v[j];
}
/* If so, we're done. */
if (cond == 0) break;
}
/* Determine if len>1 and limb (len-1) of both f and g is 0 or -1. */
fn = f.v[len - 1];
gn = g.v[len - 1];
cond = ((int64_t)len - 2) >> 63;
cond |= fn ^ (fn >> 63);
cond |= gn ^ (gn >> 63);
/* If so, reduce length, propagating the sign of f and g's top limb into the one below. */
if (cond == 0) {
f.v[len - 2] |= (uint64_t)fn << 62;
g.v[len - 2] |= (uint64_t)gn << 62;
--len;
}
#ifdef VERIFY
VERIFY_CHECK(++i < 12); /* We should never need more than 12*62 = 744 divsteps */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
}
/* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of
* the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */
#ifdef VERIFY
/* g == 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0);
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, -1) == 0 ||
secp256k1_modinv64_mul_cmp_62(&f, len, &SECP256K1_SIGNED62_ONE, 1) == 0 ||
(secp256k1_modinv64_mul_cmp_62(x, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0 ||
secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) == 0)));
#endif
/* Optionally negate d, normalize to [0,modulus), and return it. */
secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo);
*x = d;
}
#endif /* SECP256K1_MODINV64_IMPL_H */

View file

@ -1,14 +1,14 @@
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_MODULE_ECDH_MAIN_H
#define SECP256K1_MODULE_ECDH_MAIN_H
#include "include/secp256k1_ecdh.h"
#include "ecmult_const_impl.h"
#include "../../../include/secp256k1_ecdh.h"
#include "../../ecmult_const_impl.h"
static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
unsigned char version = (y32[31] & 0x01) | 0x02;

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2015 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_MODULE_ECDH_TESTS_H
#define SECP256K1_MODULE_ECDH_TESTS_H

View file

@ -0,0 +1,4 @@
include_HEADERS += include/secp256k1_ecdsa_adaptor.h
noinst_HEADERS += src/modules/ecdsa_adaptor/main_impl.h
noinst_HEADERS += src/modules/ecdsa_adaptor/dleq_impl.h
noinst_HEADERS += src/modules/ecdsa_adaptor/tests_impl.h

View file

@ -0,0 +1,158 @@
#ifndef SECP256K1_DLEQ_IMPL_H
#define SECP256K1_DLEQ_IMPL_H
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("DLEQ")||SHA256("DLEQ"). */
static void secp256k1_nonce_function_dleq_sha256_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0x8cc4beacul;
sha->s[1] = 0x2e011f3ful;
sha->s[2] = 0x355c75fbul;
sha->s[3] = 0x3ba6a2c5ul;
sha->s[4] = 0xe96f3aeful;
sha->s[5] = 0x180530fdul;
sha->s[6] = 0x94582499ul;
sha->s[7] = 0x577fd564ul;
sha->bytes = 64;
}
/* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */
static const unsigned char dleq_algo[4] = "DLEQ";
static int secp256k1_dleq_hash_point(secp256k1_sha256 *sha, secp256k1_ge *p) {
unsigned char buf[33];
size_t size = 33;
if (!secp256k1_eckey_pubkey_serialize(p, buf, &size, 1)) {
return 0;
}
secp256k1_sha256_write(sha, buf, size);
return 1;
}
static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *sk32, const unsigned char *gen2_33, const unsigned char *p1_33, const unsigned char *p2_33, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
secp256k1_sha256 sha;
unsigned char buf[32];
unsigned char nonce[32];
size_t size = 33;
if (noncefp == NULL) {
noncefp = secp256k1_nonce_function_ecdsa_adaptor;
}
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, p1_33, size);
secp256k1_sha256_write(&sha, p2_33, size);
secp256k1_sha256_finalize(&sha, buf);
if (!noncefp(nonce, buf, sk32, gen2_33, dleq_algo, sizeof(dleq_algo), ndata)) {
return 0;
}
secp256k1_scalar_set_b32(k, nonce, NULL);
if (secp256k1_scalar_is_zero(k)) {
return 0;
}
return 1;
}
/* Generates a challenge as defined in the DLC Specification at
* https://github.com/discreetlogcontracts/dlcspecs */
static void secp256k1_dleq_challenge(secp256k1_scalar *e, secp256k1_ge *gen2, secp256k1_ge *r1, secp256k1_ge *r2, secp256k1_ge *p1, secp256k1_ge *p2) {
unsigned char buf[32];
secp256k1_sha256 sha;
secp256k1_nonce_function_dleq_sha256_tagged(&sha);
secp256k1_dleq_hash_point(&sha, p1);
secp256k1_dleq_hash_point(&sha, gen2);
secp256k1_dleq_hash_point(&sha, p2);
secp256k1_dleq_hash_point(&sha, r1);
secp256k1_dleq_hash_point(&sha, r2);
secp256k1_sha256_finalize(&sha, buf);
secp256k1_scalar_set_b32(e, buf, NULL);
}
/* P1 = x*G, P2 = x*Y */
static void secp256k1_dleq_pair(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_ge *p1, secp256k1_ge *p2, const secp256k1_scalar *sk, const secp256k1_ge *gen2) {
secp256k1_gej p1j, p2j;
secp256k1_ecmult_gen(ecmult_gen_ctx, &p1j, sk);
secp256k1_ge_set_gej(p1, &p1j);
secp256k1_ecmult_const(&p2j, gen2, sk, 256);
secp256k1_ge_set_gej(p2, &p2j);
}
/* Generates a proof that the discrete logarithm of P1 to the secp256k1 base G is the
* same as the discrete logarithm of P2 to the base Y */
static int secp256k1_dleq_prove(const secp256k1_context* ctx, secp256k1_scalar *s, secp256k1_scalar *e, const secp256k1_scalar *sk, secp256k1_ge *gen2, secp256k1_ge *p1, secp256k1_ge *p2, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
secp256k1_ge r1, r2;
secp256k1_scalar k = { 0 };
unsigned char sk32[32];
unsigned char gen2_33[33];
unsigned char p1_33[33];
unsigned char p2_33[33];
int ret = 1;
size_t pubkey_size = 33;
secp256k1_scalar_get_b32(sk32, sk);
if (!secp256k1_eckey_pubkey_serialize(gen2, gen2_33, &pubkey_size, 1)) {
return 0;
}
if (!secp256k1_eckey_pubkey_serialize(p1, p1_33, &pubkey_size, 1)) {
return 0;
}
if (!secp256k1_eckey_pubkey_serialize(p2, p2_33, &pubkey_size, 1)) {
return 0;
}
ret &= secp256k1_dleq_nonce(&k, sk32, gen2_33, p1_33, p2_33, noncefp, ndata);
/* R1 = k*G, R2 = k*Y */
secp256k1_dleq_pair(&ctx->ecmult_gen_ctx, &r1, &r2, &k, gen2);
/* We declassify the non-secret values r1 and r2 to allow using them as
* branch points. */
secp256k1_declassify(ctx, &r1, sizeof(r1));
secp256k1_declassify(ctx, &r2, sizeof(r2));
/* e = tagged hash(p1, gen2, p2, r1, r2) */
/* s = k + e * sk */
secp256k1_dleq_challenge(e, gen2, &r1, &r2, p1, p2);
secp256k1_scalar_mul(s, e, sk);
secp256k1_scalar_add(s, s, &k);
secp256k1_scalar_clear(&k);
return ret;
}
static int secp256k1_dleq_verify(const secp256k1_ecmult_context *ecmult_ctx, const secp256k1_scalar *s, const secp256k1_scalar *e, secp256k1_ge *p1, secp256k1_ge *gen2, secp256k1_ge *p2) {
secp256k1_scalar e_neg;
secp256k1_scalar e_expected;
secp256k1_gej gen2j;
secp256k1_gej p1j, p2j;
secp256k1_gej r1j, r2j;
secp256k1_ge r1, r2;
secp256k1_gej tmpj;
secp256k1_gej_set_ge(&p1j, p1);
secp256k1_gej_set_ge(&p2j, p2);
secp256k1_scalar_negate(&e_neg, e);
/* R1 = s*G - e*P1 */
secp256k1_ecmult(ecmult_ctx, &r1j, &p1j, &e_neg, s);
/* R2 = s*gen2 - e*P2 */
secp256k1_ecmult(ecmult_ctx, &tmpj, &p2j, &e_neg, &secp256k1_scalar_zero);
secp256k1_gej_set_ge(&gen2j, gen2);
secp256k1_ecmult(ecmult_ctx, &r2j, &gen2j, s, &secp256k1_scalar_zero);
secp256k1_gej_add_var(&r2j, &r2j, &tmpj, NULL);
secp256k1_ge_set_gej(&r1, &r1j);
secp256k1_ge_set_gej(&r2, &r2j);
secp256k1_dleq_challenge(&e_expected, gen2, &r1, &r2, p1, p2);
secp256k1_scalar_add(&e_expected, &e_expected, &e_neg);
return secp256k1_scalar_is_zero(&e_expected);
}
#endif

View file

@ -0,0 +1,376 @@
/**********************************************************************
* Copyright (c) 2020-2021 Jonas Nick, Jesse Posner *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H
#define SECP256K1_MODULE_ECDSA_ADAPTOR_MAIN_H
#include "include/secp256k1_ecdsa_adaptor.h"
#include "modules/ecdsa_adaptor/dleq_impl.h"
/* (R, R', s', dleq_proof) */
static int secp256k1_ecdsa_adaptor_sig_serialize(unsigned char *adaptor_sig162, secp256k1_ge *r, secp256k1_ge *rp, const secp256k1_scalar *sp, const secp256k1_scalar *dleq_proof_e, const secp256k1_scalar *dleq_proof_s) {
size_t size = 33;
if (!secp256k1_eckey_pubkey_serialize(r, adaptor_sig162, &size, 1)) {
return 0;
}
if (!secp256k1_eckey_pubkey_serialize(rp, &adaptor_sig162[33], &size, 1)) {
return 0;
}
secp256k1_scalar_get_b32(&adaptor_sig162[66], sp);
secp256k1_scalar_get_b32(&adaptor_sig162[98], dleq_proof_e);
secp256k1_scalar_get_b32(&adaptor_sig162[130], dleq_proof_s);
return 1;
}
static int secp256k1_ecdsa_adaptor_sig_deserialize(secp256k1_ge *r, secp256k1_scalar *sigr, secp256k1_ge *rp, secp256k1_scalar *sp, secp256k1_scalar *dleq_proof_e, secp256k1_scalar *dleq_proof_s, const unsigned char *adaptor_sig162) {
/* If r is deserialized, require that a sigr is provided to receive
* the X-coordinate */
VERIFY_CHECK((r == NULL) || (r != NULL && sigr != NULL));
if (r != NULL) {
if (!secp256k1_eckey_pubkey_parse(r, &adaptor_sig162[0], 33)) {
return 0;
}
}
if (sigr != NULL) {
secp256k1_scalar_set_b32(sigr, &adaptor_sig162[1], NULL);
if (secp256k1_scalar_is_zero(sigr)) {
return 0;
}
}
if (rp != NULL) {
if (!secp256k1_eckey_pubkey_parse(rp, &adaptor_sig162[33], 33)) {
return 0;
}
}
if (sp != NULL) {
if (!secp256k1_scalar_set_b32_seckey(sp, &adaptor_sig162[66])) {
return 0;
}
}
if (dleq_proof_e != NULL) {
secp256k1_scalar_set_b32(dleq_proof_e, &adaptor_sig162[98], NULL);
}
if (dleq_proof_s != NULL) {
int overflow;
secp256k1_scalar_set_b32(dleq_proof_s, &adaptor_sig162[130], &overflow);
if (overflow) {
return 0;
}
}
return 1;
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("ECDSAadaptor/non")||SHA256("ECDSAadaptor/non"). */
static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0x791dae43ul;
sha->s[1] = 0xe52d3b44ul;
sha->s[2] = 0x37f9edeaul;
sha->s[3] = 0x9bfd2ab1ul;
sha->s[4] = 0xcfb0f44dul;
sha->s[5] = 0xccf1d880ul;
sha->s[6] = 0xd18f2c13ul;
sha->s[7] = 0xa37b9024ul;
sha->bytes = 64;
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("ECDSAadaptor/aux")||SHA256("ECDSAadaptor/aux"). */
static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0xd14c7bd9ul;
sha->s[1] = 0x095d35e6ul;
sha->s[2] = 0xb8490a88ul;
sha->s[3] = 0xfb00ef74ul;
sha->s[4] = 0x0baa488ful;
sha->s[5] = 0x69366693ul;
sha->s[6] = 0x1c81c5baul;
sha->s[7] = 0xc33b296aul;
sha->bytes = 64;
}
/* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */
static const unsigned char ecdsa_adaptor_algo[16] = "ECDSAadaptor/non";
/* Modified BIP-340 nonce function */
static int nonce_function_ecdsa_adaptor(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *pk33, const unsigned char *algo, size_t algolen, void *data) {
secp256k1_sha256 sha;
unsigned char masked_key[32];
int i;
if (algo == NULL) {
return 0;
}
if (data != NULL) {
secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux(&sha);
secp256k1_sha256_write(&sha, data, 32);
secp256k1_sha256_finalize(&sha, masked_key);
for (i = 0; i < 32; i++) {
masked_key[i] ^= key32[i];
}
}
/* Tag the hash with algo which is important to avoid nonce reuse across
* algorithims. An optimized tagging implementation is used if the default
* tag is provided. */
if (algolen == sizeof(ecdsa_adaptor_algo)
&& secp256k1_memcmp_var(algo, ecdsa_adaptor_algo, algolen) == 0) {
secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(&sha);
} else if (algolen == sizeof(dleq_algo)
&& secp256k1_memcmp_var(algo, dleq_algo, algolen) == 0) {
secp256k1_nonce_function_dleq_sha256_tagged(&sha);
} else {
secp256k1_sha256_initialize_tagged(&sha, algo, algolen);
}
/* Hash (masked-)key||pk||msg using the tagged hash as per BIP-340 */
if (data != NULL) {
secp256k1_sha256_write(&sha, masked_key, 32);
} else {
secp256k1_sha256_write(&sha, key32, 32);
}
secp256k1_sha256_write(&sha, pk33, 33);
secp256k1_sha256_write(&sha, msg32, 32);
secp256k1_sha256_finalize(&sha, nonce32);
return 1;
}
const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor = nonce_function_ecdsa_adaptor;
int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char *adaptor_sig162, unsigned char *seckey32, const secp256k1_pubkey *enckey, const unsigned char *msg32, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
secp256k1_scalar k;
secp256k1_gej rj, rpj;
secp256k1_ge r, rp;
secp256k1_ge enckey_ge;
secp256k1_scalar dleq_proof_s;
secp256k1_scalar dleq_proof_e;
secp256k1_scalar sk;
secp256k1_scalar msg;
secp256k1_scalar sp;
secp256k1_scalar sigr;
secp256k1_scalar n;
unsigned char nonce32[32] = { 0 };
unsigned char buf33[33];
size_t size = 33;
int ret = 1;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(adaptor_sig162 != NULL);
ARG_CHECK(seckey32 != NULL);
ARG_CHECK(enckey != NULL);
ARG_CHECK(msg32 != NULL);
secp256k1_scalar_clear(&dleq_proof_e);
secp256k1_scalar_clear(&dleq_proof_s);
if (noncefp == NULL) {
noncefp = secp256k1_nonce_function_ecdsa_adaptor;
}
ret &= secp256k1_pubkey_load(ctx, &enckey_ge, enckey);
ret &= secp256k1_eckey_pubkey_serialize(&enckey_ge, buf33, &size, 1);
ret &= !!noncefp(nonce32, msg32, seckey32, buf33, ecdsa_adaptor_algo, sizeof(ecdsa_adaptor_algo), ndata);
secp256k1_scalar_set_b32(&k, nonce32, NULL);
ret &= !secp256k1_scalar_is_zero(&k);
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
/* R' := k*G */
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rpj, &k);
secp256k1_ge_set_gej(&rp, &rpj);
/* R = k*Y; */
secp256k1_ecmult_const(&rj, &enckey_ge, &k, 256);
secp256k1_ge_set_gej(&r, &rj);
/* We declassify the non-secret values rp and r to allow using them
* as branch points. */
secp256k1_declassify(ctx, &rp, sizeof(rp));
secp256k1_declassify(ctx, &r, sizeof(r));
/* dleq_proof = DLEQ_prove(k, (R', Y, R)) */
ret &= secp256k1_dleq_prove(ctx, &dleq_proof_s, &dleq_proof_e, &k, &enckey_ge, &rp, &r, noncefp, ndata);
ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey32);
secp256k1_scalar_cmov(&sk, &secp256k1_scalar_one, !ret);
secp256k1_scalar_set_b32(&msg, msg32, NULL);
secp256k1_fe_normalize(&r.x);
secp256k1_fe_get_b32(buf33, &r.x);
secp256k1_scalar_set_b32(&sigr, buf33, NULL);
ret &= !secp256k1_scalar_is_zero(&sigr);
/* s' = k⁻¹(m + R.x * x) */
secp256k1_scalar_mul(&n, &sigr, &sk);
secp256k1_scalar_add(&n, &n, &msg);
secp256k1_scalar_inverse(&sp, &k);
secp256k1_scalar_mul(&sp, &sp, &n);
ret &= !secp256k1_scalar_is_zero(&sp);
/* return (R, R', s', dleq_proof) */
ret &= secp256k1_ecdsa_adaptor_sig_serialize(adaptor_sig162, &r, &rp, &sp, &dleq_proof_e, &dleq_proof_s);
secp256k1_memczero(adaptor_sig162, 162, !ret);
secp256k1_scalar_clear(&n);
secp256k1_scalar_clear(&k);
secp256k1_scalar_clear(&sk);
return ret;
}
int secp256k1_ecdsa_adaptor_verify(const secp256k1_context* ctx, const unsigned char *adaptor_sig162, const secp256k1_pubkey *pubkey, const unsigned char *msg32, const secp256k1_pubkey *enckey) {
secp256k1_scalar dleq_proof_s, dleq_proof_e;
secp256k1_scalar msg;
secp256k1_ge pubkey_ge;
secp256k1_ge r, rp;
secp256k1_scalar sp;
secp256k1_scalar sigr;
secp256k1_ge enckey_ge;
secp256k1_gej derived_rp;
secp256k1_scalar sn, u1, u2;
secp256k1_gej pubkeyj;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(adaptor_sig162 != NULL);
ARG_CHECK(pubkey != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(enckey != NULL);
if (!secp256k1_ecdsa_adaptor_sig_deserialize(&r, &sigr, &rp, &sp, &dleq_proof_e, &dleq_proof_s, adaptor_sig162)) {
return 0;
}
if (!secp256k1_pubkey_load(ctx, &enckey_ge, enckey)) {
return 0;
}
/* DLEQ_verify((R', Y, R), dleq_proof) */
if(!secp256k1_dleq_verify(&ctx->ecmult_ctx, &dleq_proof_s, &dleq_proof_e, &rp, &enckey_ge, &r)) {
return 0;
}
secp256k1_scalar_set_b32(&msg, msg32, NULL);
if (!secp256k1_pubkey_load(ctx, &pubkey_ge, pubkey)) {
return 0;
}
/* return R' == s'⁻¹(m * G + R.x * X) */
secp256k1_scalar_inverse_var(&sn, &sp);
secp256k1_scalar_mul(&u1, &sn, &msg);
secp256k1_scalar_mul(&u2, &sn, &sigr);
secp256k1_gej_set_ge(&pubkeyj, &pubkey_ge);
secp256k1_ecmult(&ctx->ecmult_ctx, &derived_rp, &pubkeyj, &u2, &u1);
if (secp256k1_gej_is_infinity(&derived_rp)) {
return 0;
}
secp256k1_gej_neg(&derived_rp, &derived_rp);
secp256k1_gej_add_ge_var(&derived_rp, &derived_rp, &rp, NULL);
return secp256k1_gej_is_infinity(&derived_rp);
}
int secp256k1_ecdsa_adaptor_decrypt(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sig, const unsigned char *deckey32, const unsigned char *adaptor_sig162) {
secp256k1_scalar deckey;
secp256k1_scalar sp;
secp256k1_scalar s;
secp256k1_scalar sigr;
int overflow;
int high;
int ret = 1;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(deckey32 != NULL);
ARG_CHECK(adaptor_sig162 != NULL);
secp256k1_scalar_clear(&sp);
secp256k1_scalar_set_b32(&deckey, deckey32, &overflow);
ret &= !overflow;
ret &= secp256k1_ecdsa_adaptor_sig_deserialize(NULL, &sigr, NULL, &sp, NULL, NULL, adaptor_sig162);
ret &= !secp256k1_scalar_is_zero(&deckey);
secp256k1_scalar_inverse(&s, &deckey);
/* s = s' * y⁻¹ */
secp256k1_scalar_mul(&s, &s, &sp);
high = secp256k1_scalar_is_high(&s);
secp256k1_scalar_cond_negate(&s, high);
secp256k1_ecdsa_signature_save(sig, &sigr, &s);
secp256k1_memczero(&sig->data[0], 64, !ret);
secp256k1_scalar_clear(&deckey);
secp256k1_scalar_clear(&sp);
secp256k1_scalar_clear(&s);
return ret;
}
int secp256k1_ecdsa_adaptor_recover(const secp256k1_context* ctx, unsigned char *deckey32, const secp256k1_ecdsa_signature *sig, const unsigned char *adaptor_sig162, const secp256k1_pubkey *enckey) {
secp256k1_scalar sp, adaptor_sigr;
secp256k1_scalar s, r;
secp256k1_scalar deckey;
secp256k1_ge enckey_expected_ge;
secp256k1_gej enckey_expected_gej;
unsigned char enckey33[33];
unsigned char enckey_expected33[33];
size_t size = 33;
int ret = 1;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(deckey32 != NULL);
ARG_CHECK(sig != NULL);
ARG_CHECK(adaptor_sig162 != NULL);
ARG_CHECK(enckey != NULL);
if (!secp256k1_ecdsa_adaptor_sig_deserialize(NULL, &adaptor_sigr, NULL, &sp, NULL, NULL, adaptor_sig162)) {
return 0;
}
secp256k1_ecdsa_signature_load(ctx, &r, &s, sig);
/* Check that we're not looking at some unrelated signature */
ret &= secp256k1_scalar_eq(&adaptor_sigr, &r);
/* y = s⁻¹ * s' */
ret &= !secp256k1_scalar_is_zero(&s);
secp256k1_scalar_inverse(&deckey, &s);
secp256k1_scalar_mul(&deckey, &deckey, &sp);
/* Deal with ECDSA malleability */
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &enckey_expected_gej, &deckey);
secp256k1_ge_set_gej(&enckey_expected_ge, &enckey_expected_gej);
/* We declassify non-secret enckey_expected_ge to allow using it as a
* branch point. */
secp256k1_declassify(ctx, &enckey_expected_ge, sizeof(enckey_expected_ge));
if (!secp256k1_eckey_pubkey_serialize(&enckey_expected_ge, enckey_expected33, &size, SECP256K1_EC_COMPRESSED)) {
/* Unreachable from tests (and other VERIFY builds) and therefore this
* branch should be ignored in test coverage analysis.
*
* Proof:
* eckey_pubkey_serialize fails <=> deckey = 0
* deckey = 0 <=> s^-1 = 0 or sp = 0
* case 1: s^-1 = 0 impossible by the definition of multiplicative
* inverse and because the scalar_inverse implementation
* VERIFY_CHECKs that the inputs are valid scalars.
* case 2: sp = 0 impossible because ecdsa_adaptor_sig_deserialize would have already failed
*/
return 0;
}
if (!secp256k1_ec_pubkey_serialize(ctx, enckey33, &size, enckey, SECP256K1_EC_COMPRESSED)) {
return 0;
}
if (secp256k1_memcmp_var(&enckey_expected33[1], &enckey33[1], 32) != 0) {
return 0;
}
if (enckey_expected33[0] != enckey33[0]) {
/* try Y_implied == -Y */
secp256k1_scalar_negate(&deckey, &deckey);
}
secp256k1_scalar_get_b32(deckey32, &deckey);
secp256k1_scalar_clear(&deckey);
secp256k1_scalar_clear(&sp);
secp256k1_scalar_clear(&s);
return ret;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,3 @@
include_HEADERS += include/secp256k1_ecdsa_s2c.h
noinst_HEADERS += src/modules/ecdsa_s2c/main_impl.h
noinst_HEADERS += src/modules/ecdsa_s2c/tests_impl.h

198
src/modules/ecdsa_s2c/main_impl.h Executable file
View file

@ -0,0 +1,198 @@
/**********************************************************************
* Copyright (c) 2019-2020 Marko Bencun, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODULE_ECDSA_S2C_MAIN_H
#define SECP256K1_MODULE_ECDSA_S2C_MAIN_H
#include "include/secp256k1.h"
#include "include/secp256k1_ecdsa_s2c.h"
static void secp256k1_ecdsa_s2c_opening_save(secp256k1_ecdsa_s2c_opening* opening, secp256k1_ge* ge) {
secp256k1_pubkey_save((secp256k1_pubkey*) opening, ge);
}
static int secp256k1_ecdsa_s2c_opening_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_ecdsa_s2c_opening* opening) {
return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey*) opening);
}
int secp256k1_ecdsa_s2c_opening_parse(const secp256k1_context* ctx, secp256k1_ecdsa_s2c_opening* opening, const unsigned char* input33) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(opening != NULL);
ARG_CHECK(input33 != NULL);
return secp256k1_ec_pubkey_parse(ctx, (secp256k1_pubkey*) opening, input33, 33);
}
int secp256k1_ecdsa_s2c_opening_serialize(const secp256k1_context* ctx, unsigned char* output33, const secp256k1_ecdsa_s2c_opening* opening) {
size_t out_len = 33;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(output33 != NULL);
ARG_CHECK(opening != NULL);
return secp256k1_ec_pubkey_serialize(ctx, output33, &out_len, (const secp256k1_pubkey*) opening, SECP256K1_EC_COMPRESSED);
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("s2c/ecdsa/point")||SHA256("s2c/ecdsa/point"). */
static void secp256k1_s2c_ecdsa_point_sha256_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0xa9b21c7bul;
sha->s[1] = 0x358c3e3eul;
sha->s[2] = 0x0b6863d1ul;
sha->s[3] = 0xc62b2035ul;
sha->s[4] = 0xb44b40ceul;
sha->s[5] = 0x254a8912ul;
sha->s[6] = 0x0f85d0d4ul;
sha->s[7] = 0x8a5bf91cul;
sha->bytes = 64;
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("s2c/ecdsa/data")||SHA256("s2c/ecdsa/data"). */
static void secp256k1_s2c_ecdsa_data_sha256_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0xfeefd675ul;
sha->s[1] = 0x73166c99ul;
sha->s[2] = 0xe2309cb8ul;
sha->s[3] = 0x6d458113ul;
sha->s[4] = 0x01d3a512ul;
sha->s[5] = 0x00e18112ul;
sha->s[6] = 0x37ee0874ul;
sha->s[7] = 0x421fc55ful;
sha->bytes = 64;
}
int secp256k1_ecdsa_s2c_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature* signature, secp256k1_ecdsa_s2c_opening* s2c_opening, const unsigned char
*msg32, const unsigned char *seckey, const unsigned char* s2c_data32) {
secp256k1_scalar r, s;
int ret;
unsigned char ndata[32];
secp256k1_sha256 s2c_sha;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(msg32 != NULL);
ARG_CHECK(signature != NULL);
ARG_CHECK(seckey != NULL);
ARG_CHECK(s2c_data32 != NULL);
/* Provide `s2c_data32` to the nonce function as additional data to
* derive the nonce. It is first hashed because it should be possible
* to derive nonces even if only a SHA256 commitment to the data is
* known. This is important in the ECDSA anti-exfil protocol. */
secp256k1_s2c_ecdsa_data_sha256_tagged(&s2c_sha);
secp256k1_sha256_write(&s2c_sha, s2c_data32, 32);
secp256k1_sha256_finalize(&s2c_sha, ndata);
secp256k1_s2c_ecdsa_point_sha256_tagged(&s2c_sha);
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, NULL, &s2c_sha, s2c_opening, s2c_data32, msg32, seckey, NULL, ndata);
secp256k1_scalar_cmov(&r, &secp256k1_scalar_zero, !ret);
secp256k1_scalar_cmov(&s, &secp256k1_scalar_zero, !ret);
secp256k1_ecdsa_signature_save(signature, &r, &s);
return ret;
}
int secp256k1_ecdsa_s2c_verify_commit(const secp256k1_context* ctx, const secp256k1_ecdsa_signature* sig, const unsigned char* data32, const secp256k1_ecdsa_s2c_opening* opening) {
secp256k1_ge commitment_ge;
secp256k1_ge original_pubnonce_ge;
unsigned char x_bytes[32];
secp256k1_scalar sigr, sigs, x_scalar;
secp256k1_sha256 s2c_sha;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(sig != NULL);
ARG_CHECK(data32 != NULL);
ARG_CHECK(opening != NULL);
if (!secp256k1_ecdsa_s2c_opening_load(ctx, &original_pubnonce_ge, opening)) {
return 0;
}
secp256k1_s2c_ecdsa_point_sha256_tagged(&s2c_sha);
if (!secp256k1_ec_commit(&ctx->ecmult_ctx, &commitment_ge, &original_pubnonce_ge, &s2c_sha, data32, 32)) {
return 0;
}
/* Check that sig_r == commitment_x (mod n)
* sig_r is the x coordinate of R represented by a scalar.
* commitment_x is the x coordinate of the commitment (field element).
*
* Note that we are only checking the x-coordinate -- this is because the y-coordinate
* is not part of the ECDSA signature (and therefore not part of the commitment!)
*/
secp256k1_ecdsa_signature_load(ctx, &sigr, &sigs, sig);
secp256k1_fe_normalize(&commitment_ge.x);
secp256k1_fe_get_b32(x_bytes, &commitment_ge.x);
/* Do not check overflow; overflowing a scalar does not affect whether
* or not the R value is a cryptographic commitment, only whether it
* is a valid R value for an ECDSA signature. If users care about that
* they should use `ecdsa_verify` or `anti_exfil_host_verify`. In other
* words, this check would be (at best) unnecessary, and (at worst)
* insufficient. */
secp256k1_scalar_set_b32(&x_scalar, x_bytes, NULL);
return secp256k1_scalar_eq(&sigr, &x_scalar);
}
/*** anti-exfil ***/
int secp256k1_ecdsa_anti_exfil_host_commit(const secp256k1_context* ctx, unsigned char* rand_commitment32, const unsigned char* rand32) {
secp256k1_sha256 sha;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(rand_commitment32 != NULL);
ARG_CHECK(rand32 != NULL);
secp256k1_s2c_ecdsa_data_sha256_tagged(&sha);
secp256k1_sha256_write(&sha, rand32, 32);
secp256k1_sha256_finalize(&sha, rand_commitment32);
return 1;
}
int secp256k1_ecdsa_anti_exfil_signer_commit(const secp256k1_context* ctx, secp256k1_ecdsa_s2c_opening* opening, const unsigned char* msg32, const unsigned char* seckey32, const unsigned char* rand_commitment32) {
unsigned char nonce32[32];
secp256k1_scalar k;
secp256k1_gej rj;
secp256k1_ge r;
unsigned int count = 0;
int is_nonce_valid = 0;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(opening != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(seckey32 != NULL);
ARG_CHECK(rand_commitment32 != NULL);
memset(nonce32, 0, 32);
while (!is_nonce_valid) {
/* cast to void* removes const qualifier, but secp256k1_nonce_function_default does not modify it */
if (!secp256k1_nonce_function_default(nonce32, msg32, seckey32, NULL, (void*)rand_commitment32, count)) {
secp256k1_callback_call(&ctx->error_callback, "(cryptographically unreachable) generated bad nonce");
}
is_nonce_valid = secp256k1_scalar_set_b32_seckey(&k, nonce32);
/* The nonce is still secret here, but it being invalid is is less likely than 1:2^255. */
secp256k1_declassify(ctx, &is_nonce_valid, sizeof(is_nonce_valid));
count++;
}
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k);
secp256k1_ge_set_gej(&r, &rj);
secp256k1_ecdsa_s2c_opening_save(opening, &r);
memset(nonce32, 0, 32);
secp256k1_scalar_clear(&k);
return 1;
}
int secp256k1_anti_exfil_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char* msg32, const unsigned char* seckey, const unsigned char* host_data32) {
return secp256k1_ecdsa_s2c_sign(ctx, sig, NULL, msg32, seckey, host_data32);
}
int secp256k1_anti_exfil_host_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey, const unsigned char *host_data32, const secp256k1_ecdsa_s2c_opening *opening) {
return secp256k1_ecdsa_s2c_verify_commit(ctx, sig, host_data32, opening) &&
secp256k1_ecdsa_verify(ctx, sig, msg32, pubkey);
}
#endif /* SECP256K1_ECDSA_S2C_MAIN_H */

View file

@ -0,0 +1,416 @@
/**********************************************************************
* Copyright (c) 2019-2020 Marko Bencun, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
#ifndef SECP256K1_MODULE_ECDSA_S2C_TESTS_H
#define SECP256K1_MODULE_ECDSA_S2C_TESTS_H
#include "include/secp256k1_ecdsa_s2c.h"
static void test_ecdsa_s2c_tagged_hash(void) {
unsigned char tag_data[14] = "s2c/ecdsa/data";
unsigned char tag_point[15] = "s2c/ecdsa/point";
secp256k1_sha256 sha;
secp256k1_sha256 sha_optimized;
unsigned char output[32];
unsigned char output_optimized[32];
secp256k1_sha256_initialize_tagged(&sha, tag_data, sizeof(tag_data));
secp256k1_s2c_ecdsa_data_sha256_tagged(&sha_optimized);
secp256k1_sha256_finalize(&sha, output);
secp256k1_sha256_finalize(&sha_optimized, output_optimized);
CHECK(secp256k1_memcmp_var(output, output_optimized, 32) == 0);
secp256k1_sha256_initialize_tagged(&sha, tag_point, sizeof(tag_point));
secp256k1_s2c_ecdsa_point_sha256_tagged(&sha_optimized);
secp256k1_sha256_finalize(&sha, output);
secp256k1_sha256_finalize(&sha_optimized, output_optimized);
CHECK(secp256k1_memcmp_var(output, output_optimized, 32) == 0);
}
void run_s2c_opening_test(void) {
int i = 0;
unsigned char output[33];
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
unsigned char input[33] = {
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02
};
secp256k1_ecdsa_s2c_opening opening;
int32_t ecount = 0;
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
/* First parsing, then serializing works */
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(none, output, &opening) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, NULL, input) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(none, NULL, &opening) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(none, output, NULL) == 0);
CHECK(ecount == 4);
/* Invalid pubkey makes parsing fail */
input[0] = 0; /* bad oddness bit */
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 0);
input[0] = 2;
input[31] = 1; /* point not on the curve */
CHECK(secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 0);
CHECK(ecount == 4); /* neither of the above are API errors */
/* Try parsing and serializing a bunch of openings */
for (i = 0; i < count; i++) {
/* This is expected to fail in about 50% of iterations because the
* points' x-coordinates are uniformly random */
if (secp256k1_ecdsa_s2c_opening_parse(none, &opening, input) == 1) {
CHECK(secp256k1_ecdsa_s2c_opening_serialize(none, output, &opening) == 1);
CHECK(memcmp(output, input, sizeof(output)) == 0);
}
secp256k1_testrand256(&input[1]);
/* Set pubkey oddness tag to first bit of input[1] */
input[0] = (input[1] & 1) + 2;
}
secp256k1_context_destroy(none);
}
static void test_ecdsa_s2c_api(void) {
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
secp256k1_ecdsa_s2c_opening s2c_opening;
secp256k1_ecdsa_signature sig;
const unsigned char msg[32] = "mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm";
const unsigned char sec[32] = "ssssssssssssssssssssssssssssssss";
const unsigned char s2c_data[32] = "dddddddddddddddddddddddddddddddd";
const unsigned char hostrand[32] = "hrhrhrhrhrhrhrhrhrhrhrhrhrhrhrhr";
unsigned char hostrand_commitment[32];
secp256k1_pubkey pk;
int32_t ecount;
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sec));
ecount = 0;
CHECK(secp256k1_ecdsa_s2c_sign(both, NULL, &s2c_opening, msg, sec, s2c_data) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, NULL, msg, sec, s2c_data) == 1);
CHECK(ecount == 1); /* NULL opening is not an API error */
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, &s2c_opening, NULL, sec, s2c_data) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, &s2c_opening, msg, NULL, s2c_data) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_s2c_sign(both, &sig, &s2c_opening, msg, sec, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_s2c_sign(none, &sig, &s2c_opening, msg, sec, s2c_data) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_s2c_sign(vrfy, &sig, &s2c_opening, msg, sec, s2c_data) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_s2c_sign(sign, &sig, &s2c_opening, msg, sec, s2c_data) == 1);
CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pk) == 1);
ecount = 0;
CHECK(secp256k1_ecdsa_s2c_verify_commit(both, NULL, s2c_data, &s2c_opening) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(both, &sig, NULL, &s2c_opening) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_s2c_verify_commit(both, &sig, s2c_data, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_s2c_verify_commit(none, &sig, s2c_data, &s2c_opening) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_s2c_verify_commit(sign, &sig, s2c_data, &s2c_opening) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_s2c_verify_commit(vrfy, &sig, s2c_data, &s2c_opening) == 1);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_s2c_verify_commit(vrfy, &sig, sec, &s2c_opening) == 0);
CHECK(ecount == 5); /* wrong data is not an API error */
/* Signing with NULL s2c_opening gives the same result */
CHECK(secp256k1_ecdsa_s2c_sign(sign, &sig, NULL, msg, sec, s2c_data) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(vrfy, &sig, s2c_data, &s2c_opening) == 1);
/* anti-exfil */
ecount = 0;
CHECK(secp256k1_ecdsa_anti_exfil_host_commit(none, NULL, hostrand) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_anti_exfil_host_commit(none, hostrand_commitment, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_anti_exfil_host_commit(none, hostrand_commitment, hostrand) == 1);
CHECK(ecount == 2);
ecount = 0;
CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(both, NULL, msg, sec, hostrand_commitment) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(both, &s2c_opening, NULL, sec, hostrand_commitment) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(both, &s2c_opening, msg, NULL, hostrand_commitment) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(both, &s2c_opening, msg, sec, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(none, &s2c_opening, msg, sec, hostrand_commitment) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(vrfy, &s2c_opening, msg, sec, hostrand_commitment) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(sign, &s2c_opening, msg, sec, hostrand_commitment) == 1);
CHECK(ecount == 6);
ecount = 0;
CHECK(secp256k1_anti_exfil_sign(both, NULL, msg, sec, hostrand) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_anti_exfil_sign(both, &sig, NULL, sec, hostrand) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_anti_exfil_sign(both, &sig, msg, NULL, hostrand) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_anti_exfil_sign(both, &sig, msg, sec, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_anti_exfil_sign(none, &sig, msg, sec, hostrand) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_anti_exfil_sign(vrfy, &sig, msg, sec, hostrand) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_anti_exfil_sign(both, &sig, msg, sec, hostrand) == 1);
CHECK(ecount == 6);
ecount = 0;
CHECK(secp256k1_anti_exfil_host_verify(both, NULL, msg, &pk, hostrand, &s2c_opening) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_anti_exfil_host_verify(both, &sig, NULL, &pk, hostrand, &s2c_opening) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_anti_exfil_host_verify(both, &sig, msg, NULL, hostrand, &s2c_opening) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_anti_exfil_host_verify(both, &sig, msg, &pk, NULL, &s2c_opening) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_anti_exfil_host_verify(both, &sig, msg, &pk, hostrand, NULL) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_anti_exfil_host_verify(none, &sig, msg, &pk, hostrand, &s2c_opening) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_anti_exfil_host_verify(sign, &sig, msg, &pk, hostrand, &s2c_opening) == 0);
CHECK(ecount == 7);
CHECK(secp256k1_anti_exfil_host_verify(vrfy, &sig, msg, &pk, hostrand, &s2c_opening) == 1);
CHECK(ecount == 7);
secp256k1_context_destroy(both);
secp256k1_context_destroy(vrfy);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(none);
}
/* When using sign-to-contract commitments, the nonce function is fixed, so we can use fixtures to test. */
typedef struct {
/* Data to commit to */
unsigned char s2c_data[32];
/* Original nonce */
unsigned char expected_s2c_opening[33];
/* Original nonce (anti-exfil protocol, which mixes in host randomness) */
unsigned char expected_s2c_exfil_opening[33];
} ecdsa_s2c_test;
static ecdsa_s2c_test ecdsa_s2c_tests[] = {
{
"\x1b\xf6\xfb\x42\xf4\x1e\xb8\x76\xc4\xd7\xaa\x0d\x67\x24\x2b\x00\xba\xab\x99\xdc\x20\x84\x49\x3e\x4e\x63\x27\x7f\xa1\xf7\x7f\x22",
"\x03\xf0\x30\xde\xf3\x18\x8c\x0f\x56\xfc\xea\x87\x43\x5b\x30\x76\x43\xf4\x5d\xaf\xe2\x2c\xbc\x82\xfd\x56\x03\x4f\xae\x97\x41\x7d\x3a",
"\x02\xdf\x63\x75\x5d\x1f\x32\x92\xbf\xfe\xd8\x29\x86\xb1\x06\x49\x7c\x93\xb1\xf8\xbd\xc0\x45\x4b\x6b\x0b\x0a\x47\x79\xc0\xef\x71\x88",
},
{
"\x35\x19\x9a\x8f\xbf\x84\xad\x6e\xf6\x9a\x18\x4c\x1b\x19\x28\x5b\xef\xbe\x06\xe6\x0b\x62\x64\xe6\xd3\x73\x89\x3f\x68\x55\xe2\x4a",
"\x03\x90\x17\x17\xce\x7c\x74\x84\xa2\xce\x1b\x7d\xc7\x40\x3b\x14\xe0\x35\x49\x71\x39\x3e\xc0\x92\xa7\xf3\xe0\xc8\xe4\xe2\xd2\x63\x9d",
"\x02\xc0\x4a\xc7\xf7\x71\xe8\xeb\xdb\xf3\x15\xff\x5e\x58\xb7\xfe\x95\x16\x10\x21\x03\x50\x00\x66\x17\x2c\x4f\xac\x5b\x20\xf9\xe0\xea",
},
};
static void test_ecdsa_s2c_fixed_vectors(void) {
const unsigned char privkey[32] = {
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
};
const unsigned char message[32] = {
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
};
size_t i;
for (i = 0; i < sizeof(ecdsa_s2c_tests) / sizeof(ecdsa_s2c_tests[0]); i++) {
secp256k1_ecdsa_s2c_opening s2c_opening;
unsigned char opening_ser[33];
const ecdsa_s2c_test *test = &ecdsa_s2c_tests[i];
secp256k1_ecdsa_signature signature;
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, test->s2c_data) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(ctx, opening_ser, &s2c_opening) == 1);
CHECK(memcmp(test->expected_s2c_opening, opening_ser, sizeof(opening_ser)) == 0);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, test->s2c_data, &s2c_opening) == 1);
}
}
static void test_ecdsa_s2c_sign_verify(void) {
unsigned char privkey[32];
secp256k1_pubkey pubkey;
unsigned char message[32];
unsigned char noncedata[32];
unsigned char s2c_data[32];
unsigned char s2c_data2[32];
secp256k1_ecdsa_signature signature;
secp256k1_ecdsa_s2c_opening s2c_opening;
/* Generate a random key, message, noncedata and s2c_data. */
{
secp256k1_scalar key;
random_scalar_order_test(&key);
secp256k1_scalar_get_b32(privkey, &key);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
secp256k1_testrand256_test(message);
secp256k1_testrand256_test(noncedata);
secp256k1_testrand256_test(s2c_data);
secp256k1_testrand256_test(s2c_data2);
}
{ /* invalid privkeys */
unsigned char zero_privkey[32] = {0};
unsigned char overflow_privkey[32] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, NULL, message, zero_privkey, s2c_data) == 0);
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, NULL, message, overflow_privkey, s2c_data) == 0);
}
/* Check that the sign-to-contract signature is valid, with s2c_data. Also check the commitment. */
{
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, s2c_data) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature, message, &pubkey) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, s2c_data, &s2c_opening) == 1);
}
/* Check that an invalid commitment does not verify */
{
unsigned char sigbytes[64];
size_t i;
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, message, privkey, s2c_data) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature, message, &pubkey) == 1);
CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sigbytes, &signature) == 1);
for(i = 0; i < 32; i++) {
/* change one byte */
sigbytes[i] = (((int)sigbytes[i]) + 1) % 256;
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature, sigbytes) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, s2c_data, &s2c_opening) == 0);
/* revert */
sigbytes[i] = (((int)sigbytes[i]) + 255) % 256;
}
}
}
static void test_ecdsa_anti_exfil_signer_commit(void) {
size_t i;
unsigned char privkey[32] = {
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
};
unsigned char message[32] = {
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
};
/* Check that original pubnonce is derived from s2c_data */
for (i = 0; i < sizeof(ecdsa_s2c_tests) / sizeof(ecdsa_s2c_tests[0]); i++) {
secp256k1_ecdsa_s2c_opening s2c_opening;
unsigned char buf[33];
const ecdsa_s2c_test *test = &ecdsa_s2c_tests[i];
CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(ctx, &s2c_opening, message, privkey, test->s2c_data) == 1);
CHECK(secp256k1_ecdsa_s2c_opening_serialize(ctx, buf, &s2c_opening) == 1);
CHECK(memcmp(test->expected_s2c_exfil_opening, buf, sizeof(buf)) == 0);
}
}
/* This tests the full ECDSA Anti-Exfil Protocol */
static void test_ecdsa_anti_exfil(void) {
unsigned char signer_privkey[32];
unsigned char host_msg[32];
unsigned char host_commitment[32];
unsigned char host_nonce_contribution[32];
secp256k1_pubkey signer_pubkey;
secp256k1_ecdsa_signature signature;
secp256k1_ecdsa_s2c_opening s2c_opening;
/* Generate a random key, message. */
{
secp256k1_scalar key;
random_scalar_order_test(&key);
secp256k1_scalar_get_b32(signer_privkey, &key);
CHECK(secp256k1_ec_pubkey_create(ctx, &signer_pubkey, signer_privkey) == 1);
secp256k1_testrand256_test(host_msg);
secp256k1_testrand256_test(host_nonce_contribution);
}
/* Protocol step 1. */
CHECK(secp256k1_ecdsa_anti_exfil_host_commit(ctx, host_commitment, host_nonce_contribution) == 1);
/* Protocol step 2. */
CHECK(secp256k1_ecdsa_anti_exfil_signer_commit(ctx, &s2c_opening, host_msg, signer_privkey, host_commitment) == 1);
/* Protocol step 3: host_nonce_contribution send to signer to be used in step 4. */
/* Protocol step 4. */
CHECK(secp256k1_anti_exfil_sign(ctx, &signature, host_msg, signer_privkey, host_nonce_contribution) == 1);
/* Protocol step 5. */
CHECK(secp256k1_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 1);
/* Protocol step 5 (explicitly) */
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, host_nonce_contribution, &s2c_opening) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, &signature, host_msg, &signer_pubkey) == 1);
{ /* host_verify: commitment does not match */
unsigned char sigbytes[64];
size_t i;
CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sigbytes, &signature) == 1);
for(i = 0; i < 32; i++) {
/* change one byte */
sigbytes[i] += 1;
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature, sigbytes) == 1);
CHECK(secp256k1_ecdsa_s2c_verify_commit(ctx, &signature, host_nonce_contribution, &s2c_opening) == 0);
CHECK(secp256k1_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0);
/* revert */
sigbytes[i] -= 1;
}
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature, sigbytes) == 1);
}
{ /* host_verify: message does not match */
unsigned char bad_msg[32];
secp256k1_testrand256_test(bad_msg);
CHECK(secp256k1_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 1);
CHECK(secp256k1_anti_exfil_host_verify(ctx, &signature, bad_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0);
}
{ /* s2c_sign: host provided data that didn't match commitment */
secp256k1_ecdsa_s2c_opening orig_opening = s2c_opening;
unsigned char bad_nonce_contribution[32] = { 1, 2, 3, 4 };
CHECK(secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, host_msg, signer_privkey, bad_nonce_contribution) == 1);
/* good signature but the opening (original public nonce does not match the original */
CHECK(secp256k1_ecdsa_verify(ctx, &signature, host_msg, &signer_pubkey) == 1);
CHECK(secp256k1_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, host_nonce_contribution, &s2c_opening) == 0);
CHECK(secp256k1_anti_exfil_host_verify(ctx, &signature, host_msg, &signer_pubkey, bad_nonce_contribution, &s2c_opening) == 1);
CHECK(memcmp(&s2c_opening, &orig_opening, sizeof(s2c_opening)) != 0);
}
}
static void run_ecdsa_s2c_tests(void) {
run_s2c_opening_test();
test_ecdsa_s2c_tagged_hash();
test_ecdsa_s2c_api();
test_ecdsa_s2c_fixed_vectors();
test_ecdsa_s2c_sign_verify();
test_ecdsa_anti_exfil_signer_commit();
test_ecdsa_anti_exfil();
}
#endif /* SECP256K1_MODULE_ECDSA_S2C_TESTS_H */

View file

@ -2,3 +2,5 @@ include_HEADERS += include/secp256k1_extrakeys.h
noinst_HEADERS += src/modules/extrakeys/tests_impl.h
noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h
noinst_HEADERS += src/modules/extrakeys/main_impl.h
noinst_HEADERS += src/modules/extrakeys/hsort.h
noinst_HEADERS += src/modules/extrakeys/hsort_impl.h

View file

@ -0,0 +1,22 @@
/***********************************************************************
* Copyright (c) 2021 Russell O'Connor, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_HSORT_H_
#define SECP256K1_HSORT_H_
#include <stddef.h>
#include <string.h>
/* In-place, iterative heapsort with an interface matching glibc's qsort_r. This
* is preferred over standard library implementations because they generally
* make no guarantee about being fast for malicious inputs.
*
* See the qsort_r manpage for a description of the interface.
*/
static void secp256k1_hsort(void *ptr, size_t count, size_t size,
int (*cmp)(const void *, const void *, void *),
void *cmp_data);
#endif

View file

@ -0,0 +1,116 @@
/***********************************************************************
* Copyright (c) 2021 Russell O'Connor, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_HSORT_IMPL_H_
#define SECP256K1_HSORT_IMPL_H_
#include "hsort.h"
/* An array is a heap when, for all non-zero indexes i, the element at index i
* compares as less than or equal to the element at index parent(i) = (i-1)/2.
*/
static SECP256K1_INLINE size_t child1(size_t i) {
VERIFY_CHECK(i <= (SIZE_MAX - 1)/2);
return 2*i + 1;
}
static SECP256K1_INLINE size_t child2(size_t i) {
VERIFY_CHECK(i <= SIZE_MAX/2 - 1);
return child1(i)+1;
}
static SECP256K1_INLINE void swap64(unsigned char *a, size_t i, size_t j, size_t stride) {
unsigned char tmp[64];
VERIFY_CHECK(stride <= 64);
memcpy(tmp, a + i*stride, stride);
memmove(a + i*stride, a + j*stride, stride);
memcpy(a + j*stride, tmp, stride);
}
static SECP256K1_INLINE void swap(unsigned char *a, size_t i, size_t j, size_t stride) {
while (64 < stride) {
swap64(a + (stride - 64), i, j, 64);
stride -= 64;
}
swap64(a, i, j, stride);
}
static SECP256K1_INLINE void heap_down(unsigned char *a, size_t i, size_t heap_size, size_t stride,
int (*cmp)(const void *, const void *, void *), void *cmp_data) {
while (i < heap_size/2) {
VERIFY_CHECK(i <= SIZE_MAX/2 - 1);
/* Proof:
* i < heap_size/2
* i + 1 <= heap_size/2
* 2*i + 2 <= heap_size <= SIZE_MAX
* 2*i <= SIZE_MAX - 2
*/
VERIFY_CHECK(child1(i) < heap_size);
/* Proof:
* i < heap_size/2
* i + 1 <= heap_size/2
* 2*i + 2 <= heap_size
* 2*i + 1 < heap_size
* child1(i) < heap_size
*/
/* Let [x] be notation for the contents at a[x*stride].
*
* If [child1(i)] > [i] and [child2(i)] > [i],
* swap [i] with the larger child to ensure the new parent is larger
* than both children. When [child1(i)] == [child2(i)], swap [i] with
* [child2(i)].
* Else if [child1(i)] > [i], swap [i] with [child1(i)].
* Else if [child2(i)] > [i], swap [i] with [child2(i)].
*/
if (child2(i) < heap_size
&& 0 <= cmp(a + child2(i)*stride, a + child1(i)*stride, cmp_data)) {
if (0 < cmp(a + child2(i)*stride, a + i*stride, cmp_data)) {
swap(a, i, child2(i), stride);
i = child2(i);
} else {
/* At this point we have [child2(i)] >= [child1(i)] and we have
* [child2(i)] <= [i], and thus [child1(i)] <= [i] which means
* that the next comparison can be skipped. */
return;
}
} else if (0 < cmp(a + child1(i)*stride, a + i*stride, cmp_data)) {
swap(a, i, child1(i), stride);
i = child1(i);
} else {
return;
}
}
/* heap_size/2 <= i
* heap_size/2 < i + 1
* heap_size < 2*i + 2
* heap_size <= 2*i + 1
* heap_size <= child1(i)
* Thus child1(i) and child2(i) are now out of bounds and we are at a leaf.
*/
}
/* In-place heap sort. */
static void secp256k1_hsort(void *ptr, size_t count, size_t size,
int (*cmp)(const void *, const void *, void *),
void *cmp_data ) {
size_t i;
for(i = count/2; 0 < i; --i) {
heap_down(ptr, i-1, count, size, cmp, cmp_data);
}
for(i = count; 1 < i; --i) {
/* Extract the largest value from the heap */
swap(ptr, 0, i-1, size);
/* Repair the heap condition */
heap_down(ptr, 0, i-1, size, cmp, cmp_data);
}
}
#endif

View file

@ -1,14 +1,15 @@
/**********************************************************************
* Copyright (c) 2020 Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2020 Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef _SECP256K1_MODULE_EXTRAKEYS_MAIN_
#define _SECP256K1_MODULE_EXTRAKEYS_MAIN_
#ifndef SECP256K1_MODULE_EXTRAKEYS_MAIN_H
#define SECP256K1_MODULE_EXTRAKEYS_MAIN_H
#include "include/secp256k1.h"
#include "include/secp256k1_extrakeys.h"
#include "../../../include/secp256k1.h"
#include "../../../include/secp256k1_extrakeys.h"
#include "hsort_impl.h"
static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) {
return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey);
@ -55,6 +56,32 @@ int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char
return 1;
}
int secp256k1_xonly_pubkey_cmp(const secp256k1_context* ctx, const secp256k1_xonly_pubkey* pk0, const secp256k1_xonly_pubkey* pk1) {
unsigned char out[2][32];
const secp256k1_xonly_pubkey* pk[2];
int i;
VERIFY_CHECK(ctx != NULL);
pk[0] = pk0; pk[1] = pk1;
for (i = 0; i < 2; i++) {
/* If the public key is NULL or invalid, xonly_pubkey_serialize will
* call the illegal_callback and return 0. In that case we will
* serialize the key as all zeros which is less than any valid public
* key. This results in consistent comparisons even if NULL or invalid
* pubkeys are involved and prevents edge cases such as sorting
* algorithms that use this function and do not terminate as a
* result. */
if (!secp256k1_xonly_pubkey_serialize(ctx, out[i], pk[i])) {
/* Note that xonly_pubkey_serialize should already set the output to
* zero in that case, but it's not guaranteed by the API, we can't
* test it and writing a VERIFY_CHECK is more complex than
* explicitly memsetting (again). */
memset(out[i], 0, sizeof(out[i]));
}
}
return secp256k1_memcmp_var(out[0], out[1], sizeof(out[1]));
}
/** Keeps a group element as is if it has an even Y and otherwise negates it.
* y_parity is set to 0 in the former case and to 1 in the latter case.
* Requires that the coordinates of r are normalized. */
@ -128,6 +155,28 @@ int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const u
&& secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity;
}
/* This struct wraps a const context pointer to satisfy the secp256k1_hsort api
* which expects a non-const cmp_data pointer. */
typedef struct {
const secp256k1_context *ctx;
} secp256k1_xonly_sort_cmp_data;
static int secp256k1_xonly_sort_cmp(const void* pk1, const void* pk2, void *cmp_data) {
return secp256k1_xonly_pubkey_cmp(((secp256k1_xonly_sort_cmp_data*)cmp_data)->ctx,
*(secp256k1_xonly_pubkey **)pk1,
*(secp256k1_xonly_pubkey **)pk2);
}
int secp256k1_xonly_sort(const secp256k1_context* ctx, const secp256k1_xonly_pubkey **pubkeys, size_t n_pubkeys) {
secp256k1_xonly_sort_cmp_data cmp_data;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pubkeys != NULL);
cmp_data.ctx = ctx;
secp256k1_hsort(pubkeys, n_pubkeys, sizeof(*pubkeys), secp256k1_xonly_sort_cmp, &cmp_data);
return 1;
}
static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) {
secp256k1_scalar_get_b32(&keypair->data[0], sk);
secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk);
@ -186,6 +235,16 @@ int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *ke
return ret;
}
int secp256k1_keypair_sec(const secp256k1_context* ctx, unsigned char *seckey, const secp256k1_keypair *keypair) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(seckey != NULL);
memset(seckey, 0, 32);
ARG_CHECK(keypair != NULL);
memcpy(seckey, &keypair->data[0], 32);
return 1;
}
int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pubkey != NULL);

View file

@ -1,14 +1,14 @@
/**********************************************************************
* Copyright (c) 2020 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2020 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_
#define _SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_
#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
#define SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_H
#include "src/modules/extrakeys/main_impl.h"
#include "include/secp256k1_extrakeys.h"
#include "../../../include/secp256k1_extrakeys.h"
static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) {
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1];

View file

@ -1,13 +1,13 @@
/**********************************************************************
* Copyright (c) 2020 Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2020 Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_
#define _SECP256K1_MODULE_EXTRAKEYS_TESTS_
#ifndef SECP256K1_MODULE_EXTRAKEYS_TESTS_H
#define SECP256K1_MODULE_EXTRAKEYS_TESTS_H
#include "secp256k1_extrakeys.h"
#include "../../../include/secp256k1_extrakeys.h"
static secp256k1_context* api_test_context(int flags, int *ecount) {
secp256k1_context *ctx0 = secp256k1_context_create(flags);
@ -137,6 +137,43 @@ void test_xonly_pubkey(void) {
secp256k1_context_destroy(verify);
}
void test_xonly_pubkey_comparison(void) {
unsigned char pk1_ser[32] = {
0x58, 0x84, 0xb3, 0xa2, 0x4b, 0x97, 0x37, 0x88, 0x92, 0x38, 0xa6, 0x26, 0x62, 0x52, 0x35, 0x11,
0xd0, 0x9a, 0xa1, 0x1b, 0x80, 0x0b, 0x5e, 0x93, 0x80, 0x26, 0x11, 0xef, 0x67, 0x4b, 0xd9, 0x23
};
const unsigned char pk2_ser[32] = {
0xde, 0x36, 0x0e, 0x87, 0x59, 0x8f, 0x3c, 0x01, 0x36, 0x2a, 0x2a, 0xb8, 0xc6, 0xf4, 0x5e, 0x4d,
0xb2, 0xc2, 0xd5, 0x03, 0xa7, 0xf9, 0xf1, 0x4f, 0xa8, 0xfa, 0x95, 0xa8, 0xe9, 0x69, 0x76, 0x1c
};
secp256k1_xonly_pubkey pk1;
secp256k1_xonly_pubkey pk2;
int ecount = 0;
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
CHECK(secp256k1_xonly_pubkey_parse(none, &pk1, pk1_ser) == 1);
CHECK(secp256k1_xonly_pubkey_parse(none, &pk2, pk2_ser) == 1);
CHECK(secp256k1_xonly_pubkey_cmp(none, NULL, &pk2) < 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, NULL) > 0);
CHECK(ecount == 2);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk2) < 0);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk1) > 0);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk1) == 0);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk2) == 0);
CHECK(ecount == 2);
memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk2) < 0);
CHECK(ecount == 3);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk1, &pk1) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_xonly_pubkey_cmp(none, &pk2, &pk1) > 0);
CHECK(ecount == 6);
secp256k1_context_destroy(none);
}
void test_xonly_pubkey_tweak(void) {
unsigned char zeros64[64] = { 0 };
unsigned char overflows[32];
@ -311,6 +348,7 @@ void test_xonly_pubkey_tweak_recursive(void) {
void test_keypair(void) {
unsigned char sk[32];
unsigned char sk_tmp[32];
unsigned char zeros96[96] = { 0 };
unsigned char overflows[32];
secp256k1_keypair keypair;
@ -396,6 +434,28 @@ void test_keypair(void) {
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
CHECK(pk_parity == pk_parity_tmp);
/* Test keypair_seckey */
ecount = 0;
secp256k1_testrand256(sk);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
CHECK(secp256k1_keypair_sec(none, NULL, &keypair) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_keypair_sec(none, sk_tmp, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
/* keypair returns the same seckey it got */
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(sk, sk_tmp, sizeof(sk_tmp)) == 0);
/* Using an invalid keypair is fine for keypair_seckey */
memset(&keypair, 0, sizeof(keypair));
CHECK(secp256k1_keypair_sec(none, sk_tmp, &keypair) == 1);
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
secp256k1_context_destroy(none);
secp256k1_context_destroy(sign);
secp256k1_context_destroy(verify);
@ -484,6 +544,7 @@ void test_keypair_add(void) {
secp256k1_pubkey output_pk_xy;
secp256k1_pubkey output_pk_expected;
unsigned char pk32[32];
unsigned char sk32[32];
int pk_parity;
secp256k1_testrand256(tweak);
@ -501,7 +562,8 @@ void test_keypair_add(void) {
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(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, &keypair.data[0]) == 1);
CHECK(secp256k1_keypair_sec(none, sk32, &keypair) == 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);
}
secp256k1_context_destroy(none);
@ -509,16 +571,167 @@ void test_keypair_add(void) {
secp256k1_context_destroy(verify);
}
static void test_hsort_is_sorted(int *ints, size_t n) {
size_t i;
for (i = 1; i < n; i++) {
CHECK(ints[i-1] <= ints[i]);
}
}
static int test_hsort_cmp(const void *i1, const void *i2, void *counter) {
*(size_t*)counter += 1;
return *(int*)i1 - *(int*)i2;
}
#define NUM 64
void test_hsort(void) {
int ints[NUM] = { 0 };
size_t counter = 0;
int i, j;
secp256k1_hsort(ints, 0, sizeof(ints[0]), test_hsort_cmp, &counter);
CHECK(counter == 0);
secp256k1_hsort(ints, 1, sizeof(ints[0]), test_hsort_cmp, &counter);
CHECK(counter == 0);
secp256k1_hsort(ints, NUM, sizeof(ints[0]), test_hsort_cmp, &counter);
CHECK(counter > 0);
test_hsort_is_sorted(ints, NUM);
/* Test hsort with length n array and random elements in
* [-interval/2, interval/2] */
for (i = 0; i < count; i++) {
int n = secp256k1_testrand_int(NUM);
int interval = secp256k1_testrand_int(64);
for (j = 0; j < n; j++) {
ints[j] = secp256k1_testrand_int(interval) - interval/2;
}
secp256k1_hsort(ints, n, sizeof(ints[0]), test_hsort_cmp, &counter);
test_hsort_is_sorted(ints, n);
}
}
#undef NUM
void test_xonly_sort_helper(secp256k1_xonly_pubkey *pk, size_t *pk_order, size_t n_pk) {
size_t i;
const secp256k1_xonly_pubkey *pk_test[5];
for (i = 0; i < n_pk; i++) {
pk_test[i] = &pk[pk_order[i]];
}
secp256k1_xonly_sort(ctx, pk_test, n_pk);
for (i = 0; i < n_pk; i++) {
CHECK(secp256k1_memcmp_var(pk_test[i], &pk[i], sizeof(*pk_test[i])) == 0);
}
}
void permute(size_t *arr, size_t n) {
size_t i;
for (i = n - 1; i >= 1; i--) {
size_t tmp, j;
j = secp256k1_testrand_int(i + 1);
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
void rand_xonly_pk(secp256k1_xonly_pubkey *pk) {
unsigned char seckey[32];
secp256k1_keypair keypair;
secp256k1_testrand256(seckey);
CHECK(secp256k1_keypair_create(ctx, &keypair, seckey) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair) == 1);
}
void test_xonly_sort_api(void) {
int ecount = 0;
secp256k1_xonly_pubkey pks[2];
const secp256k1_xonly_pubkey *pks_ptr[2];
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
pks_ptr[0] = &pks[0];
pks_ptr[1] = &pks[1];
rand_xonly_pk(&pks[0]);
rand_xonly_pk(&pks[1]);
CHECK(secp256k1_xonly_sort(none, pks_ptr, 2) == 1);
CHECK(secp256k1_xonly_sort(none, NULL, 2) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_xonly_sort(none, pks_ptr, 0) == 1);
/* Test illegal public keys */
memset(&pks[0], 0, sizeof(pks[0]));
CHECK(secp256k1_xonly_sort(none, pks_ptr, 2) == 1);
CHECK(ecount == 2);
memset(&pks[1], 0, sizeof(pks[1]));
CHECK(secp256k1_xonly_sort(none, pks_ptr, 2) == 1);
CHECK(ecount > 2);
secp256k1_context_destroy(none);
}
void test_xonly_sort(void) {
secp256k1_xonly_pubkey pk[5];
unsigned char pk_ser[5][32];
int i;
size_t pk_order[5] = { 0, 1, 2, 3, 4 };
for (i = 0; i < 5; i++) {
memset(pk_ser[i], 0, sizeof(pk_ser[i]));
}
pk_ser[0][0] = 5;
pk_ser[1][0] = 8;
pk_ser[2][0] = 0x0a;
pk_ser[3][0] = 0x0b;
pk_ser[4][0] = 0x0c;
for (i = 0; i < 5; i++) {
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk[i], pk_ser[i]));
}
permute(pk_order, 1);
test_xonly_sort_helper(pk, pk_order, 1);
permute(pk_order, 2);
test_xonly_sort_helper(pk, pk_order, 2);
permute(pk_order, 3);
test_xonly_sort_helper(pk, pk_order, 3);
for (i = 0; i < count; i++) {
permute(pk_order, 4);
test_xonly_sort_helper(pk, pk_order, 4);
}
for (i = 0; i < count; i++) {
permute(pk_order, 5);
test_xonly_sort_helper(pk, pk_order, 5);
}
/* Check that sorting also works for random pubkeys */
for (i = 0; i < count; i++) {
int j;
const secp256k1_xonly_pubkey *pk_ptr[5];
for (j = 0; j < 5; j++) {
rand_xonly_pk(&pk[j]);
pk_ptr[j] = &pk[j];
}
secp256k1_xonly_sort(ctx, pk_ptr, 5);
for (j = 1; j < 5; j++) {
CHECK(secp256k1_xonly_sort_cmp(&pk_ptr[j - 1], &pk_ptr[j], ctx) <= 0);
}
}
}
void run_extrakeys_tests(void) {
/* xonly key test cases */
test_xonly_pubkey();
test_xonly_pubkey_tweak();
test_xonly_pubkey_tweak_check();
test_xonly_pubkey_tweak_recursive();
test_xonly_pubkey_comparison();
/* keypair tests */
test_keypair();
test_keypair_add();
test_hsort();
test_xonly_sort_api();
test_xonly_sort();
}
#endif

View file

@ -40,7 +40,7 @@ int create_keypair(const secp256k1_context* ctx, unsigned char *seckey, secp256k
}
/* Sign a message hash with the given key pairs and store the result in sig */
int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_xonly_pubkey* pubkeys, const unsigned char* msg32, unsigned char *sig64) {
int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_xonly_pubkey** pubkeys, const unsigned char* msg32, unsigned char *sig64) {
secp256k1_musig_session musig_session[N_SIGNERS];
unsigned char nonce_commitment[N_SIGNERS][32];
const unsigned char *nonce_commitment_ptr[N_SIGNERS];
@ -72,7 +72,7 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
}
fclose(frand);
/* Initialize session */
if (!secp256k1_musig_session_init(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, &pre_session, N_SIGNERS, i, seckeys[i])) {
if (!secp256k1_musig_session_init(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, &pre_session, N_SIGNERS, seckeys[i])) {
return 0;
}
nonce_commitment_ptr[i] = &nonce_commitment[i][0];
@ -107,7 +107,7 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
for (i = 0; i < N_SIGNERS; i++) {
for (j = 0; j < N_SIGNERS; j++) {
/* To check whether signing was successful, it suffices to either verify
* the the combined signature with the combined public key using
* the combined signature with the combined public key using
* secp256k1_schnorrsig_verify, or verify all partial signatures of all
* signers individually. Verifying the combined signature is cheaper but
* verifying the individual partial signatures has the advantage that it
@ -117,7 +117,7 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
* fine to first verify the combined sig, and only verify the individual
* sigs if it does not work.
*/
if (!secp256k1_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j], &pubkeys[j])) {
if (!secp256k1_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j], pubkeys[j])) {
return 0;
}
}
@ -130,6 +130,7 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
int i;
unsigned char seckeys[N_SIGNERS][32];
secp256k1_xonly_pubkey pubkeys[N_SIGNERS];
const secp256k1_xonly_pubkey *pubkeys_ptr[N_SIGNERS];
secp256k1_xonly_pubkey combined_pk;
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
unsigned char sig[64];
@ -142,22 +143,23 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
printf("FAILED\n");
return 1;
}
pubkeys_ptr[i] = &pubkeys[i];
}
printf("ok\n");
printf("Combining public keys...");
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys, N_SIGNERS)) {
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys_ptr, N_SIGNERS)) {
printf("FAILED\n");
return 1;
}
printf("ok\n");
printf("Signing message.........");
if (!sign(ctx, seckeys, pubkeys, msg, sig)) {
if (!sign(ctx, seckeys, pubkeys_ptr, msg, sig)) {
printf("FAILED\n");
return 1;
}
printf("ok\n");
printf("Verifying signature.....");
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, &combined_pk)) {
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, 32, &combined_pk)) {
printf("FAILED\n");
return 1;
}

View file

@ -13,14 +13,14 @@
#include "hash.h"
/* Computes ell = SHA256(pk[0], ..., pk[np-1]) */
static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_xonly_pubkey *pk, size_t np) {
static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_xonly_pubkey * const* pk, size_t np) {
secp256k1_sha256 sha;
size_t i;
secp256k1_sha256_initialize(&sha);
for (i = 0; i < np; i++) {
unsigned char ser[32];
if (!secp256k1_xonly_pubkey_serialize(ctx, ser, &pk[i])) {
if (!secp256k1_xonly_pubkey_serialize(ctx, ser, pk[i])) {
return 0;
}
secp256k1_sha256_write(&sha, ser, 32);
@ -30,79 +30,82 @@ static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned ch
}
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("MuSig coefficient")||SHA256("MuSig coefficient"). */
* SHA256 to SHA256("KeyAgg coefficient")||SHA256("KeyAgg coefficient"). */
static void secp256k1_musig_sha256_init_tagged(secp256k1_sha256 *sha) {
secp256k1_sha256_initialize(sha);
sha->s[0] = 0x0fd0690cul;
sha->s[1] = 0xfefeae97ul;
sha->s[2] = 0x996eac7ful;
sha->s[3] = 0x5c30d864ul;
sha->s[4] = 0x8c4a0573ul;
sha->s[5] = 0xaca1a22ful;
sha->s[6] = 0x6f43b801ul;
sha->s[7] = 0x85ce27cdul;
sha->s[0] = 0x6ef02c5aul;
sha->s[1] = 0x06a480deul;
sha->s[2] = 0x1f298665ul;
sha->s[3] = 0x1d1134f2ul;
sha->s[4] = 0x56a0b063ul;
sha->s[5] = 0x52da4147ul;
sha->s[6] = 0xf280d9d4ul;
sha->s[7] = 0x4484be15ul;
sha->bytes = 64;
}
/* Compute r = SHA256(ell, idx). The four bytes of idx are serialized least significant byte first. */
static void secp256k1_musig_coefficient(secp256k1_scalar *r, const unsigned char *ell, uint32_t idx) {
/* Compute KeyAgg coefficient which is constant 1 for the second pubkey and
* SHA256(ell, x) otherwise. second_pk_x can be NULL in case there is no
* second_pk. Assumes both field elements x and second_pk_x are normalized. */
static void secp256k1_musig_keyaggcoef_internal(secp256k1_scalar *r, const unsigned char *ell, secp256k1_fe *x, const secp256k1_fe *second_pk_x) {
secp256k1_sha256 sha;
unsigned char buf[32];
size_t i;
secp256k1_musig_sha256_init_tagged(&sha);
secp256k1_sha256_write(&sha, ell, 32);
/* We're hashing the index of the signer instead of its public key as specified
* in the MuSig paper. This reduces the total amount of data that needs to be
* hashed.
* Additionally, it prevents creating identical musig_coefficients for identical
* public keys. A participant Bob could choose his public key to be the same as
* Alice's, then replay Alice's messages (nonce and partial signature) to create
* a valid partial signature. This is not a problem for MuSig per se, but could
* result in subtle issues with protocols building on threshold signatures.
* With the assumption that public keys are unique, hashing the index is
* equivalent to hashing the public key. Because the public key can be
* identified by the index given the ordered list of public keys (included in
* ell), the index is just a different encoding of the public key.*/
for (i = 0; i < sizeof(uint32_t); i++) {
unsigned char c = idx;
secp256k1_sha256_write(&sha, &c, 1);
idx >>= 8;
if (secp256k1_fe_cmp_var(x, second_pk_x) == 0) {
secp256k1_scalar_set_int(r, 1);
} else {
secp256k1_musig_sha256_init_tagged(&sha);
secp256k1_sha256_write(&sha, ell, 32);
secp256k1_fe_get_b32(buf, x);
secp256k1_sha256_write(&sha, buf, 32);
secp256k1_sha256_finalize(&sha, buf);
secp256k1_scalar_set_b32(r, buf, NULL);
}
secp256k1_sha256_finalize(&sha, buf);
secp256k1_scalar_set_b32(r, buf, NULL);
}
/* Assumes both field elements x and second_pk_x are normalized. */
static void secp256k1_musig_keyaggcoef(secp256k1_scalar *r, const secp256k1_musig_pre_session *pre_session, secp256k1_fe *x) {
secp256k1_fe second_pk_x;
secp256k1_fe_set_b32(&second_pk_x, pre_session->second_pk);
secp256k1_musig_keyaggcoef_internal(r, pre_session->pk_hash, x, &second_pk_x);
}
typedef struct {
const secp256k1_context *ctx;
unsigned char ell[32];
const secp256k1_xonly_pubkey *pks;
const secp256k1_xonly_pubkey * const* pks;
secp256k1_fe second_pk_x;
} secp256k1_musig_pubkey_combine_ecmult_data;
/* Callback for batch EC multiplication to compute ell_0*P0 + ell_1*P1 + ... */
static int secp256k1_musig_pubkey_combine_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
secp256k1_musig_pubkey_combine_ecmult_data *ctx = (secp256k1_musig_pubkey_combine_ecmult_data *) data;
secp256k1_musig_coefficient(sc, ctx->ell, idx);
return secp256k1_xonly_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]);
int ret;
ret = secp256k1_xonly_pubkey_load(ctx->ctx, pt, ctx->pks[idx]);
/* pubkey_load can't fail because the same pks have already been loaded (and
* we test this) */
VERIFY_CHECK(ret);
secp256k1_musig_keyaggcoef_internal(sc, ctx->ell, &pt->x, &ctx->second_pk_x);
return 1;
}
static void secp256k1_musig_signers_init(secp256k1_musig_session_signer_data *signers, uint32_t n_signers) {
uint32_t i;
for (i = 0; i < n_signers; i++) {
memset(&signers[i], 0, sizeof(signers[i]));
signers[i].index = i;
signers[i].present = 0;
}
}
static const uint64_t pre_session_magic = 0xf4adbbdf7c7dd304UL;
int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const secp256k1_xonly_pubkey *pubkeys, size_t n_pubkeys) {
int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const secp256k1_xonly_pubkey * const* pubkeys, size_t n_pubkeys) {
secp256k1_musig_pubkey_combine_ecmult_data ecmult_data;
secp256k1_gej pkj;
secp256k1_ge pkp;
int pk_parity;
size_t i;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(combined_pk != NULL);
@ -112,14 +115,28 @@ int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scrat
ecmult_data.ctx = ctx;
ecmult_data.pks = pubkeys;
/* No point on the curve has an X coordinate equal to 0 */
secp256k1_fe_set_int(&ecmult_data.second_pk_x, 0);
for (i = 1; i < n_pubkeys; i++) {
secp256k1_ge pt;
if (!secp256k1_xonly_pubkey_load(ctx, &pt, pubkeys[i])) {
return 0;
}
if (secp256k1_memcmp_var(pubkeys[0], pubkeys[i], sizeof(*pubkeys[0])) != 0) {
ecmult_data.second_pk_x = pt.x;
break;
}
}
if (!secp256k1_musig_compute_ell(ctx, ecmult_data.ell, pubkeys, n_pubkeys)) {
return 0;
}
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &pkj, NULL, secp256k1_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) {
/* The current implementation of ecmult_multi_var makes this code unreachable with tests. */
return 0;
}
secp256k1_ge_set_gej(&pkp, &pkj);
secp256k1_fe_normalize(&pkp.y);
secp256k1_fe_normalize_var(&pkp.y);
pk_parity = secp256k1_extrakeys_ge_even_y(&pkp);
secp256k1_xonly_pubkey_save(combined_pk, &pkp);
@ -128,12 +145,14 @@ int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scrat
memcpy(pre_session->pk_hash, ecmult_data.ell, 32);
pre_session->pk_parity = pk_parity;
pre_session->is_tweaked = 0;
secp256k1_fe_get_b32(pre_session->second_pk, &ecmult_data.second_pk_x);
}
return 1;
}
int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_musig_pre_session *pre_session, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
secp256k1_ge pk;
int ret;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(pre_session != NULL);
@ -150,16 +169,17 @@ int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_mus
memcpy(pre_session->tweak, tweak32, 32);
pre_session->is_tweaked = 1;
if (!secp256k1_pubkey_load(ctx, &pk, output_pubkey)) {
return 0;
}
ret = secp256k1_pubkey_load(ctx, &pk, output_pubkey);
/* Successful xonly_pubkey_tweak_add always returns valid output_pubkey */
VERIFY_CHECK(ret);
pre_session->pk_parity = secp256k1_extrakeys_ge_even_y(&pk);
return 1;
}
static const uint64_t session_magic = 0xd92e6fc1ee41b4cbUL;
int secp256k1_musig_session_init(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, size_t n_signers, size_t my_index, const unsigned char *seckey) {
int secp256k1_musig_session_init(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, size_t n_signers, const unsigned char *seckey) {
unsigned char combined_ser[32];
int overflow;
secp256k1_scalar secret;
@ -183,7 +203,6 @@ int secp256k1_musig_session_init(const secp256k1_context* ctx, secp256k1_musig_s
ARG_CHECK(n_signers > 0);
ARG_CHECK(n_signers <= UINT32_MAX);
ARG_CHECK(my_index < n_signers);
memset(session, 0, sizeof(*session));
@ -206,7 +225,11 @@ int secp256k1_musig_session_init(const secp256k1_context* ctx, secp256k1_musig_s
secp256k1_scalar_clear(&secret);
return 0;
}
secp256k1_musig_coefficient(&mu, session->pre_session.pk_hash, (uint32_t) my_index);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret);
secp256k1_ge_set_gej(&p, &pj);
secp256k1_fe_normalize_var(&p.x);
secp256k1_musig_keyaggcoef(&mu, &session->pre_session, &p.x);
/* Compute the signer's public key point and determine if the secret is
* negated before signing. That happens if if the signer's pubkey has an odd
* Y coordinate XOR the MuSig-combined pubkey has an odd Y coordinate XOR
@ -215,7 +238,7 @@ int secp256k1_musig_session_init(const secp256k1_context* ctx, secp256k1_musig_s
* This can be seen by looking at the secret key belonging to `combined_pk`.
* Let's define
* P' := mu_0*|P_0| + ... + mu_n*|P_n| where P_i is the i-th public key
* point x_i*G, mu_i is the i-th musig coefficient and |.| is a function
* point x_i*G, mu_i is the i-th KeyAgg coefficient and |.| is a function
* that normalizes a point to an even Y by negating if necessary similar to
* secp256k1_extrakeys_ge_even_y. Then we have
* P := |P'| + t*G where t is the tweak.
@ -226,9 +249,7 @@ int secp256k1_musig_session_init(const secp256k1_context* ctx, secp256k1_musig_s
* b_i = -1 if (P_i != |P_i| XOR P' != |P'| XOR P != |P|) and 1
* otherwise.
*/
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret);
secp256k1_ge_set_gej(&p, &pj);
secp256k1_fe_normalize(&p.y);
secp256k1_fe_normalize_var(&p.y);
if((secp256k1_fe_is_odd(&p.y)
+ session->pre_session.pk_parity
+ (session->pre_session.is_tweaked
@ -596,10 +617,13 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2
secp256k1_musig_compute_messagehash(ctx, msghash, session);
secp256k1_scalar_set_b32(&e, msghash, NULL);
/* Multiplying the messagehash by the musig coefficient is equivalent
if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) {
return 0;
}
/* Multiplying the messagehash by the KeyAgg coefficient is equivalent
* to multiplying the signer's public key by the coefficient, except
* much easier to do. */
secp256k1_musig_coefficient(&mu, session->pre_session.pk_hash, signer->index);
secp256k1_musig_keyaggcoef(&mu, &session->pre_session, &pkp.x);
secp256k1_scalar_mul(&e, &e, &mu);
if (!secp256k1_xonly_pubkey_load(ctx, &rp, &signer->nonce)) {
@ -619,9 +643,7 @@ int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp2
/* Compute rj = s*G + (-e)*pkj */
secp256k1_scalar_negate(&e, &e);
if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) {
return 0;
}
secp256k1_gej_set_ge(&pkj, &pkp);
secp256k1_ecmult(&ctx->ecmult_ctx, &rj, &pkj, &e, &s);

View file

@ -0,0 +1,102 @@
<pre>
Title: MuSig Key Aggregation
Author:
Status: Draft
License: BSD-2-Clause
Created: 2020-01-19
</pre>
== Introduction ==
=== Abstract ===
This document describes MuSig Key Aggregation in libsecp256k1-zkp.
=== Copyright ===
This document is licensed under the 2-clause BSD license.
=== Motivation ===
== Description ==
=== Design ===
* A function for sorting public keys allows to aggregate keys independent of the (initial) order.
* The KeyAgg coefficient is computed by hashing the key instead of key index. Otherwise, if the pubkey list gets sorted, the signer needs to translate between key indices pre- and post-sorting.
* The second unique key in the pubkey list gets the constant KeyAgg coefficient 1 which saves an exponentiation (see the MuSig2* appendix in the [https://eprint.iacr.org/2020/1261 MuSig2 paper]).
=== Specification ===
The following conventions are used, with constants as defined for [https://www.secg.org/sec2-v2.pdf secp256k1]. We note that adapting this specification to other elliptic curves is not straightforward and can result in an insecure scheme<ref>Among other pitfalls, using the specification with a curve whose order is not close to the size of the range of the nonce derivation function is insecure.</ref>.
* Lowercase variables represent integers or byte arrays.
** The constant ''p'' refers to the field size, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F''.
** The constant ''n'' refers to the curve order, ''0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141''.
* Uppercase variables refer to points on the curve with equation ''y<sup>2</sup> = x<sup>3</sup> + 7'' over the integers modulo ''p''.
** ''is_infinite(P)'' returns whether or not ''P'' is the point at infinity.
** ''x(P)'' and ''y(P)'' are integers in the range ''0..p-1'' and refer to the X and Y coordinates of a point ''P'' (assuming it is not infinity).
** The constant ''G'' refers to the base point, for which ''x(G) = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798'' and ''y(G) = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8''.
** Addition of points refers to the usual [https://en.wikipedia.org/wiki/Elliptic_curve#The_group_law elliptic curve group operation].
** [https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication Multiplication (⋅) of an integer and a point] refers to the repeated application of the group operation.
* Functions and operations:
** ''||'' refers to byte array concatenation.
** The function ''x[i:j]'', where ''x'' is a byte array and ''i, j &ge; 0'', returns a ''(j - i)''-byte array with a copy of the ''i''-th byte (inclusive) to the ''j''-th byte (exclusive) of ''x''.
** The function ''bytes(x)'', where ''x'' is an integer, returns the 32-byte encoding of ''x'', most significant byte first.
** The function ''bytes(P)'', where ''P'' is a point, returns ''bytes(x(P))''.
** The function ''int(x)'', where ''x'' is a 32-byte array, returns the 256-bit unsigned integer whose most significant byte first encoding is ''x''.
** The function ''has_even_y(P)'', where ''P'' is a point for which ''not is_infinite(P)'', returns ''y(P) mod 2 = 0''.
** The function ''lift_x(x)'', where ''x'' is an integer in range ''0..p-1'', returns the point ''P'' for which ''x(P) = x''<ref>
Given a candidate X coordinate ''x'' in the range ''0..p-1'', there exist either exactly two or exactly zero valid Y coordinates. If no valid Y coordinate exists, then ''x'' is not a valid X coordinate either, i.e., no point ''P'' exists for which ''x(P) = x''. The valid Y coordinates for a given candidate ''x'' are the square roots of ''c = x<sup>3</sup> + 7 mod p'' and they can be computed as ''y = &plusmn;c<sup>(p+1)/4</sup> mod p'' (see [https://en.wikipedia.org/wiki/Quadratic_residue#Prime_or_prime_power_modulus Quadratic residue]) if they exist, which can be checked by squaring and comparing with ''c''.</ref> and ''has_even_y(P)'', or fails if no such point exists. The function ''lift_x(x)'' is equivalent to the following pseudocode:
*** Let ''c = x<sup>3</sup> + 7 mod p''.
*** Let ''y = c<sup>(p+1)/4</sup> mod p''.
*** Fail if ''c &ne; y<sup>2</sup> mod p''.
*** Return the unique point ''P'' such that ''x(P) = x'' and ''y(P) = y'' if ''y mod 2 = 0'' or ''y(P) = p-y'' otherwise.
** The function ''hash<sub>tag</sub>(x)'' where ''tag'' is a UTF-8 encoded tag name and ''x'' is a byte array returns the 32-byte hash ''SHA256(SHA256(tag) || SHA256(tag) || x)''.
==== Key Sorting ====
Input:
* The number ''u'' of signatures with ''0 < u < 2^32''
* The public keys ''pk<sub>1..u</sub>'': ''u'' 32-byte arrays
The algorithm ''KeySort(pk<sub>1..u</sub>)'' is defined as:
* Return ''pk<sub>1..u</sub>'' sorted in lexicographical order.
==== Key Aggregation ====
Input:
* The number ''u'' of signatures with ''0 < u < 2^32''
* The public keys ''pk<sub>1..u</sub>'': ''u'' 32-byte arrays
The algorithm ''KeyAgg(pk<sub>1..u</sub>)'' is defined as:
* For ''i = 1 .. u'':
** Let ''a<sub>i</sub> = KeyAggCoeff(pk<sub>1..u</sub>, i)''.
** Let ''P<sub>i</sub> = lift_x(int(pk<sub>i</sub>))''; fail if it fails.
* Let ''S = a<sub>1</sub>⋅P<sub>1</sub> + a<sub>2</sub>⋅P<sub>1</sub> + ... + a<sub>u</sub>⋅P<sub>u</sub>''
* Fail if ''is_infinite(S)''.
* Return ''bytes(S)''.
The algorithm ''HashKeys(pk<sub>1..u</sub>)'' is defined as:
* Return ''hash(pk<sub>1</sub> || pk<sub>2</sub> || ... || pk<sub>u</sub>)''
The algorithm ''IsSecond(pk<sub>1..u</sub>, i)'' is defined as:
* For ''j = 1 .. u'':
** If ''pk<sub>j</sub> &ne; pk<sub>1</sub>'':
*** Return ''true'' if ''pk<sub>j</sub> = pk<sub>i</sub>'', otherwise return ''false''.
* Return ''false''
The algorithm ''KeyAggCoeff(pk<sub>1..u</sub>, i)'' is defined as:
* Let ''L = HashKeys(pk<sub>1..u</sub>)''.
* Return 1 if ''IsSecond(pk<sub>1..u</sub>, i)'', otherwise return ''int(hash<sub>KeyAgg coefficient</sub>(L || pk) mod n''.
== Applications ==
== Test Vectors and Reference Code ==
== Footnotes ==
<references />
== Acknowledgements ==

View file

@ -30,6 +30,7 @@ void musig_simple_test(secp256k1_scratch_space *scratch) {
secp256k1_musig_pre_session pre_session;
unsigned char session_id[2][32];
secp256k1_xonly_pubkey pk[2];
const secp256k1_xonly_pubkey *pk_ptr[2];
const unsigned char *ncs[2];
unsigned char public_nonce[3][32];
secp256k1_musig_partial_signature partial_sig[2];
@ -41,12 +42,14 @@ void musig_simple_test(secp256k1_scratch_space *scratch) {
secp256k1_testrand256(sk[1]);
secp256k1_testrand256(msg);
pk_ptr[0] = &pk[0];
pk_ptr[1] = &pk[1];
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, sk[1]) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 1);
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
@ -69,7 +72,7 @@ void musig_simple_test(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1);
CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], final_sig, partial_sig, 2) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, &combined_pk) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, sizeof(msg), &combined_pk) == 1);
}
void musig_api_tests(secp256k1_scratch_space *scratch) {
@ -98,11 +101,16 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_musig_pre_session pre_session;
secp256k1_musig_pre_session pre_session_uninitialized;
secp256k1_xonly_pubkey pk[2];
const secp256k1_xonly_pubkey *pk_ptr[2];
secp256k1_xonly_pubkey invalid_pk;
const secp256k1_xonly_pubkey *invalid_pk_ptr2[2];
const secp256k1_xonly_pubkey *invalid_pk_ptr3[3];
unsigned char tweak[32];
unsigned char sec_adaptor[32];
unsigned char sec_adaptor1[32];
secp256k1_pubkey adaptor;
int i;
/** setup **/
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
@ -123,6 +131,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
* structs. */
memset(&pre_session_uninitialized, 0, sizeof(pre_session_uninitialized));
memset(&session_uninitialized, 0, sizeof(session_uninitialized));
memset(&invalid_pk, 0, sizeof(invalid_pk));
secp256k1_testrand256(session_id[0]);
secp256k1_testrand256(session_id[1]);
@ -132,43 +141,56 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_testrand256(sec_adaptor);
secp256k1_testrand256(tweak);
pk_ptr[0] = &pk[0];
pk_ptr[1] = &pk[1];
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor) == 1);
for (i = 0; i < 2; i++) {
invalid_pk_ptr2[i] = &invalid_pk;
invalid_pk_ptr3[i] = &pk[i];
}
/* invalid_pk_ptr3 has two valid, one invalid pk, which is important to test
* musig_pubkeys_combine */
invalid_pk_ptr3[2] = &invalid_pk;
/** main test body **/
/* Key combination */
ecount = 0;
CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, &pre_session, pk, 2) == 0);
CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, &pre_session, pk, 2) == 0);
CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1);
CHECK(ecount == 2);
/* pubkey_combine does not require a scratch space */
CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, &pre_session, pk_ptr, 2) == 1);
CHECK(ecount == 2);
/* A small scratch space works too, but will result in using an ineffecient algorithm */
scratch_small = secp256k1_scratch_space_create(ctx, 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, &pre_session, pk_ptr, 2) == 1);
secp256k1_scratch_space_destroy(ctx, scratch_small);
CHECK(ecount == 2);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, &pre_session, pk, 2) == 0);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, &pre_session, pk_ptr, 2) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, NULL, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, NULL, pk_ptr, 2) == 1);
CHECK(ecount == 3);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 2) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 0) == 0);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, invalid_pk_ptr2, 2) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 0) == 0);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, invalid_pk_ptr3, 3) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk_ptr, 0) == 0);
CHECK(ecount == 7);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 0) == 0);
CHECK(ecount == 8);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1);
/** Tweaking */
ecount = 0;
@ -208,45 +230,47 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
/** Session creation **/
ecount = 0;
CHECK(secp256k1_musig_session_init(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_init(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_init(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_session_init(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, &pre_session, 2, sk[0]) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, &pre_session, 2, sk[0]) == 1);
CHECK(ecount == 6);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, &pre_session, 2, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, &pre_session, 2, sk[0]) == 0);
CHECK(ecount == 7);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, sk[0]) == 0);
CHECK(ecount == 8);
/* Uninitialized pre_session */
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session_uninitialized, 2, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session_uninitialized, 2, sk[0]) == 0);
CHECK(ecount == 9);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 0, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 0, sk[0]) == 0);
CHECK(ecount == 10);
/* If more than UINT32_MAX fits in a size_t, test that session_init
* rejects n_signers that high. */
if (SIZE_MAX > UINT32_MAX) {
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, ((size_t) UINT32_MAX) + 2, sk[0]) == 0);
CHECK(ecount == 11);
} else {
ecount = 11;
}
CHECK(ecount == 11);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, NULL) == 0);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, NULL) == 0);
CHECK(ecount == 12);
/* secret key overflows */
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, ones) == 0);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, ones) == 0);
CHECK(ecount == 12);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_init(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 1);
CHECK(secp256k1_musig_session_init(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, sk[1]) == 1);
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
@ -267,8 +291,10 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(ecount == 6);
if (SIZE_MAX > UINT32_MAX) {
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, ((size_t) UINT32_MAX) + 2) == 0);
CHECK(ecount == 7);
} else {
ecount = 7;
}
CHECK(ecount == 7);
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1);
/** Signing step 0 -- exchange nonce commitments */
@ -462,7 +488,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_verify(vrfy, final_sig, msg, &combined_pk) == 1);
CHECK(secp256k1_schnorrsig_verify(vrfy, final_sig, msg, sizeof(msg), &combined_pk) == 1);
/** Secret adaptor can be extracted from signature */
ecount = 0;
@ -513,6 +539,7 @@ void musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp25
secp256k1_musig_session_signer_data signers_tmp[2];
unsigned char sk_dummy[32];
secp256k1_xonly_pubkey pks_tmp[2];
const secp256k1_xonly_pubkey *pks_tmp_ptr[2];
secp256k1_xonly_pubkey combined_pk_tmp;
secp256k1_musig_pre_session pre_session_tmp;
unsigned char nonce[32];
@ -521,10 +548,12 @@ void musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp25
secp256k1_testrand256(sk_dummy);
pks_tmp[0] = pks[0];
CHECK(secp256k1_xonly_pubkey_create(&pks_tmp[1], sk_dummy) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, &pre_session_tmp, pks_tmp, 2) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, &pre_session_tmp, 2, 1, sk_dummy) == 1);
pks_tmp_ptr[0] = &pks_tmp[0];
pks_tmp_ptr[1] = &pks_tmp[1];
CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, &pre_session_tmp, pks_tmp_ptr, 2) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, &pre_session_tmp, 2, sk_dummy) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 0, sk) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, sk) == 1);
CHECK(memcmp(nonce_commitment, nonce_commitments[1], 32) == 0);
/* Call get_public_nonce with different signers than the signers the session was
* initialized with. */
@ -553,7 +582,7 @@ int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_xonly_pubkey *
/* Initialize new signers */
secp256k1_testrand256(session_id);
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 1, sk) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, sk) == 1);
ncs[0] = nonce_commitment_other;
ncs[1] = nonce_commitment;
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, nonce, ncs, 2, NULL) == 1);
@ -585,7 +614,7 @@ void musig_state_machine_late_msg_test(secp256k1_xonly_pubkey *pks, secp256k1_xo
secp256k1_musig_partial_signature partial_sig;
secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount);
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, NULL, combined_pk, pre_session, 2, 1, sk) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, NULL, combined_pk, pre_session, 2, sk) == 1);
ncs[0] = nonce_commitment_other;
ncs[1] = nonce_commitment;
@ -621,6 +650,7 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
unsigned char msg[32];
unsigned char sk[2][32];
secp256k1_xonly_pubkey pk[2];
const secp256k1_xonly_pubkey *pk_ptr[2];
secp256k1_xonly_pubkey combined_pk;
secp256k1_musig_pre_session pre_session;
unsigned char nonce[2][32];
@ -643,11 +673,13 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
secp256k1_testrand256(sk[0]);
secp256k1_testrand256(sk[1]);
secp256k1_testrand256(msg);
pk_ptr[0] = &pk[0];
pk_ptr[1] = &pk[1];
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk, 2) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk_ptr, 2) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, sk[0]) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, sk[1]) == 1);
/* Can't combine nonces unless we're through round 1 already */
ecount = 0;
CHECK(secp256k1_musig_session_combine_nonces(ctx_tmp, &session[0], signers0, 2, NULL, NULL) == 0);
@ -732,7 +764,9 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
unsigned char seckey_a[2][32];
unsigned char seckey_b[2][32];
secp256k1_xonly_pubkey pk_a[2];
const secp256k1_xonly_pubkey *pk_a_ptr[2];
secp256k1_xonly_pubkey pk_b[2];
const secp256k1_xonly_pubkey *pk_b_ptr[2];
secp256k1_musig_pre_session pre_session_a;
secp256k1_musig_pre_session pre_session_b;
secp256k1_xonly_pubkey combined_pk_a;
@ -761,22 +795,26 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
secp256k1_testrand256(seckey_b[1]);
secp256k1_testrand256(sec_adaptor);
pk_a_ptr[0] = &pk_a[0];
pk_a_ptr[1] = &pk_a[1];
pk_b_ptr[0] = &pk_b[0];
pk_b_ptr[1] = &pk_b[1];
CHECK(secp256k1_xonly_pubkey_create(&pk_a[0], seckey_a[0]));
CHECK(secp256k1_xonly_pubkey_create(&pk_a[1], seckey_a[1]));
CHECK(secp256k1_xonly_pubkey_create(&pk_b[0], seckey_b[0]));
CHECK(secp256k1_xonly_pubkey_create(&pk_b[1], seckey_b[1]));
CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor));
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, &pre_session_a, pk_a, 2));
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, &pre_session_b, pk_b, 2));
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, &pre_session_a, pk_a_ptr, 2));
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, &pre_session_b, pk_b_ptr, 2));
CHECK(secp256k1_musig_session_init(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, 0, seckey_a[0]));
CHECK(secp256k1_musig_session_init(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, 1, seckey_a[1]));
CHECK(secp256k1_musig_session_init(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, seckey_a[0]));
CHECK(secp256k1_musig_session_init(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, seckey_a[1]));
noncommit_a_ptr[0] = noncommit_a[0];
noncommit_a_ptr[1] = noncommit_a[1];
CHECK(secp256k1_musig_session_init(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, 0, seckey_b[0]));
CHECK(secp256k1_musig_session_init(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, 1, seckey_b[1]));
CHECK(secp256k1_musig_session_init(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, seckey_b[0]));
CHECK(secp256k1_musig_session_init(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, seckey_b[1]));
noncommit_b_ptr[0] = noncommit_b[0];
noncommit_b_ptr[1] = noncommit_b[1];
@ -810,7 +848,7 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_b_adapted[0], &partial_sig_b[0], sec_adaptor, combined_nonce_parity_b));
memcpy(&partial_sig_b_adapted[1], &partial_sig_b[1], sizeof(partial_sig_b_adapted[1]));
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], final_sig_b, partial_sig_b_adapted, 2) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_b, msg32_b, &combined_pk_b) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_b, msg32_b, sizeof(msg32_b), &combined_pk_b) == 1);
/* Step 6: Signer 1 extracts adaptor from the published signature, applies it to
* other partial signature, and takes A-coins. */
@ -819,13 +857,13 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_a[0], &partial_sig_a[0], sec_adaptor_extracted, combined_nonce_parity_a));
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[1], &partial_sig_a[1]));
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], final_sig_a, partial_sig_a, 2) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_a, msg32_a, &combined_pk_a) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_a, msg32_a, sizeof(msg32_a), &combined_pk_a) == 1);
}
/* Checks that hash initialized by secp256k1_musig_sha256_init_tagged has the
* expected state. */
void sha256_tag_test(void) {
char tag[17] = "MuSig coefficient";
char tag[18] = "KeyAgg coefficient";
secp256k1_sha256 sha;
secp256k1_sha256 sha_tagged;
unsigned char buf[32];
@ -833,9 +871,9 @@ void sha256_tag_test(void) {
size_t i;
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, (unsigned char *) tag, 17);
secp256k1_sha256_write(&sha, (unsigned char *) tag, sizeof(tag));
secp256k1_sha256_finalize(&sha, buf);
/* buf = SHA256("MuSig coefficient") */
/* buf = SHA256("KeyAgg coefficient") */
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, buf, 32);
@ -877,8 +915,8 @@ void musig_tweak_test_helper(const secp256k1_xonly_pubkey* combined_pubkey, cons
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk0) == 1);
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk1) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, combined_pubkey, pre_session, 2, 0, sk0) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, combined_pubkey, pre_session, 2, 1, sk1) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, combined_pubkey, pre_session, 2, sk0) == 1);
CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, combined_pubkey, pre_session, 2, sk1) == 1);
/* Set nonce commitments */
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
@ -896,7 +934,7 @@ void musig_tweak_test_helper(const secp256k1_xonly_pubkey* combined_pubkey, cons
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signers0[1], &partial_sig[1], &pk[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1);
CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], final_sig, partial_sig, 2));
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, combined_pubkey) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, sizeof(msg), combined_pubkey) == 1);
}
/* In this test we create a combined public key P and a commitment Q = P +
@ -905,6 +943,7 @@ void musig_tweak_test_helper(const secp256k1_xonly_pubkey* combined_pubkey, cons
void musig_tweak_test(secp256k1_scratch_space *scratch) {
unsigned char sk[2][32];
secp256k1_xonly_pubkey pk[2];
const secp256k1_xonly_pubkey *pk_ptr[2];
secp256k1_musig_pre_session pre_session_P;
secp256k1_musig_pre_session pre_session_Q;
secp256k1_xonly_pubkey P;
@ -923,9 +962,11 @@ void musig_tweak_test(secp256k1_scratch_space *scratch) {
secp256k1_testrand256(sk[1]);
secp256k1_testrand256(contract);
pk_ptr[0] = &pk[0];
pk_ptr[1] = &pk[1];
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &P, &pre_session_P, pk, 2) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &P, &pre_session_P, pk_ptr, 2) == 1);
CHECK(secp256k1_xonly_pubkey_serialize(ctx, P_serialized, &P) == 1);
secp256k1_sha256_initialize(&sha);
@ -946,6 +987,145 @@ void musig_tweak_test(secp256k1_scratch_space *scratch) {
musig_tweak_test_helper(&Q_xonly, sk[0], sk[1], &pre_session_Q);
}
void musig_test_vectors_helper(unsigned char pk_ser[][32], int n_pks, const unsigned char *combined_pk_expected, int has_second_pk, int second_pk_idx) {
secp256k1_xonly_pubkey *pk = malloc(n_pks * sizeof(*pk));
const secp256k1_xonly_pubkey **pk_ptr = malloc(n_pks * sizeof(*pk_ptr));
secp256k1_xonly_pubkey combined_pk;
unsigned char combined_pk_ser[32];
secp256k1_musig_pre_session pre_session;
secp256k1_fe second_pk_x;
int i;
for (i = 0; i < n_pks; i++) {
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk[i], pk_ser[i]));
pk_ptr[i] = &pk[i];
}
CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, &pre_session, pk_ptr, n_pks) == 1);
CHECK(secp256k1_fe_set_b32(&second_pk_x, pre_session.second_pk));
CHECK(secp256k1_fe_is_zero(&second_pk_x) == !has_second_pk);
if (!secp256k1_fe_is_zero(&second_pk_x)) {
CHECK(secp256k1_memcmp_var(&pk_ser[second_pk_idx], &pre_session.second_pk, sizeof(pk_ser[second_pk_idx])) == 0);
}
CHECK(secp256k1_xonly_pubkey_serialize(ctx, combined_pk_ser, &combined_pk));
/* TODO: remove when test vectors are not expected to change anymore */
/* int k, l; */
/* printf("const unsigned char combined_pk_expected[32] = {\n"); */
/* for (k = 0; k < 4; k++) { */
/* printf(" "); */
/* for (l = 0; l < 8; l++) { */
/* printf("0x%02X, ", combined_pk_ser[k*8+l]); */
/* } */
/* printf("\n"); */
/* } */
/* printf("};\n"); */
CHECK(secp256k1_memcmp_var(combined_pk_ser, combined_pk_expected, sizeof(combined_pk_ser)) == 0);
free(pk);
free(pk_ptr);
}
void musig_test_vectors(void) {
size_t i;
unsigned char pk_ser_tmp[4][32];
unsigned char pk_ser[3][32] = {
/* X1 */
{
0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10,
0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29,
0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0,
0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9
},
/* X2 */
{
0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
},
/* X3 */
{
0x35, 0x90, 0xA9, 0x4E, 0x76, 0x8F, 0x8E, 0x18,
0x15, 0xC2, 0xF2, 0x4B, 0x4D, 0x80, 0xA8, 0xE3,
0x14, 0x93, 0x16, 0xC3, 0x51, 0x8C, 0xE7, 0xB7,
0xAD, 0x33, 0x83, 0x68, 0xD0, 0x38, 0xCA, 0x66
}
};
const unsigned char combined_pk_expected[4][32] = {
{ /* 0 */
0xEA, 0x06, 0x7B, 0x01, 0x67, 0x24, 0x5A, 0x6F,
0xED, 0xB1, 0xB1, 0x22, 0xBB, 0x03, 0xAB, 0x7E,
0x5D, 0x48, 0x6C, 0x81, 0x83, 0x42, 0xE0, 0xE9,
0xB6, 0x41, 0x79, 0xAD, 0x32, 0x8D, 0x9D, 0x19,
},
{ /* 1 */
0x14, 0xE1, 0xF8, 0x3E, 0x9E, 0x25, 0x60, 0xFB,
0x2A, 0x6C, 0x04, 0x24, 0x55, 0x6C, 0x86, 0x8D,
0x9F, 0xB4, 0x63, 0x35, 0xD4, 0xF7, 0x8D, 0x22,
0x7D, 0x5D, 0x1D, 0x3C, 0x89, 0x90, 0x6F, 0x1E,
},
{ /* 2 */
0x70, 0x28, 0x8D, 0xF2, 0xB7, 0x60, 0x3D, 0xBE,
0xA0, 0xC7, 0xB7, 0x41, 0xDD, 0xAA, 0xB9, 0x46,
0x81, 0x14, 0x4E, 0x0B, 0x19, 0x08, 0x6C, 0x69,
0xB2, 0x34, 0x89, 0xE4, 0xF5, 0xB7, 0x01, 0x9A,
},
{ /* 3 */
0x93, 0xEE, 0xD8, 0x24, 0xF2, 0x3C, 0x5A, 0xE1,
0xC1, 0x05, 0xE7, 0x31, 0x09, 0x97, 0x3F, 0xCD,
0x4A, 0xE3, 0x3A, 0x9F, 0xA0, 0x2F, 0x0A, 0xC8,
0x5A, 0x3E, 0x55, 0x89, 0x07, 0x53, 0xB0, 0x67,
},
};
for (i = 0; i < sizeof(combined_pk_expected)/sizeof(combined_pk_expected[0]); i++) {
size_t n_pks;
int has_second_pk;
int second_pk_idx;
switch (i) {
case 0:
/* [X1, X2, X3] */
n_pks = 3;
memcpy(pk_ser_tmp[0], pk_ser[0], sizeof(pk_ser_tmp[0]));
memcpy(pk_ser_tmp[1], pk_ser[1], sizeof(pk_ser_tmp[1]));
memcpy(pk_ser_tmp[2], pk_ser[2], sizeof(pk_ser_tmp[2]));
has_second_pk = 1;
second_pk_idx = 1;
break;
case 1:
/* [X3, X2, X1] */
n_pks = 3;
memcpy(pk_ser_tmp[2], pk_ser[0], sizeof(pk_ser_tmp[0]));
memcpy(pk_ser_tmp[1], pk_ser[1], sizeof(pk_ser_tmp[1]));
memcpy(pk_ser_tmp[0], pk_ser[2], sizeof(pk_ser_tmp[2]));
has_second_pk = 1;
second_pk_idx = 1;
break;
case 2:
/* [X1, X1, X1] */
n_pks = 3;
memcpy(pk_ser_tmp[0], pk_ser[0], sizeof(pk_ser_tmp[0]));
memcpy(pk_ser_tmp[1], pk_ser[0], sizeof(pk_ser_tmp[1]));
memcpy(pk_ser_tmp[2], pk_ser[0], sizeof(pk_ser_tmp[2]));
has_second_pk = 0;
second_pk_idx = 0; /* unchecked */
break;
case 3:
/* [X1, X1, X2, X2] */
n_pks = 4;
memcpy(pk_ser_tmp[0], pk_ser[0], sizeof(pk_ser_tmp[0]));
memcpy(pk_ser_tmp[1], pk_ser[0], sizeof(pk_ser_tmp[1]));
memcpy(pk_ser_tmp[2], pk_ser[1], sizeof(pk_ser_tmp[2]));
memcpy(pk_ser_tmp[3], pk_ser[1], sizeof(pk_ser_tmp[3]));
has_second_pk = 1;
second_pk_idx = 3;
break;
default:
CHECK(0);
}
musig_test_vectors_helper(pk_ser_tmp, n_pks, combined_pk_expected[i], has_second_pk, second_pk_idx);
}
}
void run_musig_tests(void) {
int i;
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024);
@ -961,6 +1141,7 @@ void run_musig_tests(void) {
scriptless_atomic_swap(scratch);
musig_tweak_test(scratch);
}
musig_test_vectors();
sha256_tag_test();
secp256k1_scratch_space_destroy(ctx, scratch);

View file

@ -182,7 +182,15 @@ int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, c
}
secp256k1_scalar_set_int(&sum, 0);
for (i = 0; i < n_total; i++) {
/* Here, n_total > 0. Thus the loop runs at least once.
Thus we may use a do-while loop, which checks the loop
condition only at the end.
The do-while loop helps GCC prove that the loop runs at least
once and suppresses a -Wmaybe-uninitialized warning. */
i = 0;
do {
int overflow = 0;
secp256k1_scalar addend;
secp256k1_scalar_set_u64(&addend, value[i]); /* s = v */
@ -207,7 +215,9 @@ int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, c
secp256k1_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */
secp256k1_scalar_add(&sum, &sum, &addend); /* sum += s */
secp256k1_scalar_clear(&addend);
}
i++;
} while (i < n_total);
/* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */
secp256k1_scalar_negate(&sum, &sum);

View file

@ -369,7 +369,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar *
secp256k1_scalar stmp;
unsigned char prep[4096];
unsigned char tmp[32];
uint64_t value;
uint64_t value = 0;
size_t offset;
size_t i;
size_t j;

View file

@ -1,13 +1,13 @@
/**********************************************************************
* Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H
#define SECP256K1_MODULE_RECOVERY_MAIN_H
#include "include/secp256k1_recovery.h"
#include "../../../include/secp256k1_recovery.h"
static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) {
(void)ctx;
@ -120,34 +120,34 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, cons
return !secp256k1_gej_is_infinity(&qj);
}
int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
secp256k1_scalar r, s;
int ret, recid;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(msg32 != NULL);
ARG_CHECK(msghash32 != NULL);
ARG_CHECK(signature != NULL);
ARG_CHECK(seckey != NULL);
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, msg32, seckey, noncefp, noncedata);
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, NULL, NULL, NULL, msghash32, seckey, noncefp, noncedata);
secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
return ret;
}
int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) {
int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msghash32) {
secp256k1_ge q;
secp256k1_scalar r, s;
secp256k1_scalar m;
int recid;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(msg32 != NULL);
ARG_CHECK(msghash32 != NULL);
ARG_CHECK(signature != NULL);
ARG_CHECK(pubkey != NULL);
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature);
VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */
secp256k1_scalar_set_b32(&m, msg32, NULL);
secp256k1_scalar_set_b32(&m, msghash32, NULL);
if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
secp256k1_pubkey_save(pubkey, &q);
return 1;

View file

@ -1,14 +1,14 @@
/**********************************************************************
* Copyright (c) 2016 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2016 Andrew Poelstra *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
#include "src/modules/recovery/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) {
int i, j, k;

View file

@ -1,8 +1,8 @@
/**********************************************************************
* Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2013-2015 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H
#define SECP256K1_MODULE_RECOVERY_TESTS_H

View file

@ -1,15 +1,15 @@
/**********************************************************************
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef _SECP256K1_MODULE_SCHNORRSIG_MAIN_
#define _SECP256K1_MODULE_SCHNORRSIG_MAIN_
#ifndef SECP256K1_MODULE_SCHNORRSIG_MAIN_H
#define SECP256K1_MODULE_SCHNORRSIG_MAIN_H
#include "include/secp256k1.h"
#include "include/secp256k1_schnorrsig.h"
#include "hash.h"
#include "../../../include/secp256k1.h"
#include "../../../include/secp256k1_schnorrsig.h"
#include "../../hash.h"
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
* SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */
@ -43,16 +43,18 @@ static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *
sha->bytes = 64;
}
/* algo16 argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340
/* algo argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340
* by using the correct tagged hash function. */
static const unsigned char bip340_algo16[16] = "BIP0340/nonce\0\0\0";
static const unsigned char bip340_algo[13] = "BIP0340/nonce";
static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
static const unsigned char schnorrsig_extraparams_magic[4] = SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC;
static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
secp256k1_sha256 sha;
unsigned char masked_key[32];
int i;
if (algo16 == NULL) {
if (algo == NULL) {
return 0;
}
@ -65,18 +67,14 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms
}
}
/* Tag the hash with algo16 which is important to avoid nonce reuse across
/* Tag the hash with algo which is important to avoid nonce reuse across
* algorithms. If this nonce function is used in BIP-340 signing as defined
* in the spec, an optimized tagging implementation is used. */
if (secp256k1_memcmp_var(algo16, bip340_algo16, 16) == 0) {
if (algolen == sizeof(bip340_algo)
&& secp256k1_memcmp_var(algo, bip340_algo, algolen) == 0) {
secp256k1_nonce_function_bip340_sha256_tagged(&sha);
} else {
int algo16_len = 16;
/* Remove terminating null bytes */
while (algo16_len > 0 && !algo16[algo16_len - 1]) {
algo16_len--;
}
secp256k1_sha256_initialize_tagged(&sha, algo16, algo16_len);
secp256k1_sha256_initialize_tagged(&sha, algo, algolen);
}
/* Hash (masked-)key||pk||msg using the tagged hash as per the spec */
@ -86,7 +84,7 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms
secp256k1_sha256_write(&sha, key32, 32);
}
secp256k1_sha256_write(&sha, xonly_pk32, 32);
secp256k1_sha256_write(&sha, msg32, 32);
secp256k1_sha256_write(&sha, msg, msglen);
secp256k1_sha256_finalize(&sha, nonce32);
return 1;
}
@ -108,23 +106,23 @@ static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) {
sha->bytes = 64;
}
static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg32, const unsigned char *pubkey32)
static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg, size_t msglen, const unsigned char *pubkey32)
{
unsigned char buf[32];
secp256k1_sha256 sha;
/* tagged hash(r.x, pk.x, msg32) */
/* tagged hash(r.x, pk.x, msg) */
secp256k1_schnorrsig_sha256_tagged(&sha);
secp256k1_sha256_write(&sha, r32, 32);
secp256k1_sha256_write(&sha, pubkey32, 32);
secp256k1_sha256_write(&sha, msg32, 32);
secp256k1_sha256_write(&sha, msg, msglen);
secp256k1_sha256_finalize(&sha, buf);
/* Set scalar e to the challenge hash modulo the curve order as per
* BIP340. */
secp256k1_scalar_set_b32(e, buf, NULL);
}
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) {
int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) {
secp256k1_scalar sk;
secp256k1_scalar e;
secp256k1_scalar k;
@ -139,7 +137,7 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
ARG_CHECK(sig64 != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(msg != NULL || msglen == 0);
ARG_CHECK(keypair != NULL);
if (noncefp == NULL) {
@ -156,7 +154,7 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64
secp256k1_scalar_get_b32(seckey, &sk);
secp256k1_fe_get_b32(pk_buf, &pk.x);
ret &= !!noncefp(buf, msg32, seckey, pk_buf, bip340_algo16, ndata);
ret &= !!noncefp(buf, msg, msglen, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata);
secp256k1_scalar_set_b32(&k, buf, NULL);
ret &= !secp256k1_scalar_is_zero(&k);
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
@ -174,7 +172,7 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64
secp256k1_fe_normalize_var(&r.x);
secp256k1_fe_get_b32(&sig64[0], &r.x);
secp256k1_schnorrsig_challenge(&e, &sig64[0], msg32, pk_buf);
secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, pk_buf);
secp256k1_scalar_mul(&e, &e, &sk);
secp256k1_scalar_add(&e, &e, &k);
secp256k1_scalar_get_b32(&sig64[32], &e);
@ -187,7 +185,26 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64
return ret;
}
int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_xonly_pubkey *pubkey) {
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, unsigned char *aux_rand32) {
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, secp256k1_nonce_function_bip340, aux_rand32);
}
int secp256k1_schnorrsig_sign_custom(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_keypair *keypair, secp256k1_schnorrsig_extraparams *extraparams) {
secp256k1_nonce_function_hardened noncefp = NULL;
void *ndata = NULL;
VERIFY_CHECK(ctx != NULL);
if (extraparams != NULL) {
ARG_CHECK(secp256k1_memcmp_var(extraparams->magic,
schnorrsig_extraparams_magic,
sizeof(extraparams->magic)) == 0);
noncefp = extraparams->noncefp;
ndata = extraparams->ndata;
}
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg, msglen, keypair, noncefp, ndata);
}
int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg, size_t msglen, const secp256k1_xonly_pubkey *pubkey) {
secp256k1_scalar s;
secp256k1_scalar e;
secp256k1_gej rj;
@ -201,7 +218,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
ARG_CHECK(sig64 != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(msg != NULL || msglen == 0);
ARG_CHECK(pubkey != NULL);
if (!secp256k1_fe_set_b32(&rx, &sig64[0])) {
@ -219,7 +236,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha
/* Compute e. */
secp256k1_fe_get_b32(buf, &pk.x);
secp256k1_schnorrsig_challenge(&e, &sig64[0], msg32, buf);
secp256k1_schnorrsig_challenge(&e, &sig64[0], msg, msglen, buf);
/* Compute rj = s*G + (-e)*pkj */
secp256k1_scalar_negate(&e, &e);

View file

@ -1,13 +1,13 @@
/**********************************************************************
* Copyright (c) 2020 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2020 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_
#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_
#ifndef SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H
#define SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_H
#include "include/secp256k1_schnorrsig.h"
#include "../../../include/secp256k1_schnorrsig.h"
#include "src/modules/schnorrsig/main_impl.h"
static const unsigned char invalid_pubkey_bytes[][32] = {
@ -58,15 +58,19 @@ static const unsigned char invalid_pubkey_bytes[][32] = {
#define NUM_INVALID_KEYS (sizeof(invalid_pubkey_bytes) / sizeof(invalid_pubkey_bytes[0]))
static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,
static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg,
size_t msglen,
const unsigned char *key32, const unsigned char *xonly_pk32,
const unsigned char *algo16, void* data) {
const unsigned char *algo, size_t algolen,
void* data) {
secp256k1_scalar s;
int *idata = data;
(void)msg32;
(void)msg;
(void)msglen;
(void)key32;
(void)xonly_pk32;
(void)algo16;
(void)algo;
(void)algolen;
secp256k1_scalar_set_int(&s, *idata);
secp256k1_scalar_get_b32(nonce32, &s);
return 1;
@ -101,7 +105,7 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons
secp256k1_scalar e;
unsigned char msg32[32];
secp256k1_testrand256(msg32);
secp256k1_schnorrsig_challenge(&e, sig64, msg32, pk32);
secp256k1_schnorrsig_challenge(&e, sig64, msg32, sizeof(msg32), pk32);
/* Only do work if we hit a challenge we haven't tried before. */
if (!e_done[e]) {
/* Iterate over the possible valid last 32 bytes in the signature.
@ -119,7 +123,7 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons
secp256k1_testrand256(sig64 + 32);
expect_valid = 0;
}
valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, &pubkeys[d - 1]);
valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, sizeof(msg32), &pubkeys[d - 1]);
CHECK(valid == expect_valid);
count_valid += valid;
}
@ -137,6 +141,8 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons
static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const secp256k1_keypair* keypairs, const int* parities) {
int d, k;
uint64_t iter = 0;
secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
/* Loop over keys. */
for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) {
int actual_d = d;
@ -149,19 +155,21 @@ static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsign
unsigned char sig64[64];
int actual_k = k;
if (skip_section(&iter)) continue;
extraparams.noncefp = secp256k1_hardened_nonce_function_smallint;
extraparams.ndata = &k;
if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k;
/* Generate random messages until all challenges have been tried. */
while (e_count_done < EXHAUSTIVE_TEST_ORDER) {
secp256k1_scalar e;
secp256k1_testrand256(msg32);
secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, xonly_pubkey_bytes[d - 1]);
secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, sizeof(msg32), xonly_pubkey_bytes[d - 1]);
/* Only do work if we hit a challenge we haven't tried before. */
if (!e_done[e]) {
secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER;
unsigned char expected_s_bytes[32];
secp256k1_scalar_get_b32(expected_s_bytes, &expected_s);
/* Invoke the real function to construct a signature. */
CHECK(secp256k1_schnorrsig_sign(ctx, sig64, msg32, &keypairs[d - 1], secp256k1_hardened_nonce_function_smallint, &k));
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig64, msg32, sizeof(msg32), &keypairs[d - 1], &extraparams));
/* The first 32 bytes must match the xonly pubkey for the specified k. */
CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0);
/* The last 32 bytes must match the expected s value. */

View file

@ -1,22 +1,22 @@
/**********************************************************************
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
**********************************************************************/
/***********************************************************************
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_
#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_
#ifndef SECP256K1_MODULE_SCHNORRSIG_TESTS_H
#define SECP256K1_MODULE_SCHNORRSIG_TESTS_H
#include "secp256k1_schnorrsig.h"
#include "../../../include/secp256k1_schnorrsig.h"
/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many
* bytes) changes the hash function
*/
void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) {
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];
CHECK(nonce_function_bip340(nonces[0], args[0], args[1], args[2], args[3], 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);
CHECK(nonce_function_bip340(nonces[1], args[0], args[1], args[2], args[3], args[4]) == 1);
CHECK(nonce_function_bip340(nonces[1], args[0], msglen, args[1], args[2], args[3], algolen, args[4]) == 1);
CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0);
}
@ -34,11 +34,13 @@ void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2)
void run_nonce_function_bip340_tests(void) {
unsigned char tag[13] = "BIP0340/nonce";
unsigned char aux_tag[11] = "BIP0340/aux";
unsigned char algo16[16] = "BIP0340/nonce\0\0\0";
unsigned char algo[13] = "BIP0340/nonce";
size_t algolen = sizeof(algo);
secp256k1_sha256 sha;
secp256k1_sha256 sha_optimized;
unsigned char nonce[32];
unsigned char msg[32];
size_t msglen = sizeof(msg);
unsigned char key[32];
unsigned char pk[32];
unsigned char aux_rand[32];
@ -68,33 +70,45 @@ void run_nonce_function_bip340_tests(void) {
args[0] = msg;
args[1] = key;
args[2] = pk;
args[3] = algo16;
args[3] = algo;
args[4] = aux_rand;
for (i = 0; i < count; i++) {
nonce_function_bip340_bitflip(args, 0, 32);
nonce_function_bip340_bitflip(args, 1, 32);
nonce_function_bip340_bitflip(args, 2, 32);
/* Flip algo16 special case "BIP0340/nonce" */
nonce_function_bip340_bitflip(args, 3, 16);
/* Flip algo16 again */
nonce_function_bip340_bitflip(args, 3, 16);
nonce_function_bip340_bitflip(args, 4, 32);
nonce_function_bip340_bitflip(args, 0, 32, msglen, algolen);
nonce_function_bip340_bitflip(args, 1, 32, msglen, algolen);
nonce_function_bip340_bitflip(args, 2, 32, msglen, algolen);
/* Flip algo special case "BIP0340/nonce" */
nonce_function_bip340_bitflip(args, 3, algolen, msglen, algolen);
/* Flip algo again */
nonce_function_bip340_bitflip(args, 3, algolen, msglen, algolen);
nonce_function_bip340_bitflip(args, 4, 32, msglen, algolen);
}
/* NULL algo16 is disallowed */
CHECK(nonce_function_bip340(nonce, msg, key, pk, NULL, NULL) == 0);
/* Empty algo16 is fine */
memset(algo16, 0x00, 16);
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
/* algo16 with terminating null bytes is fine */
algo16[1] = 65;
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
/* Other algo16 is fine */
memset(algo16, 0xFF, 16);
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
/* NULL algo is disallowed */
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, NULL, 0, NULL) == 0);
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1);
/* Other algo is fine */
secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, algo, algolen);
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1);
for (i = 0; i < count; i++) {
unsigned char nonce2[32];
uint32_t offset = secp256k1_testrand_int(msglen - 1);
size_t msglen_tmp = (msglen + offset) % msglen;
size_t algolen_tmp;
/* Different msglen gives different nonce */
CHECK(nonce_function_bip340(nonce2, msg, msglen_tmp, key, pk, algo, algolen, NULL) == 1);
CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0);
/* Different algolen gives different nonce */
offset = secp256k1_testrand_int(algolen - 1);
algolen_tmp = (algolen + offset) % algolen;
CHECK(nonce_function_bip340(nonce2, msg, msglen, key, pk, algo, algolen_tmp, NULL) == 1);
CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0);
}
/* NULL aux_rand argument is allowed. */
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
CHECK(nonce_function_bip340(nonce, msg, msglen, key, pk, algo, algolen, NULL) == 1);
}
void test_schnorrsig_api(void) {
@ -103,10 +117,12 @@ void test_schnorrsig_api(void) {
unsigned char sk3[32];
unsigned char msg[32];
secp256k1_keypair keypairs[3];
secp256k1_keypair invalid_keypair = { 0 };
secp256k1_keypair invalid_keypair = {{ 0 }};
secp256k1_xonly_pubkey pk[3];
secp256k1_xonly_pubkey zero_pk;
unsigned char sig[64];
secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL};
/** setup **/
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
@ -138,36 +154,60 @@ void test_schnorrsig_api(void) {
/** main test body **/
ecount = 0;
CHECK(secp256k1_schnorrsig_sign(none, sig, msg, &keypairs[0], NULL, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign(none, sig, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_sign(vrfy, sig, msg, &keypairs[0], NULL, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign(vrfy, sig, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL, NULL) == 1);
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_sign(sign, NULL, msg, &keypairs[0], NULL, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign(sign, NULL, msg, &keypairs[0], NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_sign(sign, sig, NULL, &keypairs[0], NULL, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign(sign, sig, NULL, &keypairs[0], NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, NULL, NULL, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, NULL, NULL) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &invalid_keypair, NULL, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &invalid_keypair, NULL) == 0);
CHECK(ecount == 6);
ecount = 0;
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL, NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(none, sig, msg, &pk[0]) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(none, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, &pk[0]) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(vrfy, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, &pk[0]) == 1);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, &pk[0]) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(sign, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, &pk[0]) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, NULL) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, NULL, 0, &keypairs[0], &extraparams) == 1);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), NULL, &extraparams) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, &zero_pk) == 0);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1);
CHECK(ecount == 6);
CHECK(secp256k1_schnorrsig_sign_custom(sign, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0);
CHECK(ecount == 7);
ecount = 0;
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(none, sig, msg, sizeof(msg), &pk[0]) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, sizeof(msg), &pk[0]) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), &pk[0]) == 1);
CHECK(ecount == 2);
CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, sizeof(msg), &pk[0]) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, sizeof(msg), &pk[0]) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, 0, &pk[0]) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), NULL) == 0);
CHECK(ecount == 5);
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, sizeof(msg), &zero_pk) == 0);
CHECK(ecount == 6);
secp256k1_context_destroy(none);
@ -179,7 +219,7 @@ void test_schnorrsig_api(void) {
/* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the
* expected state. */
void test_schnorrsig_sha256_tagged(void) {
char tag[17] = "BIP0340/challenge";
unsigned char tag[17] = "BIP0340/challenge";
secp256k1_sha256 sha;
secp256k1_sha256 sha_optimized;
@ -190,19 +230,19 @@ void test_schnorrsig_sha256_tagged(void) {
/* Helper function for schnorrsig_bip_vectors
* 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, unsigned char *aux_rand, const unsigned char *msg, const unsigned char *expected_sig) {
void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, unsigned char *aux_rand, const unsigned char *msg32, const unsigned char *expected_sig) {
unsigned char sig[64];
secp256k1_keypair keypair;
secp256k1_xonly_pubkey pk, pk_expected;
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, aux_rand));
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg32, &keypair, aux_rand));
CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized));
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, &pk));
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg32, 32, &pk));
}
/* Helper function for schnorrsig_bip_vectors
@ -211,7 +251,7 @@ void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized
secp256k1_xonly_pubkey pk;
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk, pk_serialized));
CHECK(expected == secp256k1_schnorrsig_verify(ctx, sig, msg32, &pk));
CHECK(expected == secp256k1_schnorrsig_verify(ctx, sig, msg32, 32, &pk));
}
/* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See
@ -634,22 +674,26 @@ void test_schnorrsig_bip_vectors(void) {
}
/* Nonce function that returns constant 0 */
static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
(void) msg32;
static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
(void) msg;
(void) msglen;
(void) key32;
(void) xonly_pk32;
(void) algo16;
(void) algo;
(void) algolen;
(void) data;
(void) nonce32;
return 0;
}
/* Nonce function that sets nonce to 0 */
static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
(void) msg32;
static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
(void) msg;
(void) msglen;
(void) key32;
(void) xonly_pk32;
(void) algo16;
(void) algo;
(void) algolen;
(void) data;
memset(nonce32, 0, 32);
@ -657,11 +701,13 @@ static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg32,
}
/* Nonce function that sets nonce to 0xFF...0xFF */
static int nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
(void) msg32;
static int nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg, size_t msglen, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
(void) msg;
(void) msglen;
(void) key32;
(void) xonly_pk32;
(void) algo16;
(void) algo;
(void) algolen;
(void) data;
memset(nonce32, 0xFF, 32);
@ -670,24 +716,45 @@ static int nonce_function_overflowing(unsigned char *nonce32, const unsigned cha
void test_schnorrsig_sign(void) {
unsigned char sk[32];
secp256k1_xonly_pubkey pk;
secp256k1_keypair keypair;
const unsigned char msg[32] = "this is a msg for a schnorrsig..";
unsigned char sig[64];
unsigned char sig2[64];
unsigned char zeros64[64] = { 0 };
secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
unsigned char aux_rand[32];
secp256k1_testrand256(sk);
secp256k1_testrand256(aux_rand);
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL) == 1);
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk));
/* Test different nonce functions */
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk));
memset(sig, 1, sizeof(sig));
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_failing, NULL) == 0);
extraparams.noncefp = nonce_function_failing;
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 0);
CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0);
memset(&sig, 1, sizeof(sig));
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_0, NULL) == 0);
extraparams.noncefp = nonce_function_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_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_overflowing, NULL) == 1);
CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) != 0);
memset(&sig, 1, sizeof(sig));
extraparams.noncefp = nonce_function_overflowing;
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk));
/* When using the default nonce function, schnorrsig_sign_custom produces
* the same result as schnorrsig_sign with aux_rand = extraparams.ndata */
extraparams.noncefp = NULL;
extraparams.ndata = aux_rand;
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
CHECK(secp256k1_schnorrsig_sign(ctx, sig2, msg, &keypair, extraparams.ndata) == 1);
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
}
#define N_SIGS 3
@ -709,8 +776,8 @@ void test_schnorrsig_sign_verify(void) {
for (i = 0; i < N_SIGS; i++) {
secp256k1_testrand256(msg[i]);
CHECK(secp256k1_schnorrsig_sign(ctx, sig[i], msg[i], &keypair, NULL, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], &pk));
CHECK(secp256k1_schnorrsig_sign(ctx, sig[i], msg[i], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], sizeof(msg[i]), &pk));
}
{
@ -720,36 +787,54 @@ void test_schnorrsig_sign_verify(void) {
size_t byte_idx = secp256k1_testrand_int(32);
unsigned char xorbyte = secp256k1_testrand_int(254)+1;
sig[sig_idx][byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], 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;
byte_idx = secp256k1_testrand_int(32);
sig[sig_idx][32+byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], 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;
byte_idx = secp256k1_testrand_int(32);
msg[sig_idx][byte_idx] ^= xorbyte;
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], 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;
/* Check that above bitflips have been reversed correctly */
CHECK(secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], sizeof(msg[sig_idx]), &pk));
}
/* Test overflowing s */
CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
memset(&sig[0][32], 0xFF, 32);
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
/* Test negative s */
CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL));
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
secp256k1_scalar_set_b32(&s, &sig[0][32], NULL);
secp256k1_scalar_negate(&s, &s);
secp256k1_scalar_get_b32(&sig[0][32], &s);
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
/* The empty message can be signed & verified */
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig[0], NULL, 0, &keypair, NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], NULL, 0, &pk) == 1);
{
/* Test varying message lengths */
unsigned char msg_large[32 * 8];
uint32_t msglen = secp256k1_testrand_int(sizeof(msg_large));
for (i = 0; i < sizeof(msg_large); i += 32) {
secp256k1_testrand256(&msg_large[i]);
}
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);
/* Verification for a random wrong message length fails */
msglen = (msglen + (sizeof(msg_large) - 1)) % sizeof(msg_large);
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg_large, msglen, &pk) == 0);
}
}
#undef N_SIGS
@ -777,10 +862,10 @@ void test_schnorrsig_taproot(void) {
/* Key spend */
secp256k1_testrand256(msg);
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL) == 1);
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL) == 1);
/* Verify key spend */
CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, &output_pk) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &output_pk) == 1);
/* Script spend */
CHECK(secp256k1_xonly_pubkey_serialize(ctx, internal_pk_bytes, &internal_pk) == 1);

View file

@ -5,6 +5,7 @@ noinst_HEADERS += src/modules/whitelist/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_whitelist
bench_whitelist_SOURCES = src/bench_whitelist.c
bench_whitelist_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
bench_whitelist_LDADD = libsecp256k1.la $(SECP_LIBS)
bench_generator_LDFLAGS = -static
endif

Some files were not shown because too many files have changed in this diff Show more