Compare commits
278 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ad5185cd4 | ||
|
|
672053d801 | ||
|
|
1a81df826e | ||
|
|
74a4d974d5 | ||
|
|
e7f830e32c | ||
|
|
77af1da9f6 | ||
|
|
3928b7c383 | ||
|
|
5e9a4d7aec | ||
|
|
4197d667ec | ||
|
|
0e5ea62207 | ||
|
|
e2c9888eee | ||
|
|
d2e36a2b81 | ||
|
|
1a432cb982 | ||
|
|
0922a047fb | ||
|
|
76880e4015 | ||
|
|
d3e29db8bb | ||
|
|
04af0ba162 | ||
|
|
60525f6c14 | ||
|
|
a47cd97d51 | ||
|
|
10e6d29b60 | ||
|
|
07687e811d | ||
|
|
bb4672342e | ||
|
|
a3a3e11acd | ||
|
|
a0fb68a2e7 | ||
|
|
cf25c86d05 | ||
|
|
5d89bc031b | ||
|
|
c2688f8de9 | ||
|
|
5814d8485c | ||
|
|
c1b4966410 | ||
|
|
f07cead0ca | ||
|
|
2f0762fa8f | ||
|
|
1ddd76af0a | ||
|
|
e72103932d | ||
|
|
ea47c82e01 | ||
|
|
dcdda31f2c | ||
|
|
10271356c8 | ||
|
|
33dc7e4d3e | ||
|
|
c891c5c2f4 | ||
|
|
8185e72d29 | ||
|
|
40f50d0fbd | ||
|
|
8e2a5fe908 | ||
|
|
355bbdf38a | ||
|
|
21f49d9bec | ||
|
|
115fdc7232 | ||
|
|
aa9f3a3c00 | ||
|
|
4d16e90111 | ||
|
|
ba523be067 | ||
|
|
2140da9cd5 | ||
|
|
1f1bb78b7f | ||
|
|
5dab0baa80 | ||
|
|
b314cf2833 | ||
|
|
fa4d6c76b6 | ||
|
|
ee7aaf213e | ||
|
|
ba9cb6f378 | ||
|
|
d9d80fd155 | ||
|
|
4fd00f4bfe | ||
|
|
421d84855a | ||
|
|
9f005c60d6 | ||
|
|
2262d0eaab | ||
|
|
b10ddd2bd2 | ||
|
|
49be5be9e8 | ||
|
|
cbf3053ff1 | ||
|
|
9b118bc7fb | ||
|
|
199d27cea3 | ||
|
|
70303643cf | ||
|
|
f8d7ea68df | ||
|
|
16339804c9 | ||
|
|
d9a85065a9 | ||
|
|
b0f7bfedc9 | ||
|
|
bd9d98d353 | ||
|
|
0b4640aedd | ||
|
|
8659a01714 | ||
|
|
f9b38894ba | ||
|
|
a1d52e3e12 | ||
|
|
875b0ada25 | ||
|
|
727bec5bc2 | ||
|
|
2635068abf | ||
|
|
e78c7b68eb | ||
|
|
2f0d3bbffb | ||
|
|
4b8a647ad3 | ||
|
|
6ebe7d2bb3 | ||
|
|
65c79fe2d0 | ||
|
|
c223d7e33d | ||
|
|
ea26b71c3a | ||
|
|
cce0456304 | ||
|
|
317a4c48f0 | ||
|
|
4d7fe60905 | ||
|
|
676ed8f9cf | ||
|
|
61fc3a2dc8 | ||
|
|
d51fb0a533 | ||
|
|
c22ac27529 | ||
|
|
26a989924b | ||
|
|
ee1be62d84 | ||
|
|
6ee14550c8 | ||
|
|
fc3dea29ea | ||
|
|
7782dc8276 | ||
|
|
0a16de671c | ||
|
|
ea33914e00 | ||
|
|
880be8af99 | ||
|
|
2e6cf9bae5 | ||
|
|
5373693e45 | ||
|
|
ef9fe959de | ||
|
|
e10878f58e | ||
|
|
4ad4914bd1 | ||
|
|
6617a620d9 | ||
|
|
03c9e6508c | ||
|
|
ad3e65d9fe | ||
|
|
6b9507adf6 | ||
|
|
87d35f30c0 | ||
|
|
d6281dd008 | ||
|
|
2b6f9cd546 | ||
|
|
48b1d939b5 | ||
|
|
0ba2b94551 | ||
|
|
c45b7c4fbb | ||
|
|
dc5514144f | ||
|
|
060e32cb60 | ||
|
|
de657c2044 | ||
|
|
bcffeb14bc | ||
|
|
c2f6435802 | ||
|
|
4a24fae0bc | ||
|
|
b0886fd35c | ||
|
|
3d05c86d63 | ||
|
|
d78bec7001 | ||
|
|
3545dc2b9b | ||
|
|
5d8fa825e2 | ||
|
|
8e54a346d2 | ||
|
|
b327abfcea | ||
|
|
d62db57427 | ||
|
|
54058d16fe | ||
|
|
bb4efd6404 | ||
|
|
eedd781085 | ||
|
|
b2f6712dd3 | ||
|
|
9c91ea41b1 | ||
|
|
db32a24761 | ||
|
|
ce765a5b8e | ||
|
|
8408dfdc4c | ||
|
|
c8d9914fb1 | ||
|
|
8d2960c8e2 | ||
|
|
f1774e5ec4 | ||
|
|
5ee039bb58 | ||
|
|
96294c00fb | ||
|
|
a2f7ccdecc | ||
|
|
374e2b54e2 | ||
|
|
1b13415df9 | ||
|
|
a1bd4971d6 | ||
|
|
b7c685e74a | ||
|
|
c83afa66e0 | ||
|
|
26392da2fb | ||
|
|
d23da6d557 | ||
|
|
4692478853 | ||
|
|
c7d0454932 | ||
|
|
c734c64278 | ||
|
|
ad152151b0 | ||
|
|
78ca880788 | ||
|
|
0e00fc7d10 | ||
|
|
b097a466c1 | ||
|
|
2bd5f3e618 | ||
|
|
4f8c5bd761 | ||
|
|
173e8d061a | ||
|
|
49afd2f5d8 | ||
|
|
4e9661fc42 | ||
|
|
690b0fc05a | ||
|
|
c545fdc374 | ||
|
|
b40e2d30b7 | ||
|
|
c424e2fb43 | ||
|
|
175db31149 | ||
|
|
116d2ab3df | ||
|
|
cef373997c | ||
|
|
907a67212e | ||
|
|
0f7657d59c | ||
|
|
cc55757552 | ||
|
|
600c5adcd5 | ||
|
|
981e5be38c | ||
|
|
e9e9648219 | ||
|
|
609093b387 | ||
|
|
1deecaaf3b | ||
|
|
b79ba8aa4c | ||
|
|
c9ebca95f9 | ||
|
|
afd7eb4a55 | ||
|
|
2792119278 | ||
|
|
c7d900ffd1 | ||
|
|
332af315fc | ||
|
|
9e6d1b0e9b | ||
|
|
0aacf64352 | ||
|
|
b6b9834e8d | ||
|
|
07c0e8b82e | ||
|
|
3fc1de5c55 | ||
|
|
fb758fe8d6 | ||
|
|
c6cd2b15a0 | ||
|
|
020bf69a44 | ||
|
|
0196e8ade1 | ||
|
|
9f1b1904a3 | ||
|
|
ae9db95cea | ||
|
|
7966aee31d | ||
|
|
a7bec34231 | ||
|
|
249c81eaa3 | ||
|
|
98579e297b | ||
|
|
5b9f37f136 | ||
|
|
a6ca76cdf2 | ||
|
|
0fa84f869d | ||
|
|
5a95a268b9 | ||
|
|
304421d57b | ||
|
|
3aef6ab8e1 | ||
|
|
4494a369b6 | ||
|
|
799f4eec27 | ||
|
|
c862a9fb49 | ||
|
|
a1782098a9 | ||
|
|
7d8d5c86df | ||
|
|
8a7273465b | ||
|
|
fd491ea1bb | ||
|
|
ac43613d25 | ||
|
|
67887ae65c | ||
|
|
926dd3e962 | ||
|
|
10836832e7 | ||
|
|
7c7467ab7f | ||
|
|
c32ffd8d8c | ||
|
|
3c1a0fd37f | ||
|
|
705ce7ed8c | ||
|
|
0702ecb061 | ||
|
|
5779137457 | ||
|
|
90e360acc2 | ||
|
|
4f091847c2 | ||
|
|
1bcea8c57f | ||
|
|
2d1d41acf8 | ||
|
|
df633cdeba | ||
|
|
9695deb351 | ||
|
|
c47917bbd6 | ||
|
|
79e5b2a8b8 | ||
|
|
a597a5a9ce | ||
|
|
30574f22ea | ||
|
|
45c5ca7675 | ||
|
|
f1652528be | ||
|
|
7067ee54b4 | ||
|
|
740528caad | ||
|
|
be8ff3a02a | ||
|
|
efa76c4bf7 | ||
|
|
67214f5f7d | ||
|
|
cb1a59275c | ||
|
|
f3644287b1 | ||
|
|
887183e7de | ||
|
|
52b84238de | ||
|
|
e449af6872 | ||
|
|
747ada3587 | ||
|
|
5b7bf2e9d4 | ||
|
|
60556c9f49 | ||
|
|
db29bf220c | ||
|
|
c7db4942b3 | ||
|
|
7dae115861 | ||
|
|
bf29f8d0a6 | ||
|
|
605e07e365 | ||
|
|
debf3e5c08 | ||
|
|
d75dc59b58 | ||
|
|
ade5b36701 | ||
|
|
e83801f5db | ||
|
|
654246c635 | ||
|
|
908e02d596 | ||
|
|
1549db0ca5 | ||
|
|
20a5da5fb1 | ||
|
|
05873bb6b1 | ||
|
|
ad84603297 | ||
|
|
6348bc7eee | ||
|
|
79fa50b082 | ||
|
|
165206789b | ||
|
|
09df0bfb23 | ||
|
|
27504d5c94 | ||
|
|
d373a7215b | ||
|
|
6433175ffe | ||
|
|
5f7903c73c | ||
|
|
e9e4526a4e | ||
|
|
5768b50229 | ||
|
|
31b4bbee1e | ||
|
|
83186db34a | ||
|
|
95448ef2f8 | ||
|
|
6ec3731e8c | ||
|
|
fb5bfa4eed | ||
|
|
723e8ca8f7 | ||
|
|
bc7c8db179 | ||
|
|
e02f313b1f |
402
.cirrus.yml
402
.cirrus.yml
@@ -21,6 +21,7 @@ env:
|
||||
ECDH: no
|
||||
RECOVERY: no
|
||||
SCHNORRSIG: no
|
||||
ELLSWIFT: no
|
||||
### test options
|
||||
SECP256K1_TEST_ITERS:
|
||||
BENCH: yes
|
||||
@@ -29,11 +30,6 @@ env:
|
||||
# Compile and run the tests
|
||||
EXAMPLES: yes
|
||||
|
||||
# https://cirrus-ci.org/pricing/#compute-credits
|
||||
credits_snippet: &CREDITS
|
||||
# Don't use any credits for now.
|
||||
use_compute_credits: false
|
||||
|
||||
cat_logs_snippet: &CAT_LOGS
|
||||
always:
|
||||
cat_tests_log_script:
|
||||
@@ -53,357 +49,47 @@ cat_logs_snippet: &CAT_LOGS
|
||||
cat_ci_env_script:
|
||||
- env
|
||||
|
||||
merge_base_script_snippet: &MERGE_BASE
|
||||
merge_base_script:
|
||||
- if [ "$CIRRUS_PR" = "" ]; then exit 0; fi
|
||||
- git fetch --depth=1 $CIRRUS_REPO_CLONE_URL "pull/${CIRRUS_PR}/merge"
|
||||
- git checkout FETCH_HEAD # Use merged changes to detect silent merge conflicts
|
||||
|
||||
linux_container_snippet: &LINUX_CONTAINER
|
||||
container:
|
||||
dockerfile: ci/linux-debian.Dockerfile
|
||||
# Reduce number of CPUs to be able to do more builds in parallel.
|
||||
cpu: 1
|
||||
# Gives us more CPUs for free if they're available.
|
||||
greedy: true
|
||||
# More than enough for our scripts.
|
||||
memory: 1G
|
||||
|
||||
task:
|
||||
name: "x86_64: Linux (Debian stable)"
|
||||
<< : *LINUX_CONTAINER
|
||||
matrix: &ENV_MATRIX
|
||||
- env: {WIDEMUL: int64, RECOVERY: yes}
|
||||
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes}
|
||||
- env: {WIDEMUL: int128}
|
||||
- env: {WIDEMUL: int128_struct}
|
||||
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
|
||||
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes}
|
||||
- env: {WIDEMUL: int128, ASM: x86_64}
|
||||
- env: { RECOVERY: yes, SCHNORRSIG: yes}
|
||||
- env: {CTIMETESTS: no, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, CPPFLAGS: -DVERIFY}
|
||||
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no}
|
||||
- env: {CPPFLAGS: -DDETERMINISTIC}
|
||||
- env: {CFLAGS: -O0, CTIMETESTS: no}
|
||||
- env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
|
||||
- env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 }
|
||||
matrix:
|
||||
- env:
|
||||
CC: gcc
|
||||
- env:
|
||||
CC: clang
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "i686: Linux (Debian stable)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
HOST: i686-linux-gnu
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
matrix:
|
||||
- env:
|
||||
CC: i686-linux-gnu-gcc
|
||||
- env:
|
||||
CC: clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "arm64: macOS Ventura"
|
||||
macos_instance:
|
||||
image: ghcr.io/cirruslabs/macos-ventura-base:latest
|
||||
env:
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
# Cirrus gives us a fixed number of 4 virtual CPUs. Not that we even have that many jobs at the moment...
|
||||
MAKEFLAGS: -j5
|
||||
matrix:
|
||||
<< : *ENV_MATRIX
|
||||
env:
|
||||
ASM: no
|
||||
WITH_VALGRIND: no
|
||||
CTIMETESTS: no
|
||||
matrix:
|
||||
- env:
|
||||
CC: gcc
|
||||
- env:
|
||||
CC: clang
|
||||
brew_script:
|
||||
- brew install automake libtool gcc
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
<< : *CREDITS
|
||||
|
||||
task:
|
||||
name: "s390x (big-endian): Linux (Debian stable, QEMU)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: qemu-s390x
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: s390x-linux-gnu
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
# https://sourceware.org/bugzilla/show_bug.cgi?id=27008
|
||||
- rm /etc/ld.so.cache
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "ARM32: Linux (Debian stable, QEMU)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: qemu-arm
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: arm-linux-gnueabihf
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
matrix:
|
||||
- env: {}
|
||||
- env: {EXPERIMENTAL: yes, ASM: arm32}
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "ARM64: Linux (Debian stable, QEMU)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: qemu-aarch64
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: aarch64-linux-gnu
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "ppc64le: Linux (Debian stable, QEMU)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: qemu-ppc64le
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: powerpc64le-linux-gnu
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: wine
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
matrix:
|
||||
- name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
|
||||
env:
|
||||
HOST: x86_64-w64-mingw32
|
||||
- name: "i686 (mingw32-w64): Windows (Debian stable, Wine)"
|
||||
env:
|
||||
HOST: i686-w64-mingw32
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
WRAPPER_CMD: wine
|
||||
WERROR_CFLAGS: -WX
|
||||
WITH_VALGRIND: no
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
EXPERIMENTAL: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
# Use a MinGW-w64 host to tell ./configure we're building for Windows.
|
||||
# This will detect some MinGW-w64 tools but then make will need only
|
||||
# the MSVC tools CC, AR and NM as specified below.
|
||||
HOST: x86_64-w64-mingw32
|
||||
CC: /opt/msvc/bin/x64/cl
|
||||
AR: /opt/msvc/bin/x64/lib
|
||||
NM: /opt/msvc/bin/x64/dumpbin -symbols -headers
|
||||
# Set non-essential options that affect the CLI messages here.
|
||||
# (They depend on the user's taste, so we don't want to set them automatically in configure.ac.)
|
||||
CFLAGS: -nologo -diagnostics:caret
|
||||
LDFLAGS: -Xlinker -Xlinker -Xlinker -nologo
|
||||
matrix:
|
||||
- name: "x86_64 (MSVC): Windows (Debian stable, Wine)"
|
||||
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)"
|
||||
env:
|
||||
WIDEMUL: int128_struct
|
||||
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct with __(u)mulh)"
|
||||
env:
|
||||
WIDEMUL: int128_struct
|
||||
CPPFLAGS: -DSECP256K1_MSVC_MULH_TEST_OVERRIDE
|
||||
- name: "i686 (MSVC): Windows (Debian stable, Wine)"
|
||||
env:
|
||||
HOST: i686-w64-mingw32
|
||||
CC: /opt/msvc/bin/x86/cl
|
||||
AR: /opt/msvc/bin/x86/lib
|
||||
NM: /opt/msvc/bin/x86/dumpbin -symbols -headers
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
# Sanitizers
|
||||
task:
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: no
|
||||
matrix:
|
||||
- name: "Valgrind (memcheck)"
|
||||
container:
|
||||
cpu: 2
|
||||
env:
|
||||
# The `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (https://www.valgrind.org/docs/manual/manual-core.html)
|
||||
WRAPPER_CMD: "valgrind --error-exitcode=42"
|
||||
SECP256K1_TEST_ITERS: 2
|
||||
- name: "UBSan, ASan, LSan"
|
||||
container:
|
||||
memory: 2G
|
||||
env:
|
||||
CFLAGS: "-fsanitize=undefined,address -g"
|
||||
UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1"
|
||||
ASAN_OPTIONS: "strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1"
|
||||
LSAN_OPTIONS: "use_unaligned=1"
|
||||
SECP256K1_TEST_ITERS: 32
|
||||
# Try to cover many configurations with just a tiny matrix.
|
||||
matrix:
|
||||
- env:
|
||||
ASM: auto
|
||||
- env:
|
||||
ASM: no
|
||||
ECMULTGENPRECISION: 2
|
||||
ECMULTWINDOW: 2
|
||||
matrix:
|
||||
- env:
|
||||
CC: clang
|
||||
- env:
|
||||
HOST: i686-linux-gnu
|
||||
CC: i686-linux-gnu-gcc
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
# Memory sanitizers
|
||||
task:
|
||||
<< : *LINUX_CONTAINER
|
||||
name: "MSan"
|
||||
env:
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
CTIMETESTS: yes
|
||||
CC: clang
|
||||
SECP256K1_TEST_ITERS: 32
|
||||
ASM: no
|
||||
WITH_VALGRIND: no
|
||||
container:
|
||||
memory: 2G
|
||||
matrix:
|
||||
- env:
|
||||
CFLAGS: "-fsanitize=memory -g"
|
||||
- env:
|
||||
ECMULTGENPRECISION: 2
|
||||
ECMULTWINDOW: 2
|
||||
CFLAGS: "-fsanitize=memory -g -O3"
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "C++ -fpermissive (entire project)"
|
||||
<< : *LINUX_CONTAINER
|
||||
env:
|
||||
CC: g++
|
||||
CFLAGS: -fpermissive -g
|
||||
CPPFLAGS: -DSECP256K1_CPLUSPLUS_TEST_OVERRIDE
|
||||
WERROR_CFLAGS:
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
<< : *MERGE_BASE
|
||||
test_script:
|
||||
- ./ci/cirrus.sh
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "C++ (public headers)"
|
||||
<< : *LINUX_CONTAINER
|
||||
test_script:
|
||||
- g++ -Werror include/*.h
|
||||
- clang -Werror -x c++-header include/*.h
|
||||
- /opt/msvc/bin/x64/cl.exe -c -WX -TP include/*.h
|
||||
|
||||
task:
|
||||
name: "sage prover"
|
||||
<< : *LINUX_CONTAINER
|
||||
test_script:
|
||||
- cd sage
|
||||
- sage prove_group_implementations.sage
|
||||
|
||||
task:
|
||||
name: "x86_64: Windows (VS 2022)"
|
||||
windows_container:
|
||||
image: cirrusci/windowsservercore:visualstudio2022
|
||||
cpu: 4
|
||||
memory: 3840MB
|
||||
env:
|
||||
PATH: '%CIRRUS_WORKING_DIR%\build\src\RelWithDebInfo;%PATH%'
|
||||
x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"'
|
||||
# Ignore MSBuild warning MSB8029.
|
||||
# See: https://learn.microsoft.com/en-us/visualstudio/msbuild/errors/msb8029?view=vs-2022
|
||||
IgnoreWarnIntDirInTempDetected: 'true'
|
||||
merge_script:
|
||||
- PowerShell -NoLogo -Command if ($env:CIRRUS_PR -ne $null) { git fetch $env:CIRRUS_REPO_CLONE_URL pull/$env:CIRRUS_PR/merge; git reset --hard FETCH_HEAD; }
|
||||
configure_script:
|
||||
- '%x64_NATIVE_TOOLS%'
|
||||
- cmake -E env CFLAGS="/WX" cmake -G "Visual Studio 17 2022" -A x64 -S . -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON
|
||||
linux_arm64_container_snippet: &LINUX_ARM64_CONTAINER
|
||||
env_script:
|
||||
- env | tee /tmp/env
|
||||
build_script:
|
||||
- '%x64_NATIVE_TOOLS%'
|
||||
- cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5
|
||||
check_script:
|
||||
- '%x64_NATIVE_TOOLS%'
|
||||
- ctest -C RelWithDebInfo --test-dir build -j 5
|
||||
- build\src\RelWithDebInfo\bench_ecmult.exe
|
||||
- build\src\RelWithDebInfo\bench_internal.exe
|
||||
- build\src\RelWithDebInfo\bench.exe
|
||||
- DOCKER_BUILDKIT=1 docker build --file "ci/linux-debian.Dockerfile" --tag="ci_secp256k1_arm"
|
||||
- docker image prune --force # Cleanup stale layers
|
||||
test_script:
|
||||
- docker run --rm --mount "type=bind,src=./,dst=/ci_secp256k1" --env-file /tmp/env --replace --name "ci_secp256k1_arm" "ci_secp256k1_arm" bash -c "cd /ci_secp256k1/ && ./ci/ci.sh"
|
||||
|
||||
task:
|
||||
name: "ARM64: Linux (Debian stable)"
|
||||
persistent_worker:
|
||||
labels:
|
||||
type: arm64
|
||||
env:
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
ELLSWIFT: yes
|
||||
matrix:
|
||||
# Currently only gcc-snapshot, the other compilers are tested on GHA with QEMU
|
||||
- env: { CC: 'gcc-snapshot' }
|
||||
<< : *LINUX_ARM64_CONTAINER
|
||||
<< : *CAT_LOGS
|
||||
|
||||
task:
|
||||
name: "ARM64: Linux (Debian stable), Valgrind"
|
||||
persistent_worker:
|
||||
labels:
|
||||
type: arm64
|
||||
env:
|
||||
ECDH: yes
|
||||
RECOVERY: yes
|
||||
SCHNORRSIG: yes
|
||||
ELLSWIFT: yes
|
||||
WRAPPER_CMD: 'valgrind --error-exitcode=42'
|
||||
SECP256K1_TEST_ITERS: 2
|
||||
matrix:
|
||||
- env: { CC: 'gcc' }
|
||||
- env: { CC: 'clang' }
|
||||
- env: { CC: 'gcc-snapshot' }
|
||||
- env: { CC: 'clang-snapshot' }
|
||||
<< : *LINUX_ARM64_CONTAINER
|
||||
<< : *CAT_LOGS
|
||||
|
||||
33
.github/actions/install-homebrew-valgrind/action.yml
vendored
Normal file
33
.github/actions/install-homebrew-valgrind/action.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: "Install Valgrind"
|
||||
description: "Install Homebrew's Valgrind package and cache it."
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- run: |
|
||||
brew tap LouisBrunner/valgrind
|
||||
brew fetch --HEAD LouisBrunner/valgrind/valgrind
|
||||
echo "CI_HOMEBREW_CELLAR_VALGRIND=$(brew --cellar valgrind)" >> "$GITHUB_ENV"
|
||||
shell: bash
|
||||
|
||||
- run: |
|
||||
sw_vers > valgrind_fingerprint
|
||||
brew --version >> valgrind_fingerprint
|
||||
git -C "$(brew --cache)/valgrind--git" rev-parse HEAD >> valgrind_fingerprint
|
||||
cat valgrind_fingerprint
|
||||
shell: bash
|
||||
|
||||
- uses: actions/cache@v3
|
||||
id: cache
|
||||
with:
|
||||
path: ${{ env.CI_HOMEBREW_CELLAR_VALGRIND }}
|
||||
key: ${{ github.job }}-valgrind-${{ hashFiles('valgrind_fingerprint') }}
|
||||
|
||||
- if: steps.cache.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
brew install --HEAD LouisBrunner/valgrind/valgrind
|
||||
shell: bash
|
||||
|
||||
- if: steps.cache.outputs.cache-hit == 'true'
|
||||
run: |
|
||||
brew link valgrind
|
||||
shell: bash
|
||||
49
.github/actions/run-in-docker-action/action.yml
vendored
Normal file
49
.github/actions/run-in-docker-action/action.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: 'Run in Docker with environment'
|
||||
description: 'Run a command in a Docker container, while passing explicitly set environment variables into the container.'
|
||||
inputs:
|
||||
dockerfile:
|
||||
description: 'A Dockerfile that defines an image'
|
||||
required: true
|
||||
tag:
|
||||
description: 'A tag of an image'
|
||||
required: true
|
||||
command:
|
||||
description: 'A command to run in a container'
|
||||
required: false
|
||||
default: ./ci/ci.sh
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
|
||||
- uses: docker/build-push-action@v5
|
||||
id: main_builder
|
||||
continue-on-error: true
|
||||
with:
|
||||
context: .
|
||||
file: ${{ inputs.dockerfile }}
|
||||
tags: ${{ inputs.tag }}
|
||||
load: true
|
||||
cache-from: type=gha
|
||||
|
||||
- uses: docker/build-push-action@v5
|
||||
id: retry_builder
|
||||
if: steps.main_builder.outcome == 'failure'
|
||||
with:
|
||||
context: .
|
||||
file: ${{ inputs.dockerfile }}
|
||||
tags: ${{ inputs.tag }}
|
||||
load: true
|
||||
cache-from: type=gha
|
||||
|
||||
- # Tell Docker to pass environment variables in `env` into the container.
|
||||
run: >
|
||||
docker run \
|
||||
$(echo '${{ toJSON(env) }}' | jq -r 'keys[] | "--env \(.) "') \
|
||||
--volume ${{ github.workspace }}:${{ github.workspace }} \
|
||||
--workdir ${{ github.workspace }} \
|
||||
${{ inputs.tag }} bash -c "
|
||||
git config --global --add safe.directory ${{ github.workspace }}
|
||||
${{ inputs.command }}
|
||||
"
|
||||
shell: bash
|
||||
806
.github/workflows/ci.yml
vendored
Normal file
806
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,806 @@
|
||||
name: CI
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- '**'
|
||||
tags-ignore:
|
||||
- '**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
### compiler options
|
||||
HOST:
|
||||
WRAPPER_CMD:
|
||||
# Specific warnings can be disabled with -Wno-error=foo.
|
||||
# -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual.
|
||||
WERROR_CFLAGS: '-Werror -pedantic-errors'
|
||||
MAKEFLAGS: '-j4'
|
||||
BUILD: 'check'
|
||||
### secp256k1 config
|
||||
ECMULTWINDOW: 'auto'
|
||||
ECMULTGENPRECISION: 'auto'
|
||||
ASM: 'no'
|
||||
WIDEMUL: 'auto'
|
||||
WITH_VALGRIND: 'yes'
|
||||
EXTRAFLAGS:
|
||||
### secp256k1 modules
|
||||
EXPERIMENTAL: 'no'
|
||||
ECDH: 'no'
|
||||
RECOVERY: 'no'
|
||||
SCHNORRSIG: 'no'
|
||||
ELLSWIFT: 'no'
|
||||
### test options
|
||||
SECP256K1_TEST_ITERS:
|
||||
BENCH: 'yes'
|
||||
SECP256K1_BENCH_ITERS: 2
|
||||
CTIMETESTS: 'yes'
|
||||
# Compile and run the examples.
|
||||
EXAMPLES: 'yes'
|
||||
|
||||
jobs:
|
||||
docker_cache:
|
||||
name: "Build Docker image"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
# See: https://github.com/moby/buildkit/issues/3969.
|
||||
driver-opts: |
|
||||
network=host
|
||||
|
||||
- name: Build container
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
file: ./ci/linux-debian.Dockerfile
|
||||
tags: linux-debian-image
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=min
|
||||
|
||||
linux_debian:
|
||||
name: "x86_64: Linux (Debian stable)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars: { WIDEMUL: 'int64', RECOVERY: 'yes' }
|
||||
- env_vars: { WIDEMUL: 'int64', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
||||
- env_vars: { WIDEMUL: 'int128' }
|
||||
- env_vars: { WIDEMUL: 'int128_struct', ELLSWIFT: 'yes' }
|
||||
- env_vars: { WIDEMUL: 'int128', RECOVERY: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
||||
- env_vars: { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes' }
|
||||
- env_vars: { WIDEMUL: 'int128', ASM: 'x86_64', ELLSWIFT: 'yes' }
|
||||
- env_vars: { RECOVERY: 'yes', SCHNORRSIG: 'yes' }
|
||||
- env_vars: { CTIMETESTS: 'no', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', CPPFLAGS: '-DVERIFY' }
|
||||
- env_vars: { BUILD: 'distcheck', WITH_VALGRIND: 'no', CTIMETESTS: 'no', BENCH: 'no' }
|
||||
- env_vars: { CPPFLAGS: '-DDETERMINISTIC' }
|
||||
- env_vars: { CFLAGS: '-O0', CTIMETESTS: 'no' }
|
||||
- env_vars: { CFLAGS: '-O1', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
||||
- env_vars: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
|
||||
- env_vars: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 }
|
||||
cc:
|
||||
- 'gcc'
|
||||
- 'clang'
|
||||
- 'gcc-snapshot'
|
||||
- 'clang-snapshot'
|
||||
|
||||
env:
|
||||
CC: ${{ matrix.cc }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
env: ${{ matrix.configuration.env_vars }}
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
i686_debian:
|
||||
name: "i686: Linux (Debian stable)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
cc:
|
||||
- 'i686-linux-gnu-gcc'
|
||||
- 'clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include'
|
||||
|
||||
env:
|
||||
HOST: 'i686-linux-gnu'
|
||||
ECDH: 'yes'
|
||||
RECOVERY: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
CC: ${{ matrix.cc }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
s390x_debian:
|
||||
name: "s390x (big-endian): Linux (Debian stable, QEMU)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
env:
|
||||
WRAPPER_CMD: 'qemu-s390x'
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: 's390x-linux-gnu'
|
||||
WITH_VALGRIND: 'no'
|
||||
ECDH: 'yes'
|
||||
RECOVERY: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
CTIMETESTS: 'no'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
arm32_debian:
|
||||
name: "ARM32: Linux (Debian stable, QEMU)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars: {}
|
||||
- env_vars: { EXPERIMENTAL: 'yes', ASM: 'arm32' }
|
||||
|
||||
env:
|
||||
WRAPPER_CMD: 'qemu-arm'
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: 'arm-linux-gnueabihf'
|
||||
WITH_VALGRIND: 'no'
|
||||
ECDH: 'yes'
|
||||
RECOVERY: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
CTIMETESTS: 'no'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
env: ${{ matrix.configuration.env_vars }}
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
arm64_debian:
|
||||
name: "ARM64: Linux (Debian stable, QEMU)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
env:
|
||||
WRAPPER_CMD: 'qemu-aarch64'
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: 'aarch64-linux-gnu'
|
||||
WITH_VALGRIND: 'no'
|
||||
ECDH: 'yes'
|
||||
RECOVERY: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
CTIMETESTS: 'no'
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars: { } # gcc
|
||||
- env_vars: # clang
|
||||
CC: 'clang --target=aarch64-linux-gnu'
|
||||
- env_vars: # clang-snapshot
|
||||
CC: 'clang-snapshot --target=aarch64-linux-gnu'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
env: ${{ matrix.configuration.env_vars }}
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
ppc64le_debian:
|
||||
name: "ppc64le: Linux (Debian stable, QEMU)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
env:
|
||||
WRAPPER_CMD: 'qemu-ppc64le'
|
||||
SECP256K1_TEST_ITERS: 16
|
||||
HOST: 'powerpc64le-linux-gnu'
|
||||
WITH_VALGRIND: 'no'
|
||||
ECDH: 'yes'
|
||||
RECOVERY: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
CTIMETESTS: 'no'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
valgrind_debian:
|
||||
name: "Valgrind (memcheck)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars: { CC: 'clang', ASM: 'auto' }
|
||||
- env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' }
|
||||
- env_vars: { CC: 'clang', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
|
||||
- env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
|
||||
|
||||
env:
|
||||
# The `--error-exitcode` is required to make the test fail if valgrind found errors,
|
||||
# otherwise it will return 0 (https://www.valgrind.org/docs/manual/manual-core.html).
|
||||
WRAPPER_CMD: 'valgrind --error-exitcode=42'
|
||||
ECDH: 'yes'
|
||||
RECOVERY: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
CTIMETESTS: 'no'
|
||||
SECP256K1_TEST_ITERS: 2
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
env: ${{ matrix.configuration.env_vars }}
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
sanitizers_debian:
|
||||
name: "UBSan, ASan, LSan"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars: { CC: 'clang', ASM: 'auto' }
|
||||
- env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'auto' }
|
||||
- env_vars: { CC: 'clang', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
|
||||
- env_vars: { CC: 'i686-linux-gnu-gcc', HOST: 'i686-linux-gnu', ASM: 'no', ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
|
||||
|
||||
env:
|
||||
ECDH: 'yes'
|
||||
RECOVERY: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
CTIMETESTS: 'no'
|
||||
CFLAGS: '-fsanitize=undefined,address -g'
|
||||
UBSAN_OPTIONS: 'print_stacktrace=1:halt_on_error=1'
|
||||
ASAN_OPTIONS: 'strict_string_checks=1:detect_stack_use_after_return=1:detect_leaks=1'
|
||||
LSAN_OPTIONS: 'use_unaligned=1'
|
||||
SECP256K1_TEST_ITERS: 32
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
env: ${{ matrix.configuration.env_vars }}
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
msan_debian:
|
||||
name: "MSan"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration:
|
||||
- env_vars:
|
||||
CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g'
|
||||
- env_vars:
|
||||
ECMULTGENPRECISION: 2
|
||||
ECMULTWINDOW: 2
|
||||
CFLAGS: '-fsanitize=memory -fsanitize-recover=memory -g -O3'
|
||||
|
||||
env:
|
||||
ECDH: 'yes'
|
||||
RECOVERY: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
CTIMETESTS: 'yes'
|
||||
CC: 'clang'
|
||||
SECP256K1_TEST_ITERS: 32
|
||||
ASM: 'no'
|
||||
WITH_VALGRIND: 'no'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
env: ${{ matrix.configuration.env_vars }}
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
mingw_debian:
|
||||
name: ${{ matrix.configuration.job_name }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
env:
|
||||
WRAPPER_CMD: 'wine'
|
||||
WITH_VALGRIND: 'no'
|
||||
ECDH: 'yes'
|
||||
RECOVERY: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
CTIMETESTS: 'no'
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration:
|
||||
- job_name: 'x86_64 (mingw32-w64): Windows (Debian stable, Wine)'
|
||||
env_vars:
|
||||
HOST: 'x86_64-w64-mingw32'
|
||||
- job_name: 'i686 (mingw32-w64): Windows (Debian stable, Wine)'
|
||||
env_vars:
|
||||
HOST: 'i686-w64-mingw32'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
env: ${{ matrix.configuration.env_vars }}
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
macos-native:
|
||||
name: "x86_64: macOS Monterey"
|
||||
# See: https://github.com/actions/runner-images#available-images.
|
||||
runs-on: macos-12 # Use M1 once available https://github.com/github/roadmap/issues/528
|
||||
|
||||
env:
|
||||
CC: 'clang'
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
env_vars:
|
||||
- { WIDEMUL: 'int64', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
||||
- { WIDEMUL: 'int128_struct', ECMULTGENPRECISION: 2, ECMULTWINDOW: 4 }
|
||||
- { WIDEMUL: 'int128', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
||||
- { WIDEMUL: 'int128', RECOVERY: 'yes' }
|
||||
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes' }
|
||||
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc' }
|
||||
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
|
||||
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CC: 'gcc', WRAPPER_CMD: 'valgrind --error-exitcode=42', SECP256K1_TEST_ITERS: 2 }
|
||||
- { WIDEMUL: 'int128', RECOVERY: 'yes', ECDH: 'yes', SCHNORRSIG: 'yes', ELLSWIFT: 'yes', CPPFLAGS: '-DVERIFY', CTIMETESTS: 'no' }
|
||||
- BUILD: 'distcheck'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Homebrew packages
|
||||
run: |
|
||||
brew install automake libtool gcc
|
||||
ln -s $(brew --prefix gcc)/bin/gcc-?? /usr/local/bin/gcc
|
||||
|
||||
- name: Install and cache Valgrind
|
||||
uses: ./.github/actions/install-homebrew-valgrind
|
||||
|
||||
- name: CI script
|
||||
env: ${{ matrix.env_vars }}
|
||||
run: ./ci/ci.sh
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
win64-native:
|
||||
name: ${{ matrix.configuration.job_name }}
|
||||
# See: https://github.com/actions/runner-images#available-images.
|
||||
runs-on: windows-2022
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration:
|
||||
- job_name: 'x64 (MSVC): Windows (VS 2022, shared)'
|
||||
cmake_options: '-A x64 -DBUILD_SHARED_LIBS=ON'
|
||||
- job_name: 'x64 (MSVC): Windows (VS 2022, static)'
|
||||
cmake_options: '-A x64 -DBUILD_SHARED_LIBS=OFF'
|
||||
- job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct)'
|
||||
cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct'
|
||||
- job_name: 'x64 (MSVC): Windows (VS 2022, int128_struct with __(u)mulh)'
|
||||
cmake_options: '-A x64 -DSECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY=int128_struct'
|
||||
cpp_flags: '/DSECP256K1_MSVC_MULH_TEST_OVERRIDE'
|
||||
- job_name: 'x86 (MSVC): Windows (VS 2022)'
|
||||
cmake_options: '-A Win32'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Generate buildsystem
|
||||
run: cmake -E env CFLAGS="/WX ${{ matrix.configuration.cpp_flags }}" cmake -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON ${{ matrix.configuration.cmake_options }}
|
||||
|
||||
- name: Build
|
||||
run: cmake --build build --config RelWithDebInfo -- /p:UseMultiToolTask=true /maxCpuCount
|
||||
|
||||
- name: Binaries info
|
||||
# Use the bash shell included with Git for Windows.
|
||||
shell: bash
|
||||
run: |
|
||||
cd build/src/RelWithDebInfo && file *tests.exe bench*.exe libsecp256k1-*.dll || true
|
||||
|
||||
- name: Check
|
||||
run: |
|
||||
ctest -C RelWithDebInfo --test-dir build -j ([int]$env:NUMBER_OF_PROCESSORS + 1)
|
||||
build\src\RelWithDebInfo\bench_ecmult.exe
|
||||
build\src\RelWithDebInfo\bench_internal.exe
|
||||
build\src\RelWithDebInfo\bench.exe
|
||||
|
||||
win64-native-headers:
|
||||
name: "x64 (MSVC): C++ (public headers)"
|
||||
# See: https://github.com/actions/runner-images#available-images.
|
||||
runs-on: windows-2022
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Add cl.exe to PATH
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
- name: C++ (public headers)
|
||||
run: |
|
||||
cl.exe -c -WX -TP include/*.h
|
||||
|
||||
cxx_fpermissive_debian:
|
||||
name: "C++ -fpermissive (entire project)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
env:
|
||||
CC: 'g++'
|
||||
CFLAGS: '-fpermissive -g'
|
||||
CPPFLAGS: '-DSECP256K1_CPLUSPLUS_TEST_OVERRIDE'
|
||||
WERROR_CFLAGS:
|
||||
ECDH: 'yes'
|
||||
RECOVERY: 'yes'
|
||||
SCHNORRSIG: 'yes'
|
||||
ELLSWIFT: 'yes'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
|
||||
- run: cat tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat noverify_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat exhaustive_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat ctime_tests.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat bench.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat config.log || true
|
||||
if: ${{ always() }}
|
||||
- run: cat test_env.log || true
|
||||
if: ${{ always() }}
|
||||
- name: CI env
|
||||
run: env
|
||||
if: ${{ always() }}
|
||||
|
||||
cxx_headers_debian:
|
||||
name: "C++ (public headers)"
|
||||
runs-on: ubuntu-latest
|
||||
needs: docker_cache
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
uses: ./.github/actions/run-in-docker-action
|
||||
with:
|
||||
dockerfile: ./ci/linux-debian.Dockerfile
|
||||
tag: linux-debian-image
|
||||
command: |
|
||||
g++ -Werror include/*.h
|
||||
clang -Werror -x c++-header include/*.h
|
||||
|
||||
sage:
|
||||
name: "SageMath prover"
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: sagemath/sagemath:latest
|
||||
options: --user root
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CI script
|
||||
run: |
|
||||
cd sage
|
||||
sage prove_group_implementations.sage
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- run: ./autogen.sh && ./configure --enable-dev-mode && make distcheck
|
||||
|
||||
- name: Check installation with Autotools
|
||||
env:
|
||||
CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install
|
||||
run: |
|
||||
./autogen.sh && ./configure --prefix=${{ env.CI_INSTALL }} && make clean && make install && ls -RlAh ${{ env.CI_INSTALL }}
|
||||
gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=${{ env.CI_INSTALL }}/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"${{ env.CI_INSTALL }}/lib" && ./ecdsa
|
||||
|
||||
- name: Check installation with CMake
|
||||
env:
|
||||
CI_BUILD: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/build
|
||||
CI_INSTALL: ${{ runner.temp }}/${{ github.run_id }}${{ github.action }}/install
|
||||
run: |
|
||||
cmake -B ${{ env.CI_BUILD }} -DCMAKE_INSTALL_PREFIX=${{ env.CI_INSTALL }} && cmake --build ${{ env.CI_BUILD }} --target install && ls -RlAh ${{ env.CI_INSTALL }}
|
||||
gcc -o ecdsa examples/ecdsa.c -I ${{ env.CI_INSTALL }}/include -L ${{ env.CI_INSTALL }}/lib*/ -l secp256k1 -Wl,-rpath,"${{ env.CI_INSTALL }}/lib",-rpath,"${{ env.CI_INSTALL }}/lib64" && ./ecdsa
|
||||
31
CHANGELOG.md
31
CHANGELOG.md
@@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.4.1] - 2023-12-21
|
||||
|
||||
#### Changed
|
||||
- The point multiplication algorithm used for ECDH operations (module `ecdh`) was replaced with a slightly faster one.
|
||||
- Optional handwritten x86_64 assembly for field operations was removed because modern C compilers are able to output more efficient assembly. This change results in a significant speedup of some library functions when handwritten x86_64 assembly is enabled (`--with-asm=x86_64` in GNU Autotools, `-DSECP256K1_ASM=x86_64` in CMake), which is the default on x86_64. Benchmarks with GCC 10.5.0 show a 10% speedup for `secp256k1_ecdsa_verify` and `secp256k1_schnorrsig_verify`.
|
||||
|
||||
#### ABI Compatibility
|
||||
The ABI is backward compatible with versions 0.4.0 and 0.3.x.
|
||||
|
||||
## [0.4.0] - 2023-09-04
|
||||
|
||||
#### Added
|
||||
- New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them.
|
||||
ElligatorSwift permits representing secp256k1 public keys as 64-byte arrays which cannot be distinguished from uniformly random. See:
|
||||
- Header file `include/secp256k1_ellswift.h` which defines the new API.
|
||||
- Document `doc/ellswift.md` which explains the mathematical background of the scheme.
|
||||
- The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based.
|
||||
- We now test the library with unreleased development snapshots of GCC and Clang. This gives us an early chance to catch miscompilations and constant-time issues introduced by the compiler (such as those that led to the previous two releases).
|
||||
|
||||
#### Fixed
|
||||
- Fixed symbol visibility in Windows DLL builds, where three internal library symbols were wrongly exported.
|
||||
|
||||
#### Changed
|
||||
- When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`.
|
||||
|
||||
#### ABI Compatibility
|
||||
This release is backward compatible with the ABI of 0.3.0, 0.3.1, and 0.3.2. Symbol visibility is now believed to be handled properly on supported platforms and is now considered to be part of the ABI. Please report any improperly exported symbols as a bug.
|
||||
|
||||
## [0.3.2] - 2023-05-13
|
||||
We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`.
|
||||
|
||||
@@ -85,7 +113,8 @@ This version was in fact never released.
|
||||
The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6).
|
||||
Therefore, this version number does not uniquely identify a set of source files.
|
||||
|
||||
[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...HEAD
|
||||
[0.4.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.4.0...v0.4.1
|
||||
[0.4.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...v0.4.0
|
||||
[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2
|
||||
[0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1
|
||||
[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0
|
||||
|
||||
@@ -11,7 +11,7 @@ project(libsecp256k1
|
||||
# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
|
||||
# the API. All changes in experimental modules are treated as
|
||||
# backwards-compatible and therefore at most increase the minor version.
|
||||
VERSION 0.3.2
|
||||
VERSION 0.4.1
|
||||
DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1."
|
||||
HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1"
|
||||
LANGUAGES C
|
||||
@@ -34,9 +34,9 @@ endif()
|
||||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
# All changes in experimental modules are treated as if they don't affect the
|
||||
# interface and therefore only increase the revision.
|
||||
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 2)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_REVISION 2)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 3)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_REVISION 1)
|
||||
set(${PROJECT_NAME}_LIB_VERSION_AGE 1)
|
||||
|
||||
set(CMAKE_C_STANDARD 90)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
@@ -71,6 +71,11 @@ if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
|
||||
add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1)
|
||||
endif()
|
||||
|
||||
option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON)
|
||||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||
add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
|
||||
endif()
|
||||
|
||||
option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
|
||||
if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
|
||||
add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1)
|
||||
@@ -102,7 +107,7 @@ if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
|
||||
endif()
|
||||
mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
|
||||
|
||||
set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]")
|
||||
set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]")
|
||||
set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32")
|
||||
check_string_option_value(SECP256K1_ASM)
|
||||
if(SECP256K1_ASM STREQUAL "arm32")
|
||||
@@ -112,7 +117,7 @@ if(SECP256K1_ASM STREQUAL "arm32")
|
||||
if(HAVE_ARM32_ASM)
|
||||
add_compile_definitions(USE_EXTERNAL_ASM=1)
|
||||
else()
|
||||
message(FATAL_ERROR "ARM32 assembly optimization requested but not available.")
|
||||
message(FATAL_ERROR "ARM32 assembly requested but not available.")
|
||||
endif()
|
||||
elseif(SECP256K1_ASM)
|
||||
include(CheckX86_64Assembly)
|
||||
@@ -123,14 +128,14 @@ elseif(SECP256K1_ASM)
|
||||
elseif(SECP256K1_ASM STREQUAL "AUTO")
|
||||
set(SECP256K1_ASM "OFF")
|
||||
else()
|
||||
message(FATAL_ERROR "x86_64 assembly optimization requested but not available.")
|
||||
message(FATAL_ERROR "x86_64 assembly requested but not available.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
|
||||
if(NOT SECP256K1_EXPERIMENTAL)
|
||||
if(SECP256K1_ASM STREQUAL "arm32")
|
||||
message(FATAL_ERROR "ARM32 assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
|
||||
message(FATAL_ERROR "ARM32 assembly is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -212,8 +217,12 @@ endif()
|
||||
include(TryAppendCFlags)
|
||||
if(MSVC)
|
||||
# Keep the following commands ordered lexicographically.
|
||||
try_append_c_flags(/W2) # Moderate warning level.
|
||||
try_append_c_flags(/W3) # Production quality warning level.
|
||||
try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
|
||||
try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
|
||||
try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
|
||||
# Eliminate deprecation warnings for the older, less secure functions.
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
# Keep the following commands ordered lexicographically.
|
||||
try_append_c_flags(-pedantic)
|
||||
@@ -266,11 +275,12 @@ message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}
|
||||
message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}")
|
||||
message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
|
||||
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
|
||||
message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
|
||||
message("Parameters:")
|
||||
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
|
||||
message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
|
||||
message("Optional features:")
|
||||
message(" assembly optimization ............... ${SECP256K1_ASM}")
|
||||
message(" assembly ............................ ${SECP256K1_ASM}")
|
||||
message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}")
|
||||
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
|
||||
message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}")
|
||||
|
||||
107
CONTRIBUTING.md
Normal file
107
CONTRIBUTING.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# Contributing to libsecp256k1
|
||||
|
||||
## Scope
|
||||
|
||||
libsecp256k1 is a library for elliptic curve cryptography on the curve secp256k1, not a general-purpose cryptography library.
|
||||
The library primarily serves the needs of the Bitcoin Core project but provides additional functionality for the benefit of the wider Bitcoin ecosystem.
|
||||
|
||||
## Adding new functionality or modules
|
||||
|
||||
The libsecp256k1 project welcomes contributions in the form of new functionality or modules, provided they are within the project's scope.
|
||||
|
||||
It is the responsibility of the contributors to convince the maintainers that the proposed functionality is within the project's scope, high-quality and maintainable.
|
||||
Contributors are recommended to provide the following in addition to the new code:
|
||||
|
||||
* **Specification:**
|
||||
A specification can help significantly in reviewing the new code as it provides documentation and context.
|
||||
It may justify various design decisions, give a motivation and outline security goals.
|
||||
If the specification contains pseudocode, a reference implementation or test vectors, these can be used to compare with the proposed libsecp256k1 code.
|
||||
* **Security Arguments:**
|
||||
In addition to a defining the security goals, it should be argued that the new functionality meets these goals.
|
||||
Depending on the nature of the new functionality, a wide range of security arguments are acceptable, ranging from being "obviously secure" to rigorous proofs of security.
|
||||
* **Relevance Arguments:**
|
||||
The relevance of the new functionality for the Bitcoin ecosystem should be argued by outlining clear use cases.
|
||||
|
||||
These are not the only factors taken into account when considering to add new functionality.
|
||||
The proposed new libsecp256k1 code must be of high quality, including API documentation and tests, as well as featuring a misuse-resistant API design.
|
||||
|
||||
We recommend reaching out to other contributors (see [Communication Channels](#communication-channels)) and get feedback before implementing new functionality.
|
||||
|
||||
## Communication channels
|
||||
|
||||
Most communication about libsecp256k1 occurs on the GitHub repository: in issues, pull request or on the discussion board.
|
||||
|
||||
Additionally, there is an IRC channel dedicated to libsecp256k1, with biweekly meetings (see channel topic).
|
||||
The channel is `#secp256k1` on Libera Chat.
|
||||
The easiest way to participate on IRC is with the web client, [web.libera.chat](https://web.libera.chat/#secp256k1).
|
||||
Chat history logs can be found at https://gnusha.org/secp256k1/.
|
||||
|
||||
## Contributor workflow & peer review
|
||||
|
||||
The Contributor Workflow & Peer Review in libsecp256k1 are similar to Bitcoin Core's workflow and review processes described in its [CONTRIBUTING.md](https://github.com/bitcoin/bitcoin/blob/master/CONTRIBUTING.md).
|
||||
|
||||
### Coding conventions
|
||||
|
||||
In addition, libsecp256k1 tries to maintain the following coding conventions:
|
||||
|
||||
* No runtime heap allocation (e.g., no `malloc`) unless explicitly requested by the caller (via `secp256k1_context_create` or `secp256k1_scratch_space_create`, for example). Morever, it should be possible to use the library without any heap allocations.
|
||||
* The tests should cover all lines and branches of the library (see [Test coverage](#coverage)).
|
||||
* Operations involving secret data should be tested for being constant time with respect to the secrets (see [src/ctime_tests.c](src/ctime_tests.c)).
|
||||
* Local variables containing secret data should be cleared explicitly to try to delete secrets from memory.
|
||||
* Use `secp256k1_memcmp_var` instead of `memcmp` (see [#823](https://github.com/bitcoin-core/secp256k1/issues/823)).
|
||||
|
||||
#### Style conventions
|
||||
|
||||
* Commits should be atomic and diffs should be easy to read. For this reason, do not mix any formatting fixes or code moves with actual code changes. Make sure each individual commit is hygienic: that it builds successfully on its own without warnings, errors, regressions, or test failures.
|
||||
* New code should adhere to the style of existing, in particular surrounding, code. Other than that, we do not enforce strict rules for code formatting.
|
||||
* The code conforms to C89. Most notably, that means that only `/* ... */` comments are allowed (no `//` line comments). Moreover, any declarations in a `{ ... }` block (e.g., a function) must appear at the beginning of the block before any statements. When you would like to declare a variable in the middle of a block, you can open a new block:
|
||||
```C
|
||||
void secp256k_foo(void) {
|
||||
unsigned int x; /* declaration */
|
||||
int y = 2*x; /* declaration */
|
||||
x = 17; /* statement */
|
||||
{
|
||||
int a, b; /* declaration */
|
||||
a = x + y; /* statement */
|
||||
secp256k_bar(x, &b); /* statement */
|
||||
}
|
||||
}
|
||||
```
|
||||
* Use `unsigned int` instead of just `unsigned`.
|
||||
* Use `void *ptr` instead of `void* ptr`.
|
||||
* Arguments of the publicly-facing API must have a specific order defined in [include/secp256k1.h](include/secp256k1.h).
|
||||
* User-facing comment lines in headers should be limited to 80 chars if possible.
|
||||
* All identifiers in file scope should start with `secp256k1_`.
|
||||
* Avoid trailing whitespace.
|
||||
|
||||
### Tests
|
||||
|
||||
#### Coverage
|
||||
|
||||
This library aims to have full coverage of reachable lines and branches.
|
||||
|
||||
To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary):
|
||||
|
||||
$ ./configure --enable-coverage
|
||||
|
||||
Run the tests:
|
||||
|
||||
$ make check
|
||||
|
||||
To create a report, `gcovr` is recommended, as it includes branch coverage reporting:
|
||||
|
||||
$ gcovr --exclude 'src/bench*' --print-summary
|
||||
|
||||
To create a HTML report with coloured and annotated source code:
|
||||
|
||||
$ mkdir -p coverage
|
||||
$ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html
|
||||
|
||||
#### Exhaustive tests
|
||||
|
||||
There are tests of several functions in which a small group replaces secp256k1.
|
||||
These tests are *exhaustive* since they provide all elements and scalars of the small group as input arguments (see [src/tests_exhaustive.c](src/tests_exhaustive.c)).
|
||||
|
||||
### Benchmarks
|
||||
|
||||
See `src/bench*.c` for examples of benchmarks.
|
||||
16
Makefile.am
16
Makefile.am
@@ -37,7 +37,6 @@ noinst_HEADERS += src/field_10x26_impl.h
|
||||
noinst_HEADERS += src/field_5x52.h
|
||||
noinst_HEADERS += src/field_5x52_impl.h
|
||||
noinst_HEADERS += src/field_5x52_int128_impl.h
|
||||
noinst_HEADERS += src/field_5x52_asm_impl.h
|
||||
noinst_HEADERS += src/modinv32.h
|
||||
noinst_HEADERS += src/modinv32_impl.h
|
||||
noinst_HEADERS += src/modinv64.h
|
||||
@@ -46,6 +45,7 @@ noinst_HEADERS += src/precomputed_ecmult.h
|
||||
noinst_HEADERS += src/precomputed_ecmult_gen.h
|
||||
noinst_HEADERS += src/assumptions.h
|
||||
noinst_HEADERS += src/checkmem.h
|
||||
noinst_HEADERS += src/testutil.h
|
||||
noinst_HEADERS += src/util.h
|
||||
noinst_HEADERS += src/int128.h
|
||||
noinst_HEADERS += src/int128_impl.h
|
||||
@@ -153,7 +153,7 @@ endif
|
||||
if USE_EXAMPLES
|
||||
noinst_PROGRAMS += ecdsa_example
|
||||
ecdsa_example_SOURCES = examples/ecdsa.c
|
||||
ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||
ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
|
||||
ecdsa_example_LDADD = libsecp256k1.la
|
||||
ecdsa_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
@@ -163,7 +163,7 @@ 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_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
|
||||
ecdh_example_LDADD = libsecp256k1.la
|
||||
ecdh_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
@@ -174,7 +174,7 @@ endif
|
||||
if ENABLE_MODULE_SCHNORRSIG
|
||||
noinst_PROGRAMS += schnorr_example
|
||||
schnorr_example_SOURCES = examples/schnorr.c
|
||||
schnorr_example_CPPFLAGS = -I$(top_srcdir)/include
|
||||
schnorr_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
|
||||
schnorr_example_LDADD = libsecp256k1.la
|
||||
schnorr_example_LDFLAGS = -static
|
||||
if BUILD_WINDOWS
|
||||
@@ -189,11 +189,11 @@ EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen
|
||||
CLEANFILES = $(EXTRA_PROGRAMS)
|
||||
|
||||
precompute_ecmult_SOURCES = src/precompute_ecmult.c
|
||||
precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY
|
||||
precompute_ecmult_LDADD = $(COMMON_LIB)
|
||||
|
||||
precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c
|
||||
precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES)
|
||||
precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY
|
||||
precompute_ecmult_gen_LDADD = $(COMMON_LIB)
|
||||
|
||||
# See Automake manual, Section "Errors with distclean".
|
||||
@@ -267,3 +267,7 @@ endif
|
||||
if ENABLE_MODULE_SCHNORRSIG
|
||||
include src/modules/schnorrsig/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_ELLSWIFT
|
||||
include src/modules/ellswift/Makefile.am.include
|
||||
endif
|
||||
|
||||
32
README.md
32
README.md
@@ -1,11 +1,10 @@
|
||||
libsecp256k1
|
||||
============
|
||||
|
||||
[](https://cirrus-ci.com/github/bitcoin-core/secp256k1)
|
||||

|
||||
[](https://web.libera.chat/#secp256k1)
|
||||
|
||||
Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.
|
||||
High-performance high-assurance C library for digital signatures and other cryptographic primitives on the secp256k1 elliptic curve.
|
||||
|
||||
This library is intended to be the highest quality publicly available library for cryptography on the secp256k1 curve. However, the primary focus of its development has been for usage in the Bitcoin system and usage unlike Bitcoin's may be less well tested, verified, or suffer from a less well thought out interface. Correct usage requires some care and consideration that the library is fit for your application's purpose.
|
||||
|
||||
@@ -34,7 +33,7 @@ Implementation details
|
||||
* Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
|
||||
* Field operations
|
||||
* 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
|
||||
* 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
|
||||
@@ -117,28 +116,6 @@ Usage examples can be found in the [examples](examples) directory. To compile th
|
||||
|
||||
To compile the Schnorr signature and ECDH examples, you also need to configure with `--enable-module-schnorrsig` and `--enable-module-ecdh`.
|
||||
|
||||
Test coverage
|
||||
-----------
|
||||
|
||||
This library aims to have full coverage of the reachable lines and branches.
|
||||
|
||||
To create a test coverage report, configure with `--enable-coverage` (use of GCC is necessary):
|
||||
|
||||
$ ./configure --enable-coverage
|
||||
|
||||
Run the tests:
|
||||
|
||||
$ make check
|
||||
|
||||
To create a report, `gcovr` is recommended, as it includes branch coverage reporting:
|
||||
|
||||
$ gcovr --exclude 'src/bench*' --print-summary
|
||||
|
||||
To create a HTML report with coloured and annotated source code:
|
||||
|
||||
$ mkdir -p coverage
|
||||
$ gcovr --exclude 'src/bench*' --html --html-details -o coverage/coverage.html
|
||||
|
||||
Benchmark
|
||||
------------
|
||||
If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1 functions will be present in the root directory after the build.
|
||||
@@ -155,3 +132,8 @@ Reporting a vulnerability
|
||||
------------
|
||||
|
||||
See [SECURITY.md](SECURITY.md)
|
||||
|
||||
Contributing to libsecp256k1
|
||||
------------
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
@@ -4,7 +4,8 @@ set -eux
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
# Print relevant CI environment to allow reproducing the job outside of CI.
|
||||
# Print commit and relevant CI environment to allow reproducing the job outside of CI.
|
||||
git show --no-patch
|
||||
print_environment() {
|
||||
# Turn off -x because it messes up the output
|
||||
set +x
|
||||
@@ -12,7 +13,7 @@ print_environment() {
|
||||
# does not rely on bash.
|
||||
for var in WERROR_CFLAGS MAKEFLAGS BUILD \
|
||||
ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
|
||||
EXPERIMENTAL ECDH RECOVERY SCHNORRSIG \
|
||||
EXPERIMENTAL ECDH RECOVERY SCHNORRSIG ELLSWIFT \
|
||||
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
|
||||
EXAMPLES \
|
||||
HOST WRAPPER_CMD \
|
||||
@@ -30,19 +31,15 @@ print_environment() {
|
||||
}
|
||||
print_environment
|
||||
|
||||
# Start persistent wineserver if necessary.
|
||||
# This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously.
|
||||
case "$WRAPPER_CMD" in
|
||||
*wine*)
|
||||
# Make sure to shutdown wineserver whenever we exit.
|
||||
trap "wineserver -k || true" EXIT INT HUP
|
||||
# This is apparently only reliable when we run a dummy command such as "hh.exe" afterwards.
|
||||
wineserver -p && wine hh.exe
|
||||
env >> test_env.log
|
||||
|
||||
# If gcc is requested, assert that it's in fact gcc (and not some symlinked Apple clang).
|
||||
case "${CC:-undefined}" in
|
||||
*gcc*)
|
||||
$CC -v 2>&1 | grep -q "gcc version" || exit 1;
|
||||
;;
|
||||
esac
|
||||
|
||||
env >> test_env.log
|
||||
|
||||
if [ -n "${CC+x}" ]; then
|
||||
# The MSVC compiler "cl" doesn't understand "-v"
|
||||
$CC -v || true
|
||||
@@ -54,6 +51,22 @@ if [ -n "$WRAPPER_CMD" ]; then
|
||||
$WRAPPER_CMD --version
|
||||
fi
|
||||
|
||||
# Workaround for https://bugs.kde.org/show_bug.cgi?id=452758 (fixed in valgrind 3.20.0).
|
||||
case "${CC:-undefined}" in
|
||||
clang*)
|
||||
if [ "$CTIMETESTS" = "yes" ] && [ "$WITH_VALGRIND" = "yes" ]
|
||||
then
|
||||
export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4"
|
||||
else
|
||||
case "$WRAPPER_CMD" in
|
||||
valgrind*)
|
||||
export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
./autogen.sh
|
||||
|
||||
./configure \
|
||||
@@ -62,6 +75,7 @@ fi
|
||||
--with-ecmult-window="$ECMULTWINDOW" \
|
||||
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
|
||||
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
|
||||
--enable-module-ellswift="$ELLSWIFT" \
|
||||
--enable-module-schnorrsig="$SCHNORRSIG" \
|
||||
--enable-examples="$EXAMPLES" \
|
||||
--enable-ctime-tests="$CTIMETESTS" \
|
||||
@@ -69,7 +83,21 @@ fi
|
||||
--host="$HOST" $EXTRAFLAGS
|
||||
|
||||
# We have set "-j<n>" in MAKEFLAGS.
|
||||
make
|
||||
build_exit_code=0
|
||||
make > make.log 2>&1 || build_exit_code=$?
|
||||
cat make.log
|
||||
if [ $build_exit_code -ne 0 ]; then
|
||||
case "${CC:-undefined}" in
|
||||
*snapshot*)
|
||||
# Ignore internal compiler errors in gcc-snapshot and clang-snapshot
|
||||
grep -e "internal compiler error:" -e "PLEASE submit a bug report" make.log
|
||||
return $?;
|
||||
;;
|
||||
*)
|
||||
return 1;
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Print information about binaries so that we can see that the architecture is correct
|
||||
file *tests* || true
|
||||
@@ -1,4 +1,17 @@
|
||||
FROM debian:stable
|
||||
FROM debian:stable-slim
|
||||
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
|
||||
WORKDIR /root
|
||||
|
||||
# A too high maximum number of file descriptors (with the default value
|
||||
# inherited from the docker host) can cause issues with some of our tools:
|
||||
# - sanitizers hanging: https://github.com/google/sanitizers/issues/1662
|
||||
# - valgrind crashing: https://stackoverflow.com/a/75293014
|
||||
# This is not be a problem on our CI hosts, but developers who run the image
|
||||
# on their machines may run into this (e.g., on Arch Linux), so warn them.
|
||||
# (Note that .bashrc is only executed in interactive bash shells.)
|
||||
RUN echo 'if [[ $(ulimit -n) -gt 200000 ]]; then echo "WARNING: Very high value reported by \"ulimit -n\". Consider passing \"--ulimit nofile=32768\" to \"docker run\"."; fi' >> /root/.bashrc
|
||||
|
||||
RUN dpkg --add-architecture i386 && \
|
||||
dpkg --add-architecture s390x && \
|
||||
@@ -11,27 +24,56 @@ RUN dpkg --add-architecture i386 && \
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
git ca-certificates \
|
||||
make automake libtool pkg-config dpkg-dev valgrind qemu-user \
|
||||
gcc clang llvm libc6-dbg \
|
||||
gcc clang llvm libclang-rt-dev libc6-dbg \
|
||||
g++ \
|
||||
gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan6:i386 \
|
||||
gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan8:i386 \
|
||||
gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \
|
||||
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
|
||||
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
|
||||
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
|
||||
gcc-mingw-w64-x86-64-win32 wine64 wine \
|
||||
gcc-mingw-w64-i686-win32 wine32 \
|
||||
sagemath
|
||||
python3 && \
|
||||
if ! ( dpkg --print-architecture | grep --quiet "arm64" ) ; then \
|
||||
apt-get install --no-install-recommends -y \
|
||||
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 ;\
|
||||
fi && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /root
|
||||
# The "wine" package provides a convience wrapper that we need
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
git ca-certificates wine64 wine python3-simplejson python3-six msitools winbind procps && \
|
||||
git clone https://github.com/mstorsjo/msvc-wine && \
|
||||
mkdir /opt/msvc && \
|
||||
python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \
|
||||
msvc-wine/install.sh /opt/msvc
|
||||
# Build and install gcc snapshot
|
||||
ARG GCC_SNAPSHOT_MAJOR=14
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \
|
||||
mkdir gcc && cd gcc && \
|
||||
wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --level 1 --no-directories "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}" && \
|
||||
wget "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}/sha512.sum" && \
|
||||
sha512sum --check --ignore-missing sha512.sum && \
|
||||
# We should have downloaded exactly one tar.xz file
|
||||
ls && \
|
||||
[ $(ls *.tar.xz | wc -l) -eq "1" ] && \
|
||||
tar xf *.tar.xz && \
|
||||
mkdir gcc-build && cd gcc-build && \
|
||||
../*/configure --prefix=/opt/gcc-snapshot --enable-languages=c --disable-bootstrap --disable-multilib --without-isl && \
|
||||
make -j $(nproc) && \
|
||||
make install && \
|
||||
cd ../.. && rm -rf gcc && \
|
||||
ln -s /opt/gcc-snapshot/bin/gcc /usr/bin/gcc-snapshot && \
|
||||
apt-get autoremove -y wget libgmp-dev libmpfr-dev libmpc-dev flex && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install clang snapshot, see https://apt.llvm.org/
|
||||
RUN \
|
||||
# Setup GPG keys of LLVM repository
|
||||
apt-get update && apt-get install --no-install-recommends -y wget && \
|
||||
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \
|
||||
# Add repository for this Debian release
|
||||
. /etc/os-release && echo "deb http://apt.llvm.org/${VERSION_CODENAME} llvm-toolchain-${VERSION_CODENAME} main" >> /etc/apt/sources.list && \
|
||||
apt-get update && \
|
||||
# Determine the version number of the LLVM development branch
|
||||
LLVM_VERSION=$(apt-cache search --names-only '^clang-[0-9]+$' | sort -V | tail -1 | cut -f1 -d" " | cut -f2 -d"-" ) && \
|
||||
# Install
|
||||
apt-get install --no-install-recommends -y "clang-${LLVM_VERSION}" && \
|
||||
# Create symlink
|
||||
ln -s "/usr/bin/clang-${LLVM_VERSION}" /usr/bin/clang-snapshot && \
|
||||
# Clean up
|
||||
apt-get autoremove -y wget && \
|
||||
apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Initialize the wine environment. Wait until the wineserver process has
|
||||
# exited before closing the session, to avoid corrupting the wine prefix.
|
||||
RUN wine64 wineboot --init && \
|
||||
while (ps -A | grep wineserver) > /dev/null; do sleep 1; done
|
||||
|
||||
8
cmake/GeneratePkgConfigFile.cmake
Normal file
8
cmake/GeneratePkgConfigFile.cmake
Normal file
@@ -0,0 +1,8 @@
|
||||
function(generate_pkg_config_file in_file)
|
||||
set(prefix ${CMAKE_INSTALL_PREFIX})
|
||||
set(exec_prefix \${prefix})
|
||||
set(libdir \${exec_prefix}/${CMAKE_INSTALL_LIBDIR})
|
||||
set(includedir \${prefix}/${CMAKE_INSTALL_INCLUDEDIR})
|
||||
set(PACKAGE_VERSION ${PROJECT_VERSION})
|
||||
configure_file(${in_file} ${PROJECT_NAME}.pc @ONLY)
|
||||
endfunction()
|
||||
47
configure.ac
47
configure.ac
@@ -4,8 +4,8 @@ AC_PREREQ([2.60])
|
||||
# the API. All changes in experimental modules are treated as
|
||||
# backwards-compatible and therefore at most increase the minor version.
|
||||
define(_PKG_VERSION_MAJOR, 0)
|
||||
define(_PKG_VERSION_MINOR, 3)
|
||||
define(_PKG_VERSION_PATCH, 2)
|
||||
define(_PKG_VERSION_MINOR, 4)
|
||||
define(_PKG_VERSION_PATCH, 1)
|
||||
define(_PKG_VERSION_IS_RELEASE, true)
|
||||
|
||||
# The library version is based on libtool versioning of the ABI. The set of
|
||||
@@ -13,9 +13,9 @@ define(_PKG_VERSION_IS_RELEASE, true)
|
||||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
# All changes in experimental modules are treated as if they don't affect the
|
||||
# interface and therefore only increase the revision.
|
||||
define(_LIB_VERSION_CURRENT, 2)
|
||||
define(_LIB_VERSION_REVISION, 2)
|
||||
define(_LIB_VERSION_AGE, 0)
|
||||
define(_LIB_VERSION_CURRENT, 3)
|
||||
define(_LIB_VERSION_REVISION, 1)
|
||||
define(_LIB_VERSION_AGE, 1)
|
||||
|
||||
AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
|
||||
|
||||
@@ -121,13 +121,12 @@ AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
|
||||
# libtool makes the same assumption internally.
|
||||
# Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path.
|
||||
if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then
|
||||
SECP_TRY_APPEND_CFLAGS([-W2 -wd4146], $1) # Moderate warning level, disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned"
|
||||
# We pass -ignore:4217 to the MSVC linker to suppress warning 4217 when
|
||||
# importing variables from a statically linked secp256k1.
|
||||
# (See the libtool manual, section "Windows DLLs" for background.)
|
||||
# Unfortunately, libtool tries to be too clever and strips "-Xlinker arg"
|
||||
# into "arg", so this will be " -Xlinker -ignore:4217" after stripping.
|
||||
LDFLAGS="-Xlinker -Xlinker -Xlinker -ignore:4217 $LDFLAGS"
|
||||
SECP_TRY_APPEND_CFLAGS([-W3], $1) # Production quality warning level.
|
||||
SECP_TRY_APPEND_CFLAGS([-wd4146], $1) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
|
||||
SECP_TRY_APPEND_CFLAGS([-wd4244], $1) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
|
||||
SECP_TRY_APPEND_CFLAGS([-wd4267], $1) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
|
||||
# Eliminate deprecation warnings for the older, less secure functions.
|
||||
CPPFLAGS="-D_CRT_SECURE_NO_WARNINGS $CPPFLAGS"
|
||||
fi
|
||||
])
|
||||
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
|
||||
@@ -185,6 +184,10 @@ AC_ARG_ENABLE(module_schnorrsig,
|
||||
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
|
||||
[SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(module_ellswift,
|
||||
AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [],
|
||||
[SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])])
|
||||
|
||||
AC_ARG_ENABLE(external_default_callbacks,
|
||||
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]), [],
|
||||
[SECP_SET_DEFAULT([enable_external_default_callbacks], [no], [no])])
|
||||
@@ -198,7 +201,7 @@ AC_ARG_ENABLE(external_default_callbacks,
|
||||
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
|
||||
|
||||
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm32|no|auto],
|
||||
[assembly optimizations to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
|
||||
[assembly to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
|
||||
|
||||
AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto],
|
||||
[window size for ecmult precomputation for verification, specified as integer in range [2..24].]
|
||||
@@ -276,24 +279,24 @@ else
|
||||
x86_64)
|
||||
SECP_X86_64_ASM_CHECK
|
||||
if test x"$has_x86_64_asm" != x"yes"; then
|
||||
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
|
||||
AC_MSG_ERROR([x86_64 assembly requested but not available])
|
||||
fi
|
||||
;;
|
||||
arm32)
|
||||
SECP_ARM32_ASM_CHECK
|
||||
if test x"$has_arm32_asm" != x"yes"; then
|
||||
AC_MSG_ERROR([ARM32 assembly optimization requested but not available])
|
||||
AC_MSG_ERROR([ARM32 assembly requested but not available])
|
||||
fi
|
||||
;;
|
||||
no)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid assembly optimization selection])
|
||||
AC_MSG_ERROR([invalid assembly selection])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Select assembly optimization
|
||||
# Select assembly
|
||||
enable_external_asm=no
|
||||
|
||||
case $set_asm in
|
||||
@@ -306,7 +309,7 @@ arm32)
|
||||
no)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid assembly optimizations])
|
||||
AC_MSG_ERROR([invalid assembly selection])
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -397,6 +400,10 @@ if test x"$enable_module_schnorrsig" = x"yes"; then
|
||||
enable_module_extrakeys=yes
|
||||
fi
|
||||
|
||||
if test x"$enable_module_ellswift" = x"yes"; then
|
||||
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1"
|
||||
fi
|
||||
|
||||
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
|
||||
# module to set enable_module_extrakeys=yes
|
||||
if test x"$enable_module_extrakeys" = x"yes"; then
|
||||
@@ -418,7 +425,7 @@ if test x"$enable_experimental" = x"yes"; then
|
||||
AC_MSG_NOTICE([******])
|
||||
else
|
||||
if test x"$set_asm" = x"arm32"; then
|
||||
AC_MSG_ERROR([ARM32 assembly optimization is experimental. Use --enable-experimental to allow.])
|
||||
AC_MSG_ERROR([ARM32 assembly is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -439,6 +446,7 @@ AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
|
||||
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"])
|
||||
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
|
||||
@@ -460,6 +468,7 @@ echo " module ecdh = $enable_module_ecdh"
|
||||
echo " module recovery = $enable_module_recovery"
|
||||
echo " module extrakeys = $enable_module_extrakeys"
|
||||
echo " module schnorrsig = $enable_module_schnorrsig"
|
||||
echo " module ellswift = $enable_module_ellswift"
|
||||
echo
|
||||
echo " asm = $set_asm"
|
||||
echo " ecmult window size = $set_ecmult_window"
|
||||
|
||||
483
doc/ellswift.md
Normal file
483
doc/ellswift.md
Normal file
@@ -0,0 +1,483 @@
|
||||
# ElligatorSwift for secp256k1 explained
|
||||
|
||||
In this document we explain how the `ellswift` module implementation is related to the
|
||||
construction in the
|
||||
["SwiftEC: Shallue–van de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759)
|
||||
paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi.
|
||||
|
||||
* [1. Introduction](#1-introduction)
|
||||
* [2. The decoding function](#2-the-decoding-function)
|
||||
+ [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1)
|
||||
* [3. The encoding function](#3-the-encoding-function)
|
||||
+ [3.1 Switching to *v, w* coordinates](#31-switching-to-v-w-coordinates)
|
||||
+ [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses)
|
||||
+ [3.3 Finding the inverse](#33-finding-the-inverse)
|
||||
+ [3.4 Dealing with special cases](#34-dealing-with-special-cases)
|
||||
+ [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1)
|
||||
* [4. Encoding and decoding full *(x, y)* coordinates](#4-encoding-and-decoding-full-x-y-coordinates)
|
||||
+ [4.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1)
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
The `ellswift` module effectively introduces a new 64-byte public key format, with the property
|
||||
that (uniformly random) public keys can be encoded as 64-byte arrays which are computationally
|
||||
indistinguishable from uniform byte arrays. The module provides functions to convert public keys
|
||||
from and to this format, as well as convenience functions for key generation and ECDH that operate
|
||||
directly on ellswift-encoded keys.
|
||||
|
||||
The encoding consists of the concatenation of two (32-byte big endian) encoded field elements $u$
|
||||
and $t.$ Together they encode an x-coordinate on the curve $x$, or (see further) a full point $(x, y)$ on
|
||||
the curve.
|
||||
|
||||
**Decoding** consists of decoding the field elements $u$ and $t$ (values above the field size $p$
|
||||
are taken modulo $p$), and then evaluating $F_u(t)$, which for every $u$ and $t$ results in a valid
|
||||
x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function).
|
||||
|
||||
**Encoding** a given $x$ coordinate is conceptually done as follows:
|
||||
* Loop:
|
||||
* Pick a uniformly random field element $u.$
|
||||
* Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to *8* elements.
|
||||
* With probability $1 - \dfrac{\\#L}{8}$, restart the loop.
|
||||
* Select a uniformly random $t \in L$ and return $(u, t).$
|
||||
|
||||
This is the *ElligatorSwift* algorithm, here given for just x-coordinates. An extension to full
|
||||
$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates).
|
||||
The algorithm finds a uniformly random $(u, t)$ among (almost all) those
|
||||
for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for
|
||||
almost all x-coordinates on the curve (all but at most 39) is close to two times the field size
|
||||
(specifically, it lies in the range $2q \pm (22\sqrt{q} + O(1))$, where $q$ is the size of the field).
|
||||
|
||||
## 2. The decoding function
|
||||
|
||||
First some definitions:
|
||||
* $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$
|
||||
* For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement.
|
||||
* Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$
|
||||
public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square.
|
||||
This implies that the order of $E$ is either odd, or a multiple of *4*.
|
||||
If $a=0$, this condition is always fulfilled.
|
||||
* For `secp256k1`, $a=0$ and $b=7.$
|
||||
* Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$
|
||||
* Let the function $h(x) = 3x^3 + 4a.$
|
||||
* Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$
|
||||
* Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$
|
||||
* $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below.
|
||||
* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below.
|
||||
|
||||
**Note**: In the paper:
|
||||
* $F_u$ corresponds to $F_{0,u}$ there.
|
||||
* $P_u(t)$ is called $P$ there.
|
||||
* All $S_u$ sets together correspond to $S$ there.
|
||||
* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there.
|
||||
|
||||
Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right
|
||||
hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$,
|
||||
out of the three right-hand side factors an even number must be non-squares.
|
||||
This implies that exactly *1* or exactly *3* out of
|
||||
$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$,
|
||||
at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception
|
||||
to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate.
|
||||
|
||||
**Define** the decoding function $F_u(t)$ as:
|
||||
* Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$
|
||||
* Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square).
|
||||
|
||||
$P_u(t) = (X(u, t), Y(u, t))$, where:
|
||||
|
||||
$$
|
||||
\begin{array}{lcl}
|
||||
X(u, t) & = & \left\\{\begin{array}{ll}
|
||||
\dfrac{g(u) - t^2}{2t} & a = 0 \\
|
||||
\dfrac{g(u) + h(u)(Y_0(u) - X_0(u)t)^2}{X_0(u)(1 + h(u)t^2)} & a \neq 0
|
||||
\end{array}\right. \\
|
||||
Y(u, t) & = & \left\\{\begin{array}{ll}
|
||||
\dfrac{X(u, t) + t}{u \sqrt{-3}} = \dfrac{g(u) + t^2}{2tu\sqrt{-3}} & a = 0 \\
|
||||
Y_0(u) + t(X(u, t) - X_0(u)) & a \neq 0
|
||||
\end{array}\right.
|
||||
\end{array}
|
||||
$$
|
||||
|
||||
$P_u(t)$ is defined:
|
||||
* For $a=0$, unless:
|
||||
* $u = 0$ or $t = 0$ (division by zero)
|
||||
* $g(u) = -t^2$ (would give $Y=0$).
|
||||
* For $a \neq 0$, unless:
|
||||
* $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero)
|
||||
* $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$).
|
||||
|
||||
The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$
|
||||
|
||||
The function $\psi_u$ is the same for all curves: $\psi_u(X, Y) = (x_1, x_2, x_3, z)$, where:
|
||||
|
||||
$$
|
||||
\begin{array}{lcl}
|
||||
x_1 & = & \dfrac{X}{2Y} - \dfrac{u}{2} && \\
|
||||
x_2 & = & -\dfrac{X}{2Y} - \dfrac{u}{2} && \\
|
||||
x_3 & = & u + 4Y^2 && \\
|
||||
z & = & \dfrac{g(x_3)}{2Y}(u^2 + ux_1 + x_1^2 + a) = \dfrac{-g(u)g(x_3)}{8Y^3}
|
||||
\end{array}
|
||||
$$
|
||||
|
||||
### 2.1 Decoding for `secp256k1`
|
||||
|
||||
Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is:
|
||||
|
||||
**Define** $F_u(t)$ as:
|
||||
* Let $X = \dfrac{u^3 + b - t^2}{2t}.$
|
||||
* Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$
|
||||
* Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square.
|
||||
|
||||
To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case
|
||||
$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$):
|
||||
|
||||
**Define** $F_u(t)$ as:
|
||||
* Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$).
|
||||
* Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$).
|
||||
* Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$).
|
||||
* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
|
||||
* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
|
||||
* Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square.
|
||||
|
||||
The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice,
|
||||
but the approach here is simple enough and gives fairly uniform output even in these cases.
|
||||
|
||||
**Note**: in the paper these conditions result in $\infty$ as output, due to the use of projective coordinates there.
|
||||
We wish to avoid the need for callers to deal with this special case.
|
||||
|
||||
This is implemented in `secp256k1_ellswift_xswiftec_frac_var` (which decodes to an x-coordinate represented as a fraction), and
|
||||
in `secp256k1_ellswift_xswiftec_var` (which outputs the actual x-coordinate).
|
||||
|
||||
## 3. The encoding function
|
||||
|
||||
To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process:
|
||||
* Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$
|
||||
* Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$
|
||||
* For each of the found $t$ values, verify that $F_u(t) = x.$
|
||||
* Return the remaining $t$ values.
|
||||
|
||||
The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$
|
||||
|
||||
$$
|
||||
P_u^{-1}(X, Y) = \left\\{\begin{array}{ll}
|
||||
Yu\sqrt{-3} - X & a = 0 \\
|
||||
\dfrac{Y-Y_0(u)}{X-X_0(u)} & a \neq 0 \land X \neq X_0(u) \\
|
||||
\dfrac{-X_0(u)}{h(u)Y_0(u)} & a \neq 0 \land X = X_0(u) \land Y = Y_0(u)
|
||||
\end{array}\right.
|
||||
$$
|
||||
|
||||
The third step above, verifying that $F_u(t) = x$, is necessary because for the $(X, Y)$ values found through the $x_1$ and $x_2$ expressions,
|
||||
it is possible that decoding through $\psi_u(X, Y)$ yields a valid $x_3$ on the curve, which would take precedence over the
|
||||
$x_1$ or $x_2$ decoding. These $(X, Y)$ solutions must be rejected.
|
||||
|
||||
Since we know that exactly one or exactly three out of $\\{x_1, x_2, x_3\\}$ are valid x-coordinates for any $t$,
|
||||
the case where either $x_1$ or $x_2$ is valid and in addition also $x_3$ is valid must mean that all three are valid.
|
||||
This means that instead of checking whether $x_3$ is on the curve, it is also possible to check whether the other one out of
|
||||
$x_1$ and $x_2$ is on the curve. This is significantly simpler, as it turns out.
|
||||
|
||||
Observe that $\psi_u$ guarantees that $x_1 + x_2 = -u.$ So given either $x = x_1$ or $x = x_2$, the other one of the two can be computed as
|
||||
$-u - x.$ Thus, when encoding $x$ through the $x_1$ or $x_2$ expressions, one can simply check whether $g(-u-x)$ is a square,
|
||||
and if so, not include the corresponding $t$ values in the returned set. As this does not need $X$, $Y$, or $t$, this condition can be determined
|
||||
before those values are computed.
|
||||
|
||||
It is not possible that an encoding found through the $x_1$ expression decodes to a different valid x-coordinate using $x_2$ (which would
|
||||
take precedence), for the same reason: if both $x_1$ and $x_2$ decodings were valid, $x_3$ would be valid as well, and thus take
|
||||
precedence over both. Because of this, the $g(-u-x)$ being square test for $x_1$ and $x_2$ is the only test necessary to guarantee the found $t$
|
||||
values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder;
|
||||
any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder.
|
||||
|
||||
### 3.1 Switching to *v, w* coordinates
|
||||
|
||||
Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and
|
||||
$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$
|
||||
* $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$
|
||||
* For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$
|
||||
* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where
|
||||
|
||||
$$
|
||||
\begin{array}{lcl}
|
||||
x_1 & = & v \\
|
||||
x_2 & = & -u - v \\
|
||||
x_3 & = & u + w^2 \\
|
||||
z & = & \dfrac{g(x_3)}{w}(u^2 + uv + v^2 + a) = \dfrac{-g(u)g(x_3)}{w^3}
|
||||
\end{array}
|
||||
$$
|
||||
|
||||
We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$
|
||||
expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable:
|
||||
* Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
|
||||
* Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
|
||||
* Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions).
|
||||
|
||||
### 3.2 Avoiding computing all inverses
|
||||
|
||||
The *ElligatorSwift* algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the
|
||||
set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary.
|
||||
|
||||
Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a
|
||||
uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8,
|
||||
picking a uniformly random element from that, restarting whenever $\bot$ is picked:
|
||||
|
||||
**Define** *ElligatorSwift(x)* as:
|
||||
* Loop:
|
||||
* Pick a uniformly random field element $u.$
|
||||
* Compute the set $L = F_u^{-1}(x).$
|
||||
* Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$
|
||||
* Select a uniformly random $t \in T.$
|
||||
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
||||
|
||||
Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly
|
||||
random element in it, so we do not need to have all $\bot$ values at the end.
|
||||
As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account),
|
||||
we can associate every index in $T$ with exactly one of those formulas, making sure that:
|
||||
* Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$
|
||||
* For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check).
|
||||
* In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those.
|
||||
|
||||
The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting
|
||||
to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases)
|
||||
for an analysis of all the negligible cases.
|
||||
|
||||
If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas,
|
||||
the loop can be simplified to only compute one of the inverses instead of all of them:
|
||||
|
||||
**Define** *ElligatorSwift(x)* as:
|
||||
* Loop:
|
||||
* Pick a uniformly random field element $u.$
|
||||
* Pick a uniformly random integer $c$ in $[0,8).$
|
||||
* Let $t = G_{c,u}(x).$
|
||||
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
||||
|
||||
This is implemented in `secp256k1_ellswift_xelligatorswift_var`.
|
||||
|
||||
### 3.3 Finding the inverse
|
||||
|
||||
To implement $G_{c,u}$, we map $c=0$ to the $x_1$ formula, $c=1$ to the $x_2$ formula, and $c=2$ and $c=3$ to the $x_3$ formula.
|
||||
Those are then repeated as $c=4$ through $c=7$ for the other sign of $w$ (noting that in each formula, $w$ is a square root of some expression).
|
||||
Ignoring the negligible cases, we get:
|
||||
|
||||
**Define** $G_{c,u}(x)$ as:
|
||||
* If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas):
|
||||
* If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence).
|
||||
* If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula)
|
||||
* Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows).
|
||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas):
|
||||
* Let $s = x-u.$
|
||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}.$
|
||||
* Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise.
|
||||
* Let $w = \sqrt{s}.$
|
||||
* Depending on $c:$
|
||||
* If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$
|
||||
* If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$
|
||||
|
||||
Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly
|
||||
50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen
|
||||
with negligible probability. A division by 0 in the first branch in fact cannot occur at all, because $u^2 + uv + v^2 + a = 0$
|
||||
implies $g(-u-x) = g(x)$ which would mean the $g(-u-x)$ is square condition has triggered
|
||||
and $\bot$ would have been returned already.
|
||||
|
||||
**Note**: In the paper, the $case$ variable corresponds roughly to the $c$ above, but only takes on 4 possible values (1 to 4).
|
||||
The conditional negation of $w$ at the end is done randomly, which is equivalent, but makes testing harder. We choose to
|
||||
have the $G_{c,u}$ be deterministic, and capture all choices in $c.$
|
||||
|
||||
Now observe that the $c \in \\{1, 5\\}$ and $c \in \\{3, 7\\}$ conditions effectively perform the same $v \rightarrow -u-v$
|
||||
transformation. Furthermore, that transformation has no effect on $s$ in the first branch
|
||||
as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down:
|
||||
|
||||
**Define** $G_{c,u}(x)$ as:
|
||||
* If $c \in \\{0, 1, 4, 5\\}:$
|
||||
* If $g(-u-x)$ is square, return $\bot.$
|
||||
* Let $s = -g(u)/(u^2 + ux + x^2 + a).$
|
||||
* Let $v = x.$
|
||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
||||
* Let $s = x-u.$
|
||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}.$
|
||||
* Let $v = (r/s - u)/2.$
|
||||
* Let $w = \sqrt{s}.$
|
||||
* Depending on $c:$
|
||||
* If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$
|
||||
* If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$
|
||||
* If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$
|
||||
* If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$
|
||||
|
||||
This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input.
|
||||
There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values.
|
||||
|
||||
### 3.4 Dealing with special cases
|
||||
|
||||
As mentioned before there are a few cases to deal with which only happen in a negligibly small subset of inputs.
|
||||
For cryptographically sized fields, if only random inputs are going to be considered, it is unnecessary to deal with these. Still, for completeness
|
||||
we analyse them here. They generally fall into two categories: cases in which the encoder would produce $t$ values that
|
||||
do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same
|
||||
$t$ value for multiple $c$ inputs (thereby biasing that encoding):
|
||||
|
||||
* In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$):
|
||||
* When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves.
|
||||
Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve
|
||||
fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square).
|
||||
This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$),
|
||||
the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the
|
||||
encoder anyway as there will generally be more than 8.
|
||||
* When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence
|
||||
as it can deal with $g(u)=0$.
|
||||
This is again only possible on even-ordered curves.
|
||||
* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$):
|
||||
* When $s=0$, a division by zero would occur.
|
||||
* When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases.
|
||||
It is equivalent to checking whether $r=0$.
|
||||
This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition.
|
||||
A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first
|
||||
it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero.
|
||||
* Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder:
|
||||
* For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve.
|
||||
* For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$.
|
||||
|
||||
**Define** a version of $G_{c,u}(x)$ which deals with all these cases:
|
||||
* If $a=0$ and $u=0$, return $\bot.$
|
||||
* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$
|
||||
* If $c \in \\{0, 1, 4, 5\\}:$
|
||||
* If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
|
||||
* If $g(-u-x)$ is square, return $\bot.$
|
||||
* Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
|
||||
* Let $v = x.$
|
||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
||||
* Let $s = x-u.$
|
||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
|
||||
* If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
|
||||
* If $s = 0$, return $\bot.$
|
||||
* Let $v = (r/s - u)/2.$
|
||||
* Let $w = \sqrt{s}$; return $\bot$ if not square.
|
||||
* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$
|
||||
* Depending on $c:$
|
||||
* If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$
|
||||
* If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$
|
||||
* If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$
|
||||
* If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$
|
||||
* If $a=0$ and $t=0$, return $\bot$ (even curves only).
|
||||
* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$
|
||||
* Return $t.$
|
||||
|
||||
Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once,
|
||||
for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached:
|
||||
* All cases where $P_u(t)$ is not defined:
|
||||
* For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$
|
||||
* For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$
|
||||
* When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch.
|
||||
|
||||
These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves.
|
||||
|
||||
### 3.5 Encoding for `secp256k1`
|
||||
|
||||
Specialized for odd-ordered $a=0$ curves:
|
||||
|
||||
**Define** $G_{c,u}(x)$ as:
|
||||
* If $u=0$, return $\bot.$
|
||||
* If $c \in \\{0, 1, 4, 5\\}:$
|
||||
* If $(-u-x)^3 + b$ is square, return $\bot$
|
||||
* Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0).
|
||||
* Let $v = x.$
|
||||
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
|
||||
* Let $s = x-u.$
|
||||
* Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square.
|
||||
* If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
|
||||
* If $s = 0$, return $\bot.$
|
||||
* Let $v = (r/s - u)/2.$
|
||||
* Let $w = \sqrt{s}$; return $\bot$ if not square.
|
||||
* Depending on $c:$
|
||||
* If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$
|
||||
* If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$
|
||||
* If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$
|
||||
* If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$
|
||||
|
||||
This is implemented in `secp256k1_ellswift_xswiftec_inv_var`.
|
||||
|
||||
And the x-only ElligatorSwift encoding algorithm is still:
|
||||
|
||||
**Define** *ElligatorSwift(x)* as:
|
||||
* Loop:
|
||||
* Pick a uniformly random field element $u.$
|
||||
* Pick a uniformly random integer $c$ in $[0,8).$
|
||||
* Let $t = G_{c,u}(x).$
|
||||
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
|
||||
|
||||
Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them.
|
||||
While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$
|
||||
combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity.
|
||||
|
||||
## 4. Encoding and decoding full *(x, y)* coordinates
|
||||
|
||||
So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding
|
||||
for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information
|
||||
in $t$ as well.
|
||||
|
||||
Note that for any $(X, Y) \in S_u$, $(\pm X, \pm Y)$ are all on $S_u.$ Moreover, all of these are
|
||||
mapped to the same x-coordinate. Negating $X$ or negating $Y$ just results in $x_1$ and $x_2$
|
||||
being swapped, and does not affect $x_3.$ This will not change the outcome x-coordinate as the order
|
||||
of $x_1$ and $x_2$ only matters if both were to be valid, and in that case $x_3$ would be used instead.
|
||||
|
||||
Still, these four $(X, Y)$ combinations all correspond to distinct $t$ values, so we can encode
|
||||
the sign of the y-coordinate in the sign of $X$ or the sign of $Y.$ They correspond to the
|
||||
four distinct $P_u^{'-1}$ calls in the definition of $G_{u,c}.$
|
||||
|
||||
**Note**: In the paper, the sign of the y coordinate is encoded in a separately-coded bit.
|
||||
|
||||
To encode the sign of $y$ in the sign of $Y:$
|
||||
|
||||
**Define** *Decode(u, t)* for full $(x, y)$ as:
|
||||
* Let $(X, Y) = P_u(t).$
|
||||
* Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square.
|
||||
* Let $y = \sqrt{g(x)}.$
|
||||
* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$
|
||||
|
||||
And encoding would be done using a $G_{c,u}(x, y)$ function defined as:
|
||||
|
||||
**Define** $G_{c,u}(x, y)$ as:
|
||||
* If $c \in \\{0, 1\\}:$
|
||||
* If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
|
||||
* If $g(-u-x)$ is square, return $\bot.$
|
||||
* Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
|
||||
* Let $v = x.$
|
||||
* Otherwise, when $c \in \\{2, 3\\}:$
|
||||
* Let $s = x-u.$
|
||||
* Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
|
||||
* If $c = 3$ and $r = 0$, return $\bot.$
|
||||
* Let $v = (r/s - u)/2.$
|
||||
* Let $w = \sqrt{s}$; return $\bot$ if not square.
|
||||
* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise.
|
||||
* Depending on $c:$
|
||||
* If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$
|
||||
* If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$
|
||||
|
||||
Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$
|
||||
This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$.
|
||||
|
||||
In the above logic, $sign$ can be implemented in several ways, such as parity of the integer representation
|
||||
of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where
|
||||
$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$.
|
||||
|
||||
### 4.1 Full *(x, y)* coordinates for `secp256k1`
|
||||
|
||||
For $a=0$ curves, there is another option. Note that for those,
|
||||
the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to
|
||||
encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get
|
||||
as decoder:
|
||||
|
||||
**Define** *Decode(u, t)* as:
|
||||
* Let $u'=u$ if $u \neq 0$; $1$ otherwise.
|
||||
* Let $t'=t$ if $t \neq 0$; $1$ otherwise.
|
||||
* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise.
|
||||
* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
|
||||
* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
|
||||
* Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square.
|
||||
* Let $y = \sqrt{g(x)}.$
|
||||
* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise.
|
||||
|
||||
This is implemented in `secp256k1_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$
|
||||
|
||||
The corresponding encoder would invoke the x-only one, but negating the output $t$ if $sign(t) \neq sign(y).$
|
||||
|
||||
This is implemented in `secp256k1_ellswift_elligatorswift_var`.
|
||||
|
||||
Note that this is only intended for encoding points where both the x-coordinate and y-coordinate are unpredictable. When encoding x-only points
|
||||
where the y-coordinate is implicitly even (or implicitly square, or implicitly in $[0,q/2]$), the encoder in
|
||||
[Section 3.5](#35-encoding-for-secp256k1) must be used, or a bias is reintroduced that undoes all the benefit of using ElligatorSwift
|
||||
in the first place.
|
||||
@@ -12,10 +12,41 @@ It is best if the maintainers are present during the release, so they can help e
|
||||
|
||||
This process also assumes that there will be no minor releases for old major releases.
|
||||
|
||||
We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core.
|
||||
|
||||
## Sanity Checks
|
||||
Perform these checks before creating a release:
|
||||
|
||||
1. Ensure `make distcheck` doesn't fail.
|
||||
```shell
|
||||
./autogen.sh && ./configure --enable-dev-mode && make distcheck
|
||||
```
|
||||
2. Check installation with autotools:
|
||||
```shell
|
||||
dir=$(mktemp -d)
|
||||
./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -RlAh $dir
|
||||
gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa
|
||||
```
|
||||
3. Check installation with CMake:
|
||||
```shell
|
||||
dir=$(mktemp -d)
|
||||
build=$(mktemp -d)
|
||||
cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -RlAh $dir
|
||||
gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa
|
||||
```
|
||||
4. Use the [`check-abi.sh`](/tools/check-abi.sh) tool to ensure there are no unexpected ABI incompatibilities and that the version number and release notes accurately reflect all potential ABI changes. To run this tool, the `abi-dumper` and `abi-compliance-checker` packages are required.
|
||||
|
||||
```shell
|
||||
tools/check-abi.sh
|
||||
```
|
||||
|
||||
## Regular release
|
||||
|
||||
1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that
|
||||
* finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) (make sure to include an entry for `### ABI Compatibility`),
|
||||
* finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by
|
||||
* adding a section for the release (make sure that the version number is a link to a diff between the previous and new version),
|
||||
* removing the `[Unreleased]` section header, and
|
||||
* including an entry for `### ABI Compatibility` if it doesn't exist,
|
||||
* sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and
|
||||
* if this is not a patch release
|
||||
* updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac` and
|
||||
@@ -27,8 +58,9 @@ This process also assumes that there will be no minor releases for old major rel
|
||||
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
|
||||
```
|
||||
3. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that
|
||||
* sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`, and
|
||||
* increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`.
|
||||
* sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`,
|
||||
* increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and
|
||||
* adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md).
|
||||
|
||||
If other maintainers are not present to approve the PR, it can be merged without ACKs.
|
||||
4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
|
||||
@@ -37,14 +69,14 @@ This process also assumes that there will be no minor releases for old major rel
|
||||
|
||||
Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists.
|
||||
|
||||
1. If `$PATCH = 1`, create maintenance branch `$MAJOR.$MINOR`:
|
||||
1. If there's no maintenance branch `$MAJOR.$MINOR`, create one:
|
||||
```
|
||||
git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.0
|
||||
git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.$((PATCH - 1))
|
||||
git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR
|
||||
```
|
||||
2. Open a pull request to the `$MAJOR.$MINOR` branch that
|
||||
* includes the bugfixes,
|
||||
* finalizes the release notes,
|
||||
* finalizes the release notes similar to a regular release,
|
||||
* increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`
|
||||
and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`
|
||||
(with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example).
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
add_library(example INTERFACE)
|
||||
target_include_directories(example INTERFACE
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
)
|
||||
target_link_libraries(example INTERFACE
|
||||
secp256k1
|
||||
$<$<PLATFORM_ID:Windows>:bcrypt>
|
||||
)
|
||||
if(NOT BUILD_SHARED_LIBS AND MSVC)
|
||||
target_link_options(example INTERFACE /IGNORE:4217)
|
||||
endif()
|
||||
function(add_example name)
|
||||
set(target_name ${name}_example)
|
||||
add_executable(${target_name} ${name}.c)
|
||||
target_include_directories(${target_name} PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
)
|
||||
target_link_libraries(${target_name}
|
||||
secp256k1
|
||||
$<$<PLATFORM_ID:Windows>:bcrypt>
|
||||
)
|
||||
set(test_name ${name}_example)
|
||||
add_test(NAME ${test_name} COMMAND ${target_name})
|
||||
if(BUILD_SHARED_LIBS AND MSVC)
|
||||
# The DLL must reside either in the same folder where the executable is
|
||||
# or somewhere in PATH. Using the latter option.
|
||||
set_tests_properties(${test_name} PROPERTIES
|
||||
ENVIRONMENT "PATH=$<TARGET_FILE_DIR:secp256k1>;$ENV{PATH}"
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
add_executable(ecdsa_example ecdsa.c)
|
||||
target_link_libraries(ecdsa_example example)
|
||||
add_test(NAME ecdsa_example COMMAND ecdsa_example)
|
||||
add_example(ecdsa)
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_ECDH)
|
||||
add_executable(ecdh_example ecdh.c)
|
||||
target_link_libraries(ecdh_example example)
|
||||
add_test(NAME ecdh_example COMMAND ecdh_example)
|
||||
add_example(ecdh)
|
||||
endif()
|
||||
|
||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
add_executable(schnorr_example schnorr.c)
|
||||
target_link_libraries(schnorr_example example)
|
||||
add_test(NAME schnorr_example COMMAND schnorr_example)
|
||||
add_example(schnorr)
|
||||
endif()
|
||||
|
||||
@@ -95,7 +95,7 @@ static void secure_erase(void *ptr, size_t len) {
|
||||
* As best as we can tell, this is sufficient to break any optimisations that
|
||||
* might try to eliminate "superfluous" memsets.
|
||||
* This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is
|
||||
* pretty efficient, because the compiler can still implement the memset() efficently,
|
||||
* pretty efficient, because the compiler can still implement the memset() efficiently,
|
||||
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
|
||||
* Yang et al. (USENIX Security 2017) for more background.
|
||||
*/
|
||||
|
||||
@@ -133,28 +133,35 @@ typedef int (*secp256k1_nonce_function)(
|
||||
# define SECP256K1_NO_BUILD
|
||||
#endif
|
||||
|
||||
/* Symbol visibility. See libtool manual, section "Windows DLLs". */
|
||||
#if defined(_WIN32) && !defined(__GNUC__)
|
||||
# ifdef SECP256K1_BUILD
|
||||
# ifdef DLL_EXPORT
|
||||
# define SECP256K1_API __declspec (dllexport)
|
||||
# define SECP256K1_API_VAR extern __declspec (dllexport)
|
||||
/* Symbol visibility. */
|
||||
#if defined(_WIN32)
|
||||
/* GCC for Windows (e.g., MinGW) accepts the __declspec syntax
|
||||
* for MSVC compatibility. A __declspec declaration implies (but is not
|
||||
* exactly equivalent to) __attribute__ ((visibility("default"))), and so we
|
||||
* actually want __declspec even on GCC, see "Microsoft Windows Function
|
||||
* Attributes" in the GCC manual and the recommendations in
|
||||
* https://gcc.gnu.org/wiki/Visibility. */
|
||||
# if defined(SECP256K1_BUILD)
|
||||
# if defined(DLL_EXPORT) || defined(SECP256K1_DLL_EXPORT)
|
||||
/* Building libsecp256k1 as a DLL.
|
||||
* 1. If using Libtool, it defines DLL_EXPORT automatically.
|
||||
* 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */
|
||||
# define SECP256K1_API extern __declspec (dllexport)
|
||||
# endif
|
||||
# elif defined _MSC_VER
|
||||
# define SECP256K1_API
|
||||
# define SECP256K1_API_VAR extern __declspec (dllimport)
|
||||
# elif defined DLL_EXPORT
|
||||
# define SECP256K1_API __declspec (dllimport)
|
||||
# define SECP256K1_API_VAR extern __declspec (dllimport)
|
||||
/* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static
|
||||
* library on Windows. */
|
||||
# elif !defined(SECP256K1_STATIC)
|
||||
/* Consuming libsecp256k1 as a DLL. */
|
||||
# define SECP256K1_API extern __declspec (dllimport)
|
||||
# endif
|
||||
#endif
|
||||
#ifndef SECP256K1_API
|
||||
# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
|
||||
# define SECP256K1_API __attribute__ ((visibility ("default")))
|
||||
# define SECP256K1_API_VAR extern __attribute__ ((visibility ("default")))
|
||||
/* Building libsecp256k1 on non-Windows using GCC or compatible. */
|
||||
# define SECP256K1_API extern __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define SECP256K1_API
|
||||
# define SECP256K1_API_VAR extern
|
||||
/* All cases not captured above. */
|
||||
# define SECP256K1_API extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -226,10 +233,10 @@ typedef int (*secp256k1_nonce_function)(
|
||||
*
|
||||
* It is highly recommended to call secp256k1_selftest before using this context.
|
||||
*/
|
||||
SECP256K1_API_VAR const secp256k1_context *secp256k1_context_static;
|
||||
SECP256K1_API const secp256k1_context *secp256k1_context_static;
|
||||
|
||||
/** Deprecated alias for secp256k1_context_static. */
|
||||
SECP256K1_API_VAR const secp256k1_context *secp256k1_context_no_precomp
|
||||
SECP256K1_API const secp256k1_context *secp256k1_context_no_precomp
|
||||
SECP256K1_DEPRECATED("Use secp256k1_context_static instead");
|
||||
|
||||
/** Perform basic self tests (to be used in conjunction with secp256k1_context_static)
|
||||
@@ -626,10 +633,10 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize(
|
||||
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
|
||||
* extra entropy.
|
||||
*/
|
||||
SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
|
||||
SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
|
||||
|
||||
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
|
||||
SECP256K1_API_VAR const secp256k1_nonce_function secp256k1_nonce_function_default;
|
||||
SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_default;
|
||||
|
||||
/** Create an ECDSA signature.
|
||||
*
|
||||
@@ -733,10 +740,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
|
||||
* invalid according to secp256k1_ec_seckey_verify, this
|
||||
* function returns 0. seckey will be set to some unspecified
|
||||
* value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128).
|
||||
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
|
||||
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
|
||||
* random 32-byte tweaks, the chance of being invalid is
|
||||
* negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
@@ -761,10 +768,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
|
||||
* invalid value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128).
|
||||
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
|
||||
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
|
||||
* random 32-byte tweaks, the chance of being invalid is
|
||||
* negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
|
||||
@@ -27,11 +27,11 @@ typedef int (*secp256k1_ecdh_hash_function)(
|
||||
|
||||
/** An implementation of SHA256 hash function that applies to compressed public key.
|
||||
* Populates the output parameter with 32 bytes. */
|
||||
SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
|
||||
SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
|
||||
|
||||
/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256).
|
||||
* Populates the output parameter with 32 bytes. */
|
||||
SECP256K1_API_VAR const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
|
||||
SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
|
||||
|
||||
/** Compute an EC Diffie-Hellman secret in constant time
|
||||
*
|
||||
|
||||
200
include/secp256k1_ellswift.h
Normal file
200
include/secp256k1_ellswift.h
Normal file
@@ -0,0 +1,200 @@
|
||||
#ifndef SECP256K1_ELLSWIFT_H
|
||||
#define SECP256K1_ELLSWIFT_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This module provides an implementation of ElligatorSwift as well as a
|
||||
* version of x-only ECDH using it (including compatibility with BIP324).
|
||||
*
|
||||
* ElligatorSwift is described in https://eprint.iacr.org/2022/759 by
|
||||
* Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding
|
||||
* uniformly chosen public keys as 64-byte arrays which are indistinguishable
|
||||
* from uniformly random arrays.
|
||||
*
|
||||
* Let f be the function from pairs of field elements to point X coordinates,
|
||||
* defined as follows (all operations modulo p = 2^256 - 2^32 - 977)
|
||||
* f(u,t):
|
||||
* - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852,
|
||||
* a square root of -3.
|
||||
* - If u=0, set u=1 instead.
|
||||
* - If t=0, set t=1 instead.
|
||||
* - If u^3 + t^2 + 7 = 0, multiply t by 2.
|
||||
* - Let X = (u^3 + 7 - t^2) / (2 * t)
|
||||
* - Let Y = (X + t) / (C * u)
|
||||
* - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an
|
||||
* X coordinate on the curve (at least one of them is, for any u and t).
|
||||
*
|
||||
* Then an ElligatorSwift encoding of x consists of the 32-byte big-endian
|
||||
* encodings of field elements u and t concatenated, where f(u,t) = x.
|
||||
* The encoding algorithm is described in the paper, and effectively picks a
|
||||
* uniformly random pair (u,t) among those which encode x.
|
||||
*
|
||||
* If the Y coordinate is relevant, it is given the same parity as t.
|
||||
*
|
||||
* Changes w.r.t. the the paper:
|
||||
* - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point
|
||||
* at infinity in the paper. Here they are remapped to finite points.
|
||||
* - The paper uses an additional encoding bit for the parity of y. Here the
|
||||
* parity of t is used (negating t does not affect the decoded x coordinate,
|
||||
* so this is possible).
|
||||
*
|
||||
* For mathematical background about the scheme, see the doc/ellswift.md file.
|
||||
*/
|
||||
|
||||
/** A pointer to a function used by secp256k1_ellswift_xdh to hash the shared X
|
||||
* coordinate along with the encoded public keys to a uniform shared secret.
|
||||
*
|
||||
* Returns: 1 if a shared secret was successfully computed.
|
||||
* 0 will cause secp256k1_ellswift_xdh to fail and return 0.
|
||||
* Other return values are not allowed, and the behaviour of
|
||||
* secp256k1_ellswift_xdh is undefined for other return values.
|
||||
* Out: output: pointer to an array to be filled by the function
|
||||
* In: x32: pointer to the 32-byte serialized X coordinate
|
||||
* of the resulting shared point (will not be NULL)
|
||||
* ell_a64: pointer to the 64-byte encoded public key of party A
|
||||
* (will not be NULL)
|
||||
* ell_b64: pointer to the 64-byte encoded public key of party B
|
||||
* (will not be NULL)
|
||||
* data: arbitrary data pointer that is passed through
|
||||
*/
|
||||
typedef int (*secp256k1_ellswift_xdh_hash_function)(
|
||||
unsigned char *output,
|
||||
const unsigned char *x32,
|
||||
const unsigned char *ell_a64,
|
||||
const unsigned char *ell_b64,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses
|
||||
* SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte
|
||||
* array pointed to by data. */
|
||||
SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix;
|
||||
|
||||
/** An implementation of an secp256k1_ellswift_xdh_hash_function compatible with
|
||||
* BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the
|
||||
* BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent
|
||||
* to secp256k1_ellswift_xdh_hash_function_prefix with prefix64 set to
|
||||
* SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh").
|
||||
* The data argument is ignored. */
|
||||
SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324;
|
||||
|
||||
/** Construct a 64-byte ElligatorSwift encoding of a given pubkey.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: ell64: pointer to a 64-byte array to be filled
|
||||
* In: pubkey: a pointer to a secp256k1_pubkey containing an
|
||||
* initialized public key
|
||||
* rnd32: pointer to 32 bytes of randomness
|
||||
*
|
||||
* It is recommended that rnd32 consists of 32 uniformly random bytes, not
|
||||
* known to any adversary trying to detect whether public keys are being
|
||||
* encoded, though 16 bytes of randomness (padded to an array of 32 bytes,
|
||||
* e.g., with zeros) suffice to make the result indistinguishable from
|
||||
* uniform. The randomness in rnd32 must not be a deterministic function of
|
||||
* the pubkey (it can be derived from the private key, though).
|
||||
*
|
||||
* It is not guaranteed that the computed encoding is stable across versions
|
||||
* of the library, even if all arguments to this function (including rnd32)
|
||||
* are the same.
|
||||
*
|
||||
* This function runs in variable time.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ellswift_encode(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *ell64,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const unsigned char *rnd32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Decode a 64-bytes ElligatorSwift encoded public key.
|
||||
*
|
||||
* Returns: always 1
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: pubkey: pointer to a secp256k1_pubkey that will be filled
|
||||
* In: ell64: pointer to a 64-byte array to decode
|
||||
*
|
||||
* This function runs in variable time.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_ellswift_decode(
|
||||
const secp256k1_context *ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const unsigned char *ell64
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Compute an ElligatorSwift public key for a secret key.
|
||||
*
|
||||
* Returns: 1: secret was valid, public key was stored.
|
||||
* 0: secret was invalid, try again.
|
||||
* Args: ctx: pointer to a context object
|
||||
* Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift
|
||||
* public key
|
||||
* In: seckey32: pointer to a 32-byte secret key
|
||||
* auxrnd32: (optional) pointer to 32 bytes of randomness
|
||||
*
|
||||
* Constant time in seckey and auxrnd32, but not in the resulting public key.
|
||||
*
|
||||
* It is recommended that auxrnd32 contains 32 uniformly random bytes, though
|
||||
* it is optional (and does result in encodings that are indistinguishable from
|
||||
* uniform even without any auxrnd32). It differs from the (mandatory) rnd32
|
||||
* argument to secp256k1_ellswift_encode in this regard.
|
||||
*
|
||||
* This function can be used instead of calling secp256k1_ec_pubkey_create
|
||||
* followed by secp256k1_ellswift_encode. It is safer, as it uses the secret
|
||||
* key as entropy for the encoding (supplemented with auxrnd32, if provided).
|
||||
*
|
||||
* Like secp256k1_ellswift_encode, this function does not guarantee that the
|
||||
* computed encoding is stable across versions of the library, even if all
|
||||
* arguments (including auxrnd32) are the same.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *ell64,
|
||||
const unsigned char *seckey32,
|
||||
const unsigned char *auxrnd32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Given a private key, and ElligatorSwift public keys sent in both directions,
|
||||
* compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH).
|
||||
*
|
||||
* Returns: 1: shared secret was successfully computed
|
||||
* 0: secret was invalid or hashfp returned 0
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: output: pointer to an array to be filled by hashfp.
|
||||
* In: ell_a64: pointer to the 64-byte encoded public key of party A
|
||||
* (will not be NULL)
|
||||
* ell_b64: pointer to the 64-byte encoded public key of party B
|
||||
* (will not be NULL)
|
||||
* seckey32: a pointer to our 32-byte secret key
|
||||
* party: boolean indicating which party we are: zero if we are
|
||||
* party A, non-zero if we are party B. seckey32 must be
|
||||
* the private key corresponding to that party's ell_?64.
|
||||
* This correspondence is not checked.
|
||||
* hashfp: pointer to a hash function.
|
||||
* data: arbitrary data pointer passed through to hashfp.
|
||||
*
|
||||
* Constant time in seckey32.
|
||||
*
|
||||
* This function is more efficient than decoding the public keys, and performing
|
||||
* ECDH on them.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh(
|
||||
const secp256k1_context *ctx,
|
||||
unsigned char *output,
|
||||
const unsigned char *ell_a64,
|
||||
const unsigned char *ell_b64,
|
||||
const unsigned char *seckey32,
|
||||
int party,
|
||||
secp256k1_ellswift_xdh_hash_function hashfp,
|
||||
void *data
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_ELLSWIFT_H */
|
||||
@@ -112,10 +112,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubke
|
||||
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
||||
* to an invalid value if this function returns 0.
|
||||
* In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
|
||||
* tweak32: pointer to a 32-byte tweak. If the tweak is invalid
|
||||
* according to secp256k1_ec_seckey_verify, this function
|
||||
* returns 0. For uniformly random 32-byte arrays the
|
||||
* chance of being invalid is negligible (around 1 in 2^128).
|
||||
* tweak32: pointer to a 32-byte tweak, which must be valid
|
||||
* according to secp256k1_ec_seckey_verify or 32 zero
|
||||
* bytes. For uniformly random 32-byte tweaks, the chance of
|
||||
* being invalid is negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
@@ -185,9 +185,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
|
||||
/** Get the public key from a keypair.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* 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.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* Out: pubkey: pointer to a pubkey object, set to the keypair public key.
|
||||
* In: keypair: pointer to a keypair.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
|
||||
@@ -203,9 +202,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: pointer to a context object.
|
||||
* 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
|
||||
* xonly_pubkey. If not, it's set to an invalid value.
|
||||
* Out: pubkey: pointer to an xonly_pubkey object, set to the keypair
|
||||
* public key after converting it to an xonly_pubkey.
|
||||
* pk_parity: Ignored if NULL. Otherwise, pointer to an integer that will be set to the
|
||||
* pk_parity argument of secp256k1_xonly_pubkey_from_pubkey.
|
||||
* In: keypair: pointer to a keypair.
|
||||
@@ -231,10 +229,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
|
||||
* Args: ctx: pointer to a context object.
|
||||
* In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
|
||||
* an invalid value if this function returns 0.
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according
|
||||
* to secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128).
|
||||
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
|
||||
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
|
||||
* random 32-byte tweaks, the chance of being invalid is
|
||||
* negligible (around 1 in 2^128).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
|
||||
const secp256k1_context *ctx,
|
||||
|
||||
@@ -61,7 +61,7 @@ typedef int (*secp256k1_nonce_function_hardened)(
|
||||
* Therefore, to create BIP-340 compliant signatures, algo must be set to
|
||||
* "BIP0340/nonce" and algolen to 13.
|
||||
*/
|
||||
SECP256K1_API_VAR const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
|
||||
SECP256K1_API const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
|
||||
|
||||
/** Data structure that contains additional arguments for schnorrsig_sign_custom.
|
||||
*
|
||||
|
||||
@@ -198,7 +198,7 @@ def normalize_factor(p):
|
||||
(8) * (-bx + ax)^3
|
||||
```
|
||||
"""
|
||||
# Assert p is not 0 and that its non-zero coeffients are coprime.
|
||||
# Assert p is not 0 and that its non-zero coefficients 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
|
||||
|
||||
@@ -20,10 +20,10 @@ if(SECP256K1_ASM STREQUAL "arm32")
|
||||
target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm)
|
||||
endif()
|
||||
|
||||
# Define our export symbol only for Win32 and only for shared libs.
|
||||
# This matches libtool's usage of DLL_EXPORT
|
||||
if(WIN32)
|
||||
set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL "DLL_EXPORT")
|
||||
# Define our export symbol only for shared libs.
|
||||
set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL SECP256K1_DLL_EXPORT)
|
||||
target_compile_definitions(secp256k1 INTERFACE $<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:SECP256K1_STATIC>)
|
||||
endif()
|
||||
|
||||
# Object libs don't know if they're being built for a shared or static lib.
|
||||
@@ -132,6 +132,9 @@ if(SECP256K1_INSTALL)
|
||||
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
|
||||
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
|
||||
endif()
|
||||
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
|
||||
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h")
|
||||
endif()
|
||||
install(FILES ${${PROJECT_NAME}_headers}
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
)
|
||||
@@ -158,5 +161,13 @@ if(SECP256K1_INSTALL)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
)
|
||||
|
||||
include(GeneratePkgConfigFile)
|
||||
generate_pkg_config_file(${PROJECT_SOURCE_DIR}/libsecp256k1.pc.in)
|
||||
install(
|
||||
FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -913,3 +913,4 @@ secp256k1_fe_sqr_inner:
|
||||
ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}
|
||||
.size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner
|
||||
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
|
||||
58
src/bench.c
58
src/bench.c
@@ -38,6 +38,8 @@ static void help(int default_iters) {
|
||||
printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n");
|
||||
printf(" ecdsa_sign : ECDSA siging algorithm\n");
|
||||
printf(" ecdsa_verify : ECDSA verification algorithm\n");
|
||||
printf(" ec : all EC public key algorithms (keygen)\n");
|
||||
printf(" ec_keygen : EC public key generation\n");
|
||||
|
||||
#ifdef ENABLE_MODULE_RECOVERY
|
||||
printf(" ecdsa_recover : ECDSA public key recovery algorithm\n");
|
||||
@@ -53,6 +55,14 @@ static void help(int default_iters) {
|
||||
printf(" schnorrsig_verify : Schnorr verification algorithm\n");
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
printf(" ellswift : all ElligatorSwift benchmarks (encode, decode, keygen, ecdh)\n");
|
||||
printf(" ellswift_encode : ElligatorSwift encoding\n");
|
||||
printf(" ellswift_decode : ElligatorSwift decoding\n");
|
||||
printf(" ellswift_keygen : ElligatorSwift key generation\n");
|
||||
printf(" ellswift_ecdh : ECDH on ElligatorSwift keys\n");
|
||||
#endif
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -115,6 +125,30 @@ static void bench_sign_run(void* arg, int iters) {
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_keygen_setup(void* arg) {
|
||||
int i;
|
||||
bench_data *data = (bench_data*)arg;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->key[i] = i + 65;
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_keygen_run(void *arg, int iters) {
|
||||
int i;
|
||||
bench_data *data = (bench_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
unsigned char pub33[33];
|
||||
size_t len = 33;
|
||||
secp256k1_pubkey pubkey;
|
||||
CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->key));
|
||||
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED));
|
||||
memcpy(data->key, pub33 + 1, 32);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_MODULE_ECDH
|
||||
# include "modules/ecdh/bench_impl.h"
|
||||
#endif
|
||||
@@ -127,6 +161,10 @@ static void bench_sign_run(void* arg, int iters) {
|
||||
# include "modules/schnorrsig/bench_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
# include "modules/ellswift/bench_impl.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int i;
|
||||
secp256k1_pubkey pubkey;
|
||||
@@ -139,7 +177,9 @@ int main(int argc, char** argv) {
|
||||
|
||||
/* Check for invalid user arguments */
|
||||
char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover",
|
||||
"ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign"};
|
||||
"ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec",
|
||||
"keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode",
|
||||
"ellswift_decode", "ellswift_keygen", "ellswift_ecdh"};
|
||||
size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]);
|
||||
int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size);
|
||||
|
||||
@@ -181,6 +221,16 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_MODULE_ELLSWIFT
|
||||
if (have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ellswift_encode") || have_flag(argc, argv, "ellswift_decode") ||
|
||||
have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") ||
|
||||
have_flag(argc, argv, "ellswift_ecdh")) {
|
||||
fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n");
|
||||
fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ECDSA benchmark */
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
|
||||
@@ -201,6 +251,7 @@ int main(int argc, char** argv) {
|
||||
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);
|
||||
|
||||
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_keygen_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
|
||||
@@ -219,5 +270,10 @@ int main(int argc, char** argv) {
|
||||
run_schnorrsig_bench(iters, argc, argv);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
/* ElligatorSwift benchmarks */
|
||||
run_ellswift_bench(iters, argc, argv);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -138,12 +138,10 @@ static void bench_ecmult_1p_teardown(void* arg, int iters) {
|
||||
|
||||
static void bench_ecmult_0p_g(void* arg, int iters) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
secp256k1_scalar zero;
|
||||
int i;
|
||||
|
||||
secp256k1_scalar_set_int(&zero, 0);
|
||||
for (i = 0; i < iters; ++i) {
|
||||
secp256k1_ecmult(&data->output[i], NULL, &zero, &data->scalars[(data->offset1+i) % POINTS]);
|
||||
secp256k1_ecmult(&data->output[i], NULL, &secp256k1_scalar_zero, &data->scalars[(data->offset1+i) % POINTS]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,7 +244,6 @@ static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
|
||||
|
||||
static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_g, int num_iters) {
|
||||
char str[32];
|
||||
static const secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0);
|
||||
size_t iters = 1 + num_iters / count;
|
||||
size_t iter;
|
||||
|
||||
@@ -264,7 +261,7 @@ static void run_ecmult_multi_bench(bench_data* data, size_t count, int includes_
|
||||
secp256k1_scalar_add(&total, &total, &tmp);
|
||||
}
|
||||
secp256k1_scalar_negate(&total, &total);
|
||||
secp256k1_ecmult(&data->expected_output[iter], NULL, &zero, &total);
|
||||
secp256k1_ecmult(&data->expected_output[iter], NULL, &secp256k1_scalar_zero, &total);
|
||||
}
|
||||
|
||||
/* Run the benchmark. */
|
||||
|
||||
@@ -14,10 +14,28 @@
|
||||
#include "field_impl.h"
|
||||
#include "group_impl.h"
|
||||
#include "scalar_impl.h"
|
||||
#include "ecmult_const_impl.h"
|
||||
#include "ecmult_impl.h"
|
||||
#include "bench.h"
|
||||
|
||||
static void help(int default_iters) {
|
||||
printf("Benchmarks various internal routines.\n");
|
||||
printf("\n");
|
||||
printf("The default number of iterations for each benchmark is %d. This can be\n", default_iters);
|
||||
printf("customized using the SECP256K1_BENCH_ITERS environment variable.\n");
|
||||
printf("\n");
|
||||
printf("Usage: ./bench_internal [args]\n");
|
||||
printf("By default, all benchmarks will be run.\n");
|
||||
printf("args:\n");
|
||||
printf(" help : display this help and exit\n");
|
||||
printf(" scalar : all scalar operations (add, half, inverse, mul, negate, split)\n");
|
||||
printf(" field : all field operations (half, inverse, issquare, mul, normalize, sqr, sqrt)\n");
|
||||
printf(" group : all group operations (add, double, to_affine)\n");
|
||||
printf(" ecmult : all point multiplication operations (ecmult_wnaf) \n");
|
||||
printf(" hash : all hash algorithms (hmac, rng6979, sha256)\n");
|
||||
printf(" context : all context object operations (context_create)\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
secp256k1_scalar scalar[2];
|
||||
secp256k1_fe fe[4];
|
||||
@@ -98,6 +116,18 @@ static void bench_scalar_negate(void* arg, int iters) {
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_scalar_half(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
secp256k1_scalar s = data->scalar[0];
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_scalar_half(&s, &s);
|
||||
}
|
||||
|
||||
data->scalar[0] = s;
|
||||
}
|
||||
|
||||
static void bench_scalar_mul(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
@@ -309,18 +339,6 @@ static void bench_ecmult_wnaf(void* arg, int iters) {
|
||||
CHECK(bits <= 256*iters);
|
||||
}
|
||||
|
||||
static void bench_wnaf_const(void* arg, int iters) {
|
||||
int i, bits = 0, overflow = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
bits += secp256k1_wnaf_const(data->wnaf, &data->scalar[0], WINDOW_A, 256);
|
||||
overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
|
||||
}
|
||||
CHECK(overflow >= 0);
|
||||
CHECK(bits <= 256*iters);
|
||||
}
|
||||
|
||||
static void bench_sha256(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
@@ -366,10 +384,22 @@ static void bench_context(void* arg, int iters) {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
bench_inv data;
|
||||
int iters = get_iters(20000);
|
||||
int default_iters = 20000;
|
||||
int iters = get_iters(default_iters);
|
||||
int d = argc == 1; /* default */
|
||||
|
||||
if (argc > 1) {
|
||||
if (have_flag(argc, argv, "-h")
|
||||
|| have_flag(argc, argv, "--help")
|
||||
|| have_flag(argc, argv, "help")) {
|
||||
help(default_iters);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
print_output_table_header_row();
|
||||
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "half")) run_benchmark("scalar_half", bench_scalar_half, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10);
|
||||
@@ -394,7 +424,6 @@ int main(int argc, char **argv) {
|
||||
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_zinv_var", bench_group_add_zinv_var, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters);
|
||||
|
||||
if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters);
|
||||
|
||||
if (d || have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters);
|
||||
|
||||
@@ -58,7 +58,14 @@
|
||||
#if !defined SECP256K1_CHECKMEM_ENABLED
|
||||
# if defined VALGRIND
|
||||
# include <stddef.h>
|
||||
# if defined(__clang__) && defined(__APPLE__)
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
||||
# endif
|
||||
# include <valgrind/memcheck.h>
|
||||
# if defined(__clang__) && defined(__APPLE__)
|
||||
# pragma clang diagnostic pop
|
||||
# endif
|
||||
# define SECP256K1_CHECKMEM_ENABLED 1
|
||||
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len))
|
||||
# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len))
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
#include "../include/secp256k1_schnorrsig.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
#include "../include/secp256k1_ellswift.h"
|
||||
#endif
|
||||
|
||||
static void run_tests(secp256k1_context *ctx, unsigned char *key);
|
||||
|
||||
int main(void) {
|
||||
@@ -80,6 +84,10 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
||||
#ifdef ENABLE_MODULE_EXTRAKEYS
|
||||
secp256k1_keypair keypair;
|
||||
#endif
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
unsigned char ellswift[64];
|
||||
static const unsigned char prefix[64] = {'t', 'e', 's', 't'};
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
msg[i] = i + 1;
|
||||
@@ -171,4 +179,31 @@ static void run_tests(secp256k1_context *ctx, unsigned char *key) {
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
ret = secp256k1_ellswift_create(ctx, ellswift, key, ellswift);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift));
|
||||
ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_bip324, NULL);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
|
||||
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift));
|
||||
ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_prefix, (void *)prefix);
|
||||
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
|
||||
CHECK(ret == 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -16,17 +16,8 @@
|
||||
#include "ecdsa.h"
|
||||
|
||||
/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1
|
||||
* sage: for t in xrange(1023, -1, -1):
|
||||
* .. p = 2**256 - 2**32 - t
|
||||
* .. if p.is_prime():
|
||||
* .. print '%x'%p
|
||||
* .. break
|
||||
* 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'
|
||||
* sage: a = 0
|
||||
* sage: b = 7
|
||||
* sage: F = FiniteField (p)
|
||||
* sage: '%x' % (EllipticCurve ([F (a), F (b)]).order())
|
||||
* 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'
|
||||
* $ sage -c 'load("secp256k1_params.sage"); print(hex(N))'
|
||||
* 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
|
||||
*/
|
||||
static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(
|
||||
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
|
||||
@@ -35,12 +26,8 @@ static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST
|
||||
|
||||
/** Difference between field and order, values 'p' and 'n' values defined in
|
||||
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
|
||||
* sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
|
||||
* sage: a = 0
|
||||
* sage: b = 7
|
||||
* sage: F = FiniteField (p)
|
||||
* sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order())
|
||||
* '14551231950b75fc4402da1722fc9baee'
|
||||
* $ sage -c 'load("secp256k1_params.sage"); print(hex(P-N))'
|
||||
* 0x14551231950b75fc4402da1722fc9baee
|
||||
*/
|
||||
static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(
|
||||
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
|
||||
@@ -79,8 +66,7 @@ static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const
|
||||
}
|
||||
if (lenleft > sizeof(size_t)) {
|
||||
/* The resulting length would exceed the range of a size_t, so
|
||||
* certainly longer than the passed array size.
|
||||
*/
|
||||
* it is certainly longer than the passed array size. */
|
||||
return 0;
|
||||
}
|
||||
while (lenleft > 0) {
|
||||
@@ -89,7 +75,9 @@ static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const
|
||||
lenleft--;
|
||||
}
|
||||
if (*len > (size_t)(sigend - *sigp)) {
|
||||
/* Result exceeds the length of the passed array. */
|
||||
/* Result exceeds the length of the passed array.
|
||||
(Checking this is the responsibility of the caller but it
|
||||
can't hurt do it here, too.) */
|
||||
return 0;
|
||||
}
|
||||
if (*len < 128) {
|
||||
|
||||
@@ -59,10 +59,8 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp25
|
||||
|
||||
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak) {
|
||||
secp256k1_gej pt;
|
||||
secp256k1_scalar one;
|
||||
secp256k1_gej_set_ge(&pt, key);
|
||||
secp256k1_scalar_set_int(&one, 1);
|
||||
secp256k1_ecmult(&pt, &pt, &one, tweak);
|
||||
secp256k1_ecmult(&pt, &pt, &secp256k1_scalar_one, tweak);
|
||||
|
||||
if (secp256k1_gej_is_infinity(&pt)) {
|
||||
return 0;
|
||||
@@ -80,15 +78,13 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp25
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak) {
|
||||
secp256k1_scalar zero;
|
||||
secp256k1_gej pt;
|
||||
if (secp256k1_scalar_is_zero(tweak)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_int(&zero, 0);
|
||||
secp256k1_gej_set_ge(&pt, key);
|
||||
secp256k1_ecmult(&pt, &pt, tweak, &zero);
|
||||
secp256k1_ecmult(&pt, &pt, tweak, &secp256k1_scalar_zero);
|
||||
secp256k1_ge_set_gej(key, &pt);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE)
|
||||
#endif
|
||||
|
||||
/* Noone will ever need more than a window size of 24. The code might
|
||||
/* No one will ever need more than a window size of 24. The code might
|
||||
* be correct for larger values of ECMULT_WINDOW_SIZE but this is not
|
||||
* tested.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2015 Pieter Wuille, Andrew Poelstra *
|
||||
* Copyright (c) 2015, 2022 Pieter Wuille, Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
@@ -12,208 +12,259 @@
|
||||
#include "ecmult_const.h"
|
||||
#include "ecmult_impl.h"
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
/* We need 2^ECMULT_CONST_GROUP_SIZE - 1 to be less than EXHAUSTIVE_TEST_ORDER, because
|
||||
* the tables cannot have infinities in them (this breaks the effective-affine technique's
|
||||
* z-ratio tracking) */
|
||||
# if EXHAUSTIVE_TEST_ORDER == 199
|
||||
# define ECMULT_CONST_GROUP_SIZE 4
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 13
|
||||
# define ECMULT_CONST_GROUP_SIZE 3
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 7
|
||||
# define ECMULT_CONST_GROUP_SIZE 2
|
||||
# else
|
||||
# error "Unknown EXHAUSTIVE_TEST_ORDER"
|
||||
# endif
|
||||
#else
|
||||
/* Group size 4 or 5 appears optimal. */
|
||||
# define ECMULT_CONST_GROUP_SIZE 5
|
||||
#endif
|
||||
|
||||
#define ECMULT_CONST_TABLE_SIZE (1L << (ECMULT_CONST_GROUP_SIZE - 1))
|
||||
#define ECMULT_CONST_GROUPS ((129 + ECMULT_CONST_GROUP_SIZE - 1) / ECMULT_CONST_GROUP_SIZE)
|
||||
#define ECMULT_CONST_BITS (ECMULT_CONST_GROUPS * ECMULT_CONST_GROUP_SIZE)
|
||||
|
||||
/** Fill a table 'pre' with precomputed odd multiples of a.
|
||||
*
|
||||
* The resulting point set is brought to a single constant Z denominator, stores the X and Y
|
||||
* coordinates as ge_storage points in pre, and stores the global Z in globalz.
|
||||
* It only operates on tables sized for WINDOW_A wnaf multiples.
|
||||
* coordinates as ge points in pre, and stores the global Z in globalz.
|
||||
*
|
||||
* 'pre' must be an array of size ECMULT_CONST_TABLE_SIZE.
|
||||
*/
|
||||
static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
|
||||
secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
static void secp256k1_ecmult_const_odd_multiples_table_globalz(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) {
|
||||
secp256k1_fe zr[ECMULT_CONST_TABLE_SIZE];
|
||||
|
||||
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr, globalz, a);
|
||||
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A), pre, zr);
|
||||
secp256k1_ecmult_odd_multiples_table(ECMULT_CONST_TABLE_SIZE, pre, zr, globalz, a);
|
||||
secp256k1_ge_table_set_globalz(ECMULT_CONST_TABLE_SIZE, pre, zr);
|
||||
}
|
||||
|
||||
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
|
||||
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
|
||||
int m = 0; \
|
||||
/* Extract the sign-bit for a constant time absolute-value. */ \
|
||||
int volatile mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
|
||||
int abs_n = ((n) + mask) ^ mask; \
|
||||
int idx_n = abs_n >> 1; \
|
||||
/* Given a table 'pre' with odd multiples of a point, put in r the signed-bit multiplication of n with that point.
|
||||
*
|
||||
* For example, if ECMULT_CONST_GROUP_SIZE is 4, then pre is expected to contain 8 entries:
|
||||
* [1*P, 3*P, 5*P, 7*P, 9*P, 11*P, 13*P, 15*P]. n is then expected to be a 4-bit integer (range 0-15), and its
|
||||
* bits are interpreted as signs of powers of two to look up.
|
||||
*
|
||||
* For example, if n=4, which is 0100 in binary, which is interpreted as [- + - -], so the looked up value is
|
||||
* [ -(2^3) + (2^2) - (2^1) - (2^0) ]*P = -7*P. Every valid n translates to an odd number in range [-15,15],
|
||||
* which means we just need to look up one of the precomputed values, and optionally negate it.
|
||||
*/
|
||||
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n) do { \
|
||||
unsigned int m = 0; \
|
||||
/* If the top bit of n is 0, we want the negation. */ \
|
||||
volatile unsigned int negative = ((n) >> (ECMULT_CONST_GROUP_SIZE - 1)) ^ 1; \
|
||||
/* Let n[i] be the i-th bit of n, then the index is
|
||||
* sum(cnot(n[i]) * 2^i, i=0..l-2)
|
||||
* where cnot(b) = b if n[l-1] = 1 and 1 - b otherwise.
|
||||
* For example, if n = 4, in binary 0100, the index is 3, in binary 011.
|
||||
*
|
||||
* Proof:
|
||||
* Let
|
||||
* x = sum((2*n[i] - 1)*2^i, i=0..l-1)
|
||||
* = 2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 1
|
||||
* be the value represented by n.
|
||||
* The index is (x - 1)/2 if x > 0 and -(x + 1)/2 otherwise.
|
||||
* Case x > 0:
|
||||
* n[l-1] = 1
|
||||
* index = sum(n[i] * 2^i, i=0..l-1) - 2^(l-1)
|
||||
* = sum(n[i] * 2^i, i=0..l-2)
|
||||
* Case x <= 0:
|
||||
* n[l-1] = 0
|
||||
* index = -(2*sum(n[i] * 2^i, i=0..l-1) - 2^l + 2)/2
|
||||
* = 2^(l-1) - 1 - sum(n[i] * 2^i, i=0..l-1)
|
||||
* = sum((1 - n[i]) * 2^i, i=0..l-2)
|
||||
*/ \
|
||||
unsigned int index = ((unsigned int)(-negative) ^ n) & ((1U << (ECMULT_CONST_GROUP_SIZE - 1)) - 1U); \
|
||||
secp256k1_fe neg_y; \
|
||||
VERIFY_CHECK(((n) & 1) == 1); \
|
||||
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
|
||||
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \
|
||||
VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \
|
||||
VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \
|
||||
/* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one \
|
||||
VERIFY_CHECK((n) < (1U << ECMULT_CONST_GROUP_SIZE)); \
|
||||
VERIFY_CHECK(index < (1U << (ECMULT_CONST_GROUP_SIZE - 1))); \
|
||||
/* Unconditionally set r->x = (pre)[m].x. r->y = (pre)[m].y. because it's either the correct one
|
||||
* or will get replaced in the later iterations, this is needed to make sure `r` is initialized. */ \
|
||||
(r)->x = (pre)[m].x; \
|
||||
(r)->y = (pre)[m].y; \
|
||||
for (m = 1; m < ECMULT_TABLE_SIZE(w); m++) { \
|
||||
for (m = 1; m < ECMULT_CONST_TABLE_SIZE; m++) { \
|
||||
/* This loop is used to avoid secret data in array indices. See
|
||||
* the comment in ecmult_gen_impl.h for rationale. */ \
|
||||
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \
|
||||
secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \
|
||||
secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == index); \
|
||||
secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == index); \
|
||||
} \
|
||||
(r)->infinity = 0; \
|
||||
secp256k1_fe_negate(&neg_y, &(r)->y, 1); \
|
||||
secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \
|
||||
secp256k1_fe_cmov(&(r)->y, &neg_y, negative); \
|
||||
} while(0)
|
||||
|
||||
/** Convert a number to WNAF notation.
|
||||
* The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val.
|
||||
* It has the following guarantees:
|
||||
* - each wnaf[i] an odd integer between -(1 << w) and (1 << w)
|
||||
* - each wnaf[i] is nonzero
|
||||
* - the number of words set is always WNAF_SIZE(w) + 1
|
||||
*
|
||||
* Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar
|
||||
* Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.)
|
||||
* CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlag Berlin Heidelberg 2003
|
||||
*
|
||||
* Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
|
||||
*/
|
||||
static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w, int size) {
|
||||
int global_sign;
|
||||
int skew;
|
||||
int word = 0;
|
||||
/* For K as defined in the comment of secp256k1_ecmult_const, we have several precomputed
|
||||
* formulas/constants.
|
||||
* - in exhaustive test mode, we give an explicit expression to compute it at compile time: */
|
||||
#ifdef EXHAUSTIVE_TEST_ORDER
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = ((SECP256K1_SCALAR_CONST(0, 0, 0, (1U << (ECMULT_CONST_BITS - 128)) - 2U, 0, 0, 0, 0) + EXHAUSTIVE_TEST_ORDER - 1U) * (1U + EXHAUSTIVE_TEST_LAMBDA)) % EXHAUSTIVE_TEST_ORDER;
|
||||
/* - for the real secp256k1 group we have constants for various ECMULT_CONST_BITS values. */
|
||||
#elif ECMULT_CONST_BITS == 129
|
||||
/* For GROUP_SIZE = 1,3. */
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xac9c52b3ul, 0x3fa3cf1ful, 0x5ad9e3fdul, 0x77ed9ba4ul, 0xa880b9fcul, 0x8ec739c2ul, 0xe0cfc810ul, 0xb51283ceul);
|
||||
#elif ECMULT_CONST_BITS == 130
|
||||
/* For GROUP_SIZE = 2,5. */
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0xa4e88a7dul, 0xcb13034eul, 0xc2bdd6bful, 0x7c118d6bul, 0x589ae848ul, 0x26ba29e4ul, 0xb5c2c1dcul, 0xde9798d9ul);
|
||||
#elif ECMULT_CONST_BITS == 132
|
||||
/* For GROUP_SIZE = 4,6 */
|
||||
static const secp256k1_scalar secp256k1_ecmult_const_K = SECP256K1_SCALAR_CONST(0x76b1d93dul, 0x0fae3c6bul, 0x3215874bul, 0x94e93813ul, 0x7937fe0dul, 0xb66bcaaful, 0xb3749ca5ul, 0xd7b6171bul);
|
||||
#else
|
||||
# error "Unknown ECMULT_CONST_BITS"
|
||||
#endif
|
||||
|
||||
/* 1 2 3 */
|
||||
int u_last;
|
||||
int u;
|
||||
|
||||
int flip;
|
||||
secp256k1_scalar s = *scalar;
|
||||
|
||||
VERIFY_CHECK(w > 0);
|
||||
VERIFY_CHECK(size > 0);
|
||||
|
||||
/* Note that we cannot handle even numbers by negating them to be odd, as is
|
||||
* done in other implementations, since if our scalars were specified to have
|
||||
* width < 256 for performance reasons, their negations would have width 256
|
||||
* and we'd lose any performance benefit. Instead, we use a variation of a
|
||||
* technique from Section 4.2 of the Okeya/Tagaki paper, which is to add 1 to the
|
||||
* number we are encoding when it is even, returning a skew value indicating
|
||||
* this, and having the caller compensate after doing the multiplication.
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q) {
|
||||
/* The approach below combines the signed-digit logic from Mike Hamburg's
|
||||
* "Fast and compact elliptic-curve cryptography" (https://eprint.iacr.org/2012/309)
|
||||
* Section 3.3, with the GLV endomorphism.
|
||||
*
|
||||
* In fact, we _do_ want to negate numbers to minimize their bit-lengths (and in
|
||||
* particular, to ensure that the outputs from the endomorphism-split fit into
|
||||
* 128 bits). If we negate, the parity of our number flips, affecting whether
|
||||
* we want to add to the scalar to ensure that it's odd. */
|
||||
flip = secp256k1_scalar_is_high(&s);
|
||||
skew = flip ^ secp256k1_scalar_is_even(&s);
|
||||
secp256k1_scalar_cadd_bit(&s, 0, skew);
|
||||
global_sign = secp256k1_scalar_cond_negate(&s, flip);
|
||||
* The idea there is to interpret the bits of a scalar as signs (1 = +, 0 = -), and compute a
|
||||
* point multiplication in that fashion. Let v be an n-bit non-negative integer (0 <= v < 2^n),
|
||||
* and v[i] its i'th bit (so v = sum(v[i] * 2^i, i=0..n-1)). Then define:
|
||||
*
|
||||
* C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1)
|
||||
*
|
||||
* Then it holds that C_l(v, A) = sum((2*v[i] - 1) * 2^i*A, i=0..l-1)
|
||||
* = (2*sum(v[i] * 2^i, i=0..l-1) + 1 - 2^l) * A
|
||||
* = (2*v + 1 - 2^l) * A
|
||||
*
|
||||
* Thus, one can compute q*A as C_256((q + 2^256 - 1) / 2, A). This is the basis for the
|
||||
* paper's signed-digit multi-comb algorithm for multiplication using a precomputed table.
|
||||
*
|
||||
* It is appealing to try to combine this with the GLV optimization: the idea that a scalar
|
||||
* s can be written as s1 + lambda*s2, where lambda is a curve-specific constant such that
|
||||
* lambda*A is easy to compute, and where s1 and s2 are small. In particular we have the
|
||||
* secp256k1_scalar_split_lambda function which performs such a split with the resulting s1
|
||||
* and s2 in range (-2^128, 2^128) mod n. This does work, but is uninteresting:
|
||||
*
|
||||
* To compute q*A:
|
||||
* - Let s1, s2 = split_lambda(q)
|
||||
* - Let R1 = C_256((s1 + 2^256 - 1) / 2, A)
|
||||
* - Let R2 = C_256((s2 + 2^256 - 1) / 2, lambda*A)
|
||||
* - Return R1 + R2
|
||||
*
|
||||
* The issue is that while s1 and s2 are small-range numbers, (s1 + 2^256 - 1) / 2 (mod n)
|
||||
* and (s2 + 2^256 - 1) / 2 (mod n) are not, undoing the benefit of the splitting.
|
||||
*
|
||||
* To make it work, we want to modify the input scalar q first, before splitting, and then only
|
||||
* add a 2^128 offset of the split results (so that they end up in the single 129-bit range
|
||||
* [0,2^129]). A slightly smaller offset would work due to the bounds on the split, but we pick
|
||||
* 2^128 for simplicity. Let s be the scalar fed to split_lambda, and f(q) the function to
|
||||
* compute it from q:
|
||||
*
|
||||
* To compute q*A:
|
||||
* - Compute s = f(q)
|
||||
* - Let s1, s2 = split_lambda(s)
|
||||
* - Let v1 = s1 + 2^128 (mod n)
|
||||
* - Let v2 = s2 + 2^128 (mod n)
|
||||
* - Let R1 = C_l(v1, A)
|
||||
* - Let R2 = C_l(v2, lambda*A)
|
||||
* - Return R1 + R2
|
||||
*
|
||||
* l will thus need to be at least 129, but we may overshoot by a few bits (see
|
||||
* further), so keep it as a variable.
|
||||
*
|
||||
* To solve for s, we reason:
|
||||
* q*A = R1 + R2
|
||||
* <=> q*A = C_l(s1 + 2^128, A) + C_l(s2 + 2^128, lambda*A)
|
||||
* <=> q*A = (2*(s1 + 2^128) + 1 - 2^l) * A + (2*(s2 + 2^128) + 1 - 2^l) * lambda*A
|
||||
* <=> q*A = (2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda)) * A
|
||||
* <=> q = 2*(s1 + s2*lambda) + (2^129 + 1 - 2^l) * (1 + lambda) (mod n)
|
||||
* <=> q = 2*s + (2^129 + 1 - 2^l) * (1 + lambda) (mod n)
|
||||
* <=> s = (q + (2^l - 2^129 - 1) * (1 + lambda)) / 2 (mod n)
|
||||
* <=> f(q) = (q + K) / 2 (mod n)
|
||||
* where K = (2^l - 2^129 - 1)*(1 + lambda) (mod n)
|
||||
*
|
||||
* We will process the computation of C_l(v1, A) and C_l(v2, lambda*A) in groups of
|
||||
* ECMULT_CONST_GROUP_SIZE, so we set l to the smallest multiple of ECMULT_CONST_GROUP_SIZE
|
||||
* that is not less than 129; this equals ECMULT_CONST_BITS.
|
||||
*/
|
||||
|
||||
/* 4 */
|
||||
u_last = secp256k1_scalar_shr_int(&s, w);
|
||||
do {
|
||||
int even;
|
||||
|
||||
/* 4.1 4.4 */
|
||||
u = secp256k1_scalar_shr_int(&s, w);
|
||||
/* 4.2 */
|
||||
even = ((u & 1) == 0);
|
||||
/* In contrast to the original algorithm, u_last is always > 0 and
|
||||
* therefore we do not need to check its sign. In particular, it's easy
|
||||
* to see that u_last is never < 0 because u is never < 0. Moreover,
|
||||
* u_last is never = 0 because u is never even after a loop
|
||||
* iteration. The same holds analogously for the initial value of
|
||||
* u_last (in the first loop iteration). */
|
||||
VERIFY_CHECK(u_last > 0);
|
||||
VERIFY_CHECK((u_last & 1) == 1);
|
||||
u += even;
|
||||
u_last -= even * (1 << w);
|
||||
|
||||
/* 4.3, adapted for global sign change */
|
||||
wnaf[word++] = u_last * global_sign;
|
||||
|
||||
u_last = u;
|
||||
} while (word * w < size);
|
||||
wnaf[word] = u * global_sign;
|
||||
|
||||
VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
|
||||
VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w));
|
||||
return skew;
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
|
||||
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
secp256k1_ge tmpa;
|
||||
secp256k1_fe Z;
|
||||
|
||||
int skew_1;
|
||||
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
int skew_lam;
|
||||
secp256k1_scalar q_1, q_lam;
|
||||
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
|
||||
int i;
|
||||
/* The offset to add to s1 and s2 to make them non-negative. Equal to 2^128. */
|
||||
static const secp256k1_scalar S_OFFSET = SECP256K1_SCALAR_CONST(0, 0, 0, 1, 0, 0, 0, 0);
|
||||
secp256k1_scalar s, v1, v2;
|
||||
secp256k1_ge pre_a[ECMULT_CONST_TABLE_SIZE];
|
||||
secp256k1_ge pre_a_lam[ECMULT_CONST_TABLE_SIZE];
|
||||
secp256k1_fe global_z;
|
||||
int group, i;
|
||||
|
||||
/* We're allowed to be non-constant time in the point, and the code below (in particular,
|
||||
* secp256k1_ecmult_const_odd_multiples_table_globalz) cannot deal with infinity in a
|
||||
* constant-time manner anyway. */
|
||||
if (secp256k1_ge_is_infinity(a)) {
|
||||
secp256k1_gej_set_infinity(r);
|
||||
return;
|
||||
}
|
||||
|
||||
/* build wnaf representation for q. */
|
||||
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
|
||||
secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar);
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128);
|
||||
skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128);
|
||||
/* Compute v1 and v2. */
|
||||
secp256k1_scalar_add(&s, q, &secp256k1_ecmult_const_K);
|
||||
secp256k1_scalar_half(&s, &s);
|
||||
secp256k1_scalar_split_lambda(&v1, &v2, &s);
|
||||
secp256k1_scalar_add(&v1, &v1, &S_OFFSET);
|
||||
secp256k1_scalar_add(&v2, &v2, &S_OFFSET);
|
||||
|
||||
/* Calculate odd multiples of a.
|
||||
#ifdef VERIFY
|
||||
/* Verify that v1 and v2 are in range [0, 2^129-1]. */
|
||||
for (i = 129; i < 256; ++i) {
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits(&v1, i, 1) == 0);
|
||||
VERIFY_CHECK(secp256k1_scalar_get_bits(&v2, i, 1) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate odd multiples of A and A*lambda.
|
||||
* All multiples are brought to the same Z 'denominator', which is stored
|
||||
* in Z. Due to secp256k1' isomorphism we can do all operations pretending
|
||||
* in global_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.
|
||||
*/
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
secp256k1_gej_set_ge(r, a);
|
||||
secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r);
|
||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||
secp256k1_fe_normalize_weak(&pre_a[i].y);
|
||||
}
|
||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||
secp256k1_ecmult_const_odd_multiples_table_globalz(pre_a, &global_z, r);
|
||||
for (i = 0; i < ECMULT_CONST_TABLE_SIZE; i++) {
|
||||
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
|
||||
}
|
||||
|
||||
/* first loop iteration (separated out so we can directly set r, rather
|
||||
* than having it start at infinity, get doubled several times, then have
|
||||
* its new value added to it) */
|
||||
i = wnaf_1[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
|
||||
VERIFY_CHECK(i != 0);
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
|
||||
secp256k1_gej_set_ge(r, &tmpa);
|
||||
i = wnaf_lam[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
|
||||
VERIFY_CHECK(i != 0);
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
/* remaining loop iterations */
|
||||
for (i = WNAF_SIZE_BITS(128, WINDOW_A - 1) - 1; i >= 0; i--) {
|
||||
int n;
|
||||
/* Next, we compute r = C_l(v1, A) + C_l(v2, lambda*A).
|
||||
*
|
||||
* We proceed in groups of ECMULT_CONST_GROUP_SIZE bits, operating on that many bits
|
||||
* at a time, from high in v1, v2 to low. Call these bits1 (from v1) and bits2 (from v2).
|
||||
*
|
||||
* Now note that ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1) loads into t a point equal
|
||||
* to C_{ECMULT_CONST_GROUP_SIZE}(bits1, A), and analogously for pre_lam_a / bits2.
|
||||
* This means that all we need to do is add these looked up values together, multiplied
|
||||
* by 2^(ECMULT_GROUP_SIZE * group).
|
||||
*/
|
||||
for (group = ECMULT_CONST_GROUPS - 1; group >= 0; --group) {
|
||||
/* Using the _var get_bits function is ok here, since it's only variable in offset and count, not in the scalar. */
|
||||
unsigned int bits1 = secp256k1_scalar_get_bits_var(&v1, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE);
|
||||
unsigned int bits2 = secp256k1_scalar_get_bits_var(&v2, group * ECMULT_CONST_GROUP_SIZE, ECMULT_CONST_GROUP_SIZE);
|
||||
secp256k1_ge t;
|
||||
int j;
|
||||
for (j = 0; j < WINDOW_A - 1; ++j) {
|
||||
secp256k1_gej_double(r, r);
|
||||
|
||||
ECMULT_CONST_TABLE_GET_GE(&t, pre_a, bits1);
|
||||
if (group == ECMULT_CONST_GROUPS - 1) {
|
||||
/* Directly set r in the first iteration. */
|
||||
secp256k1_gej_set_ge(r, &t);
|
||||
} else {
|
||||
/* Shift the result so far up. */
|
||||
for (j = 0; j < ECMULT_CONST_GROUP_SIZE; ++j) {
|
||||
secp256k1_gej_double(r, r);
|
||||
}
|
||||
secp256k1_gej_add_ge(r, r, &t);
|
||||
}
|
||||
|
||||
n = wnaf_1[i];
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
|
||||
VERIFY_CHECK(n != 0);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
n = wnaf_lam[i];
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A);
|
||||
VERIFY_CHECK(n != 0);
|
||||
secp256k1_gej_add_ge(r, r, &tmpa);
|
||||
ECMULT_CONST_TABLE_GET_GE(&t, pre_a_lam, bits2);
|
||||
secp256k1_gej_add_ge(r, r, &t);
|
||||
}
|
||||
|
||||
{
|
||||
/* Correct for wNAF skew */
|
||||
secp256k1_gej tmpj;
|
||||
|
||||
secp256k1_ge_neg(&tmpa, &pre_a[0]);
|
||||
secp256k1_gej_add_ge(&tmpj, r, &tmpa);
|
||||
secp256k1_gej_cmov(r, &tmpj, skew_1);
|
||||
|
||||
secp256k1_ge_neg(&tmpa, &pre_a_lam[0]);
|
||||
secp256k1_gej_add_ge(&tmpj, r, &tmpa);
|
||||
secp256k1_gej_cmov(r, &tmpj, skew_lam);
|
||||
}
|
||||
|
||||
secp256k1_fe_mul(&r->z, &r->z, &Z);
|
||||
/* Map the result back to the secp256k1 curve from the isomorphic curve. */
|
||||
secp256k1_fe_mul(&r->z, &r->z, &global_z);
|
||||
}
|
||||
|
||||
static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) {
|
||||
@@ -276,7 +327,7 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n,
|
||||
*
|
||||
* It is easy to verify that both (n*g, g^2, v) and its negation (n*g, -g^2, v) have affine X
|
||||
* coordinate n/d, and this holds even when the square root function doesn't have a
|
||||
* determinstic sign. We choose the (n*g, g^2, v) version.
|
||||
* deterministic sign. We choose the (n*g, g^2, v) version.
|
||||
*
|
||||
* Now switch to the effective affine curve using phi_v, where the input point has coordinates
|
||||
* (n*g, g^2). Compute (X, Y, Z) = q * (n*g, g^2) there.
|
||||
@@ -296,9 +347,7 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n,
|
||||
secp256k1_fe_mul(&g, &g, n);
|
||||
if (d) {
|
||||
secp256k1_fe b;
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero(d));
|
||||
#endif
|
||||
secp256k1_fe_sqr(&b, d);
|
||||
VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */
|
||||
secp256k1_fe_mul_int(&b, SECP256K1_B);
|
||||
@@ -331,13 +380,9 @@ static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n,
|
||||
p.infinity = 0;
|
||||
|
||||
/* Perform x-only EC multiplication of P with q. */
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(q));
|
||||
#endif
|
||||
secp256k1_ecmult_const(&rj, &p, q);
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj));
|
||||
#endif
|
||||
|
||||
/* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to
|
||||
* (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate
|
||||
|
||||
@@ -22,6 +22,9 @@ static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, cons
|
||||
secp256k1_gej nums_gej;
|
||||
int i, j;
|
||||
|
||||
VERIFY_CHECK(g > 0);
|
||||
VERIFY_CHECK(n > 0);
|
||||
|
||||
/* get the generator */
|
||||
secp256k1_gej_set_ge(&gj, gen);
|
||||
|
||||
|
||||
@@ -87,7 +87,6 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
|
||||
secp256k1_fe s;
|
||||
unsigned char nonce32[32];
|
||||
secp256k1_rfc6979_hmac_sha256 rng;
|
||||
int overflow;
|
||||
unsigned char keydata[64];
|
||||
if (seed32 == NULL) {
|
||||
/* When seed is NULL, reset the initial point and blinding value. */
|
||||
@@ -106,11 +105,9 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
|
||||
memcpy(keydata + 32, seed32, 32);
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
|
||||
memset(keydata, 0, sizeof(keydata));
|
||||
/* Accept unobservably small non-uniformity. */
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
overflow = !secp256k1_fe_set_b32_limit(&s, nonce32);
|
||||
overflow |= secp256k1_fe_is_zero(&s);
|
||||
secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
|
||||
secp256k1_fe_set_b32_mod(&s, nonce32);
|
||||
secp256k1_fe_cmov(&s, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&s));
|
||||
/* Randomize the projection to defend against multiplier sidechannels.
|
||||
Do this before our own call to secp256k1_ecmult_gen below. */
|
||||
secp256k1_gej_rescale(&ctx->initial, &s);
|
||||
|
||||
@@ -288,7 +288,9 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
|
||||
}
|
||||
|
||||
/* Bring them to the same Z denominator. */
|
||||
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux);
|
||||
if (no) {
|
||||
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux);
|
||||
}
|
||||
|
||||
for (np = 0; np < no; ++np) {
|
||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||
@@ -770,14 +772,12 @@ static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_cal
|
||||
* require a scratch space */
|
||||
static int secp256k1_ecmult_multi_simple_var(secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) {
|
||||
size_t point_idx;
|
||||
secp256k1_scalar szero;
|
||||
secp256k1_gej tmpj;
|
||||
|
||||
secp256k1_scalar_set_int(&szero, 0);
|
||||
secp256k1_gej_set_infinity(r);
|
||||
secp256k1_gej_set_infinity(&tmpj);
|
||||
/* r = inp_g_sc*G */
|
||||
secp256k1_ecmult(r, &tmpj, &szero, inp_g_sc);
|
||||
secp256k1_ecmult(r, &tmpj, &secp256k1_scalar_zero, inp_g_sc);
|
||||
for (point_idx = 0; point_idx < n_points; point_idx++) {
|
||||
secp256k1_ge point;
|
||||
secp256k1_gej pointj;
|
||||
@@ -825,9 +825,7 @@ static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback,
|
||||
if (inp_g_sc == NULL && n == 0) {
|
||||
return 1;
|
||||
} else if (n == 0) {
|
||||
secp256k1_scalar szero;
|
||||
secp256k1_scalar_set_int(&szero, 0);
|
||||
secp256k1_ecmult(r, r, &szero, inp_g_sc);
|
||||
secp256k1_ecmult(r, r, &secp256k1_scalar_zero, inp_g_sc);
|
||||
return 1;
|
||||
}
|
||||
if (scratch == NULL) {
|
||||
|
||||
54
src/field.h
54
src/field.h
@@ -88,8 +88,8 @@ static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
|
||||
# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod
|
||||
# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit
|
||||
# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32
|
||||
# define secp256k1_fe_negate secp256k1_fe_impl_negate
|
||||
# define secp256k1_fe_mul_int secp256k1_fe_impl_mul_int
|
||||
# define secp256k1_fe_negate_unchecked secp256k1_fe_impl_negate_unchecked
|
||||
# define secp256k1_fe_mul_int_unchecked secp256k1_fe_impl_mul_int_unchecked
|
||||
# define secp256k1_fe_add secp256k1_fe_impl_add
|
||||
# define secp256k1_fe_mul secp256k1_fe_impl_mul
|
||||
# define secp256k1_fe_sqr secp256k1_fe_impl_sqr
|
||||
@@ -176,12 +176,6 @@ static int secp256k1_fe_is_odd(const secp256k1_fe *a);
|
||||
*/
|
||||
static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
|
||||
/** Determine whether two field elements are equal, without constant-time guarantee.
|
||||
*
|
||||
* Identical in behavior to secp256k1_fe_equal, but not constant time in either a or b.
|
||||
*/
|
||||
static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
|
||||
/** Compare the values represented by 2 field elements, without constant-time guarantee.
|
||||
*
|
||||
* On input, a and b must be valid normalized field elements.
|
||||
@@ -190,16 +184,17 @@ static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
*/
|
||||
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
|
||||
/** Set a field element equal to a provided 32-byte big endian value, reducing it.
|
||||
/** Set a field element equal to the element represented by a provided 32-byte big endian value
|
||||
* interpreted modulo p.
|
||||
*
|
||||
* On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
|
||||
* On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array.
|
||||
* On output, r = a (mod p). It will have magnitude 1, and not be normalized.
|
||||
*/
|
||||
static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
|
||||
|
||||
/** Set a field element equal to a provided 32-byte big endian value, checking for overflow.
|
||||
*
|
||||
* On input, r does not need to be initalized. a must be a pointer to an initialized 32-byte array.
|
||||
* On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array.
|
||||
* On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned.
|
||||
* If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting).
|
||||
*/
|
||||
@@ -214,27 +209,39 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
|
||||
/** Negate a field element.
|
||||
*
|
||||
* On input, r does not need to be initialized. a must be a valid field element with
|
||||
* magnitude not exceeding m. m must be an integer in [0,31].
|
||||
* magnitude not exceeding m. m must be an integer constant expression in [0,31].
|
||||
* Performs {r = -a}.
|
||||
* On output, r will not be normalized, and will have magnitude m+1.
|
||||
*/
|
||||
static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||
#define secp256k1_fe_negate(r, a, m) ASSERT_INT_CONST_AND_DO(m, secp256k1_fe_negate_unchecked(r, a, m))
|
||||
|
||||
/** Like secp256k1_fe_negate_unchecked but m is not checked to be an integer constant expression.
|
||||
*
|
||||
* Should not be called directly outside of tests.
|
||||
*/
|
||||
static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||
|
||||
/** Add a small integer to a field element.
|
||||
*
|
||||
* Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared.
|
||||
* a must be in range [0,0xFFFF].
|
||||
* a must be in range [0,0x7FFF].
|
||||
*/
|
||||
static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
|
||||
|
||||
/** Multiply a field element with a small integer.
|
||||
*
|
||||
* On input, r must be a valid field element. a must be an integer in [0,32].
|
||||
* On input, r must be a valid field element. a must be an integer constant expression in [0,32].
|
||||
* The magnitude of r times a must not exceed 32.
|
||||
* Performs {r *= a}.
|
||||
* On output, r's magnitude is multiplied by a, and r will not be normalized.
|
||||
*/
|
||||
static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
|
||||
#define secp256k1_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, secp256k1_fe_mul_int_unchecked(r, a))
|
||||
|
||||
/** Like secp256k1_fe_mul_int but a is not checked to be an integer constant expression.
|
||||
*
|
||||
* Should not be called directly outside of tests.
|
||||
*/
|
||||
static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a);
|
||||
|
||||
/** Increment a field element by another.
|
||||
*
|
||||
@@ -267,8 +274,10 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
/** Compute a square root of a field element.
|
||||
*
|
||||
* On input, a must be a valid field element with magnitude<=8; r need not be initialized.
|
||||
* Performs {r = sqrt(a)} or {r = sqrt(-a)}, whichever exists. The resulting value
|
||||
* represented by r will be a square itself. Variables r and a must not point to the same object.
|
||||
* If sqrt(a) exists, performs {r = sqrt(a)} and returns 1.
|
||||
* Otherwise, sqrt(-a) exists. The function performs {r = sqrt(-a)} and returns 0.
|
||||
* The resulting value represented by r will be a square itself.
|
||||
* Variables r and a must not point to the same object.
|
||||
* On output, r will have magnitude 1 but will not be normalized.
|
||||
*/
|
||||
static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a);
|
||||
@@ -310,7 +319,9 @@ static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_f
|
||||
*
|
||||
* On input, both r and a must be valid field elements. Flag must be 0 or 1.
|
||||
* Performs {r = flag ? a : r}.
|
||||
* On output, r's magnitude and normalized will equal a's in case of flag=1, unchanged otherwise.
|
||||
*
|
||||
* On output, r's magnitude will be the maximum of both input magnitudes.
|
||||
* It will be normalized if and only if both inputs were normalized.
|
||||
*/
|
||||
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
||||
|
||||
@@ -335,5 +346,10 @@ static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
|
||||
|
||||
/** Check invariants on a field element (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a);
|
||||
#define SECP256K1_FE_VERIFY(a) secp256k1_fe_verify(a)
|
||||
|
||||
/** Check that magnitude of a is at most m (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m);
|
||||
#define SECP256K1_FE_VERIFY_MAGNITUDE(a, m) secp256k1_fe_verify_magnitude(a, m)
|
||||
|
||||
#endif /* SECP256K1_FIELD_H */
|
||||
|
||||
@@ -344,7 +344,7 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
r[31] = a->n[0] & 0xff;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
/* For all legal values of m (0..31), the following properties hold: */
|
||||
VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
|
||||
VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
|
||||
@@ -365,7 +365,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec
|
||||
r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9];
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) {
|
||||
r->n[0] *= a;
|
||||
r->n[1] *= a;
|
||||
r->n[2] *= a;
|
||||
@@ -403,11 +403,7 @@ void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a);
|
||||
|
||||
#else
|
||||
|
||||
#ifdef VERIFY
|
||||
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
|
||||
#else
|
||||
#define VERIFY_BITS(x, n) do { } while(0)
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) {
|
||||
uint64_t c, d;
|
||||
|
||||
@@ -1,504 +0,0 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
/**
|
||||
* Changelog:
|
||||
* - March 2013, Diederik Huys: original version
|
||||
* - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm
|
||||
* - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly
|
||||
*/
|
||||
|
||||
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
|
||||
#define SECP256K1_FIELD_INNER5X52_IMPL_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
|
||||
/**
|
||||
* Registers: rdx:rax = multiplication accumulator
|
||||
* r9:r8 = c
|
||||
* r15:rcx = d
|
||||
* r10-r14 = a0-a4
|
||||
* rbx = b
|
||||
* rdi = r
|
||||
* rsi = a / t?
|
||||
*/
|
||||
uint64_t tmp1, tmp2, tmp3;
|
||||
__asm__ __volatile__(
|
||||
"movq 0(%%rsi),%%r10\n"
|
||||
"movq 8(%%rsi),%%r11\n"
|
||||
"movq 16(%%rsi),%%r12\n"
|
||||
"movq 24(%%rsi),%%r13\n"
|
||||
"movq 32(%%rsi),%%r14\n"
|
||||
|
||||
/* d += a3 * b0 */
|
||||
"movq 0(%%rbx),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"movq %%rax,%%rcx\n"
|
||||
"movq %%rdx,%%r15\n"
|
||||
/* d += a2 * b1 */
|
||||
"movq 8(%%rbx),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a1 * b2 */
|
||||
"movq 16(%%rbx),%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d = a0 * b3 */
|
||||
"movq 24(%%rbx),%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* c = a4 * b4 */
|
||||
"movq 32(%%rbx),%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"movq %%rax,%%r8\n"
|
||||
"movq %%rdx,%%r9\n"
|
||||
/* d += (c & M) * R */
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* c >>= 52 (%%r8 only) */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
/* t3 (tmp1) = d & M */
|
||||
"movq %%rcx,%%rsi\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rsi\n"
|
||||
"movq %%rsi,%q1\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%r15,%%rcx\n"
|
||||
"xorq %%r15,%%r15\n"
|
||||
/* d += a4 * b0 */
|
||||
"movq 0(%%rbx),%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a3 * b1 */
|
||||
"movq 8(%%rbx),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a2 * b2 */
|
||||
"movq 16(%%rbx),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a1 * b3 */
|
||||
"movq 24(%%rbx),%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a0 * b4 */
|
||||
"movq 32(%%rbx),%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += c * R */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* t4 = d & M (%%rsi) */
|
||||
"movq %%rcx,%%rsi\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rsi\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%r15,%%rcx\n"
|
||||
"xorq %%r15,%%r15\n"
|
||||
/* tx = t4 >> 48 (tmp3) */
|
||||
"movq %%rsi,%%rax\n"
|
||||
"shrq $48,%%rax\n"
|
||||
"movq %%rax,%q3\n"
|
||||
/* t4 &= (M >> 4) (tmp2) */
|
||||
"movq $0xffffffffffff,%%rax\n"
|
||||
"andq %%rax,%%rsi\n"
|
||||
"movq %%rsi,%q2\n"
|
||||
/* c = a0 * b0 */
|
||||
"movq 0(%%rbx),%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"movq %%rax,%%r8\n"
|
||||
"movq %%rdx,%%r9\n"
|
||||
/* d += a4 * b1 */
|
||||
"movq 8(%%rbx),%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a3 * b2 */
|
||||
"movq 16(%%rbx),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a2 * b3 */
|
||||
"movq 24(%%rbx),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a1 * b4 */
|
||||
"movq 32(%%rbx),%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* u0 = d & M (%%rsi) */
|
||||
"movq %%rcx,%%rsi\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rsi\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%r15,%%rcx\n"
|
||||
"xorq %%r15,%%r15\n"
|
||||
/* u0 = (u0 << 4) | tx (%%rsi) */
|
||||
"shlq $4,%%rsi\n"
|
||||
"movq %q3,%%rax\n"
|
||||
"orq %%rax,%%rsi\n"
|
||||
/* c += u0 * (R >> 4) */
|
||||
"movq $0x1000003d1,%%rax\n"
|
||||
"mulq %%rsi\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* r[0] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq %%rax,0(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* c += a1 * b0 */
|
||||
"movq 0(%%rbx),%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* c += a0 * b1 */
|
||||
"movq 8(%%rbx),%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d += a4 * b2 */
|
||||
"movq 16(%%rbx),%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a3 * b3 */
|
||||
"movq 24(%%rbx),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a2 * b4 */
|
||||
"movq 32(%%rbx),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* c += (d & M) * R */
|
||||
"movq %%rcx,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%r15,%%rcx\n"
|
||||
"xorq %%r15,%%r15\n"
|
||||
/* r[1] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq %%rax,8(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* c += a2 * b0 */
|
||||
"movq 0(%%rbx),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* c += a1 * b1 */
|
||||
"movq 8(%%rbx),%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* c += a0 * b2 (last use of %%r10 = a0) */
|
||||
"movq 16(%%rbx),%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */
|
||||
"movq %q2,%%rsi\n"
|
||||
"movq %q1,%%r10\n"
|
||||
/* d += a4 * b3 */
|
||||
"movq 24(%%rbx),%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* d += a3 * b4 */
|
||||
"movq 32(%%rbx),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rcx\n"
|
||||
"adcq %%rdx,%%r15\n"
|
||||
/* c += (d & M) * R */
|
||||
"movq %%rcx,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d >>= 52 (%%rcx only) */
|
||||
"shrdq $52,%%r15,%%rcx\n"
|
||||
/* r[2] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq %%rax,16(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* c += t3 */
|
||||
"addq %%r10,%%r8\n"
|
||||
/* c += d * R */
|
||||
"movq %%rcx,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* r[3] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0xfffffffffffff,%%rdx\n"
|
||||
"andq %%rdx,%%rax\n"
|
||||
"movq %%rax,24(%%rdi)\n"
|
||||
/* c >>= 52 (%%r8 only) */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
/* c += t4 (%%r8 only) */
|
||||
"addq %%rsi,%%r8\n"
|
||||
/* r[4] = c */
|
||||
"movq %%r8,32(%%rdi)\n"
|
||||
: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
|
||||
: "b"(b), "D"(r)
|
||||
: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
|
||||
/**
|
||||
* Registers: rdx:rax = multiplication accumulator
|
||||
* r9:r8 = c
|
||||
* rcx:rbx = d
|
||||
* r10-r14 = a0-a4
|
||||
* r15 = M (0xfffffffffffff)
|
||||
* rdi = r
|
||||
* rsi = a / t?
|
||||
*/
|
||||
uint64_t tmp1, tmp2, tmp3;
|
||||
__asm__ __volatile__(
|
||||
"movq 0(%%rsi),%%r10\n"
|
||||
"movq 8(%%rsi),%%r11\n"
|
||||
"movq 16(%%rsi),%%r12\n"
|
||||
"movq 24(%%rsi),%%r13\n"
|
||||
"movq 32(%%rsi),%%r14\n"
|
||||
"movq $0xfffffffffffff,%%r15\n"
|
||||
|
||||
/* d = (a0*2) * a3 */
|
||||
"leaq (%%r10,%%r10,1),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"movq %%rax,%%rbx\n"
|
||||
"movq %%rdx,%%rcx\n"
|
||||
/* d += (a1*2) * a2 */
|
||||
"leaq (%%r11,%%r11,1),%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* c = a4 * a4 */
|
||||
"movq %%r14,%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"movq %%rax,%%r8\n"
|
||||
"movq %%rdx,%%r9\n"
|
||||
/* d += (c & M) * R */
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* c >>= 52 (%%r8 only) */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
/* t3 (tmp1) = d & M */
|
||||
"movq %%rbx,%%rsi\n"
|
||||
"andq %%r15,%%rsi\n"
|
||||
"movq %%rsi,%q1\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%rcx,%%rbx\n"
|
||||
"xorq %%rcx,%%rcx\n"
|
||||
/* a4 *= 2 */
|
||||
"addq %%r14,%%r14\n"
|
||||
/* d += a0 * a4 */
|
||||
"movq %%r10,%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* d+= (a1*2) * a3 */
|
||||
"leaq (%%r11,%%r11,1),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* d += a2 * a2 */
|
||||
"movq %%r12,%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* d += c * R */
|
||||
"movq %%r8,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* t4 = d & M (%%rsi) */
|
||||
"movq %%rbx,%%rsi\n"
|
||||
"andq %%r15,%%rsi\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%rcx,%%rbx\n"
|
||||
"xorq %%rcx,%%rcx\n"
|
||||
/* tx = t4 >> 48 (tmp3) */
|
||||
"movq %%rsi,%%rax\n"
|
||||
"shrq $48,%%rax\n"
|
||||
"movq %%rax,%q3\n"
|
||||
/* t4 &= (M >> 4) (tmp2) */
|
||||
"movq $0xffffffffffff,%%rax\n"
|
||||
"andq %%rax,%%rsi\n"
|
||||
"movq %%rsi,%q2\n"
|
||||
/* c = a0 * a0 */
|
||||
"movq %%r10,%%rax\n"
|
||||
"mulq %%r10\n"
|
||||
"movq %%rax,%%r8\n"
|
||||
"movq %%rdx,%%r9\n"
|
||||
/* d += a1 * a4 */
|
||||
"movq %%r11,%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* d += (a2*2) * a3 */
|
||||
"leaq (%%r12,%%r12,1),%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* u0 = d & M (%%rsi) */
|
||||
"movq %%rbx,%%rsi\n"
|
||||
"andq %%r15,%%rsi\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%rcx,%%rbx\n"
|
||||
"xorq %%rcx,%%rcx\n"
|
||||
/* u0 = (u0 << 4) | tx (%%rsi) */
|
||||
"shlq $4,%%rsi\n"
|
||||
"movq %q3,%%rax\n"
|
||||
"orq %%rax,%%rsi\n"
|
||||
/* c += u0 * (R >> 4) */
|
||||
"movq $0x1000003d1,%%rax\n"
|
||||
"mulq %%rsi\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* r[0] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq %%rax,0(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* a0 *= 2 */
|
||||
"addq %%r10,%%r10\n"
|
||||
/* c += a0 * a1 */
|
||||
"movq %%r10,%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d += a2 * a4 */
|
||||
"movq %%r12,%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* d += a3 * a3 */
|
||||
"movq %%r13,%%rax\n"
|
||||
"mulq %%r13\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* c += (d & M) * R */
|
||||
"movq %%rbx,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d >>= 52 */
|
||||
"shrdq $52,%%rcx,%%rbx\n"
|
||||
"xorq %%rcx,%%rcx\n"
|
||||
/* r[1] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq %%rax,8(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* c += a0 * a2 (last use of %%r10) */
|
||||
"movq %%r10,%%rax\n"
|
||||
"mulq %%r12\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */
|
||||
"movq %q2,%%rsi\n"
|
||||
"movq %q1,%%r10\n"
|
||||
/* c += a1 * a1 */
|
||||
"movq %%r11,%%rax\n"
|
||||
"mulq %%r11\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d += a3 * a4 */
|
||||
"movq %%r13,%%rax\n"
|
||||
"mulq %%r14\n"
|
||||
"addq %%rax,%%rbx\n"
|
||||
"adcq %%rdx,%%rcx\n"
|
||||
/* c += (d & M) * R */
|
||||
"movq %%rbx,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* d >>= 52 (%%rbx only) */
|
||||
"shrdq $52,%%rcx,%%rbx\n"
|
||||
/* r[2] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq %%rax,16(%%rdi)\n"
|
||||
/* c >>= 52 */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
"xorq %%r9,%%r9\n"
|
||||
/* c += t3 */
|
||||
"addq %%r10,%%r8\n"
|
||||
/* c += d * R */
|
||||
"movq %%rbx,%%rax\n"
|
||||
"movq $0x1000003d10,%%rdx\n"
|
||||
"mulq %%rdx\n"
|
||||
"addq %%rax,%%r8\n"
|
||||
"adcq %%rdx,%%r9\n"
|
||||
/* r[3] = c & M */
|
||||
"movq %%r8,%%rax\n"
|
||||
"andq %%r15,%%rax\n"
|
||||
"movq %%rax,24(%%rdi)\n"
|
||||
/* c >>= 52 (%%r8 only) */
|
||||
"shrdq $52,%%r9,%%r8\n"
|
||||
/* c += t4 (%%r8 only) */
|
||||
"addq %%rsi,%%r8\n"
|
||||
/* r[4] = c */
|
||||
"movq %%r8,32(%%rdi)\n"
|
||||
: "+S"(a), "=&m"(tmp1), "=&m"(tmp2), "=&m"(tmp3)
|
||||
: "D"(r)
|
||||
: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory"
|
||||
);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
|
||||
@@ -12,11 +12,7 @@
|
||||
#include "field.h"
|
||||
#include "modinv64_impl.h"
|
||||
|
||||
#if defined(USE_ASM_X86_64)
|
||||
#include "field_5x52_asm_impl.h"
|
||||
#else
|
||||
#include "field_5x52_int128_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef VERIFY
|
||||
static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
|
||||
@@ -314,7 +310,7 @@ static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
r[31] = a->n[0] & 0xFF;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
/* For all legal values of m (0..31), the following properties hold: */
|
||||
VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
|
||||
VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
|
||||
@@ -329,7 +325,7 @@ SECP256K1_INLINE static void secp256k1_fe_impl_negate(secp256k1_fe *r, const sec
|
||||
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4];
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a) {
|
||||
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) {
|
||||
r->n[0] *= a;
|
||||
r->n[1] *= a;
|
||||
r->n[2] *= a;
|
||||
|
||||
@@ -12,13 +12,8 @@
|
||||
#include "int128.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef VERIFY
|
||||
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
|
||||
#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n)))
|
||||
#else
|
||||
#define VERIFY_BITS(x, n) do { } while(0)
|
||||
#define VERIFY_BITS_128(x, n) do { } while(0)
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
|
||||
secp256k1_uint128 c, d;
|
||||
@@ -89,18 +84,18 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
|
||||
secp256k1_u128_accum_mul(&d, a2, b[3]);
|
||||
secp256k1_u128_accum_mul(&d, a3, b[2]);
|
||||
secp256k1_u128_accum_mul(&d, a4, b[1]);
|
||||
VERIFY_BITS_128(&d, 115);
|
||||
VERIFY_BITS_128(&d, 114);
|
||||
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
|
||||
VERIFY_BITS(u0, 52);
|
||||
VERIFY_BITS_128(&d, 63);
|
||||
VERIFY_BITS_128(&d, 62);
|
||||
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
u0 = (u0 << 4) | tx;
|
||||
VERIFY_BITS(u0, 56);
|
||||
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
secp256k1_u128_accum_mul(&c, u0, R >> 4);
|
||||
VERIFY_BITS_128(&c, 115);
|
||||
VERIFY_BITS_128(&c, 113);
|
||||
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
|
||||
r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
|
||||
VERIFY_BITS(r[0], 52);
|
||||
@@ -159,7 +154,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
|
||||
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
|
||||
secp256k1_uint128 c, d;
|
||||
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
|
||||
int64_t t3, t4, tx, u0;
|
||||
uint64_t t3, t4, tx, u0;
|
||||
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
|
||||
|
||||
VERIFY_BITS(a[0], 56);
|
||||
|
||||
202
src/field_impl.h
202
src/field_impl.h
@@ -20,31 +20,17 @@
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
secp256k1_fe na;
|
||||
#ifdef VERIFY
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(b);
|
||||
VERIFY_CHECK(a->magnitude <= 1);
|
||||
VERIFY_CHECK(b->magnitude <= 31);
|
||||
#endif
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(b);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 1);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(b, 31);
|
||||
|
||||
secp256k1_fe_negate(&na, a, 1);
|
||||
secp256k1_fe_add(&na, b);
|
||||
return secp256k1_fe_normalizes_to_zero(&na);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
secp256k1_fe na;
|
||||
#ifdef VERIFY
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(b);
|
||||
VERIFY_CHECK(a->magnitude <= 1);
|
||||
VERIFY_CHECK(b->magnitude <= 31);
|
||||
#endif
|
||||
secp256k1_fe_negate(&na, a, 1);
|
||||
secp256k1_fe_add(&na, b);
|
||||
return secp256k1_fe_normalizes_to_zero_var(&na);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a) {
|
||||
/** Given that p is congruent to 3 mod 4, we can compute the square root of
|
||||
* a mod p as the (p+1)/4'th power of a.
|
||||
*
|
||||
@@ -57,11 +43,9 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
|
||||
int j, ret;
|
||||
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(r != a);
|
||||
secp256k1_fe_verify(a);
|
||||
VERIFY_CHECK(a->magnitude <= 8);
|
||||
#endif
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
|
||||
|
||||
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
|
||||
* { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
|
||||
@@ -151,7 +135,7 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
if (!ret) {
|
||||
secp256k1_fe_negate(&t1, &t1, 1);
|
||||
secp256k1_fe_normalize_var(&t1);
|
||||
VERIFY_CHECK(secp256k1_fe_equal_var(&t1, a));
|
||||
VERIFY_CHECK(secp256k1_fe_equal(&t1, a));
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
@@ -159,74 +143,93 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
|
||||
#ifndef VERIFY
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; }
|
||||
static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) { (void)a; (void)m; }
|
||||
#else
|
||||
static void secp256k1_fe_impl_verify(const secp256k1_fe *a);
|
||||
static void secp256k1_fe_verify(const secp256k1_fe *a) {
|
||||
/* Magnitude between 0 and 32. */
|
||||
VERIFY_CHECK((a->magnitude >= 0) && (a->magnitude <= 32));
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 32);
|
||||
/* Normalized is 0 or 1. */
|
||||
VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1));
|
||||
/* If normalized, magnitude must be 0 or 1. */
|
||||
if (a->normalized) VERIFY_CHECK(a->magnitude <= 1);
|
||||
if (a->normalized) SECP256K1_FE_VERIFY_MAGNITUDE(a, 1);
|
||||
/* Invoke implementation-specific checks. */
|
||||
secp256k1_fe_impl_verify(a);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_verify_magnitude(const secp256k1_fe *a, int m) {
|
||||
VERIFY_CHECK(m >= 0);
|
||||
VERIFY_CHECK(m <= 32);
|
||||
VERIFY_CHECK(a->magnitude <= m);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_normalize(r);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_normalize_weak(r);
|
||||
r->magnitude = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_normalize_var(r);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r);
|
||||
SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
return secp256k1_fe_impl_normalizes_to_zero(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r);
|
||||
SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
return secp256k1_fe_impl_normalizes_to_zero_var(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
|
||||
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
|
||||
|
||||
secp256k1_fe_impl_set_int(r, a);
|
||||
r->magnitude = (a != 0);
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
|
||||
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_add_int(r, a);
|
||||
r->magnitude += 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_clear(secp256k1_fe *a);
|
||||
@@ -234,29 +237,33 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
|
||||
a->magnitude = 0;
|
||||
a->normalized = 1;
|
||||
secp256k1_fe_impl_clear(a);
|
||||
secp256k1_fe_verify(a);
|
||||
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
return secp256k1_fe_impl_is_zero(a);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
return secp256k1_fe_impl_is_odd(a);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
|
||||
SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(b);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(b);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
VERIFY_CHECK(b->normalized);
|
||||
|
||||
return secp256k1_fe_impl_cmp_var(a, b);
|
||||
}
|
||||
|
||||
@@ -265,7 +272,8 @@ SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const uns
|
||||
secp256k1_fe_impl_set_b32_mod(r, a);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
|
||||
@@ -273,7 +281,7 @@ SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const un
|
||||
if (secp256k1_fe_impl_set_b32_limit(r, a)) {
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
return 1;
|
||||
} else {
|
||||
/* Mark the output field element as invalid. */
|
||||
@@ -284,85 +292,97 @@ SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const un
|
||||
|
||||
static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
secp256k1_fe_impl_get_b32(r, a);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
secp256k1_fe_verify(a);
|
||||
static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
|
||||
SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(m >= 0 && m <= 31);
|
||||
VERIFY_CHECK(a->magnitude <= m);
|
||||
secp256k1_fe_impl_negate(r, a, m);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, m);
|
||||
|
||||
secp256k1_fe_impl_negate_unchecked(r, a, m);
|
||||
r->magnitude = m + 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_mul_int(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
|
||||
secp256k1_fe_verify(r);
|
||||
static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a) {
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
VERIFY_CHECK(a >= 0 && a <= 32);
|
||||
VERIFY_CHECK(a*r->magnitude <= 32);
|
||||
secp256k1_fe_impl_mul_int(r, a);
|
||||
secp256k1_fe_impl_mul_int_unchecked(r, a);
|
||||
r->magnitude *= a;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(r);
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(r->magnitude + a->magnitude <= 32);
|
||||
|
||||
secp256k1_fe_impl_add(r, a);
|
||||
r->magnitude += a->magnitude;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(b);
|
||||
VERIFY_CHECK(a->magnitude <= 8);
|
||||
VERIFY_CHECK(b->magnitude <= 8);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(b);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(b, 8);
|
||||
VERIFY_CHECK(r != b);
|
||||
VERIFY_CHECK(a != b);
|
||||
|
||||
secp256k1_fe_impl_mul(r, a, b);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(a);
|
||||
VERIFY_CHECK(a->magnitude <= 8);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(a, 8);
|
||||
|
||||
secp256k1_fe_impl_sqr(r, a);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
||||
SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
|
||||
VERIFY_CHECK(flag == 0 || flag == 1);
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
|
||||
secp256k1_fe_impl_cmov(r, a, flag);
|
||||
if (flag) {
|
||||
r->magnitude = a->magnitude;
|
||||
r->normalized = a->normalized;
|
||||
}
|
||||
secp256k1_fe_verify(r);
|
||||
if (a->magnitude > r->magnitude) r->magnitude = a->magnitude;
|
||||
if (!a->normalized) r->normalized = 0;
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
|
||||
SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
|
||||
secp256k1_fe_verify(a);
|
||||
SECP256K1_FE_VERIFY(a);
|
||||
VERIFY_CHECK(a->normalized);
|
||||
|
||||
secp256k1_fe_impl_to_storage(r, a);
|
||||
}
|
||||
|
||||
@@ -371,36 +391,42 @@ SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const se
|
||||
secp256k1_fe_impl_from_storage(r, a);
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x);
|
||||
SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
|
||||
int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
|
||||
secp256k1_fe_verify(x);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
secp256k1_fe_impl_inv(r, x);
|
||||
r->magnitude = x->magnitude > 0;
|
||||
r->normalized = 1;
|
||||
|
||||
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x);
|
||||
SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
|
||||
int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
|
||||
secp256k1_fe_verify(x);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
secp256k1_fe_impl_inv_var(r, x);
|
||||
r->magnitude = x->magnitude > 0;
|
||||
r->normalized = 1;
|
||||
|
||||
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
|
||||
secp256k1_fe_verify(r);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x);
|
||||
SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
|
||||
int ret;
|
||||
secp256k1_fe tmp = *x, sqrt;
|
||||
secp256k1_fe_verify(x);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
ret = secp256k1_fe_impl_is_square_var(x);
|
||||
secp256k1_fe_normalize_weak(&tmp);
|
||||
VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp));
|
||||
@@ -411,20 +437,24 @@ static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m);
|
||||
SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) {
|
||||
VERIFY_CHECK(m >= 0);
|
||||
VERIFY_CHECK(m <= 32);
|
||||
|
||||
secp256k1_fe_impl_get_bounds(r, m);
|
||||
r->magnitude = m;
|
||||
r->normalized = (m == 0);
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_fe_impl_half(secp256k1_fe *r);
|
||||
SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) {
|
||||
secp256k1_fe_verify(r);
|
||||
VERIFY_CHECK(r->magnitude < 32);
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(r, 31);
|
||||
|
||||
secp256k1_fe_impl_half(r);
|
||||
r->magnitude = (r->magnitude >> 1) + 1;
|
||||
r->normalized = 0;
|
||||
secp256k1_fe_verify(r);
|
||||
|
||||
SECP256K1_FE_VERIFY(r);
|
||||
}
|
||||
|
||||
#endif /* defined(VERIFY) */
|
||||
|
||||
25
src/group.h
25
src/group.h
@@ -44,6 +44,14 @@ typedef struct {
|
||||
|
||||
#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y)
|
||||
|
||||
/** Maximum allowed magnitudes for group element coordinates
|
||||
* in affine (x, y) and jacobian (x, y, z) representation. */
|
||||
#define SECP256K1_GE_X_MAGNITUDE_MAX 4
|
||||
#define SECP256K1_GE_Y_MAGNITUDE_MAX 3
|
||||
#define SECP256K1_GEJ_X_MAGNITUDE_MAX 4
|
||||
#define SECP256K1_GEJ_Y_MAGNITUDE_MAX 4
|
||||
#define SECP256K1_GEJ_Z_MAGNITUDE_MAX 1
|
||||
|
||||
/** Set a group element equal to the point with given X and Y coordinates */
|
||||
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y);
|
||||
|
||||
@@ -51,6 +59,12 @@ static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const se
|
||||
* for Y. Return value indicates whether the result is valid. */
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
|
||||
|
||||
/** Determine whether x is a valid X coordinate on the curve. */
|
||||
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x);
|
||||
|
||||
/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */
|
||||
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd);
|
||||
|
||||
/** Check whether a group element is the point at infinity. */
|
||||
static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
|
||||
|
||||
@@ -88,6 +102,9 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
|
||||
*/
|
||||
static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const secp256k1_fe *zr);
|
||||
|
||||
/** Check two group elements (affine) for equality in variable time. */
|
||||
static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b);
|
||||
|
||||
/** Set a group element (affine) equal to the point at infinity. */
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r);
|
||||
|
||||
@@ -100,7 +117,11 @@ static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a);
|
||||
/** Check two group elements (jacobian) for equality in variable time. */
|
||||
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b);
|
||||
|
||||
/** Compare the X coordinate of a group element (jacobian). */
|
||||
/** Check two group elements (jacobian and affine) for equality in variable time. */
|
||||
static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b);
|
||||
|
||||
/** Compare the X coordinate of a group element (jacobian).
|
||||
* The magnitude of the group element's X coordinate must not exceed 31. */
|
||||
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a);
|
||||
|
||||
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
|
||||
@@ -166,8 +187,10 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
|
||||
|
||||
/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_ge_verify(const secp256k1_ge *a);
|
||||
#define SECP256K1_GE_VERIFY(a) secp256k1_ge_verify(a)
|
||||
|
||||
/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_gej_verify(const secp256k1_gej *a);
|
||||
#define SECP256K1_GEJ_VERIFY(a) secp256k1_gej_verify(a)
|
||||
|
||||
#endif /* SECP256K1_GROUP_H */
|
||||
|
||||
344
src/group_impl.h
344
src/group_impl.h
@@ -74,21 +74,22 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;
|
||||
/* End of section generated by sage/gen_exhaustive_groups.sage. */
|
||||
|
||||
static void secp256k1_ge_verify(const secp256k1_ge *a) {
|
||||
#ifdef VERIFY
|
||||
secp256k1_fe_verify(&a->x);
|
||||
secp256k1_fe_verify(&a->y);
|
||||
SECP256K1_FE_VERIFY(&a->x);
|
||||
SECP256K1_FE_VERIFY(&a->y);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GE_X_MAGNITUDE_MAX);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GE_Y_MAGNITUDE_MAX);
|
||||
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
|
||||
#endif
|
||||
(void)a;
|
||||
}
|
||||
|
||||
static void secp256k1_gej_verify(const secp256k1_gej *a) {
|
||||
#ifdef VERIFY
|
||||
secp256k1_fe_verify(&a->x);
|
||||
secp256k1_fe_verify(&a->y);
|
||||
secp256k1_fe_verify(&a->z);
|
||||
SECP256K1_FE_VERIFY(&a->x);
|
||||
SECP256K1_FE_VERIFY(&a->y);
|
||||
SECP256K1_FE_VERIFY(&a->z);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&a->x, SECP256K1_GEJ_X_MAGNITUDE_MAX);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&a->y, SECP256K1_GEJ_Y_MAGNITUDE_MAX);
|
||||
SECP256K1_FE_VERIFY_MAGNITUDE(&a->z, SECP256K1_GEJ_Z_MAGNITUDE_MAX);
|
||||
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
|
||||
#endif
|
||||
(void)a;
|
||||
}
|
||||
|
||||
@@ -96,57 +97,67 @@ static void secp256k1_gej_verify(const secp256k1_gej *a) {
|
||||
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
|
||||
secp256k1_fe zi2;
|
||||
secp256k1_fe zi3;
|
||||
secp256k1_gej_verify(a);
|
||||
secp256k1_fe_verify(zi);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(zi);
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
|
||||
secp256k1_fe_sqr(&zi2, zi);
|
||||
secp256k1_fe_mul(&zi3, &zi2, zi);
|
||||
secp256k1_fe_mul(&r->x, &a->x, &zi2);
|
||||
secp256k1_fe_mul(&r->y, &a->y, &zi3);
|
||||
r->infinity = a->infinity;
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
|
||||
static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) {
|
||||
secp256k1_fe zi2;
|
||||
secp256k1_fe zi3;
|
||||
secp256k1_ge_verify(a);
|
||||
secp256k1_fe_verify(zi);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
SECP256K1_FE_VERIFY(zi);
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
|
||||
secp256k1_fe_sqr(&zi2, zi);
|
||||
secp256k1_fe_mul(&zi3, &zi2, zi);
|
||||
secp256k1_fe_mul(&r->x, &a->x, &zi2);
|
||||
secp256k1_fe_mul(&r->y, &a->y, &zi3);
|
||||
r->infinity = a->infinity;
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) {
|
||||
secp256k1_fe_verify(x);
|
||||
secp256k1_fe_verify(y);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
SECP256K1_FE_VERIFY(y);
|
||||
|
||||
r->infinity = 0;
|
||||
r->x = *x;
|
||||
r->y = *y;
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_is_infinity(const secp256k1_ge *a) {
|
||||
secp256k1_ge_verify(a);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
|
||||
return a->infinity;
|
||||
}
|
||||
|
||||
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) {
|
||||
secp256k1_ge_verify(a);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
|
||||
*r = *a;
|
||||
secp256k1_fe_normalize_weak(&r->y);
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
|
||||
secp256k1_fe z2, z3;
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
r->infinity = a->infinity;
|
||||
secp256k1_fe_inv(&a->z, &a->z);
|
||||
secp256k1_fe_sqr(&z2, &a->z);
|
||||
@@ -156,12 +167,15 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
|
||||
secp256k1_fe_set_int(&a->z, 1);
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
|
||||
secp256k1_fe z2, z3;
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
if (secp256k1_gej_is_infinity(a)) {
|
||||
secp256k1_ge_set_infinity(r);
|
||||
return;
|
||||
@@ -174,16 +188,22 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
|
||||
secp256k1_fe_mul(&a->y, &a->y, &z3);
|
||||
secp256k1_fe_set_int(&a->z, 1);
|
||||
secp256k1_ge_set_xy(r, &a->x, &a->y);
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
|
||||
secp256k1_fe u;
|
||||
size_t i;
|
||||
size_t last_i = SIZE_MAX;
|
||||
#ifdef VERIFY
|
||||
for (i = 0; i < len; i++) {
|
||||
SECP256K1_GEJ_VERIFY(&a[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
secp256k1_gej_verify(&a[i]);
|
||||
if (a[i].infinity) {
|
||||
secp256k1_ge_set_infinity(&r[i]);
|
||||
} else {
|
||||
@@ -217,36 +237,46 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
|
||||
if (!a[i].infinity) {
|
||||
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
|
||||
}
|
||||
secp256k1_ge_verify(&r[i]);
|
||||
}
|
||||
|
||||
#ifdef VERIFY
|
||||
for (i = 0; i < len; i++) {
|
||||
SECP256K1_GE_VERIFY(&r[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
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;
|
||||
secp256k1_fe zs;
|
||||
#ifdef VERIFY
|
||||
for (i = 0; i < len; i++) {
|
||||
SECP256K1_GE_VERIFY(&a[i]);
|
||||
SECP256K1_FE_VERIFY(&zr[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len > 0) {
|
||||
/* Verify inputs a[len-1] and zr[len-1]. */
|
||||
secp256k1_ge_verify(&a[i]);
|
||||
secp256k1_fe_verify(&zr[i]);
|
||||
i = len - 1;
|
||||
/* Ensure all y values are in weak normal form for fast negation of points */
|
||||
secp256k1_fe_normalize_weak(&a[i].y);
|
||||
zs = zr[i];
|
||||
|
||||
/* Work our way backwards, using the z-ratios to scale the x/y values. */
|
||||
while (i > 0) {
|
||||
/* Verify all inputs a[i] and zr[i]. */
|
||||
secp256k1_fe_verify(&zr[i]);
|
||||
secp256k1_ge_verify(&a[i]);
|
||||
if (i != len - 1) {
|
||||
secp256k1_fe_mul(&zs, &zs, &zr[i]);
|
||||
}
|
||||
i--;
|
||||
secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs);
|
||||
/* Verify the output a[i]. */
|
||||
secp256k1_ge_verify(&a[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VERIFY
|
||||
for (i = 0; i < len; i++) {
|
||||
SECP256K1_GE_VERIFY(&a[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
|
||||
@@ -254,14 +284,16 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_fe_clear(&r->z);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
|
||||
r->infinity = 1;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_clear(secp256k1_gej *r) {
|
||||
@@ -269,18 +301,23 @@ static void secp256k1_gej_clear(secp256k1_gej *r) {
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
secp256k1_fe_clear(&r->z);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_clear(secp256k1_ge *r) {
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
||||
secp256k1_fe x2, x3;
|
||||
int ret;
|
||||
secp256k1_fe_verify(x);
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
|
||||
r->x = *x;
|
||||
secp256k1_fe_sqr(&x2, x);
|
||||
secp256k1_fe_mul(&x3, x, &x2);
|
||||
@@ -291,57 +328,94 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o
|
||||
if (secp256k1_fe_is_odd(&r->y) != odd) {
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
}
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
|
||||
secp256k1_ge_verify(a);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
|
||||
r->infinity = a->infinity;
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
secp256k1_fe_set_int(&r->z, 1);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) {
|
||||
secp256k1_gej tmp;
|
||||
secp256k1_gej_verify(b);
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(b);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
secp256k1_gej_neg(&tmp, a);
|
||||
secp256k1_gej_add_var(&tmp, &tmp, b, NULL);
|
||||
return secp256k1_gej_is_infinity(&tmp);
|
||||
}
|
||||
|
||||
static int secp256k1_gej_eq_ge_var(const secp256k1_gej *a, const secp256k1_ge *b) {
|
||||
secp256k1_gej tmp;
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(b);
|
||||
|
||||
secp256k1_gej_neg(&tmp, a);
|
||||
secp256k1_gej_add_ge_var(&tmp, &tmp, b, NULL);
|
||||
return secp256k1_gej_is_infinity(&tmp);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_eq_var(const secp256k1_ge *a, const secp256k1_ge *b) {
|
||||
secp256k1_fe tmp;
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(b);
|
||||
|
||||
if (a->infinity != b->infinity) return 0;
|
||||
if (a->infinity) return 1;
|
||||
|
||||
tmp = a->x;
|
||||
secp256k1_fe_normalize_weak(&tmp);
|
||||
if (!secp256k1_fe_equal(&tmp, &b->x)) return 0;
|
||||
|
||||
tmp = a->y;
|
||||
secp256k1_fe_normalize_weak(&tmp);
|
||||
if (!secp256k1_fe_equal(&tmp, &b->y)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
|
||||
secp256k1_fe r, r2;
|
||||
secp256k1_fe_verify(x);
|
||||
secp256k1_gej_verify(a);
|
||||
secp256k1_fe r;
|
||||
SECP256K1_FE_VERIFY(x);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
|
||||
secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);
|
||||
r2 = a->x; secp256k1_fe_normalize_weak(&r2);
|
||||
return secp256k1_fe_equal_var(&r, &r2);
|
||||
return secp256k1_fe_equal(&r, &a->x);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
r->infinity = a->infinity;
|
||||
r->x = a->x;
|
||||
r->y = a->y;
|
||||
r->z = a->z;
|
||||
secp256k1_fe_normalize_weak(&r->y);
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
return a->infinity;
|
||||
}
|
||||
|
||||
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
|
||||
secp256k1_fe y2, x3;
|
||||
secp256k1_ge_verify(a);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
|
||||
if (a->infinity) {
|
||||
return 0;
|
||||
}
|
||||
@@ -349,15 +423,14 @@ static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
|
||||
secp256k1_fe_sqr(&y2, &a->y);
|
||||
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
|
||||
secp256k1_fe_add_int(&x3, SECP256K1_B);
|
||||
secp256k1_fe_normalize_weak(&x3);
|
||||
return secp256k1_fe_equal_var(&y2, &x3);
|
||||
return secp256k1_fe_equal(&y2, &x3);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) {
|
||||
/* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */
|
||||
secp256k1_fe l, s, t;
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
secp256k1_gej_verify(a);
|
||||
r->infinity = a->infinity;
|
||||
|
||||
/* Formula used:
|
||||
@@ -384,10 +457,13 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
|
||||
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) */
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
/** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity,
|
||||
* Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have
|
||||
* y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p.
|
||||
@@ -398,7 +474,6 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
|
||||
* the infinity flag even though the point doubles to infinity, and the result
|
||||
* point will be gibberish (z = 0 but infinity = 0).
|
||||
*/
|
||||
secp256k1_gej_verify(a);
|
||||
if (a->infinity) {
|
||||
secp256k1_gej_set_infinity(r);
|
||||
if (rzr != NULL) {
|
||||
@@ -413,15 +488,16 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
|
||||
}
|
||||
|
||||
secp256k1_gej_double(r, a);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
|
||||
/* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
|
||||
secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t;
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GEJ_VERIFY(b);
|
||||
|
||||
secp256k1_gej_verify(a);
|
||||
secp256k1_gej_verify(b);
|
||||
if (a->infinity) {
|
||||
VERIFY_CHECK(rzr == NULL);
|
||||
*r = *b;
|
||||
@@ -476,14 +552,16 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
|
||||
secp256k1_fe_mul(&r->y, &t, &i);
|
||||
secp256k1_fe_mul(&h3, &h3, &s1);
|
||||
secp256k1_fe_add(&r->y, &h3);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) {
|
||||
/* 8 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
|
||||
/* Operations: 8 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
|
||||
secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t;
|
||||
secp256k1_gej_verify(a);
|
||||
secp256k1_ge_verify(b);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(b);
|
||||
|
||||
if (a->infinity) {
|
||||
VERIFY_CHECK(rzr == NULL);
|
||||
secp256k1_gej_set_ge(r, b);
|
||||
@@ -498,11 +576,11 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
|
||||
}
|
||||
|
||||
secp256k1_fe_sqr(&z12, &a->z);
|
||||
u1 = a->x; secp256k1_fe_normalize_weak(&u1);
|
||||
u1 = a->x;
|
||||
secp256k1_fe_mul(&u2, &b->x, &z12);
|
||||
s1 = a->y; secp256k1_fe_normalize_weak(&s1);
|
||||
s1 = a->y;
|
||||
secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
|
||||
secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
|
||||
secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2);
|
||||
secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1);
|
||||
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
|
||||
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
|
||||
@@ -536,16 +614,18 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
|
||||
secp256k1_fe_mul(&r->y, &t, &i);
|
||||
secp256k1_fe_mul(&h3, &h3, &s1);
|
||||
secp256k1_fe_add(&r->y, &h3);
|
||||
secp256k1_gej_verify(r);
|
||||
if (rzr != NULL) secp256k1_fe_verify(rzr);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
if (rzr != NULL) SECP256K1_FE_VERIFY(rzr);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) {
|
||||
/* 9 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
|
||||
/* Operations: 9 mul, 3 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
|
||||
secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t;
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(b);
|
||||
SECP256K1_FE_VERIFY(bzinv);
|
||||
|
||||
secp256k1_ge_verify(b);
|
||||
secp256k1_fe_verify(bzinv);
|
||||
if (a->infinity) {
|
||||
secp256k1_fe bzinv2, bzinv3;
|
||||
r->infinity = b->infinity;
|
||||
@@ -554,6 +634,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
|
||||
secp256k1_fe_mul(&r->x, &b->x, &bzinv2);
|
||||
secp256k1_fe_mul(&r->y, &b->y, &bzinv3);
|
||||
secp256k1_fe_set_int(&r->z, 1);
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
return;
|
||||
}
|
||||
if (b->infinity) {
|
||||
@@ -572,11 +653,11 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
|
||||
secp256k1_fe_mul(&az, &a->z, bzinv);
|
||||
|
||||
secp256k1_fe_sqr(&z12, &az);
|
||||
u1 = a->x; secp256k1_fe_normalize_weak(&u1);
|
||||
u1 = a->x;
|
||||
secp256k1_fe_mul(&u2, &b->x, &z12);
|
||||
s1 = a->y; secp256k1_fe_normalize_weak(&s1);
|
||||
s1 = a->y;
|
||||
secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az);
|
||||
secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
|
||||
secp256k1_fe_negate(&h, &u1, SECP256K1_GEJ_X_MAGNITUDE_MAX); secp256k1_fe_add(&h, &u2);
|
||||
secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1);
|
||||
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
|
||||
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
|
||||
@@ -604,19 +685,19 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
|
||||
secp256k1_fe_mul(&r->y, &t, &i);
|
||||
secp256k1_fe_mul(&h3, &h3, &s1);
|
||||
secp256k1_fe_add(&r->y, &h3);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
|
||||
static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) {
|
||||
/* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */
|
||||
/* Operations: 7 mul, 5 sqr, 21 add/cmov/half/mul_int/negate/normalizes_to_zero */
|
||||
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
|
||||
secp256k1_fe m_alt, rr_alt;
|
||||
int degenerate;
|
||||
secp256k1_gej_verify(a);
|
||||
secp256k1_ge_verify(b);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
SECP256K1_GE_VERIFY(b);
|
||||
VERIFY_CHECK(!b->infinity);
|
||||
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
|
||||
|
||||
/* In:
|
||||
* Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks.
|
||||
@@ -669,17 +750,17 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
||||
*/
|
||||
|
||||
secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */
|
||||
u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */
|
||||
u1 = a->x; /* u1 = U1 = X1*Z2^2 (GEJ_X_M) */
|
||||
secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */
|
||||
s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */
|
||||
s1 = a->y; /* s1 = S1 = Y1*Z2^3 (GEJ_Y_M) */
|
||||
secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */
|
||||
secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */
|
||||
t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */
|
||||
m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */
|
||||
t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (GEJ_X_M+1) */
|
||||
m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (GEJ_Y_M+1) */
|
||||
secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */
|
||||
secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */
|
||||
secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */
|
||||
secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */
|
||||
secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 (2) */
|
||||
secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (1) */
|
||||
secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (2) */
|
||||
/* If lambda = R/M = R/0 we have a problem (except in the "trivial"
|
||||
* case that Z = z1z2 = 0, and this is special-cased later on). */
|
||||
degenerate = secp256k1_fe_normalizes_to_zero(&m);
|
||||
@@ -689,24 +770,25 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
||||
* non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2),
|
||||
* so we set R/M equal to this. */
|
||||
rr_alt = s1;
|
||||
secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */
|
||||
secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */
|
||||
secp256k1_fe_mul_int(&rr_alt, 2); /* rr_alt = Y1*Z2^3 - Y2*Z1^3 (GEJ_Y_M*2) */
|
||||
secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 (GEJ_X_M+2) */
|
||||
|
||||
secp256k1_fe_cmov(&rr_alt, &rr, !degenerate);
|
||||
secp256k1_fe_cmov(&m_alt, &m, !degenerate);
|
||||
secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); /* rr_alt (GEJ_Y_M*2) */
|
||||
secp256k1_fe_cmov(&m_alt, &m, !degenerate); /* m_alt (GEJ_X_M+2) */
|
||||
/* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0.
|
||||
* From here on out Ralt and Malt represent the numerator
|
||||
* and denominator of lambda; R and M represent the explicit
|
||||
* expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
|
||||
secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */
|
||||
secp256k1_fe_negate(&q, &t, 2); /* q = -T (3) */
|
||||
secp256k1_fe_negate(&q, &t,
|
||||
SECP256K1_GEJ_X_MAGNITUDE_MAX + 1); /* q = -T (GEJ_X_M+2) */
|
||||
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,
|
||||
* 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
|
||||
* versus two multiplications. */
|
||||
secp256k1_fe_sqr(&n, &n);
|
||||
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
|
||||
secp256k1_fe_sqr(&n, &n); /* n = Malt^4 (1) */
|
||||
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (GEJ_Y_M+1) */
|
||||
secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
|
||||
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */
|
||||
secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */
|
||||
@@ -714,9 +796,10 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
||||
secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */
|
||||
secp256k1_fe_add(&t, &q); /* t = 2*X3 + Q (5) */
|
||||
secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*X3 + Q) (1) */
|
||||
secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (3) */
|
||||
secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */
|
||||
secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */
|
||||
secp256k1_fe_add(&t, &n); /* t = Ralt*(2*X3 + Q) + M^3*Malt (GEJ_Y_M+2) */
|
||||
secp256k1_fe_negate(&r->y, &t,
|
||||
SECP256K1_GEJ_Y_MAGNITUDE_MAX + 2); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (GEJ_Y_M+3) */
|
||||
secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 ((GEJ_Y_M+3)/2 + 1) */
|
||||
|
||||
/* In case a->infinity == 1, replace r with (b->x, b->y, 1). */
|
||||
secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
|
||||
@@ -740,29 +823,31 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
||||
* We have degenerate = false, r->z = (y1 + y2) * Z.
|
||||
* Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */
|
||||
r->infinity = secp256k1_fe_normalizes_to_zero(&r->z);
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
|
||||
/* Operations: 4 mul, 1 sqr */
|
||||
secp256k1_fe zz;
|
||||
secp256k1_gej_verify(r);
|
||||
secp256k1_fe_verify(s);
|
||||
#ifdef VERIFY
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
SECP256K1_FE_VERIFY(s);
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s));
|
||||
#endif
|
||||
|
||||
secp256k1_fe_sqr(&zz, s);
|
||||
secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */
|
||||
secp256k1_fe_mul(&r->y, &r->y, &zz);
|
||||
secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */
|
||||
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) {
|
||||
secp256k1_fe x, y;
|
||||
secp256k1_ge_verify(a);
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
VERIFY_CHECK(!a->infinity);
|
||||
|
||||
x = a->x;
|
||||
secp256k1_fe_normalize(&x);
|
||||
y = a->y;
|
||||
@@ -775,18 +860,20 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag
|
||||
secp256k1_fe_from_storage(&r->x, &a->x);
|
||||
secp256k1_fe_from_storage(&r->y, &a->y);
|
||||
r->infinity = 0;
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) {
|
||||
secp256k1_gej_verify(r);
|
||||
secp256k1_gej_verify(a);
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
SECP256K1_GEJ_VERIFY(a);
|
||||
|
||||
secp256k1_fe_cmov(&r->x, &a->x, flag);
|
||||
secp256k1_fe_cmov(&r->y, &a->y, flag);
|
||||
secp256k1_fe_cmov(&r->z, &a->z, flag);
|
||||
|
||||
r->infinity ^= (r->infinity ^ a->infinity) & flag;
|
||||
secp256k1_gej_verify(r);
|
||||
|
||||
SECP256K1_GEJ_VERIFY(r);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
|
||||
@@ -795,18 +882,20 @@ 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) {
|
||||
SECP256K1_GE_VERIFY(a);
|
||||
|
||||
*r = *a;
|
||||
secp256k1_ge_verify(a);
|
||||
secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta);
|
||||
secp256k1_ge_verify(r);
|
||||
|
||||
SECP256K1_GE_VERIFY(r);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
|
||||
#ifdef EXHAUSTIVE_TEST_ORDER
|
||||
secp256k1_gej out;
|
||||
int i;
|
||||
SECP256K1_GE_VERIFY(ge);
|
||||
|
||||
secp256k1_ge_verify(ge);
|
||||
/* A very simple EC multiplication ladder that avoids a dependency on ecmult. */
|
||||
secp256k1_gej_set_infinity(&out);
|
||||
for (i = 0; i < 32; ++i) {
|
||||
@@ -817,10 +906,39 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
|
||||
}
|
||||
return secp256k1_gej_is_infinity(&out);
|
||||
#else
|
||||
SECP256K1_GE_VERIFY(ge);
|
||||
|
||||
(void)ge;
|
||||
/* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x) {
|
||||
secp256k1_fe c;
|
||||
secp256k1_fe_sqr(&c, x);
|
||||
secp256k1_fe_mul(&c, &c, x);
|
||||
secp256k1_fe_add_int(&c, SECP256K1_B);
|
||||
return secp256k1_fe_is_square_var(&c);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd) {
|
||||
/* We want to determine whether (xn/xd) is on the curve.
|
||||
*
|
||||
* (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square).
|
||||
*/
|
||||
secp256k1_fe r, t;
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd));
|
||||
|
||||
secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */
|
||||
secp256k1_fe_sqr(&t, xn); /* t = xn^2 */
|
||||
secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */
|
||||
secp256k1_fe_sqr(&t, xd); /* t = xd^2 */
|
||||
secp256k1_fe_sqr(&t, &t); /* t = xd^4 */
|
||||
VERIFY_CHECK(SECP256K1_B <= 31);
|
||||
secp256k1_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */
|
||||
secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */
|
||||
return secp256k1_fe_is_square_var(&r);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_GROUP_IMPL_H */
|
||||
|
||||
@@ -138,7 +138,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
|
||||
}
|
||||
if (len) {
|
||||
/* Fill the buffer with what remains. */
|
||||
memcpy(((unsigned char*)hash->buf) + bufsize, data, len);
|
||||
memcpy(hash->buf + bufsize, data, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,12 @@ static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigne
|
||||
r->lo = r->hi >> (n-64);
|
||||
r->hi = 0;
|
||||
} else if (n > 0) {
|
||||
#if defined(_MSC_VER) && defined(_M_X64)
|
||||
VERIFY_CHECK(n < 64);
|
||||
r->lo = __shiftright128(r->lo, r->hi, n);
|
||||
#else
|
||||
r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
|
||||
#endif
|
||||
r->hi >>= n;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,6 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3
|
||||
r->v[7] = r7;
|
||||
r->v[8] = r8;
|
||||
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(r0 >> 30 == 0);
|
||||
VERIFY_CHECK(r1 >> 30 == 0);
|
||||
VERIFY_CHECK(r2 >> 30 == 0);
|
||||
@@ -156,7 +155,6 @@ static void secp256k1_modinv32_normalize_30(secp256k1_modinv32_signed30 *r, int3
|
||||
VERIFY_CHECK(r8 >> 30 == 0);
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 0) >= 0); /* r >= 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(r, 9, &modinfo->modulus, 1) < 0); /* r < modulus */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Data type for transition matrices (see section 3 of explanation).
|
||||
@@ -413,14 +411,13 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp
|
||||
int32_t di, ei, md, me, sd, se;
|
||||
int64_t cd, ce;
|
||||
int i;
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
|
||||
VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */
|
||||
VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */
|
||||
#endif
|
||||
|
||||
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
|
||||
sd = d->v[8] >> 31;
|
||||
se = e->v[8] >> 31;
|
||||
@@ -455,12 +452,11 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp
|
||||
/* What remains is limb 9 of t*[d,e]+modulus*[md,me]; store it as output limb 8. */
|
||||
d->v[8] = (int32_t)cd;
|
||||
e->v[8] = (int32_t)ce;
|
||||
#ifdef VERIFY
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps.
|
||||
@@ -550,25 +546,23 @@ static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_m
|
||||
/* Update d,e using that transition matrix. */
|
||||
secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo);
|
||||
/* Update f,g using that transition matrix. */
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
|
||||
secp256k1_modinv32_update_fg_30(&f, &g, &t);
|
||||
#ifdef VERIFY
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* At this point sufficient iterations have been performed that g must have reached 0
|
||||
* and (if g was not originally 0) f must now equal +/- GCD of the initial f, g
|
||||
* values i.e. +/- 1, and d now contains +/- the modular inverse. */
|
||||
#ifdef VERIFY
|
||||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, 9, &SECP256K1_SIGNED30_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
|
||||
@@ -578,7 +572,6 @@ static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_m
|
||||
secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
|
||||
(secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, 1) == 0 ||
|
||||
secp256k1_modinv32_mul_cmp_30(&f, 9, &modinfo->modulus, -1) == 0)));
|
||||
#endif
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv32_normalize_30(&d, f.v[8], modinfo);
|
||||
@@ -607,12 +600,12 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
|
||||
/* Update d,e using that transition matrix. */
|
||||
secp256k1_modinv32_update_de_30(&d, &e, &t, modinfo);
|
||||
/* Update f,g using that transition matrix. */
|
||||
#ifdef VERIFY
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
|
||||
secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
|
||||
/* If the bottom limb of g is 0, there is a chance g=0. */
|
||||
if (g.v[0] == 0) {
|
||||
@@ -637,18 +630,17 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
|
||||
g.v[len - 2] |= (uint32_t)gn << 30;
|
||||
--len;
|
||||
}
|
||||
#ifdef VERIFY
|
||||
|
||||
VERIFY_CHECK(++i < 25); /* We should never need more than 25*30 = 750 divsteps */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of
|
||||
* the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */
|
||||
#ifdef VERIFY
|
||||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &SECP256K1_SIGNED30_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
|
||||
@@ -658,7 +650,6 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
|
||||
secp256k1_modinv32_mul_cmp_30(&d, 9, &SECP256K1_SIGNED30_ONE, 0) == 0 &&
|
||||
(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) == 0 ||
|
||||
secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, -1) == 0)));
|
||||
#endif
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv32_normalize_30(&d, f.v[len - 1], modinfo);
|
||||
@@ -697,12 +688,11 @@ static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, co
|
||||
secp256k1_modinv32_trans2x2 t;
|
||||
eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac);
|
||||
/* Update f,g using that transition matrix. */
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
|
||||
secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
|
||||
/* If the bottom limb of f is 1, there is a chance that f=1. */
|
||||
if (f.v[0] == 1) {
|
||||
@@ -723,12 +713,11 @@ static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, co
|
||||
cond |= gn;
|
||||
/* If so, reduce length. */
|
||||
if (cond == 0) --len;
|
||||
#ifdef VERIFY
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */
|
||||
|
||||
@@ -144,7 +144,6 @@ static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int6
|
||||
r->v[3] = r3;
|
||||
r->v[4] = r4;
|
||||
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(r0 >> 62 == 0);
|
||||
VERIFY_CHECK(r1 >> 62 == 0);
|
||||
VERIFY_CHECK(r2 >> 62 == 0);
|
||||
@@ -152,7 +151,6 @@ static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int6
|
||||
VERIFY_CHECK(r4 >> 62 == 0);
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 0) >= 0); /* r >= 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(r, 5, &modinfo->modulus, 1) < 0); /* r < modulus */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)).
|
||||
@@ -216,7 +214,7 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
|
||||
t->v = (int64_t)v;
|
||||
t->q = (int64_t)q;
|
||||
t->r = (int64_t)r;
|
||||
#ifdef VERIFY
|
||||
|
||||
/* The determinant of t must be a power of two. This guarantees that multiplication with t
|
||||
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
|
||||
* will be divided out again). As each divstep's individual matrix has determinant 2, the
|
||||
@@ -224,7 +222,7 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
|
||||
* 8*identity (which has determinant 2^6) means the overall outputs has determinant
|
||||
* 2^65. */
|
||||
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0));
|
||||
#endif
|
||||
|
||||
return zeta;
|
||||
}
|
||||
|
||||
@@ -301,13 +299,13 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
|
||||
t->v = (int64_t)v;
|
||||
t->q = (int64_t)q;
|
||||
t->r = (int64_t)r;
|
||||
#ifdef VERIFY
|
||||
|
||||
/* The determinant of t must be a power of two. This guarantees that multiplication with t
|
||||
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
|
||||
* will be divided out again). As each divstep's individual matrix has determinant 2, the
|
||||
* aggregate of 62 of them will have determinant 2^62. */
|
||||
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0));
|
||||
#endif
|
||||
|
||||
return eta;
|
||||
}
|
||||
|
||||
@@ -392,13 +390,13 @@ static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, u
|
||||
t->v = (int64_t)v;
|
||||
t->q = (int64_t)q;
|
||||
t->r = (int64_t)r;
|
||||
#ifdef VERIFY
|
||||
|
||||
/* The determinant of t must be a power of two. This guarantees that multiplication with t
|
||||
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
|
||||
* will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
|
||||
* the aggregate of 62 of them will have determinant 2^62 or -2^62. */
|
||||
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1));
|
||||
#endif
|
||||
|
||||
*jacp = jac;
|
||||
return eta;
|
||||
}
|
||||
@@ -417,14 +415,13 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
|
||||
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
|
||||
int64_t md, me, sd, se;
|
||||
secp256k1_int128 cd, ce;
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */
|
||||
#endif
|
||||
|
||||
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
|
||||
sd = d4 >> 63;
|
||||
se = e4 >> 63;
|
||||
@@ -489,12 +486,11 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
|
||||
/* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
|
||||
d->v[4] = secp256k1_i128_to_i64(&cd);
|
||||
e->v[4] = secp256k1_i128_to_i64(&ce);
|
||||
#ifdef VERIFY
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Compute (t/2^62) * [f, g], where t is a transition matrix scaled by 2^62.
|
||||
@@ -606,25 +602,23 @@ static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_m
|
||||
/* Update d,e using that transition matrix. */
|
||||
secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo);
|
||||
/* Update f,g using that transition matrix. */
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
|
||||
secp256k1_modinv64_update_fg_62(&f, &g, &t);
|
||||
#ifdef VERIFY
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* At this point sufficient iterations have been performed that g must have reached 0
|
||||
* and (if g was not originally 0) f must now equal +/- GCD of the initial f, g
|
||||
* values i.e. +/- 1, and d now contains +/- the modular inverse. */
|
||||
#ifdef VERIFY
|
||||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, 5, &SECP256K1_SIGNED62_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
|
||||
@@ -634,7 +628,6 @@ static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_m
|
||||
secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
|
||||
(secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, 1) == 0 ||
|
||||
secp256k1_modinv64_mul_cmp_62(&f, 5, &modinfo->modulus, -1) == 0)));
|
||||
#endif
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv64_normalize_62(&d, f.v[4], modinfo);
|
||||
@@ -663,12 +656,11 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
|
||||
/* Update d,e using that transition matrix. */
|
||||
secp256k1_modinv64_update_de_62(&d, &e, &t, modinfo);
|
||||
/* Update f,g using that transition matrix. */
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
|
||||
secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
|
||||
/* If the bottom limb of g is zero, there is a chance that g=0. */
|
||||
if (g.v[0] == 0) {
|
||||
@@ -693,18 +685,17 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
|
||||
g.v[len - 2] |= (uint64_t)gn << 62;
|
||||
--len;
|
||||
}
|
||||
#ifdef VERIFY
|
||||
|
||||
VERIFY_CHECK(++i < 12); /* We should never need more than 12*62 = 744 divsteps */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) > 0); /* f > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, -1) > 0); /* g > -modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* At this point g is 0 and (if g was not originally 0) f must now equal +/- GCD of
|
||||
* the initial f, g values i.e. +/- 1, and d now contains +/- the modular inverse. */
|
||||
#ifdef VERIFY
|
||||
|
||||
/* g == 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &SECP256K1_SIGNED62_ONE, 0) == 0);
|
||||
/* |f| == 1, or (x == 0 and d == 0 and |f|=modulus) */
|
||||
@@ -714,7 +705,6 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
|
||||
secp256k1_modinv64_mul_cmp_62(&d, 5, &SECP256K1_SIGNED62_ONE, 0) == 0 &&
|
||||
(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) == 0 ||
|
||||
secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, -1) == 0)));
|
||||
#endif
|
||||
|
||||
/* Optionally negate d, normalize to [0,modulus), and return it. */
|
||||
secp256k1_modinv64_normalize_62(&d, f.v[len - 1], modinfo);
|
||||
@@ -753,12 +743,11 @@ static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, co
|
||||
secp256k1_modinv64_trans2x2 t;
|
||||
eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac);
|
||||
/* Update f,g using that transition matrix. */
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
|
||||
secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
|
||||
/* If the bottom limb of f is 1, there is a chance that f=1. */
|
||||
if (f.v[0] == 1) {
|
||||
@@ -779,12 +768,11 @@ static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, co
|
||||
cond |= gn;
|
||||
/* If so, reduce length. */
|
||||
if (cond == 0) --len;
|
||||
#ifdef VERIFY
|
||||
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
|
||||
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */
|
||||
|
||||
@@ -25,32 +25,19 @@ static int ecdh_hash_function_custom(unsigned char *output, const unsigned char
|
||||
}
|
||||
|
||||
static void test_ecdh_api(void) {
|
||||
/* Setup context that just counts errors */
|
||||
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
secp256k1_pubkey point;
|
||||
unsigned char res[32];
|
||||
unsigned char s_one[32] = { 0 };
|
||||
int32_t ecount = 0;
|
||||
s_one[31] = 1;
|
||||
|
||||
secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount);
|
||||
CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1);
|
||||
|
||||
/* Check all NULLs are detected */
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/* Cleanup */
|
||||
secp256k1_context_destroy(tctx);
|
||||
CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, NULL, &point, s_one, NULL, NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, NULL, s_one, NULL, NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdh(CTX, res, &point, NULL, NULL, NULL));
|
||||
CHECK(secp256k1_ecdh(CTX, res, &point, s_one, NULL, NULL) == 1);
|
||||
}
|
||||
|
||||
static void test_ecdh_generator_basepoint(void) {
|
||||
|
||||
5
src/modules/ellswift/Makefile.am.include
Normal file
5
src/modules/ellswift/Makefile.am.include
Normal file
@@ -0,0 +1,5 @@
|
||||
include_HEADERS += include/secp256k1_ellswift.h
|
||||
noinst_HEADERS += src/modules/ellswift/bench_impl.h
|
||||
noinst_HEADERS += src/modules/ellswift/main_impl.h
|
||||
noinst_HEADERS += src/modules/ellswift/tests_impl.h
|
||||
noinst_HEADERS += src/modules/ellswift/tests_exhaustive_impl.h
|
||||
106
src/modules/ellswift/bench_impl.h
Normal file
106
src/modules/ellswift/bench_impl.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ELLSWIFT_BENCH_H
|
||||
#define SECP256K1_MODULE_ELLSWIFT_BENCH_H
|
||||
|
||||
#include "../../../include/secp256k1_ellswift.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
secp256k1_pubkey point[256];
|
||||
unsigned char rnd64[64];
|
||||
} bench_ellswift_data;
|
||||
|
||||
static void bench_ellswift_setup(void *arg) {
|
||||
int i;
|
||||
bench_ellswift_data *data = (bench_ellswift_data*)arg;
|
||||
static const unsigned char init[64] = {
|
||||
0x78, 0x1f, 0xb7, 0xd4, 0x67, 0x7f, 0x08, 0x68,
|
||||
0xdb, 0xe3, 0x1d, 0x7f, 0x1b, 0xb0, 0xf6, 0x9e,
|
||||
0x0a, 0x64, 0xca, 0x32, 0x9e, 0xc6, 0x20, 0x79,
|
||||
0x03, 0xf3, 0xd0, 0x46, 0x7a, 0x0f, 0xd2, 0x21,
|
||||
0xb0, 0x2c, 0x46, 0xd8, 0xba, 0xca, 0x26, 0x4f,
|
||||
0x8f, 0x8c, 0xd4, 0xdd, 0x2d, 0x04, 0xbe, 0x30,
|
||||
0x48, 0x51, 0x1e, 0xd4, 0x16, 0xfd, 0x42, 0x85,
|
||||
0x62, 0xc9, 0x02, 0xf9, 0x89, 0x84, 0xff, 0xdc
|
||||
};
|
||||
memcpy(data->rnd64, init, 64);
|
||||
for (i = 0; i < 256; ++i) {
|
||||
int j;
|
||||
CHECK(secp256k1_ellswift_decode(data->ctx, &data->point[i], data->rnd64));
|
||||
for (j = 0; j < 64; ++j) {
|
||||
data->rnd64[j] += 1;
|
||||
}
|
||||
}
|
||||
CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[255], init + 16));
|
||||
}
|
||||
|
||||
static void bench_ellswift_encode(void *arg, int iters) {
|
||||
int i;
|
||||
bench_ellswift_data *data = (bench_ellswift_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
CHECK(secp256k1_ellswift_encode(data->ctx, data->rnd64, &data->point[i & 255], data->rnd64 + 16));
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_ellswift_create(void *arg, int iters) {
|
||||
int i;
|
||||
bench_ellswift_data *data = (bench_ellswift_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
unsigned char buf[64];
|
||||
CHECK(secp256k1_ellswift_create(data->ctx, buf, data->rnd64, data->rnd64 + 32));
|
||||
memcpy(data->rnd64, buf, 64);
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_ellswift_decode(void *arg, int iters) {
|
||||
int i;
|
||||
secp256k1_pubkey out;
|
||||
size_t len;
|
||||
bench_ellswift_data *data = (bench_ellswift_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
CHECK(secp256k1_ellswift_decode(data->ctx, &out, data->rnd64) == 1);
|
||||
len = 33;
|
||||
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->rnd64 + (i % 32), &len, &out, SECP256K1_EC_COMPRESSED));
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_ellswift_xdh(void *arg, int iters) {
|
||||
int i;
|
||||
bench_ellswift_data *data = (bench_ellswift_data*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
int party = i & 1;
|
||||
CHECK(secp256k1_ellswift_xdh(data->ctx,
|
||||
data->rnd64 + (i % 33),
|
||||
data->rnd64,
|
||||
data->rnd64,
|
||||
data->rnd64 + ((i + 16) % 33),
|
||||
party,
|
||||
secp256k1_ellswift_xdh_hash_function_bip324,
|
||||
NULL) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
void run_ellswift_bench(int iters, int argc, char **argv) {
|
||||
bench_ellswift_data data;
|
||||
int d = argc == 1;
|
||||
|
||||
/* create a context with signing capabilities */
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
|
||||
if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "encode") || have_flag(argc, argv, "ellswift_encode")) run_benchmark("ellswift_encode", bench_ellswift_encode, bench_ellswift_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_decode")) run_benchmark("ellswift_decode", bench_ellswift_decode, bench_ellswift_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ellswift_keygen")) run_benchmark("ellswift_keygen", bench_ellswift_create, bench_ellswift_setup, NULL, &data, 10, iters);
|
||||
if (d || have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ecdh") || have_flag(argc, argv, "ellswift_ecdh")) run_benchmark("ellswift_ecdh", bench_ellswift_xdh, bench_ellswift_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
}
|
||||
|
||||
#endif
|
||||
590
src/modules/ellswift/main_impl.h
Normal file
590
src/modules/ellswift/main_impl.h
Normal file
@@ -0,0 +1,590 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ELLSWIFT_MAIN_H
|
||||
#define SECP256K1_MODULE_ELLSWIFT_MAIN_H
|
||||
|
||||
#include "../../../include/secp256k1.h"
|
||||
#include "../../../include/secp256k1_ellswift.h"
|
||||
#include "../../eckey.h"
|
||||
#include "../../hash.h"
|
||||
|
||||
/** c1 = (sqrt(-3)-1)/2 */
|
||||
static const secp256k1_fe secp256k1_ellswift_c1 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40);
|
||||
/** c2 = (-sqrt(-3)-1)/2 = -(c1+1) */
|
||||
static const secp256k1_fe secp256k1_ellswift_c2 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ee);
|
||||
/** c3 = (-sqrt(-3)+1)/2 = -c1 = c2+1 */
|
||||
static const secp256k1_fe secp256k1_ellswift_c3 = SECP256K1_FE_CONST(0x7ae96a2b, 0x657c0710, 0x6e64479e, 0xac3434e9, 0x9cf04975, 0x12f58995, 0xc1396c28, 0x719501ef);
|
||||
/** c4 = (sqrt(-3)+1)/2 = -c2 = c1+1 */
|
||||
static const secp256k1_fe secp256k1_ellswift_c4 = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa41);
|
||||
|
||||
/** Decode ElligatorSwift encoding (u, t) to a fraction xn/xd representing a curve X coordinate. */
|
||||
static void secp256k1_ellswift_xswiftec_frac_var(secp256k1_fe *xn, secp256k1_fe *xd, const secp256k1_fe *u, const secp256k1_fe *t) {
|
||||
/* The implemented algorithm is the following (all operations in GF(p)):
|
||||
*
|
||||
* - Let c0 = sqrt(-3) = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852.
|
||||
* - If u = 0, set u = 1.
|
||||
* - If t = 0, set t = 1.
|
||||
* - If u^3+7+t^2 = 0, set t = 2*t.
|
||||
* - Let X = (u^3+7-t^2)/(2*t).
|
||||
* - Let Y = (X+t)/(c0*u).
|
||||
* - If x3 = u+4*Y^2 is a valid x coordinate, return it.
|
||||
* - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it.
|
||||
* - Return x1 = (X/Y-u)/2 (which is now guaranteed to be a valid x coordinate).
|
||||
*
|
||||
* Introducing s=t^2, g=u^3+7, and simplifying x1=-(x2+u) we get:
|
||||
*
|
||||
* - Let c0 = ...
|
||||
* - If u = 0, set u = 1.
|
||||
* - If t = 0, set t = 1.
|
||||
* - Let s = t^2
|
||||
* - Let g = u^3+7
|
||||
* - If g+s = 0, set t = 2*t, s = 4*s
|
||||
* - Let X = (g-s)/(2*t).
|
||||
* - Let Y = (X+t)/(c0*u) = (g+s)/(2*c0*t*u).
|
||||
* - If x3 = u+4*Y^2 is a valid x coordinate, return it.
|
||||
* - If x2 = (-X/Y-u)/2 is a valid x coordinate, return it.
|
||||
* - Return x1 = -(x2+u).
|
||||
*
|
||||
* Now substitute Y^2 = -(g+s)^2/(12*s*u^2) and X/Y = c0*u*(g-s)/(g+s). This
|
||||
* means X and Y do not need to be evaluated explicitly anymore.
|
||||
*
|
||||
* - ...
|
||||
* - If g+s = 0, set s = 4*s.
|
||||
* - If x3 = u-(g+s)^2/(3*s*u^2) is a valid x coordinate, return it.
|
||||
* - If x2 = (-c0*u*(g-s)/(g+s)-u)/2 is a valid x coordinate, return it.
|
||||
* - Return x1 = -(x2+u).
|
||||
*
|
||||
* Simplifying x2 using 2 additional constants:
|
||||
*
|
||||
* - Let c1 = (c0-1)/2 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40.
|
||||
* - Let c2 = (-c0-1)/2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee.
|
||||
* - ...
|
||||
* - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it.
|
||||
* - ...
|
||||
*
|
||||
* Writing x3 as a fraction:
|
||||
*
|
||||
* - ...
|
||||
* - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) ...
|
||||
* - ...
|
||||
|
||||
* Overall, we get:
|
||||
*
|
||||
* - Let c1 = 0x851695d49a83f8ef919bb86153cbcb16630fb68aed0a766a3ec693d68e6afa40.
|
||||
* - Let c2 = 0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee.
|
||||
* - If u = 0, set u = 1.
|
||||
* - If t = 0, set s = 1, else set s = t^2.
|
||||
* - Let g = u^3+7.
|
||||
* - If g+s = 0, set s = 4*s.
|
||||
* - If x3 = (3*s*u^3-(g+s)^2)/(3*s*u^2) is a valid x coordinate, return it.
|
||||
* - If x2 = u*(c1*s+c2*g)/(g+s) is a valid x coordinate, return it.
|
||||
* - Return x1 = -(x2+u).
|
||||
*/
|
||||
secp256k1_fe u1, s, g, p, d, n, l;
|
||||
u1 = *u;
|
||||
if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&u1), 0)) u1 = secp256k1_fe_one;
|
||||
secp256k1_fe_sqr(&s, t);
|
||||
if (EXPECT(secp256k1_fe_normalizes_to_zero_var(t), 0)) s = secp256k1_fe_one;
|
||||
secp256k1_fe_sqr(&l, &u1); /* l = u^2 */
|
||||
secp256k1_fe_mul(&g, &l, &u1); /* g = u^3 */
|
||||
secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3 + 7 */
|
||||
p = g; /* p = g */
|
||||
secp256k1_fe_add(&p, &s); /* p = g+s */
|
||||
if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&p), 0)) {
|
||||
secp256k1_fe_mul_int(&s, 4);
|
||||
/* Recompute p = g+s */
|
||||
p = g; /* p = g */
|
||||
secp256k1_fe_add(&p, &s); /* p = g+s */
|
||||
}
|
||||
secp256k1_fe_mul(&d, &s, &l); /* d = s*u^2 */
|
||||
secp256k1_fe_mul_int(&d, 3); /* d = 3*s*u^2 */
|
||||
secp256k1_fe_sqr(&l, &p); /* l = (g+s)^2 */
|
||||
secp256k1_fe_negate(&l, &l, 1); /* l = -(g+s)^2 */
|
||||
secp256k1_fe_mul(&n, &d, &u1); /* n = 3*s*u^3 */
|
||||
secp256k1_fe_add(&n, &l); /* n = 3*s*u^3-(g+s)^2 */
|
||||
if (secp256k1_ge_x_frac_on_curve_var(&n, &d)) {
|
||||
/* Return x3 = n/d = (3*s*u^3-(g+s)^2)/(3*s*u^2) */
|
||||
*xn = n;
|
||||
*xd = d;
|
||||
return;
|
||||
}
|
||||
*xd = p;
|
||||
secp256k1_fe_mul(&l, &secp256k1_ellswift_c1, &s); /* l = c1*s */
|
||||
secp256k1_fe_mul(&n, &secp256k1_ellswift_c2, &g); /* n = c2*g */
|
||||
secp256k1_fe_add(&n, &l); /* n = c1*s+c2*g */
|
||||
secp256k1_fe_mul(&n, &n, &u1); /* n = u*(c1*s+c2*g) */
|
||||
/* Possible optimization: in the invocation below, p^2 = (g+s)^2 is computed,
|
||||
* which we already have computed above. This could be deduplicated. */
|
||||
if (secp256k1_ge_x_frac_on_curve_var(&n, &p)) {
|
||||
/* Return x2 = n/p = u*(c1*s+c2*g)/(g+s) */
|
||||
*xn = n;
|
||||
return;
|
||||
}
|
||||
secp256k1_fe_mul(&l, &p, &u1); /* l = u*(g+s) */
|
||||
secp256k1_fe_add(&n, &l); /* n = u*(c1*s+c2*g)+u*(g+s) */
|
||||
secp256k1_fe_negate(xn, &n, 2); /* n = -u*(c1*s+c2*g)-u*(g+s) */
|
||||
|
||||
VERIFY_CHECK(secp256k1_ge_x_frac_on_curve_var(xn, &p));
|
||||
/* Return x3 = n/p = -(u*(c1*s+c2*g)/(g+s)+u) */
|
||||
}
|
||||
|
||||
/** Decode ElligatorSwift encoding (u, t) to X coordinate. */
|
||||
static void secp256k1_ellswift_xswiftec_var(secp256k1_fe *x, const secp256k1_fe *u, const secp256k1_fe *t) {
|
||||
secp256k1_fe xn, xd;
|
||||
secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, u, t);
|
||||
secp256k1_fe_inv_var(&xd, &xd);
|
||||
secp256k1_fe_mul(x, &xn, &xd);
|
||||
}
|
||||
|
||||
/** Decode ElligatorSwift encoding (u, t) to point P. */
|
||||
static void secp256k1_ellswift_swiftec_var(secp256k1_ge *p, const secp256k1_fe *u, const secp256k1_fe *t) {
|
||||
secp256k1_fe x;
|
||||
secp256k1_ellswift_xswiftec_var(&x, u, t);
|
||||
secp256k1_ge_set_xo_var(p, &x, secp256k1_fe_is_odd(t));
|
||||
}
|
||||
|
||||
/* Try to complete an ElligatorSwift encoding (u, t) for X coordinate x, given u and x.
|
||||
*
|
||||
* There may be up to 8 distinct t values such that (u, t) decodes back to x, but also
|
||||
* fewer, or none at all. Each such partial inverse can be accessed individually using a
|
||||
* distinct input argument c (in range 0-7), and some or all of these may return failure.
|
||||
* The following guarantees exist:
|
||||
* - Given (x, u), no two distinct c values give the same successful result t.
|
||||
* - Every successful result maps back to x through secp256k1_ellswift_xswiftec_var.
|
||||
* - Given (x, u), all t values that map back to x can be reached by combining the
|
||||
* successful results from this function over all c values, with the exception of:
|
||||
* - this function cannot be called with u=0
|
||||
* - no result with t=0 will be returned
|
||||
* - no result for which u^3 + t^2 + 7 = 0 will be returned.
|
||||
*
|
||||
* The rather unusual encoding of bits in c (a large "if" based on the middle bit, and then
|
||||
* using the low and high bits to pick signs of square roots) is to match the paper's
|
||||
* encoding more closely: c=0 through c=3 match branches 1..4 in the paper, while c=4 through
|
||||
* c=7 are copies of those with an additional negation of sqrt(w).
|
||||
*/
|
||||
static int secp256k1_ellswift_xswiftec_inv_var(secp256k1_fe *t, const secp256k1_fe *x_in, const secp256k1_fe *u_in, int c) {
|
||||
/* The implemented algorithm is this (all arithmetic, except involving c, is mod p):
|
||||
*
|
||||
* - If (c & 2) = 0:
|
||||
* - If (-x-u) is a valid X coordinate, fail.
|
||||
* - Let s=-(u^3+7)/(u^2+u*x+x^2).
|
||||
* - If s is not square, fail.
|
||||
* - Let v=x.
|
||||
* - If (c & 2) = 2:
|
||||
* - Let s=x-u.
|
||||
* - If s is not square, fail.
|
||||
* - Let r=sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist.
|
||||
* - If (c & 1) = 1 and r = 0, fail.
|
||||
* - If s=0, fail.
|
||||
* - Let v=(r/s-u)/2.
|
||||
* - Let w=sqrt(s).
|
||||
* - If (c & 5) = 0: return -w*(c3*u + v).
|
||||
* - If (c & 5) = 1: return w*(c4*u + v).
|
||||
* - If (c & 5) = 4: return w*(c3*u + v).
|
||||
* - If (c & 5) = 5: return -w*(c4*u + v).
|
||||
*/
|
||||
secp256k1_fe x = *x_in, u = *u_in, g, v, s, m, r, q;
|
||||
int ret;
|
||||
|
||||
secp256k1_fe_normalize_weak(&x);
|
||||
secp256k1_fe_normalize_weak(&u);
|
||||
|
||||
VERIFY_CHECK(c >= 0 && c < 8);
|
||||
VERIFY_CHECK(secp256k1_ge_x_on_curve_var(&x));
|
||||
|
||||
if (!(c & 2)) {
|
||||
/* c is in {0, 1, 4, 5}. In this case we look for an inverse under the x1 (if c=0 or
|
||||
* c=4) formula, or x2 (if c=1 or c=5) formula. */
|
||||
|
||||
/* If -u-x is a valid X coordinate, fail. This would yield an encoding that roundtrips
|
||||
* back under the x3 formula instead (which has priority over x1 and x2, so the decoding
|
||||
* would not match x). */
|
||||
m = x; /* m = x */
|
||||
secp256k1_fe_add(&m, &u); /* m = u+x */
|
||||
secp256k1_fe_negate(&m, &m, 2); /* m = -u-x */
|
||||
/* Test if (-u-x) is a valid X coordinate. If so, fail. */
|
||||
if (secp256k1_ge_x_on_curve_var(&m)) return 0;
|
||||
|
||||
/* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [first part] */
|
||||
secp256k1_fe_sqr(&s, &m); /* s = (u+x)^2 */
|
||||
secp256k1_fe_negate(&s, &s, 1); /* s = -(u+x)^2 */
|
||||
secp256k1_fe_mul(&m, &u, &x); /* m = u*x */
|
||||
secp256k1_fe_add(&s, &m); /* s = -(u^2 + u*x + x^2) */
|
||||
|
||||
/* Note that at this point, s = 0 is impossible. If it were the case:
|
||||
* s = -(u^2 + u*x + x^2) = 0
|
||||
* => u^2 + u*x + x^2 = 0
|
||||
* => (u + 2*x) * (u^2 + u*x + x^2) = 0
|
||||
* => 2*x^3 + 3*x^2*u + 3*x*u^2 + u^3 = 0
|
||||
* => (x + u)^3 + x^3 = 0
|
||||
* => x^3 = -(x + u)^3
|
||||
* => x^3 + B = (-u - x)^3 + B
|
||||
*
|
||||
* However, we know x^3 + B is square (because x is on the curve) and
|
||||
* that (-u-x)^3 + B is not square (the secp256k1_ge_x_on_curve_var(&m)
|
||||
* test above would have failed). This is a contradiction, and thus the
|
||||
* assumption s=0 is false. */
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&s));
|
||||
|
||||
/* If s is not square, fail. We have not fully computed s yet, but s is square iff
|
||||
* -(u^3+7)*(u^2+u*x+x^2) is square (because a/b is square iff a*b is square and b is
|
||||
* nonzero). */
|
||||
secp256k1_fe_sqr(&g, &u); /* g = u^2 */
|
||||
secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */
|
||||
secp256k1_fe_add_int(&g, SECP256K1_B); /* g = u^3+7 */
|
||||
secp256k1_fe_mul(&m, &s, &g); /* m = -(u^3 + 7)*(u^2 + u*x + x^2) */
|
||||
if (!secp256k1_fe_is_square_var(&m)) return 0;
|
||||
|
||||
/* Let s = -(u^3 + 7)/(u^2 + u*x + x^2) [second part] */
|
||||
secp256k1_fe_inv_var(&s, &s); /* s = -1/(u^2 + u*x + x^2) [no div by 0] */
|
||||
secp256k1_fe_mul(&s, &s, &g); /* s = -(u^3 + 7)/(u^2 + u*x + x^2) */
|
||||
|
||||
/* Let v = x. */
|
||||
v = x;
|
||||
} else {
|
||||
/* c is in {2, 3, 6, 7}. In this case we look for an inverse under the x3 formula. */
|
||||
|
||||
/* Let s = x-u. */
|
||||
secp256k1_fe_negate(&m, &u, 1); /* m = -u */
|
||||
s = m; /* s = -u */
|
||||
secp256k1_fe_add(&s, &x); /* s = x-u */
|
||||
|
||||
/* If s is not square, fail. */
|
||||
if (!secp256k1_fe_is_square_var(&s)) return 0;
|
||||
|
||||
/* Let r = sqrt(-s*(4*(u^3+7)+3*u^2*s)); fail if it doesn't exist. */
|
||||
secp256k1_fe_sqr(&g, &u); /* g = u^2 */
|
||||
secp256k1_fe_mul(&q, &s, &g); /* q = s*u^2 */
|
||||
secp256k1_fe_mul_int(&q, 3); /* q = 3*s*u^2 */
|
||||
secp256k1_fe_mul(&g, &g, &u); /* g = u^3 */
|
||||
secp256k1_fe_mul_int(&g, 4); /* g = 4*u^3 */
|
||||
secp256k1_fe_add_int(&g, 4 * SECP256K1_B); /* g = 4*(u^3+7) */
|
||||
secp256k1_fe_add(&q, &g); /* q = 4*(u^3+7)+3*s*u^2 */
|
||||
secp256k1_fe_mul(&q, &q, &s); /* q = s*(4*(u^3+7)+3*u^2*s) */
|
||||
secp256k1_fe_negate(&q, &q, 1); /* q = -s*(4*(u^3+7)+3*u^2*s) */
|
||||
if (!secp256k1_fe_is_square_var(&q)) return 0;
|
||||
ret = secp256k1_fe_sqrt(&r, &q); /* r = sqrt(-s*(4*(u^3+7)+3*u^2*s)) */
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(ret);
|
||||
#else
|
||||
(void)ret;
|
||||
#endif
|
||||
|
||||
/* If (c & 1) = 1 and r = 0, fail. */
|
||||
if (EXPECT((c & 1) && secp256k1_fe_normalizes_to_zero_var(&r), 0)) return 0;
|
||||
|
||||
/* If s = 0, fail. */
|
||||
if (EXPECT(secp256k1_fe_normalizes_to_zero_var(&s), 0)) return 0;
|
||||
|
||||
/* Let v = (r/s-u)/2. */
|
||||
secp256k1_fe_inv_var(&v, &s); /* v = 1/s [no div by 0] */
|
||||
secp256k1_fe_mul(&v, &v, &r); /* v = r/s */
|
||||
secp256k1_fe_add(&v, &m); /* v = r/s-u */
|
||||
secp256k1_fe_half(&v); /* v = (r/s-u)/2 */
|
||||
}
|
||||
|
||||
/* Let w = sqrt(s). */
|
||||
ret = secp256k1_fe_sqrt(&m, &s); /* m = sqrt(s) = w */
|
||||
VERIFY_CHECK(ret);
|
||||
|
||||
/* Return logic. */
|
||||
if ((c & 5) == 0 || (c & 5) == 5) {
|
||||
secp256k1_fe_negate(&m, &m, 1); /* m = -w */
|
||||
}
|
||||
/* Now m = {-w if c&5=0 or c&5=5; w otherwise}. */
|
||||
secp256k1_fe_mul(&u, &u, c&1 ? &secp256k1_ellswift_c4 : &secp256k1_ellswift_c3);
|
||||
/* u = {c4 if c&1=1; c3 otherwise}*u */
|
||||
secp256k1_fe_add(&u, &v); /* u = {c4 if c&1=1; c3 otherwise}*u + v */
|
||||
secp256k1_fe_mul(t, &m, &u);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Use SHA256 as a PRNG, returning SHA256(hasher || cnt).
|
||||
*
|
||||
* hasher is a SHA256 object to which an incrementing 4-byte counter is written to generate randomness.
|
||||
* Writing 13 bytes (4 bytes for counter, plus 9 bytes for the SHA256 padding) cannot cross a
|
||||
* 64-byte block size boundary (to make sure it only triggers a single SHA256 compression). */
|
||||
static void secp256k1_ellswift_prng(unsigned char* out32, const secp256k1_sha256 *hasher, uint32_t cnt) {
|
||||
secp256k1_sha256 hash = *hasher;
|
||||
unsigned char buf4[4];
|
||||
#ifdef VERIFY
|
||||
size_t blocks = hash.bytes >> 6;
|
||||
#endif
|
||||
buf4[0] = cnt;
|
||||
buf4[1] = cnt >> 8;
|
||||
buf4[2] = cnt >> 16;
|
||||
buf4[3] = cnt >> 24;
|
||||
secp256k1_sha256_write(&hash, buf4, 4);
|
||||
secp256k1_sha256_finalize(&hash, out32);
|
||||
|
||||
/* Writing and finalizing together should trigger exactly one SHA256 compression. */
|
||||
VERIFY_CHECK(((hash.bytes) >> 6) == (blocks + 1));
|
||||
}
|
||||
|
||||
/** Find an ElligatorSwift encoding (u, t) for X coordinate x, and random Y coordinate.
|
||||
*
|
||||
* u32 is the 32-byte big endian encoding of u; t is the output field element t that still
|
||||
* needs encoding.
|
||||
*
|
||||
* hasher is a hasher in the secp256k1_ellswift_prng sense, with the same restrictions. */
|
||||
static void secp256k1_ellswift_xelligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_fe *x, const secp256k1_sha256 *hasher) {
|
||||
/* Pool of 3-bit branch values. */
|
||||
unsigned char branch_hash[32];
|
||||
/* Number of 3-bit values in branch_hash left. */
|
||||
int branches_left = 0;
|
||||
/* Field elements u and branch values are extracted from RNG based on hasher for consecutive
|
||||
* values of cnt. cnt==0 is first used to populate a pool of 64 4-bit branch values. The 64
|
||||
* cnt values that follow are used to generate field elements u. cnt==65 (and multiples
|
||||
* thereof) are used to repopulate the pool and start over, if that were ever necessary.
|
||||
* On average, 4 iterations are needed. */
|
||||
uint32_t cnt = 0;
|
||||
while (1) {
|
||||
int branch;
|
||||
secp256k1_fe u;
|
||||
/* If the pool of branch values is empty, populate it. */
|
||||
if (branches_left == 0) {
|
||||
secp256k1_ellswift_prng(branch_hash, hasher, cnt++);
|
||||
branches_left = 64;
|
||||
}
|
||||
/* Take a 3-bit branch value from the branch pool (top bit is discarded). */
|
||||
--branches_left;
|
||||
branch = (branch_hash[branches_left >> 1] >> ((branches_left & 1) << 2)) & 7;
|
||||
/* Compute a new u value by hashing. */
|
||||
secp256k1_ellswift_prng(u32, hasher, cnt++);
|
||||
/* overflow is not a problem (we prefer uniform u32 over uniform u). */
|
||||
secp256k1_fe_set_b32_mod(&u, u32);
|
||||
/* Since u is the output of a hash, it should practically never be 0. We could apply the
|
||||
* u=0 to u=1 correction here too to deal with that case still, but it's such a low
|
||||
* probability event that we do not bother. */
|
||||
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(&u));
|
||||
|
||||
/* Find a remainder t, and return it if found. */
|
||||
if (EXPECT(secp256k1_ellswift_xswiftec_inv_var(t, x, &u, branch), 0)) break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Find an ElligatorSwift encoding (u, t) for point P.
|
||||
*
|
||||
* This is similar secp256k1_ellswift_xelligatorswift_var, except it takes a full group element p
|
||||
* as input, and returns an encoding that matches the provided Y coordinate rather than a random
|
||||
* one.
|
||||
*/
|
||||
static void secp256k1_ellswift_elligatorswift_var(unsigned char *u32, secp256k1_fe *t, const secp256k1_ge *p, const secp256k1_sha256 *hasher) {
|
||||
secp256k1_ellswift_xelligatorswift_var(u32, t, &p->x, hasher);
|
||||
secp256k1_fe_normalize_var(t);
|
||||
if (secp256k1_fe_is_odd(t) != secp256k1_fe_is_odd(&p->y)) {
|
||||
secp256k1_fe_negate(t, t, 1);
|
||||
secp256k1_fe_normalize_var(t);
|
||||
}
|
||||
}
|
||||
|
||||
/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_encode". */
|
||||
static void secp256k1_ellswift_sha256_init_encode(secp256k1_sha256* hash) {
|
||||
secp256k1_sha256_initialize(hash);
|
||||
hash->s[0] = 0xd1a6524bul;
|
||||
hash->s[1] = 0x028594b3ul;
|
||||
hash->s[2] = 0x96e42f4eul;
|
||||
hash->s[3] = 0x1037a177ul;
|
||||
hash->s[4] = 0x1b8fcb8bul;
|
||||
hash->s[5] = 0x56023885ul;
|
||||
hash->s[6] = 0x2560ede1ul;
|
||||
hash->s[7] = 0xd626b715ul;
|
||||
|
||||
hash->bytes = 64;
|
||||
}
|
||||
|
||||
int secp256k1_ellswift_encode(const secp256k1_context *ctx, unsigned char *ell64, const secp256k1_pubkey *pubkey, const unsigned char *rnd32) {
|
||||
secp256k1_ge p;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(ell64 != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(rnd32 != NULL);
|
||||
|
||||
if (secp256k1_pubkey_load(ctx, &p, pubkey)) {
|
||||
secp256k1_fe t;
|
||||
unsigned char p64[64] = {0};
|
||||
size_t ser_size;
|
||||
int ser_ret;
|
||||
secp256k1_sha256 hash;
|
||||
|
||||
/* Set up hasher state; the used RNG is H(pubkey || "\x00"*31 || rnd32 || cnt++), using
|
||||
* BIP340 tagged hash with tag "secp256k1_ellswift_encode". */
|
||||
secp256k1_ellswift_sha256_init_encode(&hash);
|
||||
ser_ret = secp256k1_eckey_pubkey_serialize(&p, p64, &ser_size, 1);
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(ser_ret && ser_size == 33);
|
||||
#else
|
||||
(void)ser_ret;
|
||||
#endif
|
||||
secp256k1_sha256_write(&hash, p64, sizeof(p64));
|
||||
secp256k1_sha256_write(&hash, rnd32, 32);
|
||||
|
||||
/* Compute ElligatorSwift encoding and construct output. */
|
||||
secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
|
||||
secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
|
||||
return 1;
|
||||
}
|
||||
/* Only reached in case the provided pubkey is invalid. */
|
||||
memset(ell64, 0, 64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Set hash state to the BIP340 tagged hash midstate for "secp256k1_ellswift_create". */
|
||||
static void secp256k1_ellswift_sha256_init_create(secp256k1_sha256* hash) {
|
||||
secp256k1_sha256_initialize(hash);
|
||||
hash->s[0] = 0xd29e1bf5ul;
|
||||
hash->s[1] = 0xf7025f42ul;
|
||||
hash->s[2] = 0x9b024773ul;
|
||||
hash->s[3] = 0x094cb7d5ul;
|
||||
hash->s[4] = 0xe59ed789ul;
|
||||
hash->s[5] = 0x03bc9786ul;
|
||||
hash->s[6] = 0x68335b35ul;
|
||||
hash->s[7] = 0x4e363b53ul;
|
||||
|
||||
hash->bytes = 64;
|
||||
}
|
||||
|
||||
int secp256k1_ellswift_create(const secp256k1_context *ctx, unsigned char *ell64, const unsigned char *seckey32, const unsigned char *auxrnd32) {
|
||||
secp256k1_ge p;
|
||||
secp256k1_fe t;
|
||||
secp256k1_sha256 hash;
|
||||
secp256k1_scalar seckey_scalar;
|
||||
int ret;
|
||||
static const unsigned char zero32[32] = {0};
|
||||
|
||||
/* Sanity check inputs. */
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(ell64 != NULL);
|
||||
memset(ell64, 0, 64);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(seckey32 != NULL);
|
||||
|
||||
/* Compute (affine) public key */
|
||||
ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &seckey_scalar, &p, seckey32);
|
||||
secp256k1_declassify(ctx, &p, sizeof(p)); /* not constant time in produced pubkey */
|
||||
secp256k1_fe_normalize_var(&p.x);
|
||||
secp256k1_fe_normalize_var(&p.y);
|
||||
|
||||
/* Set up hasher state. The used RNG is H(privkey || "\x00"*32 [|| auxrnd32] || cnt++),
|
||||
* using BIP340 tagged hash with tag "secp256k1_ellswift_create". */
|
||||
secp256k1_ellswift_sha256_init_create(&hash);
|
||||
secp256k1_sha256_write(&hash, seckey32, 32);
|
||||
secp256k1_sha256_write(&hash, zero32, sizeof(zero32));
|
||||
secp256k1_declassify(ctx, &hash, sizeof(hash)); /* private key is hashed now */
|
||||
if (auxrnd32) secp256k1_sha256_write(&hash, auxrnd32, 32);
|
||||
|
||||
/* Compute ElligatorSwift encoding and construct output. */
|
||||
secp256k1_ellswift_elligatorswift_var(ell64, &t, &p, &hash); /* puts u in ell64[0..32] */
|
||||
secp256k1_fe_get_b32(ell64 + 32, &t); /* puts t in ell64[32..64] */
|
||||
|
||||
secp256k1_memczero(ell64, 64, !ret);
|
||||
secp256k1_scalar_clear(&seckey_scalar);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_ellswift_decode(const secp256k1_context *ctx, secp256k1_pubkey *pubkey, const unsigned char *ell64) {
|
||||
secp256k1_fe u, t;
|
||||
secp256k1_ge p;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(ell64 != NULL);
|
||||
|
||||
secp256k1_fe_set_b32_mod(&u, ell64);
|
||||
secp256k1_fe_set_b32_mod(&t, ell64 + 32);
|
||||
secp256k1_fe_normalize_var(&t);
|
||||
secp256k1_ellswift_swiftec_var(&p, &u, &t);
|
||||
secp256k1_pubkey_save(pubkey, &p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ellswift_xdh_hash_function_prefix(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, data, 64);
|
||||
secp256k1_sha256_write(&sha, ell_a64, 64);
|
||||
secp256k1_sha256_write(&sha, ell_b64, 64);
|
||||
secp256k1_sha256_write(&sha, x32, 32);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Set hash state to the BIP340 tagged hash midstate for "bip324_ellswift_xonly_ecdh". */
|
||||
static void secp256k1_ellswift_sha256_init_bip324(secp256k1_sha256* hash) {
|
||||
secp256k1_sha256_initialize(hash);
|
||||
hash->s[0] = 0x8c12d730ul;
|
||||
hash->s[1] = 0x827bd392ul;
|
||||
hash->s[2] = 0x9e4fb2eeul;
|
||||
hash->s[3] = 0x207b373eul;
|
||||
hash->s[4] = 0x2292bd7aul;
|
||||
hash->s[5] = 0xaa5441bcul;
|
||||
hash->s[6] = 0x15c3779ful;
|
||||
hash->s[7] = 0xcfb52549ul;
|
||||
|
||||
hash->bytes = 64;
|
||||
}
|
||||
|
||||
static int ellswift_xdh_hash_function_bip324(unsigned char* output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
(void)data;
|
||||
|
||||
secp256k1_ellswift_sha256_init_bip324(&sha);
|
||||
secp256k1_sha256_write(&sha, ell_a64, 64);
|
||||
secp256k1_sha256_write(&sha, ell_b64, 64);
|
||||
secp256k1_sha256_write(&sha, x32, 32);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix = ellswift_xdh_hash_function_prefix;
|
||||
const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324 = ellswift_xdh_hash_function_bip324;
|
||||
|
||||
int secp256k1_ellswift_xdh(const secp256k1_context *ctx, unsigned char *output, const unsigned char *ell_a64, const unsigned char *ell_b64, const unsigned char *seckey32, int party, secp256k1_ellswift_xdh_hash_function hashfp, void *data) {
|
||||
int ret = 0;
|
||||
int overflow;
|
||||
secp256k1_scalar s;
|
||||
secp256k1_fe xn, xd, px, u, t;
|
||||
unsigned char sx[32];
|
||||
const unsigned char* theirs64;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(ell_a64 != NULL);
|
||||
ARG_CHECK(ell_b64 != NULL);
|
||||
ARG_CHECK(seckey32 != NULL);
|
||||
ARG_CHECK(hashfp != NULL);
|
||||
|
||||
/* Load remote public key (as fraction). */
|
||||
theirs64 = party ? ell_a64 : ell_b64;
|
||||
secp256k1_fe_set_b32_mod(&u, theirs64);
|
||||
secp256k1_fe_set_b32_mod(&t, theirs64 + 32);
|
||||
secp256k1_ellswift_xswiftec_frac_var(&xn, &xd, &u, &t);
|
||||
|
||||
/* Load private key (using one if invalid). */
|
||||
secp256k1_scalar_set_b32(&s, seckey32, &overflow);
|
||||
overflow = secp256k1_scalar_is_zero(&s);
|
||||
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
|
||||
|
||||
/* Compute shared X coordinate. */
|
||||
secp256k1_ecmult_const_xonly(&px, &xn, &xd, &s, 1);
|
||||
secp256k1_fe_normalize(&px);
|
||||
secp256k1_fe_get_b32(sx, &px);
|
||||
|
||||
/* Invoke hasher */
|
||||
ret = hashfp(output, sx, ell_a64, ell_b64, data);
|
||||
|
||||
memset(sx, 0, 32);
|
||||
secp256k1_fe_clear(&px);
|
||||
secp256k1_scalar_clear(&s);
|
||||
|
||||
return !!ret & !overflow;
|
||||
}
|
||||
|
||||
#endif
|
||||
39
src/modules/ellswift/tests_exhaustive_impl.h
Normal file
39
src/modules/ellswift/tests_exhaustive_impl.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H
|
||||
#define SECP256K1_MODULE_ELLSWIFT_TESTS_EXHAUSTIVE_H
|
||||
|
||||
#include "../../../include/secp256k1_ellswift.h"
|
||||
#include "main_impl.h"
|
||||
|
||||
static void test_exhaustive_ellswift(const secp256k1_context *ctx, const secp256k1_ge *group) {
|
||||
int i;
|
||||
|
||||
/* Note that SwiftEC/ElligatorSwift are inherently curve operations, not
|
||||
* group operations, and this test only checks the curve points which are in
|
||||
* a tiny subgroup. In that sense it can't be really seen as exhaustive as
|
||||
* it doesn't (and for computational reasons obviously cannot) test the
|
||||
* entire domain ellswift operates under. */
|
||||
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) {
|
||||
secp256k1_scalar scalar_i;
|
||||
unsigned char sec32[32];
|
||||
unsigned char ell64[64];
|
||||
secp256k1_pubkey pub_decoded;
|
||||
secp256k1_ge ge_decoded;
|
||||
|
||||
/* Construct ellswift pubkey from exhaustive loop scalar i. */
|
||||
secp256k1_scalar_set_int(&scalar_i, i);
|
||||
secp256k1_scalar_get_b32(sec32, &scalar_i);
|
||||
CHECK(secp256k1_ellswift_create(ctx, ell64, sec32, NULL));
|
||||
|
||||
/* Decode ellswift pubkey and check that it matches the precomputed group element. */
|
||||
secp256k1_ellswift_decode(ctx, &pub_decoded, ell64);
|
||||
secp256k1_pubkey_load(ctx, &ge_decoded, &pub_decoded);
|
||||
CHECK(secp256k1_ge_eq_var(&ge_decoded, &group[i]));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
436
src/modules/ellswift/tests_impl.h
Normal file
436
src/modules/ellswift/tests_impl.h
Normal file
@@ -0,0 +1,436 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_ELLSWIFT_TESTS_H
|
||||
#define SECP256K1_MODULE_ELLSWIFT_TESTS_H
|
||||
|
||||
#include "../../../include/secp256k1_ellswift.h"
|
||||
|
||||
struct ellswift_xswiftec_inv_test {
|
||||
int enc_bitmap;
|
||||
secp256k1_fe u;
|
||||
secp256k1_fe x;
|
||||
secp256k1_fe encs[8];
|
||||
};
|
||||
|
||||
struct ellswift_decode_test {
|
||||
unsigned char enc[64];
|
||||
secp256k1_fe x;
|
||||
int odd_y;
|
||||
};
|
||||
|
||||
struct ellswift_xdh_test {
|
||||
unsigned char priv_ours[32];
|
||||
unsigned char ellswift_ours[64];
|
||||
unsigned char ellswift_theirs[64];
|
||||
int initiating;
|
||||
unsigned char shared_secret[32];
|
||||
};
|
||||
|
||||
/* Set of (point, encodings) test vectors, selected to maximize branch coverage, part of the BIP324
|
||||
* test vectors. Created using an independent implementation, and tested decoding against paper
|
||||
* authors' code. */
|
||||
static const struct ellswift_xswiftec_inv_test ellswift_xswiftec_inv_tests[] = {
|
||||
{0xcc, SECP256K1_FE_CONST(0x05ff6bda, 0xd900fc32, 0x61bc7fe3, 0x4e2fb0f5, 0x69f06e09, 0x1ae437d3, 0xa52e9da0, 0xcbfb9590), SECP256K1_FE_CONST(0x80cdf637, 0x74ec7022, 0xc89a5a85, 0x58e373a2, 0x79170285, 0xe0ab2741, 0x2dbce510, 0xbdfe23fc), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x45654798, 0xece071ba, 0x79286d04, 0xf7f3eb1c, 0x3f1d17dd, 0x883610f2, 0xad2efd82, 0xa287466b), SECP256K1_FE_CONST(0x0aeaa886, 0xf6b76c71, 0x58452418, 0xcbf5033a, 0xdc5747e9, 0xe9b5d3b2, 0x303db969, 0x36528557), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xba9ab867, 0x131f8e45, 0x86d792fb, 0x080c14e3, 0xc0e2e822, 0x77c9ef0d, 0x52d1027c, 0x5d78b5c4), SECP256K1_FE_CONST(0xf5155779, 0x0948938e, 0xa7badbe7, 0x340afcc5, 0x23a8b816, 0x164a2c4d, 0xcfc24695, 0xc9ad76d8)}},
|
||||
{0x33, SECP256K1_FE_CONST(0x1737a85f, 0x4c8d146c, 0xec96e3ff, 0xdca76d99, 0x03dcf3bd, 0x53061868, 0xd478c78c, 0x63c2aa9e), SECP256K1_FE_CONST(0x39e48dd1, 0x50d2f429, 0xbe088dfd, 0x5b61882e, 0x7e840748, 0x3702ae9a, 0x5ab35927, 0xb15f85ea), {SECP256K1_FE_CONST(0x1be8cc0b, 0x04be0c68, 0x1d0c6a68, 0xf733f82c, 0x6c896e0c, 0x8a262fcd, 0x392918e3, 0x03a7abf4), SECP256K1_FE_CONST(0x605b5814, 0xbf9b8cb0, 0x66667c9e, 0x5480d22d, 0xc5b6c92f, 0x14b4af3e, 0xe0a9eb83, 0xb03685e3), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xe41733f4, 0xfb41f397, 0xe2f39597, 0x08cc07d3, 0x937691f3, 0x75d9d032, 0xc6d6e71b, 0xfc58503b), SECP256K1_FE_CONST(0x9fa4a7eb, 0x4064734f, 0x99998361, 0xab7f2dd2, 0x3a4936d0, 0xeb4b50c1, 0x1f56147b, 0x4fc9764c), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0x1aaa1cce, 0xbf9c7241, 0x91033df3, 0x66b36f69, 0x1c4d902c, 0x228033ff, 0x4516d122, 0xb2564f68), SECP256K1_FE_CONST(0xc7554125, 0x9d3ba98f, 0x207eaa30, 0xc69634d1, 0x87d0b6da, 0x594e719e, 0x420f4898, 0x638fc5b0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x33, SECP256K1_FE_CONST(0x2323a1d0, 0x79b0fd72, 0xfc8bb62e, 0xc34230a8, 0x15cb0596, 0xc2bfac99, 0x8bd6b842, 0x60f5dc26), SECP256K1_FE_CONST(0x239342df, 0xb675500a, 0x34a19631, 0x0b8d87d5, 0x4f49dcac, 0x9da50c17, 0x43ceab41, 0xa7b249ff), {SECP256K1_FE_CONST(0xf63580b8, 0xaa49c484, 0x6de56e39, 0xe1b3e73f, 0x171e881e, 0xba8c66f6, 0x14e67e5c, 0x975dfc07), SECP256K1_FE_CONST(0xb6307b33, 0x2e699f1c, 0xf77841d9, 0x0af25365, 0x404deb7f, 0xed5edb30, 0x90db49e6, 0x42a156b6), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x09ca7f47, 0x55b63b7b, 0x921a91c6, 0x1e4c18c0, 0xe8e177e1, 0x45739909, 0xeb1981a2, 0x68a20028), SECP256K1_FE_CONST(0x49cf84cc, 0xd19660e3, 0x0887be26, 0xf50dac9a, 0xbfb21480, 0x12a124cf, 0x6f24b618, 0xbd5ea579), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x33, SECP256K1_FE_CONST(0x2dc90e64, 0x0cb646ae, 0x9164c0b5, 0xa9ef0169, 0xfebe34dc, 0x4437d6e4, 0x6acb0e27, 0xe219d1e8), SECP256K1_FE_CONST(0xd236f19b, 0xf349b951, 0x6e9b3f4a, 0x5610fe96, 0x0141cb23, 0xbbc8291b, 0x9534f1d7, 0x1de62a47), {SECP256K1_FE_CONST(0xe69df7d9, 0xc026c366, 0x00ebdf58, 0x80726758, 0x47c0c431, 0xc8eb7306, 0x82533e96, 0x4b6252c9), SECP256K1_FE_CONST(0x4f18bbdf, 0x7c2d6c5f, 0x818c1880, 0x2fa35cd0, 0x69eaa79f, 0xff74e4fc, 0x837c80d9, 0x3fece2f8), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x19620826, 0x3fd93c99, 0xff1420a7, 0x7f8d98a7, 0xb83f3bce, 0x37148cf9, 0x7dacc168, 0xb49da966), SECP256K1_FE_CONST(0xb0e74420, 0x83d293a0, 0x7e73e77f, 0xd05ca32f, 0x96155860, 0x008b1b03, 0x7c837f25, 0xc0131937), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0x3edd7b39, 0x80e2f2f3, 0x4d1409a2, 0x07069f88, 0x1fda5f96, 0xf08027ac, 0x4465b63d, 0xc278d672), SECP256K1_FE_CONST(0x053a98de, 0x4a27b196, 0x1155822b, 0x3a3121f0, 0x3b2a1445, 0x8bd80eb4, 0xa560c4c7, 0xa85c149c), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb3dae4b7, 0xdcf858e4, 0xc6968057, 0xcef2b156, 0x46543152, 0x6538199c, 0xf52dc1b2, 0xd62fda30), SECP256K1_FE_CONST(0x4aa77dd5, 0x5d6b6d3c, 0xfa10cc9d, 0x0fe42f79, 0x232e4575, 0x661049ae, 0x36779c1d, 0x0c666d88), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x4c251b48, 0x2307a71b, 0x39697fa8, 0x310d4ea9, 0xb9abcead, 0x9ac7e663, 0x0ad23e4c, 0x29d021ff), SECP256K1_FE_CONST(0xb558822a, 0xa29492c3, 0x05ef3362, 0xf01bd086, 0xdcd1ba8a, 0x99efb651, 0xc98863e1, 0xf3998ea7)}},
|
||||
{0x00, SECP256K1_FE_CONST(0x4295737e, 0xfcb1da6f, 0xb1d96b9c, 0xa7dcd1e3, 0x20024b37, 0xa736c494, 0x8b625981, 0x73069f70), SECP256K1_FE_CONST(0xfa7ffe4f, 0x25f88362, 0x831c087a, 0xfe2e8a9b, 0x0713e2ca, 0xc1ddca6a, 0x383205a2, 0x66f14307), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xff, SECP256K1_FE_CONST(0x587c1a0c, 0xee91939e, 0x7f784d23, 0xb963004a, 0x3bf44f5d, 0x4e32a008, 0x1995ba20, 0xb0fca59e), SECP256K1_FE_CONST(0x2ea98853, 0x0715e8d1, 0x0363907f, 0xf2512452, 0x4d471ba2, 0x454d5ce3, 0xbe3f0419, 0x4dfd3a3c), {SECP256K1_FE_CONST(0xcfd5a094, 0xaa0b9b88, 0x91b76c6a, 0xb9438f66, 0xaa1c095a, 0x65f9f701, 0x35e81712, 0x92245e74), SECP256K1_FE_CONST(0xa89057d7, 0xc6563f0d, 0x6efa19ae, 0x84412b8a, 0x7b47e791, 0xa191ecdf, 0xdf2af84f, 0xd97bc339), SECP256K1_FE_CONST(0x475d0ae9, 0xef46920d, 0xf07b3411, 0x7be5a081, 0x7de1023e, 0x3cc32689, 0xe9be145b, 0x406b0aef), SECP256K1_FE_CONST(0xa0759178, 0xad802324, 0x54f827ef, 0x05ea3e72, 0xad8d7541, 0x8e6d4cc1, 0xcd4f5306, 0xc5e7c453), SECP256K1_FE_CONST(0x302a5f6b, 0x55f46477, 0x6e489395, 0x46bc7099, 0x55e3f6a5, 0x9a0608fe, 0xca17e8ec, 0x6ddb9dbb), SECP256K1_FE_CONST(0x576fa828, 0x39a9c0f2, 0x9105e651, 0x7bbed475, 0x84b8186e, 0x5e6e1320, 0x20d507af, 0x268438f6), SECP256K1_FE_CONST(0xb8a2f516, 0x10b96df2, 0x0f84cbee, 0x841a5f7e, 0x821efdc1, 0xc33cd976, 0x1641eba3, 0xbf94f140), SECP256K1_FE_CONST(0x5f8a6e87, 0x527fdcdb, 0xab07d810, 0xfa15c18d, 0x52728abe, 0x7192b33e, 0x32b0acf8, 0x3a1837dc)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0x5fa88b33, 0x65a635cb, 0xbcee003c, 0xce9ef51d, 0xd1a310de, 0x277e441a, 0xbccdb7be, 0x1e4ba249), SECP256K1_FE_CONST(0x79461ff6, 0x2bfcbcac, 0x4249ba84, 0xdd040f2c, 0xec3c63f7, 0x25204dc7, 0xf464c16b, 0xf0ff3170), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x6bb700e1, 0xf4d7e236, 0xe8d193ff, 0x4a76c1b3, 0xbcd4e2b2, 0x5acac3d5, 0x1c8dac65, 0x3fe909a0), SECP256K1_FE_CONST(0xf4c73410, 0x633da7f6, 0x3a4f1d55, 0xaec6dd32, 0xc4c6d89e, 0xe74075ed, 0xb5515ed9, 0x0da9e683), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x9448ff1e, 0x0b281dc9, 0x172e6c00, 0xb5893e4c, 0x432b1d4d, 0xa5353c2a, 0xe3725399, 0xc016f28f), SECP256K1_FE_CONST(0x0b38cbef, 0x9cc25809, 0xc5b0e2aa, 0x513922cd, 0x3b392761, 0x18bf8a12, 0x4aaea125, 0xf25615ac)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0x6fb31c75, 0x31f03130, 0xb42b155b, 0x952779ef, 0xbb46087d, 0xd9807d24, 0x1a48eac6, 0x3c3d96d6), SECP256K1_FE_CONST(0x56f81be7, 0x53e8d4ae, 0x4940ea6f, 0x46f6ec9f, 0xda66a6f9, 0x6cc95f50, 0x6cb2b574, 0x90e94260), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x59059774, 0x795bdb7a, 0x837fbe11, 0x40a5fa59, 0x984f48af, 0x8df95d57, 0xdd6d1c05, 0x437dcec1), SECP256K1_FE_CONST(0x22a644db, 0x79376ad4, 0xe7b3a009, 0xe58b3f13, 0x137c54fd, 0xf911122c, 0xc93667c4, 0x7077d784), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xa6fa688b, 0x86a42485, 0x7c8041ee, 0xbf5a05a6, 0x67b0b750, 0x7206a2a8, 0x2292e3f9, 0xbc822d6e), SECP256K1_FE_CONST(0xdd59bb24, 0x86c8952b, 0x184c5ff6, 0x1a74c0ec, 0xec83ab02, 0x06eeedd3, 0x36c9983a, 0x8f8824ab)}},
|
||||
{0x00, SECP256K1_FE_CONST(0x704cd226, 0xe71cb682, 0x6a590e80, 0xdac90f2d, 0x2f5830f0, 0xfdf135a3, 0xeae3965b, 0xff25ff12), SECP256K1_FE_CONST(0x138e0afa, 0x68936ee6, 0x70bd2b8d, 0xb53aedbb, 0x7bea2a85, 0x97388b24, 0xd0518edd, 0x22ad66ec), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x33, SECP256K1_FE_CONST(0x725e9147, 0x92cb8c89, 0x49e7e116, 0x8b7cdd8a, 0x8094c91c, 0x6ec2202c, 0xcd53a6a1, 0x8771edeb), SECP256K1_FE_CONST(0x8da16eb8, 0x6d347376, 0xb6181ee9, 0x74832275, 0x7f6b36e3, 0x913ddfd3, 0x32ac595d, 0x788e0e44), {SECP256K1_FE_CONST(0xdd357786, 0xb9f68733, 0x30391aa5, 0x62580965, 0x4e43116e, 0x82a5a5d8, 0x2ffd1d66, 0x24101fc4), SECP256K1_FE_CONST(0xa0b7efca, 0x01814594, 0xc59c9aae, 0x8e497001, 0x86ca5d95, 0xe88bcc80, 0x399044d9, 0xc2d8613d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x22ca8879, 0x460978cc, 0xcfc6e55a, 0x9da7f69a, 0xb1bcee91, 0x7d5a5a27, 0xd002e298, 0xdbefdc6b), SECP256K1_FE_CONST(0x5f481035, 0xfe7eba6b, 0x3a636551, 0x71b68ffe, 0x7935a26a, 0x1774337f, 0xc66fbb25, 0x3d279af2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0x78fe6b71, 0x7f2ea4a3, 0x2708d79c, 0x151bf503, 0xa5312a18, 0xc0963437, 0xe865cc6e, 0xd3f6ae97), SECP256K1_FE_CONST(0x8701948e, 0x80d15b5c, 0xd8f72863, 0xeae40afc, 0x5aced5e7, 0x3f69cbc8, 0x179a3390, 0x2c094d98), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x44, SECP256K1_FE_CONST(0x7c37bb9c, 0x5061dc07, 0x413f11ac, 0xd5a34006, 0xe64c5c45, 0x7fdb9a43, 0x8f217255, 0xa961f50d), SECP256K1_FE_CONST(0x5c1a76b4, 0x4568eb59, 0xd6789a74, 0x42d9ed7c, 0xdc6226b7, 0x752b4ff8, 0xeaf8e1a9, 0x5736e507), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb94d30cd, 0x7dbff60b, 0x64620c17, 0xca0fafaa, 0x40b3d1f5, 0x2d077a60, 0xa2e0cafd, 0x145086c2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x46b2cf32, 0x824009f4, 0x9b9df3e8, 0x35f05055, 0xbf4c2e0a, 0xd2f8859f, 0x5d1f3501, 0xebaf756d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0x82388888, 0x967f82a6, 0xb444438a, 0x7d44838e, 0x13c0d478, 0xb9ca060d, 0xa95a41fb, 0x94303de6), SECP256K1_FE_CONST(0x29e96541, 0x70628fec, 0x8b497289, 0x8b113cf9, 0x8807f460, 0x9274f4f3, 0x140d0674, 0x157c90a0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x33, SECP256K1_FE_CONST(0x91298f57, 0x70af7a27, 0xf0a47188, 0xd24c3b7b, 0xf98ab299, 0x0d84b0b8, 0x98507e3c, 0x561d6472), SECP256K1_FE_CONST(0x144f4ccb, 0xd9a74698, 0xa88cbf6f, 0xd00ad886, 0xd339d29e, 0xa19448f2, 0xc572cac0, 0xa07d5562), {SECP256K1_FE_CONST(0xe6a0ffa3, 0x807f09da, 0xdbe71e0f, 0x4be4725f, 0x2832e76c, 0xad8dc1d9, 0x43ce8393, 0x75eff248), SECP256K1_FE_CONST(0x837b8e68, 0xd4917544, 0x764ad090, 0x3cb11f86, 0x15d2823c, 0xefbb06d8, 0x9049dbab, 0xc69befda), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x195f005c, 0x7f80f625, 0x2418e1f0, 0xb41b8da0, 0xd7cd1893, 0x52723e26, 0xbc317c6b, 0x8a1009e7), SECP256K1_FE_CONST(0x7c847197, 0x2b6e8abb, 0x89b52f6f, 0xc34ee079, 0xea2d7dc3, 0x1044f927, 0x6fb62453, 0x39640c55), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xb682f3d0, 0x3bbb5dee, 0x4f54b5eb, 0xfba931b4, 0xf52f6a19, 0x1e5c2f48, 0x3c73c66e, 0x9ace97e1), SECP256K1_FE_CONST(0x904717bf, 0x0bc0cb78, 0x73fcdc38, 0xaa97f19e, 0x3a626309, 0x72acff92, 0xb24cc6dd, 0xa197cb96), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x77, SECP256K1_FE_CONST(0xc17ec69e, 0x665f0fb0, 0xdbab48d9, 0xc2f94d12, 0xec8a9d7e, 0xacb58084, 0x83309180, 0x1eb0b80b), SECP256K1_FE_CONST(0x147756e6, 0x6d96e31c, 0x426d3cc8, 0x5ed0c4cf, 0xbef6341d, 0xd8b28558, 0x5aa574ea, 0x0204b55e), {SECP256K1_FE_CONST(0x6f4aea43, 0x1a0043bd, 0xd03134d6, 0xd9159119, 0xce034b88, 0xc32e50e8, 0xe36c4ee4, 0x5eac7ae9), SECP256K1_FE_CONST(0xfd5be16d, 0x4ffa2690, 0x126c67c3, 0xef7cb9d2, 0x9b74d397, 0xc78b06b3, 0x605fda34, 0xdc9696a6), SECP256K1_FE_CONST(0x5e9c6079, 0x2a2f000e, 0x45c6250f, 0x296f875e, 0x174efc0e, 0x9703e628, 0x706103a9, 0xdd2d82c7), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x90b515bc, 0xe5ffbc42, 0x2fcecb29, 0x26ea6ee6, 0x31fcb477, 0x3cd1af17, 0x1c93b11a, 0xa1538146), SECP256K1_FE_CONST(0x02a41e92, 0xb005d96f, 0xed93983c, 0x1083462d, 0x648b2c68, 0x3874f94c, 0x9fa025ca, 0x23696589), SECP256K1_FE_CONST(0xa1639f86, 0xd5d0fff1, 0xba39daf0, 0xd69078a1, 0xe8b103f1, 0x68fc19d7, 0x8f9efc55, 0x22d27968), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0xc25172fc, 0x3f29b6fc, 0x4a1155b8, 0x57523315, 0x5486b274, 0x64b74b8b, 0x260b499a, 0x3f53cb14), SECP256K1_FE_CONST(0x1ea9cbdb, 0x35cf6e03, 0x29aa31b0, 0xbb0a702a, 0x65123ed0, 0x08655a93, 0xb7dcd528, 0x0e52e1ab), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x7422edc7, 0x843136af, 0x0053bb88, 0x54448a82, 0x99994f9d, 0xdcefd3a9, 0xa92d4546, 0x2c59298a), SECP256K1_FE_CONST(0x78c7774a, 0x266f8b97, 0xea23d05d, 0x064f033c, 0x77319f92, 0x3f6b78bc, 0xe4e20bf0, 0x5fa5398d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x8bdd1238, 0x7bcec950, 0xffac4477, 0xabbb757d, 0x6666b062, 0x23102c56, 0x56d2bab8, 0xd3a6d2a5), SECP256K1_FE_CONST(0x873888b5, 0xd9907468, 0x15dc2fa2, 0xf9b0fcc3, 0x88ce606d, 0xc0948743, 0x1b1df40e, 0xa05ac2a2)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xcab6626f, 0x832a4b12, 0x80ba7add, 0x2fc5322f, 0xf011caed, 0xedf7ff4d, 0xb6735d50, 0x26dc0367), SECP256K1_FE_CONST(0x2b2bef08, 0x52c6f7c9, 0x5d72ac99, 0xa23802b8, 0x75029cd5, 0x73b248d1, 0xf1b3fc80, 0x33788eb6), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x33, SECP256K1_FE_CONST(0xd8621b4f, 0xfc85b9ed, 0x56e99d8d, 0xd1dd24ae, 0xdcecb147, 0x63b861a1, 0x7112dc77, 0x1a104fd2), SECP256K1_FE_CONST(0x812cabe9, 0x72a22aa6, 0x7c7da0c9, 0x4d8a9362, 0x96eb9949, 0xd70c37cb, 0x2b248757, 0x4cb3ce58), {SECP256K1_FE_CONST(0xfbc5febc, 0x6fdbc9ae, 0x3eb88a93, 0xb982196e, 0x8b6275a6, 0xd5a73c17, 0x387e000c, 0x711bd0e3), SECP256K1_FE_CONST(0x8724c96b, 0xd4e5527f, 0x2dd195a5, 0x1c468d2d, 0x211ba2fa, 0xc7cbe0b4, 0xb3434253, 0x409fb42d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x043a0143, 0x90243651, 0xc147756c, 0x467de691, 0x749d8a59, 0x2a58c3e8, 0xc781fff2, 0x8ee42b4c), SECP256K1_FE_CONST(0x78db3694, 0x2b1aad80, 0xd22e6a5a, 0xe3b972d2, 0xdee45d05, 0x38341f4b, 0x4cbcbdab, 0xbf604802), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xda463164, 0xc6f4bf71, 0x29ee5f0e, 0xc00f65a6, 0x75a8adf1, 0xbd931b39, 0xb64806af, 0xdcda9a22), SECP256K1_FE_CONST(0x25b9ce9b, 0x390b408e, 0xd611a0f1, 0x3ff09a59, 0x8a57520e, 0x426ce4c6, 0x49b7f94f, 0x2325620d), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0xdafc971e, 0x4a3a7b6d, 0xcfb42a08, 0xd9692d82, 0xad9e7838, 0x523fcbda, 0x1d4827e1, 0x4481ae2d), SECP256K1_FE_CONST(0x250368e1, 0xb5c58492, 0x304bd5f7, 0x2696d27d, 0x526187c7, 0xadc03425, 0xe2b7d81d, 0xbb7e4e02), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x370c28f1, 0xbe665efa, 0xcde6aa43, 0x6bf86fe2, 0x1e6e314c, 0x1e53dd04, 0x0e6c73a4, 0x6b4c8c49), SECP256K1_FE_CONST(0xcd8acee9, 0x8ffe5653, 0x1a84d7eb, 0x3e48fa40, 0x34206ce8, 0x25ace907, 0xd0edf0ea, 0xeb5e9ca2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xc8f3d70e, 0x4199a105, 0x321955bc, 0x9407901d, 0xe191ceb3, 0xe1ac22fb, 0xf1938c5a, 0x94b36fe6), SECP256K1_FE_CONST(0x32753116, 0x7001a9ac, 0xe57b2814, 0xc1b705bf, 0xcbdf9317, 0xda5316f8, 0x2f120f14, 0x14a15f8d)}},
|
||||
{0x44, SECP256K1_FE_CONST(0xe0294c8b, 0xc1a36b41, 0x66ee92bf, 0xa70a5c34, 0x976fa982, 0x9405efea, 0x8f9cd54d, 0xcb29b99e), SECP256K1_FE_CONST(0xae9690d1, 0x3b8d20a0, 0xfbbf37be, 0xd8474f67, 0xa04e142f, 0x56efd787, 0x70a76b35, 0x9165d8a1), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xdcd45d93, 0x5613916a, 0xf167b029, 0x058ba3a7, 0x00d37150, 0xb9df3472, 0x8cb05412, 0xc16d4182), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x232ba26c, 0xa9ec6e95, 0x0e984fd6, 0xfa745c58, 0xff2c8eaf, 0x4620cb8d, 0x734fabec, 0x3e92baad), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xe148441c, 0xd7b92b8b, 0x0e4fa3bd, 0x68712cfd, 0x0d709ad1, 0x98cace61, 0x1493c10e, 0x97f5394e), SECP256K1_FE_CONST(0x164a6397, 0x94d74c53, 0xafc4d329, 0x4e79cdb3, 0xcd25f99f, 0x6df45c00, 0x0f758aba, 0x54d699c0), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xff, SECP256K1_FE_CONST(0xe4b00ec9, 0x7aadcca9, 0x7644d3b0, 0xc8a931b1, 0x4ce7bcf7, 0xbc877954, 0x6d6e35aa, 0x5937381c), SECP256K1_FE_CONST(0x94e9588d, 0x41647b3f, 0xcc772dc8, 0xd83c67ce, 0x3be00353, 0x8517c834, 0x103d2cd4, 0x9d62ef4d), {SECP256K1_FE_CONST(0xc88d25f4, 0x1407376b, 0xb2c03a7f, 0xffeb3ec7, 0x811cc434, 0x91a0c3aa, 0xc0378cdc, 0x78357bee), SECP256K1_FE_CONST(0x51c02636, 0xce00c234, 0x5ecd89ad, 0xb6089fe4, 0xd5e18ac9, 0x24e3145e, 0x6669501c, 0xd37a00d4), SECP256K1_FE_CONST(0x205b3512, 0xdb40521c, 0xb200952e, 0x67b46f67, 0xe09e7839, 0xe0de4400, 0x4138329e, 0xbd9138c5), SECP256K1_FE_CONST(0x58aab390, 0xab6fb55c, 0x1d1b8089, 0x7a207ce9, 0x4a78fa5b, 0x4aa61a33, 0x398bcae9, 0xadb20d3e), SECP256K1_FE_CONST(0x3772da0b, 0xebf8c894, 0x4d3fc580, 0x0014c138, 0x7ee33bcb, 0x6e5f3c55, 0x3fc87322, 0x87ca8041), SECP256K1_FE_CONST(0xae3fd9c9, 0x31ff3dcb, 0xa1327652, 0x49f7601b, 0x2a1e7536, 0xdb1ceba1, 0x9996afe2, 0x2c85fb5b), SECP256K1_FE_CONST(0xdfa4caed, 0x24bfade3, 0x4dff6ad1, 0x984b9098, 0x1f6187c6, 0x1f21bbff, 0xbec7cd60, 0x426ec36a), SECP256K1_FE_CONST(0xa7554c6f, 0x54904aa3, 0xe2e47f76, 0x85df8316, 0xb58705a4, 0xb559e5cc, 0xc6743515, 0x524deef1)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), SECP256K1_FE_CONST(0xe5bbb9ef, 0x360d0a50, 0x1618f006, 0x7d36dceb, 0x75f5be9a, 0x620232aa, 0x9fd5139d, 0x0863fde5), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xff, SECP256K1_FE_CONST(0xe6bcb5c3, 0xd63467d4, 0x90bfa54f, 0xbbc6092a, 0x7248c25e, 0x11b248dc, 0x2964a6e1, 0x5edb1457), SECP256K1_FE_CONST(0x19434a3c, 0x29cb982b, 0x6f405ab0, 0x4439f6d5, 0x8db73da1, 0xee4db723, 0xd69b591d, 0xa124e7d8), {SECP256K1_FE_CONST(0x67119877, 0x832ab8f4, 0x59a82165, 0x6d8261f5, 0x44a553b8, 0x9ae4f25c, 0x52a97134, 0xb70f3426), SECP256K1_FE_CONST(0xffee02f5, 0xe649c07f, 0x0560eff1, 0x867ec7b3, 0x2d0e595e, 0x9b1c0ea6, 0xe2a4fc70, 0xc97cd71f), SECP256K1_FE_CONST(0xb5e0c189, 0xeb5b4bac, 0xd025b744, 0x4d74178b, 0xe8d5246c, 0xfa4a9a20, 0x7964a057, 0xee969992), SECP256K1_FE_CONST(0x5746e459, 0x1bf7f4c3, 0x044609ea, 0x372e9086, 0x03975d27, 0x9fdef834, 0x9f0b08d3, 0x2f07619d), SECP256K1_FE_CONST(0x98ee6788, 0x7cd5470b, 0xa657de9a, 0x927d9e0a, 0xbb5aac47, 0x651b0da3, 0xad568eca, 0x48f0c809), SECP256K1_FE_CONST(0x0011fd0a, 0x19b63f80, 0xfa9f100e, 0x7981384c, 0xd2f1a6a1, 0x64e3f159, 0x1d5b038e, 0x36832510), SECP256K1_FE_CONST(0x4a1f3e76, 0x14a4b453, 0x2fda48bb, 0xb28be874, 0x172adb93, 0x05b565df, 0x869b5fa7, 0x1169629d), SECP256K1_FE_CONST(0xa8b91ba6, 0xe4080b3c, 0xfbb9f615, 0xc8d16f79, 0xfc68a2d8, 0x602107cb, 0x60f4f72b, 0xd0f89a92)}},
|
||||
{0x33, SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), SECP256K1_FE_CONST(0xf28fba64, 0xaf766845, 0xeb2f4302, 0x456e2b9f, 0x8d80affe, 0x57e7aae4, 0x2738d7cd, 0xdb1c2ce6), {SECP256K1_FE_CONST(0x4f867ad8, 0xbb3d8404, 0x09d26b67, 0x307e6210, 0x0153273f, 0x72fa4b74, 0x84becfa1, 0x4ebe7408), SECP256K1_FE_CONST(0x5bbc4f59, 0xe452cc5f, 0x22a99144, 0xb10ce898, 0x9a89a995, 0xec3cea1c, 0x91ae10e8, 0xf721bb5d), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xb0798527, 0x44c27bfb, 0xf62d9498, 0xcf819def, 0xfeacd8c0, 0x8d05b48b, 0x7b41305d, 0xb1418827), SECP256K1_FE_CONST(0xa443b0a6, 0x1bad33a0, 0xdd566ebb, 0x4ef31767, 0x6576566a, 0x13c315e3, 0x6e51ef16, 0x08de40d2), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
{0xcc, SECP256K1_FE_CONST(0xf455605b, 0xc85bf48e, 0x3a908c31, 0x023faf98, 0x381504c6, 0xc6d3aeb9, 0xede55f8d, 0xd528924d), SECP256K1_FE_CONST(0xd31fbcd5, 0xcdb798f6, 0xc00db669, 0x2f8fe896, 0x7fa9c79d, 0xd10958f4, 0xa194f013, 0x74905e99), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0x0c00c571, 0x5b56fe63, 0x2d814ad8, 0xa77f8e66, 0x628ea47a, 0x6116834f, 0x8c1218f3, 0xa03cbd50), SECP256K1_FE_CONST(0xdf88e44f, 0xac84fa52, 0xdf4d59f4, 0x8819f18f, 0x6a8cd415, 0x1d162afa, 0xf773166f, 0x57c7ff46), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0xf3ff3a8e, 0xa4a9019c, 0xd27eb527, 0x58807199, 0x9d715b85, 0x9ee97cb0, 0x73ede70b, 0x5fc33edf), SECP256K1_FE_CONST(0x20771bb0, 0x537b05ad, 0x20b2a60b, 0x77e60e70, 0x95732bea, 0xe2e9d505, 0x088ce98f, 0xa837fce9)}},
|
||||
{0xff, SECP256K1_FE_CONST(0xf58cd4d9, 0x830bad32, 0x2699035e, 0x8246007d, 0x4be27e19, 0xb6f53621, 0x317b4f30, 0x9b3daa9d), SECP256K1_FE_CONST(0x78ec2b3d, 0xc0948de5, 0x60148bbc, 0x7c6dc963, 0x3ad5df70, 0xa5a5750c, 0xbed72180, 0x4f082a3b), {SECP256K1_FE_CONST(0x6c4c580b, 0x76c75940, 0x43569f9d, 0xae16dc28, 0x01c16a1f, 0xbe128608, 0x81b75f8e, 0xf929bce5), SECP256K1_FE_CONST(0x94231355, 0xe7385c5f, 0x25ca436a, 0xa6419147, 0x1aea4393, 0xd6e86ab7, 0xa35fe2af, 0xacaefd0d), SECP256K1_FE_CONST(0xdff2a195, 0x1ada6db5, 0x74df8340, 0x48149da3, 0x397a75b8, 0x29abf58c, 0x7e69db1b, 0x41ac0989), SECP256K1_FE_CONST(0xa52b66d3, 0xc9070355, 0x48028bf8, 0x04711bf4, 0x22aba95f, 0x1a666fc8, 0x6f4648e0, 0x5f29caae), SECP256K1_FE_CONST(0x93b3a7f4, 0x8938a6bf, 0xbca96062, 0x51e923d7, 0xfe3e95e0, 0x41ed79f7, 0x7e48a070, 0x06d63f4a), SECP256K1_FE_CONST(0x6bdcecaa, 0x18c7a3a0, 0xda35bc95, 0x59be6eb8, 0xe515bc6c, 0x29179548, 0x5ca01d4f, 0x5350ff22), SECP256K1_FE_CONST(0x200d5e6a, 0xe525924a, 0x8b207cbf, 0xb7eb625c, 0xc6858a47, 0xd6540a73, 0x819624e3, 0xbe53f2a6), SECP256K1_FE_CONST(0x5ad4992c, 0x36f8fcaa, 0xb7fd7407, 0xfb8ee40b, 0xdd5456a0, 0xe5999037, 0x90b9b71e, 0xa0d63181)}},
|
||||
{0x00, SECP256K1_FE_CONST(0xfd7d912a, 0x40f182a3, 0x588800d6, 0x9ebfb504, 0x8766da20, 0x6fd7ebc8, 0xd2436c81, 0xcbef6421), SECP256K1_FE_CONST(0x8d37c862, 0x054debe7, 0x31694536, 0xff46b273, 0xec122b35, 0xa9bf1445, 0xac3c4ff9, 0xf262c952), {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0)}},
|
||||
};
|
||||
|
||||
/* Set of (encoding, xcoord) test vectors, selected to maximize branch coverage, part of the BIP324
|
||||
* test vectors. Created using an independent implementation, and tested decoding against the paper
|
||||
* authors' code. */
|
||||
static const struct ellswift_decode_test ellswift_decode_tests[] = {
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 1},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0},
|
||||
{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0},
|
||||
{{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0},
|
||||
{{0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x532167c1, 0x1200b08c, 0x0e84a354, 0xe74dcc40, 0xf8b25f4f, 0xe686e308, 0x69526366, 0x278a0688), 0},
|
||||
{{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x74e880b3, 0xffd18fe3, 0xcddf7902, 0x522551dd, 0xf97fa4a3, 0x5a3cfda8, 0x197f9470, 0x81a57b8f), 0},
|
||||
{{0x0f, 0xfd, 0xe9, 0xca, 0x81, 0xd7, 0x51, 0xe9, 0xcd, 0xaf, 0xfc, 0x1a, 0x50, 0x77, 0x92, 0x45, 0x32, 0x0b, 0x28, 0x99, 0x6d, 0xba, 0xf3, 0x2f, 0x82, 0x2f, 0x20, 0x11, 0x7c, 0x22, 0xfb, 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x377b643f, 0xce2271f6, 0x4e5c8101, 0x566107c1, 0xbe498074, 0x50917838, 0x04f65478, 0x1ac9217c), 1},
|
||||
{{0x12, 0x36, 0x58, 0x44, 0x4f, 0x32, 0xbe, 0x8f, 0x02, 0xea, 0x20, 0x34, 0xaf, 0xa7, 0xef, 0x4b, 0xbe, 0x8a, 0xdc, 0x91, 0x8c, 0xeb, 0x49, 0xb1, 0x27, 0x73, 0xb6, 0x25, 0xf4, 0x90, 0xb3, 0x68, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8d, 0xc5, 0xfe, 0x11}, SECP256K1_FE_CONST(0xed16d65c, 0xf3a9538f, 0xcb2c139f, 0x1ecbc143, 0xee148271, 0x20cbc265, 0x9e667256, 0x800b8142), 0},
|
||||
{{0x14, 0x6f, 0x92, 0x46, 0x4d, 0x15, 0xd3, 0x6e, 0x35, 0x38, 0x2b, 0xd3, 0xca, 0x5b, 0x0f, 0x97, 0x6c, 0x95, 0xcb, 0x08, 0xac, 0xdc, 0xf2, 0xd5, 0xb3, 0x57, 0x06, 0x17, 0x99, 0x08, 0x39, 0xd7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x45, 0xe9, 0x3b}, SECP256K1_FE_CONST(0x0d5cd840, 0x427f941f, 0x65193079, 0xab8e2e83, 0x024ef2ee, 0x7ca558d8, 0x8879ffd8, 0x79fb6657), 0},
|
||||
{{0x15, 0xfd, 0xf5, 0xcf, 0x09, 0xc9, 0x07, 0x59, 0xad, 0xd2, 0x27, 0x2d, 0x57, 0x4d, 0x2b, 0xb5, 0xfe, 0x14, 0x29, 0xf9, 0xf3, 0xc1, 0x4c, 0x65, 0xe3, 0x19, 0x4b, 0xf6, 0x1b, 0x82, 0xaa, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0xcf, 0xd9, 0x06}, SECP256K1_FE_CONST(0x16d0e439, 0x46aec93f, 0x62d57eb8, 0xcde68951, 0xaf136cf4, 0xb307938d, 0xd1447411, 0xe07bffe1), 1},
|
||||
{{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0},
|
||||
{{0x1f, 0x67, 0xed, 0xf7, 0x79, 0xa8, 0xa6, 0x49, 0xd6, 0xde, 0xf6, 0x00, 0x35, 0xf2, 0xfa, 0x22, 0xd0, 0x22, 0xdd, 0x35, 0x90, 0x79, 0xa1, 0xa1, 0x44, 0x07, 0x3d, 0x84, 0xf1, 0x9b, 0x92, 0xd5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x025661f9, 0xaba9d15c, 0x3118456b, 0xbe980e3e, 0x1b8ba2e0, 0x47c737a4, 0xeb48a040, 0xbb566f6c), 0},
|
||||
{{0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x98bec3b2, 0xa351fa96, 0xcfd191c1, 0x77835193, 0x1b9e9ba9, 0xad1149f6, 0xd9eadca8, 0x0981b801), 0},
|
||||
{{0x40, 0x56, 0xa3, 0x4a, 0x21, 0x0e, 0xec, 0x78, 0x92, 0xe8, 0x82, 0x06, 0x75, 0xc8, 0x60, 0x09, 0x9f, 0x85, 0x7b, 0x26, 0xaa, 0xd8, 0x54, 0x70, 0xee, 0x6d, 0x3c, 0xf1, 0x30, 0x4a, 0x9d, 0xcf, 0x37, 0x5e, 0x70, 0x37, 0x42, 0x71, 0xf2, 0x0b, 0x13, 0xc9, 0x98, 0x6e, 0xd7, 0xd3, 0xc1, 0x77, 0x99, 0x69, 0x8c, 0xfc, 0x43, 0x5d, 0xbe, 0xd3, 0xa9, 0xf3, 0x4b, 0x38, 0xc8, 0x23, 0xc2, 0xb4}, SECP256K1_FE_CONST(0x868aac20, 0x03b29dbc, 0xad1a3e80, 0x3855e078, 0xa89d1654, 0x3ac64392, 0xd1224172, 0x98cec76e), 0},
|
||||
{{0x41, 0x97, 0xec, 0x37, 0x23, 0xc6, 0x54, 0xcf, 0xdd, 0x32, 0xab, 0x07, 0x55, 0x06, 0x64, 0x8b, 0x2f, 0xf5, 0x07, 0x03, 0x62, 0xd0, 0x1a, 0x4f, 0xff, 0x14, 0xb3, 0x36, 0xb7, 0x8f, 0x96, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb3, 0xab, 0x1e, 0x95}, SECP256K1_FE_CONST(0xba5a6314, 0x502a8952, 0xb8f456e0, 0x85928105, 0xf665377a, 0x8ce27726, 0xa5b0eb7e, 0xc1ac0286), 0},
|
||||
{{0x47, 0xeb, 0x3e, 0x20, 0x8f, 0xed, 0xcd, 0xf8, 0x23, 0x4c, 0x94, 0x21, 0xe9, 0xcd, 0x9a, 0x7a, 0xe8, 0x73, 0xbf, 0xbd, 0xbc, 0x39, 0x37, 0x23, 0xd1, 0xba, 0x1e, 0x1e, 0x6a, 0x8e, 0x6b, 0x24, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7c, 0xd1, 0x2c, 0xb1}, SECP256K1_FE_CONST(0xd192d520, 0x07e541c9, 0x807006ed, 0x0468df77, 0xfd214af0, 0xa795fe11, 0x9359666f, 0xdcf08f7c), 0},
|
||||
{{0x5e, 0xb9, 0x69, 0x6a, 0x23, 0x36, 0xfe, 0x2c, 0x3c, 0x66, 0x6b, 0x02, 0xc7, 0x55, 0xdb, 0x4c, 0x0c, 0xfd, 0x62, 0x82, 0x5c, 0x7b, 0x58, 0x9a, 0x7b, 0x7b, 0xb4, 0x42, 0xe1, 0x41, 0xc1, 0xd6, 0x93, 0x41, 0x3f, 0x00, 0x52, 0xd4, 0x9e, 0x64, 0xab, 0xec, 0x6d, 0x58, 0x31, 0xd6, 0x6c, 0x43, 0x61, 0x28, 0x30, 0xa1, 0x7d, 0xf1, 0xfe, 0x43, 0x83, 0xdb, 0x89, 0x64, 0x68, 0x10, 0x02, 0x21}, SECP256K1_FE_CONST(0xef6e1da6, 0xd6c7627e, 0x80f7a723, 0x4cb08a02, 0x2c1ee1cf, 0x29e4d0f9, 0x642ae924, 0xcef9eb38), 1},
|
||||
{{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0},
|
||||
{{0x7b, 0xf9, 0x6b, 0x7b, 0x6d, 0xa1, 0x5d, 0x34, 0x76, 0xa2, 0xb1, 0x95, 0x93, 0x4b, 0x69, 0x0a, 0x3a, 0x3d, 0xe3, 0xe8, 0xab, 0x84, 0x74, 0x85, 0x68, 0x63, 0xb0, 0xde, 0x3a, 0xf9, 0x0b, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x50851dfc, 0x9f418c31, 0x4a437295, 0xb24feeea, 0x27af3d0c, 0xd2308348, 0xfda6e21c, 0x463e46ff), 0},
|
||||
{{0x85, 0x1b, 0x1c, 0xa9, 0x45, 0x49, 0x37, 0x1c, 0x4f, 0x1f, 0x71, 0x87, 0x32, 0x1d, 0x39, 0xbf, 0x51, 0xc6, 0xb7, 0xfb, 0x61, 0xf7, 0xcb, 0xf0, 0x27, 0xc9, 0xda, 0x62, 0x02, 0x1b, 0x7a, 0x65, 0xfc, 0x54, 0xc9, 0x68, 0x37, 0xfb, 0x22, 0xb3, 0x62, 0xed, 0xa6, 0x3e, 0xc5, 0x2e, 0xc8, 0x3d, 0x81, 0xbe, 0xdd, 0x16, 0x0c, 0x11, 0xb2, 0x2d, 0x96, 0x5d, 0x9f, 0x4a, 0x6d, 0x64, 0xd2, 0x51}, SECP256K1_FE_CONST(0x3e731051, 0xe12d3323, 0x7eb324f2, 0xaa5b16bb, 0x868eb49a, 0x1aa1fadc, 0x19b6e876, 0x1b5a5f7b), 1},
|
||||
{{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0},
|
||||
{{0x94, 0x3c, 0x2f, 0x77, 0x51, 0x08, 0xb7, 0x37, 0xfe, 0x65, 0xa9, 0x53, 0x1e, 0x19, 0xf2, 0xfc, 0x2a, 0x19, 0x7f, 0x56, 0x03, 0xe3, 0xa2, 0x88, 0x1d, 0x1d, 0x83, 0xe4, 0x00, 0x8f, 0x91, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x311c61f0, 0xab2f32b7, 0xb1f0223f, 0xa72f0a78, 0x752b8146, 0xe46107f8, 0x876dd9c4, 0xf92b2942), 0},
|
||||
{{0xa0, 0xf1, 0x84, 0x92, 0x18, 0x3e, 0x61, 0xe8, 0x06, 0x3e, 0x57, 0x36, 0x06, 0x59, 0x14, 0x21, 0xb0, 0x6b, 0xc3, 0x51, 0x36, 0x31, 0x57, 0x8a, 0x73, 0xa3, 0x9c, 0x1c, 0x33, 0x06, 0x23, 0x9f, 0x2f, 0x32, 0x90, 0x4f, 0x0d, 0x2a, 0x33, 0xec, 0xca, 0x8a, 0x54, 0x51, 0x70, 0x5b, 0xb5, 0x37, 0xd3, 0xbf, 0x44, 0xe0, 0x71, 0x22, 0x60, 0x25, 0xcd, 0xbf, 0xd2, 0x49, 0xfe, 0x0f, 0x7a, 0xd6}, SECP256K1_FE_CONST(0x97a09cf1, 0xa2eae7c4, 0x94df3c6f, 0x8a9445bf, 0xb8c09d60, 0x832f9b0b, 0x9d5eabe2, 0x5fbd14b9), 0},
|
||||
{{0xa1, 0xed, 0x0a, 0x0b, 0xd7, 0x9d, 0x8a, 0x23, 0xcf, 0xe4, 0xec, 0x5f, 0xef, 0x5b, 0xa5, 0xcc, 0xcf, 0xd8, 0x44, 0xe4, 0xff, 0x5c, 0xb4, 0xb0, 0xf2, 0xe7, 0x16, 0x27, 0x34, 0x1f, 0x1c, 0x5b, 0x17, 0xc4, 0x99, 0x24, 0x9e, 0x0a, 0xc0, 0x8d, 0x5d, 0x11, 0xea, 0x1c, 0x2c, 0x8c, 0xa7, 0x00, 0x16, 0x16, 0x55, 0x9a, 0x79, 0x94, 0xea, 0xde, 0xc9, 0xca, 0x10, 0xfb, 0x4b, 0x85, 0x16, 0xdc}, SECP256K1_FE_CONST(0x65a89640, 0x744192cd, 0xac64b2d2, 0x1ddf989c, 0xdac75007, 0x25b645be, 0xf8e2200a, 0xe39691f2), 0},
|
||||
{{0xba, 0x94, 0x59, 0x4a, 0x43, 0x27, 0x21, 0xaa, 0x35, 0x80, 0xb8, 0x4c, 0x16, 0x1d, 0x0d, 0x13, 0x4b, 0xc3, 0x54, 0xb6, 0x90, 0x40, 0x4d, 0x7c, 0xd4, 0xec, 0x57, 0xc1, 0x6d, 0x3f, 0xbe, 0x98, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xea, 0x50, 0x7d, 0xd7}, SECP256K1_FE_CONST(0x5e0d7656, 0x4aae92cb, 0x347e01a6, 0x2afd389a, 0x9aa401c7, 0x6c8dd227, 0x543dc9cd, 0x0efe685a), 0},
|
||||
{{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x2d97f96c, 0xac882dfe, 0x73dc44db, 0x6ce0f1d3, 0x1d624135, 0x8dd5d74e, 0xb3d3b500, 0x03d24c2b), 0},
|
||||
{{0xbc, 0xaf, 0x72, 0x19, 0xf2, 0xf6, 0xfb, 0xf5, 0x5f, 0xe5, 0xe0, 0x62, 0xdc, 0xe0, 0xe4, 0x8c, 0x18, 0xf6, 0x81, 0x03, 0xf1, 0x0b, 0x81, 0x98, 0xe9, 0x74, 0xc1, 0x84, 0x75, 0x0e, 0x1b, 0xe3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x65, 0x07, 0xd0, 0x9a}, SECP256K1_FE_CONST(0xe7008afe, 0x6e8cbd50, 0x55df120b, 0xd748757c, 0x686dadb4, 0x1cce75e4, 0xaddcc5e0, 0x2ec02b44), 1},
|
||||
{{0xc5, 0x98, 0x1b, 0xae, 0x27, 0xfd, 0x84, 0x40, 0x1c, 0x72, 0xa1, 0x55, 0xe5, 0x70, 0x7f, 0xbb, 0x81, 0x1b, 0x2b, 0x62, 0x06, 0x45, 0xd1, 0x02, 0x8e, 0xa2, 0x70, 0xcb, 0xe0, 0xee, 0x22, 0x5d, 0x4b, 0x62, 0xaa, 0x4d, 0xca, 0x65, 0x06, 0xc1, 0xac, 0xdb, 0xec, 0xc0, 0x55, 0x25, 0x69, 0xb4, 0xb2, 0x14, 0x36, 0xa5, 0x69, 0x2e, 0x25, 0xd9, 0x0d, 0x3b, 0xc2, 0xeb, 0x7c, 0xe2, 0x40, 0x78}, SECP256K1_FE_CONST(0x948b40e7, 0x181713bc, 0x018ec170, 0x2d3d054d, 0x15746c59, 0xa7020730, 0xdd13ecf9, 0x85a010d7), 0},
|
||||
{{0xc8, 0x94, 0xce, 0x48, 0xbf, 0xec, 0x43, 0x30, 0x14, 0xb9, 0x31, 0xa6, 0xad, 0x42, 0x26, 0xd7, 0xdb, 0xd8, 0xea, 0xa7, 0xb6, 0xe3, 0xfa, 0xa8, 0xd0, 0xef, 0x94, 0x05, 0x2b, 0xcf, 0x8c, 0xff, 0x33, 0x6e, 0xeb, 0x39, 0x19, 0xe2, 0xb4, 0xef, 0xb7, 0x46, 0xc7, 0xf7, 0x1b, 0xbc, 0xa7, 0xe9, 0x38, 0x32, 0x30, 0xfb, 0xbc, 0x48, 0xff, 0xaf, 0xe7, 0x7e, 0x8b, 0xcc, 0x69, 0x54, 0x24, 0x71}, SECP256K1_FE_CONST(0xf1c91acd, 0xc2525330, 0xf9b53158, 0x434a4d43, 0xa1c547cf, 0xf29f1550, 0x6f5da4eb, 0x4fe8fa5a), 1},
|
||||
{{0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x872d81ed, 0x8831d999, 0x8b67cb71, 0x05243edb, 0xf86c10ed, 0xfebb786c, 0x110b02d0, 0x7b2e67cd), 0},
|
||||
{{0xd9, 0x17, 0xb7, 0x86, 0xda, 0xc3, 0x56, 0x70, 0xc3, 0x30, 0xc9, 0xc5, 0xae, 0x59, 0x71, 0xdf, 0xb4, 0x95, 0xc8, 0xae, 0x52, 0x3e, 0xd9, 0x7e, 0xe2, 0x42, 0x01, 0x17, 0xb1, 0x71, 0xf4, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x20, 0x01, 0xf6, 0xf6}, SECP256K1_FE_CONST(0xe45b71e1, 0x10b831f2, 0xbdad8651, 0x994526e5, 0x8393fde4, 0x328b1ec0, 0x4d598971, 0x42584691), 1},
|
||||
{{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0},
|
||||
{{0xe2, 0x8b, 0xd8, 0xf5, 0x92, 0x9b, 0x46, 0x7e, 0xb7, 0x0e, 0x04, 0x33, 0x23, 0x74, 0xff, 0xb7, 0xe7, 0x18, 0x02, 0x18, 0xad, 0x16, 0xea, 0xa4, 0x6b, 0x71, 0x61, 0xaa, 0x67, 0x9e, 0xb4, 0x26, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x66b8c980, 0xa75c72e5, 0x98d383a3, 0x5a62879f, 0x844242ad, 0x1e73ff12, 0xedaa59f4, 0xe58632b5), 0},
|
||||
{{0xe7, 0xee, 0x58, 0x14, 0xc1, 0x70, 0x6b, 0xf8, 0xa8, 0x93, 0x96, 0xa9, 0xb0, 0x32, 0xbc, 0x01, 0x4c, 0x2c, 0xac, 0x9c, 0x12, 0x11, 0x27, 0xdb, 0xf6, 0xc9, 0x92, 0x78, 0xf8, 0xbb, 0x53, 0xd1, 0xdf, 0xd0, 0x4d, 0xbc, 0xda, 0x8e, 0x35, 0x24, 0x66, 0xb6, 0xfc, 0xd5, 0xf2, 0xde, 0xa3, 0xe1, 0x7d, 0x5e, 0x13, 0x31, 0x15, 0x88, 0x6e, 0xda, 0x20, 0xdb, 0x8a, 0x12, 0xb5, 0x4d, 0xe7, 0x1b}, SECP256K1_FE_CONST(0xe842c6e3, 0x529b2342, 0x70a5e977, 0x44edc34a, 0x04d7ba94, 0xe44b6d25, 0x23c9cf01, 0x95730a50), 1},
|
||||
{{0xf2, 0x92, 0xe4, 0x68, 0x25, 0xf9, 0x22, 0x5a, 0xd2, 0x3d, 0xc0, 0x57, 0xc1, 0xd9, 0x1c, 0x4f, 0x57, 0xfc, 0xb1, 0x38, 0x6f, 0x29, 0xef, 0x10, 0x48, 0x1c, 0xb1, 0xd2, 0x25, 0x18, 0x59, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x11, 0xc9, 0x89}, SECP256K1_FE_CONST(0x3cea2c53, 0xb8b01701, 0x66ac7da6, 0x7194694a, 0xdacc84d5, 0x6389225e, 0x330134da, 0xb85a4d55), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x01, 0xd3, 0x47, 0x5b, 0xf7, 0x65, 0x5b, 0x0f, 0xb2, 0xd8, 0x52, 0x92, 0x10, 0x35, 0xb2, 0xef, 0x60, 0x7f, 0x49, 0x06, 0x9b, 0x97, 0x45, 0x4e, 0x67, 0x95, 0x25, 0x10, 0x62, 0x74, 0x17, 0x71}, SECP256K1_FE_CONST(0xb5da00b7, 0x3cd65605, 0x20e7c364, 0x086e7cd2, 0x3a34bf60, 0xd0e707be, 0x9fc34d4c, 0xd5fdfa2c), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee}, SECP256K1_FE_CONST(0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaa9, 0xfffffd6b), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x82, 0x27, 0x7c, 0x4a, 0x71, 0xf9, 0xd2, 0x2e, 0x66, 0xec, 0xe5, 0x23, 0xf8, 0xfa, 0x08, 0x74, 0x1a, 0x7c, 0x09, 0x12, 0xc6, 0x6a, 0x69, 0xce, 0x68, 0x51, 0x4b, 0xfd, 0x35, 0x15, 0xb4, 0x9f}, SECP256K1_FE_CONST(0xf482f2e2, 0x41753ad0, 0xfb89150d, 0x8491dc1e, 0x34ff0b8a, 0xcfbb442c, 0xfe999e2e, 0x5e6fd1d2), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x84, 0x21, 0xcc, 0x93, 0x0e, 0x77, 0xc9, 0xf5, 0x14, 0xb6, 0x91, 0x5c, 0x3d, 0xbe, 0x2a, 0x94, 0xc6, 0xd8, 0xf6, 0x90, 0xb5, 0xb7, 0x39, 0x86, 0x4b, 0xa6, 0x78, 0x9f, 0xb8, 0xa5, 0x5d, 0xd0}, SECP256K1_FE_CONST(0x9f59c402, 0x75f5085a, 0x006f05da, 0xe77eb98c, 0x6fd0db1a, 0xb4a72ac4, 0x7eae90a4, 0xfc9e57e0), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xd1, 0x9c, 0x18, 0x2d, 0x27, 0x59, 0xcd, 0x99, 0x82, 0x42, 0x28, 0xd9, 0x47, 0x99, 0xf8, 0xc6, 0x55, 0x7c, 0x38, 0xa1, 0xc0, 0xd6, 0x77, 0x9b, 0x9d, 0x4b, 0x72, 0x9c, 0x6f, 0x1c, 0xcc, 0x42}, SECP256K1_FE_CONST(0x70720db7, 0xe238d041, 0x21f5b1af, 0xd8cc5ad9, 0xd18944c6, 0xbdc94881, 0xf502b7a3, 0xaf3aecff), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x64, 0xbb, 0xd5}, SECP256K1_FE_CONST(0x50873db3, 0x1badcc71, 0x890e4f67, 0x753a6575, 0x7f97aaa7, 0xdd5f1e82, 0xb753ace3, 0x2219064b), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x28, 0xde, 0x7d}, SECP256K1_FE_CONST(0x1eea9cc5, 0x9cfcf2fa, 0x151ac6c2, 0x74eea411, 0x0feb4f7b, 0x68c59657, 0x32e9992e, 0x976ef68e), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xcb, 0xcf, 0xb7, 0xe7}, SECP256K1_FE_CONST(0x12303941, 0xaedc2088, 0x80735b1f, 0x1795c8e5, 0x5be520ea, 0x93e10335, 0x7b5d2adb, 0x7ed59b8e), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x11, 0x3a, 0xd9}, SECP256K1_FE_CONST(0x7eed6b70, 0xe7b0767c, 0x7d7feac0, 0x4e57aa2a, 0x12fef5e0, 0xf48f878f, 0xcbb88b3b, 0x6b5e0783), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x13, 0xce, 0xa4, 0xa7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x64998443, 0x5b62b4a2, 0x5d40c613, 0x3e8d9ab8, 0xc53d4b05, 0x9ee8a154, 0xa3be0fcf, 0x4e892edb), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x02, 0x8c, 0x59, 0x00, 0x63, 0xf6, 0x4d, 0x5a, 0x7f, 0x1c, 0x14, 0x91, 0x5c, 0xd6, 0x1e, 0xac, 0x88, 0x6a, 0xb2, 0x95, 0xbe, 0xbd, 0x91, 0x99, 0x25, 0x04, 0xcf, 0x77, 0xed, 0xb0, 0x28, 0xbd, 0xd6, 0x26, 0x7f}, SECP256K1_FE_CONST(0x3fde5713, 0xf8282eea, 0xd7d39d42, 0x01f44a7c, 0x85a5ac8a, 0x0681f35e, 0x54085c6b, 0x69543374), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x27, 0x15, 0xde, 0x86, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x3524f77f, 0xa3a6eb43, 0x89c3cb5d, 0x27f1f914, 0x62086429, 0xcd6c0cb0, 0xdf43ea8f, 0x1e7b3fb4), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x2c, 0x57, 0x09, 0xe7, 0x15, 0x6c, 0x41, 0x77, 0x17, 0xf2, 0xfe, 0xab, 0x14, 0x71, 0x41, 0xec, 0x3d, 0xa1, 0x9f, 0xb7, 0x59, 0x57, 0x5c, 0xc6, 0xe3, 0x7b, 0x2e, 0xa5, 0xac, 0x93, 0x09, 0xf2, 0x6f, 0x0f, 0x66}, SECP256K1_FE_CONST(0xd2469ab3, 0xe04acbb2, 0x1c65a180, 0x9f39caaf, 0xe7a77c13, 0xd10f9dd3, 0x8f391c01, 0xdc499c52), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3a, 0x08, 0xcc, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0x60, 0xe9, 0xf0}, SECP256K1_FE_CONST(0x38e2a5ce, 0x6a93e795, 0xe16d2c39, 0x8bc99f03, 0x69202ce2, 0x1e8f09d5, 0x6777b40f, 0xc512bccc), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0x91, 0x25, 0x7d, 0x93, 0x20, 0x16, 0xcb, 0xf6, 0x9c, 0x44, 0x71, 0xbd, 0x1f, 0x65, 0x6c, 0x6a, 0x10, 0x7f, 0x19, 0x73, 0xde, 0x4a, 0xf7, 0x08, 0x6d, 0xb8, 0x97, 0x27, 0x70, 0x60, 0xe2, 0x56, 0x77, 0xf1, 0x9a}, SECP256K1_FE_CONST(0x864b3dc9, 0x02c37670, 0x9c10a93a, 0xd4bbe29f, 0xce0012f3, 0xdc8672c6, 0x286bba28, 0xd7d6d6fc), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0x5d, 0x6c, 0x1c, 0x32, 0x2c, 0xad, 0xf5, 0x99, 0xdb, 0xb8, 0x64, 0x81, 0x52, 0x2b, 0x3c, 0xc5, 0x5f, 0x15, 0xa6, 0x79, 0x32, 0xdb, 0x2a, 0xfa, 0x01, 0x11, 0xd9, 0xed, 0x69, 0x81, 0xbc, 0xd1, 0x24, 0xbf, 0x44}, SECP256K1_FE_CONST(0x766dfe4a, 0x700d9bee, 0x288b903a, 0xd58870e3, 0xd4fe2f0e, 0xf780bcac, 0x5c823f32, 0x0d9a9bef), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8e, 0x42, 0x6f, 0x03, 0x92, 0x38, 0x90, 0x78, 0xc1, 0x2b, 0x1a, 0x89, 0xe9, 0x54, 0x2f, 0x05, 0x93, 0xbc, 0x96, 0xb6, 0xbf, 0xde, 0x82, 0x24, 0xf8, 0x65, 0x4e, 0xf5, 0xd5, 0xcd, 0xa9, 0x35, 0xa3, 0x58, 0x21, 0x94}, SECP256K1_FE_CONST(0xfaec7bc1, 0x987b6323, 0x3fbc5f95, 0x6edbf37d, 0x54404e74, 0x61c58ab8, 0x631bc68e, 0x451a0478), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x91, 0x19, 0x21, 0x39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x45, 0xf0, 0xf1, 0xeb}, SECP256K1_FE_CONST(0xec29a50b, 0xae138dbf, 0x7d8e2482, 0x5006bb5f, 0xc1a2cc12, 0x43ba335b, 0xc6116fb9, 0xe498ec1f), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x98, 0xeb, 0x9a, 0xb7, 0x6e, 0x84, 0x49, 0x9c, 0x48, 0x3b, 0x3b, 0xf0, 0x62, 0x14, 0xab, 0xfe, 0x06, 0x5d, 0xdd, 0xf4, 0x3b, 0x86, 0x01, 0xde, 0x59, 0x6d, 0x63, 0xb9, 0xe4, 0x5a, 0x16, 0x6a, 0x58, 0x05, 0x41, 0xfe}, SECP256K1_FE_CONST(0x1e0ff2de, 0xe9b09b13, 0x6292a9e9, 0x10f0d6ac, 0x3e552a64, 0x4bba39e6, 0x4e9dd3e3, 0xbbd3d4d4), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xc7, 0x4d, 0x99, 0xef, 0xce, 0xaa, 0x55, 0x0f, 0x1a, 0xd1, 0xc0, 0xf4, 0x3f, 0x46, 0xe7, 0xff, 0x1e, 0xe3, 0xbd, 0x01, 0x62, 0xb7, 0xbf, 0x55, 0xf2, 0x96, 0x5d, 0xa9, 0xc3, 0x45, 0x06, 0x46}, SECP256K1_FE_CONST(0x8b7dd5c3, 0xedba9ee9, 0x7b70eff4, 0x38f22dca, 0x9849c825, 0x4a2f3345, 0xa0a572ff, 0xeaae0928), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9b, 0x77, 0xb7, 0xf2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x15, 0x6c, 0xa8, 0x96}, SECP256K1_FE_CONST(0x0881950c, 0x8f51d6b9, 0xa6387465, 0xd5f12609, 0xef1bb254, 0x12a08a74, 0xcb2dfb20, 0x0c74bfbf), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa2, 0xf5, 0xcd, 0x83, 0x88, 0x16, 0xc1, 0x6c, 0x4f, 0xe8, 0xa1, 0x66, 0x1d, 0x60, 0x6f, 0xdb, 0x13, 0xcf, 0x9a, 0xf0, 0x4b, 0x97, 0x9a, 0x2e, 0x15, 0x9a, 0x09, 0x40, 0x9e, 0xbc, 0x86, 0x45, 0xd5, 0x8f, 0xde, 0x02}, SECP256K1_FE_CONST(0x2f083207, 0xb9fd9b55, 0x0063c31c, 0xd62b8746, 0xbd543bdc, 0x5bbf10e3, 0xa35563e9, 0x27f440c8), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb1, 0x3f, 0x75, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x4f51e0be, 0x078e0cdd, 0xab274215, 0x6adba7e7, 0xa148e731, 0x57072fd6, 0x18cd6094, 0x2b146bd0), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xbc, 0x1f, 0x8d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f}, SECP256K1_FE_CONST(0x16c2ccb5, 0x4352ff4b, 0xd794f6ef, 0xd613c721, 0x97ab7082, 0xda5b563b, 0xdf9cb3ed, 0xaafe74c2), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0x64, 0xd1, 0x62, 0x75, 0x05, 0x46, 0xce, 0x42, 0xb0, 0x43, 0x13, 0x61, 0xe5, 0x2d, 0x4f, 0x52, 0x42, 0xd8, 0xf2, 0x4f, 0x33, 0xe6, 0xb1, 0xf9, 0x9b, 0x59, 0x16, 0x47, 0xcb, 0xc8, 0x08, 0xf4, 0x62, 0xaf, 0x51}, SECP256K1_FE_CONST(0xd41244d1, 0x1ca4f652, 0x40687759, 0xf95ca9ef, 0xbab767ed, 0xedb38fd1, 0x8c36e18c, 0xd3b6f6a9), 1},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe5, 0xbe, 0x52, 0x37, 0x2d, 0xd6, 0xe8, 0x94, 0xb2, 0xa3, 0x26, 0xfc, 0x36, 0x05, 0xa6, 0xe8, 0xf3, 0xc6, 0x9c, 0x71, 0x0b, 0xf2, 0x7d, 0x63, 0x0d, 0xfe, 0x20, 0x04, 0x98, 0x8b, 0x78, 0xeb, 0x6e, 0xab, 0x36}, SECP256K1_FE_CONST(0x64bf84dd, 0x5e03670f, 0xdb24c0f5, 0xd3c2c365, 0x736f51db, 0x6c92d950, 0x10716ad2, 0xd36134c8), 0},
|
||||
{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfb, 0xb9, 0x82, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf6, 0xd6, 0xdb, 0x1f}, SECP256K1_FE_CONST(0x1c92ccdf, 0xcf4ac550, 0xc28db57c, 0xff0c8515, 0xcb26936c, 0x786584a7, 0x0114008d, 0x6c33a34b), 0},
|
||||
};
|
||||
|
||||
/* Set of expected ellswift_xdh BIP324 shared secrets, given private key, encodings, initiating,
|
||||
* taken from the BIP324 test vectors. Created using an independent implementation, and tested
|
||||
* against the paper authors' decoding code. */
|
||||
static const struct ellswift_xdh_test ellswift_xdh_tests_bip324[] = {
|
||||
{{0x61, 0x06, 0x2e, 0xa5, 0x07, 0x1d, 0x80, 0x0b, 0xbf, 0xd5, 0x9e, 0x2e, 0x8b, 0x53, 0xd4, 0x7d, 0x19, 0x4b, 0x09, 0x5a, 0xe5, 0xa4, 0xdf, 0x04, 0x93, 0x6b, 0x49, 0x77, 0x2e, 0xf0, 0xd4, 0xd7}, {0xec, 0x0a, 0xdf, 0xf2, 0x57, 0xbb, 0xfe, 0x50, 0x0c, 0x18, 0x8c, 0x80, 0xb4, 0xfd, 0xd6, 0x40, 0xf6, 0xb4, 0x5a, 0x48, 0x2b, 0xbc, 0x15, 0xfc, 0x7c, 0xef, 0x59, 0x31, 0xde, 0xff, 0x0a, 0xa1, 0x86, 0xf6, 0xeb, 0x9b, 0xba, 0x7b, 0x85, 0xdc, 0x4d, 0xcc, 0x28, 0xb2, 0x87, 0x22, 0xde, 0x1e, 0x3d, 0x91, 0x08, 0xb9, 0x85, 0xe2, 0x96, 0x70, 0x45, 0x66, 0x8f, 0x66, 0x09, 0x8e, 0x47, 0x5b}, {0xa4, 0xa9, 0x4d, 0xfc, 0xe6, 0x9b, 0x4a, 0x2a, 0x0a, 0x09, 0x93, 0x13, 0xd1, 0x0f, 0x9f, 0x7e, 0x7d, 0x64, 0x9d, 0x60, 0x50, 0x1c, 0x9e, 0x1d, 0x27, 0x4c, 0x30, 0x0e, 0x0d, 0x89, 0xaa, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xaf, 0x88, 0xd5}, 1, {0xc6, 0x99, 0x2a, 0x11, 0x7f, 0x5e, 0xdb, 0xea, 0x70, 0xc3, 0xf5, 0x11, 0xd3, 0x2d, 0x26, 0xb9, 0x79, 0x8b, 0xe4, 0xb8, 0x1a, 0x62, 0xea, 0xee, 0x1a, 0x5a, 0xca, 0xa8, 0x45, 0x9a, 0x35, 0x92}},
|
||||
{{0x1f, 0x9c, 0x58, 0x1b, 0x35, 0x23, 0x18, 0x38, 0xf0, 0xf1, 0x7c, 0xf0, 0xc9, 0x79, 0x83, 0x5b, 0xac, 0xcb, 0x7f, 0x3a, 0xbb, 0xbb, 0x96, 0xff, 0xcc, 0x31, 0x8a, 0xb7, 0x1e, 0x6e, 0x12, 0x6f}, {0xa1, 0x85, 0x5e, 0x10, 0xe9, 0x4e, 0x00, 0xba, 0xa2, 0x30, 0x41, 0xd9, 0x16, 0xe2, 0x59, 0xf7, 0x04, 0x4e, 0x49, 0x1d, 0xa6, 0x17, 0x12, 0x69, 0x69, 0x47, 0x63, 0xf0, 0x18, 0xc7, 0xe6, 0x36, 0x93, 0xd2, 0x95, 0x75, 0xdc, 0xb4, 0x64, 0xac, 0x81, 0x6b, 0xaa, 0x1b, 0xe3, 0x53, 0xba, 0x12, 0xe3, 0x87, 0x6c, 0xba, 0x76, 0x28, 0xbd, 0x0b, 0xd8, 0xe7, 0x55, 0xe7, 0x21, 0xeb, 0x01, 0x40}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0, {0xa0, 0x13, 0x8f, 0x56, 0x4f, 0x74, 0xd0, 0xad, 0x70, 0xbc, 0x33, 0x7d, 0xac, 0xc9, 0xd0, 0xbf, 0x1d, 0x23, 0x49, 0x36, 0x4c, 0xaf, 0x11, 0x88, 0xa1, 0xe6, 0xe8, 0xdd, 0xb3, 0xb7, 0xb1, 0x84}},
|
||||
{{0x02, 0x86, 0xc4, 0x1c, 0xd3, 0x09, 0x13, 0xdb, 0x0f, 0xdf, 0xf7, 0xa6, 0x4e, 0xbd, 0xa5, 0xc8, 0xe3, 0xe7, 0xce, 0xf1, 0x0f, 0x2a, 0xeb, 0xc0, 0x0a, 0x76, 0x50, 0x44, 0x3c, 0xf4, 0xc6, 0x0d}, {0xd1, 0xee, 0x8a, 0x93, 0xa0, 0x11, 0x30, 0xcb, 0xf2, 0x99, 0x24, 0x9a, 0x25, 0x8f, 0x94, 0xfe, 0xb5, 0xf4, 0x69, 0xe7, 0xd0, 0xf2, 0xf2, 0x8f, 0x69, 0xee, 0x5e, 0x9a, 0xa8, 0xf9, 0xb5, 0x4a, 0x60, 0xf2, 0xc3, 0xff, 0x2d, 0x02, 0x36, 0x34, 0xec, 0x7f, 0x41, 0x27, 0xa9, 0x6c, 0xc1, 0x16, 0x62, 0xe4, 0x02, 0x89, 0x4c, 0xf1, 0xf6, 0x94, 0xfb, 0x9a, 0x7e, 0xaa, 0x5f, 0x1d, 0x92, 0x44}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x22, 0xd5, 0xe4, 0x41, 0x52, 0x4d, 0x57, 0x1a, 0x52, 0xb3, 0xde, 0xf1, 0x26, 0x18, 0x9d, 0x3f, 0x41, 0x68, 0x90, 0xa9, 0x9d, 0x4d, 0xa6, 0xed, 0xe2, 0xb0, 0xcd, 0xe1, 0x76, 0x0c, 0xe2, 0xc3, 0xf9, 0x84, 0x57, 0xae}, 1, {0x25, 0x0b, 0x93, 0x57, 0x0d, 0x41, 0x11, 0x49, 0x10, 0x5a, 0xb8, 0xcb, 0x0b, 0xc5, 0x07, 0x99, 0x14, 0x90, 0x63, 0x06, 0x36, 0x8c, 0x23, 0xe9, 0xd7, 0x7c, 0x2a, 0x33, 0x26, 0x5b, 0x99, 0x4c}},
|
||||
{{0x6c, 0x77, 0x43, 0x2d, 0x1f, 0xda, 0x31, 0xe9, 0xf9, 0x42, 0xf8, 0xaf, 0x44, 0x60, 0x7e, 0x10, 0xf3, 0xad, 0x38, 0xa6, 0x5f, 0x8a, 0x4b, 0xdd, 0xae, 0x82, 0x3e, 0x5e, 0xff, 0x90, 0xdc, 0x38}, {0xd2, 0x68, 0x50, 0x70, 0xc1, 0xe6, 0x37, 0x6e, 0x63, 0x3e, 0x82, 0x52, 0x96, 0x63, 0x4f, 0xd4, 0x61, 0xfa, 0x9e, 0x5b, 0xdf, 0x21, 0x09, 0xbc, 0xeb, 0xd7, 0x35, 0xe5, 0xa9, 0x1f, 0x3e, 0x58, 0x7c, 0x5c, 0xb7, 0x82, 0xab, 0xb7, 0x97, 0xfb, 0xf6, 0xbb, 0x50, 0x74, 0xfd, 0x15, 0x42, 0xa4, 0x74, 0xf2, 0xa4, 0x5b, 0x67, 0x37, 0x63, 0xec, 0x2d, 0xb7, 0xfb, 0x99, 0xb7, 0x37, 0xbb, 0xb9}, {0x56, 0xbd, 0x0c, 0x06, 0xf1, 0x03, 0x52, 0xc3, 0xa1, 0xa9, 0xf4, 0xb4, 0xc9, 0x2f, 0x6f, 0xa2, 0xb2, 0x6d, 0xf1, 0x24, 0xb5, 0x78, 0x78, 0x35, 0x3c, 0x1f, 0xc6, 0x91, 0xc5, 0x1a, 0xbe, 0xa7, 0x7c, 0x88, 0x17, 0xda, 0xee, 0xb9, 0xfa, 0x54, 0x6b, 0x77, 0xc8, 0xda, 0xf7, 0x9d, 0x89, 0xb2, 0x2b, 0x0e, 0x1b, 0x87, 0x57, 0x4e, 0xce, 0x42, 0x37, 0x1f, 0x00, 0x23, 0x7a, 0xa9, 0xd8, 0x3a}, 0, {0x19, 0x18, 0xb7, 0x41, 0xef, 0x5f, 0x9d, 0x1d, 0x76, 0x70, 0xb0, 0x50, 0xc1, 0x52, 0xb4, 0xa4, 0xea, 0xd2, 0xc3, 0x1b, 0xe9, 0xae, 0xcb, 0x06, 0x81, 0xc0, 0xcd, 0x43, 0x24, 0x15, 0x08, 0x53}},
|
||||
{{0xa6, 0xec, 0x25, 0x12, 0x7c, 0xa1, 0xaa, 0x4c, 0xf1, 0x6b, 0x20, 0x08, 0x4b, 0xa1, 0xe6, 0x51, 0x6b, 0xaa, 0xe4, 0xd3, 0x24, 0x22, 0x28, 0x8e, 0x9b, 0x36, 0xd8, 0xbd, 0xdd, 0x2d, 0xe3, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x3d, 0x7e, 0xcc, 0xa5, 0x3e, 0x33, 0xe1, 0x85, 0xa8, 0xb9, 0xbe, 0x4e, 0x76, 0x99, 0xa9, 0x7c, 0x6f, 0xf4, 0xc7, 0x95, 0x52, 0x2e, 0x59, 0x18, 0xab, 0x7c, 0xd6, 0xb6, 0x88, 0x4f, 0x67, 0xe6, 0x83, 0xf3, 0xdc}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7, 0x73, 0x0b, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 1, {0xdd, 0x21, 0x0a, 0xa6, 0x62, 0x9f, 0x20, 0xbb, 0x32, 0x8e, 0x5d, 0x89, 0xda, 0xa6, 0xeb, 0x2a, 0xc3, 0xd1, 0xc6, 0x58, 0xa7, 0x25, 0x53, 0x6f, 0xf1, 0x54, 0xf3, 0x1b, 0x53, 0x6c, 0x23, 0xb2}},
|
||||
{{0x0a, 0xf9, 0x52, 0x65, 0x9e, 0xd7, 0x6f, 0x80, 0xf5, 0x85, 0x96, 0x6b, 0x95, 0xab, 0x6e, 0x6f, 0xd6, 0x86, 0x54, 0x67, 0x28, 0x27, 0x87, 0x86, 0x84, 0xc8, 0xb5, 0x47, 0xb1, 0xb9, 0x4f, 0x5a}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x10, 0x17, 0xfd, 0x92, 0xfd, 0x31, 0x63, 0x7c, 0x26, 0xc9, 0x06, 0xb4, 0x20, 0x92, 0xe1, 0x1c, 0xc0, 0xd3, 0xaf, 0xae, 0x8d, 0x90, 0x19, 0xd2, 0x57, 0x8a, 0xf2, 0x27, 0x35, 0xce, 0x7b, 0xc4, 0x69, 0xc7, 0x2d}, {0x96, 0x52, 0xd7, 0x8b, 0xae, 0xfc, 0x02, 0x8c, 0xd3, 0x7a, 0x6a, 0x92, 0x62, 0x5b, 0x8b, 0x8f, 0x85, 0xfd, 0xe1, 0xe4, 0xc9, 0x44, 0xad, 0x3f, 0x20, 0xe1, 0x98, 0xbe, 0xf8, 0xc0, 0x2f, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf2, 0xe9, 0x18, 0x70}, 0, {0x35, 0x68, 0xf2, 0xae, 0xa2, 0xe1, 0x4e, 0xf4, 0xee, 0x4a, 0x3c, 0x2a, 0x8b, 0x8d, 0x31, 0xbc, 0x5e, 0x31, 0x87, 0xba, 0x86, 0xdb, 0x10, 0x73, 0x9b, 0x4f, 0xf8, 0xec, 0x92, 0xff, 0x66, 0x55}},
|
||||
{{0xf9, 0x0e, 0x08, 0x0c, 0x64, 0xb0, 0x58, 0x24, 0xc5, 0xa2, 0x4b, 0x25, 0x01, 0xd5, 0xae, 0xaf, 0x08, 0xaf, 0x38, 0x72, 0xee, 0x86, 0x0a, 0xa8, 0x0b, 0xdc, 0xd4, 0x30, 0xf7, 0xb6, 0x34, 0x94}, {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x51, 0x73, 0x76, 0x5d, 0xc2, 0x02, 0xcf, 0x02, 0x9a, 0xd3, 0xf1, 0x54, 0x79, 0x73, 0x5d, 0x57, 0x69, 0x7a, 0xf1, 0x2b, 0x01, 0x31, 0xdd, 0x21, 0x43, 0x0d, 0x57, 0x72, 0xe4, 0xef, 0x11, 0x47, 0x4d, 0x58, 0xb9}, {0x12, 0xa5, 0x0f, 0x3f, 0xaf, 0xea, 0x7c, 0x1e, 0xea, 0xda, 0x4c, 0xf8, 0xd3, 0x37, 0x77, 0x70, 0x4b, 0x77, 0x36, 0x14, 0x53, 0xaf, 0xc8, 0x3b, 0xda, 0x91, 0xee, 0xf3, 0x49, 0xae, 0x04, 0x4d, 0x20, 0x12, 0x6c, 0x62, 0x00, 0x54, 0x7e, 0xa5, 0xa6, 0x91, 0x17, 0x76, 0xc0, 0x5d, 0xee, 0x2a, 0x7f, 0x1a, 0x9b, 0xa7, 0xdf, 0xba, 0xbb, 0xbd, 0x27, 0x3c, 0x3e, 0xf2, 0x9e, 0xf4, 0x6e, 0x46}, 1, {0xe2, 0x54, 0x61, 0xfb, 0x0e, 0x4c, 0x16, 0x2e, 0x18, 0x12, 0x3e, 0xcd, 0xe8, 0x83, 0x42, 0xd5, 0x4d, 0x44, 0x96, 0x31, 0xe9, 0xb7, 0x5a, 0x26, 0x6f, 0xd9, 0x26, 0x0c, 0x2b, 0xb2, 0xf4, 0x1d}},
|
||||
};
|
||||
|
||||
/** This is a hasher for ellswift_xdh which just returns the shared X coordinate.
|
||||
*
|
||||
* This is generally a bad idea as it means changes to the encoding of the
|
||||
* exchanged public keys do not affect the shared secret. However, it's used here
|
||||
* in tests to be able to verify the X coordinate through other means.
|
||||
*/
|
||||
static int ellswift_xdh_hash_x32(unsigned char *output, const unsigned char *x32, const unsigned char *ell_a64, const unsigned char *ell_b64, void *data) {
|
||||
(void)ell_a64;
|
||||
(void)ell_b64;
|
||||
(void)data;
|
||||
memcpy(output, x32, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void run_ellswift_tests(void) {
|
||||
int i = 0;
|
||||
/* Test vectors. */
|
||||
for (i = 0; (unsigned)i < sizeof(ellswift_xswiftec_inv_tests) / sizeof(ellswift_xswiftec_inv_tests[0]); ++i) {
|
||||
const struct ellswift_xswiftec_inv_test *testcase = &ellswift_xswiftec_inv_tests[i];
|
||||
int c;
|
||||
for (c = 0; c < 8; ++c) {
|
||||
secp256k1_fe t;
|
||||
int ret = secp256k1_ellswift_xswiftec_inv_var(&t, &testcase->x, &testcase->u, c);
|
||||
CHECK(ret == ((testcase->enc_bitmap >> c) & 1));
|
||||
if (ret) {
|
||||
secp256k1_fe x2;
|
||||
CHECK(check_fe_equal(&t, &testcase->encs[c]));
|
||||
secp256k1_ellswift_xswiftec_var(&x2, &testcase->u, &testcase->encs[c]);
|
||||
CHECK(check_fe_equal(&testcase->x, &x2));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; (unsigned)i < sizeof(ellswift_decode_tests) / sizeof(ellswift_decode_tests[0]); ++i) {
|
||||
const struct ellswift_decode_test *testcase = &ellswift_decode_tests[i];
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ge ge;
|
||||
int ret;
|
||||
ret = secp256k1_ellswift_decode(CTX, &pubkey, testcase->enc);
|
||||
CHECK(ret);
|
||||
ret = secp256k1_pubkey_load(CTX, &ge, &pubkey);
|
||||
CHECK(ret);
|
||||
CHECK(check_fe_equal(&testcase->x, &ge.x));
|
||||
CHECK(secp256k1_fe_is_odd(&ge.y) == testcase->odd_y);
|
||||
}
|
||||
for (i = 0; (unsigned)i < sizeof(ellswift_xdh_tests_bip324) / sizeof(ellswift_xdh_tests_bip324[0]); ++i) {
|
||||
const struct ellswift_xdh_test *test = &ellswift_xdh_tests_bip324[i];
|
||||
unsigned char shared_secret[32];
|
||||
int ret;
|
||||
int party = !test->initiating;
|
||||
const unsigned char* ell_a64 = party ? test->ellswift_theirs : test->ellswift_ours;
|
||||
const unsigned char* ell_b64 = party ? test->ellswift_ours : test->ellswift_theirs;
|
||||
ret = secp256k1_ellswift_xdh(CTX, shared_secret,
|
||||
ell_a64, ell_b64,
|
||||
test->priv_ours,
|
||||
party,
|
||||
secp256k1_ellswift_xdh_hash_function_bip324,
|
||||
NULL);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(shared_secret, test->shared_secret, 32) == 0);
|
||||
}
|
||||
/* Verify that secp256k1_ellswift_encode + decode roundtrips. */
|
||||
for (i = 0; i < 1000 * COUNT; i++) {
|
||||
unsigned char rnd32[32];
|
||||
unsigned char ell64[64];
|
||||
secp256k1_ge g, g2;
|
||||
secp256k1_pubkey pubkey, pubkey2;
|
||||
/* Generate random public key and random randomizer. */
|
||||
random_group_element_test(&g);
|
||||
secp256k1_pubkey_save(&pubkey, &g);
|
||||
secp256k1_testrand256(rnd32);
|
||||
/* Convert the public key to ElligatorSwift and back. */
|
||||
secp256k1_ellswift_encode(CTX, ell64, &pubkey, rnd32);
|
||||
secp256k1_ellswift_decode(CTX, &pubkey2, ell64);
|
||||
secp256k1_pubkey_load(CTX, &g2, &pubkey2);
|
||||
/* Compare with original. */
|
||||
CHECK(secp256k1_ge_eq_var(&g, &g2));
|
||||
}
|
||||
/* Verify the behavior of secp256k1_ellswift_create */
|
||||
for (i = 0; i < 400 * COUNT; i++) {
|
||||
unsigned char auxrnd32[32], sec32[32];
|
||||
secp256k1_scalar sec;
|
||||
secp256k1_gej res;
|
||||
secp256k1_ge dec;
|
||||
secp256k1_pubkey pub;
|
||||
unsigned char ell64[64];
|
||||
int ret;
|
||||
/* Generate random secret key and random randomizer. */
|
||||
if (i & 1) secp256k1_testrand256_test(auxrnd32);
|
||||
random_scalar_order_test(&sec);
|
||||
secp256k1_scalar_get_b32(sec32, &sec);
|
||||
/* Construct ElligatorSwift-encoded public keys for that key. */
|
||||
ret = secp256k1_ellswift_create(CTX, ell64, sec32, (i & 1) ? auxrnd32 : NULL);
|
||||
CHECK(ret);
|
||||
/* Decode it, and compare with traditionally-computed public key. */
|
||||
secp256k1_ellswift_decode(CTX, &pub, ell64);
|
||||
secp256k1_pubkey_load(CTX, &dec, &pub);
|
||||
secp256k1_ecmult(&res, NULL, &secp256k1_scalar_zero, &sec);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&res, &dec));
|
||||
}
|
||||
/* Verify that secp256k1_ellswift_xdh computes the right shared X coordinate. */
|
||||
for (i = 0; i < 800 * COUNT; i++) {
|
||||
unsigned char ell64[64], sec32[32], share32[32];
|
||||
secp256k1_scalar sec;
|
||||
secp256k1_ge dec, res;
|
||||
secp256k1_fe share_x;
|
||||
secp256k1_gej decj, resj;
|
||||
secp256k1_pubkey pub;
|
||||
int ret;
|
||||
/* Generate random secret key. */
|
||||
random_scalar_order_test(&sec);
|
||||
secp256k1_scalar_get_b32(sec32, &sec);
|
||||
/* Generate random ElligatorSwift encoding for the remote key and decode it. */
|
||||
secp256k1_testrand256_test(ell64);
|
||||
secp256k1_testrand256_test(ell64 + 32);
|
||||
secp256k1_ellswift_decode(CTX, &pub, ell64);
|
||||
secp256k1_pubkey_load(CTX, &dec, &pub);
|
||||
secp256k1_gej_set_ge(&decj, &dec);
|
||||
/* Compute the X coordinate of seckey*pubkey using ellswift_xdh. Note that we
|
||||
* pass ell64 as claimed (but incorrect) encoding for sec32 here; this works
|
||||
* because the "hasher" function we use here ignores the ell64 arguments. */
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32, ell64, ell64, sec32, i & 1, &ellswift_xdh_hash_x32, NULL);
|
||||
CHECK(ret);
|
||||
(void)secp256k1_fe_set_b32_limit(&share_x, share32); /* no overflow is possible */
|
||||
SECP256K1_FE_VERIFY(&share_x);
|
||||
/* Compute seckey*pubkey directly. */
|
||||
secp256k1_ecmult(&resj, &decj, &sec, NULL);
|
||||
secp256k1_ge_set_gej(&res, &resj);
|
||||
/* Compare. */
|
||||
CHECK(check_fe_equal(&res.x, &share_x));
|
||||
}
|
||||
/* Verify the joint behavior of secp256k1_ellswift_xdh */
|
||||
for (i = 0; i < 200 * COUNT; i++) {
|
||||
unsigned char auxrnd32a[32], auxrnd32b[32], auxrnd32a_bad[32], auxrnd32b_bad[32];
|
||||
unsigned char sec32a[32], sec32b[32], sec32a_bad[32], sec32b_bad[32];
|
||||
secp256k1_scalar seca, secb;
|
||||
unsigned char ell64a[64], ell64b[64], ell64a_bad[64], ell64b_bad[64];
|
||||
unsigned char share32a[32], share32b[32], share32_bad[32];
|
||||
unsigned char prefix64[64];
|
||||
secp256k1_ellswift_xdh_hash_function hash_function;
|
||||
void* data;
|
||||
int ret;
|
||||
|
||||
/* Pick hasher to use. */
|
||||
if ((i % 3) == 0) {
|
||||
hash_function = ellswift_xdh_hash_x32;
|
||||
data = NULL;
|
||||
} else if ((i % 3) == 1) {
|
||||
hash_function = secp256k1_ellswift_xdh_hash_function_bip324;
|
||||
data = NULL;
|
||||
} else {
|
||||
hash_function = secp256k1_ellswift_xdh_hash_function_prefix;
|
||||
secp256k1_testrand256_test(prefix64);
|
||||
secp256k1_testrand256_test(prefix64 + 32);
|
||||
data = prefix64;
|
||||
}
|
||||
|
||||
/* Generate random secret keys and random randomizers. */
|
||||
secp256k1_testrand256_test(auxrnd32a);
|
||||
secp256k1_testrand256_test(auxrnd32b);
|
||||
random_scalar_order_test(&seca);
|
||||
/* Draw secb uniformly at random to make sure that the secret keys
|
||||
* differ */
|
||||
random_scalar_order(&secb);
|
||||
secp256k1_scalar_get_b32(sec32a, &seca);
|
||||
secp256k1_scalar_get_b32(sec32b, &secb);
|
||||
|
||||
/* Construct ElligatorSwift-encoded public keys for those keys. */
|
||||
/* For A: */
|
||||
ret = secp256k1_ellswift_create(CTX, ell64a, sec32a, auxrnd32a);
|
||||
CHECK(ret);
|
||||
/* For B: */
|
||||
ret = secp256k1_ellswift_create(CTX, ell64b, sec32b, auxrnd32b);
|
||||
CHECK(ret);
|
||||
|
||||
/* Compute the shared secret both ways and compare with each other. */
|
||||
/* For A: */
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32a, ell64a, ell64b, sec32a, 0, hash_function, data);
|
||||
CHECK(ret);
|
||||
/* For B: */
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32b, ell64a, ell64b, sec32b, 1, hash_function, data);
|
||||
CHECK(ret);
|
||||
/* And compare: */
|
||||
CHECK(secp256k1_memcmp_var(share32a, share32b, 32) == 0);
|
||||
|
||||
/* Verify that the shared secret doesn't match if other side's public key is incorrect. */
|
||||
/* For A (using a bad public key for B): */
|
||||
memcpy(ell64b_bad, ell64b, sizeof(ell64a_bad));
|
||||
secp256k1_testrand_flip(ell64b_bad, sizeof(ell64b_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data);
|
||||
CHECK(ret); /* Mismatching encodings don't get detected by secp256k1_ellswift_xdh. */
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B (using a bad public key for A): */
|
||||
memcpy(ell64a_bad, ell64a, sizeof(ell64a_bad));
|
||||
secp256k1_testrand_flip(ell64a_bad, sizeof(ell64a_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
|
||||
/* Verify that the shared secret doesn't match if the private key is incorrect. */
|
||||
/* For A: */
|
||||
memcpy(sec32a_bad, sec32a, sizeof(sec32a_bad));
|
||||
secp256k1_testrand_flip(sec32a_bad, sizeof(sec32a_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a_bad, 0, hash_function, data);
|
||||
CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B: */
|
||||
memcpy(sec32b_bad, sec32b, sizeof(sec32b_bad));
|
||||
secp256k1_testrand_flip(sec32b_bad, sizeof(sec32b_bad));
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b_bad, 1, hash_function, data);
|
||||
CHECK(!ret || secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
|
||||
if (hash_function != ellswift_xdh_hash_x32) {
|
||||
/* Verify that the shared secret doesn't match when a different encoding of the same public key is used. */
|
||||
/* For A (changing B's public key): */
|
||||
memcpy(auxrnd32b_bad, auxrnd32b, sizeof(auxrnd32b_bad));
|
||||
secp256k1_testrand_flip(auxrnd32b_bad, sizeof(auxrnd32b_bad));
|
||||
ret = secp256k1_ellswift_create(CTX, ell64b_bad, sec32b, auxrnd32b_bad);
|
||||
CHECK(ret);
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b_bad, sec32a, 0, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B (changing A's public key): */
|
||||
memcpy(auxrnd32a_bad, auxrnd32a, sizeof(auxrnd32a_bad));
|
||||
secp256k1_testrand_flip(auxrnd32a_bad, sizeof(auxrnd32a_bad));
|
||||
ret = secp256k1_ellswift_create(CTX, ell64a_bad, sec32a, auxrnd32a_bad);
|
||||
CHECK(ret);
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a_bad, ell64b, sec32b, 1, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
|
||||
/* Verify that swapping sides changes the shared secret. */
|
||||
/* For A (claiming to be B): */
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32a, 1, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32a, 32) != 0);
|
||||
/* For B (claiming to be A): */
|
||||
ret = secp256k1_ellswift_xdh(CTX, share32_bad, ell64a, ell64b, sec32b, 0, hash_function, data);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_memcmp_var(share32_bad, share32b, 32) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test hash initializers. */
|
||||
{
|
||||
secp256k1_sha256 sha, sha_optimized;
|
||||
static const unsigned char encode_tag[25] = "secp256k1_ellswift_encode";
|
||||
static const unsigned char create_tag[25] = "secp256k1_ellswift_create";
|
||||
static const unsigned char bip324_tag[26] = "bip324_ellswift_xonly_ecdh";
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_encode has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, encode_tag, sizeof(encode_tag));
|
||||
secp256k1_ellswift_sha256_init_encode(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_create has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, create_tag, sizeof(create_tag));
|
||||
secp256k1_ellswift_sha256_init_create(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_ellswift_sha256_init_bip324 has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, bip324_tag, sizeof(bip324_tag));
|
||||
secp256k1_ellswift_sha256_init_bip324(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -48,7 +48,7 @@ static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp25
|
||||
|
||||
/* Compare the xonly_pubkey bytes against the precomputed group. */
|
||||
secp256k1_fe_set_b32_mod(&fe, xonly_pubkey_bytes[i - 1]);
|
||||
CHECK(secp256k1_fe_equal_var(&fe, &group[i].x));
|
||||
CHECK(secp256k1_fe_equal(&fe, &group[i].x));
|
||||
|
||||
/* Check the parity against the precomputed group. */
|
||||
fe = group[i].y;
|
||||
|
||||
@@ -9,11 +9,6 @@
|
||||
|
||||
#include "../../../include/secp256k1_extrakeys.h"
|
||||
|
||||
static void set_counting_callbacks(secp256k1_context *ctx0, int *ecount) {
|
||||
secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount);
|
||||
secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount);
|
||||
}
|
||||
|
||||
static void test_xonly_pubkey(void) {
|
||||
secp256k1_pubkey pk;
|
||||
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
|
||||
@@ -28,10 +23,6 @@ static void test_xonly_pubkey(void) {
|
||||
int pk_parity;
|
||||
int i;
|
||||
|
||||
int ecount;
|
||||
|
||||
set_counting_callbacks(CTX, &ecount);
|
||||
|
||||
secp256k1_testrand256(sk);
|
||||
memset(ones32, 0xFF, 32);
|
||||
secp256k1_testrand256(xy_sk);
|
||||
@@ -39,16 +30,12 @@ static void test_xonly_pubkey(void) {
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
|
||||
/* Test xonly_pubkey_from_pubkey */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, NULL, &pk_parity, &pk));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, NULL));
|
||||
memset(&pk, 0, sizeof(pk));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, &pk_parity, &pk));
|
||||
|
||||
/* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */
|
||||
memset(sk, 0, sizeof(sk));
|
||||
@@ -72,28 +59,21 @@ static void test_xonly_pubkey(void) {
|
||||
CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1);
|
||||
|
||||
/* Test xonly_pubkey_serialize and xonly_pubkey_parse */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL) == 0);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, NULL, &xonly_pk));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, NULL));
|
||||
CHECK(secp256k1_memcmp_var(buf32, zeros64, 32) == 0);
|
||||
CHECK(ecount == 2);
|
||||
{
|
||||
/* A pubkey filled with 0s will fail to serialize due to pubkey_load
|
||||
* special casing. */
|
||||
secp256k1_xonly_pubkey pk_tmp;
|
||||
memset(&pk_tmp, 0, sizeof(pk_tmp));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp) == 0);
|
||||
/* pubkey_load calls illegal callback */
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_serialize(CTX, buf32, &pk_tmp));
|
||||
}
|
||||
/* pubkey_load called illegal callback */
|
||||
CHECK(ecount == 3);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &xonly_pk) == 1);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, NULL, buf32) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, NULL, buf32));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, NULL));
|
||||
|
||||
/* Serialization and parse roundtrip */
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &xonly_pk, NULL, &pk) == 1);
|
||||
@@ -125,7 +105,6 @@ static void test_xonly_pubkey(void) {
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &xonly_pk, &rand33[1]) == 1);
|
||||
}
|
||||
}
|
||||
CHECK(ecount == 2);
|
||||
}
|
||||
|
||||
static void test_xonly_pubkey_comparison(void) {
|
||||
@@ -139,29 +118,26 @@ static void test_xonly_pubkey_comparison(void) {
|
||||
};
|
||||
secp256k1_xonly_pubkey pk1;
|
||||
secp256k1_xonly_pubkey pk2;
|
||||
int ecount = 0;
|
||||
|
||||
set_counting_callbacks(CTX, &ecount);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk1, pk1_ser) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_parse(CTX, &pk2, pk2_ser) == 1);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, NULL, &pk2) < 0));
|
||||
CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, NULL) > 0));
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk2) == 0);
|
||||
CHECK(ecount == 2);
|
||||
memset(&pk1, 0, sizeof(pk1)); /* illegal pubkey */
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk2) < 0));
|
||||
{
|
||||
int32_t ecount = 0;
|
||||
secp256k1_context_set_illegal_callback(CTX, counting_callback_fn, &ecount);
|
||||
CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk1, &pk1) == 0);
|
||||
CHECK(ecount == 2);
|
||||
secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
|
||||
}
|
||||
CHECK_ILLEGAL_VOID(CTX, CHECK(secp256k1_xonly_pubkey_cmp(CTX, &pk2, &pk1) > 0));
|
||||
}
|
||||
|
||||
static void test_xonly_pubkey_tweak(void) {
|
||||
@@ -175,30 +151,20 @@ static void test_xonly_pubkey_tweak(void) {
|
||||
unsigned char tweak[32];
|
||||
int i;
|
||||
|
||||
int ecount;
|
||||
|
||||
set_counting_callbacks(CTX, &ecount);
|
||||
|
||||
memset(overflows, 0xff, sizeof(overflows));
|
||||
secp256k1_testrand256(tweak);
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, NULL, &internal_xonly_pk, tweak));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, NULL, tweak));
|
||||
/* NULL internal_xonly_pk zeroes the output_pk */
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, NULL));
|
||||
/* NULL tweak zeroes the output_pk */
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
|
||||
@@ -225,9 +191,7 @@ static void test_xonly_pubkey_tweak(void) {
|
||||
/* Invalid pk with a valid tweak */
|
||||
memset(&internal_xonly_pk, 0, sizeof(internal_xonly_pk));
|
||||
secp256k1_testrand256(tweak);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak));
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
}
|
||||
|
||||
@@ -244,34 +208,23 @@ static void test_xonly_pubkey_tweak_check(void) {
|
||||
int pk_parity;
|
||||
unsigned char tweak[32];
|
||||
|
||||
int ecount;
|
||||
|
||||
set_counting_callbacks(CTX, &ecount);
|
||||
|
||||
memset(overflows, 0xff, sizeof(overflows));
|
||||
secp256k1_testrand256(tweak);
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &internal_pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &output_xonly_pk, &pk_parity, &output_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(CTX, buf32, &output_xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, NULL, pk_parity, &internal_xonly_pk, tweak));
|
||||
/* invalid pk_parity value */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, 2, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, NULL, tweak));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_xonly_pubkey_tweak_add_check(CTX, buf32, pk_parity, &internal_xonly_pk, NULL));
|
||||
|
||||
memset(tweak, 1, sizeof(tweak));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(CTX, &internal_xonly_pk, NULL, &internal_pk) == 1);
|
||||
@@ -290,7 +243,6 @@ static void test_xonly_pubkey_tweak_check(void) {
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(CTX, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(CTX, &output_pk, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
CHECK(ecount == 3);
|
||||
}
|
||||
|
||||
/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1
|
||||
@@ -335,33 +287,22 @@ static void test_keypair(void) {
|
||||
secp256k1_pubkey pk, pk_tmp;
|
||||
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
|
||||
int pk_parity, pk_parity_tmp;
|
||||
int ecount;
|
||||
|
||||
set_counting_callbacks(CTX, &ecount);
|
||||
set_counting_callbacks(STATIC_CTX, &ecount);
|
||||
|
||||
CHECK(sizeof(zeros96) == sizeof(keypair));
|
||||
memset(overflows, 0xFF, sizeof(overflows));
|
||||
|
||||
/* Test keypair_create */
|
||||
ecount = 0;
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) != 0);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_keypair_create(CTX, NULL, sk) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, NULL) == 0);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, NULL, sk));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_create(CTX, &keypair, NULL));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_keypair_create(STATIC_CTX, &keypair, sk) == 0);
|
||||
CHECK_ILLEGAL(STATIC_CTX, secp256k1_keypair_create(STATIC_CTX, &keypair, sk));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/* Invalid secret key */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, zeros96) == 0);
|
||||
@@ -370,14 +311,11 @@ static void test_keypair(void) {
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
|
||||
/* Test keypair_pub */
|
||||
ecount = 0;
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_pub(CTX, &pk, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_pub(CTX, NULL, &keypair) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_pub(CTX, &pk, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, NULL, &keypair));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_pub(CTX, &pk, NULL));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
|
||||
|
||||
/* Using an invalid keypair is fine for keypair_pub */
|
||||
@@ -392,23 +330,19 @@ static void test_keypair(void) {
|
||||
CHECK(secp256k1_memcmp_var(&pk, &pk_tmp, sizeof(pk)) == 0);
|
||||
|
||||
/** Test keypair_xonly_pub **/
|
||||
ecount = 0;
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, NULL, &pk_parity, &keypair));
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, NULL, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, NULL));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
|
||||
/* Using an invalid keypair will set the xonly_pk to 0 (first reset
|
||||
* xonly_pk). */
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 1);
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
CHECK(secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair) == 0);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_pub(CTX, &xonly_pk, &pk_parity, &keypair));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &xonly_pk, sizeof(xonly_pk)) == 0);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/** keypair holds the same xonly pubkey as pubkey_create **/
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pk, sk) == 1);
|
||||
@@ -419,14 +353,11 @@ static void test_keypair(void) {
|
||||
CHECK(pk_parity == pk_parity_tmp);
|
||||
|
||||
/* Test keypair_seckey */
|
||||
ecount = 0;
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_sec(CTX, NULL, &keypair) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_sec(CTX, sk_tmp, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, NULL, &keypair));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_sec(CTX, sk_tmp, NULL));
|
||||
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
|
||||
|
||||
/* keypair returns the same seckey it got */
|
||||
@@ -439,9 +370,6 @@ static void test_keypair(void) {
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
CHECK(secp256k1_keypair_sec(CTX, sk_tmp, &keypair) == 1);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, sk_tmp, sizeof(sk_tmp)) == 0);
|
||||
|
||||
secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
|
||||
secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
|
||||
}
|
||||
|
||||
static void test_keypair_add(void) {
|
||||
@@ -451,9 +379,6 @@ static void test_keypair_add(void) {
|
||||
unsigned char zeros96[96] = { 0 };
|
||||
unsigned char tweak[32];
|
||||
int i;
|
||||
int ecount = 0;
|
||||
|
||||
set_counting_callbacks(CTX, &ecount);
|
||||
|
||||
CHECK(sizeof(zeros96) == sizeof(keypair));
|
||||
secp256k1_testrand256(sk);
|
||||
@@ -462,14 +387,10 @@ static void test_keypair_add(void) {
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, NULL, tweak));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, NULL));
|
||||
/* This does not set the keypair to zeroes */
|
||||
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0);
|
||||
|
||||
@@ -503,20 +424,16 @@ static void test_keypair_add(void) {
|
||||
/* Invalid keypair with a valid tweak */
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
secp256k1_testrand256(tweak);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak));
|
||||
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
|
||||
/* Only seckey part of keypair invalid */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
memset(&keypair, 0, 32);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak));
|
||||
/* Only pubkey part of keypair invalid */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
memset(&keypair.data[32], 0, 64);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_keypair_xonly_tweak_add(CTX, &keypair, tweak));
|
||||
|
||||
/* Check that the keypair_tweak_add implementation is correct */
|
||||
CHECK(secp256k1_keypair_create(CTX, &keypair, sk) == 1);
|
||||
|
||||
@@ -36,7 +36,6 @@ static void test_ecdsa_recovery_api(void) {
|
||||
secp256k1_ecdsa_recoverable_signature recsig;
|
||||
unsigned char privkey[32] = { 1 };
|
||||
unsigned char message[32] = { 2 };
|
||||
int32_t ecount = 0;
|
||||
int recid = 0;
|
||||
unsigned char sig[74];
|
||||
unsigned char zero_privkey[32] = { 0 };
|
||||
@@ -45,86 +44,52 @@ static void test_ecdsa_recovery_api(void) {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
/* Construct and verify corresponding public key. */
|
||||
CHECK(secp256k1_ec_seckey_verify(CTX, privkey) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(CTX, &pubkey, privkey) == 1);
|
||||
|
||||
/* Check bad contexts and NULLs for signing */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, NULL, message, privkey, NULL, NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, NULL, privkey, NULL, NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, NULL, NULL, NULL));
|
||||
CHECK_ILLEGAL(STATIC_CTX, secp256k1_ecdsa_sign_recoverable(STATIC_CTX, &recsig, message, privkey, NULL, NULL));
|
||||
/* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */
|
||||
secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, recovery_test_nonce_function, NULL);
|
||||
CHECK(ecount == 4);
|
||||
/* These will all fail, but not in ARG_CHECK way */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, zero_privkey, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, over_privkey, NULL, NULL) == 0);
|
||||
/* This one will succeed. */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
CHECK(ecount == 4);
|
||||
|
||||
/* Check signing with a goofy nonce function */
|
||||
|
||||
/* Check bad contexts and NULLs for recovery */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, message) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, NULL, &recsig, message) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, NULL, &recsig, message));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, NULL, message));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recover(CTX, &recpubkey, &recsig, NULL));
|
||||
|
||||
/* Check NULLs for conversion */
|
||||
CHECK(secp256k1_ecdsa_sign(CTX, &normal_sig, message, privkey, NULL, NULL) == 1);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, NULL, &recsig));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, NULL));
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(CTX, &normal_sig, &recsig) == 1);
|
||||
|
||||
/* Check NULLs for de/serialization */
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(CTX, &recsig, message, privkey, NULL, NULL) == 1);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, NULL, &recid, &recsig));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, NULL, &recsig));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, NULL));
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(CTX, sig, &recid, &recsig) == 1);
|
||||
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5) == 0);
|
||||
CHECK(ecount == 7);
|
||||
/* overflow in signature will fail but not affect ecount */
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, NULL, sig, recid));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, NULL, recid));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, -1));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, 5));
|
||||
/* overflow in signature will not result in calling illegal_callback */
|
||||
memcpy(sig, over_privkey, 32);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(CTX, &recsig, sig, recid) == 0);
|
||||
CHECK(ecount == 7);
|
||||
|
||||
/* cleanup */
|
||||
secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
|
||||
secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
|
||||
}
|
||||
|
||||
static void test_ecdsa_recovery_end_to_end(void) {
|
||||
|
||||
@@ -261,7 +261,7 @@ int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned cha
|
||||
|
||||
secp256k1_fe_normalize_var(&r.y);
|
||||
return !secp256k1_fe_is_odd(&r.y) &&
|
||||
secp256k1_fe_equal_var(&rx, &r.x);
|
||||
secp256k1_fe_equal(&rx, &r.x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -110,15 +110,15 @@ static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, cons
|
||||
if (!e_done[e]) {
|
||||
/* Iterate over the possible valid last 32 bytes in the signature.
|
||||
0..order=that s value; order+1=random bytes */
|
||||
int count_valid = 0, s;
|
||||
int count_valid = 0;
|
||||
unsigned int s;
|
||||
for (s = 0; s <= EXHAUSTIVE_TEST_ORDER + 1; ++s) {
|
||||
int expect_valid, valid;
|
||||
if (s <= EXHAUSTIVE_TEST_ORDER) {
|
||||
secp256k1_scalar s_s;
|
||||
secp256k1_scalar_set_int(&s_s, s);
|
||||
secp256k1_scalar_get_b32(sig64 + 32, &s_s);
|
||||
memset(sig64 + 32, 0, 32);
|
||||
secp256k1_write_be32(sig64 + 60, s);
|
||||
expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER &&
|
||||
(s_s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER);
|
||||
(s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER);
|
||||
} else {
|
||||
secp256k1_testrand256(sig64 + 32);
|
||||
expect_valid = 0;
|
||||
|
||||
@@ -20,17 +20,6 @@ static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, s
|
||||
CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0);
|
||||
}
|
||||
|
||||
/* Tests for the equality of two sha256 structs. This function only produces a
|
||||
* correct result if an integer multiple of 64 many bytes have been written
|
||||
* into the hash functions. */
|
||||
static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2) {
|
||||
/* Is buffer fully consumed? */
|
||||
CHECK((sha1->bytes & 0x3F) == 0);
|
||||
|
||||
CHECK(sha1->bytes == sha2->bytes);
|
||||
CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
|
||||
}
|
||||
|
||||
static void run_nonce_function_bip340_tests(void) {
|
||||
unsigned char tag[13] = "BIP0340/nonce";
|
||||
unsigned char aux_tag[11] = "BIP0340/aux";
|
||||
@@ -127,14 +116,6 @@ static void test_schnorrsig_api(void) {
|
||||
secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
|
||||
secp256k1_schnorrsig_extraparams invalid_extraparams = {{ 0 }, NULL, NULL};
|
||||
|
||||
/** setup **/
|
||||
int ecount = 0;
|
||||
|
||||
secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(STATIC_CTX, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
secp256k1_testrand256(sk1);
|
||||
secp256k1_testrand256(sk2);
|
||||
secp256k1_testrand256(sk3);
|
||||
@@ -148,57 +129,30 @@ static void test_schnorrsig_api(void) {
|
||||
memset(&zero_pk, 0, sizeof(zero_pk));
|
||||
|
||||
/** main test body **/
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, NULL, msg, &keypairs[0], NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, NULL, &keypairs[0], NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, NULL, NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign32(CTX, sig, msg, &invalid_keypair, NULL));
|
||||
CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign32(STATIC_CTX, sig, msg, &keypairs[0], NULL));
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, NULL, msg, sizeof(msg), &keypairs[0], &extraparams));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, sizeof(msg), &keypairs[0], &extraparams));
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, NULL, 0, &keypairs[0], &extraparams) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), NULL, &extraparams));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &invalid_keypair, &extraparams));
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], NULL) == 1);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_sign_custom(CTX, sig, msg, sizeof(msg), &keypairs[0], &invalid_extraparams));
|
||||
CHECK_ILLEGAL(STATIC_CTX, secp256k1_schnorrsig_sign_custom(STATIC_CTX, sig, msg, sizeof(msg), &keypairs[0], &extraparams));
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_schnorrsig_sign32(CTX, sig, msg, &keypairs[0], NULL) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &pk[0]) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0]) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0]) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, NULL, msg, sizeof(msg), &pk[0]));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, NULL, sizeof(msg), &pk[0]));
|
||||
CHECK(secp256k1_schnorrsig_verify(CTX, sig, NULL, 0, &pk[0]) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk) == 0);
|
||||
CHECK(ecount == 4);
|
||||
|
||||
secp256k1_context_set_error_callback(STATIC_CTX, NULL, NULL);
|
||||
secp256k1_context_set_illegal_callback(STATIC_CTX, NULL, NULL);
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), NULL));
|
||||
CHECK_ILLEGAL(CTX, secp256k1_schnorrsig_verify(CTX, sig, msg, sizeof(msg), &zero_pk));
|
||||
}
|
||||
|
||||
/* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the
|
||||
|
||||
@@ -56,11 +56,12 @@ static void print_two_tables(FILE *fp, int window_g) {
|
||||
int main(void) {
|
||||
/* Always compute all tables for window sizes up to 15. */
|
||||
int window_g = (ECMULT_WINDOW_SIZE < 15) ? 15 : ECMULT_WINDOW_SIZE;
|
||||
const char outfile[] = "src/precomputed_ecmult.c";
|
||||
FILE* fp;
|
||||
|
||||
fp = fopen("src/precomputed_ecmult.c","w");
|
||||
fp = fopen(outfile, "w");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Could not open src/precomputed_ecmult.h for writing!\n");
|
||||
fprintf(stderr, "Could not open %s for writing!\n", outfile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -68,7 +69,6 @@ int main(void) {
|
||||
fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n");
|
||||
fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n");
|
||||
fprintf(fp, " */\n");
|
||||
fprintf(fp, "#include \"../include/secp256k1.h\"\n");
|
||||
fprintf(fp, "#include \"group.h\"\n");
|
||||
fprintf(fp, "#include \"ecmult.h\"\n");
|
||||
fprintf(fp, "#include \"precomputed_ecmult.h\"\n");
|
||||
|
||||
@@ -33,7 +33,6 @@ int main(int argc, char **argv) {
|
||||
|
||||
fprintf(fp, "/* This file was automatically generated by precompute_ecmult_gen. */\n");
|
||||
fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n");
|
||||
fprintf(fp, "#include \"../include/secp256k1.h\"\n");
|
||||
fprintf(fp, "#include \"group.h\"\n");
|
||||
fprintf(fp, "#include \"ecmult_gen.h\"\n");
|
||||
fprintf(fp, "#include \"precomputed_ecmult_gen.h\"\n");
|
||||
|
||||
1
src/precomputed_ecmult.c
generated
1
src/precomputed_ecmult.c
generated
@@ -2,7 +2,6 @@
|
||||
/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and
|
||||
* an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.
|
||||
*/
|
||||
#include "../include/secp256k1.h"
|
||||
#include "group.h"
|
||||
#include "ecmult.h"
|
||||
#include "precomputed_ecmult.h"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ecmult.h"
|
||||
#include "group.h"
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
# if EXHAUSTIVE_TEST_ORDER == 7
|
||||
|
||||
1
src/precomputed_ecmult_gen.c
generated
1
src/precomputed_ecmult_gen.c
generated
@@ -1,6 +1,5 @@
|
||||
/* This file was automatically generated by precompute_ecmult_gen. */
|
||||
/* See ecmult_gen_impl.h for details about the contents of this file. */
|
||||
#include "../include/secp256k1.h"
|
||||
#include "group.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "precomputed_ecmult_gen.h"
|
||||
|
||||
13
src/scalar.h
13
src/scalar.h
@@ -25,7 +25,7 @@ static void secp256k1_scalar_clear(secp256k1_scalar *r);
|
||||
/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */
|
||||
static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count);
|
||||
|
||||
/** Access bits from a scalar. Not constant time. */
|
||||
/** Access bits from a scalar. Not constant time in offset and count. */
|
||||
static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count);
|
||||
|
||||
/** Set a scalar from a big endian byte array. The scalar will be reduced modulo group order `n`.
|
||||
@@ -54,10 +54,6 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int
|
||||
/** Multiply two scalars (modulo the group order). */
|
||||
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b);
|
||||
|
||||
/** Shift a scalar right by some amount strictly between 0 and 16, returning
|
||||
* the low bits that were shifted off */
|
||||
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n);
|
||||
|
||||
/** Compute the inverse of a scalar (modulo the group order). */
|
||||
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a);
|
||||
|
||||
@@ -67,6 +63,9 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc
|
||||
/** Compute the complement of a scalar (modulo the group order). */
|
||||
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a);
|
||||
|
||||
/** Multiply a scalar with the multiplicative inverse of 2. */
|
||||
static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a);
|
||||
|
||||
/** Check whether a scalar equals zero. */
|
||||
static int secp256k1_scalar_is_zero(const secp256k1_scalar *a);
|
||||
|
||||
@@ -99,4 +98,8 @@ static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
|
||||
static void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag);
|
||||
|
||||
/** Check invariants on a scalar (no-op unless VERIFY is enabled). */
|
||||
static void secp256k1_scalar_verify(const secp256k1_scalar *r);
|
||||
#define SECP256K1_SCALAR_VERIFY(r) secp256k1_scalar_verify(r)
|
||||
|
||||
#endif /* SECP256K1_SCALAR_H */
|
||||
|
||||
@@ -41,16 +41,22 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
|
||||
r->d[1] = 0;
|
||||
r->d[2] = 0;
|
||||
r->d[3] = 0;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6);
|
||||
|
||||
return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
VERIFY_CHECK(count < 32);
|
||||
VERIFY_CHECK(offset + count <= 256);
|
||||
|
||||
if ((offset + count - 1) >> 6 == offset >> 6) {
|
||||
return secp256k1_scalar_get_bits(a, offset, count);
|
||||
} else {
|
||||
@@ -74,6 +80,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal
|
||||
SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) {
|
||||
secp256k1_uint128 t;
|
||||
VERIFY_CHECK(overflow <= 1);
|
||||
|
||||
secp256k1_u128_from_u64(&t, r->d[0]);
|
||||
secp256k1_u128_accum_u64(&t, overflow * SECP256K1_N_C_0);
|
||||
r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
|
||||
@@ -85,12 +92,17 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigne
|
||||
r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
|
||||
secp256k1_u128_accum_u64(&t, r->d[3]);
|
||||
r->d[3] = secp256k1_u128_to_u64(&t);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
return overflow;
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
int overflow;
|
||||
secp256k1_uint128 t;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
|
||||
secp256k1_u128_from_u64(&t, a->d[0]);
|
||||
secp256k1_u128_accum_u64(&t, b->d[0]);
|
||||
r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
|
||||
@@ -106,13 +118,17 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
|
||||
overflow = secp256k1_u128_to_u64(&t) + secp256k1_scalar_check_overflow(r);
|
||||
VERIFY_CHECK(overflow == 0 || overflow == 1);
|
||||
secp256k1_scalar_reduce(r, overflow);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
return overflow;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
|
||||
secp256k1_uint128 t;
|
||||
volatile int vflag = flag;
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
VERIFY_CHECK(bit < 256);
|
||||
|
||||
bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */
|
||||
secp256k1_u128_from_u64(&t, r->d[0]);
|
||||
secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F));
|
||||
@@ -126,37 +142,45 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int
|
||||
secp256k1_u128_accum_u64(&t, r->d[3]);
|
||||
secp256k1_u128_accum_u64(&t, ((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F));
|
||||
r->d[3] = secp256k1_u128_to_u64(&t);
|
||||
#ifdef VERIFY
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
VERIFY_CHECK(secp256k1_u128_hi_u64(&t) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
|
||||
int over;
|
||||
r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56;
|
||||
r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56;
|
||||
r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56;
|
||||
r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56;
|
||||
r->d[0] = secp256k1_read_be64(&b32[24]);
|
||||
r->d[1] = secp256k1_read_be64(&b32[16]);
|
||||
r->d[2] = secp256k1_read_be64(&b32[8]);
|
||||
r->d[3] = secp256k1_read_be64(&b32[0]);
|
||||
over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
|
||||
if (overflow) {
|
||||
*overflow = over;
|
||||
}
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
|
||||
bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3];
|
||||
bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2];
|
||||
bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1];
|
||||
bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
secp256k1_write_be64(&bin[0], a->d[3]);
|
||||
secp256k1_write_be64(&bin[8], a->d[2]);
|
||||
secp256k1_write_be64(&bin[16], a->d[1]);
|
||||
secp256k1_write_be64(&bin[24], a->d[0]);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0);
|
||||
secp256k1_uint128 t;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
secp256k1_u128_from_u64(&t, ~a->d[0]);
|
||||
secp256k1_u128_accum_u64(&t, SECP256K1_N_0 + 1);
|
||||
r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
|
||||
@@ -169,15 +193,62 @@ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar
|
||||
secp256k1_u128_accum_u64(&t, ~a->d[3]);
|
||||
secp256k1_u128_accum_u64(&t, SECP256K1_N_3);
|
||||
r->d[3] = secp256k1_u128_to_u64(&t) & nonzero;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
/* Writing `/` for field division and `//` for integer division, we compute
|
||||
*
|
||||
* a/2 = (a - (a&1))/2 + (a&1)/2
|
||||
* = (a >> 1) + (a&1 ? 1/2 : 0)
|
||||
* = (a >> 1) + (a&1 ? n//2+1 : 0),
|
||||
*
|
||||
* where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n).
|
||||
* For n//2, we have the constants SECP256K1_N_H_0, ...
|
||||
*
|
||||
* This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here:
|
||||
* - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2
|
||||
* - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2
|
||||
* Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n.
|
||||
*/
|
||||
uint64_t mask = -(uint64_t)(a->d[0] & 1U);
|
||||
secp256k1_uint128 t;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
secp256k1_u128_from_u64(&t, (a->d[0] >> 1) | (a->d[1] << 63));
|
||||
secp256k1_u128_accum_u64(&t, (SECP256K1_N_H_0 + 1U) & mask);
|
||||
r->d[0] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
|
||||
secp256k1_u128_accum_u64(&t, (a->d[1] >> 1) | (a->d[2] << 63));
|
||||
secp256k1_u128_accum_u64(&t, SECP256K1_N_H_1 & mask);
|
||||
r->d[1] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
|
||||
secp256k1_u128_accum_u64(&t, (a->d[2] >> 1) | (a->d[3] << 63));
|
||||
secp256k1_u128_accum_u64(&t, SECP256K1_N_H_2 & mask);
|
||||
r->d[2] = secp256k1_u128_to_u64(&t); secp256k1_u128_rshift(&t, 64);
|
||||
r->d[3] = secp256k1_u128_to_u64(&t) + (a->d[3] >> 1) + (SECP256K1_N_H_3 & mask);
|
||||
#ifdef VERIFY
|
||||
/* The line above only computed the bottom 64 bits of r->d[3]; redo the computation
|
||||
* in full 128 bits to make sure the top 64 bits are indeed zero. */
|
||||
secp256k1_u128_accum_u64(&t, a->d[3] >> 1);
|
||||
secp256k1_u128_accum_u64(&t, SECP256K1_N_H_3 & mask);
|
||||
secp256k1_u128_rshift(&t, 64);
|
||||
VERIFY_CHECK(secp256k1_u128_to_u64(&t) == 0);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0;
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
|
||||
int yes = 0;
|
||||
int no = 0;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
no |= (a->d[3] < SECP256K1_N_H_3);
|
||||
yes |= (a->d[3] > SECP256K1_N_H_3) & ~no;
|
||||
no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */
|
||||
@@ -194,6 +265,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
|
||||
uint64_t mask = -vflag;
|
||||
uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1;
|
||||
secp256k1_uint128 t;
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
|
||||
secp256k1_u128_from_u64(&t, r->d[0] ^ mask);
|
||||
secp256k1_u128_accum_u64(&t, (SECP256K1_N_0 + 1) & mask);
|
||||
r->d[0] = secp256k1_u128_to_u64(&t) & nonzero; secp256k1_u128_rshift(&t, 64);
|
||||
@@ -206,6 +279,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
|
||||
secp256k1_u128_accum_u64(&t, r->d[3] ^ mask);
|
||||
secp256k1_u128_accum_u64(&t, SECP256K1_N_3 & mask);
|
||||
r->d[3] = secp256k1_u128_to_u64(&t) & nonzero;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
return 2 * (mask == 0) - 1;
|
||||
}
|
||||
|
||||
@@ -764,23 +839,18 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, c
|
||||
|
||||
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
uint64_t l[8];
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
|
||||
secp256k1_scalar_mul_512(l, a, b);
|
||||
secp256k1_scalar_reduce_512(r, l);
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
|
||||
int ret;
|
||||
VERIFY_CHECK(n > 0);
|
||||
VERIFY_CHECK(n < 16);
|
||||
ret = r->d[0] & ((1 << n) - 1);
|
||||
r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n));
|
||||
r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n));
|
||||
r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n));
|
||||
r->d[3] = (r->d[3] >> n);
|
||||
return ret;
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) {
|
||||
SECP256K1_SCALAR_VERIFY(k);
|
||||
|
||||
r1->d[0] = k->d[0];
|
||||
r1->d[1] = k->d[1];
|
||||
r1->d[2] = 0;
|
||||
@@ -789,9 +859,15 @@ static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r
|
||||
r2->d[1] = k->d[3];
|
||||
r2->d[2] = 0;
|
||||
r2->d[3] = 0;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r1);
|
||||
SECP256K1_SCALAR_VERIFY(r2);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
|
||||
return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0;
|
||||
}
|
||||
|
||||
@@ -800,7 +876,10 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
|
||||
unsigned int shiftlimbs;
|
||||
unsigned int shiftlow;
|
||||
unsigned int shifthigh;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
VERIFY_CHECK(shift >= 256);
|
||||
|
||||
secp256k1_scalar_mul_512(l, a, b);
|
||||
shiftlimbs = shift >> 6;
|
||||
shiftlow = shift & 0x3F;
|
||||
@@ -810,18 +889,24 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
|
||||
r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0;
|
||||
r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0;
|
||||
secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
|
||||
uint64_t mask0, mask1;
|
||||
volatile int vflag = flag;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d));
|
||||
|
||||
mask0 = vflag + ~((uint64_t)0);
|
||||
mask1 = ~mask0;
|
||||
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);
|
||||
r->d[1] = (r->d[1] & mask0) | (a->d[1] & mask1);
|
||||
r->d[2] = (r->d[2] & mask0) | (a->d[2] & mask1);
|
||||
r->d[3] = (r->d[3] & mask0) | (a->d[3] & mask1);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_from_signed62(secp256k1_scalar *r, const secp256k1_modinv64_signed62 *a) {
|
||||
@@ -841,18 +926,13 @@ static void secp256k1_scalar_from_signed62(secp256k1_scalar *r, const secp256k1_
|
||||
r->d[2] = a2 >> 4 | a3 << 58;
|
||||
r->d[3] = a3 >> 6 | a4 << 56;
|
||||
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
|
||||
#endif
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_scalar *a) {
|
||||
const uint64_t M62 = UINT64_MAX >> 2;
|
||||
const uint64_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3];
|
||||
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_scalar_check_overflow(a) == 0);
|
||||
#endif
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
r->v[0] = a0 & M62;
|
||||
r->v[1] = (a0 >> 62 | a1 << 2) & M62;
|
||||
@@ -871,13 +951,14 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
|
||||
#ifdef VERIFY
|
||||
int zero_in = secp256k1_scalar_is_zero(x);
|
||||
#endif
|
||||
SECP256K1_SCALAR_VERIFY(x);
|
||||
|
||||
secp256k1_scalar_to_signed62(&s, x);
|
||||
secp256k1_modinv64(&s, &secp256k1_const_modinfo_scalar);
|
||||
secp256k1_scalar_from_signed62(r, &s);
|
||||
|
||||
#ifdef VERIFY
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
|
||||
@@ -885,16 +966,19 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc
|
||||
#ifdef VERIFY
|
||||
int zero_in = secp256k1_scalar_is_zero(x);
|
||||
#endif
|
||||
SECP256K1_SCALAR_VERIFY(x);
|
||||
|
||||
secp256k1_scalar_to_signed62(&s, x);
|
||||
secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_scalar);
|
||||
secp256k1_scalar_from_signed62(r, &s);
|
||||
|
||||
#ifdef VERIFY
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return !(a->d[0] & 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,16 +58,22 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsig
|
||||
r->d[5] = 0;
|
||||
r->d[6] = 0;
|
||||
r->d[7] = 0;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5);
|
||||
|
||||
return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
VERIFY_CHECK(count < 32);
|
||||
VERIFY_CHECK(offset + count <= 256);
|
||||
|
||||
if ((offset + count - 1) >> 5 == offset >> 5) {
|
||||
return secp256k1_scalar_get_bits(a, offset, count);
|
||||
} else {
|
||||
@@ -97,6 +103,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal
|
||||
SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) {
|
||||
uint64_t t;
|
||||
VERIFY_CHECK(overflow <= 1);
|
||||
|
||||
t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0;
|
||||
r->d[0] = t & 0xFFFFFFFFUL; t >>= 32;
|
||||
t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1;
|
||||
@@ -113,12 +120,17 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_
|
||||
r->d[6] = t & 0xFFFFFFFFUL; t >>= 32;
|
||||
t += (uint64_t)r->d[7];
|
||||
r->d[7] = t & 0xFFFFFFFFUL;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
return overflow;
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
int overflow;
|
||||
uint64_t t = (uint64_t)a->d[0] + b->d[0];
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
|
||||
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
|
||||
t += (uint64_t)a->d[1] + b->d[1];
|
||||
r->d[1] = t & 0xFFFFFFFFULL; t >>= 32;
|
||||
@@ -137,13 +149,17 @@ static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a,
|
||||
overflow = t + secp256k1_scalar_check_overflow(r);
|
||||
VERIFY_CHECK(overflow == 0 || overflow == 1);
|
||||
secp256k1_scalar_reduce(r, overflow);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
return overflow;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
|
||||
uint64_t t;
|
||||
volatile int vflag = flag;
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
VERIFY_CHECK(bit < 256);
|
||||
|
||||
bit += ((uint32_t) vflag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */
|
||||
t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F));
|
||||
r->d[0] = t & 0xFFFFFFFFULL; t >>= 32;
|
||||
@@ -161,46 +177,53 @@ static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int
|
||||
r->d[6] = t & 0xFFFFFFFFULL; t >>= 32;
|
||||
t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F));
|
||||
r->d[7] = t & 0xFFFFFFFFULL;
|
||||
#ifdef VERIFY
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
VERIFY_CHECK((t >> 32) == 0);
|
||||
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
|
||||
int over;
|
||||
r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24;
|
||||
r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24;
|
||||
r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24;
|
||||
r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24;
|
||||
r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24;
|
||||
r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24;
|
||||
r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24;
|
||||
r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24;
|
||||
r->d[0] = secp256k1_read_be32(&b32[28]);
|
||||
r->d[1] = secp256k1_read_be32(&b32[24]);
|
||||
r->d[2] = secp256k1_read_be32(&b32[20]);
|
||||
r->d[3] = secp256k1_read_be32(&b32[16]);
|
||||
r->d[4] = secp256k1_read_be32(&b32[12]);
|
||||
r->d[5] = secp256k1_read_be32(&b32[8]);
|
||||
r->d[6] = secp256k1_read_be32(&b32[4]);
|
||||
r->d[7] = secp256k1_read_be32(&b32[0]);
|
||||
over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r));
|
||||
if (overflow) {
|
||||
*overflow = over;
|
||||
}
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
|
||||
bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7];
|
||||
bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6];
|
||||
bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5];
|
||||
bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4];
|
||||
bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3];
|
||||
bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2];
|
||||
bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1];
|
||||
bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0];
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
secp256k1_write_be32(&bin[0], a->d[7]);
|
||||
secp256k1_write_be32(&bin[4], a->d[6]);
|
||||
secp256k1_write_be32(&bin[8], a->d[5]);
|
||||
secp256k1_write_be32(&bin[12], a->d[4]);
|
||||
secp256k1_write_be32(&bin[16], a->d[3]);
|
||||
secp256k1_write_be32(&bin[20], a->d[2]);
|
||||
secp256k1_write_be32(&bin[24], a->d[1]);
|
||||
secp256k1_write_be32(&bin[28], a->d[0]);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0);
|
||||
uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
r->d[0] = t & nonzero; t >>= 32;
|
||||
t += (uint64_t)(~a->d[1]) + SECP256K1_N_1;
|
||||
r->d[1] = t & nonzero; t >>= 32;
|
||||
@@ -216,15 +239,69 @@ static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar
|
||||
r->d[6] = t & nonzero; t >>= 32;
|
||||
t += (uint64_t)(~a->d[7]) + SECP256K1_N_7;
|
||||
r->d[7] = t & nonzero;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
/* Writing `/` for field division and `//` for integer division, we compute
|
||||
*
|
||||
* a/2 = (a - (a&1))/2 + (a&1)/2
|
||||
* = (a >> 1) + (a&1 ? 1/2 : 0)
|
||||
* = (a >> 1) + (a&1 ? n//2+1 : 0),
|
||||
*
|
||||
* where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n).
|
||||
* For n//2, we have the constants SECP256K1_N_H_0, ...
|
||||
*
|
||||
* This sum does not overflow. The most extreme case is a = -2, the largest odd scalar. Here:
|
||||
* - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2
|
||||
* - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2
|
||||
* Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n.
|
||||
*/
|
||||
uint32_t mask = -(uint32_t)(a->d[0] & 1U);
|
||||
uint64_t t = (uint32_t)((a->d[0] >> 1) | (a->d[1] << 31));
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
t += (SECP256K1_N_H_0 + 1U) & mask;
|
||||
r->d[0] = t; t >>= 32;
|
||||
t += (uint32_t)((a->d[1] >> 1) | (a->d[2] << 31));
|
||||
t += SECP256K1_N_H_1 & mask;
|
||||
r->d[1] = t; t >>= 32;
|
||||
t += (uint32_t)((a->d[2] >> 1) | (a->d[3] << 31));
|
||||
t += SECP256K1_N_H_2 & mask;
|
||||
r->d[2] = t; t >>= 32;
|
||||
t += (uint32_t)((a->d[3] >> 1) | (a->d[4] << 31));
|
||||
t += SECP256K1_N_H_3 & mask;
|
||||
r->d[3] = t; t >>= 32;
|
||||
t += (uint32_t)((a->d[4] >> 1) | (a->d[5] << 31));
|
||||
t += SECP256K1_N_H_4 & mask;
|
||||
r->d[4] = t; t >>= 32;
|
||||
t += (uint32_t)((a->d[5] >> 1) | (a->d[6] << 31));
|
||||
t += SECP256K1_N_H_5 & mask;
|
||||
r->d[5] = t; t >>= 32;
|
||||
t += (uint32_t)((a->d[6] >> 1) | (a->d[7] << 31));
|
||||
t += SECP256K1_N_H_6 & mask;
|
||||
r->d[6] = t; t >>= 32;
|
||||
r->d[7] = (uint32_t)t + (uint32_t)(a->d[7] >> 1) + (SECP256K1_N_H_7 & mask);
|
||||
|
||||
/* The line above only computed the bottom 32 bits of r->d[7]. Redo the computation
|
||||
* in full 64 bits to make sure the top 32 bits are indeed zero. */
|
||||
VERIFY_CHECK((t + (a->d[7] >> 1) + (SECP256K1_N_H_7 & mask)) >> 32 == 0);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0;
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
|
||||
int yes = 0;
|
||||
int no = 0;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
no |= (a->d[7] < SECP256K1_N_H_7);
|
||||
yes |= (a->d[7] > SECP256K1_N_H_7) & ~no;
|
||||
no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */
|
||||
@@ -247,6 +324,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
|
||||
uint32_t mask = -vflag;
|
||||
uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0);
|
||||
uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask);
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
|
||||
r->d[0] = t & nonzero; t >>= 32;
|
||||
t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask);
|
||||
r->d[1] = t & nonzero; t >>= 32;
|
||||
@@ -262,6 +341,8 @@ static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
|
||||
r->d[6] = t & nonzero; t >>= 32;
|
||||
t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask);
|
||||
r->d[7] = t & nonzero;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
return 2 * (mask == 0) - 1;
|
||||
}
|
||||
|
||||
@@ -569,27 +650,18 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, con
|
||||
|
||||
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
uint32_t l[16];
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
|
||||
secp256k1_scalar_mul_512(l, a, b);
|
||||
secp256k1_scalar_reduce_512(r, l);
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
|
||||
int ret;
|
||||
VERIFY_CHECK(n > 0);
|
||||
VERIFY_CHECK(n < 16);
|
||||
ret = r->d[0] & ((1 << n) - 1);
|
||||
r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n));
|
||||
r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n));
|
||||
r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n));
|
||||
r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n));
|
||||
r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n));
|
||||
r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n));
|
||||
r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n));
|
||||
r->d[7] = (r->d[7] >> n);
|
||||
return ret;
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *k) {
|
||||
SECP256K1_SCALAR_VERIFY(k);
|
||||
|
||||
r1->d[0] = k->d[0];
|
||||
r1->d[1] = k->d[1];
|
||||
r1->d[2] = k->d[2];
|
||||
@@ -606,9 +678,15 @@ static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r
|
||||
r2->d[5] = 0;
|
||||
r2->d[6] = 0;
|
||||
r2->d[7] = 0;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r1);
|
||||
SECP256K1_SCALAR_VERIFY(r2);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
|
||||
return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0;
|
||||
}
|
||||
|
||||
@@ -617,7 +695,10 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
|
||||
unsigned int shiftlimbs;
|
||||
unsigned int shiftlow;
|
||||
unsigned int shifthigh;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
VERIFY_CHECK(shift >= 256);
|
||||
|
||||
secp256k1_scalar_mul_512(l, a, b);
|
||||
shiftlimbs = shift >> 5;
|
||||
shiftlow = shift & 0x1F;
|
||||
@@ -631,12 +712,16 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
|
||||
r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0;
|
||||
r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0;
|
||||
secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
|
||||
uint32_t mask0, mask1;
|
||||
volatile int vflag = flag;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_CHECKMEM_CHECK_VERIFY(r->d, sizeof(r->d));
|
||||
|
||||
mask0 = vflag + ~((uint32_t)0);
|
||||
mask1 = ~mask0;
|
||||
r->d[0] = (r->d[0] & mask0) | (a->d[0] & mask1);
|
||||
@@ -647,6 +732,8 @@ static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const se
|
||||
r->d[5] = (r->d[5] & mask0) | (a->d[5] & mask1);
|
||||
r->d[6] = (r->d[6] & mask0) | (a->d[6] & mask1);
|
||||
r->d[7] = (r->d[7] & mask0) | (a->d[7] & mask1);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_from_signed30(secp256k1_scalar *r, const secp256k1_modinv32_signed30 *a) {
|
||||
@@ -675,19 +762,14 @@ static void secp256k1_scalar_from_signed30(secp256k1_scalar *r, const secp256k1_
|
||||
r->d[6] = a6 >> 12 | a7 << 18;
|
||||
r->d[7] = a7 >> 14 | a8 << 16;
|
||||
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
|
||||
#endif
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_scalar *a) {
|
||||
const uint32_t M30 = UINT32_MAX >> 2;
|
||||
const uint32_t a0 = a->d[0], a1 = a->d[1], a2 = a->d[2], a3 = a->d[3],
|
||||
a4 = a->d[4], a5 = a->d[5], a6 = a->d[6], a7 = a->d[7];
|
||||
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(secp256k1_scalar_check_overflow(a) == 0);
|
||||
#endif
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
r->v[0] = a0 & M30;
|
||||
r->v[1] = (a0 >> 30 | a1 << 2) & M30;
|
||||
@@ -710,13 +792,14 @@ static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar
|
||||
#ifdef VERIFY
|
||||
int zero_in = secp256k1_scalar_is_zero(x);
|
||||
#endif
|
||||
SECP256K1_SCALAR_VERIFY(x);
|
||||
|
||||
secp256k1_scalar_to_signed30(&s, x);
|
||||
secp256k1_modinv32(&s, &secp256k1_const_modinfo_scalar);
|
||||
secp256k1_scalar_from_signed30(r, &s);
|
||||
|
||||
#ifdef VERIFY
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
|
||||
@@ -724,16 +807,19 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_sc
|
||||
#ifdef VERIFY
|
||||
int zero_in = secp256k1_scalar_is_zero(x);
|
||||
#endif
|
||||
SECP256K1_SCALAR_VERIFY(x);
|
||||
|
||||
secp256k1_scalar_to_signed30(&s, x);
|
||||
secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_scalar);
|
||||
secp256k1_scalar_from_signed30(r, &s);
|
||||
|
||||
#ifdef VERIFY
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
VERIFY_CHECK(secp256k1_scalar_is_zero(r) == zero_in);
|
||||
#endif
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return !(a->d[0] & 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,17 @@ static const secp256k1_scalar secp256k1_scalar_zero = SECP256K1_SCALAR_CONST(0,
|
||||
static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned char *bin) {
|
||||
int overflow;
|
||||
secp256k1_scalar_set_b32(r, bin, &overflow);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
return (!overflow) & (!secp256k1_scalar_is_zero(r));
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_verify(const secp256k1_scalar *r) {
|
||||
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
|
||||
|
||||
(void)r;
|
||||
}
|
||||
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
/* Begin of section generated by sage/gen_exhaustive_groups.sage. */
|
||||
# if EXHAUSTIVE_TEST_ORDER == 7
|
||||
@@ -53,11 +61,16 @@ static int secp256k1_scalar_set_b32_seckey(secp256k1_scalar *r, const unsigned c
|
||||
* (arbitrarily) set r2 = k + 5 (mod n) and r1 = k - r2 * lambda (mod n).
|
||||
*/
|
||||
static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT r1, secp256k1_scalar * SECP256K1_RESTRICT r2, const secp256k1_scalar * SECP256K1_RESTRICT k) {
|
||||
SECP256K1_SCALAR_VERIFY(k);
|
||||
VERIFY_CHECK(r1 != k);
|
||||
VERIFY_CHECK(r2 != k);
|
||||
VERIFY_CHECK(r1 != r2);
|
||||
|
||||
*r2 = (*k + 5) % EXHAUSTIVE_TEST_ORDER;
|
||||
*r1 = (*k + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r1);
|
||||
SECP256K1_SCALAR_VERIFY(r2);
|
||||
}
|
||||
#else
|
||||
/**
|
||||
@@ -140,9 +153,11 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT
|
||||
0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C4UL,
|
||||
0x221208ACUL, 0x9DF506C6UL, 0x1571B4AEUL, 0x8AC47F71UL
|
||||
);
|
||||
SECP256K1_SCALAR_VERIFY(k);
|
||||
VERIFY_CHECK(r1 != k);
|
||||
VERIFY_CHECK(r2 != k);
|
||||
VERIFY_CHECK(r1 != r2);
|
||||
|
||||
/* these _var calls are constant time since the shift amount is constant */
|
||||
secp256k1_scalar_mul_shift_var(&c1, k, &g1, 384);
|
||||
secp256k1_scalar_mul_shift_var(&c2, k, &g2, 384);
|
||||
@@ -153,6 +168,8 @@ static void secp256k1_scalar_split_lambda(secp256k1_scalar * SECP256K1_RESTRICT
|
||||
secp256k1_scalar_negate(r1, r1);
|
||||
secp256k1_scalar_add(r1, r1, k);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r1);
|
||||
SECP256K1_SCALAR_VERIFY(r2);
|
||||
#ifdef VERIFY
|
||||
secp256k1_scalar_split_lambda_verify(r1, r2, k);
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2015 Andrew Poelstra *
|
||||
* Copyright (c) 2015, 2022 Andrew Poelstra, Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
@@ -12,6 +12,13 @@
|
||||
/** A scalar modulo the group order of the secp256k1 curve. */
|
||||
typedef uint32_t secp256k1_scalar;
|
||||
|
||||
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) (d0)
|
||||
/* A compile-time constant equal to 2^32 (modulo order). */
|
||||
#define SCALAR_2P32 ((0xffffffffUL % EXHAUSTIVE_TEST_ORDER) + 1U)
|
||||
|
||||
/* Compute a*2^32 + b (modulo order). */
|
||||
#define SCALAR_HORNER(a, b) (((uint64_t)(a) * SCALAR_2P32 + (b)) % EXHAUSTIVE_TEST_ORDER)
|
||||
|
||||
/* Evaluates to the provided 256-bit constant reduced modulo order. */
|
||||
#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER(SCALAR_HORNER((d7), (d6)), (d5)), (d4)), (d3)), (d2)), (d1)), (d0))
|
||||
|
||||
#endif /* SECP256K1_SCALAR_REPR_H */
|
||||
|
||||
@@ -14,13 +14,22 @@
|
||||
#include <string.h>
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return !(*a & 1);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; }
|
||||
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; }
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) {
|
||||
*r = v % EXHAUSTIVE_TEST_ORDER;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
if (offset < 32)
|
||||
return ((*a >> offset) & ((((uint32_t)1) << count) - 1));
|
||||
else
|
||||
@@ -28,25 +37,33 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_s
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return secp256k1_scalar_get_bits(a, offset, count);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; }
|
||||
|
||||
static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
|
||||
*r = (*a + *b) % EXHAUSTIVE_TEST_ORDER;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
return *r < *b;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) {
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
|
||||
if (flag && bit < 32)
|
||||
*r += ((uint32_t)1 << bit);
|
||||
#ifdef VERIFY
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
VERIFY_CHECK(bit < 32);
|
||||
/* Verify that adding (1 << bit) will not overflow any in-range scalar *r by overflowing the underlying uint32_t. */
|
||||
VERIFY_CHECK(((uint32_t)1 << bit) - 1 <= UINT32_MAX - EXHAUSTIVE_TEST_ORDER);
|
||||
VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) {
|
||||
@@ -61,82 +78,124 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b
|
||||
}
|
||||
}
|
||||
if (overflow) *overflow = over;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
memset(bin, 0, 32);
|
||||
bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return *a == 0;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
if (*a == 0) {
|
||||
*r = 0;
|
||||
} else {
|
||||
*r = EXHAUSTIVE_TEST_ORDER - *a;
|
||||
}
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return *a == 1;
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_is_high(const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
return *a > EXHAUSTIVE_TEST_ORDER / 2;
|
||||
}
|
||||
|
||||
static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) {
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
|
||||
if (flag) secp256k1_scalar_negate(r, r);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
return flag ? -1 : 1;
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
*r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;
|
||||
}
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
|
||||
static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) {
|
||||
int ret;
|
||||
VERIFY_CHECK(n > 0);
|
||||
VERIFY_CHECK(n < 16);
|
||||
ret = *r & ((1 << n) - 1);
|
||||
*r >>= n;
|
||||
return ret;
|
||||
*r = (*a * *b) % EXHAUSTIVE_TEST_ORDER;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
*r1 = *a;
|
||||
*r2 = 0;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r1);
|
||||
SECP256K1_SCALAR_VERIFY(r2);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_SCALAR_VERIFY(b);
|
||||
|
||||
return *a == *b;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_scalar_cmov(secp256k1_scalar *r, const secp256k1_scalar *a, int flag) {
|
||||
uint32_t mask0, mask1;
|
||||
volatile int vflag = flag;
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
SECP256K1_CHECKMEM_CHECK_VERIFY(r, sizeof(*r));
|
||||
|
||||
mask0 = vflag + ~((uint32_t)0);
|
||||
mask1 = ~mask0;
|
||||
*r = (*r & mask0) | (*a & mask1);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) {
|
||||
int i;
|
||||
*r = 0;
|
||||
SECP256K1_SCALAR_VERIFY(x);
|
||||
|
||||
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++)
|
||||
if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1)
|
||||
*r = i;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
/* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus
|
||||
* have a composite group order; fix it in exhaustive_tests.c). */
|
||||
VERIFY_CHECK(*r != 0);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) {
|
||||
SECP256K1_SCALAR_VERIFY(x);
|
||||
|
||||
secp256k1_scalar_inverse(r, x);
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
static void secp256k1_scalar_half(secp256k1_scalar *r, const secp256k1_scalar *a) {
|
||||
SECP256K1_SCALAR_VERIFY(a);
|
||||
|
||||
*r = (*a + ((-(uint32_t)(*a & 1)) & EXHAUSTIVE_TEST_ORDER)) >> 1;
|
||||
|
||||
SECP256K1_SCALAR_VERIFY(r);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_SCALAR_REPR_IMPL_H */
|
||||
|
||||
@@ -247,8 +247,8 @@ static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge,
|
||||
} else {
|
||||
/* Otherwise, fall back to 32-byte big endian for X and Y. */
|
||||
secp256k1_fe x, y;
|
||||
secp256k1_fe_set_b32_mod(&x, pubkey->data);
|
||||
secp256k1_fe_set_b32_mod(&y, pubkey->data + 32);
|
||||
ARG_CHECK(secp256k1_fe_set_b32_limit(&x, pubkey->data));
|
||||
ARG_CHECK(secp256k1_fe_set_b32_limit(&y, pubkey->data + 32));
|
||||
secp256k1_ge_set_xy(ge, &x, &y);
|
||||
}
|
||||
ARG_CHECK(!secp256k1_fe_is_zero(&ge->x));
|
||||
@@ -811,3 +811,7 @@ int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32,
|
||||
#ifdef ENABLE_MODULE_SCHNORRSIG
|
||||
# include "modules/schnorrsig/main_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
# include "modules/ellswift/main_impl.h"
|
||||
#endif
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
#include "util.h"
|
||||
|
||||
static uint64_t secp256k1_test_state[4];
|
||||
static uint64_t secp256k1_test_rng_integer;
|
||||
static int secp256k1_test_rng_integer_bits_left = 0;
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16) {
|
||||
static const unsigned char PREFIX[19] = "secp256k1 test init";
|
||||
@@ -36,7 +34,6 @@ SECP256K1_INLINE static void secp256k1_testrand_seed(const unsigned char *seed16
|
||||
for (j = 0; j < 8; ++j) s = (s << 8) | out32[8*i + j];
|
||||
secp256k1_test_state[i] = s;
|
||||
}
|
||||
secp256k1_test_rng_integer_bits_left = 0;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static uint64_t rotl(const uint64_t x, int k) {
|
||||
@@ -57,58 +54,30 @@ SECP256K1_INLINE static uint64_t secp256k1_testrand64(void) {
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static uint64_t secp256k1_testrand_bits(int bits) {
|
||||
uint64_t ret;
|
||||
if (secp256k1_test_rng_integer_bits_left < bits) {
|
||||
secp256k1_test_rng_integer = secp256k1_testrand64();
|
||||
secp256k1_test_rng_integer_bits_left = 64;
|
||||
}
|
||||
ret = secp256k1_test_rng_integer;
|
||||
secp256k1_test_rng_integer >>= bits;
|
||||
secp256k1_test_rng_integer_bits_left -= bits;
|
||||
ret &= ((~((uint64_t)0)) >> (64 - bits));
|
||||
return ret;
|
||||
if (bits == 0) return 0;
|
||||
return secp256k1_testrand64() >> (64 - bits);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static uint32_t secp256k1_testrand32(void) {
|
||||
return secp256k1_testrand_bits(32);
|
||||
return secp256k1_testrand64() >> 32;
|
||||
}
|
||||
|
||||
static uint32_t secp256k1_testrand_int(uint32_t range) {
|
||||
/* We want a uniform integer between 0 and range-1, inclusive.
|
||||
* B is the smallest number such that range <= 2**B.
|
||||
* two mechanisms implemented here:
|
||||
* - generate B bits numbers until one below range is found, and return it
|
||||
* - find the largest multiple M of range that is <= 2**(B+A), generate B+A
|
||||
* bits numbers until one below M is found, and return it modulo range
|
||||
* The second mechanism consumes A more bits of entropy in every iteration,
|
||||
* but may need fewer iterations due to M being closer to 2**(B+A) then
|
||||
* range is to 2**B. The array below (indexed by B) contains a 0 when the
|
||||
* first mechanism is to be used, and the number A otherwise.
|
||||
*/
|
||||
static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0};
|
||||
uint32_t trange, mult;
|
||||
int bits = 0;
|
||||
if (range <= 1) {
|
||||
return 0;
|
||||
uint32_t mask = 0;
|
||||
uint32_t range_copy;
|
||||
/* Reduce range by 1, changing its meaning to "maximum value". */
|
||||
VERIFY_CHECK(range != 0);
|
||||
range -= 1;
|
||||
/* Count the number of bits in range. */
|
||||
range_copy = range;
|
||||
while (range_copy) {
|
||||
mask = (mask << 1) | 1U;
|
||||
range_copy >>= 1;
|
||||
}
|
||||
trange = range - 1;
|
||||
while (trange > 0) {
|
||||
trange >>= 1;
|
||||
bits++;
|
||||
}
|
||||
if (addbits[bits]) {
|
||||
bits = bits + addbits[bits];
|
||||
mult = ((~((uint32_t)0)) >> (32 - bits)) / range;
|
||||
trange = range * mult;
|
||||
} else {
|
||||
trange = range;
|
||||
mult = 1;
|
||||
}
|
||||
while(1) {
|
||||
uint32_t x = secp256k1_testrand_bits(bits);
|
||||
if (x < trange) {
|
||||
return (mult == 1) ? x : (x % range);
|
||||
}
|
||||
/* Generation loop. */
|
||||
while (1) {
|
||||
uint32_t val = secp256k1_testrand64() & mask;
|
||||
if (val <= range) return val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1219
src/tests.c
1219
src/tests.c
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,9 @@
|
||||
#define EXHAUSTIVE_TEST_ORDER 13
|
||||
#endif
|
||||
|
||||
/* These values of B are all values in [1, 8] that result in a curve with even order. */
|
||||
#define EXHAUSTIVE_TEST_CURVE_HAS_EVEN_ORDER (SECP256K1_B == 1 || SECP256K1_B == 6 || SECP256K1_B == 8)
|
||||
|
||||
#ifdef USE_EXTERNAL_DEFAULT_CALLBACKS
|
||||
#pragma message("Ignoring USE_EXTERNAL_CALLBACKS in exhaustive_tests.")
|
||||
#undef USE_EXTERNAL_DEFAULT_CALLBACKS
|
||||
@@ -25,61 +28,11 @@
|
||||
#include "testrand_impl.h"
|
||||
#include "ecmult_compute_table_impl.h"
|
||||
#include "ecmult_gen_compute_table_impl.h"
|
||||
#include "testutil.h"
|
||||
#include "util.h"
|
||||
|
||||
static int count = 2;
|
||||
|
||||
/** stolen from tests.c */
|
||||
static void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) {
|
||||
CHECK(a->infinity == b->infinity);
|
||||
if (a->infinity) {
|
||||
return;
|
||||
}
|
||||
CHECK(secp256k1_fe_equal_var(&a->x, &b->x));
|
||||
CHECK(secp256k1_fe_equal_var(&a->y, &b->y));
|
||||
}
|
||||
|
||||
static void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) {
|
||||
secp256k1_fe z2s;
|
||||
secp256k1_fe u1, u2, s1, s2;
|
||||
CHECK(a->infinity == b->infinity);
|
||||
if (a->infinity) {
|
||||
return;
|
||||
}
|
||||
/* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */
|
||||
secp256k1_fe_sqr(&z2s, &b->z);
|
||||
secp256k1_fe_mul(&u1, &a->x, &z2s);
|
||||
u2 = b->x; secp256k1_fe_normalize_weak(&u2);
|
||||
secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z);
|
||||
s2 = b->y; secp256k1_fe_normalize_weak(&s2);
|
||||
CHECK(secp256k1_fe_equal_var(&u1, &u2));
|
||||
CHECK(secp256k1_fe_equal_var(&s1, &s2));
|
||||
}
|
||||
|
||||
static void random_fe(secp256k1_fe *x) {
|
||||
unsigned char bin[32];
|
||||
do {
|
||||
secp256k1_testrand256(bin);
|
||||
if (secp256k1_fe_set_b32_limit(x, bin)) {
|
||||
return;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
|
||||
static void random_fe_non_zero(secp256k1_fe *nz) {
|
||||
int tries = 10;
|
||||
while (--tries >= 0) {
|
||||
random_fe(nz);
|
||||
secp256k1_fe_normalize(nz);
|
||||
if (!secp256k1_fe_is_zero(nz)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Infinitesimal probability of spurious failure here */
|
||||
CHECK(tries >= 0);
|
||||
}
|
||||
/** END stolen from tests.c */
|
||||
|
||||
static uint32_t num_cores = 1;
|
||||
static uint32_t this_core = 0;
|
||||
|
||||
@@ -114,7 +67,7 @@ static void test_exhaustive_endomorphism(const secp256k1_ge *group) {
|
||||
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) {
|
||||
secp256k1_ge res;
|
||||
secp256k1_ge_mul_lambda(&res, &group[i]);
|
||||
ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res);
|
||||
CHECK(secp256k1_ge_eq_var(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,21 +93,21 @@ static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_
|
||||
secp256k1_gej tmp;
|
||||
/* add_var */
|
||||
secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL);
|
||||
ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER]));
|
||||
/* add_ge */
|
||||
if (j > 0) {
|
||||
secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]);
|
||||
ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER]));
|
||||
}
|
||||
/* add_ge_var */
|
||||
secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL);
|
||||
ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER]));
|
||||
/* add_zinv_var */
|
||||
zless_gej.infinity = groupj[j].infinity;
|
||||
zless_gej.x = groupj[j].x;
|
||||
zless_gej.y = groupj[j].y;
|
||||
secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv);
|
||||
ge_equals_gej(&group[(i + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i + j) % EXHAUSTIVE_TEST_ORDER]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,9 +115,9 @@ static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_
|
||||
for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) {
|
||||
secp256k1_gej tmp;
|
||||
secp256k1_gej_double(&tmp, &groupj[i]);
|
||||
ge_equals_gej(&group[(2 * i) % EXHAUSTIVE_TEST_ORDER], &tmp);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER]));
|
||||
secp256k1_gej_double_var(&tmp, &groupj[i], NULL);
|
||||
ge_equals_gej(&group[(2 * i) % EXHAUSTIVE_TEST_ORDER], &tmp);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(2 * i) % EXHAUSTIVE_TEST_ORDER]));
|
||||
}
|
||||
|
||||
/* Check negation */
|
||||
@@ -172,9 +125,9 @@ static void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_
|
||||
secp256k1_ge tmp;
|
||||
secp256k1_gej tmpj;
|
||||
secp256k1_ge_neg(&tmp, &group[i]);
|
||||
ge_equals_ge(&group[EXHAUSTIVE_TEST_ORDER - i], &tmp);
|
||||
CHECK(secp256k1_ge_eq_var(&tmp, &group[EXHAUSTIVE_TEST_ORDER - i]));
|
||||
secp256k1_gej_neg(&tmpj, &groupj[i]);
|
||||
ge_equals_gej(&group[EXHAUSTIVE_TEST_ORDER - i], &tmpj);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&tmpj, &group[EXHAUSTIVE_TEST_ORDER - i]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,8 +144,7 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge
|
||||
secp256k1_scalar_set_int(&ng, j);
|
||||
|
||||
secp256k1_ecmult(&tmp, &groupj[r_log], &na, &ng);
|
||||
ge_equals_gej(&group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER], &tmp);
|
||||
|
||||
CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * r_log + j) % EXHAUSTIVE_TEST_ORDER]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,20 +162,20 @@ static void test_exhaustive_ecmult(const secp256k1_ge *group, const secp256k1_ge
|
||||
|
||||
/* Test secp256k1_ecmult_const. */
|
||||
secp256k1_ecmult_const(&tmp, &group[i], &ng);
|
||||
ge_equals_gej(&group[(i * j) % EXHAUSTIVE_TEST_ORDER], &tmp);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * j) % EXHAUSTIVE_TEST_ORDER]));
|
||||
|
||||
if (i != 0 && j != 0) {
|
||||
/* Test secp256k1_ecmult_const_xonly with all curve X coordinates, and xd=NULL. */
|
||||
ret = secp256k1_ecmult_const_xonly(&tmpf, &group[i].x, NULL, &ng, 0);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_fe_equal_var(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x));
|
||||
CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x));
|
||||
|
||||
/* Test secp256k1_ecmult_const_xonly with all curve X coordinates, with random xd. */
|
||||
random_fe_non_zero(&xd);
|
||||
secp256k1_fe_mul(&xn, &xd, &group[i].x);
|
||||
ret = secp256k1_ecmult_const_xonly(&tmpf, &xn, &xd, &ng, 0);
|
||||
CHECK(ret);
|
||||
CHECK(secp256k1_fe_equal_var(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x));
|
||||
CHECK(secp256k1_fe_equal(&tmpf, &group[(i * j) % EXHAUSTIVE_TEST_ORDER].x));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,7 +214,7 @@ static void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const sec
|
||||
data.pt[1] = group[y];
|
||||
|
||||
secp256k1_ecmult_multi_var(&ctx->error_callback, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2);
|
||||
ge_equals_gej(&group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER], &tmp);
|
||||
CHECK(secp256k1_gej_eq_ge_var(&tmp, &group[(i * x + j * y + k) % EXHAUSTIVE_TEST_ORDER]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,6 +347,10 @@ static void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_g
|
||||
#include "modules/schnorrsig/tests_exhaustive_impl.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
#include "modules/ellswift/tests_exhaustive_impl.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int i;
|
||||
secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER];
|
||||
@@ -468,8 +424,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
CHECK(group[i].infinity == 0);
|
||||
CHECK(generated.infinity == 0);
|
||||
CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x));
|
||||
CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y));
|
||||
CHECK(secp256k1_fe_equal(&generated.x, &group[i].x));
|
||||
CHECK(secp256k1_fe_equal(&generated.y, &group[i].y));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,6 +446,15 @@ int main(int argc, char** argv) {
|
||||
#ifdef ENABLE_MODULE_SCHNORRSIG
|
||||
test_exhaustive_schnorrsig(ctx);
|
||||
#endif
|
||||
#ifdef ENABLE_MODULE_ELLSWIFT
|
||||
/* The ellswift algorithm does have additional edge cases when operating on
|
||||
* curves of even order, which are not included in the code as secp256k1 is
|
||||
* of odd order. Skip the ellswift tests if the used exhaustive tests curve
|
||||
* is even-ordered accordingly. */
|
||||
#if !EXHAUSTIVE_TEST_CURVE_HAS_EVEN_ORDER
|
||||
test_exhaustive_ellswift(ctx, group);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
secp256k1_context_destroy(ctx);
|
||||
}
|
||||
|
||||
29
src/testutil.h
Normal file
29
src/testutil.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/***********************************************************************
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_TESTUTIL_H
|
||||
#define SECP256K1_TESTUTIL_H
|
||||
|
||||
#include "field.h"
|
||||
#include "testrand.h"
|
||||
#include "util.h"
|
||||
|
||||
static void random_fe(secp256k1_fe *x) {
|
||||
unsigned char bin[32];
|
||||
do {
|
||||
secp256k1_testrand256(bin);
|
||||
if (secp256k1_fe_set_b32_limit(x, bin)) {
|
||||
return;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
|
||||
static void random_fe_non_zero(secp256k1_fe *nz) {
|
||||
do {
|
||||
random_fe(nz);
|
||||
} while (secp256k1_fe_is_zero(nz));
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_TESTUTIL_H */
|
||||
56
src/util.h
56
src/util.h
@@ -51,6 +51,19 @@ static void print_buf_plain(const unsigned char *buf, size_t len) {
|
||||
# define SECP256K1_INLINE inline
|
||||
# endif
|
||||
|
||||
/** Assert statically that expr is an integer constant expression, and run stmt.
|
||||
*
|
||||
* Useful for example to enforce that magnitude arguments are constant.
|
||||
*/
|
||||
#define ASSERT_INT_CONST_AND_DO(expr, stmt) do { \
|
||||
switch(42) { \
|
||||
case /* ERROR: integer argument is not constant */ expr: \
|
||||
break; \
|
||||
default: ; \
|
||||
} \
|
||||
stmt; \
|
||||
} while(0)
|
||||
|
||||
typedef struct {
|
||||
void (*fn)(const char *text, void* data);
|
||||
const void* data;
|
||||
@@ -119,16 +132,11 @@ static const secp256k1_callback default_error_callback = {
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/* Like assert(), but when VERIFY is defined, and side-effect safe. */
|
||||
#if defined(COVERAGE)
|
||||
#define VERIFY_CHECK(check)
|
||||
#define VERIFY_SETUP(stmt)
|
||||
#elif defined(VERIFY)
|
||||
/* Like assert(), but when VERIFY is defined. */
|
||||
#if defined(VERIFY)
|
||||
#define VERIFY_CHECK CHECK
|
||||
#define VERIFY_SETUP(stmt) do { stmt; } while(0)
|
||||
#else
|
||||
#define VERIFY_CHECK(cond) do { (void)(cond); } while(0)
|
||||
#define VERIFY_SETUP(stmt)
|
||||
#define VERIFY_CHECK(cond)
|
||||
#endif
|
||||
|
||||
static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) {
|
||||
@@ -139,14 +147,6 @@ static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void *ptr, size_t size) {
|
||||
void *ret = realloc(ptr, size);
|
||||
if (ret == NULL) {
|
||||
secp256k1_callback_call(cb, "Out of memory");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(__BIGGEST_ALIGNMENT__)
|
||||
#define ALIGNMENT __BIGGEST_ALIGNMENT__
|
||||
#else
|
||||
@@ -353,4 +353,28 @@ SECP256K1_INLINE static void secp256k1_write_be32(unsigned char* p, uint32_t x)
|
||||
p[0] = x >> 24;
|
||||
}
|
||||
|
||||
/* Read a uint64_t in big endian */
|
||||
SECP256K1_INLINE static uint64_t secp256k1_read_be64(const unsigned char* p) {
|
||||
return (uint64_t)p[0] << 56 |
|
||||
(uint64_t)p[1] << 48 |
|
||||
(uint64_t)p[2] << 40 |
|
||||
(uint64_t)p[3] << 32 |
|
||||
(uint64_t)p[4] << 24 |
|
||||
(uint64_t)p[5] << 16 |
|
||||
(uint64_t)p[6] << 8 |
|
||||
(uint64_t)p[7];
|
||||
}
|
||||
|
||||
/* Write a uint64_t in big endian */
|
||||
SECP256K1_INLINE static void secp256k1_write_be64(unsigned char* p, uint64_t x) {
|
||||
p[7] = x;
|
||||
p[6] = x >> 8;
|
||||
p[5] = x >> 16;
|
||||
p[4] = x >> 24;
|
||||
p[3] = x >> 32;
|
||||
p[2] = x >> 40;
|
||||
p[1] = x >> 48;
|
||||
p[0] = x >> 56;
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_UTIL_H */
|
||||
|
||||
64
tools/check-abi.sh
Executable file
64
tools/check-abi.sh
Executable file
@@ -0,0 +1,64 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
default_base_version="$(git describe --match "v*.*.*" --abbrev=0)"
|
||||
default_new_version="master"
|
||||
|
||||
display_help_and_exit() {
|
||||
echo "Usage: $0 <base_ver> <new_ver>"
|
||||
echo ""
|
||||
echo "Description: This script uses the ABI Compliance Checker tool to determine if the ABI"
|
||||
echo " of a new version of libsecp256k1 has changed in a backward-incompatible way."
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " base_ver Specify the base version (default: $default_base_version)"
|
||||
echo " new_ver Specify the new version (default: $default_new_version)"
|
||||
echo " -h, --help Display this help message"
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [ "$#" -eq 0 ]; then
|
||||
base_version="$default_base_version"
|
||||
new_version="$default_new_version"
|
||||
elif [ "$#" -eq 1 ] && { [ "$1" = "-h" ] || [ "$1" = "--help" ]; }; then
|
||||
display_help_and_exit
|
||||
elif [ "$#" -eq 2 ]; then
|
||||
base_version="$1"
|
||||
new_version="$2"
|
||||
else
|
||||
echo "Invalid usage. See help:"
|
||||
echo ""
|
||||
display_help_and_exit
|
||||
fi
|
||||
|
||||
checkout_and_build() {
|
||||
git worktree add -d "$1" "$2"
|
||||
cd "$1"
|
||||
mkdir build && cd build
|
||||
cmake -S .. --preset dev-mode \
|
||||
-DCMAKE_C_COMPILER=gcc -DCMAKE_BUILD_TYPE=None -DCMAKE_C_FLAGS="-g -Og -gdwarf-4" \
|
||||
-DSECP256K1_BUILD_BENCHMARK=OFF \
|
||||
-DSECP256K1_BUILD_TESTS=OFF \
|
||||
-DSECP256K1_BUILD_EXHAUSTIVE_TESTS=OFF \
|
||||
-DSECP256K1_BUILD_CTIME_TESTS=OFF \
|
||||
-DSECP256K1_BUILD_EXAMPLES=OFF
|
||||
cmake --build . -j "$(nproc)"
|
||||
abi-dumper src/libsecp256k1.so -o ABI.dump -lver "$2"
|
||||
}
|
||||
|
||||
echo "Comparing $base_version (base version) to $new_version (new version)"
|
||||
echo
|
||||
|
||||
original_dir="$(pwd)"
|
||||
|
||||
base_source_dir=$(mktemp -d)
|
||||
checkout_and_build "$base_source_dir" "$base_version"
|
||||
|
||||
new_source_dir=$(mktemp -d)
|
||||
checkout_and_build "$new_source_dir" "$new_version"
|
||||
|
||||
cd "$original_dir"
|
||||
abi-compliance-checker -lib libsecp256k1 -old "${base_source_dir}/build/ABI.dump" -new "${new_source_dir}/build/ABI.dump"
|
||||
git worktree remove "$base_source_dir"
|
||||
git worktree remove "$new_source_dir"
|
||||
Reference in New Issue
Block a user