Compare commits
555 Commits
gen-header
...
secp256k1-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0129b77767 | ||
|
|
e1756dfddc | ||
|
|
7093e633b8 | ||
|
|
29f9a7dc62 | ||
|
|
8f0c6f1545 | ||
|
|
f4fa8d226a | ||
|
|
ff4714e641 | ||
|
|
3fb4d6db9c | ||
|
|
b9d91b3ecb | ||
|
|
0d71b6c61f | ||
|
|
4721bec0ef | ||
|
|
ebf57dc2f5 | ||
|
|
4d20713425 | ||
|
|
3a106966aa | ||
|
|
13c88efed0 | ||
|
|
0ce4554881 | ||
|
|
38a8b20991 | ||
|
|
5b4eb18ec5 | ||
|
|
62f0b2d867 | ||
|
|
73792e4a27 | ||
|
|
2117e7466a | ||
|
|
ebc31f1f9d | ||
|
|
ac2d0e6697 | ||
|
|
29b4bd85d7 | ||
|
|
6370bdd537 | ||
|
|
e0ced690cf | ||
|
|
b0917f3de1 | ||
|
|
81052ca411 | ||
|
|
9e5939d284 | ||
|
|
96b9236c42 | ||
|
|
23900a0d86 | ||
|
|
005fe79262 | ||
|
|
a11250330b | ||
|
|
bac746c55e | ||
|
|
d0a83f7328 | ||
|
|
903b16aa6c | ||
|
|
1f4dd03838 | ||
|
|
3967d96bf1 | ||
|
|
3734b68200 | ||
|
|
ebfa2058e9 | ||
|
|
6f54e69f03 | ||
|
|
29a299e373 | ||
|
|
7506e064d7 | ||
|
|
8893f42438 | ||
|
|
e6692778d3 | ||
|
|
ac05f61fcf | ||
|
|
e6e3d5da2f | ||
|
|
353dff156f | ||
|
|
e89278f211 | ||
|
|
c6b6b8f1bb | ||
|
|
c582abade1 | ||
|
|
63c6b71616 | ||
|
|
2edc514c90 | ||
|
|
4232e5b7da | ||
|
|
ebad8414b0 | ||
|
|
fe7fc1fda8 | ||
|
|
9d2f2b44d8 | ||
|
|
9aca2f7f07 | ||
|
|
acab934d24 | ||
|
|
73acc8fef6 | ||
|
|
8b70795b5e | ||
|
|
76ed922a5f | ||
|
|
6173839c90 | ||
|
|
d1b13b0014 | ||
|
|
23bf5b732b | ||
|
|
0a5b60d8b0 | ||
|
|
caa5d24446 | ||
|
|
1789183cba | ||
|
|
63150ab4da | ||
|
|
c5257aed0b | ||
|
|
bb1f54280f | ||
|
|
a45c1fa63c | ||
|
|
5006895bd6 | ||
|
|
a39b08d672 | ||
|
|
a3a3a17f47 | ||
|
|
4eecb4d6ef | ||
|
|
66a765c775 | ||
|
|
d7838ba6a6 | ||
|
|
7ceb0b7611 | ||
|
|
8b7dcdd955 | ||
|
|
08d7d89299 | ||
|
|
87af00b511 | ||
|
|
63e1b2aa7d | ||
|
|
39f67dd072 | ||
|
|
e99b26fcd5 | ||
|
|
49e6630bca | ||
|
|
b110c106fa | ||
|
|
cec7b18a34 | ||
|
|
78f6cdfaae | ||
|
|
d7f39ae4b6 | ||
|
|
8bcd78cd79 | ||
|
|
c498366e5b | ||
|
|
be31791543 | ||
|
|
e73ff30922 | ||
|
|
c0041b5cfc | ||
|
|
4ad408faf3 | ||
|
|
412bf874d0 | ||
|
|
34debf7a6d | ||
|
|
a0e99fc121 | ||
|
|
5738e8622d | ||
|
|
c9939ba55d | ||
|
|
a51f2af62b | ||
|
|
8ab24e8dad | ||
|
|
f3733c5433 | ||
|
|
cb5524adc5 | ||
|
|
5c6af60ec5 | ||
|
|
d0fdd5f009 | ||
|
|
c7a3424c5f | ||
|
|
875d68b95f | ||
|
|
54caf2e74f | ||
|
|
f431b3f28a | ||
|
|
16ffa9d97c | ||
|
|
8dfd53ee3f | ||
|
|
4e43520026 | ||
|
|
7332d2db6b | ||
|
|
7a703fd97d | ||
|
|
eabd9bc46a | ||
|
|
6fcb5b845d | ||
|
|
58254463f9 | ||
|
|
f0010349b8 | ||
|
|
910d9c284c | ||
|
|
176bfb1110 | ||
|
|
4cd2ee474d | ||
|
|
f49c9896b0 | ||
|
|
aabf00c155 | ||
|
|
f5adab16a9 | ||
|
|
bceefd6547 | ||
|
|
1c325199d5 | ||
|
|
47e6618e11 | ||
|
|
3e08b02e2a | ||
|
|
8bc6aeffa9 | ||
|
|
670cdd3f8b | ||
|
|
5e5fb28b4a | ||
|
|
7c068998ba | ||
|
|
02b6c87b52 | ||
|
|
979961c506 | ||
|
|
887bd1f8b6 | ||
|
|
0dccf98a21 | ||
|
|
b2c8c42cf1 | ||
|
|
57d3a3c64c | ||
|
|
79f1f7a4f1 | ||
|
|
0d7727f95e | ||
|
|
805082de11 | ||
|
|
39295362cf | ||
|
|
ef37761fee | ||
|
|
6034a04fb1 | ||
|
|
f60915906d | ||
|
|
9e49a9b255 | ||
|
|
18d36327fd | ||
|
|
214cb3c321 | ||
|
|
40412b1930 | ||
|
|
2e1b9e0458 | ||
|
|
67a429f31f | ||
|
|
5b196338f0 | ||
|
|
3e5cfc5c73 | ||
|
|
66bb9320c0 | ||
|
|
1309c03c45 | ||
|
|
fabc8f74e7 | ||
|
|
96201b4f6e | ||
|
|
4fd0d56e37 | ||
|
|
b74f2dc478 | ||
|
|
b368a5d163 | ||
|
|
bedff79848 | ||
|
|
9957307c3f | ||
|
|
d924027765 | ||
|
|
a4410ac779 | ||
|
|
d6738e890e | ||
|
|
bd70820123 | ||
|
|
56f69d979f | ||
|
|
b8a3ff5f3b | ||
|
|
68d937fe11 | ||
|
|
41bc9ce129 | ||
|
|
b0644d4ab3 | ||
|
|
c0415eb0cb | ||
|
|
00fffeb172 | ||
|
|
2dc868f35b | ||
|
|
0d4ee3c62d | ||
|
|
2a1750dedd | ||
|
|
ed7394f005 | ||
|
|
9dd117fd2b | ||
|
|
f35b5e271f | ||
|
|
068f03c35b | ||
|
|
3424cb1fa3 | ||
|
|
13ef445721 | ||
|
|
b86c210747 | ||
|
|
c59c602dd6 | ||
|
|
a1f16a0a53 | ||
|
|
3cdc02ef8a | ||
|
|
cf21c9d715 | ||
|
|
0dfb356f95 | ||
|
|
4c231568fb | ||
|
|
f416e039bb | ||
|
|
936d62f248 | ||
|
|
e06540de8c | ||
|
|
edb879f578 | ||
|
|
fca4c3b62f | ||
|
|
c50b218698 | ||
|
|
c33e597245 | ||
|
|
0c5cb7cd08 | ||
|
|
dbc49df80c | ||
|
|
47be098bac | ||
|
|
16aaa4a02c | ||
|
|
949e994cb3 | ||
|
|
c87618157e | ||
|
|
fc3dc94049 | ||
|
|
edc7cb6cdd | ||
|
|
4320490e88 | ||
|
|
126493ef01 | ||
|
|
253f131310 | ||
|
|
3997128ad9 | ||
|
|
04f4c09111 | ||
|
|
dbf3d752a8 | ||
|
|
29d0d562dc | ||
|
|
660ad39fb3 | ||
|
|
e13bdf2f23 | ||
|
|
18c5c62b45 | ||
|
|
5f1ad03d00 | ||
|
|
f858a4e3d5 | ||
|
|
002002e735 | ||
|
|
ba8b4f53ef | ||
|
|
8c77fe1590 | ||
|
|
94425d4a67 | ||
|
|
f6c84a02f3 | ||
|
|
360e218043 | ||
|
|
e7a8a5f638 | ||
|
|
a88db4a744 | ||
|
|
16618fcd8d | ||
|
|
3cf8f70ba1 | ||
|
|
2309c7dd4a | ||
|
|
22e578bb11 | ||
|
|
3f4a5a10e4 | ||
|
|
f00d6575ca | ||
|
|
dbd41db16a | ||
|
|
2e7fc5b537 | ||
|
|
2ed54da18a | ||
|
|
28609507e7 | ||
|
|
73596a85a2 | ||
|
|
2876af4f8d | ||
|
|
5e1c885efb | ||
|
|
f79a7adcf5 | ||
|
|
05d315affe | ||
|
|
a39c2b09de | ||
|
|
3a6fd7f636 | ||
|
|
5e8747ae2a | ||
|
|
71757da5cc | ||
|
|
99bd661d71 | ||
|
|
bc818b160c | ||
|
|
0c5ff9066e | ||
|
|
b6807d91d8 | ||
|
|
f39f99be0e | ||
|
|
37dba329c6 | ||
|
|
6bb0b77e15 | ||
|
|
39198a03ea | ||
|
|
59a8de8f64 | ||
|
|
4e284655d9 | ||
|
|
f862b4ca13 | ||
|
|
ffef45c98a | ||
|
|
2361b3719a | ||
|
|
3b7d26b23c | ||
|
|
84b5fc5bc3 | ||
|
|
37ed51a7ea | ||
|
|
93d343bfc5 | ||
|
|
7e3952ae82 | ||
|
|
89853a0f2e | ||
|
|
41fc785602 | ||
|
|
22911ee6da | ||
|
|
5a73f14d6c | ||
|
|
f03df0e6d7 | ||
|
|
5894e1f1df | ||
|
|
8f814cddb9 | ||
|
|
3fec982608 | ||
|
|
9ab2cbe0eb | ||
|
|
4f27e344c6 | ||
|
|
01993878bb | ||
|
|
52a03512c1 | ||
|
|
8f78e208ad | ||
|
|
ed1b91171a | ||
|
|
85b35afa76 | ||
|
|
ca4906b02e | ||
|
|
02dd5f1bbb | ||
|
|
e9fccd4de1 | ||
|
|
08fb6c4926 | ||
|
|
3d2302257f | ||
|
|
96d8ccbd16 | ||
|
|
0585b8b2ee | ||
|
|
7b50483ad7 | ||
|
|
34a67c773b | ||
|
|
ca739cba23 | ||
|
|
eb45ef3384 | ||
|
|
856a01d6ad | ||
|
|
d72b9e2483 | ||
|
|
4b48a43106 | ||
|
|
1b4d256e2e | ||
|
|
dabfea7e21 | ||
|
|
dc7d8fd9e2 | ||
|
|
074ab582dd | ||
|
|
acb7f97eb8 | ||
|
|
227a4f2d07 | ||
|
|
d567b779fe | ||
|
|
2241ae6d14 | ||
|
|
642cd062bd | ||
|
|
83fb1bcef4 | ||
|
|
ecba8138ec | ||
|
|
613c34cd86 | ||
|
|
f45d897101 | ||
|
|
2e759ec753 | ||
|
|
d644dda5c9 | ||
|
|
bde2a32286 | ||
|
|
47a7b8382f | ||
|
|
61d1ecb028 | ||
|
|
387d723c3f | ||
|
|
0db61d25c9 | ||
|
|
a0771d15e6 | ||
|
|
fb424fbba2 | ||
|
|
22a6031184 | ||
|
|
544002c008 | ||
|
|
dd98cc988f | ||
|
|
b4c1382a87 | ||
|
|
0c774d89e6 | ||
|
|
5c5f71eea5 | ||
|
|
e2625f8a98 | ||
|
|
bae1bea3c4 | ||
|
|
78c3836341 | ||
|
|
362bb25608 | ||
|
|
73a30c6b58 | ||
|
|
770b3dcd6f | ||
|
|
b76142ff25 | ||
|
|
137d304a6b | ||
|
|
0d9540b13f | ||
|
|
59782c68b4 | ||
|
|
96cd94e385 | ||
|
|
dcb2e3b3ff | ||
|
|
b4bff99028 | ||
|
|
a467047e11 | ||
|
|
e729cc7f5a | ||
|
|
b64a2e2597 | ||
|
|
e028aa33d3 | ||
|
|
f1e11d363d | ||
|
|
ef83281c3a | ||
|
|
556caad2ca | ||
|
|
0d82732a9a | ||
|
|
786dfb49f5 | ||
|
|
e95f8ab098 | ||
|
|
384f55606a | ||
|
|
ee56accd47 | ||
|
|
7b9b117230 | ||
|
|
d99bec2e21 | ||
|
|
2abcf951af | ||
|
|
271582b3b7 | ||
|
|
60f7f2de5d | ||
|
|
ada6361dec | ||
|
|
8ecc6ce50e | ||
|
|
4edaf06fb0 | ||
|
|
ce6d438266 | ||
|
|
b1e68cb8e6 | ||
|
|
a11c76c59a | ||
|
|
8fe63e5654 | ||
|
|
94ae7cbf83 | ||
|
|
2cb73b1064 | ||
|
|
fa33017135 | ||
|
|
ee9e68cd30 | ||
|
|
d0d738d32d | ||
|
|
6914c25276 | ||
|
|
e541a90ef6 | ||
|
|
f34b0c3f35 | ||
|
|
8d1563b0ff | ||
|
|
1669bb2865 | ||
|
|
ecc94abcc8 | ||
|
|
544435fc90 | ||
|
|
143dc6e9ee | ||
|
|
e49f7991c2 | ||
|
|
77defd2c3b | ||
|
|
908bdce64e | ||
|
|
5db782e655 | ||
|
|
6095a863fa | ||
|
|
cd473e02c3 | ||
|
|
6c36de7a33 | ||
|
|
98836b11f0 | ||
|
|
7623cf2b97 | ||
|
|
a7a164f2c6 | ||
|
|
5a4bc0bb95 | ||
|
|
c2b028a281 | ||
|
|
0be1a4ae62 | ||
|
|
92a48a764d | ||
|
|
40839e21b9 | ||
|
|
dcf392027b | ||
|
|
a484e0008b | ||
|
|
0522caac8f | ||
|
|
238305fdbb | ||
|
|
695feb6fbd | ||
|
|
814cc78d71 | ||
|
|
ba12dd08da | ||
|
|
5feadde462 | ||
|
|
c4fd5dab45 | ||
|
|
ef020de16f | ||
|
|
1bf7c056ba | ||
|
|
248bffb052 | ||
|
|
36698dcfee | ||
|
|
a61a93ff50 | ||
|
|
2842dc523e | ||
|
|
1a02d6ce51 | ||
|
|
662918cb29 | ||
|
|
14c7dbd444 | ||
|
|
ec8f20babd | ||
|
|
01ee1b3b3c | ||
|
|
912680ed86 | ||
|
|
91fae3ace0 | ||
|
|
5df77a0eda | ||
|
|
975e51e0d9 | ||
|
|
735fbde04e | ||
|
|
16e86150d0 | ||
|
|
069870d92a | ||
|
|
8979ec0d9a | ||
|
|
84a808598b | ||
|
|
d4d270a59c | ||
|
|
b19c000063 | ||
|
|
4d01bc2d9c | ||
|
|
e6d01e9347 | ||
|
|
7667532bd7 | ||
|
|
248f046611 | ||
|
|
9ab96f7b12 | ||
|
|
ee99f12f3d | ||
|
|
d58bc93f2c | ||
|
|
05362ee042 | ||
|
|
83483869ac | ||
|
|
aa15154a48 | ||
|
|
2277af5ff0 | ||
|
|
dbed75d969 | ||
|
|
310111e093 | ||
|
|
85d0e1bcce | ||
|
|
14196379ec | ||
|
|
a697d82da9 | ||
|
|
bade617417 | ||
|
|
5545e13dea | ||
|
|
20c5869df2 | ||
|
|
b76e45d5d6 | ||
|
|
870a977644 | ||
|
|
be40c4d0b5 | ||
|
|
c71dd2c08f | ||
|
|
6492bf88cc | ||
|
|
0e9ada1941 | ||
|
|
e96901a4b9 | ||
|
|
58df8d03ad | ||
|
|
2ebdad772a | ||
|
|
1c131affd3 | ||
|
|
ba698f883b | ||
|
|
949e85b009 | ||
|
|
a34bcaadf1 | ||
|
|
2d5f4cebdc | ||
|
|
b408c6a8b2 | ||
|
|
6198375218 | ||
|
|
74e2dbd68e | ||
|
|
c663397f46 | ||
|
|
3cb057f842 | ||
|
|
e34ceb333b | ||
|
|
b3bf5f99a3 | ||
|
|
efa783f8f0 | ||
|
|
ffd3b346fe | ||
|
|
84740acd2a | ||
|
|
47045270fa | ||
|
|
7f7a2ed3a8 | ||
|
|
314a61d724 | ||
|
|
89a20a8945 | ||
|
|
1086fda4c1 | ||
|
|
d3cb1f95eb | ||
|
|
40fde611bd | ||
|
|
ed7c08417a | ||
|
|
496c5b43b8 | ||
|
|
bf8b86cc07 | ||
|
|
9bd89c836b | ||
|
|
52ab96fedb | ||
|
|
deff5edd42 | ||
|
|
4efb3f8dd1 | ||
|
|
1e6f1f5ad5 | ||
|
|
c8fbc3c397 | ||
|
|
b00be65056 | ||
|
|
95e99f196f | ||
|
|
452d8e4d2a | ||
|
|
6fe50439ae | ||
|
|
9bc2e26502 | ||
|
|
7c1b91ba4b | ||
|
|
dbc3ddd5e2 | ||
|
|
3965027c81 | ||
|
|
0f0517369c | ||
|
|
fb9271dcf0 | ||
|
|
cd5f6028e5 | ||
|
|
09146ae854 | ||
|
|
ec0a7b3ae3 | ||
|
|
9e36d1bfe2 | ||
|
|
96f68a0afc | ||
|
|
8b3841c91d | ||
|
|
cddef0c0be | ||
|
|
9b7c47a21e | ||
|
|
6dbb007869 | ||
|
|
1646ace4d5 | ||
|
|
270f6c80db | ||
|
|
9b3ff0309d | ||
|
|
cd329dbc3e | ||
|
|
7f9c1a1565 | ||
|
|
f99aa8d4d3 | ||
|
|
b549d3d5f7 | ||
|
|
d333521516 | ||
|
|
2ef8ea5d21 | ||
|
|
82a96e4587 | ||
|
|
5aae5b5bb2 | ||
|
|
cb32940df3 | ||
|
|
31abd3ab8d | ||
|
|
c95f6f1360 | ||
|
|
fb46c83881 | ||
|
|
02f5001dfc | ||
|
|
1f46d6089e | ||
|
|
f54c6c5083 | ||
|
|
c77fc08597 | ||
|
|
d2f9c6b5dc | ||
|
|
4c950bbeaf | ||
|
|
a58f543f5a | ||
|
|
36b22c9337 | ||
|
|
355a38f113 | ||
|
|
bc65aa794e | ||
|
|
dba5471b69 | ||
|
|
8c1c831bdb | ||
|
|
548de42ecf | ||
|
|
0e96cdc6b6 | ||
|
|
c7680e570f | ||
|
|
6ad5cdb42a | ||
|
|
7a78f60598 | ||
|
|
4afec9f1ae | ||
|
|
d1dc9dfc0a | ||
|
|
0b70241850 | ||
|
|
ab1f89f00a | ||
|
|
8c7ea22d54 | ||
|
|
abe2d3e84b | ||
|
|
57752d28b3 | ||
|
|
f532bdc9f7 | ||
|
|
cac7c5559d | ||
|
|
768514bac0 | ||
|
|
b8c26a3990 | ||
|
|
817fb2013a | ||
|
|
12230f90ed | ||
|
|
2e1ccdca0d | ||
|
|
e7daa9b3c2 | ||
|
|
5b22977922 | ||
|
|
bc61b91aca | ||
|
|
b0452e664b | ||
|
|
84973d393a | ||
|
|
5e95bf2285 | ||
|
|
cbc20b8c34 | ||
|
|
4cc8f52505 | ||
|
|
465159c278 | ||
|
|
a2b6b1914f | ||
|
|
8b7680a826 | ||
|
|
aa8499080e | ||
|
|
cf12fa13cb | ||
|
|
4c0f32ed51 | ||
|
|
73aca8364f |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,13 +1,17 @@
|
||||
bench_inv
|
||||
bench_ecdh
|
||||
bench_ecmult
|
||||
bench_generator
|
||||
bench_rangeproof
|
||||
bench_schnorrsig
|
||||
bench_sign
|
||||
bench_verify
|
||||
bench_schnorr_verify
|
||||
bench_recover
|
||||
bench_internal
|
||||
tests
|
||||
exhaustive_tests
|
||||
gen_context
|
||||
valgrind_ctime_test
|
||||
*.exe
|
||||
*.so
|
||||
*.a
|
||||
@@ -29,6 +33,8 @@ libtool
|
||||
*.lo
|
||||
*.o
|
||||
*~
|
||||
*.log
|
||||
*.trs
|
||||
src/libsecp256k1-config.h
|
||||
src/libsecp256k1-config.h.in
|
||||
src/ecmult_static_context.h
|
||||
|
||||
100
.travis.yml
100
.travis.yml
@@ -1,69 +1,111 @@
|
||||
language: c
|
||||
sudo: false
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
dist: bionic
|
||||
# Valgrind currently supports upto macOS 10.13, the latest xcode of that version is 10.1
|
||||
osx_image: xcode10.1
|
||||
addons:
|
||||
apt:
|
||||
packages: libgmp-dev
|
||||
packages:
|
||||
- libgmp-dev
|
||||
- valgrind
|
||||
- libtool-bin
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
cache:
|
||||
directories:
|
||||
- src/java/guava/
|
||||
env:
|
||||
global:
|
||||
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no
|
||||
- GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
|
||||
- WIDEMUL=auto BIGNUM=auto STATICPRECOMPUTATION=yes ECMULTGENPRECISION=auto ASM=no BUILD=check WITH_VALGRIND=yes RUN_VALGRIND=no EXTRAFLAGS= HOST= ECDH=no RECOVERY=no SCHNORRSIG=no EXPERIMENTAL=no CTIMETEST=yes BENCH=yes ITERS=2 GENERATOR=no RANGEPROOF=no WHITELIST=no SCHNORRSIG=no MUSIG=no
|
||||
matrix:
|
||||
- SCALAR=32bit RECOVERY=yes
|
||||
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
|
||||
- SCALAR=64bit
|
||||
- FIELD=64bit RECOVERY=yes
|
||||
- FIELD=64bit ENDOMORPHISM=yes
|
||||
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
|
||||
- FIELD=64bit ASM=x86_64
|
||||
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
|
||||
- FIELD=32bit ENDOMORPHISM=yes
|
||||
- WIDEMUL=int64 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
|
||||
- WIDEMUL=int128 EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
|
||||
- WIDEMUL=int64 RECOVERY=yes
|
||||
- WIDEMUL=int64 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
|
||||
- WIDEMUL=int128
|
||||
- WIDEMUL=int128 RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
|
||||
- WIDEMUL=int128 ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
|
||||
- WIDEMUL=int128 ASM=x86_64
|
||||
- BIGNUM=no
|
||||
- BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
|
||||
- BIGNUM=no RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
|
||||
- BIGNUM=no STATICPRECOMPUTATION=no
|
||||
- BUILD=distcheck
|
||||
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
|
||||
- EXTRAFLAGS=CFLAGS=-O0
|
||||
- BUILD=check-java ECDH=yes EXPERIMENTAL=yes
|
||||
- BUILD=distcheck WITH_VALGRIND=no CTIMETEST=no BENCH=no
|
||||
- CPPFLAGS=-DDETERMINISTIC
|
||||
- CFLAGS=-O0 CTIMETEST=no
|
||||
- CFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" LDFLAGS="-fsanitize=undefined -fno-omit-frame-pointer" UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=no
|
||||
- ECMULTGENPRECISION=2
|
||||
- ECMULTGENPRECISION=8
|
||||
- RUN_VALGRIND=yes BIGNUM=no ASM=x86_64 ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes EXTRAFLAGS="--disable-openssl-tests" BUILD=
|
||||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- compiler: clang
|
||||
env: HOST=i686-linux-gnu ENDOMORPHISM=yes
|
||||
os: linux
|
||||
env: HOST=i686-linux-gnu
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- libgmp-dev:i386
|
||||
- valgrind
|
||||
- libtool-bin
|
||||
- libc6-dbg:i386
|
||||
- compiler: clang
|
||||
env: HOST=i686-linux-gnu
|
||||
os: linux
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- valgrind
|
||||
- libtool-bin
|
||||
- libc6-dbg:i386
|
||||
- compiler: gcc
|
||||
env: HOST=i686-linux-gnu ENDOMORPHISM=yes
|
||||
env: HOST=i686-linux-gnu
|
||||
os: linux
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- valgrind
|
||||
- libtool-bin
|
||||
- libc6-dbg:i386
|
||||
- compiler: gcc
|
||||
os: linux
|
||||
env: HOST=i686-linux-gnu
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
- libgmp-dev:i386
|
||||
before_install: mkdir -p `dirname $GUAVA_JAR`
|
||||
install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi
|
||||
- valgrind
|
||||
- libtool-bin
|
||||
- libc6-dbg:i386
|
||||
# S390x build (big endian system)
|
||||
- compiler: gcc
|
||||
env: HOST=s390x-unknown-linux-gnu ECDH=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes CTIMETEST=
|
||||
arch: s390x
|
||||
|
||||
# We use this to install macOS dependencies instead of the built in `homebrew` plugin,
|
||||
# because in xcode earlier than 11 they have a bug requiring updating the system which overall takes ~8 minutes.
|
||||
# https://travis-ci.community/t/macos-build-fails-because-of-homebrew-bundle-unknown-command/7296
|
||||
before_install:
|
||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then HOMEBREW_NO_AUTO_UPDATE=1 brew install gmp valgrind gcc@9; fi
|
||||
|
||||
before_script: ./autogen.sh
|
||||
|
||||
# travis auto terminates jobs that go for 10 minutes without printing to stdout, but travis_wait doesn't work well with forking programs like valgrind (https://docs.travis-ci.com/user/common-build-problems/#build-times-out-because-no-output-was-received https://github.com/bitcoin-core/secp256k1/pull/750#issuecomment-623476860)
|
||||
script:
|
||||
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
|
||||
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
|
||||
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
|
||||
os: linux
|
||||
- function keep_alive() { while true; do echo -en "\a"; sleep 60; done }
|
||||
- keep_alive &
|
||||
- ./contrib/travis.sh
|
||||
- kill %keep_alive
|
||||
|
||||
after_script:
|
||||
- cat ./tests.log
|
||||
- cat ./exhaustive_tests.log
|
||||
- cat ./valgrind_ctime_test.log
|
||||
- cat ./bench.log
|
||||
- $CC --version
|
||||
- valgrind --version
|
||||
|
||||
89
Makefile.am
89
Makefile.am
@@ -1,13 +1,8 @@
|
||||
ACLOCAL_AMFLAGS = -I build-aux/m4
|
||||
|
||||
lib_LTLIBRARIES = libsecp256k1.la
|
||||
if USE_JNI
|
||||
JNI_LIB = libsecp256k1_jni.la
|
||||
noinst_LTLIBRARIES = $(JNI_LIB)
|
||||
else
|
||||
JNI_LIB =
|
||||
endif
|
||||
include_HEADERS = include/secp256k1.h
|
||||
include_HEADERS += include/secp256k1_preallocated.h
|
||||
noinst_HEADERS =
|
||||
noinst_HEADERS += src/scalar.h
|
||||
noinst_HEADERS += src/scalar_4x64.h
|
||||
@@ -39,9 +34,11 @@ 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/java/org_bitcoin_NativeSecp256k1.h
|
||||
noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h
|
||||
noinst_HEADERS += src/assumptions.h
|
||||
noinst_HEADERS += src/util.h
|
||||
noinst_HEADERS += src/scratch.h
|
||||
noinst_HEADERS += src/scratch_impl.h
|
||||
noinst_HEADERS += src/selftest.h
|
||||
noinst_HEADERS += src/testrand.h
|
||||
noinst_HEADERS += src/testrand_impl.h
|
||||
noinst_HEADERS += src/hash.h
|
||||
@@ -72,21 +69,27 @@ endif
|
||||
|
||||
libsecp256k1_la_SOURCES = src/secp256k1.c
|
||||
libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
|
||||
libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB)
|
||||
libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB)
|
||||
|
||||
libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c
|
||||
libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES)
|
||||
if VALGRIND_ENABLED
|
||||
libsecp256k1_la_CPPFLAGS += -DVALGRIND
|
||||
endif
|
||||
|
||||
noinst_PROGRAMS =
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_verify bench_sign bench_internal
|
||||
noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_ecmult
|
||||
bench_verify_SOURCES = src/bench_verify.c
|
||||
bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
|
||||
# SECP_TEST_INCLUDES are only used here for CRYPTO_CPPFLAGS
|
||||
bench_verify_CPPFLAGS = -DSECP256K1_BUILD $(SECP_TEST_INCLUDES)
|
||||
bench_sign_SOURCES = src/bench_sign.c
|
||||
bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
|
||||
bench_internal_SOURCES = src/bench_internal.c
|
||||
bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB)
|
||||
bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
|
||||
bench_ecmult_SOURCES = src/bench_ecmult.c
|
||||
bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB)
|
||||
bench_ecmult_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES)
|
||||
endif
|
||||
|
||||
TESTS =
|
||||
@@ -94,6 +97,12 @@ if USE_TESTS
|
||||
noinst_PROGRAMS += tests
|
||||
tests_SOURCES = src/tests.c
|
||||
tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
|
||||
if VALGRIND_ENABLED
|
||||
tests_CPPFLAGS += -DVALGRIND
|
||||
noinst_PROGRAMS += valgrind_ctime_test
|
||||
valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c
|
||||
valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_LIBS) $(COMMON_LIB)
|
||||
endif
|
||||
if !ENABLE_COVERAGE
|
||||
tests_CPPFLAGS += -DVERIFY
|
||||
endif
|
||||
@@ -109,69 +118,43 @@ exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDE
|
||||
if !ENABLE_COVERAGE
|
||||
exhaustive_tests_CPPFLAGS += -DVERIFY
|
||||
endif
|
||||
exhaustive_tests_LDADD = $(SECP_LIBS)
|
||||
exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB)
|
||||
exhaustive_tests_LDFLAGS = -static
|
||||
TESTS += exhaustive_tests
|
||||
endif
|
||||
|
||||
JAVAROOT=src/java
|
||||
JAVAORG=org/bitcoin
|
||||
JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar
|
||||
CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA)
|
||||
JAVA_FILES= \
|
||||
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \
|
||||
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \
|
||||
$(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \
|
||||
$(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java
|
||||
|
||||
if USE_JNI
|
||||
|
||||
$(JAVA_GUAVA):
|
||||
@echo Guava is missing. Fetch it via: \
|
||||
wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@)
|
||||
@false
|
||||
|
||||
.stamp-java: $(JAVA_FILES)
|
||||
@echo Compiling $^
|
||||
$(AM_V_at)$(CLASSPATH_ENV) javac $^
|
||||
@touch $@
|
||||
|
||||
if USE_TESTS
|
||||
|
||||
check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java
|
||||
$(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
if USE_ECMULT_STATIC_PRECOMPUTATION
|
||||
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir)
|
||||
CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function
|
||||
CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) -I$(builddir)/src
|
||||
|
||||
gen_context_OBJECTS = gen_context.o
|
||||
gen_context_BIN = gen_context$(BUILD_EXEEXT)
|
||||
gen_%.o: src/gen_%.c
|
||||
gen_%.o: src/gen_%.c src/libsecp256k1-config.h
|
||||
$(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@
|
||||
|
||||
$(gen_context_BIN): $(gen_context_OBJECTS)
|
||||
$(CC_FOR_BUILD) $^ -o $@
|
||||
$(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) $(LDFLAGS_FOR_BUILD) $^ -o $@
|
||||
|
||||
$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h
|
||||
$(tests_OBJECTS): src/ecmult_static_context.h
|
||||
$(bench_internal_OBJECTS): src/ecmult_static_context.h
|
||||
$(bench_ecmult_OBJECTS): src/ecmult_static_context.h
|
||||
|
||||
src/ecmult_static_context.h: $(gen_context_BIN)
|
||||
./$(gen_context_BIN)
|
||||
|
||||
CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java
|
||||
CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h
|
||||
endif
|
||||
|
||||
EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES)
|
||||
EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h
|
||||
|
||||
if ENABLE_MODULE_ECDH
|
||||
include src/modules/ecdh/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_MUSIG
|
||||
include src/modules/musig/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_RECOVERY
|
||||
include src/modules/recovery/Makefile.am.include
|
||||
endif
|
||||
@@ -191,3 +174,11 @@ endif
|
||||
if ENABLE_MODULE_SURJECTIONPROOF
|
||||
include src/modules/surjection/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_EXTRAKEYS
|
||||
include src/modules/extrakeys/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_SCHNORRSIG
|
||||
include src/modules/schnorrsig/Makefile.am.include
|
||||
endif
|
||||
|
||||
67
README.md
67
README.md
@@ -3,17 +3,22 @@ libsecp256k1
|
||||
|
||||
[](https://travis-ci.org/bitcoin-core/secp256k1)
|
||||
|
||||
Optimized C library for EC operations on curve secp256k1.
|
||||
Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1.
|
||||
|
||||
This library is a work in progress and is being used to research best practices. Use at your own risk.
|
||||
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.
|
||||
|
||||
Features:
|
||||
* secp256k1 ECDSA signing/verification and key generation.
|
||||
* Adding/multiplying private/public keys.
|
||||
* Serialization/parsing of private keys, public keys, signatures.
|
||||
* Constant time, constant memory access signing and pubkey generation.
|
||||
* Derandomized DSA (via RFC6979 or with a caller provided function.)
|
||||
* Additive and multiplicative tweaking of secret/public keys.
|
||||
* Serialization/parsing of secret keys, public keys, signatures.
|
||||
* Constant time, constant memory access signing and public key generation.
|
||||
* Derandomized ECDSA (via RFC6979 or with a caller provided function.)
|
||||
* Very efficient implementation.
|
||||
* Suitable for embedded systems.
|
||||
* Optional module for public key recovery.
|
||||
* Optional module for ECDH key exchange.
|
||||
|
||||
Experimental features have not received enough scrutiny to satisfy the standard of quality of this library but are made available for testing and review by the community. The APIs of these features should not be considered stable.
|
||||
|
||||
Implementation details
|
||||
----------------------
|
||||
@@ -23,11 +28,12 @@ Implementation details
|
||||
* Extensive testing infrastructure.
|
||||
* Structured to facilitate review and analysis.
|
||||
* Intended to be portable to any system with a C89 compiler and uint64_t support.
|
||||
* No use of floating types.
|
||||
* 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 10 26-bit limbs.
|
||||
* Using 10 26-bit limbs (including hand-optimized assembly for 32-bit ARM, by Wladimir J. van der Laan).
|
||||
* Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman).
|
||||
* Scalar operations
|
||||
* Optimized implementation without data-dependent branches of arithmetic modulo the curve's order.
|
||||
@@ -42,12 +48,14 @@ Implementation details
|
||||
* Use wNAF notation for point multiplicands.
|
||||
* Use a much larger window for multiples of G, using precomputed multiples.
|
||||
* Use Shamir's trick to do the multiplication with the public key and the generator simultaneously.
|
||||
* Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
|
||||
* Use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
|
||||
* Point multiplication for signing
|
||||
* Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
|
||||
* Access the table with branch-free conditional moves so memory access is uniform.
|
||||
* No data-dependent branches
|
||||
* The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally.
|
||||
* Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains)
|
||||
* Access the table with branch-free conditional moves so memory access is uniform.
|
||||
* No data-dependent branches
|
||||
* Optional runtime blinding which attempts to frustrate differential power analysis.
|
||||
* The precomputed tables add and eventually subtract points for which no known scalar (secret key) is known, preventing even an attacker with control over the secret key used to control the data internally.
|
||||
|
||||
Build steps
|
||||
-----------
|
||||
@@ -57,5 +65,40 @@ libsecp256k1 is built using autotools:
|
||||
$ ./autogen.sh
|
||||
$ ./configure
|
||||
$ make
|
||||
$ ./tests
|
||||
$ make check
|
||||
$ sudo make install # optional
|
||||
|
||||
Exhaustive tests
|
||||
-----------
|
||||
|
||||
$ ./exhaustive_tests
|
||||
|
||||
With valgrind, you might need to increase the max stack size:
|
||||
|
||||
$ valgrind --max-stackframe=2500000 ./exhaustive_tests
|
||||
|
||||
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:
|
||||
|
||||
$ gcovr --exclude 'src/bench*' --html --html-details -o coverage.html
|
||||
|
||||
Reporting a vulnerability
|
||||
------------
|
||||
|
||||
See [SECURITY.md](SECURITY.md)
|
||||
|
||||
15
SECURITY.md
Normal file
15
SECURITY.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
To report security issues send an email to secp256k1-security@bitcoincore.org (not for support).
|
||||
|
||||
The following keys may be used to communicate sensitive information to developers:
|
||||
|
||||
| Name | Fingerprint |
|
||||
|------|-------------|
|
||||
| Pieter Wuille | 133E AC17 9436 F14A 5CF1 B794 860F EB80 4E66 9320 |
|
||||
| Andrew Poelstra | 699A 63EF C17A D3A9 A34C FFC0 7AD0 A91C 40BD 0091 |
|
||||
| Tim Ruffing | 09E0 3F87 1092 E40E 106E 902B 33BC 86AB 80FF 5516 |
|
||||
|
||||
You can import a key by running the following command with that individual’s fingerprint: `gpg --recv-keys "<fingerprint>"` Ensure that you put quotes around fingerprints containing spaces.
|
||||
3
TODO
3
TODO
@@ -1,3 +0,0 @@
|
||||
* Unit tests for fieldelem/groupelem, including ones intended to
|
||||
trigger fieldelem's boundary cases.
|
||||
* Complete constant-time operations for signing/keygen
|
||||
@@ -1,140 +0,0 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_JNI_INCLUDE_DIR
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# AX_JNI_INCLUDE_DIR finds include directories needed for compiling
|
||||
# programs using the JNI interface.
|
||||
#
|
||||
# JNI include directories are usually in the Java distribution. This is
|
||||
# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in
|
||||
# that order. When this macro completes, a list of directories is left in
|
||||
# the variable JNI_INCLUDE_DIRS.
|
||||
#
|
||||
# Example usage follows:
|
||||
#
|
||||
# AX_JNI_INCLUDE_DIR
|
||||
#
|
||||
# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS
|
||||
# do
|
||||
# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR"
|
||||
# done
|
||||
#
|
||||
# If you want to force a specific compiler:
|
||||
#
|
||||
# - at the configure.in level, set JAVAC=yourcompiler before calling
|
||||
# AX_JNI_INCLUDE_DIR
|
||||
#
|
||||
# - at the configure level, setenv JAVAC
|
||||
#
|
||||
# Note: This macro can work with the autoconf M4 macros for Java programs.
|
||||
# This particular macro is not part of the original set of macros.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Don Anderson <dda@sleepycat.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 10
|
||||
|
||||
AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR])
|
||||
AC_DEFUN([AX_JNI_INCLUDE_DIR],[
|
||||
|
||||
JNI_INCLUDE_DIRS=""
|
||||
|
||||
if test "x$JAVA_HOME" != x; then
|
||||
_JTOPDIR="$JAVA_HOME"
|
||||
else
|
||||
if test "x$JAVAC" = x; then
|
||||
JAVAC=javac
|
||||
fi
|
||||
AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no])
|
||||
if test "x$_ACJNI_JAVAC" = xno; then
|
||||
AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME])
|
||||
fi
|
||||
_ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC")
|
||||
_JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'`
|
||||
fi
|
||||
|
||||
case "$host_os" in
|
||||
darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
|
||||
_JINC="$_JTOPDIR/Headers";;
|
||||
*) _JINC="$_JTOPDIR/include";;
|
||||
esac
|
||||
_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR])
|
||||
_AS_ECHO_LOG([_JINC=$_JINC])
|
||||
|
||||
# On Mac OS X 10.6.4, jni.h is a symlink:
|
||||
# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h
|
||||
# -> ../../CurrentJDK/Headers/jni.h.
|
||||
|
||||
AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path,
|
||||
[
|
||||
if test -f "$_JINC/jni.h"; then
|
||||
ac_cv_jni_header_path="$_JINC"
|
||||
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
|
||||
else
|
||||
_JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'`
|
||||
if test -f "$_JTOPDIR/include/jni.h"; then
|
||||
ac_cv_jni_header_path="$_JTOPDIR/include"
|
||||
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path"
|
||||
else
|
||||
ac_cv_jni_header_path=none
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
|
||||
# get the likely subdirectories for system specific java includes
|
||||
case "$host_os" in
|
||||
bsdi*) _JNI_INC_SUBDIRS="bsdos";;
|
||||
darwin*) _JNI_INC_SUBDIRS="darwin";;
|
||||
freebsd*) _JNI_INC_SUBDIRS="freebsd";;
|
||||
linux*) _JNI_INC_SUBDIRS="linux genunix";;
|
||||
osf*) _JNI_INC_SUBDIRS="alpha";;
|
||||
solaris*) _JNI_INC_SUBDIRS="solaris";;
|
||||
mingw*) _JNI_INC_SUBDIRS="win32";;
|
||||
cygwin*) _JNI_INC_SUBDIRS="win32";;
|
||||
*) _JNI_INC_SUBDIRS="genunix";;
|
||||
esac
|
||||
|
||||
if test "x$ac_cv_jni_header_path" != "xnone"; then
|
||||
# add any subdirectories that are present
|
||||
for JINCSUBDIR in $_JNI_INC_SUBDIRS
|
||||
do
|
||||
if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then
|
||||
JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
])
|
||||
|
||||
# _ACJNI_FOLLOW_SYMLINKS <path>
|
||||
# Follows symbolic links on <path>,
|
||||
# finally setting variable _ACJNI_FOLLOWED
|
||||
# ----------------------------------------
|
||||
AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[
|
||||
# find the include directory relative to the javac executable
|
||||
_cur="$1"
|
||||
while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do
|
||||
AC_MSG_CHECKING([symlink for $_cur])
|
||||
_slink=`ls -ld "$_cur" | sed 's/.* -> //'`
|
||||
case "$_slink" in
|
||||
/*) _cur="$_slink";;
|
||||
# 'X' avoids triggering unwanted echo options.
|
||||
*) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";;
|
||||
esac
|
||||
AC_MSG_RESULT([$_cur])
|
||||
done
|
||||
_ACJNI_FOLLOWED="$_cur"
|
||||
])# _ACJNI
|
||||
@@ -1,8 +1,3 @@
|
||||
dnl libsecp25k1 helper checks
|
||||
AC_DEFUN([SECP_INT128_CHECK],[
|
||||
has_int128=$ac_cv_type___int128
|
||||
])
|
||||
|
||||
dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell.
|
||||
AC_DEFUN([SECP_64BIT_ASM_CHECK],[
|
||||
AC_MSG_CHECKING(for x86_64 assembly availability)
|
||||
@@ -38,20 +33,45 @@ AC_DEFUN([SECP_OPENSSL_CHECK],[
|
||||
fi
|
||||
if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then
|
||||
AC_MSG_CHECKING(for EC functions in libcrypto)
|
||||
CPPFLAGS_TEMP="$CPPFLAGS"
|
||||
CPPFLAGS="$CRYPTO_CPPFLAGS $CPPFLAGS"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ecdsa.h>
|
||||
#include <openssl/obj_mac.h>]],[[
|
||||
EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
ECDSA_sign(0, NULL, 0, NULL, NULL, eckey);
|
||||
# if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) {(void)sig->r; (void)sig->s;}
|
||||
# endif
|
||||
|
||||
unsigned int zero = 0;
|
||||
const unsigned char *zero_ptr = (unsigned char*)&zero;
|
||||
EC_KEY_free(EC_KEY_new_by_curve_name(NID_secp256k1));
|
||||
EC_KEY *eckey = EC_KEY_new();
|
||||
EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp256k1);
|
||||
EC_KEY_set_group(eckey, group);
|
||||
ECDSA_sign(0, NULL, 0, NULL, &zero, eckey);
|
||||
ECDSA_verify(0, NULL, 0, NULL, 0, eckey);
|
||||
o2i_ECPublicKey(&eckey, &zero_ptr, 0);
|
||||
d2i_ECPrivateKey(&eckey, &zero_ptr, 0);
|
||||
EC_KEY_check_key(eckey);
|
||||
EC_KEY_free(eckey);
|
||||
EC_GROUP_free(group);
|
||||
ECDSA_SIG *sig_openssl;
|
||||
sig_openssl = ECDSA_SIG_new();
|
||||
(void)sig_openssl->r;
|
||||
d2i_ECDSA_SIG(&sig_openssl, &zero_ptr, 0);
|
||||
i2d_ECDSA_SIG(sig_openssl, NULL);
|
||||
ECDSA_SIG_get0(sig_openssl, NULL, NULL);
|
||||
ECDSA_SIG_free(sig_openssl);
|
||||
const BIGNUM *bignum = BN_value_one();
|
||||
BN_is_negative(bignum);
|
||||
BN_num_bits(bignum);
|
||||
if (sizeof(zero) >= BN_num_bytes(bignum)) {
|
||||
BN_bn2bin(bignum, (unsigned char*)&zero);
|
||||
}
|
||||
]])],[has_openssl_ec=yes],[has_openssl_ec=no])
|
||||
AC_MSG_RESULT([$has_openssl_ec])
|
||||
CPPFLAGS="$CPPFLAGS_TEMP"
|
||||
fi
|
||||
])
|
||||
|
||||
|
||||
415
configure.ac
415
configure.ac
@@ -7,6 +7,11 @@ AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
|
||||
AH_TOP([#define LIBSECP256K1_CONFIG_H])
|
||||
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
||||
|
||||
# Set -g if CFLAGS are not already set, which matches the default autoconf
|
||||
# behavior (see PROG_CC in the Autoconf manual) with the exception that we don't
|
||||
# set -O2 here because we set it in any case (see further down).
|
||||
: ${CFLAGS="-g"}
|
||||
LT_INIT
|
||||
|
||||
dnl make the compilation flags quiet unless V=1 is used
|
||||
@@ -19,10 +24,6 @@ AC_PATH_TOOL(RANLIB, ranlib)
|
||||
AC_PATH_TOOL(STRIP, strip)
|
||||
AX_PROG_CC_FOR_BUILD
|
||||
|
||||
if test "x$CFLAGS" = "x"; then
|
||||
CFLAGS="-g"
|
||||
fi
|
||||
|
||||
AM_PROG_CC_C_O
|
||||
|
||||
AC_PROG_CC_C89
|
||||
@@ -45,6 +46,7 @@ case $host_os in
|
||||
if test x$openssl_prefix != x; then
|
||||
PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
export PKG_CONFIG_PATH
|
||||
CRYPTO_CPPFLAGS="-I$openssl_prefix/include"
|
||||
fi
|
||||
if test x$gmp_prefix != x; then
|
||||
GMP_CPPFLAGS="-I$gmp_prefix/include"
|
||||
@@ -63,11 +65,11 @@ case $host_os in
|
||||
;;
|
||||
esac
|
||||
|
||||
CFLAGS="$CFLAGS -W"
|
||||
CFLAGS="-W $CFLAGS"
|
||||
|
||||
warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings"
|
||||
warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef -Wno-unused-function -Wno-long-long -Wno-overlength-strings"
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $warn_CFLAGS"
|
||||
CFLAGS="$warn_CFLAGS $CFLAGS"
|
||||
AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
|
||||
[ AC_MSG_RESULT([yes]) ],
|
||||
@@ -76,7 +78,7 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
|
||||
])
|
||||
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -fvisibility=hidden"
|
||||
CFLAGS="-fvisibility=hidden $CFLAGS"
|
||||
AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
|
||||
[ AC_MSG_RESULT([yes]) ],
|
||||
@@ -85,106 +87,144 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
|
||||
])
|
||||
|
||||
AC_ARG_ENABLE(benchmark,
|
||||
AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]),
|
||||
AS_HELP_STRING([--enable-benchmark],[compile benchmark [default=yes]]),
|
||||
[use_benchmark=$enableval],
|
||||
[use_benchmark=no])
|
||||
[use_benchmark=yes])
|
||||
|
||||
AC_ARG_ENABLE(coverage,
|
||||
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]),
|
||||
AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]),
|
||||
[enable_coverage=$enableval],
|
||||
[enable_coverage=no])
|
||||
|
||||
AC_ARG_ENABLE(tests,
|
||||
AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]),
|
||||
AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]),
|
||||
[use_tests=$enableval],
|
||||
[use_tests=yes])
|
||||
|
||||
AC_ARG_ENABLE(openssl_tests,
|
||||
AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]),
|
||||
AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests [default=auto]]),
|
||||
[enable_openssl_tests=$enableval],
|
||||
[enable_openssl_tests=auto])
|
||||
|
||||
AC_ARG_ENABLE(experimental,
|
||||
AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]),
|
||||
AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]),
|
||||
[use_experimental=$enableval],
|
||||
[use_experimental=no])
|
||||
|
||||
AC_ARG_ENABLE(exhaustive_tests,
|
||||
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]),
|
||||
AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests [default=yes]]),
|
||||
[use_exhaustive_tests=$enableval],
|
||||
[use_exhaustive_tests=yes])
|
||||
|
||||
AC_ARG_ENABLE(endomorphism,
|
||||
AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]),
|
||||
[use_endomorphism=$enableval],
|
||||
[use_endomorphism=no])
|
||||
|
||||
AC_ARG_ENABLE(ecmult_static_precomputation,
|
||||
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]),
|
||||
AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing [default=auto]]),
|
||||
[use_ecmult_static_precomputation=$enableval],
|
||||
[use_ecmult_static_precomputation=auto])
|
||||
|
||||
AC_ARG_ENABLE(module_ecdh,
|
||||
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]),
|
||||
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation]),
|
||||
[enable_module_ecdh=$enableval],
|
||||
[enable_module_ecdh=no])
|
||||
|
||||
AC_ARG_ENABLE(module_musig,
|
||||
AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]),
|
||||
[enable_module_musig=$enableval],
|
||||
[enable_module_musig=no])
|
||||
|
||||
AC_ARG_ENABLE(module_recovery,
|
||||
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]),
|
||||
AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module [default=no]]),
|
||||
[enable_module_recovery=$enableval],
|
||||
[enable_module_recovery=no])
|
||||
|
||||
AC_ARG_ENABLE(module_generator,
|
||||
AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module (default is no)]),
|
||||
AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module [default=no]]),
|
||||
[enable_module_generator=$enableval],
|
||||
[enable_module_generator=no])
|
||||
|
||||
AC_ARG_ENABLE(module_rangeproof,
|
||||
AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module (default is no)]),
|
||||
AS_HELP_STRING([--enable-module-rangeproof],[enable Pedersen / zero-knowledge range proofs module [default=no]]),
|
||||
[enable_module_rangeproof=$enableval],
|
||||
[enable_module_rangeproof=no])
|
||||
|
||||
AC_ARG_ENABLE(module_whitelist,
|
||||
AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module (default is no)]),
|
||||
AS_HELP_STRING([--enable-module-whitelist],[enable key whitelisting module [default=no]]),
|
||||
[enable_module_whitelist=$enableval],
|
||||
[enable_module_whitelist=no])
|
||||
|
||||
AC_ARG_ENABLE(jni,
|
||||
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
|
||||
[use_jni=$enableval],
|
||||
[use_jni=auto])
|
||||
AC_ARG_ENABLE(module_extrakeys,
|
||||
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module (experimental)]),
|
||||
[enable_module_extrakeys=$enableval],
|
||||
[enable_module_extrakeys=no])
|
||||
|
||||
AC_ARG_ENABLE(module_schnorrsig,
|
||||
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module (experimental)]),
|
||||
[enable_module_schnorrsig=$enableval],
|
||||
[enable_module_schnorrsig=no])
|
||||
|
||||
AC_ARG_ENABLE(external_default_callbacks,
|
||||
AS_HELP_STRING([--enable-external-default-callbacks],[enable external default callback functions [default=no]]),
|
||||
[use_external_default_callbacks=$enableval],
|
||||
[use_external_default_callbacks=no])
|
||||
|
||||
AC_ARG_ENABLE(module_surjectionproof,
|
||||
AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module (default is no)]),
|
||||
AS_HELP_STRING([--enable-module-surjectionproof],[enable surjection proof module [default=no]]),
|
||||
[enable_module_surjectionproof=$enableval],
|
||||
[enable_module_surjectionproof=no])
|
||||
|
||||
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
|
||||
[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto])
|
||||
AC_ARG_ENABLE(reduced_surjection_proof_size,
|
||||
AS_HELP_STRING([--enable-reduced-surjection-proof-size],[use reduced surjection proof size (disabling parsing and verification) [default=no]]),
|
||||
[use_reduced_surjection_proof_size=$enableval],
|
||||
[use_reduced_surjection_proof_size=no])
|
||||
|
||||
dnl Test-only override of the (autodetected by the C code) "widemul" setting.
|
||||
dnl Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
|
||||
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=auto])
|
||||
|
||||
AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto],
|
||||
[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto])
|
||||
[bignum implementation to use [default=auto]])],[req_bignum=$withval], [req_bignum=auto])
|
||||
|
||||
AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto],
|
||||
[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto])
|
||||
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto],
|
||||
[assembly optimizations to use (experimental: arm) [default=auto]])],[req_asm=$withval], [req_asm=auto])
|
||||
|
||||
AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto]
|
||||
[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[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].]
|
||||
[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.]
|
||||
[The table will store 2^(SIZE-1) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.]
|
||||
["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]]
|
||||
)],
|
||||
[req_ecmult_window=$withval], [req_ecmult_window=auto])
|
||||
|
||||
AC_CHECK_TYPES([__int128])
|
||||
AC_ARG_WITH([ecmult-gen-precision], [AS_HELP_STRING([--with-ecmult-gen-precision=2|4|8|auto],
|
||||
[Precision bits to tune the precomputed table size for signing.]
|
||||
[The size of the table is 32kB for 2 bits, 64kB for 4 bits, 512kB for 8 bits of precision.]
|
||||
[A larger table size usually results in possible faster signing.]
|
||||
["auto" is a reasonable setting for desktop machines (currently 4). [default=auto]]
|
||||
)],
|
||||
[req_ecmult_gen_precision=$withval], [req_ecmult_gen_precision=auto])
|
||||
|
||||
AC_MSG_CHECKING([for __builtin_expect])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
|
||||
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ],
|
||||
[ AC_MSG_RESULT([no])
|
||||
])
|
||||
AC_ARG_WITH([valgrind], [AS_HELP_STRING([--with-valgrind=yes|no|auto],
|
||||
[Build with extra checks for running inside Valgrind [default=auto]]
|
||||
)],
|
||||
[req_valgrind=$withval], [req_valgrind=auto])
|
||||
|
||||
if test x"$req_valgrind" = x"no"; then
|
||||
enable_valgrind=no
|
||||
else
|
||||
AC_CHECK_HEADER([valgrind/memcheck.h], [enable_valgrind=yes], [
|
||||
if test x"$req_valgrind" = x"yes"; then
|
||||
AC_MSG_ERROR([Valgrind support explicitly requested but valgrind/memcheck.h header not available])
|
||||
fi
|
||||
enable_valgrind=no
|
||||
], [])
|
||||
fi
|
||||
AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
|
||||
|
||||
if test x"$enable_coverage" = x"yes"; then
|
||||
AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
|
||||
CFLAGS="$CFLAGS -O0 --coverage"
|
||||
LDFLAGS="--coverage"
|
||||
CFLAGS="-O0 --coverage $CFLAGS"
|
||||
LDFLAGS="--coverage $LDFLAGS"
|
||||
else
|
||||
CFLAGS="$CFLAGS -O3"
|
||||
CFLAGS="-O2 $CFLAGS"
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for __builtin_popcount])
|
||||
@@ -194,27 +234,54 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_popcount(0);}]])],
|
||||
])
|
||||
|
||||
if test x"$use_ecmult_static_precomputation" != x"no"; then
|
||||
# Temporarily switch to an environment for the native compiler
|
||||
save_cross_compiling=$cross_compiling
|
||||
cross_compiling=no
|
||||
TEMP_CC="$CC"
|
||||
SAVE_CC="$CC"
|
||||
CC="$CC_FOR_BUILD"
|
||||
AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}])
|
||||
SAVE_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS_FOR_BUILD"
|
||||
SAVE_CPPFLAGS="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS_FOR_BUILD"
|
||||
SAVE_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS_FOR_BUILD"
|
||||
|
||||
warn_CFLAGS_FOR_BUILD="-Wall -Wextra -Wno-unused-function"
|
||||
saved_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$warn_CFLAGS_FOR_BUILD $CFLAGS"
|
||||
AC_MSG_CHECKING([if native ${CC_FOR_BUILD} supports ${warn_CFLAGS_FOR_BUILD}])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])],
|
||||
[ AC_MSG_RESULT([yes]) ],
|
||||
[ AC_MSG_RESULT([no])
|
||||
CFLAGS="$saved_CFLAGS"
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING([for working native compiler: ${CC_FOR_BUILD}])
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM([], [return 0])],
|
||||
[AC_LANG_PROGRAM([], [])],
|
||||
[working_native_cc=yes],
|
||||
[working_native_cc=no],[dnl])
|
||||
CC="$TEMP_CC"
|
||||
[working_native_cc=no],[:])
|
||||
|
||||
CFLAGS_FOR_BUILD="$CFLAGS"
|
||||
|
||||
# Restore the environment
|
||||
cross_compiling=$save_cross_compiling
|
||||
CC="$SAVE_CC"
|
||||
CFLAGS="$SAVE_CFLAGS"
|
||||
CPPFLAGS="$SAVE_CPPFLAGS"
|
||||
LDFLAGS="$SAVE_LDFLAGS"
|
||||
|
||||
if test x"$working_native_cc" = x"no"; then
|
||||
AC_MSG_RESULT([no])
|
||||
set_precomp=no
|
||||
m4_define([please_set_for_build], [Please set CC_FOR_BUILD, CFLAGS_FOR_BUILD, CPPFLAGS_FOR_BUILD, and/or LDFLAGS_FOR_BUILD.])
|
||||
if test x"$use_ecmult_static_precomputation" = x"yes"; then
|
||||
AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
|
||||
AC_MSG_ERROR([native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
|
||||
else
|
||||
AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD])
|
||||
AC_MSG_WARN([Disabling statically generated ecmult table because the native compiler ${CC_FOR_BUILD} does not produce working binaries. please_set_for_build])
|
||||
fi
|
||||
else
|
||||
AC_MSG_RESULT([ok])
|
||||
AC_MSG_RESULT([yes])
|
||||
set_precomp=yes
|
||||
fi
|
||||
else
|
||||
@@ -254,63 +321,6 @@ else
|
||||
esac
|
||||
fi
|
||||
|
||||
if test x"$req_field" = x"auto"; then
|
||||
if test x"set_asm" = x"x86_64"; then
|
||||
set_field=64bit
|
||||
fi
|
||||
if test x"$set_field" = x; then
|
||||
SECP_INT128_CHECK
|
||||
if test x"$has_int128" = x"yes"; then
|
||||
set_field=64bit
|
||||
fi
|
||||
fi
|
||||
if test x"$set_field" = x; then
|
||||
set_field=32bit
|
||||
fi
|
||||
else
|
||||
set_field=$req_field
|
||||
case $set_field in
|
||||
64bit)
|
||||
if test x"$set_asm" != x"x86_64"; then
|
||||
SECP_INT128_CHECK
|
||||
if test x"$has_int128" != x"yes"; then
|
||||
AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available])
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
32bit)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid field implementation selection])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test x"$req_scalar" = x"auto"; then
|
||||
SECP_INT128_CHECK
|
||||
if test x"$has_int128" = x"yes"; then
|
||||
set_scalar=64bit
|
||||
fi
|
||||
if test x"$set_scalar" = x; then
|
||||
set_scalar=32bit
|
||||
fi
|
||||
else
|
||||
set_scalar=$req_scalar
|
||||
case $set_scalar in
|
||||
64bit)
|
||||
SECP_INT128_CHECK
|
||||
if test x"$has_int128" != x"yes"; then
|
||||
AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available])
|
||||
fi
|
||||
;;
|
||||
32bit)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid scalar implementation selected])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test x"$req_bignum" = x"auto"; then
|
||||
SECP_GMP_CHECK
|
||||
if test x"$has_gmp" = x"yes"; then
|
||||
@@ -354,16 +364,18 @@ no)
|
||||
;;
|
||||
esac
|
||||
|
||||
# select field implementation
|
||||
case $set_field in
|
||||
64bit)
|
||||
AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation])
|
||||
# select wide multiplication implementation
|
||||
case $set_widemul in
|
||||
int128)
|
||||
AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation])
|
||||
;;
|
||||
32bit)
|
||||
AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation])
|
||||
int64)
|
||||
AC_DEFINE(USE_FORCE_WIDEMUL_INT64, 1, [Define this symbol to force the use of the (u)int64_t based wide multiplication implementation])
|
||||
;;
|
||||
auto)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid field implementation])
|
||||
AC_MSG_ERROR([invalid wide multiplication implementation])
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -385,25 +397,50 @@ no)
|
||||
;;
|
||||
esac
|
||||
|
||||
#select scalar implementation
|
||||
case $set_scalar in
|
||||
64bit)
|
||||
AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation])
|
||||
;;
|
||||
32bit)
|
||||
AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation])
|
||||
#set ecmult window size
|
||||
if test x"$req_ecmult_window" = x"auto"; then
|
||||
set_ecmult_window=15
|
||||
else
|
||||
set_ecmult_window=$req_ecmult_window
|
||||
fi
|
||||
|
||||
error_window_size=['window size for ecmult precomputation not an integer in range [2..24] or "auto"']
|
||||
case $set_ecmult_window in
|
||||
''|*[[!0-9]]*)
|
||||
# no valid integer
|
||||
AC_MSG_ERROR($error_window_size)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid scalar implementation])
|
||||
if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then
|
||||
# not in range
|
||||
AC_MSG_ERROR($error_window_size)
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(ECMULT_WINDOW_SIZE, $set_ecmult_window, [Set window size for ecmult precomputation])
|
||||
;;
|
||||
esac
|
||||
|
||||
#set ecmult gen precision
|
||||
if test x"$req_ecmult_gen_precision" = x"auto"; then
|
||||
set_ecmult_gen_precision=4
|
||||
else
|
||||
set_ecmult_gen_precision=$req_ecmult_gen_precision
|
||||
fi
|
||||
|
||||
case $set_ecmult_gen_precision in
|
||||
2|4|8)
|
||||
AC_DEFINE_UNQUOTED(ECMULT_GEN_PREC_BITS, $set_ecmult_gen_precision, [Set ecmult gen precision bits])
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"'])
|
||||
;;
|
||||
esac
|
||||
|
||||
if test x"$use_tests" = x"yes"; then
|
||||
SECP_OPENSSL_CHECK
|
||||
if test x"$has_openssl_ec" = x"yes"; then
|
||||
if test x"$enable_openssl_tests" != x"no"; then
|
||||
if test x"$enable_openssl_tests" != x"no" && test x"$has_openssl_ec" = x"yes"; then
|
||||
enable_openssl_tests=yes
|
||||
AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available])
|
||||
SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS"
|
||||
SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS $CRYPTO_CPPFLAGS"
|
||||
SECP_TEST_LIBS="$CRYPTO_LIBS"
|
||||
|
||||
case $host in
|
||||
@@ -411,39 +448,17 @@ if test x"$use_tests" = x"yes"; then
|
||||
SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
else
|
||||
if test x"$enable_openssl_tests" = x"yes"; then
|
||||
AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available])
|
||||
fi
|
||||
enable_openssl_tests=no
|
||||
fi
|
||||
else
|
||||
if test x"$enable_openssl_tests" = x"yes"; then
|
||||
AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$use_jni" != x"no"; then
|
||||
AX_JNI_INCLUDE_DIR
|
||||
have_jni_dependencies=yes
|
||||
if test x"$enable_module_ecdh" = x"no"; then
|
||||
have_jni_dependencies=no
|
||||
fi
|
||||
if test "x$JNI_INCLUDE_DIRS" = "x"; then
|
||||
have_jni_dependencies=no
|
||||
fi
|
||||
if test "x$have_jni_dependencies" = "xno"; then
|
||||
if test x"$use_jni" = x"yes"; then
|
||||
AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.])
|
||||
fi
|
||||
AC_MSG_WARN([jni headers/dependencies not found. jni support disabled])
|
||||
use_jni=no
|
||||
else
|
||||
use_jni=yes
|
||||
for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do
|
||||
JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR"
|
||||
done
|
||||
fi
|
||||
enable_openssl_tests=no
|
||||
fi
|
||||
|
||||
if test x"$set_bignum" = x"gmp"; then
|
||||
@@ -451,10 +466,6 @@ if test x"$set_bignum" = x"gmp"; then
|
||||
SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS"
|
||||
fi
|
||||
|
||||
if test x"$use_endomorphism" = x"yes"; then
|
||||
AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization])
|
||||
fi
|
||||
|
||||
if test x"$set_precomp" = x"yes"; then
|
||||
AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table])
|
||||
fi
|
||||
@@ -463,6 +474,10 @@ if test x"$enable_module_ecdh" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_musig" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_MUSIG, 1, [Define this symbol to enable the MuSig module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_recovery" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module])
|
||||
fi
|
||||
@@ -483,34 +498,49 @@ if test x"$enable_module_surjectionproof" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module])
|
||||
fi
|
||||
|
||||
AC_C_BIGENDIAN()
|
||||
if test x"$enable_module_schnorrsig" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module])
|
||||
enable_module_extrakeys=yes
|
||||
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
|
||||
AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module])
|
||||
fi
|
||||
|
||||
if test x"$use_external_asm" = x"yes"; then
|
||||
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
|
||||
fi
|
||||
|
||||
AC_MSG_NOTICE([Using static precomputation: $set_precomp])
|
||||
AC_MSG_NOTICE([Using assembly optimizations: $set_asm])
|
||||
AC_MSG_NOTICE([Using field implementation: $set_field])
|
||||
AC_MSG_NOTICE([Using bignum implementation: $set_bignum])
|
||||
AC_MSG_NOTICE([Using scalar implementation: $set_scalar])
|
||||
AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism])
|
||||
AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage])
|
||||
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
||||
AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery])
|
||||
AC_MSG_NOTICE([Using jni: $use_jni])
|
||||
if test x"$use_external_default_callbacks" = x"yes"; then
|
||||
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
|
||||
fi
|
||||
|
||||
if test x"$use_reduced_surjection_proof_size" = x"yes"; then
|
||||
AC_DEFINE(USE_REDUCED_SURJECTION_PROOF_SIZE, 1, [Define this symbol to reduce SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS to 16, disabling parsing and verification])
|
||||
fi
|
||||
|
||||
if test x"$enable_experimental" = x"yes"; then
|
||||
AC_MSG_NOTICE([******])
|
||||
AC_MSG_NOTICE([WARNING: experimental build])
|
||||
AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.])
|
||||
AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh])
|
||||
AC_MSG_NOTICE([Building NUMS generator module: $enable_module_generator])
|
||||
AC_MSG_NOTICE([Building range proof module: $enable_module_rangeproof])
|
||||
AC_MSG_NOTICE([Building key whitelisting module: $enable_module_whitelist])
|
||||
AC_MSG_NOTICE([Building surjection proof module: $enable_module_surjectionproof])
|
||||
AC_MSG_NOTICE([Building MuSig module: $enable_module_musig])
|
||||
AC_MSG_NOTICE([Building extrakeys module: $enable_module_extrakeys])
|
||||
AC_MSG_NOTICE([Building schnorrsig module: $enable_module_schnorrsig])
|
||||
AC_MSG_NOTICE([******])
|
||||
|
||||
|
||||
if test x"$enable_module_schnorrsig" != x"yes"; then
|
||||
if test x"$enable_module_musig" = x"yes"; then
|
||||
AC_MSG_ERROR([MuSig module requires the schnorrsig module. Use --enable-module-schnorrsig to allow.])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$enable_module_generator" != x"yes"; then
|
||||
if test x"$enable_module_rangeproof" = x"yes"; then
|
||||
AC_MSG_ERROR([Rangeproof module requires the generator module. Use --enable-module-generator to allow.])
|
||||
@@ -526,8 +556,14 @@ if test x"$enable_experimental" = x"yes"; then
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if test x"$enable_module_ecdh" = x"yes"; then
|
||||
AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.])
|
||||
if test x"$enable_module_musig" = x"yes"; then
|
||||
AC_MSG_ERROR([MuSig module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_extrakeys" = x"yes"; then
|
||||
AC_MSG_ERROR([extrakeys module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_schnorrsig" = x"yes"; then
|
||||
AC_MSG_ERROR([schnorrsig module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$set_asm" = x"arm"; then
|
||||
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
|
||||
@@ -548,7 +584,6 @@ fi
|
||||
|
||||
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
|
||||
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
|
||||
AC_SUBST(JNI_INCLUDES)
|
||||
AC_SUBST(SECP_INCLUDES)
|
||||
AC_SUBST(SECP_LIBS)
|
||||
AC_SUBST(SECP_TEST_LIBS)
|
||||
@@ -559,14 +594,17 @@ AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"])
|
||||
AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_MUSIG], [test x"$enable_module_musig" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"])
|
||||
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == 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([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
|
||||
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
|
||||
AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"])
|
||||
AM_CONDITIONAL([USE_REDUCED_SURJECTION_PROOF_SIZE], [test x"$use_reduced_surjection_proof_size" = x"yes"])
|
||||
|
||||
dnl make sure nothing new is exported so that we don't break the cache
|
||||
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
|
||||
@@ -574,3 +612,32 @@ unset PKG_CONFIG_PATH
|
||||
PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP"
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
echo
|
||||
echo "Build Options:"
|
||||
echo " with ecmult precomp = $set_precomp"
|
||||
echo " with external callbacks = $use_external_default_callbacks"
|
||||
echo " with benchmarks = $use_benchmark"
|
||||
echo " with tests = $use_tests"
|
||||
echo " with openssl tests = $enable_openssl_tests"
|
||||
echo " with coverage = $enable_coverage"
|
||||
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
|
||||
echo " asm = $set_asm"
|
||||
echo " bignum = $set_bignum"
|
||||
echo " ecmult window size = $set_ecmult_window"
|
||||
echo " ecmult gen prec. bits = $set_ecmult_gen_precision"
|
||||
dnl Hide test-only options unless they're used.
|
||||
if test x"$set_widemul" != xauto; then
|
||||
echo " wide multiplication = $set_widemul"
|
||||
fi
|
||||
echo
|
||||
echo " valgrind = $enable_valgrind"
|
||||
echo " CC = $CC"
|
||||
echo " CFLAGS = $CFLAGS"
|
||||
echo " CPPFLAGS = $CPPFLAGS"
|
||||
echo " LDFLAGS = $LDFLAGS"
|
||||
echo
|
||||
|
||||
@@ -32,7 +32,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
|
||||
lenbyte = input[pos++];
|
||||
if (lenbyte & 0x80) {
|
||||
lenbyte -= 0x80;
|
||||
if (pos + lenbyte > inputlen) {
|
||||
if (lenbyte > inputlen - pos) {
|
||||
return 0;
|
||||
}
|
||||
pos += lenbyte;
|
||||
@@ -51,7 +51,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
|
||||
lenbyte = input[pos++];
|
||||
if (lenbyte & 0x80) {
|
||||
lenbyte -= 0x80;
|
||||
if (pos + lenbyte > inputlen) {
|
||||
if (lenbyte > inputlen - pos) {
|
||||
return 0;
|
||||
}
|
||||
while (lenbyte > 0 && input[pos] == 0) {
|
||||
@@ -89,7 +89,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
|
||||
lenbyte = input[pos++];
|
||||
if (lenbyte & 0x80) {
|
||||
lenbyte -= 0x80;
|
||||
if (pos + lenbyte > inputlen) {
|
||||
if (lenbyte > inputlen - pos) {
|
||||
return 0;
|
||||
}
|
||||
while (lenbyte > 0 && input[pos] == 0) {
|
||||
@@ -112,7 +112,6 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
|
||||
return 0;
|
||||
}
|
||||
spos = pos;
|
||||
pos += slen;
|
||||
|
||||
/* Ignore leading zeroes in R */
|
||||
while (rlen > 0 && input[rpos] == 0) {
|
||||
|
||||
@@ -48,14 +48,14 @@
|
||||
* 8.3.1.
|
||||
*/
|
||||
|
||||
#ifndef _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
|
||||
#define _SECP256K1_CONTRIB_LAX_DER_PARSING_H_
|
||||
#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H
|
||||
#define SECP256K1_CONTRIB_LAX_DER_PARSING_H
|
||||
|
||||
#include <secp256k1.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/** Parse a signature in "lax DER" format
|
||||
*
|
||||
@@ -88,4 +88,4 @@ int ecdsa_signature_parse_der_lax(
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */
|
||||
|
||||
@@ -25,14 +25,14 @@
|
||||
* library are sufficient.
|
||||
*/
|
||||
|
||||
#ifndef _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
|
||||
#define _SECP256K1_CONTRIB_BER_PRIVATEKEY_H_
|
||||
#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H
|
||||
#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H
|
||||
|
||||
#include <secp256k1.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/** Export a private key in DER format.
|
||||
*
|
||||
@@ -87,4 +87,4 @@ SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der(
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */
|
||||
|
||||
69
contrib/travis.sh
Executable file
69
contrib/travis.sh
Executable file
@@ -0,0 +1,69 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
if [ "$HOST" = "i686-linux-gnu" ]
|
||||
then
|
||||
export CC="$CC -m32"
|
||||
fi
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$TRAVIS_COMPILER" = "gcc" ]
|
||||
then
|
||||
export CC="gcc-9"
|
||||
fi
|
||||
|
||||
./configure \
|
||||
--enable-experimental="$EXPERIMENTAL" \
|
||||
--with-test-override-wide-multiply="$WIDEMUL" --with-bignum="$BIGNUM" --with-asm="$ASM" \
|
||||
--enable-ecmult-static-precomputation="$STATICPRECOMPUTATION" --with-ecmult-gen-precision="$ECMULTGENPRECISION" \
|
||||
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
|
||||
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
|
||||
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG"\
|
||||
--with-valgrind="$WITH_VALGRIND" \
|
||||
--host="$HOST" $EXTRAFLAGS
|
||||
|
||||
if [ -n "$BUILD" ]
|
||||
then
|
||||
make -j2 "$BUILD"
|
||||
fi
|
||||
if [ "$RUN_VALGRIND" = "yes" ]
|
||||
then
|
||||
make -j2
|
||||
# the `--error-exitcode` is required to make the test fail if valgrind found errors, otherwise it'll return 0 (http://valgrind.org/docs/manual/manual-core.html)
|
||||
valgrind --error-exitcode=42 ./tests 16
|
||||
valgrind --error-exitcode=42 ./exhaustive_tests
|
||||
fi
|
||||
if [ "$BENCH" = "yes" ]
|
||||
then
|
||||
if [ "$RUN_VALGRIND" = "yes" ]
|
||||
then
|
||||
# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
|
||||
EXEC='./libtool --mode=execute valgrind --error-exitcode=42'
|
||||
else
|
||||
EXEC=
|
||||
fi
|
||||
# This limits the iterations in the benchmarks below to ITER(set in .travis.yml) iterations.
|
||||
export SECP256K1_BENCH_ITERS="$ITERS"
|
||||
{
|
||||
$EXEC ./bench_ecmult
|
||||
$EXEC ./bench_internal
|
||||
$EXEC ./bench_sign
|
||||
$EXEC ./bench_verify
|
||||
} >> bench.log 2>&1
|
||||
if [ "$RECOVERY" = "yes" ]
|
||||
then
|
||||
$EXEC ./bench_recover >> bench.log 2>&1
|
||||
fi
|
||||
if [ "$ECDH" = "yes" ]
|
||||
then
|
||||
$EXEC ./bench_ecdh >> bench.log 2>&1
|
||||
fi
|
||||
if [ "$SCHNORRSIG" = "yes" ]
|
||||
then
|
||||
$EXEC ./bench_schnorrsig >> bench.log 2>&1
|
||||
fi
|
||||
fi
|
||||
if [ "$CTIMETEST" = "yes" ]
|
||||
then
|
||||
./libtool --mode=execute valgrind --error-exitcode=42 ./valgrind_ctime_test > valgrind_ctime_test.log 2>&1
|
||||
fi
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef _SECP256K1_
|
||||
# define _SECP256K1_
|
||||
#ifndef SECP256K1_H
|
||||
#define SECP256K1_H
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -14,7 +14,7 @@ extern "C" {
|
||||
* 2. Array lengths always immediately the follow the argument whose length
|
||||
* they describe, even if this violates rule 1.
|
||||
* 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated
|
||||
* later go first. This means: signatures, public nonces, private nonces,
|
||||
* later go first. This means: signatures, public nonces, secret nonces,
|
||||
* messages, public keys, secret keys, tweaks.
|
||||
* 4. Arguments that are not data pointers go last, from more complex to less
|
||||
* complex: function pointers, algorithm names, messages, void pointers,
|
||||
@@ -33,15 +33,29 @@ extern "C" {
|
||||
* verification).
|
||||
*
|
||||
* A constructed context can safely be used from multiple threads
|
||||
* simultaneously, but API call that take a non-const pointer to a context
|
||||
* simultaneously, but API calls that take a non-const pointer to a context
|
||||
* need exclusive access to it. In particular this is the case for
|
||||
* secp256k1_context_destroy and secp256k1_context_randomize.
|
||||
* secp256k1_context_destroy, secp256k1_context_preallocated_destroy,
|
||||
* and secp256k1_context_randomize.
|
||||
*
|
||||
* Regarding randomization, either do it once at creation time (in which case
|
||||
* you do not need any locking for the other calls), or use a read-write lock.
|
||||
*/
|
||||
typedef struct secp256k1_context_struct secp256k1_context;
|
||||
|
||||
/** Opaque data structure that holds rewriteable "scratch space"
|
||||
*
|
||||
* The purpose of this structure is to replace dynamic memory allocations,
|
||||
* because we target architectures where this may not be available. It is
|
||||
* essentially a resizable (within specified parameters) block of bytes,
|
||||
* which is initially created either by memory allocation or TODO as a pointer
|
||||
* into some fixed rewritable space.
|
||||
*
|
||||
* Unlike the context object, this cannot safely be shared between threads
|
||||
* without additional synchronization logic.
|
||||
*/
|
||||
typedef struct secp256k1_scratch_space_struct secp256k1_scratch_space;
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid public key.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
@@ -61,7 +75,7 @@ typedef struct {
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage, transmission, or
|
||||
* comparison, use the secp256k1_ecdsa_signature_serialize_* and
|
||||
* secp256k1_ecdsa_signature_serialize_* functions.
|
||||
* secp256k1_ecdsa_signature_parse_* functions.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
@@ -120,7 +134,7 @@ typedef int (*secp256k1_nonce_function)(
|
||||
# else
|
||||
# define SECP256K1_API
|
||||
# endif
|
||||
# elif defined(__GNUC__) && defined(SECP256K1_BUILD)
|
||||
# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
|
||||
# define SECP256K1_API __attribute__ ((visibility ("default")))
|
||||
# else
|
||||
# define SECP256K1_API
|
||||
@@ -148,18 +162,39 @@ typedef int (*secp256k1_nonce_function)(
|
||||
/** The higher bits contain the actual data. Do not use directly. */
|
||||
#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
|
||||
#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
|
||||
#define SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY (1 << 10)
|
||||
#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
|
||||
|
||||
/** Flags to pass to secp256k1_context_create. */
|
||||
/** Flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
|
||||
* secp256k1_context_preallocated_create. */
|
||||
#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
|
||||
#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
|
||||
#define SECP256K1_CONTEXT_DECLASSIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_DECLASSIFY)
|
||||
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
|
||||
|
||||
/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */
|
||||
/** Flag to pass to secp256k1_ec_pubkey_serialize. */
|
||||
#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
|
||||
#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)
|
||||
|
||||
/** Create a secp256k1 context object.
|
||||
/** Prefix byte used to tag various encoded curvepoints for specific purposes */
|
||||
#define SECP256K1_TAG_PUBKEY_EVEN 0x02
|
||||
#define SECP256K1_TAG_PUBKEY_ODD 0x03
|
||||
#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04
|
||||
#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06
|
||||
#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07
|
||||
|
||||
/** A simple secp256k1 context object with no precomputed tables. These are useful for
|
||||
* type serialization/parsing functions which require a context object to maintain
|
||||
* API consistency, but currently do not require expensive precomputations or dynamic
|
||||
* allocations.
|
||||
*/
|
||||
SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
|
||||
|
||||
/** Create a secp256k1 context object (in dynamically allocated memory).
|
||||
*
|
||||
* This function uses malloc to allocate memory. It is guaranteed that malloc is
|
||||
* called at most once for every call of this function. If you need to avoid dynamic
|
||||
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
|
||||
*
|
||||
* Returns: a newly created context object.
|
||||
* In: flags: which parts of the context to initialize.
|
||||
@@ -170,7 +205,11 @@ SECP256K1_API secp256k1_context* secp256k1_context_create(
|
||||
unsigned int flags
|
||||
) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Copies a secp256k1 context object.
|
||||
/** Copy a secp256k1 context object (into dynamically allocated memory).
|
||||
*
|
||||
* This function uses malloc to allocate memory. It is guaranteed that malloc is
|
||||
* called at most once for every call of this function. If you need to avoid dynamic
|
||||
* memory allocation entirely, see the functions in secp256k1_preallocated.h.
|
||||
*
|
||||
* Returns: a newly created context object.
|
||||
* Args: ctx: an existing context to copy (cannot be NULL)
|
||||
@@ -179,10 +218,18 @@ SECP256K1_API secp256k1_context* secp256k1_context_clone(
|
||||
const secp256k1_context* ctx
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Destroy a secp256k1 context object.
|
||||
/** Destroy a secp256k1 context object (created in dynamically allocated memory).
|
||||
*
|
||||
* The context pointer may not be used afterwards.
|
||||
* Args: ctx: an existing context to destroy (cannot be NULL)
|
||||
*
|
||||
* The context to destroy must have been created using secp256k1_context_create
|
||||
* or secp256k1_context_clone. If the context has instead been created using
|
||||
* secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone, the
|
||||
* behaviour is undefined. In that case, secp256k1_context_preallocated_destroy must
|
||||
* be used instead.
|
||||
*
|
||||
* Args: ctx: an existing context to destroy, constructed using
|
||||
* secp256k1_context_create or secp256k1_context_clone
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_destroy(
|
||||
secp256k1_context* ctx
|
||||
@@ -202,11 +249,28 @@ SECP256K1_API void secp256k1_context_destroy(
|
||||
* to cause a crash, though its return value and output arguments are
|
||||
* undefined.
|
||||
*
|
||||
* When this function has not been called (or called with fn==NULL), then the
|
||||
* default handler will be used. The library provides a default handler which
|
||||
* writes the message to stderr and calls abort. This default handler can be
|
||||
* replaced at link time if the preprocessor macro
|
||||
* USE_EXTERNAL_DEFAULT_CALLBACKS is defined, which is the case if the build
|
||||
* has been configured with --enable-external-default-callbacks. Then the
|
||||
* following two symbols must be provided to link against:
|
||||
* - void secp256k1_default_illegal_callback_fn(const char* message, void* data);
|
||||
* - void secp256k1_default_error_callback_fn(const char* message, void* data);
|
||||
* The library can call these default handlers even before a proper callback data
|
||||
* pointer could have been set using secp256k1_context_set_illegal_callback or
|
||||
* secp256k1_context_set_error_callback, e.g., when the creation of a context
|
||||
* fails. In this case, the corresponding default handler will be called with
|
||||
* the data pointer argument set to NULL.
|
||||
*
|
||||
* Args: ctx: an existing context object (cannot be NULL)
|
||||
* In: fun: a pointer to a function to call when an illegal argument is
|
||||
* passed to the API, taking a message and an opaque pointer
|
||||
* (NULL restores a default handler that calls abort).
|
||||
* passed to the API, taking a message and an opaque pointer.
|
||||
* (NULL restores the default handler.)
|
||||
* data: the opaque pointer to pass to fun above.
|
||||
*
|
||||
* See also secp256k1_context_set_error_callback.
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_set_illegal_callback(
|
||||
secp256k1_context* ctx,
|
||||
@@ -226,9 +290,12 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
|
||||
*
|
||||
* Args: ctx: an existing context object (cannot be NULL)
|
||||
* In: fun: a pointer to a function to call when an internal error occurs,
|
||||
* taking a message and an opaque pointer (NULL restores a default
|
||||
* handler that calls abort).
|
||||
* taking a message and an opaque pointer (NULL restores the
|
||||
* default handler, see secp256k1_context_set_illegal_callback
|
||||
* for details).
|
||||
* data: the opaque pointer to pass to fun above.
|
||||
*
|
||||
* See also secp256k1_context_set_illegal_callback.
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_set_error_callback(
|
||||
secp256k1_context* ctx,
|
||||
@@ -236,6 +303,29 @@ SECP256K1_API void secp256k1_context_set_error_callback(
|
||||
const void* data
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Create a secp256k1 scratch space object.
|
||||
*
|
||||
* Returns: a newly created scratch space.
|
||||
* Args: ctx: an existing context object (cannot be NULL)
|
||||
* In: size: amount of memory to be available as scratch space. Some extra
|
||||
* (<100 bytes) will be allocated for extra accounting.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_scratch_space_create(
|
||||
const secp256k1_context* ctx,
|
||||
size_t size
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Destroy a secp256k1 scratch space.
|
||||
*
|
||||
* The pointer may not be used afterwards.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* scratch: space to destroy
|
||||
*/
|
||||
SECP256K1_API void secp256k1_scratch_space_destroy(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_scratch_space* scratch
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Parse a variable-length public key into the pubkey object.
|
||||
*
|
||||
* Returns: 1 if the public key was fully valid.
|
||||
@@ -441,7 +531,7 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def
|
||||
/** Create an ECDSA signature.
|
||||
*
|
||||
* Returns: 1: signature created
|
||||
* 0: the nonce generation function failed, or the private key was invalid.
|
||||
* 0: the nonce generation function failed, or the secret key was invalid.
|
||||
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
|
||||
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
|
||||
@@ -462,6 +552,11 @@ SECP256K1_API int secp256k1_ecdsa_sign(
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Verify an ECDSA secret key.
|
||||
*
|
||||
* A secret key is valid if it is not 0 and less than the secp256k1 curve order
|
||||
* when interpreted as an integer (most significant byte first). The
|
||||
* probability of choosing a 32-byte string uniformly at random which is an
|
||||
* invalid secret key is negligible.
|
||||
*
|
||||
* Returns: 1: secret key is valid
|
||||
* 0: secret key is invalid
|
||||
@@ -479,7 +574,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
|
||||
* 0: secret was invalid, try again
|
||||
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
* Out: pubkey: pointer to the created public key (cannot be NULL)
|
||||
* In: seckey: pointer to a 32-byte private key (cannot be NULL)
|
||||
* In: seckey: pointer to a 32-byte secret key (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
|
||||
const secp256k1_context* ctx,
|
||||
@@ -487,12 +582,24 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Negates a private key in place.
|
||||
/** Negates a secret key in place.
|
||||
*
|
||||
* Returns: 1 always
|
||||
* Args: ctx: pointer to a context object
|
||||
* In/Out: pubkey: pointer to the public key to be negated (cannot be NULL)
|
||||
* Returns: 0 if the given secret key is invalid according to
|
||||
* secp256k1_ec_seckey_verify. 1 otherwise
|
||||
* Args: ctx: pointer to a context object
|
||||
* In/Out: seckey: pointer to the 32-byte secret key to be negated. If the
|
||||
* secret key is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0 and
|
||||
* seckey will be set to some unspecified value. (cannot be
|
||||
* NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Same as secp256k1_ec_seckey_negate, but DEPRECATED. Will be removed in
|
||||
* future versions. */
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey
|
||||
@@ -509,15 +616,29 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
|
||||
secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Tweak a private key by adding tweak to it.
|
||||
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
|
||||
* uniformly random 32-byte arrays, or if the resulting private key
|
||||
* would be invalid (only when the tweak is the complement of the
|
||||
* private key). 1 otherwise.
|
||||
* Args: ctx: pointer to a context object (cannot be NULL).
|
||||
* In/Out: seckey: pointer to a 32-byte private key.
|
||||
* In: tweak: pointer to a 32-byte tweak.
|
||||
/** Tweak a secret key by adding tweak to it.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting secret key would be
|
||||
* invalid (only when the tweak is the negation of the secret key). 1
|
||||
* otherwise.
|
||||
* Args: ctx: pointer to a context object (cannot be NULL).
|
||||
* In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
|
||||
* invalid according to secp256k1_ec_seckey_verify, this
|
||||
* function returns 0. seckey will be set to some unspecified
|
||||
* value if this function returns 0. (cannot be NULL)
|
||||
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128) (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *tweak
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Same as secp256k1_ec_seckey_tweak_add, but DEPRECATED. Will be removed in
|
||||
* future versions. */
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey,
|
||||
@@ -525,14 +646,18 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Tweak a public key by adding tweak times the generator to it.
|
||||
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
|
||||
* uniformly random 32-byte arrays, or if the resulting public key
|
||||
* would be invalid (only when the tweak is the complement of the
|
||||
* corresponding private key). 1 otherwise.
|
||||
* Args: ctx: pointer to a context object initialized for validation
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting public key would be
|
||||
* invalid (only when the tweak is the negation of the corresponding
|
||||
* secret key). 1 otherwise.
|
||||
* Args: ctx: pointer to a context object initialized for validation
|
||||
* (cannot be NULL).
|
||||
* In/Out: pubkey: pointer to a public key object.
|
||||
* In: tweak: pointer to a 32-byte tweak.
|
||||
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
|
||||
* invalid value if this function returns 0 (cannot be NULL).
|
||||
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128) (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
@@ -540,13 +665,27 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
|
||||
const unsigned char *tweak
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Tweak a private key by multiplying it by a tweak.
|
||||
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
|
||||
* uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object (cannot be NULL).
|
||||
* In/Out: seckey: pointer to a 32-byte private key.
|
||||
* In: tweak: pointer to a 32-byte tweak.
|
||||
/** Tweak a secret key by multiplying it by a tweak.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object (cannot be NULL).
|
||||
* In/Out: seckey: pointer to a 32-byte secret key. If the secret key is
|
||||
* invalid according to secp256k1_ec_seckey_verify, this
|
||||
* function returns 0. seckey will be set to some unspecified
|
||||
* value if this function returns 0. (cannot be NULL)
|
||||
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128) (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey,
|
||||
const unsigned char *tweak
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Same as secp256k1_ec_seckey_tweak_mul, but DEPRECATED. Will be removed in
|
||||
* future versions. */
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *seckey,
|
||||
@@ -554,12 +693,16 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Tweak a public key by multiplying it by a tweak value.
|
||||
* Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for
|
||||
* uniformly random 32-byte arrays, or equal to zero. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object initialized for validation
|
||||
* (cannot be NULL).
|
||||
* In/Out: pubkey: pointer to a public key obkect.
|
||||
* In: tweak: pointer to a 32-byte tweak.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object initialized for validation
|
||||
* (cannot be NULL).
|
||||
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
|
||||
* invalid value if this function returns 0 (cannot be NULL).
|
||||
* In: tweak: pointer to a 32-byte tweak. If the tweak is invalid according to
|
||||
* secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128) (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
|
||||
const secp256k1_context* ctx,
|
||||
@@ -568,7 +711,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Updates the context randomization to protect against side-channel leakage.
|
||||
* Returns: 1: randomization successfully updated
|
||||
* Returns: 1: randomization successfully updated or nothing to randomize
|
||||
* 0: error
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
|
||||
@@ -583,8 +726,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
|
||||
* that it does not affect function results, but shields against attacks which
|
||||
* rely on any input-dependent behaviour.
|
||||
*
|
||||
* This function has currently an effect only on contexts initialized for signing
|
||||
* because randomization is currently used only for signing. However, this is not
|
||||
* guaranteed and may change in the future. It is safe to call this function on
|
||||
* contexts not initialized for signing; then it will have no effect and return 1.
|
||||
*
|
||||
* You should call this after secp256k1_context_create or
|
||||
* secp256k1_context_clone, and may call this repeatedly afterwards.
|
||||
* secp256k1_context_clone (and secp256k1_context_preallocated_create or
|
||||
* secp256k1_context_clone, resp.), and you may call this repeatedly afterwards.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
|
||||
secp256k1_context* ctx,
|
||||
@@ -592,6 +741,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Add a number of public keys together.
|
||||
*
|
||||
* Returns: 1: the sum of the public keys is valid.
|
||||
* 0: the sum of the public keys is not valid.
|
||||
* Args: ctx: pointer to a context object
|
||||
@@ -607,8 +757,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
|
||||
size_t n
|
||||
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_H */
|
||||
|
||||
@@ -1,31 +1,62 @@
|
||||
#ifndef _SECP256K1_ECDH_
|
||||
# define _SECP256K1_ECDH_
|
||||
#ifndef SECP256K1_ECDH_H
|
||||
#define SECP256K1_ECDH_H
|
||||
|
||||
# include "secp256k1.h"
|
||||
#include "secp256k1.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/** A pointer to a function that hashes an EC point to obtain an ECDH secret
|
||||
*
|
||||
* Returns: 1 if the point was successfully hashed.
|
||||
* 0 will cause secp256k1_ecdh to fail and return 0.
|
||||
* Other return values are not allowed, and the behaviour of
|
||||
* secp256k1_ecdh is undefined for other return values.
|
||||
* Out: output: pointer to an array to be filled by the function
|
||||
* In: x32: pointer to a 32-byte x coordinate
|
||||
* y32: pointer to a 32-byte y coordinate
|
||||
* data: arbitrary data pointer that is passed through
|
||||
*/
|
||||
typedef int (*secp256k1_ecdh_hash_function)(
|
||||
unsigned char *output,
|
||||
const unsigned char *x32,
|
||||
const unsigned char *y32,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** An implementation of SHA256 hash function that applies to compressed public key.
|
||||
* Populates the output parameter with 32 bytes. */
|
||||
SECP256K1_API extern 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 extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
|
||||
|
||||
/** Compute an EC Diffie-Hellman secret in constant time
|
||||
*
|
||||
* Returns: 1: exponentiation was successful
|
||||
* 0: scalar was invalid (zero or overflow)
|
||||
* 0: scalar was invalid (zero or overflow) or hashfp returned 0
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* Out: result: a 32-byte array which will be populated by an ECDH
|
||||
* secret computed from the point and scalar
|
||||
* Out: output: pointer to an array to be filled by hashfp
|
||||
* In: pubkey: a pointer to a secp256k1_pubkey containing an
|
||||
* initialized public key
|
||||
* privkey: a 32-byte scalar with which to multiply the point
|
||||
* seckey: a 32-byte scalar with which to multiply the point
|
||||
* hashfp: pointer to a hash function. If NULL, secp256k1_ecdh_hash_function_sha256 is used
|
||||
* (in which case, 32 bytes will be written to output)
|
||||
* data: arbitrary data pointer that is passed through to hashfp
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *result,
|
||||
unsigned char *output,
|
||||
const secp256k1_pubkey *pubkey,
|
||||
const unsigned char *privkey
|
||||
const unsigned char *seckey,
|
||||
secp256k1_ecdh_hash_function hashfp,
|
||||
void *data
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_ECDH_H */
|
||||
|
||||
236
include/secp256k1_extrakeys.h
Normal file
236
include/secp256k1_extrakeys.h
Normal file
@@ -0,0 +1,236 @@
|
||||
#ifndef SECP256K1_EXTRAKEYS_H
|
||||
#define SECP256K1_EXTRAKEYS_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Opaque data structure that holds a parsed and valid "x-only" public key.
|
||||
* An x-only pubkey encodes a point whose Y coordinate is even. It is
|
||||
* serialized using only its X coordinate (32 bytes). See BIP-340 for more
|
||||
* information about x-only pubkeys.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage, transmission, or
|
||||
* comparison, use secp256k1_xonly_pubkey_serialize and
|
||||
* secp256k1_xonly_pubkey_parse.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} secp256k1_xonly_pubkey;
|
||||
|
||||
/** Opaque data structure that holds a keypair consisting of a secret and a
|
||||
* public key.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 96 bytes in size, and can be safely copied/moved.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[96];
|
||||
} secp256k1_keypair;
|
||||
|
||||
/** Parse a 32-byte sequence into a xonly_pubkey object.
|
||||
*
|
||||
* Returns: 1 if the public key was fully valid.
|
||||
* 0 if the public key could not be parsed or is invalid.
|
||||
*
|
||||
* Args: ctx: a secp256k1 context object (cannot be NULL).
|
||||
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
|
||||
* parsed version of input. If not, it's set to an invalid value.
|
||||
* (cannot be NULL).
|
||||
* In: input32: pointer to a serialized xonly_pubkey (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_xonly_pubkey* pubkey,
|
||||
const unsigned char *input32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize an xonly_pubkey object into a 32-byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
*
|
||||
* Args: ctx: a secp256k1 context object (cannot be NULL).
|
||||
* Out: output32: a pointer to a 32-byte array to place the serialized key in
|
||||
* (cannot be NULL).
|
||||
* In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an
|
||||
* initialized public key (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API int secp256k1_xonly_pubkey_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output32,
|
||||
const secp256k1_xonly_pubkey* pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
|
||||
*
|
||||
* Returns: 1 if the public key was successfully converted
|
||||
* 0 otherwise
|
||||
*
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* Out: xonly_pubkey: pointer to an x-only public key object for placing the
|
||||
* converted public key (cannot be NULL)
|
||||
* pk_parity: pointer to an integer that will be set to 1 if the point
|
||||
* encoded by xonly_pubkey is the negation of the pubkey and
|
||||
* set to 0 otherwise. (can be NULL)
|
||||
* In: pubkey: pointer to a public key that is converted (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_xonly_pubkey *xonly_pubkey,
|
||||
int *pk_parity,
|
||||
const secp256k1_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Tweak an x-only public key by adding the generator multiplied with tweak32
|
||||
* to it.
|
||||
*
|
||||
* Note that the resulting point can not in general be represented by an x-only
|
||||
* pubkey because it may have an odd Y coordinate. Instead, the output_pubkey
|
||||
* is a normal secp256k1_pubkey.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting public key would be
|
||||
* invalid (only when the tweak is the negation of the corresponding
|
||||
* secret key). 1 otherwise.
|
||||
*
|
||||
* Args: ctx: pointer to a context object initialized for verification
|
||||
* (cannot be NULL)
|
||||
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
||||
* to an invalid value if this function returns 0 (cannot
|
||||
* be NULL)
|
||||
* In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
|
||||
* (cannot be NULL).
|
||||
* tweak32: pointer to a 32-byte tweak. If the tweak is invalid
|
||||
* according to secp256k1_ec_seckey_verify, this function
|
||||
* returns 0. For uniformly random 32-byte arrays the
|
||||
* chance of being invalid is negligible (around 1 in
|
||||
* 2^128) (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *output_pubkey,
|
||||
const secp256k1_xonly_pubkey *internal_pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Checks that a tweaked pubkey is the result of calling
|
||||
* secp256k1_xonly_pubkey_tweak_add with internal_pubkey and tweak32.
|
||||
*
|
||||
* The tweaked pubkey is represented by its 32-byte x-only serialization and
|
||||
* its pk_parity, which can both be obtained by converting the result of
|
||||
* tweak_add to a secp256k1_xonly_pubkey.
|
||||
*
|
||||
* Note that this alone does _not_ verify that the tweaked pubkey is a
|
||||
* commitment. If the tweak is not chosen in a specific way, the tweaked pubkey
|
||||
* can easily be the result of a different internal_pubkey and tweak.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the tweaked pubkey is not the
|
||||
* result of tweaking the internal_pubkey with tweak32. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object initialized for verification
|
||||
* (cannot be NULL)
|
||||
* In: tweaked_pubkey32: pointer to a serialized xonly_pubkey (cannot be NULL)
|
||||
* tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization
|
||||
* is passed in as tweaked_pubkey32). This must match the
|
||||
* pk_parity value that is returned when calling
|
||||
* secp256k1_xonly_pubkey with the tweaked pubkey, or
|
||||
* this function will fail.
|
||||
* internal_pubkey: pointer to an x-only public key object to apply the
|
||||
* tweak to (cannot be NULL)
|
||||
* tweak32: pointer to a 32-byte tweak (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char *tweaked_pubkey32,
|
||||
int tweaked_pk_parity,
|
||||
const secp256k1_xonly_pubkey *internal_pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Compute the keypair for a secret key.
|
||||
*
|
||||
* Returns: 1: secret was valid, keypair is ready to use
|
||||
* 0: secret was invalid, try again with a different secret
|
||||
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
* Out: keypair: pointer to the created keypair (cannot be NULL)
|
||||
* In: seckey: pointer to a 32-byte secret key (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_keypair *keypair,
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Get the public key from a keypair.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* 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.
|
||||
* (cannot be NULL)
|
||||
* In: keypair: pointer to a keypair (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pubkey *pubkey,
|
||||
const secp256k1_keypair *keypair
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Get the x-only public key from a keypair.
|
||||
*
|
||||
* This is the same as calling secp256k1_keypair_pub and then
|
||||
* secp256k1_xonly_pubkey_from_pubkey.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid. 1 otherwise.
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* 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 (cannot be
|
||||
* NULL).
|
||||
* pk_parity: pointer to an integer that will be set to the pk_parity
|
||||
* argument of secp256k1_xonly_pubkey_from_pubkey (can be NULL).
|
||||
* In: keypair: pointer to a keypair (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_xonly_pubkey *pubkey,
|
||||
int *pk_parity,
|
||||
const secp256k1_keypair *keypair
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Tweak a keypair by adding tweak32 to the secret key and updating the public
|
||||
* key accordingly.
|
||||
*
|
||||
* Calling this function and then secp256k1_keypair_pub results in the same
|
||||
* public key as calling secp256k1_keypair_xonly_pub and then
|
||||
* secp256k1_xonly_pubkey_tweak_add.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting keypair would be
|
||||
* invalid (only when the tweak is the negation of the keypair's
|
||||
* secret key). 1 otherwise.
|
||||
*
|
||||
* Args: ctx: pointer to a context object initialized for verification
|
||||
* (cannot be NULL)
|
||||
* In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
|
||||
* an invalid value if this function returns 0 (cannot be
|
||||
* NULL).
|
||||
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according
|
||||
* to secp256k1_ec_seckey_verify, this function returns 0. For
|
||||
* uniformly random 32-byte arrays the chance of being invalid
|
||||
* is negligible (around 1 in 2^128) (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_keypair *keypair,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_EXTRAKEYS_H */
|
||||
@@ -13,27 +13,24 @@ extern "C" {
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 33 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage or transmission, use
|
||||
* the secp256k1_generator_serialize_*.
|
||||
*
|
||||
* Furthermore, it is guaranteed to identical points will have identical
|
||||
* representation, so they can be memcmp'ed.
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage, transmission, or
|
||||
* comparison, use secp256k1_generator_serialize and secp256k1_generator_parse.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[33];
|
||||
unsigned char data[64];
|
||||
} secp256k1_generator;
|
||||
|
||||
/** Parse a 33-byte generator byte sequence into a generator object.
|
||||
*
|
||||
* Returns: 1 if input contains a valid generator.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: commit: pointer to the output generator object
|
||||
* Out: gen: pointer to the output generator object
|
||||
* In: input: pointer to a 33-byte serialized generator
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_generator* commit,
|
||||
secp256k1_generator* gen,
|
||||
const unsigned char *input
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
@@ -42,12 +39,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_parse(
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: output: a pointer to a 33-byte byte array
|
||||
* In: commit: a pointer to a generator
|
||||
* In: gen: a pointer to a generator
|
||||
*/
|
||||
SECP256K1_API int secp256k1_generator_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
const secp256k1_generator* commit
|
||||
const secp256k1_generator* gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Generate a generator for the curve.
|
||||
@@ -58,9 +55,9 @@ SECP256K1_API int secp256k1_generator_serialize(
|
||||
* Out: gen: a generator object
|
||||
* In: seed32: a 32-byte seed
|
||||
*
|
||||
* If succesful, a valid generator will be placed in gen. The produced
|
||||
* If successful a valid generator will be placed in gen. The produced
|
||||
* generators are distributed uniformly over the curve, and will not have a
|
||||
* known dicrete logarithm with respect to any other generator produced,
|
||||
* known discrete logarithm with respect to any other generator produced,
|
||||
* or to the base generator G.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate(
|
||||
@@ -73,7 +70,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate(
|
||||
*
|
||||
* Returns: 0 in the highly unlikely case the seed is not acceptable or when
|
||||
* blind is out of range. 1 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Args: ctx: a secp256k1 context object, initialized for signing
|
||||
* Out: gen: a generator object
|
||||
* In: seed32: a 32-byte seed
|
||||
* blind32: a 32-byte secret value to blind the generator with.
|
||||
|
||||
488
include/secp256k1_musig.h
Normal file
488
include/secp256k1_musig.h
Normal file
@@ -0,0 +1,488 @@
|
||||
#ifndef SECP256K1_MUSIG_H
|
||||
#define SECP256K1_MUSIG_H
|
||||
|
||||
#include "secp256k1_extrakeys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** This module implements a Schnorr-based multi-signature scheme called MuSig
|
||||
* (https://eprint.iacr.org/2018/068.pdf). It is compatible with bip-schnorr.
|
||||
* There's an example C source file in the module's directory
|
||||
* (src/modules/musig/example.c) that demonstrates how it can be used.
|
||||
*
|
||||
* The documentation in this include file is for reference and may not be sufficient
|
||||
* for users to begin using the library. A full description of API usage can be found
|
||||
* in src/modules/musig/musig.md
|
||||
*/
|
||||
|
||||
/** Data structure containing auxiliary data generated in `pubkey_combine` and
|
||||
* required for `session_*_init`.
|
||||
* Fields:
|
||||
* magic: Set during initialization in `pubkey_combine` to allow
|
||||
* detecting an uninitialized object.
|
||||
* pk_hash: The 32-byte hash of the original public keys
|
||||
* pk_parity: Whether the MuSig-aggregated point was negated when
|
||||
* converting it to the combined xonly pubkey.
|
||||
* is_tweaked: Whether the combined pubkey was tweaked
|
||||
* tweak: If is_tweaked, array with the 32-byte tweak
|
||||
* internal_key_parity: If is_tweaked, the parity of the combined pubkey
|
||||
* before tweaking
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t magic;
|
||||
unsigned char pk_hash[32];
|
||||
int pk_parity;
|
||||
int is_tweaked;
|
||||
unsigned char tweak[32];
|
||||
int internal_key_parity;
|
||||
} secp256k1_musig_pre_session;
|
||||
|
||||
/** Data structure containing data related to a signing session resulting in a single
|
||||
* signature.
|
||||
*
|
||||
* This structure is not opaque, but it MUST NOT be copied or read or written to it
|
||||
* directly. A signer who is online throughout the whole process and can keep this
|
||||
* structure in memory can use the provided API functions for a safe standard
|
||||
* workflow. See https://blockstream.com/2019/02/18/musig-a-new-multisignature-standard/
|
||||
* for more details about the risks associated with serializing or deserializing this
|
||||
* structure.
|
||||
*
|
||||
* Fields:
|
||||
* magic: Set in `musig_session_init` to allow detecting an
|
||||
* uninitialized object.
|
||||
* round: Current round of the session
|
||||
* pre_session: Auxiliary data created in `pubkey_combine`
|
||||
* combined_pk: MuSig-computed combined xonly public key
|
||||
* n_signers: Number of signers
|
||||
* msg: The 32-byte message (hash) to be signed
|
||||
* is_msg_set: Whether the above message has been set
|
||||
* has_secret_data: Whether this session object has a signers' secret data; if this
|
||||
* is `false`, it may still be used for verification purposes.
|
||||
* seckey: If `has_secret_data`, the signer's secret key
|
||||
* secnonce: If `has_secret_data`, the signer's secret nonce
|
||||
* nonce: If `has_secret_data`, the signer's public nonce
|
||||
* nonce_commitments_hash: If `has_secret_data` and round >= 1, the hash of all
|
||||
* signers' commitments
|
||||
* combined_nonce: If round >= 2, the summed combined public nonce
|
||||
* combined_nonce_parity: If round >= 2, the parity of the Y coordinate of above
|
||||
* nonce.
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t magic;
|
||||
int round;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
uint32_t n_signers;
|
||||
int is_msg_set;
|
||||
unsigned char msg[32];
|
||||
int has_secret_data;
|
||||
unsigned char seckey[32];
|
||||
unsigned char secnonce[32];
|
||||
secp256k1_xonly_pubkey nonce;
|
||||
int partial_nonce_parity;
|
||||
unsigned char nonce_commitments_hash[32];
|
||||
secp256k1_xonly_pubkey combined_nonce;
|
||||
int combined_nonce_parity;
|
||||
} secp256k1_musig_session;
|
||||
|
||||
/** Data structure containing data on all signers in a single session.
|
||||
*
|
||||
* The workflow for this structure is as follows:
|
||||
*
|
||||
* 1. This structure is initialized with `musig_session_init` or
|
||||
* `musig_session_init_verifier`, which set the `index` field, and zero out
|
||||
* all other fields. The public session is initialized with the signers'
|
||||
* nonce_commitments.
|
||||
*
|
||||
* 2. In a non-public session the nonce_commitments are set with the function
|
||||
* `musig_get_public_nonce`, which also returns the signer's public nonce. This
|
||||
* ensures that the public nonce is not exposed until all commitments have been
|
||||
* received.
|
||||
*
|
||||
* 3. Each individual data struct should be updated with `musig_set_nonce` once a
|
||||
* nonce is available. This function takes a single signer data struct rather than
|
||||
* an array because it may fail in the case that the provided nonce does not match
|
||||
* the commitment. In this case, it is desirable to identify the exact party whose
|
||||
* nonce was inconsistent.
|
||||
*
|
||||
* Fields:
|
||||
* present: indicates whether the signer's nonce is set
|
||||
* index: index of the signer in the MuSig key aggregation
|
||||
* nonce: public nonce, must be a valid curvepoint if the signer is `present`
|
||||
* nonce_commitment: commitment to the nonce, or all-bits zero if a commitment
|
||||
* has not yet been set
|
||||
*/
|
||||
typedef struct {
|
||||
int present;
|
||||
uint32_t index;
|
||||
secp256k1_xonly_pubkey nonce;
|
||||
unsigned char nonce_commitment[32];
|
||||
} secp256k1_musig_session_signer_data;
|
||||
|
||||
/** Opaque data structure that holds a MuSig partial signature.
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is however
|
||||
* guaranteed to be 32 bytes in size, and can be safely copied/moved. If you need
|
||||
* to convert to a format suitable for storage, transmission, or comparison, use the
|
||||
* `musig_partial_signature_serialize` and `musig_partial_signature_parse`
|
||||
* functions.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[32];
|
||||
} secp256k1_musig_partial_signature;
|
||||
|
||||
/** Computes a combined public key and the hash of the given public keys.
|
||||
* Different orders of `pubkeys` result in different `combined_pk`s.
|
||||
*
|
||||
* Returns: 1 if the public keys were successfully combined, 0 otherwise
|
||||
* Args: ctx: pointer to a context object initialized for verification
|
||||
* (cannot be NULL)
|
||||
* scratch: scratch space used to compute the combined pubkey by
|
||||
* multiexponentiation. If NULL, an inefficient algorithm is used.
|
||||
* Out: combined_pk: the MuSig-combined xonly public key (cannot be NULL)
|
||||
* pre_session: if non-NULL, pointer to a musig_pre_session struct to be used in
|
||||
* `musig_session_init` or `musig_pubkey_tweak_add`.
|
||||
* In: pubkeys: input array of public keys to combine. The order is important;
|
||||
* a different order will result in a different combined public
|
||||
* key (cannot be NULL)
|
||||
* n_pubkeys: length of pubkeys array. Must be greater than 0.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_pubkey_combine(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_scratch_space *scratch,
|
||||
secp256k1_xonly_pubkey *combined_pk,
|
||||
secp256k1_musig_pre_session *pre_session,
|
||||
const secp256k1_xonly_pubkey *pubkeys,
|
||||
size_t n_pubkeys
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Tweak an x-only public key by adding the generator multiplied with tweak32
|
||||
* to it. The resulting output_pubkey with the given internal_pubkey and tweak
|
||||
* passes `secp256k1_xonly_pubkey_tweak_test`.
|
||||
*
|
||||
* This function is only useful before initializing a signing session. If you
|
||||
* are only computing a public key, but not intending to create a signature for
|
||||
* it, you can just use `secp256k1_xonly_pubkey_tweak_add`. Can only be called
|
||||
* once with a given pre_session.
|
||||
*
|
||||
* Returns: 0 if the arguments are invalid or the resulting public key would be
|
||||
* invalid (only when the tweak is the negation of the corresponding
|
||||
* secret key). 1 otherwise.
|
||||
* Args: ctx: pointer to a context object initialized for verification
|
||||
* (cannot be NULL)
|
||||
* pre_session: pointer to a `musig_pre_session` struct initialized in
|
||||
* `musig_pubkey_combine` (cannot be NULL)
|
||||
* Out: output_pubkey: pointer to a public key to store the result. Will be set
|
||||
* to an invalid value if this function returns 0 (cannot
|
||||
* be NULL)
|
||||
* In: internal_pubkey: pointer to the `combined_pk` from
|
||||
* `musig_pubkey_combine` to which the tweak is applied.
|
||||
* (cannot be NULL).
|
||||
* tweak32: pointer to a 32-byte tweak. If the tweak is invalid
|
||||
* according to secp256k1_ec_seckey_verify, this function
|
||||
* returns 0. For uniformly random 32-byte arrays the
|
||||
* chance of being invalid is negligible (around 1 in
|
||||
* 2^128) (cannot be NULL).
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_tweak_add(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_musig_pre_session *pre_session,
|
||||
secp256k1_pubkey *output_pubkey,
|
||||
const secp256k1_xonly_pubkey *internal_pubkey,
|
||||
const unsigned char *tweak32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Initializes a signing session for a signer
|
||||
*
|
||||
* Returns: 1: session is successfully initialized
|
||||
* 0: session could not be initialized: secret key or secret nonce overflow
|
||||
* Args: ctx: pointer to a context object, initialized for signing (cannot
|
||||
* be NULL)
|
||||
* Out: session: the session structure to initialize (cannot be NULL)
|
||||
* signers: an array of signers' data to be initialized. Array length must
|
||||
* equal to `n_signers` (cannot be NULL)
|
||||
* nonce_commitment32: filled with a 32-byte commitment to the generated nonce
|
||||
* (cannot be NULL)
|
||||
* In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be
|
||||
* NULL). If a non-unique session_id32 was given then a partial
|
||||
* signature will LEAK THE SECRET KEY.
|
||||
* msg32: the 32-byte message to be signed. Shouldn't be NULL unless you
|
||||
* require sharing nonce commitments before the message is known
|
||||
* because it reduces nonce misuse resistance. If NULL, must be
|
||||
* set with `musig_session_get_public_nonce`.
|
||||
* combined_pk: the combined xonly public key of all signers (cannot be NULL)
|
||||
* pre_session: pointer to a musig_pre_session struct after initializing
|
||||
* it with `musig_pubkey_combine` and optionally provided to
|
||||
* `musig_pubkey_tweak_add` (cannot be NULL).
|
||||
* n_signers: length of signers array. Number of signers participating in
|
||||
* the MuSig. Must be greater than 0 and at most 2^32 - 1.
|
||||
* my_index: index of this signer in the signers array. Must be less
|
||||
* than `n_signers`.
|
||||
* seckey: the signer's 32-byte secret key (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_session_init(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_musig_session *session,
|
||||
secp256k1_musig_session_signer_data *signers,
|
||||
unsigned char *nonce_commitment32,
|
||||
const unsigned char *session_id32,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_xonly_pubkey *combined_pk,
|
||||
const secp256k1_musig_pre_session *pre_session,
|
||||
size_t n_signers,
|
||||
size_t my_index,
|
||||
const unsigned char *seckey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(11);
|
||||
|
||||
/** Gets the signer's public nonce given a list of all signers' data with
|
||||
* commitments. Called by participating signers after
|
||||
* `secp256k1_musig_session_init` and after all nonce commitments have
|
||||
* been collected
|
||||
*
|
||||
* Returns: 1: public nonce is written in nonce
|
||||
* 0: signer data is missing commitments or session isn't initialized
|
||||
* for signing
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* session: the signing session to get the nonce from (cannot be NULL)
|
||||
* signers: an array of signers' data initialized with
|
||||
* `musig_session_init`. Array length must equal to
|
||||
* `n_commitments` (cannot be NULL)
|
||||
* Out: nonce32: filled with a 32-byte public nonce which is supposed to be
|
||||
* sent to the other signers and then used in `musig_set nonce`
|
||||
* (cannot be NULL)
|
||||
* In: commitments: array of pointers to 32-byte nonce commitments (cannot be NULL)
|
||||
* n_commitments: the length of commitments and signers array. Must be the total
|
||||
* number of signers participating in the MuSig.
|
||||
* msg32: the 32-byte message to be signed. Must be NULL if already
|
||||
* set with `musig_session_init` otherwise can not be NULL.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_public_nonce(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_musig_session *session,
|
||||
secp256k1_musig_session_signer_data *signers,
|
||||
unsigned char *nonce32,
|
||||
const unsigned char *const *commitments,
|
||||
size_t n_commitments,
|
||||
const unsigned char *msg32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Initializes a verifier session that can be used for verifying nonce commitments
|
||||
* and partial signatures. It does not have secret key material and therefore can not
|
||||
* be used to create signatures.
|
||||
*
|
||||
* Returns: 1 when session is successfully initialized, 0 otherwise
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* Out: session: the session structure to initialize (cannot be NULL)
|
||||
* signers: an array of signers' data to be initialized. Array length must
|
||||
* equal to `n_signers`(cannot be NULL)
|
||||
* In: msg32: the 32-byte message to be signed (cannot be NULL)
|
||||
* combined_pk: the combined xonly public key of all signers (cannot be NULL)
|
||||
* pre_session: pointer to a musig_pre_session struct from
|
||||
* `musig_pubkey_combine` (cannot be NULL)
|
||||
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be NULL)
|
||||
* commitments: array of pointers to 32-byte nonce commitments. Array
|
||||
* length must equal to `n_signers` (cannot be NULL)
|
||||
* n_signers: length of signers and commitments array. Number of signers
|
||||
* participating in the MuSig. Must be greater than 0 and at most
|
||||
* 2^32 - 1.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_session_init_verifier(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_musig_session *session,
|
||||
secp256k1_musig_session_signer_data *signers,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_xonly_pubkey *combined_pk,
|
||||
const secp256k1_musig_pre_session *pre_session,
|
||||
const unsigned char *const *commitments,
|
||||
size_t n_signers
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
|
||||
|
||||
/** Checks a signer's public nonce against a commitment to said nonce, and update
|
||||
* data structure if they match
|
||||
*
|
||||
* Returns: 1: commitment was valid, data structure updated
|
||||
* 0: commitment was invalid, nothing happened
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* signer: pointer to the signer data to update (cannot be NULL). Must have
|
||||
* been used with `musig_session_get_public_nonce` or initialized
|
||||
* with `musig_session_init_verifier`.
|
||||
* In: nonce32: signer's alleged public nonce (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_set_nonce(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_musig_session_signer_data *signer,
|
||||
const unsigned char *nonce32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Updates a session with the combined public nonce of all signers. The combined
|
||||
* public nonce is the sum of every signer's public nonce.
|
||||
*
|
||||
* Returns: 1: nonces are successfully combined
|
||||
* 0: a signer's nonce is missing
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* session: session to update with the combined public nonce (cannot be
|
||||
* NULL)
|
||||
* signers: an array of signers' data, which must have had public nonces
|
||||
* set with `musig_set_nonce`. Array length must equal to `n_signers`
|
||||
* (cannot be NULL)
|
||||
* n_signers: the length of the signers array. Must be the total number of
|
||||
* signers participating in the MuSig.
|
||||
* Out: nonce_parity: if non-NULL, a pointer to an integer that indicates the
|
||||
* parity of the combined public nonce. Used for adaptor
|
||||
* signatures.
|
||||
* adaptor: point to add to the combined public nonce. If NULL, nothing is
|
||||
* added to the combined nonce.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_session_combine_nonces(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_musig_session *session,
|
||||
const secp256k1_musig_session_signer_data *signers,
|
||||
size_t n_signers,
|
||||
int *nonce_parity,
|
||||
const secp256k1_pubkey *adaptor
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a MuSig partial signature or adaptor signature
|
||||
*
|
||||
* Returns: 1 when the signature could be serialized, 0 otherwise
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: out32: pointer to a 32-byte array to store the serialized signature
|
||||
* In: sig: pointer to the signature
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_partial_signature_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *out32,
|
||||
const secp256k1_musig_partial_signature* sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Parse and verify a MuSig partial signature.
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: sig: pointer to a signature object
|
||||
* In: in32: pointer to the 32-byte signature to be parsed
|
||||
*
|
||||
* After the call, sig will always be initialized. If parsing failed or the
|
||||
* encoded numbers are out of range, signature verification with it is
|
||||
* guaranteed to fail for every message and public key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_partial_signature_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_musig_partial_signature* sig,
|
||||
const unsigned char *in32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Produces a partial signature
|
||||
*
|
||||
* Returns: 1: partial signature constructed
|
||||
* 0: session in incorrect or inconsistent state
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* session: active signing session for which the combined nonce has been
|
||||
* computed (cannot be NULL)
|
||||
* Out: partial_sig: partial signature (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_partial_sign(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_musig_session *session,
|
||||
secp256k1_musig_partial_signature *partial_sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Checks that an individual partial signature verifies
|
||||
*
|
||||
* This function is essential when using protocols with adaptor signatures.
|
||||
* However, it is not essential for regular MuSig's, in the sense that if any
|
||||
* partial signatures does not verify, the full signature will also not verify, so the
|
||||
* problem will be caught. But this function allows determining the specific party
|
||||
* who produced an invalid signature, so that signing can be restarted without them.
|
||||
*
|
||||
* Returns: 1: partial signature verifies
|
||||
* 0: invalid signature or bad data
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* session: active session for which the combined nonce has been computed
|
||||
* (cannot be NULL)
|
||||
* signer: data for the signer who produced this signature (cannot be NULL)
|
||||
* In: partial_sig: signature to verify (cannot be NULL)
|
||||
* pubkey: public key of the signer who produced the signature (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_musig_session *session,
|
||||
const secp256k1_musig_session_signer_data *signer,
|
||||
const secp256k1_musig_partial_signature *partial_sig,
|
||||
const secp256k1_xonly_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Combines partial signatures
|
||||
*
|
||||
* Returns: 1: all partial signatures have values in range. Does NOT mean the
|
||||
* resulting signature verifies.
|
||||
* 0: some partial signature are missing or had s or r out of range
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* session: initialized session for which the combined nonce has been
|
||||
* computed (cannot be NULL)
|
||||
* Out: sig64: complete signature (cannot be NULL)
|
||||
* In: partial_sigs: array of partial signatures to combine (cannot be NULL)
|
||||
* n_sigs: number of signatures in the partial_sigs array
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combine(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_musig_session *session,
|
||||
unsigned char *sig64,
|
||||
const secp256k1_musig_partial_signature *partial_sigs,
|
||||
size_t n_sigs
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Converts a partial signature to an adaptor signature by adding a given secret
|
||||
* adaptor.
|
||||
*
|
||||
* Returns: 1: signature and secret adaptor contained valid values
|
||||
* 0: otherwise
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* Out: adaptor_sig: adaptor signature to produce (cannot be NULL)
|
||||
* In: partial_sig: partial signature to tweak with secret adaptor (cannot be NULL)
|
||||
* sec_adaptor32: 32-byte secret adaptor to add to the partial signature (cannot
|
||||
* be NULL)
|
||||
* nonce_parity: the `nonce_parity` output of `musig_session_combine_nonces`
|
||||
*/
|
||||
SECP256K1_API int secp256k1_musig_partial_sig_adapt(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_musig_partial_signature *adaptor_sig,
|
||||
const secp256k1_musig_partial_signature *partial_sig,
|
||||
const unsigned char *sec_adaptor32,
|
||||
int nonce_parity
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Extracts a secret adaptor from a MuSig, given all parties' partial
|
||||
* signatures. This function will not fail unless given grossly invalid data; if it
|
||||
* is merely given signatures that do not verify, the returned value will be
|
||||
* nonsense. It is therefore important that all data be verified at earlier steps of
|
||||
* any protocol that uses this function.
|
||||
*
|
||||
* Returns: 1: signatures contained valid data such that an adaptor could be extracted
|
||||
* 0: otherwise
|
||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
||||
* Out:sec_adaptor32: 32-byte secret adaptor (cannot be NULL)
|
||||
* In: sig64: complete 2-of-2 signature (cannot be NULL)
|
||||
* partial_sigs: array of partial signatures (cannot be NULL)
|
||||
* n_partial_sigs: number of elements in partial_sigs array
|
||||
* nonce_parity: the `nonce_parity` output of `musig_session_combine_nonces`
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_adaptor(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *sec_adaptor32,
|
||||
const unsigned char *sig64,
|
||||
const secp256k1_musig_partial_signature *partial_sigs,
|
||||
size_t n_partial_sigs,
|
||||
int nonce_parity
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
128
include/secp256k1_preallocated.h
Normal file
128
include/secp256k1_preallocated.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#ifndef SECP256K1_PREALLOCATED_H
|
||||
#define SECP256K1_PREALLOCATED_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* The module provided by this header file is intended for settings in which it
|
||||
* is not possible or desirable to rely on dynamic memory allocation. It provides
|
||||
* functions for creating, cloning, and destroying secp256k1 context objects in a
|
||||
* contiguous fixed-size block of memory provided by the caller.
|
||||
*
|
||||
* Context objects created by functions in this module can be used like contexts
|
||||
* objects created by functions in secp256k1.h, i.e., they can be passed to any
|
||||
* API function that expects a context object (see secp256k1.h for details). The
|
||||
* only exception is that context objects created by functions in this module
|
||||
* must be destroyed using secp256k1_context_preallocated_destroy (in this
|
||||
* module) instead of secp256k1_context_destroy (in secp256k1.h).
|
||||
*
|
||||
* It is guaranteed that functions in this module will not call malloc or its
|
||||
* friends realloc, calloc, and free.
|
||||
*/
|
||||
|
||||
/** Determine the memory size of a secp256k1 context object to be created in
|
||||
* caller-provided memory.
|
||||
*
|
||||
* The purpose of this function is to determine how much memory must be provided
|
||||
* to secp256k1_context_preallocated_create.
|
||||
*
|
||||
* Returns: the required size of the caller-provided memory block
|
||||
* In: flags: which parts of the context to initialize.
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_context_preallocated_size(
|
||||
unsigned int flags
|
||||
) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Create a secp256k1 context object in caller-provided memory.
|
||||
*
|
||||
* The caller must provide a pointer to a rewritable contiguous block of memory
|
||||
* of size at least secp256k1_context_preallocated_size(flags) bytes, suitably
|
||||
* aligned to hold an object of any type.
|
||||
*
|
||||
* The block of memory is exclusively owned by the created context object during
|
||||
* the lifetime of this context object, which begins with the call to this
|
||||
* function and ends when a call to secp256k1_context_preallocated_destroy
|
||||
* (which destroys the context object again) returns. During the lifetime of the
|
||||
* context object, the caller is obligated not to access this block of memory,
|
||||
* i.e., the caller may not read or write the memory, e.g., by copying the memory
|
||||
* contents to a different location or trying to create a second context object
|
||||
* in the memory. In simpler words, the prealloc pointer (or any pointer derived
|
||||
* from it) should not be used during the lifetime of the context object.
|
||||
*
|
||||
* Returns: a newly created context object.
|
||||
* In: prealloc: a pointer to a rewritable contiguous block of memory of
|
||||
* size at least secp256k1_context_preallocated_size(flags)
|
||||
* bytes, as detailed above (cannot be NULL)
|
||||
* flags: which parts of the context to initialize.
|
||||
*
|
||||
* See also secp256k1_context_randomize (in secp256k1.h)
|
||||
* and secp256k1_context_preallocated_destroy.
|
||||
*/
|
||||
SECP256K1_API secp256k1_context* secp256k1_context_preallocated_create(
|
||||
void* prealloc,
|
||||
unsigned int flags
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Determine the memory size of a secp256k1 context object to be copied into
|
||||
* caller-provided memory.
|
||||
*
|
||||
* Returns: the required size of the caller-provided memory block.
|
||||
* In: ctx: an existing context to copy (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
|
||||
const secp256k1_context* ctx
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Copy a secp256k1 context object into caller-provided memory.
|
||||
*
|
||||
* The caller must provide a pointer to a rewritable contiguous block of memory
|
||||
* of size at least secp256k1_context_preallocated_size(flags) bytes, suitably
|
||||
* aligned to hold an object of any type.
|
||||
*
|
||||
* The block of memory is exclusively owned by the created context object during
|
||||
* the lifetime of this context object, see the description of
|
||||
* secp256k1_context_preallocated_create for details.
|
||||
*
|
||||
* Returns: a newly created context object.
|
||||
* Args: ctx: an existing context to copy (cannot be NULL)
|
||||
* In: prealloc: a pointer to a rewritable contiguous block of memory of
|
||||
* size at least secp256k1_context_preallocated_size(flags)
|
||||
* bytes, as detailed above (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
|
||||
const secp256k1_context* ctx,
|
||||
void* prealloc
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_WARN_UNUSED_RESULT;
|
||||
|
||||
/** Destroy a secp256k1 context object that has been created in
|
||||
* caller-provided memory.
|
||||
*
|
||||
* The context pointer may not be used afterwards.
|
||||
*
|
||||
* The context to destroy must have been created using
|
||||
* secp256k1_context_preallocated_create or secp256k1_context_preallocated_clone.
|
||||
* If the context has instead been created using secp256k1_context_create or
|
||||
* secp256k1_context_clone, the behaviour is undefined. In that case,
|
||||
* secp256k1_context_destroy must be used instead.
|
||||
*
|
||||
* If required, it is the responsibility of the caller to deallocate the block
|
||||
* of memory properly after this function returns, e.g., by calling free on the
|
||||
* preallocated pointer given to secp256k1_context_preallocated_create or
|
||||
* secp256k1_context_preallocated_clone.
|
||||
*
|
||||
* Args: ctx: an existing context to destroy, constructed using
|
||||
* secp256k1_context_preallocated_create or
|
||||
* secp256k1_context_preallocated_clone (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API void secp256k1_context_preallocated_destroy(
|
||||
secp256k1_context* ctx
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_PREALLOCATED_H */
|
||||
@@ -14,21 +14,19 @@ extern "C" {
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. It is
|
||||
* however guaranteed to be 33 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage or transmission, use
|
||||
* secp256k1_pedersen_commitment_serialize and secp256k1_pedersen_commitment_parse.
|
||||
*
|
||||
* Furthermore, it is guaranteed to identical signatures will have identical
|
||||
* representation, so they can be memcmp'ed.
|
||||
* however guaranteed to be 64 bytes in size, and can be safely copied/moved.
|
||||
* If you need to convert to a format suitable for storage, transmission, or
|
||||
* comparison, use secp256k1_pedersen_commitment_serialize and
|
||||
* secp256k1_pedersen_commitment_parse.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[33];
|
||||
unsigned char data[64];
|
||||
} secp256k1_pedersen_commitment;
|
||||
|
||||
/**
|
||||
* Static constant generator 'h' maintained for historical reasons.
|
||||
*/
|
||||
extern const secp256k1_generator *secp256k1_generator_h;
|
||||
SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h;
|
||||
|
||||
/** Parse a 33-byte commitment into a commitment object.
|
||||
*
|
||||
@@ -57,9 +55,6 @@ SECP256K1_API int secp256k1_pedersen_commitment_serialize(
|
||||
const secp256k1_pedersen_commitment* commit
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Initialize a context for usage with Pedersen commitments. */
|
||||
void secp256k1_pedersen_context_initialize(secp256k1_context* ctx);
|
||||
|
||||
/** Generate a pedersen commitment.
|
||||
* Returns 1: Commitment successfully created.
|
||||
* 0: Error. The blinding factor is larger than the group order
|
||||
@@ -163,9 +158,6 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generato
|
||||
size_t n_inputs
|
||||
);
|
||||
|
||||
/** Initialize a context for usage with Pedersen commitments. */
|
||||
void secp256k1_rangeproof_context_initialize(secp256k1_context* ctx);
|
||||
|
||||
/** Verify a proof that a committed value is within a range.
|
||||
* Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs.
|
||||
* 0: Proof failed or other error.
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef _SECP256K1_RECOVERY_
|
||||
# define _SECP256K1_RECOVERY_
|
||||
#ifndef SECP256K1_RECOVERY_H
|
||||
#define SECP256K1_RECOVERY_H
|
||||
|
||||
# include "secp256k1.h"
|
||||
#include "secp256k1.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/** Opaque data structured that holds a parsed ECDSA signature,
|
||||
* supporting pubkey recovery.
|
||||
@@ -70,7 +70,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
|
||||
/** Create a recoverable ECDSA signature.
|
||||
*
|
||||
* Returns: 1: signature created
|
||||
* 0: the nonce generation function failed, or the private key was invalid.
|
||||
* 0: the nonce generation function failed, or the secret key was invalid.
|
||||
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
|
||||
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
|
||||
@@ -103,8 +103,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
|
||||
const unsigned char *msg32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_RECOVERY_H */
|
||||
|
||||
111
include/secp256k1_schnorrsig.h
Normal file
111
include/secp256k1_schnorrsig.h
Normal file
@@ -0,0 +1,111 @@
|
||||
#ifndef SECP256K1_SCHNORRSIG_H
|
||||
#define SECP256K1_SCHNORRSIG_H
|
||||
|
||||
#include "secp256k1.h"
|
||||
#include "secp256k1_extrakeys.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** This module implements a variant of Schnorr signatures compliant with
|
||||
* Bitcoin Improvement Proposal 340 "Schnorr Signatures for secp256k1"
|
||||
* (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||
*/
|
||||
|
||||
/** A pointer to a function to deterministically generate a nonce.
|
||||
*
|
||||
* Same as secp256k1_nonce function with the exception of accepting an
|
||||
* additional pubkey argument and not requiring an attempt argument. The pubkey
|
||||
* argument can protect signature schemes with key-prefixed challenge hash
|
||||
* inputs against reusing the nonce when signing with the wrong precomputed
|
||||
* pubkey.
|
||||
*
|
||||
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to
|
||||
* return an error.
|
||||
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
|
||||
* In: msg32: the 32-byte message hash being verified (will not be NULL)
|
||||
* key32: pointer to a 32-byte secret key (will not be NULL)
|
||||
* xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
|
||||
* (will not be NULL)
|
||||
* algo16: pointer to a 16-byte array describing the signature
|
||||
* algorithm (will not be NULL).
|
||||
* data: Arbitrary data pointer that is passed through.
|
||||
*
|
||||
* Except for test cases, this function should compute some cryptographic hash of
|
||||
* the message, the key, the pubkey, the algorithm description, and data.
|
||||
*/
|
||||
typedef int (*secp256k1_nonce_function_hardened)(
|
||||
unsigned char *nonce32,
|
||||
const unsigned char *msg32,
|
||||
const unsigned char *key32,
|
||||
const unsigned char *xonly_pk32,
|
||||
const unsigned char *algo16,
|
||||
void *data
|
||||
);
|
||||
|
||||
/** An implementation of the nonce generation function as defined in Bitcoin
|
||||
* Improvement Proposal 340 "Schnorr Signatures for secp256k1"
|
||||
* (https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki).
|
||||
*
|
||||
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
|
||||
* auxiliary random data as defined in BIP-340. If the data pointer is NULL,
|
||||
* schnorrsig_sign does not produce BIP-340 compliant signatures. The algo16
|
||||
* argument must be non-NULL, otherwise the function will fail and return 0.
|
||||
* The hash will be tagged with algo16 after removing all terminating null
|
||||
* bytes. Therefore, to create BIP-340 compliant signatures, algo16 must be set
|
||||
* to "BIP0340/nonce\0\0\0"
|
||||
*/
|
||||
SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
|
||||
|
||||
/** Create a Schnorr signature.
|
||||
*
|
||||
* Does _not_ strictly follow BIP-340 because it does not verify the resulting
|
||||
* signature. Instead, you can manually use secp256k1_schnorrsig_verify and
|
||||
* abort if it fails.
|
||||
*
|
||||
* Otherwise BIP-340 compliant if the noncefp argument is NULL or
|
||||
* secp256k1_nonce_function_bip340 and the ndata argument is 32-byte auxiliary
|
||||
* randomness.
|
||||
*
|
||||
* Returns 1 on success, 0 on failure.
|
||||
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
|
||||
* Out: sig64: pointer to a 64-byte array to store the serialized signature (cannot be NULL)
|
||||
* In: msg32: the 32-byte message being signed (cannot be NULL)
|
||||
* keypair: pointer to an initialized keypair (cannot be NULL)
|
||||
* noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bip340 is used
|
||||
* ndata: pointer to arbitrary data used by the nonce generation
|
||||
* function (can be NULL). If it is non-NULL and
|
||||
* secp256k1_nonce_function_bip340 is used, then ndata must be a
|
||||
* pointer to 32-byte auxiliary randomness as per BIP-340.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_schnorrsig_sign(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_keypair *keypair,
|
||||
secp256k1_nonce_function_hardened noncefp,
|
||||
void *ndata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Verify a Schnorr signature.
|
||||
*
|
||||
* Returns: 1: correct signature
|
||||
* 0: incorrect signature
|
||||
* Args: ctx: a secp256k1 context object, initialized for verification.
|
||||
* In: sig64: pointer to the 64-byte signature to verify (cannot be NULL)
|
||||
* msg32: the 32-byte message being verified (cannot be NULL)
|
||||
* pubkey: pointer to an x-only public key to verify with (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const unsigned char *sig64,
|
||||
const unsigned char *msg32,
|
||||
const secp256k1_xonly_pubkey *pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_SCHNORRSIG_H */
|
||||
@@ -11,6 +11,9 @@ extern "C" {
|
||||
/** Maximum number of inputs that may be given in a surjection proof */
|
||||
#define SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS 256
|
||||
|
||||
/** Maximum number of inputs that may be used in a surjection proof */
|
||||
#define SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS 256
|
||||
|
||||
/** Number of bytes a serialized surjection proof requires given the
|
||||
* number of inputs and the number of used inputs.
|
||||
*/
|
||||
@@ -19,7 +22,7 @@ extern "C" {
|
||||
|
||||
/** Maximum number of bytes a serialized surjection proof requires. */
|
||||
#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX \
|
||||
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)
|
||||
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS)
|
||||
|
||||
/** Opaque data structure that holds a parsed surjection proof
|
||||
*
|
||||
@@ -46,9 +49,10 @@ typedef struct {
|
||||
/** Bitmap of which input tags are used in the surjection proof */
|
||||
unsigned char used_inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8];
|
||||
/** Borromean signature: e0, scalars */
|
||||
unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)];
|
||||
unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS)];
|
||||
} secp256k1_surjectionproof;
|
||||
|
||||
#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||
/** Parse a surjection proof
|
||||
*
|
||||
* Returns: 1 when the proof could be parsed, 0 otherwise.
|
||||
@@ -70,6 +74,7 @@ SECP256K1_API int secp256k1_surjectionproof_parse(
|
||||
const unsigned char *input,
|
||||
size_t inputlen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
#endif
|
||||
|
||||
/** Serialize a surjection proof
|
||||
*
|
||||
@@ -134,6 +139,7 @@ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Surjection proof initialization function; decides on inputs to use
|
||||
* To be used to initialize stack-allocated secp256k1_surjectionproof struct
|
||||
* Returns 0: inputs could not be selected
|
||||
* n: inputs were selected after n iterations of random selection
|
||||
*
|
||||
@@ -142,9 +148,14 @@ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
|
||||
* e.g. in a coinjoin with others' inputs, an ephemeral tag can be given;
|
||||
* this won't match the output tag but might be used in the anonymity set.)
|
||||
* n_input_tags: the number of entries in the fixed_input_tags array
|
||||
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
|
||||
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
|
||||
* Must be <= SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS
|
||||
* fixed_output_tag: fixed output tag
|
||||
* max_n_iterations: the maximum number of iterations to do before giving up
|
||||
* max_n_iterations: the maximum number of iterations to do before giving up. Because the
|
||||
* maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is
|
||||
* limited to 256 the probability of giving up is smaller than
|
||||
* (255/256)^(n_input_tags_to_use*max_n_iterations).
|
||||
*
|
||||
* random_seed32: a random seed to be used for input selection
|
||||
* Out: proof: The proof whose bitvector will be initialized. In case of failure,
|
||||
* the state of the proof is undefined.
|
||||
@@ -162,6 +173,51 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_initial
|
||||
const unsigned char *random_seed32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7);
|
||||
|
||||
|
||||
/** Surjection proof allocation and initialization function; decides on inputs to use
|
||||
* Returns 0: inputs could not be selected, or malloc failure
|
||||
* n: inputs were selected after n iterations of random selection
|
||||
*
|
||||
* In: ctx: pointer to a context object
|
||||
* proof_out_p: a pointer to a pointer to `secp256k1_surjectionproof*`.
|
||||
* the newly-allocated struct pointer will be saved here.
|
||||
* fixed_input_tags: fixed input tags `A_i` for all inputs. (If the fixed tag is not known,
|
||||
* e.g. in a coinjoin with others' inputs, an ephemeral tag can be given;
|
||||
* this won't match the output tag but might be used in the anonymity set.)
|
||||
* n_input_tags: the number of entries in the fixed_input_tags array
|
||||
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
|
||||
* fixed_output_tag: fixed output tag
|
||||
* max_n_iterations: the maximum number of iterations to do before giving up. Because the
|
||||
* maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is
|
||||
* limited to 256 the probability of giving up is smaller than
|
||||
* (255/256)^(n_input_tags_to_use*max_n_iterations).
|
||||
*
|
||||
* random_seed32: a random seed to be used for input selection
|
||||
* Out: proof_out_p: The pointer to newly-allocated proof whose bitvector will be initialized.
|
||||
* In case of failure, the pointer will be NULL.
|
||||
* input_index: The index of the actual input that is secretly mapped to the output
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_allocate_initialized(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_surjectionproof** proof_out_p,
|
||||
size_t *input_index,
|
||||
const secp256k1_fixed_asset_tag* fixed_input_tags,
|
||||
const size_t n_input_tags,
|
||||
const size_t n_input_tags_to_use,
|
||||
const secp256k1_fixed_asset_tag* fixed_output_tag,
|
||||
const size_t n_max_iterations,
|
||||
const unsigned char *random_seed32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7);
|
||||
|
||||
/** Surjection proof destroy function
|
||||
* deallocates the struct that was allocated with secp256k1_surjectionproof_allocate_initialized
|
||||
*
|
||||
* In: proof: pointer to secp256k1_surjectionproof struct
|
||||
*/
|
||||
SECP256K1_API void secp256k1_surjectionproof_destroy(
|
||||
secp256k1_surjectionproof* proof
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Surjection proof generation function
|
||||
* Returns 0: proof could not be created
|
||||
* 1: proof was successfully created
|
||||
@@ -187,6 +243,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_generat
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
|
||||
|
||||
|
||||
#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||
/** Surjection proof verification function
|
||||
* Returns 0: proof was invalid
|
||||
* 1: proof was valid
|
||||
@@ -204,6 +261,7 @@ SECP256K1_API int secp256k1_surjectionproof_verify(
|
||||
size_t n_ephemeral_input_tags,
|
||||
const secp256k1_generator* ephemeral_output_tag
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@ Description: Optimized C library for EC operations on curve secp256k1
|
||||
URL: https://github.com/bitcoin-core/secp256k1
|
||||
Version: @PACKAGE_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs.private: @SECP_LIBS@
|
||||
Libs: -L${libdir} -lsecp256k1
|
||||
Libs.private: @SECP_LIBS@
|
||||
|
||||
|
||||
129
sage/gen_exhaustive_groups.sage
Normal file
129
sage/gen_exhaustive_groups.sage
Normal file
@@ -0,0 +1,129 @@
|
||||
# Define field size and field
|
||||
P = 2^256 - 2^32 - 977
|
||||
F = GF(P)
|
||||
BETA = F(0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee)
|
||||
|
||||
assert(BETA != F(1) and BETA^3 == F(1))
|
||||
|
||||
orders_done = set()
|
||||
results = {}
|
||||
first = True
|
||||
for b in range(1, P):
|
||||
# There are only 6 curves (up to isomorphism) of the form y^2=x^3+B. Stop once we have tried all.
|
||||
if len(orders_done) == 6:
|
||||
break
|
||||
|
||||
E = EllipticCurve(F, [0, b])
|
||||
print("Analyzing curve y^2 = x^3 + %i" % b)
|
||||
n = E.order()
|
||||
# Skip curves with an order we've already tried
|
||||
if n in orders_done:
|
||||
print("- Isomorphic to earlier curve")
|
||||
continue
|
||||
orders_done.add(n)
|
||||
# Skip curves isomorphic to the real secp256k1
|
||||
if n.is_pseudoprime():
|
||||
print(" - Isomorphic to secp256k1")
|
||||
continue
|
||||
|
||||
print("- Finding subgroups")
|
||||
|
||||
# Find what prime subgroups exist
|
||||
for f, _ in n.factor():
|
||||
print("- Analyzing subgroup of order %i" % f)
|
||||
# Skip subgroups of order >1000
|
||||
if f < 4 or f > 1000:
|
||||
print(" - Bad size")
|
||||
continue
|
||||
|
||||
# Iterate over X coordinates until we find one that is on the curve, has order f,
|
||||
# and for which curve isomorphism exists that maps it to X coordinate 1.
|
||||
for x in range(1, P):
|
||||
# Skip X coordinates not on the curve, and construct the full point otherwise.
|
||||
if not E.is_x_coord(x):
|
||||
continue
|
||||
G = E.lift_x(F(x))
|
||||
|
||||
print(" - Analyzing (multiples of) point with X=%i" % x)
|
||||
|
||||
# Skip points whose order is not a multiple of f. Project the point to have
|
||||
# order f otherwise.
|
||||
if (G.order() % f):
|
||||
print(" - Bad order")
|
||||
continue
|
||||
G = G * (G.order() // f)
|
||||
|
||||
# Find lambda for endomorphism. Skip if none can be found.
|
||||
lam = None
|
||||
for l in Integers(f)(1).nth_root(3, all=True):
|
||||
if int(l)*G == E(BETA*G[0], G[1]):
|
||||
lam = int(l)
|
||||
break
|
||||
if lam is None:
|
||||
print(" - No endomorphism for this subgroup")
|
||||
break
|
||||
|
||||
# Now look for an isomorphism of the curve that gives this point an X
|
||||
# coordinate equal to 1.
|
||||
# If (x,y) is on y^2 = x^3 + b, then (a^2*x, a^3*y) is on y^2 = x^3 + a^6*b.
|
||||
# So look for m=a^2=1/x.
|
||||
m = F(1)/G[0]
|
||||
if not m.is_square():
|
||||
print(" - No curve isomorphism maps it to a point with X=1")
|
||||
continue
|
||||
a = m.sqrt()
|
||||
rb = a^6*b
|
||||
RE = EllipticCurve(F, [0, rb])
|
||||
|
||||
# Use as generator twice the image of G under the above isormorphism.
|
||||
# This means that generator*(1/2 mod f) will have X coordinate 1.
|
||||
RG = RE(1, a^3*G[1]) * 2
|
||||
# And even Y coordinate.
|
||||
if int(RG[1]) % 2:
|
||||
RG = -RG
|
||||
assert(RG.order() == f)
|
||||
assert(lam*RG == RE(BETA*RG[0], RG[1]))
|
||||
|
||||
# We have found curve RE:y^2=x^3+rb with generator RG of order f. Remember it
|
||||
results[f] = {"b": rb, "G": RG, "lambda": lam}
|
||||
print(" - Found solution")
|
||||
break
|
||||
|
||||
print("")
|
||||
|
||||
print("")
|
||||
print("")
|
||||
print("/* To be put in src/group_impl.h: */")
|
||||
first = True
|
||||
for f in sorted(results.keys()):
|
||||
b = results[f]["b"]
|
||||
G = results[f]["G"]
|
||||
print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f))
|
||||
first = False
|
||||
print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(")
|
||||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
|
||||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
|
||||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
|
||||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
|
||||
print(");")
|
||||
print("static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(")
|
||||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4)))
|
||||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8)))
|
||||
print(");")
|
||||
print("# else")
|
||||
print("# error No known generator for the specified exhaustive test group order.")
|
||||
print("# endif")
|
||||
|
||||
print("")
|
||||
print("")
|
||||
print("/* To be put in src/scalar_impl.h: */")
|
||||
first = True
|
||||
for f in sorted(results.keys()):
|
||||
lam = results[f]["lambda"]
|
||||
print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f))
|
||||
first = False
|
||||
print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam)
|
||||
print("# else")
|
||||
print("# error No known lambda for the specified exhaustive test group order.")
|
||||
print("# endif")
|
||||
print("")
|
||||
@@ -3,7 +3,7 @@
|
||||
# to independently set assumptions on input or intermediary variables.
|
||||
#
|
||||
# The general approach is:
|
||||
# * A constraint is a tuple of two sets of of symbolic expressions:
|
||||
# * A constraint is a tuple of two sets of symbolic expressions:
|
||||
# the first of which are required to evaluate to zero, the second of which
|
||||
# are required to evaluate to nonzero.
|
||||
# - A constraint is said to be conflicting if any of its nonzero expressions
|
||||
@@ -17,7 +17,7 @@
|
||||
# - A constraint describing the requirements of the law, called "require"
|
||||
# * Implementations are transliterated into functions that operate as well on
|
||||
# algebraic input points, and are called once per combination of branches
|
||||
# exectured. Each execution returns:
|
||||
# executed. Each execution returns:
|
||||
# - A constraint describing the assumptions this implementation requires
|
||||
# (such as Z1=1), called "assumeFormula"
|
||||
# - A constraint describing the assumptions this specific branch requires,
|
||||
@@ -65,7 +65,7 @@ class fastfrac:
|
||||
return self.top in I and self.bot not in I
|
||||
|
||||
def reduce(self,assumeZero):
|
||||
zero = self.R.ideal(map(numerator, assumeZero))
|
||||
zero = self.R.ideal(list(map(numerator, assumeZero)))
|
||||
return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot))
|
||||
|
||||
def __add__(self,other):
|
||||
@@ -100,7 +100,7 @@ class fastfrac:
|
||||
"""Multiply something else with a fraction."""
|
||||
return self.__mul__(other)
|
||||
|
||||
def __div__(self,other):
|
||||
def __truediv__(self,other):
|
||||
"""Divide two fractions."""
|
||||
if parent(other) == ZZ:
|
||||
return fastfrac(self.R,self.top,self.bot * other)
|
||||
@@ -108,6 +108,11 @@ class fastfrac:
|
||||
return fastfrac(self.R,self.top * other.bot,self.bot * other.top)
|
||||
return NotImplemented
|
||||
|
||||
# Compatibility wrapper for Sage versions based on Python 2
|
||||
def __div__(self,other):
|
||||
"""Divide two fractions."""
|
||||
return self.__truediv__(other)
|
||||
|
||||
def __pow__(self,other):
|
||||
"""Compute a power of a fraction."""
|
||||
if parent(other) == ZZ:
|
||||
@@ -175,7 +180,7 @@ class constraints:
|
||||
|
||||
def conflicts(R, con):
|
||||
"""Check whether any of the passed non-zero assumptions is implied by the zero assumptions"""
|
||||
zero = R.ideal(map(numerator, con.zero))
|
||||
zero = R.ideal(list(map(numerator, con.zero)))
|
||||
if 1 in zero:
|
||||
return True
|
||||
# First a cheap check whether any of the individual nonzero terms conflict on
|
||||
@@ -195,7 +200,7 @@ def conflicts(R, con):
|
||||
|
||||
def get_nonzero_set(R, assume):
|
||||
"""Calculate a simple set of nonzero expressions"""
|
||||
zero = R.ideal(map(numerator, assume.zero))
|
||||
zero = R.ideal(list(map(numerator, assume.zero)))
|
||||
nonzero = set()
|
||||
for nz in map(numerator, assume.nonzero):
|
||||
for (f,n) in nz.factor():
|
||||
@@ -208,7 +213,7 @@ def get_nonzero_set(R, assume):
|
||||
|
||||
def prove_nonzero(R, exprs, assume):
|
||||
"""Check whether an expression is provably nonzero, given assumptions"""
|
||||
zero = R.ideal(map(numerator, assume.zero))
|
||||
zero = R.ideal(list(map(numerator, assume.zero)))
|
||||
nonzero = get_nonzero_set(R, assume)
|
||||
expl = set()
|
||||
ok = True
|
||||
@@ -250,7 +255,7 @@ def prove_zero(R, exprs, assume):
|
||||
r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume)
|
||||
if not r:
|
||||
return (False, map(lambda x: "Possibly zero denominator: %s" % x, e))
|
||||
zero = R.ideal(map(numerator, assume.zero))
|
||||
zero = R.ideal(list(map(numerator, assume.zero)))
|
||||
nonzero = prod(x for x in assume.nonzero)
|
||||
expl = []
|
||||
for expr in exprs:
|
||||
@@ -265,8 +270,8 @@ def describe_extra(R, assume, assumeExtra):
|
||||
"""Describe what assumptions are added, given existing assumptions"""
|
||||
zerox = assume.zero.copy()
|
||||
zerox.update(assumeExtra.zero)
|
||||
zero = R.ideal(map(numerator, assume.zero))
|
||||
zeroextra = R.ideal(map(numerator, zerox))
|
||||
zero = R.ideal(list(map(numerator, assume.zero)))
|
||||
zeroextra = R.ideal(list(map(numerator, zerox)))
|
||||
nonzero = get_nonzero_set(R, assume)
|
||||
ret = set()
|
||||
# Iterate over the extra zero expressions
|
||||
|
||||
@@ -175,24 +175,24 @@ laws_jacobian_weierstrass = {
|
||||
def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
|
||||
"""Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field"""
|
||||
F = Integers(p)
|
||||
print "Formula %s on Z%i:" % (name, p)
|
||||
print("Formula %s on Z%i:" % (name, p))
|
||||
points = []
|
||||
for x in xrange(0, p):
|
||||
for y in xrange(0, p):
|
||||
for x in range(0, p):
|
||||
for y in range(0, p):
|
||||
point = affinepoint(F(x), F(y))
|
||||
r, e = concrete_verify(on_weierstrass_curve(A, B, point))
|
||||
if r:
|
||||
points.append(point)
|
||||
|
||||
for za in xrange(1, p):
|
||||
for zb in xrange(1, p):
|
||||
for za in range(1, p):
|
||||
for zb in range(1, p):
|
||||
for pa in points:
|
||||
for pb in points:
|
||||
for ia in xrange(2):
|
||||
for ib in xrange(2):
|
||||
for ia in range(2):
|
||||
for ib in range(2):
|
||||
pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia)
|
||||
pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib)
|
||||
for branch in xrange(0, branches):
|
||||
for branch in range(0, branches):
|
||||
assumeAssert, assumeBranch, pC = formula(branch, pA, pB)
|
||||
pC.X = F(pC.X)
|
||||
pC.Y = F(pC.Y)
|
||||
@@ -206,13 +206,13 @@ def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p):
|
||||
r, e = concrete_verify(assumeLaw)
|
||||
if r:
|
||||
if match:
|
||||
print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity)
|
||||
print(" multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity))
|
||||
else:
|
||||
match = True
|
||||
r, e = concrete_verify(require)
|
||||
if not r:
|
||||
print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e)
|
||||
print
|
||||
print(" failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e))
|
||||
print()
|
||||
|
||||
|
||||
def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC):
|
||||
@@ -242,9 +242,9 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
|
||||
for key in laws_jacobian_weierstrass:
|
||||
res[key] = []
|
||||
|
||||
print ("Formula " + name + ":")
|
||||
print("Formula " + name + ":")
|
||||
count = 0
|
||||
for branch in xrange(branches):
|
||||
for branch in range(branches):
|
||||
assumeFormula, assumeBranch, pC = formula(branch, pA, pB)
|
||||
pC.X = lift(pC.X)
|
||||
pC.Y = lift(pC.Y)
|
||||
@@ -255,10 +255,10 @@ def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula):
|
||||
res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch))
|
||||
|
||||
for key in res:
|
||||
print " %s:" % key
|
||||
print(" %s:" % key)
|
||||
val = res[key]
|
||||
for x in val:
|
||||
if x[0] is not None:
|
||||
print " branch %i: %s" % (x[1], x[0])
|
||||
print(" branch %i: %s" % (x[1], x[0]))
|
||||
|
||||
print
|
||||
print()
|
||||
|
||||
@@ -11,20 +11,14 @@ Note:
|
||||
|
||||
- To avoid unnecessary loads and make use of available registers, two
|
||||
'passes' have every time been interleaved, with the odd passes accumulating c' and d'
|
||||
which will be added to c and d respectively in the the even passes
|
||||
which will be added to c and d respectively in the even passes
|
||||
|
||||
*/
|
||||
|
||||
.syntax unified
|
||||
.arch armv7-a
|
||||
@ eabi attributes - see readelf -A
|
||||
.eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes
|
||||
.eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no
|
||||
.eabi_attribute 10, 0 @ Tag_FP_arch = none
|
||||
.eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte
|
||||
.eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP
|
||||
.eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Agressive Speed
|
||||
.eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6
|
||||
.text
|
||||
|
||||
@ Field constants
|
||||
|
||||
80
src/assumptions.h
Normal file
80
src/assumptions.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_ASSUMPTIONS_H
|
||||
#define SECP256K1_ASSUMPTIONS_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/* This library, like most software, relies on a number of compiler implementation defined (but not undefined)
|
||||
behaviours. Although the behaviours we require are essentially universal we test them specifically here to
|
||||
reduce the odds of experiencing an unwelcome surprise.
|
||||
*/
|
||||
|
||||
struct secp256k1_assumption_checker {
|
||||
/* This uses a trick to implement a static assertion in C89: a type with an array of negative size is not
|
||||
allowed. */
|
||||
int dummy_array[(
|
||||
/* Bytes are 8 bits. */
|
||||
(CHAR_BIT == 8) &&
|
||||
|
||||
/* No integer promotion for uint32_t. This ensures that we can multiply uintXX_t values where XX >= 32
|
||||
without signed overflow, which would be undefined behaviour. */
|
||||
(UINT_MAX <= UINT32_MAX) &&
|
||||
|
||||
/* Conversions from unsigned to signed outside of the bounds of the signed type are
|
||||
implementation-defined. Verify that they function as reinterpreting the lower
|
||||
bits of the input in two's complement notation. Do this for conversions:
|
||||
- from uint(N)_t to int(N)_t with negative result
|
||||
- from uint(2N)_t to int(N)_t with negative result
|
||||
- from int(2N)_t to int(N)_t with negative result
|
||||
- from int(2N)_t to int(N)_t with positive result */
|
||||
|
||||
/* To int8_t. */
|
||||
((int8_t)(uint8_t)0xAB == (int8_t)-(int8_t)0x55) &&
|
||||
((int8_t)(uint16_t)0xABCD == (int8_t)-(int8_t)0x33) &&
|
||||
((int8_t)(int16_t)(uint16_t)0xCDEF == (int8_t)(uint8_t)0xEF) &&
|
||||
((int8_t)(int16_t)(uint16_t)0x9234 == (int8_t)(uint8_t)0x34) &&
|
||||
|
||||
/* To int16_t. */
|
||||
((int16_t)(uint16_t)0xBCDE == (int16_t)-(int16_t)0x4322) &&
|
||||
((int16_t)(uint32_t)0xA1B2C3D4 == (int16_t)-(int16_t)0x3C2C) &&
|
||||
((int16_t)(int32_t)(uint32_t)0xC1D2E3F4 == (int16_t)(uint16_t)0xE3F4) &&
|
||||
((int16_t)(int32_t)(uint32_t)0x92345678 == (int16_t)(uint16_t)0x5678) &&
|
||||
|
||||
/* To int32_t. */
|
||||
((int32_t)(uint32_t)0xB2C3D4E5 == (int32_t)-(int32_t)0x4D3C2B1B) &&
|
||||
((int32_t)(uint64_t)0xA123B456C789D012ULL == (int32_t)-(int32_t)0x38762FEE) &&
|
||||
((int32_t)(int64_t)(uint64_t)0xC1D2E3F4A5B6C7D8ULL == (int32_t)(uint32_t)0xA5B6C7D8) &&
|
||||
((int32_t)(int64_t)(uint64_t)0xABCDEF0123456789ULL == (int32_t)(uint32_t)0x23456789) &&
|
||||
|
||||
/* To int64_t. */
|
||||
((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) &&
|
||||
#if defined(SECP256K1_WIDEMUL_INT128)
|
||||
((int64_t)(((uint128_t)0xA1234567B8901234ULL << 64) + 0xC5678901D2345678ULL) == (int64_t)-(int64_t)0x3A9876FE2DCBA988ULL) &&
|
||||
(((int64_t)(int128_t)(((uint128_t)0xB1C2D3E4F5A6B7C8ULL << 64) + 0xD9E0F1A2B3C4D5E6ULL)) == (int64_t)(uint64_t)0xD9E0F1A2B3C4D5E6ULL) &&
|
||||
(((int64_t)(int128_t)(((uint128_t)0xABCDEF0123456789ULL << 64) + 0x0123456789ABCDEFULL)) == (int64_t)(uint64_t)0x0123456789ABCDEFULL) &&
|
||||
|
||||
/* To int128_t. */
|
||||
((int128_t)(((uint128_t)0xB1234567C8901234ULL << 64) + 0xD5678901E2345678ULL) == (int128_t)(-(int128_t)0x8E1648B3F50E80DCULL * 0x8E1648B3F50E80DDULL + 0x5EA688D5482F9464ULL)) &&
|
||||
#endif
|
||||
|
||||
/* Right shift on negative signed values is implementation defined. Verify that it
|
||||
acts as a right shift in two's complement with sign extension (i.e duplicating
|
||||
the top bit into newly added bits). */
|
||||
((((int8_t)0xE8) >> 2) == (int8_t)(uint8_t)0xFA) &&
|
||||
((((int16_t)0xE9AC) >> 4) == (int16_t)(uint16_t)0xFE9A) &&
|
||||
((((int32_t)0x937C918A) >> 9) == (int32_t)(uint32_t)0xFFC9BE48) &&
|
||||
((((int64_t)0xA8B72231DF9CF4B9ULL) >> 19) == (int64_t)(uint64_t)0xFFFFF516E4463BF3ULL) &&
|
||||
#if defined(SECP256K1_WIDEMUL_INT128)
|
||||
((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) &&
|
||||
#endif
|
||||
1) * 2 - 1];
|
||||
};
|
||||
|
||||
#endif /* SECP256K1_ASSUMPTIONS_H */
|
||||
@@ -4,29 +4,31 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_BASIC_CONFIG_
|
||||
#define _SECP256K1_BASIC_CONFIG_
|
||||
#ifndef SECP256K1_BASIC_CONFIG_H
|
||||
#define SECP256K1_BASIC_CONFIG_H
|
||||
|
||||
#ifdef USE_BASIC_CONFIG
|
||||
|
||||
#undef USE_ASM_X86_64
|
||||
#undef USE_ENDOMORPHISM
|
||||
#undef USE_FIELD_10X26
|
||||
#undef USE_FIELD_5X52
|
||||
#undef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||
#undef USE_EXTERNAL_ASM
|
||||
#undef USE_EXTERNAL_DEFAULT_CALLBACKS
|
||||
#undef USE_FIELD_INV_BUILTIN
|
||||
#undef USE_FIELD_INV_NUM
|
||||
#undef USE_NUM_GMP
|
||||
#undef USE_NUM_NONE
|
||||
#undef USE_SCALAR_4X64
|
||||
#undef USE_SCALAR_8X32
|
||||
#undef USE_SCALAR_INV_BUILTIN
|
||||
#undef USE_SCALAR_INV_NUM
|
||||
#undef USE_FORCE_WIDEMUL_INT64
|
||||
#undef USE_FORCE_WIDEMUL_INT128
|
||||
#undef ECMULT_WINDOW_SIZE
|
||||
|
||||
#define USE_NUM_NONE 1
|
||||
#define USE_FIELD_INV_BUILTIN 1
|
||||
#define USE_SCALAR_INV_BUILTIN 1
|
||||
#define USE_FIELD_10X26 1
|
||||
#define USE_SCALAR_8X32 1
|
||||
#define USE_WIDEMUL_64 1
|
||||
#define ECMULT_WINDOW_SIZE 15
|
||||
|
||||
#endif // USE_BASIC_CONFIG
|
||||
#endif // _SECP256K1_BASIC_CONFIG_
|
||||
#endif /* USE_BASIC_CONFIG */
|
||||
|
||||
#endif /* SECP256K1_BASIC_CONFIG_H */
|
||||
|
||||
119
src/bench.h
119
src/bench.h
@@ -4,47 +4,90 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_BENCH_H_
|
||||
#define _SECP256K1_BENCH_H_
|
||||
#ifndef SECP256K1_BENCH_H
|
||||
#define SECP256K1_BENCH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "sys/time.h"
|
||||
|
||||
static double gettimedouble(void) {
|
||||
static int64_t gettime_i64(void) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_usec * 0.000001 + tv.tv_sec;
|
||||
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
|
||||
}
|
||||
|
||||
void print_number(double x) {
|
||||
double y = x;
|
||||
int c = 0;
|
||||
if (y < 0.0) {
|
||||
y = -y;
|
||||
#define FP_EXP (6)
|
||||
#define FP_MULT (1000000LL)
|
||||
|
||||
/* Format fixed point number. */
|
||||
void print_number(const int64_t x) {
|
||||
int64_t x_abs, y;
|
||||
int c, i, rounding;
|
||||
size_t ptr;
|
||||
char buffer[30];
|
||||
|
||||
if (x == INT64_MIN) {
|
||||
/* Prevent UB. */
|
||||
printf("ERR");
|
||||
return;
|
||||
}
|
||||
while (y < 100.0) {
|
||||
y *= 10.0;
|
||||
x_abs = x < 0 ? -x : x;
|
||||
|
||||
/* Determine how many decimals we want to show (more than FP_EXP makes no
|
||||
* sense). */
|
||||
y = x_abs;
|
||||
c = 0;
|
||||
while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) {
|
||||
y *= 10LL;
|
||||
c++;
|
||||
}
|
||||
printf("%.*f", c, x);
|
||||
|
||||
/* Round to 'c' decimals. */
|
||||
y = x_abs;
|
||||
rounding = 0;
|
||||
for (i = c; i < FP_EXP; ++i) {
|
||||
rounding = (y % 10) >= 5;
|
||||
y /= 10;
|
||||
}
|
||||
y += rounding;
|
||||
|
||||
/* Format and print the number. */
|
||||
ptr = sizeof(buffer) - 1;
|
||||
buffer[ptr] = 0;
|
||||
if (c != 0) {
|
||||
for (i = 0; i < c; ++i) {
|
||||
buffer[--ptr] = '0' + (y % 10);
|
||||
y /= 10;
|
||||
}
|
||||
buffer[--ptr] = '.';
|
||||
}
|
||||
do {
|
||||
buffer[--ptr] = '0' + (y % 10);
|
||||
y /= 10;
|
||||
} while (y != 0);
|
||||
if (x < 0) {
|
||||
buffer[--ptr] = '-';
|
||||
}
|
||||
printf("%s", &buffer[ptr]);
|
||||
}
|
||||
|
||||
void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {
|
||||
void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
|
||||
int i;
|
||||
double min = HUGE_VAL;
|
||||
double sum = 0.0;
|
||||
double max = 0.0;
|
||||
int64_t min = INT64_MAX;
|
||||
int64_t sum = 0;
|
||||
int64_t max = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
double begin, total;
|
||||
int64_t begin, total;
|
||||
if (setup != NULL) {
|
||||
setup(data);
|
||||
}
|
||||
begin = gettimedouble();
|
||||
benchmark(data);
|
||||
total = gettimedouble() - begin;
|
||||
begin = gettime_i64();
|
||||
benchmark(data, iter);
|
||||
total = gettime_i64() - begin;
|
||||
if (teardown != NULL) {
|
||||
teardown(data);
|
||||
teardown(data, iter);
|
||||
}
|
||||
if (total < min) {
|
||||
min = total;
|
||||
@@ -55,12 +98,36 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v
|
||||
sum += total;
|
||||
}
|
||||
printf("%s: min ", name);
|
||||
print_number(min * 1000000.0 / iter);
|
||||
print_number(min * FP_MULT / iter);
|
||||
printf("us / avg ");
|
||||
print_number((sum / count) * 1000000.0 / iter);
|
||||
print_number(((sum * FP_MULT) / count) / iter);
|
||||
printf("us / max ");
|
||||
print_number(max * 1000000.0 / iter);
|
||||
print_number(max * FP_MULT / iter);
|
||||
printf("us\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
int have_flag(int argc, char** argv, char *flag) {
|
||||
char** argm = argv + argc;
|
||||
argv++;
|
||||
if (argv == argm) {
|
||||
return 1;
|
||||
}
|
||||
while (argv != NULL && argv != argm) {
|
||||
if (strcmp(*argv, flag) == 0) {
|
||||
return 1;
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_iters(int default_iters) {
|
||||
char* env = getenv("SECP256K1_BENCH_ITERS");
|
||||
if (env) {
|
||||
return strtol(env, NULL, 0);
|
||||
} else {
|
||||
return default_iters;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_BENCH_H */
|
||||
|
||||
@@ -15,11 +15,11 @@ typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
secp256k1_pubkey point;
|
||||
unsigned char scalar[32];
|
||||
} bench_ecdh_t;
|
||||
} bench_ecdh_data;
|
||||
|
||||
static void bench_ecdh_setup(void* arg) {
|
||||
int i;
|
||||
bench_ecdh_t *data = (bench_ecdh_t*)arg;
|
||||
bench_ecdh_data *data = (bench_ecdh_data*)arg;
|
||||
const unsigned char point[] = {
|
||||
0x03,
|
||||
0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06,
|
||||
@@ -28,27 +28,32 @@ static void bench_ecdh_setup(void* arg) {
|
||||
0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f
|
||||
};
|
||||
|
||||
/* create a context with no capabilities */
|
||||
data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->scalar[i] = i + 1;
|
||||
}
|
||||
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1);
|
||||
}
|
||||
|
||||
static void bench_ecdh(void* arg) {
|
||||
static void bench_ecdh(void* arg, int iters) {
|
||||
int i;
|
||||
unsigned char res[32];
|
||||
bench_ecdh_t *data = (bench_ecdh_t*)arg;
|
||||
bench_ecdh_data *data = (bench_ecdh_data*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1);
|
||||
for (i = 0; i < iters; i++) {
|
||||
CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar, NULL, NULL) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
bench_ecdh_t data;
|
||||
bench_ecdh_data data;
|
||||
|
||||
run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000);
|
||||
int iters = get_iters(20000);
|
||||
|
||||
/* create a context with no capabilities */
|
||||
data.ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT);
|
||||
|
||||
run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
214
src/bench_ecmult.c
Normal file
214
src/bench_ecmult.c
Normal file
@@ -0,0 +1,214 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2017 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
|
||||
#include "util.h"
|
||||
#include "hash_impl.h"
|
||||
#include "num_impl.h"
|
||||
#include "field_impl.h"
|
||||
#include "group_impl.h"
|
||||
#include "scalar_impl.h"
|
||||
#include "ecmult_impl.h"
|
||||
#include "bench.h"
|
||||
#include "secp256k1.c"
|
||||
|
||||
#define POINTS 32768
|
||||
|
||||
typedef struct {
|
||||
/* Setup once in advance */
|
||||
secp256k1_context* ctx;
|
||||
secp256k1_scratch_space* scratch;
|
||||
secp256k1_scalar* scalars;
|
||||
secp256k1_ge* pubkeys;
|
||||
secp256k1_scalar* seckeys;
|
||||
secp256k1_gej* expected_output;
|
||||
secp256k1_ecmult_multi_func ecmult_multi;
|
||||
|
||||
/* Changes per test */
|
||||
size_t count;
|
||||
int includes_g;
|
||||
|
||||
/* Changes per test iteration */
|
||||
size_t offset1;
|
||||
size_t offset2;
|
||||
|
||||
/* Test output. */
|
||||
secp256k1_gej* output;
|
||||
} bench_data;
|
||||
|
||||
static int bench_callback(secp256k1_scalar* sc, secp256k1_ge* ge, size_t idx, void* arg) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
if (data->includes_g) ++idx;
|
||||
if (idx == 0) {
|
||||
*sc = data->scalars[data->offset1];
|
||||
*ge = secp256k1_ge_const_g;
|
||||
} else {
|
||||
*sc = data->scalars[(data->offset1 + idx) % POINTS];
|
||||
*ge = data->pubkeys[(data->offset2 + idx - 1) % POINTS];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void bench_ecmult(void* arg, int iters) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
|
||||
int includes_g = data->includes_g;
|
||||
int iter;
|
||||
int count = data->count;
|
||||
iters = iters / data->count;
|
||||
|
||||
for (iter = 0; iter < iters; ++iter) {
|
||||
data->ecmult_multi(&data->ctx->error_callback, &data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g);
|
||||
data->offset1 = (data->offset1 + count) % POINTS;
|
||||
data->offset2 = (data->offset2 + count - 1) % POINTS;
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_ecmult_setup(void* arg) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS;
|
||||
data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS;
|
||||
}
|
||||
|
||||
static void bench_ecmult_teardown(void* arg, int iters) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
int iter;
|
||||
iters = iters / data->count;
|
||||
/* Verify the results in teardown, to avoid doing comparisons while benchmarking. */
|
||||
for (iter = 0; iter < iters; ++iter) {
|
||||
secp256k1_gej tmp;
|
||||
secp256k1_gej_add_var(&tmp, &data->output[iter], &data->expected_output[iter], NULL);
|
||||
CHECK(secp256k1_gej_is_infinity(&tmp));
|
||||
}
|
||||
}
|
||||
|
||||
static void generate_scalar(uint32_t num, secp256k1_scalar* scalar) {
|
||||
secp256k1_sha256 sha256;
|
||||
unsigned char c[11] = {'e', 'c', 'm', 'u', 'l', 't', 0, 0, 0, 0};
|
||||
unsigned char buf[32];
|
||||
int overflow = 0;
|
||||
c[6] = num;
|
||||
c[7] = num >> 8;
|
||||
c[8] = num >> 16;
|
||||
c[9] = num >> 24;
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&sha256, c, sizeof(c));
|
||||
secp256k1_sha256_finalize(&sha256, buf);
|
||||
secp256k1_scalar_set_b32(scalar, buf, &overflow);
|
||||
CHECK(!overflow);
|
||||
}
|
||||
|
||||
static void run_test(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;
|
||||
|
||||
data->count = count;
|
||||
data->includes_g = includes_g;
|
||||
|
||||
/* Compute (the negation of) the expected results directly. */
|
||||
data->offset1 = (data->count * 0x537b7f6f + 0x8f66a481) % POINTS;
|
||||
data->offset2 = (data->count * 0x7f6f537b + 0x6a1a8f49) % POINTS;
|
||||
for (iter = 0; iter < iters; ++iter) {
|
||||
secp256k1_scalar tmp;
|
||||
secp256k1_scalar total = data->scalars[(data->offset1++) % POINTS];
|
||||
size_t i = 0;
|
||||
for (i = 0; i + 1 < count; ++i) {
|
||||
secp256k1_scalar_mul(&tmp, &data->seckeys[(data->offset2++) % POINTS], &data->scalars[(data->offset1++) % POINTS]);
|
||||
secp256k1_scalar_add(&total, &total, &tmp);
|
||||
}
|
||||
secp256k1_scalar_negate(&total, &total);
|
||||
secp256k1_ecmult(&data->ctx->ecmult_ctx, &data->expected_output[iter], NULL, &zero, &total);
|
||||
}
|
||||
|
||||
/* Run the benchmark. */
|
||||
sprintf(str, includes_g ? "ecmult_%ig" : "ecmult_%i", (int)count);
|
||||
run_benchmark(str, bench_ecmult, bench_ecmult_setup, bench_ecmult_teardown, data, 10, count * iters);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
bench_data data;
|
||||
int i, p;
|
||||
secp256k1_gej* pubkeys_gej;
|
||||
size_t scratch_size;
|
||||
|
||||
int iters = get_iters(10000);
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
|
||||
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
|
||||
data.ecmult_multi = secp256k1_ecmult_multi_var;
|
||||
|
||||
if (argc > 1) {
|
||||
if(have_flag(argc, argv, "pippenger_wnaf")) {
|
||||
printf("Using pippenger_wnaf:\n");
|
||||
data.ecmult_multi = secp256k1_ecmult_pippenger_batch_single;
|
||||
} else if(have_flag(argc, argv, "strauss_wnaf")) {
|
||||
printf("Using strauss_wnaf:\n");
|
||||
data.ecmult_multi = secp256k1_ecmult_strauss_batch_single;
|
||||
} else if(have_flag(argc, argv, "simple")) {
|
||||
printf("Using simple algorithm:\n");
|
||||
data.ecmult_multi = secp256k1_ecmult_multi_var;
|
||||
secp256k1_scratch_space_destroy(data.ctx, data.scratch);
|
||||
data.scratch = NULL;
|
||||
} else {
|
||||
fprintf(stderr, "%s: unrecognized argument '%s'.\n", argv[0], argv[1]);
|
||||
fprintf(stderr, "Use 'pippenger_wnaf', 'strauss_wnaf', 'simple' or no argument to benchmark a combined algorithm.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate stuff */
|
||||
data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS);
|
||||
data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS);
|
||||
data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS);
|
||||
data.expected_output = malloc(sizeof(secp256k1_gej) * (iters + 1));
|
||||
data.output = malloc(sizeof(secp256k1_gej) * (iters + 1));
|
||||
|
||||
/* Generate a set of scalars, and private/public keypairs. */
|
||||
pubkeys_gej = malloc(sizeof(secp256k1_gej) * POINTS);
|
||||
secp256k1_gej_set_ge(&pubkeys_gej[0], &secp256k1_ge_const_g);
|
||||
secp256k1_scalar_set_int(&data.seckeys[0], 1);
|
||||
for (i = 0; i < POINTS; ++i) {
|
||||
generate_scalar(i, &data.scalars[i]);
|
||||
if (i) {
|
||||
secp256k1_gej_double_var(&pubkeys_gej[i], &pubkeys_gej[i - 1], NULL);
|
||||
secp256k1_scalar_add(&data.seckeys[i], &data.seckeys[i - 1], &data.seckeys[i - 1]);
|
||||
}
|
||||
}
|
||||
secp256k1_ge_set_all_gej_var(data.pubkeys, pubkeys_gej, POINTS);
|
||||
free(pubkeys_gej);
|
||||
|
||||
for (i = 1; i <= 8; ++i) {
|
||||
run_test(&data, i, 1, iters);
|
||||
}
|
||||
|
||||
/* This is disabled with low count of iterations because the loop runs 77 times even with iters=1
|
||||
* and the higher it goes the longer the computation takes(more points)
|
||||
* So we don't run this benchmark with low iterations to prevent slow down */
|
||||
if (iters > 2) {
|
||||
for (p = 0; p <= 11; ++p) {
|
||||
for (i = 9; i <= 16; ++i) {
|
||||
run_test(&data, i << p, 1, iters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.scratch != NULL) {
|
||||
secp256k1_scratch_space_destroy(data.ctx, data.scratch);
|
||||
}
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
free(data.scalars);
|
||||
free(data.pubkeys);
|
||||
free(data.seckeys);
|
||||
free(data.output);
|
||||
free(data.expected_output);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -23,22 +23,22 @@ static void bench_generator_setup(void* arg) {
|
||||
memset(data->blind, 0x13, 32);
|
||||
}
|
||||
|
||||
static void bench_generator_generate(void* arg) {
|
||||
static void bench_generator_generate(void* arg, int iters) {
|
||||
int i;
|
||||
bench_generator_t *data = (bench_generator_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_generator gen;
|
||||
CHECK(secp256k1_generator_generate(data->ctx, &gen, data->key));
|
||||
data->key[i & 31]++;
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_generator_generate_blinded(void* arg) {
|
||||
static void bench_generator_generate_blinded(void* arg, int iters) {
|
||||
int i;
|
||||
bench_generator_t *data = (bench_generator_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_generator gen;
|
||||
CHECK(secp256k1_generator_generate_blinded(data->ctx, &gen, data->key, data->blind));
|
||||
data->key[1 + (i & 30)]++;
|
||||
@@ -48,11 +48,12 @@ static void bench_generator_generate_blinded(void* arg) {
|
||||
|
||||
int main(void) {
|
||||
bench_generator_t data;
|
||||
int iters = get_iters(20000);
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
run_benchmark("generator_generate", bench_generator_generate, bench_generator_setup, NULL, &data, 10, 20000);
|
||||
run_benchmark("generator_generate_blinded", bench_generator_generate_blinded, bench_generator_setup, NULL, &data, 10, 20000);
|
||||
run_benchmark("generator_generate", bench_generator_generate, bench_generator_setup, NULL, &data, 10, iters);
|
||||
run_benchmark("generator_generate_blinded", bench_generator_generate_blinded, bench_generator_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
|
||||
#include "assumptions.h"
|
||||
#include "util.h"
|
||||
#include "hash_impl.h"
|
||||
#include "num_impl.h"
|
||||
@@ -19,364 +20,412 @@
|
||||
#include "secp256k1.c"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_scalar scalar_x, scalar_y;
|
||||
secp256k1_fe fe_x, fe_y;
|
||||
secp256k1_ge ge_x, ge_y;
|
||||
secp256k1_gej gej_x, gej_y;
|
||||
secp256k1_scalar scalar[2];
|
||||
secp256k1_fe fe[4];
|
||||
secp256k1_ge ge[2];
|
||||
secp256k1_gej gej[2];
|
||||
unsigned char data[64];
|
||||
int wnaf[256];
|
||||
} bench_inv_t;
|
||||
} bench_inv;
|
||||
|
||||
void bench_setup(void* arg) {
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
static const unsigned char init_x[32] = {
|
||||
0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
|
||||
0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
|
||||
0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,
|
||||
0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83
|
||||
static const unsigned char init[4][32] = {
|
||||
/* Initializer for scalar[0], fe[0], first half of data, the X coordinate of ge[0],
|
||||
and the (implied affine) X coordinate of gej[0]. */
|
||||
{
|
||||
0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13,
|
||||
0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35,
|
||||
0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59,
|
||||
0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83
|
||||
},
|
||||
/* Initializer for scalar[1], fe[1], first half of data, the X coordinate of ge[1],
|
||||
and the (implied affine) X coordinate of gej[1]. */
|
||||
{
|
||||
0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83,
|
||||
0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5,
|
||||
0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9,
|
||||
0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3
|
||||
},
|
||||
/* Initializer for fe[2] and the Z coordinate of gej[0]. */
|
||||
{
|
||||
0x3d, 0x2d, 0xef, 0xf4, 0x25, 0x98, 0x4f, 0x5d,
|
||||
0xe2, 0xca, 0x5f, 0x41, 0x3f, 0x3f, 0xce, 0x44,
|
||||
0xaa, 0x2c, 0x53, 0x8a, 0xc6, 0x59, 0x1f, 0x38,
|
||||
0x38, 0x23, 0xe4, 0x11, 0x27, 0xc6, 0xa0, 0xe7
|
||||
},
|
||||
/* Initializer for fe[3] and the Z coordinate of gej[1]. */
|
||||
{
|
||||
0xbd, 0x21, 0xa5, 0xe1, 0x13, 0x50, 0x73, 0x2e,
|
||||
0x52, 0x98, 0xc8, 0x9e, 0xab, 0x00, 0xa2, 0x68,
|
||||
0x43, 0xf5, 0xd7, 0x49, 0x80, 0x72, 0xa7, 0xf3,
|
||||
0xd7, 0x60, 0xe6, 0xab, 0x90, 0x92, 0xdf, 0xc5
|
||||
}
|
||||
};
|
||||
|
||||
static const unsigned char init_y[32] = {
|
||||
0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83,
|
||||
0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5,
|
||||
0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9,
|
||||
0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3
|
||||
};
|
||||
|
||||
secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL);
|
||||
secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL);
|
||||
secp256k1_fe_set_b32(&data->fe_x, init_x);
|
||||
secp256k1_fe_set_b32(&data->fe_y, init_y);
|
||||
CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0));
|
||||
CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1));
|
||||
secp256k1_gej_set_ge(&data->gej_x, &data->ge_x);
|
||||
secp256k1_gej_set_ge(&data->gej_y, &data->ge_y);
|
||||
memcpy(data->data, init_x, 32);
|
||||
memcpy(data->data + 32, init_y, 32);
|
||||
secp256k1_scalar_set_b32(&data->scalar[0], init[0], NULL);
|
||||
secp256k1_scalar_set_b32(&data->scalar[1], init[1], NULL);
|
||||
secp256k1_fe_set_b32(&data->fe[0], init[0]);
|
||||
secp256k1_fe_set_b32(&data->fe[1], init[1]);
|
||||
secp256k1_fe_set_b32(&data->fe[2], init[2]);
|
||||
secp256k1_fe_set_b32(&data->fe[3], init[3]);
|
||||
CHECK(secp256k1_ge_set_xo_var(&data->ge[0], &data->fe[0], 0));
|
||||
CHECK(secp256k1_ge_set_xo_var(&data->ge[1], &data->fe[1], 1));
|
||||
secp256k1_gej_set_ge(&data->gej[0], &data->ge[0]);
|
||||
secp256k1_gej_rescale(&data->gej[0], &data->fe[2]);
|
||||
secp256k1_gej_set_ge(&data->gej[1], &data->ge[1]);
|
||||
secp256k1_gej_rescale(&data->gej[1], &data->fe[3]);
|
||||
memcpy(data->data, init[0], 32);
|
||||
memcpy(data->data + 32, init[1], 32);
|
||||
}
|
||||
|
||||
void bench_scalar_add(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
void bench_scalar_add(void* arg, int iters) {
|
||||
int i, j = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 2000000; i++) {
|
||||
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||
for (i = 0; i < iters; i++) {
|
||||
j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
|
||||
}
|
||||
CHECK(j <= iters);
|
||||
}
|
||||
|
||||
void bench_scalar_negate(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_scalar_negate(&data->scalar[0], &data->scalar[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_scalar_negate(void* arg) {
|
||||
void bench_scalar_sqr(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 2000000; i++) {
|
||||
secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_scalar_sqr(&data->scalar[0], &data->scalar[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_scalar_sqr(void* arg) {
|
||||
void bench_scalar_mul(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_scalar_mul(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_scalar_mul(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
void bench_scalar_split(void* arg, int iters) {
|
||||
int i, j = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_scalar_split_lambda(&data->scalar[0], &data->scalar[1], &data->scalar[0]);
|
||||
j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
|
||||
}
|
||||
CHECK(j <= iters);
|
||||
}
|
||||
|
||||
void bench_scalar_inverse(void* arg, int iters) {
|
||||
int i, j = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_scalar_inverse(&data->scalar[0], &data->scalar[0]);
|
||||
j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
|
||||
}
|
||||
CHECK(j <= iters);
|
||||
}
|
||||
|
||||
void bench_scalar_inverse_var(void* arg, int iters) {
|
||||
int i, j = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_scalar_inverse_var(&data->scalar[0], &data->scalar[0]);
|
||||
j += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
|
||||
}
|
||||
CHECK(j <= iters);
|
||||
}
|
||||
|
||||
void bench_field_normalize(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_fe_normalize(&data->fe[0]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
void bench_scalar_split(void* arg) {
|
||||
void bench_field_normalize_weak(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_scalar l, r;
|
||||
secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x);
|
||||
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void bench_scalar_inverse(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 2000; i++) {
|
||||
secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x);
|
||||
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_fe_normalize_weak(&data->fe[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_scalar_inverse_var(void* arg) {
|
||||
void bench_field_mul(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 2000; i++) {
|
||||
secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x);
|
||||
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_fe_mul(&data->fe[0], &data->fe[0], &data->fe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_field_normalize(void* arg) {
|
||||
void bench_field_sqr(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 2000000; i++) {
|
||||
secp256k1_fe_normalize(&data->fe_x);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_fe_sqr(&data->fe[0], &data->fe[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_field_normalize_weak(void* arg) {
|
||||
void bench_field_inverse(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 2000000; i++) {
|
||||
secp256k1_fe_normalize_weak(&data->fe_x);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_fe_inv(&data->fe[0], &data->fe[0]);
|
||||
secp256k1_fe_add(&data->fe[0], &data->fe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_field_mul(void* arg) {
|
||||
void bench_field_inverse_var(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_fe_inv_var(&data->fe[0], &data->fe[0]);
|
||||
secp256k1_fe_add(&data->fe[0], &data->fe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_field_sqr(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
void bench_field_sqrt(void* arg, int iters) {
|
||||
int i, j = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
secp256k1_fe t;
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_fe_sqr(&data->fe_x, &data->fe_x);
|
||||
for (i = 0; i < iters; i++) {
|
||||
t = data->fe[0];
|
||||
j += secp256k1_fe_sqrt(&data->fe[0], &t);
|
||||
secp256k1_fe_add(&data->fe[0], &data->fe[1]);
|
||||
}
|
||||
CHECK(j <= iters);
|
||||
}
|
||||
|
||||
void bench_group_double_var(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_gej_double_var(&data->gej[0], &data->gej[0], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_field_inverse(void* arg) {
|
||||
void bench_group_add_var(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_fe_inv(&data->fe_x, &data->fe_x);
|
||||
secp256k1_fe_add(&data->fe_x, &data->fe_y);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_gej_add_var(&data->gej[0], &data->gej[0], &data->gej[1], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_field_inverse_var(void* arg) {
|
||||
void bench_group_add_affine(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_fe_inv_var(&data->fe_x, &data->fe_x);
|
||||
secp256k1_fe_add(&data->fe_x, &data->fe_y);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_gej_add_ge(&data->gej[0], &data->gej[0], &data->ge[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_field_sqrt(void* arg) {
|
||||
void bench_group_add_affine_var(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);
|
||||
secp256k1_fe_add(&data->fe_x, &data->fe_y);
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_gej_add_ge_var(&data->gej[0], &data->gej[0], &data->ge[1], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_group_double_var(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
void bench_group_jacobi_var(void* arg, int iters) {
|
||||
int i, j = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL);
|
||||
for (i = 0; i < iters; i++) {
|
||||
j += secp256k1_gej_has_quad_y_var(&data->gej[0]);
|
||||
/* Vary the Y and Z coordinates of the input (the X coordinate doesn't matter to
|
||||
secp256k1_gej_has_quad_y_var). Note that the resulting coordinates will
|
||||
generally not correspond to a point on the curve, but this is not a problem
|
||||
for the code being benchmarked here. Adding and normalizing have less
|
||||
overhead than EC operations (which could guarantee the point remains on the
|
||||
curve). */
|
||||
secp256k1_fe_add(&data->gej[0].y, &data->fe[1]);
|
||||
secp256k1_fe_add(&data->gej[0].z, &data->fe[2]);
|
||||
secp256k1_fe_normalize_var(&data->gej[0].y);
|
||||
secp256k1_fe_normalize_var(&data->gej[0].z);
|
||||
}
|
||||
CHECK(j <= iters);
|
||||
}
|
||||
|
||||
void bench_group_to_affine_var(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < iters; ++i) {
|
||||
secp256k1_ge_set_gej_var(&data->ge[1], &data->gej[0]);
|
||||
/* Use the output affine X/Y coordinates to vary the input X/Y/Z coordinates.
|
||||
Similar to bench_group_jacobi_var, this approach does not result in
|
||||
coordinates of points on the curve. */
|
||||
secp256k1_fe_add(&data->gej[0].x, &data->ge[1].y);
|
||||
secp256k1_fe_add(&data->gej[0].y, &data->fe[2]);
|
||||
secp256k1_fe_add(&data->gej[0].z, &data->ge[1].x);
|
||||
secp256k1_fe_normalize_var(&data->gej[0].x);
|
||||
secp256k1_fe_normalize_var(&data->gej[0].y);
|
||||
secp256k1_fe_normalize_var(&data->gej[0].z);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_group_add_var(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
void bench_ecmult_wnaf(void* arg, int iters) {
|
||||
int i, bits = 0, overflow = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL);
|
||||
for (i = 0; i < iters; i++) {
|
||||
bits += secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar[0], WINDOW_A);
|
||||
overflow += secp256k1_scalar_add(&data->scalar[0], &data->scalar[0], &data->scalar[1]);
|
||||
}
|
||||
CHECK(overflow >= 0);
|
||||
CHECK(bits <= 256*iters);
|
||||
}
|
||||
|
||||
void bench_group_add_affine(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
void bench_wnaf_const(void* arg, int iters) {
|
||||
int i, bits = 0, overflow = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_group_add_affine_var(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_group_jacobi_var(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_gej_has_quad_y_var(&data->gej_x);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_ecmult_wnaf(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A);
|
||||
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_wnaf_const(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A, 256, 1);
|
||||
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void bench_sha256(void* arg) {
|
||||
void bench_sha256(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
secp256k1_sha256_t sha;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, data->data, 32);
|
||||
secp256k1_sha256_finalize(&sha, data->data);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_hmac_sha256(void* arg) {
|
||||
void bench_hmac_sha256(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
secp256k1_hmac_sha256_t hmac;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_hmac_sha256_initialize(&hmac, data->data, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, data->data, 32);
|
||||
secp256k1_hmac_sha256_finalize(&hmac, data->data);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_rfc6979_hmac_sha256(void* arg) {
|
||||
void bench_rfc6979_hmac_sha256(void* arg, int iters) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
secp256k1_rfc6979_hmac_sha256_t rng;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
secp256k1_rfc6979_hmac_sha256 rng;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64);
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32);
|
||||
}
|
||||
}
|
||||
|
||||
void bench_context_verify(void* arg) {
|
||||
void bench_context_verify(void* arg, int iters) {
|
||||
int i;
|
||||
(void)arg;
|
||||
for (i = 0; i < 20; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY));
|
||||
}
|
||||
}
|
||||
|
||||
void bench_context_sign(void* arg) {
|
||||
void bench_context_sign(void* arg, int iters) {
|
||||
int i;
|
||||
(void)arg;
|
||||
for (i = 0; i < 200; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_NUM_NONE
|
||||
void bench_num_jacobi(void* arg) {
|
||||
int i;
|
||||
bench_inv_t *data = (bench_inv_t*)arg;
|
||||
secp256k1_num nx, norder;
|
||||
void bench_num_jacobi(void* arg, int iters) {
|
||||
int i, j = 0;
|
||||
bench_inv *data = (bench_inv*)arg;
|
||||
secp256k1_num nx, na, norder;
|
||||
|
||||
secp256k1_scalar_get_num(&nx, &data->scalar_x);
|
||||
secp256k1_scalar_get_num(&nx, &data->scalar[0]);
|
||||
secp256k1_scalar_order_get_num(&norder);
|
||||
secp256k1_scalar_get_num(&norder, &data->scalar_y);
|
||||
secp256k1_scalar_get_num(&na, &data->scalar[1]);
|
||||
|
||||
for (i = 0; i < 200000; i++) {
|
||||
secp256k1_num_jacobi(&nx, &norder);
|
||||
for (i = 0; i < iters; i++) {
|
||||
j += secp256k1_num_jacobi(&nx, &norder);
|
||||
secp256k1_num_add(&nx, &nx, &na);
|
||||
}
|
||||
CHECK(j <= iters);
|
||||
}
|
||||
#endif
|
||||
|
||||
int have_flag(int argc, char** argv, char *flag) {
|
||||
char** argm = argv + argc;
|
||||
argv++;
|
||||
if (argv == argm) {
|
||||
return 1;
|
||||
}
|
||||
while (argv != NULL && argv != argm) {
|
||||
if (strcmp(*argv, flag) == 0) {
|
||||
return 1;
|
||||
}
|
||||
argv++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
bench_inv_t data;
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000);
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000);
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000);
|
||||
#endif
|
||||
bench_inv data;
|
||||
int iters = get_iters(20000);
|
||||
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, iters);
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000);
|
||||
if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000);
|
||||
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, iters*100);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters);
|
||||
if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters);
|
||||
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, iters*10);
|
||||
if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, iters);
|
||||
if (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 (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, iters);
|
||||
if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, iters);
|
||||
|
||||
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000);
|
||||
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, iters);
|
||||
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, iters);
|
||||
if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, iters);
|
||||
|
||||
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20);
|
||||
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200);
|
||||
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 1 + iters/1000);
|
||||
if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 1 + iters/100);
|
||||
|
||||
#ifndef USE_NUM_NONE
|
||||
if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000);
|
||||
if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, iters*10);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -34,11 +34,11 @@ static void bench_rangeproof_setup(void* arg) {
|
||||
CHECK(secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len, NULL, 0, secp256k1_generator_h));
|
||||
}
|
||||
|
||||
static void bench_rangeproof(void* arg) {
|
||||
static void bench_rangeproof(void* arg, int iters) {
|
||||
int i;
|
||||
bench_rangeproof_t *data = (bench_rangeproof_t*)arg;
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
for (i = 0; i < iters/data->min_bits; i++) {
|
||||
int j;
|
||||
uint64_t minv;
|
||||
uint64_t maxv;
|
||||
@@ -51,12 +51,14 @@ static void bench_rangeproof(void* arg) {
|
||||
|
||||
int main(void) {
|
||||
bench_rangeproof_t data;
|
||||
int iters;
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
data.min_bits = 32;
|
||||
iters = data.min_bits*get_iters(32);
|
||||
|
||||
run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, 1000 * data.min_bits);
|
||||
run_benchmark("rangeproof_verify_bit", bench_rangeproof, bench_rangeproof_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
|
||||
@@ -13,15 +13,15 @@ typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
unsigned char msg[32];
|
||||
unsigned char sig[64];
|
||||
} bench_recover_t;
|
||||
} bench_recover_data;
|
||||
|
||||
void bench_recover(void* arg) {
|
||||
void bench_recover(void* arg, int iters) {
|
||||
int i;
|
||||
bench_recover_t *data = (bench_recover_t*)arg;
|
||||
bench_recover_data *data = (bench_recover_data*)arg;
|
||||
secp256k1_pubkey pubkey;
|
||||
unsigned char pubkeyc[33];
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
int j;
|
||||
size_t pubkeylen = 33;
|
||||
secp256k1_ecdsa_recoverable_signature sig;
|
||||
@@ -38,7 +38,7 @@ void bench_recover(void* arg) {
|
||||
|
||||
void bench_recover_setup(void* arg) {
|
||||
int i;
|
||||
bench_recover_t *data = (bench_recover_t*)arg;
|
||||
bench_recover_data *data = (bench_recover_data*)arg;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->msg[i] = 1 + i;
|
||||
@@ -49,11 +49,13 @@ void bench_recover_setup(void* arg) {
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
bench_recover_t data;
|
||||
bench_recover_data data;
|
||||
|
||||
int iters = get_iters(20000);
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000);
|
||||
run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2014 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_schnorr.h"
|
||||
#include "util.h"
|
||||
#include "bench.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned char key[32];
|
||||
unsigned char sig[64];
|
||||
unsigned char pubkey[33];
|
||||
size_t pubkeylen;
|
||||
} benchmark_schnorr_sig_t;
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
unsigned char msg[32];
|
||||
benchmark_schnorr_sig_t sigs[64];
|
||||
int numsigs;
|
||||
} benchmark_schnorr_verify_t;
|
||||
|
||||
static void benchmark_schnorr_init(void* arg) {
|
||||
int i, k;
|
||||
benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->msg[i] = 1 + i;
|
||||
}
|
||||
for (k = 0; k < data->numsigs; k++) {
|
||||
secp256k1_pubkey pubkey;
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->sigs[k].key[i] = 33 + i + k;
|
||||
}
|
||||
secp256k1_schnorr_sign(data->ctx, data->sigs[k].sig, data->msg, data->sigs[k].key, NULL, NULL);
|
||||
data->sigs[k].pubkeylen = 33;
|
||||
CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->sigs[k].key));
|
||||
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, data->sigs[k].pubkey, &data->sigs[k].pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED));
|
||||
}
|
||||
}
|
||||
|
||||
static void benchmark_schnorr_verify(void* arg) {
|
||||
int i;
|
||||
benchmark_schnorr_verify_t* data = (benchmark_schnorr_verify_t*)arg;
|
||||
|
||||
for (i = 0; i < 20000 / data->numsigs; i++) {
|
||||
secp256k1_pubkey pubkey;
|
||||
data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
|
||||
CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->sigs[0].pubkey, data->sigs[0].pubkeylen));
|
||||
CHECK(secp256k1_schnorr_verify(data->ctx, data->sigs[0].sig, data->msg, &pubkey) == ((i & 0xFF) == 0));
|
||||
data->sigs[0].sig[(i >> 8) % 64] ^= (i & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(void) {
|
||||
benchmark_schnorr_verify_t data;
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
data.numsigs = 1;
|
||||
run_benchmark("schnorr_verify", benchmark_schnorr_verify, benchmark_schnorr_init, NULL, &data, 10, 20000);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
}
|
||||
102
src/bench_schnorrsig.c
Normal file
102
src/bench_schnorrsig.c
Normal file
@@ -0,0 +1,102 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_schnorrsig.h"
|
||||
#include "util.h"
|
||||
#include "bench.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
int n;
|
||||
|
||||
const secp256k1_keypair **keypairs;
|
||||
const unsigned char **pk;
|
||||
const unsigned char **sigs;
|
||||
const unsigned char **msgs;
|
||||
} bench_schnorrsig_data;
|
||||
|
||||
void bench_schnorrsig_sign(void* arg, int iters) {
|
||||
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
|
||||
int i;
|
||||
unsigned char msg[32] = "benchmarkexamplemessagetemplate";
|
||||
unsigned char sig[64];
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
msg[0] = i;
|
||||
msg[1] = i >> 8;
|
||||
CHECK(secp256k1_schnorrsig_sign(data->ctx, sig, msg, data->keypairs[i], NULL, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
void bench_schnorrsig_verify(void* arg, int iters) {
|
||||
bench_schnorrsig_data *data = (bench_schnorrsig_data *)arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_xonly_pubkey pk;
|
||||
CHECK(secp256k1_xonly_pubkey_parse(data->ctx, &pk, data->pk[i]) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(data->ctx, data->sigs[i], data->msgs[i], &pk));
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int i;
|
||||
bench_schnorrsig_data data;
|
||||
int iters = get_iters(10000);
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN);
|
||||
data.keypairs = (const secp256k1_keypair **)malloc(iters * sizeof(secp256k1_keypair *));
|
||||
data.pk = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
|
||||
data.msgs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
|
||||
data.sigs = (const unsigned char **)malloc(iters * sizeof(unsigned char *));
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
unsigned char sk[32];
|
||||
unsigned char *msg = (unsigned char *)malloc(32);
|
||||
unsigned char *sig = (unsigned char *)malloc(64);
|
||||
secp256k1_keypair *keypair = (secp256k1_keypair *)malloc(sizeof(*keypair));
|
||||
unsigned char *pk_char = (unsigned char *)malloc(32);
|
||||
secp256k1_xonly_pubkey pk;
|
||||
msg[0] = sk[0] = i;
|
||||
msg[1] = sk[1] = i >> 8;
|
||||
msg[2] = sk[2] = i >> 16;
|
||||
msg[3] = sk[3] = i >> 24;
|
||||
memset(&msg[4], 'm', 28);
|
||||
memset(&sk[4], 's', 28);
|
||||
|
||||
data.keypairs[i] = keypair;
|
||||
data.pk[i] = pk_char;
|
||||
data.msgs[i] = msg;
|
||||
data.sigs[i] = sig;
|
||||
|
||||
CHECK(secp256k1_keypair_create(data.ctx, keypair, sk));
|
||||
CHECK(secp256k1_schnorrsig_sign(data.ctx, sig, msg, keypair, NULL, NULL));
|
||||
CHECK(secp256k1_keypair_xonly_pub(data.ctx, &pk, NULL, keypair));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(data.ctx, pk_char, &pk) == 1);
|
||||
}
|
||||
|
||||
run_benchmark("schnorrsig_sign", bench_schnorrsig_sign, NULL, NULL, (void *) &data, 10, iters);
|
||||
run_benchmark("schnorrsig_verify", bench_schnorrsig_verify, NULL, NULL, (void *) &data, 10, iters);
|
||||
|
||||
for (i = 0; i < iters; i++) {
|
||||
free((void *)data.keypairs[i]);
|
||||
free((void *)data.pk[i]);
|
||||
free((void *)data.msgs[i]);
|
||||
free((void *)data.sigs[i]);
|
||||
}
|
||||
free(data.keypairs);
|
||||
free(data.pk);
|
||||
free(data.msgs);
|
||||
free(data.sigs);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
}
|
||||
@@ -12,11 +12,11 @@ typedef struct {
|
||||
secp256k1_context* ctx;
|
||||
unsigned char msg[32];
|
||||
unsigned char key[32];
|
||||
} bench_sign_t;
|
||||
} bench_sign_data;
|
||||
|
||||
static void bench_sign_setup(void* arg) {
|
||||
int i;
|
||||
bench_sign_t *data = (bench_sign_t*)arg;
|
||||
bench_sign_data *data = (bench_sign_data*)arg;
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
data->msg[i] = i + 1;
|
||||
@@ -26,12 +26,12 @@ static void bench_sign_setup(void* arg) {
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_sign(void* arg) {
|
||||
static void bench_sign_run(void* arg, int iters) {
|
||||
int i;
|
||||
bench_sign_t *data = (bench_sign_t*)arg;
|
||||
bench_sign_data *data = (bench_sign_data*)arg;
|
||||
|
||||
unsigned char sig[74];
|
||||
for (i = 0; i < 20000; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
size_t siglen = 74;
|
||||
int j;
|
||||
secp256k1_ecdsa_signature signature;
|
||||
@@ -45,11 +45,13 @@ static void bench_sign(void* arg) {
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
bench_sign_t data;
|
||||
bench_sign_data data;
|
||||
|
||||
int iters = get_iters(20000);
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
|
||||
run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000);
|
||||
run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return 0;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <openssl/obj_mac.h>
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context *ctx;
|
||||
unsigned char msg[32];
|
||||
@@ -28,13 +29,13 @@ typedef struct {
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
EC_GROUP* ec_group;
|
||||
#endif
|
||||
} benchmark_verify_t;
|
||||
} bench_verify_data;
|
||||
|
||||
static void benchmark_verify(void* arg) {
|
||||
static void bench_verify(void* arg, int iters) {
|
||||
int i;
|
||||
benchmark_verify_t* data = (benchmark_verify_t*)arg;
|
||||
bench_verify_data* data = (bench_verify_data*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
data->sig[data->siglen - 1] ^= (i & 0xFF);
|
||||
@@ -50,11 +51,11 @@ static void benchmark_verify(void* arg) {
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
static void benchmark_verify_openssl(void* arg) {
|
||||
static void bench_verify_openssl(void* arg, int iters) {
|
||||
int i;
|
||||
benchmark_verify_t* data = (benchmark_verify_t*)arg;
|
||||
bench_verify_data* data = (bench_verify_data*)arg;
|
||||
|
||||
for (i = 0; i < 20000; i++) {
|
||||
for (i = 0; i < iters; i++) {
|
||||
data->sig[data->siglen - 1] ^= (i & 0xFF);
|
||||
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
|
||||
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
|
||||
@@ -83,7 +84,9 @@ int main(void) {
|
||||
int i;
|
||||
secp256k1_pubkey pubkey;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
benchmark_verify_t data;
|
||||
bench_verify_data data;
|
||||
|
||||
int iters = get_iters(20000);
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
@@ -100,10 +103,10 @@ int main(void) {
|
||||
data.pubkeylen = 33;
|
||||
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
|
||||
|
||||
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);
|
||||
run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);
|
||||
#ifdef ENABLE_OPENSSL_TESTS
|
||||
data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1);
|
||||
run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000);
|
||||
run_benchmark("ecdsa_verify_openssl", bench_verify_openssl, NULL, NULL, &data, 10, iters);
|
||||
EC_GROUP_free(data.ec_group);
|
||||
#endif
|
||||
|
||||
|
||||
108
src/bench_whitelist.c
Normal file
108
src/bench_whitelist.c
Normal file
@@ -0,0 +1,108 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2017 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
|
||||
#include "include/secp256k1_whitelist.h"
|
||||
#include "util.h"
|
||||
#include "bench.h"
|
||||
#include "hash_impl.h"
|
||||
#include "num_impl.h"
|
||||
#include "scalar_impl.h"
|
||||
#include "testrand_impl.h"
|
||||
|
||||
#define MAX_N_KEYS 30
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context* ctx;
|
||||
unsigned char online_seckey[MAX_N_KEYS][32];
|
||||
unsigned char summed_seckey[MAX_N_KEYS][32];
|
||||
secp256k1_pubkey online_pubkeys[MAX_N_KEYS];
|
||||
secp256k1_pubkey offline_pubkeys[MAX_N_KEYS];
|
||||
unsigned char csub[32];
|
||||
secp256k1_pubkey sub_pubkey;
|
||||
secp256k1_whitelist_signature sig;
|
||||
size_t n_keys;
|
||||
} bench_data;
|
||||
|
||||
static void bench_whitelist(void* arg, int iters) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
int i;
|
||||
for (i = 0; i < iters; i++) {
|
||||
CHECK(secp256k1_whitelist_verify(data->ctx, &data->sig, data->online_pubkeys, data->offline_pubkeys, data->n_keys, &data->sub_pubkey) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void bench_whitelist_setup(void* arg) {
|
||||
bench_data* data = (bench_data*)arg;
|
||||
int i = 0;
|
||||
CHECK(secp256k1_whitelist_sign(data->ctx, &data->sig, data->online_pubkeys, data->offline_pubkeys, data->n_keys, &data->sub_pubkey, data->online_seckey[i], data->summed_seckey[i], i, NULL, NULL));
|
||||
}
|
||||
|
||||
static void run_test(bench_data* data, int iters) {
|
||||
char str[32];
|
||||
sprintf(str, "whitelist_%i", (int)data->n_keys);
|
||||
run_benchmark(str, bench_whitelist, bench_whitelist_setup, NULL, data, 100, iters);
|
||||
}
|
||||
|
||||
void random_scalar_order(secp256k1_scalar *num) {
|
||||
do {
|
||||
unsigned char b32[32];
|
||||
int overflow = 0;
|
||||
secp256k1_testrand256(b32);
|
||||
secp256k1_scalar_set_b32(num, b32, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(num)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} while(1);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
bench_data data;
|
||||
size_t i;
|
||||
size_t n_keys = 30;
|
||||
secp256k1_scalar ssub;
|
||||
int iters = get_iters(5);
|
||||
|
||||
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
/* Start with subkey */
|
||||
random_scalar_order(&ssub);
|
||||
secp256k1_scalar_get_b32(data.csub, &ssub);
|
||||
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.csub) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(data.ctx, &data.sub_pubkey, data.csub) == 1);
|
||||
/* Then offline and online whitelist keys */
|
||||
for (i = 0; i < n_keys; i++) {
|
||||
secp256k1_scalar son, soff;
|
||||
|
||||
/* Create two keys */
|
||||
random_scalar_order(&son);
|
||||
secp256k1_scalar_get_b32(data.online_seckey[i], &son);
|
||||
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.online_seckey[i]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(data.ctx, &data.online_pubkeys[i], data.online_seckey[i]) == 1);
|
||||
|
||||
random_scalar_order(&soff);
|
||||
secp256k1_scalar_get_b32(data.summed_seckey[i], &soff);
|
||||
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.summed_seckey[i]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(data.ctx, &data.offline_pubkeys[i], data.summed_seckey[i]) == 1);
|
||||
|
||||
/* Make summed_seckey correspond to the sum of offline_pubkey and sub_pubkey */
|
||||
secp256k1_scalar_add(&soff, &soff, &ssub);
|
||||
secp256k1_scalar_get_b32(data.summed_seckey[i], &soff);
|
||||
CHECK(secp256k1_ec_seckey_verify(data.ctx, data.summed_seckey[i]) == 1);
|
||||
}
|
||||
|
||||
/* Run test */
|
||||
for (i = 1; i <= n_keys; ++i) {
|
||||
data.n_keys = i;
|
||||
run_test(&data, iters);
|
||||
}
|
||||
|
||||
secp256k1_context_destroy(data.ctx);
|
||||
return(0);
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_ECDSA_
|
||||
#define _SECP256K1_ECDSA_
|
||||
#ifndef SECP256K1_ECDSA_H
|
||||
#define SECP256K1_ECDSA_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -18,4 +18,4 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const
|
||||
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message);
|
||||
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid);
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_ECDSA_H */
|
||||
|
||||
104
src/ecdsa_impl.h
104
src/ecdsa_impl.h
@@ -5,8 +5,8 @@
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef _SECP256K1_ECDSA_IMPL_H_
|
||||
#define _SECP256K1_ECDSA_IMPL_H_
|
||||
#ifndef SECP256K1_ECDSA_IMPL_H
|
||||
#define SECP256K1_ECDSA_IMPL_H
|
||||
|
||||
#include "scalar.h"
|
||||
#include "field.h"
|
||||
@@ -46,70 +46,73 @@ static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CON
|
||||
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
|
||||
);
|
||||
|
||||
static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) {
|
||||
int lenleft, b1;
|
||||
size_t ret = 0;
|
||||
static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const unsigned char *sigend) {
|
||||
size_t lenleft;
|
||||
unsigned char b1;
|
||||
VERIFY_CHECK(len != NULL);
|
||||
*len = 0;
|
||||
if (*sigp >= sigend) {
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
b1 = *((*sigp)++);
|
||||
if (b1 == 0xFF) {
|
||||
/* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
if ((b1 & 0x80) == 0) {
|
||||
/* X.690-0207 8.1.3.4 short form length octets */
|
||||
return b1;
|
||||
*len = b1;
|
||||
return 1;
|
||||
}
|
||||
if (b1 == 0x80) {
|
||||
/* Indefinite length is not allowed in DER. */
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
/* X.690-207 8.1.3.5 long form length octets */
|
||||
lenleft = b1 & 0x7F;
|
||||
if (lenleft > sigend - *sigp) {
|
||||
return -1;
|
||||
lenleft = b1 & 0x7F; /* lenleft is at least 1 */
|
||||
if (lenleft > (size_t)(sigend - *sigp)) {
|
||||
return 0;
|
||||
}
|
||||
if (**sigp == 0) {
|
||||
/* Not the shortest possible length encoding. */
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
if ((size_t)lenleft > sizeof(size_t)) {
|
||||
if (lenleft > sizeof(size_t)) {
|
||||
/* The resulting length would exceed the range of a size_t, so
|
||||
* certainly longer than the passed array size.
|
||||
*/
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
while (lenleft > 0) {
|
||||
if ((ret >> ((sizeof(size_t) - 1) * 8)) != 0) {
|
||||
}
|
||||
ret = (ret << 8) | **sigp;
|
||||
if (ret + lenleft > (size_t)(sigend - *sigp)) {
|
||||
/* Result exceeds the length of the passed array. */
|
||||
return -1;
|
||||
}
|
||||
*len = (*len << 8) | **sigp;
|
||||
(*sigp)++;
|
||||
lenleft--;
|
||||
}
|
||||
if (ret < 128) {
|
||||
/* Not the shortest possible length encoding. */
|
||||
return -1;
|
||||
if (*len > (size_t)(sigend - *sigp)) {
|
||||
/* Result exceeds the length of the passed array. */
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
if (*len < 128) {
|
||||
/* Not the shortest possible length encoding. */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) {
|
||||
int overflow = 0;
|
||||
unsigned char ra[32] = {0};
|
||||
int rlen;
|
||||
size_t rlen;
|
||||
|
||||
if (*sig == sigend || **sig != 0x02) {
|
||||
/* Not a primitive integer (X.690-0207 8.3.1). */
|
||||
return 0;
|
||||
}
|
||||
(*sig)++;
|
||||
rlen = secp256k1_der_read_len(sig, sigend);
|
||||
if (rlen <= 0 || (*sig) + rlen > sigend) {
|
||||
if (secp256k1_der_read_len(&rlen, sig, sigend) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (rlen == 0 || *sig + rlen > sigend) {
|
||||
/* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */
|
||||
return 0;
|
||||
}
|
||||
@@ -125,8 +128,11 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char
|
||||
/* Negative. */
|
||||
overflow = 1;
|
||||
}
|
||||
while (rlen > 0 && **sig == 0) {
|
||||
/* Skip leading zero bytes */
|
||||
/* There is at most one leading zero byte:
|
||||
* if there were two leading zero bytes, we would have failed and returned 0
|
||||
* because of excessive 0x00 padding already. */
|
||||
if (rlen > 0 && **sig == 0) {
|
||||
/* Skip leading zero byte */
|
||||
rlen--;
|
||||
(*sig)++;
|
||||
}
|
||||
@@ -146,18 +152,16 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char
|
||||
|
||||
static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) {
|
||||
const unsigned char *sigend = sig + size;
|
||||
int rlen;
|
||||
size_t rlen;
|
||||
if (sig == sigend || *(sig++) != 0x30) {
|
||||
/* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */
|
||||
return 0;
|
||||
}
|
||||
rlen = secp256k1_der_read_len(&sig, sigend);
|
||||
if (rlen < 0 || sig + rlen > sigend) {
|
||||
/* Tuple exceeds bounds */
|
||||
if (secp256k1_der_read_len(&rlen, &sig, sigend) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (sig + rlen != sigend) {
|
||||
/* Garbage after tuple. */
|
||||
if (rlen != (size_t)(sigend - sig)) {
|
||||
/* Tuple exceeds bounds or garage after tuple. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -276,6 +280,7 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
|
||||
secp256k1_ge r;
|
||||
secp256k1_scalar n;
|
||||
int overflow = 0;
|
||||
int high;
|
||||
|
||||
secp256k1_ecmult_gen(ctx, &rp, nonce);
|
||||
secp256k1_ge_set_gej(&r, &rp);
|
||||
@@ -283,15 +288,11 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
|
||||
secp256k1_fe_normalize(&r.y);
|
||||
secp256k1_fe_get_b32(b, &r.x);
|
||||
secp256k1_scalar_set_b32(sigr, b, &overflow);
|
||||
/* These two conditions should be checked before calling */
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr));
|
||||
VERIFY_CHECK(overflow == 0);
|
||||
|
||||
if (recid) {
|
||||
/* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log
|
||||
* of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria.
|
||||
*/
|
||||
*recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
|
||||
*recid = (overflow << 1) | secp256k1_fe_is_odd(&r.y);
|
||||
}
|
||||
secp256k1_scalar_mul(&n, sigr, seckey);
|
||||
secp256k1_scalar_add(&n, &n, message);
|
||||
@@ -300,16 +301,15 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, sec
|
||||
secp256k1_scalar_clear(&n);
|
||||
secp256k1_gej_clear(&rp);
|
||||
secp256k1_ge_clear(&r);
|
||||
if (secp256k1_scalar_is_zero(sigs)) {
|
||||
return 0;
|
||||
high = secp256k1_scalar_is_high(sigs);
|
||||
secp256k1_scalar_cond_negate(sigs, high);
|
||||
if (recid) {
|
||||
*recid ^= high;
|
||||
}
|
||||
if (secp256k1_scalar_is_high(sigs)) {
|
||||
secp256k1_scalar_negate(sigs, sigs);
|
||||
if (recid) {
|
||||
*recid ^= 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
/* P.x = order is on the curve, so technically sig->r could end up being zero, which would be an invalid signature.
|
||||
* This is cryptographically unreachable as hitting it requires finding the discrete log of P.x = N.
|
||||
*/
|
||||
return !secp256k1_scalar_is_zero(sigr) & !secp256k1_scalar_is_zero(sigs);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_ECDSA_IMPL_H */
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_ECKEY_
|
||||
#define _SECP256K1_ECKEY_
|
||||
#ifndef SECP256K1_ECKEY_H
|
||||
#define SECP256K1_ECKEY_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -22,4 +22,4 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx,
|
||||
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak);
|
||||
static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_ECKEY_H */
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_ECKEY_IMPL_H_
|
||||
#define _SECP256K1_ECKEY_IMPL_H_
|
||||
#ifndef SECP256K1_ECKEY_IMPL_H
|
||||
#define SECP256K1_ECKEY_IMPL_H
|
||||
|
||||
#include "eckey.h"
|
||||
|
||||
@@ -15,16 +15,17 @@
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
|
||||
if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) {
|
||||
if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) {
|
||||
secp256k1_fe x;
|
||||
return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03);
|
||||
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
|
||||
return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD);
|
||||
} else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
|
||||
secp256k1_fe x, y;
|
||||
if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_xy(elem, &x, &y);
|
||||
if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) {
|
||||
if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) &&
|
||||
secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
|
||||
return 0;
|
||||
}
|
||||
return secp256k1_ge_is_valid_var(elem);
|
||||
@@ -42,10 +43,10 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p
|
||||
secp256k1_fe_get_b32(&pub[1], &elem->x);
|
||||
if (compressed) {
|
||||
*size = 33;
|
||||
pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);
|
||||
pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN;
|
||||
} else {
|
||||
*size = 65;
|
||||
pub[0] = 0x04;
|
||||
pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED;
|
||||
secp256k1_fe_get_b32(&pub[33], &elem->y);
|
||||
}
|
||||
return 1;
|
||||
@@ -53,10 +54,7 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *p
|
||||
|
||||
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
|
||||
secp256k1_scalar_add(key, key, tweak);
|
||||
if (secp256k1_scalar_is_zero(key)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return !secp256k1_scalar_is_zero(key);
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {
|
||||
@@ -74,12 +72,11 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx,
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) {
|
||||
if (secp256k1_scalar_is_zero(tweak)) {
|
||||
return 0;
|
||||
}
|
||||
int ret;
|
||||
ret = !secp256k1_scalar_is_zero(tweak);
|
||||
|
||||
secp256k1_scalar_mul(key, key, tweak);
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) {
|
||||
@@ -96,4 +93,4 @@ static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx,
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_ECKEY_IMPL_H */
|
||||
|
||||
33
src/ecmult.h
33
src/ecmult.h
@@ -1,31 +1,46 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2013, 2014 Pieter Wuille *
|
||||
* Copyright (c) 2013, 2014, 2017 Pieter Wuille, Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_ECMULT_
|
||||
#define _SECP256K1_ECMULT_
|
||||
#ifndef SECP256K1_ECMULT_H
|
||||
#define SECP256K1_ECMULT_H
|
||||
|
||||
#include "num.h"
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "scratch.h"
|
||||
|
||||
typedef struct {
|
||||
/* For accelerating the computation of a*P + b*G: */
|
||||
secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */
|
||||
#endif
|
||||
} secp256k1_ecmult_context;
|
||||
|
||||
static const size_t SECP256K1_ECMULT_CONTEXT_PREALLOCATED_SIZE;
|
||||
static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx);
|
||||
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb);
|
||||
static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst,
|
||||
const secp256k1_ecmult_context *src, const secp256k1_callback *cb);
|
||||
static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void **prealloc);
|
||||
static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src);
|
||||
static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx);
|
||||
static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx);
|
||||
|
||||
/** Double multiply: R = na*A + ng*G */
|
||||
static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng);
|
||||
|
||||
#endif
|
||||
typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data);
|
||||
|
||||
/**
|
||||
* Multi-multiply: R = inp_g_sc * G + sum_i ni * Ai.
|
||||
* Chooses the right algorithm for a given number of points and scratch space
|
||||
* size. Resets and overwrites the given scratch space. If the points do not
|
||||
* fit in the scratch space the algorithm is repeatedly run with batches of
|
||||
* points. If no scratch space is given then a simple algorithm is used that
|
||||
* simply multiplies the points with the corresponding scalars and adds them up.
|
||||
* Returns: 1 on success (including when inp_g_sc is NULL and n is 0)
|
||||
* 0 if there is not enough scratch space for a single point or
|
||||
* callback returns 0
|
||||
*/
|
||||
static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n);
|
||||
|
||||
#endif /* SECP256K1_ECMULT_H */
|
||||
|
||||
@@ -4,12 +4,17 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_ECMULT_CONST_
|
||||
#define _SECP256K1_ECMULT_CONST_
|
||||
#ifndef SECP256K1_ECMULT_CONST_H
|
||||
#define SECP256K1_ECMULT_CONST_H
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
/**
|
||||
* Multiply: R = q*A (in constant-time)
|
||||
* Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus
|
||||
* one because we internally sometimes add 2 to the number during the WNAF conversion.
|
||||
*/
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_ECMULT_CONST_H */
|
||||
|
||||
@@ -4,28 +4,32 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_ECMULT_CONST_IMPL_
|
||||
#define _SECP256K1_ECMULT_CONST_IMPL_
|
||||
#ifndef SECP256K1_ECMULT_CONST_IMPL_H
|
||||
#define SECP256K1_ECMULT_CONST_IMPL_H
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "ecmult_const.h"
|
||||
#include "ecmult_impl.h"
|
||||
|
||||
#define WNAF_SIZE(bits, w) (((bits) + (w) - 1) / (w))
|
||||
|
||||
/* This is like `ECMULT_TABLE_GET_GE` but is constant time */
|
||||
#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \
|
||||
int m; \
|
||||
int abs_n = (n) * (((n) > 0) * 2 - 1); \
|
||||
int idx_n = abs_n / 2; \
|
||||
int m = 0; \
|
||||
/* Extract the sign-bit for a constant time absolute-value. */ \
|
||||
int mask = (n) >> (sizeof(n) * CHAR_BIT - 1); \
|
||||
int abs_n = ((n) + mask) ^ mask; \
|
||||
int idx_n = abs_n >> 1; \
|
||||
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)); \
|
||||
for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \
|
||||
/* 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++) { \
|
||||
/* 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); \
|
||||
@@ -37,19 +41,20 @@
|
||||
} while(0)
|
||||
|
||||
|
||||
/** Convert a number to WNAF notation. The number becomes represented by sum(2^{wi} * wnaf[i], i=0..return_val)
|
||||
* with the following guarantees:
|
||||
/** 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 returned; this is always (WNAF_BITS + w - 1) / w
|
||||
* - 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-Verlagy Berlin Heidelberg 2003
|
||||
* 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, secp256k1_scalar s, int w, int size, int maybe_negative) {
|
||||
static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w, int size) {
|
||||
int global_sign;
|
||||
int skew = 0;
|
||||
int word = 0;
|
||||
@@ -60,64 +65,72 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size,
|
||||
|
||||
int flip;
|
||||
int bit;
|
||||
secp256k1_scalar neg_s;
|
||||
secp256k1_scalar s;
|
||||
int not_neg_one;
|
||||
|
||||
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 technique from
|
||||
* Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even)
|
||||
* or 2 (for odd) to the number we are encoding, returning a skew value indicating
|
||||
* this, and having the caller compensate after doing the multiplication. */
|
||||
|
||||
if (maybe_negative) {
|
||||
/* Negative numbers will be negated to keep their bit representation below the maximum width */
|
||||
flip = maybe_negative ? secp256k1_scalar_is_high(&s) : 0;
|
||||
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
|
||||
bit = flip ^ !secp256k1_scalar_is_even(&s);
|
||||
/* We check for negative one, since adding 2 to it will cause an overflow */
|
||||
secp256k1_scalar_negate(&neg_s, &s);
|
||||
not_neg_one = !secp256k1_scalar_is_one(&neg_s);
|
||||
secp256k1_scalar_cadd_bit(&s, bit, not_neg_one);
|
||||
/* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects
|
||||
* that we added two to it and flipped it. In fact for -1 these operations are
|
||||
* identical. We only flipped, but since skewing is required (in the sense that
|
||||
* the skew must be 1 or 2, never zero) and flipping is not, we need to change
|
||||
* our flags to claim that we only skewed. */
|
||||
global_sign = secp256k1_scalar_cond_negate(&s, flip);
|
||||
global_sign *= not_neg_one * 2 - 1;
|
||||
skew = 1 << bit;
|
||||
} else {
|
||||
VERIFY_CHECK(!secp256k1_scalar_is_high(&s));
|
||||
bit = !secp256k1_scalar_is_even(&s);
|
||||
skew = 1 << bit;
|
||||
secp256k1_scalar_cadd_bit(&s, bit, 1);
|
||||
global_sign = 1;
|
||||
}
|
||||
* this, and having the caller compensate after doing the multiplication.
|
||||
*
|
||||
* 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, inverting which of
|
||||
* {1, 2} we want to add to the scalar when ensuring that it's odd. Further
|
||||
* complicating things, -1 interacts badly with `secp256k1_scalar_cadd_bit` and
|
||||
* we need to special-case it in this logic. */
|
||||
flip = secp256k1_scalar_is_high(scalar);
|
||||
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
|
||||
bit = flip ^ !secp256k1_scalar_is_even(scalar);
|
||||
/* We check for negative one, since adding 2 to it will cause an overflow */
|
||||
secp256k1_scalar_negate(&s, scalar);
|
||||
not_neg_one = !secp256k1_scalar_is_one(&s);
|
||||
s = *scalar;
|
||||
secp256k1_scalar_cadd_bit(&s, bit, not_neg_one);
|
||||
/* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects
|
||||
* that we added two to it and flipped it. In fact for -1 these operations are
|
||||
* identical. We only flipped, but since skewing is required (in the sense that
|
||||
* the skew must be 1 or 2, never zero) and flipping is not, we need to change
|
||||
* our flags to claim that we only skewed. */
|
||||
global_sign = secp256k1_scalar_cond_negate(&s, flip);
|
||||
global_sign *= not_neg_one * 2 - 1;
|
||||
skew = 1 << bit;
|
||||
|
||||
/* 4 */
|
||||
u_last = secp256k1_scalar_shr_int(&s, w);
|
||||
do {
|
||||
int sign;
|
||||
int even;
|
||||
|
||||
/* 4.1 4.4 */
|
||||
u = secp256k1_scalar_shr_int(&s, w);
|
||||
/* 4.2 */
|
||||
even = ((u & 1) == 0);
|
||||
sign = 2 * (u_last > 0) - 1;
|
||||
u += sign * even;
|
||||
u_last -= sign * even * (1 << w);
|
||||
/* 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);
|
||||
} while (word * w < size);
|
||||
wnaf[word] = u * global_sign;
|
||||
|
||||
VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
|
||||
VERIFY_CHECK(word == WNAF_SIZE(size, w));
|
||||
VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w));
|
||||
return skew;
|
||||
}
|
||||
|
||||
@@ -127,35 +140,26 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
||||
secp256k1_fe Z;
|
||||
|
||||
int skew_1;
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
int wnaf_1[1 + WNAF_SIZE(128, WINDOW_A - 1)];
|
||||
int wnaf_lam[1 + WNAF_SIZE(128, WINDOW_A - 1)];
|
||||
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
int skew_lam;
|
||||
secp256k1_scalar q_1, q_lam;
|
||||
#else
|
||||
int wnaf_1[1 + WNAF_SIZE(256, WINDOW_A - 1)];
|
||||
#endif
|
||||
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
|
||||
int i;
|
||||
secp256k1_scalar sc = *scalar;
|
||||
|
||||
/* build wnaf representation for q. */
|
||||
int rsize = size;
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
if (size > 128) {
|
||||
rsize = 128;
|
||||
/* 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, &sc);
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1, 128, 1);
|
||||
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1, 128, 1);
|
||||
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);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1, size, size == 256);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, scalar, WINDOW_A - 1, size);
|
||||
skew_lam = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Calculate odd multiples of a.
|
||||
@@ -169,49 +173,44 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||
secp256k1_fe_normalize_weak(&pre_a[i].y);
|
||||
}
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
if (size > 128) {
|
||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 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(rsize, WINDOW_A - 1)];
|
||||
i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
|
||||
VERIFY_CHECK(i != 0);
|
||||
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
|
||||
secp256k1_gej_set_ge(r, &tmpa);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
if (size > 128) {
|
||||
i = wnaf_lam[WNAF_SIZE(rsize, WINDOW_A - 1)];
|
||||
i = wnaf_lam[WNAF_SIZE_BITS(rsize, 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);
|
||||
}
|
||||
#endif
|
||||
/* remaining loop iterations */
|
||||
for (i = WNAF_SIZE(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
|
||||
for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
|
||||
int n;
|
||||
int j;
|
||||
for (j = 0; j < WINDOW_A - 1; ++j) {
|
||||
secp256k1_gej_double_nonzero(r, r, NULL);
|
||||
secp256k1_gej_double(r, r);
|
||||
}
|
||||
|
||||
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);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
if (size > 128) {
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
secp256k1_fe_mul(&r->z, &r->z, &Z);
|
||||
@@ -220,44 +219,36 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
|
||||
/* Correct for wNAF skew */
|
||||
secp256k1_ge correction = *a;
|
||||
secp256k1_ge_storage correction_1_stor;
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge_storage correction_lam_stor;
|
||||
#endif
|
||||
secp256k1_ge_storage a2_stor;
|
||||
secp256k1_gej tmpj;
|
||||
secp256k1_gej_set_ge(&tmpj, &correction);
|
||||
secp256k1_gej_double_var(&tmpj, &tmpj, NULL);
|
||||
secp256k1_ge_set_gej(&correction, &tmpj);
|
||||
secp256k1_ge_to_storage(&correction_1_stor, a);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
if (size > 128) {
|
||||
secp256k1_ge_to_storage(&correction_lam_stor, a);
|
||||
}
|
||||
#endif
|
||||
secp256k1_ge_to_storage(&a2_stor, &correction);
|
||||
|
||||
/* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */
|
||||
secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2);
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
if (size > 128) {
|
||||
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Apply the correction */
|
||||
secp256k1_ge_from_storage(&correction, &correction_1_stor);
|
||||
secp256k1_ge_neg(&correction, &correction);
|
||||
secp256k1_gej_add_ge(r, r, &correction);
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
if (size > 128) {
|
||||
secp256k1_ge_from_storage(&correction, &correction_lam_stor);
|
||||
secp256k1_ge_neg(&correction, &correction);
|
||||
secp256k1_ge_mul_lambda(&correction, &correction);
|
||||
secp256k1_gej_add_ge(r, r, &correction);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */
|
||||
|
||||
@@ -4,34 +4,41 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_ECMULT_GEN_
|
||||
#define _SECP256K1_ECMULT_GEN_
|
||||
#ifndef SECP256K1_ECMULT_GEN_H
|
||||
#define SECP256K1_ECMULT_GEN_H
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
|
||||
#if ECMULT_GEN_PREC_BITS != 2 && ECMULT_GEN_PREC_BITS != 4 && ECMULT_GEN_PREC_BITS != 8
|
||||
# error "Set ECMULT_GEN_PREC_BITS to 2, 4 or 8."
|
||||
#endif
|
||||
#define ECMULT_GEN_PREC_B ECMULT_GEN_PREC_BITS
|
||||
#define ECMULT_GEN_PREC_G (1 << ECMULT_GEN_PREC_B)
|
||||
#define ECMULT_GEN_PREC_N (256 / ECMULT_GEN_PREC_B)
|
||||
|
||||
typedef struct {
|
||||
/* For accelerating the computation of a*G:
|
||||
* To harden against timing attacks, use the following mechanism:
|
||||
* * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63.
|
||||
* * Compute sum(n_i * 16^i * G + U_i, i=0..63), where:
|
||||
* * U_i = U * 2^i (for i=0..62)
|
||||
* * U_i = U * (1-2^63) (for i=63)
|
||||
* where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0.
|
||||
* For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is
|
||||
* precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63).
|
||||
* * Break up the multiplicand into groups of PREC_B bits, called n_0, n_1, n_2, ..., n_(PREC_N-1).
|
||||
* * Compute sum(n_i * (PREC_G)^i * G + U_i, i=0 ... PREC_N-1), where:
|
||||
* * U_i = U * 2^i, for i=0 ... PREC_N-2
|
||||
* * U_i = U * (1-2^(PREC_N-1)), for i=PREC_N-1
|
||||
* where U is a point with no known corresponding scalar. Note that sum(U_i, i=0 ... PREC_N-1) = 0.
|
||||
* For each i, and each of the PREC_G possible values of n_i, (n_i * (PREC_G)^i * G + U_i) is
|
||||
* precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0 ... PREC_N-1).
|
||||
* None of the resulting prec group elements have a known scalar, and neither do any of
|
||||
* the intermediate sums while computing a*G.
|
||||
*/
|
||||
secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */
|
||||
secp256k1_ge_storage (*prec)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G]; /* prec[j][i] = (PREC_G)^j * i * G + U_i */
|
||||
secp256k1_scalar blind;
|
||||
secp256k1_gej initial;
|
||||
} secp256k1_ecmult_gen_context;
|
||||
|
||||
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
|
||||
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx);
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb);
|
||||
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
|
||||
const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb);
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, void **prealloc);
|
||||
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context* src);
|
||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx);
|
||||
static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx);
|
||||
|
||||
@@ -40,4 +47,4 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp25
|
||||
|
||||
static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32);
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_ECMULT_GEN_H */
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_
|
||||
#define _SECP256K1_ECMULT_GEN_IMPL_H_
|
||||
#ifndef SECP256K1_ECMULT_GEN_IMPL_H
|
||||
#define SECP256K1_ECMULT_GEN_IMPL_H
|
||||
|
||||
#include "util.h"
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "ecmult_gen.h"
|
||||
@@ -14,23 +15,32 @@
|
||||
#ifdef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||
#include "ecmult_static_context.h"
|
||||
#endif
|
||||
|
||||
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = ROUND_TO_ALIGN(sizeof(*((secp256k1_ecmult_gen_context*) NULL)->prec));
|
||||
#else
|
||||
static const size_t SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE = 0;
|
||||
#endif
|
||||
|
||||
static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) {
|
||||
ctx->prec = NULL;
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) {
|
||||
static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, void **prealloc) {
|
||||
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||
secp256k1_ge prec[1024];
|
||||
secp256k1_ge prec[ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G];
|
||||
secp256k1_gej gj;
|
||||
secp256k1_gej nums_gej;
|
||||
int i, j;
|
||||
size_t const prealloc_size = SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE;
|
||||
void* const base = *prealloc;
|
||||
#endif
|
||||
|
||||
if (ctx->prec != NULL) {
|
||||
return;
|
||||
}
|
||||
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||
ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec));
|
||||
ctx->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])manual_alloc(prealloc, prealloc_size, base, prealloc_size);
|
||||
|
||||
/* get the generator */
|
||||
secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g);
|
||||
@@ -54,39 +64,39 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx
|
||||
|
||||
/* compute prec. */
|
||||
{
|
||||
secp256k1_gej precj[1024]; /* Jacobian versions of prec. */
|
||||
secp256k1_gej precj[ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G]; /* Jacobian versions of prec. */
|
||||
secp256k1_gej gbase;
|
||||
secp256k1_gej numsbase;
|
||||
gbase = gj; /* 16^j * G */
|
||||
gbase = gj; /* PREC_G^j * G */
|
||||
numsbase = nums_gej; /* 2^j * nums. */
|
||||
for (j = 0; j < 64; j++) {
|
||||
/* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */
|
||||
precj[j*16] = numsbase;
|
||||
for (i = 1; i < 16; i++) {
|
||||
secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL);
|
||||
for (j = 0; j < ECMULT_GEN_PREC_N; j++) {
|
||||
/* Set precj[j*PREC_G .. j*PREC_G+(PREC_G-1)] to (numsbase, numsbase + gbase, ..., numsbase + (PREC_G-1)*gbase). */
|
||||
precj[j*ECMULT_GEN_PREC_G] = numsbase;
|
||||
for (i = 1; i < ECMULT_GEN_PREC_G; i++) {
|
||||
secp256k1_gej_add_var(&precj[j*ECMULT_GEN_PREC_G + i], &precj[j*ECMULT_GEN_PREC_G + i - 1], &gbase, NULL);
|
||||
}
|
||||
/* Multiply gbase by 16. */
|
||||
for (i = 0; i < 4; i++) {
|
||||
/* Multiply gbase by PREC_G. */
|
||||
for (i = 0; i < ECMULT_GEN_PREC_B; i++) {
|
||||
secp256k1_gej_double_var(&gbase, &gbase, NULL);
|
||||
}
|
||||
/* Multiply numbase by 2. */
|
||||
secp256k1_gej_double_var(&numsbase, &numsbase, NULL);
|
||||
if (j == 62) {
|
||||
if (j == ECMULT_GEN_PREC_N - 2) {
|
||||
/* In the last iteration, numsbase is (1 - 2^j) * nums instead. */
|
||||
secp256k1_gej_neg(&numsbase, &numsbase);
|
||||
secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL);
|
||||
}
|
||||
}
|
||||
secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb);
|
||||
secp256k1_ge_set_all_gej_var(prec, precj, ECMULT_GEN_PREC_N * ECMULT_GEN_PREC_G);
|
||||
}
|
||||
for (j = 0; j < 64; j++) {
|
||||
for (i = 0; i < 16; i++) {
|
||||
secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]);
|
||||
for (j = 0; j < ECMULT_GEN_PREC_N; j++) {
|
||||
for (i = 0; i < ECMULT_GEN_PREC_G; i++) {
|
||||
secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*ECMULT_GEN_PREC_G + i]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)cb;
|
||||
ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context;
|
||||
(void)prealloc;
|
||||
ctx->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])secp256k1_ecmult_static_context;
|
||||
#endif
|
||||
secp256k1_ecmult_gen_blind(ctx, NULL);
|
||||
}
|
||||
@@ -95,27 +105,18 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont
|
||||
return ctx->prec != NULL;
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst,
|
||||
const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) {
|
||||
if (src->prec == NULL) {
|
||||
dst->prec = NULL;
|
||||
} else {
|
||||
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context *src) {
|
||||
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||
dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec));
|
||||
memcpy(dst->prec, src->prec, sizeof(*dst->prec));
|
||||
#else
|
||||
(void)cb;
|
||||
dst->prec = src->prec;
|
||||
#endif
|
||||
dst->initial = src->initial;
|
||||
dst->blind = src->blind;
|
||||
if (src->prec != NULL) {
|
||||
/* We cast to void* first to suppress a -Wcast-align warning. */
|
||||
dst->prec = (secp256k1_ge_storage (*)[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src));
|
||||
}
|
||||
#else
|
||||
(void)dst, (void)src;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) {
|
||||
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
|
||||
free(ctx->prec);
|
||||
#endif
|
||||
secp256k1_scalar_clear(&ctx->blind);
|
||||
secp256k1_gej_clear(&ctx->initial);
|
||||
ctx->prec = NULL;
|
||||
@@ -132,9 +133,9 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp25
|
||||
/* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */
|
||||
secp256k1_scalar_add(&gnb, gn, &ctx->blind);
|
||||
add.infinity = 0;
|
||||
for (j = 0; j < 64; j++) {
|
||||
bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4);
|
||||
for (i = 0; i < 16; i++) {
|
||||
for (j = 0; j < ECMULT_GEN_PREC_N; j++) {
|
||||
bits = secp256k1_scalar_get_bits(&gnb, j * ECMULT_GEN_PREC_B, ECMULT_GEN_PREC_B);
|
||||
for (i = 0; i < ECMULT_GEN_PREC_G; i++) {
|
||||
/** This uses a conditional move to avoid any secret data in array indexes.
|
||||
* _Any_ use of secret indexes has been demonstrated to result in timing
|
||||
* sidechannels, even when the cache-line access patterns are uniform.
|
||||
@@ -161,8 +162,8 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
|
||||
secp256k1_gej gb;
|
||||
secp256k1_fe s;
|
||||
unsigned char nonce32[32];
|
||||
secp256k1_rfc6979_hmac_sha256_t rng;
|
||||
int retry;
|
||||
secp256k1_rfc6979_hmac_sha256 rng;
|
||||
int overflow;
|
||||
unsigned char keydata[64] = {0};
|
||||
if (seed32 == NULL) {
|
||||
/* When seed is NULL, reset the initial point and blinding value. */
|
||||
@@ -182,21 +183,18 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
|
||||
}
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32);
|
||||
memset(keydata, 0, sizeof(keydata));
|
||||
/* Retry for out of range results to achieve uniformity. */
|
||||
do {
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
retry = !secp256k1_fe_set_b32(&s, nonce32);
|
||||
retry |= secp256k1_fe_is_zero(&s);
|
||||
} while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */
|
||||
/* Accept unobservably small non-uniformity. */
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
overflow = !secp256k1_fe_set_b32(&s, nonce32);
|
||||
overflow |= secp256k1_fe_is_zero(&s);
|
||||
secp256k1_fe_cmov(&s, &secp256k1_fe_one, overflow);
|
||||
/* Randomize the projection to defend against multiplier sidechannels. */
|
||||
secp256k1_gej_rescale(&ctx->initial, &s);
|
||||
secp256k1_fe_clear(&s);
|
||||
do {
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
secp256k1_scalar_set_b32(&b, nonce32, &retry);
|
||||
/* A blinding value of 0 works, but would undermine the projection hardening. */
|
||||
retry |= secp256k1_scalar_is_zero(&b);
|
||||
} while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
|
||||
secp256k1_scalar_set_b32(&b, nonce32, NULL);
|
||||
/* A blinding value of 0 works, but would undermine the projection hardening. */
|
||||
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
|
||||
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||
memset(nonce32, 0, 32);
|
||||
secp256k1_ecmult_gen(ctx, &gb, &b);
|
||||
@@ -207,4 +205,4 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
|
||||
secp256k1_gej_clear(&gb);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_ECMULT_GEN_IMPL_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
32
src/field.h
32
src/field.h
@@ -4,8 +4,8 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_FIELD_
|
||||
#define _SECP256K1_FIELD_
|
||||
#ifndef SECP256K1_FIELD_H
|
||||
#define SECP256K1_FIELD_H
|
||||
|
||||
/** Field element module.
|
||||
*
|
||||
@@ -22,20 +22,22 @@
|
||||
#include "libsecp256k1-config.h"
|
||||
#endif
|
||||
|
||||
#if defined(USE_FIELD_10X26)
|
||||
#include "field_10x26.h"
|
||||
#elif defined(USE_FIELD_5X52)
|
||||
#include "field_5x52.h"
|
||||
#else
|
||||
#error "Please select field implementation"
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/** Normalize a field element. */
|
||||
#if defined(SECP256K1_WIDEMUL_INT128)
|
||||
#include "field_5x52.h"
|
||||
#elif defined(SECP256K1_WIDEMUL_INT64)
|
||||
#include "field_10x26.h"
|
||||
#else
|
||||
#error "Please select wide multiplication implementation"
|
||||
#endif
|
||||
|
||||
/** Normalize a field element. This brings the field element to a canonical representation, reduces
|
||||
* its magnitude to 1, and reduces it modulo field size `p`.
|
||||
*/
|
||||
static void secp256k1_fe_normalize(secp256k1_fe *r);
|
||||
|
||||
/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */
|
||||
/** Weakly normalize a field element: reduce its magnitude to 1, but don't fully normalize. */
|
||||
static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
|
||||
|
||||
/** Normalize a field element, without constant-time guarantee. */
|
||||
@@ -123,10 +125,10 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe
|
||||
/** Convert a field element back from the storage type. */
|
||||
static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
|
||||
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
|
||||
static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag);
|
||||
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
|
||||
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_FIELD_H */
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_
|
||||
#define _SECP256K1_FIELD_REPR_
|
||||
#ifndef SECP256K1_FIELD_REPR_H
|
||||
#define SECP256K1_FIELD_REPR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
/* X = sum(i=0..9, elem[i]*2^26) mod n */
|
||||
/* X = sum(i=0..9, n[i]*2^(i*26)) mod p
|
||||
* where p = 2^256 - 0x1000003D1
|
||||
*/
|
||||
uint32_t n[10];
|
||||
#ifdef VERIFY
|
||||
int magnitude;
|
||||
@@ -44,4 +46,5 @@ typedef struct {
|
||||
|
||||
#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}
|
||||
#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0]
|
||||
#endif
|
||||
|
||||
#endif /* SECP256K1_FIELD_REPR_H */
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
#define _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
#ifndef SECP256K1_FIELD_REPR_IMPL_H
|
||||
#define SECP256K1_FIELD_REPR_IMPL_H
|
||||
|
||||
#include "util.h"
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
|
||||
#ifdef VERIFY
|
||||
@@ -321,45 +320,69 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
}
|
||||
|
||||
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
|
||||
int i;
|
||||
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||
r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
|
||||
for (i=0; i<32; i++) {
|
||||
int j;
|
||||
for (j=0; j<4; j++) {
|
||||
int limb = (8*i+2*j)/26;
|
||||
int shift = (8*i+2*j)%26;
|
||||
r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift;
|
||||
}
|
||||
}
|
||||
if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) {
|
||||
return 0;
|
||||
}
|
||||
int ret;
|
||||
r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24);
|
||||
r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22);
|
||||
r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20);
|
||||
r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18);
|
||||
r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24);
|
||||
r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22);
|
||||
r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20);
|
||||
r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18);
|
||||
r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24);
|
||||
r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14);
|
||||
|
||||
ret = !((r->n[9] == 0x3FFFFFUL) & ((r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL) & ((r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL));
|
||||
#ifdef VERIFY
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
if (ret) {
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
} else {
|
||||
r->normalized = 0;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
int i;
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
secp256k1_fe_verify(a);
|
||||
#endif
|
||||
for (i=0; i<32; i++) {
|
||||
int j;
|
||||
int c = 0;
|
||||
for (j=0; j<4; j++) {
|
||||
int limb = (8*i+2*j)/26;
|
||||
int shift = (8*i+2*j)%26;
|
||||
c |= ((a->n[limb] >> shift) & 0x3) << (2 * j);
|
||||
}
|
||||
r[31-i] = c;
|
||||
}
|
||||
r[0] = (a->n[9] >> 14) & 0xff;
|
||||
r[1] = (a->n[9] >> 6) & 0xff;
|
||||
r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3);
|
||||
r[3] = (a->n[8] >> 16) & 0xff;
|
||||
r[4] = (a->n[8] >> 8) & 0xff;
|
||||
r[5] = a->n[8] & 0xff;
|
||||
r[6] = (a->n[7] >> 18) & 0xff;
|
||||
r[7] = (a->n[7] >> 10) & 0xff;
|
||||
r[8] = (a->n[7] >> 2) & 0xff;
|
||||
r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f);
|
||||
r[10] = (a->n[6] >> 12) & 0xff;
|
||||
r[11] = (a->n[6] >> 4) & 0xff;
|
||||
r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf);
|
||||
r[13] = (a->n[5] >> 14) & 0xff;
|
||||
r[14] = (a->n[5] >> 6) & 0xff;
|
||||
r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3);
|
||||
r[16] = (a->n[4] >> 16) & 0xff;
|
||||
r[17] = (a->n[4] >> 8) & 0xff;
|
||||
r[18] = a->n[4] & 0xff;
|
||||
r[19] = (a->n[3] >> 18) & 0xff;
|
||||
r[20] = (a->n[3] >> 10) & 0xff;
|
||||
r[21] = (a->n[3] >> 2) & 0xff;
|
||||
r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f);
|
||||
r[23] = (a->n[2] >> 12) & 0xff;
|
||||
r[24] = (a->n[2] >> 4) & 0xff;
|
||||
r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf);
|
||||
r[26] = (a->n[1] >> 14) & 0xff;
|
||||
r[27] = (a->n[1] >> 6) & 0xff;
|
||||
r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3);
|
||||
r[29] = (a->n[0] >> 16) & 0xff;
|
||||
r[30] = (a->n[0] >> 8) & 0xff;
|
||||
r[31] = a->n[0] & 0xff;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
@@ -465,7 +488,8 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
|
||||
VERIFY_BITS(b[9], 26);
|
||||
|
||||
/** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.
|
||||
* px is a shorthand for sum(a[i]*b[x-i], i=0..x).
|
||||
* for 0 <= x <= 9, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
|
||||
* for 9 <= x <= 18, px is a shorthand for sum(a[i]*b[x-i], i=(x-9)..9)
|
||||
* Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].
|
||||
*/
|
||||
|
||||
@@ -1048,6 +1072,7 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(b);
|
||||
VERIFY_CHECK(r != b);
|
||||
VERIFY_CHECK(a != b);
|
||||
#endif
|
||||
secp256k1_fe_mul_inner(r->n, a->n, b->n);
|
||||
#ifdef VERIFY
|
||||
@@ -1072,6 +1097,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
|
||||
uint32_t mask0, mask1;
|
||||
VG_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||
mask0 = flag + ~((uint32_t)0);
|
||||
mask1 = ~mask0;
|
||||
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
|
||||
@@ -1085,15 +1111,16 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
|
||||
r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1);
|
||||
r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1);
|
||||
#ifdef VERIFY
|
||||
if (a->magnitude > r->magnitude) {
|
||||
if (flag) {
|
||||
r->magnitude = a->magnitude;
|
||||
r->normalized = a->normalized;
|
||||
}
|
||||
r->normalized &= a->normalized;
|
||||
#endif
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
|
||||
uint32_t mask0, mask1;
|
||||
VG_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||
mask0 = flag + ~((uint32_t)0);
|
||||
mask1 = ~mask0;
|
||||
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
|
||||
@@ -1137,4 +1164,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_
|
||||
#define _SECP256K1_FIELD_REPR_
|
||||
#ifndef SECP256K1_FIELD_REPR_H
|
||||
#define SECP256K1_FIELD_REPR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
/* X = sum(i=0..4, elem[i]*2^52) mod n */
|
||||
/* X = sum(i=0..4, n[i]*2^(i*52)) mod p
|
||||
* where p = 2^256 - 0x1000003D1
|
||||
*/
|
||||
uint64_t n[5];
|
||||
#ifdef VERIFY
|
||||
int magnitude;
|
||||
@@ -44,4 +46,10 @@ typedef struct {
|
||||
(d6) | (((uint64_t)(d7)) << 32) \
|
||||
}}
|
||||
|
||||
#endif
|
||||
#define SECP256K1_FE_STORAGE_CONST_GET(d) \
|
||||
(uint32_t)(d.n[3] >> 32), (uint32_t)d.n[3], \
|
||||
(uint32_t)(d.n[2] >> 32), (uint32_t)d.n[2], \
|
||||
(uint32_t)(d.n[1] >> 32), (uint32_t)d.n[1], \
|
||||
(uint32_t)(d.n[0] >> 32), (uint32_t)d.n[0]
|
||||
|
||||
#endif /* SECP256K1_FIELD_REPR_H */
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
* - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly
|
||||
*/
|
||||
|
||||
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
|
||||
#define SECP256K1_FIELD_INNER5X52_IMPL_H
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
|
||||
/**
|
||||
@@ -499,4 +499,4 @@ __asm__ __volatile__(
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
|
||||
|
||||
@@ -4,15 +4,14 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
#define _SECP256K1_FIELD_REPR_IMPL_H_
|
||||
#ifndef SECP256K1_FIELD_REPR_IMPL_H
|
||||
#define SECP256K1_FIELD_REPR_IMPL_H
|
||||
|
||||
#if defined HAVE_CONFIG_H
|
||||
#include "libsecp256k1-config.h"
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
|
||||
#if defined(USE_ASM_X86_64)
|
||||
@@ -284,44 +283,92 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
}
|
||||
|
||||
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
|
||||
int i;
|
||||
r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
|
||||
for (i=0; i<32; i++) {
|
||||
int j;
|
||||
for (j=0; j<2; j++) {
|
||||
int limb = (8*i+4*j)/52;
|
||||
int shift = (8*i+4*j)%52;
|
||||
r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift;
|
||||
}
|
||||
}
|
||||
if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) {
|
||||
return 0;
|
||||
}
|
||||
int ret;
|
||||
r->n[0] = (uint64_t)a[31]
|
||||
| ((uint64_t)a[30] << 8)
|
||||
| ((uint64_t)a[29] << 16)
|
||||
| ((uint64_t)a[28] << 24)
|
||||
| ((uint64_t)a[27] << 32)
|
||||
| ((uint64_t)a[26] << 40)
|
||||
| ((uint64_t)(a[25] & 0xF) << 48);
|
||||
r->n[1] = (uint64_t)((a[25] >> 4) & 0xF)
|
||||
| ((uint64_t)a[24] << 4)
|
||||
| ((uint64_t)a[23] << 12)
|
||||
| ((uint64_t)a[22] << 20)
|
||||
| ((uint64_t)a[21] << 28)
|
||||
| ((uint64_t)a[20] << 36)
|
||||
| ((uint64_t)a[19] << 44);
|
||||
r->n[2] = (uint64_t)a[18]
|
||||
| ((uint64_t)a[17] << 8)
|
||||
| ((uint64_t)a[16] << 16)
|
||||
| ((uint64_t)a[15] << 24)
|
||||
| ((uint64_t)a[14] << 32)
|
||||
| ((uint64_t)a[13] << 40)
|
||||
| ((uint64_t)(a[12] & 0xF) << 48);
|
||||
r->n[3] = (uint64_t)((a[12] >> 4) & 0xF)
|
||||
| ((uint64_t)a[11] << 4)
|
||||
| ((uint64_t)a[10] << 12)
|
||||
| ((uint64_t)a[9] << 20)
|
||||
| ((uint64_t)a[8] << 28)
|
||||
| ((uint64_t)a[7] << 36)
|
||||
| ((uint64_t)a[6] << 44);
|
||||
r->n[4] = (uint64_t)a[5]
|
||||
| ((uint64_t)a[4] << 8)
|
||||
| ((uint64_t)a[3] << 16)
|
||||
| ((uint64_t)a[2] << 24)
|
||||
| ((uint64_t)a[1] << 32)
|
||||
| ((uint64_t)a[0] << 40);
|
||||
ret = !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
|
||||
#ifdef VERIFY
|
||||
r->magnitude = 1;
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
if (ret) {
|
||||
r->normalized = 1;
|
||||
secp256k1_fe_verify(r);
|
||||
} else {
|
||||
r->normalized = 0;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
|
||||
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
|
||||
int i;
|
||||
#ifdef VERIFY
|
||||
VERIFY_CHECK(a->normalized);
|
||||
secp256k1_fe_verify(a);
|
||||
#endif
|
||||
for (i=0; i<32; i++) {
|
||||
int j;
|
||||
int c = 0;
|
||||
for (j=0; j<2; j++) {
|
||||
int limb = (8*i+4*j)/52;
|
||||
int shift = (8*i+4*j)%52;
|
||||
c |= ((a->n[limb] >> shift) & 0xF) << (4 * j);
|
||||
}
|
||||
r[31-i] = c;
|
||||
}
|
||||
r[0] = (a->n[4] >> 40) & 0xFF;
|
||||
r[1] = (a->n[4] >> 32) & 0xFF;
|
||||
r[2] = (a->n[4] >> 24) & 0xFF;
|
||||
r[3] = (a->n[4] >> 16) & 0xFF;
|
||||
r[4] = (a->n[4] >> 8) & 0xFF;
|
||||
r[5] = a->n[4] & 0xFF;
|
||||
r[6] = (a->n[3] >> 44) & 0xFF;
|
||||
r[7] = (a->n[3] >> 36) & 0xFF;
|
||||
r[8] = (a->n[3] >> 28) & 0xFF;
|
||||
r[9] = (a->n[3] >> 20) & 0xFF;
|
||||
r[10] = (a->n[3] >> 12) & 0xFF;
|
||||
r[11] = (a->n[3] >> 4) & 0xFF;
|
||||
r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4);
|
||||
r[13] = (a->n[2] >> 40) & 0xFF;
|
||||
r[14] = (a->n[2] >> 32) & 0xFF;
|
||||
r[15] = (a->n[2] >> 24) & 0xFF;
|
||||
r[16] = (a->n[2] >> 16) & 0xFF;
|
||||
r[17] = (a->n[2] >> 8) & 0xFF;
|
||||
r[18] = a->n[2] & 0xFF;
|
||||
r[19] = (a->n[1] >> 44) & 0xFF;
|
||||
r[20] = (a->n[1] >> 36) & 0xFF;
|
||||
r[21] = (a->n[1] >> 28) & 0xFF;
|
||||
r[22] = (a->n[1] >> 20) & 0xFF;
|
||||
r[23] = (a->n[1] >> 12) & 0xFF;
|
||||
r[24] = (a->n[1] >> 4) & 0xFF;
|
||||
r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4);
|
||||
r[26] = (a->n[0] >> 40) & 0xFF;
|
||||
r[27] = (a->n[0] >> 32) & 0xFF;
|
||||
r[28] = (a->n[0] >> 24) & 0xFF;
|
||||
r[29] = (a->n[0] >> 16) & 0xFF;
|
||||
r[30] = (a->n[0] >> 8) & 0xFF;
|
||||
r[31] = a->n[0] & 0xFF;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
|
||||
@@ -377,6 +424,7 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
|
||||
secp256k1_fe_verify(a);
|
||||
secp256k1_fe_verify(b);
|
||||
VERIFY_CHECK(r != b);
|
||||
VERIFY_CHECK(a != b);
|
||||
#endif
|
||||
secp256k1_fe_mul_inner(r->n, a->n, b->n);
|
||||
#ifdef VERIFY
|
||||
@@ -401,6 +449,7 @@ static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
|
||||
uint64_t mask0, mask1;
|
||||
VG_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||
mask0 = flag + ~((uint64_t)0);
|
||||
mask1 = ~mask0;
|
||||
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
|
||||
@@ -409,15 +458,16 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
|
||||
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
|
||||
r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1);
|
||||
#ifdef VERIFY
|
||||
if (a->magnitude > r->magnitude) {
|
||||
if (flag) {
|
||||
r->magnitude = a->magnitude;
|
||||
r->normalized = a->normalized;
|
||||
}
|
||||
r->normalized &= a->normalized;
|
||||
#endif
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
|
||||
uint64_t mask0, mask1;
|
||||
VG_CHECK_VERIFY(r->n, sizeof(r->n));
|
||||
mask0 = flag + ~((uint64_t)0);
|
||||
mask1 = ~mask0;
|
||||
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
|
||||
@@ -448,4 +498,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||
#define _SECP256K1_FIELD_INNER5X52_IMPL_H_
|
||||
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
|
||||
#define SECP256K1_FIELD_INNER5X52_IMPL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -32,9 +32,11 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
|
||||
VERIFY_BITS(b[3], 56);
|
||||
VERIFY_BITS(b[4], 52);
|
||||
VERIFY_CHECK(r != b);
|
||||
VERIFY_CHECK(a != b);
|
||||
|
||||
/* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
|
||||
* px is a shorthand for sum(a[i]*b[x-i], i=0..x).
|
||||
* for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
|
||||
* for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4)
|
||||
* Note that [x 0 0 0 0 0] = [x*R].
|
||||
*/
|
||||
|
||||
@@ -274,4 +276,4 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
|
||||
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */
|
||||
|
||||
@@ -4,21 +4,22 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_FIELD_IMPL_H_
|
||||
#define _SECP256K1_FIELD_IMPL_H_
|
||||
#ifndef SECP256K1_FIELD_IMPL_H
|
||||
#define SECP256K1_FIELD_IMPL_H
|
||||
|
||||
#if defined HAVE_CONFIG_H
|
||||
#include "libsecp256k1-config.h"
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "num.h"
|
||||
|
||||
#if defined(USE_FIELD_10X26)
|
||||
#include "field_10x26_impl.h"
|
||||
#elif defined(USE_FIELD_5X52)
|
||||
#if defined(SECP256K1_WIDEMUL_INT128)
|
||||
#include "field_5x52_impl.h"
|
||||
#elif defined(SECP256K1_WIDEMUL_INT64)
|
||||
#include "field_10x26_impl.h"
|
||||
#else
|
||||
#error "Please select field implementation"
|
||||
#error "Please select wide multiplication implementation"
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
|
||||
@@ -48,6 +49,8 @@ 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;
|
||||
|
||||
VERIFY_CHECK(r != a);
|
||||
|
||||
/** 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:
|
||||
* 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]
|
||||
@@ -312,4 +315,6 @@ static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
|
||||
|
||||
#endif /* SECP256K1_FIELD_IMPL_H */
|
||||
|
||||
@@ -4,10 +4,17 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
// Autotools creates libsecp256k1-config.h, of which ECMULT_GEN_PREC_BITS is needed.
|
||||
// ifndef guard so downstream users can define their own if they do not use autotools.
|
||||
#if !defined(ECMULT_GEN_PREC_BITS)
|
||||
#include "libsecp256k1-config.h"
|
||||
#endif
|
||||
#define USE_BASIC_CONFIG 1
|
||||
|
||||
#include "basic-config.h"
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
#include "assumptions.h"
|
||||
#include "util.h"
|
||||
#include "field_impl.h"
|
||||
#include "scalar_impl.h"
|
||||
#include "group_impl.h"
|
||||
@@ -26,6 +33,7 @@ static const secp256k1_callback default_error_callback = {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
secp256k1_ecmult_gen_context ctx;
|
||||
void *prealloc, *base;
|
||||
int inner;
|
||||
int outer;
|
||||
FILE* fp;
|
||||
@@ -38,26 +46,31 @@ int main(int argc, char **argv) {
|
||||
fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
|
||||
fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n");
|
||||
fprintf(fp, "#include \"group.h\"\n");
|
||||
fprintf(fp, "#include \"src/group.h\"\n");
|
||||
fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n");
|
||||
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n");
|
||||
fprintf(fp, "#if ECMULT_GEN_PREC_N != %d || ECMULT_GEN_PREC_G != %d\n", ECMULT_GEN_PREC_N, ECMULT_GEN_PREC_G);
|
||||
fprintf(fp, " #error configuration mismatch, invalid ECMULT_GEN_PREC_N, ECMULT_GEN_PREC_G. Try deleting ecmult_static_context.h before the build.\n");
|
||||
fprintf(fp, "#endif\n");
|
||||
fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[ECMULT_GEN_PREC_N][ECMULT_GEN_PREC_G] = {\n");
|
||||
|
||||
base = checked_malloc(&default_error_callback, SECP256K1_ECMULT_GEN_CONTEXT_PREALLOCATED_SIZE);
|
||||
prealloc = base;
|
||||
secp256k1_ecmult_gen_context_init(&ctx);
|
||||
secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback);
|
||||
for(outer = 0; outer != 64; outer++) {
|
||||
secp256k1_ecmult_gen_context_build(&ctx, &prealloc);
|
||||
for(outer = 0; outer != ECMULT_GEN_PREC_N; outer++) {
|
||||
fprintf(fp,"{\n");
|
||||
for(inner = 0; inner != 16; inner++) {
|
||||
for(inner = 0; inner != ECMULT_GEN_PREC_G; inner++) {
|
||||
fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner]));
|
||||
if (inner != 15) {
|
||||
if (inner != ECMULT_GEN_PREC_G - 1) {
|
||||
fprintf(fp,",\n");
|
||||
} else {
|
||||
fprintf(fp,"\n");
|
||||
}
|
||||
}
|
||||
if (outer != 63) {
|
||||
if (outer != ECMULT_GEN_PREC_N - 1) {
|
||||
fprintf(fp,"},\n");
|
||||
} else {
|
||||
fprintf(fp,"}\n");
|
||||
@@ -65,10 +78,11 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
fprintf(fp,"};\n");
|
||||
secp256k1_ecmult_gen_context_clear(&ctx);
|
||||
|
||||
free(base);
|
||||
|
||||
fprintf(fp, "#undef SC\n");
|
||||
fprintf(fp, "#endif\n");
|
||||
fclose(fp);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
43
src/group.h
43
src/group.h
@@ -4,8 +4,8 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_GROUP_
|
||||
#define _SECP256K1_GROUP_
|
||||
#ifndef SECP256K1_GROUP_H
|
||||
#define SECP256K1_GROUP_H
|
||||
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
@@ -59,18 +59,14 @@ static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
|
||||
/** Check whether a group element is valid (i.e., on the curve). */
|
||||
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a);
|
||||
|
||||
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
|
||||
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a);
|
||||
|
||||
/** Set a group element equal to another which is given in jacobian coordinates */
|
||||
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a);
|
||||
|
||||
/** Set a batch of group elements equal to the inputs given in jacobian coordinates */
|
||||
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb);
|
||||
|
||||
/** Set a batch of group elements equal to the inputs given in jacobian
|
||||
* coordinates (with known z-ratios). zr must contain the known z-ratios such
|
||||
* that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */
|
||||
static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len);
|
||||
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len);
|
||||
|
||||
/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to
|
||||
* the same global z "denominator". zr must contain the known z-ratios such
|
||||
@@ -79,6 +75,9 @@ static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej
|
||||
* stored in globalz. */
|
||||
static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr);
|
||||
|
||||
/** Set a group element (affine) equal to the point at infinity. */
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r);
|
||||
|
||||
/** Set a group element (jacobian) equal to the point at infinity. */
|
||||
static void secp256k1_gej_set_infinity(secp256k1_gej *r);
|
||||
|
||||
@@ -97,14 +96,13 @@ static int secp256k1_gej_is_infinity(const secp256k1_gej *a);
|
||||
/** Check whether a group element's y coordinate is a quadratic residue. */
|
||||
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a);
|
||||
|
||||
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0).
|
||||
* a may not be zero. Constant time. */
|
||||
static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
|
||||
/** Set r equal to the double of a. Constant time. */
|
||||
static void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a);
|
||||
|
||||
/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */
|
||||
/** Set r equal to the double of a. If rzr is not-NULL this sets *rzr such that r->z == a->z * *rzr (where infinity means an implicit z = 0). */
|
||||
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr);
|
||||
|
||||
/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
|
||||
/** Set r equal to the sum of a and b. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */
|
||||
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr);
|
||||
|
||||
/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */
|
||||
@@ -112,16 +110,14 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
|
||||
|
||||
/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient
|
||||
than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time
|
||||
guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */
|
||||
guarantee, and b is allowed to be infinity. If rzr is non-NULL this sets *rzr such that r->z == a->z * *rzr (a cannot be infinity in that case). */
|
||||
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr);
|
||||
|
||||
/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */
|
||||
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv);
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */
|
||||
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a);
|
||||
#endif
|
||||
|
||||
/** Clear a secp256k1_gej to prevent leaking sensitive information. */
|
||||
static void secp256k1_gej_clear(secp256k1_gej *r);
|
||||
@@ -135,10 +131,21 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge
|
||||
/** Convert a group element back from the storage type. */
|
||||
static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a);
|
||||
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */
|
||||
/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. Both *r and *a must be initialized.*/
|
||||
static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag);
|
||||
|
||||
/** Rescale a jacobian point by b which must be non-zero. Constant-time. */
|
||||
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
|
||||
|
||||
#endif
|
||||
/** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve.
|
||||
*
|
||||
* In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the
|
||||
* group, and this function returns always true.
|
||||
*
|
||||
* When compiling in exhaustive test mode, a slightly different curve equation is used, leading to a group with a
|
||||
* (very) small subgroup, and that subgroup is what is used for all cryptographic operations. In that mode, this
|
||||
* function checks whether a point that is on the curve is in fact also in that subgroup.
|
||||
*/
|
||||
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
|
||||
|
||||
#endif /* SECP256K1_GROUP_H */
|
||||
|
||||
251
src/group_impl.h
251
src/group_impl.h
@@ -4,56 +4,45 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_GROUP_IMPL_H_
|
||||
#define _SECP256K1_GROUP_IMPL_H_
|
||||
#ifndef SECP256K1_GROUP_IMPL_H
|
||||
#define SECP256K1_GROUP_IMPL_H
|
||||
|
||||
#include "num.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
|
||||
/* These points can be generated in sage as follows:
|
||||
/* These exhaustive group test orders and generators are chosen such that:
|
||||
* - The field size is equal to that of secp256k1, so field code is the same.
|
||||
* - The curve equation is of the form y^2=x^3+B for some constant B.
|
||||
* - The subgroup has a generator 2*P, where P.x=1.
|
||||
* - The subgroup has size less than 1000 to permit exhaustive testing.
|
||||
* - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).
|
||||
*
|
||||
* 0. Setup a worksheet with the following parameters.
|
||||
* b = 4 # whatever CURVE_B will be set to
|
||||
* F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
|
||||
* C = EllipticCurve ([F (0), F (b)])
|
||||
*
|
||||
* 1. Determine all the small orders available to you. (If there are
|
||||
* no satisfactory ones, go back and change b.)
|
||||
* print C.order().factor(limit=1000)
|
||||
*
|
||||
* 2. Choose an order as one of the prime factors listed in the above step.
|
||||
* (You can also multiply some to get a composite order, though the
|
||||
* tests will crash trying to invert scalars during signing.) We take a
|
||||
* random point and scale it to drop its order to the desired value.
|
||||
* There is some probability this won't work; just try again.
|
||||
* order = 199
|
||||
* P = C.random_point()
|
||||
* P = (int(P.order()) / int(order)) * P
|
||||
* assert(P.order() == order)
|
||||
*
|
||||
* 3. Print the values. You'll need to use a vim macro or something to
|
||||
* split the hex output into 4-byte chunks.
|
||||
* print "%x %x" % P.xy()
|
||||
* These parameters are generated using sage/gen_exhaustive_groups.sage.
|
||||
*/
|
||||
#if defined(EXHAUSTIVE_TEST_ORDER)
|
||||
# if EXHAUSTIVE_TEST_ORDER == 199
|
||||
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
|
||||
0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069,
|
||||
0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18,
|
||||
0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868,
|
||||
0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED
|
||||
# if EXHAUSTIVE_TEST_ORDER == 13
|
||||
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
|
||||
0xc3459c3d, 0x35326167, 0xcd86cce8, 0x07a2417f,
|
||||
0x5b8bd567, 0xde8538ee, 0x0d507b0c, 0xd128f5bb,
|
||||
0x8e467fec, 0xcd30000a, 0x6cc1184e, 0x25d382c2,
|
||||
0xa2f4494e, 0x2fbe9abc, 0x8b64abac, 0xd005fb24
|
||||
);
|
||||
|
||||
const int CURVE_B = 4;
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 13
|
||||
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
|
||||
0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0,
|
||||
0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15,
|
||||
0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e,
|
||||
0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac
|
||||
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(
|
||||
0x3d3486b2, 0x159a9ca5, 0xc75638be, 0xb23a69bc,
|
||||
0x946a45ab, 0x24801247, 0xb4ed2b8e, 0x26b6a417
|
||||
);
|
||||
# elif EXHAUSTIVE_TEST_ORDER == 199
|
||||
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
|
||||
0x226e653f, 0xc8df7744, 0x9bacbf12, 0x7d1dcbf9,
|
||||
0x87f05b2a, 0xe7edbd28, 0x1f564575, 0xc48dcf18,
|
||||
0xa13872c2, 0xe933bb17, 0x5d9ffd5b, 0xb5b6e10c,
|
||||
0x57fe3c00, 0xbaaaa15a, 0xe003ec3e, 0x9c269bae
|
||||
);
|
||||
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(
|
||||
0x2cca28fa, 0xfc614b80, 0x2a3db42b, 0x00ba00b1,
|
||||
0xbea8d943, 0xdace9ab2, 0x9536daea, 0x0074defb
|
||||
);
|
||||
const int CURVE_B = 2;
|
||||
# else
|
||||
# error No known generator for the specified exhaustive test group order.
|
||||
# endif
|
||||
@@ -68,7 +57,7 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
|
||||
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
|
||||
);
|
||||
|
||||
const int CURVE_B = 7;
|
||||
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7);
|
||||
#endif
|
||||
|
||||
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
|
||||
@@ -126,46 +115,43 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
|
||||
r->y = a->y;
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) {
|
||||
secp256k1_fe *az;
|
||||
secp256k1_fe *azi;
|
||||
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 count = 0;
|
||||
az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len);
|
||||
size_t last_i = SIZE_MAX;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!a[i].infinity) {
|
||||
az[count++] = a[i].z;
|
||||
/* Use destination's x coordinates as scratch space */
|
||||
if (last_i == SIZE_MAX) {
|
||||
r[i].x = a[i].z;
|
||||
} else {
|
||||
secp256k1_fe_mul(&r[i].x, &r[last_i].x, &a[i].z);
|
||||
}
|
||||
last_i = i;
|
||||
}
|
||||
}
|
||||
if (last_i == SIZE_MAX) {
|
||||
return;
|
||||
}
|
||||
secp256k1_fe_inv_var(&u, &r[last_i].x);
|
||||
|
||||
azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count);
|
||||
secp256k1_fe_inv_all_var(azi, az, count);
|
||||
free(az);
|
||||
i = last_i;
|
||||
while (i > 0) {
|
||||
i--;
|
||||
if (!a[i].infinity) {
|
||||
secp256k1_fe_mul(&r[last_i].x, &r[i].x, &u);
|
||||
secp256k1_fe_mul(&u, &u, &a[last_i].z);
|
||||
last_i = i;
|
||||
}
|
||||
}
|
||||
VERIFY_CHECK(!a[last_i].infinity);
|
||||
r[last_i].x = u;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
r[i].infinity = a[i].infinity;
|
||||
if (!a[i].infinity) {
|
||||
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]);
|
||||
}
|
||||
}
|
||||
free(azi);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) {
|
||||
size_t i = len - 1;
|
||||
secp256k1_fe zi;
|
||||
|
||||
if (len > 0) {
|
||||
/* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */
|
||||
secp256k1_fe_inv(&zi, &a[i].z);
|
||||
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
|
||||
|
||||
/* Work out way backwards, using the z-ratios to scale the x/y values. */
|
||||
while (i > 0) {
|
||||
secp256k1_fe_mul(&zi, &zi, &zr[i]);
|
||||
i--;
|
||||
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi);
|
||||
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,6 +164,8 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp
|
||||
/* The z of the final point gives us the "global Z" for the table. */
|
||||
r[i].x = a[i].x;
|
||||
r[i].y = a[i].y;
|
||||
/* Ensure all y values are in weak normal form for fast negation of points */
|
||||
secp256k1_fe_normalize_weak(&r[i].y);
|
||||
*globalz = a[i].z;
|
||||
r[i].infinity = 0;
|
||||
zs = zr[i];
|
||||
@@ -200,6 +188,12 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
|
||||
secp256k1_fe_clear(&r->z);
|
||||
}
|
||||
|
||||
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
|
||||
r->infinity = 1;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
secp256k1_fe_clear(&r->y);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_clear(secp256k1_gej *r) {
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_clear(&r->x);
|
||||
@@ -214,14 +208,13 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) {
|
||||
secp256k1_fe x2, x3, c;
|
||||
secp256k1_fe x2, x3;
|
||||
r->x = *x;
|
||||
secp256k1_fe_sqr(&x2, x);
|
||||
secp256k1_fe_mul(&x3, x, &x2);
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_set_int(&c, CURVE_B);
|
||||
secp256k1_fe_add(&c, &x3);
|
||||
return secp256k1_fe_sqrt(&r->y, &c);
|
||||
secp256k1_fe_add(&x3, &secp256k1_fe_const_b);
|
||||
return secp256k1_fe_sqrt(&r->y, &x3);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
||||
@@ -264,41 +257,20 @@ static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
|
||||
return a->infinity;
|
||||
}
|
||||
|
||||
static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) {
|
||||
secp256k1_fe y2, x3, z2, z6;
|
||||
if (a->infinity) {
|
||||
return 0;
|
||||
}
|
||||
/** y^2 = x^3 + 7
|
||||
* (Y/Z^3)^2 = (X/Z^2)^3 + 7
|
||||
* Y^2 / Z^6 = X^3 / Z^6 + 7
|
||||
* Y^2 = X^3 + 7*Z^6
|
||||
*/
|
||||
secp256k1_fe_sqr(&y2, &a->y);
|
||||
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
|
||||
secp256k1_fe_sqr(&z2, &a->z);
|
||||
secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2);
|
||||
secp256k1_fe_mul_int(&z6, CURVE_B);
|
||||
secp256k1_fe_add(&x3, &z6);
|
||||
secp256k1_fe_normalize_weak(&x3);
|
||||
return secp256k1_fe_equal_var(&y2, &x3);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
|
||||
secp256k1_fe y2, x3, c;
|
||||
secp256k1_fe y2, x3;
|
||||
if (a->infinity) {
|
||||
return 0;
|
||||
}
|
||||
/* y^2 = x^3 + 7 */
|
||||
secp256k1_fe_sqr(&y2, &a->y);
|
||||
secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x);
|
||||
secp256k1_fe_set_int(&c, CURVE_B);
|
||||
secp256k1_fe_add(&x3, &c);
|
||||
secp256k1_fe_add(&x3, &secp256k1_fe_const_b);
|
||||
secp256k1_fe_normalize_weak(&x3);
|
||||
return secp256k1_fe_equal_var(&y2, &x3);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
|
||||
static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp256k1_gej *a) {
|
||||
/* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate.
|
||||
*
|
||||
* Note that there is an implementation described at
|
||||
@@ -307,29 +279,8 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
|
||||
* mainly because it requires more normalizations.
|
||||
*/
|
||||
secp256k1_fe t1,t2,t3,t4;
|
||||
/** 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.
|
||||
*
|
||||
* Having said this, if this function receives a point on a sextic twist, e.g. by
|
||||
* a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
|
||||
* since -6 does have a cube root mod p. For this point, this function will not set
|
||||
* the infinity flag even though the point doubles to infinity, and the result
|
||||
* point will be gibberish (z = 0 but infinity = 0).
|
||||
*/
|
||||
r->infinity = a->infinity;
|
||||
if (r->infinity) {
|
||||
if (rzr != NULL) {
|
||||
secp256k1_fe_set_int(rzr, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (rzr != NULL) {
|
||||
*rzr = a->y;
|
||||
secp256k1_fe_normalize_weak(rzr);
|
||||
secp256k1_fe_mul_int(rzr, 2);
|
||||
}
|
||||
r->infinity = a->infinity;
|
||||
|
||||
secp256k1_fe_mul(&r->z, &a->z, &a->y);
|
||||
secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */
|
||||
@@ -353,9 +304,32 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
|
||||
secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
|
||||
VERIFY_CHECK(!secp256k1_gej_is_infinity(a));
|
||||
secp256k1_gej_double_var(r, a, rzr);
|
||||
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
|
||||
/** 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.
|
||||
*
|
||||
* Having said this, if this function receives a point on a sextic twist, e.g. by
|
||||
* a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6,
|
||||
* since -6 does have a cube root mod p. For this point, this function will not set
|
||||
* the infinity flag even though the point doubles to infinity, and the result
|
||||
* point will be gibberish (z = 0 but infinity = 0).
|
||||
*/
|
||||
if (a->infinity) {
|
||||
r->infinity = 1;
|
||||
if (rzr != NULL) {
|
||||
secp256k1_fe_set_int(rzr, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (rzr != NULL) {
|
||||
*rzr = a->y;
|
||||
secp256k1_fe_normalize_weak(rzr);
|
||||
secp256k1_fe_mul_int(rzr, 2);
|
||||
}
|
||||
|
||||
secp256k1_gej_double(r, a);
|
||||
}
|
||||
|
||||
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
|
||||
@@ -392,7 +366,7 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
|
||||
if (rzr != NULL) {
|
||||
secp256k1_fe_set_int(rzr, 0);
|
||||
}
|
||||
r->infinity = 1;
|
||||
secp256k1_gej_set_infinity(r);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -442,7 +416,7 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
|
||||
if (rzr != NULL) {
|
||||
secp256k1_fe_set_int(rzr, 0);
|
||||
}
|
||||
r->infinity = 1;
|
||||
secp256k1_gej_set_infinity(r);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -501,7 +475,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
|
||||
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
|
||||
secp256k1_gej_double_var(r, a, NULL);
|
||||
} else {
|
||||
r->infinity = 1;
|
||||
secp256k1_gej_set_infinity(r);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -672,7 +646,6 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r,
|
||||
secp256k1_fe_storage_cmov(&r->y, &a->y, flag);
|
||||
}
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
|
||||
static const secp256k1_fe beta = SECP256K1_FE_CONST(
|
||||
0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
|
||||
@@ -681,7 +654,6 @@ static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
|
||||
*r = *a;
|
||||
secp256k1_fe_mul(&r->x, &r->x, &beta);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
|
||||
secp256k1_fe yz;
|
||||
@@ -697,4 +669,25 @@ static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
|
||||
return secp256k1_fe_is_quad_var(&yz);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
|
||||
#ifdef EXHAUSTIVE_TEST_ORDER
|
||||
secp256k1_gej out;
|
||||
int i;
|
||||
|
||||
/* A very simple EC multiplication ladder that avoids a dependecy on ecmult. */
|
||||
secp256k1_gej_set_infinity(&out);
|
||||
for (i = 0; i < 32; ++i) {
|
||||
secp256k1_gej_double_var(&out, &out, NULL);
|
||||
if ((((uint32_t)EXHAUSTIVE_TEST_ORDER) >> (31 - i)) & 1) {
|
||||
secp256k1_gej_add_ge_var(&out, &out, ge, NULL);
|
||||
}
|
||||
}
|
||||
return secp256k1_gej_is_infinity(&out);
|
||||
#else
|
||||
(void)ge;
|
||||
/* The real secp256k1 group has cofactor 1, so the subgroup is the entire curve. */
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_GROUP_IMPL_H */
|
||||
|
||||
32
src/hash.h
32
src/hash.h
@@ -4,8 +4,8 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_HASH_
|
||||
#define _SECP256K1_HASH_
|
||||
#ifndef SECP256K1_HASH_H
|
||||
#define SECP256K1_HASH_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@@ -14,28 +14,28 @@ typedef struct {
|
||||
uint32_t s[8];
|
||||
uint32_t buf[16]; /* In big endian */
|
||||
size_t bytes;
|
||||
} secp256k1_sha256_t;
|
||||
} secp256k1_sha256;
|
||||
|
||||
static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash);
|
||||
static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32);
|
||||
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash);
|
||||
static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32);
|
||||
|
||||
typedef struct {
|
||||
secp256k1_sha256_t inner, outer;
|
||||
} secp256k1_hmac_sha256_t;
|
||||
secp256k1_sha256 inner, outer;
|
||||
} secp256k1_hmac_sha256;
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size);
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32);
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size);
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size);
|
||||
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32);
|
||||
|
||||
typedef struct {
|
||||
unsigned char v[32];
|
||||
unsigned char k[32];
|
||||
int retry;
|
||||
} secp256k1_rfc6979_hmac_sha256_t;
|
||||
} secp256k1_rfc6979_hmac_sha256;
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng);
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen);
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng);
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_HASH_H */
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_HASH_IMPL_H_
|
||||
#define _SECP256K1_HASH_IMPL_H_
|
||||
#ifndef SECP256K1_HASH_IMPL_H
|
||||
#define SECP256K1_HASH_IMPL_H
|
||||
|
||||
#include "hash.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
@@ -27,13 +28,13 @@
|
||||
(h) = t1 + t2; \
|
||||
} while(0)
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#if defined(SECP256K1_BIG_ENDIAN)
|
||||
#define BE32(x) (x)
|
||||
#else
|
||||
#elif defined(SECP256K1_LITTLE_ENDIAN)
|
||||
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
|
||||
#endif
|
||||
|
||||
static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) {
|
||||
static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) {
|
||||
hash->s[0] = 0x6a09e667ul;
|
||||
hash->s[1] = 0xbb67ae85ul;
|
||||
hash->s[2] = 0x3c6ef372ul;
|
||||
@@ -128,14 +129,16 @@ static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {
|
||||
s[7] += h;
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) {
|
||||
static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) {
|
||||
size_t bufsize = hash->bytes & 0x3F;
|
||||
hash->bytes += len;
|
||||
while (bufsize + len >= 64) {
|
||||
VERIFY_CHECK(hash->bytes >= len);
|
||||
while (len >= 64 - bufsize) {
|
||||
/* Fill the buffer, and process it. */
|
||||
memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize);
|
||||
data += 64 - bufsize;
|
||||
len -= 64 - bufsize;
|
||||
size_t chunk_len = 64 - bufsize;
|
||||
memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len);
|
||||
data += chunk_len;
|
||||
len -= chunk_len;
|
||||
secp256k1_sha256_transform(hash->s, hash->buf);
|
||||
bufsize = 0;
|
||||
}
|
||||
@@ -145,7 +148,7 @@ static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) {
|
||||
static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) {
|
||||
static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint32_t sizedesc[2];
|
||||
uint32_t out[8];
|
||||
@@ -161,14 +164,27 @@ static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *o
|
||||
memcpy(out32, (const unsigned char*)out, 32);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) {
|
||||
int n;
|
||||
/* Initializes a sha256 struct and writes the 64 byte string
|
||||
* SHA256(tag)||SHA256(tag) into it. */
|
||||
static void secp256k1_sha256_initialize_tagged(secp256k1_sha256 *hash, const unsigned char *tag, size_t taglen) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256_initialize(hash);
|
||||
secp256k1_sha256_write(hash, tag, taglen);
|
||||
secp256k1_sha256_finalize(hash, buf);
|
||||
|
||||
secp256k1_sha256_initialize(hash);
|
||||
secp256k1_sha256_write(hash, buf, 32);
|
||||
secp256k1_sha256_write(hash, buf, 32);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) {
|
||||
size_t n;
|
||||
unsigned char rkey[64];
|
||||
if (keylen <= 64) {
|
||||
if (keylen <= sizeof(rkey)) {
|
||||
memcpy(rkey, key, keylen);
|
||||
memset(rkey + keylen, 0, 64 - keylen);
|
||||
memset(rkey + keylen, 0, sizeof(rkey) - keylen);
|
||||
} else {
|
||||
secp256k1_sha256_t sha256;
|
||||
secp256k1_sha256 sha256;
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&sha256, key, keylen);
|
||||
secp256k1_sha256_finalize(&sha256, rkey);
|
||||
@@ -176,24 +192,24 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, cons
|
||||
}
|
||||
|
||||
secp256k1_sha256_initialize(&hash->outer);
|
||||
for (n = 0; n < 64; n++) {
|
||||
for (n = 0; n < sizeof(rkey); n++) {
|
||||
rkey[n] ^= 0x5c;
|
||||
}
|
||||
secp256k1_sha256_write(&hash->outer, rkey, 64);
|
||||
secp256k1_sha256_write(&hash->outer, rkey, sizeof(rkey));
|
||||
|
||||
secp256k1_sha256_initialize(&hash->inner);
|
||||
for (n = 0; n < 64; n++) {
|
||||
for (n = 0; n < sizeof(rkey); n++) {
|
||||
rkey[n] ^= 0x5c ^ 0x36;
|
||||
}
|
||||
secp256k1_sha256_write(&hash->inner, rkey, 64);
|
||||
memset(rkey, 0, 64);
|
||||
secp256k1_sha256_write(&hash->inner, rkey, sizeof(rkey));
|
||||
memset(rkey, 0, sizeof(rkey));
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) {
|
||||
static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) {
|
||||
secp256k1_sha256_write(&hash->inner, data, size);
|
||||
}
|
||||
|
||||
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) {
|
||||
static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) {
|
||||
unsigned char temp[32];
|
||||
secp256k1_sha256_finalize(&hash->inner, temp);
|
||||
secp256k1_sha256_write(&hash->outer, temp, 32);
|
||||
@@ -202,8 +218,8 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsign
|
||||
}
|
||||
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen) {
|
||||
secp256k1_hmac_sha256_t hmac;
|
||||
static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) {
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
static const unsigned char zero[1] = {0x00};
|
||||
static const unsigned char one[1] = {0x01};
|
||||
|
||||
@@ -232,11 +248,11 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2
|
||||
rng->retry = 0;
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) {
|
||||
static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) {
|
||||
/* RFC6979 3.2.h. */
|
||||
static const unsigned char zero[1] = {0x00};
|
||||
if (rng->retry) {
|
||||
secp256k1_hmac_sha256_t hmac;
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, zero, 1);
|
||||
@@ -247,7 +263,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256
|
||||
}
|
||||
|
||||
while (outlen > 0) {
|
||||
secp256k1_hmac_sha256_t hmac;
|
||||
secp256k1_hmac_sha256 hmac;
|
||||
int now = outlen;
|
||||
secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32);
|
||||
secp256k1_hmac_sha256_write(&hmac, rng->v, 32);
|
||||
@@ -263,7 +279,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256
|
||||
rng->retry = 1;
|
||||
}
|
||||
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) {
|
||||
static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) {
|
||||
memset(rng->k, 0, 32);
|
||||
memset(rng->v, 0, 32);
|
||||
rng->retry = 0;
|
||||
@@ -278,4 +294,4 @@ static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256
|
||||
#undef Maj
|
||||
#undef Ch
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_HASH_IMPL_H */
|
||||
|
||||
@@ -1,446 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
* Copyright 2014-2016 the libsecp256k1 contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoin;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import static org.bitcoin.NativeSecp256k1Util.*;
|
||||
|
||||
/**
|
||||
* <p>This class holds native methods to handle ECDSA verification.</p>
|
||||
*
|
||||
* <p>You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1</p>
|
||||
*
|
||||
* <p>To build secp256k1 for use with bitcoinj, run
|
||||
* `./configure --enable-jni --enable-experimental --enable-module-ecdh`
|
||||
* and `make` then copy `.libs/libsecp256k1.so` to your system library path
|
||||
* or point the JVM to the folder containing it with -Djava.library.path
|
||||
* </p>
|
||||
*/
|
||||
public class NativeSecp256k1 {
|
||||
|
||||
private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||
private static final Lock r = rwl.readLock();
|
||||
private static final Lock w = rwl.writeLock();
|
||||
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
|
||||
/**
|
||||
* Verifies the given secp256k1 signature in native code.
|
||||
* Calling when enabled == false is undefined (probably library not loaded)
|
||||
*
|
||||
* @param data The data which was signed, must be exactly 32 bytes
|
||||
* @param signature The signature
|
||||
* @param pub The public key which did the signing
|
||||
*/
|
||||
public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{
|
||||
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < 520) {
|
||||
byteBuff = ByteBuffer.allocateDirect(520);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(data);
|
||||
byteBuff.put(signature);
|
||||
byteBuff.put(pub);
|
||||
|
||||
byte[][] retByteArray;
|
||||
|
||||
r.lock();
|
||||
try {
|
||||
return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1;
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 Create an ECDSA signature.
|
||||
*
|
||||
* @param data Message hash, 32 bytes
|
||||
* @param key Secret key, 32 bytes
|
||||
*
|
||||
* Return values
|
||||
* @param sig byte array of signature
|
||||
*/
|
||||
public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{
|
||||
Preconditions.checkArgument(data.length == 32 && sec.length <= 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < 32 + 32) {
|
||||
byteBuff = ByteBuffer.allocateDirect(32 + 32);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(data);
|
||||
byteBuff.put(sec);
|
||||
|
||||
byte[][] retByteArray;
|
||||
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] sigArr = retByteArray[0];
|
||||
int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(sigArr.length, sigLen, "Got bad signature length.");
|
||||
|
||||
return retVal == 0 ? new byte[0] : sigArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid
|
||||
*
|
||||
* @param seckey ECDSA Secret key, 32 bytes
|
||||
*/
|
||||
public static boolean secKeyVerify(byte[] seckey) {
|
||||
Preconditions.checkArgument(seckey.length == 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(seckey.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(seckey);
|
||||
|
||||
r.lock();
|
||||
try {
|
||||
return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1;
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* libsecp256k1 Compute Pubkey - computes public key from secret key
|
||||
*
|
||||
* @param seckey ECDSA Secret key, 32 bytes
|
||||
*
|
||||
* Return values
|
||||
* @param pubkey ECDSA Public key, 33 or 65 bytes
|
||||
*/
|
||||
//TODO add a 'compressed' arg
|
||||
public static byte[] computePubkey(byte[] seckey) throws AssertFailException{
|
||||
Preconditions.checkArgument(seckey.length == 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < seckey.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(seckey.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(seckey);
|
||||
|
||||
byte[][] retByteArray;
|
||||
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] pubArr = retByteArray[0];
|
||||
int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||
|
||||
return retVal == 0 ? new byte[0]: pubArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 Cleanup - This destroys the secp256k1 context object
|
||||
* This should be called at the end of the program for proper cleanup of the context.
|
||||
*/
|
||||
public static synchronized void cleanup() {
|
||||
w.lock();
|
||||
try {
|
||||
secp256k1_destroy_context(Secp256k1Context.getContext());
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static long cloneContext() {
|
||||
r.lock();
|
||||
try {
|
||||
return secp256k1_ctx_clone(Secp256k1Context.getContext());
|
||||
} finally { r.unlock(); }
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it
|
||||
*
|
||||
* @param tweak some bytes to tweak with
|
||||
* @param seckey 32-byte seckey
|
||||
*/
|
||||
public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{
|
||||
Preconditions.checkArgument(privkey.length == 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(privkey);
|
||||
byteBuff.put(tweak);
|
||||
|
||||
byte[][] retByteArray;
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] privArr = retByteArray[0];
|
||||
|
||||
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
|
||||
|
||||
assertEquals(retVal, 1, "Failed return value check.");
|
||||
|
||||
return privArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it
|
||||
*
|
||||
* @param tweak some bytes to tweak with
|
||||
* @param seckey 32-byte seckey
|
||||
*/
|
||||
public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{
|
||||
Preconditions.checkArgument(privkey.length == 32);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(privkey);
|
||||
byteBuff.put(tweak);
|
||||
|
||||
byte[][] retByteArray;
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext());
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] privArr = retByteArray[0];
|
||||
|
||||
int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(privArr.length, privLen, "Got bad pubkey length.");
|
||||
|
||||
assertEquals(retVal, 1, "Failed return value check.");
|
||||
|
||||
return privArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it
|
||||
*
|
||||
* @param tweak some bytes to tweak with
|
||||
* @param pubkey 32-byte seckey
|
||||
*/
|
||||
public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{
|
||||
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(pubkey);
|
||||
byteBuff.put(tweak);
|
||||
|
||||
byte[][] retByteArray;
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] pubArr = retByteArray[0];
|
||||
|
||||
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||
|
||||
assertEquals(retVal, 1, "Failed return value check.");
|
||||
|
||||
return pubArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it
|
||||
*
|
||||
* @param tweak some bytes to tweak with
|
||||
* @param pubkey 32-byte seckey
|
||||
*/
|
||||
public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{
|
||||
Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(pubkey);
|
||||
byteBuff.put(tweak);
|
||||
|
||||
byte[][] retByteArray;
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length);
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] pubArr = retByteArray[0];
|
||||
|
||||
int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF;
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue();
|
||||
|
||||
assertEquals(pubArr.length, pubLen, "Got bad pubkey length.");
|
||||
|
||||
assertEquals(retVal, 1, "Failed return value check.");
|
||||
|
||||
return pubArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 create ECDH secret - constant time ECDH calculation
|
||||
*
|
||||
* @param seckey byte array of secret key used in exponentiaion
|
||||
* @param pubkey byte array of public key used in exponentiaion
|
||||
*/
|
||||
public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{
|
||||
Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(seckey);
|
||||
byteBuff.put(pubkey);
|
||||
|
||||
byte[][] retByteArray;
|
||||
r.lock();
|
||||
try {
|
||||
retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length);
|
||||
} finally {
|
||||
r.unlock();
|
||||
}
|
||||
|
||||
byte[] resArr = retByteArray[0];
|
||||
int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue();
|
||||
|
||||
assertEquals(resArr.length, 32, "Got bad result length.");
|
||||
assertEquals(retVal, 1, "Failed return value check.");
|
||||
|
||||
return resArr;
|
||||
}
|
||||
|
||||
/**
|
||||
* libsecp256k1 randomize - updates the context randomization
|
||||
*
|
||||
* @param seed 32-byte random seed
|
||||
*/
|
||||
public static synchronized boolean randomize(byte[] seed) throws AssertFailException{
|
||||
Preconditions.checkArgument(seed.length == 32 || seed == null);
|
||||
|
||||
ByteBuffer byteBuff = nativeECDSABuffer.get();
|
||||
if (byteBuff == null || byteBuff.capacity() < seed.length) {
|
||||
byteBuff = ByteBuffer.allocateDirect(seed.length);
|
||||
byteBuff.order(ByteOrder.nativeOrder());
|
||||
nativeECDSABuffer.set(byteBuff);
|
||||
}
|
||||
byteBuff.rewind();
|
||||
byteBuff.put(seed);
|
||||
|
||||
w.lock();
|
||||
try {
|
||||
return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1;
|
||||
} finally {
|
||||
w.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static native long secp256k1_ctx_clone(long context);
|
||||
|
||||
private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen);
|
||||
|
||||
private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen);
|
||||
|
||||
private static native void secp256k1_destroy_context(long context);
|
||||
|
||||
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen);
|
||||
|
||||
private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context);
|
||||
|
||||
private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen);
|
||||
|
||||
private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen);
|
||||
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
package org.bitcoin;
|
||||
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import java.util.Arrays;
|
||||
import java.math.BigInteger;
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import static org.bitcoin.NativeSecp256k1Util.*;
|
||||
|
||||
/**
|
||||
* This class holds test cases defined for testing this library.
|
||||
*/
|
||||
public class NativeSecp256k1Test {
|
||||
|
||||
//TODO improve comments/add more tests
|
||||
/**
|
||||
* This tests verify() for a valid signature
|
||||
*/
|
||||
public static void testVerifyPos() throws AssertFailException{
|
||||
boolean result = false;
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
|
||||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||
|
||||
result = NativeSecp256k1.verify( data, sig, pub);
|
||||
assertEquals( result, true , "testVerifyPos");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests verify() for a non-valid signature
|
||||
*/
|
||||
public static void testVerifyNeg() throws AssertFailException{
|
||||
boolean result = false;
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing"
|
||||
byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase());
|
||||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||
|
||||
result = NativeSecp256k1.verify( data, sig, pub);
|
||||
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||
assertEquals( result, false , "testVerifyNeg");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests secret key verify() for a valid secretkey
|
||||
*/
|
||||
public static void testSecKeyVerifyPos() throws AssertFailException{
|
||||
boolean result = false;
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
|
||||
result = NativeSecp256k1.secKeyVerify( sec );
|
||||
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||
assertEquals( result, true , "testSecKeyVerifyPos");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests secret key verify() for a invalid secretkey
|
||||
*/
|
||||
public static void testSecKeyVerifyNeg() throws AssertFailException{
|
||||
boolean result = false;
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||
|
||||
result = NativeSecp256k1.secKeyVerify( sec );
|
||||
//System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16));
|
||||
assertEquals( result, false , "testSecKeyVerifyNeg");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests public key create() for a valid secretkey
|
||||
*/
|
||||
public static void testPubKeyCreatePos() throws AssertFailException{
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
|
||||
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests public key create() for a invalid secretkey
|
||||
*/
|
||||
public static void testPubKeyCreateNeg() throws AssertFailException{
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
|
||||
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( pubkeyString, "" , "testPubKeyCreateNeg");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests sign() for a valid secretkey
|
||||
*/
|
||||
public static void testSignPos() throws AssertFailException{
|
||||
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.sign(data, sec);
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests sign() for a invalid secretkey
|
||||
*/
|
||||
public static void testSignNeg() throws AssertFailException{
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing"
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.sign(data, sec);
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString, "" , "testSignNeg");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests private key tweak-add
|
||||
*/
|
||||
public static void testPrivKeyTweakAdd_1() throws AssertFailException {
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests private key tweak-mul
|
||||
*/
|
||||
public static void testPrivKeyTweakMul_1() throws AssertFailException {
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests private key tweak-add uncompressed
|
||||
*/
|
||||
public static void testPrivKeyTweakAdd_2() throws AssertFailException {
|
||||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests private key tweak-mul uncompressed
|
||||
*/
|
||||
public static void testPrivKeyTweakMul_2() throws AssertFailException {
|
||||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );
|
||||
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2");
|
||||
}
|
||||
|
||||
/**
|
||||
* This tests seed randomization
|
||||
*/
|
||||
public static void testRandomize() throws AssertFailException {
|
||||
byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random"
|
||||
boolean result = NativeSecp256k1.randomize(seed);
|
||||
assertEquals( result, true, "testRandomize");
|
||||
}
|
||||
|
||||
public static void testCreateECDHSecret() throws AssertFailException{
|
||||
|
||||
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
|
||||
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
|
||||
|
||||
byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);
|
||||
String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
|
||||
assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws AssertFailException{
|
||||
|
||||
|
||||
System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n");
|
||||
|
||||
assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" );
|
||||
|
||||
//Test verify() success/fail
|
||||
testVerifyPos();
|
||||
testVerifyNeg();
|
||||
|
||||
//Test secKeyVerify() success/fail
|
||||
testSecKeyVerifyPos();
|
||||
testSecKeyVerifyNeg();
|
||||
|
||||
//Test computePubkey() success/fail
|
||||
testPubKeyCreatePos();
|
||||
testPubKeyCreateNeg();
|
||||
|
||||
//Test sign() success/fail
|
||||
testSignPos();
|
||||
testSignNeg();
|
||||
|
||||
//Test privKeyTweakAdd() 1
|
||||
testPrivKeyTweakAdd_1();
|
||||
|
||||
//Test privKeyTweakMul() 2
|
||||
testPrivKeyTweakMul_1();
|
||||
|
||||
//Test privKeyTweakAdd() 3
|
||||
testPrivKeyTweakAdd_2();
|
||||
|
||||
//Test privKeyTweakMul() 4
|
||||
testPrivKeyTweakMul_2();
|
||||
|
||||
//Test randomize()
|
||||
testRandomize();
|
||||
|
||||
//Test ECDH
|
||||
testCreateECDHSecret();
|
||||
|
||||
NativeSecp256k1.cleanup();
|
||||
|
||||
System.out.println(" All tests passed." );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the libsecp256k1 contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoin;
|
||||
|
||||
public class NativeSecp256k1Util{
|
||||
|
||||
public static void assertEquals( int val, int val2, String message ) throws AssertFailException{
|
||||
if( val != val2 )
|
||||
throw new AssertFailException("FAIL: " + message);
|
||||
}
|
||||
|
||||
public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{
|
||||
if( val != val2 )
|
||||
throw new AssertFailException("FAIL: " + message);
|
||||
else
|
||||
System.out.println("PASS: " + message);
|
||||
}
|
||||
|
||||
public static void assertEquals( String val, String val2, String message ) throws AssertFailException{
|
||||
if( !val.equals(val2) )
|
||||
throw new AssertFailException("FAIL: " + message);
|
||||
else
|
||||
System.out.println("PASS: " + message);
|
||||
}
|
||||
|
||||
public static class AssertFailException extends Exception {
|
||||
public AssertFailException(String message) {
|
||||
super( message );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2016 the libsecp256k1 contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoin;
|
||||
|
||||
/**
|
||||
* This class holds the context reference used in native methods
|
||||
* to handle ECDSA operations.
|
||||
*/
|
||||
public class Secp256k1Context {
|
||||
private static final boolean enabled; //true if the library is loaded
|
||||
private static final long context; //ref to pointer to context obj
|
||||
|
||||
static { //static initializer
|
||||
boolean isEnabled = true;
|
||||
long contextRef = -1;
|
||||
try {
|
||||
System.loadLibrary("secp256k1");
|
||||
contextRef = secp256k1_init_context();
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.out.println("UnsatisfiedLinkError: " + e.toString());
|
||||
isEnabled = false;
|
||||
}
|
||||
enabled = isEnabled;
|
||||
context = contextRef;
|
||||
}
|
||||
|
||||
public static boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public static long getContext() {
|
||||
if(!enabled) return -1; //sanity check
|
||||
return context;
|
||||
}
|
||||
|
||||
private static native long secp256k1_init_context();
|
||||
}
|
||||
@@ -1,377 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "org_bitcoin_NativeSecp256k1.h"
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_ecdh.h"
|
||||
#include "include/secp256k1_recovery.h"
|
||||
|
||||
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||
(JNIEnv* env, jclass classObject, jlong ctx_l)
|
||||
{
|
||||
const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
|
||||
jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx);
|
||||
|
||||
(void)classObject;(void)env;
|
||||
|
||||
return ctx_clone_l;
|
||||
|
||||
}
|
||||
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
|
||||
const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return secp256k1_context_randomize(ctx, seed);
|
||||
|
||||
}
|
||||
|
||||
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
|
||||
(JNIEnv* env, jclass classObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
|
||||
secp256k1_context_destroy(ctx);
|
||||
|
||||
(void)classObject;(void)env;
|
||||
}
|
||||
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* sigdata = { (unsigned char*) (data + 32) };
|
||||
const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) };
|
||||
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_pubkey pubkey;
|
||||
|
||||
int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen);
|
||||
|
||||
if( ret ) {
|
||||
ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
|
||||
|
||||
if( ret ) {
|
||||
ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey);
|
||||
}
|
||||
}
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
unsigned char* secKey = (unsigned char*) (data + 32);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray sigArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
|
||||
secp256k1_ecdsa_signature sig[72];
|
||||
|
||||
int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL );
|
||||
|
||||
unsigned char outputSer[72];
|
||||
size_t outputLen = 72;
|
||||
|
||||
if( ret ) {
|
||||
int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2;
|
||||
}
|
||||
|
||||
intsarray[0] = outputLen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
sigArray = (*env)->NewByteArray(env, outputLen);
|
||||
(*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, sigArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return secp256k1_ec_seckey_verify(ctx, secKey);
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
|
||||
secp256k1_pubkey pubkey;
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray pubkeyArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
|
||||
int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey);
|
||||
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
|
||||
if( ret ) {
|
||||
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||
}
|
||||
|
||||
intsarray[0] = outputLen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
pubkeyArray = (*env)->NewByteArray(env, outputLen);
|
||||
(*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* tweak = (unsigned char*) (privkey + 32);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray privArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
|
||||
int privkeylen = 32;
|
||||
|
||||
int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak);
|
||||
|
||||
intsarray[0] = privkeylen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
privArray = (*env)->NewByteArray(env, privkeylen);
|
||||
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* tweak = (unsigned char*) (privkey + 32);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray privArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
|
||||
int privkeylen = 32;
|
||||
|
||||
int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak);
|
||||
|
||||
intsarray[0] = privkeylen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
privArray = (*env)->NewByteArray(env, privkeylen);
|
||||
(*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, privArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/
|
||||
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* tweak = (unsigned char*) (pkey + publen);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray pubArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
|
||||
secp256k1_pubkey pubkey;
|
||||
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
|
||||
|
||||
if( ret ) {
|
||||
ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak);
|
||||
}
|
||||
|
||||
if( ret ) {
|
||||
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||
}
|
||||
|
||||
intsarray[0] = outputLen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* tweak = (unsigned char*) (pkey + publen);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray pubArray, intsByteArray;
|
||||
unsigned char intsarray[2];
|
||||
unsigned char outputSer[65];
|
||||
size_t outputLen = 65;
|
||||
|
||||
secp256k1_pubkey pubkey;
|
||||
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen);
|
||||
|
||||
if ( ret ) {
|
||||
ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak);
|
||||
}
|
||||
|
||||
if( ret ) {
|
||||
int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2;
|
||||
}
|
||||
|
||||
intsarray[0] = outputLen;
|
||||
intsarray[1] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
pubArray = (*env)->NewByteArray(env, outputLen);
|
||||
(*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, pubArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 2);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine
|
||||
(JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys)
|
||||
{
|
||||
(void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen)
|
||||
{
|
||||
secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l;
|
||||
const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject);
|
||||
const unsigned char* pubdata = (const unsigned char*) (secdata + 32);
|
||||
|
||||
jobjectArray retArray;
|
||||
jbyteArray outArray, intsByteArray;
|
||||
unsigned char intsarray[1];
|
||||
secp256k1_pubkey pubkey;
|
||||
unsigned char nonce_res[32];
|
||||
size_t outputLen = 32;
|
||||
|
||||
int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen);
|
||||
|
||||
if (ret) {
|
||||
ret = secp256k1_ecdh(
|
||||
ctx,
|
||||
nonce_res,
|
||||
&pubkey,
|
||||
secdata
|
||||
);
|
||||
}
|
||||
|
||||
intsarray[0] = ret;
|
||||
|
||||
retArray = (*env)->NewObjectArray(env, 2,
|
||||
(*env)->FindClass(env, "[B"),
|
||||
(*env)->NewByteArray(env, 1));
|
||||
|
||||
outArray = (*env)->NewByteArray(env, outputLen);
|
||||
(*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 0, outArray);
|
||||
|
||||
intsByteArray = (*env)->NewByteArray(env, 1);
|
||||
(*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray);
|
||||
(*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray);
|
||||
|
||||
(void)classObject;
|
||||
|
||||
return retArray;
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
#include "include/secp256k1.h"
|
||||
/* Header for class org_bitcoin_NativeSecp256k1 */
|
||||
|
||||
#ifndef _Included_org_bitcoin_NativeSecp256k1
|
||||
#define _Included_org_bitcoin_NativeSecp256k1
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ctx_clone
|
||||
* Signature: (J)J
|
||||
*/
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone
|
||||
(JNIEnv *, jclass, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_context_randomize
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)I
|
||||
*/
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_privkey_tweak_add
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_privkey_tweak_mul
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_pubkey_tweak_add
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add
|
||||
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_pubkey_tweak_mul
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul
|
||||
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_destroy_context
|
||||
* Signature: (J)V
|
||||
*/
|
||||
SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context
|
||||
(JNIEnv *, jclass, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdsa_verify
|
||||
* Signature: (Ljava/nio/ByteBuffer;JII)I
|
||||
*/
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify
|
||||
(JNIEnv *, jclass, jobject, jlong, jint, jint);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdsa_sign
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ec_seckey_verify
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)I
|
||||
*/
|
||||
SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ec_pubkey_create
|
||||
* Signature: (Ljava/nio/ByteBuffer;J)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create
|
||||
(JNIEnv *, jclass, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ec_pubkey_parse
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse
|
||||
(JNIEnv *, jclass, jobject, jlong, jint);
|
||||
|
||||
/*
|
||||
* Class: org_bitcoin_NativeSecp256k1
|
||||
* Method: secp256k1_ecdh
|
||||
* Signature: (Ljava/nio/ByteBuffer;JI)[[B
|
||||
*/
|
||||
SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh
|
||||
(JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,15 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "org_bitcoin_Secp256k1Context.h"
|
||||
#include "include/secp256k1.h"
|
||||
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
|
||||
(JNIEnv* env, jclass classObject)
|
||||
{
|
||||
secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
|
||||
(void)classObject;(void)env;
|
||||
|
||||
return (uintptr_t)ctx;
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
#include "include/secp256k1.h"
|
||||
/* Header for class org_bitcoin_Secp256k1Context */
|
||||
|
||||
#ifndef _Included_org_bitcoin_Secp256k1Context
|
||||
#define _Included_org_bitcoin_Secp256k1Context
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: org_bitcoin_Secp256k1Context
|
||||
* Method: secp256k1_init_context
|
||||
* Signature: ()J
|
||||
*/
|
||||
SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -4,51 +4,68 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_ECDH_MAIN_
|
||||
#define _SECP256K1_MODULE_ECDH_MAIN_
|
||||
#ifndef SECP256K1_MODULE_ECDH_MAIN_H
|
||||
#define SECP256K1_MODULE_ECDH_MAIN_H
|
||||
|
||||
#include "include/secp256k1_ecdh.h"
|
||||
#include "ecmult_const_impl.h"
|
||||
|
||||
int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) {
|
||||
static int ecdh_hash_function_sha256(unsigned char *output, const unsigned char *x32, const unsigned char *y32, void *data) {
|
||||
unsigned char version = (y32[31] & 0x01) | 0x02;
|
||||
secp256k1_sha256 sha;
|
||||
(void)data;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, &version, 1);
|
||||
secp256k1_sha256_write(&sha, x32, 32);
|
||||
secp256k1_sha256_finalize(&sha, output);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256 = ecdh_hash_function_sha256;
|
||||
const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default = ecdh_hash_function_sha256;
|
||||
|
||||
int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pubkey *point, const unsigned char *scalar, secp256k1_ecdh_hash_function hashfp, void *data) {
|
||||
int ret = 0;
|
||||
int overflow = 0;
|
||||
secp256k1_gej res;
|
||||
secp256k1_ge pt;
|
||||
secp256k1_scalar s;
|
||||
unsigned char x[32];
|
||||
unsigned char y[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(result != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(point != NULL);
|
||||
ARG_CHECK(scalar != NULL);
|
||||
|
||||
secp256k1_pubkey_load(ctx, &pt, point);
|
||||
secp256k1_scalar_set_b32(&s, scalar, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&s)) {
|
||||
ret = 0;
|
||||
} else {
|
||||
unsigned char x[32];
|
||||
unsigned char y[1];
|
||||
secp256k1_sha256_t sha;
|
||||
|
||||
secp256k1_ecmult_const(&res, &pt, &s, 256);
|
||||
secp256k1_ge_set_gej(&pt, &res);
|
||||
/* Compute a hash of the point in compressed form
|
||||
* Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not
|
||||
* expect its output to be secret and has a timing sidechannel. */
|
||||
secp256k1_fe_normalize(&pt.x);
|
||||
secp256k1_fe_normalize(&pt.y);
|
||||
secp256k1_fe_get_b32(x, &pt.x);
|
||||
y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y);
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, y, sizeof(y));
|
||||
secp256k1_sha256_write(&sha, x, sizeof(x));
|
||||
secp256k1_sha256_finalize(&sha, result);
|
||||
ret = 1;
|
||||
if (hashfp == NULL) {
|
||||
hashfp = secp256k1_ecdh_hash_function_default;
|
||||
}
|
||||
|
||||
secp256k1_pubkey_load(ctx, &pt, point);
|
||||
secp256k1_scalar_set_b32(&s, scalar, &overflow);
|
||||
|
||||
overflow |= secp256k1_scalar_is_zero(&s);
|
||||
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
|
||||
|
||||
secp256k1_ecmult_const(&res, &pt, &s, 256);
|
||||
secp256k1_ge_set_gej(&pt, &res);
|
||||
|
||||
/* Compute a hash of the point */
|
||||
secp256k1_fe_normalize(&pt.x);
|
||||
secp256k1_fe_normalize(&pt.y);
|
||||
secp256k1_fe_get_b32(x, &pt.x);
|
||||
secp256k1_fe_get_b32(y, &pt.y);
|
||||
|
||||
ret = hashfp(output, x, y, data);
|
||||
|
||||
memset(x, 0, 32);
|
||||
memset(y, 0, 32);
|
||||
secp256k1_scalar_clear(&s);
|
||||
return ret;
|
||||
|
||||
return !!ret & !overflow;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_MODULE_ECDH_MAIN_H */
|
||||
|
||||
@@ -4,8 +4,25 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_ECDH_TESTS_
|
||||
#define _SECP256K1_MODULE_ECDH_TESTS_
|
||||
#ifndef SECP256K1_MODULE_ECDH_TESTS_H
|
||||
#define SECP256K1_MODULE_ECDH_TESTS_H
|
||||
|
||||
int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||
(void)output;
|
||||
(void)x;
|
||||
(void)y;
|
||||
(void)data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
|
||||
(void)data;
|
||||
/* Save x and y as uncompressed public key */
|
||||
output[0] = 0x04;
|
||||
memcpy(output + 1, x, 32);
|
||||
memcpy(output + 33, y, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void test_ecdh_api(void) {
|
||||
/* Setup context that just counts errors */
|
||||
@@ -21,15 +38,15 @@ void test_ecdh_api(void) {
|
||||
CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1);
|
||||
|
||||
/* Check all NULLs are detected */
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0);
|
||||
CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one, NULL, NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0);
|
||||
CHECK(secp256k1_ecdh(tctx, res, NULL, s_one, NULL, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, NULL, NULL, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1);
|
||||
CHECK(secp256k1_ecdh(tctx, res, &point, s_one, NULL, NULL) == 1);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/* Cleanup */
|
||||
@@ -44,29 +61,36 @@ void test_ecdh_generator_basepoint(void) {
|
||||
s_one[31] = 1;
|
||||
/* Check against pubkey creation when the basepoint is the generator */
|
||||
for (i = 0; i < 100; ++i) {
|
||||
secp256k1_sha256_t sha;
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char s_b32[32];
|
||||
unsigned char output_ecdh[32];
|
||||
unsigned char output_ecdh[65];
|
||||
unsigned char output_ser[32];
|
||||
unsigned char point_ser[33];
|
||||
unsigned char point_ser[65];
|
||||
size_t point_ser_len = sizeof(point_ser);
|
||||
secp256k1_scalar s;
|
||||
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(s_b32, &s);
|
||||
|
||||
/* compute using ECDH function */
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1);
|
||||
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1);
|
||||
/* compute "explicitly" */
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1);
|
||||
|
||||
/* compute using ECDH function with custom hash function */
|
||||
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, ecdh_hash_function_custom, NULL) == 1);
|
||||
/* compute "explicitly" */
|
||||
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_UNCOMPRESSED) == 1);
|
||||
/* compare */
|
||||
CHECK(secp256k1_memcmp_var(output_ecdh, point_ser, 65) == 0);
|
||||
|
||||
/* compute using ECDH function with default hash function */
|
||||
CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32, NULL, NULL) == 1);
|
||||
/* compute "explicitly" */
|
||||
CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
|
||||
CHECK(point_ser_len == sizeof(point_ser));
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, point_ser, point_ser_len);
|
||||
secp256k1_sha256_finalize(&sha, output_ser);
|
||||
/* compare */
|
||||
CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0);
|
||||
CHECK(secp256k1_memcmp_var(output_ecdh, output_ser, 32) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,11 +113,14 @@ void test_bad_scalar(void) {
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);
|
||||
|
||||
/* Try to multiply it by bad values */
|
||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0);
|
||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0);
|
||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_zero, NULL, NULL) == 0);
|
||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 0);
|
||||
/* ...and a good one */
|
||||
s_overflow[31] -= 1;
|
||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1);
|
||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 1);
|
||||
|
||||
/* Hash function failure results in ecdh failure */
|
||||
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
|
||||
}
|
||||
|
||||
void run_ecdh_tests(void) {
|
||||
@@ -102,4 +129,4 @@ void run_ecdh_tests(void) {
|
||||
test_bad_scalar();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_MODULE_ECDH_TESTS_H */
|
||||
|
||||
4
src/modules/extrakeys/Makefile.am.include
Normal file
4
src/modules/extrakeys/Makefile.am.include
Normal file
@@ -0,0 +1,4 @@
|
||||
include_HEADERS += include/secp256k1_extrakeys.h
|
||||
noinst_HEADERS += src/modules/extrakeys/tests_impl.h
|
||||
noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h
|
||||
noinst_HEADERS += src/modules/extrakeys/main_impl.h
|
||||
251
src/modules/extrakeys/main_impl.h
Normal file
251
src/modules/extrakeys/main_impl.h
Normal file
@@ -0,0 +1,251 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_EXTRAKEYS_MAIN_
|
||||
#define _SECP256K1_MODULE_EXTRAKEYS_MAIN_
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_extrakeys.h"
|
||||
|
||||
static SECP256K1_INLINE int secp256k1_xonly_pubkey_load(const secp256k1_context* ctx, secp256k1_ge *ge, const secp256k1_xonly_pubkey *pubkey) {
|
||||
return secp256k1_pubkey_load(ctx, ge, (const secp256k1_pubkey *) pubkey);
|
||||
}
|
||||
|
||||
static SECP256K1_INLINE void secp256k1_xonly_pubkey_save(secp256k1_xonly_pubkey *pubkey, secp256k1_ge *ge) {
|
||||
secp256k1_pubkey_save((secp256k1_pubkey *) pubkey, ge);
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_parse(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, const unsigned char *input32) {
|
||||
secp256k1_ge pk;
|
||||
secp256k1_fe x;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
ARG_CHECK(input32 != NULL);
|
||||
|
||||
if (!secp256k1_fe_set_b32(&x, input32)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ge_set_xo_var(&pk, &x, 0)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ge_is_in_correct_subgroup(&pk)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(pubkey, &pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output32, const secp256k1_xonly_pubkey *pubkey) {
|
||||
secp256k1_ge pk;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output32 != NULL);
|
||||
memset(output32, 0, 32);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_get_b32(output32, &pk.x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Keeps a group element as is if it has an even Y and otherwise negates it.
|
||||
* y_parity is set to 0 in the former case and to 1 in the latter case.
|
||||
* Requires that the coordinates of r are normalized. */
|
||||
static int secp256k1_extrakeys_ge_even_y(secp256k1_ge *r) {
|
||||
int y_parity = 0;
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(r));
|
||||
|
||||
if (secp256k1_fe_is_odd(&r->y)) {
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
y_parity = 1;
|
||||
}
|
||||
return y_parity;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_from_pubkey(const secp256k1_context* ctx, secp256k1_xonly_pubkey *xonly_pubkey, int *pk_parity, const secp256k1_pubkey *pubkey) {
|
||||
secp256k1_ge pk;
|
||||
int tmp;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(xonly_pubkey != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (!secp256k1_pubkey_load(ctx, &pk, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
tmp = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
if (pk_parity != NULL) {
|
||||
*pk_parity = tmp;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(xonly_pubkey, &pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output_pubkey != NULL);
|
||||
memset(output_pubkey, 0, sizeof(*output_pubkey));
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(internal_pubkey != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey)
|
||||
|| !secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_pubkey_save(output_pubkey, &pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_xonly_pubkey_tweak_add_check(const secp256k1_context* ctx, const unsigned char *tweaked_pubkey32, int tweaked_pk_parity, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
unsigned char pk_expected32[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(internal_pubkey != NULL);
|
||||
ARG_CHECK(tweaked_pubkey32 != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, internal_pubkey)
|
||||
|| !secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_normalize_var(&pk.x);
|
||||
secp256k1_fe_normalize_var(&pk.y);
|
||||
secp256k1_fe_get_b32(pk_expected32, &pk.x);
|
||||
|
||||
return secp256k1_memcmp_var(&pk_expected32, tweaked_pubkey32, 32) == 0
|
||||
&& secp256k1_fe_is_odd(&pk.y) == tweaked_pk_parity;
|
||||
}
|
||||
|
||||
static void secp256k1_keypair_save(secp256k1_keypair *keypair, const secp256k1_scalar *sk, secp256k1_ge *pk) {
|
||||
secp256k1_scalar_get_b32(&keypair->data[0], sk);
|
||||
secp256k1_pubkey_save((secp256k1_pubkey *)&keypair->data[32], pk);
|
||||
}
|
||||
|
||||
|
||||
static int secp256k1_keypair_seckey_load(const secp256k1_context* ctx, secp256k1_scalar *sk, const secp256k1_keypair *keypair) {
|
||||
int ret;
|
||||
|
||||
ret = secp256k1_scalar_set_b32_seckey(sk, &keypair->data[0]);
|
||||
/* We can declassify ret here because sk is only zero if a keypair function
|
||||
* failed (which zeroes the keypair) and its return value is ignored. */
|
||||
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
||||
ARG_CHECK(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Load a keypair into pk and sk (if non-NULL). This function declassifies pk
|
||||
* and ARG_CHECKs that the keypair is not invalid. It always initializes sk and
|
||||
* pk with dummy values. */
|
||||
static int secp256k1_keypair_load(const secp256k1_context* ctx, secp256k1_scalar *sk, secp256k1_ge *pk, const secp256k1_keypair *keypair) {
|
||||
int ret;
|
||||
const secp256k1_pubkey *pubkey = (const secp256k1_pubkey *)&keypair->data[32];
|
||||
|
||||
/* Need to declassify the pubkey because pubkey_load ARG_CHECKs if it's
|
||||
* invalid. */
|
||||
secp256k1_declassify(ctx, pubkey, sizeof(*pubkey));
|
||||
ret = secp256k1_pubkey_load(ctx, pk, pubkey);
|
||||
if (sk != NULL) {
|
||||
ret = ret && secp256k1_keypair_seckey_load(ctx, sk, keypair);
|
||||
}
|
||||
if (!ret) {
|
||||
*pk = secp256k1_ge_const_g;
|
||||
if (sk != NULL) {
|
||||
*sk = secp256k1_scalar_one;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_create(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *seckey32) {
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_ge pk;
|
||||
int ret = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(keypair != NULL);
|
||||
memset(keypair, 0, sizeof(*keypair));
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(seckey32 != NULL);
|
||||
|
||||
ret = secp256k1_ec_pubkey_create_helper(&ctx->ecmult_gen_ctx, &sk, &pk, seckey32);
|
||||
secp256k1_keypair_save(keypair, &sk, &pk);
|
||||
secp256k1_memczero(keypair, sizeof(*keypair), !ret);
|
||||
|
||||
secp256k1_scalar_clear(&sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_pub(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_keypair *keypair) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
memcpy(pubkey->data, &keypair->data[32], sizeof(*pubkey));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_xonly_pub(const secp256k1_context* ctx, secp256k1_xonly_pubkey *pubkey, int *pk_parity, const secp256k1_keypair *keypair) {
|
||||
secp256k1_ge pk;
|
||||
int tmp;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
memset(pubkey, 0, sizeof(*pubkey));
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
if (!secp256k1_keypair_load(ctx, NULL, &pk, keypair)) {
|
||||
return 0;
|
||||
}
|
||||
tmp = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
if (pk_parity != NULL) {
|
||||
*pk_parity = tmp;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(pubkey, &pk);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_keypair_xonly_tweak_add(const secp256k1_context* ctx, secp256k1_keypair *keypair, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
secp256k1_scalar sk;
|
||||
int y_parity;
|
||||
int ret;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(keypair != NULL);
|
||||
ARG_CHECK(tweak32 != NULL);
|
||||
|
||||
ret = secp256k1_keypair_load(ctx, &sk, &pk, keypair);
|
||||
memset(keypair, 0, sizeof(*keypair));
|
||||
|
||||
y_parity = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
if (y_parity == 1) {
|
||||
secp256k1_scalar_negate(&sk, &sk);
|
||||
}
|
||||
|
||||
ret &= secp256k1_ec_seckey_tweak_add_helper(&sk, tweak32);
|
||||
ret &= secp256k1_ec_pubkey_tweak_add_helper(&ctx->ecmult_ctx, &pk, tweak32);
|
||||
|
||||
secp256k1_declassify(ctx, &ret, sizeof(ret));
|
||||
if (ret) {
|
||||
secp256k1_keypair_save(keypair, &sk, &pk);
|
||||
}
|
||||
|
||||
secp256k1_scalar_clear(&sk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
68
src/modules/extrakeys/tests_exhaustive_impl.h
Normal file
68
src/modules/extrakeys/tests_exhaustive_impl.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_
|
||||
#define _SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_
|
||||
|
||||
#include "src/modules/extrakeys/main_impl.h"
|
||||
#include "include/secp256k1_extrakeys.h"
|
||||
|
||||
static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) {
|
||||
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
secp256k1_pubkey pubkey[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
int parities[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32];
|
||||
int i;
|
||||
|
||||
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) {
|
||||
secp256k1_fe fe;
|
||||
secp256k1_scalar scalar_i;
|
||||
unsigned char buf[33];
|
||||
int parity;
|
||||
|
||||
secp256k1_scalar_set_int(&scalar_i, i);
|
||||
secp256k1_scalar_get_b32(buf, &scalar_i);
|
||||
|
||||
/* Construct pubkey and keypair. */
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey[i - 1], buf));
|
||||
|
||||
/* Construct serialized xonly_pubkey from keypair. */
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parities[i - 1], &keypair[i - 1]));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1]));
|
||||
|
||||
/* Parse the xonly_pubkey back and verify it matches the previously serialized value. */
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pubkey[i - 1], xonly_pubkey_bytes[i - 1]));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1]));
|
||||
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0);
|
||||
|
||||
/* Construct the xonly_pubkey from the pubkey, and verify it matches the same. */
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey[i - 1], &parity, &pubkey[i - 1]));
|
||||
CHECK(parity == parities[i - 1]);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1]));
|
||||
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], buf, 32) == 0);
|
||||
|
||||
/* Compare the xonly_pubkey bytes against the precomputed group. */
|
||||
secp256k1_fe_set_b32(&fe, xonly_pubkey_bytes[i - 1]);
|
||||
CHECK(secp256k1_fe_equal_var(&fe, &group[i].x));
|
||||
|
||||
/* Check the parity against the precomputed group. */
|
||||
fe = group[i].y;
|
||||
secp256k1_fe_normalize_var(&fe);
|
||||
CHECK(secp256k1_fe_is_odd(&fe) == parities[i - 1]);
|
||||
|
||||
/* Verify that the higher half is identical to the lower half mirrored. */
|
||||
if (i > EXHAUSTIVE_TEST_ORDER / 2) {
|
||||
CHECK(secp256k1_memcmp_var(xonly_pubkey_bytes[i - 1], xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - i - 1], 32) == 0);
|
||||
CHECK(parities[i - 1] == 1 - parities[EXHAUSTIVE_TEST_ORDER - i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: keypair/xonly_pubkey tweak tests */
|
||||
}
|
||||
|
||||
#endif
|
||||
524
src/modules/extrakeys/tests_impl.h
Normal file
524
src/modules/extrakeys/tests_impl.h
Normal file
@@ -0,0 +1,524 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_
|
||||
#define _SECP256K1_MODULE_EXTRAKEYS_TESTS_
|
||||
|
||||
#include "secp256k1_extrakeys.h"
|
||||
|
||||
static secp256k1_context* api_test_context(int flags, int *ecount) {
|
||||
secp256k1_context *ctx0 = secp256k1_context_create(flags);
|
||||
secp256k1_context_set_error_callback(ctx0, counting_illegal_callback_fn, ecount);
|
||||
secp256k1_context_set_illegal_callback(ctx0, counting_illegal_callback_fn, ecount);
|
||||
return ctx0;
|
||||
}
|
||||
|
||||
void test_xonly_pubkey(void) {
|
||||
secp256k1_pubkey pk;
|
||||
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
|
||||
secp256k1_ge pk1;
|
||||
secp256k1_ge pk2;
|
||||
secp256k1_fe y;
|
||||
unsigned char sk[32];
|
||||
unsigned char xy_sk[32];
|
||||
unsigned char buf32[32];
|
||||
unsigned char ones32[32];
|
||||
unsigned char zeros64[64] = { 0 };
|
||||
int pk_parity;
|
||||
int i;
|
||||
|
||||
int ecount;
|
||||
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
|
||||
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
|
||||
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
|
||||
|
||||
secp256k1_testrand256(sk);
|
||||
memset(ones32, 0xFF, 32);
|
||||
secp256k1_testrand256(xy_sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
|
||||
/* Test xonly_pubkey_from_pubkey */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(sign, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, NULL, &pk_parity, &pk) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
memset(&pk, 0, sizeof(pk));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 0);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/* Choose a secret key such that the resulting pubkey and xonly_pubkey match. */
|
||||
memset(sk, 0, sizeof(sk));
|
||||
sk[0] = 1;
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&pk, &xonly_pk, sizeof(pk)) == 0);
|
||||
CHECK(pk_parity == 0);
|
||||
|
||||
/* Choose a secret key such that pubkey and xonly_pubkey are each others
|
||||
* negation. */
|
||||
sk[0] = 2;
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, &pk, sizeof(xonly_pk)) != 0);
|
||||
CHECK(pk_parity == 1);
|
||||
secp256k1_pubkey_load(ctx, &pk1, &pk);
|
||||
secp256k1_pubkey_load(ctx, &pk2, (secp256k1_pubkey *) &xonly_pk);
|
||||
CHECK(secp256k1_fe_equal(&pk1.x, &pk2.x) == 1);
|
||||
secp256k1_fe_negate(&y, &pk2.y, 1);
|
||||
CHECK(secp256k1_fe_equal(&pk1.y, &y) == 1);
|
||||
|
||||
/* Test xonly_pubkey_serialize and xonly_pubkey_parse */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(none, NULL, &xonly_pk) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, NULL) == 0);
|
||||
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(none, buf32, &pk_tmp) == 0);
|
||||
}
|
||||
/* pubkey_load called illegal callback */
|
||||
CHECK(ecount == 3);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(none, buf32, &xonly_pk) == 1);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_parse(none, NULL, buf32) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
|
||||
/* Serialization and parse roundtrip */
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, NULL, &pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk_tmp, buf32) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(xonly_pk)) == 0);
|
||||
|
||||
/* Test parsing invalid field elements */
|
||||
memset(&xonly_pk, 1, sizeof(xonly_pk));
|
||||
/* Overflowing field element */
|
||||
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, ones32) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
|
||||
memset(&xonly_pk, 1, sizeof(xonly_pk));
|
||||
/* There's no point with x-coordinate 0 on secp256k1 */
|
||||
CHECK(secp256k1_xonly_pubkey_parse(none, &xonly_pk, zeros64) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
|
||||
/* If a random 32-byte string can not be parsed with ec_pubkey_parse
|
||||
* (because interpreted as X coordinate it does not correspond to a point on
|
||||
* the curve) then xonly_pubkey_parse should fail as well. */
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned char rand33[33];
|
||||
secp256k1_testrand256(&rand33[1]);
|
||||
rand33[0] = SECP256K1_TAG_PUBKEY_EVEN;
|
||||
if (!secp256k1_ec_pubkey_parse(ctx, &pk, rand33, 33)) {
|
||||
memset(&xonly_pk, 1, sizeof(xonly_pk));
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, zeros64, sizeof(xonly_pk)) == 0);
|
||||
} else {
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pk, &rand33[1]) == 1);
|
||||
}
|
||||
}
|
||||
CHECK(ecount == 2);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(verify);
|
||||
}
|
||||
|
||||
void test_xonly_pubkey_tweak(void) {
|
||||
unsigned char zeros64[64] = { 0 };
|
||||
unsigned char overflows[32];
|
||||
unsigned char sk[32];
|
||||
secp256k1_pubkey internal_pk;
|
||||
secp256k1_xonly_pubkey internal_xonly_pk;
|
||||
secp256k1_pubkey output_pk;
|
||||
int pk_parity;
|
||||
unsigned char tweak[32];
|
||||
int i;
|
||||
|
||||
int ecount;
|
||||
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
|
||||
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
|
||||
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &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(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(none, &output_pk, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(sign, &output_pk, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, NULL, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, NULL, tweak) == 0);
|
||||
CHECK(ecount == 4);
|
||||
/* 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(verify, &output_pk, &internal_xonly_pk, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
/* NULL tweak zeroes the output_pk */
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
|
||||
/* Invalid tweak zeroes the output_pk */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
|
||||
/* A zero tweak is fine */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, zeros64) == 1);
|
||||
|
||||
/* Fails if the resulting key was infinity */
|
||||
for (i = 0; i < count; i++) {
|
||||
secp256k1_scalar scalar_tweak;
|
||||
/* Because sk may be negated before adding, we need to try with tweak =
|
||||
* sk as well as tweak = -sk. */
|
||||
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
|
||||
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
|
||||
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
|
||||
CHECK((secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, sk) == 0)
|
||||
|| (secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 0));
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
}
|
||||
|
||||
/* 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(verify, &output_pk, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(verify);
|
||||
}
|
||||
|
||||
void test_xonly_pubkey_tweak_check(void) {
|
||||
unsigned char zeros64[64] = { 0 };
|
||||
unsigned char overflows[32];
|
||||
unsigned char sk[32];
|
||||
secp256k1_pubkey internal_pk;
|
||||
secp256k1_xonly_pubkey internal_xonly_pk;
|
||||
secp256k1_pubkey output_pk;
|
||||
secp256k1_xonly_pubkey output_xonly_pk;
|
||||
unsigned char output_pk32[32];
|
||||
unsigned char buf32[32];
|
||||
int pk_parity;
|
||||
unsigned char tweak[32];
|
||||
|
||||
int ecount;
|
||||
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
|
||||
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
|
||||
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &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(none, &internal_xonly_pk, &pk_parity, &internal_pk) == 1);
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(verify, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(verify, &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(none, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(sign, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, NULL, pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
/* invalid pk_parity value */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, 2, &internal_xonly_pk, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, NULL, tweak) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(verify, buf32, pk_parity, &internal_xonly_pk, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
|
||||
memset(tweak, 1, sizeof(tweak));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &internal_xonly_pk, NULL, &internal_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &output_xonly_pk, &pk_parity, &output_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk32, &output_xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, tweak) == 1);
|
||||
|
||||
/* Wrong pk_parity */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, !pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
/* Wrong public key */
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf32, &internal_xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, buf32, pk_parity, &internal_xonly_pk, tweak) == 0);
|
||||
|
||||
/* Overflowing tweak not allowed */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk32, pk_parity, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk, &internal_xonly_pk, overflows) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&output_pk, zeros64, sizeof(output_pk)) == 0);
|
||||
CHECK(ecount == 5);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(verify);
|
||||
}
|
||||
|
||||
/* Starts with an initial pubkey and recursively creates N_PUBKEYS - 1
|
||||
* additional pubkeys by calling tweak_add. Then verifies every tweak starting
|
||||
* from the last pubkey. */
|
||||
#define N_PUBKEYS 32
|
||||
void test_xonly_pubkey_tweak_recursive(void) {
|
||||
unsigned char sk[32];
|
||||
secp256k1_pubkey pk[N_PUBKEYS];
|
||||
unsigned char pk_serialized[32];
|
||||
unsigned char tweak[N_PUBKEYS - 1][32];
|
||||
int i;
|
||||
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk) == 1);
|
||||
/* Add tweaks */
|
||||
for (i = 0; i < N_PUBKEYS - 1; i++) {
|
||||
secp256k1_xonly_pubkey xonly_pk;
|
||||
memset(tweak[i], i + 1, sizeof(tweak[i]));
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &pk[i + 1], &xonly_pk, tweak[i]) == 1);
|
||||
}
|
||||
|
||||
/* Verify tweaks */
|
||||
for (i = N_PUBKEYS - 1; i > 0; i--) {
|
||||
secp256k1_xonly_pubkey xonly_pk;
|
||||
int pk_parity;
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, &pk_parity, &pk[i]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk_serialized, &xonly_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pk, NULL, &pk[i - 1]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk_serialized, pk_parity, &xonly_pk, tweak[i - 1]) == 1);
|
||||
}
|
||||
}
|
||||
#undef N_PUBKEYS
|
||||
|
||||
void test_keypair(void) {
|
||||
unsigned char sk[32];
|
||||
unsigned char zeros96[96] = { 0 };
|
||||
unsigned char overflows[32];
|
||||
secp256k1_keypair keypair;
|
||||
secp256k1_pubkey pk, pk_tmp;
|
||||
secp256k1_xonly_pubkey xonly_pk, xonly_pk_tmp;
|
||||
int pk_parity, pk_parity_tmp;
|
||||
int ecount;
|
||||
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
|
||||
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
|
||||
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
|
||||
|
||||
CHECK(sizeof(zeros96) == sizeof(keypair));
|
||||
memset(overflows, 0xFF, sizeof(overflows));
|
||||
|
||||
/* Test keypair_create */
|
||||
ecount = 0;
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(none, &keypair, sk) == 0);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_create(verify, &keypair, sk) == 0);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_create(sign, NULL, sk) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, NULL) == 0);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(ecount == 4);
|
||||
|
||||
/* Invalid secret key */
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, zeros96) == 0);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &keypair, sizeof(keypair)) == 0);
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, overflows) == 0);
|
||||
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(none, &pk, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_pub(none, NULL, &keypair) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_pub(none, &pk, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
|
||||
|
||||
/* Using an invalid keypair is fine for keypair_pub */
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
CHECK(secp256k1_keypair_pub(none, &pk, &keypair) == 1);
|
||||
CHECK(secp256k1_memcmp_var(zeros96, &pk, sizeof(pk)) == 0);
|
||||
|
||||
/* keypair holds the same pubkey as pubkey_create */
|
||||
CHECK(secp256k1_ec_pubkey_create(sign, &pk, sk) == 1);
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_pub(none, &pk_tmp, &keypair) == 1);
|
||||
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(none, &xonly_pk, &pk_parity, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, NULL, &pk_parity, &keypair) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, NULL, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
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(none, &xonly_pk, &pk_parity, &keypair) == 1);
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk, &pk_parity, &keypair) == 0);
|
||||
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(sign, &pk, sk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(none, &xonly_pk, &pk_parity, &pk) == 1);
|
||||
CHECK(secp256k1_keypair_create(sign, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(none, &xonly_pk_tmp, &pk_parity_tmp, &keypair) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&xonly_pk, &xonly_pk_tmp, sizeof(pk)) == 0);
|
||||
CHECK(pk_parity == pk_parity_tmp);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(verify);
|
||||
}
|
||||
|
||||
void test_keypair_add(void) {
|
||||
unsigned char sk[32];
|
||||
secp256k1_keypair keypair;
|
||||
unsigned char overflows[32];
|
||||
unsigned char zeros96[96] = { 0 };
|
||||
unsigned char tweak[32];
|
||||
int i;
|
||||
int ecount = 0;
|
||||
secp256k1_context *none = api_test_context(SECP256K1_CONTEXT_NONE, &ecount);
|
||||
secp256k1_context *sign = api_test_context(SECP256K1_CONTEXT_SIGN, &ecount);
|
||||
secp256k1_context *verify = api_test_context(SECP256K1_CONTEXT_VERIFY, &ecount);
|
||||
|
||||
CHECK(sizeof(zeros96) == sizeof(keypair));
|
||||
secp256k1_testrand256(sk);
|
||||
secp256k1_testrand256(tweak);
|
||||
memset(overflows, 0xFF, 32);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(none, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(sign, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(verify, NULL, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, NULL) == 0);
|
||||
CHECK(ecount == 4);
|
||||
/* This does not set the keypair to zeroes */
|
||||
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) != 0);
|
||||
|
||||
/* Invalid tweak zeroes the keypair */
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, overflows) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0);
|
||||
|
||||
/* A zero tweak is fine */
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, zeros96) == 1);
|
||||
|
||||
/* Fails if the resulting keypair was (sk=0, pk=infinity) */
|
||||
for (i = 0; i < count; i++) {
|
||||
secp256k1_scalar scalar_tweak;
|
||||
secp256k1_keypair keypair_tmp;
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
memcpy(&keypair_tmp, &keypair, sizeof(keypair));
|
||||
/* Because sk may be negated before adding, we need to try with tweak =
|
||||
* sk as well as tweak = -sk. */
|
||||
secp256k1_scalar_set_b32(&scalar_tweak, sk, NULL);
|
||||
secp256k1_scalar_negate(&scalar_tweak, &scalar_tweak);
|
||||
secp256k1_scalar_get_b32(tweak, &scalar_tweak);
|
||||
CHECK((secp256k1_keypair_xonly_tweak_add(ctx, &keypair, sk) == 0)
|
||||
|| (secp256k1_keypair_xonly_tweak_add(ctx, &keypair_tmp, tweak) == 0));
|
||||
CHECK(secp256k1_memcmp_var(&keypair, zeros96, sizeof(keypair)) == 0
|
||||
|| secp256k1_memcmp_var(&keypair_tmp, zeros96, sizeof(keypair_tmp)) == 0);
|
||||
}
|
||||
|
||||
/* Invalid keypair with a valid tweak */
|
||||
memset(&keypair, 0, sizeof(keypair));
|
||||
secp256k1_testrand256(tweak);
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(verify, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
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(verify, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
/* 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(verify, &keypair, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/* Check that the keypair_tweak_add implementation is correct */
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
for (i = 0; i < count; i++) {
|
||||
secp256k1_xonly_pubkey internal_pk;
|
||||
secp256k1_xonly_pubkey output_pk;
|
||||
secp256k1_pubkey output_pk_xy;
|
||||
secp256k1_pubkey output_pk_expected;
|
||||
unsigned char pk32[32];
|
||||
int pk_parity;
|
||||
|
||||
secp256k1_testrand256(tweak);
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1);
|
||||
|
||||
/* Check that it passes xonly_pubkey_tweak_add_check */
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, pk32, &output_pk) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, pk32, pk_parity, &internal_pk, tweak) == 1);
|
||||
|
||||
/* Check that the resulting pubkey matches xonly_pubkey_tweak_add */
|
||||
CHECK(secp256k1_keypair_pub(ctx, &output_pk_xy, &keypair) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add(ctx, &output_pk_expected, &internal_pk, tweak) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
|
||||
|
||||
/* Check that the secret key in the keypair is tweaked correctly */
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &output_pk_expected, &keypair.data[0]) == 1);
|
||||
CHECK(secp256k1_memcmp_var(&output_pk_xy, &output_pk_expected, sizeof(output_pk_xy)) == 0);
|
||||
}
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(verify);
|
||||
}
|
||||
|
||||
void run_extrakeys_tests(void) {
|
||||
/* xonly key test cases */
|
||||
test_xonly_pubkey();
|
||||
test_xonly_pubkey_tweak();
|
||||
test_xonly_pubkey_tweak_check();
|
||||
test_xonly_pubkey_tweak_recursive();
|
||||
|
||||
/* keypair tests */
|
||||
test_keypair();
|
||||
test_keypair_add();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -15,36 +15,55 @@
|
||||
#include "scalar.h"
|
||||
|
||||
static void secp256k1_generator_load(secp256k1_ge* ge, const secp256k1_generator* gen) {
|
||||
secp256k1_fe fe;
|
||||
secp256k1_fe_set_b32(&fe, &gen->data[1]);
|
||||
secp256k1_ge_set_xquad(ge, &fe);
|
||||
if (gen->data[0] & 1) {
|
||||
secp256k1_ge_neg(ge, ge);
|
||||
}
|
||||
int succeed;
|
||||
succeed = secp256k1_fe_set_b32(&ge->x, &gen->data[0]);
|
||||
VERIFY_CHECK(succeed != 0);
|
||||
succeed = secp256k1_fe_set_b32(&ge->y, &gen->data[32]);
|
||||
VERIFY_CHECK(succeed != 0);
|
||||
ge->infinity = 0;
|
||||
(void) succeed;
|
||||
}
|
||||
|
||||
static void secp256k1_generator_save(secp256k1_generator* commit, secp256k1_ge* ge) {
|
||||
secp256k1_fe_normalize(&ge->x);
|
||||
secp256k1_fe_get_b32(&commit->data[1], &ge->x);
|
||||
commit->data[0] = 11 ^ secp256k1_fe_is_quad_var(&ge->y);
|
||||
static void secp256k1_generator_save(secp256k1_generator *gen, secp256k1_ge* ge) {
|
||||
VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
|
||||
secp256k1_fe_normalize_var(&ge->x);
|
||||
secp256k1_fe_normalize_var(&ge->y);
|
||||
secp256k1_fe_get_b32(&gen->data[0], &ge->x);
|
||||
secp256k1_fe_get_b32(&gen->data[32], &ge->y);
|
||||
}
|
||||
|
||||
int secp256k1_generator_parse(const secp256k1_context* ctx, secp256k1_generator* gen, const unsigned char *input) {
|
||||
secp256k1_fe x;
|
||||
secp256k1_ge ge;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
ARG_CHECK(input != NULL);
|
||||
if ((input[0] & 0xFE) != 10) {
|
||||
|
||||
if ((input[0] & 0xFE) != 10 ||
|
||||
!secp256k1_fe_set_b32(&x, &input[1]) ||
|
||||
!secp256k1_ge_set_xquad(&ge, &x)) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(gen->data, input, sizeof(gen->data));
|
||||
if (input[0] & 1) {
|
||||
secp256k1_ge_neg(&ge, &ge);
|
||||
}
|
||||
secp256k1_generator_save(gen, &ge);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_generator_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_generator* gen) {
|
||||
secp256k1_ge ge;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
memcpy(output, gen->data, sizeof(gen->data));
|
||||
|
||||
secp256k1_generator_load(&ge, gen);
|
||||
|
||||
output[0] = 11 ^ secp256k1_fe_is_quad_var(&ge.y);
|
||||
secp256k1_fe_normalize_var(&ge.x);
|
||||
secp256k1_fe_get_b32(&output[1], &ge.x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -142,13 +161,13 @@ static void shallue_van_de_woestijne(secp256k1_ge* ge, const secp256k1_fe* t) {
|
||||
}
|
||||
|
||||
static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, secp256k1_generator* gen, const unsigned char *key32, const unsigned char *blind32) {
|
||||
static const unsigned char prefix1[16] = "1st generation: ";
|
||||
static const unsigned char prefix2[16] = "2nd generation: ";
|
||||
static const unsigned char prefix1[17] = "1st generation: ";
|
||||
static const unsigned char prefix2[17] = "2nd generation: ";
|
||||
secp256k1_fe t = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 4);
|
||||
secp256k1_ge add;
|
||||
secp256k1_gej accum;
|
||||
int overflow;
|
||||
secp256k1_sha256_t sha256;
|
||||
secp256k1_sha256 sha256;
|
||||
unsigned char b32[32];
|
||||
int ret = 1;
|
||||
|
||||
@@ -156,7 +175,6 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s
|
||||
secp256k1_scalar blind;
|
||||
secp256k1_scalar_set_b32(&blind, blind32, &overflow);
|
||||
ret = !overflow;
|
||||
CHECK(ret);
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &accum, &blind);
|
||||
}
|
||||
|
||||
@@ -165,7 +183,6 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s
|
||||
secp256k1_sha256_write(&sha256, key32, 32);
|
||||
secp256k1_sha256_finalize(&sha256, b32);
|
||||
ret &= secp256k1_fe_set_b32(&t, b32);
|
||||
CHECK(ret);
|
||||
shallue_van_de_woestijne(&add, &t);
|
||||
if (blind32) {
|
||||
secp256k1_gej_add_ge(&accum, &accum, &add);
|
||||
@@ -178,7 +195,6 @@ static int secp256k1_generator_generate_internal(const secp256k1_context* ctx, s
|
||||
secp256k1_sha256_write(&sha256, key32, 32);
|
||||
secp256k1_sha256_finalize(&sha256, b32);
|
||||
ret &= secp256k1_fe_set_b32(&t, b32);
|
||||
CHECK(ret);
|
||||
shallue_van_de_woestijne(&add, &t);
|
||||
secp256k1_gej_add_ge(&accum, &accum, &add);
|
||||
|
||||
@@ -191,7 +207,6 @@ int secp256k1_generator_generate(const secp256k1_context* ctx, secp256k1_generat
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
ARG_CHECK(key32 != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
return secp256k1_generator_generate_internal(ctx, gen, key32, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,65 @@
|
||||
|
||||
#include "include/secp256k1_generator.h"
|
||||
|
||||
void test_generator_api(void) {
|
||||
unsigned char key[32];
|
||||
unsigned char blind[32];
|
||||
unsigned char sergen[33];
|
||||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
secp256k1_generator gen;
|
||||
int32_t ecount = 0;
|
||||
|
||||
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_testrand256(key);
|
||||
secp256k1_testrand256(blind);
|
||||
|
||||
CHECK(secp256k1_generator_generate(none, &gen, key) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_generator_generate(none, NULL, key) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_generator_generate(none, &gen, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
|
||||
CHECK(secp256k1_generator_generate_blinded(sign, &gen, key, blind) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_generator_generate_blinded(vrfy, &gen, key, blind) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_generator_generate_blinded(none, &gen, key, blind) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_generator_generate_blinded(vrfy, NULL, key, blind) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_generator_generate_blinded(vrfy, &gen, NULL, blind) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_generator_generate_blinded(vrfy, &gen, key, NULL) == 0);
|
||||
CHECK(ecount == 7);
|
||||
|
||||
CHECK(secp256k1_generator_serialize(none, sergen, &gen) == 1);
|
||||
CHECK(ecount == 7);
|
||||
CHECK(secp256k1_generator_serialize(none, NULL, &gen) == 0);
|
||||
CHECK(ecount == 8);
|
||||
CHECK(secp256k1_generator_serialize(none, sergen, NULL) == 0);
|
||||
CHECK(ecount == 9);
|
||||
|
||||
CHECK(secp256k1_generator_serialize(none, sergen, &gen) == 1);
|
||||
CHECK(secp256k1_generator_parse(none, &gen, sergen) == 1);
|
||||
CHECK(ecount == 9);
|
||||
CHECK(secp256k1_generator_parse(none, NULL, sergen) == 0);
|
||||
CHECK(ecount == 10);
|
||||
CHECK(secp256k1_generator_parse(none, &gen, NULL) == 0);
|
||||
CHECK(ecount == 11);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(vrfy);
|
||||
}
|
||||
|
||||
void test_shallue_van_de_woestijne(void) {
|
||||
/* Matches with the output of the shallue_van_de_woestijne.sage SAGE program */
|
||||
static const secp256k1_ge_storage results[32] = {
|
||||
@@ -114,7 +173,7 @@ void test_generator_generate(void) {
|
||||
secp256k1_ge_storage ges;
|
||||
int i;
|
||||
unsigned char v[32];
|
||||
static const unsigned char s[32] = {0};
|
||||
unsigned char s[32] = {0};
|
||||
secp256k1_scalar sc;
|
||||
secp256k1_scalar_set_b32(&sc, s, NULL);
|
||||
for (i = 1; i <= 32; i++) {
|
||||
@@ -129,10 +188,39 @@ void test_generator_generate(void) {
|
||||
secp256k1_ge_to_storage(&ges, &ge);
|
||||
CHECK(memcmp(&ges, &results[i - 1], sizeof(secp256k1_ge_storage)) == 0);
|
||||
}
|
||||
|
||||
/* There is no range restriction on the value, but the blinder must be a
|
||||
* valid scalar. Check that an invalid blinder causes the call to fail
|
||||
* but not crash. */
|
||||
memset(v, 0xff, 32);
|
||||
CHECK(secp256k1_generator_generate(ctx, &gen, v));
|
||||
memset(s, 0xff, 32);
|
||||
CHECK(!secp256k1_generator_generate_blinded(ctx, &gen, v, s));
|
||||
}
|
||||
|
||||
void test_generator_fixed_vector(void) {
|
||||
const unsigned char two_g[33] = {
|
||||
0x0b,
|
||||
0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8,
|
||||
0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5
|
||||
};
|
||||
unsigned char result[33];
|
||||
secp256k1_generator parse;
|
||||
|
||||
CHECK(secp256k1_generator_parse(ctx, &parse, two_g));
|
||||
CHECK(secp256k1_generator_serialize(ctx, result, &parse));
|
||||
CHECK(memcmp(two_g, result, 33) == 0);
|
||||
|
||||
result[0] = 0x0a;
|
||||
CHECK(secp256k1_generator_parse(ctx, &parse, result));
|
||||
result[0] = 0x08;
|
||||
CHECK(!secp256k1_generator_parse(ctx, &parse, result));
|
||||
}
|
||||
|
||||
void run_generator_tests(void) {
|
||||
test_shallue_van_de_woestijne();
|
||||
test_generator_fixed_vector();
|
||||
test_generator_api();
|
||||
test_generator_generate();
|
||||
}
|
||||
|
||||
|
||||
16
src/modules/musig/Makefile.am.include
Normal file
16
src/modules/musig/Makefile.am.include
Normal file
@@ -0,0 +1,16 @@
|
||||
include_HEADERS += include/secp256k1_musig.h
|
||||
noinst_HEADERS += src/modules/musig/main_impl.h
|
||||
noinst_HEADERS += src/modules/musig/tests_impl.h
|
||||
|
||||
noinst_PROGRAMS += example_musig
|
||||
example_musig_SOURCES = src/modules/musig/example.c
|
||||
example_musig_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include $(SECP_INCLUDES)
|
||||
if !ENABLE_COVERAGE
|
||||
example_musig_CPPFLAGS += -DVERIFY
|
||||
endif
|
||||
example_musig_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
example_musig_LDFLAGS = -static
|
||||
|
||||
if USE_TESTS
|
||||
TESTS += example_musig
|
||||
endif
|
||||
168
src/modules/musig/example.c
Normal file
168
src/modules/musig/example.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2018 Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
/**
|
||||
* This file demonstrates how to use the MuSig module to create a multisignature.
|
||||
* Additionally, see the documentation in include/secp256k1_musig.h.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_schnorrsig.h>
|
||||
#include <secp256k1_musig.h>
|
||||
|
||||
/* Number of public keys involved in creating the aggregate signature */
|
||||
#define N_SIGNERS 3
|
||||
/* Create a key pair and store it in seckey and pubkey */
|
||||
int create_keypair(const secp256k1_context* ctx, unsigned char *seckey, secp256k1_xonly_pubkey *pubkey) {
|
||||
int ret;
|
||||
secp256k1_keypair keypair;
|
||||
FILE *frand = fopen("/dev/urandom", "r");
|
||||
if (frand == NULL) {
|
||||
return 0;
|
||||
}
|
||||
do {
|
||||
if(!fread(seckey, 32, 1, frand)) {
|
||||
fclose(frand);
|
||||
return 0;
|
||||
}
|
||||
/* The probability that this not a valid secret key is approximately 2^-128 */
|
||||
} while (!secp256k1_ec_seckey_verify(ctx, seckey));
|
||||
fclose(frand);
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, seckey);
|
||||
ret &= secp256k1_keypair_xonly_pub(ctx, pubkey, NULL, &keypair);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Sign a message hash with the given key pairs and store the result in sig */
|
||||
int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp256k1_xonly_pubkey* pubkeys, const unsigned char* msg32, unsigned char *sig64) {
|
||||
secp256k1_musig_session musig_session[N_SIGNERS];
|
||||
unsigned char nonce_commitment[N_SIGNERS][32];
|
||||
const unsigned char *nonce_commitment_ptr[N_SIGNERS];
|
||||
secp256k1_musig_session_signer_data signer_data[N_SIGNERS][N_SIGNERS];
|
||||
unsigned char nonce[N_SIGNERS][32];
|
||||
int i, j;
|
||||
secp256k1_musig_partial_signature partial_sig[N_SIGNERS];
|
||||
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
FILE *frand;
|
||||
unsigned char session_id32[32];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
|
||||
/* Create combined pubkey and initialize signer data */
|
||||
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, &pre_session, pubkeys, N_SIGNERS)) {
|
||||
return 0;
|
||||
}
|
||||
/* Create random session ID. It is absolutely necessary that the session ID
|
||||
* is unique for every call of secp256k1_musig_session_init. Otherwise
|
||||
* it's trivial for an attacker to extract the secret key! */
|
||||
frand = fopen("/dev/urandom", "r");
|
||||
if(frand == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if (!fread(session_id32, 32, 1, frand)) {
|
||||
fclose(frand);
|
||||
return 0;
|
||||
}
|
||||
fclose(frand);
|
||||
/* Initialize session */
|
||||
if (!secp256k1_musig_session_init(ctx, &musig_session[i], signer_data[i], nonce_commitment[i], session_id32, msg32, &combined_pk, &pre_session, N_SIGNERS, i, seckeys[i])) {
|
||||
return 0;
|
||||
}
|
||||
nonce_commitment_ptr[i] = &nonce_commitment[i][0];
|
||||
}
|
||||
/* Communication round 1: Exchange nonce commitments */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
/* Set nonce commitments in the signer data and get the own public nonce */
|
||||
if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], nonce[i], nonce_commitment_ptr, N_SIGNERS, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Communication round 2: Exchange nonces */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
for (j = 0; j < N_SIGNERS; j++) {
|
||||
if (!secp256k1_musig_set_nonce(ctx, &signer_data[i][j], nonce[j])) {
|
||||
/* Signer j's nonce does not match the nonce commitment. In this case
|
||||
* abort the protocol. If you make another attempt at finishing the
|
||||
* protocol, create a new session (with a fresh session ID!). */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!secp256k1_musig_session_combine_nonces(ctx, &musig_session[i], signer_data[i], N_SIGNERS, NULL, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
if (!secp256k1_musig_partial_sign(ctx, &musig_session[i], &partial_sig[i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Communication round 3: Exchange partial signatures */
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
for (j = 0; j < N_SIGNERS; j++) {
|
||||
/* To check whether signing was successful, it suffices to either verify
|
||||
* the the combined signature with the combined public key using
|
||||
* secp256k1_schnorrsig_verify, or verify all partial signatures of all
|
||||
* signers individually. Verifying the combined signature is cheaper but
|
||||
* verifying the individual partial signatures has the advantage that it
|
||||
* can be used to determine which of the partial signatures are invalid
|
||||
* (if any), i.e., which of the partial signatures cause the combined
|
||||
* signature to be invalid and thus the protocol run to fail. It's also
|
||||
* fine to first verify the combined sig, and only verify the individual
|
||||
* sigs if it does not work.
|
||||
*/
|
||||
if (!secp256k1_musig_partial_sig_verify(ctx, &musig_session[i], &signer_data[i][j], &partial_sig[j], &pubkeys[j])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig64, partial_sig, N_SIGNERS);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
secp256k1_context* ctx;
|
||||
int i;
|
||||
unsigned char seckeys[N_SIGNERS][32];
|
||||
secp256k1_xonly_pubkey pubkeys[N_SIGNERS];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
unsigned char msg[32] = "this_could_be_the_hash_of_a_msg!";
|
||||
unsigned char sig[64];
|
||||
|
||||
/* Create a context for signing and verification */
|
||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
printf("Creating key pairs......");
|
||||
for (i = 0; i < N_SIGNERS; i++) {
|
||||
if (!create_keypair(ctx, seckeys[i], &pubkeys[i])) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Combining public keys...");
|
||||
if (!secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk, NULL, pubkeys, N_SIGNERS)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Signing message.........");
|
||||
if (!sign(ctx, seckeys, pubkeys, msg, sig)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
printf("Verifying signature.....");
|
||||
if (!secp256k1_schnorrsig_verify(ctx, sig, msg, &combined_pk)) {
|
||||
printf("FAILED\n");
|
||||
return 1;
|
||||
}
|
||||
printf("ok\n");
|
||||
secp256k1_context_destroy(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
702
src/modules/musig/main_impl.h
Normal file
702
src/modules/musig/main_impl.h
Normal file
@@ -0,0 +1,702 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2018 Andrew Poelstra, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_MUSIG_MAIN_
|
||||
#define _SECP256K1_MODULE_MUSIG_MAIN_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_musig.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* Computes ell = SHA256(pk[0], ..., pk[np-1]) */
|
||||
static int secp256k1_musig_compute_ell(const secp256k1_context *ctx, unsigned char *ell, const secp256k1_xonly_pubkey *pk, size_t np) {
|
||||
secp256k1_sha256 sha;
|
||||
size_t i;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
for (i = 0; i < np; i++) {
|
||||
unsigned char ser[32];
|
||||
if (!secp256k1_xonly_pubkey_serialize(ctx, ser, &pk[i])) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha, ser, 32);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, ell);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("MuSig coefficient")||SHA256("MuSig coefficient"). */
|
||||
static void secp256k1_musig_sha256_init_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
|
||||
sha->s[0] = 0x0fd0690cul;
|
||||
sha->s[1] = 0xfefeae97ul;
|
||||
sha->s[2] = 0x996eac7ful;
|
||||
sha->s[3] = 0x5c30d864ul;
|
||||
sha->s[4] = 0x8c4a0573ul;
|
||||
sha->s[5] = 0xaca1a22ful;
|
||||
sha->s[6] = 0x6f43b801ul;
|
||||
sha->s[7] = 0x85ce27cdul;
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* Compute r = SHA256(ell, idx). The four bytes of idx are serialized least significant byte first. */
|
||||
static void secp256k1_musig_coefficient(secp256k1_scalar *r, const unsigned char *ell, uint32_t idx) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char buf[32];
|
||||
size_t i;
|
||||
|
||||
secp256k1_musig_sha256_init_tagged(&sha);
|
||||
secp256k1_sha256_write(&sha, ell, 32);
|
||||
/* We're hashing the index of the signer instead of its public key as specified
|
||||
* in the MuSig paper. This reduces the total amount of data that needs to be
|
||||
* hashed.
|
||||
* Additionally, it prevents creating identical musig_coefficients for identical
|
||||
* public keys. A participant Bob could choose his public key to be the same as
|
||||
* Alice's, then replay Alice's messages (nonce and partial signature) to create
|
||||
* a valid partial signature. This is not a problem for MuSig per se, but could
|
||||
* result in subtle issues with protocols building on threshold signatures.
|
||||
* With the assumption that public keys are unique, hashing the index is
|
||||
* equivalent to hashing the public key. Because the public key can be
|
||||
* identified by the index given the ordered list of public keys (included in
|
||||
* ell), the index is just a different encoding of the public key.*/
|
||||
for (i = 0; i < sizeof(uint32_t); i++) {
|
||||
unsigned char c = idx;
|
||||
secp256k1_sha256_write(&sha, &c, 1);
|
||||
idx >>= 8;
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_scalar_set_b32(r, buf, NULL);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const secp256k1_context *ctx;
|
||||
unsigned char ell[32];
|
||||
const secp256k1_xonly_pubkey *pks;
|
||||
} secp256k1_musig_pubkey_combine_ecmult_data;
|
||||
|
||||
/* Callback for batch EC multiplication to compute ell_0*P0 + ell_1*P1 + ... */
|
||||
static int secp256k1_musig_pubkey_combine_callback(secp256k1_scalar *sc, secp256k1_ge *pt, size_t idx, void *data) {
|
||||
secp256k1_musig_pubkey_combine_ecmult_data *ctx = (secp256k1_musig_pubkey_combine_ecmult_data *) data;
|
||||
secp256k1_musig_coefficient(sc, ctx->ell, idx);
|
||||
return secp256k1_xonly_pubkey_load(ctx->ctx, pt, &ctx->pks[idx]);
|
||||
}
|
||||
|
||||
static void secp256k1_musig_signers_init(secp256k1_musig_session_signer_data *signers, uint32_t n_signers) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < n_signers; i++) {
|
||||
memset(&signers[i], 0, sizeof(signers[i]));
|
||||
signers[i].index = i;
|
||||
signers[i].present = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint64_t pre_session_magic = 0xf4adbbdf7c7dd304UL;
|
||||
|
||||
int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const secp256k1_xonly_pubkey *pubkeys, size_t n_pubkeys) {
|
||||
secp256k1_musig_pubkey_combine_ecmult_data ecmult_data;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_ge pkp;
|
||||
int pk_parity;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(combined_pk != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(pubkeys != NULL);
|
||||
ARG_CHECK(n_pubkeys > 0);
|
||||
|
||||
ecmult_data.ctx = ctx;
|
||||
ecmult_data.pks = pubkeys;
|
||||
if (!secp256k1_musig_compute_ell(ctx, ecmult_data.ell, pubkeys, n_pubkeys)) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &pkj, NULL, secp256k1_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej(&pkp, &pkj);
|
||||
secp256k1_fe_normalize(&pkp.y);
|
||||
pk_parity = secp256k1_extrakeys_ge_even_y(&pkp);
|
||||
secp256k1_xonly_pubkey_save(combined_pk, &pkp);
|
||||
|
||||
if (pre_session != NULL) {
|
||||
pre_session->magic = pre_session_magic;
|
||||
memcpy(pre_session->pk_hash, ecmult_data.ell, 32);
|
||||
pre_session->pk_parity = pk_parity;
|
||||
pre_session->is_tweaked = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_musig_pre_session *pre_session, secp256k1_pubkey *output_pubkey, const secp256k1_xonly_pubkey *internal_pubkey, const unsigned char *tweak32) {
|
||||
secp256k1_ge pk;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(pre_session != NULL);
|
||||
ARG_CHECK(pre_session->magic == pre_session_magic);
|
||||
/* This function can only be called once because otherwise signing would not
|
||||
* succeed */
|
||||
ARG_CHECK(pre_session->is_tweaked == 0);
|
||||
|
||||
pre_session->internal_key_parity = pre_session->pk_parity;
|
||||
if(!secp256k1_xonly_pubkey_tweak_add(ctx, output_pubkey, internal_pubkey, tweak32)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(pre_session->tweak, tweak32, 32);
|
||||
pre_session->is_tweaked = 1;
|
||||
|
||||
if (!secp256k1_pubkey_load(ctx, &pk, output_pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
pre_session->pk_parity = secp256k1_extrakeys_ge_even_y(&pk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const uint64_t session_magic = 0xd92e6fc1ee41b4cbUL;
|
||||
|
||||
int secp256k1_musig_session_init(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, size_t n_signers, size_t my_index, const unsigned char *seckey) {
|
||||
unsigned char combined_ser[32];
|
||||
int overflow;
|
||||
secp256k1_scalar secret;
|
||||
secp256k1_scalar mu;
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_gej pj;
|
||||
secp256k1_ge p;
|
||||
unsigned char nonce_ser[32];
|
||||
size_t nonce_ser_size = sizeof(nonce_ser);
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(signers != NULL);
|
||||
ARG_CHECK(nonce_commitment32 != NULL);
|
||||
ARG_CHECK(session_id32 != NULL);
|
||||
ARG_CHECK(combined_pk != NULL);
|
||||
ARG_CHECK(pre_session != NULL);
|
||||
ARG_CHECK(pre_session->magic == pre_session_magic);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
|
||||
ARG_CHECK(n_signers > 0);
|
||||
ARG_CHECK(n_signers <= UINT32_MAX);
|
||||
ARG_CHECK(my_index < n_signers);
|
||||
|
||||
memset(session, 0, sizeof(*session));
|
||||
|
||||
session->magic = session_magic;
|
||||
if (msg32 != NULL) {
|
||||
memcpy(session->msg, msg32, 32);
|
||||
session->is_msg_set = 1;
|
||||
} else {
|
||||
session->is_msg_set = 0;
|
||||
}
|
||||
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
|
||||
session->pre_session = *pre_session;
|
||||
session->has_secret_data = 1;
|
||||
session->n_signers = (uint32_t) n_signers;
|
||||
secp256k1_musig_signers_init(signers, session->n_signers);
|
||||
|
||||
/* Compute secret key */
|
||||
secp256k1_scalar_set_b32(&secret, seckey, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&secret);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_musig_coefficient(&mu, session->pre_session.pk_hash, (uint32_t) my_index);
|
||||
/* Compute the signer's public key point and determine if the secret is
|
||||
* negated before signing. That happens if if the signer's pubkey has an odd
|
||||
* Y coordinate XOR the MuSig-combined pubkey has an odd Y coordinate XOR
|
||||
* (if tweaked) the internal key has an odd Y coordinate.
|
||||
*
|
||||
* This can be seen by looking at the secret key belonging to `combined_pk`.
|
||||
* Let's define
|
||||
* P' := mu_0*|P_0| + ... + mu_n*|P_n| where P_i is the i-th public key
|
||||
* point x_i*G, mu_i is the i-th musig coefficient and |.| is a function
|
||||
* that normalizes a point to an even Y by negating if necessary similar to
|
||||
* secp256k1_extrakeys_ge_even_y. Then we have
|
||||
* P := |P'| + t*G where t is the tweak.
|
||||
* And the combined xonly public key is
|
||||
* |P| = x*G
|
||||
* where x = sum_i(b_i*mu_i*x_i) + b'*t
|
||||
* b' = -1 if P != |P|, 1 otherwise
|
||||
* b_i = -1 if (P_i != |P_i| XOR P' != |P'| XOR P != |P|) and 1
|
||||
* otherwise.
|
||||
*/
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret);
|
||||
secp256k1_ge_set_gej(&p, &pj);
|
||||
secp256k1_fe_normalize(&p.y);
|
||||
if((secp256k1_fe_is_odd(&p.y)
|
||||
+ session->pre_session.pk_parity
|
||||
+ (session->pre_session.is_tweaked
|
||||
&& session->pre_session.internal_key_parity))
|
||||
% 2 == 1) {
|
||||
secp256k1_scalar_negate(&secret, &secret);
|
||||
}
|
||||
secp256k1_scalar_mul(&secret, &secret, &mu);
|
||||
secp256k1_scalar_get_b32(session->seckey, &secret);
|
||||
|
||||
/* Compute secret nonce */
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, session_id32, 32);
|
||||
if (session->is_msg_set) {
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
}
|
||||
secp256k1_xonly_pubkey_serialize(ctx, combined_ser, combined_pk);
|
||||
secp256k1_sha256_write(&sha, combined_ser, 32);
|
||||
secp256k1_sha256_write(&sha, seckey, 32);
|
||||
secp256k1_sha256_finalize(&sha, session->secnonce);
|
||||
secp256k1_scalar_set_b32(&secret, session->secnonce, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&secret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute public nonce and commitment */
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &secret);
|
||||
secp256k1_ge_set_gej(&p, &pj);
|
||||
secp256k1_fe_normalize_var(&p.y);
|
||||
session->partial_nonce_parity = secp256k1_extrakeys_ge_even_y(&p);
|
||||
secp256k1_xonly_pubkey_save(&session->nonce, &p);
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_xonly_pubkey_serialize(ctx, nonce_ser, &session->nonce);
|
||||
secp256k1_sha256_write(&sha, nonce_ser, nonce_ser_size);
|
||||
secp256k1_sha256_finalize(&sha, nonce_commitment32);
|
||||
|
||||
session->round = 0;
|
||||
secp256k1_scalar_clear(&secret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce, const unsigned char *const *commitments, size_t n_commitments, const unsigned char *msg32) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char nonce_commitments_hash[32];
|
||||
size_t i;
|
||||
unsigned char nonce_ser[32];
|
||||
size_t nonce_ser_size = sizeof(nonce_ser);
|
||||
(void) ctx;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(session->magic == session_magic);
|
||||
ARG_CHECK(signers != NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
ARG_CHECK(commitments != NULL);
|
||||
|
||||
ARG_CHECK(session->round == 0);
|
||||
/* If the message was not set during initialization it must be set now. */
|
||||
ARG_CHECK(!(!session->is_msg_set && msg32 == NULL));
|
||||
/* The message can only be set once. */
|
||||
ARG_CHECK(!(session->is_msg_set && msg32 != NULL));
|
||||
ARG_CHECK(session->has_secret_data);
|
||||
ARG_CHECK(n_commitments == session->n_signers);
|
||||
for (i = 0; i < n_commitments; i++) {
|
||||
ARG_CHECK(commitments[i] != NULL);
|
||||
}
|
||||
|
||||
if (msg32 != NULL) {
|
||||
memcpy(session->msg, msg32, 32);
|
||||
session->is_msg_set = 1;
|
||||
}
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
for (i = 0; i < n_commitments; i++) {
|
||||
memcpy(signers[i].nonce_commitment, commitments[i], 32);
|
||||
secp256k1_sha256_write(&sha, commitments[i], 32);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, nonce_commitments_hash);
|
||||
memcpy(session->nonce_commitments_hash, nonce_commitments_hash, 32);
|
||||
|
||||
secp256k1_xonly_pubkey_serialize(ctx, nonce_ser, &session->nonce);
|
||||
memcpy(nonce, &nonce_ser, nonce_ser_size);
|
||||
session->round = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_session_init_verifier(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, const unsigned char *msg32, const secp256k1_xonly_pubkey *combined_pk, const secp256k1_musig_pre_session *pre_session, const unsigned char *const *commitments, size_t n_signers) {
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(signers != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(combined_pk != NULL);
|
||||
ARG_CHECK(pre_session != NULL);
|
||||
ARG_CHECK(pre_session->magic == pre_session_magic);
|
||||
ARG_CHECK(commitments != NULL);
|
||||
/* Check n_signers before checking commitments to allow testing the case where
|
||||
* n_signers is big without allocating the space. */
|
||||
ARG_CHECK(n_signers > 0);
|
||||
ARG_CHECK(n_signers <= UINT32_MAX);
|
||||
for (i = 0; i < n_signers; i++) {
|
||||
ARG_CHECK(commitments[i] != NULL);
|
||||
}
|
||||
(void) ctx;
|
||||
|
||||
memset(session, 0, sizeof(*session));
|
||||
|
||||
session->magic = session_magic;
|
||||
memcpy(&session->combined_pk, combined_pk, sizeof(*combined_pk));
|
||||
session->pre_session = *pre_session;
|
||||
session->n_signers = (uint32_t) n_signers;
|
||||
secp256k1_musig_signers_init(signers, session->n_signers);
|
||||
|
||||
session->pre_session = *pre_session;
|
||||
session->is_msg_set = 1;
|
||||
memcpy(session->msg, msg32, 32);
|
||||
session->has_secret_data = 0;
|
||||
|
||||
for (i = 0; i < n_signers; i++) {
|
||||
memcpy(signers[i].nonce_commitment, commitments[i], 32);
|
||||
}
|
||||
session->round = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_set_nonce(const secp256k1_context* ctx, secp256k1_musig_session_signer_data *signer, const unsigned char *nonce) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char commit[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(signer != NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, nonce, 32);
|
||||
secp256k1_sha256_finalize(&sha, commit);
|
||||
|
||||
if (memcmp(commit, signer->nonce_commitment, 32) != 0) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(&signer->nonce, nonce, sizeof(*nonce));
|
||||
if (!secp256k1_xonly_pubkey_parse(ctx, &signer->nonce, nonce)) {
|
||||
return 0;
|
||||
}
|
||||
signer->present = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signers, size_t n_signers, int *nonce_parity, const secp256k1_pubkey *adaptor) {
|
||||
secp256k1_gej combined_noncej;
|
||||
secp256k1_ge combined_noncep;
|
||||
secp256k1_ge noncep;
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char nonce_commitments_hash[32];
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(signers != NULL);
|
||||
ARG_CHECK(session->magic == session_magic);
|
||||
ARG_CHECK(session->round == 1);
|
||||
ARG_CHECK(n_signers == session->n_signers);
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_gej_set_infinity(&combined_noncej);
|
||||
for (i = 0; i < n_signers; i++) {
|
||||
if (!signers[i].present) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_write(&sha, signers[i].nonce_commitment, 32);
|
||||
secp256k1_xonly_pubkey_load(ctx, &noncep, &signers[i].nonce);
|
||||
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha, nonce_commitments_hash);
|
||||
/* If the signers' commitments changed between get_public_nonce and now we
|
||||
* have to abort because in that case they may have seen our nonce before
|
||||
* creating their commitment. That can happen if the signer_data given to
|
||||
* this function is different to the signer_data given to get_public_nonce.
|
||||
* */
|
||||
if (session->has_secret_data
|
||||
&& memcmp(session->nonce_commitments_hash, nonce_commitments_hash, 32) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add public adaptor to nonce */
|
||||
if (adaptor != NULL) {
|
||||
secp256k1_pubkey_load(ctx, &noncep, adaptor);
|
||||
secp256k1_gej_add_ge_var(&combined_noncej, &combined_noncej, &noncep, NULL);
|
||||
}
|
||||
|
||||
/* Negate nonce if Y coordinate is not square */
|
||||
secp256k1_ge_set_gej(&combined_noncep, &combined_noncej);
|
||||
secp256k1_fe_normalize_var(&combined_noncep.y);
|
||||
session->combined_nonce_parity = secp256k1_extrakeys_ge_even_y(&combined_noncep);
|
||||
if (nonce_parity != NULL) {
|
||||
*nonce_parity = session->combined_nonce_parity;
|
||||
}
|
||||
secp256k1_xonly_pubkey_save(&session->combined_nonce, &combined_noncep);
|
||||
session->round = 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_signature_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_signature* sig) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(out32 != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
memcpy(out32, sig->data, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_signature_parse(const secp256k1_context* ctx, secp256k1_musig_partial_signature* sig, const unsigned char *in32) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig != NULL);
|
||||
ARG_CHECK(in32 != NULL);
|
||||
memcpy(sig->data, in32, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute msghash = SHA256(combined_nonce, combined_pk, msg) */
|
||||
static void secp256k1_musig_compute_messagehash(const secp256k1_context *ctx, unsigned char *msghash, const secp256k1_musig_session *session) {
|
||||
unsigned char buf[32];
|
||||
secp256k1_ge rp;
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
VERIFY_CHECK(session->round >= 2);
|
||||
|
||||
secp256k1_schnorrsig_sha256_tagged(&sha);
|
||||
secp256k1_xonly_pubkey_load(ctx, &rp, &session->combined_nonce);
|
||||
secp256k1_fe_get_b32(buf, &rp.x);
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
|
||||
secp256k1_xonly_pubkey_serialize(ctx, buf, &session->combined_pk);
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
secp256k1_sha256_write(&sha, session->msg, 32);
|
||||
secp256k1_sha256_finalize(&sha, msghash);
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_musig_partial_signature *partial_sig) {
|
||||
unsigned char msghash[32];
|
||||
int overflow;
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_scalar e, k;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(partial_sig != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(session->magic == session_magic);
|
||||
ARG_CHECK(session->round == 2);
|
||||
ARG_CHECK(session->has_secret_data);
|
||||
|
||||
/* build message hash */
|
||||
secp256k1_musig_compute_messagehash(ctx, msghash, session);
|
||||
secp256k1_scalar_set_b32(&e, msghash, NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&sk, session->seckey, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&sk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&k, session->secnonce, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&k)) {
|
||||
secp256k1_scalar_clear(&sk);
|
||||
secp256k1_scalar_clear(&k);
|
||||
return 0;
|
||||
}
|
||||
if (session->partial_nonce_parity != session->combined_nonce_parity) {
|
||||
secp256k1_scalar_negate(&k, &k);
|
||||
}
|
||||
|
||||
/* Sign */
|
||||
secp256k1_scalar_mul(&e, &e, &sk);
|
||||
secp256k1_scalar_add(&e, &e, &k);
|
||||
secp256k1_scalar_get_b32(&partial_sig->data[0], &e);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
secp256k1_scalar_clear(&k);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs) {
|
||||
size_t i;
|
||||
secp256k1_scalar s;
|
||||
secp256k1_ge noncep;
|
||||
(void) ctx;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(partial_sigs != NULL);
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(session->magic == session_magic);
|
||||
ARG_CHECK(session->round == 2);
|
||||
|
||||
if (n_sigs != session->n_signers) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_clear(&s);
|
||||
for (i = 0; i < n_sigs; i++) {
|
||||
int overflow;
|
||||
secp256k1_scalar term;
|
||||
|
||||
secp256k1_scalar_set_b32(&term, partial_sigs[i].data, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&s, &s, &term);
|
||||
}
|
||||
|
||||
/* If there is a tweak then add (or subtract) `msghash` times `tweak` to `s`.*/
|
||||
if (session->pre_session.is_tweaked) {
|
||||
unsigned char msghash[32];
|
||||
secp256k1_scalar e, scalar_tweak;
|
||||
int overflow = 0;
|
||||
|
||||
secp256k1_musig_compute_messagehash(ctx, msghash, session);
|
||||
secp256k1_scalar_set_b32(&e, msghash, NULL);
|
||||
secp256k1_scalar_set_b32(&scalar_tweak, session->pre_session.tweak, &overflow);
|
||||
if (overflow || !secp256k1_eckey_privkey_tweak_mul(&e, &scalar_tweak)) {
|
||||
/* This mimics the behavior of secp256k1_ec_seckey_tweak_mul regarding
|
||||
* overflow and tweak being 0. */
|
||||
return 0;
|
||||
}
|
||||
if (session->pre_session.pk_parity) {
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
}
|
||||
secp256k1_scalar_add(&s, &s, &e);
|
||||
}
|
||||
|
||||
secp256k1_xonly_pubkey_load(ctx, &noncep, &session->combined_nonce);
|
||||
VERIFY_CHECK(!secp256k1_fe_is_odd(&noncep.y));
|
||||
secp256k1_fe_normalize(&noncep.x);
|
||||
secp256k1_fe_get_b32(&sig64[0], &noncep.x);
|
||||
secp256k1_scalar_get_b32(&sig64[32], &s);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_verify(const secp256k1_context* ctx, const secp256k1_musig_session *session, const secp256k1_musig_session_signer_data *signer, const secp256k1_musig_partial_signature *partial_sig, const secp256k1_xonly_pubkey *pubkey) {
|
||||
unsigned char msghash[32];
|
||||
secp256k1_scalar s;
|
||||
secp256k1_scalar e;
|
||||
secp256k1_scalar mu;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge pkp;
|
||||
secp256k1_ge rp;
|
||||
int overflow;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(session != NULL);
|
||||
ARG_CHECK(signer != NULL);
|
||||
ARG_CHECK(partial_sig != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
ARG_CHECK(session->magic == session_magic);
|
||||
ARG_CHECK(session->round == 2);
|
||||
ARG_CHECK(signer->present);
|
||||
|
||||
secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_musig_compute_messagehash(ctx, msghash, session);
|
||||
secp256k1_scalar_set_b32(&e, msghash, NULL);
|
||||
|
||||
/* Multiplying the messagehash by the musig coefficient is equivalent
|
||||
* to multiplying the signer's public key by the coefficient, except
|
||||
* much easier to do. */
|
||||
secp256k1_musig_coefficient(&mu, session->pre_session.pk_hash, signer->index);
|
||||
secp256k1_scalar_mul(&e, &e, &mu);
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &rp, &signer->nonce)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the MuSig-combined point has an odd Y coordinate, the signers will
|
||||
* sign for the negation of their individual xonly public key such that the
|
||||
* combined signature is valid for the MuSig aggregated xonly key. If the
|
||||
* MuSig-combined point was tweaked then `e` is negated if the combined key
|
||||
* has an odd Y coordinate XOR the internal key has an odd Y coordinate.*/
|
||||
if (session->pre_session.pk_parity
|
||||
!= (session->pre_session.is_tweaked
|
||||
&& session->pre_session.internal_key_parity)) {
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
}
|
||||
|
||||
/* Compute rj = s*G + (-e)*pkj */
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pkp, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&pkj, &pkp);
|
||||
secp256k1_ecmult(&ctx->ecmult_ctx, &rj, &pkj, &e, &s);
|
||||
|
||||
if (!session->combined_nonce_parity) {
|
||||
secp256k1_ge_neg(&rp, &rp);
|
||||
}
|
||||
secp256k1_gej_add_ge_var(&rj, &rj, &rp, NULL);
|
||||
|
||||
return secp256k1_gej_is_infinity(&rj);
|
||||
}
|
||||
|
||||
int secp256k1_musig_partial_sig_adapt(const secp256k1_context* ctx, secp256k1_musig_partial_signature *adaptor_sig, const secp256k1_musig_partial_signature *partial_sig, const unsigned char *sec_adaptor32, int nonce_parity) {
|
||||
secp256k1_scalar s;
|
||||
secp256k1_scalar t;
|
||||
int overflow;
|
||||
|
||||
(void) ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(adaptor_sig != NULL);
|
||||
ARG_CHECK(partial_sig != NULL);
|
||||
ARG_CHECK(sec_adaptor32 != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&s, partial_sig->data, &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&t, sec_adaptor32, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nonce_parity) {
|
||||
secp256k1_scalar_negate(&t, &t);
|
||||
}
|
||||
|
||||
secp256k1_scalar_add(&s, &s, &t);
|
||||
secp256k1_scalar_get_b32(adaptor_sig->data, &s);
|
||||
secp256k1_scalar_clear(&t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_musig_extract_secret_adaptor(const secp256k1_context* ctx, unsigned char *sec_adaptor32, const unsigned char *sig64, const secp256k1_musig_partial_signature *partial_sigs, size_t n_partial_sigs, int nonce_parity) {
|
||||
secp256k1_scalar t;
|
||||
secp256k1_scalar s;
|
||||
int overflow;
|
||||
size_t i;
|
||||
|
||||
(void) ctx;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(sec_adaptor32 != NULL);
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(partial_sigs != NULL);
|
||||
|
||||
secp256k1_scalar_set_b32(&t, &sig64[32], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_negate(&t, &t);
|
||||
|
||||
for (i = 0; i < n_partial_sigs; i++) {
|
||||
secp256k1_scalar_set_b32(&s, partial_sigs[i].data, &overflow);
|
||||
if (overflow) {
|
||||
secp256k1_scalar_clear(&t);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&t, &t, &s);
|
||||
}
|
||||
|
||||
if (!nonce_parity) {
|
||||
secp256k1_scalar_negate(&t, &t);
|
||||
}
|
||||
secp256k1_scalar_get_b32(sec_adaptor32, &t);
|
||||
secp256k1_scalar_clear(&t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
198
src/modules/musig/musig.md
Normal file
198
src/modules/musig/musig.md
Normal file
@@ -0,0 +1,198 @@
|
||||
MuSig - Rogue-Key-Resistant Multisignatures Module
|
||||
===========================
|
||||
|
||||
This module implements the MuSig [1] multisignature scheme. The majority of
|
||||
the module is an API designed to be used by signing or auditing participants
|
||||
in a multisignature scheme. This involves a somewhat complex state machine
|
||||
and significant effort has been taken to prevent accidental misuse of the
|
||||
API in ways that could lead to accidental signatures or loss of key material.
|
||||
|
||||
The resulting signatures are valid Schnorr signatures as described in [2].
|
||||
|
||||
# Theory
|
||||
|
||||
In MuSig all signers contribute key material to a single signing key,
|
||||
using the equation
|
||||
|
||||
P = sum_i µ_i * P_i
|
||||
|
||||
where `P_i` is the public key of the `i`th signer and `µ_i` is a so-called
|
||||
_MuSig coefficient_ computed according to the following equation
|
||||
|
||||
L = H(P_1 || P_2 || ... || P_n)
|
||||
µ_i = H(L || i)
|
||||
|
||||
where H is a hash function modelled as a random oracle.
|
||||
|
||||
To produce a multisignature `(s, R)` on a message `m` using verification key
|
||||
`P`, signers act as follows:
|
||||
|
||||
1. Each computes a nonce, or ephemeral keypair, `(k_i, R_i)`. Every signer
|
||||
communicates `H(R_i)` to every participant (both signers and auditors).
|
||||
2. Upon receipt of every `H(R_i)`, each signer communicates `R_i` to every
|
||||
participant. The recipients check that each `R_i` is consistent with the
|
||||
previously-communicated hash.
|
||||
3. Each signer computes a combined nonce
|
||||
`R = sum_i R_i`
|
||||
and shared challenge
|
||||
`e = H(R || P || m)`
|
||||
and partial signature
|
||||
`s_i = k_i + µ_i*x_i*e`
|
||||
where `x_i` is the secret key corresponding to `P_i`.
|
||||
|
||||
The complete signature is then the `(s, R)` where `s = sum_i s_i` and `R = sum_i R_i`.
|
||||
|
||||
# API Usage
|
||||
|
||||
The following sections describe use of our API, and are mirrored in code in `src/modules/musig/example.c`.
|
||||
|
||||
It is essential to security that signers use a unique uniformly random nonce for all
|
||||
signing sessions, and that they do not reuse these nonces even in the case that a
|
||||
signing session fails to complete. To that end, all signing state is encapsulated
|
||||
in the data structure `secp256k1_musig_session`. The API does not expose any
|
||||
functionality to serialize or deserialize this structure; it is designed to exist
|
||||
only in memory.
|
||||
|
||||
Users who need to persist this structure must take additional security measures
|
||||
which cannot be enforced by a C API. Some guidance is provided in the documentation
|
||||
for this data structure in `include/secp256k1_musig.h`.
|
||||
|
||||
## Key Generation
|
||||
|
||||
To use MuSig, users must first compute their combined public key `P`, which is
|
||||
suitable for use on a blockchain or other public key repository. They do this
|
||||
by calling `secp256k1_musig_pubkey_combine`.
|
||||
|
||||
This function takes as input a list of public keys `P_i` in the argument
|
||||
`pubkeys`. It outputs the combined public key `P` in the out-pointer `combined_pk`
|
||||
and hash `L` in the out-pointer `pk_hash32`, if this pointer is non-NULL.
|
||||
|
||||
## Signing
|
||||
|
||||
A participant who wishes to sign a message (as opposed to observing/auditing the
|
||||
signature process, which is also a supported mode) acts as follows.
|
||||
|
||||
### Signing Participant
|
||||
|
||||
1. The signer starts the session by calling `secp256k1_musig_session_init`.
|
||||
This function outputs
|
||||
- an initialized session state in the out-pointer `session`
|
||||
- an array of initialized signer data in the out-pointer `signers`
|
||||
- a commitment `H(R_i)` to a nonce in the out-pointer `nonce_commitment32`
|
||||
It takes as input
|
||||
- a unique session ID `session_id32`
|
||||
- (optionally) a message to be signed `msg32`
|
||||
- the combined public key output from `secp256k1_musig_pubkey_combine`
|
||||
- the public key hash output from `secp256k1_musig_pubkey_combine`
|
||||
- the signer's index `i` `my_index`
|
||||
- the signer's secret key `seckey`
|
||||
2. The signer then communicates `H(R_i)` to all other signers, and receives
|
||||
commitments `H(R_j)` from all other signers `j`. These hashes are simply
|
||||
length-32 byte arrays which can be communicated however is communicated.
|
||||
3. Once all signers nonce commitments have been received, the signer records
|
||||
these commitments with the function `secp256k1_musig_session_get_public_nonce`.
|
||||
If the signer did not provide a message to `secp256k1_musig_session_init`,
|
||||
a message must be provided now.
|
||||
This function updates in place
|
||||
- the session state `session`
|
||||
- the array of signer data `signers`
|
||||
taking in as input the list of commitments `commitments` and outputting the
|
||||
signer's public nonce `R_i` in the out-pointer `nonce`.
|
||||
4. The signer then communicates `R_i` to all other signers, and receives `R_j`
|
||||
from each signer `j`. On receipt of a nonce `R_j` he calls the function
|
||||
`secp256k1_musig_set_nonce` to record this fact. This function checks that
|
||||
the received nonce is consistent with the previously-received nonce and will
|
||||
return 0 in this case. The signer must also call this function with his own
|
||||
nonce and his own index `i`.
|
||||
These nonces `R_i` are secp256k1 public keys; they should be serialized using
|
||||
`secp256k1_ec_pubkey_serialize` and parsed with `secp256k1_ec_pubkey_parse`.
|
||||
5. Once all nonces have been exchanged in this way, signers are able to compute
|
||||
their partial signatures. They do so by calling `secp256k1_musig_session_combine_nonces`
|
||||
which updates in place
|
||||
- the session state `session`
|
||||
- the array of signer data `signers`
|
||||
It outputs an auxiliary integer `nonce_is_negated` and has an auxiliary input
|
||||
`adaptor`. Both of these may be set to NULL for ordinary signing purposes.
|
||||
6. The signer computes a partial signature `s_i` using the function
|
||||
`secp256k1_musig_partial_sign` which takes the session state as input and
|
||||
partial signature as output.
|
||||
7. The signer then communicates the partial signature `s_i` to all other signers, or
|
||||
to a central coordinator. These partial signatures should be serialized using
|
||||
`musig_partial_signature_serialize` and parsed using `musig_partial_signature_parse`.
|
||||
8. Each signer calls `secp256k1_musig_partial_sig_verify` on the other signers' partial
|
||||
signatures to verify their correctness. If only the validity of the final signature
|
||||
is important, not assigning blame, this step can be skipped.
|
||||
9. Any signer, or central coordinator, may combine the partial signatures to obtain
|
||||
a complete signature using `secp256k1_musig_partial_sig_combine`. This function takes
|
||||
a signing session and array of MuSig partial signatures, and outputs a single
|
||||
Schnorr signature.
|
||||
|
||||
### Non-signing Participant
|
||||
|
||||
A participant who wants to verify the signing process, i.e. check that nonce commitments
|
||||
are consistent and partial signatures are correct without contributing a partial signature,
|
||||
may do so using the above instructions except for the following changes:
|
||||
|
||||
1. A signing session should be produced using `musig_session_init_verifier`
|
||||
rather than `musig_session_init`; this function takes no secret data or
|
||||
signer index.
|
||||
2. The participant receives nonce commitments, public nonces and partial signatures,
|
||||
but does not produce these values. Therefore `secp256k1_musig_session_get_public_nonce`
|
||||
and `secp256k1_musig_partial_sign` are not called.
|
||||
|
||||
### Verifier
|
||||
|
||||
The final signature is simply a valid Schnorr signature using the combined public key. It
|
||||
can be verified using the `secp256k1_schnorrsig_verify` with the correct message and
|
||||
public key output from `secp256k1_musig_pubkey_combine`.
|
||||
|
||||
## Atomic Swaps
|
||||
|
||||
The signing API supports the production of "adaptor signatures", modified partial signatures
|
||||
which are offset by an auxiliary secret known to one party. That is,
|
||||
1. One party generates a (secret) adaptor `t` with corresponding (public) adaptor `T = t*G`.
|
||||
2. When combining nonces, each party adds `T` to the total nonce used in the signature.
|
||||
3. The party who knows `t` must "adapt" their partial signature with `t` to complete the
|
||||
signature.
|
||||
4. Any party who sees both the final signature and the original partial signatures
|
||||
can compute `t`.
|
||||
|
||||
Using these adaptor signatures, two 2-of-2 MuSig signing protocols can be executed in
|
||||
parallel such that one party's partial signatures are made atomic. That is, when the other
|
||||
party learns one partial signature, she automatically learns the other. This has applications
|
||||
in cross-chain atomic swaps.
|
||||
|
||||
Such a protocol can be executed as follows. Consider two participants, Alice and Bob, who
|
||||
are simultaneously producing 2-of-2 multisignatures for two blockchains A and B. They act
|
||||
as follows.
|
||||
|
||||
1. Before the protocol begins, Bob chooses a 32-byte auxiliary secret `t` at random and
|
||||
computes a corresponding public point `T` by calling `secp256k1_ec_pubkey_create`.
|
||||
He communicates `T` to Alice.
|
||||
2. Together, the parties execute steps 1-4 of the signing protocol above.
|
||||
3. At step 5, when combining the two parties' public nonces, both parties call
|
||||
`secp256k1_musig_session_combine_nonces` with `adaptor` set to `T` and `nonce_is_negated`
|
||||
set to a non-NULL pointer to int.
|
||||
4. Steps 6 and 7 proceed as before. Step 8, verifying the partial signatures, is now
|
||||
essential to the security of the protocol and must not be omitted!
|
||||
|
||||
The above steps are executed identically for both signing sessions. However, step 9 will
|
||||
not work as before, since the partial signatures will not add up to a valid total signature.
|
||||
Additional steps must be taken, and it is at this point that the two signing sessions
|
||||
diverge. From here on we consider "Session A" which benefits Alice (e.g. which sends her
|
||||
coins) and "Session B" which benefits Bob (e.g. which sends him coins).
|
||||
|
||||
5. In Session B, Bob calls `secp256k1_musig_partial_sig_adapt` with his partial signature
|
||||
and `t`, to produce an adaptor signature. He can then call `secp256k1_musig_partial_sig_combine`
|
||||
with this adaptor signature and Alice's partial signature, to produce a complete
|
||||
signature for blockchain B.
|
||||
6. Alice reads this signature from blockchain B. She calls `secp256k1_musig_extract_secret_adaptor`,
|
||||
passing the complete signature along with her and Bob's partial signatures from Session B.
|
||||
This function outputs `t`, which until this point was only known to Bob.
|
||||
7. In Session A, Alice is now able to replicate Bob's action, calling
|
||||
`secp256k1_musig_partial_sig_adapt` with her own partial signature and `t`, ultimately
|
||||
producing a complete signature on blockchain A.
|
||||
|
||||
[1] https://eprint.iacr.org/2018/068
|
||||
[2] https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki
|
||||
|
||||
969
src/modules/musig/tests_impl.h
Normal file
969
src/modules/musig/tests_impl.h
Normal file
@@ -0,0 +1,969 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2018 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_MUSIG_TESTS_
|
||||
#define _SECP256K1_MODULE_MUSIG_TESTS_
|
||||
|
||||
#include "secp256k1_musig.h"
|
||||
|
||||
int secp256k1_xonly_pubkey_create(secp256k1_xonly_pubkey *pk, const unsigned char *seckey) {
|
||||
int ret;
|
||||
secp256k1_keypair keypair;
|
||||
ret = secp256k1_keypair_create(ctx, &keypair, seckey);
|
||||
ret &= secp256k1_keypair_xonly_pub(ctx, pk, NULL, &keypair);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Just a simple (non-adaptor, non-tweaked) 2-of-2 MuSig combine, sign, verify
|
||||
* test. */
|
||||
void musig_simple_test(secp256k1_scratch_space *scratch) {
|
||||
unsigned char sk[2][32];
|
||||
secp256k1_musig_session session[2];
|
||||
secp256k1_musig_session_signer_data signer0[2];
|
||||
secp256k1_musig_session_signer_data signer1[2];
|
||||
unsigned char nonce_commitment[2][32];
|
||||
unsigned char msg[32];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
unsigned char session_id[2][32];
|
||||
secp256k1_xonly_pubkey pk[2];
|
||||
const unsigned char *ncs[2];
|
||||
unsigned char public_nonce[3][32];
|
||||
secp256k1_musig_partial_signature partial_sig[2];
|
||||
unsigned char final_sig[64];
|
||||
|
||||
secp256k1_testrand256(session_id[0]);
|
||||
secp256k1_testrand256(session_id[1]);
|
||||
secp256k1_testrand256(sk[0]);
|
||||
secp256k1_testrand256(sk[1]);
|
||||
secp256k1_testrand256(msg);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_session_init(ctx, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
|
||||
CHECK(secp256k1_musig_session_init(ctx, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
|
||||
|
||||
ncs[0] = nonce_commitment[0];
|
||||
ncs[1] = nonce_commitment[1];
|
||||
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signer0, public_nonce[0], ncs, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signer1, public_nonce[1], ncs, 2, NULL) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signer0[0], public_nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signer0[1], public_nonce[1]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signer1[0], public_nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signer1[1], public_nonce[1]) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signer0, 2, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signer1, 2, NULL, NULL) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], final_sig, partial_sig, 2) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, &combined_pk) == 1);
|
||||
}
|
||||
|
||||
void musig_api_tests(secp256k1_scratch_space *scratch) {
|
||||
secp256k1_scratch_space *scratch_small;
|
||||
secp256k1_musig_session session[2];
|
||||
secp256k1_musig_session session_uninitialized;
|
||||
secp256k1_musig_session verifier_session;
|
||||
secp256k1_musig_session_signer_data signer0[2];
|
||||
secp256k1_musig_session_signer_data signer1[2];
|
||||
secp256k1_musig_session_signer_data verifier_signer_data[2];
|
||||
secp256k1_musig_partial_signature partial_sig[2];
|
||||
secp256k1_musig_partial_signature partial_sig_adapted[2];
|
||||
secp256k1_musig_partial_signature partial_sig_overflow;
|
||||
unsigned char final_sig[64];
|
||||
unsigned char final_sig_cmp[64];
|
||||
|
||||
unsigned char buf[32];
|
||||
unsigned char sk[2][32];
|
||||
unsigned char ones[32];
|
||||
unsigned char session_id[2][32];
|
||||
unsigned char nonce_commitment[2][32];
|
||||
int combined_nonce_parity;
|
||||
const unsigned char *ncs[2];
|
||||
unsigned char msg[32];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
secp256k1_musig_pre_session pre_session_uninitialized;
|
||||
secp256k1_xonly_pubkey pk[2];
|
||||
unsigned char tweak[32];
|
||||
|
||||
unsigned char sec_adaptor[32];
|
||||
unsigned char sec_adaptor1[32];
|
||||
secp256k1_pubkey adaptor;
|
||||
|
||||
/** setup **/
|
||||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
int ecount;
|
||||
|
||||
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
memset(ones, 0xff, 32);
|
||||
/* Simulate structs being uninitialized by setting it to 0s. We don't want
|
||||
* to produce undefined behavior by actually providing uninitialized
|
||||
* structs. */
|
||||
memset(&pre_session_uninitialized, 0, sizeof(pre_session_uninitialized));
|
||||
memset(&session_uninitialized, 0, sizeof(session_uninitialized));
|
||||
|
||||
secp256k1_testrand256(session_id[0]);
|
||||
secp256k1_testrand256(session_id[1]);
|
||||
secp256k1_testrand256(sk[0]);
|
||||
secp256k1_testrand256(sk[1]);
|
||||
secp256k1_testrand256(msg);
|
||||
secp256k1_testrand256(sec_adaptor);
|
||||
secp256k1_testrand256(tweak);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor) == 1);
|
||||
|
||||
|
||||
/** main test body **/
|
||||
|
||||
/* Key combination */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_pubkey_combine(none, scratch, &combined_pk, &pre_session, pk, 2) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(sign, scratch, &combined_pk, &pre_session, pk, 2) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(ecount == 2);
|
||||
/* pubkey_combine does not require a scratch space */
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(ecount == 2);
|
||||
/* A small scratch space works too, but will result in using an ineffecient algorithm */
|
||||
scratch_small = secp256k1_scratch_space_create(ctx, 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
secp256k1_scratch_space_destroy(ctx, scratch_small);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, &pre_session, pk, 2) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, NULL, pk, 2) == 1);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 2) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 0) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, NULL, 0) == 0);
|
||||
CHECK(ecount == 6);
|
||||
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
|
||||
/** Tweaking */
|
||||
ecount = 0;
|
||||
{
|
||||
secp256k1_xonly_pubkey tmp_internal_pk = combined_pk;
|
||||
secp256k1_pubkey tmp_output_pk;
|
||||
secp256k1_musig_pre_session tmp_pre_session = pre_session;
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(ctx, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1);
|
||||
/* Reset pre_session */
|
||||
tmp_pre_session = pre_session;
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(none, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(sign, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1);
|
||||
CHECK(ecount == 2);
|
||||
tmp_pre_session = pre_session;
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, NULL, &tmp_output_pk, &tmp_internal_pk, tweak) == 0);
|
||||
CHECK(ecount == 3);
|
||||
/* Uninitialized pre_session */
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &pre_session_uninitialized, &tmp_output_pk, &tmp_internal_pk, tweak) == 0);
|
||||
CHECK(ecount == 4);
|
||||
/* Using the same pre_session twice does not work */
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, tweak) == 0);
|
||||
CHECK(ecount == 5);
|
||||
tmp_pre_session = pre_session;
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, NULL, &tmp_internal_pk, tweak) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, NULL, tweak) == 0);
|
||||
CHECK(ecount == 7);
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, NULL) == 0);
|
||||
CHECK(ecount == 8);
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(vrfy, &tmp_pre_session, &tmp_output_pk, &tmp_internal_pk, ones) == 0);
|
||||
CHECK(ecount == 8);
|
||||
}
|
||||
|
||||
/** Session creation **/
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_session_init(none, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_session_init(vrfy, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_session_init(sign, NULL, signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], NULL, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, NULL, session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], NULL, msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, NULL, &pre_session, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 7);
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, NULL, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 8);
|
||||
/* Uninitialized pre_session */
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session_uninitialized, 2, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 9);
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 0, 0, sk[0]) == 0);
|
||||
CHECK(ecount == 10);
|
||||
/* If more than UINT32_MAX fits in a size_t, test that session_init
|
||||
* rejects n_signers that high. */
|
||||
if (SIZE_MAX > UINT32_MAX) {
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, ((size_t) UINT32_MAX) + 2, 0, sk[0]) == 0);
|
||||
}
|
||||
CHECK(ecount == 11);
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, NULL) == 0);
|
||||
CHECK(ecount == 12);
|
||||
/* secret key overflows */
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, ones) == 0);
|
||||
CHECK(ecount == 12);
|
||||
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
|
||||
CHECK(secp256k1_musig_session_init(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
|
||||
ncs[0] = nonce_commitment[0];
|
||||
ncs[1] = nonce_commitment[1];
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_musig_session_init_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, &pre_session, ncs, 2) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, &pre_session, ncs, 2) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, NULL, ncs, 2) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, NULL, 2) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 0) == 0);
|
||||
CHECK(ecount == 6);
|
||||
if (SIZE_MAX > UINT32_MAX) {
|
||||
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, ((size_t) UINT32_MAX) + 2) == 0);
|
||||
}
|
||||
CHECK(ecount == 7);
|
||||
CHECK(secp256k1_musig_session_init_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, &pre_session, ncs, 2) == 1);
|
||||
|
||||
/** Signing step 0 -- exchange nonce commitments */
|
||||
ecount = 0;
|
||||
{
|
||||
unsigned char nonce[32];
|
||||
secp256k1_musig_session session_0_tmp;
|
||||
|
||||
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
|
||||
|
||||
/* Can obtain public nonce after commitments have been exchanged; still can't sign */
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, nonce, ncs, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(none, &session_0_tmp, &partial_sig[0]) == 0);
|
||||
CHECK(ecount == 1);
|
||||
}
|
||||
|
||||
/** Signing step 1 -- exchange nonces */
|
||||
ecount = 0;
|
||||
{
|
||||
unsigned char public_nonce[3][32];
|
||||
secp256k1_musig_session session_0_tmp;
|
||||
|
||||
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, public_nonce[0], ncs, 2, NULL) == 1);
|
||||
CHECK(ecount == 0);
|
||||
/* Reset session */
|
||||
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(none, NULL, signer0, public_nonce[0], ncs, 2, NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
/* uninitialized session */
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_uninitialized, signer0, public_nonce[0], ncs, 2, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, NULL, public_nonce[0], ncs, 2, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, NULL, ncs, 2, NULL) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, public_nonce[0], NULL, 2, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
/* Number of commitments and number of signers are different */
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session_0_tmp, signer0, public_nonce[0], ncs, 1, NULL) == 0);
|
||||
CHECK(ecount == 6);
|
||||
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, public_nonce[0], ncs, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[1], signer1, public_nonce[1], ncs, 2, NULL) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_set_nonce(none, &signer0[0], public_nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], public_nonce[0]) == 0);
|
||||
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], public_nonce[1]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], public_nonce[1]) == 1);
|
||||
CHECK(ecount == 6);
|
||||
|
||||
CHECK(secp256k1_musig_set_nonce(none, NULL, public_nonce[0]) == 0);
|
||||
CHECK(ecount == 7);
|
||||
CHECK(secp256k1_musig_set_nonce(none, &signer1[0], NULL) == 0);
|
||||
CHECK(ecount == 8);
|
||||
|
||||
CHECK(secp256k1_musig_set_nonce(none, &signer1[0], public_nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(none, &signer1[1], public_nonce[1]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[0], public_nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(none, &verifier_signer_data[1], public_nonce[1]) == 1);
|
||||
|
||||
ecount = 0;
|
||||
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
|
||||
CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 2, &combined_nonce_parity, &adaptor) == 1);
|
||||
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
|
||||
CHECK(secp256k1_musig_session_combine_nonces(none, NULL, signer0, 2, &combined_nonce_parity, &adaptor) == 0);
|
||||
CHECK(ecount == 1);
|
||||
/* Uninitialized session */
|
||||
CHECK(secp256k1_musig_session_combine_nonces(none, &session_uninitialized, signer0, 2, &combined_nonce_parity, &adaptor) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, NULL, 2, &combined_nonce_parity, &adaptor) == 0);
|
||||
CHECK(ecount == 3);
|
||||
/* Number of signers differs from number during intialization */
|
||||
CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 1, &combined_nonce_parity, &adaptor) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 2, NULL, &adaptor) == 1);
|
||||
CHECK(ecount == 4);
|
||||
memcpy(&session_0_tmp, &session[0], sizeof(session_0_tmp));
|
||||
CHECK(secp256k1_musig_session_combine_nonces(none, &session_0_tmp, signer0, 2, &combined_nonce_parity, NULL) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_session_combine_nonces(none, &session[0], signer0, 2, &combined_nonce_parity, &adaptor) == 1);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(none, &session[1], signer0, 2, &combined_nonce_parity, &adaptor) == 1);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(none, &verifier_session, verifier_signer_data, 2, &combined_nonce_parity, &adaptor) == 1);
|
||||
}
|
||||
|
||||
/** Signing step 2 -- partial signatures */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1);
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_musig_partial_sign(none, NULL, &partial_sig[0]) == 0);
|
||||
CHECK(ecount == 1);
|
||||
/* Uninitialized session */
|
||||
CHECK(secp256k1_musig_partial_sign(none, &session_uninitialized, &partial_sig[0]) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_partial_sign(none, &session[0], NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(none, &session[1], &partial_sig[1]) == 1);
|
||||
/* observer can't sign */
|
||||
CHECK(secp256k1_musig_partial_sign(none, &verifier_session, &partial_sig[2]) == 0);
|
||||
CHECK(ecount == 4);
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_partial_signature_serialize(none, buf, &partial_sig[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_signature_serialize(none, NULL, &partial_sig[0]) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_partial_signature_serialize(none, buf, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig[0], buf) == 1);
|
||||
CHECK(secp256k1_musig_partial_signature_parse(none, NULL, buf) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig[0], NULL) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_partial_signature_parse(none, &partial_sig_overflow, ones) == 1);
|
||||
|
||||
/** Partial signature verification */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_partial_sig_verify(none, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(sign, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[1], &pk[0]) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, NULL, &signer0[0], &partial_sig[0], &pk[0]) == 0);
|
||||
CHECK(ecount == 3);
|
||||
/* Unitialized session */
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session_uninitialized, &signer0[0], &partial_sig[0], &pk[0]) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], NULL, &partial_sig[0], &pk[0]) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], NULL, &pk[0]) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig_overflow, &pk[0]) == 0);
|
||||
CHECK(ecount == 6);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], NULL) == 0);
|
||||
CHECK(ecount == 7);
|
||||
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[0], &partial_sig[0], &pk[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[1], &signer1[0], &partial_sig[0], &pk[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[0], &signer0[1], &partial_sig[1], &pk[1]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &session[1], &signer1[1], &partial_sig[1], &pk[1]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[0], &partial_sig[0], &pk[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(vrfy, &verifier_session, &verifier_signer_data[1], &partial_sig[1], &pk[1]) == 1);
|
||||
CHECK(ecount == 7);
|
||||
|
||||
/** Adaptor signature verification */
|
||||
memcpy(&partial_sig_adapted[1], &partial_sig[1], sizeof(partial_sig_adapted[1]));
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], sec_adaptor, combined_nonce_parity) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_adapt(none, NULL, &partial_sig[0], sec_adaptor, 0) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], NULL, sec_adaptor, 0) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig_overflow, sec_adaptor, combined_nonce_parity) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], NULL, 0) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_partial_sig_adapt(none, &partial_sig_adapted[0], &partial_sig[0], ones, combined_nonce_parity) == 0);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
/** Signing combining and verification */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig_cmp, partial_sig_adapted, 2) == 1);
|
||||
CHECK(memcmp(final_sig, final_sig_cmp, sizeof(final_sig)) == 0);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig_cmp, partial_sig_adapted, 2) == 1);
|
||||
CHECK(memcmp(final_sig, final_sig_cmp, sizeof(final_sig)) == 0);
|
||||
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, NULL, final_sig, partial_sig_adapted, 2) == 0);
|
||||
CHECK(ecount == 1);
|
||||
/* Unitialized session */
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session_uninitialized, final_sig, partial_sig_adapted, 2) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, NULL, 2) == 0);
|
||||
CHECK(ecount == 4);
|
||||
{
|
||||
secp256k1_musig_partial_signature partial_sig_tmp[2];
|
||||
partial_sig_tmp[0] = partial_sig_adapted[0];
|
||||
partial_sig_tmp[1] = partial_sig_overflow;
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_tmp, 2) == 0);
|
||||
}
|
||||
CHECK(ecount == 4);
|
||||
/* Wrong number of partial sigs */
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 1) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], final_sig, partial_sig_adapted, 2) == 1);
|
||||
CHECK(ecount == 4);
|
||||
|
||||
CHECK(secp256k1_schnorrsig_verify(vrfy, final_sig, msg, &combined_pk) == 1);
|
||||
|
||||
/** Secret adaptor can be extracted from signature */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 2, combined_nonce_parity) == 1);
|
||||
CHECK(memcmp(sec_adaptor, sec_adaptor1, 32) == 0);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, NULL, final_sig, partial_sig, 2, 0) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, NULL, partial_sig, 2, 0) == 0);
|
||||
CHECK(ecount == 2);
|
||||
{
|
||||
unsigned char final_sig_tmp[64];
|
||||
memcpy(final_sig_tmp, final_sig, sizeof(final_sig_tmp));
|
||||
memcpy(&final_sig_tmp[32], ones, 32);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig_tmp, partial_sig, 2, combined_nonce_parity) == 0);
|
||||
}
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, NULL, 2, 0) == 0);
|
||||
CHECK(ecount == 3);
|
||||
{
|
||||
secp256k1_musig_partial_signature partial_sig_tmp[2];
|
||||
partial_sig_tmp[0] = partial_sig[0];
|
||||
partial_sig_tmp[1] = partial_sig_overflow;
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig_tmp, 2, combined_nonce_parity) == 0);
|
||||
}
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 0, 0) == 1);
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(none, sec_adaptor1, final_sig, partial_sig, 2, 1) == 1);
|
||||
|
||||
/** cleanup **/
|
||||
memset(&session, 0, sizeof(session));
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(vrfy);
|
||||
}
|
||||
|
||||
/* Initializes two sessions, one use the given parameters (session_id,
|
||||
* nonce_commitments, etc.) except that `session_tmp` uses new signers with different
|
||||
* public keys. The point of this test is to call `musig_session_get_public_nonce`
|
||||
* with signers from `session_tmp` who have different public keys than the correct
|
||||
* ones and return the resulting messagehash. This should not result in a different
|
||||
* messagehash because the public keys of the signers are only used during session
|
||||
* initialization. */
|
||||
void musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256k1_xonly_pubkey *pks, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, const unsigned char * const *nonce_commitments, unsigned char *msg, unsigned char *nonce_other, unsigned char *sk, unsigned char *session_id) {
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_session session_tmp;
|
||||
unsigned char nonce_commitment[32];
|
||||
secp256k1_musig_session_signer_data signers[2];
|
||||
secp256k1_musig_session_signer_data signers_tmp[2];
|
||||
unsigned char sk_dummy[32];
|
||||
secp256k1_xonly_pubkey pks_tmp[2];
|
||||
secp256k1_xonly_pubkey combined_pk_tmp;
|
||||
secp256k1_musig_pre_session pre_session_tmp;
|
||||
unsigned char nonce[32];
|
||||
|
||||
/* Set up signers with different public keys */
|
||||
secp256k1_testrand256(sk_dummy);
|
||||
pks_tmp[0] = pks[0];
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pks_tmp[1], sk_dummy) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, &pre_session_tmp, pks_tmp, 2) == 1);
|
||||
CHECK(secp256k1_musig_session_init(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, &pre_session_tmp, 2, 1, sk_dummy) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 0, sk) == 1);
|
||||
CHECK(memcmp(nonce_commitment, nonce_commitments[1], 32) == 0);
|
||||
/* Call get_public_nonce with different signers than the signers the session was
|
||||
* initialized with. */
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session_tmp, signers, nonce, nonce_commitments, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers_tmp, nonce, nonce_commitments, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
|
||||
|
||||
secp256k1_musig_compute_messagehash(ctx, msghash, &session);
|
||||
}
|
||||
|
||||
/* Creates a new session (with a different session id) and tries to use that session
|
||||
* to combine nonces with given signers_other. This should fail, because the nonce
|
||||
* commitments of signers_other do not match the nonce commitments the new session
|
||||
* was initialized with. If do_test is 0, the correct signers are being used and
|
||||
* therefore the function should return 1. */
|
||||
int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, unsigned char *nonce_commitment_other, unsigned char *nonce_other, unsigned char *msg, unsigned char *sk, secp256k1_musig_session_signer_data *signers_other, int do_test) {
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_session_signer_data signers[2];
|
||||
secp256k1_musig_session_signer_data *signers_to_use;
|
||||
unsigned char nonce_commitment[32];
|
||||
unsigned char session_id[32];
|
||||
unsigned char nonce[32];
|
||||
const unsigned char *ncs[2];
|
||||
|
||||
/* Initialize new signers */
|
||||
secp256k1_testrand256(session_id);
|
||||
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pre_session, 2, 1, sk) == 1);
|
||||
ncs[0] = nonce_commitment_other;
|
||||
ncs[1] = nonce_commitment;
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, nonce, ncs, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1);
|
||||
secp256k1_musig_session_combine_nonces(ctx, &session, signers_other, 2, NULL, NULL);
|
||||
if (do_test) {
|
||||
signers_to_use = signers_other;
|
||||
} else {
|
||||
signers_to_use = signers;
|
||||
}
|
||||
return secp256k1_musig_session_combine_nonces(ctx, &session, signers_to_use, 2, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Initializaes a session with the given session_id, signers, pk, msg etc.
|
||||
* parameters but without a message. Will test that the message must be
|
||||
* provided with `get_public_nonce`.
|
||||
*/
|
||||
void musig_state_machine_late_msg_test(secp256k1_xonly_pubkey *pks, secp256k1_xonly_pubkey *combined_pk, secp256k1_musig_pre_session *pre_session, unsigned char *nonce_commitment_other, unsigned char *nonce_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) {
|
||||
/* Create context for testing ARG_CHECKs by setting an illegal_callback. */
|
||||
secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
int ecount = 0;
|
||||
secp256k1_musig_session session;
|
||||
secp256k1_musig_session_signer_data signers[2];
|
||||
unsigned char nonce_commitment[32];
|
||||
const unsigned char *ncs[2];
|
||||
unsigned char nonce[32];
|
||||
secp256k1_musig_partial_signature partial_sig;
|
||||
|
||||
secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount);
|
||||
CHECK(secp256k1_musig_session_init(ctx, &session, signers, nonce_commitment, session_id, NULL, combined_pk, pre_session, 2, 1, sk) == 1);
|
||||
ncs[0] = nonce_commitment_other;
|
||||
ncs[1] = nonce_commitment;
|
||||
|
||||
/* Trying to get the nonce without providing a message fails. */
|
||||
CHECK(ecount == 0);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session, signers, nonce, ncs, 2, NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
|
||||
/* Providing a message should make get_public_nonce succeed. */
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, nonce, ncs, 2, msg) == 1);
|
||||
/* Trying to set the message again fails. */
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session, signers, nonce, ncs, 2, msg) == 0);
|
||||
CHECK(ecount == 2);
|
||||
|
||||
/* Check that it's working */
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], nonce) == 1);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session, &partial_sig));
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session, &signers[1], &partial_sig, &pks[1]));
|
||||
secp256k1_context_destroy(ctx_tmp);
|
||||
}
|
||||
|
||||
void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
|
||||
secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_VERIFY);
|
||||
size_t i;
|
||||
secp256k1_musig_session session[2];
|
||||
secp256k1_musig_session_signer_data signers0[2];
|
||||
secp256k1_musig_session_signer_data signers1[2];
|
||||
unsigned char nonce_commitment[2][32];
|
||||
unsigned char session_id[2][32];
|
||||
unsigned char msg[32];
|
||||
unsigned char sk[2][32];
|
||||
secp256k1_xonly_pubkey pk[2];
|
||||
secp256k1_xonly_pubkey combined_pk;
|
||||
secp256k1_musig_pre_session pre_session;
|
||||
unsigned char nonce[2][32];
|
||||
const unsigned char *ncs[2];
|
||||
secp256k1_musig_partial_signature partial_sig[2];
|
||||
unsigned char sig[64];
|
||||
unsigned char msghash1[32];
|
||||
unsigned char msghash2[32];
|
||||
int ecount;
|
||||
|
||||
secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount);
|
||||
ecount = 0;
|
||||
|
||||
/* Run state machine with the same objects twice to test that it's allowed to
|
||||
* reinitialize session and session_signer_data. */
|
||||
for (i = 0; i < 2; i++) {
|
||||
/* Setup */
|
||||
secp256k1_testrand256(session_id[0]);
|
||||
secp256k1_testrand256(session_id[1]);
|
||||
secp256k1_testrand256(sk[0]);
|
||||
secp256k1_testrand256(sk[1]);
|
||||
secp256k1_testrand256(msg);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk, &pre_session, pk, 2) == 1);
|
||||
CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, &combined_pk, &pre_session, 2, 0, sk[0]) == 1);
|
||||
CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, &combined_pk, &pre_session, 2, 1, sk[1]) == 1);
|
||||
/* Can't combine nonces unless we're through round 1 already */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx_tmp, &session[0], signers0, 2, NULL, NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
|
||||
/* Set nonce commitments */
|
||||
ncs[0] = nonce_commitment[0];
|
||||
ncs[1] = nonce_commitment[1];
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, nonce[0], ncs, 2, NULL) == 1);
|
||||
/* Calling the function again is not okay */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session[0], signers0, nonce[0], ncs, 2, NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
|
||||
/* Get nonce for signer 1 */
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, nonce[1], ncs, 2, NULL) == 1);
|
||||
|
||||
/* Set nonces */
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[0], nonce[0]) == 1);
|
||||
/* Can't set nonce that doesn't match nonce commitment */
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], nonce[0]) == 0);
|
||||
/* Set correct nonce */
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], nonce[1]) == 1);
|
||||
|
||||
/* Combine nonces */
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1);
|
||||
/* Not everyone is present from signer 1's view */
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 0);
|
||||
/* Make everyone present */
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[0], nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], nonce[1]) == 1);
|
||||
|
||||
/* Can't combine nonces from signers of a different session */
|
||||
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, &pre_session, nonce_commitment[0], nonce[0], msg, sk[1], signers1, 1) == 0);
|
||||
CHECK(musig_state_machine_diff_signers_combine_nonce_test(&combined_pk, &pre_session, nonce_commitment[0], nonce[0], msg, sk[1], signers1, 0) == 1);
|
||||
|
||||
/* Partially sign */
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
|
||||
/* Can't verify, sign or combine signatures until nonce is combined */
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx_tmp, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx_tmp, &session[1], &partial_sig[1]) == 0);
|
||||
CHECK(ecount == 2);
|
||||
memset(&partial_sig[1], 0, sizeof(partial_sig[1]));
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx_tmp, &session[1], sig, partial_sig, 2) == 0);
|
||||
CHECK(ecount == 3);
|
||||
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1);
|
||||
/* messagehash should be the same as a session whose get_public_nonce was called
|
||||
* with different signers (i.e. they diff in public keys). This is because the
|
||||
* public keys of the signers is set in stone when initializing the session. */
|
||||
secp256k1_musig_compute_messagehash(ctx, msghash1, &session[1]);
|
||||
musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, &pre_session, ncs, msg, nonce[0], sk[1], session_id[1]);
|
||||
CHECK(memcmp(msghash1, msghash2, 32) == 0);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[1], &pk[1]) == 1);
|
||||
/* Wrong signature */
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[0], &pk[1]) == 0);
|
||||
/* Can't get the public nonce until msg is set */
|
||||
musig_state_machine_late_msg_test(pk, &combined_pk, &pre_session, nonce_commitment[0], nonce[0], sk[1], session_id[1], msg);
|
||||
}
|
||||
secp256k1_context_destroy(ctx_tmp);
|
||||
}
|
||||
|
||||
void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
|
||||
/* Throughout this test "a" and "b" refer to two hypothetical blockchains,
|
||||
* while the indices 0 and 1 refer to the two signers. Here signer 0 is
|
||||
* sending a-coins to signer 1, while signer 1 is sending b-coins to signer
|
||||
* 0. Signer 0 produces the adaptor signatures. */
|
||||
unsigned char final_sig_a[64];
|
||||
unsigned char final_sig_b[64];
|
||||
secp256k1_musig_partial_signature partial_sig_a[2];
|
||||
secp256k1_musig_partial_signature partial_sig_b_adapted[2];
|
||||
secp256k1_musig_partial_signature partial_sig_b[2];
|
||||
unsigned char sec_adaptor[32];
|
||||
unsigned char sec_adaptor_extracted[32];
|
||||
secp256k1_pubkey pub_adaptor;
|
||||
|
||||
unsigned char seckey_a[2][32];
|
||||
unsigned char seckey_b[2][32];
|
||||
secp256k1_xonly_pubkey pk_a[2];
|
||||
secp256k1_xonly_pubkey pk_b[2];
|
||||
secp256k1_musig_pre_session pre_session_a;
|
||||
secp256k1_musig_pre_session pre_session_b;
|
||||
secp256k1_xonly_pubkey combined_pk_a;
|
||||
secp256k1_xonly_pubkey combined_pk_b;
|
||||
secp256k1_musig_session musig_session_a[2];
|
||||
secp256k1_musig_session musig_session_b[2];
|
||||
unsigned char noncommit_a[2][32];
|
||||
unsigned char noncommit_b[2][32];
|
||||
const unsigned char *noncommit_a_ptr[2];
|
||||
const unsigned char *noncommit_b_ptr[2];
|
||||
unsigned char pubnon_a[2][32];
|
||||
unsigned char pubnon_b[2][32];
|
||||
int combined_nonce_parity_a;
|
||||
int combined_nonce_parity_b;
|
||||
secp256k1_musig_session_signer_data data_a[2];
|
||||
secp256k1_musig_session_signer_data data_b[2];
|
||||
|
||||
const unsigned char seed[32] = "still tired of choosing seeds...";
|
||||
const unsigned char msg32_a[32] = "this is the message blockchain a";
|
||||
const unsigned char msg32_b[32] = "this is the message blockchain b";
|
||||
|
||||
/* Step 1: key setup */
|
||||
secp256k1_testrand256(seckey_a[0]);
|
||||
secp256k1_testrand256(seckey_a[1]);
|
||||
secp256k1_testrand256(seckey_b[0]);
|
||||
secp256k1_testrand256(seckey_b[1]);
|
||||
secp256k1_testrand256(sec_adaptor);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk_a[0], seckey_a[0]));
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk_a[1], seckey_a[1]));
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk_b[0], seckey_b[0]));
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk_b[1], seckey_b[1]));
|
||||
CHECK(secp256k1_ec_pubkey_create(ctx, &pub_adaptor, sec_adaptor));
|
||||
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_a, &pre_session_a, pk_a, 2));
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &combined_pk_b, &pre_session_b, pk_b, 2));
|
||||
|
||||
CHECK(secp256k1_musig_session_init(ctx, &musig_session_a[0], data_a, noncommit_a[0], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, 0, seckey_a[0]));
|
||||
CHECK(secp256k1_musig_session_init(ctx, &musig_session_a[1], data_a, noncommit_a[1], seed, msg32_a, &combined_pk_a, &pre_session_a, 2, 1, seckey_a[1]));
|
||||
noncommit_a_ptr[0] = noncommit_a[0];
|
||||
noncommit_a_ptr[1] = noncommit_a[1];
|
||||
|
||||
CHECK(secp256k1_musig_session_init(ctx, &musig_session_b[0], data_b, noncommit_b[0], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, 0, seckey_b[0]));
|
||||
CHECK(secp256k1_musig_session_init(ctx, &musig_session_b[1], data_b, noncommit_b[1], seed, msg32_b, &combined_pk_b, &pre_session_b, 2, 1, seckey_b[1]));
|
||||
noncommit_b_ptr[0] = noncommit_b[0];
|
||||
noncommit_b_ptr[1] = noncommit_b[1];
|
||||
|
||||
/* Step 2: Exchange nonces */
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[0], data_a, pubnon_a[0], noncommit_a_ptr, 2, NULL));
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[1], data_a, pubnon_a[1], noncommit_a_ptr, 2, NULL));
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[0], data_b, pubnon_b[0], noncommit_b_ptr, 2, NULL));
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[1], data_b, pubnon_b[1], noncommit_b_ptr, 2, NULL));
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &data_a[0], pubnon_a[0]));
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &data_a[1], pubnon_a[1]));
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &data_b[0], pubnon_b[0]));
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &data_b[1], pubnon_b[1]));
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[0], data_a, 2, &combined_nonce_parity_a, &pub_adaptor));
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_a[1], data_a, 2, NULL, &pub_adaptor));
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[0], data_b, 2, &combined_nonce_parity_b, &pub_adaptor));
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &musig_session_b[1], data_b, 2, NULL, &pub_adaptor));
|
||||
|
||||
/* Step 3: Signer 0 produces partial signatures for both chains. */
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[0], &partial_sig_a[0]));
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_b[0], &partial_sig_b[0]));
|
||||
|
||||
/* Step 4: Signer 1 receives partial signatures, verifies them and creates a
|
||||
* partial signature to send B-coins to signer 0. */
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &musig_session_a[1], data_a, &partial_sig_a[0], &pk_a[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &musig_session_b[1], data_b, &partial_sig_b[0], &pk_b[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_b[1], &partial_sig_b[1]));
|
||||
|
||||
/* Step 5: Signer 0 adapts its own partial signature and combines it with the
|
||||
* partial signature from signer 1. This results in a complete signature which
|
||||
* is broadcasted by signer 0 to take B-coins. */
|
||||
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_b_adapted[0], &partial_sig_b[0], sec_adaptor, combined_nonce_parity_b));
|
||||
memcpy(&partial_sig_b_adapted[1], &partial_sig_b[1], sizeof(partial_sig_b_adapted[1]));
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], final_sig_b, partial_sig_b_adapted, 2) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_b, msg32_b, &combined_pk_b) == 1);
|
||||
|
||||
/* Step 6: Signer 1 extracts adaptor from the published signature, applies it to
|
||||
* other partial signature, and takes A-coins. */
|
||||
CHECK(secp256k1_musig_extract_secret_adaptor(ctx, sec_adaptor_extracted, final_sig_b, partial_sig_b, 2, combined_nonce_parity_b) == 1);
|
||||
CHECK(memcmp(sec_adaptor_extracted, sec_adaptor, sizeof(sec_adaptor)) == 0); /* in real life we couldn't check this, of course */
|
||||
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_a[0], &partial_sig_a[0], sec_adaptor_extracted, combined_nonce_parity_a));
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[1], &partial_sig_a[1]));
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], final_sig_a, partial_sig_a, 2) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig_a, msg32_a, &combined_pk_a) == 1);
|
||||
}
|
||||
|
||||
/* Checks that hash initialized by secp256k1_musig_sha256_init_tagged has the
|
||||
* expected state. */
|
||||
void sha256_tag_test(void) {
|
||||
char tag[17] = "MuSig coefficient";
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256 sha_tagged;
|
||||
unsigned char buf[32];
|
||||
unsigned char buf2[32];
|
||||
size_t i;
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, (unsigned char *) tag, 17);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
/* buf = SHA256("MuSig coefficient") */
|
||||
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
/* Is buffer fully consumed? */
|
||||
CHECK((sha.bytes & 0x3F) == 0);
|
||||
|
||||
/* Compare with tagged SHA */
|
||||
secp256k1_musig_sha256_init_tagged(&sha_tagged);
|
||||
for (i = 0; i < 8; i++) {
|
||||
CHECK(sha_tagged.s[i] == sha.s[i]);
|
||||
}
|
||||
secp256k1_sha256_write(&sha, buf, 32);
|
||||
secp256k1_sha256_write(&sha_tagged, buf, 32);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
secp256k1_sha256_finalize(&sha_tagged, buf2);
|
||||
CHECK(memcmp(buf, buf2, 32) == 0);
|
||||
}
|
||||
|
||||
/* Attempts to create a signature for the combined public key using given secret
|
||||
* keys and pre_session. */
|
||||
void musig_tweak_test_helper(const secp256k1_xonly_pubkey* combined_pubkey, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_pre_session *pre_session) {
|
||||
secp256k1_musig_session session[2];
|
||||
secp256k1_musig_session_signer_data signers0[2];
|
||||
secp256k1_musig_session_signer_data signers1[2];
|
||||
secp256k1_xonly_pubkey pk[2];
|
||||
unsigned char session_id[2][32];
|
||||
unsigned char msg[32];
|
||||
unsigned char nonce_commitment[2][32];
|
||||
unsigned char nonce[2][32];
|
||||
const unsigned char *ncs[2];
|
||||
secp256k1_musig_partial_signature partial_sig[2];
|
||||
unsigned char final_sig[64];
|
||||
|
||||
secp256k1_testrand256(session_id[0]);
|
||||
secp256k1_testrand256(session_id[1]);
|
||||
secp256k1_testrand256(msg);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk0) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk1) == 1);
|
||||
|
||||
CHECK(secp256k1_musig_session_init(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, combined_pubkey, pre_session, 2, 0, sk0) == 1);
|
||||
CHECK(secp256k1_musig_session_init(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, combined_pubkey, pre_session, 2, 1, sk1) == 1);
|
||||
/* Set nonce commitments */
|
||||
ncs[0] = nonce_commitment[0];
|
||||
ncs[1] = nonce_commitment[1];
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, nonce[0], ncs, 2, NULL) == 1);
|
||||
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, nonce[1], ncs, 2, NULL) == 1);
|
||||
/* Set nonces */
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[0], nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], nonce[1]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[0], nonce[0]) == 1);
|
||||
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], nonce[1]) == 1);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signers0[1], &partial_sig[1], &pk[1]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1);
|
||||
CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], final_sig, partial_sig, 2));
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, final_sig, msg, combined_pubkey) == 1);
|
||||
}
|
||||
|
||||
/* In this test we create a combined public key P and a commitment Q = P +
|
||||
* hash(P, contract)*G. Then we test that we can sign for both public keys. In
|
||||
* order to sign for Q we use the tweak32 argument of partial_sig_combine. */
|
||||
void musig_tweak_test(secp256k1_scratch_space *scratch) {
|
||||
unsigned char sk[2][32];
|
||||
secp256k1_xonly_pubkey pk[2];
|
||||
secp256k1_musig_pre_session pre_session_P;
|
||||
secp256k1_musig_pre_session pre_session_Q;
|
||||
secp256k1_xonly_pubkey P;
|
||||
unsigned char P_serialized[32];
|
||||
secp256k1_pubkey Q;
|
||||
int Q_parity;
|
||||
secp256k1_xonly_pubkey Q_xonly;
|
||||
unsigned char Q_serialized[32];
|
||||
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char contract[32];
|
||||
unsigned char ec_commit_tweak[32];
|
||||
|
||||
/* Setup */
|
||||
secp256k1_testrand256(sk[0]);
|
||||
secp256k1_testrand256(sk[1]);
|
||||
secp256k1_testrand256(contract);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[0], sk[0]) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_create(&pk[1], sk[1]) == 1);
|
||||
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &P, &pre_session_P, pk, 2) == 1);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, P_serialized, &P) == 1);
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, P_serialized, 32);
|
||||
secp256k1_sha256_write(&sha, contract, 32);
|
||||
secp256k1_sha256_finalize(&sha, ec_commit_tweak);
|
||||
pre_session_Q = pre_session_P;
|
||||
CHECK(secp256k1_musig_pubkey_tweak_add(ctx, &pre_session_Q, &Q, &P, ec_commit_tweak) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &Q_xonly, &Q_parity, &Q));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, Q_serialized, &Q_xonly));
|
||||
/* Check that musig_pubkey_tweak_add produces same result as
|
||||
* xonly_pubkey_tweak_add. */
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, Q_serialized, Q_parity, &P, ec_commit_tweak) == 1);
|
||||
|
||||
/* Test signing for P */
|
||||
musig_tweak_test_helper(&P, sk[0], sk[1], &pre_session_P);
|
||||
/* Test signing for Q */
|
||||
musig_tweak_test_helper(&Q_xonly, sk[0], sk[1], &pre_session_Q);
|
||||
}
|
||||
|
||||
void run_musig_tests(void) {
|
||||
int i;
|
||||
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
musig_simple_test(scratch);
|
||||
}
|
||||
musig_api_tests(scratch);
|
||||
musig_state_machine_tests(scratch);
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Run multiple times to ensure that pk and nonce have different y
|
||||
* parities */
|
||||
scriptless_atomic_swap(scratch);
|
||||
musig_tweak_test(scratch);
|
||||
}
|
||||
sha256_tag_test();
|
||||
|
||||
secp256k1_scratch_space_destroy(ctx, scratch);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -20,9 +20,9 @@
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#if defined(SECP256K1_BIG_ENDIAN)
|
||||
#define BE32(x) (x)
|
||||
#else
|
||||
#elif defined(SECP256K1_LITTLE_ENDIAN)
|
||||
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@ SECP256K1_INLINE static void secp256k1_borromean_hash(unsigned char *hash, const
|
||||
size_t ridx, size_t eidx) {
|
||||
uint32_t ring;
|
||||
uint32_t epos;
|
||||
secp256k1_sha256_t sha256_en;
|
||||
secp256k1_sha256 sha256_en;
|
||||
secp256k1_sha256_initialize(&sha256_en);
|
||||
ring = BE32((uint32_t)ridx);
|
||||
epos = BE32((uint32_t)eidx);
|
||||
@@ -60,7 +60,7 @@ int secp256k1_borromean_verify(const secp256k1_ecmult_context* ecmult_ctx, secp2
|
||||
secp256k1_gej rgej;
|
||||
secp256k1_ge rge;
|
||||
secp256k1_scalar ens;
|
||||
secp256k1_sha256_t sha256_e0;
|
||||
secp256k1_sha256 sha256_e0;
|
||||
unsigned char tmp[33];
|
||||
size_t i;
|
||||
size_t j;
|
||||
@@ -115,7 +115,7 @@ int secp256k1_borromean_sign(const secp256k1_ecmult_context* ecmult_ctx, const s
|
||||
secp256k1_gej rgej;
|
||||
secp256k1_ge rge;
|
||||
secp256k1_scalar ens;
|
||||
secp256k1_sha256_t sha256_e0;
|
||||
secp256k1_sha256 sha256_e0;
|
||||
unsigned char tmp[33];
|
||||
size_t i;
|
||||
size_t j;
|
||||
|
||||
@@ -14,15 +14,21 @@
|
||||
#include "modules/rangeproof/rangeproof_impl.h"
|
||||
|
||||
/** Alternative generator for secp256k1.
|
||||
* This is the sha256 of 'g' after DER encoding (without compression),
|
||||
* which happens to be a point on the curve.
|
||||
* sage: G2 = EllipticCurve ([F (0), F (7)]).lift_x(int(hashlib.sha256('0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'.decode('hex')).hexdigest(),16))
|
||||
* sage: '%x %x' % (11 - G2.xy()[1].is_square(), G2.xy()[0])
|
||||
* This is the sha256 of 'g' after standard encoding (without compression),
|
||||
* which happens to be a point on the curve. More precisely, the generator is
|
||||
* derived by running the following script with the sage mathematics software.
|
||||
|
||||
import hashlib
|
||||
F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
|
||||
G = '0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
|
||||
H = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256(G.decode('hex')).hexdigest(),16)))
|
||||
print('%x %x' % H.xy())
|
||||
*/
|
||||
static const secp256k1_generator secp256k1_generator_h_internal = {{
|
||||
0x11,
|
||||
0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e,
|
||||
0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0
|
||||
0x07, 0x8a, 0x5a, 0x0f, 0x28, 0xec, 0x96, 0xd5, 0x47, 0xbf, 0xee, 0x9a, 0xce, 0x80, 0x3a, 0xc0,
|
||||
0x31, 0xd3, 0xc6, 0x86, 0x39, 0x73, 0x92, 0x6e, 0x04, 0x9e, 0x63, 0x7c, 0xb1, 0xb5, 0xf4, 0x0a,
|
||||
0x36, 0xda, 0xc2, 0x8a, 0xf1, 0x76, 0x69, 0x68, 0xc3, 0x0c, 0x23, 0x13, 0xf3, 0xa3, 0x89, 0x04
|
||||
}};
|
||||
|
||||
const secp256k1_generator *secp256k1_generator_h = &secp256k1_generator_h_internal;
|
||||
@@ -43,22 +49,38 @@ static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* co
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_pedersen_commitment* commit, const unsigned char *input) {
|
||||
secp256k1_fe x;
|
||||
secp256k1_ge ge;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(input != NULL);
|
||||
(void) ctx;
|
||||
if ((input[0] & 0xFE) != 8) {
|
||||
|
||||
if ((input[0] & 0xFE) != 8 ||
|
||||
!secp256k1_fe_set_b32(&x, &input[1]) ||
|
||||
!secp256k1_ge_set_xquad(&ge, &x)) {
|
||||
return 0;
|
||||
}
|
||||
memcpy(commit->data, input, sizeof(commit->data));
|
||||
if (input[0] & 1) {
|
||||
secp256k1_ge_neg(&ge, &ge);
|
||||
}
|
||||
secp256k1_pedersen_commitment_save(commit, &ge);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_commitment_serialize(const secp256k1_context* ctx, unsigned char *output, const secp256k1_pedersen_commitment* commit) {
|
||||
secp256k1_ge ge;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(output != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
memcpy(output, commit->data, sizeof(commit->data));
|
||||
|
||||
secp256k1_pedersen_commitment_load(&ge, commit);
|
||||
|
||||
output[0] = 9 ^ secp256k1_fe_is_quad_var(&ge.y);
|
||||
secp256k1_fe_normalize_var(&ge.x);
|
||||
secp256k1_fe_get_b32(&output[1], &ge.x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar *sec,
|
||||
size_t *rsizes, size_t rings, const unsigned char *nonce, const secp256k1_ge *commit, const unsigned char *proof, size_t len, const secp256k1_ge* genp) {
|
||||
unsigned char tmp[32];
|
||||
unsigned char rngseed[32 + 33 + 33 + 10];
|
||||
secp256k1_rfc6979_hmac_sha256_t rng;
|
||||
secp256k1_rfc6979_hmac_sha256 rng;
|
||||
secp256k1_scalar acc;
|
||||
int overflow;
|
||||
int ret;
|
||||
@@ -199,7 +199,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmul
|
||||
secp256k1_scalar sec[32]; /* Blinding factors for the correct digits. */
|
||||
secp256k1_scalar k[32]; /* Nonces for our non-forged signatures. */
|
||||
secp256k1_scalar stmp;
|
||||
secp256k1_sha256_t sha256_m;
|
||||
secp256k1_sha256 sha256_m;
|
||||
unsigned char prep[4096];
|
||||
unsigned char tmp[33];
|
||||
unsigned char *signs; /* Location of sign flags in the proof. */
|
||||
@@ -547,7 +547,7 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm
|
||||
secp256k1_ge c;
|
||||
secp256k1_scalar s[128];
|
||||
secp256k1_scalar evalues[128]; /* Challenges, only used during proof rewind. */
|
||||
secp256k1_sha256_t sha256_m;
|
||||
secp256k1_sha256 sha256_m;
|
||||
size_t rsizes[32];
|
||||
int ret;
|
||||
size_t i;
|
||||
@@ -609,8 +609,10 @@ SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecm
|
||||
}
|
||||
for(i = 0; i < rings - 1; i++) {
|
||||
secp256k1_fe fe;
|
||||
secp256k1_fe_set_b32(&fe, &proof[offset]);
|
||||
secp256k1_ge_set_xquad(&c, &fe);
|
||||
if (!secp256k1_fe_set_b32(&fe, &proof[offset]) ||
|
||||
!secp256k1_ge_set_xquad(&c, &fe)) {
|
||||
return 0;
|
||||
}
|
||||
if (signs[i]) {
|
||||
secp256k1_ge_neg(&c, &c);
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@ static void test_pedersen_api(const secp256k1_context *none, const secp256k1_con
|
||||
unsigned char blind_out[32];
|
||||
const unsigned char *blind_ptr = blind;
|
||||
unsigned char *blind_out_ptr = blind_out;
|
||||
uint64_t val = secp256k1_rand32();
|
||||
uint64_t val = secp256k1_testrand32();
|
||||
|
||||
secp256k1_rand256(blind);
|
||||
secp256k1_testrand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 1);
|
||||
CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, secp256k1_generator_h) == 0);
|
||||
@@ -80,8 +80,8 @@ static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_c
|
||||
unsigned char proof[5134];
|
||||
unsigned char blind[32];
|
||||
secp256k1_pedersen_commitment commit;
|
||||
uint64_t vmin = secp256k1_rand32();
|
||||
uint64_t val = vmin + secp256k1_rand32();
|
||||
uint64_t vmin = secp256k1_testrand32();
|
||||
uint64_t val = vmin + secp256k1_testrand32();
|
||||
size_t len = sizeof(proof);
|
||||
/* we'll switch to dylan thomas for this one */
|
||||
const unsigned char message[68] = "My tears are like the quiet drift / Of petals from some magic rose;";
|
||||
@@ -89,7 +89,7 @@ static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_c
|
||||
const unsigned char ext_commit[72] = "And all my grief flows from the rift / Of unremembered skies and snows.";
|
||||
size_t ext_commit_len = sizeof(ext_commit);
|
||||
|
||||
secp256k1_rand256(blind);
|
||||
secp256k1_testrand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, val, secp256k1_generator_h));
|
||||
|
||||
CHECK(secp256k1_rangeproof_sign(none, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
@@ -271,8 +271,8 @@ static void test_pedersen(void) {
|
||||
int inputs;
|
||||
int outputs;
|
||||
int total;
|
||||
inputs = (secp256k1_rand32() & 7) + 1;
|
||||
outputs = (secp256k1_rand32() & 7) + 2;
|
||||
inputs = (secp256k1_testrand32() & 7) + 1;
|
||||
outputs = (secp256k1_testrand32() & 7) + 2;
|
||||
total = inputs + outputs;
|
||||
for (i = 0; i < 19; i++) {
|
||||
cptr[i] = &commits[i];
|
||||
@@ -280,11 +280,11 @@ static void test_pedersen(void) {
|
||||
}
|
||||
totalv = 0;
|
||||
for (i = 0; i < inputs; i++) {
|
||||
values[i] = secp256k1_rands64(0, INT64_MAX - totalv);
|
||||
values[i] = secp256k1_testrandi64(0, INT64_MAX - totalv);
|
||||
totalv += values[i];
|
||||
}
|
||||
for (i = 0; i < outputs - 1; i++) {
|
||||
values[i + inputs] = secp256k1_rands64(0, totalv);
|
||||
values[i + inputs] = secp256k1_testrandi64(0, totalv);
|
||||
totalv -= values[i + inputs];
|
||||
}
|
||||
values[total - 1] = totalv;
|
||||
@@ -331,27 +331,27 @@ static void test_borromean(void) {
|
||||
size_t i;
|
||||
size_t j;
|
||||
int c;
|
||||
secp256k1_rand256_test(m);
|
||||
nrings = 1 + (secp256k1_rand32()&7);
|
||||
secp256k1_testrand256_test(m);
|
||||
nrings = 1 + (secp256k1_testrand32()&7);
|
||||
c = 0;
|
||||
secp256k1_scalar_set_int(&one, 1);
|
||||
if (secp256k1_rand32()&1) {
|
||||
if (secp256k1_testrand32()&1) {
|
||||
secp256k1_scalar_negate(&one, &one);
|
||||
}
|
||||
for (i = 0; i < nrings; i++) {
|
||||
rsizes[i] = 1 + (secp256k1_rand32()&7);
|
||||
secidx[i] = secp256k1_rand32() % rsizes[i];
|
||||
rsizes[i] = 1 + (secp256k1_testrand32()&7);
|
||||
secidx[i] = secp256k1_testrand32() % rsizes[i];
|
||||
random_scalar_order(&sec[i]);
|
||||
random_scalar_order(&k[i]);
|
||||
if(secp256k1_rand32()&7) {
|
||||
if(secp256k1_testrand32()&7) {
|
||||
sec[i] = one;
|
||||
}
|
||||
if(secp256k1_rand32()&7) {
|
||||
if(secp256k1_testrand32()&7) {
|
||||
k[i] = one;
|
||||
}
|
||||
for (j = 0; j < rsizes[i]; j++) {
|
||||
random_scalar_order(&s[c + j]);
|
||||
if(secp256k1_rand32()&7) {
|
||||
if(secp256k1_testrand32()&7) {
|
||||
s[i] = one;
|
||||
}
|
||||
if (j == secidx[i]) {
|
||||
@@ -365,14 +365,14 @@ static void test_borromean(void) {
|
||||
}
|
||||
CHECK(secp256k1_borromean_sign(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx, e0, s, pubs, k, sec, rsizes, secidx, nrings, m, 32));
|
||||
CHECK(secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32));
|
||||
i = secp256k1_rand32() % c;
|
||||
i = secp256k1_testrand32() % c;
|
||||
secp256k1_scalar_negate(&s[i],&s[i]);
|
||||
CHECK(!secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32));
|
||||
secp256k1_scalar_negate(&s[i],&s[i]);
|
||||
secp256k1_scalar_set_int(&one, 1);
|
||||
for(j = 0; j < 4; j++) {
|
||||
i = secp256k1_rand32() % c;
|
||||
if (secp256k1_rand32() & 1) {
|
||||
i = secp256k1_testrand32() % c;
|
||||
if (secp256k1_testrand32() & 1) {
|
||||
secp256k1_gej_double_var(&pubs[i],&pubs[i], NULL);
|
||||
} else {
|
||||
secp256k1_scalar_add(&s[i],&s[i],&one);
|
||||
@@ -385,7 +385,7 @@ static void test_rangeproof(void) {
|
||||
const uint64_t testvs[11] = {0, 1, 5, 11, 65535, 65537, INT32_MAX, UINT32_MAX, INT64_MAX - 1, INT64_MAX, UINT64_MAX};
|
||||
secp256k1_pedersen_commitment commit;
|
||||
secp256k1_pedersen_commitment commit2;
|
||||
unsigned char proof[5134];
|
||||
unsigned char proof[5134 + 1]; /* One additional byte to test if trailing bytes are rejected */
|
||||
unsigned char blind[32];
|
||||
unsigned char blindout[32];
|
||||
unsigned char message[4096];
|
||||
@@ -408,7 +408,7 @@ static void test_rangeproof(void) {
|
||||
memcpy(&message_long[i], message_short, sizeof(message_short));
|
||||
}
|
||||
|
||||
secp256k1_rand256(blind);
|
||||
secp256k1_testrand256(blind);
|
||||
for (i = 0; i < 11; i++) {
|
||||
v = testvs[i];
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
@@ -464,7 +464,7 @@ static void test_rangeproof(void) {
|
||||
CHECK(maxv == v);
|
||||
}
|
||||
}
|
||||
secp256k1_rand256(blind);
|
||||
secp256k1_testrand256(blind);
|
||||
v = INT64_MAX - 1;
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
for (i = 0; i < 19; i++) {
|
||||
@@ -477,14 +477,17 @@ static void test_rangeproof(void) {
|
||||
/* Make sure it fails when validating with a committed message */
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), secp256k1_generator_h));
|
||||
}
|
||||
secp256k1_rand256(blind);
|
||||
secp256k1_testrand256(blind);
|
||||
{
|
||||
/*Malleability test.*/
|
||||
v = secp256k1_rands64(0, 255);
|
||||
v = secp256k1_testrandi64(0, 255);
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, 0, 3, v, NULL, 0, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(len <= 5134);
|
||||
/* Test if trailing bytes are rejected. */
|
||||
proof[len] = v;
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len + 1, NULL, 0, secp256k1_generator_h));
|
||||
for (i = 0; i < len*8; i++) {
|
||||
proof[i >> 3] ^= 1 << (i & 7);
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
@@ -495,22 +498,22 @@ static void test_rangeproof(void) {
|
||||
CHECK(maxv >= v);
|
||||
}
|
||||
memcpy(&commit2, &commit, sizeof(commit));
|
||||
for (i = 0; i < 10 * (size_t) count; i++) {
|
||||
for (i = 0; i < (size_t) count; i++) {
|
||||
int exp;
|
||||
int min_bits;
|
||||
v = secp256k1_rands64(0, UINT64_MAX >> (secp256k1_rand32()&63));
|
||||
v = secp256k1_testrandi64(0, UINT64_MAX >> (secp256k1_testrand32()&63));
|
||||
vmin = 0;
|
||||
if ((v < INT64_MAX) && (secp256k1_rand32()&1)) {
|
||||
vmin = secp256k1_rands64(0, v);
|
||||
if ((v < INT64_MAX) && (secp256k1_testrand32()&1)) {
|
||||
vmin = secp256k1_testrandi64(0, v);
|
||||
}
|
||||
secp256k1_rand256(blind);
|
||||
secp256k1_testrand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
len = 5134;
|
||||
exp = (int)secp256k1_rands64(0,18)-(int)secp256k1_rands64(0,18);
|
||||
exp = (int)secp256k1_testrandi64(0,18)-(int)secp256k1_testrandi64(0,18);
|
||||
if (exp < 0) {
|
||||
exp = -exp;
|
||||
}
|
||||
min_bits = (int)secp256k1_rands64(0,64)-(int)secp256k1_rands64(0,64);
|
||||
min_bits = (int)secp256k1_testrandi64(0,64)-(int)secp256k1_testrandi64(0,64);
|
||||
if (min_bits < 0) {
|
||||
min_bits = -min_bits;
|
||||
}
|
||||
@@ -523,29 +526,29 @@ static void test_rangeproof(void) {
|
||||
}
|
||||
CHECK(mlen <= 4096);
|
||||
CHECK(memcmp(blindout, blind, 32) == 0);
|
||||
CHECK(vout == v);
|
||||
|
||||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
memcpy(&commit2, &commit, sizeof(commit));
|
||||
}
|
||||
for (j = 0; j < 10; j++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
for (i = 0; i < 96; i++) {
|
||||
secp256k1_rand256(&proof[i * 32]);
|
||||
secp256k1_testrand256(&proof[i * 32]);
|
||||
}
|
||||
for (k = 0; k < 128; k++) {
|
||||
for (k = 0; k < 128; k += 3) {
|
||||
len = k;
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
}
|
||||
len = secp256k1_rands64(0, 3072);
|
||||
len = secp256k1_testrandi64(0, 3072);
|
||||
CHECK(!secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit2, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_N_GENS 30
|
||||
void test_multiple_generators(void) {
|
||||
const size_t n_inputs = (secp256k1_rand32() % (MAX_N_GENS / 2)) + 1;
|
||||
const size_t n_outputs = (secp256k1_rand32() % (MAX_N_GENS / 2)) + 1;
|
||||
const size_t n_inputs = (secp256k1_testrand32() % (MAX_N_GENS / 2)) + 1;
|
||||
const size_t n_outputs = (secp256k1_testrand32() % (MAX_N_GENS / 2)) + 1;
|
||||
const size_t n_generators = n_inputs + n_outputs;
|
||||
unsigned char *generator_blind[MAX_N_GENS];
|
||||
unsigned char *pedersen_blind[MAX_N_GENS];
|
||||
@@ -579,11 +582,11 @@ void test_multiple_generators(void) {
|
||||
/* Compute all the values -- can be positive or negative */
|
||||
total_value = 0;
|
||||
for (i = 0; i < n_outputs; i++) {
|
||||
value[n_inputs + i] = secp256k1_rands64(0, INT64_MAX - total_value);
|
||||
value[n_inputs + i] = secp256k1_testrandi64(0, INT64_MAX - total_value);
|
||||
total_value += value[n_inputs + i];
|
||||
}
|
||||
for (i = 0; i < n_inputs - 1; i++) {
|
||||
value[i] = secp256k1_rands64(0, total_value);
|
||||
value[i] = secp256k1_testrandi64(0, total_value);
|
||||
total_value -= value[i];
|
||||
}
|
||||
value[i] = total_value;
|
||||
@@ -604,13 +607,99 @@ void test_multiple_generators(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void test_rangeproof_fixed_vectors(void) {
|
||||
const unsigned char vector_1[] = {
|
||||
0x62, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x02, 0x2a, 0x5c, 0x42, 0x0e, 0x1d,
|
||||
0x51, 0xe1, 0xb7, 0xf3, 0x69, 0x04, 0xb5, 0xbb, 0x9b, 0x41, 0x66, 0x14, 0xf3, 0x64, 0x42, 0x26,
|
||||
0xe3, 0xa7, 0x6a, 0x06, 0xbb, 0xa8, 0x5a, 0x49, 0x6f, 0x19, 0x76, 0xfb, 0xe5, 0x75, 0x77, 0x88,
|
||||
0xab, 0xa9, 0x66, 0x44, 0x80, 0xea, 0x29, 0x95, 0x7f, 0xdf, 0x72, 0x4a, 0xaf, 0x02, 0xbe, 0xdd,
|
||||
0x5d, 0x15, 0xd8, 0xae, 0xff, 0x74, 0xc9, 0x8c, 0x1a, 0x67, 0x0e, 0xb2, 0x57, 0x22, 0x99, 0xc3,
|
||||
0x21, 0x46, 0x6f, 0x15, 0x58, 0x0e, 0xdb, 0xe6, 0x6e, 0xc4, 0x0d, 0xfe, 0x6f, 0x04, 0x6b, 0x0d,
|
||||
0x18, 0x3d, 0x78, 0x40, 0x98, 0x56, 0x4e, 0xe4, 0x4a, 0x74, 0x90, 0xa7, 0xac, 0x9c, 0x16, 0xe0,
|
||||
0x3e, 0x81, 0xaf, 0x0f, 0xe3, 0x4f, 0x34, 0x99, 0x52, 0xf7, 0xa7, 0xf6, 0xd3, 0x83, 0xa0, 0x17,
|
||||
0x4b, 0x2d, 0xa7, 0xd4, 0xfd, 0xf7, 0x84, 0x45, 0xc4, 0x11, 0x71, 0x3d, 0x4a, 0x22, 0x34, 0x09,
|
||||
0x9c, 0xa7, 0xe5, 0xc8, 0xba, 0x04, 0xbf, 0xfd, 0x25, 0x11, 0x7d, 0xa4, 0x43, 0x45, 0xc7, 0x62,
|
||||
0x9e, 0x7b, 0x80, 0xf6, 0x09, 0xbb, 0x1b, 0x2e, 0xf3, 0xcd, 0x23, 0xe0, 0xed, 0x81, 0x43, 0x42,
|
||||
0xbe, 0xc4, 0x9f, 0x58, 0x8a, 0x0d, 0x66, 0x79, 0x09, 0x70, 0x11, 0x68, 0x3d, 0x87, 0x38, 0x1c,
|
||||
0x3c, 0x85, 0x52, 0x5b, 0x62, 0xf7, 0x3e, 0x7e, 0x87, 0xa2, 0x99, 0x24, 0xd0, 0x7d, 0x18, 0x63,
|
||||
0x56, 0x48, 0xa4, 0x3a, 0xfe, 0x65, 0xfa, 0xa4, 0xd0, 0x67, 0xaa, 0x98, 0x65, 0x4d, 0xe4, 0x22,
|
||||
0x75, 0x45, 0x52, 0xe8, 0x41, 0xc7, 0xed, 0x38, 0xeb, 0xf5, 0x02, 0x90, 0xc9, 0x45, 0xa3, 0xb0,
|
||||
0x4d, 0x03, 0xd7, 0xab, 0x43, 0xe4, 0x21, 0xfc, 0x83, 0xd6, 0x12, 0x1d, 0x76, 0xb1, 0x3c, 0x67,
|
||||
0x63, 0x1f, 0x52, 0x9d, 0xc3, 0x23, 0x5c, 0x4e, 0xa6, 0x8d, 0x01, 0x4a, 0xba, 0x9a, 0xf4, 0x16,
|
||||
0x5b, 0x67, 0xc8, 0xe1, 0xd2, 0x42, 0x6d, 0xdf, 0xcd, 0x08, 0x6a, 0x73, 0x41, 0x6a, 0xc2, 0x84,
|
||||
0xc6, 0x31, 0xbe, 0x57, 0xcb, 0x0e, 0xde, 0xbf, 0x71, 0xd5, 0x8a, 0xf7, 0x24, 0xb2, 0xa7, 0x89,
|
||||
0x96, 0x62, 0x4f, 0xd9, 0xf7, 0xc3, 0xde, 0x4c, 0xab, 0x13, 0x72, 0xb4, 0xb3, 0x35, 0x04, 0x82,
|
||||
0xa8, 0x75, 0x1d, 0xde, 0x46, 0xa8, 0x0d, 0xb8, 0x23, 0x44, 0x00, 0x44, 0xfa, 0x53, 0x6c, 0x2d,
|
||||
0xce, 0xd3, 0xa6, 0x80, 0xa1, 0x20, 0xca, 0xd1, 0x63, 0xbb, 0xbe, 0x39, 0x5f, 0x9d, 0x27, 0x69,
|
||||
0xb3, 0x33, 0x1f, 0xdb, 0xda, 0x67, 0x05, 0x37, 0xbe, 0x65, 0xe9, 0x7e, 0xa9, 0xc3, 0xff, 0x37,
|
||||
0x8a, 0xb4, 0x2d, 0xfe, 0xf2, 0x16, 0x85, 0xc7, 0x0f, 0xd9, 0xbe, 0x14, 0xd1, 0x80, 0x14, 0x9f,
|
||||
0x58, 0x56, 0x98, 0x41, 0xf6, 0x26, 0xf7, 0xa2, 0x71, 0x66, 0xb4, 0x7a, 0x9c, 0x12, 0x73, 0xd3,
|
||||
0xdf, 0x77, 0x2b, 0x49, 0xe5, 0xca, 0x50, 0x57, 0x44, 0x6e, 0x3f, 0x58, 0x56, 0xbc, 0x21, 0x70,
|
||||
0x4f, 0xc6, 0xaa, 0x12, 0xff, 0x7c, 0xa7, 0x3d, 0xed, 0x46, 0xc1, 0x40, 0xe6, 0x58, 0x09, 0x2a,
|
||||
0xda, 0xb3, 0x76, 0xab, 0x44, 0xb5, 0x4e, 0xb3, 0x12, 0xe0, 0x26, 0x8a, 0x52, 0xac, 0x49, 0x1d,
|
||||
0xe7, 0x06, 0x53, 0x3a, 0x01, 0x35, 0x21, 0x2e, 0x86, 0x48, 0xc5, 0x75, 0xc1, 0xa2, 0x7d, 0x22,
|
||||
0x53, 0xf6, 0x3f, 0x41, 0xc5, 0xb3, 0x08, 0x7d, 0xa3, 0x67, 0xc0, 0xbb, 0xb6, 0x8d, 0xf0, 0xd3,
|
||||
0x01, 0x72, 0xd3, 0x63, 0x82, 0x01, 0x1a, 0xe7, 0x1d, 0x22, 0xfa, 0x95, 0x33, 0xf6, 0xf2, 0xde,
|
||||
0xa2, 0x53, 0x86, 0x55, 0x5a, 0xb4, 0x2e, 0x75, 0x75, 0xc6, 0xd5, 0x93, 0x9c, 0x57, 0xa9, 0x1f,
|
||||
0xb9, 0x3e, 0xe8, 0x1c, 0xbf, 0xac, 0x1c, 0x54, 0x6f, 0xf5, 0xab, 0x41, 0xee, 0xb3, 0x0e, 0xd0,
|
||||
0x76, 0xc4, 0x1a, 0x45, 0xcd, 0xf1, 0xd6, 0xcc, 0xb0, 0x83, 0x70, 0x73, 0xbc, 0x88, 0x74, 0xa0,
|
||||
0x5b, 0xe7, 0x98, 0x10, 0x36, 0xbf, 0xec, 0x23, 0x1c, 0xc2, 0xb5, 0xba, 0x4b, 0x9d, 0x7f, 0x8c,
|
||||
0x8a, 0xe2, 0xda, 0x18, 0xdd, 0xab, 0x27, 0x8a, 0x15, 0xeb, 0xb0, 0xd4, 0x3a, 0x8b, 0x77, 0x00,
|
||||
0xc7, 0xbb, 0xcc, 0xfa, 0xba, 0xa4, 0x6a, 0x17, 0x5c, 0xf8, 0x51, 0x5d, 0x8d, 0x16, 0xcd, 0xa7,
|
||||
0x0e, 0x71, 0x97, 0x98, 0x78, 0x5a, 0x41, 0xb3, 0xf0, 0x1f, 0x87, 0x2d, 0x65, 0xcd, 0x29, 0x49,
|
||||
0xd2, 0x87, 0x2c, 0x91, 0xa9, 0x5f, 0xcc, 0xa9, 0xd8, 0xbb, 0x53, 0x18, 0xe7, 0xd6, 0xec, 0x65,
|
||||
0xa6, 0x45, 0xf6, 0xce, 0xcf, 0x48, 0xf6, 0x1e, 0x3d, 0xd2, 0xcf, 0xcb, 0x3a, 0xcd, 0xbb, 0x92,
|
||||
0x29, 0x24, 0x16, 0x7f, 0x8a, 0xa8, 0x5c, 0x0c, 0x45, 0x71, 0x33
|
||||
};
|
||||
const unsigned char commit_1[] = {
|
||||
0x08,
|
||||
0xf5, 0x1e, 0x0d, 0xc5, 0x86, 0x78, 0x51, 0xa9, 0x00, 0x00, 0xef, 0x4d, 0xe2, 0x94, 0x60, 0x89,
|
||||
0x83, 0x04, 0xb4, 0x0e, 0x90, 0x10, 0x05, 0x1c, 0x7f, 0xd7, 0x33, 0x92, 0x1f, 0xe7, 0x74, 0x59
|
||||
};
|
||||
uint64_t min_value_1;
|
||||
uint64_t max_value_1;
|
||||
secp256k1_pedersen_commitment pc;
|
||||
|
||||
CHECK(secp256k1_pedersen_commitment_parse(ctx, &pc, commit_1));
|
||||
|
||||
CHECK(secp256k1_rangeproof_verify(
|
||||
ctx,
|
||||
&min_value_1, &max_value_1,
|
||||
&pc,
|
||||
vector_1, sizeof(vector_1),
|
||||
NULL, 0,
|
||||
secp256k1_generator_h
|
||||
));
|
||||
}
|
||||
|
||||
void test_pedersen_commitment_fixed_vector(void) {
|
||||
const unsigned char two_g[33] = {
|
||||
0x09,
|
||||
0xc6, 0x04, 0x7f, 0x94, 0x41, 0xed, 0x7d, 0x6d, 0x30, 0x45, 0x40, 0x6e, 0x95, 0xc0, 0x7c, 0xd8,
|
||||
0x5c, 0x77, 0x8e, 0x4b, 0x8c, 0xef, 0x3c, 0xa7, 0xab, 0xac, 0x09, 0xb9, 0x5c, 0x70, 0x9e, 0xe5
|
||||
};
|
||||
unsigned char result[33];
|
||||
secp256k1_pedersen_commitment parse;
|
||||
|
||||
CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, two_g));
|
||||
CHECK(secp256k1_pedersen_commitment_serialize(ctx, result, &parse));
|
||||
CHECK(memcmp(two_g, result, 33) == 0);
|
||||
|
||||
result[0] = 0x08;
|
||||
CHECK(secp256k1_pedersen_commitment_parse(ctx, &parse, result));
|
||||
result[0] = 0x0c;
|
||||
CHECK(!secp256k1_pedersen_commitment_parse(ctx, &parse, result));
|
||||
}
|
||||
|
||||
void run_rangeproof_tests(void) {
|
||||
int i;
|
||||
test_api();
|
||||
for (i = 0; i < 10*count; i++) {
|
||||
test_rangeproof_fixed_vectors();
|
||||
test_pedersen_commitment_fixed_vector();
|
||||
for (i = 0; i < count / 2 + 1; i++) {
|
||||
test_pedersen();
|
||||
}
|
||||
for (i = 0; i < 10*count; i++) {
|
||||
for (i = 0; i < count / 2 + 1; i++) {
|
||||
test_borromean();
|
||||
}
|
||||
test_rangeproof();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
include_HEADERS += include/secp256k1_recovery.h
|
||||
noinst_HEADERS += src/modules/recovery/main_impl.h
|
||||
noinst_HEADERS += src/modules/recovery/tests_impl.h
|
||||
noinst_HEADERS += src/modules/recovery/tests_exhaustive_impl.h
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_recover
|
||||
bench_recover_SOURCES = src/bench_recover.c
|
||||
|
||||
45
src/modules/recovery/main_impl.h
Executable file → Normal file
45
src/modules/recovery/main_impl.h
Executable file → Normal file
@@ -4,8 +4,8 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_RECOVERY_MAIN_
|
||||
#define _SECP256K1_MODULE_RECOVERY_MAIN_
|
||||
#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H
|
||||
#define SECP256K1_MODULE_RECOVERY_MAIN_H
|
||||
|
||||
#include "include/secp256k1_recovery.h"
|
||||
|
||||
@@ -122,48 +122,15 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, cons
|
||||
|
||||
int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) {
|
||||
secp256k1_scalar r, s;
|
||||
secp256k1_scalar sec, non, msg;
|
||||
int recid;
|
||||
int ret = 0;
|
||||
int overflow = 0;
|
||||
int ret, recid;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(signature != NULL);
|
||||
ARG_CHECK(seckey != NULL);
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_default;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
|
||||
/* Fail if the secret key is invalid. */
|
||||
if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
|
||||
unsigned char nonce32[32];
|
||||
unsigned int count = 0;
|
||||
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||
while (1) {
|
||||
ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count);
|
||||
if (!ret) {
|
||||
break;
|
||||
}
|
||||
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
|
||||
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
|
||||
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
count++;
|
||||
}
|
||||
memset(nonce32, 0, 32);
|
||||
secp256k1_scalar_clear(&msg);
|
||||
secp256k1_scalar_clear(&non);
|
||||
secp256k1_scalar_clear(&sec);
|
||||
}
|
||||
if (ret) {
|
||||
secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
|
||||
} else {
|
||||
memset(signature, 0, sizeof(*signature));
|
||||
}
|
||||
ret = secp256k1_ecdsa_sign_inner(ctx, &r, &s, &recid, msg32, seckey, noncefp, noncedata);
|
||||
secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -190,4 +157,4 @@ int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubk
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */
|
||||
|
||||
149
src/modules/recovery/tests_exhaustive_impl.h
Normal file
149
src/modules/recovery/tests_exhaustive_impl.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
|
||||
#define SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H
|
||||
|
||||
#include "src/modules/recovery/main_impl.h"
|
||||
#include "include/secp256k1_recovery.h"
|
||||
|
||||
void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group) {
|
||||
int i, j, k;
|
||||
uint64_t iter = 0;
|
||||
|
||||
/* Loop */
|
||||
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { /* message */
|
||||
for (j = 1; j < EXHAUSTIVE_TEST_ORDER; j++) { /* key */
|
||||
if (skip_section(&iter)) continue;
|
||||
for (k = 1; k < EXHAUSTIVE_TEST_ORDER; k++) { /* nonce */
|
||||
const int starting_k = k;
|
||||
secp256k1_fe r_dot_y_normalized;
|
||||
secp256k1_ecdsa_recoverable_signature rsig;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_scalar sk, msg, r, s, expected_r;
|
||||
unsigned char sk32[32], msg32[32];
|
||||
int expected_recid;
|
||||
int recid;
|
||||
int overflow;
|
||||
secp256k1_scalar_set_int(&msg, i);
|
||||
secp256k1_scalar_set_int(&sk, j);
|
||||
secp256k1_scalar_get_b32(sk32, &sk);
|
||||
secp256k1_scalar_get_b32(msg32, &msg);
|
||||
|
||||
secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k);
|
||||
|
||||
/* Check directly */
|
||||
secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig);
|
||||
r_from_k(&expected_r, group, k, &overflow);
|
||||
CHECK(r == expected_r);
|
||||
CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER ||
|
||||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER);
|
||||
/* The recid's second bit is for conveying overflow (R.x value >= group order).
|
||||
* In the actual secp256k1 this is an astronomically unlikely event, but in the
|
||||
* small group used here, it will be the case for all points except the ones where
|
||||
* R.x=1 (which the group is specifically selected to have).
|
||||
* Note that this isn't actually useful; full recovery would need to convey
|
||||
* floor(R.x / group_order), but only one bit is used as that is sufficient
|
||||
* in the real group. */
|
||||
expected_recid = overflow ? 2 : 0;
|
||||
r_dot_y_normalized = group[k].y;
|
||||
secp256k1_fe_normalize(&r_dot_y_normalized);
|
||||
/* Also the recovery id is flipped depending if we hit the low-s branch */
|
||||
if ((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER) {
|
||||
expected_recid |= secp256k1_fe_is_odd(&r_dot_y_normalized);
|
||||
} else {
|
||||
expected_recid |= !secp256k1_fe_is_odd(&r_dot_y_normalized);
|
||||
}
|
||||
CHECK(recid == expected_recid);
|
||||
|
||||
/* Convert to a standard sig then check */
|
||||
secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
|
||||
secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig);
|
||||
/* Note that we compute expected_r *after* signing -- this is important
|
||||
* because our nonce-computing function function might change k during
|
||||
* signing. */
|
||||
r_from_k(&expected_r, group, k, NULL);
|
||||
CHECK(r == expected_r);
|
||||
CHECK((k * s) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER ||
|
||||
(k * (EXHAUSTIVE_TEST_ORDER - s)) % EXHAUSTIVE_TEST_ORDER == (i + r * j) % EXHAUSTIVE_TEST_ORDER);
|
||||
|
||||
/* Overflow means we've tried every possible nonce */
|
||||
if (k < starting_k) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group) {
|
||||
/* This is essentially a copy of test_exhaustive_verify, with recovery added */
|
||||
int s, r, msg, key;
|
||||
uint64_t iter = 0;
|
||||
for (s = 1; s < EXHAUSTIVE_TEST_ORDER; s++) {
|
||||
for (r = 1; r < EXHAUSTIVE_TEST_ORDER; r++) {
|
||||
for (msg = 1; msg < EXHAUSTIVE_TEST_ORDER; msg++) {
|
||||
for (key = 1; key < EXHAUSTIVE_TEST_ORDER; key++) {
|
||||
secp256k1_ge nonconst_ge;
|
||||
secp256k1_ecdsa_recoverable_signature rsig;
|
||||
secp256k1_ecdsa_signature sig;
|
||||
secp256k1_pubkey pk;
|
||||
secp256k1_scalar sk_s, msg_s, r_s, s_s;
|
||||
secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s;
|
||||
int recid = 0;
|
||||
int k, should_verify;
|
||||
unsigned char msg32[32];
|
||||
|
||||
if (skip_section(&iter)) continue;
|
||||
|
||||
secp256k1_scalar_set_int(&s_s, s);
|
||||
secp256k1_scalar_set_int(&r_s, r);
|
||||
secp256k1_scalar_set_int(&msg_s, msg);
|
||||
secp256k1_scalar_set_int(&sk_s, key);
|
||||
secp256k1_scalar_get_b32(msg32, &msg_s);
|
||||
|
||||
/* Verify by hand */
|
||||
/* Run through every k value that gives us this r and check that *one* works.
|
||||
* Note there could be none, there could be multiple, ECDSA is weird. */
|
||||
should_verify = 0;
|
||||
for (k = 0; k < EXHAUSTIVE_TEST_ORDER; k++) {
|
||||
secp256k1_scalar check_x_s;
|
||||
r_from_k(&check_x_s, group, k, NULL);
|
||||
if (r_s == check_x_s) {
|
||||
secp256k1_scalar_set_int(&s_times_k_s, k);
|
||||
secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s);
|
||||
secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s);
|
||||
secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s);
|
||||
should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s);
|
||||
}
|
||||
}
|
||||
/* nb we have a "high s" rule */
|
||||
should_verify &= !secp256k1_scalar_is_high(&s_s);
|
||||
|
||||
/* We would like to try recovering the pubkey and checking that it matches,
|
||||
* but pubkey recovery is impossible in the exhaustive tests (the reason
|
||||
* being that there are 12 nonzero r values, 12 nonzero points, and no
|
||||
* overlap between the sets, so there are no valid signatures). */
|
||||
|
||||
/* Verify by converting to a standard signature and calling verify */
|
||||
secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid);
|
||||
secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig);
|
||||
memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge));
|
||||
secp256k1_pubkey_save(&pk, &nonconst_ge);
|
||||
CHECK(should_verify ==
|
||||
secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_exhaustive_recovery(const secp256k1_context *ctx, const secp256k1_ge *group) {
|
||||
test_exhaustive_recovery_sign(ctx, group);
|
||||
test_exhaustive_recovery_verify(ctx, group);
|
||||
}
|
||||
|
||||
#endif /* SECP256K1_MODULE_RECOVERY_EXHAUSTIVE_TESTS_H */
|
||||
@@ -4,8 +4,8 @@
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_RECOVERY_TESTS_
|
||||
#define _SECP256K1_MODULE_RECOVERY_TESTS_
|
||||
#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H
|
||||
#define SECP256K1_MODULE_RECOVERY_TESTS_H
|
||||
|
||||
static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
|
||||
(void) msg32;
|
||||
@@ -25,7 +25,7 @@ static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned c
|
||||
}
|
||||
/* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */
|
||||
memset(nonce32, 1, 32);
|
||||
return secp256k1_rand_bits(1);
|
||||
return secp256k1_testrand_bits(1);
|
||||
}
|
||||
|
||||
void test_ecdsa_recovery_api(void) {
|
||||
@@ -184,7 +184,7 @@ void test_ecdsa_recovery_end_to_end(void) {
|
||||
CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
|
||||
CHECK(memcmp(&signature[4], &signature[0], 64) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&signature[4], &signature[0], 64) == 0);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1);
|
||||
memset(&rsignature[4], 0, sizeof(rsignature[4]));
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
|
||||
@@ -193,16 +193,16 @@ void test_ecdsa_recovery_end_to_end(void) {
|
||||
/* Parse compact (with recovery id) and recover. */
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
|
||||
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1);
|
||||
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
|
||||
CHECK(secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
|
||||
/* Serialize/destroy/parse signature and verify again. */
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1);
|
||||
sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255);
|
||||
sig[secp256k1_testrand_bits(6)] += 1 + secp256k1_testrand_int(255);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1);
|
||||
CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1);
|
||||
CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0);
|
||||
/* Recover again */
|
||||
CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 ||
|
||||
memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
|
||||
secp256k1_memcmp_var(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
|
||||
}
|
||||
|
||||
/* Tests several edge cases. */
|
||||
@@ -215,7 +215,7 @@ void test_ecdsa_recovery_edge_cases(void) {
|
||||
};
|
||||
const unsigned char sig64[64] = {
|
||||
/* Generated by signing the above message with nonce 'This is the nonce we will use...'
|
||||
* and secret key 0 (which is not valid), resulting in recid 0. */
|
||||
* and secret key 0 (which is not valid), resulting in recid 1. */
|
||||
0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8,
|
||||
0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96,
|
||||
0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63,
|
||||
@@ -390,4 +390,4 @@ void run_recovery_tests(void) {
|
||||
test_ecdsa_recovery_edge_cases();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */
|
||||
|
||||
9
src/modules/schnorrsig/Makefile.am.include
Normal file
9
src/modules/schnorrsig/Makefile.am.include
Normal file
@@ -0,0 +1,9 @@
|
||||
include_HEADERS += include/secp256k1_schnorrsig.h
|
||||
noinst_HEADERS += src/modules/schnorrsig/main_impl.h
|
||||
noinst_HEADERS += src/modules/schnorrsig/tests_impl.h
|
||||
noinst_HEADERS += src/modules/schnorrsig/tests_exhaustive_impl.h
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_schnorrsig
|
||||
bench_schnorrsig_SOURCES = src/bench_schnorrsig.c
|
||||
bench_schnorrsig_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
|
||||
endif
|
||||
239
src/modules/schnorrsig/main_impl.h
Normal file
239
src/modules/schnorrsig/main_impl.h
Normal file
@@ -0,0 +1,239 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_SCHNORRSIG_MAIN_
|
||||
#define _SECP256K1_MODULE_SCHNORRSIG_MAIN_
|
||||
|
||||
#include "include/secp256k1.h"
|
||||
#include "include/secp256k1_schnorrsig.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("BIP0340/nonce")||SHA256("BIP0340/nonce"). */
|
||||
static void secp256k1_nonce_function_bip340_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x46615b35ul;
|
||||
sha->s[1] = 0xf4bfbff7ul;
|
||||
sha->s[2] = 0x9f8dc671ul;
|
||||
sha->s[3] = 0x83627ab3ul;
|
||||
sha->s[4] = 0x60217180ul;
|
||||
sha->s[5] = 0x57358661ul;
|
||||
sha->s[6] = 0x21a29e54ul;
|
||||
sha->s[7] = 0x68b07b4cul;
|
||||
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("BIP0340/aux")||SHA256("BIP0340/aux"). */
|
||||
static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x24dd3219ul;
|
||||
sha->s[1] = 0x4eba7e70ul;
|
||||
sha->s[2] = 0xca0fabb9ul;
|
||||
sha->s[3] = 0x0fa3166dul;
|
||||
sha->s[4] = 0x3afbe4b1ul;
|
||||
sha->s[5] = 0x4c44df97ul;
|
||||
sha->s[6] = 0x4aac2739ul;
|
||||
sha->s[7] = 0x249e850aul;
|
||||
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
/* algo16 argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340
|
||||
* by using the correct tagged hash function. */
|
||||
static const unsigned char bip340_algo16[16] = "BIP0340/nonce\0\0\0";
|
||||
|
||||
static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
|
||||
secp256k1_sha256 sha;
|
||||
unsigned char masked_key[32];
|
||||
int i;
|
||||
|
||||
if (algo16 == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha);
|
||||
secp256k1_sha256_write(&sha, data, 32);
|
||||
secp256k1_sha256_finalize(&sha, masked_key);
|
||||
for (i = 0; i < 32; i++) {
|
||||
masked_key[i] ^= key32[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Tag the hash with algo16 which is important to avoid nonce reuse across
|
||||
* algorithms. If this nonce function is used in BIP-340 signing as defined
|
||||
* in the spec, an optimized tagging implementation is used. */
|
||||
if (secp256k1_memcmp_var(algo16, bip340_algo16, 16) == 0) {
|
||||
secp256k1_nonce_function_bip340_sha256_tagged(&sha);
|
||||
} else {
|
||||
int algo16_len = 16;
|
||||
/* Remove terminating null bytes */
|
||||
while (algo16_len > 0 && !algo16[algo16_len - 1]) {
|
||||
algo16_len--;
|
||||
}
|
||||
secp256k1_sha256_initialize_tagged(&sha, algo16, algo16_len);
|
||||
}
|
||||
|
||||
/* Hash (masked-)key||pk||msg using the tagged hash as per the spec */
|
||||
if (data != NULL) {
|
||||
secp256k1_sha256_write(&sha, masked_key, 32);
|
||||
} else {
|
||||
secp256k1_sha256_write(&sha, key32, 32);
|
||||
}
|
||||
secp256k1_sha256_write(&sha, xonly_pk32, 32);
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
secp256k1_sha256_finalize(&sha, nonce32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340 = nonce_function_bip340;
|
||||
|
||||
/* Initializes SHA256 with fixed midstate. This midstate was computed by applying
|
||||
* SHA256 to SHA256("BIP0340/challenge")||SHA256("BIP0340/challenge"). */
|
||||
static void secp256k1_schnorrsig_sha256_tagged(secp256k1_sha256 *sha) {
|
||||
secp256k1_sha256_initialize(sha);
|
||||
sha->s[0] = 0x9cecba11ul;
|
||||
sha->s[1] = 0x23925381ul;
|
||||
sha->s[2] = 0x11679112ul;
|
||||
sha->s[3] = 0xd1627e0ful;
|
||||
sha->s[4] = 0x97c87550ul;
|
||||
sha->s[5] = 0x003cc765ul;
|
||||
sha->s[6] = 0x90f61164ul;
|
||||
sha->s[7] = 0x33e9b66aul;
|
||||
sha->bytes = 64;
|
||||
}
|
||||
|
||||
static void secp256k1_schnorrsig_challenge(secp256k1_scalar* e, const unsigned char *r32, const unsigned char *msg32, const unsigned char *pubkey32)
|
||||
{
|
||||
unsigned char buf[32];
|
||||
secp256k1_sha256 sha;
|
||||
|
||||
/* tagged hash(r.x, pk.x, msg32) */
|
||||
secp256k1_schnorrsig_sha256_tagged(&sha);
|
||||
secp256k1_sha256_write(&sha, r32, 32);
|
||||
secp256k1_sha256_write(&sha, pubkey32, 32);
|
||||
secp256k1_sha256_write(&sha, msg32, 32);
|
||||
secp256k1_sha256_finalize(&sha, buf);
|
||||
/* Set scalar e to the challenge hash modulo the curve order as per
|
||||
* BIP340. */
|
||||
secp256k1_scalar_set_b32(e, buf, NULL);
|
||||
}
|
||||
|
||||
int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64, const unsigned char *msg32, const secp256k1_keypair *keypair, secp256k1_nonce_function_hardened noncefp, void *ndata) {
|
||||
secp256k1_scalar sk;
|
||||
secp256k1_scalar e;
|
||||
secp256k1_scalar k;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge pk;
|
||||
secp256k1_ge r;
|
||||
unsigned char buf[32] = { 0 };
|
||||
unsigned char pk_buf[32];
|
||||
unsigned char seckey[32];
|
||||
int ret = 1;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(keypair != NULL);
|
||||
|
||||
if (noncefp == NULL) {
|
||||
noncefp = secp256k1_nonce_function_bip340;
|
||||
}
|
||||
|
||||
ret &= secp256k1_keypair_load(ctx, &sk, &pk, keypair);
|
||||
/* Because we are signing for a x-only pubkey, the secret key is negated
|
||||
* before signing if the point corresponding to the secret key does not
|
||||
* have an even Y. */
|
||||
if (secp256k1_fe_is_odd(&pk.y)) {
|
||||
secp256k1_scalar_negate(&sk, &sk);
|
||||
}
|
||||
|
||||
secp256k1_scalar_get_b32(seckey, &sk);
|
||||
secp256k1_fe_get_b32(pk_buf, &pk.x);
|
||||
ret &= !!noncefp(buf, msg32, seckey, pk_buf, bip340_algo16, ndata);
|
||||
secp256k1_scalar_set_b32(&k, buf, NULL);
|
||||
ret &= !secp256k1_scalar_is_zero(&k);
|
||||
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
|
||||
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &rj, &k);
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
|
||||
/* We declassify r to allow using it as a branch point. This is fine
|
||||
* because r is not a secret. */
|
||||
secp256k1_declassify(ctx, &r, sizeof(r));
|
||||
secp256k1_fe_normalize_var(&r.y);
|
||||
if (secp256k1_fe_is_odd(&r.y)) {
|
||||
secp256k1_scalar_negate(&k, &k);
|
||||
}
|
||||
secp256k1_fe_normalize_var(&r.x);
|
||||
secp256k1_fe_get_b32(&sig64[0], &r.x);
|
||||
|
||||
secp256k1_schnorrsig_challenge(&e, &sig64[0], msg32, pk_buf);
|
||||
secp256k1_scalar_mul(&e, &e, &sk);
|
||||
secp256k1_scalar_add(&e, &e, &k);
|
||||
secp256k1_scalar_get_b32(&sig64[32], &e);
|
||||
|
||||
secp256k1_memczero(sig64, 64, !ret);
|
||||
secp256k1_scalar_clear(&k);
|
||||
secp256k1_scalar_clear(&sk);
|
||||
memset(seckey, 0, sizeof(seckey));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const unsigned char *sig64, const unsigned char *msg32, const secp256k1_xonly_pubkey *pubkey) {
|
||||
secp256k1_scalar s;
|
||||
secp256k1_scalar e;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge pk;
|
||||
secp256k1_gej pkj;
|
||||
secp256k1_fe rx;
|
||||
secp256k1_ge r;
|
||||
unsigned char buf[32];
|
||||
int overflow;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(sig64 != NULL);
|
||||
ARG_CHECK(msg32 != NULL);
|
||||
ARG_CHECK(pubkey != NULL);
|
||||
|
||||
if (!secp256k1_fe_set_b32(&rx, &sig64[0])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_b32(&s, &sig64[32], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!secp256k1_xonly_pubkey_load(ctx, &pk, pubkey)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute e. */
|
||||
secp256k1_fe_get_b32(buf, &pk.x);
|
||||
secp256k1_schnorrsig_challenge(&e, &sig64[0], msg32, buf);
|
||||
|
||||
/* Compute rj = s*G + (-e)*pkj */
|
||||
secp256k1_scalar_negate(&e, &e);
|
||||
secp256k1_gej_set_ge(&pkj, &pk);
|
||||
secp256k1_ecmult(&ctx->ecmult_ctx, &rj, &pkj, &e, &s);
|
||||
|
||||
secp256k1_ge_set_gej_var(&r, &rj);
|
||||
if (secp256k1_ge_is_infinity(&r)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_fe_normalize_var(&r.y);
|
||||
return !secp256k1_fe_is_odd(&r.y) &&
|
||||
secp256k1_fe_equal_var(&rx, &r.x);
|
||||
}
|
||||
|
||||
#endif
|
||||
206
src/modules/schnorrsig/tests_exhaustive_impl.h
Normal file
206
src/modules/schnorrsig/tests_exhaustive_impl.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2020 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_
|
||||
#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_EXHAUSTIVE_
|
||||
|
||||
#include "include/secp256k1_schnorrsig.h"
|
||||
#include "src/modules/schnorrsig/main_impl.h"
|
||||
|
||||
static const unsigned char invalid_pubkey_bytes[][32] = {
|
||||
/* 0 */
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
},
|
||||
/* 2 */
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2
|
||||
},
|
||||
/* order */
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
((EXHAUSTIVE_TEST_ORDER + 0UL) >> 24) & 0xFF,
|
||||
((EXHAUSTIVE_TEST_ORDER + 0UL) >> 16) & 0xFF,
|
||||
((EXHAUSTIVE_TEST_ORDER + 0UL) >> 8) & 0xFF,
|
||||
(EXHAUSTIVE_TEST_ORDER + 0UL) & 0xFF
|
||||
},
|
||||
/* order + 1 */
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
((EXHAUSTIVE_TEST_ORDER + 1UL) >> 24) & 0xFF,
|
||||
((EXHAUSTIVE_TEST_ORDER + 1UL) >> 16) & 0xFF,
|
||||
((EXHAUSTIVE_TEST_ORDER + 1UL) >> 8) & 0xFF,
|
||||
(EXHAUSTIVE_TEST_ORDER + 1UL) & 0xFF
|
||||
},
|
||||
/* field size */
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 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
|
||||
},
|
||||
/* field size + 1 (note that 1 is legal) */
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 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, 0x30
|
||||
},
|
||||
/* 2^256 - 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, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
}
|
||||
};
|
||||
|
||||
#define NUM_INVALID_KEYS (sizeof(invalid_pubkey_bytes) / sizeof(invalid_pubkey_bytes[0]))
|
||||
|
||||
static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,
|
||||
const unsigned char *key32, const unsigned char *xonly_pk32,
|
||||
const unsigned char *algo16, void* data) {
|
||||
secp256k1_scalar s;
|
||||
int *idata = data;
|
||||
(void)msg32;
|
||||
(void)key32;
|
||||
(void)xonly_pk32;
|
||||
(void)algo16;
|
||||
secp256k1_scalar_set_int(&s, *idata);
|
||||
secp256k1_scalar_get_b32(nonce32, &s);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_exhaustive_schnorrsig_verify(const secp256k1_context *ctx, const secp256k1_xonly_pubkey* pubkeys, unsigned char (*xonly_pubkey_bytes)[32], const int* parities) {
|
||||
int d;
|
||||
uint64_t iter = 0;
|
||||
/* Iterate over the possible public keys to verify against (through their corresponding DL d). */
|
||||
for (d = 1; d <= EXHAUSTIVE_TEST_ORDER / 2; ++d) {
|
||||
int actual_d;
|
||||
unsigned k;
|
||||
unsigned char pk32[32];
|
||||
memcpy(pk32, xonly_pubkey_bytes[d - 1], 32);
|
||||
actual_d = parities[d - 1] ? EXHAUSTIVE_TEST_ORDER - d : d;
|
||||
/* Iterate over the possible valid first 32 bytes in the signature, through their corresponding DL k.
|
||||
Values above EXHAUSTIVE_TEST_ORDER/2 refer to the entries in invalid_pubkey_bytes. */
|
||||
for (k = 1; k <= EXHAUSTIVE_TEST_ORDER / 2 + NUM_INVALID_KEYS; ++k) {
|
||||
unsigned char sig64[64];
|
||||
int actual_k = -1;
|
||||
int e_done[EXHAUSTIVE_TEST_ORDER] = {0};
|
||||
int e_count_done = 0;
|
||||
if (skip_section(&iter)) continue;
|
||||
if (k <= EXHAUSTIVE_TEST_ORDER / 2) {
|
||||
memcpy(sig64, xonly_pubkey_bytes[k - 1], 32);
|
||||
actual_k = parities[k - 1] ? EXHAUSTIVE_TEST_ORDER - k : k;
|
||||
} else {
|
||||
memcpy(sig64, invalid_pubkey_bytes[k - 1 - EXHAUSTIVE_TEST_ORDER / 2], 32);
|
||||
}
|
||||
/* Randomly generate messages until all challenges have been hit. */
|
||||
while (e_count_done < EXHAUSTIVE_TEST_ORDER) {
|
||||
secp256k1_scalar e;
|
||||
unsigned char msg32[32];
|
||||
secp256k1_testrand256(msg32);
|
||||
secp256k1_schnorrsig_challenge(&e, sig64, msg32, pk32);
|
||||
/* Only do work if we hit a challenge we haven't tried before. */
|
||||
if (!e_done[e]) {
|
||||
/* Iterate over the possible valid last 32 bytes in the signature.
|
||||
0..order=that s value; order+1=random bytes */
|
||||
int count_valid = 0, 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);
|
||||
expect_valid = actual_k != -1 && s != EXHAUSTIVE_TEST_ORDER &&
|
||||
(s_s == (actual_k + actual_d * e) % EXHAUSTIVE_TEST_ORDER);
|
||||
} else {
|
||||
secp256k1_testrand256(sig64 + 32);
|
||||
expect_valid = 0;
|
||||
}
|
||||
valid = secp256k1_schnorrsig_verify(ctx, sig64, msg32, &pubkeys[d - 1]);
|
||||
CHECK(valid == expect_valid);
|
||||
count_valid += valid;
|
||||
}
|
||||
/* Exactly one s value must verify, unless R is illegal. */
|
||||
CHECK(count_valid == (actual_k != -1));
|
||||
/* Don't retry other messages that result in the same challenge. */
|
||||
e_done[e] = 1;
|
||||
++e_count_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_exhaustive_schnorrsig_sign(const secp256k1_context *ctx, unsigned char (*xonly_pubkey_bytes)[32], const secp256k1_keypair* keypairs, const int* parities) {
|
||||
int d, k;
|
||||
uint64_t iter = 0;
|
||||
/* Loop over keys. */
|
||||
for (d = 1; d < EXHAUSTIVE_TEST_ORDER; ++d) {
|
||||
int actual_d = d;
|
||||
if (parities[d - 1]) actual_d = EXHAUSTIVE_TEST_ORDER - d;
|
||||
/* Loop over nonces. */
|
||||
for (k = 1; k < EXHAUSTIVE_TEST_ORDER; ++k) {
|
||||
int e_done[EXHAUSTIVE_TEST_ORDER] = {0};
|
||||
int e_count_done = 0;
|
||||
unsigned char msg32[32];
|
||||
unsigned char sig64[64];
|
||||
int actual_k = k;
|
||||
if (skip_section(&iter)) continue;
|
||||
if (parities[k - 1]) actual_k = EXHAUSTIVE_TEST_ORDER - k;
|
||||
/* Generate random messages until all challenges have been tried. */
|
||||
while (e_count_done < EXHAUSTIVE_TEST_ORDER) {
|
||||
secp256k1_scalar e;
|
||||
secp256k1_testrand256(msg32);
|
||||
secp256k1_schnorrsig_challenge(&e, xonly_pubkey_bytes[k - 1], msg32, xonly_pubkey_bytes[d - 1]);
|
||||
/* Only do work if we hit a challenge we haven't tried before. */
|
||||
if (!e_done[e]) {
|
||||
secp256k1_scalar expected_s = (actual_k + e * actual_d) % EXHAUSTIVE_TEST_ORDER;
|
||||
unsigned char expected_s_bytes[32];
|
||||
secp256k1_scalar_get_b32(expected_s_bytes, &expected_s);
|
||||
/* Invoke the real function to construct a signature. */
|
||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig64, msg32, &keypairs[d - 1], secp256k1_hardened_nonce_function_smallint, &k));
|
||||
/* The first 32 bytes must match the xonly pubkey for the specified k. */
|
||||
CHECK(secp256k1_memcmp_var(sig64, xonly_pubkey_bytes[k - 1], 32) == 0);
|
||||
/* The last 32 bytes must match the expected s value. */
|
||||
CHECK(secp256k1_memcmp_var(sig64 + 32, expected_s_bytes, 32) == 0);
|
||||
/* Don't retry other messages that result in the same challenge. */
|
||||
e_done[e] = 1;
|
||||
++e_count_done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_exhaustive_schnorrsig(const secp256k1_context *ctx) {
|
||||
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
int parity[EXHAUSTIVE_TEST_ORDER - 1];
|
||||
unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32];
|
||||
unsigned i;
|
||||
|
||||
/* Verify that all invalid_pubkey_bytes are actually invalid. */
|
||||
for (i = 0; i < NUM_INVALID_KEYS; ++i) {
|
||||
secp256k1_xonly_pubkey pk;
|
||||
CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk, invalid_pubkey_bytes[i]));
|
||||
}
|
||||
|
||||
/* Construct keypairs and xonly-pubkeys for the entire group. */
|
||||
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; ++i) {
|
||||
secp256k1_scalar scalar_i;
|
||||
unsigned char buf[32];
|
||||
secp256k1_scalar_set_int(&scalar_i, i);
|
||||
secp256k1_scalar_get_b32(buf, &scalar_i);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf));
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parity[i - 1], &keypair[i - 1]));
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1]));
|
||||
}
|
||||
|
||||
test_exhaustive_schnorrsig_sign(ctx, xonly_pubkey_bytes, keypair, parity);
|
||||
test_exhaustive_schnorrsig_verify(ctx, xonly_pubkey, xonly_pubkey_bytes, parity);
|
||||
}
|
||||
|
||||
#endif
|
||||
806
src/modules/schnorrsig/tests_impl.h
Normal file
806
src/modules/schnorrsig/tests_impl.h
Normal file
@@ -0,0 +1,806 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2018-2020 Andrew Poelstra, Jonas Nick *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_MODULE_SCHNORRSIG_TESTS_
|
||||
#define _SECP256K1_MODULE_SCHNORRSIG_TESTS_
|
||||
|
||||
#include "secp256k1_schnorrsig.h"
|
||||
|
||||
/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many
|
||||
* bytes) changes the hash function
|
||||
*/
|
||||
void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) {
|
||||
unsigned char nonces[2][32];
|
||||
CHECK(nonce_function_bip340(nonces[0], args[0], args[1], args[2], args[3], args[4]) == 1);
|
||||
secp256k1_testrand_flip(args[n_flip], n_bytes);
|
||||
CHECK(nonce_function_bip340(nonces[1], args[0], args[1], args[2], args[3], args[4]) == 1);
|
||||
CHECK(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. */
|
||||
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);
|
||||
}
|
||||
|
||||
void run_nonce_function_bip340_tests(void) {
|
||||
unsigned char tag[13] = "BIP0340/nonce";
|
||||
unsigned char aux_tag[11] = "BIP0340/aux";
|
||||
unsigned char algo16[16] = "BIP0340/nonce\0\0\0";
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256 sha_optimized;
|
||||
unsigned char nonce[32];
|
||||
unsigned char msg[32];
|
||||
unsigned char key[32];
|
||||
unsigned char pk[32];
|
||||
unsigned char aux_rand[32];
|
||||
unsigned char *args[5];
|
||||
int i;
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_nonce_function_bip340_sha256_tagged has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, tag, sizeof(tag));
|
||||
secp256k1_nonce_function_bip340_sha256_tagged(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
|
||||
/* Check that hash initialized by
|
||||
* secp256k1_nonce_function_bip340_sha256_tagged_aux has the expected
|
||||
* state. */
|
||||
secp256k1_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag));
|
||||
secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
|
||||
secp256k1_testrand256(msg);
|
||||
secp256k1_testrand256(key);
|
||||
secp256k1_testrand256(pk);
|
||||
secp256k1_testrand256(aux_rand);
|
||||
|
||||
/* Check that a bitflip in an argument results in different nonces. */
|
||||
args[0] = msg;
|
||||
args[1] = key;
|
||||
args[2] = pk;
|
||||
args[3] = algo16;
|
||||
args[4] = aux_rand;
|
||||
for (i = 0; i < count; i++) {
|
||||
nonce_function_bip340_bitflip(args, 0, 32);
|
||||
nonce_function_bip340_bitflip(args, 1, 32);
|
||||
nonce_function_bip340_bitflip(args, 2, 32);
|
||||
/* Flip algo16 special case "BIP0340/nonce" */
|
||||
nonce_function_bip340_bitflip(args, 3, 16);
|
||||
/* Flip algo16 again */
|
||||
nonce_function_bip340_bitflip(args, 3, 16);
|
||||
nonce_function_bip340_bitflip(args, 4, 32);
|
||||
}
|
||||
|
||||
/* NULL algo16 is disallowed */
|
||||
CHECK(nonce_function_bip340(nonce, msg, key, pk, NULL, NULL) == 0);
|
||||
/* Empty algo16 is fine */
|
||||
memset(algo16, 0x00, 16);
|
||||
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
|
||||
/* algo16 with terminating null bytes is fine */
|
||||
algo16[1] = 65;
|
||||
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
|
||||
/* Other algo16 is fine */
|
||||
memset(algo16, 0xFF, 16);
|
||||
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
|
||||
|
||||
/* NULL aux_rand argument is allowed. */
|
||||
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
|
||||
}
|
||||
|
||||
void test_schnorrsig_api(void) {
|
||||
unsigned char sk1[32];
|
||||
unsigned char sk2[32];
|
||||
unsigned char sk3[32];
|
||||
unsigned char msg[32];
|
||||
secp256k1_keypair keypairs[3];
|
||||
secp256k1_keypair invalid_keypair = { 0 };
|
||||
secp256k1_xonly_pubkey pk[3];
|
||||
secp256k1_xonly_pubkey zero_pk;
|
||||
unsigned char sig[64];
|
||||
|
||||
/** setup **/
|
||||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
int ecount;
|
||||
|
||||
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount);
|
||||
secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount);
|
||||
|
||||
secp256k1_testrand256(sk1);
|
||||
secp256k1_testrand256(sk2);
|
||||
secp256k1_testrand256(sk3);
|
||||
secp256k1_testrand256(msg);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypairs[0], sk1) == 1);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypairs[1], sk2) == 1);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypairs[2], sk3) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[0], NULL, &keypairs[0]) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[1], NULL, &keypairs[1]) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk[2], NULL, &keypairs[2]) == 1);
|
||||
memset(&zero_pk, 0, sizeof(zero_pk));
|
||||
|
||||
/** main test body **/
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_schnorrsig_sign(none, sig, msg, &keypairs[0], NULL, NULL) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_schnorrsig_sign(vrfy, sig, msg, &keypairs[0], NULL, NULL) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL, NULL) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_schnorrsig_sign(sign, NULL, msg, &keypairs[0], NULL, NULL) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_schnorrsig_sign(sign, sig, NULL, &keypairs[0], NULL, NULL) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, NULL, NULL, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &invalid_keypair, NULL, NULL) == 0);
|
||||
CHECK(ecount == 6);
|
||||
|
||||
ecount = 0;
|
||||
CHECK(secp256k1_schnorrsig_sign(sign, sig, msg, &keypairs[0], NULL, NULL) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(none, sig, msg, &pk[0]) == 0);
|
||||
CHECK(ecount == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(sign, sig, msg, &pk[0]) == 0);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, &pk[0]) == 1);
|
||||
CHECK(ecount == 2);
|
||||
CHECK(secp256k1_schnorrsig_verify(vrfy, NULL, msg, &pk[0]) == 0);
|
||||
CHECK(ecount == 3);
|
||||
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, NULL, &pk[0]) == 0);
|
||||
CHECK(ecount == 4);
|
||||
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, NULL) == 0);
|
||||
CHECK(ecount == 5);
|
||||
CHECK(secp256k1_schnorrsig_verify(vrfy, sig, msg, &zero_pk) == 0);
|
||||
CHECK(ecount == 6);
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(vrfy);
|
||||
secp256k1_context_destroy(both);
|
||||
}
|
||||
|
||||
/* Checks that hash initialized by secp256k1_schnorrsig_sha256_tagged has the
|
||||
* expected state. */
|
||||
void test_schnorrsig_sha256_tagged(void) {
|
||||
char tag[17] = "BIP0340/challenge";
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256 sha_optimized;
|
||||
|
||||
secp256k1_sha256_initialize_tagged(&sha, (unsigned char *) tag, sizeof(tag));
|
||||
secp256k1_schnorrsig_sha256_tagged(&sha_optimized);
|
||||
test_sha256_eq(&sha, &sha_optimized);
|
||||
}
|
||||
|
||||
/* Helper function for schnorrsig_bip_vectors
|
||||
* Signs the message and checks that it's the same as expected_sig. */
|
||||
void test_schnorrsig_bip_vectors_check_signing(const unsigned char *sk, const unsigned char *pk_serialized, unsigned char *aux_rand, const unsigned char *msg, const unsigned char *expected_sig) {
|
||||
unsigned char sig[64];
|
||||
secp256k1_keypair keypair;
|
||||
secp256k1_xonly_pubkey pk, pk_expected;
|
||||
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
|
||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, aux_rand));
|
||||
CHECK(secp256k1_memcmp_var(sig, expected_sig, 64) == 0);
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk_expected, pk_serialized));
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
|
||||
CHECK(secp256k1_memcmp_var(&pk, &pk_expected, sizeof(pk)) == 0);
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, &pk));
|
||||
}
|
||||
|
||||
/* Helper function for schnorrsig_bip_vectors
|
||||
* Checks that both verify and verify_batch (TODO) return the same value as expected. */
|
||||
void test_schnorrsig_bip_vectors_check_verify(const unsigned char *pk_serialized, const unsigned char *msg32, const unsigned char *sig, int expected) {
|
||||
secp256k1_xonly_pubkey pk;
|
||||
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &pk, pk_serialized));
|
||||
CHECK(expected == secp256k1_schnorrsig_verify(ctx, sig, msg32, &pk));
|
||||
}
|
||||
|
||||
/* Test vectors according to BIP-340 ("Schnorr Signatures for secp256k1"). See
|
||||
* https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv. */
|
||||
void test_schnorrsig_bip_vectors(void) {
|
||||
{
|
||||
/* Test vector 0 */
|
||||
const unsigned char sk[32] = {
|
||||
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, 0x03
|
||||
};
|
||||
const unsigned char pk[32] = {
|
||||
0xF9, 0x30, 0x8A, 0x01, 0x92, 0x58, 0xC3, 0x10,
|
||||
0x49, 0x34, 0x4F, 0x85, 0xF8, 0x9D, 0x52, 0x29,
|
||||
0xB5, 0x31, 0xC8, 0x45, 0x83, 0x6F, 0x99, 0xB0,
|
||||
0x86, 0x01, 0xF1, 0x13, 0xBC, 0xE0, 0x36, 0xF9
|
||||
};
|
||||
unsigned char aux_rand[32] = {
|
||||
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
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
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
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0xE9, 0x07, 0x83, 0x1F, 0x80, 0x84, 0x8D, 0x10,
|
||||
0x69, 0xA5, 0x37, 0x1B, 0x40, 0x24, 0x10, 0x36,
|
||||
0x4B, 0xDF, 0x1C, 0x5F, 0x83, 0x07, 0xB0, 0x08,
|
||||
0x4C, 0x55, 0xF1, 0xCE, 0x2D, 0xCA, 0x82, 0x15,
|
||||
0x25, 0xF6, 0x6A, 0x4A, 0x85, 0xEA, 0x8B, 0x71,
|
||||
0xE4, 0x82, 0xA7, 0x4F, 0x38, 0x2D, 0x2C, 0xE5,
|
||||
0xEB, 0xEE, 0xE8, 0xFD, 0xB2, 0x17, 0x2F, 0x47,
|
||||
0x7D, 0xF4, 0x90, 0x0D, 0x31, 0x05, 0x36, 0xC0
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
|
||||
}
|
||||
{
|
||||
/* Test vector 1 */
|
||||
const unsigned char sk[32] = {
|
||||
0xB7, 0xE1, 0x51, 0x62, 0x8A, 0xED, 0x2A, 0x6A,
|
||||
0xBF, 0x71, 0x58, 0x80, 0x9C, 0xF4, 0xF3, 0xC7,
|
||||
0x62, 0xE7, 0x16, 0x0F, 0x38, 0xB4, 0xDA, 0x56,
|
||||
0xA7, 0x84, 0xD9, 0x04, 0x51, 0x90, 0xCF, 0xEF
|
||||
};
|
||||
const unsigned char pk[32] = {
|
||||
0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
|
||||
0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
|
||||
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
|
||||
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
|
||||
};
|
||||
unsigned char aux_rand[32] = {
|
||||
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
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
|
||||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
|
||||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
|
||||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0x68, 0x96, 0xBD, 0x60, 0xEE, 0xAE, 0x29, 0x6D,
|
||||
0xB4, 0x8A, 0x22, 0x9F, 0xF7, 0x1D, 0xFE, 0x07,
|
||||
0x1B, 0xDE, 0x41, 0x3E, 0x6D, 0x43, 0xF9, 0x17,
|
||||
0xDC, 0x8D, 0xCF, 0x8C, 0x78, 0xDE, 0x33, 0x41,
|
||||
0x89, 0x06, 0xD1, 0x1A, 0xC9, 0x76, 0xAB, 0xCC,
|
||||
0xB2, 0x0B, 0x09, 0x12, 0x92, 0xBF, 0xF4, 0xEA,
|
||||
0x89, 0x7E, 0xFC, 0xB6, 0x39, 0xEA, 0x87, 0x1C,
|
||||
0xFA, 0x95, 0xF6, 0xDE, 0x33, 0x9E, 0x4B, 0x0A
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
|
||||
}
|
||||
{
|
||||
/* Test vector 2 */
|
||||
const unsigned char sk[32] = {
|
||||
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
|
||||
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
|
||||
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
|
||||
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x14, 0xE5, 0xC9
|
||||
};
|
||||
const unsigned char pk[32] = {
|
||||
0xDD, 0x30, 0x8A, 0xFE, 0xC5, 0x77, 0x7E, 0x13,
|
||||
0x12, 0x1F, 0xA7, 0x2B, 0x9C, 0xC1, 0xB7, 0xCC,
|
||||
0x01, 0x39, 0x71, 0x53, 0x09, 0xB0, 0x86, 0xC9,
|
||||
0x60, 0xE1, 0x8F, 0xD9, 0x69, 0x77, 0x4E, 0xB8
|
||||
};
|
||||
unsigned char aux_rand[32] = {
|
||||
0xC8, 0x7A, 0xA5, 0x38, 0x24, 0xB4, 0xD7, 0xAE,
|
||||
0x2E, 0xB0, 0x35, 0xA2, 0xB5, 0xBB, 0xBC, 0xCC,
|
||||
0x08, 0x0E, 0x76, 0xCD, 0xC6, 0xD1, 0x69, 0x2C,
|
||||
0x4B, 0x0B, 0x62, 0xD7, 0x98, 0xE6, 0xD9, 0x06
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x7E, 0x2D, 0x58, 0xD8, 0xB3, 0xBC, 0xDF, 0x1A,
|
||||
0xBA, 0xDE, 0xC7, 0x82, 0x90, 0x54, 0xF9, 0x0D,
|
||||
0xDA, 0x98, 0x05, 0xAA, 0xB5, 0x6C, 0x77, 0x33,
|
||||
0x30, 0x24, 0xB9, 0xD0, 0xA5, 0x08, 0xB7, 0x5C
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0x58, 0x31, 0xAA, 0xEE, 0xD7, 0xB4, 0x4B, 0xB7,
|
||||
0x4E, 0x5E, 0xAB, 0x94, 0xBA, 0x9D, 0x42, 0x94,
|
||||
0xC4, 0x9B, 0xCF, 0x2A, 0x60, 0x72, 0x8D, 0x8B,
|
||||
0x4C, 0x20, 0x0F, 0x50, 0xDD, 0x31, 0x3C, 0x1B,
|
||||
0xAB, 0x74, 0x58, 0x79, 0xA5, 0xAD, 0x95, 0x4A,
|
||||
0x72, 0xC4, 0x5A, 0x91, 0xC3, 0xA5, 0x1D, 0x3C,
|
||||
0x7A, 0xDE, 0xA9, 0x8D, 0x82, 0xF8, 0x48, 0x1E,
|
||||
0x0E, 0x1E, 0x03, 0x67, 0x4A, 0x6F, 0x3F, 0xB7
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
|
||||
}
|
||||
{
|
||||
/* Test vector 3 */
|
||||
const unsigned char sk[32] = {
|
||||
0x0B, 0x43, 0x2B, 0x26, 0x77, 0x93, 0x73, 0x81,
|
||||
0xAE, 0xF0, 0x5B, 0xB0, 0x2A, 0x66, 0xEC, 0xD0,
|
||||
0x12, 0x77, 0x30, 0x62, 0xCF, 0x3F, 0xA2, 0x54,
|
||||
0x9E, 0x44, 0xF5, 0x8E, 0xD2, 0x40, 0x17, 0x10
|
||||
};
|
||||
const unsigned char pk[32] = {
|
||||
0x25, 0xD1, 0xDF, 0xF9, 0x51, 0x05, 0xF5, 0x25,
|
||||
0x3C, 0x40, 0x22, 0xF6, 0x28, 0xA9, 0x96, 0xAD,
|
||||
0x3A, 0x0D, 0x95, 0xFB, 0xF2, 0x1D, 0x46, 0x8A,
|
||||
0x1B, 0x33, 0xF8, 0xC1, 0x60, 0xD8, 0xF5, 0x17
|
||||
};
|
||||
unsigned char aux_rand[32] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0x7E, 0xB0, 0x50, 0x97, 0x57, 0xE2, 0x46, 0xF1,
|
||||
0x94, 0x49, 0x88, 0x56, 0x51, 0x61, 0x1C, 0xB9,
|
||||
0x65, 0xEC, 0xC1, 0xA1, 0x87, 0xDD, 0x51, 0xB6,
|
||||
0x4F, 0xDA, 0x1E, 0xDC, 0x96, 0x37, 0xD5, 0xEC,
|
||||
0x97, 0x58, 0x2B, 0x9C, 0xB1, 0x3D, 0xB3, 0x93,
|
||||
0x37, 0x05, 0xB3, 0x2B, 0xA9, 0x82, 0xAF, 0x5A,
|
||||
0xF2, 0x5F, 0xD7, 0x88, 0x81, 0xEB, 0xB3, 0x27,
|
||||
0x71, 0xFC, 0x59, 0x22, 0xEF, 0xC6, 0x6E, 0xA3
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_signing(sk, pk, aux_rand, msg, sig);
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
|
||||
}
|
||||
{
|
||||
/* Test vector 4 */
|
||||
const unsigned char pk[32] = {
|
||||
0xD6, 0x9C, 0x35, 0x09, 0xBB, 0x99, 0xE4, 0x12,
|
||||
0xE6, 0x8B, 0x0F, 0xE8, 0x54, 0x4E, 0x72, 0x83,
|
||||
0x7D, 0xFA, 0x30, 0x74, 0x6D, 0x8B, 0xE2, 0xAA,
|
||||
0x65, 0x97, 0x5F, 0x29, 0xD2, 0x2D, 0xC7, 0xB9
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x4D, 0xF3, 0xC3, 0xF6, 0x8F, 0xCC, 0x83, 0xB2,
|
||||
0x7E, 0x9D, 0x42, 0xC9, 0x04, 0x31, 0xA7, 0x24,
|
||||
0x99, 0xF1, 0x78, 0x75, 0xC8, 0x1A, 0x59, 0x9B,
|
||||
0x56, 0x6C, 0x98, 0x89, 0xB9, 0x69, 0x67, 0x03
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x3B, 0x78, 0xCE, 0x56, 0x3F,
|
||||
0x89, 0xA0, 0xED, 0x94, 0x14, 0xF5, 0xAA, 0x28,
|
||||
0xAD, 0x0D, 0x96, 0xD6, 0x79, 0x5F, 0x9C, 0x63,
|
||||
0x76, 0xAF, 0xB1, 0x54, 0x8A, 0xF6, 0x03, 0xB3,
|
||||
0xEB, 0x45, 0xC9, 0xF8, 0x20, 0x7D, 0xEE, 0x10,
|
||||
0x60, 0xCB, 0x71, 0xC0, 0x4E, 0x80, 0xF5, 0x93,
|
||||
0x06, 0x0B, 0x07, 0xD2, 0x83, 0x08, 0xD7, 0xF4
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 1);
|
||||
}
|
||||
{
|
||||
/* Test vector 5 */
|
||||
const unsigned char pk[32] = {
|
||||
0xEE, 0xFD, 0xEA, 0x4C, 0xDB, 0x67, 0x77, 0x50,
|
||||
0xA4, 0x20, 0xFE, 0xE8, 0x07, 0xEA, 0xCF, 0x21,
|
||||
0xEB, 0x98, 0x98, 0xAE, 0x79, 0xB9, 0x76, 0x87,
|
||||
0x66, 0xE4, 0xFA, 0xA0, 0x4A, 0x2D, 0x4A, 0x34
|
||||
};
|
||||
secp256k1_xonly_pubkey pk_parsed;
|
||||
/* No need to check the signature of the test vector as parsing the pubkey already fails */
|
||||
CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk_parsed, pk));
|
||||
}
|
||||
{
|
||||
/* Test vector 6 */
|
||||
const unsigned char pk[32] = {
|
||||
0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
|
||||
0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
|
||||
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
|
||||
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
|
||||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
|
||||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
|
||||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0xFF, 0xF9, 0x7B, 0xD5, 0x75, 0x5E, 0xEE, 0xA4,
|
||||
0x20, 0x45, 0x3A, 0x14, 0x35, 0x52, 0x35, 0xD3,
|
||||
0x82, 0xF6, 0x47, 0x2F, 0x85, 0x68, 0xA1, 0x8B,
|
||||
0x2F, 0x05, 0x7A, 0x14, 0x60, 0x29, 0x75, 0x56,
|
||||
0x3C, 0xC2, 0x79, 0x44, 0x64, 0x0A, 0xC6, 0x07,
|
||||
0xCD, 0x10, 0x7A, 0xE1, 0x09, 0x23, 0xD9, 0xEF,
|
||||
0x7A, 0x73, 0xC6, 0x43, 0xE1, 0x66, 0xBE, 0x5E,
|
||||
0xBE, 0xAF, 0xA3, 0x4B, 0x1A, 0xC5, 0x53, 0xE2
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
|
||||
}
|
||||
{
|
||||
/* Test vector 7 */
|
||||
const unsigned char pk[32] = {
|
||||
0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
|
||||
0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
|
||||
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
|
||||
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
|
||||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
|
||||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
|
||||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0x1F, 0xA6, 0x2E, 0x33, 0x1E, 0xDB, 0xC2, 0x1C,
|
||||
0x39, 0x47, 0x92, 0xD2, 0xAB, 0x11, 0x00, 0xA7,
|
||||
0xB4, 0x32, 0xB0, 0x13, 0xDF, 0x3F, 0x6F, 0xF4,
|
||||
0xF9, 0x9F, 0xCB, 0x33, 0xE0, 0xE1, 0x51, 0x5F,
|
||||
0x28, 0x89, 0x0B, 0x3E, 0xDB, 0x6E, 0x71, 0x89,
|
||||
0xB6, 0x30, 0x44, 0x8B, 0x51, 0x5C, 0xE4, 0xF8,
|
||||
0x62, 0x2A, 0x95, 0x4C, 0xFE, 0x54, 0x57, 0x35,
|
||||
0xAA, 0xEA, 0x51, 0x34, 0xFC, 0xCD, 0xB2, 0xBD
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
|
||||
}
|
||||
{
|
||||
/* Test vector 8 */
|
||||
const unsigned char pk[32] = {
|
||||
0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
|
||||
0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
|
||||
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
|
||||
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
|
||||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
|
||||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
|
||||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0x6C, 0xFF, 0x5C, 0x3B, 0xA8, 0x6C, 0x69, 0xEA,
|
||||
0x4B, 0x73, 0x76, 0xF3, 0x1A, 0x9B, 0xCB, 0x4F,
|
||||
0x74, 0xC1, 0x97, 0x60, 0x89, 0xB2, 0xD9, 0x96,
|
||||
0x3D, 0xA2, 0xE5, 0x54, 0x3E, 0x17, 0x77, 0x69,
|
||||
0x96, 0x17, 0x64, 0xB3, 0xAA, 0x9B, 0x2F, 0xFC,
|
||||
0xB6, 0xEF, 0x94, 0x7B, 0x68, 0x87, 0xA2, 0x26,
|
||||
0xE8, 0xD7, 0xC9, 0x3E, 0x00, 0xC5, 0xED, 0x0C,
|
||||
0x18, 0x34, 0xFF, 0x0D, 0x0C, 0x2E, 0x6D, 0xA6
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
|
||||
}
|
||||
{
|
||||
/* Test vector 9 */
|
||||
const unsigned char pk[32] = {
|
||||
0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
|
||||
0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
|
||||
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
|
||||
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
|
||||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
|
||||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
|
||||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
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,
|
||||
0x12, 0x3D, 0xDA, 0x83, 0x28, 0xAF, 0x9C, 0x23,
|
||||
0xA9, 0x4C, 0x1F, 0xEE, 0xCF, 0xD1, 0x23, 0xBA,
|
||||
0x4F, 0xB7, 0x34, 0x76, 0xF0, 0xD5, 0x94, 0xDC,
|
||||
0xB6, 0x5C, 0x64, 0x25, 0xBD, 0x18, 0x60, 0x51
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
|
||||
}
|
||||
{
|
||||
/* Test vector 10 */
|
||||
const unsigned char pk[32] = {
|
||||
0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
|
||||
0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
|
||||
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
|
||||
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
|
||||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
|
||||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
|
||||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
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,
|
||||
0x76, 0x15, 0xFB, 0xAF, 0x5A, 0xE2, 0x88, 0x64,
|
||||
0x01, 0x3C, 0x09, 0x97, 0x42, 0xDE, 0xAD, 0xB4,
|
||||
0xDB, 0xA8, 0x7F, 0x11, 0xAC, 0x67, 0x54, 0xF9,
|
||||
0x37, 0x80, 0xD5, 0xA1, 0x83, 0x7C, 0xF1, 0x97
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
|
||||
}
|
||||
{
|
||||
/* Test vector 11 */
|
||||
const unsigned char pk[32] = {
|
||||
0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
|
||||
0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
|
||||
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
|
||||
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
|
||||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
|
||||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
|
||||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0x4A, 0x29, 0x8D, 0xAC, 0xAE, 0x57, 0x39, 0x5A,
|
||||
0x15, 0xD0, 0x79, 0x5D, 0xDB, 0xFD, 0x1D, 0xCB,
|
||||
0x56, 0x4D, 0xA8, 0x2B, 0x0F, 0x26, 0x9B, 0xC7,
|
||||
0x0A, 0x74, 0xF8, 0x22, 0x04, 0x29, 0xBA, 0x1D,
|
||||
0x69, 0xE8, 0x9B, 0x4C, 0x55, 0x64, 0xD0, 0x03,
|
||||
0x49, 0x10, 0x6B, 0x84, 0x97, 0x78, 0x5D, 0xD7,
|
||||
0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F,
|
||||
0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
|
||||
}
|
||||
{
|
||||
/* Test vector 12 */
|
||||
const unsigned char pk[32] = {
|
||||
0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
|
||||
0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
|
||||
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
|
||||
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
|
||||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
|
||||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
|
||||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0xFF, 0xFF, 0xFF, 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,
|
||||
0x69, 0xE8, 0x9B, 0x4C, 0x55, 0x64, 0xD0, 0x03,
|
||||
0x49, 0x10, 0x6B, 0x84, 0x97, 0x78, 0x5D, 0xD7,
|
||||
0xD1, 0xD7, 0x13, 0xA8, 0xAE, 0x82, 0xB3, 0x2F,
|
||||
0xA7, 0x9D, 0x5F, 0x7F, 0xC4, 0x07, 0xD3, 0x9B
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
|
||||
}
|
||||
{
|
||||
/* Test vector 13 */
|
||||
const unsigned char pk[32] = {
|
||||
0xDF, 0xF1, 0xD7, 0x7F, 0x2A, 0x67, 0x1C, 0x5F,
|
||||
0x36, 0x18, 0x37, 0x26, 0xDB, 0x23, 0x41, 0xBE,
|
||||
0x58, 0xFE, 0xAE, 0x1D, 0xA2, 0xDE, 0xCE, 0xD8,
|
||||
0x43, 0x24, 0x0F, 0x7B, 0x50, 0x2B, 0xA6, 0x59
|
||||
};
|
||||
const unsigned char msg[32] = {
|
||||
0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3,
|
||||
0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44,
|
||||
0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0,
|
||||
0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89
|
||||
};
|
||||
const unsigned char sig[64] = {
|
||||
0x6C, 0xFF, 0x5C, 0x3B, 0xA8, 0x6C, 0x69, 0xEA,
|
||||
0x4B, 0x73, 0x76, 0xF3, 0x1A, 0x9B, 0xCB, 0x4F,
|
||||
0x74, 0xC1, 0x97, 0x60, 0x89, 0xB2, 0xD9, 0x96,
|
||||
0x3D, 0xA2, 0xE5, 0x54, 0x3E, 0x17, 0x77, 0x69,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
|
||||
0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
|
||||
0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
|
||||
};
|
||||
test_schnorrsig_bip_vectors_check_verify(pk, msg, sig, 0);
|
||||
}
|
||||
{
|
||||
/* Test vector 14 */
|
||||
const unsigned char pk[32] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFC, 0x30
|
||||
};
|
||||
secp256k1_xonly_pubkey pk_parsed;
|
||||
/* No need to check the signature of the test vector as parsing the pubkey already fails */
|
||||
CHECK(!secp256k1_xonly_pubkey_parse(ctx, &pk_parsed, pk));
|
||||
}
|
||||
}
|
||||
|
||||
/* Nonce function that returns constant 0 */
|
||||
static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
|
||||
(void) msg32;
|
||||
(void) key32;
|
||||
(void) xonly_pk32;
|
||||
(void) algo16;
|
||||
(void) data;
|
||||
(void) nonce32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Nonce function that sets nonce to 0 */
|
||||
static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
|
||||
(void) msg32;
|
||||
(void) key32;
|
||||
(void) xonly_pk32;
|
||||
(void) algo16;
|
||||
(void) data;
|
||||
|
||||
memset(nonce32, 0, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Nonce function that sets nonce to 0xFF...0xFF */
|
||||
static int nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
|
||||
(void) msg32;
|
||||
(void) key32;
|
||||
(void) xonly_pk32;
|
||||
(void) algo16;
|
||||
(void) data;
|
||||
|
||||
memset(nonce32, 0xFF, 32);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void test_schnorrsig_sign(void) {
|
||||
unsigned char sk[32];
|
||||
secp256k1_keypair keypair;
|
||||
const unsigned char msg[32] = "this is a msg for a schnorrsig..";
|
||||
unsigned char sig[64];
|
||||
unsigned char zeros64[64] = { 0 };
|
||||
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
|
||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL) == 1);
|
||||
|
||||
/* Test different nonce functions */
|
||||
memset(sig, 1, sizeof(sig));
|
||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_failing, NULL) == 0);
|
||||
CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0);
|
||||
memset(&sig, 1, sizeof(sig));
|
||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_0, NULL) == 0);
|
||||
CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) == 0);
|
||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, nonce_function_overflowing, NULL) == 1);
|
||||
CHECK(secp256k1_memcmp_var(sig, zeros64, sizeof(sig)) != 0);
|
||||
}
|
||||
|
||||
#define N_SIGS 3
|
||||
/* Creates N_SIGS valid signatures and verifies them with verify and
|
||||
* verify_batch (TODO). Then flips some bits and checks that verification now
|
||||
* fails. */
|
||||
void test_schnorrsig_sign_verify(void) {
|
||||
unsigned char sk[32];
|
||||
unsigned char msg[N_SIGS][32];
|
||||
unsigned char sig[N_SIGS][64];
|
||||
size_t i;
|
||||
secp256k1_keypair keypair;
|
||||
secp256k1_xonly_pubkey pk;
|
||||
secp256k1_scalar s;
|
||||
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk));
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &pk, NULL, &keypair));
|
||||
|
||||
for (i = 0; i < N_SIGS; i++) {
|
||||
secp256k1_testrand256(msg[i]);
|
||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig[i], msg[i], &keypair, NULL, NULL));
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig[i], msg[i], &pk));
|
||||
}
|
||||
|
||||
{
|
||||
/* Flip a few bits in the signature and in the message and check that
|
||||
* verify and verify_batch (TODO) fail */
|
||||
size_t sig_idx = secp256k1_testrand_int(N_SIGS);
|
||||
size_t byte_idx = secp256k1_testrand_int(32);
|
||||
unsigned char xorbyte = secp256k1_testrand_int(254)+1;
|
||||
sig[sig_idx][byte_idx] ^= xorbyte;
|
||||
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk));
|
||||
sig[sig_idx][byte_idx] ^= xorbyte;
|
||||
|
||||
byte_idx = secp256k1_testrand_int(32);
|
||||
sig[sig_idx][32+byte_idx] ^= xorbyte;
|
||||
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk));
|
||||
sig[sig_idx][32+byte_idx] ^= xorbyte;
|
||||
|
||||
byte_idx = secp256k1_testrand_int(32);
|
||||
msg[sig_idx][byte_idx] ^= xorbyte;
|
||||
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk));
|
||||
msg[sig_idx][byte_idx] ^= xorbyte;
|
||||
|
||||
/* Check that above bitflips have been reversed correctly */
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig[sig_idx], msg[sig_idx], &pk));
|
||||
}
|
||||
|
||||
/* Test overflowing s */
|
||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL, NULL));
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
|
||||
memset(&sig[0][32], 0xFF, 32);
|
||||
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
|
||||
|
||||
/* Test negative s */
|
||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig[0], msg[0], &keypair, NULL, NULL));
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
|
||||
secp256k1_scalar_set_b32(&s, &sig[0][32], NULL);
|
||||
secp256k1_scalar_negate(&s, &s);
|
||||
secp256k1_scalar_get_b32(&sig[0][32], &s);
|
||||
CHECK(!secp256k1_schnorrsig_verify(ctx, sig[0], msg[0], &pk));
|
||||
}
|
||||
#undef N_SIGS
|
||||
|
||||
void test_schnorrsig_taproot(void) {
|
||||
unsigned char sk[32];
|
||||
secp256k1_keypair keypair;
|
||||
secp256k1_xonly_pubkey internal_pk;
|
||||
unsigned char internal_pk_bytes[32];
|
||||
secp256k1_xonly_pubkey output_pk;
|
||||
unsigned char output_pk_bytes[32];
|
||||
unsigned char tweak[32];
|
||||
int pk_parity;
|
||||
unsigned char msg[32];
|
||||
unsigned char sig[64];
|
||||
|
||||
/* Create output key */
|
||||
secp256k1_testrand256(sk);
|
||||
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &internal_pk, NULL, &keypair) == 1);
|
||||
/* In actual taproot the tweak would be hash of internal_pk */
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, tweak, &internal_pk) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_tweak_add(ctx, &keypair, tweak) == 1);
|
||||
CHECK(secp256k1_keypair_xonly_pub(ctx, &output_pk, &pk_parity, &keypair) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, output_pk_bytes, &output_pk) == 1);
|
||||
|
||||
/* Key spend */
|
||||
secp256k1_testrand256(msg);
|
||||
CHECK(secp256k1_schnorrsig_sign(ctx, sig, msg, &keypair, NULL, NULL) == 1);
|
||||
/* Verify key spend */
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &output_pk, output_pk_bytes) == 1);
|
||||
CHECK(secp256k1_schnorrsig_verify(ctx, sig, msg, &output_pk) == 1);
|
||||
|
||||
/* Script spend */
|
||||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, internal_pk_bytes, &internal_pk) == 1);
|
||||
/* Verify script spend */
|
||||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &internal_pk, internal_pk_bytes) == 1);
|
||||
CHECK(secp256k1_xonly_pubkey_tweak_add_check(ctx, output_pk_bytes, pk_parity, &internal_pk, tweak) == 1);
|
||||
}
|
||||
|
||||
void run_schnorrsig_tests(void) {
|
||||
int i;
|
||||
run_nonce_function_bip340_tests();
|
||||
|
||||
test_schnorrsig_api();
|
||||
test_schnorrsig_sha256_tagged();
|
||||
test_schnorrsig_bip_vectors();
|
||||
for (i = 0; i < count; i++) {
|
||||
test_schnorrsig_sign();
|
||||
test_schnorrsig_sign_verify();
|
||||
}
|
||||
test_schnorrsig_taproot();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -9,11 +9,20 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined HAVE_CONFIG_H
|
||||
#include "libsecp256k1-config.h"
|
||||
#endif
|
||||
|
||||
#include "include/secp256k1_rangeproof.h"
|
||||
#include "include/secp256k1_surjectionproof.h"
|
||||
#include "modules/rangeproof/borromean.h"
|
||||
#include "modules/surjection/surjection_impl.h"
|
||||
#include "hash.h"
|
||||
#include "include/secp256k1_rangeproof.h"
|
||||
#include "include/secp256k1_surjectionproof.h"
|
||||
|
||||
#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||
#undef SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS
|
||||
#define SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS 16
|
||||
#endif
|
||||
|
||||
static size_t secp256k1_count_bits_set(const unsigned char* data, size_t count) {
|
||||
size_t ret = 0;
|
||||
@@ -35,6 +44,9 @@ static size_t secp256k1_count_bits_set(const unsigned char* data, size_t count)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||
static
|
||||
#endif
|
||||
int secp256k1_surjectionproof_parse(const secp256k1_context* ctx, secp256k1_surjectionproof *proof, const unsigned char *input, size_t inputlen) {
|
||||
size_t n_inputs;
|
||||
size_t signature_len;
|
||||
@@ -55,8 +67,17 @@ int secp256k1_surjectionproof_parse(const secp256k1_context* ctx, secp256k1_surj
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check that the bitvector of used inputs is of the claimed
|
||||
* length; i.e. the final byte has no "padding bits" set */
|
||||
if (n_inputs % 8 != 0) {
|
||||
const unsigned char padding_mask = (~0U) << (n_inputs % 8);
|
||||
if ((input[2 + (n_inputs + 7) / 8 - 1] & padding_mask) != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
signature_len = 32 * (1 + secp256k1_count_bits_set(&input[2], (n_inputs + 7) / 8));
|
||||
if (inputlen < 2 + (n_inputs + 7) / 8 + signature_len) {
|
||||
if (inputlen != 2 + (n_inputs + 7) / 8 + signature_len) {
|
||||
return 0;
|
||||
}
|
||||
proof->n_inputs = n_inputs;
|
||||
@@ -132,7 +153,7 @@ static size_t secp256k1_surjectionproof_csprng_next(secp256k1_surjectionproof_cs
|
||||
while (1) {
|
||||
size_t val;
|
||||
if (csprng->state_i + increment >= 32) {
|
||||
secp256k1_sha256_t sha;
|
||||
secp256k1_sha256 sha;
|
||||
secp256k1_sha256_initialize(&sha);
|
||||
secp256k1_sha256_write(&sha, csprng->state, 32);
|
||||
secp256k1_sha256_finalize(&sha, csprng->state);
|
||||
@@ -151,6 +172,48 @@ static size_t secp256k1_surjectionproof_csprng_next(secp256k1_surjectionproof_cs
|
||||
}
|
||||
}
|
||||
|
||||
/* While '_allocate_initialized' may be a wordy suffix for this function, and '_create'
|
||||
* may have been more appropriate, '_create' could be confused with '_generate',
|
||||
* as the meanings for the words are close. Therefore, more wordy, but less
|
||||
* ambiguous suffix was chosen. */
|
||||
int secp256k1_surjectionproof_allocate_initialized(const secp256k1_context* ctx, secp256k1_surjectionproof** proof_out_p, size_t *input_index, const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) {
|
||||
int ret = 0;
|
||||
secp256k1_surjectionproof* proof;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
|
||||
ARG_CHECK(proof_out_p != NULL);
|
||||
*proof_out_p = 0;
|
||||
|
||||
proof = (secp256k1_surjectionproof*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_surjectionproof));
|
||||
if (proof != NULL) {
|
||||
ret = secp256k1_surjectionproof_initialize(ctx, proof, input_index, fixed_input_tags, n_input_tags, n_input_tags_to_use, fixed_output_tag, n_max_iterations, random_seed32);
|
||||
if (ret) {
|
||||
*proof_out_p = proof;
|
||||
}
|
||||
else {
|
||||
free(proof);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* secp256k1_surjectionproof structure may also be allocated on the stack,
|
||||
* and initialized explicitly via secp256k1_surjectionproof_initialize().
|
||||
* Supplying stack-allocated struct to _destroy() will result in calling
|
||||
* free() with the pointer that points at the stack, with disasterous
|
||||
* consequences. Thus, it is not advised to mix heap- and stack-allocating
|
||||
* approaches to working with this struct. It is possible to detect this
|
||||
* situation by using additional field in the struct that can be set to
|
||||
* special value depending on the allocation path, and check it here.
|
||||
* But currently, it is not seen as big enough concern to warrant this extra code .*/
|
||||
void secp256k1_surjectionproof_destroy(secp256k1_surjectionproof* proof) {
|
||||
if (proof != NULL) {
|
||||
VERIFY_CHECK(proof->n_inputs <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
|
||||
free(proof);
|
||||
}
|
||||
}
|
||||
|
||||
int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1_surjectionproof* proof, size_t *input_index, const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) {
|
||||
secp256k1_surjectionproof_csprng csprng;
|
||||
size_t n_iterations = 0;
|
||||
@@ -162,6 +225,7 @@ int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1
|
||||
ARG_CHECK(fixed_output_tag != NULL);
|
||||
ARG_CHECK(random_seed32 != NULL);
|
||||
ARG_CHECK(n_input_tags <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
|
||||
ARG_CHECK(n_input_tags_to_use <= SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS);
|
||||
ARG_CHECK(n_input_tags_to_use <= n_input_tags);
|
||||
(void) ctx;
|
||||
|
||||
@@ -219,10 +283,8 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
|
||||
size_t n_total_pubkeys;
|
||||
size_t n_used_pubkeys;
|
||||
size_t ring_input_index = 0;
|
||||
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_ge inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_ge output;
|
||||
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
|
||||
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
|
||||
unsigned char msg32[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
@@ -261,17 +323,14 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_generator_load(&output, ephemeral_output_tag);
|
||||
for (i = 0; i < n_total_pubkeys; i++) {
|
||||
secp256k1_generator_load(&inputs[i], &ephemeral_input_tags[i]);
|
||||
if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, ephemeral_input_tags, n_total_pubkeys, proof->used_inputs, ephemeral_output_tag, input_index, &ring_input_index) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, input_index, &ring_input_index);
|
||||
|
||||
/* Produce signature */
|
||||
rsizes[0] = (int) n_used_pubkeys;
|
||||
indices[0] = (int) ring_input_index;
|
||||
secp256k1_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output);
|
||||
secp256k1_surjection_genmessage(msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag);
|
||||
if (secp256k1_surjection_genrand(borromean_s, n_used_pubkeys, &blinding_key) == 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -289,15 +348,16 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||
static
|
||||
#endif
|
||||
int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256k1_surjectionproof* proof, const secp256k1_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_generator* ephemeral_output_tag) {
|
||||
size_t rsizes[1]; /* array needed for borromean sig API */
|
||||
size_t i;
|
||||
size_t n_total_pubkeys;
|
||||
size_t n_used_pubkeys;
|
||||
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_ge inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
|
||||
secp256k1_ge output;
|
||||
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
|
||||
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
|
||||
unsigned char msg32[32];
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
@@ -313,12 +373,12 @@ int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256
|
||||
return 0;
|
||||
}
|
||||
|
||||
secp256k1_generator_load(&output, ephemeral_output_tag);
|
||||
for (i = 0; i < n_total_pubkeys; i++) {
|
||||
secp256k1_generator_load(&inputs[i], &ephemeral_input_tags[i]);
|
||||
/* Reject proofs with too many used inputs in USE_REDUCED_SURJECTION_PROOF_SIZE mode */
|
||||
if (n_used_pubkeys > SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, 0, NULL) == 0) {
|
||||
if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, ephemeral_input_tags, n_total_pubkeys, proof->used_inputs, ephemeral_output_tag, 0, NULL) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -331,7 +391,7 @@ int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
secp256k1_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output);
|
||||
secp256k1_surjection_genmessage(msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag);
|
||||
return secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, &proof->data[0], borromean_s, ring_pubkeys, rsizes, 1, msg32, 32);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,21 +15,21 @@
|
||||
#include "scalar.h"
|
||||
#include "hash.h"
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg32, secp256k1_ge *ephemeral_input_tags, size_t n_input_tags, secp256k1_ge *ephemeral_output_tag) {
|
||||
SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg32, const secp256k1_generator *ephemeral_input_tags, size_t n_input_tags, const secp256k1_generator *ephemeral_output_tag) {
|
||||
/* compute message */
|
||||
size_t i;
|
||||
unsigned char pk_ser[33];
|
||||
size_t pk_len = sizeof(pk_ser);
|
||||
secp256k1_sha256_t sha256_en;
|
||||
secp256k1_sha256 sha256_en;
|
||||
|
||||
secp256k1_sha256_initialize(&sha256_en);
|
||||
for (i = 0; i < n_input_tags; i++) {
|
||||
secp256k1_eckey_pubkey_serialize(&ephemeral_input_tags[i], pk_ser, &pk_len, 1);
|
||||
assert(pk_len == sizeof(pk_ser));
|
||||
pk_ser[0] = 2 + (ephemeral_input_tags[i].data[63] & 1);
|
||||
memcpy(&pk_ser[1], &ephemeral_input_tags[i].data[0], 32);
|
||||
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
|
||||
}
|
||||
secp256k1_eckey_pubkey_serialize(ephemeral_output_tag, pk_ser, &pk_len, 1);
|
||||
assert(pk_len == sizeof(pk_ser));
|
||||
pk_ser[0] = 2 + (ephemeral_output_tag->data[63] & 1);
|
||||
memcpy(&pk_ser[1], &ephemeral_output_tag->data[0], 32);
|
||||
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
|
||||
secp256k1_sha256_finalize(&sha256_en, msg32);
|
||||
}
|
||||
@@ -37,7 +37,7 @@ SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg3
|
||||
SECP256K1_INLINE static int secp256k1_surjection_genrand(secp256k1_scalar *s, size_t ns, const secp256k1_scalar *blinding_key) {
|
||||
size_t i;
|
||||
unsigned char sec_input[36];
|
||||
secp256k1_sha256_t sha256_en;
|
||||
secp256k1_sha256 sha256_en;
|
||||
|
||||
/* compute s values */
|
||||
secp256k1_scalar_get_b32(&sec_input[4], blinding_key);
|
||||
@@ -61,24 +61,29 @@ SECP256K1_INLINE static int secp256k1_surjection_genrand(secp256k1_scalar *s, si
|
||||
return 1;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_surjection_compute_public_keys(secp256k1_gej *pubkeys, size_t n_pubkeys, const secp256k1_ge *input_tags, size_t n_input_tags, const unsigned char *used_tags, const secp256k1_ge *output_tag, size_t input_index, size_t *ring_input_index) {
|
||||
SECP256K1_INLINE static int secp256k1_surjection_compute_public_keys(secp256k1_gej *pubkeys, size_t n_pubkeys, const secp256k1_generator *input_tags, size_t n_input_tags, const unsigned char *used_tags, const secp256k1_generator *output_tag, size_t input_index, size_t *ring_input_index) {
|
||||
size_t i;
|
||||
size_t j = 0;
|
||||
for (i = 0; i < n_input_tags; i++) {
|
||||
if (used_tags[i / 8] & (1 << (i % 8))) {
|
||||
secp256k1_ge tmpge;
|
||||
secp256k1_ge_neg(&tmpge, &input_tags[i]);
|
||||
secp256k1_generator_load(&tmpge, &input_tags[i]);
|
||||
secp256k1_ge_neg(&tmpge, &tmpge);
|
||||
|
||||
VERIFY_CHECK(j < SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS);
|
||||
VERIFY_CHECK(j < n_pubkeys);
|
||||
secp256k1_gej_set_ge(&pubkeys[j], &tmpge);
|
||||
secp256k1_gej_add_ge_var(&pubkeys[j], &pubkeys[j], output_tag, NULL);
|
||||
|
||||
secp256k1_generator_load(&tmpge, output_tag);
|
||||
secp256k1_gej_add_ge_var(&pubkeys[j], &pubkeys[j], &tmpge, NULL);
|
||||
if (ring_input_index != NULL && input_index == i) {
|
||||
*ring_input_index = j;
|
||||
}
|
||||
j++;
|
||||
if (j > n_pubkeys) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Caller needs to ensure that the number of set bits in used_tags (which we counted in j) equals n_pubkeys. */
|
||||
VERIFY_CHECK(j == n_pubkeys);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user