Merge ElementsProject/secp256k1-zkp#174: Upstream PRs 1064, 1049, 899, 1068, 1072, 1069, 1074, 1026, 1033, 748, 1079, 1088, 1090, 731, 1089, 995, 1094, 1093
645d9c53c4d9095342cf770c98e3d367f670ae46 examples: let musig use random.h instead of /dev/urandom (Jonas Nick) eccba5b4e5eb70710f4d34ae89e62abfab542f7c examples: relicense musig example to CC0 public domain (Jonas Nick) 7c5af740fab0d36a54c9e36872a87de2727c49f1 ci: fix missing EXPERIMENTAL flags (Jonas Nick) 03bea1e173d84b33ca81bba4c06b876e160dbe65 configure: add -zkp modules to dev-mode and remove redundant code (Jonas Nick) 2adb741c45ecc4ef7180009c42f961e4aee4bf5c examples: rename example_musig to musig_example for consistency (Jonas Nick) 37d36927dff793e61df6d6f6a6c50e8fa2519e33 tests: Add tests for _read_be32 and _write_be32 (Tim Ruffing) 616b43dd3b6949923f0752cd60382153cfd5dda9 util: Remove endianness detection (Tim Ruffing) 8d89b9e6e562000cdb91a70a85fae5e4817cec8a hash: Make code agnostic of endianness (Tim Ruffing) 55512d30b7921bc46247a78be1da98108f243c1c doc: clean up module help text in configure.ac (Elliott Jin) d9d94a9969785abbb3e04b2b9f75f1049c7b8936 doc: mention optional modules in README (Elliott Jin) 7f09d0f311117289719b690f91f6a907c2c6f3e2 README: mention that ARM assembly is experimental (Jonas Nick) 80cf4eea5fa0162350614c08f2252a07f9d7804b build: stop treating schnorrsig, extrakeys modules as experimental (Jonas Nick) b8f8b99f0fb3a5cd4c6fb1c9c8dfed881839e19e docs: Fix return value for functions that don't have invalid inputs (Tim Ruffing) f813bb0df3153dc055e0e76101ed9e4607155870 schnorrsig: Adapt example to new API (Tim Ruffing) 99e6568fc6ea2768f5355eb4617283086f756931 schnorrsig: Rename schnorrsig_sign to schnorsig_sign32 and deprecate (Tim Ruffing) fc94a2da4457325c4be539838ceed21b31c60fbd Use SECP256K1_DEPRECATED for existing deprecated API functions (Tim Ruffing) 3db0560606acb285cc7ef11662ce166ed67e9015 Add SECP256K1_DEPRECATED attribute for marking API parts as deprecated (Tim Ruffing) f8d9174357391ab4bf65a2f4d9d9cfb8039dc592 Add SHA256 bit counter tests (Tim Ruffing) 9b514ce1d25f1944c549ead30cc84367d616e0e6 Add test vector for very long SHA256 messages (Tim Ruffing) 8e3dde113741615fcb1aedcacfc54bd3b3d204f1 Simplify struct initializer for SHA256 padding (Tim Ruffing) eb28464a8bf8652a2b49d2ed765801d7c0aa195d Change SHA256 byte counter from size_t to uint64_t (Tim Ruffing) 21b2ebaf74222017f85123deb6f30a33c7678513 configure: Remove redundant pkg-config code (Tim Ruffing) 0d253d52e804a5affb0f1c851ec250071e7345d9 configure: Use modern way to set AR (Tim Ruffing) e0838d663deba5a9663a0ad02bd7e4c563325c4d configure: Add hidden --enable-dev-mode to enable all the stuff (Tim Ruffing) fabd579dfa85711e96e4012d20352b8ee8f2a9d1 configure: Remove redundant code that sets _enable variables (Tim Ruffing) 0d4226c051415d12384586ae938499975a248cab configure: Use canonical variable prefix _enable consistently (Tim Ruffing) 7c9502cece9c9e8d811333f7ab5bb22f4eb01c04 Add a copy of the CC0 license to the examples (Elichai Turkel) 42e03432e6be7f0bf18c7f86130d3930bdf4038d Add usage examples to the readme (Elichai Turkel) 517644eab14ef397e1f0bc2b45f2dff8b1a473ec Optionally compile the examples in autotools, compile+run in travis (Elichai Turkel) 422a7cc86ae86496794c5014028ee249bbe0e072 Add a ecdh shared secret example (Elichai Turkel) b0cfbcc14347ff6b04ff62a0d935638840a37971 Add a Schnorr signing and verifying example (Elichai Turkel) fee7d4bf9e4ea316ea4ff3151bbe52bec1f0745c Add an ECDSA signing and verifying example (Elichai Turkel) e848c3799c4f31367c3ed98d17e3b7de504d4c6e Update sage files for new formulae (Peter Dettman) d64bb5d4f3fbd48b570d847c9389b9cf8f3d9abc Add fe_half tests for worst-case inputs (Peter Dettman) 4eb8b932ff8e64f8de3ae8ecfebeab1e84ca420e Further improve doubling formula using fe_half (Peter Dettman) 557b31fac36529948709d4bfcc00ad3acb7e83b9 Doubling formula using fe_half (Pieter Wuille) 2cbb4b1a424d9dee12a4e11f0479410b7e4cc930 Run more iterations of run_field_misc (Pieter Wuille) 9cc5c257eddc2d7614985be60bee29cf2bec65fb Add test for secp256k1_fe_half (Pieter Wuille) 925f78d55e112cd00f1e2867886bdc751a5d6606 Add _fe_half and use in _gej_add_ge (Peter Dettman) 3531a43b5bc739838f5634afcfd02bdbef71b1ef ecdh: Make generator_basepoint test depend on global iteration count (Tim Ruffing) c881dd49bdb865d9e455d504b90aebf77e807e85 ecdh: Add test computing shared_secret=basepoint with random inputs (Tim Ruffing) e51ad3b737a2f12605d346cf9c0e7eaabf6a39ec ci: Retry `brew update` a few times to avoid random failures (Tim Ruffing) b1cb969e8ab9ad86fec3ce30cb732f4c42e015e0 ci: Revert "Attempt to make macOS builds more reliable" (Tim Ruffing) e0db3f8a25c20a247a0b49ca00dd6c973b6a16e0 build: Replace use of deprecated autoconf macro AC_PROG_CC_C89 (laanwj) d9396a56da13df97827e193f636a7593fb4d7864 ci: Attempt to make macOS builds more reliable (Tim Ruffing) ebb1beea7832207e5c8c5112d250fd216259ef41 sage: Ensure that constraints are always fastfracs (Tim Ruffing) d8d54859ed138a8ed9a8486d847155211c9f4a7d ci: Run sage prover on CI (Tim Ruffing) 77cfa98dbc40f9494048447b8a302867235300da sage: Normalize sign of polynomial factors in prover (Tim Ruffing) eae75869cfbbbcb69d881bc5d313bd94c6155655 sage: Exit with non-zero status in case of failures (Tim Ruffing) b54d843eac905993eba2314a89a2d7f155445eaa sage: Fix printing of errors (Tim Ruffing) e108d0039c36483dffe4be00815c1b6d65ef5751 sage: Fix incompatibility with sage 9.4 (Tim Ruffing) b797a500ec194948eecbea8bd80f6b7d455f7ca2 Create a SECP256K1_ECMULT_TABLE_VERIFY macro. (Russell O'Connor) a731200cc30fcf019af08a41f7b6f329a08eaa0c Replace ECMULT_TABLE_GET_GE_STORAGE macro with a function. (Russell O'Connor) fe34d9f3419d090e94b0c0897895c5b2b9fdc244 Eliminate input_pos state field from ecmult_strauss_wnaf. (Russell O'Connor) 0397d00ba0401bf5be7c4312d84d17fc789a6566 Eliminate na_1 and na_lam state fields from ecmult_strauss_wnaf. (Russell O'Connor) 7ba3ffcca0ae054cf0a1d6407c2dcf7445a46935 Remove the unused pre_a_lam allocations. (Russell O'Connor) b3b57ad6eedac86bda40f062daee7d5f4241d25c Eliminate the pre_a_lam array from ecmult_strauss_wnaf. (Russell O'Connor) ae7ba0f922b4c1439888b8488b307cd0f0e8ec59 Remove the unused prej allocations. (Russell O'Connor) e5c18892db69b5db44d282225ab4fea788af8035 Eliminate the prej array from ecmult_strauss_wnaf. (Russell O'Connor) c9da1baad125e830901f0ed6ad65eb4f9ccb81f4 Move secp256k1_fe_one to field.h (Russell O'Connor) 070e772211b3fcd297577b90b56bbf7a5cfbd0a3 Faster fixed-input ecmult tests (Pieter Wuille) 45f37b650635e46865104f37baed26ef8d2cfb97 Modulo-reduce msg32 inside RFC6979 nonce fn to match spec. Fixes #1063. (Paul Miller) Pull request description: [bitcoin-core/secp256k1#1064]: Modulo-reduce msg32 inside RFC6979 nonce fn to match spec. Fixes #1063 [bitcoin-core/secp256k1#1049]: Faster fixed-input ecmult tests [bitcoin-core/secp256k1#899]: Reduce stratch space needed by ecmult_strauss_wnaf. [bitcoin-core/secp256k1#1068]: sage: Fix incompatibility with sage 9.4 [bitcoin-core/secp256k1#1072]: ci: Attempt to make macOS builds more reliable [bitcoin-core/secp256k1#1069]: build: Replace use of deprecated autoconf macro AC_PROG_CC_C89 [bitcoin-core/secp256k1#1074]: ci: Retry brew update a few times to avoid random failures [bitcoin-core/secp256k1#1026]: ecdh: Add test computing shared_secret=basepoint with random inputs [bitcoin-core/secp256k1#1033]: Add _fe_half and use in _gej_add_ge and _gej_double [bitcoin-core/secp256k1#748]: Add usage examples [bitcoin-core/secp256k1#1079]: configure: Add hidden --enable-dev-mode to enable all the stuff [bitcoin-core/secp256k1#1088]: configure: Use modern way to set AR [bitcoin-core/secp256k1#1090]: configure: Remove redundant pkg-config code [bitcoin-core/secp256k1#731]: Change SHA256 byte counter from size_t to uint64_t [bitcoin-core/secp256k1#1089]: Schnorrsig API improvements [bitcoin-core/secp256k1#995]: build: stop treating schnorrsig, extrakeys modules as experimental [bitcoin-core/secp256k1#1094]: doc: Clarify configure flags for optional modules [bitcoin-core/secp256k1#1093]: hash: Make code agnostic of endianness This PR can be recreated with `./sync-upstream.sh range 8746600eec5e7fcd35dabd480839a3a4bdfee87b`. ACKs for top commit: real-or-random: ACK 645d9c53c4d9095342cf770c98e3d367f670ae46 I rederived the tree, and tested it with MSVC, including the musig example Tree-SHA512: 3b771630806ed8481053958c21820dce6e869371833cd18a5c430a2768bda8064ad2bb247afbe38e3fa37320a8b1dbbe65ad68c8963efb995d96aa29ae574884
This commit is contained in:
commit
6c0aecf72b
33
.cirrus.yml
33
.cirrus.yml
@ -28,6 +28,8 @@ env:
|
|||||||
BENCH: yes
|
BENCH: yes
|
||||||
SECP256K1_BENCH_ITERS: 2
|
SECP256K1_BENCH_ITERS: 2
|
||||||
CTIMETEST: yes
|
CTIMETEST: yes
|
||||||
|
# Compile and run the tests
|
||||||
|
EXAMPLES: yes
|
||||||
|
|
||||||
cat_logs_snippet: &CAT_LOGS
|
cat_logs_snippet: &CAT_LOGS
|
||||||
always:
|
always:
|
||||||
@ -70,12 +72,12 @@ task:
|
|||||||
<< : *LINUX_CONTAINER
|
<< : *LINUX_CONTAINER
|
||||||
matrix: &ENV_MATRIX
|
matrix: &ENV_MATRIX
|
||||||
- env: {WIDEMUL: int64, RECOVERY: yes}
|
- 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: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
|
||||||
- env: {WIDEMUL: int128}
|
- env: {WIDEMUL: int128}
|
||||||
- env: {WIDEMUL: int128, RECOVERY: yes, EXPERIMENTAL: yes, SCHNORRSIG: yes}
|
- env: {WIDEMUL: int128, RECOVERY: 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, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
|
||||||
- env: {WIDEMUL: int128, ASM: x86_64}
|
- 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: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes}
|
||||||
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
|
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
|
||||||
- env: {CPPFLAGS: -DDETERMINISTIC}
|
- env: {CPPFLAGS: -DDETERMINISTIC}
|
||||||
- env: {CFLAGS: -O0, CTIMETEST: no}
|
- env: {CFLAGS: -O0, CTIMETEST: no}
|
||||||
@ -98,8 +100,8 @@ task:
|
|||||||
HOST: i686-linux-gnu
|
HOST: i686-linux-gnu
|
||||||
ECDH: yes
|
ECDH: yes
|
||||||
RECOVERY: yes
|
RECOVERY: yes
|
||||||
EXPERIMENTAL: yes
|
|
||||||
SCHNORRSIG: yes
|
SCHNORRSIG: yes
|
||||||
|
EXPERIMENTAL: yes
|
||||||
ECDSA_S2C: yes
|
ECDSA_S2C: yes
|
||||||
RANGEPROOF: yes
|
RANGEPROOF: yes
|
||||||
WHITELIST: yes
|
WHITELIST: yes
|
||||||
@ -148,7 +150,8 @@ task:
|
|||||||
## - rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
|
## - rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
|
||||||
##
|
##
|
||||||
brew_valgrind_pre_script:
|
brew_valgrind_pre_script:
|
||||||
- brew update
|
# Retry a few times because this tends to fail randomly.
|
||||||
|
- for i in {1..5}; do brew update && break || sleep 15; done
|
||||||
- brew config
|
- brew config
|
||||||
- brew tap LouisBrunner/valgrind
|
- brew tap LouisBrunner/valgrind
|
||||||
# Fetch valgrind source but don't build it yet.
|
# Fetch valgrind source but don't build it yet.
|
||||||
@ -188,8 +191,8 @@ task:
|
|||||||
WITH_VALGRIND: no
|
WITH_VALGRIND: no
|
||||||
ECDH: yes
|
ECDH: yes
|
||||||
RECOVERY: yes
|
RECOVERY: yes
|
||||||
EXPERIMENTAL: yes
|
|
||||||
SCHNORRSIG: yes
|
SCHNORRSIG: yes
|
||||||
|
EXPERIMENTAL: yes
|
||||||
ECDSA_S2C: yes
|
ECDSA_S2C: yes
|
||||||
RANGEPROOF: yes
|
RANGEPROOF: yes
|
||||||
WHITELIST: yes
|
WHITELIST: yes
|
||||||
@ -214,12 +217,11 @@ task:
|
|||||||
WITH_VALGRIND: no
|
WITH_VALGRIND: no
|
||||||
ECDH: yes
|
ECDH: yes
|
||||||
RECOVERY: yes
|
RECOVERY: yes
|
||||||
EXPERIMENTAL: yes
|
|
||||||
SCHNORRSIG: yes
|
SCHNORRSIG: yes
|
||||||
CTIMETEST: no
|
CTIMETEST: no
|
||||||
matrix:
|
matrix:
|
||||||
- env: {}
|
- env: {}
|
||||||
- env: {ASM: arm}
|
- env: {EXPERIMENTAL: yes, ASM: arm}
|
||||||
<< : *MERGE_BASE
|
<< : *MERGE_BASE
|
||||||
test_script:
|
test_script:
|
||||||
- ./ci/cirrus.sh
|
- ./ci/cirrus.sh
|
||||||
@ -235,7 +237,6 @@ task:
|
|||||||
WITH_VALGRIND: no
|
WITH_VALGRIND: no
|
||||||
ECDH: yes
|
ECDH: yes
|
||||||
RECOVERY: yes
|
RECOVERY: yes
|
||||||
EXPERIMENTAL: yes
|
|
||||||
SCHNORRSIG: yes
|
SCHNORRSIG: yes
|
||||||
CTIMETEST: no
|
CTIMETEST: no
|
||||||
<< : *MERGE_BASE
|
<< : *MERGE_BASE
|
||||||
@ -253,7 +254,6 @@ task:
|
|||||||
WITH_VALGRIND: no
|
WITH_VALGRIND: no
|
||||||
ECDH: yes
|
ECDH: yes
|
||||||
RECOVERY: yes
|
RECOVERY: yes
|
||||||
EXPERIMENTAL: yes
|
|
||||||
SCHNORRSIG: yes
|
SCHNORRSIG: yes
|
||||||
CTIMETEST: no
|
CTIMETEST: no
|
||||||
<< : *MERGE_BASE
|
<< : *MERGE_BASE
|
||||||
@ -271,7 +271,6 @@ task:
|
|||||||
WITH_VALGRIND: no
|
WITH_VALGRIND: no
|
||||||
ECDH: yes
|
ECDH: yes
|
||||||
RECOVERY: yes
|
RECOVERY: yes
|
||||||
EXPERIMENTAL: yes
|
|
||||||
SCHNORRSIG: yes
|
SCHNORRSIG: yes
|
||||||
CTIMETEST: no
|
CTIMETEST: no
|
||||||
<< : *MERGE_BASE
|
<< : *MERGE_BASE
|
||||||
@ -286,8 +285,8 @@ task:
|
|||||||
env:
|
env:
|
||||||
ECDH: yes
|
ECDH: yes
|
||||||
RECOVERY: yes
|
RECOVERY: yes
|
||||||
EXPERIMENTAL: yes
|
|
||||||
SCHNORRSIG: yes
|
SCHNORRSIG: yes
|
||||||
|
EXPERIMENTAL: yes
|
||||||
ECDSA_S2C: yes
|
ECDSA_S2C: yes
|
||||||
RANGEPROOF: yes
|
RANGEPROOF: yes
|
||||||
WHITELIST: yes
|
WHITELIST: yes
|
||||||
@ -340,7 +339,6 @@ task:
|
|||||||
CC: gcc
|
CC: gcc
|
||||||
MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g
|
MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g
|
||||||
WERROR_CFLAGS:
|
WERROR_CFLAGS:
|
||||||
EXPERIMENTAL: yes
|
|
||||||
ECDH: yes
|
ECDH: yes
|
||||||
RECOVERY: yes
|
RECOVERY: yes
|
||||||
SCHNORRSIG: yes
|
SCHNORRSIG: yes
|
||||||
@ -348,3 +346,10 @@ task:
|
|||||||
test_script:
|
test_script:
|
||||||
- ./ci/cirrus.sh
|
- ./ci/cirrus.sh
|
||||||
<< : *CAT_LOGS
|
<< : *CAT_LOGS
|
||||||
|
|
||||||
|
task:
|
||||||
|
name: "sage prover"
|
||||||
|
<< : *LINUX_CONTAINER
|
||||||
|
test_script:
|
||||||
|
- cd sage
|
||||||
|
- sage prove_group_implementations.sage
|
||||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -8,11 +8,16 @@ exhaustive_tests
|
|||||||
precompute_ecmult_gen
|
precompute_ecmult_gen
|
||||||
precompute_ecmult
|
precompute_ecmult
|
||||||
valgrind_ctime_test
|
valgrind_ctime_test
|
||||||
|
ecdh_example
|
||||||
|
ecdsa_example
|
||||||
|
schnorr_example
|
||||||
*.exe
|
*.exe
|
||||||
*.so
|
*.so
|
||||||
*.a
|
*.a
|
||||||
*.csv
|
*.csv
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
*.log
|
||||||
|
*.trs
|
||||||
|
|
||||||
Makefile
|
Makefile
|
||||||
configure
|
configure
|
||||||
@ -43,6 +48,7 @@ coverage.*.html
|
|||||||
|
|
||||||
src/libsecp256k1-config.h
|
src/libsecp256k1-config.h
|
||||||
src/libsecp256k1-config.h.in
|
src/libsecp256k1-config.h.in
|
||||||
|
build-aux/ar-lib
|
||||||
build-aux/config.guess
|
build-aux/config.guess
|
||||||
build-aux/config.sub
|
build-aux/config.sub
|
||||||
build-aux/depcomp
|
build-aux/depcomp
|
||||||
@ -60,4 +66,4 @@ src/stamp-h1
|
|||||||
libsecp256k1.pc
|
libsecp256k1.pc
|
||||||
contrib/gh-pr-create.sh
|
contrib/gh-pr-create.sh
|
||||||
|
|
||||||
example_musig
|
musig_example
|
49
Makefile.am
49
Makefile.am
@ -65,6 +65,7 @@ noinst_HEADERS += contrib/lax_der_parsing.h
|
|||||||
noinst_HEADERS += contrib/lax_der_parsing.c
|
noinst_HEADERS += contrib/lax_der_parsing.c
|
||||||
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
|
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
|
||||||
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
|
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
|
||||||
|
noinst_HEADERS += examples/random.h
|
||||||
|
|
||||||
PRECOMPUTED_LIB = libsecp256k1_precomputed.la
|
PRECOMPUTED_LIB = libsecp256k1_precomputed.la
|
||||||
noinst_LTLIBRARIES = $(PRECOMPUTED_LIB)
|
noinst_LTLIBRARIES = $(PRECOMPUTED_LIB)
|
||||||
@ -141,13 +142,49 @@ exhaustive_tests_LDFLAGS = -static
|
|||||||
TESTS += exhaustive_tests
|
TESTS += exhaustive_tests
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if USE_EXAMPLES
|
||||||
|
noinst_PROGRAMS += ecdsa_example
|
||||||
|
ecdsa_example_SOURCES = examples/ecdsa.c
|
||||||
|
ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||||
|
ecdsa_example_LDADD = libsecp256k1.la
|
||||||
|
ecdsa_example_LDFLAGS = -static
|
||||||
|
if BUILD_WINDOWS
|
||||||
|
ecdsa_example_LDFLAGS += -lbcrypt
|
||||||
|
endif
|
||||||
|
TESTS += ecdsa_example
|
||||||
|
if ENABLE_MODULE_ECDH
|
||||||
|
noinst_PROGRAMS += ecdh_example
|
||||||
|
ecdh_example_SOURCES = examples/ecdh.c
|
||||||
|
ecdh_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||||
|
ecdh_example_LDADD = libsecp256k1.la
|
||||||
|
ecdh_example_LDFLAGS = -static
|
||||||
|
if BUILD_WINDOWS
|
||||||
|
ecdh_example_LDFLAGS += -lbcrypt
|
||||||
|
endif
|
||||||
|
TESTS += ecdh_example
|
||||||
|
endif
|
||||||
|
if ENABLE_MODULE_SCHNORRSIG
|
||||||
|
noinst_PROGRAMS += schnorr_example
|
||||||
|
schnorr_example_SOURCES = examples/schnorr.c
|
||||||
|
schnorr_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||||
|
schnorr_example_LDADD = libsecp256k1.la
|
||||||
|
schnorr_example_LDFLAGS = -static
|
||||||
|
if BUILD_WINDOWS
|
||||||
|
schnorr_example_LDFLAGS += -lbcrypt
|
||||||
|
endif
|
||||||
|
TESTS += schnorr_example
|
||||||
|
endif
|
||||||
if ENABLE_MODULE_MUSIG
|
if ENABLE_MODULE_MUSIG
|
||||||
noinst_PROGRAMS += example_musig
|
noinst_PROGRAMS += musig_example
|
||||||
example_musig_SOURCES = examples/musig.c
|
musig_example_SOURCES = examples/musig.c
|
||||||
example_musig_CPPFLAGS = -I$(top_srcdir)/include
|
musig_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||||
example_musig_LDADD = libsecp256k1.la
|
musig_example_LDADD = libsecp256k1.la
|
||||||
example_musig_LDFLAGS = -static
|
musig_example_LDFLAGS = -static
|
||||||
TESTS += example_musig
|
if BUILD_WINDOWS
|
||||||
|
musig_example_LDFLAGS += -lbcrypt
|
||||||
|
endif
|
||||||
|
TESTS += musig_example
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
### Precomputed tables
|
### Precomputed tables
|
||||||
|
13
README.md
13
README.md
@ -17,7 +17,7 @@ Features:
|
|||||||
* Suitable for embedded systems.
|
* Suitable for embedded systems.
|
||||||
* Optional module for public key recovery.
|
* Optional module for public key recovery.
|
||||||
* Optional module for ECDH key exchange.
|
* 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 Schnorr signatures according to [BIP-340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||||
* Optional module for ECDSA adaptor signatures (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.
|
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.
|
||||||
@ -36,6 +36,7 @@ Implementation details
|
|||||||
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
|
* 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 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).
|
* Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan).
|
||||||
|
* This is an experimental feature that has not received enough scrutiny to satisfy the standard of quality of this library but is made available for testing and review by the community.
|
||||||
* Scalar operations
|
* Scalar operations
|
||||||
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
|
* 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 4 64-bit limbs (relying on __int128 support in the compiler).
|
||||||
@ -70,6 +71,16 @@ libsecp256k1 is built using autotools:
|
|||||||
$ make check # run the test suite
|
$ make check # run the test suite
|
||||||
$ sudo make install # optional
|
$ sudo make install # optional
|
||||||
|
|
||||||
|
To compile optional modules (such as Schnorr signatures), you need to run `./configure` with additional flags (such as `--enable-module-schnorrsig`). Run `./configure --help` to see the full list of available flags.
|
||||||
|
|
||||||
|
Usage examples
|
||||||
|
-----------
|
||||||
|
Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
|
||||||
|
* [ECDSA example](examples/ecdsa.c)
|
||||||
|
* [Schnorr signatures example](examples/schnorr.c)
|
||||||
|
* [Deriving a shared secret (ECDH) example](examples/ecdh.c)
|
||||||
|
To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
|
||||||
|
|
||||||
Test coverage
|
Test coverage
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -38,3 +38,16 @@ AC_DEFUN([SECP_TRY_APPEND_CFLAGS], [
|
|||||||
unset flag_works
|
unset flag_works
|
||||||
AC_SUBST($2)
|
AC_SUBST($2)
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl SECP_SET_DEFAULT(VAR, default, default-dev-mode)
|
||||||
|
dnl Set VAR to default or default-dev-mode, depending on whether dev mode is enabled
|
||||||
|
AC_DEFUN([SECP_SET_DEFAULT], [
|
||||||
|
if test "${enable_dev_mode+set}" != set; then
|
||||||
|
AC_MSG_ERROR([[Set enable_dev_mode before calling SECP_SET_DEFAULT]])
|
||||||
|
fi
|
||||||
|
if test x"$enable_dev_mode" = x"yes"; then
|
||||||
|
$1="$3"
|
||||||
|
else
|
||||||
|
$1="$2"
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
@ -21,6 +21,8 @@ valgrind --version || true
|
|||||||
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
|
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
|
||||||
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
|
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
|
||||||
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
|
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
|
||||||
|
--enable-module-schnorrsig="$SCHNORRSIG" \
|
||||||
|
--enable-examples="$EXAMPLES" \
|
||||||
--with-valgrind="$WITH_VALGRIND" \
|
--with-valgrind="$WITH_VALGRIND" \
|
||||||
--host="$HOST" $EXTRAFLAGS
|
--host="$HOST" $EXTRAFLAGS
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@ RUN apt-get install --no-install-recommends --no-upgrade -y \
|
|||||||
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
|
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
|
||||||
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
|
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
|
||||||
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
|
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
|
||||||
wine gcc-mingw-w64-x86-64
|
wine gcc-mingw-w64-x86-64 \
|
||||||
|
sagemath
|
||||||
|
|
||||||
# Run a dummy command in wine to make it set up configuration
|
# Run a dummy command in wine to make it set up configuration
|
||||||
RUN wine64-stable xcopy || true
|
RUN wine64-stable xcopy || true
|
||||||
|
150
configure.ac
150
configure.ac
@ -25,25 +25,23 @@ AC_CANONICAL_HOST
|
|||||||
AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
|
AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
|
||||||
AH_TOP([#define LIBSECP256K1_CONFIG_H])
|
AH_TOP([#define LIBSECP256K1_CONFIG_H])
|
||||||
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
|
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
|
||||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
|
||||||
|
|
||||||
LT_INIT([win32-dll])
|
# Require Automake 1.11.2 for AM_PROG_AR
|
||||||
|
AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
|
||||||
|
|
||||||
# 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])])
|
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||||
|
|
||||||
PKG_PROG_PKG_CONFIG
|
AC_PROG_CC
|
||||||
|
|
||||||
AC_PATH_TOOL(AR, ar)
|
|
||||||
AC_PATH_TOOL(RANLIB, ranlib)
|
|
||||||
AC_PATH_TOOL(STRIP, strip)
|
|
||||||
|
|
||||||
AM_PROG_CC_C_O
|
|
||||||
AC_PROG_CC_C89
|
|
||||||
if test x"$ac_cv_prog_cc_c89" = x"no"; then
|
if test x"$ac_cv_prog_cc_c89" = x"no"; then
|
||||||
AC_MSG_ERROR([c89 compiler support required])
|
AC_MSG_ERROR([c89 compiler support required])
|
||||||
fi
|
fi
|
||||||
AM_PROG_AS
|
AM_PROG_AS
|
||||||
|
AM_PROG_AR
|
||||||
|
|
||||||
|
LT_INIT([win32-dll])
|
||||||
|
|
||||||
|
build_windows=no
|
||||||
|
|
||||||
case $host_os in
|
case $host_os in
|
||||||
*darwin*)
|
*darwin*)
|
||||||
@ -68,6 +66,9 @@ case $host_os in
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
cygwin*|mingw*)
|
||||||
|
build_windows=yes
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS.
|
# Try if some desirable compiler flags are supported and append them to SECP_CFLAGS.
|
||||||
@ -110,95 +111,94 @@ SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
|
|||||||
### Define config arguments
|
### Define config arguments
|
||||||
###
|
###
|
||||||
|
|
||||||
|
# In dev mode, we enable all binaries and modules by default but individual options can still be overridden explicitly.
|
||||||
|
# Check for dev mode first because SECP_SET_DEFAULT needs enable_dev_mode set.
|
||||||
|
AC_ARG_ENABLE(dev_mode, [], [],
|
||||||
|
[enable_dev_mode=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(benchmark,
|
AC_ARG_ENABLE(benchmark,
|
||||||
AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]),
|
AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]), [],
|
||||||
[use_benchmark=$enableval],
|
[SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])])
|
||||||
[use_benchmark=yes])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(coverage,
|
AC_ARG_ENABLE(coverage,
|
||||||
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]),
|
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [],
|
||||||
[enable_coverage=$enableval],
|
[SECP_SET_DEFAULT([enable_coverage], [no], [no])])
|
||||||
[enable_coverage=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(tests,
|
AC_ARG_ENABLE(tests,
|
||||||
AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]),
|
AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [],
|
||||||
[use_tests=$enableval],
|
[SECP_SET_DEFAULT([enable_tests], [yes], [yes])])
|
||||||
[use_tests=yes])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(experimental,
|
AC_ARG_ENABLE(experimental,
|
||||||
AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]),
|
AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [],
|
||||||
[use_experimental=$enableval],
|
[SECP_SET_DEFAULT([enable_experimental], [no], [yes])])
|
||||||
[use_experimental=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(exhaustive_tests,
|
AC_ARG_ENABLE(exhaustive_tests,
|
||||||
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]),
|
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]), [],
|
||||||
[use_exhaustive_tests=$enableval],
|
[SECP_SET_DEFAULT([enable_exhaustive_tests], [yes], [yes])])
|
||||||
[use_exhaustive_tests=yes])
|
|
||||||
|
AC_ARG_ENABLE(examples,
|
||||||
|
AS_HELP_STRING([--enable-examples],[compile the examples [default=no]]), [],
|
||||||
|
[SECP_SET_DEFAULT([enable_examples], [no], [yes])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_ecdh,
|
AC_ARG_ENABLE(module_ecdh,
|
||||||
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation]),
|
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [],
|
||||||
[enable_module_ecdh=$enableval],
|
[SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])])
|
||||||
[enable_module_ecdh=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_musig,
|
AC_ARG_ENABLE(module_musig,
|
||||||
AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]),
|
AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]),
|
||||||
[enable_module_musig=$enableval],
|
[],
|
||||||
[enable_module_musig=no])
|
[SECP_SET_DEFAULT([enable_module_musig], [no], [yes])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_recovery,
|
AC_ARG_ENABLE(module_recovery,
|
||||||
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]),
|
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]), [],
|
||||||
[enable_module_recovery=$enableval],
|
[SECP_SET_DEFAULT([enable_module_recovery], [no], [yes])])
|
||||||
[enable_module_recovery=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_generator,
|
AC_ARG_ENABLE(module_generator,
|
||||||
AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module [default=no]]),
|
AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module [default=no]]),
|
||||||
[enable_module_generator=$enableval],
|
[],
|
||||||
[enable_module_generator=no])
|
[SECP_SET_DEFAULT([enable_module_generator], [no], [yes])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_rangeproof,
|
AC_ARG_ENABLE(module_rangeproof,
|
||||||
AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module [default=no]]),
|
AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module [default=no]]),
|
||||||
[enable_module_rangeproof=$enableval],
|
[],
|
||||||
[enable_module_rangeproof=no])
|
[SECP_SET_DEFAULT([enable_module_rangeproof], [no], [yes])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_whitelist,
|
AC_ARG_ENABLE(module_whitelist,
|
||||||
AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module [default=no]]),
|
AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module [default=no]]),
|
||||||
[enable_module_whitelist=$enableval],
|
[],
|
||||||
[enable_module_whitelist=no])
|
[SECP_SET_DEFAULT([enable_module_whitelist], [no], [yes])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_extrakeys,
|
AC_ARG_ENABLE(module_extrakeys,
|
||||||
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module (experimental)]),
|
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=no]]), [],
|
||||||
[enable_module_extrakeys=$enableval],
|
[SECP_SET_DEFAULT([enable_module_extrakeys], [no], [yes])])
|
||||||
[enable_module_extrakeys=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_schnorrsig,
|
AC_ARG_ENABLE(module_schnorrsig,
|
||||||
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]),
|
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [],
|
||||||
[enable_module_schnorrsig=$enableval],
|
[SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])])
|
||||||
[enable_module_schnorrsig=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_ecdsa_s2c,
|
AC_ARG_ENABLE(module_ecdsa_s2c,
|
||||||
AS_HELP_STRING([--enable-module-ecdsa-s2c],[enable ECDSA sign-to-contract module [default=no]]),
|
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])
|
[SECP_SET_DEFAULT([enable_module_ecdsa_s2c], [no], [yes])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_ecdsa-adaptor,
|
AC_ARG_ENABLE(module_ecdsa-adaptor,
|
||||||
AS_HELP_STRING([--enable-module-ecdsa-adaptor],[enable ECDSA adaptor module [default=no]]),
|
AS_HELP_STRING([--enable-module-ecdsa-adaptor],[enable ECDSA adaptor module [default=no]]),
|
||||||
[enable_module_ecdsa_adaptor=$enableval],
|
[],
|
||||||
[enable_module_ecdsa_adaptor=no])
|
[SECP_SET_DEFAULT([enable_module_ecdsa_adaptor], [no], [yes])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(external_default_callbacks,
|
AC_ARG_ENABLE(external_default_callbacks,
|
||||||
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
|
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
|
||||||
[use_external_default_callbacks=$enableval],
|
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
|
||||||
[use_external_default_callbacks=no])
|
|
||||||
|
|
||||||
AC_ARG_ENABLE(module_surjectionproof,
|
AC_ARG_ENABLE(module_surjectionproof,
|
||||||
AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module [default=no]]),
|
AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module [default=no]]),
|
||||||
[enable_module_surjectionproof=$enableval],
|
[],
|
||||||
[enable_module_surjectionproof=no])
|
[SECP_SET_DEFAULT([enable_module_surjectionproof], [no], [yes])])
|
||||||
|
|
||||||
AC_ARG_ENABLE(reduced_surjection_proof_size,
|
AC_ARG_ENABLE(reduced_surjection_proof_size,
|
||||||
AS_HELP_STRING([--enable-reduced-surjection-proof-size],[use reduced surjection proof size (disabling parsing and verification) [default=no]]),
|
AS_HELP_STRING([--enable-reduced-surjection-proof-size],[use reduced surjection proof size (disabling parsing and verification) [default=no]]),
|
||||||
[use_reduced_surjection_proof_size=$enableval],
|
[],
|
||||||
[use_reduced_surjection_proof_size=no])
|
[SECP_SET_DEFAULT([use_reduced_surjection_proof_size], [no], [no])])
|
||||||
|
|
||||||
# Test-only override of the (autodetected by the C code) "widemul" setting.
|
# 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).
|
# Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
|
||||||
@ -300,14 +300,14 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Select assembly optimization
|
# Select assembly optimization
|
||||||
use_external_asm=no
|
enable_external_asm=no
|
||||||
|
|
||||||
case $set_asm in
|
case $set_asm in
|
||||||
x86_64)
|
x86_64)
|
||||||
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
|
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
|
||||||
;;
|
;;
|
||||||
arm)
|
arm)
|
||||||
use_external_asm=yes
|
enable_external_asm=yes
|
||||||
;;
|
;;
|
||||||
no)
|
no)
|
||||||
;;
|
;;
|
||||||
@ -316,7 +316,7 @@ no)
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if test x"$use_external_asm" = x"yes"; then
|
if test x"$enable_external_asm" = x"yes"; then
|
||||||
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
|
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -430,7 +430,7 @@ 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])
|
AC_DEFINE(ENABLE_MODULE_ECDSA_S2C, 1, [Define this symbol to enable the ECDSA sign-to-contract module])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test x"$use_external_default_callbacks" = x"yes"; then
|
if test x"$enable_external_default_callbacks" = x"yes"; then
|
||||||
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
|
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -455,8 +455,6 @@ if test x"$enable_experimental" = x"yes"; then
|
|||||||
AC_MSG_NOTICE([Building key whitelisting module: $enable_module_whitelist])
|
AC_MSG_NOTICE([Building key whitelisting module: $enable_module_whitelist])
|
||||||
AC_MSG_NOTICE([Building surjection proof module: $enable_module_surjectionproof])
|
AC_MSG_NOTICE([Building surjection proof module: $enable_module_surjectionproof])
|
||||||
AC_MSG_NOTICE([Building MuSig module: $enable_module_musig])
|
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 sign-to-contract module: $enable_module_ecdsa_s2c])
|
||||||
AC_MSG_NOTICE([Building ECDSA adaptor signatures module: $enable_module_ecdsa_adaptor])
|
AC_MSG_NOTICE([Building ECDSA adaptor signatures module: $enable_module_ecdsa_adaptor])
|
||||||
AC_MSG_NOTICE([******])
|
AC_MSG_NOTICE([******])
|
||||||
@ -486,12 +484,6 @@ else
|
|||||||
if test x"$enable_module_musig" = x"yes"; then
|
if test x"$enable_module_musig" = x"yes"; then
|
||||||
AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.])
|
AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.])
|
||||||
fi
|
fi
|
||||||
if test x"$enable_module_extrakeys" = x"yes"; then
|
|
||||||
AC_MSG_ERROR([extrakeys module is experimental. Use --enable-experimental to allow.])
|
|
||||||
fi
|
|
||||||
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
|
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.])
|
AC_MSG_ERROR([ECDSA sign-to-contract module module is experimental. Use --enable-experimental to allow.])
|
||||||
fi
|
fi
|
||||||
@ -527,9 +519,10 @@ AC_SUBST(SECP_TEST_LIBS)
|
|||||||
AC_SUBST(SECP_TEST_INCLUDES)
|
AC_SUBST(SECP_TEST_INCLUDES)
|
||||||
AC_SUBST(SECP_CFLAGS)
|
AC_SUBST(SECP_CFLAGS)
|
||||||
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
|
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
|
||||||
AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"])
|
AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"])
|
||||||
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
|
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"])
|
||||||
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
|
AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"])
|
||||||
|
AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"])
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
|
AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||||
@ -540,27 +533,24 @@ AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"
|
|||||||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = 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_S2C], [test x"$enable_module_ecdsa_s2c" = x"yes"])
|
||||||
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_ADAPTOR], [test x"$enable_module_ecdsa_adaptor" = x"yes"])
|
AM_CONDITIONAL([ENABLE_MODULE_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_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
|
||||||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
|
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([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"])
|
AM_CONDITIONAL([USE_REDUCED_SURJECTION_PROOF_SIZE], [test x"$use_reduced_surjection_proof_size" = x"yes"])
|
||||||
|
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
|
||||||
AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT)
|
AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT)
|
||||||
AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION)
|
AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION)
|
||||||
AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE)
|
AC_SUBST(LIB_VERSION_AGE, _LIB_VERSION_AGE)
|
||||||
|
|
||||||
# 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"
|
|
||||||
|
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Build Options:"
|
echo "Build Options:"
|
||||||
echo " with external callbacks = $use_external_default_callbacks"
|
echo " with external callbacks = $enable_external_default_callbacks"
|
||||||
echo " with benchmarks = $use_benchmark"
|
echo " with benchmarks = $enable_benchmark"
|
||||||
echo " with tests = $use_tests"
|
echo " with tests = $enable_tests"
|
||||||
echo " with coverage = $enable_coverage"
|
echo " with coverage = $enable_coverage"
|
||||||
|
echo " with examples = $enable_examples"
|
||||||
echo " module ecdh = $enable_module_ecdh"
|
echo " module ecdh = $enable_module_ecdh"
|
||||||
echo " module recovery = $enable_module_recovery"
|
echo " module recovery = $enable_module_recovery"
|
||||||
echo " module extrakeys = $enable_module_extrakeys"
|
echo " module extrakeys = $enable_module_extrakeys"
|
||||||
|
121
examples/EXAMPLES_COPYING
Normal file
121
examples/EXAMPLES_COPYING
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
Creative Commons Legal Code
|
||||||
|
|
||||||
|
CC0 1.0 Universal
|
||||||
|
|
||||||
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||||
|
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||||
|
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||||
|
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||||
|
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||||
|
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||||
|
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||||
|
HEREUNDER.
|
||||||
|
|
||||||
|
Statement of Purpose
|
||||||
|
|
||||||
|
The laws of most jurisdictions throughout the world automatically confer
|
||||||
|
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||||
|
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||||
|
authorship and/or a database (each, a "Work").
|
||||||
|
|
||||||
|
Certain owners wish to permanently relinquish those rights to a Work for
|
||||||
|
the purpose of contributing to a commons of creative, cultural and
|
||||||
|
scientific works ("Commons") that the public can reliably and without fear
|
||||||
|
of later claims of infringement build upon, modify, incorporate in other
|
||||||
|
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||||
|
and for any purposes, including without limitation commercial purposes.
|
||||||
|
These owners may contribute to the Commons to promote the ideal of a free
|
||||||
|
culture and the further production of creative, cultural and scientific
|
||||||
|
works, or to gain reputation or greater distribution for their Work in
|
||||||
|
part through the use and efforts of others.
|
||||||
|
|
||||||
|
For these and/or other purposes and motivations, and without any
|
||||||
|
expectation of additional consideration or compensation, the person
|
||||||
|
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||||
|
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||||
|
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||||
|
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||||
|
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||||
|
|
||||||
|
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||||
|
protected by copyright and related or neighboring rights ("Copyright and
|
||||||
|
Related Rights"). Copyright and Related Rights include, but are not
|
||||||
|
limited to, the following:
|
||||||
|
|
||||||
|
i. the right to reproduce, adapt, distribute, perform, display,
|
||||||
|
communicate, and translate a Work;
|
||||||
|
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||||
|
iii. publicity and privacy rights pertaining to a person's image or
|
||||||
|
likeness depicted in a Work;
|
||||||
|
iv. rights protecting against unfair competition in regards to a Work,
|
||||||
|
subject to the limitations in paragraph 4(a), below;
|
||||||
|
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||||
|
in a Work;
|
||||||
|
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||||
|
European Parliament and of the Council of 11 March 1996 on the legal
|
||||||
|
protection of databases, and under any national implementation
|
||||||
|
thereof, including any amended or successor version of such
|
||||||
|
directive); and
|
||||||
|
vii. other similar, equivalent or corresponding rights throughout the
|
||||||
|
world based on applicable law or treaty, and any national
|
||||||
|
implementations thereof.
|
||||||
|
|
||||||
|
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||||
|
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||||
|
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||||
|
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||||
|
of action, whether now known or unknown (including existing as well as
|
||||||
|
future claims and causes of action), in the Work (i) in all territories
|
||||||
|
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||||
|
treaty (including future time extensions), (iii) in any current or future
|
||||||
|
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||||
|
including without limitation commercial, advertising or promotional
|
||||||
|
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||||
|
member of the public at large and to the detriment of Affirmer's heirs and
|
||||||
|
successors, fully intending that such Waiver shall not be subject to
|
||||||
|
revocation, rescission, cancellation, termination, or any other legal or
|
||||||
|
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||||
|
as contemplated by Affirmer's express Statement of Purpose.
|
||||||
|
|
||||||
|
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||||
|
be judged legally invalid or ineffective under applicable law, then the
|
||||||
|
Waiver shall be preserved to the maximum extent permitted taking into
|
||||||
|
account Affirmer's express Statement of Purpose. In addition, to the
|
||||||
|
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||||
|
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||||
|
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||||
|
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||||
|
maximum duration provided by applicable law or treaty (including future
|
||||||
|
time extensions), (iii) in any current or future medium and for any number
|
||||||
|
of copies, and (iv) for any purpose whatsoever, including without
|
||||||
|
limitation commercial, advertising or promotional purposes (the
|
||||||
|
"License"). The License shall be deemed effective as of the date CC0 was
|
||||||
|
applied by Affirmer to the Work. Should any part of the License for any
|
||||||
|
reason be judged legally invalid or ineffective under applicable law, such
|
||||||
|
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||||
|
of the License, and in such case Affirmer hereby affirms that he or she
|
||||||
|
will not (i) exercise any of his or her remaining Copyright and Related
|
||||||
|
Rights in the Work or (ii) assert any associated claims and causes of
|
||||||
|
action with respect to the Work, in either case contrary to Affirmer's
|
||||||
|
express Statement of Purpose.
|
||||||
|
|
||||||
|
4. Limitations and Disclaimers.
|
||||||
|
|
||||||
|
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||||
|
surrendered, licensed or otherwise affected by this document.
|
||||||
|
b. Affirmer offers the Work as-is and makes no representations or
|
||||||
|
warranties of any kind concerning the Work, express, implied,
|
||||||
|
statutory or otherwise, including without limitation warranties of
|
||||||
|
title, merchantability, fitness for a particular purpose, non
|
||||||
|
infringement, or the absence of latent or other defects, accuracy, or
|
||||||
|
the present or absence of errors, whether or not discoverable, all to
|
||||||
|
the greatest extent permissible under applicable law.
|
||||||
|
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||||
|
that may apply to the Work or any use thereof, including without
|
||||||
|
limitation any person's Copyright and Related Rights in the Work.
|
||||||
|
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||||
|
consents, permissions or other rights required for any use of the
|
||||||
|
Work.
|
||||||
|
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||||
|
party to this document and has no duty or obligation with respect to
|
||||||
|
this CC0 or use of the Work.
|
127
examples/ecdh.c
Normal file
127
examples/ecdh.c
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* Written in 2020-2022 by Elichai Turkel *
|
||||||
|
* To the extent possible under law, the author(s) have dedicated all *
|
||||||
|
* copyright and related and neighboring rights to the software in this *
|
||||||
|
* file to the public domain worldwide. This software is distributed *
|
||||||
|
* without any warranty. For the CC0 Public Domain Dedication, see *
|
||||||
|
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <secp256k1.h>
|
||||||
|
#include <secp256k1_ecdh.h>
|
||||||
|
|
||||||
|
#include "random.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
unsigned char seckey1[32];
|
||||||
|
unsigned char seckey2[32];
|
||||||
|
unsigned char compressed_pubkey1[33];
|
||||||
|
unsigned char compressed_pubkey2[33];
|
||||||
|
unsigned char shared_secret1[32];
|
||||||
|
unsigned char shared_secret2[32];
|
||||||
|
unsigned char randomize[32];
|
||||||
|
int return_val;
|
||||||
|
size_t len;
|
||||||
|
secp256k1_pubkey pubkey1;
|
||||||
|
secp256k1_pubkey pubkey2;
|
||||||
|
|
||||||
|
/* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create`
|
||||||
|
* needs a context object initialized for signing, which is why we create
|
||||||
|
* a context with the SECP256K1_CONTEXT_SIGN flag.
|
||||||
|
* (The docs for `secp256k1_ecdh` don't require any special context, just
|
||||||
|
* some initialized context) */
|
||||||
|
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||||
|
if (!fill_random(randomize, sizeof(randomize))) {
|
||||||
|
printf("Failed to generate randomness\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* Randomizing the context is recommended to protect against side-channel
|
||||||
|
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
|
||||||
|
* information about it. This should never fail. */
|
||||||
|
return_val = secp256k1_context_randomize(ctx, randomize);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/*** Key Generation ***/
|
||||||
|
|
||||||
|
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||||
|
* order), we try to sample a new key. Note that the probability of this
|
||||||
|
* happening is negligible. */
|
||||||
|
while (1) {
|
||||||
|
if (!fill_random(seckey1, sizeof(seckey1)) || !fill_random(seckey2, sizeof(seckey2))) {
|
||||||
|
printf("Failed to generate randomness\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (secp256k1_ec_seckey_verify(ctx, seckey1) && secp256k1_ec_seckey_verify(ctx, seckey2)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public key creation using a valid context with a verified secret key should never fail */
|
||||||
|
return_val = secp256k1_ec_pubkey_create(ctx, &pubkey1, seckey1);
|
||||||
|
assert(return_val);
|
||||||
|
return_val = secp256k1_ec_pubkey_create(ctx, &pubkey2, seckey2);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/* Serialize pubkey1 in a compressed form (33 bytes), should always return 1 */
|
||||||
|
len = sizeof(compressed_pubkey1);
|
||||||
|
return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey1, &len, &pubkey1, SECP256K1_EC_COMPRESSED);
|
||||||
|
assert(return_val);
|
||||||
|
/* Should be the same size as the size of the output, because we passed a 33 byte array. */
|
||||||
|
assert(len == sizeof(compressed_pubkey1));
|
||||||
|
|
||||||
|
/* Serialize pubkey2 in a compressed form (33 bytes) */
|
||||||
|
len = sizeof(compressed_pubkey2);
|
||||||
|
return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey2, &len, &pubkey2, SECP256K1_EC_COMPRESSED);
|
||||||
|
assert(return_val);
|
||||||
|
/* Should be the same size as the size of the output, because we passed a 33 byte array. */
|
||||||
|
assert(len == sizeof(compressed_pubkey2));
|
||||||
|
|
||||||
|
/*** Creating the shared secret ***/
|
||||||
|
|
||||||
|
/* Perform ECDH with seckey1 and pubkey2. Should never fail with a verified
|
||||||
|
* seckey and valid pubkey */
|
||||||
|
return_val = secp256k1_ecdh(ctx, shared_secret1, &pubkey2, seckey1, NULL, NULL);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/* Perform ECDH with seckey2 and pubkey1. Should never fail with a verified
|
||||||
|
* seckey and valid pubkey */
|
||||||
|
return_val = secp256k1_ecdh(ctx, shared_secret2, &pubkey1, seckey2, NULL, NULL);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/* Both parties should end up with the same shared secret */
|
||||||
|
return_val = memcmp(shared_secret1, shared_secret2, sizeof(shared_secret1));
|
||||||
|
assert(return_val == 0);
|
||||||
|
|
||||||
|
printf("Secret Key1: ");
|
||||||
|
print_hex(seckey1, sizeof(seckey1));
|
||||||
|
printf("Compressed Pubkey1: ");
|
||||||
|
print_hex(compressed_pubkey1, sizeof(compressed_pubkey1));
|
||||||
|
printf("\nSecret Key2: ");
|
||||||
|
print_hex(seckey2, sizeof(seckey2));
|
||||||
|
printf("Compressed Pubkey2: ");
|
||||||
|
print_hex(compressed_pubkey2, sizeof(compressed_pubkey2));
|
||||||
|
printf("\nShared Secret: ");
|
||||||
|
print_hex(shared_secret1, sizeof(shared_secret1));
|
||||||
|
|
||||||
|
/* This will clear everything from the context and free the memory */
|
||||||
|
secp256k1_context_destroy(ctx);
|
||||||
|
|
||||||
|
/* It's best practice to try to clear secrets from memory after using them.
|
||||||
|
* This is done because some bugs can allow an attacker to leak memory, for
|
||||||
|
* example through "out of bounds" array access (see Heartbleed), Or the OS
|
||||||
|
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
|
||||||
|
*
|
||||||
|
* TODO: Prevent these writes from being optimized out, as any good compiler
|
||||||
|
* will remove any writes that aren't used. */
|
||||||
|
memset(seckey1, 0, sizeof(seckey1));
|
||||||
|
memset(seckey2, 0, sizeof(seckey2));
|
||||||
|
memset(shared_secret1, 0, sizeof(shared_secret1));
|
||||||
|
memset(shared_secret2, 0, sizeof(shared_secret2));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
137
examples/ecdsa.c
Normal file
137
examples/ecdsa.c
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* Written in 2020-2022 by Elichai Turkel *
|
||||||
|
* To the extent possible under law, the author(s) have dedicated all *
|
||||||
|
* copyright and related and neighboring rights to the software in this *
|
||||||
|
* file to the public domain worldwide. This software is distributed *
|
||||||
|
* without any warranty. For the CC0 Public Domain Dedication, see *
|
||||||
|
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <secp256k1.h>
|
||||||
|
|
||||||
|
#include "random.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
/* Instead of signing the message directly, we must sign a 32-byte hash.
|
||||||
|
* Here the message is "Hello, world!" and the hash function was SHA-256.
|
||||||
|
* An actual implementation should just call SHA-256, but this example
|
||||||
|
* hardcodes the output to avoid depending on an additional library.
|
||||||
|
* See https://bitcoin.stackexchange.com/questions/81115/if-someone-wanted-to-pretend-to-be-satoshi-by-posting-a-fake-signature-to-defrau/81116#81116 */
|
||||||
|
unsigned char msg_hash[32] = {
|
||||||
|
0x31, 0x5F, 0x5B, 0xDB, 0x76, 0xD0, 0x78, 0xC4,
|
||||||
|
0x3B, 0x8A, 0xC0, 0x06, 0x4E, 0x4A, 0x01, 0x64,
|
||||||
|
0x61, 0x2B, 0x1F, 0xCE, 0x77, 0xC8, 0x69, 0x34,
|
||||||
|
0x5B, 0xFC, 0x94, 0xC7, 0x58, 0x94, 0xED, 0xD3,
|
||||||
|
};
|
||||||
|
unsigned char seckey[32];
|
||||||
|
unsigned char randomize[32];
|
||||||
|
unsigned char compressed_pubkey[33];
|
||||||
|
unsigned char serialized_signature[64];
|
||||||
|
size_t len;
|
||||||
|
int is_signature_valid;
|
||||||
|
int return_val;
|
||||||
|
secp256k1_pubkey pubkey;
|
||||||
|
secp256k1_ecdsa_signature sig;
|
||||||
|
/* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create` needs
|
||||||
|
* a context object initialized for signing and `secp256k1_ecdsa_verify` needs
|
||||||
|
* a context initialized for verification, which is why we create a context
|
||||||
|
* for both signing and verification with the SECP256K1_CONTEXT_SIGN and
|
||||||
|
* SECP256K1_CONTEXT_VERIFY flags. */
|
||||||
|
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
|
if (!fill_random(randomize, sizeof(randomize))) {
|
||||||
|
printf("Failed to generate randomness\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* Randomizing the context is recommended to protect against side-channel
|
||||||
|
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
|
||||||
|
* information about it. This should never fail. */
|
||||||
|
return_val = secp256k1_context_randomize(ctx, randomize);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/*** Key Generation ***/
|
||||||
|
|
||||||
|
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||||
|
* order), we try to sample a new key. Note that the probability of this
|
||||||
|
* happening is negligible. */
|
||||||
|
while (1) {
|
||||||
|
if (!fill_random(seckey, sizeof(seckey))) {
|
||||||
|
printf("Failed to generate randomness\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (secp256k1_ec_seckey_verify(ctx, seckey)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public key creation using a valid context with a verified secret key should never fail */
|
||||||
|
return_val = secp256k1_ec_pubkey_create(ctx, &pubkey, seckey);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/* Serialize the pubkey in a compressed form(33 bytes). Should always return 1. */
|
||||||
|
len = sizeof(compressed_pubkey);
|
||||||
|
return_val = secp256k1_ec_pubkey_serialize(ctx, compressed_pubkey, &len, &pubkey, SECP256K1_EC_COMPRESSED);
|
||||||
|
assert(return_val);
|
||||||
|
/* Should be the same size as the size of the output, because we passed a 33 byte array. */
|
||||||
|
assert(len == sizeof(compressed_pubkey));
|
||||||
|
|
||||||
|
/*** Signing ***/
|
||||||
|
|
||||||
|
/* Generate an ECDSA signature `noncefp` and `ndata` allows you to pass a
|
||||||
|
* custom nonce function, passing `NULL` will use the RFC-6979 safe default.
|
||||||
|
* Signing with a valid context, verified secret key
|
||||||
|
* and the default nonce function should never fail. */
|
||||||
|
return_val = secp256k1_ecdsa_sign(ctx, &sig, msg_hash, seckey, NULL, NULL);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/* Serialize the signature in a compact form. Should always return 1
|
||||||
|
* according to the documentation in secp256k1.h. */
|
||||||
|
return_val = secp256k1_ecdsa_signature_serialize_compact(ctx, serialized_signature, &sig);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
|
||||||
|
/*** Verification ***/
|
||||||
|
|
||||||
|
/* Deserialize the signature. This will return 0 if the signature can't be parsed correctly. */
|
||||||
|
if (!secp256k1_ecdsa_signature_parse_compact(ctx, &sig, serialized_signature)) {
|
||||||
|
printf("Failed parsing the signature\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deserialize the public key. This will return 0 if the public key can't be parsed correctly. */
|
||||||
|
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, compressed_pubkey, sizeof(compressed_pubkey))) {
|
||||||
|
printf("Failed parsing the public key\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
|
||||||
|
is_signature_valid = secp256k1_ecdsa_verify(ctx, &sig, msg_hash, &pubkey);
|
||||||
|
|
||||||
|
printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false");
|
||||||
|
printf("Secret Key: ");
|
||||||
|
print_hex(seckey, sizeof(seckey));
|
||||||
|
printf("Public Key: ");
|
||||||
|
print_hex(compressed_pubkey, sizeof(compressed_pubkey));
|
||||||
|
printf("Signature: ");
|
||||||
|
print_hex(serialized_signature, sizeof(serialized_signature));
|
||||||
|
|
||||||
|
|
||||||
|
/* This will clear everything from the context and free the memory */
|
||||||
|
secp256k1_context_destroy(ctx);
|
||||||
|
|
||||||
|
/* It's best practice to try to clear secrets from memory after using them.
|
||||||
|
* This is done because some bugs can allow an attacker to leak memory, for
|
||||||
|
* example through "out of bounds" array access (see Heartbleed), Or the OS
|
||||||
|
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
|
||||||
|
*
|
||||||
|
* TODO: Prevent these writes from being optimized out, as any good compiler
|
||||||
|
* will remove any writes that aren't used. */
|
||||||
|
memset(seckey, 0, sizeof(seckey));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,8 +1,11 @@
|
|||||||
/***********************************************************************
|
/*************************************************************************
|
||||||
* Copyright (c) 2018 Jonas Nick *
|
* Written in 2018 by Jonas Nick *
|
||||||
* Distributed under the MIT software license, see the accompanying *
|
* To the extent possible under law, the author(s) have dedicated all *
|
||||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
* copyright and related and neighboring rights to the software in this *
|
||||||
**********************************************************************/
|
* file to the public domain worldwide. This software is distributed *
|
||||||
|
* without any warranty. For the CC0 Public Domain Dedication, see *
|
||||||
|
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
/** This file demonstrates how to use the MuSig module to create a
|
/** This file demonstrates how to use the MuSig module to create a
|
||||||
* 3-of-3 multisignature. Additionally, see the documentation in
|
* 3-of-3 multisignature. Additionally, see the documentation in
|
||||||
@ -15,6 +18,8 @@
|
|||||||
#include <secp256k1_schnorrsig.h>
|
#include <secp256k1_schnorrsig.h>
|
||||||
#include <secp256k1_musig.h>
|
#include <secp256k1_musig.h>
|
||||||
|
|
||||||
|
#include "random.h"
|
||||||
|
|
||||||
struct signer_secrets {
|
struct signer_secrets {
|
||||||
secp256k1_keypair keypair;
|
secp256k1_keypair keypair;
|
||||||
secp256k1_musig_secnonce secnonce;
|
secp256k1_musig_secnonce secnonce;
|
||||||
@ -31,20 +36,14 @@ struct signer {
|
|||||||
/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */
|
/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */
|
||||||
int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {
|
int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {
|
||||||
unsigned char seckey[32];
|
unsigned char seckey[32];
|
||||||
FILE *frand = fopen("/dev/urandom", "r");
|
while (1) {
|
||||||
if (frand == NULL) {
|
if (!fill_random(seckey, sizeof(seckey))) {
|
||||||
return 0;
|
printf("Failed to generate randomness\n");
|
||||||
}
|
return 1;
|
||||||
do {
|
}
|
||||||
if(!fread(seckey, sizeof(seckey), 1, frand)) {
|
if (secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) {
|
||||||
fclose(frand);
|
break;
|
||||||
return 0;
|
}
|
||||||
}
|
|
||||||
/* The probability that this not a valid secret key is approximately 2^-128 */
|
|
||||||
} while (!secp256k1_ec_seckey_verify(ctx, seckey));
|
|
||||||
fclose(frand);
|
|
||||||
if (!secp256k1_keypair_create(ctx, &signer_secrets->keypair, seckey)) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
if (!secp256k1_keypair_xonly_pub(ctx, &signer->pubkey, NULL, &signer_secrets->keypair)) {
|
if (!secp256k1_keypair_xonly_pub(ctx, &signer->pubkey, NULL, &signer_secrets->keypair)) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -100,21 +99,14 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
|
|||||||
secp256k1_musig_session session;
|
secp256k1_musig_session session;
|
||||||
|
|
||||||
for (i = 0; i < N_SIGNERS; i++) {
|
for (i = 0; i < N_SIGNERS; i++) {
|
||||||
FILE *frand;
|
|
||||||
unsigned char seckey[32];
|
unsigned char seckey[32];
|
||||||
unsigned char session_id[32];
|
unsigned char session_id[32];
|
||||||
/* Create random session ID. It is absolutely necessary that the session ID
|
/* Create random session ID. It is absolutely necessary that the session ID
|
||||||
* is unique for every call of secp256k1_musig_nonce_gen. Otherwise
|
* is unique for every call of secp256k1_musig_nonce_gen. Otherwise
|
||||||
* it's trivial for an attacker to extract the secret key! */
|
* it's trivial for an attacker to extract the secret key! */
|
||||||
frand = fopen("/dev/urandom", "r");
|
if (!fill_random(session_id, sizeof(session_id))) {
|
||||||
if(frand == NULL) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!fread(session_id, 32, 1, frand)) {
|
|
||||||
fclose(frand);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
fclose(frand);
|
|
||||||
if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {
|
if (!secp256k1_keypair_sec(ctx, seckey, &signer_secrets[i].keypair)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
73
examples/random.h
Normal file
73
examples/random.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* Copyright (c) 2020-2021 Elichai Turkel *
|
||||||
|
* Distributed under the CC0 software license, see the accompanying file *
|
||||||
|
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is an attempt at collecting best practice methods for obtaining randomness with different operating systems.
|
||||||
|
* It may be out-of-date. Consult the documentation of the operating system before considering to use the methods below.
|
||||||
|
*
|
||||||
|
* Platform randomness sources:
|
||||||
|
* Linux -> `getrandom(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. http://man7.org/linux/man-pages/man2/getrandom.2.html, https://linux.die.net/man/4/urandom
|
||||||
|
* macOS -> `getentropy(2)`(`sys/random.h`), if not available `/dev/urandom` should be used. https://www.unix.com/man-page/mojave/2/getentropy, https://opensource.apple.com/source/xnu/xnu-517.12.7/bsd/man/man4/random.4.auto.html
|
||||||
|
* FreeBSD -> `getrandom(2)`(`sys/random.h`), if not available `kern.arandom` should be used. https://www.freebsd.org/cgi/man.cgi?query=getrandom, https://www.freebsd.org/cgi/man.cgi?query=random&sektion=4
|
||||||
|
* OpenBSD -> `getentropy(2)`(`unistd.h`), if not available `/dev/urandom` should be used. https://man.openbsd.org/getentropy, https://man.openbsd.org/urandom
|
||||||
|
* Windows -> `BCryptGenRandom`(`bcrypt.h`). https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#include <ntstatus.h>
|
||||||
|
#include <bcrypt.h>
|
||||||
|
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||||
|
#include <sys/random.h>
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
#include <unistd.h>
|
||||||
|
#else
|
||||||
|
#error "Couldn't identify the OS"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* Returns 1 on success, and 0 on failure. */
|
||||||
|
static int fill_random(unsigned char* data, size_t size) {
|
||||||
|
#if defined(_WIN32)
|
||||||
|
NTSTATUS res = BCryptGenRandom(NULL, data, size, BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||||
|
if (res != STATUS_SUCCESS || size > ULONG_MAX) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||||
|
/* If `getrandom(2)` is not available you should fallback to /dev/urandom */
|
||||||
|
ssize_t res = getrandom(data, size, 0);
|
||||||
|
if (res < 0 || (size_t)res != size ) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#elif defined(__APPLE__) || defined(__OpenBSD__)
|
||||||
|
/* If `getentropy(2)` is not available you should fallback to either
|
||||||
|
* `SecRandomCopyBytes` or /dev/urandom */
|
||||||
|
int res = getentropy(data, size);
|
||||||
|
if (res == 0) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_hex(unsigned char* data, size_t size) {
|
||||||
|
size_t i;
|
||||||
|
printf("0x");
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
printf("%02x", data[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
152
examples/schnorr.c
Normal file
152
examples/schnorr.c
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
* Written in 2020-2022 by Elichai Turkel *
|
||||||
|
* To the extent possible under law, the author(s) have dedicated all *
|
||||||
|
* copyright and related and neighboring rights to the software in this *
|
||||||
|
* file to the public domain worldwide. This software is distributed *
|
||||||
|
* without any warranty. For the CC0 Public Domain Dedication, see *
|
||||||
|
* EXAMPLES_COPYING or https://creativecommons.org/publicdomain/zero/1.0 *
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <secp256k1.h>
|
||||||
|
#include <secp256k1_extrakeys.h>
|
||||||
|
#include <secp256k1_schnorrsig.h>
|
||||||
|
|
||||||
|
#include "random.h"
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
unsigned char msg[12] = "Hello World!";
|
||||||
|
unsigned char msg_hash[32];
|
||||||
|
unsigned char tag[17] = "my_fancy_protocol";
|
||||||
|
unsigned char seckey[32];
|
||||||
|
unsigned char randomize[32];
|
||||||
|
unsigned char auxiliary_rand[32];
|
||||||
|
unsigned char serialized_pubkey[32];
|
||||||
|
unsigned char signature[64];
|
||||||
|
int is_signature_valid;
|
||||||
|
int return_val;
|
||||||
|
secp256k1_xonly_pubkey pubkey;
|
||||||
|
secp256k1_keypair keypair;
|
||||||
|
/* The specification in secp256k1_extrakeys.h states that `secp256k1_keypair_create`
|
||||||
|
* needs a context object initialized for signing. And in secp256k1_schnorrsig.h
|
||||||
|
* they state that `secp256k1_schnorrsig_verify` needs a context initialized for
|
||||||
|
* verification, which is why we create a context for both signing and verification
|
||||||
|
* with the SECP256K1_CONTEXT_SIGN and SECP256K1_CONTEXT_VERIFY flags. */
|
||||||
|
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||||
|
if (!fill_random(randomize, sizeof(randomize))) {
|
||||||
|
printf("Failed to generate randomness\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* Randomizing the context is recommended to protect against side-channel
|
||||||
|
* leakage See `secp256k1_context_randomize` in secp256k1.h for more
|
||||||
|
* information about it. This should never fail. */
|
||||||
|
return_val = secp256k1_context_randomize(ctx, randomize);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/*** Key Generation ***/
|
||||||
|
|
||||||
|
/* If the secret key is zero or out of range (bigger than secp256k1's
|
||||||
|
* order), we try to sample a new key. Note that the probability of this
|
||||||
|
* happening is negligible. */
|
||||||
|
while (1) {
|
||||||
|
if (!fill_random(seckey, sizeof(seckey))) {
|
||||||
|
printf("Failed to generate randomness\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* Try to create a keypair with a valid context, it should only fail if
|
||||||
|
* the secret key is zero or out of range. */
|
||||||
|
if (secp256k1_keypair_create(ctx, &keypair, seckey)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extract the X-only public key from the keypair. We pass NULL for
|
||||||
|
* `pk_parity` as the parity isn't needed for signing or verification.
|
||||||
|
* `secp256k1_keypair_xonly_pub` supports returning the parity for
|
||||||
|
* other use cases such as tests or verifying Taproot tweaks.
|
||||||
|
* This should never fail with a valid context and public key. */
|
||||||
|
return_val = secp256k1_keypair_xonly_pub(ctx, &pubkey, NULL, &keypair);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/* Serialize the public key. Should always return 1 for a valid public key. */
|
||||||
|
return_val = secp256k1_xonly_pubkey_serialize(ctx, serialized_pubkey, &pubkey);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/*** Signing ***/
|
||||||
|
|
||||||
|
/* Instead of signing (possibly very long) messages directly, we sign a
|
||||||
|
* 32-byte hash of the message in this example.
|
||||||
|
*
|
||||||
|
* We use secp256k1_tagged_sha256 to create this hash. This function expects
|
||||||
|
* a context-specific "tag", which restricts the context in which the signed
|
||||||
|
* messages should be considered valid. For example, if protocol A mandates
|
||||||
|
* to use the tag "my_fancy_protocol" and protocol B mandates to use the tag
|
||||||
|
* "my_boring_protocol", then signed messages from protocol A will never be
|
||||||
|
* valid in protocol B (and vice versa), even if keys are reused across
|
||||||
|
* protocols. This implements "domain separation", which is considered good
|
||||||
|
* practice. It avoids attacks in which users are tricked into signing a
|
||||||
|
* message that has intended consequences in the intended context (e.g.,
|
||||||
|
* protocol A) but would have unintended consequences if it were valid in
|
||||||
|
* some other context (e.g., protocol B). */
|
||||||
|
return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg));
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/* Generate 32 bytes of randomness to use with BIP-340 schnorr signing. */
|
||||||
|
if (!fill_random(auxiliary_rand, sizeof(auxiliary_rand))) {
|
||||||
|
printf("Failed to generate randomness\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate a Schnorr signature.
|
||||||
|
*
|
||||||
|
* We use the secp256k1_schnorrsig_sign32 function that provides a simple
|
||||||
|
* interface for signing 32-byte messages (which in our case is a hash of
|
||||||
|
* the actual message). BIP-340 recommends passing 32 bytes of randomness
|
||||||
|
* to the signing function to improve security against side-channel attacks.
|
||||||
|
* Signing with a valid context, a 32-byte message, a verified keypair, and
|
||||||
|
* any 32 bytes of auxiliary random data should never fail. */
|
||||||
|
return_val = secp256k1_schnorrsig_sign32(ctx, signature, msg_hash, &keypair, auxiliary_rand);
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/*** Verification ***/
|
||||||
|
|
||||||
|
/* Deserialize the public key. This will return 0 if the public key can't
|
||||||
|
* be parsed correctly */
|
||||||
|
if (!secp256k1_xonly_pubkey_parse(ctx, &pubkey, serialized_pubkey)) {
|
||||||
|
printf("Failed parsing the public key\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute the tagged hash on the received messages using the same tag as the signer. */
|
||||||
|
return_val = secp256k1_tagged_sha256(ctx, msg_hash, tag, sizeof(tag), msg, sizeof(msg));
|
||||||
|
assert(return_val);
|
||||||
|
|
||||||
|
/* Verify a signature. This will return 1 if it's valid and 0 if it's not. */
|
||||||
|
is_signature_valid = secp256k1_schnorrsig_verify(ctx, signature, msg_hash, 32, &pubkey);
|
||||||
|
|
||||||
|
|
||||||
|
printf("Is the signature valid? %s\n", is_signature_valid ? "true" : "false");
|
||||||
|
printf("Secret Key: ");
|
||||||
|
print_hex(seckey, sizeof(seckey));
|
||||||
|
printf("Public Key: ");
|
||||||
|
print_hex(serialized_pubkey, sizeof(serialized_pubkey));
|
||||||
|
printf("Signature: ");
|
||||||
|
print_hex(signature, sizeof(signature));
|
||||||
|
|
||||||
|
/* This will clear everything from the context and free the memory */
|
||||||
|
secp256k1_context_destroy(ctx);
|
||||||
|
|
||||||
|
/* It's best practice to try to clear secrets from memory after using them.
|
||||||
|
* This is done because some bugs can allow an attacker to leak memory, for
|
||||||
|
* example through "out of bounds" array access (see Heartbleed), Or the OS
|
||||||
|
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
|
||||||
|
*
|
||||||
|
* TODO: Prevent these writes from being optimized out, as any good compiler
|
||||||
|
* will remove any writes that aren't used. */
|
||||||
|
memset(seckey, 0, sizeof(seckey));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -169,6 +169,17 @@ typedef int (*secp256k1_nonce_function)(
|
|||||||
# define SECP256K1_ARG_NONNULL(_x)
|
# define SECP256K1_ARG_NONNULL(_x)
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
/** Attribute for marking functions, types, and variables as deprecated */
|
||||||
|
#if !defined(SECP256K1_BUILD) && defined(__has_attribute)
|
||||||
|
# if __has_attribute(__deprecated__)
|
||||||
|
# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg)))
|
||||||
|
# else
|
||||||
|
# define SECP256K1_DEPRECATED(_msg)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define SECP256K1_DEPRECATED(_msg)
|
||||||
|
#endif
|
||||||
|
|
||||||
/** All flags' lower 8 bits indicate what they're for. Do not use directly. */
|
/** All flags' lower 8 bits indicate what they're for. Do not use directly. */
|
||||||
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
|
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
|
||||||
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
|
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
|
||||||
@ -641,7 +652,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
|
|||||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
|
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
|
||||||
const secp256k1_context* ctx,
|
const secp256k1_context* ctx,
|
||||||
unsigned char *seckey
|
unsigned char *seckey
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
|
||||||
|
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead");
|
||||||
|
|
||||||
/** Negates a public key in place.
|
/** Negates a public key in place.
|
||||||
*
|
*
|
||||||
@ -681,7 +693,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
|
|||||||
const secp256k1_context* ctx,
|
const secp256k1_context* ctx,
|
||||||
unsigned char *seckey,
|
unsigned char *seckey,
|
||||||
const unsigned char *tweak32
|
const unsigned char *tweak32
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
|
||||||
|
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_add instead");
|
||||||
|
|
||||||
/** Tweak a public key by adding tweak times the generator to it.
|
/** Tweak a public key by adding tweak times the generator to it.
|
||||||
*
|
*
|
||||||
@ -727,7 +740,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
|
|||||||
const secp256k1_context* ctx,
|
const secp256k1_context* ctx,
|
||||||
unsigned char *seckey,
|
unsigned char *seckey,
|
||||||
const unsigned char *tweak32
|
const unsigned char *tweak32
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
|
||||||
|
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_tweak_mul instead");
|
||||||
|
|
||||||
/** Tweak a public key by multiplying it by a tweak value.
|
/** Tweak a public key by multiplying it by a tweak value.
|
||||||
*
|
*
|
||||||
@ -800,7 +814,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
|
|||||||
* implementations optimized for a specific tag can precompute the SHA256 state
|
* implementations optimized for a specific tag can precompute the SHA256 state
|
||||||
* after hashing the tag hashes.
|
* after hashing the tag hashes.
|
||||||
*
|
*
|
||||||
* Returns 0 if the arguments are invalid and 1 otherwise.
|
* Returns: 1 always.
|
||||||
* Args: ctx: pointer to a context object
|
* Args: ctx: pointer to a context object
|
||||||
* Out: hash32: pointer to a 32-byte array to store the resulting hash
|
* Out: hash32: pointer to a 32-byte array to store the resulting hash
|
||||||
* In: tag: pointer to an array containing the tag
|
* In: tag: pointer to an array containing the tag
|
||||||
|
@ -81,8 +81,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_cmp(
|
|||||||
|
|
||||||
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
|
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
|
||||||
*
|
*
|
||||||
* Returns: 1 if the public key was successfully converted
|
* Returns: 1 always.
|
||||||
* 0 otherwise
|
|
||||||
*
|
*
|
||||||
* Args: ctx: pointer to a context object.
|
* Args: ctx: pointer to a context object.
|
||||||
* Out: xonly_pubkey: pointer to an x-only public key object for placing the converted public key.
|
* Out: xonly_pubkey: pointer to an x-only public key object for placing the converted public key.
|
||||||
@ -186,7 +185,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
|
|||||||
|
|
||||||
/** Get the secret key from a keypair.
|
/** Get the secret key from a keypair.
|
||||||
*
|
*
|
||||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
* Returns: 1 always.
|
||||||
* Args: ctx: pointer to a context object.
|
* Args: ctx: pointer to a context object.
|
||||||
* Out: seckey: pointer to a 32-byte buffer for the secret key.
|
* Out: seckey: pointer to a 32-byte buffer for the secret key.
|
||||||
* In: keypair: pointer to a keypair.
|
* In: keypair: pointer to a keypair.
|
||||||
@ -199,7 +198,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
|
|||||||
|
|
||||||
/** Get the public key from a keypair.
|
/** Get the public key from a keypair.
|
||||||
*
|
*
|
||||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
* Returns: 1 always.
|
||||||
* Args: ctx: pointer to a context object.
|
* Args: ctx: pointer to a context object.
|
||||||
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to
|
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to
|
||||||
* the keypair public key. If not, it's set to an invalid value.
|
* the keypair public key. If not, it's set to an invalid value.
|
||||||
@ -216,7 +215,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
|
|||||||
* This is the same as calling secp256k1_keypair_pub and then
|
* This is the same as calling secp256k1_keypair_pub and then
|
||||||
* secp256k1_xonly_pubkey_from_pubkey.
|
* secp256k1_xonly_pubkey_from_pubkey.
|
||||||
*
|
*
|
||||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
* Returns: 1 always.
|
||||||
* Args: ctx: pointer to a context object.
|
* Args: ctx: pointer to a context object.
|
||||||
* Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set
|
* Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set
|
||||||
* to the keypair public key after converting it to an
|
* to the keypair public key after converting it to an
|
||||||
|
@ -116,7 +116,7 @@ typedef struct {
|
|||||||
* BIP-340 "Default Signing" for a full explanation of this
|
* BIP-340 "Default Signing" for a full explanation of this
|
||||||
* argument and for guidance if randomness is expensive.
|
* argument and for guidance if randomness is expensive.
|
||||||
*/
|
*/
|
||||||
SECP256K1_API int secp256k1_schnorrsig_sign(
|
SECP256K1_API int secp256k1_schnorrsig_sign32(
|
||||||
const secp256k1_context* ctx,
|
const secp256k1_context* ctx,
|
||||||
unsigned char *sig64,
|
unsigned char *sig64,
|
||||||
const unsigned char *msg32,
|
const unsigned char *msg32,
|
||||||
@ -124,6 +124,17 @@ SECP256K1_API int secp256k1_schnorrsig_sign(
|
|||||||
const unsigned char *aux_rand32
|
const unsigned char *aux_rand32
|
||||||
) 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(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** Same as secp256k1_schnorrsig_sign32, but DEPRECATED. Will be removed in
|
||||||
|
* future versions. */
|
||||||
|
SECP256K1_API int secp256k1_schnorrsig_sign(
|
||||||
|
const secp256k1_context* ctx,
|
||||||
|
unsigned char *sig64,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const secp256k1_keypair *keypair,
|
||||||
|
const unsigned char *aux_rand32
|
||||||
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4)
|
||||||
|
SECP256K1_DEPRECATED("Use secp256k1_schnorrsig_sign32 instead");
|
||||||
|
|
||||||
/** Create a Schnorr signature with a more flexible API.
|
/** Create a Schnorr signature with a more flexible API.
|
||||||
*
|
*
|
||||||
* Same arguments as secp256k1_schnorrsig_sign except that it allows signing
|
* Same arguments as secp256k1_schnorrsig_sign except that it allows signing
|
||||||
|
@ -164,6 +164,9 @@ class constraints:
|
|||||||
def negate(self):
|
def negate(self):
|
||||||
return constraints(zero=self.nonzero, nonzero=self.zero)
|
return constraints(zero=self.nonzero, nonzero=self.zero)
|
||||||
|
|
||||||
|
def map(self, fun):
|
||||||
|
return constraints(zero={fun(k): v for k, v in self.zero.items()}, nonzero={fun(k): v for k, v in self.nonzero.items()})
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
zero = self.zero.copy()
|
zero = self.zero.copy()
|
||||||
zero.update(other.zero)
|
zero.update(other.zero)
|
||||||
@ -177,6 +180,30 @@ class constraints:
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s" % self
|
return "%s" % self
|
||||||
|
|
||||||
|
def normalize_factor(p):
|
||||||
|
"""Normalizes the sign of primitive polynomials (as returned by factor())
|
||||||
|
|
||||||
|
This function ensures that the polynomial has a positive leading coefficient.
|
||||||
|
|
||||||
|
This is necessary because recent sage versions (starting with v9.3 or v9.4,
|
||||||
|
we don't know) are inconsistent about the placement of the minus sign in
|
||||||
|
polynomial factorizations:
|
||||||
|
```
|
||||||
|
sage: R.<ax,bx,ay,by,Az,Bz,Ai,Bi> = PolynomialRing(QQ,8,order='invlex')
|
||||||
|
sage: R((-2 * (bx - ax)) ^ 1).factor()
|
||||||
|
(-2) * (bx - ax)
|
||||||
|
sage: R((-2 * (bx - ax)) ^ 2).factor()
|
||||||
|
(4) * (-bx + ax)^2
|
||||||
|
sage: R((-2 * (bx - ax)) ^ 3).factor()
|
||||||
|
(8) * (-bx + ax)^3
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
# Assert p is not 0 and that its non-zero coeffients are coprime.
|
||||||
|
# (We could just work with the primitive part p/p.content() but we want to be
|
||||||
|
# aware if factor() does not return a primitive part in future sage versions.)
|
||||||
|
assert p.content() == 1
|
||||||
|
# Ensure that the first non-zero coefficient is positive.
|
||||||
|
return p if p.lc() > 0 else -p
|
||||||
|
|
||||||
def conflicts(R, con):
|
def conflicts(R, con):
|
||||||
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
|
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
|
||||||
@ -204,10 +231,10 @@ def get_nonzero_set(R, assume):
|
|||||||
nonzero = set()
|
nonzero = set()
|
||||||
for nz in map(numerator, assume.nonzero):
|
for nz in map(numerator, assume.nonzero):
|
||||||
for (f,n) in nz.factor():
|
for (f,n) in nz.factor():
|
||||||
nonzero.add(f)
|
nonzero.add(normalize_factor(f))
|
||||||
rnz = zero.reduce(nz)
|
rnz = zero.reduce(nz)
|
||||||
for (f,n) in rnz.factor():
|
for (f,n) in rnz.factor():
|
||||||
nonzero.add(f)
|
nonzero.add(normalize_factor(f))
|
||||||
return nonzero
|
return nonzero
|
||||||
|
|
||||||
|
|
||||||
@ -222,27 +249,27 @@ def prove_nonzero(R, exprs, assume):
|
|||||||
return (False, [exprs[expr]])
|
return (False, [exprs[expr]])
|
||||||
allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)
|
allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1)
|
||||||
for (f, n) in allexprs.factor():
|
for (f, n) in allexprs.factor():
|
||||||
if f not in nonzero:
|
if normalize_factor(f) not in nonzero:
|
||||||
ok = False
|
ok = False
|
||||||
if ok:
|
if ok:
|
||||||
return (True, None)
|
return (True, None)
|
||||||
ok = True
|
ok = True
|
||||||
for (f, n) in zero.reduce(numerator(allexprs)).factor():
|
for (f, n) in zero.reduce(allexprs).factor():
|
||||||
if f not in nonzero:
|
if normalize_factor(f) not in nonzero:
|
||||||
ok = False
|
ok = False
|
||||||
if ok:
|
if ok:
|
||||||
return (True, None)
|
return (True, None)
|
||||||
ok = True
|
ok = True
|
||||||
for expr in exprs:
|
for expr in exprs:
|
||||||
for (f,n) in numerator(expr).factor():
|
for (f,n) in numerator(expr).factor():
|
||||||
if f not in nonzero:
|
if normalize_factor(f) not in nonzero:
|
||||||
ok = False
|
ok = False
|
||||||
if ok:
|
if ok:
|
||||||
return (True, None)
|
return (True, None)
|
||||||
ok = True
|
ok = True
|
||||||
for expr in exprs:
|
for expr in exprs:
|
||||||
for (f,n) in zero.reduce(numerator(expr)).factor():
|
for (f,n) in zero.reduce(numerator(expr)).factor():
|
||||||
if f not in nonzero:
|
if normalize_factor(f) not in nonzero:
|
||||||
expl.add(exprs[expr])
|
expl.add(exprs[expr])
|
||||||
if expl:
|
if expl:
|
||||||
return (False, list(expl))
|
return (False, list(expl))
|
||||||
@ -254,7 +281,7 @@ def prove_zero(R, exprs, assume):
|
|||||||
"""Check whether all of the passed expressions are provably zero, given assumptions"""
|
"""Check whether all of the passed expressions are provably zero, given assumptions"""
|
||||||
r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
|
r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
|
||||||
if not r:
|
if not r:
|
||||||
return (False, map(lambda x: "Possibly zero denominator: %s" % x, e))
|
return (False, list(map(lambda x: "Possibly zero denominator: %s" % x, e)))
|
||||||
zero = R.ideal(list(map(numerator, assume.zero)))
|
zero = R.ideal(list(map(numerator, assume.zero)))
|
||||||
nonzero = prod(x for x in assume.nonzero)
|
nonzero = prod(x for x in assume.nonzero)
|
||||||
expl = []
|
expl = []
|
||||||
@ -279,8 +306,8 @@ def describe_extra(R, assume, assumeExtra):
|
|||||||
if base not in zero:
|
if base not in zero:
|
||||||
add = []
|
add = []
|
||||||
for (f, n) in numerator(base).factor():
|
for (f, n) in numerator(base).factor():
|
||||||
if f not in nonzero:
|
if normalize_factor(f) not in nonzero:
|
||||||
add += ["%s" % f]
|
add += ["%s" % normalize_factor(f)]
|
||||||
if add:
|
if add:
|
||||||
ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base])
|
ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base])
|
||||||
# Iterate over the extra nonzero expressions
|
# Iterate over the extra nonzero expressions
|
||||||
@ -288,8 +315,8 @@ def describe_extra(R, assume, assumeExtra):
|
|||||||
nzr = zeroextra.reduce(numerator(nz))
|
nzr = zeroextra.reduce(numerator(nz))
|
||||||
if nzr not in zeroextra:
|
if nzr not in zeroextra:
|
||||||
for (f,n) in nzr.factor():
|
for (f,n) in nzr.factor():
|
||||||
if zeroextra.reduce(f) not in nonzero:
|
if normalize_factor(zeroextra.reduce(f)) not in nonzero:
|
||||||
ret.add("%s != 0" % zeroextra.reduce(f))
|
ret.add("%s != 0" % normalize_factor(zeroextra.reduce(f)))
|
||||||
return ", ".join(x for x in ret)
|
return ", ".join(x for x in ret)
|
||||||
|
|
||||||
|
|
||||||
@ -299,22 +326,21 @@ def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require):
|
|||||||
|
|
||||||
if conflicts(R, assume):
|
if conflicts(R, assume):
|
||||||
# This formula does not apply
|
# This formula does not apply
|
||||||
return None
|
return (True, None)
|
||||||
|
|
||||||
describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)
|
describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert)
|
||||||
|
if describe != "":
|
||||||
|
describe = " (assuming " + describe + ")"
|
||||||
|
|
||||||
ok, msg = prove_zero(R, require.zero, assume)
|
ok, msg = prove_zero(R, require.zero, assume)
|
||||||
if not ok:
|
if not ok:
|
||||||
return "FAIL, %s fails (assuming %s)" % (str(msg), describe)
|
return (False, "FAIL, %s fails%s" % (str(msg), describe))
|
||||||
|
|
||||||
res, expl = prove_nonzero(R, require.nonzero, assume)
|
res, expl = prove_nonzero(R, require.nonzero, assume)
|
||||||
if not res:
|
if not res:
|
||||||
return "FAIL, %s fails (assuming %s)" % (str(expl), describe)
|
return (False, "FAIL, %s fails%s" % (str(expl), describe))
|
||||||
|
|
||||||
if describe != "":
|
return (True, "OK%s" % describe)
|
||||||
return "OK (assuming %s)" % describe
|
|
||||||
else:
|
|
||||||
return "OK"
|
|
||||||
|
|
||||||
|
|
||||||
def concrete_verify(c):
|
def concrete_verify(c):
|
||||||
|
@ -8,25 +8,20 @@ load("weierstrass_prover.sage")
|
|||||||
def formula_secp256k1_gej_double_var(a):
|
def formula_secp256k1_gej_double_var(a):
|
||||||
"""libsecp256k1's secp256k1_gej_double_var, used by various addition functions"""
|
"""libsecp256k1's secp256k1_gej_double_var, used by various addition functions"""
|
||||||
rz = a.Z * a.Y
|
rz = a.Z * a.Y
|
||||||
rz = rz * 2
|
s = a.Y^2
|
||||||
t1 = a.X^2
|
l = a.X^2
|
||||||
t1 = t1 * 3
|
l = l * 3
|
||||||
t2 = t1^2
|
l = l / 2
|
||||||
t3 = a.Y^2
|
t = -s
|
||||||
t3 = t3 * 2
|
t = t * a.X
|
||||||
t4 = t3^2
|
rx = l^2
|
||||||
t4 = t4 * 2
|
rx = rx + t
|
||||||
t3 = t3 * a.X
|
rx = rx + t
|
||||||
rx = t3
|
s = s^2
|
||||||
rx = rx * 4
|
t = t + rx
|
||||||
rx = -rx
|
ry = t * l
|
||||||
rx = rx + t2
|
ry = ry + s
|
||||||
t2 = -t2
|
ry = -ry
|
||||||
t3 = t3 * 6
|
|
||||||
t3 = t3 + t2
|
|
||||||
ry = t1 * t3
|
|
||||||
t2 = -t4
|
|
||||||
ry = ry + t2
|
|
||||||
return jacobianpoint(rx, ry, rz)
|
return jacobianpoint(rx, ry, rz)
|
||||||
|
|
||||||
def formula_secp256k1_gej_add_var(branch, a, b):
|
def formula_secp256k1_gej_add_var(branch, a, b):
|
||||||
@ -197,7 +192,8 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
|
|||||||
rr_alt = rr
|
rr_alt = rr
|
||||||
m_alt = m
|
m_alt = m
|
||||||
n = m_alt^2
|
n = m_alt^2
|
||||||
q = n * t
|
q = -t
|
||||||
|
q = q * n
|
||||||
n = n^2
|
n = n^2
|
||||||
if degenerate:
|
if degenerate:
|
||||||
n = m
|
n = m
|
||||||
@ -210,8 +206,6 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
|
|||||||
zeroes.update({rz : 'r.z=0'})
|
zeroes.update({rz : 'r.z=0'})
|
||||||
else:
|
else:
|
||||||
nonzeroes.update({rz : 'r.z!=0'})
|
nonzeroes.update({rz : 'r.z!=0'})
|
||||||
rz = rz * 2
|
|
||||||
q = -q
|
|
||||||
t = t + q
|
t = t + q
|
||||||
rx = t
|
rx = t
|
||||||
t = t * 2
|
t = t * 2
|
||||||
@ -219,8 +213,7 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
|
|||||||
t = t * rr_alt
|
t = t * rr_alt
|
||||||
t = t + n
|
t = t + n
|
||||||
ry = -t
|
ry = -t
|
||||||
rx = rx * 4
|
ry = ry / 2
|
||||||
ry = ry * 4
|
|
||||||
if a_infinity:
|
if a_infinity:
|
||||||
rx = b.X
|
rx = b.X
|
||||||
ry = b.Y
|
ry = b.Y
|
||||||
@ -292,15 +285,18 @@ def formula_secp256k1_gej_add_ge_old(branch, a, b):
|
|||||||
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz))
|
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
|
success = True
|
||||||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
|
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
|
||||||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
|
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
|
||||||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
|
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
|
||||||
check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old)
|
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
|
||||||
|
success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old))
|
||||||
|
|
||||||
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
|
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
|
||||||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
|
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
|
||||||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
|
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
|
||||||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
|
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
|
||||||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
|
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
|
||||||
check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43)
|
success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43))
|
||||||
|
|
||||||
|
sys.exit(int(not success))
|
||||||
|
@ -184,6 +184,7 @@ def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
|
|||||||
if r:
|
if r:
|
||||||
points.append(point)
|
points.append(point)
|
||||||
|
|
||||||
|
ret = True
|
||||||
for za in range(1, p):
|
for za in range(1, p):
|
||||||
for zb in range(1, p):
|
for zb in range(1, p):
|
||||||
for pa in points:
|
for pa in points:
|
||||||
@ -211,8 +212,11 @@ def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
|
|||||||
match = True
|
match = True
|
||||||
r, e = concrete_verify(require)
|
r, e = concrete_verify(require)
|
||||||
if not r:
|
if not r:
|
||||||
|
ret = False
|
||||||
print(" failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e))
|
print(" failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e))
|
||||||
|
|
||||||
print()
|
print()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
|
def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
|
||||||
@ -244,15 +248,21 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
|
|||||||
|
|
||||||
print("Formula " + name + ":")
|
print("Formula " + name + ":")
|
||||||
count = 0
|
count = 0
|
||||||
|
ret = True
|
||||||
for branch in range(branches):
|
for branch in range(branches):
|
||||||
assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
|
assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
|
||||||
|
assumeBranch = assumeBranch.map(lift)
|
||||||
|
assumeFormula = assumeFormula.map(lift)
|
||||||
pC.X = lift(pC.X)
|
pC.X = lift(pC.X)
|
||||||
pC.Y = lift(pC.Y)
|
pC.Y = lift(pC.Y)
|
||||||
pC.Z = lift(pC.Z)
|
pC.Z = lift(pC.Z)
|
||||||
pC.Infinity = lift(pC.Infinity)
|
pC.Infinity = lift(pC.Infinity)
|
||||||
|
|
||||||
for key in laws_jacobian_weierstrass:
|
for key in laws_jacobian_weierstrass:
|
||||||
res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
|
success, msg = check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC)
|
||||||
|
if not success:
|
||||||
|
ret = False
|
||||||
|
res[key].append((msg, branch))
|
||||||
|
|
||||||
for key in res:
|
for key in res:
|
||||||
print(" %s:" % key)
|
print(" %s:" % key)
|
||||||
@ -262,3 +272,4 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
|
|||||||
print(" branch %i: %s" % (x[1], x[0]))
|
print(" branch %i: %s" % (x[1], x[0]))
|
||||||
|
|
||||||
print()
|
print()
|
||||||
|
return ret
|
||||||
|
@ -140,6 +140,15 @@ void bench_scalar_inverse_var(void* arg, int iters) {
|
|||||||
CHECK(j <= iters);
|
CHECK(j <= iters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bench_field_half(void* arg, int iters) {
|
||||||
|
int i;
|
||||||
|
bench_inv *data = (bench_inv*)arg;
|
||||||
|
|
||||||
|
for (i = 0; i < iters; i++) {
|
||||||
|
secp256k1_fe_half(&data->fe[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void bench_field_normalize(void* arg, int iters) {
|
void bench_field_normalize(void* arg, int iters) {
|
||||||
int i;
|
int i;
|
||||||
bench_inv *data = (bench_inv*)arg;
|
bench_inv *data = (bench_inv*)arg;
|
||||||
@ -372,6 +381,7 @@ int main(int argc, char **argv) {
|
|||||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters);
|
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, iters);
|
||||||
if (d || 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 (d || 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 (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "half")) run_benchmark("field_half", bench_field_half, bench_setup, NULL, &data, 10, iters*100);
|
||||||
if (d || 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 (d || 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 (d || 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);
|
if (d || 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);
|
||||||
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10);
|
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10);
|
||||||
|
@ -19,13 +19,10 @@
|
|||||||
* It only operates on tables sized for WINDOW_A wnaf multiples.
|
* It only operates on tables sized for WINDOW_A wnaf multiples.
|
||||||
*/
|
*/
|
||||||
static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
|
static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
|
||||||
secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
|
|
||||||
secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
|
secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||||
|
|
||||||
/* Compute the odd multiples in Jacobian form. */
|
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr, globalz, a);
|
||||||
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a);
|
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr);
|
||||||
/* Bring them to the same Z denominator. */
|
|
||||||
secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
|
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
/* The number of objects allocated on the scratch space for ecmult_multi algorithms */
|
/* The number of objects allocated on the scratch space for ecmult_multi algorithms */
|
||||||
#define PIPPENGER_SCRATCH_OBJECTS 6
|
#define PIPPENGER_SCRATCH_OBJECTS 6
|
||||||
#define STRAUSS_SCRATCH_OBJECTS 7
|
#define STRAUSS_SCRATCH_OBJECTS 5
|
||||||
|
|
||||||
#define PIPPENGER_MAX_BUCKET_WINDOW 12
|
#define PIPPENGER_MAX_BUCKET_WINDOW 12
|
||||||
|
|
||||||
@ -56,14 +56,23 @@
|
|||||||
|
|
||||||
#define ECMULT_MAX_POINTS_PER_BATCH 5000000
|
#define ECMULT_MAX_POINTS_PER_BATCH 5000000
|
||||||
|
|
||||||
/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain
|
/** Fill a table 'pre_a' with precomputed odd multiples of a.
|
||||||
* the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will
|
* pre_a will contain [1*a,3*a,...,(2*n-1)*a], so it needs space for n group elements.
|
||||||
* contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z.
|
* zr needs space for n field elements.
|
||||||
* Prej's Z values are undefined, except for the last value.
|
*
|
||||||
|
* Although pre_a is an array of _ge rather than _gej, it actually represents elements
|
||||||
|
* in Jacobian coordinates with their z coordinates omitted. The omitted z-coordinates
|
||||||
|
* can be recovered using z and zr. Using the notation z(b) to represent the omitted
|
||||||
|
* z coordinate of b:
|
||||||
|
* - z(pre_a[n-1]) = 'z'
|
||||||
|
* - z(pre_a[i-1]) = z(pre_a[i]) / zr[i] for n > i > 0
|
||||||
|
*
|
||||||
|
* Lastly the zr[0] value, which isn't used above, is set so that:
|
||||||
|
* - a.z = z(pre_a[0]) / zr[0]
|
||||||
*/
|
*/
|
||||||
static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) {
|
static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, secp256k1_fe *zr, secp256k1_fe *z, const secp256k1_gej *a) {
|
||||||
secp256k1_gej d;
|
secp256k1_gej d, ai;
|
||||||
secp256k1_ge a_ge, d_ge;
|
secp256k1_ge d_ge;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
VERIFY_CHECK(!a->infinity);
|
VERIFY_CHECK(!a->infinity);
|
||||||
@ -71,56 +80,74 @@ static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, sec
|
|||||||
secp256k1_gej_double_var(&d, a, NULL);
|
secp256k1_gej_double_var(&d, a, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate
|
* Perform the additions using an isomorphic curve Y^2 = X^3 + 7*C^6 where C := d.z.
|
||||||
* of 'd', and scale the 1P starting value's x/y coordinates without changing its z.
|
* The isomorphism, phi, maps a secp256k1 point (x, y) to the point (x*C^2, y*C^3) on the other curve.
|
||||||
|
* In Jacobian coordinates phi maps (x, y, z) to (x*C^2, y*C^3, z) or, equivalently to (x, y, z/C).
|
||||||
|
*
|
||||||
|
* phi(x, y, z) = (x*C^2, y*C^3, z) = (x, y, z/C)
|
||||||
|
* d_ge := phi(d) = (d.x, d.y, 1)
|
||||||
|
* ai := phi(a) = (a.x*C^2, a.y*C^3, a.z)
|
||||||
|
*
|
||||||
|
* The group addition functions work correctly on these isomorphic curves.
|
||||||
|
* In particular phi(d) is easy to represent in affine coordinates under this isomorphism.
|
||||||
|
* This lets us use the faster secp256k1_gej_add_ge_var group addition function that we wouldn't be able to use otherwise.
|
||||||
*/
|
*/
|
||||||
d_ge.x = d.x;
|
secp256k1_ge_set_xy(&d_ge, &d.x, &d.y);
|
||||||
d_ge.y = d.y;
|
secp256k1_ge_set_gej_zinv(&pre_a[0], a, &d.z);
|
||||||
d_ge.infinity = 0;
|
secp256k1_gej_set_ge(&ai, &pre_a[0]);
|
||||||
|
ai.z = a->z;
|
||||||
secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z);
|
|
||||||
prej[0].x = a_ge.x;
|
|
||||||
prej[0].y = a_ge.y;
|
|
||||||
prej[0].z = a->z;
|
|
||||||
prej[0].infinity = 0;
|
|
||||||
|
|
||||||
|
/* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equvalent to a.
|
||||||
|
* Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z.
|
||||||
|
*/
|
||||||
zr[0] = d.z;
|
zr[0] = d.z;
|
||||||
|
|
||||||
for (i = 1; i < n; i++) {
|
for (i = 1; i < n; i++) {
|
||||||
secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]);
|
secp256k1_gej_add_ge_var(&ai, &ai, &d_ge, &zr[i]);
|
||||||
|
secp256k1_ge_set_xy(&pre_a[i], &ai.x, &ai.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Multiply the last z-coordinate by C to undo the isomorphism.
|
||||||
* Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only
|
* Since the z-coordinates of the pre_a values are implied by the zr array of z-coordinate ratios,
|
||||||
* the final point's z coordinate is actually used though, so just update that.
|
* undoing the isomorphism here undoes the isomorphism for all pre_a values.
|
||||||
*/
|
*/
|
||||||
secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z);
|
secp256k1_fe_mul(z, &ai.z, &d.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The following two macro retrieves a particular odd multiple from a table
|
#define SECP256K1_ECMULT_TABLE_VERIFY(n,w) \
|
||||||
* of precomputed multiples. */
|
|
||||||
#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \
|
|
||||||
VERIFY_CHECK(((n) & 1) == 1); \
|
VERIFY_CHECK(((n) & 1) == 1); \
|
||||||
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
|
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
|
||||||
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
|
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1));
|
||||||
if ((n) > 0) { \
|
|
||||||
*(r) = (pre)[((n)-1)/2]; \
|
|
||||||
} else { \
|
|
||||||
*(r) = (pre)[(-(n)-1)/2]; \
|
|
||||||
secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
|
|
||||||
} \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \
|
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, const secp256k1_ge *pre, int n, int w) {
|
||||||
VERIFY_CHECK(((n) & 1) == 1); \
|
SECP256K1_ECMULT_TABLE_VERIFY(n,w)
|
||||||
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
|
if (n > 0) {
|
||||||
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
|
*r = pre[(n-1)/2];
|
||||||
if ((n) > 0) { \
|
} else {
|
||||||
secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \
|
*r = pre[(-n-1)/2];
|
||||||
} else { \
|
secp256k1_fe_negate(&(r->y), &(r->y), 1);
|
||||||
secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \
|
}
|
||||||
secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
|
}
|
||||||
} \
|
|
||||||
} while(0)
|
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *r, const secp256k1_ge *pre, const secp256k1_fe *x, int n, int w) {
|
||||||
|
SECP256K1_ECMULT_TABLE_VERIFY(n,w)
|
||||||
|
if (n > 0) {
|
||||||
|
secp256k1_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y);
|
||||||
|
} else {
|
||||||
|
secp256k1_ge_set_xy(r, &x[(-n-1)/2], &pre[(-n-1)/2].y);
|
||||||
|
secp256k1_fe_negate(&(r->y), &(r->y), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_storage(secp256k1_ge *r, const secp256k1_ge_storage *pre, int n, int w) {
|
||||||
|
SECP256K1_ECMULT_TABLE_VERIFY(n,w)
|
||||||
|
if (n > 0) {
|
||||||
|
secp256k1_ge_from_storage(r, &pre[(n-1)/2]);
|
||||||
|
} else {
|
||||||
|
secp256k1_ge_from_storage(r, &pre[(-n-1)/2]);
|
||||||
|
secp256k1_fe_negate(&(r->y), &(r->y), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),
|
/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits),
|
||||||
* with the following guarantees:
|
* with the following guarantees:
|
||||||
@ -182,19 +209,16 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct secp256k1_strauss_point_state {
|
struct secp256k1_strauss_point_state {
|
||||||
secp256k1_scalar na_1, na_lam;
|
|
||||||
int wnaf_na_1[129];
|
int wnaf_na_1[129];
|
||||||
int wnaf_na_lam[129];
|
int wnaf_na_lam[129];
|
||||||
int bits_na_1;
|
int bits_na_1;
|
||||||
int bits_na_lam;
|
int bits_na_lam;
|
||||||
size_t input_pos;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct secp256k1_strauss_state {
|
struct secp256k1_strauss_state {
|
||||||
secp256k1_gej* prej;
|
/* aux is used to hold z-ratios, and then used to hold pre_a[i].x * BETA values. */
|
||||||
secp256k1_fe* zr;
|
secp256k1_fe* aux;
|
||||||
secp256k1_ge* pre_a;
|
secp256k1_ge* pre_a;
|
||||||
secp256k1_ge* pre_a_lam;
|
|
||||||
struct secp256k1_strauss_point_state* ps;
|
struct secp256k1_strauss_point_state* ps;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -212,17 +236,19 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
|
|||||||
size_t np;
|
size_t np;
|
||||||
size_t no = 0;
|
size_t no = 0;
|
||||||
|
|
||||||
|
secp256k1_fe_set_int(&Z, 1);
|
||||||
for (np = 0; np < num; ++np) {
|
for (np = 0; np < num; ++np) {
|
||||||
|
secp256k1_gej tmp;
|
||||||
|
secp256k1_scalar na_1, na_lam;
|
||||||
if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) {
|
if (secp256k1_scalar_is_zero(&na[np]) || secp256k1_gej_is_infinity(&a[np])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
state->ps[no].input_pos = np;
|
|
||||||
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
|
/* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */
|
||||||
secp256k1_scalar_split_lambda(&state->ps[no].na_1, &state->ps[no].na_lam, &na[np]);
|
secp256k1_scalar_split_lambda(&na_1, &na_lam, &na[np]);
|
||||||
|
|
||||||
/* build wnaf representation for na_1 and na_lam. */
|
/* build wnaf representation for na_1 and na_lam. */
|
||||||
state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &state->ps[no].na_1, WINDOW_A);
|
state->ps[no].bits_na_1 = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_1, 129, &na_1, WINDOW_A);
|
||||||
state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &state->ps[no].na_lam, WINDOW_A);
|
state->ps[no].bits_na_lam = secp256k1_ecmult_wnaf(state->ps[no].wnaf_na_lam, 129, &na_lam, WINDOW_A);
|
||||||
VERIFY_CHECK(state->ps[no].bits_na_1 <= 129);
|
VERIFY_CHECK(state->ps[no].bits_na_1 <= 129);
|
||||||
VERIFY_CHECK(state->ps[no].bits_na_lam <= 129);
|
VERIFY_CHECK(state->ps[no].bits_na_lam <= 129);
|
||||||
if (state->ps[no].bits_na_1 > bits) {
|
if (state->ps[no].bits_na_1 > bits) {
|
||||||
@ -231,40 +257,36 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
|
|||||||
if (state->ps[no].bits_na_lam > bits) {
|
if (state->ps[no].bits_na_lam > bits) {
|
||||||
bits = state->ps[no].bits_na_lam;
|
bits = state->ps[no].bits_na_lam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Calculate odd multiples of a.
|
||||||
|
* All multiples are brought to the same Z 'denominator', which is stored
|
||||||
|
* in Z. Due to secp256k1' isomorphism we can do all operations pretending
|
||||||
|
* that the Z coordinate was 1, use affine addition formulae, and correct
|
||||||
|
* the Z coordinate of the result once at the end.
|
||||||
|
* The exception is the precomputed G table points, which are actually
|
||||||
|
* affine. Compared to the base used for other points, they have a Z ratio
|
||||||
|
* of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same
|
||||||
|
* isomorphism to efficiently add with a known Z inverse.
|
||||||
|
*/
|
||||||
|
tmp = a[np];
|
||||||
|
if (no) {
|
||||||
|
#ifdef VERIFY
|
||||||
|
secp256k1_fe_normalize_var(&Z);
|
||||||
|
#endif
|
||||||
|
secp256k1_gej_rescale(&tmp, &Z);
|
||||||
|
}
|
||||||
|
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp);
|
||||||
|
if (no) secp256k1_fe_mul(state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &(a[np].z));
|
||||||
|
|
||||||
++no;
|
++no;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate odd multiples of a.
|
/* Bring them to the same Z denominator. */
|
||||||
* All multiples are brought to the same Z 'denominator', which is stored
|
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux);
|
||||||
* in Z. Due to secp256k1' isomorphism we can do all operations pretending
|
|
||||||
* that the Z coordinate was 1, use affine addition formulae, and correct
|
|
||||||
* the Z coordinate of the result once at the end.
|
|
||||||
* The exception is the precomputed G table points, which are actually
|
|
||||||
* affine. Compared to the base used for other points, they have a Z ratio
|
|
||||||
* of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same
|
|
||||||
* isomorphism to efficiently add with a known Z inverse.
|
|
||||||
*/
|
|
||||||
if (no > 0) {
|
|
||||||
/* Compute the odd multiples in Jacobian form. */
|
|
||||||
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej, state->zr, &a[state->ps[0].input_pos]);
|
|
||||||
for (np = 1; np < no; ++np) {
|
|
||||||
secp256k1_gej tmp = a[state->ps[np].input_pos];
|
|
||||||
#ifdef VERIFY
|
|
||||||
secp256k1_fe_normalize_var(&(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
|
|
||||||
#endif
|
|
||||||
secp256k1_gej_rescale(&tmp, &(state->prej[(np - 1) * ECMULT_TABLE_SIZE(WINDOW_A) + ECMULT_TABLE_SIZE(WINDOW_A) - 1].z));
|
|
||||||
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->prej + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &tmp);
|
|
||||||
secp256k1_fe_mul(state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), state->zr + np * ECMULT_TABLE_SIZE(WINDOW_A), &(a[state->ps[np].input_pos].z));
|
|
||||||
}
|
|
||||||
/* Bring them to the same Z denominator. */
|
|
||||||
secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, &Z, state->prej, state->zr);
|
|
||||||
} else {
|
|
||||||
secp256k1_fe_set_int(&Z, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (np = 0; np < no; ++np) {
|
for (np = 0; np < no; ++np) {
|
||||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||||
secp256k1_ge_mul_lambda(&state->pre_a_lam[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i]);
|
secp256k1_fe_mul(&state->aux[np * ECMULT_TABLE_SIZE(WINDOW_A) + i], &state->pre_a[np * ECMULT_TABLE_SIZE(WINDOW_A) + i].x, &secp256k1_const_beta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,20 +312,20 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
|
|||||||
secp256k1_gej_double_var(r, r, NULL);
|
secp256k1_gej_double_var(r, r, NULL);
|
||||||
for (np = 0; np < no; ++np) {
|
for (np = 0; np < no; ++np) {
|
||||||
if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) {
|
if (i < state->ps[np].bits_na_1 && (n = state->ps[np].wnaf_na_1[i])) {
|
||||||
ECMULT_TABLE_GET_GE(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
|
secp256k1_ecmult_table_get_ge(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
|
||||||
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
|
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
|
||||||
}
|
}
|
||||||
if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) {
|
if (i < state->ps[np].bits_na_lam && (n = state->ps[np].wnaf_na_lam[i])) {
|
||||||
ECMULT_TABLE_GET_GE(&tmpa, state->pre_a_lam + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
|
secp256k1_ecmult_table_get_ge_lambda(&tmpa, state->pre_a + np * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + np * ECMULT_TABLE_SIZE(WINDOW_A), n, WINDOW_A);
|
||||||
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
|
secp256k1_gej_add_ge_var(r, r, &tmpa, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
|
if (i < bits_ng_1 && (n = wnaf_ng_1[i])) {
|
||||||
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, secp256k1_pre_g, n, WINDOW_G);
|
secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g, n, WINDOW_G);
|
||||||
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
||||||
}
|
}
|
||||||
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
|
if (i < bits_ng_128 && (n = wnaf_ng_128[i])) {
|
||||||
ECMULT_TABLE_GET_GE_STORAGE(&tmpa, secp256k1_pre_g_128, n, WINDOW_G);
|
secp256k1_ecmult_table_get_ge_storage(&tmpa, secp256k1_pre_g_128, n, WINDOW_G);
|
||||||
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,23 +336,19 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
|
static void secp256k1_ecmult(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) {
|
||||||
secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)];
|
secp256k1_fe aux[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||||
secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
|
|
||||||
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
|
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||||
struct secp256k1_strauss_point_state ps[1];
|
struct secp256k1_strauss_point_state ps[1];
|
||||||
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
|
||||||
struct secp256k1_strauss_state state;
|
struct secp256k1_strauss_state state;
|
||||||
|
|
||||||
state.prej = prej;
|
state.aux = aux;
|
||||||
state.zr = zr;
|
|
||||||
state.pre_a = pre_a;
|
state.pre_a = pre_a;
|
||||||
state.pre_a_lam = pre_a_lam;
|
|
||||||
state.ps = ps;
|
state.ps = ps;
|
||||||
secp256k1_ecmult_strauss_wnaf(&state, r, 1, a, na, ng);
|
secp256k1_ecmult_strauss_wnaf(&state, r, 1, a, na, ng);
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t secp256k1_strauss_scratch_size(size_t n_points) {
|
static size_t secp256k1_strauss_scratch_size(size_t n_points) {
|
||||||
static const size_t point_size = (2 * sizeof(secp256k1_ge) + sizeof(secp256k1_gej) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
|
static const size_t point_size = (sizeof(secp256k1_ge) + sizeof(secp256k1_fe)) * ECMULT_TABLE_SIZE(WINDOW_A) + sizeof(struct secp256k1_strauss_point_state) + sizeof(secp256k1_gej) + sizeof(secp256k1_scalar);
|
||||||
return n_points*point_size;
|
return n_points*point_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,13 +369,11 @@ static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callba
|
|||||||
* constant and strauss_scratch_size accordingly. */
|
* constant and strauss_scratch_size accordingly. */
|
||||||
points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej));
|
points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej));
|
||||||
scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar));
|
scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar));
|
||||||
state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej));
|
state.aux = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
|
||||||
state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
|
|
||||||
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
|
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
|
||||||
state.pre_a_lam = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
|
|
||||||
state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state));
|
state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state));
|
||||||
|
|
||||||
if (points == NULL || scalars == NULL || state.prej == NULL || state.zr == NULL || state.pre_a == NULL || state.pre_a_lam == NULL || state.ps == NULL) {
|
if (points == NULL || scalars == NULL || state.aux == NULL || state.pre_a == NULL || state.ps == NULL) {
|
||||||
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
15
src/field.h
15
src/field.h
@ -32,6 +32,12 @@
|
|||||||
#error "Please select wide multiplication implementation"
|
#error "Please select wide multiplication implementation"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
|
||||||
|
static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
|
||||||
|
0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
|
||||||
|
0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
|
||||||
|
);
|
||||||
|
|
||||||
/** Normalize a field element. This brings the field element to a canonical representation, reduces
|
/** Normalize a field element. This brings the field element to a canonical representation, reduces
|
||||||
* its magnitude to 1, and reduces it modulo field size `p`.
|
* its magnitude to 1, and reduces it modulo field size `p`.
|
||||||
*/
|
*/
|
||||||
@ -127,4 +133,13 @@ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_f
|
|||||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
|
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
|
||||||
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
||||||
|
|
||||||
|
/** Halves the value of a field element modulo the field prime. Constant-time.
|
||||||
|
* For an input magnitude 'm', the output magnitude is set to 'floor(m/2) + 1'.
|
||||||
|
* The output is not guaranteed to be normalized, regardless of the input. */
|
||||||
|
static void secp256k1_fe_half(secp256k1_fe *r);
|
||||||
|
|
||||||
|
/** Sets each limb of 'r' to its upper bound at magnitude 'm'. The output will also have its
|
||||||
|
* magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */
|
||||||
|
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
|
||||||
|
|
||||||
#endif /* SECP256K1_FIELD_H */
|
#endif /* SECP256K1_FIELD_H */
|
||||||
|
@ -49,6 +49,26 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
|
||||||
|
VERIFY_CHECK(m >= 0);
|
||||||
|
VERIFY_CHECK(m <= 2048);
|
||||||
|
r->n[0] = 0x3FFFFFFUL * 2 * m;
|
||||||
|
r->n[1] = 0x3FFFFFFUL * 2 * m;
|
||||||
|
r->n[2] = 0x3FFFFFFUL * 2 * m;
|
||||||
|
r->n[3] = 0x3FFFFFFUL * 2 * m;
|
||||||
|
r->n[4] = 0x3FFFFFFUL * 2 * m;
|
||||||
|
r->n[5] = 0x3FFFFFFUL * 2 * m;
|
||||||
|
r->n[6] = 0x3FFFFFFUL * 2 * m;
|
||||||
|
r->n[7] = 0x3FFFFFFUL * 2 * m;
|
||||||
|
r->n[8] = 0x3FFFFFFUL * 2 * m;
|
||||||
|
r->n[9] = 0x03FFFFFUL * 2 * m;
|
||||||
|
#ifdef VERIFY
|
||||||
|
r->magnitude = m;
|
||||||
|
r->normalized = (m == 0);
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void secp256k1_fe_normalize(secp256k1_fe *r) {
|
static void secp256k1_fe_normalize(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],
|
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];
|
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
|
||||||
@ -1133,6 +1153,82 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SECP256K1_INLINE void secp256k1_fe_half(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];
|
||||||
|
uint32_t one = (uint32_t)1;
|
||||||
|
uint32_t mask = -(t0 & one) >> 6;
|
||||||
|
|
||||||
|
#ifdef VERIFY
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
VERIFY_CHECK(r->magnitude < 32);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Bounds analysis (over the rationals).
|
||||||
|
*
|
||||||
|
* Let m = r->magnitude
|
||||||
|
* C = 0x3FFFFFFUL * 2
|
||||||
|
* D = 0x03FFFFFUL * 2
|
||||||
|
*
|
||||||
|
* Initial bounds: t0..t8 <= C * m
|
||||||
|
* t9 <= D * m
|
||||||
|
*/
|
||||||
|
|
||||||
|
t0 += 0x3FFFC2FUL & mask;
|
||||||
|
t1 += 0x3FFFFBFUL & mask;
|
||||||
|
t2 += mask;
|
||||||
|
t3 += mask;
|
||||||
|
t4 += mask;
|
||||||
|
t5 += mask;
|
||||||
|
t6 += mask;
|
||||||
|
t7 += mask;
|
||||||
|
t8 += mask;
|
||||||
|
t9 += mask >> 4;
|
||||||
|
|
||||||
|
VERIFY_CHECK((t0 & one) == 0);
|
||||||
|
|
||||||
|
/* t0..t8: added <= C/2
|
||||||
|
* t9: added <= D/2
|
||||||
|
*
|
||||||
|
* Current bounds: t0..t8 <= C * (m + 1/2)
|
||||||
|
* t9 <= D * (m + 1/2)
|
||||||
|
*/
|
||||||
|
|
||||||
|
r->n[0] = (t0 >> 1) + ((t1 & one) << 25);
|
||||||
|
r->n[1] = (t1 >> 1) + ((t2 & one) << 25);
|
||||||
|
r->n[2] = (t2 >> 1) + ((t3 & one) << 25);
|
||||||
|
r->n[3] = (t3 >> 1) + ((t4 & one) << 25);
|
||||||
|
r->n[4] = (t4 >> 1) + ((t5 & one) << 25);
|
||||||
|
r->n[5] = (t5 >> 1) + ((t6 & one) << 25);
|
||||||
|
r->n[6] = (t6 >> 1) + ((t7 & one) << 25);
|
||||||
|
r->n[7] = (t7 >> 1) + ((t8 & one) << 25);
|
||||||
|
r->n[8] = (t8 >> 1) + ((t9 & one) << 25);
|
||||||
|
r->n[9] = (t9 >> 1);
|
||||||
|
|
||||||
|
/* t0..t8: shifted right and added <= C/4 + 1/2
|
||||||
|
* t9: shifted right
|
||||||
|
*
|
||||||
|
* Current bounds: t0..t8 <= C * (m/2 + 1/2)
|
||||||
|
* t9 <= D * (m/2 + 1/4)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef VERIFY
|
||||||
|
/* Therefore the output magnitude (M) has to be set such that:
|
||||||
|
* t0..t8: C * M >= C * (m/2 + 1/2)
|
||||||
|
* t9: D * M >= D * (m/2 + 1/4)
|
||||||
|
*
|
||||||
|
* It suffices for all limbs that, for any input magnitude m:
|
||||||
|
* M >= m/2 + 1/2
|
||||||
|
*
|
||||||
|
* and since we want the smallest such integer value for M:
|
||||||
|
* M == floor(m/2) + 1
|
||||||
|
*/
|
||||||
|
r->magnitude = (r->magnitude >> 1) + 1;
|
||||||
|
r->normalized = 0;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
|
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
|
||||||
uint32_t mask0, mask1;
|
uint32_t mask0, mask1;
|
||||||
VG_CHECK_VERIFY(r->n, sizeof(r->n));
|
VG_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||||
|
@ -58,6 +58,21 @@ static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
|
||||||
|
VERIFY_CHECK(m >= 0);
|
||||||
|
VERIFY_CHECK(m <= 2048);
|
||||||
|
r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m;
|
||||||
|
r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m;
|
||||||
|
r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m;
|
||||||
|
r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m;
|
||||||
|
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m;
|
||||||
|
#ifdef VERIFY
|
||||||
|
r->magnitude = m;
|
||||||
|
r->normalized = (m == 0);
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void secp256k1_fe_normalize(secp256k1_fe *r) {
|
static void secp256k1_fe_normalize(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];
|
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
|
||||||
|
|
||||||
@ -477,6 +492,71 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SECP256K1_INLINE void secp256k1_fe_half(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];
|
||||||
|
uint64_t one = (uint64_t)1;
|
||||||
|
uint64_t mask = -(t0 & one) >> 12;
|
||||||
|
|
||||||
|
#ifdef VERIFY
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
VERIFY_CHECK(r->magnitude < 32);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Bounds analysis (over the rationals).
|
||||||
|
*
|
||||||
|
* Let m = r->magnitude
|
||||||
|
* C = 0xFFFFFFFFFFFFFULL * 2
|
||||||
|
* D = 0x0FFFFFFFFFFFFULL * 2
|
||||||
|
*
|
||||||
|
* Initial bounds: t0..t3 <= C * m
|
||||||
|
* t4 <= D * m
|
||||||
|
*/
|
||||||
|
|
||||||
|
t0 += 0xFFFFEFFFFFC2FULL & mask;
|
||||||
|
t1 += mask;
|
||||||
|
t2 += mask;
|
||||||
|
t3 += mask;
|
||||||
|
t4 += mask >> 4;
|
||||||
|
|
||||||
|
VERIFY_CHECK((t0 & one) == 0);
|
||||||
|
|
||||||
|
/* t0..t3: added <= C/2
|
||||||
|
* t4: added <= D/2
|
||||||
|
*
|
||||||
|
* Current bounds: t0..t3 <= C * (m + 1/2)
|
||||||
|
* t4 <= D * (m + 1/2)
|
||||||
|
*/
|
||||||
|
|
||||||
|
r->n[0] = (t0 >> 1) + ((t1 & one) << 51);
|
||||||
|
r->n[1] = (t1 >> 1) + ((t2 & one) << 51);
|
||||||
|
r->n[2] = (t2 >> 1) + ((t3 & one) << 51);
|
||||||
|
r->n[3] = (t3 >> 1) + ((t4 & one) << 51);
|
||||||
|
r->n[4] = (t4 >> 1);
|
||||||
|
|
||||||
|
/* t0..t3: shifted right and added <= C/4 + 1/2
|
||||||
|
* t4: shifted right
|
||||||
|
*
|
||||||
|
* Current bounds: t0..t3 <= C * (m/2 + 1/2)
|
||||||
|
* t4 <= D * (m/2 + 1/4)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef VERIFY
|
||||||
|
/* Therefore the output magnitude (M) has to be set such that:
|
||||||
|
* t0..t3: C * M >= C * (m/2 + 1/2)
|
||||||
|
* t4: D * M >= D * (m/2 + 1/4)
|
||||||
|
*
|
||||||
|
* It suffices for all limbs that, for any input magnitude m:
|
||||||
|
* M >= m/2 + 1/2
|
||||||
|
*
|
||||||
|
* and since we want the smallest such integer value for M:
|
||||||
|
* M == floor(m/2) + 1
|
||||||
|
*/
|
||||||
|
r->magnitude = (r->magnitude >> 1) + 1;
|
||||||
|
r->normalized = 0;
|
||||||
|
secp256k1_fe_verify(r);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
|
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
|
||||||
uint64_t mask0, mask1;
|
uint64_t mask0, mask1;
|
||||||
VG_CHECK_VERIFY(r->n, sizeof(r->n));
|
VG_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||||
|
@ -140,6 +140,4 @@ static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
|
|||||||
return secp256k1_fe_sqrt(&r, a);
|
return secp256k1_fe_sqrt(&r, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
|
|
||||||
|
|
||||||
#endif /* SECP256K1_FIELD_IMPL_H */
|
#endif /* SECP256K1_FIELD_IMPL_H */
|
||||||
|
33
src/group.h
33
src/group.h
@ -9,7 +9,10 @@
|
|||||||
|
|
||||||
#include "field.h"
|
#include "field.h"
|
||||||
|
|
||||||
/** A group element of the secp256k1 curve, in affine coordinates. */
|
/** A group element in affine coordinates on the secp256k1 curve,
|
||||||
|
* or occasionally on an isomorphic curve of the form y^2 = x^3 + 7*t^6.
|
||||||
|
* Note: For exhaustive test mode, secp256k1 is replaced by a small subgroup of a different curve.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
secp256k1_fe x;
|
secp256k1_fe x;
|
||||||
secp256k1_fe y;
|
secp256k1_fe y;
|
||||||
@ -19,7 +22,9 @@ typedef struct {
|
|||||||
#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0}
|
#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0}
|
||||||
#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
|
#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
|
||||||
|
|
||||||
/** A group element of the secp256k1 curve, in jacobian coordinates. */
|
/** A group element of the secp256k1 curve, in jacobian coordinates.
|
||||||
|
* Note: For exhastive test mode, sepc256k1 is replaced by a small subgroup of a different curve.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
secp256k1_fe x; /* actual X: x/z^2 */
|
secp256k1_fe x; /* actual X: x/z^2 */
|
||||||
secp256k1_fe y; /* actual Y: y/z^3 */
|
secp256k1_fe y; /* actual Y: y/z^3 */
|
||||||
@ -70,12 +75,24 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a);
|
|||||||
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
|
/** Set 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);
|
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
|
||||||
|
|
||||||
/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
|
/** Bring a batch of inputs to the same global z "denominator", based on ratios between
|
||||||
* the same global z "denominator". zr must contain the known z-ratios such
|
* (omitted) z coordinates of adjacent elements.
|
||||||
* that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y
|
*
|
||||||
* coordinates of the result are stored in r, the common z coordinate is
|
* Although the elements a[i] are _ge rather than _gej, they actually represent elements
|
||||||
* stored in globalz. */
|
* in Jacobian coordinates with their z coordinates omitted.
|
||||||
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr);
|
*
|
||||||
|
* Using the notation z(b) to represent the omitted z coordinate of b, the array zr of
|
||||||
|
* z coordinate ratios must satisfy zr[i] == z(a[i]) / z(a[i-1]) for 0 < 'i' < len.
|
||||||
|
* The zr[0] value is unused.
|
||||||
|
*
|
||||||
|
* This function adjusts the coordinates of 'a' in place so that for all 'i', z(a[i]) == z(a[len-1]).
|
||||||
|
* In other words, the initial value of z(a[len-1]) becomes the global z "denominator". Only the
|
||||||
|
* a[i].x and a[i].y coordinates are explicitly modified; the adjustment of the omitted z coordinate is
|
||||||
|
* implicit.
|
||||||
|
*
|
||||||
|
* The coordinates of the final element a[len-1] are not changed.
|
||||||
|
*/
|
||||||
|
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr);
|
||||||
|
|
||||||
/** Set a group element (affine) equal to the point at infinity. */
|
/** Set a group element (affine) equal to the point at infinity. */
|
||||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r);
|
static void secp256k1_ge_set_infinity(secp256k1_ge *r);
|
||||||
|
115
src/group_impl.h
115
src/group_impl.h
@ -161,27 +161,26 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) {
|
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr) {
|
||||||
size_t i = len - 1;
|
size_t i = len - 1;
|
||||||
secp256k1_fe zs;
|
secp256k1_fe zs;
|
||||||
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
/* The z of the final point gives us the "global Z" for the table. */
|
|
||||||
r[i].x = a[i].x;
|
|
||||||
r[i].y = a[i].y;
|
|
||||||
/* Ensure all y values are in weak normal form for fast negation of points */
|
/* Ensure all y values are in weak normal form for fast negation of points */
|
||||||
secp256k1_fe_normalize_weak(&r[i].y);
|
secp256k1_fe_normalize_weak(&a[i].y);
|
||||||
*globalz = a[i].z;
|
|
||||||
r[i].infinity = 0;
|
|
||||||
zs = zr[i];
|
zs = zr[i];
|
||||||
|
|
||||||
/* Work our way backwards, using the z-ratios to scale the x/y values. */
|
/* Work our way backwards, using the z-ratios to scale the x/y values. */
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
|
secp256k1_gej tmpa;
|
||||||
if (i != len - 1) {
|
if (i != len - 1) {
|
||||||
secp256k1_fe_mul(&zs, &zs, &zr[i]);
|
secp256k1_fe_mul(&zs, &zs, &zr[i]);
|
||||||
}
|
}
|
||||||
i--;
|
i--;
|
||||||
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs);
|
tmpa.x = a[i].x;
|
||||||
|
tmpa.y = a[i].y;
|
||||||
|
tmpa.infinity = 0;
|
||||||
|
secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,37 +275,35 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) {
|
static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) {
|
||||||
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
|
/* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */
|
||||||
*
|
secp256k1_fe l, s, t;
|
||||||
* Note that there is an implementation described at
|
|
||||||
* https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
|
|
||||||
* which trades a multiply for a square, but in practice this is actually slower,
|
|
||||||
* mainly because it requires more normalizations.
|
|
||||||
*/
|
|
||||||
secp256k1_fe t1,t2,t3,t4;
|
|
||||||
|
|
||||||
r->infinity = a->infinity;
|
r->infinity = a->infinity;
|
||||||
|
|
||||||
secp256k1_fe_mul(&r->z, &a->z, &a->y);
|
/* Formula used:
|
||||||
secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
|
* L = (3/2) * X1^2
|
||||||
secp256k1_fe_sqr(&t1, &a->x);
|
* S = Y1^2
|
||||||
secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */
|
* T = -X1*S
|
||||||
secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */
|
* X3 = L^2 + 2*T
|
||||||
secp256k1_fe_sqr(&t3, &a->y);
|
* Y3 = -(L*(X3 + T) + S^2)
|
||||||
secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */
|
* Z3 = Y1*Z1
|
||||||
secp256k1_fe_sqr(&t4, &t3);
|
*/
|
||||||
secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */
|
|
||||||
secp256k1_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */
|
secp256k1_fe_mul(&r->z, &a->z, &a->y); /* Z3 = Y1*Z1 (1) */
|
||||||
r->x = t3;
|
secp256k1_fe_sqr(&s, &a->y); /* S = Y1^2 (1) */
|
||||||
secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */
|
secp256k1_fe_sqr(&l, &a->x); /* L = X1^2 (1) */
|
||||||
secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */
|
secp256k1_fe_mul_int(&l, 3); /* L = 3*X1^2 (3) */
|
||||||
secp256k1_fe_add(&r->x, &t2); /* X' = 9*X^4 - 8*X*Y^2 (6) */
|
secp256k1_fe_half(&l); /* L = 3/2*X1^2 (2) */
|
||||||
secp256k1_fe_negate(&t2, &t2, 1); /* T2 = -9*X^4 (2) */
|
secp256k1_fe_negate(&t, &s, 1); /* T = -S (2) */
|
||||||
secp256k1_fe_mul_int(&t3, 6); /* T3 = 12*X*Y^2 (6) */
|
secp256k1_fe_mul(&t, &t, &a->x); /* T = -X1*S (1) */
|
||||||
secp256k1_fe_add(&t3, &t2); /* T3 = 12*X*Y^2 - 9*X^4 (8) */
|
secp256k1_fe_sqr(&r->x, &l); /* X3 = L^2 (1) */
|
||||||
secp256k1_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */
|
secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + T (2) */
|
||||||
secp256k1_fe_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */
|
secp256k1_fe_add(&r->x, &t); /* X3 = L^2 + 2*T (3) */
|
||||||
secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
|
secp256k1_fe_sqr(&s, &s); /* S' = S^2 (1) */
|
||||||
|
secp256k1_fe_add(&t, &r->x); /* T' = X3 + T (4) */
|
||||||
|
secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */
|
||||||
|
secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */
|
||||||
|
secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
|
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
|
||||||
@ -331,7 +328,6 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
|
|||||||
if (rzr != NULL) {
|
if (rzr != NULL) {
|
||||||
*rzr = a->y;
|
*rzr = a->y;
|
||||||
secp256k1_fe_normalize_weak(rzr);
|
secp256k1_fe_normalize_weak(rzr);
|
||||||
secp256k1_fe_mul_int(rzr, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
secp256k1_gej_double(r, a);
|
secp256k1_gej_double(r, a);
|
||||||
@ -497,8 +493,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
|
|||||||
|
|
||||||
|
|
||||||
static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) {
|
static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) {
|
||||||
/* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */
|
/* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */
|
||||||
static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
|
|
||||||
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
|
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
|
||||||
secp256k1_fe m_alt, rr_alt;
|
secp256k1_fe m_alt, rr_alt;
|
||||||
int infinity, degenerate;
|
int infinity, degenerate;
|
||||||
@ -519,11 +514,11 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
|||||||
* Z = Z1*Z2
|
* Z = Z1*Z2
|
||||||
* T = U1+U2
|
* T = U1+U2
|
||||||
* M = S1+S2
|
* M = S1+S2
|
||||||
* Q = T*M^2
|
* Q = -T*M^2
|
||||||
* R = T^2-U1*U2
|
* R = T^2-U1*U2
|
||||||
* X3 = 4*(R^2-Q)
|
* X3 = R^2+Q
|
||||||
* Y3 = 4*(R*(3*Q-2*R^2)-M^4)
|
* Y3 = -(R*(2*X3+Q)+M^4)/2
|
||||||
* Z3 = 2*M*Z
|
* Z3 = M*Z
|
||||||
* (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.)
|
* (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.)
|
||||||
*
|
*
|
||||||
* This formula has the benefit of being the same for both addition
|
* This formula has the benefit of being the same for both addition
|
||||||
@ -587,7 +582,8 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
|||||||
* and denominator of lambda; R and M represent the explicit
|
* and denominator of lambda; R and M represent the explicit
|
||||||
* expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
|
* expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
|
||||||
secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */
|
secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */
|
||||||
secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */
|
secp256k1_fe_negate(&q, &t, 2); /* q = -T (3) */
|
||||||
|
secp256k1_fe_mul(&q, &q, &n); /* q = Q = -T*Malt^2 (1) */
|
||||||
/* These two lines use the observation that either M == Malt or M == 0,
|
/* These two lines use the observation that either M == Malt or M == 0,
|
||||||
* so M^3 * Malt is either Malt^4 (which is computed by squaring), or
|
* so M^3 * Malt is either Malt^4 (which is computed by squaring), or
|
||||||
* zero (which is "computed" by cmov). So the cost is one squaring
|
* zero (which is "computed" by cmov). So the cost is one squaring
|
||||||
@ -595,26 +591,21 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
|||||||
secp256k1_fe_sqr(&n, &n);
|
secp256k1_fe_sqr(&n, &n);
|
||||||
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
|
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
|
||||||
secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
|
secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
|
||||||
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */
|
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */
|
||||||
infinity = secp256k1_fe_normalizes_to_zero(&r->z) & ~a->infinity;
|
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_add(&t, &q); /* t = Ralt^2 + Q (2) */
|
||||||
secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */
|
r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */
|
||||||
secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */
|
secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */
|
||||||
secp256k1_fe_normalize_weak(&t);
|
secp256k1_fe_add(&t, &q); /* t = 2*X3 + Q (5) */
|
||||||
r->x = t; /* r->x = Ralt^2-Q (1) */
|
secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */
|
||||||
secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */
|
secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (3) */
|
||||||
secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */
|
secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */
|
||||||
secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */
|
secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */
|
||||||
secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */
|
|
||||||
secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */
|
|
||||||
secp256k1_fe_normalize_weak(&r->y);
|
|
||||||
secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */
|
|
||||||
secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */
|
|
||||||
|
|
||||||
/** In case a->infinity == 1, replace r with (b->x, b->y, 1). */
|
/** In case a->infinity == 1, replace r with (b->x, b->y, 1). */
|
||||||
secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
|
secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
|
||||||
secp256k1_fe_cmov(&r->y, &b->y, a->infinity);
|
secp256k1_fe_cmov(&r->y, &b->y, a->infinity);
|
||||||
secp256k1_fe_cmov(&r->z, &fe_1, a->infinity);
|
secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity);
|
||||||
r->infinity = infinity;
|
r->infinity = infinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -660,12 +651,8 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
|
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
|
||||||
static const secp256k1_fe beta = SECP256K1_FE_CONST(
|
|
||||||
0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
|
|
||||||
0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
|
|
||||||
);
|
|
||||||
*r = *a;
|
*r = *a;
|
||||||
secp256k1_fe_mul(&r->x, &r->x, &beta);
|
secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
|
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t s[8];
|
uint32_t s[8];
|
||||||
uint32_t buf[16]; /* In big endian */
|
unsigned char buf[64];
|
||||||
size_t bytes;
|
uint64_t bytes;
|
||||||
} secp256k1_sha256;
|
} secp256k1_sha256;
|
||||||
|
|
||||||
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
|
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
|
||||||
|
@ -28,12 +28,6 @@
|
|||||||
(h) = t1 + t2; \
|
(h) = t1 + t2; \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#if defined(SECP256K1_BIG_ENDIAN)
|
|
||||||
#define BE32(x) (x)
|
|
||||||
#elif defined(SECP256K1_LITTLE_ENDIAN)
|
|
||||||
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
|
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
|
||||||
hash->s[0] = 0x6a09e667ul;
|
hash->s[0] = 0x6a09e667ul;
|
||||||
hash->s[1] = 0xbb67ae85ul;
|
hash->s[1] = 0xbb67ae85ul;
|
||||||
@ -47,26 +41,26 @@ static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */
|
/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */
|
||||||
static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {
|
static void secp256k1_sha256_transform(uint32_t* s, const unsigned char* buf) {
|
||||||
uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
|
uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7];
|
||||||
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
|
uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15;
|
||||||
|
|
||||||
Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0]));
|
Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = secp256k1_read_be32(&buf[0]));
|
||||||
Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1]));
|
Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = secp256k1_read_be32(&buf[4]));
|
||||||
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2]));
|
Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = secp256k1_read_be32(&buf[8]));
|
||||||
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3]));
|
Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = secp256k1_read_be32(&buf[12]));
|
||||||
Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4]));
|
Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = secp256k1_read_be32(&buf[16]));
|
||||||
Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5]));
|
Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = secp256k1_read_be32(&buf[20]));
|
||||||
Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6]));
|
Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = secp256k1_read_be32(&buf[24]));
|
||||||
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7]));
|
Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = secp256k1_read_be32(&buf[28]));
|
||||||
Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8]));
|
Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = secp256k1_read_be32(&buf[32]));
|
||||||
Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9]));
|
Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = secp256k1_read_be32(&buf[36]));
|
||||||
Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10]));
|
Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = secp256k1_read_be32(&buf[40]));
|
||||||
Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11]));
|
Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = secp256k1_read_be32(&buf[44]));
|
||||||
Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12]));
|
Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = secp256k1_read_be32(&buf[48]));
|
||||||
Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13]));
|
Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = secp256k1_read_be32(&buf[52]));
|
||||||
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14]));
|
Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = secp256k1_read_be32(&buf[56]));
|
||||||
Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15]));
|
Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = secp256k1_read_be32(&buf[60]));
|
||||||
|
|
||||||
Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
|
Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1));
|
||||||
Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
|
Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2));
|
||||||
@ -136,7 +130,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
|
|||||||
while (len >= 64 - bufsize) {
|
while (len >= 64 - bufsize) {
|
||||||
/* Fill the buffer, and process it. */
|
/* Fill the buffer, and process it. */
|
||||||
size_t chunk_len = 64 - bufsize;
|
size_t chunk_len = 64 - bufsize;
|
||||||
memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len);
|
memcpy(hash->buf + bufsize, data, chunk_len);
|
||||||
data += chunk_len;
|
data += chunk_len;
|
||||||
len -= chunk_len;
|
len -= chunk_len;
|
||||||
secp256k1_sha256_transform(hash->s, hash->buf);
|
secp256k1_sha256_transform(hash->s, hash->buf);
|
||||||
@ -149,19 +143,19 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
|
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
|
||||||
static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
static const unsigned char pad[64] = {0x80};
|
||||||
uint32_t sizedesc[2];
|
unsigned char sizedesc[8];
|
||||||
uint32_t out[8];
|
int i;
|
||||||
int i = 0;
|
/* The maximum message size of SHA256 is 2^64-1 bits. */
|
||||||
sizedesc[0] = BE32(hash->bytes >> 29);
|
VERIFY_CHECK(hash->bytes < ((uint64_t)1 << 61));
|
||||||
sizedesc[1] = BE32(hash->bytes << 3);
|
secp256k1_write_be32(&sizedesc[0], hash->bytes >> 29);
|
||||||
|
secp256k1_write_be32(&sizedesc[4], hash->bytes << 3);
|
||||||
secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
|
secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64));
|
||||||
secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8);
|
secp256k1_sha256_write(hash, sizedesc, 8);
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
out[i] = BE32(hash->s[i]);
|
secp256k1_write_be32(&out32[4*i], hash->s[i]);
|
||||||
hash->s[i] = 0;
|
hash->s[i] = 0;
|
||||||
}
|
}
|
||||||
memcpy(out32, (const unsigned char*)out, 32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initializes a sha256 struct and writes the 64 byte string
|
/* Initializes a sha256 struct and writes the 64 byte string
|
||||||
@ -285,7 +279,6 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
|
|||||||
rng->retry = 0;
|
rng->retry = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef BE32
|
|
||||||
#undef Round
|
#undef Round
|
||||||
#undef sigma1
|
#undef sigma1
|
||||||
#undef sigma0
|
#undef sigma0
|
||||||
|
@ -60,7 +60,7 @@ void test_ecdh_generator_basepoint(void) {
|
|||||||
|
|
||||||
s_one[31] = 1;
|
s_one[31] = 1;
|
||||||
/* Check against pubkey creation when the basepoint is the generator */
|
/* Check against pubkey creation when the basepoint is the generator */
|
||||||
for (i = 0; i < 100; ++i) {
|
for (i = 0; i < 2 * count; ++i) {
|
||||||
secp256k1_sha256 sha;
|
secp256k1_sha256 sha;
|
||||||
unsigned char s_b32[32];
|
unsigned char s_b32[32];
|
||||||
unsigned char output_ecdh[65];
|
unsigned char output_ecdh[65];
|
||||||
@ -123,10 +123,43 @@ void test_bad_scalar(void) {
|
|||||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
|
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */
|
||||||
|
void test_result_basepoint(void) {
|
||||||
|
secp256k1_pubkey point;
|
||||||
|
secp256k1_scalar rand;
|
||||||
|
unsigned char s[32];
|
||||||
|
unsigned char s_inv[32];
|
||||||
|
unsigned char out[32];
|
||||||
|
unsigned char out_inv[32];
|
||||||
|
unsigned char out_base[32];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
unsigned char s_one[32] = { 0 };
|
||||||
|
s_one[31] = 1;
|
||||||
|
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_one) == 1);
|
||||||
|
CHECK(secp256k1_ecdh(ctx, out_base, &point, s_one, NULL, NULL) == 1);
|
||||||
|
|
||||||
|
for (i = 0; i < 2 * count; i++) {
|
||||||
|
random_scalar_order(&rand);
|
||||||
|
secp256k1_scalar_get_b32(s, &rand);
|
||||||
|
secp256k1_scalar_inverse(&rand, &rand);
|
||||||
|
secp256k1_scalar_get_b32(s_inv, &rand);
|
||||||
|
|
||||||
|
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s) == 1);
|
||||||
|
CHECK(secp256k1_ecdh(ctx, out, &point, s_inv, NULL, NULL) == 1);
|
||||||
|
CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0);
|
||||||
|
|
||||||
|
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_inv) == 1);
|
||||||
|
CHECK(secp256k1_ecdh(ctx, out_inv, &point, s, NULL, NULL) == 1);
|
||||||
|
CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void run_ecdh_tests(void) {
|
void run_ecdh_tests(void) {
|
||||||
test_ecdh_api();
|
test_ecdh_api();
|
||||||
test_ecdh_generator_basepoint();
|
test_ecdh_generator_basepoint();
|
||||||
test_bad_scalar();
|
test_bad_scalar();
|
||||||
|
test_result_basepoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
|
#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
|
||||||
|
@ -192,11 +192,15 @@ static int secp256k1_schnorrsig_sign_internal(const secp256k1_context* ctx, unsi
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
|
int secp256k1_schnorrsig_sign32(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
|
||||||
/* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */
|
/* We cast away const from the passed aux_rand32 argument since we know the default nonce function does not modify it. */
|
||||||
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, secp256k1_nonce_function_bip340, (unsigned char*)aux_rand32);
|
return secp256k1_schnorrsig_sign_internal(ctx, sig64, msg32, 32, keypair, secp256k1_nonce_function_bip340, (unsigned char*)aux_rand32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, const unsigned char *aux_rand32) {
|
||||||
|
return secp256k1_schnorrsig_sign32(ctx, sig64, msg32, keypair, 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) {
|
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;
|
secp256k1_nonce_function_hardened noncefp = NULL;
|
||||||
void *ndata = NULL;
|
void *ndata = NULL;
|
||||||
|
@ -160,21 +160,21 @@ void test_schnorrsig_api(void) {
|
|||||||
|
|
||||||
/** main test body **/
|
/** main test body **/
|
||||||
ecount = 0;
|
ecount = 0;
|
||||||
CHECK(secp256k1_schnorrsig_sign(none, sig, msg, &keypairs[0], NULL) == 1);
|
CHECK(secp256k1_schnorrsig_sign32(none, sig, msg, &keypairs[0], NULL) == 1);
|
||||||
CHECK(ecount == 0);
|
CHECK(ecount == 0);
|
||||||
CHECK(secp256k1_schnorrsig_sign(vrfy, sig, msg, &keypairs[0], NULL) == 1);
|
CHECK(secp256k1_schnorrsig_sign32(vrfy, sig, msg, &keypairs[0], NULL) == 1);
|
||||||
CHECK(ecount == 0);
|
CHECK(ecount == 0);
|
||||||
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL) == 1);
|
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1);
|
||||||
CHECK(ecount == 0);
|
CHECK(ecount == 0);
|
||||||
CHECK(secp256k1_schnorrsig_sign(sign, NULL, msg, &keypairs[0], NULL) == 0);
|
CHECK(secp256k1_schnorrsig_sign32(sign, NULL, msg, &keypairs[0], NULL) == 0);
|
||||||
CHECK(ecount == 1);
|
CHECK(ecount == 1);
|
||||||
CHECK(secp256k1_schnorrsig_sign(sign, sig, NULL, &keypairs[0], NULL) == 0);
|
CHECK(secp256k1_schnorrsig_sign32(sign, sig, NULL, &keypairs[0], NULL) == 0);
|
||||||
CHECK(ecount == 2);
|
CHECK(ecount == 2);
|
||||||
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, NULL, NULL) == 0);
|
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, NULL, NULL) == 0);
|
||||||
CHECK(ecount == 3);
|
CHECK(ecount == 3);
|
||||||
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &invalid_keypair, NULL) == 0);
|
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &invalid_keypair, NULL) == 0);
|
||||||
CHECK(ecount == 4);
|
CHECK(ecount == 4);
|
||||||
CHECK(secp256k1_schnorrsig_sign(sttc, sig, msg, &keypairs[0], NULL) == 0);
|
CHECK(secp256k1_schnorrsig_sign32(sttc, sig, msg, &keypairs[0], NULL) == 0);
|
||||||
CHECK(ecount == 5);
|
CHECK(ecount == 5);
|
||||||
|
|
||||||
ecount = 0;
|
ecount = 0;
|
||||||
@ -202,7 +202,7 @@ void test_schnorrsig_api(void) {
|
|||||||
CHECK(ecount == 6);
|
CHECK(ecount == 6);
|
||||||
|
|
||||||
ecount = 0;
|
ecount = 0;
|
||||||
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL) == 1);
|
CHECK(secp256k1_schnorrsig_sign32(sign, sig, msg, &keypairs[0], NULL) == 1);
|
||||||
CHECK(secp256k1_schnorrsig_verify(none, sig, msg, sizeof(msg), &pk[0]) == 1);
|
CHECK(secp256k1_schnorrsig_verify(none, sig, msg, sizeof(msg), &pk[0]) == 1);
|
||||||
CHECK(ecount == 0);
|
CHECK(ecount == 0);
|
||||||
CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, sizeof(msg), &pk[0]) == 1);
|
CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, sizeof(msg), &pk[0]) == 1);
|
||||||
@ -247,7 +247,7 @@ void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const un
|
|||||||
secp256k1_xonly_pubkey pk, pk_expected;
|
secp256k1_xonly_pubkey pk, pk_expected;
|
||||||
|
|
||||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
|
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
|
||||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg32, &keypair, aux_rand));
|
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg32, &keypair, aux_rand));
|
||||||
CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
|
CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
|
||||||
|
|
||||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized));
|
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized));
|
||||||
@ -740,8 +740,11 @@ void test_schnorrsig_sign(void) {
|
|||||||
secp256k1_testrand256(aux_rand);
|
secp256k1_testrand256(aux_rand);
|
||||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
|
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
|
||||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
|
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
|
||||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL) == 1);
|
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1);
|
||||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk));
|
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &pk));
|
||||||
|
/* Check that deprecated alias gives the same result */
|
||||||
|
CHECK(secp256k1_schnorrsig_sign(ctx, sig2, msg, &keypair, NULL) == 1);
|
||||||
|
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
|
||||||
|
|
||||||
/* Test different nonce functions */
|
/* Test different nonce functions */
|
||||||
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
|
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
|
||||||
@ -764,7 +767,7 @@ void test_schnorrsig_sign(void) {
|
|||||||
extraparams.noncefp = NULL;
|
extraparams.noncefp = NULL;
|
||||||
extraparams.ndata = aux_rand;
|
extraparams.ndata = aux_rand;
|
||||||
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
|
CHECK(secp256k1_schnorrsig_sign_custom(ctx, sig, msg, sizeof(msg), &keypair, &extraparams) == 1);
|
||||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig2, msg, &keypair, extraparams.ndata) == 1);
|
CHECK(secp256k1_schnorrsig_sign32(ctx, sig2, msg, &keypair, extraparams.ndata) == 1);
|
||||||
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
|
CHECK(secp256k1_memcmp_var(sig, sig2, sizeof(sig)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,7 +790,7 @@ void test_schnorrsig_sign_verify(void) {
|
|||||||
|
|
||||||
for (i = 0; i < N_SIGS; i++) {
|
for (i = 0; i < N_SIGS; i++) {
|
||||||
secp256k1_testrand256(msg[i]);
|
secp256k1_testrand256(msg[i]);
|
||||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig[i], msg[i], &keypair, NULL));
|
CHECK(secp256k1_schnorrsig_sign32(ctx, sig[i], msg[i], &keypair, NULL));
|
||||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], sizeof(msg[i]), &pk));
|
CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], sizeof(msg[i]), &pk));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -816,13 +819,13 @@ void test_schnorrsig_sign_verify(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Test overflowing s */
|
/* Test overflowing s */
|
||||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL));
|
CHECK(secp256k1_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL));
|
||||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
|
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
|
||||||
memset(&sig[0][32], 0xFF, 32);
|
memset(&sig[0][32], 0xFF, 32);
|
||||||
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
|
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
|
||||||
|
|
||||||
/* Test negative s */
|
/* Test negative s */
|
||||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL));
|
CHECK(secp256k1_schnorrsig_sign32(ctx, sig[0], msg[0], &keypair, NULL));
|
||||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
|
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], sizeof(msg[0]), &pk));
|
||||||
secp256k1_scalar_set_b32(&s, &sig[0][32], NULL);
|
secp256k1_scalar_set_b32(&s, &sig[0][32], NULL);
|
||||||
secp256k1_scalar_negate(&s, &s);
|
secp256k1_scalar_negate(&s, &s);
|
||||||
@ -873,7 +876,7 @@ void test_schnorrsig_taproot(void) {
|
|||||||
|
|
||||||
/* Key spend */
|
/* Key spend */
|
||||||
secp256k1_testrand256(msg);
|
secp256k1_testrand256(msg);
|
||||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL) == 1);
|
CHECK(secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL) == 1);
|
||||||
/* Verify key spend */
|
/* Verify key spend */
|
||||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1);
|
CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1);
|
||||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &output_pk) == 1);
|
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, sizeof(msg), &output_pk) == 1);
|
||||||
|
@ -446,8 +446,12 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
|
|||||||
unsigned int offset = 0;
|
unsigned int offset = 0;
|
||||||
secp256k1_rfc6979_hmac_sha256 rng;
|
secp256k1_rfc6979_hmac_sha256 rng;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
secp256k1_scalar msg;
|
||||||
|
unsigned char msgmod32[32];
|
||||||
|
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||||
|
secp256k1_scalar_get_b32(msgmod32, &msg);
|
||||||
/* We feed a byte array to the PRNG as input, consisting of:
|
/* We feed a byte array to the PRNG as input, consisting of:
|
||||||
* - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d.
|
* - the private key (32 bytes) and reduced message (32 bytes), see RFC 6979 3.2d.
|
||||||
* - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.
|
* - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data.
|
||||||
* - optionally 16 extra bytes with the algorithm name.
|
* - optionally 16 extra bytes with the algorithm name.
|
||||||
* Because the arguments have distinct fixed lengths it is not possible for
|
* Because the arguments have distinct fixed lengths it is not possible for
|
||||||
@ -455,7 +459,7 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
|
|||||||
* nonces.
|
* nonces.
|
||||||
*/
|
*/
|
||||||
buffer_append(keydata, &offset, key32, 32);
|
buffer_append(keydata, &offset, key32, 32);
|
||||||
buffer_append(keydata, &offset, msg32, 32);
|
buffer_append(keydata, &offset, msgmod32, 32);
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
buffer_append(keydata, &offset, data, 32);
|
buffer_append(keydata, &offset, data, 32);
|
||||||
}
|
}
|
||||||
|
307
src/tests.c
307
src/tests.c
@ -28,6 +28,8 @@
|
|||||||
#include "modinv64_impl.h"
|
#include "modinv64_impl.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define CONDITIONAL_TEST(cnt, nam) if (count < (cnt)) { printf("Skipping %s (iteration count too low)\n", nam); } else
|
||||||
|
|
||||||
static int count = 64;
|
static int count = 64;
|
||||||
static secp256k1_context *ctx = NULL;
|
static secp256k1_context *ctx = NULL;
|
||||||
|
|
||||||
@ -495,14 +497,18 @@ void run_ctz_tests(void) {
|
|||||||
|
|
||||||
/***** HASH TESTS *****/
|
/***** HASH TESTS *****/
|
||||||
|
|
||||||
void run_sha256_tests(void) {
|
void run_sha256_known_output_tests(void) {
|
||||||
static const char *inputs[8] = {
|
static const char *inputs[] = {
|
||||||
"", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe",
|
"", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe",
|
||||||
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
|
||||||
"For this sample, this 63-byte string will be used as input data",
|
"For this sample, this 63-byte string will be used as input data",
|
||||||
"This is exactly 64 bytes long, not counting the terminating byte"
|
"This is exactly 64 bytes long, not counting the terminating byte",
|
||||||
|
"aaaaa",
|
||||||
};
|
};
|
||||||
static const unsigned char outputs[8][32] = {
|
static const unsigned int repeat[] = {
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, 1000000/5
|
||||||
|
};
|
||||||
|
static const unsigned char outputs[][32] = {
|
||||||
{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55},
|
{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55},
|
||||||
{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad},
|
{0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad},
|
||||||
{0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50},
|
{0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50},
|
||||||
@ -510,27 +516,146 @@ void run_sha256_tests(void) {
|
|||||||
{0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30},
|
{0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30},
|
||||||
{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1},
|
{0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1},
|
||||||
{0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42},
|
{0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42},
|
||||||
{0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8}
|
{0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8},
|
||||||
|
{0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2, 0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e, 0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0},
|
||||||
};
|
};
|
||||||
int i;
|
unsigned int i, ninputs;
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
|
/* Skip last input vector for low iteration counts */
|
||||||
|
ninputs = sizeof(inputs)/sizeof(inputs[0]) - 1;
|
||||||
|
CONDITIONAL_TEST(16, "run_sha256_known_output_tests 1000000") ninputs++;
|
||||||
|
|
||||||
|
for (i = 0; i < ninputs; i++) {
|
||||||
unsigned char out[32];
|
unsigned char out[32];
|
||||||
secp256k1_sha256 hasher;
|
secp256k1_sha256 hasher;
|
||||||
|
unsigned int j;
|
||||||
|
/* 1. Run: simply write the input bytestrings */
|
||||||
|
j = repeat[i];
|
||||||
secp256k1_sha256_initialize(&hasher);
|
secp256k1_sha256_initialize(&hasher);
|
||||||
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
|
while (j > 0) {
|
||||||
|
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i]));
|
||||||
|
j--;
|
||||||
|
}
|
||||||
secp256k1_sha256_finalize(&hasher, out);
|
secp256k1_sha256_finalize(&hasher, out);
|
||||||
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
|
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
|
||||||
|
/* 2. Run: split the input bytestrings randomly before writing */
|
||||||
if (strlen(inputs[i]) > 0) {
|
if (strlen(inputs[i]) > 0) {
|
||||||
int split = secp256k1_testrand_int(strlen(inputs[i]));
|
int split = secp256k1_testrand_int(strlen(inputs[i]));
|
||||||
secp256k1_sha256_initialize(&hasher);
|
secp256k1_sha256_initialize(&hasher);
|
||||||
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
|
j = repeat[i];
|
||||||
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
|
while (j > 0) {
|
||||||
|
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split);
|
||||||
|
secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split);
|
||||||
|
j--;
|
||||||
|
}
|
||||||
secp256k1_sha256_finalize(&hasher, out);
|
secp256k1_sha256_finalize(&hasher, out);
|
||||||
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
|
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** SHA256 counter tests
|
||||||
|
|
||||||
|
The tests verify that the SHA256 counter doesn't wrap around at message length
|
||||||
|
2^i bytes for i = 20, ..., 33. This wide range aims at being independent of the
|
||||||
|
implementation of the counter and it catches multiple natural 32-bit overflows
|
||||||
|
(e.g., counting bits, counting bytes, counting blocks, ...).
|
||||||
|
|
||||||
|
The test vectors have been generated using following Python script which relies
|
||||||
|
on https://github.com/cloudtools/sha256/ (v0.3 on Python v3.10.2).
|
||||||
|
|
||||||
|
```
|
||||||
|
from sha256 import sha256
|
||||||
|
from copy import copy
|
||||||
|
|
||||||
|
def midstate_c_definition(hasher):
|
||||||
|
ret = ' {{0x' + hasher.state[0].hex('_', 4).replace('_', ', 0x') + '},\n'
|
||||||
|
ret += ' {0x00}, ' + str(hex(hasher.state[1])) + '}'
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def output_c_literal(hasher):
|
||||||
|
return '{0x' + hasher.digest().hex('_').replace('_', ', 0x') + '}'
|
||||||
|
|
||||||
|
MESSAGE = b'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno'
|
||||||
|
assert(len(MESSAGE) == 64)
|
||||||
|
BYTE_BOUNDARIES = [(2**b)//len(MESSAGE) - 1 for b in range(20, 34)]
|
||||||
|
|
||||||
|
midstates = []
|
||||||
|
digests = []
|
||||||
|
hasher = sha256()
|
||||||
|
for i in range(BYTE_BOUNDARIES[-1] + 1):
|
||||||
|
if i in BYTE_BOUNDARIES:
|
||||||
|
midstates.append(midstate_c_definition(hasher))
|
||||||
|
hasher_copy = copy(hasher)
|
||||||
|
hasher_copy.update(MESSAGE)
|
||||||
|
digests.append(output_c_literal(hasher_copy))
|
||||||
|
hasher.update(MESSAGE)
|
||||||
|
|
||||||
|
for x in midstates:
|
||||||
|
print(x + ',')
|
||||||
|
|
||||||
|
for x in digests:
|
||||||
|
print(x + ',')
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
void run_sha256_counter_tests(void) {
|
||||||
|
static const char *input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno";
|
||||||
|
static const secp256k1_sha256 midstates[] = {
|
||||||
|
{{0xa2b5c8bb, 0x26c88bb3, 0x2abdc3d2, 0x9def99a3, 0xdfd21a6e, 0x41fe585b, 0x7ef2c440, 0x2b79adda},
|
||||||
|
{0x00}, 0xfffc0},
|
||||||
|
{{0xa0d29445, 0x9287de66, 0x76aabd71, 0x41acd765, 0x0c7528b4, 0x84e14906, 0x942faec6, 0xcc5a7b26},
|
||||||
|
{0x00}, 0x1fffc0},
|
||||||
|
{{0x50449526, 0xb9f1d657, 0xa0fc13e9, 0x50860f10, 0xa550c431, 0x3fbc97c1, 0x7bbb2d89, 0xdb67bac1},
|
||||||
|
{0x00}, 0x3fffc0},
|
||||||
|
{{0x54a6efdc, 0x46762e7b, 0x88bfe73f, 0xbbd149c7, 0x41620c43, 0x1168da7b, 0x2c5960f9, 0xeccffda6},
|
||||||
|
{0x00}, 0x7fffc0},
|
||||||
|
{{0x2515a8f5, 0x5faa2977, 0x3a850486, 0xac858cad, 0x7b7276ee, 0x235c0385, 0xc53a157c, 0x7cb3e69c},
|
||||||
|
{0x00}, 0xffffc0},
|
||||||
|
{{0x34f39828, 0x409fedb7, 0x4bbdd0fb, 0x3b643634, 0x7806bf2e, 0xe0d1b713, 0xca3f2e1e, 0xe38722c2},
|
||||||
|
{0x00}, 0x1ffffc0},
|
||||||
|
{{0x389ef5c5, 0x38c54167, 0x8f5d56ab, 0x582a75cc, 0x8217caef, 0xf10947dd, 0x6a1998a8, 0x048f0b8c},
|
||||||
|
{0x00}, 0x3ffffc0},
|
||||||
|
{{0xd6c3f394, 0x0bee43b9, 0x6783f497, 0x29fa9e21, 0x6ce491c1, 0xa81fe45e, 0x2fc3859a, 0x269012d0},
|
||||||
|
{0x00}, 0x7ffffc0},
|
||||||
|
{{0x6dd3c526, 0x44d88aa0, 0x806a1bae, 0xfbcc0d32, 0x9d6144f3, 0x9d2bd757, 0x9851a957, 0xb50430ad},
|
||||||
|
{0x00}, 0xfffffc0},
|
||||||
|
{{0x2add4021, 0xdfe8a9e6, 0xa56317c6, 0x7a15f5bb, 0x4a48aacd, 0x5d368414, 0x4f00e6f0, 0xd9355023},
|
||||||
|
{0x00}, 0x1fffffc0},
|
||||||
|
{{0xb66666b4, 0xdbeac32b, 0x0ea351ae, 0xcba9da46, 0x6278b874, 0x8c508e23, 0xe16ca776, 0x8465bac1},
|
||||||
|
{0x00}, 0x3fffffc0},
|
||||||
|
{{0xb6744789, 0x9cce87aa, 0xc4c478b7, 0xf38404d8, 0x2e38ba62, 0xa3f7019b, 0x50458fe7, 0x3047dbec},
|
||||||
|
{0x00}, 0x7fffffc0},
|
||||||
|
{{0x8b1297ba, 0xba261a80, 0x2ba1b0dd, 0xfbc67d6d, 0x61072c4e, 0x4b5a2a0f, 0x52872760, 0x2dfeb162},
|
||||||
|
{0x00}, 0xffffffc0},
|
||||||
|
{{0x24f33cf7, 0x41ad6583, 0x41c8ff5d, 0xca7ef35f, 0x50395756, 0x021b743e, 0xd7126cd7, 0xd037473a},
|
||||||
|
{0x00}, 0x1ffffffc0},
|
||||||
|
};
|
||||||
|
static const unsigned char outputs[][32] = {
|
||||||
|
{0x0e, 0x83, 0xe2, 0xc9, 0x4f, 0xb2, 0xb8, 0x2b, 0x89, 0x06, 0x92, 0x78, 0x04, 0x03, 0x48, 0x5c, 0x48, 0x44, 0x67, 0x61, 0x77, 0xa4, 0xc7, 0x90, 0x9e, 0x92, 0x55, 0x10, 0x05, 0xfe, 0x39, 0x15},
|
||||||
|
{0x1d, 0x1e, 0xd7, 0xb8, 0xa3, 0xa7, 0x8a, 0x79, 0xfd, 0xa0, 0x05, 0x08, 0x9c, 0xeb, 0xf0, 0xec, 0x67, 0x07, 0x9f, 0x8e, 0x3c, 0x0d, 0x8e, 0xf9, 0x75, 0x55, 0x13, 0xc1, 0xe8, 0x77, 0xf8, 0xbb},
|
||||||
|
{0x66, 0x95, 0x6c, 0xc9, 0xe0, 0x39, 0x65, 0xb6, 0xb0, 0x05, 0xd1, 0xaf, 0xaf, 0xf3, 0x1d, 0xb9, 0xa4, 0xda, 0x6f, 0x20, 0xcd, 0x3a, 0xae, 0x64, 0xc2, 0xdb, 0xee, 0xf5, 0xb8, 0x8d, 0x57, 0x0e},
|
||||||
|
{0x3c, 0xbb, 0x1c, 0x12, 0x5e, 0x17, 0xfd, 0x54, 0x90, 0x45, 0xa7, 0x7b, 0x61, 0x6c, 0x1d, 0xfe, 0xe6, 0xcc, 0x7f, 0xee, 0xcf, 0xef, 0x33, 0x35, 0x50, 0x62, 0x16, 0x70, 0x2f, 0x87, 0xc3, 0xc9},
|
||||||
|
{0x53, 0x4d, 0xa8, 0xe7, 0x1e, 0x98, 0x73, 0x8d, 0xd9, 0xa3, 0x54, 0xa5, 0x0e, 0x59, 0x2c, 0x25, 0x43, 0x6f, 0xaa, 0xa2, 0xf5, 0x21, 0x06, 0x3e, 0xc9, 0x82, 0x06, 0x94, 0x98, 0x72, 0x9d, 0xa7},
|
||||||
|
{0xef, 0x7e, 0xe9, 0x6b, 0xd3, 0xe5, 0xb7, 0x41, 0x4c, 0xc8, 0xd3, 0x07, 0x52, 0x9a, 0x5a, 0x8b, 0x4e, 0x1e, 0x75, 0xa4, 0x17, 0x78, 0xc8, 0x36, 0xcd, 0xf8, 0x2e, 0xd9, 0x57, 0xe3, 0xd7, 0x07},
|
||||||
|
{0x87, 0x16, 0xfb, 0xf9, 0xa5, 0xf8, 0xc4, 0x56, 0x2b, 0x48, 0x52, 0x8e, 0x2d, 0x30, 0x85, 0xb6, 0x4c, 0x56, 0xb5, 0xd1, 0x16, 0x9c, 0xcf, 0x32, 0x95, 0xad, 0x03, 0xe8, 0x05, 0x58, 0x06, 0x76},
|
||||||
|
{0x75, 0x03, 0x80, 0x28, 0xf2, 0xa7, 0x63, 0x22, 0x1a, 0x26, 0x9c, 0x68, 0xe0, 0x58, 0xfc, 0x73, 0xeb, 0x42, 0xf6, 0x86, 0x16, 0x24, 0x4b, 0xbc, 0x24, 0xf7, 0x02, 0xc8, 0x3d, 0x90, 0xe2, 0xb0},
|
||||||
|
{0xdf, 0x49, 0x0f, 0x15, 0x7b, 0x7d, 0xbf, 0xe0, 0xd4, 0xcf, 0x47, 0xc0, 0x80, 0x93, 0x4a, 0x61, 0xaa, 0x03, 0x07, 0x66, 0xb3, 0x38, 0x5d, 0xc8, 0xc9, 0x07, 0x61, 0xfb, 0x97, 0x10, 0x2f, 0xd8},
|
||||||
|
{0x77, 0x19, 0x40, 0x56, 0x41, 0xad, 0xbc, 0x59, 0xda, 0x1e, 0xc5, 0x37, 0x14, 0x63, 0x7b, 0xfb, 0x79, 0xe2, 0x7a, 0xb1, 0x55, 0x42, 0x99, 0x42, 0x56, 0xfe, 0x26, 0x9d, 0x0f, 0x7e, 0x80, 0xc6},
|
||||||
|
{0x50, 0xe7, 0x2a, 0x0e, 0x26, 0x44, 0x2f, 0xe2, 0x55, 0x2d, 0xc3, 0x93, 0x8a, 0xc5, 0x86, 0x58, 0x22, 0x8c, 0x0c, 0xbf, 0xb1, 0xd2, 0xca, 0x87, 0x2a, 0xe4, 0x35, 0x26, 0x6f, 0xcd, 0x05, 0x5e},
|
||||||
|
{0xe4, 0x80, 0x6f, 0xdb, 0x3d, 0x7d, 0xba, 0xde, 0x50, 0x3f, 0xea, 0x00, 0x3d, 0x46, 0x59, 0x64, 0xfd, 0x58, 0x1c, 0xa1, 0xb8, 0x7d, 0x5f, 0xac, 0x94, 0x37, 0x9e, 0xa0, 0xc0, 0x9c, 0x93, 0x8b},
|
||||||
|
{0x2c, 0xf3, 0xa9, 0xf6, 0x15, 0x25, 0x80, 0x70, 0x76, 0x99, 0x7d, 0xf1, 0xc3, 0x2f, 0xa3, 0x31, 0xff, 0x92, 0x35, 0x2e, 0x8d, 0x04, 0x13, 0x33, 0xd8, 0x0d, 0xdb, 0x4a, 0xf6, 0x8c, 0x03, 0x34},
|
||||||
|
{0xec, 0x12, 0x24, 0x9f, 0x35, 0xa4, 0x29, 0x8b, 0x9e, 0x4a, 0x95, 0xf8, 0x61, 0xaf, 0x61, 0xc5, 0x66, 0x55, 0x3e, 0x3f, 0x2a, 0x98, 0xea, 0x71, 0x16, 0x6b, 0x1c, 0xd9, 0xe4, 0x09, 0xd2, 0x8e},
|
||||||
|
};
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < sizeof(midstates)/sizeof(midstates[0]); i++) {
|
||||||
|
unsigned char out[32];
|
||||||
|
secp256k1_sha256 hasher = midstates[i];
|
||||||
|
secp256k1_sha256_write(&hasher, (const unsigned char*)input, strlen(input));
|
||||||
|
secp256k1_sha256_finalize(&hasher, out);
|
||||||
|
CHECK(secp256k1_memcmp_var(out, outputs[i], 32) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void run_hmac_sha256_tests(void) {
|
void run_hmac_sha256_tests(void) {
|
||||||
static const char *keys[6] = {
|
static const char *keys[6] = {
|
||||||
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
|
"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
|
||||||
@ -2625,6 +2750,55 @@ int fe_identical(const secp256k1_fe *a, const secp256k1_fe *b) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void run_field_half(void) {
|
||||||
|
secp256k1_fe t, u;
|
||||||
|
int m;
|
||||||
|
|
||||||
|
/* Check magnitude 0 input */
|
||||||
|
secp256k1_fe_get_bounds(&t, 0);
|
||||||
|
secp256k1_fe_half(&t);
|
||||||
|
#ifdef VERIFY
|
||||||
|
CHECK(t.magnitude == 1);
|
||||||
|
CHECK(t.normalized == 0);
|
||||||
|
#endif
|
||||||
|
CHECK(secp256k1_fe_normalizes_to_zero(&t));
|
||||||
|
|
||||||
|
/* Check non-zero magnitudes in the supported range */
|
||||||
|
for (m = 1; m < 32; m++) {
|
||||||
|
/* Check max-value input */
|
||||||
|
secp256k1_fe_get_bounds(&t, m);
|
||||||
|
|
||||||
|
u = t;
|
||||||
|
secp256k1_fe_half(&u);
|
||||||
|
#ifdef VERIFY
|
||||||
|
CHECK(u.magnitude == (m >> 1) + 1);
|
||||||
|
CHECK(u.normalized == 0);
|
||||||
|
#endif
|
||||||
|
secp256k1_fe_normalize_weak(&u);
|
||||||
|
secp256k1_fe_add(&u, &u);
|
||||||
|
CHECK(check_fe_equal(&t, &u));
|
||||||
|
|
||||||
|
/* Check worst-case input: ensure the LSB is 1 so that P will be added,
|
||||||
|
* which will also cause all carries to be 1, since all limbs that can
|
||||||
|
* generate a carry are initially even and all limbs of P are odd in
|
||||||
|
* every existing field implementation. */
|
||||||
|
secp256k1_fe_get_bounds(&t, m);
|
||||||
|
CHECK(t.n[0] > 0);
|
||||||
|
CHECK((t.n[0] & 1) == 0);
|
||||||
|
--t.n[0];
|
||||||
|
|
||||||
|
u = t;
|
||||||
|
secp256k1_fe_half(&u);
|
||||||
|
#ifdef VERIFY
|
||||||
|
CHECK(u.magnitude == (m >> 1) + 1);
|
||||||
|
CHECK(u.normalized == 0);
|
||||||
|
#endif
|
||||||
|
secp256k1_fe_normalize_weak(&u);
|
||||||
|
secp256k1_fe_add(&u, &u);
|
||||||
|
CHECK(check_fe_equal(&t, &u));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void run_field_misc(void) {
|
void run_field_misc(void) {
|
||||||
secp256k1_fe x;
|
secp256k1_fe x;
|
||||||
secp256k1_fe y;
|
secp256k1_fe y;
|
||||||
@ -2632,9 +2806,13 @@ void run_field_misc(void) {
|
|||||||
secp256k1_fe q;
|
secp256k1_fe q;
|
||||||
secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5);
|
secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5);
|
||||||
int i, j;
|
int i, j;
|
||||||
for (i = 0; i < 5*count; i++) {
|
for (i = 0; i < 1000 * count; i++) {
|
||||||
secp256k1_fe_storage xs, ys, zs;
|
secp256k1_fe_storage xs, ys, zs;
|
||||||
random_fe(&x);
|
if (i & 1) {
|
||||||
|
random_fe(&x);
|
||||||
|
} else {
|
||||||
|
random_fe_test(&x);
|
||||||
|
}
|
||||||
random_fe_non_zero(&y);
|
random_fe_non_zero(&y);
|
||||||
/* Test the fe equality and comparison operations. */
|
/* Test the fe equality and comparison operations. */
|
||||||
CHECK(secp256k1_fe_cmp_var(&x, &x) == 0);
|
CHECK(secp256k1_fe_cmp_var(&x, &x) == 0);
|
||||||
@ -2702,6 +2880,14 @@ void run_field_misc(void) {
|
|||||||
secp256k1_fe_add(&q, &x);
|
secp256k1_fe_add(&q, &x);
|
||||||
CHECK(check_fe_equal(&y, &z));
|
CHECK(check_fe_equal(&y, &z));
|
||||||
CHECK(check_fe_equal(&q, &y));
|
CHECK(check_fe_equal(&q, &y));
|
||||||
|
/* Check secp256k1_fe_half. */
|
||||||
|
z = x;
|
||||||
|
secp256k1_fe_half(&z);
|
||||||
|
secp256k1_fe_add(&z, &z);
|
||||||
|
CHECK(check_fe_equal(&x, &z));
|
||||||
|
secp256k1_fe_add(&z, &z);
|
||||||
|
secp256k1_fe_half(&z);
|
||||||
|
CHECK(check_fe_equal(&x, &z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5014,8 +5200,8 @@ void test_ecmult_accumulate(secp256k1_sha256* acc, const secp256k1_scalar* x, se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_ecmult_constants(void) {
|
void test_ecmult_constants_2bit(void) {
|
||||||
/* Test ecmult_gen for:
|
/* Using test_ecmult_accumulate, test ecmult for:
|
||||||
* - For i in 0..36:
|
* - For i in 0..36:
|
||||||
* - Key i
|
* - Key i
|
||||||
* - Key -i
|
* - Key -i
|
||||||
@ -5058,8 +5244,81 @@ void test_ecmult_constants(void) {
|
|||||||
secp256k1_scratch_space_destroy(ctx, scratch);
|
secp256k1_scratch_space_destroy(ctx, scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_ecmult_constants_sha(uint32_t prefix, size_t iter, const unsigned char* expected32) {
|
||||||
|
/* Using test_ecmult_accumulate, test ecmult for:
|
||||||
|
* - Key 0
|
||||||
|
* - Key 1
|
||||||
|
* - Key -1
|
||||||
|
* - For i in range(iter):
|
||||||
|
* - Key SHA256(LE32(prefix) || LE16(i))
|
||||||
|
*/
|
||||||
|
secp256k1_scalar x;
|
||||||
|
secp256k1_sha256 acc;
|
||||||
|
unsigned char b32[32];
|
||||||
|
unsigned char inp[6];
|
||||||
|
size_t i;
|
||||||
|
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 65536);
|
||||||
|
|
||||||
|
inp[0] = prefix & 0xFF;
|
||||||
|
inp[1] = (prefix >> 8) & 0xFF;
|
||||||
|
inp[2] = (prefix >> 16) & 0xFF;
|
||||||
|
inp[3] = (prefix >> 24) & 0xFF;
|
||||||
|
secp256k1_sha256_initialize(&acc);
|
||||||
|
secp256k1_scalar_set_int(&x, 0);
|
||||||
|
test_ecmult_accumulate(&acc, &x, scratch);
|
||||||
|
secp256k1_scalar_set_int(&x, 1);
|
||||||
|
test_ecmult_accumulate(&acc, &x, scratch);
|
||||||
|
secp256k1_scalar_negate(&x, &x);
|
||||||
|
test_ecmult_accumulate(&acc, &x, scratch);
|
||||||
|
|
||||||
|
for (i = 0; i < iter; ++i) {
|
||||||
|
secp256k1_sha256 gen;
|
||||||
|
inp[4] = i & 0xff;
|
||||||
|
inp[5] = (i >> 8) & 0xff;
|
||||||
|
secp256k1_sha256_initialize(&gen);
|
||||||
|
secp256k1_sha256_write(&gen, inp, sizeof(inp));
|
||||||
|
secp256k1_sha256_finalize(&gen, b32);
|
||||||
|
secp256k1_scalar_set_b32(&x, b32, NULL);
|
||||||
|
test_ecmult_accumulate(&acc, &x, scratch);
|
||||||
|
}
|
||||||
|
secp256k1_sha256_finalize(&acc, b32);
|
||||||
|
CHECK(secp256k1_memcmp_var(b32, expected32, 32) == 0);
|
||||||
|
|
||||||
|
secp256k1_scratch_space_destroy(ctx, scratch);
|
||||||
|
}
|
||||||
|
|
||||||
void run_ecmult_constants(void) {
|
void run_ecmult_constants(void) {
|
||||||
test_ecmult_constants();
|
/* Expected hashes of all points in the tests below. Computed using an
|
||||||
|
* independent implementation. */
|
||||||
|
static const unsigned char expected32_6bit20[32] = {
|
||||||
|
0x68, 0xb6, 0xed, 0x6f, 0x28, 0xca, 0xc9, 0x7f,
|
||||||
|
0x8e, 0x8b, 0xd6, 0xc0, 0x61, 0x79, 0x34, 0x6e,
|
||||||
|
0x5a, 0x8f, 0x2b, 0xbc, 0x3e, 0x1f, 0xc5, 0x2e,
|
||||||
|
0x2a, 0xd0, 0x45, 0x67, 0x7f, 0x95, 0x95, 0x8e
|
||||||
|
};
|
||||||
|
static const unsigned char expected32_8bit8[32] = {
|
||||||
|
0x8b, 0x65, 0x8e, 0xea, 0x86, 0xae, 0x3c, 0x95,
|
||||||
|
0x90, 0xb6, 0x77, 0xa4, 0x8c, 0x76, 0xd9, 0xec,
|
||||||
|
0xf5, 0xab, 0x8a, 0x2f, 0xfd, 0xdb, 0x19, 0x12,
|
||||||
|
0x1a, 0xee, 0xe6, 0xb7, 0x6e, 0x05, 0x3f, 0xc6
|
||||||
|
};
|
||||||
|
/* For every combination of 6 bit positions out of 256, restricted to
|
||||||
|
* 20-bit windows (i.e., the first and last bit position are no more than
|
||||||
|
* 19 bits apart), all 64 bit patterns occur in the input scalars used in
|
||||||
|
* this test. */
|
||||||
|
CONDITIONAL_TEST(1, "test_ecmult_constants_sha 1024") {
|
||||||
|
test_ecmult_constants_sha(4808378u, 1024, expected32_6bit20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For every combination of 8 consecutive bit positions, all 256 bit
|
||||||
|
* patterns occur in the input scalars used in this test. */
|
||||||
|
CONDITIONAL_TEST(3, "test_ecmult_constants_sha 2048") {
|
||||||
|
test_ecmult_constants_sha(1607366309u, 2048, expected32_8bit8);
|
||||||
|
}
|
||||||
|
|
||||||
|
CONDITIONAL_TEST(35, "test_ecmult_constants_2bit") {
|
||||||
|
test_ecmult_constants_2bit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_ecmult_gen_blind(void) {
|
void test_ecmult_gen_blind(void) {
|
||||||
@ -6918,6 +7177,19 @@ void run_secp256k1_memczero_test(void) {
|
|||||||
CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0);
|
CHECK(secp256k1_memcmp_var(buf1, buf2, sizeof(buf1)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void run_secp256k1_byteorder_tests(void) {
|
||||||
|
const uint32_t x = 0xFF03AB45;
|
||||||
|
const unsigned char x_be[4] = {0xFF, 0x03, 0xAB, 0x45};
|
||||||
|
unsigned char buf[4];
|
||||||
|
uint32_t x_;
|
||||||
|
|
||||||
|
secp256k1_write_be32(buf, x);
|
||||||
|
CHECK(secp256k1_memcmp_var(buf, x_be, sizeof(buf)) == 0);
|
||||||
|
|
||||||
|
x_ = secp256k1_read_be32(buf);
|
||||||
|
CHECK(x == x_);
|
||||||
|
}
|
||||||
|
|
||||||
void int_cmov_test(void) {
|
void int_cmov_test(void) {
|
||||||
int r = INT_MAX;
|
int r = INT_MAX;
|
||||||
int a = 0;
|
int a = 0;
|
||||||
@ -7119,7 +7391,8 @@ int main(int argc, char **argv) {
|
|||||||
run_modinv_tests();
|
run_modinv_tests();
|
||||||
run_inverse_tests();
|
run_inverse_tests();
|
||||||
|
|
||||||
run_sha256_tests();
|
run_sha256_known_output_tests();
|
||||||
|
run_sha256_counter_tests();
|
||||||
run_hmac_sha256_tests();
|
run_hmac_sha256_tests();
|
||||||
run_rfc6979_hmac_sha256_tests();
|
run_rfc6979_hmac_sha256_tests();
|
||||||
run_tagged_sha256_tests();
|
run_tagged_sha256_tests();
|
||||||
@ -7128,6 +7401,7 @@ int main(int argc, char **argv) {
|
|||||||
run_scalar_tests();
|
run_scalar_tests();
|
||||||
|
|
||||||
/* field tests */
|
/* field tests */
|
||||||
|
run_field_half();
|
||||||
run_field_misc();
|
run_field_misc();
|
||||||
run_field_convert();
|
run_field_convert();
|
||||||
run_fe_mul();
|
run_fe_mul();
|
||||||
@ -7222,6 +7496,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
/* util tests */
|
/* util tests */
|
||||||
run_secp256k1_memczero_test();
|
run_secp256k1_memczero_test();
|
||||||
|
run_secp256k1_byteorder_tests();
|
||||||
|
|
||||||
run_cmov_tests();
|
run_cmov_tests();
|
||||||
|
|
||||||
|
16
src/util.h
16
src/util.h
@ -364,4 +364,20 @@ static SECP256K1_INLINE int secp256k1_ctz64_var(uint64_t x) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Read a uint32_t in big endian */
|
||||||
|
SECP256K1_INLINE static uint32_t secp256k1_read_be32(const unsigned char* p) {
|
||||||
|
return (uint32_t)p[0] << 24 |
|
||||||
|
(uint32_t)p[1] << 16 |
|
||||||
|
(uint32_t)p[2] << 8 |
|
||||||
|
(uint32_t)p[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a uint32_t in big endian */
|
||||||
|
SECP256K1_INLINE static void secp256k1_write_be32(unsigned char* p, uint32_t x) {
|
||||||
|
p[3] = x;
|
||||||
|
p[2] = x >> 8;
|
||||||
|
p[1] = x >> 16;
|
||||||
|
p[0] = x >> 24;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SECP256K1_UTIL_H */
|
#endif /* SECP256K1_UTIL_H */
|
||||||
|
@ -179,7 +179,7 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
|||||||
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
ret = secp256k1_keypair_create(ctx, &keypair, key);
|
||||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||||
CHECK(ret == 1);
|
CHECK(ret == 1);
|
||||||
ret = secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL);
|
ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL);
|
||||||
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
|
||||||
CHECK(ret == 1);
|
CHECK(ret == 1);
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user