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
|
||||
|
||||
105
Makefile.am
105
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,67 @@ 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
|
||||
|
||||
if ENABLE_MODULE_GENERATOR
|
||||
include src/modules/generator/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_RANGEPROOF
|
||||
include src/modules/rangeproof/Makefile.am.include
|
||||
endif
|
||||
|
||||
if ENABLE_MODULE_WHITELIST
|
||||
include src/modules/whitelist/Makefile.am.include
|
||||
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
|
||||
])
|
||||
|
||||
|
||||
490
configure.ac
490
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,116 +87,213 @@ 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(jni,
|
||||
AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]),
|
||||
[use_jni=$enableval],
|
||||
[use_jni=auto])
|
||||
AC_ARG_ENABLE(module_generator,
|
||||
AS_HELP_STRING([--enable-module-generator],[enable NUMS generator module [default=no]]),
|
||||
[enable_module_generator=$enableval],
|
||||
[enable_module_generator=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(module_rangeproof,
|
||||
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=no]]),
|
||||
[enable_module_whitelist=$enableval],
|
||||
[enable_module_whitelist=no])
|
||||
|
||||
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=no]]),
|
||||
[enable_module_surjectionproof=$enableval],
|
||||
[enable_module_surjectionproof=no])
|
||||
|
||||
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])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_popcount(0);}]])],
|
||||
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_POPCOUNT,1,[Define this symbol if __builtin_popcount is available]) ],
|
||||
[ AC_MSG_RESULT([no])
|
||||
])
|
||||
|
||||
if test x"$use_ecmult_static_precomputation" != x"no"; then
|
||||
# Temporarily switch to an environment for the native compiler
|
||||
save_cross_compiling=$cross_compiling
|
||||
cross_compiling=no
|
||||
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
|
||||
set_precomp=no
|
||||
fi
|
||||
|
||||
AC_MSG_CHECKING([for __builtin_clzll])
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() { __builtin_clzll(1);}]])],
|
||||
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_CLZLL,1,[Define this symbol if __builtin_clzll is available]) ],
|
||||
[ AC_MSG_RESULT([no])
|
||||
])
|
||||
|
||||
if test x"$req_asm" = x"auto"; then
|
||||
SECP_64BIT_ASM_CHECK
|
||||
if test x"$has_64bit_asm" = x"yes"; then
|
||||
@@ -222,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
|
||||
@@ -322,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
|
||||
|
||||
@@ -353,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
|
||||
@@ -379,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
|
||||
@@ -419,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
|
||||
@@ -431,45 +474,116 @@ 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
|
||||
|
||||
AC_C_BIGENDIAN()
|
||||
if test x"$enable_module_generator" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_GENERATOR, 1, [Define this symbol to enable the NUMS generator module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_rangeproof" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_whitelist" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_WHITELIST, 1, [Define this symbol to enable the key whitelisting module])
|
||||
fi
|
||||
|
||||
if test x"$enable_module_surjectionproof" = x"yes"; then
|
||||
AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module])
|
||||
fi
|
||||
|
||||
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.])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test x"$enable_module_rangeproof" != x"yes"; then
|
||||
if test x"$enable_module_whitelist" = x"yes"; then
|
||||
AC_MSG_ERROR([Whitelist module requires the rangeproof module. Use --enable-module-rangeproof to allow.])
|
||||
fi
|
||||
if test x"$enable_module_surjectionproof" = x"yes"; then
|
||||
AC_MSG_ERROR([Surjection proof module requires the rangeproof module. Use --enable-module-rangeproof to allow.])
|
||||
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.])
|
||||
fi
|
||||
if test x"$enable_module_generator" = x"yes"; then
|
||||
AC_MSG_ERROR([NUMS generator module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_rangeproof" = x"yes"; then
|
||||
AC_MSG_ERROR([Range proof module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_whitelist" = x"yes"; then
|
||||
AC_MSG_ERROR([Key whitelisting module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
if test x"$enable_module_surjectionproof" = x"yes"; then
|
||||
AC_MSG_ERROR([Surjection proof module is experimental. Use --enable-experimental to allow.])
|
||||
fi
|
||||
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)
|
||||
@@ -480,10 +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([USE_JNI], [test x"$use_jni" == 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([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"
|
||||
@@ -491,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 */
|
||||
93
include/secp256k1_generator.h
Normal file
93
include/secp256k1_generator.h
Normal file
@@ -0,0 +1,93 @@
|
||||
#ifndef _SECP256K1_GENERATOR_
|
||||
# define _SECP256K1_GENERATOR_
|
||||
|
||||
# include "secp256k1.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Opaque data structure that stores a base point
|
||||
*
|
||||
* 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_generator_serialize and secp256k1_generator_parse.
|
||||
*/
|
||||
typedef struct {
|
||||
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: 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* gen,
|
||||
const unsigned char *input
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a 33-byte generator into a serialized byte sequence.
|
||||
*
|
||||
* Returns: 1 always.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: output: a pointer to a 33-byte byte array
|
||||
* In: gen: a pointer to a generator
|
||||
*/
|
||||
SECP256K1_API int secp256k1_generator_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
const secp256k1_generator* gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Generate a generator for the curve.
|
||||
*
|
||||
* Returns: 0 in the highly unlikely case the seed is not acceptable,
|
||||
* 1 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: gen: a generator object
|
||||
* In: seed32: a 32-byte seed
|
||||
*
|
||||
* 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 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(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_generator* gen,
|
||||
const unsigned char *seed32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Generate a blinded generator for the curve.
|
||||
*
|
||||
* 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, 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.
|
||||
*
|
||||
* The result is equivalent to first calling secp256k1_generator_generate,
|
||||
* converting the result to a public key, calling secp256k1_ec_pubkey_tweak_add,
|
||||
* and then converting back to generator form.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate_blinded(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_generator* gen,
|
||||
const unsigned char *key32,
|
||||
const unsigned char *blind32
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
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 */
|
||||
291
include/secp256k1_rangeproof.h
Normal file
291
include/secp256k1_rangeproof.h
Normal file
@@ -0,0 +1,291 @@
|
||||
#ifndef _SECP256K1_RANGEPROOF_
|
||||
# define _SECP256K1_RANGEPROOF_
|
||||
|
||||
# include "secp256k1.h"
|
||||
# include "secp256k1_generator.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Opaque data structure that stores a Pedersen commitment
|
||||
*
|
||||
* 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_pedersen_commitment_serialize and
|
||||
* secp256k1_pedersen_commitment_parse.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[64];
|
||||
} secp256k1_pedersen_commitment;
|
||||
|
||||
/**
|
||||
* Static constant generator 'h' maintained for historical reasons.
|
||||
*/
|
||||
SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h;
|
||||
|
||||
/** Parse a 33-byte commitment into a commitment object.
|
||||
*
|
||||
* Returns: 1 if input contains a valid commitment.
|
||||
* Args: ctx: a secp256k1 context object.
|
||||
* Out: commit: pointer to the output commitment object
|
||||
* In: input: pointer to a 33-byte serialized commitment key
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pedersen_commitment* commit,
|
||||
const unsigned char *input
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Serialize a commitment object into a serialized byte sequence.
|
||||
*
|
||||
* 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 secp256k1_pedersen_commitment containing an
|
||||
* initialized commitment
|
||||
*/
|
||||
SECP256K1_API int secp256k1_pedersen_commitment_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
const secp256k1_pedersen_commitment* commit
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Generate a pedersen commitment.
|
||||
* Returns 1: Commitment successfully created.
|
||||
* 0: Error. The blinding factor is larger than the group order
|
||||
* (probability for random 32 byte number < 2^-127) or results in the
|
||||
* point at infinity. Retry with a different factor.
|
||||
* In: ctx: pointer to a context object, initialized for signing and Pedersen commitment (cannot be NULL)
|
||||
* blind: pointer to a 32-byte blinding factor (cannot be NULL)
|
||||
* value: unsigned 64-bit integer value to commit to.
|
||||
* gen: additional generator 'h'
|
||||
* Out: commit: pointer to the commitment (cannot be NULL)
|
||||
*
|
||||
* Blinding factors can be generated and verified in the same way as secp256k1 private keys for ECDSA.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_pedersen_commitment *commit,
|
||||
const unsigned char *blind,
|
||||
uint64_t value,
|
||||
const secp256k1_generator *gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
/** Computes the sum of multiple positive and negative blinding factors.
|
||||
* Returns 1: Sum successfully computed.
|
||||
* 0: Error. A blinding factor is larger than the group order
|
||||
* (probability for random 32 byte number < 2^-127). Retry with
|
||||
* different factors.
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* blinds: pointer to pointers to 32-byte character arrays for blinding factors. (cannot be NULL)
|
||||
* n: number of factors pointed to by blinds.
|
||||
* npositive: how many of the initial factors should be treated with a positive sign.
|
||||
* Out: blind_out: pointer to a 32-byte array for the sum (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *blind_out,
|
||||
const unsigned char * const *blinds,
|
||||
size_t n,
|
||||
size_t npositive
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Verify a tally of pedersen commitments
|
||||
* Returns 1: commitments successfully sum to zero.
|
||||
* 0: Commitments do not sum to zero or other error.
|
||||
* In: ctx: pointer to a context object (cannot be NULL)
|
||||
* commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero)
|
||||
* pcnt: number of commitments pointed to by commits.
|
||||
* ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero)
|
||||
* ncnt: number of commitments pointed to by ncommits.
|
||||
*
|
||||
* This computes sum(commit[0..pcnt)) - sum(ncommit[0..ncnt)) == 0.
|
||||
*
|
||||
* A pedersen commitment is xG + vA where G and A are generators for the secp256k1 group and x is a blinding factor,
|
||||
* while v is the committed value. For a collection of commitments to sum to zero, for each distinct generator
|
||||
* A all blinding factors and all values must sum to zero.
|
||||
*
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_pedersen_commitment * const* commits,
|
||||
size_t pcnt,
|
||||
const secp256k1_pedersen_commitment * const* ncommits,
|
||||
size_t ncnt
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Sets the final Pedersen blinding factor correctly when the generators themselves
|
||||
* have blinding factors.
|
||||
*
|
||||
* Consider a generator of the form A' = A + rG, where A is the "real" generator
|
||||
* but A' is the generator provided to verifiers. Then a Pedersen commitment
|
||||
* P = vA' + r'G really has the form vA + (vr + r')G. To get all these (vr + r')
|
||||
* to sum to zero for multiple commitments, we take three arrays consisting of
|
||||
* the `v`s, `r`s, and `r'`s, respectively called `value`s, `generator_blind`s
|
||||
* and `blinding_factor`s, and sum them.
|
||||
*
|
||||
* The function then subtracts the sum of all (vr + r') from the last element
|
||||
* of the `blinding_factor` array, setting the total sum to zero.
|
||||
*
|
||||
* Returns 1: Blinding factor successfully computed.
|
||||
* 0: Error. A blinding_factor or generator_blind are larger than the group
|
||||
* order (probability for random 32 byte number < 2^-127). Retry with
|
||||
* different values.
|
||||
*
|
||||
* In: ctx: pointer to a context object
|
||||
* value: array of asset values, `v` in the above paragraph.
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* generator_blind: array of asset blinding factors, `r` in the above paragraph
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* n_total: Total size of the above arrays
|
||||
* n_inputs: How many of the initial array elements represent commitments that
|
||||
* will be negated in the final sum
|
||||
* In/Out: blinding_factor: array of commitment blinding factors, `r'` in the above paragraph
|
||||
* May not be NULL unless `n_total` is 0.
|
||||
* the last value will be modified to get the total sum to zero.
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_generator_blind_sum(
|
||||
const secp256k1_context* ctx,
|
||||
const uint64_t *value,
|
||||
const unsigned char* const* generator_blind,
|
||||
unsigned char* const* blinding_factor,
|
||||
size_t n_total,
|
||||
size_t n_inputs
|
||||
);
|
||||
|
||||
/** 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.
|
||||
* In: ctx: pointer to a context object, initialized for range-proof and commitment (cannot be NULL)
|
||||
* commit: the commitment being proved. (cannot be NULL)
|
||||
* proof: pointer to character array with the proof. (cannot be NULL)
|
||||
* plen: length of proof in bytes.
|
||||
* extra_commit: additional data covered in rangeproof signature
|
||||
* extra_commit_len: length of extra_commit byte array (0 if NULL)
|
||||
* gen: additional generator 'h'
|
||||
* Out: min_value: pointer to a unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
|
||||
* max_value: pointer to a unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
|
||||
const secp256k1_context* ctx,
|
||||
uint64_t *min_value,
|
||||
uint64_t *max_value,
|
||||
const secp256k1_pedersen_commitment *commit,
|
||||
const unsigned char *proof,
|
||||
size_t plen,
|
||||
const unsigned char *extra_commit,
|
||||
size_t extra_commit_len,
|
||||
const secp256k1_generator* gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(9);
|
||||
|
||||
/** Verify a range proof proof and rewind the proof to recover information sent by its author.
|
||||
* Returns 1: Value is within the range [0..2^64), the specifically proven range is in the min/max value outputs, and the value and blinding were recovered.
|
||||
* 0: Proof failed, rewind failed, or other error.
|
||||
* In: ctx: pointer to a context object, initialized for range-proof and Pedersen commitment (cannot be NULL)
|
||||
* commit: the commitment being proved. (cannot be NULL)
|
||||
* proof: pointer to character array with the proof. (cannot be NULL)
|
||||
* plen: length of proof in bytes.
|
||||
* nonce: 32-byte secret nonce used by the prover (cannot be NULL)
|
||||
* extra_commit: additional data covered in rangeproof signature
|
||||
* extra_commit_len: length of extra_commit byte array (0 if NULL)
|
||||
* gen: additional generator 'h'
|
||||
* In/Out: blind_out: storage for the 32-byte blinding factor used for the commitment
|
||||
* value_out: pointer to an unsigned int64 which has the exact value of the commitment.
|
||||
* message_out: pointer to a 4096 byte character array to receive message data from the proof author.
|
||||
* outlen: length of message data written to message_out.
|
||||
* min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
|
||||
* max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *blind_out,
|
||||
uint64_t *value_out,
|
||||
unsigned char *message_out,
|
||||
size_t *outlen,
|
||||
const unsigned char *nonce,
|
||||
uint64_t *min_value,
|
||||
uint64_t *max_value,
|
||||
const secp256k1_pedersen_commitment *commit,
|
||||
const unsigned char *proof,
|
||||
size_t plen,
|
||||
const unsigned char *extra_commit,
|
||||
size_t extra_commit_len,
|
||||
const secp256k1_generator *gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8) SECP256K1_ARG_NONNULL(9) SECP256K1_ARG_NONNULL(10) SECP256K1_ARG_NONNULL(14);
|
||||
|
||||
/** Author a proof that a committed value is within a range.
|
||||
* Returns 1: Proof successfully created.
|
||||
* 0: Error
|
||||
* In: ctx: pointer to a context object, initialized for range-proof, signing, and Pedersen commitment (cannot be NULL)
|
||||
* proof: pointer to array to receive the proof, can be up to 5134 bytes. (cannot be NULL)
|
||||
* min_value: constructs a proof where the verifer can tell the minimum value is at least the specified amount.
|
||||
* commit: the commitment being proved.
|
||||
* blind: 32-byte blinding factor used by commit.
|
||||
* nonce: 32-byte secret nonce used to initialize the proof (value can be reverse-engineered out of the proof if this secret is known.)
|
||||
* exp: Base-10 exponent. Digits below above will be made public, but the proof will be made smaller. Allowed range is -1 to 18.
|
||||
* (-1 is a special case that makes the value public. 0 is the most private.)
|
||||
* min_bits: Number of bits of the value to keep private. (0 = auto/minimal, - 64).
|
||||
* value: Actual value of the commitment.
|
||||
* message: pointer to a byte array of data to be embedded in the rangeproof that can be recovered by rewinding the proof
|
||||
* msg_len: size of the message to be embedded in the rangeproof
|
||||
* extra_commit: additional data to be covered in rangeproof signature
|
||||
* extra_commit_len: length of extra_commit byte array (0 if NULL)
|
||||
* gen: additional generator 'h'
|
||||
* In/out: plen: point to an integer with the size of the proof buffer and the size of the constructed proof.
|
||||
*
|
||||
* If min_value or exp is non-zero then the value must be on the range [0, 2^63) to prevent the proof range from spanning past 2^64.
|
||||
*
|
||||
* If exp is -1 the value is revealed by the proof (e.g. it proves that the proof is a blinding of a specific value, without revealing the blinding key.)
|
||||
*
|
||||
* This can randomly fail with probability around one in 2^100. If this happens, buy a lottery ticket and retry with a different nonce or blinding.
|
||||
*
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *proof,
|
||||
size_t *plen,
|
||||
uint64_t min_value,
|
||||
const secp256k1_pedersen_commitment *commit,
|
||||
const unsigned char *blind,
|
||||
const unsigned char *nonce,
|
||||
int exp,
|
||||
int min_bits,
|
||||
uint64_t value,
|
||||
const unsigned char *message,
|
||||
size_t msg_len,
|
||||
const unsigned char *extra_commit,
|
||||
size_t extra_commit_len,
|
||||
const secp256k1_generator *gen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(15);
|
||||
|
||||
/** Extract some basic information from a range-proof.
|
||||
* Returns 1: Information successfully extracted.
|
||||
* 0: Decode failed.
|
||||
* In: ctx: pointer to a context object
|
||||
* proof: pointer to character array with the proof.
|
||||
* plen: length of proof in bytes.
|
||||
* Out: exp: Exponent used in the proof (-1 means the value isn't private).
|
||||
* mantissa: Number of bits covered by the proof.
|
||||
* min_value: pointer to an unsigned int64 which will be updated with the minimum value that commit could have. (cannot be NULL)
|
||||
* max_value: pointer to an unsigned int64 which will be updated with the maximum value that commit could have. (cannot be NULL)
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_info(
|
||||
const secp256k1_context* ctx,
|
||||
int *exp,
|
||||
int *mantissa,
|
||||
uint64_t *min_value,
|
||||
uint64_t *max_value,
|
||||
const unsigned char *proof,
|
||||
size_t plen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
@@ -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 */
|
||||
270
include/secp256k1_surjectionproof.h
Normal file
270
include/secp256k1_surjectionproof.h
Normal file
@@ -0,0 +1,270 @@
|
||||
#ifndef _SECP256K1_SURJECTIONPROOF_
|
||||
#define _SECP256K1_SURJECTIONPROOF_
|
||||
|
||||
#include "secp256k1.h"
|
||||
#include "secp256k1_rangeproof.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used_inputs) \
|
||||
(2 + (n_inputs + 7)/8 + 32 * (1 + (n_used_inputs)))
|
||||
|
||||
/** 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_USED_INPUTS)
|
||||
|
||||
/** Opaque data structure that holds a parsed surjection proof
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. Nor is
|
||||
* it guaranteed to have any particular size, nor that identical proofs
|
||||
* will have identical representation. (That is, memcmp may return nonzero
|
||||
* even for identical proofs.)
|
||||
*
|
||||
* To obtain these properties, instead use secp256k1_surjectionproof_parse
|
||||
* and secp256k1_surjectionproof_serialize to encode/decode proofs into a
|
||||
* well-defined format.
|
||||
*
|
||||
* The representation is exposed to allow creation of these objects on the
|
||||
* stack; please *do not* use these internals directly.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifdef VERIFY
|
||||
/** Mark whether this proof has gone through `secp256k1_surjectionproof_initialize` */
|
||||
int initialized;
|
||||
#endif
|
||||
/** Total number of input asset tags */
|
||||
size_t n_inputs;
|
||||
/** 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_USED_INPUTS)];
|
||||
} secp256k1_surjectionproof;
|
||||
|
||||
#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE
|
||||
/** Parse a surjection proof
|
||||
*
|
||||
* Returns: 1 when the proof could be parsed, 0 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: proof: a pointer to a proof object
|
||||
* In: input: a pointer to the array to parse
|
||||
* inputlen: length of the array pointed to by input
|
||||
*
|
||||
* The proof must consist of:
|
||||
* - A 2-byte little-endian total input count `n`
|
||||
* - A ceil(n/8)-byte bitmap indicating which inputs are used.
|
||||
* - A big-endian 32-byte borromean signature e0 value
|
||||
* - `m` big-endian 32-byte borromean signature s values, where `m`
|
||||
* is the number of set bits in the bitmap
|
||||
*/
|
||||
SECP256K1_API int secp256k1_surjectionproof_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_surjectionproof *proof,
|
||||
const unsigned char *input,
|
||||
size_t inputlen
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
#endif
|
||||
|
||||
/** Serialize a surjection proof
|
||||
*
|
||||
* Returns: 1 if enough space was available to serialize, 0 otherwise
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: output: a pointer to an array to store the serialization
|
||||
* In/Out: outputlen: a pointer to an integer which is initially set to the
|
||||
* size of output, and is overwritten with the written
|
||||
* size.
|
||||
* In: proof: a pointer to an initialized proof object
|
||||
*
|
||||
* See secp256k1_surjectionproof_parse for details about the encoding.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_surjectionproof_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
size_t *outputlen,
|
||||
const secp256k1_surjectionproof *proof
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Data structure that holds a fixed asset tag.
|
||||
*
|
||||
* This data type is *not* opaque. It will always be 32 bytes of whatever
|
||||
* data the API user wants to use as an asset tag. Its contents have no
|
||||
* semantic meaning to libsecp whatsoever.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned char data[32];
|
||||
} secp256k1_fixed_asset_tag;
|
||||
|
||||
/** Returns the total number of inputs a proof expects to be over.
|
||||
*
|
||||
* Returns: the number of inputs for the given proof
|
||||
* In: ctx: pointer to a context object
|
||||
* proof: a pointer to a proof object
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_surjectionproof_n_total_inputs(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_surjectionproof* proof
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Returns the actual number of inputs that a proof uses
|
||||
*
|
||||
* Returns: the number of inputs for the given proof
|
||||
* In: ctx: pointer to a context object
|
||||
* proof: a pointer to a proof object
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_surjectionproof_n_used_inputs(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_surjectionproof* proof
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
|
||||
|
||||
/** Returns the total size this proof would take, in bytes, when serialized
|
||||
*
|
||||
* Returns: the total size
|
||||
* In: ctx: pointer to a context object
|
||||
* proof: a pointer to a proof object
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_surjectionproof* proof
|
||||
) 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
|
||||
*
|
||||
* In: ctx: pointer to a context object
|
||||
* 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
|
||||
* 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. 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.
|
||||
* input_index: The index of the actual input that is secretly mapped to the output
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT 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_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
|
||||
*
|
||||
* In: ctx: pointer to a context object, initialized for signing and verification
|
||||
* ephemeral_input_tags: the ephemeral asset tag of all inputs
|
||||
* n_ephemeral_input_tags: the number of entries in the ephemeral_input_tags array
|
||||
* ephemeral_output_tag: the ephemeral asset tag of the output
|
||||
* input_index: the index of the input that actually maps to the output
|
||||
* input_blinding_key: the blinding key of the input
|
||||
* output_blinding_key: the blinding key of the output
|
||||
* In/Out: proof: The produced surjection proof. Must have already gone through `secp256k1_surjectionproof_initialize`
|
||||
*/
|
||||
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_generate(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_surjectionproof* proof,
|
||||
const secp256k1_generator* ephemeral_input_tags,
|
||||
size_t n_ephemeral_input_tags,
|
||||
const secp256k1_generator* ephemeral_output_tag,
|
||||
size_t input_index,
|
||||
const unsigned char *input_blinding_key,
|
||||
const unsigned char *output_blinding_key
|
||||
) 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
|
||||
*
|
||||
* In: ctx: pointer to a context object, initialized for signing and verification
|
||||
* proof: proof to be verified
|
||||
* ephemeral_input_tags: the ephemeral asset tag of all inputs
|
||||
* n_ephemeral_input_tags: the number of entries in the ephemeral_input_tags array
|
||||
* ephemeral_output_tag: the ephemeral asset tag of the output
|
||||
*/
|
||||
SECP256K1_API 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
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
152
include/secp256k1_whitelist.h
Normal file
152
include/secp256k1_whitelist.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/**********************************************************************
|
||||
* 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_WHITELIST_
|
||||
#define _SECP256K1_WHITELIST_
|
||||
|
||||
#include "secp256k1.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SECP256K1_WHITELIST_MAX_N_KEYS 256
|
||||
|
||||
/** Opaque data structure that holds a parsed whitelist proof
|
||||
*
|
||||
* The exact representation of data inside is implementation defined and not
|
||||
* guaranteed to be portable between different platforms or versions. Nor is
|
||||
* it guaranteed to have any particular size, nor that identical signatures
|
||||
* will have identical representation. (That is, memcmp may return nonzero
|
||||
* even for identical signatures.)
|
||||
*
|
||||
* To obtain these properties, instead use secp256k1_whitelist_signature_parse
|
||||
* and secp256k1_whitelist_signature_serialize to encode/decode signatures
|
||||
* into a well-defined format.
|
||||
*
|
||||
* The representation is exposed to allow creation of these objects on the
|
||||
* stack; please *do not* use these internals directly. To learn the number
|
||||
* of keys for a signature, use `secp256k1_whitelist_signature_n_keys`.
|
||||
*/
|
||||
typedef struct {
|
||||
size_t n_keys;
|
||||
/* e0, scalars */
|
||||
unsigned char data[32 * (1 + SECP256K1_WHITELIST_MAX_N_KEYS)];
|
||||
} secp256k1_whitelist_signature;
|
||||
|
||||
/** Parse a whitelist signature
|
||||
*
|
||||
* Returns: 1 when the signature could be parsed, 0 otherwise.
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: sig: a pointer to a signature object
|
||||
* In: input: a pointer to the array to parse
|
||||
* input_len: the length of the above array
|
||||
*
|
||||
* The signature must consist of a 1-byte n_keys value, followed by a 32-byte
|
||||
* big endian e0 value, followed by n_keys many 32-byte big endian s values.
|
||||
* If n_keys falls outside of [0..SECP256K1_WHITELIST_MAX_N_KEYS] the encoding
|
||||
* is invalid.
|
||||
*
|
||||
* The total length of the input array must therefore be 33 + 32 * n_keys.
|
||||
* If the length `input_len` does not match this value, parsing will fail.
|
||||
*
|
||||
* After the call, sig will always be initialized. If parsing failed or any
|
||||
* scalar values overflow or are zero, the resulting sig value is guaranteed
|
||||
* to fail validation for any set of keys.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_whitelist_signature_parse(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_whitelist_signature *sig,
|
||||
const unsigned char *input,
|
||||
size_t input_len
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
|
||||
|
||||
/** Returns the number of keys a signature expects to have.
|
||||
*
|
||||
* Returns: the number of keys for the given signature
|
||||
* In: sig: a pointer to a signature object
|
||||
*/
|
||||
SECP256K1_API size_t secp256k1_whitelist_signature_n_keys(
|
||||
const secp256k1_whitelist_signature *sig
|
||||
) SECP256K1_ARG_NONNULL(1);
|
||||
|
||||
/** Serialize a whitelist signature
|
||||
*
|
||||
* Returns: 1
|
||||
* Args: ctx: a secp256k1 context object
|
||||
* Out: output64: a pointer to an array to store the serialization
|
||||
* In/Out: output_len: length of the above array, updated with the actual serialized length
|
||||
* In: sig: a pointer to an initialized signature object
|
||||
*
|
||||
* See secp256k1_whitelist_signature_parse for details about the encoding.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_whitelist_signature_serialize(
|
||||
const secp256k1_context* ctx,
|
||||
unsigned char *output,
|
||||
size_t *output_len,
|
||||
const secp256k1_whitelist_signature *sig
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||
|
||||
/** Compute a whitelist signature
|
||||
* Returns 1: signature was successfully created
|
||||
* 0: signature was not successfully created
|
||||
* In: ctx: pointer to a context object, initialized for signing and verification
|
||||
* online_pubkeys: list of all online pubkeys
|
||||
* offline_pubkeys: list of all offline pubkeys
|
||||
* n_keys: the number of entries in each of the above two arrays
|
||||
* sub_pubkey: the key to be whitelisted
|
||||
* online_seckey: the secret key to the signer's online pubkey
|
||||
* summed_seckey: the secret key to the sum of (whitelisted key, signer's offline pubkey)
|
||||
* index: the signer's index in the lists of keys
|
||||
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
|
||||
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
|
||||
* Out: sig: The produced signature.
|
||||
*
|
||||
* The signatures are of the list of all passed pubkeys in the order
|
||||
* ( whitelist, online_1, offline_1, online_2, offline_2, ... )
|
||||
* The verification key list consists of
|
||||
* online_i + H(offline_i + whitelist)(offline_i + whitelist)
|
||||
* for each public key pair (offline_i, offline_i). Here H means sha256 of the
|
||||
* compressed serialization of the key.
|
||||
*/
|
||||
SECP256K1_API int secp256k1_whitelist_sign(
|
||||
const secp256k1_context* ctx,
|
||||
secp256k1_whitelist_signature *sig,
|
||||
const secp256k1_pubkey *online_pubkeys,
|
||||
const secp256k1_pubkey *offline_pubkeys,
|
||||
const size_t n_keys,
|
||||
const secp256k1_pubkey *sub_pubkey,
|
||||
const unsigned char *online_seckey,
|
||||
const unsigned char *summed_seckey,
|
||||
const size_t index,
|
||||
secp256k1_nonce_function noncefp,
|
||||
const void *noncedata
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
|
||||
|
||||
/** Verify a whitelist signature
|
||||
* Returns 1: signature is valid
|
||||
* 0: signature is not valid
|
||||
* In: ctx: pointer to a context object, initialized for signing and verification
|
||||
* sig: the signature to be verified
|
||||
* online_pubkeys: list of all online pubkeys
|
||||
* offline_pubkeys: list of all offline pubkeys
|
||||
* n_keys: the number of entries in each of the above two arrays
|
||||
* sub_pubkey: the key to be whitelisted
|
||||
*/
|
||||
SECP256K1_API int secp256k1_whitelist_verify(
|
||||
const secp256k1_context* ctx,
|
||||
const secp256k1_whitelist_signature *sig,
|
||||
const secp256k1_pubkey *online_pubkeys,
|
||||
const secp256k1_pubkey *offline_pubkeys,
|
||||
const size_t n_keys,
|
||||
const secp256k1_pubkey *sub_pubkey
|
||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(6);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
51
sage/shallue_van_de_woestijne.sage
Normal file
51
sage/shallue_van_de_woestijne.sage
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
### http://www.di.ens.fr/~fouque/pub/latincrypt12.pdf
|
||||
|
||||
# Parameters for secp256k1
|
||||
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
|
||||
a = 0
|
||||
b = 7
|
||||
F = FiniteField (p)
|
||||
C = EllipticCurve ([F(a), F(b)])
|
||||
|
||||
def svdw(t):
|
||||
sqrt_neg_3 = F(-3).nth_root(2)
|
||||
|
||||
## Compute candidate x values
|
||||
w = sqrt_neg_3 * t / (1 + b + t^2)
|
||||
x = [ F(0), F(0), F(0) ]
|
||||
x[0] = (-1 + sqrt_neg_3) / 2 - t * w
|
||||
x[1] = -1 - x[0]
|
||||
x[2] = 1 + 1 / w^2
|
||||
|
||||
print
|
||||
print "On %2d" % t
|
||||
print " x1 %064x" % x[0]
|
||||
print " x2 %064x" % x[1]
|
||||
print " x3 %064x" % x[2]
|
||||
|
||||
## Select which to use
|
||||
alph = jacobi_symbol(x[0]^3 + b, p)
|
||||
beta = jacobi_symbol(x[1]^3 + b, p)
|
||||
if alph == 1 and beta == 1:
|
||||
i = 0
|
||||
elif alph == 1 and beta == -1:
|
||||
i = 0
|
||||
elif alph == -1 and beta == 1:
|
||||
i = 1
|
||||
elif alph == -1 and beta == -1:
|
||||
i = 2
|
||||
else:
|
||||
print "Help! I don't understand Python!"
|
||||
|
||||
## Expand to full point
|
||||
sign = 1 - 2 * (int(F(t)) % 2)
|
||||
ret_x = x[i]
|
||||
ret_y = sign * F(x[i]^3 + b).nth_root(2)
|
||||
return C.point((ret_x, ret_y))
|
||||
|
||||
|
||||
## main
|
||||
for i in range(1, 11):
|
||||
res = svdw(i)
|
||||
print "Result: %064x %064x" % res.xy()
|
||||
@@ -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);
|
||||
}
|
||||
60
src/bench_generator.c
Normal file
60
src/bench_generator.c
Normal file
@@ -0,0 +1,60 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2016 Pieter Wuille *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "include/secp256k1_generator.h"
|
||||
#include "util.h"
|
||||
#include "bench.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context* ctx;
|
||||
unsigned char key[32];
|
||||
unsigned char blind[32];
|
||||
} bench_generator_t;
|
||||
|
||||
static void bench_generator_setup(void* arg) {
|
||||
bench_generator_t *data = (bench_generator_t*)arg;
|
||||
memset(data->key, 0x31, 32);
|
||||
memset(data->blind, 0x13, 32);
|
||||
}
|
||||
|
||||
static void bench_generator_generate(void* arg, int iters) {
|
||||
int i;
|
||||
bench_generator_t *data = (bench_generator_t*)arg;
|
||||
|
||||
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, int iters) {
|
||||
int i;
|
||||
bench_generator_t *data = (bench_generator_t*)arg;
|
||||
|
||||
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)]++;
|
||||
data->blind[1 + (i & 30)]++;
|
||||
}
|
||||
}
|
||||
|
||||
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, 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);
|
||||
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;
|
||||
}
|
||||
|
||||
65
src/bench_rangeproof.c
Normal file
65
src/bench_rangeproof.c
Normal file
@@ -0,0 +1,65 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2014, 2015 Pieter Wuille, Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "include/secp256k1_rangeproof.h"
|
||||
#include "util.h"
|
||||
#include "bench.h"
|
||||
|
||||
typedef struct {
|
||||
secp256k1_context* ctx;
|
||||
secp256k1_pedersen_commitment commit;
|
||||
unsigned char proof[5134];
|
||||
unsigned char blind[32];
|
||||
size_t len;
|
||||
int min_bits;
|
||||
uint64_t v;
|
||||
} bench_rangeproof_t;
|
||||
|
||||
static void bench_rangeproof_setup(void* arg) {
|
||||
int i;
|
||||
uint64_t minv;
|
||||
uint64_t maxv;
|
||||
bench_rangeproof_t *data = (bench_rangeproof_t*)arg;
|
||||
|
||||
data->v = 0;
|
||||
for (i = 0; i < 32; i++) data->blind[i] = i + 1;
|
||||
CHECK(secp256k1_pedersen_commit(data->ctx, &data->commit, data->blind, data->v, secp256k1_generator_h));
|
||||
data->len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(data->ctx, data->proof, &data->len, 0, &data->commit, data->blind, (const unsigned char*)&data->commit, 0, data->min_bits, data->v, NULL, 0, NULL, 0, secp256k1_generator_h));
|
||||
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, int iters) {
|
||||
int i;
|
||||
bench_rangeproof_t *data = (bench_rangeproof_t*)arg;
|
||||
|
||||
for (i = 0; i < iters/data->min_bits; i++) {
|
||||
int j;
|
||||
uint64_t minv;
|
||||
uint64_t maxv;
|
||||
j = secp256k1_rangeproof_verify(data->ctx, &minv, &maxv, &data->commit, data->proof, data->len, NULL, 0, secp256k1_generator_h);
|
||||
for (j = 0; j < 4; j++) {
|
||||
data->proof[j + 2 + 32 *((data->min_bits + 1) >> 1) - 4] = (i >> 8)&255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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, 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"
|
||||
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
|
||||
/**
|
||||
* 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,33 +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"
|
||||
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
#define WNAF_BITS 128
|
||||
#else
|
||||
#define WNAF_BITS 256
|
||||
#endif
|
||||
#define WNAF_SIZE(w) ((WNAF_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); \
|
||||
@@ -42,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) {
|
||||
static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w, int size) {
|
||||
int global_sign;
|
||||
int skew = 0;
|
||||
int word = 0;
|
||||
@@ -65,23 +65,33 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
|
||||
|
||||
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. */
|
||||
|
||||
/* Negative numbers will be negated to keep their bit representation below the maximum width */
|
||||
flip = secp256k1_scalar_is_high(&s);
|
||||
* 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(&s);
|
||||
bit = flip ^ !secp256k1_scalar_is_even(scalar);
|
||||
/* 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_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
|
||||
@@ -94,57 +104,63 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) {
|
||||
|
||||
/* 4 */
|
||||
u_last = secp256k1_scalar_shr_int(&s, w);
|
||||
while (word * w < WNAF_BITS) {
|
||||
int sign;
|
||||
do {
|
||||
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);
|
||||
wnaf[word] = u * global_sign;
|
||||
|
||||
VERIFY_CHECK(secp256k1_scalar_is_zero(&s));
|
||||
VERIFY_CHECK(word == WNAF_SIZE(w));
|
||||
VERIFY_CHECK(word == WNAF_SIZE_BITS(size, w));
|
||||
return skew;
|
||||
}
|
||||
|
||||
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
|
||||
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar, int size) {
|
||||
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
secp256k1_ge tmpa;
|
||||
secp256k1_fe Z;
|
||||
|
||||
int skew_1;
|
||||
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)];
|
||||
int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
int skew_lam;
|
||||
secp256k1_scalar q_1, q_lam;
|
||||
#endif
|
||||
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
|
||||
|
||||
int i;
|
||||
secp256k1_scalar sc = *scalar;
|
||||
|
||||
/* build wnaf representation for q. */
|
||||
#ifdef USE_ENDOMORPHISM
|
||||
/* 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);
|
||||
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1);
|
||||
#else
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1);
|
||||
#endif
|
||||
int rsize = size;
|
||||
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, 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
|
||||
{
|
||||
skew_1 = secp256k1_wnaf_const(wnaf_1, scalar, WINDOW_A - 1, size);
|
||||
skew_lam = 0;
|
||||
}
|
||||
|
||||
/* Calculate odd multiples of a.
|
||||
* All multiples are brought to the same Z 'denominator', which is stored
|
||||
@@ -157,43 +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
|
||||
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
|
||||
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
|
||||
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(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
|
||||
i = wnaf_lam[WNAF_SIZE(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
|
||||
if (size > 128) {
|
||||
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);
|
||||
}
|
||||
/* remaining loop iterations */
|
||||
for (i = WNAF_SIZE(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
|
||||
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
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
secp256k1_fe_mul(&r->z, &r->z, &Z);
|
||||
@@ -202,38 +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
|
||||
secp256k1_ge_to_storage(&correction_lam_stor, a);
|
||||
#endif
|
||||
if (size > 128) {
|
||||
secp256k1_ge_to_storage(&correction_lam_stor, a);
|
||||
}
|
||||
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
|
||||
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
|
||||
#endif
|
||||
if (size > 128) {
|
||||
secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2);
|
||||
}
|
||||
|
||||
/* 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
|
||||
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
|
||||
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 /* 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);
|
||||
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
|
||||
9
src/modules/generator/Makefile.am.include
Normal file
9
src/modules/generator/Makefile.am.include
Normal file
@@ -0,0 +1,9 @@
|
||||
include_HEADERS += include/secp256k1_generator.h
|
||||
noinst_HEADERS += src/modules/generator/main_impl.h
|
||||
noinst_HEADERS += src/modules/generator/tests_impl.h
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_generator
|
||||
bench_generator_SOURCES = src/bench_generator.c
|
||||
bench_generator_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_generator_LDFLAGS = -static
|
||||
endif
|
||||
222
src/modules/generator/main_impl.h
Normal file
222
src/modules/generator/main_impl.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2016 Andrew Poelstra & 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_GENERATOR_MAIN
|
||||
#define SECP256K1_MODULE_GENERATOR_MAIN
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "hash.h"
|
||||
#include "scalar.h"
|
||||
|
||||
static void secp256k1_generator_load(secp256k1_ge* ge, const secp256k1_generator* gen) {
|
||||
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 *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 ||
|
||||
!secp256k1_fe_set_b32(&x, &input[1]) ||
|
||||
!secp256k1_ge_set_xquad(&ge, &x)) {
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void shallue_van_de_woestijne(secp256k1_ge* ge, const secp256k1_fe* t) {
|
||||
/* Implements the algorithm from:
|
||||
* Indifferentiable Hashing to Barreto-Naehrig Curves
|
||||
* Pierre-Alain Fouque and Mehdi Tibouchi
|
||||
* Latincrypt 2012
|
||||
*/
|
||||
|
||||
/* Basic algorithm:
|
||||
|
||||
c = sqrt(-3)
|
||||
d = (c - 1)/2
|
||||
|
||||
w = c * t / (1 + b + t^2) [with b = 7]
|
||||
x1 = d - t*w
|
||||
x2 = -(x1 + 1)
|
||||
x3 = 1 + 1/w^2
|
||||
|
||||
To avoid the 2 divisions, compute the above in numerator/denominator form:
|
||||
wn = c * t
|
||||
wd = 1 + 7 + t^2
|
||||
x1n = d*wd - t*wn
|
||||
x1d = wd
|
||||
x2n = -(x1n + wd)
|
||||
x2d = wd
|
||||
x3n = wd^2 + c^2 + t^2
|
||||
x3d = (c * t)^2
|
||||
|
||||
The joint denominator j = wd * c^2 * t^2, and
|
||||
1 / x1d = 1/j * c^2 * t^2
|
||||
1 / x2d = x3d = 1/j * wd
|
||||
*/
|
||||
|
||||
static const secp256k1_fe c = SECP256K1_FE_CONST(0x0a2d2ba9, 0x3507f1df, 0x233770c2, 0xa797962c, 0xc61f6d15, 0xda14ecd4, 0x7d8d27ae, 0x1cd5f852);
|
||||
static const secp256k1_fe d = SECP256K1_FE_CONST(0x851695d4, 0x9a83f8ef, 0x919bb861, 0x53cbcb16, 0x630fb68a, 0xed0a766a, 0x3ec693d6, 0x8e6afa40);
|
||||
static const secp256k1_fe b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7);
|
||||
static const secp256k1_fe b_plus_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 8);
|
||||
|
||||
secp256k1_fe wn, wd, x1n, x2n, x3n, x3d, jinv, tmp, x1, x2, x3, alphain, betain, gammain, y1, y2, y3;
|
||||
int alphaquad, betaquad;
|
||||
|
||||
secp256k1_fe_mul(&wn, &c, t); /* mag 1 */
|
||||
secp256k1_fe_sqr(&wd, t); /* mag 1 */
|
||||
secp256k1_fe_add(&wd, &b_plus_one); /* mag 2 */
|
||||
secp256k1_fe_mul(&tmp, t, &wn); /* mag 1 */
|
||||
secp256k1_fe_negate(&tmp, &tmp, 1); /* mag 2 */
|
||||
secp256k1_fe_mul(&x1n, &d, &wd); /* mag 1 */
|
||||
secp256k1_fe_add(&x1n, &tmp); /* mag 3 */
|
||||
x2n = x1n; /* mag 3 */
|
||||
secp256k1_fe_add(&x2n, &wd); /* mag 5 */
|
||||
secp256k1_fe_negate(&x2n, &x2n, 5); /* mag 6 */
|
||||
secp256k1_fe_mul(&x3d, &c, t); /* mag 1 */
|
||||
secp256k1_fe_sqr(&x3d, &x3d); /* mag 1 */
|
||||
secp256k1_fe_sqr(&x3n, &wd); /* mag 1 */
|
||||
secp256k1_fe_add(&x3n, &x3d); /* mag 2 */
|
||||
secp256k1_fe_mul(&jinv, &x3d, &wd); /* mag 1 */
|
||||
secp256k1_fe_inv(&jinv, &jinv); /* mag 1 */
|
||||
secp256k1_fe_mul(&x1, &x1n, &x3d); /* mag 1 */
|
||||
secp256k1_fe_mul(&x1, &x1, &jinv); /* mag 1 */
|
||||
secp256k1_fe_mul(&x2, &x2n, &x3d); /* mag 1 */
|
||||
secp256k1_fe_mul(&x2, &x2, &jinv); /* mag 1 */
|
||||
secp256k1_fe_mul(&x3, &x3n, &wd); /* mag 1 */
|
||||
secp256k1_fe_mul(&x3, &x3, &jinv); /* mag 1 */
|
||||
|
||||
secp256k1_fe_sqr(&alphain, &x1); /* mag 1 */
|
||||
secp256k1_fe_mul(&alphain, &alphain, &x1); /* mag 1 */
|
||||
secp256k1_fe_add(&alphain, &b); /* mag 2 */
|
||||
secp256k1_fe_sqr(&betain, &x2); /* mag 1 */
|
||||
secp256k1_fe_mul(&betain, &betain, &x2); /* mag 1 */
|
||||
secp256k1_fe_add(&betain, &b); /* mag 2 */
|
||||
secp256k1_fe_sqr(&gammain, &x3); /* mag 1 */
|
||||
secp256k1_fe_mul(&gammain, &gammain, &x3); /* mag 1 */
|
||||
secp256k1_fe_add(&gammain, &b); /* mag 2 */
|
||||
|
||||
alphaquad = secp256k1_fe_sqrt(&y1, &alphain);
|
||||
betaquad = secp256k1_fe_sqrt(&y2, &betain);
|
||||
secp256k1_fe_sqrt(&y3, &gammain);
|
||||
|
||||
secp256k1_fe_cmov(&x1, &x2, (!alphaquad) & betaquad);
|
||||
secp256k1_fe_cmov(&y1, &y2, (!alphaquad) & betaquad);
|
||||
secp256k1_fe_cmov(&x1, &x3, (!alphaquad) & !betaquad);
|
||||
secp256k1_fe_cmov(&y1, &y3, (!alphaquad) & !betaquad);
|
||||
|
||||
secp256k1_ge_set_xy(ge, &x1, &y1);
|
||||
|
||||
/* The linked algorithm from the paper uses the Jacobi symbol of t to
|
||||
* determine the Jacobi symbol of the produced y coordinate. Since the
|
||||
* rest of the algorithm only uses t^2, we can safely use another criterion
|
||||
* as long as negation of t results in negation of the y coordinate. Here
|
||||
* we choose to use t's oddness, as it is faster to determine. */
|
||||
secp256k1_fe_negate(&tmp, &ge->y, 1);
|
||||
secp256k1_fe_cmov(&ge->y, &tmp, secp256k1_fe_is_odd(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[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 sha256;
|
||||
unsigned char b32[32];
|
||||
int ret = 1;
|
||||
|
||||
if (blind32) {
|
||||
secp256k1_scalar blind;
|
||||
secp256k1_scalar_set_b32(&blind, blind32, &overflow);
|
||||
ret = !overflow;
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &accum, &blind);
|
||||
}
|
||||
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&sha256, prefix1, 16);
|
||||
secp256k1_sha256_write(&sha256, key32, 32);
|
||||
secp256k1_sha256_finalize(&sha256, b32);
|
||||
ret &= secp256k1_fe_set_b32(&t, b32);
|
||||
shallue_van_de_woestijne(&add, &t);
|
||||
if (blind32) {
|
||||
secp256k1_gej_add_ge(&accum, &accum, &add);
|
||||
} else {
|
||||
secp256k1_gej_set_ge(&accum, &add);
|
||||
}
|
||||
|
||||
secp256k1_sha256_initialize(&sha256);
|
||||
secp256k1_sha256_write(&sha256, prefix2, 16);
|
||||
secp256k1_sha256_write(&sha256, key32, 32);
|
||||
secp256k1_sha256_finalize(&sha256, b32);
|
||||
ret &= secp256k1_fe_set_b32(&t, b32);
|
||||
shallue_van_de_woestijne(&add, &t);
|
||||
secp256k1_gej_add_ge(&accum, &accum, &add);
|
||||
|
||||
secp256k1_ge_set_gej(&add, &accum);
|
||||
secp256k1_generator_save(gen, &add);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int secp256k1_generator_generate(const secp256k1_context* ctx, secp256k1_generator* gen, const unsigned char *key32) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
ARG_CHECK(key32 != NULL);
|
||||
return secp256k1_generator_generate_internal(ctx, gen, key32, NULL);
|
||||
}
|
||||
|
||||
int secp256k1_generator_generate_blinded(const secp256k1_context* ctx, secp256k1_generator* gen, const unsigned char *key32, const unsigned char *blind32) {
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
ARG_CHECK(key32 != NULL);
|
||||
ARG_CHECK(blind32 != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
return secp256k1_generator_generate_internal(ctx, gen, key32, blind32);
|
||||
}
|
||||
|
||||
#endif
|
||||
227
src/modules/generator/tests_impl.h
Normal file
227
src/modules/generator/tests_impl.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2016 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_GENERATOR_TESTS
|
||||
#define SECP256K1_MODULE_GENERATOR_TESTS
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "testrand.h"
|
||||
#include "util.h"
|
||||
|
||||
#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] = {
|
||||
SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0x0225f529, 0xee75acaf, 0xccfc4560, 0x26c5e46b, 0xf80237a3, 0x3924655a, 0x16f90e88, 0x085ed52a),
|
||||
SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0xfdda0ad6, 0x118a5350, 0x3303ba9f, 0xd93a1b94, 0x07fdc85c, 0xc6db9aa5, 0xe906f176, 0xf7a12705),
|
||||
SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0x56716069, 0x6818286b, 0x72f01a3e, 0x5e8caca7, 0x36249160, 0xc7ded69d, 0xd51913c3, 0x03a2fa97),
|
||||
SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0xa98e9f96, 0x97e7d794, 0x8d0fe5c1, 0xa1735358, 0xc9db6e9f, 0x38212962, 0x2ae6ec3b, 0xfc5d0198),
|
||||
SECP256K1_GE_STORAGE_CONST(0x531f7239, 0xaebc780e, 0x179fbf8d, 0x412a1b01, 0x511f0abc, 0xe0c46151, 0x8b38db84, 0xcc2467f3, 0x82387d45, 0xec7bd5cc, 0x61fcb9df, 0x41cddd7b, 0x217d8114, 0x3577dc8f, 0x23de356a, 0x7e97704e),
|
||||
SECP256K1_GE_STORAGE_CONST(0x531f7239, 0xaebc780e, 0x179fbf8d, 0x412a1b01, 0x511f0abc, 0xe0c46151, 0x8b38db84, 0xcc2467f3, 0x7dc782ba, 0x13842a33, 0x9e034620, 0xbe322284, 0xde827eeb, 0xca882370, 0xdc21ca94, 0x81688be1),
|
||||
SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0x56716069, 0x6818286b, 0x72f01a3e, 0x5e8caca7, 0x36249160, 0xc7ded69d, 0xd51913c3, 0x03a2fa97),
|
||||
SECP256K1_GE_STORAGE_CONST(0x2c5cdc9c, 0x338152fa, 0x85de92cb, 0x1bee9907, 0x765a922e, 0x4f037cce, 0x14ecdbf2, 0x2f78fe15, 0xa98e9f96, 0x97e7d794, 0x8d0fe5c1, 0xa1735358, 0xc9db6e9f, 0x38212962, 0x2ae6ec3b, 0xfc5d0198),
|
||||
SECP256K1_GE_STORAGE_CONST(0x5e5936b1, 0x81db0b65, 0x8e33a8c6, 0x1aa687dd, 0x31d11e15, 0x85e35664, 0x6b4c2071, 0xcde7e942, 0x88bb5332, 0xa8e05654, 0x78d4f60c, 0x0cd979ec, 0x938558f2, 0xcac11216, 0x7c387a56, 0xe3a6d5f3),
|
||||
SECP256K1_GE_STORAGE_CONST(0x5e5936b1, 0x81db0b65, 0x8e33a8c6, 0x1aa687dd, 0x31d11e15, 0x85e35664, 0x6b4c2071, 0xcde7e942, 0x7744accd, 0x571fa9ab, 0x872b09f3, 0xf3268613, 0x6c7aa70d, 0x353eede9, 0x83c785a8, 0x1c59263c),
|
||||
SECP256K1_GE_STORAGE_CONST(0x657d438f, 0xfac34a50, 0x463fd07c, 0x3f09f320, 0x4c98e8ed, 0x6927e330, 0xc0c7735f, 0x76d32f6d, 0x577c2b11, 0xcaca2f6f, 0xd60bcaf0, 0x3e7cebe9, 0x5da6e1f4, 0xbb557f12, 0x2a397331, 0x81df897f),
|
||||
SECP256K1_GE_STORAGE_CONST(0x657d438f, 0xfac34a50, 0x463fd07c, 0x3f09f320, 0x4c98e8ed, 0x6927e330, 0xc0c7735f, 0x76d32f6d, 0xa883d4ee, 0x3535d090, 0x29f4350f, 0xc1831416, 0xa2591e0b, 0x44aa80ed, 0xd5c68ccd, 0x7e2072b0),
|
||||
SECP256K1_GE_STORAGE_CONST(0xbe0bc11b, 0x2bc639cb, 0xc28f72a8, 0xd07c21cc, 0xbc06cfa7, 0x4c2ff25e, 0x630c9740, 0x23128eab, 0x6f062fc8, 0x75148197, 0xd10375c3, 0xcc3fadb6, 0x20277e9c, 0x00579c55, 0xeddd7f95, 0xe95604db),
|
||||
SECP256K1_GE_STORAGE_CONST(0xbe0bc11b, 0x2bc639cb, 0xc28f72a8, 0xd07c21cc, 0xbc06cfa7, 0x4c2ff25e, 0x630c9740, 0x23128eab, 0x90f9d037, 0x8aeb7e68, 0x2efc8a3c, 0x33c05249, 0xdfd88163, 0xffa863aa, 0x12228069, 0x16a9f754),
|
||||
SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0xfdda0ad6, 0x118a5350, 0x3303ba9f, 0xd93a1b94, 0x07fdc85c, 0xc6db9aa5, 0xe906f176, 0xf7a12705),
|
||||
SECP256K1_GE_STORAGE_CONST(0xedd1fd3e, 0x327ce90c, 0xc7a35426, 0x14289aee, 0x9682003e, 0x9cf7dcc9, 0xcf2ca974, 0x3be5aa0c, 0x0225f529, 0xee75acaf, 0xccfc4560, 0x26c5e46b, 0xf80237a3, 0x3924655a, 0x16f90e88, 0x085ed52a),
|
||||
SECP256K1_GE_STORAGE_CONST(0xaee172d4, 0xce7c5010, 0xdb20a88f, 0x469598c1, 0xd7f7926f, 0xabb85cb5, 0x339f1403, 0x87e6b494, 0x38065980, 0x4de81b35, 0x098c7190, 0xe3380f9d, 0x95b2ed6c, 0x6c869e85, 0xc772bc5a, 0x7bc3d9d5),
|
||||
SECP256K1_GE_STORAGE_CONST(0xaee172d4, 0xce7c5010, 0xdb20a88f, 0x469598c1, 0xd7f7926f, 0xabb85cb5, 0x339f1403, 0x87e6b494, 0xc7f9a67f, 0xb217e4ca, 0xf6738e6f, 0x1cc7f062, 0x6a4d1293, 0x9379617a, 0x388d43a4, 0x843c225a),
|
||||
SECP256K1_GE_STORAGE_CONST(0xc28f5c28, 0xf5c28f5c, 0x28f5c28f, 0x5c28f5c2, 0x8f5c28f5, 0xc28f5c28, 0xf5c28f5b, 0x6666635a, 0x0c4da840, 0x1b2cf5be, 0x4604e6ec, 0xf92b2780, 0x063a5351, 0xe294bf65, 0xbb2f8b61, 0x00902db7),
|
||||
SECP256K1_GE_STORAGE_CONST(0xc28f5c28, 0xf5c28f5c, 0x28f5c28f, 0x5c28f5c2, 0x8f5c28f5, 0xc28f5c28, 0xf5c28f5b, 0x6666635a, 0xf3b257bf, 0xe4d30a41, 0xb9fb1913, 0x06d4d87f, 0xf9c5acae, 0x1d6b409a, 0x44d0749d, 0xff6fce78),
|
||||
SECP256K1_GE_STORAGE_CONST(0xecf56be6, 0x9c8fde26, 0x152832c6, 0xe043b3d5, 0xaf9a723f, 0x789854a0, 0xcb1b810d, 0xe2614ece, 0x66127ae4, 0xe4c17a75, 0x60a727e6, 0xffd2ea7f, 0xaed99088, 0xbec465c6, 0xbde56791, 0x37ed5572),
|
||||
SECP256K1_GE_STORAGE_CONST(0xecf56be6, 0x9c8fde26, 0x152832c6, 0xe043b3d5, 0xaf9a723f, 0x789854a0, 0xcb1b810d, 0xe2614ece, 0x99ed851b, 0x1b3e858a, 0x9f58d819, 0x002d1580, 0x51266f77, 0x413b9a39, 0x421a986d, 0xc812a6bd),
|
||||
SECP256K1_GE_STORAGE_CONST(0xba72860f, 0x10fcd142, 0x23f71e3c, 0x228deb9a, 0xc46c5ff5, 0x90b884e5, 0xcc60d51e, 0x0629d16e, 0x67999f31, 0x5a74ada3, 0x526832cf, 0x76b9fec3, 0xa348cc97, 0x33c3aa67, 0x02bd2516, 0x7814f635),
|
||||
SECP256K1_GE_STORAGE_CONST(0xba72860f, 0x10fcd142, 0x23f71e3c, 0x228deb9a, 0xc46c5ff5, 0x90b884e5, 0xcc60d51e, 0x0629d16e, 0x986660ce, 0xa58b525c, 0xad97cd30, 0x8946013c, 0x5cb73368, 0xcc3c5598, 0xfd42dae8, 0x87eb05fa),
|
||||
SECP256K1_GE_STORAGE_CONST(0x92ef5657, 0xdba51cc7, 0xf3e1b442, 0xa6a0916b, 0x8ce03079, 0x2ef5657d, 0xba51cc7e, 0xab2beb65, 0x782c65d2, 0x3f1e0eb2, 0x9179a994, 0xe5e8ff80, 0x5a0d50d9, 0xdeeaed90, 0xcec96ca5, 0x973e2ad3),
|
||||
SECP256K1_GE_STORAGE_CONST(0x92ef5657, 0xdba51cc7, 0xf3e1b442, 0xa6a0916b, 0x8ce03079, 0x2ef5657d, 0xba51cc7e, 0xab2beb65, 0x87d39a2d, 0xc0e1f14d, 0x6e86566b, 0x1a17007f, 0xa5f2af26, 0x2115126f, 0x31369359, 0x68c1d15c),
|
||||
SECP256K1_GE_STORAGE_CONST(0x9468ad22, 0xf921fc78, 0x8de3f1b0, 0x586c58eb, 0x5e6f0270, 0xe950b602, 0x7ada90d9, 0xd71ae323, 0x922a0c6a, 0x9ccc31d9, 0xc3bf87fd, 0x88381739, 0x35fe393f, 0xa64dfdec, 0x29f2846d, 0x12918d86),
|
||||
SECP256K1_GE_STORAGE_CONST(0x9468ad22, 0xf921fc78, 0x8de3f1b0, 0x586c58eb, 0x5e6f0270, 0xe950b602, 0x7ada90d9, 0xd71ae323, 0x6dd5f395, 0x6333ce26, 0x3c407802, 0x77c7e8c6, 0xca01c6c0, 0x59b20213, 0xd60d7b91, 0xed6e6ea9),
|
||||
SECP256K1_GE_STORAGE_CONST(0x76ddc7f5, 0xe029e59e, 0x22b0e54f, 0xa811db94, 0x5a209c4f, 0x5e912ca2, 0x8b4da6a7, 0x4c1e00a2, 0x1e8f516c, 0x91c20437, 0x50f6e24e, 0x8c2cf202, 0xacf68291, 0xbf8b66eb, 0xf7335b62, 0xec2c88fe),
|
||||
SECP256K1_GE_STORAGE_CONST(0x76ddc7f5, 0xe029e59e, 0x22b0e54f, 0xa811db94, 0x5a209c4f, 0x5e912ca2, 0x8b4da6a7, 0x4c1e00a2, 0xe170ae93, 0x6e3dfbc8, 0xaf091db1, 0x73d30dfd, 0x53097d6e, 0x40749914, 0x08cca49c, 0x13d37331),
|
||||
SECP256K1_GE_STORAGE_CONST(0xf75763bc, 0x2907e79b, 0x125e33c3, 0x9a027f48, 0x0f8c6409, 0x2153432f, 0x967bc2b1, 0x1d1f5cf0, 0xb4a8edc6, 0x36391b39, 0x9bc219c0, 0x3d033128, 0xdbcd463e, 0xd2506394, 0x061b87a5, 0x9e510235),
|
||||
SECP256K1_GE_STORAGE_CONST(0xf75763bc, 0x2907e79b, 0x125e33c3, 0x9a027f48, 0x0f8c6409, 0x2153432f, 0x967bc2b1, 0x1d1f5cf0, 0x4b571239, 0xc9c6e4c6, 0x643de63f, 0xc2fcced7, 0x2432b9c1, 0x2daf9c6b, 0xf9e47859, 0x61aef9fa),
|
||||
};
|
||||
|
||||
secp256k1_ge ge;
|
||||
secp256k1_fe fe;
|
||||
secp256k1_ge_storage ges;
|
||||
int i, s;
|
||||
for (i = 1; i <= 16; i++) {
|
||||
secp256k1_fe_set_int(&fe, i);
|
||||
|
||||
for (s = 0; s < 2; s++) {
|
||||
if (s) {
|
||||
secp256k1_fe_negate(&fe, &fe, 1);
|
||||
secp256k1_fe_normalize(&fe);
|
||||
}
|
||||
shallue_van_de_woestijne(&ge, &fe);
|
||||
secp256k1_ge_to_storage(&ges, &ge);
|
||||
|
||||
CHECK(memcmp(&ges, &results[i * 2 + s - 2], sizeof(secp256k1_ge_storage)) == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_generator_generate(void) {
|
||||
static const secp256k1_ge_storage results[32] = {
|
||||
SECP256K1_GE_STORAGE_CONST(0x806cd8ed, 0xd6c153e3, 0x4aa9b9a0, 0x8755c4be, 0x4718b1ef, 0xb26cb93f, 0xfdd99e1b, 0x21f2af8e, 0xc7062208, 0xcc649a03, 0x1bdc1a33, 0x9d01f115, 0x4bcd0dca, 0xfe0b875d, 0x62f35f73, 0x28673006),
|
||||
SECP256K1_GE_STORAGE_CONST(0xd91b15ec, 0x47a811f4, 0xaa189561, 0xd13f5c4d, 0x4e81f10d, 0xc7dc551f, 0x4fea9b84, 0x610314c4, 0x9b0ada1e, 0xb38efd67, 0x8bff0b6c, 0x7d7315f7, 0xb49b8cc5, 0xa679fad4, 0xc94f9dc6, 0x9da66382),
|
||||
SECP256K1_GE_STORAGE_CONST(0x11c00de6, 0xf885035e, 0x76051430, 0xa3c38b2a, 0x5f86ab8c, 0xf66dae58, 0x04ea7307, 0x348b19bf, 0xe0858ae7, 0x61dcb1ba, 0xff247e37, 0xd38fcd88, 0xf3bd7911, 0xaa4ed6e0, 0x28d792dd, 0x3ee1ac09),
|
||||
SECP256K1_GE_STORAGE_CONST(0x986b99eb, 0x3130e7f0, 0xe779f674, 0xb85cb514, 0x46a676bf, 0xb1dfb603, 0x4c4bb639, 0x7c406210, 0xdf900609, 0x8b3ef1e0, 0x30e32fb0, 0xd97a4329, 0xff98aed0, 0xcd278c3f, 0xe6078467, 0xfbd12f35),
|
||||
SECP256K1_GE_STORAGE_CONST(0xae528146, 0x03fdf91e, 0xc592977e, 0x12461dc7, 0xb9e038f8, 0x048dcb62, 0xea264756, 0xd459ae42, 0x80ef658d, 0x92becb84, 0xdba8e4f9, 0x560d7a72, 0xbaf4c393, 0xfbcf6007, 0x11039f1c, 0x224faaad),
|
||||
SECP256K1_GE_STORAGE_CONST(0x00df3d91, 0x35975eee, 0x91fab903, 0xe3128e4a, 0xca071dde, 0x270814e5, 0xcbda69ec, 0xcad58f46, 0x11b590aa, 0x92d89969, 0x2dbd932f, 0x08013b8b, 0x45afabc6, 0x43677db2, 0x143e0c0f, 0x5865fb03),
|
||||
SECP256K1_GE_STORAGE_CONST(0x1168155b, 0x987e9bc8, 0x84c5f3f4, 0x92ebf784, 0xcc8c6735, 0x39d8e5e8, 0xa967115a, 0x2949da9b, 0x0858a470, 0xf403ca97, 0xb1827f6f, 0x544c2c67, 0x08f6cb83, 0xc510c317, 0x96c981ed, 0xb9f61780),
|
||||
SECP256K1_GE_STORAGE_CONST(0xe8d7c0cf, 0x2bb4194c, 0x97bf2a36, 0xbd115ba0, 0x81a9afe8, 0x7663fa3c, 0x9c3cd253, 0x79fe2571, 0x2028ad04, 0xefa00119, 0x5a25d598, 0x67e79502, 0x49de7c61, 0x4751cd9d, 0x4fb317f6, 0xf76f1110),
|
||||
SECP256K1_GE_STORAGE_CONST(0x9532c491, 0xa64851dd, 0xcd0d3e5a, 0x93e17267, 0xa10aca95, 0xa23781aa, 0x5087f340, 0xc45fecc3, 0xb691ddc2, 0x3143a7b6, 0x09969302, 0x258affb8, 0x5bbf8666, 0xe1192319, 0xeb174d88, 0x308bd57a),
|
||||
SECP256K1_GE_STORAGE_CONST(0x6b20b6e2, 0x1ba6cc44, 0x3f2c3a0c, 0x5283ba44, 0xbee43a0a, 0x2799a6cf, 0xbecc0f8a, 0xf8c583ac, 0xf7021e76, 0xd51291a6, 0xf9396215, 0x686f25aa, 0xbec36282, 0x5e11eeea, 0x6e51a6e6, 0xd7d7c006),
|
||||
SECP256K1_GE_STORAGE_CONST(0xde27e6ff, 0x219b3ab1, 0x2b0a9e4e, 0x51fc6092, 0x96e55af6, 0xc6f717d6, 0x12cd6cce, 0x65d6c8f2, 0x48166884, 0x4dc13fd2, 0xed7a7d81, 0x66a0839a, 0x8a960863, 0xfe0001c1, 0x35d206fd, 0x63b87c09),
|
||||
SECP256K1_GE_STORAGE_CONST(0x79a96fb8, 0xd88a08d3, 0x055d38d1, 0x3346b0d4, 0x47d838ca, 0xfcc8fa40, 0x6d3a7157, 0xef84e7e3, 0x6bab9c45, 0x2871b51d, 0xb0df2369, 0xe7860e01, 0x2e37ffea, 0x6689fd1a, 0x9c6fe9cf, 0xb940acea),
|
||||
SECP256K1_GE_STORAGE_CONST(0x06c4d4cb, 0xd32c0ddb, 0x67e988c6, 0x2bdbe6ad, 0xa39b80cc, 0x61afb347, 0x234abe27, 0xa689618c, 0x5b355949, 0xf904fe08, 0x569b2313, 0xe8f19f8d, 0xc5b79e27, 0x70da0832, 0x5fb7a229, 0x238ca6b6),
|
||||
SECP256K1_GE_STORAGE_CONST(0x7027e566, 0x3e727c28, 0x42aa14e5, 0x52c2d2ec, 0x1d8beaa9, 0x8a22ceab, 0x15ccafc3, 0xb4f06249, 0x9b3dffbc, 0xdbd5e045, 0x6931fd03, 0x8b1c6a9b, 0x4c168c6d, 0xa6553897, 0xfe11ce49, 0xac728139),
|
||||
SECP256K1_GE_STORAGE_CONST(0xee3520c3, 0x9f2b954d, 0xf8e15547, 0xdaeb6cc8, 0x04c8f3b0, 0x9301f53e, 0xe0c11ea1, 0xeace539d, 0x244ff873, 0x7e060c98, 0xe843c353, 0xcd35d2e4, 0x3cd8b082, 0xcffbc9ae, 0x81eafa70, 0x332f9748),
|
||||
SECP256K1_GE_STORAGE_CONST(0xdaecd756, 0xf5b706a4, 0xc14e1095, 0x3e2f70df, 0xa81276e7, 0x71806b89, 0x4d8a5502, 0xa0ef4998, 0xbac906c0, 0x948b1d48, 0xe023f439, 0xfd3770b8, 0x837f60cc, 0x40552a51, 0x433d0b79, 0x6610da27),
|
||||
SECP256K1_GE_STORAGE_CONST(0x55e1ca28, 0x750fe2d0, 0x57f7449b, 0x3f49d999, 0x3b9616dd, 0x5387bc2e, 0x6e6698f8, 0xc4ea49f4, 0xe339e0e9, 0xa4c7fa99, 0xd063e062, 0x6582bce2, 0x33c6b1ee, 0x17a5b47f, 0x6d43ecf8, 0x98b40120),
|
||||
SECP256K1_GE_STORAGE_CONST(0xdd82cac2, 0x9e0e0135, 0x4964d3bc, 0x27469233, 0xf13bbd5e, 0xd7aff24b, 0x4902fca8, 0x17294b12, 0x561ab1d6, 0xcd9bcb6e, 0x805585cf, 0x3df8714c, 0x1bfa6304, 0x5efbf122, 0x1a3d8fd9, 0x3827764a),
|
||||
SECP256K1_GE_STORAGE_CONST(0xda5cbfb7, 0x3522e9c7, 0xcb594436, 0x83677038, 0x0eaa64a9, 0x2eca3888, 0x0fe4c9d6, 0xdeb22dbf, 0x4f46de68, 0x0447c780, 0xc54a314b, 0x5389a926, 0xbba8910b, 0x869fc6cd, 0x42ee82e8, 0x5895e42a),
|
||||
SECP256K1_GE_STORAGE_CONST(0x4e09830e, 0xc8894c58, 0x4e6278de, 0x167a96b0, 0x20d60463, 0xee48f788, 0x4974d66e, 0x871e35e9, 0x21259c4d, 0x332ca932, 0x2e187df9, 0xe7afbc23, 0x9d171ebc, 0x7d9e2560, 0x503f50b1, 0x9fe45834),
|
||||
SECP256K1_GE_STORAGE_CONST(0xabfff6ca, 0x41dcfd17, 0x03cae629, 0x9d127971, 0xf19ee000, 0x2db332e6, 0x5cc209a3, 0xc21b8f54, 0x65991d60, 0xee54f5cc, 0xddf7a732, 0xa76b0303, 0xb9f519a6, 0x22ea0390, 0x8af23ffa, 0x35ae6632),
|
||||
SECP256K1_GE_STORAGE_CONST(0xc6c9b92c, 0x91e045a5, 0xa1913277, 0x44d6fce2, 0x11b12c7c, 0x9b3112d6, 0xc61e14a6, 0xd6b1ae12, 0x04ab0396, 0xebdc4c6a, 0xc213cc3e, 0x077a2e80, 0xb4ba7b2b, 0x33907d56, 0x2c98ccf7, 0xb82a2e9f),
|
||||
SECP256K1_GE_STORAGE_CONST(0x66f6e6d9, 0xc4bb9a5f, 0x99085781, 0x83cb9362, 0x2ea437d8, 0xccd31969, 0xffadca3a, 0xff1d3935, 0x50a5b06e, 0x39e039d7, 0x1dfb2723, 0x18db74e5, 0x5af64da1, 0xdfc34586, 0x6aac3bd0, 0x5792a890),
|
||||
SECP256K1_GE_STORAGE_CONST(0x58ded03c, 0x98e1a890, 0x63fc7793, 0xe3ecd896, 0x235e75c9, 0x82e7008f, 0xddbf3ca8, 0x5b7e9ecb, 0x34594776, 0x58ab6821, 0xaf43a453, 0xa946fda9, 0x13d24999, 0xccf22df8, 0xd291ef59, 0xb08975c0),
|
||||
SECP256K1_GE_STORAGE_CONST(0x74557864, 0x4f2b0486, 0xd5beea7c, 0x2d258ccb, 0x78a870e1, 0x848982d8, 0xed3f91a4, 0x9db83a36, 0xd84e940e, 0x1d33c28a, 0x62398ec8, 0xc493aee7, 0x7c2ba722, 0x42dee7ae, 0x3c35c256, 0xad00cf42),
|
||||
SECP256K1_GE_STORAGE_CONST(0x7fc7963a, 0x16abc8fb, 0x5d61eb61, 0x0fc50a68, 0x754470d2, 0xf43df3be, 0x52228f66, 0x522fe61b, 0x499f9e7f, 0x462c6545, 0x29687af4, 0x9f7c732d, 0x48801ce5, 0x21acd546, 0xc6fb903c, 0x7c265032),
|
||||
SECP256K1_GE_STORAGE_CONST(0xb2f6257c, 0xc58df82f, 0xb9ba4f36, 0x7ededf03, 0xf8ea10f3, 0x104d7ae6, 0x233b7ac4, 0x725e11de, 0x9c7a32df, 0x4842f33d, 0xaad84f0b, 0x62e88b40, 0x46ddcbde, 0xbbeec6f8, 0x93bfde27, 0x0561dc73),
|
||||
SECP256K1_GE_STORAGE_CONST(0xe2cdfd27, 0x8a8e22be, 0xabf08b79, 0x1bc6ae38, 0x41d22a9a, 0x9472e266, 0x1a7c6e83, 0xa2f74725, 0x0e26c103, 0xe0dd93b2, 0x3724f3b7, 0x8bb7366e, 0x2c245768, 0xd64f3283, 0xd8316e8a, 0x1383b977),
|
||||
SECP256K1_GE_STORAGE_CONST(0x757c13e7, 0xe866017e, 0xe6af61d7, 0x161d208a, 0xc438f712, 0x242fcd23, 0x63a10e59, 0xd67e41fb, 0xb550c6a9, 0x4ddb15f3, 0xfeea4bfe, 0xd2faa19f, 0x2aa2fbd3, 0x0c6ae785, 0xe357f365, 0xb30d12e0),
|
||||
SECP256K1_GE_STORAGE_CONST(0x528d525e, 0xac30095b, 0x5e5f83ca, 0x4d3dea63, 0xeb608f2d, 0x18dd25a7, 0x2529c8e5, 0x1ae5f9f1, 0xfde2860b, 0x492a4106, 0x9f356c05, 0x3ebc045e, 0x4ad08b79, 0x3e264935, 0xf25785a9, 0x8690b5ee),
|
||||
SECP256K1_GE_STORAGE_CONST(0x150df593, 0x5b6956a0, 0x0cfed843, 0xb9d6ffce, 0x4f790022, 0xea18730f, 0xc495111d, 0x91568e55, 0x6700a2ca, 0x9ff4ed32, 0xc1697312, 0x4eb51ce3, 0x5656344b, 0x65a1e3d5, 0xd6c1f7ce, 0x29233f82),
|
||||
SECP256K1_GE_STORAGE_CONST(0x38e02eaf, 0x2c8774fd, 0x58b8b373, 0x732457f1, 0x16dbe53b, 0xea5683d9, 0xada20dd7, 0x14ce20a6, 0x6ac5362e, 0xbb425416, 0x8250f43f, 0xa4ee2b63, 0x0406324f, 0x1c876d60, 0xebe5be2c, 0x6eb1515b),
|
||||
};
|
||||
secp256k1_generator gen;
|
||||
secp256k1_ge ge;
|
||||
secp256k1_ge_storage ges;
|
||||
int i;
|
||||
unsigned char v[32];
|
||||
unsigned char s[32] = {0};
|
||||
secp256k1_scalar sc;
|
||||
secp256k1_scalar_set_b32(&sc, s, NULL);
|
||||
for (i = 1; i <= 32; i++) {
|
||||
memset(v, 0, 31);
|
||||
v[31] = i;
|
||||
CHECK(secp256k1_generator_generate_blinded(ctx, &gen, v, s));
|
||||
secp256k1_generator_load(&ge, &gen);
|
||||
secp256k1_ge_to_storage(&ges, &ge);
|
||||
CHECK(memcmp(&ges, &results[i - 1], sizeof(secp256k1_ge_storage)) == 0);
|
||||
CHECK(secp256k1_generator_generate(ctx, &gen, v));
|
||||
secp256k1_generator_load(&ge, &gen);
|
||||
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();
|
||||
}
|
||||
|
||||
#endif
|
||||
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
|
||||
15
src/modules/rangeproof/Makefile.am.include
Normal file
15
src/modules/rangeproof/Makefile.am.include
Normal file
@@ -0,0 +1,15 @@
|
||||
include_HEADERS += include/secp256k1_rangeproof.h
|
||||
noinst_HEADERS += src/modules/rangeproof/main_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/pedersen.h
|
||||
noinst_HEADERS += src/modules/rangeproof/pedersen_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/borromean.h
|
||||
noinst_HEADERS += src/modules/rangeproof/borromean_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/rangeproof.h
|
||||
noinst_HEADERS += src/modules/rangeproof/rangeproof_impl.h
|
||||
noinst_HEADERS += src/modules/rangeproof/tests_impl.h
|
||||
if USE_BENCHMARK
|
||||
noinst_PROGRAMS += bench_rangeproof
|
||||
bench_rangeproof_SOURCES = src/bench_rangeproof.c
|
||||
bench_rangeproof_LDADD = libsecp256k1.la $(SECP_LIBS)
|
||||
bench_rangeproof_LDFLAGS = -static
|
||||
endif
|
||||
24
src/modules/rangeproof/borromean.h
Normal file
24
src/modules/rangeproof/borromean.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2014, 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef _SECP256K1_BORROMEAN_H_
|
||||
#define _SECP256K1_BORROMEAN_H_
|
||||
|
||||
#include "scalar.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
int secp256k1_borromean_verify(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_scalar *evalues, const unsigned char *e0, const secp256k1_scalar *s,
|
||||
const secp256k1_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen);
|
||||
|
||||
int secp256k1_borromean_sign(const secp256k1_ecmult_context* ecmult_ctx, const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
|
||||
unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *k, const secp256k1_scalar *sec,
|
||||
const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen);
|
||||
|
||||
#endif
|
||||
204
src/modules/rangeproof/borromean_impl.h
Normal file
204
src/modules/rangeproof/borromean_impl.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2014, 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
#ifndef _SECP256K1_BORROMEAN_IMPL_H_
|
||||
#define _SECP256K1_BORROMEAN_IMPL_H_
|
||||
|
||||
#include "scalar.h"
|
||||
#include "field.h"
|
||||
#include "group.h"
|
||||
#include "hash.h"
|
||||
#include "eckey.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "borromean.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(SECP256K1_BIG_ENDIAN)
|
||||
#define BE32(x) (x)
|
||||
#elif defined(SECP256K1_LITTLE_ENDIAN)
|
||||
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
|
||||
#endif
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_borromean_hash(unsigned char *hash, const unsigned char *m, size_t mlen, const unsigned char *e, size_t elen,
|
||||
size_t ridx, size_t eidx) {
|
||||
uint32_t ring;
|
||||
uint32_t epos;
|
||||
secp256k1_sha256 sha256_en;
|
||||
secp256k1_sha256_initialize(&sha256_en);
|
||||
ring = BE32((uint32_t)ridx);
|
||||
epos = BE32((uint32_t)eidx);
|
||||
secp256k1_sha256_write(&sha256_en, e, elen);
|
||||
secp256k1_sha256_write(&sha256_en, m, mlen);
|
||||
secp256k1_sha256_write(&sha256_en, (unsigned char*)&ring, 4);
|
||||
secp256k1_sha256_write(&sha256_en, (unsigned char*)&epos, 4);
|
||||
secp256k1_sha256_finalize(&sha256_en, hash);
|
||||
}
|
||||
|
||||
/** "Borromean" ring signature.
|
||||
* Verifies nrings concurrent ring signatures all sharing a challenge value.
|
||||
* Signature is one s value per pubkey and a hash.
|
||||
* Verification equation:
|
||||
* | m = H(P_{0..}||message) (Message must contain pubkeys or a pubkey commitment)
|
||||
* | For each ring i:
|
||||
* | | en = to_scalar(H(e0||m||i||0))
|
||||
* | | For each pubkey j:
|
||||
* | | | r = s_i_j G + en * P_i_j
|
||||
* | | | e = H(r||m||i||j)
|
||||
* | | | en = to_scalar(e)
|
||||
* | | r_i = r
|
||||
* | return e_0 ==== H(r_{0..i}||m)
|
||||
*/
|
||||
int secp256k1_borromean_verify(const secp256k1_ecmult_context* ecmult_ctx, secp256k1_scalar *evalues, const unsigned char *e0,
|
||||
const secp256k1_scalar *s, const secp256k1_gej *pubs, const size_t *rsizes, size_t nrings, const unsigned char *m, size_t mlen) {
|
||||
secp256k1_gej rgej;
|
||||
secp256k1_ge rge;
|
||||
secp256k1_scalar ens;
|
||||
secp256k1_sha256 sha256_e0;
|
||||
unsigned char tmp[33];
|
||||
size_t i;
|
||||
size_t j;
|
||||
size_t count;
|
||||
size_t size;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ecmult_ctx != NULL);
|
||||
VERIFY_CHECK(e0 != NULL);
|
||||
VERIFY_CHECK(s != NULL);
|
||||
VERIFY_CHECK(pubs != NULL);
|
||||
VERIFY_CHECK(rsizes != NULL);
|
||||
VERIFY_CHECK(nrings > 0);
|
||||
VERIFY_CHECK(m != NULL);
|
||||
count = 0;
|
||||
secp256k1_sha256_initialize(&sha256_e0);
|
||||
for (i = 0; i < nrings; i++) {
|
||||
VERIFY_CHECK(INT_MAX - count > rsizes[i]);
|
||||
secp256k1_borromean_hash(tmp, m, mlen, e0, 32, i, 0);
|
||||
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
|
||||
for (j = 0; j < rsizes[i]; j++) {
|
||||
if (overflow || secp256k1_scalar_is_zero(&s[count]) || secp256k1_scalar_is_zero(&ens) || secp256k1_gej_is_infinity(&pubs[count])) {
|
||||
return 0;
|
||||
}
|
||||
if (evalues) {
|
||||
/*If requested, save the challenges for proof rewind.*/
|
||||
evalues[count] = ens;
|
||||
}
|
||||
secp256k1_ecmult(ecmult_ctx, &rgej, &pubs[count], &ens, &s[count]);
|
||||
if (secp256k1_gej_is_infinity(&rgej)) {
|
||||
return 0;
|
||||
}
|
||||
/* OPT: loop can be hoisted and split to use batch inversion across all the rings; this would make it much faster. */
|
||||
secp256k1_ge_set_gej_var(&rge, &rgej);
|
||||
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
|
||||
if (j != rsizes[i] - 1) {
|
||||
secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1);
|
||||
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
|
||||
} else {
|
||||
secp256k1_sha256_write(&sha256_e0, tmp, size);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
secp256k1_sha256_write(&sha256_e0, m, mlen);
|
||||
secp256k1_sha256_finalize(&sha256_e0, tmp);
|
||||
return memcmp(e0, tmp, 32) == 0;
|
||||
}
|
||||
|
||||
int secp256k1_borromean_sign(const secp256k1_ecmult_context* ecmult_ctx, const secp256k1_ecmult_gen_context *ecmult_gen_ctx,
|
||||
unsigned char *e0, secp256k1_scalar *s, const secp256k1_gej *pubs, const secp256k1_scalar *k, const secp256k1_scalar *sec,
|
||||
const size_t *rsizes, const size_t *secidx, size_t nrings, const unsigned char *m, size_t mlen) {
|
||||
secp256k1_gej rgej;
|
||||
secp256k1_ge rge;
|
||||
secp256k1_scalar ens;
|
||||
secp256k1_sha256 sha256_e0;
|
||||
unsigned char tmp[33];
|
||||
size_t i;
|
||||
size_t j;
|
||||
size_t count;
|
||||
size_t size;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ecmult_ctx != NULL);
|
||||
VERIFY_CHECK(ecmult_gen_ctx != NULL);
|
||||
VERIFY_CHECK(e0 != NULL);
|
||||
VERIFY_CHECK(s != NULL);
|
||||
VERIFY_CHECK(pubs != NULL);
|
||||
VERIFY_CHECK(k != NULL);
|
||||
VERIFY_CHECK(sec != NULL);
|
||||
VERIFY_CHECK(rsizes != NULL);
|
||||
VERIFY_CHECK(secidx != NULL);
|
||||
VERIFY_CHECK(nrings > 0);
|
||||
VERIFY_CHECK(m != NULL);
|
||||
secp256k1_sha256_initialize(&sha256_e0);
|
||||
count = 0;
|
||||
for (i = 0; i < nrings; i++) {
|
||||
VERIFY_CHECK(INT_MAX - count > rsizes[i]);
|
||||
secp256k1_ecmult_gen(ecmult_gen_ctx, &rgej, &k[i]);
|
||||
secp256k1_ge_set_gej(&rge, &rgej);
|
||||
if (secp256k1_gej_is_infinity(&rgej)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
|
||||
for (j = secidx[i] + 1; j < rsizes[i]; j++) {
|
||||
secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j);
|
||||
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&ens)) {
|
||||
return 0;
|
||||
}
|
||||
/** The signing algorithm as a whole is not memory uniform so there is likely a cache sidechannel that
|
||||
* leaks which members are non-forgeries. That the forgeries themselves are variable time may leave
|
||||
* an additional privacy impacting timing side-channel, but not a key loss one.
|
||||
*/
|
||||
secp256k1_ecmult(ecmult_ctx, &rgej, &pubs[count + j], &ens, &s[count + j]);
|
||||
if (secp256k1_gej_is_infinity(&rgej)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej_var(&rge, &rgej);
|
||||
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
|
||||
}
|
||||
secp256k1_sha256_write(&sha256_e0, tmp, size);
|
||||
count += rsizes[i];
|
||||
}
|
||||
secp256k1_sha256_write(&sha256_e0, m, mlen);
|
||||
secp256k1_sha256_finalize(&sha256_e0, e0);
|
||||
count = 0;
|
||||
for (i = 0; i < nrings; i++) {
|
||||
VERIFY_CHECK(INT_MAX - count > rsizes[i]);
|
||||
secp256k1_borromean_hash(tmp, m, mlen, e0, 32, i, 0);
|
||||
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&ens)) {
|
||||
return 0;
|
||||
}
|
||||
for (j = 0; j < secidx[i]; j++) {
|
||||
secp256k1_ecmult(ecmult_ctx, &rgej, &pubs[count + j], &ens, &s[count + j]);
|
||||
if (secp256k1_gej_is_infinity(&rgej)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_ge_set_gej_var(&rge, &rgej);
|
||||
secp256k1_eckey_pubkey_serialize(&rge, tmp, &size, 1);
|
||||
secp256k1_borromean_hash(tmp, m, mlen, tmp, 33, i, j + 1);
|
||||
secp256k1_scalar_set_b32(&ens, tmp, &overflow);
|
||||
if (overflow || secp256k1_scalar_is_zero(&ens)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
secp256k1_scalar_mul(&s[count + j], &ens, &sec[i]);
|
||||
secp256k1_scalar_negate(&s[count + j], &s[count + j]);
|
||||
secp256k1_scalar_add(&s[count + j], &s[count + j], &k[i]);
|
||||
if (secp256k1_scalar_is_zero(&s[count + j])) {
|
||||
return 0;
|
||||
}
|
||||
count += rsizes[i];
|
||||
}
|
||||
secp256k1_scalar_clear(&ens);
|
||||
secp256k1_ge_clear(&rge);
|
||||
secp256k1_gej_clear(&rgej);
|
||||
memset(tmp, 0, 33);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
300
src/modules/rangeproof/main_impl.h
Normal file
300
src/modules/rangeproof/main_impl.h
Normal file
@@ -0,0 +1,300 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2014-2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_RANGEPROOF_MAIN
|
||||
#define SECP256K1_MODULE_RANGEPROOF_MAIN
|
||||
|
||||
#include "group.h"
|
||||
|
||||
#include "modules/rangeproof/pedersen_impl.h"
|
||||
#include "modules/rangeproof/borromean_impl.h"
|
||||
#include "modules/rangeproof/rangeproof_impl.h"
|
||||
|
||||
/** Alternative generator for secp256k1.
|
||||
* 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 = {{
|
||||
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,
|
||||
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;
|
||||
|
||||
static void secp256k1_pedersen_commitment_load(secp256k1_ge* ge, const secp256k1_pedersen_commitment* commit) {
|
||||
secp256k1_fe fe;
|
||||
secp256k1_fe_set_b32(&fe, &commit->data[1]);
|
||||
secp256k1_ge_set_xquad(ge, &fe);
|
||||
if (commit->data[0] & 1) {
|
||||
secp256k1_ge_neg(ge, ge);
|
||||
}
|
||||
}
|
||||
|
||||
static void secp256k1_pedersen_commitment_save(secp256k1_pedersen_commitment* commit, secp256k1_ge* ge) {
|
||||
secp256k1_fe_normalize(&ge->x);
|
||||
secp256k1_fe_get_b32(&commit->data[1], &ge->x);
|
||||
commit->data[0] = 9 ^ secp256k1_fe_is_quad_var(&ge->y);
|
||||
}
|
||||
|
||||
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 ||
|
||||
!secp256k1_fe_set_b32(&x, &input[1]) ||
|
||||
!secp256k1_ge_set_xquad(&ge, &x)) {
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Generates a pedersen commitment: *commit = blind * G + value * G2. The blinding factor is 32 bytes.*/
|
||||
int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_commitment *commit, const unsigned char *blind, uint64_t value, const secp256k1_generator* gen) {
|
||||
secp256k1_ge genp;
|
||||
secp256k1_gej rj;
|
||||
secp256k1_ge r;
|
||||
secp256k1_scalar sec;
|
||||
int overflow;
|
||||
int ret = 0;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(blind != NULL);
|
||||
ARG_CHECK(gen != NULL);
|
||||
secp256k1_generator_load(&genp, gen);
|
||||
secp256k1_scalar_set_b32(&sec, blind, &overflow);
|
||||
if (!overflow) {
|
||||
secp256k1_pedersen_ecmult(&ctx->ecmult_gen_ctx, &rj, &sec, value, &genp);
|
||||
if (!secp256k1_gej_is_infinity(&rj)) {
|
||||
secp256k1_ge_set_gej(&r, &rj);
|
||||
secp256k1_pedersen_commitment_save(commit, &r);
|
||||
ret = 1;
|
||||
}
|
||||
secp256k1_gej_clear(&rj);
|
||||
secp256k1_ge_clear(&r);
|
||||
}
|
||||
secp256k1_scalar_clear(&sec);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Takes a list of n pointers to 32 byte blinding values, the first negs of which are treated with positive sign and the rest
|
||||
* negative, then calculates an additional blinding value that adds to zero.
|
||||
*/
|
||||
int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *blind_out, const unsigned char * const *blinds, size_t n, size_t npositive) {
|
||||
secp256k1_scalar acc;
|
||||
secp256k1_scalar x;
|
||||
size_t i;
|
||||
int overflow;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(blind_out != NULL);
|
||||
ARG_CHECK(blinds != NULL);
|
||||
ARG_CHECK(npositive <= n);
|
||||
(void) ctx;
|
||||
secp256k1_scalar_set_int(&acc, 0);
|
||||
for (i = 0; i < n; i++) {
|
||||
secp256k1_scalar_set_b32(&x, blinds[i], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
if (i >= npositive) {
|
||||
secp256k1_scalar_negate(&x, &x);
|
||||
}
|
||||
secp256k1_scalar_add(&acc, &acc, &x);
|
||||
}
|
||||
secp256k1_scalar_get_b32(blind_out, &acc);
|
||||
secp256k1_scalar_clear(&acc);
|
||||
secp256k1_scalar_clear(&x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Takes two lists of commitments and sums the first set and subtracts the second and verifies that they sum to excess. */
|
||||
int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k1_pedersen_commitment * const* commits, size_t pcnt, const secp256k1_pedersen_commitment * const* ncommits, size_t ncnt) {
|
||||
secp256k1_gej accj;
|
||||
secp256k1_ge add;
|
||||
size_t i;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(!pcnt || (commits != NULL));
|
||||
ARG_CHECK(!ncnt || (ncommits != NULL));
|
||||
(void) ctx;
|
||||
secp256k1_gej_set_infinity(&accj);
|
||||
for (i = 0; i < ncnt; i++) {
|
||||
secp256k1_pedersen_commitment_load(&add, ncommits[i]);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
|
||||
}
|
||||
secp256k1_gej_neg(&accj, &accj);
|
||||
for (i = 0; i < pcnt; i++) {
|
||||
secp256k1_pedersen_commitment_load(&add, commits[i]);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &add, NULL);
|
||||
}
|
||||
return secp256k1_gej_is_infinity(&accj);
|
||||
}
|
||||
|
||||
int secp256k1_pedersen_blind_generator_blind_sum(const secp256k1_context* ctx, const uint64_t *value, const unsigned char* const* generator_blind, unsigned char* const* blinding_factor, size_t n_total, size_t n_inputs) {
|
||||
secp256k1_scalar sum;
|
||||
secp256k1_scalar tmp;
|
||||
size_t i;
|
||||
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(n_total == 0 || value != NULL);
|
||||
ARG_CHECK(n_total == 0 || generator_blind != NULL);
|
||||
ARG_CHECK(n_total == 0 || blinding_factor != NULL);
|
||||
ARG_CHECK(n_total > n_inputs);
|
||||
(void) ctx;
|
||||
|
||||
if (n_total == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
secp256k1_scalar_set_int(&sum, 0);
|
||||
for (i = 0; i < n_total; i++) {
|
||||
int overflow = 0;
|
||||
secp256k1_scalar addend;
|
||||
secp256k1_scalar_set_u64(&addend, value[i]); /* s = v */
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, generator_blind[i], &overflow);
|
||||
if (overflow == 1) {
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&addend);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_mul(&addend, &addend, &tmp); /* s = vr */
|
||||
|
||||
secp256k1_scalar_set_b32(&tmp, blinding_factor[i], &overflow);
|
||||
if (overflow == 1) {
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&addend);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 0;
|
||||
}
|
||||
secp256k1_scalar_add(&addend, &addend, &tmp); /* s = vr + r' */
|
||||
secp256k1_scalar_cond_negate(&addend, i < n_inputs); /* s is negated if it's an input */
|
||||
secp256k1_scalar_add(&sum, &sum, &addend); /* sum += s */
|
||||
secp256k1_scalar_clear(&addend);
|
||||
}
|
||||
|
||||
/* Right now tmp has the last pedersen blinding factor. Subtract the sum from it. */
|
||||
secp256k1_scalar_negate(&sum, &sum);
|
||||
secp256k1_scalar_add(&tmp, &tmp, &sum);
|
||||
secp256k1_scalar_get_b32(blinding_factor[n_total - 1], &tmp);
|
||||
|
||||
secp256k1_scalar_clear(&tmp);
|
||||
secp256k1_scalar_clear(&sum);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int secp256k1_rangeproof_info(const secp256k1_context* ctx, int *exp, int *mantissa,
|
||||
uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) {
|
||||
size_t offset;
|
||||
uint64_t scale;
|
||||
ARG_CHECK(exp != NULL);
|
||||
ARG_CHECK(mantissa != NULL);
|
||||
ARG_CHECK(min_value != NULL);
|
||||
ARG_CHECK(max_value != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
offset = 0;
|
||||
scale = 1;
|
||||
(void)ctx;
|
||||
return secp256k1_rangeproof_getheader_impl(&offset, exp, mantissa, &scale, min_value, max_value, proof, plen);
|
||||
}
|
||||
|
||||
int secp256k1_rangeproof_rewind(const secp256k1_context* ctx,
|
||||
unsigned char *blind_out, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
|
||||
uint64_t *min_value, uint64_t *max_value,
|
||||
const secp256k1_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen) {
|
||||
secp256k1_ge commitp;
|
||||
secp256k1_ge genp;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(min_value != NULL);
|
||||
ARG_CHECK(max_value != NULL);
|
||||
ARG_CHECK(message_out != NULL || outlen == NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
ARG_CHECK(extra_commit != NULL || extra_commit_len == 0);
|
||||
ARG_CHECK(gen != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
secp256k1_pedersen_commitment_load(&commitp, commit);
|
||||
secp256k1_generator_load(&genp, gen);
|
||||
return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx,
|
||||
blind_out, value_out, message_out, outlen, nonce, min_value, max_value, &commitp, proof, plen, extra_commit, extra_commit_len, &genp);
|
||||
}
|
||||
|
||||
int secp256k1_rangeproof_verify(const secp256k1_context* ctx, uint64_t *min_value, uint64_t *max_value,
|
||||
const secp256k1_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen) {
|
||||
secp256k1_ge commitp;
|
||||
secp256k1_ge genp;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(min_value != NULL);
|
||||
ARG_CHECK(max_value != NULL);
|
||||
ARG_CHECK(extra_commit != NULL || extra_commit_len == 0);
|
||||
ARG_CHECK(gen != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
secp256k1_pedersen_commitment_load(&commitp, commit);
|
||||
secp256k1_generator_load(&genp, gen);
|
||||
return secp256k1_rangeproof_verify_impl(&ctx->ecmult_ctx, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL, min_value, max_value, &commitp, proof, plen, extra_commit, extra_commit_len, &genp);
|
||||
}
|
||||
|
||||
int secp256k1_rangeproof_sign(const secp256k1_context* ctx, unsigned char *proof, size_t *plen, uint64_t min_value,
|
||||
const secp256k1_pedersen_commitment *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value,
|
||||
const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen){
|
||||
secp256k1_ge commitp;
|
||||
secp256k1_ge genp;
|
||||
VERIFY_CHECK(ctx != NULL);
|
||||
ARG_CHECK(proof != NULL);
|
||||
ARG_CHECK(plen != NULL);
|
||||
ARG_CHECK(commit != NULL);
|
||||
ARG_CHECK(blind != NULL);
|
||||
ARG_CHECK(nonce != NULL);
|
||||
ARG_CHECK(message != NULL || msg_len == 0);
|
||||
ARG_CHECK(extra_commit != NULL || extra_commit_len == 0);
|
||||
ARG_CHECK(gen != NULL);
|
||||
ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
|
||||
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
|
||||
secp256k1_pedersen_commitment_load(&commitp, commit);
|
||||
secp256k1_generator_load(&genp, gen);
|
||||
return secp256k1_rangeproof_sign_impl(&ctx->ecmult_ctx, &ctx->ecmult_gen_ctx,
|
||||
proof, plen, min_value, &commitp, blind, nonce, exp, min_bits, value, message, msg_len, extra_commit, extra_commit_len, &genp);
|
||||
}
|
||||
|
||||
#endif
|
||||
22
src/modules/rangeproof/pedersen.h
Normal file
22
src/modules/rangeproof/pedersen.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2014, 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_PEDERSEN_H_
|
||||
#define _SECP256K1_PEDERSEN_H_
|
||||
|
||||
#include "ecmult_gen.h"
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/** Multiply a small number with the generator: r = gn*G2 */
|
||||
static void secp256k1_pedersen_ecmult_small(secp256k1_gej *r, uint64_t gn, const secp256k1_ge* genp);
|
||||
|
||||
/* sec * G + value * G2. */
|
||||
static void secp256k1_pedersen_ecmult(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_gej *rj, const secp256k1_scalar *sec, uint64_t value, const secp256k1_ge* genp);
|
||||
|
||||
#endif
|
||||
51
src/modules/rangeproof/pedersen_impl.h
Normal file
51
src/modules/rangeproof/pedersen_impl.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/***********************************************************************
|
||||
* Copyright (c) 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php. *
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_PEDERSEN_IMPL_H_
|
||||
#define _SECP256K1_PEDERSEN_IMPL_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "eckey.h"
|
||||
#include "ecmult_const.h"
|
||||
#include "ecmult_gen.h"
|
||||
#include "group.h"
|
||||
#include "field.h"
|
||||
#include "scalar.h"
|
||||
#include "util.h"
|
||||
|
||||
static void secp256k1_pedersen_scalar_set_u64(secp256k1_scalar *sec, uint64_t value) {
|
||||
unsigned char data[32];
|
||||
int i;
|
||||
for (i = 0; i < 24; i++) {
|
||||
data[i] = 0;
|
||||
}
|
||||
for (; i < 32; i++) {
|
||||
data[i] = value >> 56;
|
||||
value <<= 8;
|
||||
}
|
||||
secp256k1_scalar_set_b32(sec, data, NULL);
|
||||
memset(data, 0, 32);
|
||||
}
|
||||
|
||||
static void secp256k1_pedersen_ecmult_small(secp256k1_gej *r, uint64_t gn, const secp256k1_ge* genp) {
|
||||
secp256k1_scalar s;
|
||||
secp256k1_pedersen_scalar_set_u64(&s, gn);
|
||||
secp256k1_ecmult_const(r, genp, &s, 64);
|
||||
secp256k1_scalar_clear(&s);
|
||||
}
|
||||
|
||||
/* sec * G + value * G2. */
|
||||
SECP256K1_INLINE static void secp256k1_pedersen_ecmult(const secp256k1_ecmult_gen_context *ecmult_gen_ctx, secp256k1_gej *rj, const secp256k1_scalar *sec, uint64_t value, const secp256k1_ge* genp) {
|
||||
secp256k1_gej vj;
|
||||
secp256k1_ecmult_gen(ecmult_gen_ctx, rj, sec);
|
||||
secp256k1_pedersen_ecmult_small(&vj, value, genp);
|
||||
/* FIXME: constant time. */
|
||||
secp256k1_gej_add_var(rj, rj, &vj, NULL);
|
||||
secp256k1_gej_clear(&vj);
|
||||
}
|
||||
|
||||
#endif
|
||||
21
src/modules/rangeproof/rangeproof.h
Normal file
21
src/modules/rangeproof/rangeproof.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_RANGEPROOF_H_
|
||||
#define _SECP256K1_RANGEPROOF_H_
|
||||
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "ecmult.h"
|
||||
#include "ecmult_gen.h"
|
||||
|
||||
static int secp256k1_rangeproof_verify_impl(const secp256k1_ecmult_context* ecmult_ctx,
|
||||
const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
|
||||
unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
|
||||
uint64_t *min_value, uint64_t *max_value, const secp256k1_ge *commit, const unsigned char *proof, size_t plen,
|
||||
const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp);
|
||||
|
||||
#endif
|
||||
685
src/modules/rangeproof/rangeproof_impl.h
Normal file
685
src/modules/rangeproof/rangeproof_impl.h
Normal file
@@ -0,0 +1,685 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _SECP256K1_RANGEPROOF_IMPL_H_
|
||||
#define _SECP256K1_RANGEPROOF_IMPL_H_
|
||||
|
||||
#include "eckey.h"
|
||||
#include "scalar.h"
|
||||
#include "group.h"
|
||||
#include "rangeproof.h"
|
||||
#include "hash_impl.h"
|
||||
#include "pedersen_impl.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "modules/rangeproof/pedersen.h"
|
||||
#include "modules/rangeproof/borromean.h"
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_pub_expand(secp256k1_gej *pubs,
|
||||
int exp, size_t *rsizes, size_t rings, const secp256k1_ge* genp) {
|
||||
secp256k1_gej base;
|
||||
size_t i;
|
||||
size_t j;
|
||||
size_t npub;
|
||||
VERIFY_CHECK(exp < 19);
|
||||
if (exp < 0) {
|
||||
exp = 0;
|
||||
}
|
||||
secp256k1_gej_set_ge(&base, genp);
|
||||
secp256k1_gej_neg(&base, &base);
|
||||
while (exp--) {
|
||||
/* Multiplication by 10 */
|
||||
secp256k1_gej tmp;
|
||||
secp256k1_gej_double_var(&tmp, &base, NULL);
|
||||
secp256k1_gej_double_var(&base, &tmp, NULL);
|
||||
secp256k1_gej_double_var(&base, &base, NULL);
|
||||
secp256k1_gej_add_var(&base, &base, &tmp, NULL);
|
||||
}
|
||||
npub = 0;
|
||||
for (i = 0; i < rings; i++) {
|
||||
for (j = 1; j < rsizes[i]; j++) {
|
||||
secp256k1_gej_add_var(&pubs[npub + j], &pubs[npub + j - 1], &base, NULL);
|
||||
}
|
||||
if (i < rings - 1) {
|
||||
secp256k1_gej_double_var(&base, &base, NULL);
|
||||
secp256k1_gej_double_var(&base, &base, NULL);
|
||||
}
|
||||
npub += rsizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_serialize_point(unsigned char* data, const secp256k1_ge *point) {
|
||||
secp256k1_fe pointx;
|
||||
pointx = point->x;
|
||||
secp256k1_fe_normalize(&pointx);
|
||||
data[0] = !secp256k1_fe_is_quad_var(&point->y);
|
||||
secp256k1_fe_get_b32(data + 1, &pointx);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_rangeproof_genrand(secp256k1_scalar *sec, secp256k1_scalar *s, unsigned char *message,
|
||||
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 rng;
|
||||
secp256k1_scalar acc;
|
||||
int overflow;
|
||||
int ret;
|
||||
size_t i;
|
||||
size_t j;
|
||||
int b;
|
||||
size_t npub;
|
||||
VERIFY_CHECK(len <= 10);
|
||||
memcpy(rngseed, nonce, 32);
|
||||
secp256k1_rangeproof_serialize_point(rngseed + 32, commit);
|
||||
secp256k1_rangeproof_serialize_point(rngseed + 32 + 33, genp);
|
||||
memcpy(rngseed + 33 + 33 + 32, proof, len);
|
||||
secp256k1_rfc6979_hmac_sha256_initialize(&rng, rngseed, 32 + 33 + 33 + len);
|
||||
secp256k1_scalar_clear(&acc);
|
||||
npub = 0;
|
||||
ret = 1;
|
||||
for (i = 0; i < rings; i++) {
|
||||
if (i < rings - 1) {
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32);
|
||||
do {
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32);
|
||||
secp256k1_scalar_set_b32(&sec[i], tmp, &overflow);
|
||||
} while (overflow || secp256k1_scalar_is_zero(&sec[i]));
|
||||
secp256k1_scalar_add(&acc, &acc, &sec[i]);
|
||||
} else {
|
||||
secp256k1_scalar_negate(&acc, &acc);
|
||||
sec[i] = acc;
|
||||
}
|
||||
for (j = 0; j < rsizes[i]; j++) {
|
||||
secp256k1_rfc6979_hmac_sha256_generate(&rng, tmp, 32);
|
||||
if (message) {
|
||||
for (b = 0; b < 32; b++) {
|
||||
tmp[b] ^= message[(i * 4 + j) * 32 + b];
|
||||
message[(i * 4 + j) * 32 + b] = tmp[b];
|
||||
}
|
||||
}
|
||||
secp256k1_scalar_set_b32(&s[npub], tmp, &overflow);
|
||||
ret &= !(overflow || secp256k1_scalar_is_zero(&s[npub]));
|
||||
npub++;
|
||||
}
|
||||
}
|
||||
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
|
||||
secp256k1_scalar_clear(&acc);
|
||||
memset(tmp, 0, 32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_range_proveparams(uint64_t *v, size_t *rings, size_t *rsizes, size_t *npub, size_t *secidx, uint64_t *min_value,
|
||||
int *mantissa, uint64_t *scale, int *exp, int *min_bits, uint64_t value) {
|
||||
size_t i;
|
||||
*rings = 1;
|
||||
rsizes[0] = 1;
|
||||
secidx[0] = 0;
|
||||
*scale = 1;
|
||||
*mantissa = 0;
|
||||
*npub = 0;
|
||||
if (*min_value == UINT64_MAX) {
|
||||
/* If the minimum value is the maximal representable value, then we cannot code a range. */
|
||||
*exp = -1;
|
||||
}
|
||||
if (*exp >= 0) {
|
||||
int max_bits;
|
||||
uint64_t v2;
|
||||
if ((*min_value && value > INT64_MAX) || (value && *min_value >= INT64_MAX)) {
|
||||
/* If either value or min_value is >= 2^63-1 then the other must by zero to avoid overflowing the proven range. */
|
||||
return 0;
|
||||
}
|
||||
max_bits = *min_value ? secp256k1_clz64_var(*min_value) : 64;
|
||||
if (*min_bits > max_bits) {
|
||||
*min_bits = max_bits;
|
||||
}
|
||||
if (*min_bits > 61 || value > INT64_MAX) {
|
||||
/** Ten is not a power of two, so dividing by ten and then representing in base-2 times ten
|
||||
* expands the representable range. The verifier requires the proven range is within 0..2**64.
|
||||
* For very large numbers (all over 2**63) we must change our exponent to compensate.
|
||||
* Rather than handling it precisely, this just disables use of the exponent for big values.
|
||||
*/
|
||||
*exp = 0;
|
||||
}
|
||||
/* Mask off the least significant digits, as requested. */
|
||||
*v = value - *min_value;
|
||||
/* If the user has asked for more bits of proof then there is room for in the exponent, reduce the exponent. */
|
||||
v2 = *min_bits ? (UINT64_MAX>>(64-*min_bits)) : 0;
|
||||
for (i = 0; (int) i < *exp && (v2 <= UINT64_MAX / 10); i++) {
|
||||
*v /= 10;
|
||||
v2 *= 10;
|
||||
}
|
||||
*exp = i;
|
||||
v2 = *v;
|
||||
for (i = 0; (int) i < *exp; i++) {
|
||||
v2 *= 10;
|
||||
*scale *= 10;
|
||||
}
|
||||
/* If the masked number isn't precise, compute the public offset. */
|
||||
*min_value = value - v2;
|
||||
/* How many bits do we need to represent our value? */
|
||||
*mantissa = *v ? 64 - secp256k1_clz64_var(*v) : 1;
|
||||
if (*min_bits > *mantissa) {
|
||||
/* If the user asked for more precision, give it to them. */
|
||||
*mantissa = *min_bits;
|
||||
}
|
||||
/* Digits in radix-4, except for the last digit if our mantissa length is odd. */
|
||||
*rings = (*mantissa + 1) >> 1;
|
||||
for (i = 0; i < *rings; i++) {
|
||||
rsizes[i] = ((i < *rings - 1) | (!(*mantissa&1))) ? 4 : 2;
|
||||
*npub += rsizes[i];
|
||||
secidx[i] = (*v >> (i*2)) & 3;
|
||||
}
|
||||
VERIFY_CHECK(*mantissa>0);
|
||||
VERIFY_CHECK((*v & ~(UINT64_MAX>>(64-*mantissa))) == 0); /* Did this get all the bits? */
|
||||
} else {
|
||||
/* A proof for an exact value. */
|
||||
*exp = 0;
|
||||
*min_value = value;
|
||||
*v = 0;
|
||||
*npub = 2;
|
||||
}
|
||||
VERIFY_CHECK(*v * *scale + *min_value == value);
|
||||
VERIFY_CHECK(*rings > 0);
|
||||
VERIFY_CHECK(*rings <= 32);
|
||||
VERIFY_CHECK(*npub <= 128);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* strawman interface, writes proof in proof, a buffer of plen, proves with respect to min_value the range for commit which has the provided blinding factor and value. */
|
||||
SECP256K1_INLINE static int secp256k1_rangeproof_sign_impl(const secp256k1_ecmult_context* ecmult_ctx,
|
||||
const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
|
||||
unsigned char *proof, size_t *plen, uint64_t min_value,
|
||||
const secp256k1_ge *commit, const unsigned char *blind, const unsigned char *nonce, int exp, int min_bits, uint64_t value,
|
||||
const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp){
|
||||
secp256k1_gej pubs[128]; /* Candidate digits for our proof, most inferred. */
|
||||
secp256k1_scalar s[128]; /* Signatures in our proof, most forged. */
|
||||
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 sha256_m;
|
||||
unsigned char prep[4096];
|
||||
unsigned char tmp[33];
|
||||
unsigned char *signs; /* Location of sign flags in the proof. */
|
||||
uint64_t v;
|
||||
uint64_t scale; /* scale = 10^exp. */
|
||||
int mantissa; /* Number of bits proven in the blinded value. */
|
||||
size_t rings; /* How many digits will our proof cover. */
|
||||
size_t rsizes[32]; /* How many possible values there are for each place. */
|
||||
size_t secidx[32]; /* Which digit is the correct one. */
|
||||
size_t len; /* Number of bytes used so far. */
|
||||
size_t i;
|
||||
int overflow;
|
||||
size_t npub;
|
||||
len = 0;
|
||||
if (*plen < 65 || min_value > value || min_bits > 64 || min_bits < 0 || exp < -1 || exp > 18) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_range_proveparams(&v, &rings, rsizes, &npub, secidx, &min_value, &mantissa, &scale, &exp, &min_bits, value)) {
|
||||
return 0;
|
||||
}
|
||||
proof[len] = (rsizes[0] > 1 ? (64 | exp) : 0) | (min_value ? 32 : 0);
|
||||
len++;
|
||||
if (rsizes[0] > 1) {
|
||||
VERIFY_CHECK(mantissa > 0 && mantissa <= 64);
|
||||
proof[len] = mantissa - 1;
|
||||
len++;
|
||||
}
|
||||
if (min_value) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
proof[len + i] = (min_value >> ((7-i) * 8)) & 255;
|
||||
}
|
||||
len += 8;
|
||||
}
|
||||
/* Do we have enough room in the proof for the message? Each ring gives us 128 bytes, but the
|
||||
* final ring is used to encode the blinding factor and the value, so we can't use that. (Well,
|
||||
* technically there are 64 bytes available if we avoided the other data, but this is difficult
|
||||
* because it's not always in the same place. */
|
||||
if (msg_len > 0 && msg_len > 128 * (rings - 1)) {
|
||||
return 0;
|
||||
}
|
||||
/* Do we have enough room for the proof? */
|
||||
if (*plen - len < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_initialize(&sha256_m);
|
||||
secp256k1_rangeproof_serialize_point(tmp, commit);
|
||||
secp256k1_sha256_write(&sha256_m, tmp, 33);
|
||||
secp256k1_rangeproof_serialize_point(tmp, genp);
|
||||
secp256k1_sha256_write(&sha256_m, tmp, 33);
|
||||
secp256k1_sha256_write(&sha256_m, proof, len);
|
||||
|
||||
memset(prep, 0, 4096);
|
||||
if (message != NULL) {
|
||||
memcpy(prep, message, msg_len);
|
||||
}
|
||||
/* Note, the data corresponding to the blinding factors must be zero. */
|
||||
if (rsizes[rings - 1] > 1) {
|
||||
size_t idx;
|
||||
/* Value encoding sidechannel. */
|
||||
idx = rsizes[rings - 1] - 1;
|
||||
idx -= secidx[rings - 1] == idx;
|
||||
idx = ((rings - 1) * 4 + idx) * 32;
|
||||
for (i = 0; i < 8; i++) {
|
||||
prep[8 + i + idx] = prep[16 + i + idx] = prep[24 + i + idx] = (v >> (56 - i * 8)) & 255;
|
||||
prep[i + idx] = 0;
|
||||
}
|
||||
prep[idx] = 128;
|
||||
}
|
||||
if (!secp256k1_rangeproof_genrand(sec, s, prep, rsizes, rings, nonce, commit, proof, len, genp)) {
|
||||
return 0;
|
||||
}
|
||||
memset(prep, 0, 4096);
|
||||
for (i = 0; i < rings; i++) {
|
||||
/* Sign will overwrite the non-forged signature, move that random value into the nonce. */
|
||||
k[i] = s[i * 4 + secidx[i]];
|
||||
secp256k1_scalar_clear(&s[i * 4 + secidx[i]]);
|
||||
}
|
||||
/** Genrand returns the last blinding factor as -sum(rest),
|
||||
* adding in the blinding factor for our commitment, results in the blinding factor for
|
||||
* the commitment to the last digit that the verifier can compute for itself by subtracting
|
||||
* all the digits in the proof from the commitment. This lets the prover skip sending the
|
||||
* blinded value for one digit.
|
||||
*/
|
||||
secp256k1_scalar_set_b32(&stmp, blind, &overflow);
|
||||
secp256k1_scalar_add(&sec[rings - 1], &sec[rings - 1], &stmp);
|
||||
if (overflow || secp256k1_scalar_is_zero(&sec[rings - 1])) {
|
||||
return 0;
|
||||
}
|
||||
signs = &proof[len];
|
||||
/* We need one sign bit for each blinded value we send. */
|
||||
for (i = 0; i < (rings + 6) >> 3; i++) {
|
||||
signs[i] = 0;
|
||||
len++;
|
||||
}
|
||||
npub = 0;
|
||||
for (i = 0; i < rings; i++) {
|
||||
/*OPT: Use the precomputed gen2 basis?*/
|
||||
secp256k1_pedersen_ecmult(ecmult_gen_ctx, &pubs[npub], &sec[i], ((uint64_t)secidx[i] * scale) << (i*2), genp);
|
||||
if (secp256k1_gej_is_infinity(&pubs[npub])) {
|
||||
return 0;
|
||||
}
|
||||
if (i < rings - 1) {
|
||||
unsigned char tmpc[33];
|
||||
secp256k1_ge c;
|
||||
unsigned char quadness;
|
||||
/*OPT: split loop and batch invert.*/
|
||||
/*OPT: do not compute full pubs[npub] in ge form; we only need x */
|
||||
secp256k1_ge_set_gej_var(&c, &pubs[npub]);
|
||||
secp256k1_rangeproof_serialize_point(tmpc, &c);
|
||||
quadness = tmpc[0];
|
||||
secp256k1_sha256_write(&sha256_m, tmpc, 33);
|
||||
signs[i>>3] |= quadness << (i&7);
|
||||
memcpy(&proof[len], tmpc + 1, 32);
|
||||
len += 32;
|
||||
}
|
||||
npub += rsizes[i];
|
||||
}
|
||||
secp256k1_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp);
|
||||
if (extra_commit != NULL) {
|
||||
secp256k1_sha256_write(&sha256_m, extra_commit, extra_commit_len);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha256_m, tmp);
|
||||
if (!secp256k1_borromean_sign(ecmult_ctx, ecmult_gen_ctx, &proof[len], s, pubs, k, sec, rsizes, secidx, rings, tmp, 32)) {
|
||||
return 0;
|
||||
}
|
||||
len += 32;
|
||||
for (i = 0; i < npub; i++) {
|
||||
secp256k1_scalar_get_b32(&proof[len],&s[i]);
|
||||
len += 32;
|
||||
}
|
||||
VERIFY_CHECK(len <= *plen);
|
||||
*plen = len;
|
||||
memset(prep, 0, 4096);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Computes blinding factor x given k, s, and the challenge e. */
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_recover_x(secp256k1_scalar *x, const secp256k1_scalar *k, const secp256k1_scalar *e,
|
||||
const secp256k1_scalar *s) {
|
||||
secp256k1_scalar stmp;
|
||||
secp256k1_scalar_negate(x, s);
|
||||
secp256k1_scalar_add(x, x, k);
|
||||
secp256k1_scalar_inverse(&stmp, e);
|
||||
secp256k1_scalar_mul(x, x, &stmp);
|
||||
}
|
||||
|
||||
/* Computes ring's nonce given the blinding factor x, the challenge e, and the signature s. */
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_recover_k(secp256k1_scalar *k, const secp256k1_scalar *x, const secp256k1_scalar *e,
|
||||
const secp256k1_scalar *s) {
|
||||
secp256k1_scalar stmp;
|
||||
secp256k1_scalar_mul(&stmp, x, e);
|
||||
secp256k1_scalar_add(k, s, &stmp);
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static void secp256k1_rangeproof_ch32xor(unsigned char *x, const unsigned char *y) {
|
||||
int i;
|
||||
for (i = 0; i < 32; i++) {
|
||||
x[i] ^= y[i];
|
||||
}
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_rangeproof_rewind_inner(secp256k1_scalar *blind, uint64_t *v,
|
||||
unsigned char *m, size_t *mlen, secp256k1_scalar *ev, secp256k1_scalar *s,
|
||||
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) {
|
||||
secp256k1_scalar s_orig[128];
|
||||
secp256k1_scalar sec[32];
|
||||
secp256k1_scalar stmp;
|
||||
unsigned char prep[4096];
|
||||
unsigned char tmp[32];
|
||||
uint64_t value;
|
||||
size_t offset;
|
||||
size_t i;
|
||||
size_t j;
|
||||
int b;
|
||||
size_t skip1;
|
||||
size_t skip2;
|
||||
size_t npub;
|
||||
npub = ((rings - 1) << 2) + rsizes[rings-1];
|
||||
VERIFY_CHECK(npub <= 128);
|
||||
VERIFY_CHECK(npub >= 1);
|
||||
memset(prep, 0, 4096);
|
||||
/* Reconstruct the provers random values. */
|
||||
secp256k1_rangeproof_genrand(sec, s_orig, prep, rsizes, rings, nonce, commit, proof, len, genp);
|
||||
*v = UINT64_MAX;
|
||||
secp256k1_scalar_clear(blind);
|
||||
if (rings == 1 && rsizes[0] == 1) {
|
||||
/* With only a single proof, we can only recover the blinding factor. */
|
||||
secp256k1_rangeproof_recover_x(blind, &s_orig[0], &ev[0], &s[0]);
|
||||
if (v) {
|
||||
*v = 0;
|
||||
}
|
||||
if (mlen) {
|
||||
*mlen = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
npub = (rings - 1) << 2;
|
||||
for (j = 0; j < 2; j++) {
|
||||
size_t idx;
|
||||
/* Look for a value encoding in the last ring. */
|
||||
idx = npub + rsizes[rings - 1] - 1 - j;
|
||||
secp256k1_scalar_get_b32(tmp, &s[idx]);
|
||||
secp256k1_rangeproof_ch32xor(tmp, &prep[idx * 32]);
|
||||
if ((tmp[0] & 128) && (memcmp(&tmp[16], &tmp[24], 8) == 0) && (memcmp(&tmp[8], &tmp[16], 8) == 0)) {
|
||||
value = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
value = (value << 8) + tmp[24 + i];
|
||||
}
|
||||
if (v) {
|
||||
*v = value;
|
||||
}
|
||||
memcpy(&prep[idx * 32], tmp, 32);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j > 1) {
|
||||
/* Couldn't extract a value. */
|
||||
if (mlen) {
|
||||
*mlen = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
skip1 = rsizes[rings - 1] - 1 - j;
|
||||
skip2 = ((value >> ((rings - 1) << 1)) & 3);
|
||||
if (skip1 == skip2) {
|
||||
/*Value is in wrong position.*/
|
||||
if (mlen) {
|
||||
*mlen = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
skip1 += (rings - 1) << 2;
|
||||
skip2 += (rings - 1) << 2;
|
||||
/* Like in the rsize[] == 1 case, Having figured out which s is the one which was not forged, we can recover the blinding factor. */
|
||||
secp256k1_rangeproof_recover_x(&stmp, &s_orig[skip2], &ev[skip2], &s[skip2]);
|
||||
secp256k1_scalar_negate(&sec[rings - 1], &sec[rings - 1]);
|
||||
secp256k1_scalar_add(blind, &stmp, &sec[rings - 1]);
|
||||
if (!m || !mlen || *mlen == 0) {
|
||||
if (mlen) {
|
||||
*mlen = 0;
|
||||
}
|
||||
/* FIXME: cleanup in early out/failure cases. */
|
||||
return 1;
|
||||
}
|
||||
offset = 0;
|
||||
npub = 0;
|
||||
for (i = 0; i < rings; i++) {
|
||||
size_t idx;
|
||||
idx = (value >> (i << 1)) & 3;
|
||||
for (j = 0; j < rsizes[i]; j++) {
|
||||
if (npub == skip1 || npub == skip2) {
|
||||
npub++;
|
||||
continue;
|
||||
}
|
||||
if (idx == j) {
|
||||
/** For the non-forged signatures the signature is calculated instead of random, instead we recover the prover's nonces.
|
||||
* this could just as well recover the blinding factors and messages could be put there as is done for recovering the
|
||||
* blinding factor in the last ring, but it takes an inversion to recover x so it's faster to put the message data in k.
|
||||
*/
|
||||
secp256k1_rangeproof_recover_k(&stmp, &sec[i], &ev[npub], &s[npub]);
|
||||
} else {
|
||||
stmp = s[npub];
|
||||
}
|
||||
secp256k1_scalar_get_b32(tmp, &stmp);
|
||||
secp256k1_rangeproof_ch32xor(tmp, &prep[npub * 32]);
|
||||
for (b = 0; b < 32 && offset < *mlen; b++) {
|
||||
m[offset] = tmp[b];
|
||||
offset++;
|
||||
}
|
||||
npub++;
|
||||
}
|
||||
}
|
||||
*mlen = offset;
|
||||
memset(prep, 0, 4096);
|
||||
for (i = 0; i < 128; i++) {
|
||||
secp256k1_scalar_clear(&s_orig[i]);
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
secp256k1_scalar_clear(&sec[i]);
|
||||
}
|
||||
secp256k1_scalar_clear(&stmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SECP256K1_INLINE static int secp256k1_rangeproof_getheader_impl(size_t *offset, int *exp, int *mantissa, uint64_t *scale,
|
||||
uint64_t *min_value, uint64_t *max_value, const unsigned char *proof, size_t plen) {
|
||||
int i;
|
||||
int has_nz_range;
|
||||
int has_min;
|
||||
if (plen < 65 || ((proof[*offset] & 128) != 0)) {
|
||||
return 0;
|
||||
}
|
||||
has_nz_range = proof[*offset] & 64;
|
||||
has_min = proof[*offset] & 32;
|
||||
*exp = -1;
|
||||
*mantissa = 0;
|
||||
if (has_nz_range) {
|
||||
*exp = proof[*offset] & 31;
|
||||
*offset += 1;
|
||||
if (*exp > 18) {
|
||||
return 0;
|
||||
}
|
||||
*mantissa = proof[*offset] + 1;
|
||||
if (*mantissa > 64) {
|
||||
return 0;
|
||||
}
|
||||
*max_value = UINT64_MAX>>(64-*mantissa);
|
||||
} else {
|
||||
*max_value = 0;
|
||||
}
|
||||
*offset += 1;
|
||||
*scale = 1;
|
||||
for (i = 0; i < *exp; i++) {
|
||||
if (*max_value > UINT64_MAX / 10) {
|
||||
return 0;
|
||||
}
|
||||
*max_value *= 10;
|
||||
*scale *= 10;
|
||||
}
|
||||
*min_value = 0;
|
||||
if (has_min) {
|
||||
if(plen - *offset < 8) {
|
||||
return 0;
|
||||
}
|
||||
/*FIXME: Compact minvalue encoding?*/
|
||||
for (i = 0; i < 8; i++) {
|
||||
*min_value = (*min_value << 8) | proof[*offset + i];
|
||||
}
|
||||
*offset += 8;
|
||||
}
|
||||
if (*max_value > UINT64_MAX - *min_value) {
|
||||
return 0;
|
||||
}
|
||||
*max_value += *min_value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Verifies range proof (len plen) for commit, the min/max values proven are put in the min/max arguments; returns 0 on failure 1 on success.*/
|
||||
SECP256K1_INLINE static int secp256k1_rangeproof_verify_impl(const secp256k1_ecmult_context* ecmult_ctx,
|
||||
const secp256k1_ecmult_gen_context* ecmult_gen_ctx,
|
||||
unsigned char *blindout, uint64_t *value_out, unsigned char *message_out, size_t *outlen, const unsigned char *nonce,
|
||||
uint64_t *min_value, uint64_t *max_value, const secp256k1_ge *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_ge* genp) {
|
||||
secp256k1_gej accj;
|
||||
secp256k1_gej pubs[128];
|
||||
secp256k1_ge c;
|
||||
secp256k1_scalar s[128];
|
||||
secp256k1_scalar evalues[128]; /* Challenges, only used during proof rewind. */
|
||||
secp256k1_sha256 sha256_m;
|
||||
size_t rsizes[32];
|
||||
int ret;
|
||||
size_t i;
|
||||
int exp;
|
||||
int mantissa;
|
||||
size_t offset;
|
||||
size_t rings;
|
||||
int overflow;
|
||||
size_t npub;
|
||||
int offset_post_header;
|
||||
uint64_t scale;
|
||||
unsigned char signs[31];
|
||||
unsigned char m[33];
|
||||
const unsigned char *e0;
|
||||
offset = 0;
|
||||
if (!secp256k1_rangeproof_getheader_impl(&offset, &exp, &mantissa, &scale, min_value, max_value, proof, plen)) {
|
||||
return 0;
|
||||
}
|
||||
offset_post_header = offset;
|
||||
rings = 1;
|
||||
rsizes[0] = 1;
|
||||
npub = 1;
|
||||
if (mantissa != 0) {
|
||||
rings = (mantissa >> 1);
|
||||
for (i = 0; i < rings; i++) {
|
||||
rsizes[i] = 4;
|
||||
}
|
||||
npub = (mantissa >> 1) << 2;
|
||||
if (mantissa & 1) {
|
||||
rsizes[rings] = 2;
|
||||
npub += rsizes[rings];
|
||||
rings++;
|
||||
}
|
||||
}
|
||||
VERIFY_CHECK(rings <= 32);
|
||||
if (plen - offset < 32 * (npub + rings - 1) + 32 + ((rings+6) >> 3)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_sha256_initialize(&sha256_m);
|
||||
secp256k1_rangeproof_serialize_point(m, commit);
|
||||
secp256k1_sha256_write(&sha256_m, m, 33);
|
||||
secp256k1_rangeproof_serialize_point(m, genp);
|
||||
secp256k1_sha256_write(&sha256_m, m, 33);
|
||||
secp256k1_sha256_write(&sha256_m, proof, offset);
|
||||
for(i = 0; i < rings - 1; i++) {
|
||||
signs[i] = (proof[offset + ( i>> 3)] & (1 << (i & 7))) != 0;
|
||||
}
|
||||
offset += (rings + 6) >> 3;
|
||||
if ((rings - 1) & 7) {
|
||||
/* Number of coded blinded points is not a multiple of 8, force extra sign bits to 0 to reject mutation. */
|
||||
if ((proof[offset - 1] >> ((rings - 1) & 7)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
npub = 0;
|
||||
secp256k1_gej_set_infinity(&accj);
|
||||
if (*min_value) {
|
||||
secp256k1_pedersen_ecmult_small(&accj, *min_value, genp);
|
||||
}
|
||||
for(i = 0; i < rings - 1; i++) {
|
||||
secp256k1_fe 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);
|
||||
}
|
||||
/* Not using secp256k1_rangeproof_serialize_point as we almost have it
|
||||
* serialized form already. */
|
||||
secp256k1_sha256_write(&sha256_m, &signs[i], 1);
|
||||
secp256k1_sha256_write(&sha256_m, &proof[offset], 32);
|
||||
secp256k1_gej_set_ge(&pubs[npub], &c);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, &c, NULL);
|
||||
offset += 32;
|
||||
npub += rsizes[i];
|
||||
}
|
||||
secp256k1_gej_neg(&accj, &accj);
|
||||
secp256k1_gej_add_ge_var(&pubs[npub], &accj, commit, NULL);
|
||||
if (secp256k1_gej_is_infinity(&pubs[npub])) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_rangeproof_pub_expand(pubs, exp, rsizes, rings, genp);
|
||||
npub += rsizes[rings - 1];
|
||||
e0 = &proof[offset];
|
||||
offset += 32;
|
||||
for (i = 0; i < npub; i++) {
|
||||
secp256k1_scalar_set_b32(&s[i], &proof[offset], &overflow);
|
||||
if (overflow) {
|
||||
return 0;
|
||||
}
|
||||
offset += 32;
|
||||
}
|
||||
if (offset != plen) {
|
||||
/*Extra data found, reject.*/
|
||||
return 0;
|
||||
}
|
||||
if (extra_commit != NULL) {
|
||||
secp256k1_sha256_write(&sha256_m, extra_commit, extra_commit_len);
|
||||
}
|
||||
secp256k1_sha256_finalize(&sha256_m, m);
|
||||
ret = secp256k1_borromean_verify(ecmult_ctx, nonce ? evalues : NULL, e0, s, pubs, rsizes, rings, m, 32);
|
||||
if (ret && nonce) {
|
||||
/* Given the nonce, try rewinding the witness to recover its initial state. */
|
||||
secp256k1_scalar blind;
|
||||
uint64_t vv;
|
||||
if (!ecmult_gen_ctx) {
|
||||
return 0;
|
||||
}
|
||||
if (!secp256k1_rangeproof_rewind_inner(&blind, &vv, message_out, outlen, evalues, s, rsizes, rings, nonce, commit, proof, offset_post_header, genp)) {
|
||||
return 0;
|
||||
}
|
||||
/* Unwind apparently successful, see if the commitment can be reconstructed. */
|
||||
/* FIXME: should check vv is in the mantissa's range. */
|
||||
vv = (vv * scale) + *min_value;
|
||||
secp256k1_pedersen_ecmult(ecmult_gen_ctx, &accj, &blind, vv, genp);
|
||||
if (secp256k1_gej_is_infinity(&accj)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_gej_neg(&accj, &accj);
|
||||
secp256k1_gej_add_ge_var(&accj, &accj, commit, NULL);
|
||||
if (!secp256k1_gej_is_infinity(&accj)) {
|
||||
return 0;
|
||||
}
|
||||
if (blindout) {
|
||||
secp256k1_scalar_get_b32(blindout, &blind);
|
||||
}
|
||||
if (value_out) {
|
||||
*value_out = vv;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
709
src/modules/rangeproof/tests_impl.h
Normal file
709
src/modules/rangeproof/tests_impl.h
Normal file
@@ -0,0 +1,709 @@
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2015 Gregory Maxwell *
|
||||
* Distributed under the MIT software license, see the accompanying *
|
||||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef SECP256K1_MODULE_RANGEPROOF_TESTS
|
||||
#define SECP256K1_MODULE_RANGEPROOF_TESTS
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "group.h"
|
||||
#include "scalar.h"
|
||||
#include "testrand.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "include/secp256k1_rangeproof.h"
|
||||
|
||||
static void test_pedersen_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const int32_t *ecount) {
|
||||
secp256k1_pedersen_commitment commit;
|
||||
const secp256k1_pedersen_commitment *commit_ptr = &commit;
|
||||
unsigned char blind[32];
|
||||
unsigned char blind_out[32];
|
||||
const unsigned char *blind_ptr = blind;
|
||||
unsigned char *blind_out_ptr = blind_out;
|
||||
uint64_t val = secp256k1_testrand32();
|
||||
|
||||
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);
|
||||
CHECK(*ecount == 2);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 2);
|
||||
|
||||
CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 3);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 4);
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL) == 0);
|
||||
CHECK(*ecount == 5);
|
||||
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0);
|
||||
CHECK(*ecount == 5);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0);
|
||||
CHECK(*ecount == 6);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0);
|
||||
CHECK(*ecount == 7);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0);
|
||||
CHECK(*ecount == 8);
|
||||
CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0);
|
||||
CHECK(*ecount == 8);
|
||||
|
||||
CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0);
|
||||
CHECK(*ecount == 8);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0);
|
||||
CHECK(*ecount == 9);
|
||||
CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0);
|
||||
CHECK(*ecount == 10);
|
||||
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0);
|
||||
CHECK(*ecount == 10);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0);
|
||||
CHECK(*ecount == 11);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0);
|
||||
CHECK(*ecount == 12);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0);
|
||||
CHECK(*ecount == 13);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0);
|
||||
CHECK(*ecount == 14);
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0);
|
||||
CHECK(*ecount == 15);
|
||||
}
|
||||
|
||||
static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const secp256k1_context *both, const int32_t *ecount) {
|
||||
unsigned char proof[5134];
|
||||
unsigned char blind[32];
|
||||
secp256k1_pedersen_commitment commit;
|
||||
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;";
|
||||
size_t mlen = sizeof(message);
|
||||
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_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);
|
||||
CHECK(*ecount == 1);
|
||||
CHECK(secp256k1_rangeproof_sign(sign, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 2);
|
||||
CHECK(secp256k1_rangeproof_sign(vrfy, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 3);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 3);
|
||||
|
||||
CHECK(secp256k1_rangeproof_sign(both, NULL, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 4);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, NULL, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 5);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, NULL, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 6);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, NULL, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 7);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, NULL, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 8);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, vmin - 1, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 8);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 9);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 9);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 10);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 10);
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, NULL) == 0);
|
||||
CHECK(*ecount == 11);
|
||||
|
||||
CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
{
|
||||
int exp;
|
||||
int mantissa;
|
||||
uint64_t min_value;
|
||||
uint64_t max_value;
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, proof, len) != 0);
|
||||
CHECK(exp == 0);
|
||||
CHECK(((uint64_t) 1 << mantissa) > val - vmin);
|
||||
CHECK(((uint64_t) 1 << (mantissa - 1)) <= val - vmin);
|
||||
CHECK(min_value == vmin);
|
||||
CHECK(max_value >= val);
|
||||
|
||||
CHECK(secp256k1_rangeproof_info(none, NULL, &mantissa, &min_value, &max_value, proof, len) == 0);
|
||||
CHECK(*ecount == 12);
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, NULL, &min_value, &max_value, proof, len) == 0);
|
||||
CHECK(*ecount == 13);
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, NULL, &max_value, proof, len) == 0);
|
||||
CHECK(*ecount == 14);
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, NULL, proof, len) == 0);
|
||||
CHECK(*ecount == 15);
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, NULL, len) == 0);
|
||||
CHECK(*ecount == 16);
|
||||
CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, proof, 0) == 0);
|
||||
CHECK(*ecount == 16);
|
||||
}
|
||||
{
|
||||
uint64_t min_value;
|
||||
uint64_t max_value;
|
||||
CHECK(secp256k1_rangeproof_verify(none, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 17);
|
||||
CHECK(secp256k1_rangeproof_verify(sign, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 18);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 18);
|
||||
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 19);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 20);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 21);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 22);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 22);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 23);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, 0, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 23);
|
||||
CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0);
|
||||
CHECK(*ecount == 24);
|
||||
}
|
||||
{
|
||||
unsigned char blind_out[32];
|
||||
unsigned char message_out[68];
|
||||
uint64_t value_out;
|
||||
uint64_t min_value;
|
||||
uint64_t max_value;
|
||||
size_t message_len = sizeof(message_out);
|
||||
|
||||
CHECK(secp256k1_rangeproof_rewind(none, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 25);
|
||||
CHECK(secp256k1_rangeproof_rewind(sign, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 26);
|
||||
CHECK(secp256k1_rangeproof_rewind(vrfy, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 27);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 27);
|
||||
|
||||
CHECK(min_value == vmin);
|
||||
CHECK(max_value >= val);
|
||||
CHECK(value_out == val);
|
||||
CHECK(message_len == sizeof(message_out));
|
||||
CHECK(memcmp(message, message_out, sizeof(message_out)) == 0);
|
||||
|
||||
CHECK(secp256k1_rangeproof_rewind(both, NULL, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 27); /* blindout may be NULL */
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, NULL, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 27); /* valueout may be NULL */
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 28);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0);
|
||||
CHECK(*ecount == 28);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, NULL, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 29);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 30);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 31);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 32);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 33);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 33);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 34);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, secp256k1_generator_h) == 0);
|
||||
CHECK(*ecount == 34);
|
||||
CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0);
|
||||
CHECK(*ecount == 35);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_api(void) {
|
||||
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
|
||||
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
|
||||
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
|
||||
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
||||
int32_t ecount;
|
||||
int i;
|
||||
|
||||
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);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ecount = 0;
|
||||
test_pedersen_api(none, sign, vrfy, &ecount);
|
||||
ecount = 0;
|
||||
test_rangeproof_api(none, sign, vrfy, both, &ecount);
|
||||
}
|
||||
|
||||
secp256k1_context_destroy(none);
|
||||
secp256k1_context_destroy(sign);
|
||||
secp256k1_context_destroy(vrfy);
|
||||
secp256k1_context_destroy(both);
|
||||
}
|
||||
|
||||
static void test_pedersen(void) {
|
||||
secp256k1_pedersen_commitment commits[19];
|
||||
const secp256k1_pedersen_commitment *cptr[19];
|
||||
unsigned char blinds[32*19];
|
||||
const unsigned char *bptr[19];
|
||||
secp256k1_scalar s;
|
||||
uint64_t values[19];
|
||||
int64_t totalv;
|
||||
int i;
|
||||
int inputs;
|
||||
int outputs;
|
||||
int total;
|
||||
inputs = (secp256k1_testrand32() & 7) + 1;
|
||||
outputs = (secp256k1_testrand32() & 7) + 2;
|
||||
total = inputs + outputs;
|
||||
for (i = 0; i < 19; i++) {
|
||||
cptr[i] = &commits[i];
|
||||
bptr[i] = &blinds[i * 32];
|
||||
}
|
||||
totalv = 0;
|
||||
for (i = 0; i < inputs; i++) {
|
||||
values[i] = secp256k1_testrandi64(0, INT64_MAX - totalv);
|
||||
totalv += values[i];
|
||||
}
|
||||
for (i = 0; i < outputs - 1; i++) {
|
||||
values[i + inputs] = secp256k1_testrandi64(0, totalv);
|
||||
totalv -= values[i + inputs];
|
||||
}
|
||||
values[total - 1] = totalv;
|
||||
|
||||
for (i = 0; i < total - 1; i++) {
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
|
||||
}
|
||||
CHECK(secp256k1_pedersen_blind_sum(ctx, &blinds[(total - 1) * 32], bptr, total - 1, inputs));
|
||||
for (i = 0; i < total; i++) {
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
|
||||
}
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, cptr, inputs, &cptr[inputs], outputs));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[inputs], outputs, cptr, inputs));
|
||||
if (inputs > 0 && values[0] > 0) {
|
||||
CHECK(!secp256k1_pedersen_verify_tally(ctx, cptr, inputs - 1, &cptr[inputs], outputs));
|
||||
}
|
||||
random_scalar_order(&s);
|
||||
for (i = 0; i < 4; i++) {
|
||||
secp256k1_scalar_get_b32(&blinds[i * 32], &s);
|
||||
}
|
||||
values[0] = INT64_MAX;
|
||||
values[1] = 0;
|
||||
values[2] = 1;
|
||||
for (i = 0; i < 3; i++) {
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commits[i], &blinds[i * 32], values[i], secp256k1_generator_h));
|
||||
}
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[0], 1, &cptr[0], 1));
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &cptr[1], 1, &cptr[1], 1));
|
||||
}
|
||||
|
||||
static void test_borromean(void) {
|
||||
unsigned char e0[32];
|
||||
secp256k1_scalar s[64];
|
||||
secp256k1_gej pubs[64];
|
||||
secp256k1_scalar k[8];
|
||||
secp256k1_scalar sec[8];
|
||||
secp256k1_ge ge;
|
||||
secp256k1_scalar one;
|
||||
unsigned char m[32];
|
||||
size_t rsizes[8];
|
||||
size_t secidx[8];
|
||||
size_t nrings;
|
||||
size_t i;
|
||||
size_t j;
|
||||
int c;
|
||||
secp256k1_testrand256_test(m);
|
||||
nrings = 1 + (secp256k1_testrand32()&7);
|
||||
c = 0;
|
||||
secp256k1_scalar_set_int(&one, 1);
|
||||
if (secp256k1_testrand32()&1) {
|
||||
secp256k1_scalar_negate(&one, &one);
|
||||
}
|
||||
for (i = 0; i < nrings; 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_testrand32()&7) {
|
||||
sec[i] = one;
|
||||
}
|
||||
if(secp256k1_testrand32()&7) {
|
||||
k[i] = one;
|
||||
}
|
||||
for (j = 0; j < rsizes[i]; j++) {
|
||||
random_scalar_order(&s[c + j]);
|
||||
if(secp256k1_testrand32()&7) {
|
||||
s[i] = one;
|
||||
}
|
||||
if (j == secidx[i]) {
|
||||
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubs[c + j], &sec[i]);
|
||||
} else {
|
||||
random_group_element_test(&ge);
|
||||
random_group_element_jacobian_test(&pubs[c + j],&ge);
|
||||
}
|
||||
}
|
||||
c += rsizes[i];
|
||||
}
|
||||
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_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_testrand32() % c;
|
||||
if (secp256k1_testrand32() & 1) {
|
||||
secp256k1_gej_double_var(&pubs[i],&pubs[i], NULL);
|
||||
} else {
|
||||
secp256k1_scalar_add(&s[i],&s[i],&one);
|
||||
}
|
||||
CHECK(!secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, e0, s, pubs, rsizes, nrings, m, 32));
|
||||
}
|
||||
}
|
||||
|
||||
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 + 1]; /* One additional byte to test if trailing bytes are rejected */
|
||||
unsigned char blind[32];
|
||||
unsigned char blindout[32];
|
||||
unsigned char message[4096];
|
||||
size_t mlen;
|
||||
uint64_t v;
|
||||
uint64_t vout;
|
||||
uint64_t vmin;
|
||||
uint64_t minv;
|
||||
uint64_t maxv;
|
||||
size_t len;
|
||||
size_t i;
|
||||
size_t j;
|
||||
size_t k;
|
||||
/* Short message is a Simone de Beauvoir quote */
|
||||
const unsigned char message_short[120] = "When I see my own likeness in the depths of someone else's consciousness, I always experience a moment of panic.";
|
||||
/* Long message is 0xA5 with a bunch of this quote in the middle */
|
||||
unsigned char message_long[3968];
|
||||
memset(message_long, 0xa5, sizeof(message_long));
|
||||
for (i = 1200; i < 3600; i += 120) {
|
||||
memcpy(&message_long[i], message_short, sizeof(message_short));
|
||||
}
|
||||
|
||||
secp256k1_testrand256(blind);
|
||||
for (i = 0; i < 11; i++) {
|
||||
v = testvs[i];
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
for (vmin = 0; vmin < (i<9 && i > 0 ? 2 : 1); vmin++) {
|
||||
const unsigned char *input_message = NULL;
|
||||
size_t input_message_len = 0;
|
||||
/* vmin is always either 0 or 1; if it is 1, then we have no room for a message.
|
||||
* If it's 0, we use "minimum encoding" and only have room for a small message when
|
||||
* `testvs[i]` is >= 4; for a large message when it's >= 2^32. */
|
||||
if (vmin == 0 && i > 2) {
|
||||
input_message = message_short;
|
||||
input_message_len = sizeof(message_short);
|
||||
}
|
||||
if (vmin == 0 && i > 7) {
|
||||
input_message = message_long;
|
||||
input_message_len = sizeof(message_long);
|
||||
}
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, 0, 0, v, input_message, input_message_len, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(len <= 5134);
|
||||
mlen = 4096;
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
if (input_message != NULL) {
|
||||
CHECK(memcmp(message, input_message, input_message_len) == 0);
|
||||
}
|
||||
for (j = input_message_len; j < mlen; j++) {
|
||||
CHECK(message[j] == 0);
|
||||
}
|
||||
CHECK(mlen <= 4096);
|
||||
CHECK(memcmp(blindout, blind, 32) == 0);
|
||||
CHECK(vout == v);
|
||||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(len <= 73);
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(memcmp(blindout, blind, 32) == 0);
|
||||
CHECK(vout == v);
|
||||
CHECK(minv == v);
|
||||
CHECK(maxv == v);
|
||||
|
||||
/* Check with a committed message */
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, v, &commit, blind, commit.data, -1, 64, v, NULL, 0, message_short, sizeof(message_short), secp256k1_generator_h));
|
||||
CHECK(len <= 73);
|
||||
CHECK(!secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(!secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_long, sizeof(message_long), secp256k1_generator_h));
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, NULL, NULL, commit.data, &minv, &maxv, &commit, proof, len, message_short, sizeof(message_short), secp256k1_generator_h));
|
||||
CHECK(memcmp(blindout, blind, 32) == 0);
|
||||
CHECK(vout == v);
|
||||
CHECK(minv == v);
|
||||
CHECK(maxv == v);
|
||||
}
|
||||
}
|
||||
secp256k1_testrand256(blind);
|
||||
v = INT64_MAX - 1;
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
for (i = 0; i < 19; i++) {
|
||||
len = 5134;
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, 0, &commit, blind, commit.data, i, 0, v, NULL, 0, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(len <= 5134);
|
||||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
/* 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_testrand256(blind);
|
||||
{
|
||||
/*Malleability test.*/
|
||||
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));
|
||||
proof[i >> 3] ^= 1 << (i & 7);
|
||||
}
|
||||
CHECK(secp256k1_rangeproof_verify(ctx, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(minv <= v);
|
||||
CHECK(maxv >= v);
|
||||
}
|
||||
memcpy(&commit2, &commit, sizeof(commit));
|
||||
for (i = 0; i < (size_t) count; i++) {
|
||||
int exp;
|
||||
int min_bits;
|
||||
v = secp256k1_testrandi64(0, UINT64_MAX >> (secp256k1_testrand32()&63));
|
||||
vmin = 0;
|
||||
if ((v < INT64_MAX) && (secp256k1_testrand32()&1)) {
|
||||
vmin = secp256k1_testrandi64(0, v);
|
||||
}
|
||||
secp256k1_testrand256(blind);
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, v, secp256k1_generator_h));
|
||||
len = 5134;
|
||||
exp = (int)secp256k1_testrandi64(0,18)-(int)secp256k1_testrandi64(0,18);
|
||||
if (exp < 0) {
|
||||
exp = -exp;
|
||||
}
|
||||
min_bits = (int)secp256k1_testrandi64(0,64)-(int)secp256k1_testrandi64(0,64);
|
||||
if (min_bits < 0) {
|
||||
min_bits = -min_bits;
|
||||
}
|
||||
CHECK(secp256k1_rangeproof_sign(ctx, proof, &len, vmin, &commit, blind, commit.data, exp, min_bits, v, NULL, 0, NULL, 0, secp256k1_generator_h));
|
||||
CHECK(len <= 5134);
|
||||
mlen = 4096;
|
||||
CHECK(secp256k1_rangeproof_rewind(ctx, blindout, &vout, message, &mlen, commit.data, &minv, &maxv, &commit, proof, len, NULL, 0, secp256k1_generator_h));
|
||||
for (j = 0; j < mlen; j++) {
|
||||
CHECK(message[j] == 0);
|
||||
}
|
||||
CHECK(mlen <= 4096);
|
||||
CHECK(memcmp(blindout, blind, 32) == 0);
|
||||
|
||||
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 < 3; j++) {
|
||||
for (i = 0; i < 96; i++) {
|
||||
secp256k1_testrand256(&proof[i * 32]);
|
||||
}
|
||||
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_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_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];
|
||||
secp256k1_generator generator[MAX_N_GENS];
|
||||
secp256k1_pedersen_commitment commit[MAX_N_GENS];
|
||||
const secp256k1_pedersen_commitment *commit_ptr[MAX_N_GENS];
|
||||
size_t i;
|
||||
int64_t total_value;
|
||||
uint64_t value[MAX_N_GENS];
|
||||
|
||||
secp256k1_scalar s;
|
||||
|
||||
unsigned char generator_seed[32];
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(generator_seed, &s);
|
||||
/* Create all the needed generators */
|
||||
for (i = 0; i < n_generators; i++) {
|
||||
generator_blind[i] = (unsigned char*) malloc(32);
|
||||
pedersen_blind[i] = (unsigned char*) malloc(32);
|
||||
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(generator_blind[i], &s);
|
||||
random_scalar_order(&s);
|
||||
secp256k1_scalar_get_b32(pedersen_blind[i], &s);
|
||||
|
||||
CHECK(secp256k1_generator_generate_blinded(ctx, &generator[i], generator_seed, generator_blind[i]));
|
||||
|
||||
commit_ptr[i] = &commit[i];
|
||||
}
|
||||
|
||||
/* Compute all the values -- can be positive or negative */
|
||||
total_value = 0;
|
||||
for (i = 0; i < n_outputs; i++) {
|
||||
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_testrandi64(0, total_value);
|
||||
total_value -= value[i];
|
||||
}
|
||||
value[i] = total_value;
|
||||
|
||||
/* Correct for blinding factors and do the commitments */
|
||||
CHECK(secp256k1_pedersen_blind_generator_blind_sum(ctx, value, (const unsigned char * const *) generator_blind, pedersen_blind, n_generators, n_inputs));
|
||||
for (i = 0; i < n_generators; i++) {
|
||||
CHECK(secp256k1_pedersen_commit(ctx, &commit[i], pedersen_blind[i], value[i], &generator[i]));
|
||||
}
|
||||
|
||||
/* Verify */
|
||||
CHECK(secp256k1_pedersen_verify_tally(ctx, &commit_ptr[0], n_inputs, &commit_ptr[n_inputs], n_outputs));
|
||||
|
||||
/* Cleanup */
|
||||
for (i = 0; i < n_generators; i++) {
|
||||
free(generator_blind[i]);
|
||||
free(pedersen_blind[i]);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
test_rangeproof_fixed_vectors();
|
||||
test_pedersen_commitment_fixed_vector();
|
||||
for (i = 0; i < count / 2 + 1; i++) {
|
||||
test_pedersen();
|
||||
}
|
||||
for (i = 0; i < count / 2 + 1; i++) {
|
||||
test_borromean();
|
||||
}
|
||||
test_rangeproof();
|
||||
test_multiple_generators();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -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 */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user