Merge elementsproject/secp256k1-zkp#260: Finish sync to upstream

394e09ee84dbf88a8911db455d42da57254180d3 musig: change test vector generation code shebang from python to python3 (Jonas Nick)
aa3edea1199a7f741ed189d648c483409a7fcd6a scalar: Remove unused secp256k1_scalar_chacha20 (Tim Ruffing)
167194bede0697ed6862cc138028eee7ae509246 rangeproof: Use util functions for writing big endian (Tim Ruffing)
82777bba349b6bda24a4f22a5bdc4e31877cd8a2 bppp: Fix test for invalid sign byte (Tim Ruffing)
54b37db953f9feebae89e43f618c4859cd36acdb build: Fix linkage of extra binaries in -zkp modules (Tim Ruffing)
9e96a2e9d80d66ac2ef1a73c33ac9d1647403248 hsort tests: Don't call secp256k1_testrand_int(0) (Tim Ruffing)
4692478853df2149375d1447908a792fcf240fbf ci: print $ELLSWIFT in cirrus.sh (Jonas Nick)
78ca8807880def68a575b2487f374fdf4b49962d build: enable ellswift module via SECP_CONFIG_DEFINES (Jonas Nick)
b097a466c168dcdb3fde435ec4a1e0b63609f55d util: remove unused checked_realloc (Cory Fields)
4f8c5bd76132a0d0242c7a29b666153f927800bb refactor: Drop unused cast (Hennadii Stepanov)
6ec3731e8c53658fcf68634c81bb1e47cad791ad Simplify test PRNG implementation (Pieter Wuille)
fb5bfa4eed834dcd58109525408a2d88dabc48c5 Add static test vector for Xoshiro256++ (Tim Ruffing)
723e8ca8f7ee75126bac4240feeac825c23a0d44 Remove randomness tests (Pieter Wuille)
c424e2fb43c8ed959b2af7b2216028ce2a023488 ellswift: fix probabilistic test failure when swapping sides (Jonas Nick)
981e5be38c492f0c0230fbe61be555d157380331 ci: Fix typo in comment (Tim Ruffing)
e9e96482196da641733a8a6763341a84f8b9806a ci: Reduce number of macOS tasks from 28 to 8 (Tim Ruffing)
609093b3877b2fb21bd4bb2301a3eafb444a2fdb ci: Add x86_64 Linux tasks for gcc and clang snapshots (Tim Ruffing)
1deecaaf3b94dbf08896e015e7f1e5ec328a40f2 ci: Install development snapshots of gcc and clang (Tim Ruffing)
b79ba8aa4c074b2cd09188f6f85ba68d6b80fe50 field: Use `restrict` consistently in fe_sqrt (Tim Ruffing)
600c5adcd59240305e22918943f45dceeabb7e93 clean up in-comment Sage code (refer to secp256k1_params.sage, update to Python3) (Sebastian Falbesoner)
c7d900ffd18e88076920d4cd13fcdca210acd903 doc: minor ellswift.md updates (stratospher)
2792119278bcb2a0befce3fbc64c83578df54953 Add exhaustive test for ellswift (create+decode roundtrip) (Sebastian Falbesoner)
07c0e8b82e2cea87f85263512945fed7adffea18 group: remove unneeded normalize_weak in `secp256k1_gej_eq_x_var` (Sebastian Falbesoner)
efa76c4bf7cab1c22aa476cd2730e891450ad4a0 group: remove unneeded normalize_weak in `secp256k1_ge_is_valid_var` (Sebastian Falbesoner)
c6cd2b15a007ad0a2d5c4656ae641ba442d8b2fe ci: Add task for static library on Windows + CMake (Hennadii Stepanov)
020bf69a44ba700624d09de0c18ceb867369d24e build: Add extensive docs on visibility issues (Tim Ruffing)
0196e8ade16e2b2d8efadac01d8520205553ee39 build: Introduce `SECP256k1_DLL_EXPORT` macro (Hennadii Stepanov)
9f1b1904a358e4ce7248c6542e8c7ac143ba0e3f refactor: Replace `SECP256K1_API_VAR` with `SECP256K1_API` (Hennadii Stepanov)
ae9db95ceaa2605138fac9c237c640acea3f3bd6 build: Introduce `SECP256K1_STATIC` macro for Windows users (Hennadii Stepanov)
b6b9834e8da7f3fd91b95f750a4ee7a10bf67435 small fixes (Alejandro)
5b9f37f136620b9c61cd66439904b2db266fba70 ci: Add `CFLAGS: -O1` to task matrix (Hennadii Stepanov)
a6ca76cdf2a3d0aef091e3d26d7c6c8ee9c88e72 Avoid `-Wmaybe-uninitialized` when compiling with `gcc -O1` (Hennadii Stepanov)
05873bb6b1041227f413626717b7af69fb6176ef tweak_add: fix API doc for tweak=0 (Jonas Nick)
a7bec34231b991ad0e1f686f6505a81749a2a8c7 ci: Print commit in Windows container (Hennadii Stepanov)
98579e297b19bbb23c924f21942eccdbd618de67 ci: Drop manual checkout of merge commit (Tim Ruffing)
5a95a268b944ffe64b7857e58f5b3b44aba514da tests: introduce helper for non-zero `random_fe_test` results (Sebastian Falbesoner)
304421d57b66670428de656ae6b3272c1ab6fde5 tests: refactor: remove duplicate function `random_field_element_test` (Sebastian Falbesoner)
be8ff3a02aeff87c60d49883a1b2afa8b2999bbe field: Static-assert that int args affecting magnitude are constant (Tim Ruffing)
7d8d5c86df8b27b45e80ed50341dd0ce64546c0f tests: refactor: take use of `secp256k1_ge_x_on_curve_var` (Sebastian Falbesoner)
525b661f83554281707182dc0756f26cca325915 bppp/build: Fix linkage of benchmark (Tim Ruffing)
4c70cc9bf56ab36f20cba5695d4f728a84779f91 Suppress wrong/buggy warning in MSVC <19.33 (Tim Ruffing)
579999b4252083afc8fb59fbec9e027ca7691194 scalar: adjust muladd2 to new int128 interface (Jonas Nick)
b160486766653015e05f94b6c8742d76850e2556 ecdsa_adaptor: add missing include (Jonas Nick)
c862a9fb49e885dcafb42d4e21e05a244248aab0 ci: Adjust Docker image to Debian 12 "bookworm" (Hennadii Stepanov)
a1782098a9f0174aa7b7da431bf77c009dfeef51 ci: Force DWARF v4 for Clang when Valgrind tests are expected (Hennadii Stepanov)
8a7273465b3b17d6dedc67c7aac32a89a0a4dacf Help the compiler prove that a loop is entered (Tim Ruffing)
67887ae65cf11d02c7055709082acd0e5d86db9b Fix a typo in the error message (Hennadii Stepanov)
7c7467ab7f935f6b982064c8c48772a433da1f8f Refer to ellswift.md in API docs (Pieter Wuille)
c32ffd8d8c833a964ee7fbb294640764ad25de5d Add ellswift to CHANGELOG (Pieter Wuille)
bc7c8db179a56cf7273f3c4c0decd10543a10521 abi: Use dllexport for mingw builds (Cory Fields)
5b7bf2e9d4ee02cbec1105ad6e890c34a4da1beb Use `__shiftright128` intrinsic in `secp256k1_u128_rshift` on MSVC (Hennadii Stepanov)
57791374579595bbc5d8d2e55f7fa0bc40d861a4 field: Document return value of fe_sqrt() (Tim Ruffing)
90e360acc2511f313964e394005bafb377b4f191 Add doc/ellswift.md with ElligatorSwift explanation (Pieter Wuille)
4f091847c20c9e9dd3cece2e8b62549278e5028b Add ellswift testing to CI (Pieter Wuille)
1bcea8c57f3f232c8e91d9eb3aad522766d13026 Add benchmarks for ellswift module (Pieter Wuille)
2d1d41acf85a385be6c436307eb826122c21846f Add ctime tests for ellswift module (Pieter Wuille)
df633cdeba133a9468c43f055122b07bf102dd2d Add _prefix and _bip324 ellswift_xdh hash functions (Pieter Wuille)
9695deb351e7742f78dc4ed72dea6655dcf6bb0e Add tests for ellswift module (Pieter Wuille)
c47917bbd62c488fb168431169c1ffe780562da1 Add ellswift module implementing ElligatorSwift (Pieter Wuille)
79e5b2a8b80f507e2c9936ff1c4e2fb39bc66a4e Add functions to test if X coordinate is valid (Pieter Wuille)
a597a5a9cedc27eb6a1190b1959cb9fe0d26a7dc Add benchmark for key generation (Pieter Wuille)
e449af6872445d33a0796224fcb733be6476ad36 Drop no longer needed `#include "../include/secp256k1.h"` (Hennadii Stepanov)
f1652528be5a287a3c33a4fae1e5763693333c2b Normalize ge produced from secp256k1_pubkey_load (stratospher)
7067ee54b4206c26b382980f3c20b5fa0262a23a tests: add tests for `secp256k1_{read,write}_be64` (Sebastian Falbesoner)
740528caad8c37e335cba2bcd02790d94c22e767 scalar: use newly introduced `secp256k1_{read,write}_be64` helpers (4x64 impl.) (Sebastian Falbesoner)
887183e7de4d1941792d78471a3adb004fd4ec8e scalar: use `secp256k1_{read,write}_be32` helpers (4x64 impl.) (Sebastian Falbesoner)
52b84238de27889f2517c845757bf5c2c65ed1d6 scalar: use `secp256k1_{read,write}_be32` helpers (8x32 impl.) (Sebastian Falbesoner)
f3644287b10cd7339fbb0e35e953235351f5efb6 docs: correct `pubkey` param descriptions for `secp256k1_keypair_{xonly_,}pub` (Sebastian Falbesoner)
db29bf220c73bc71b9d48c262ba2e88c1e741f92 ci: Remove quirk that runs dummy command after wineserver (Tim Ruffing)
c7db4942b34acd2a34e6249112f6c1db6cf5681d ci: Fix error D8037 in `cl.exe` (Hennadii Stepanov)
7dae11586135b59bd59fd9889c56aa9b6509021e Revert "ci: Move wine prefix to /tmp to avoid error D8037 in cl.exe" (Hennadii Stepanov)
605e07e3657e4ff8d11893ee680a0446febf73a1 fix input range comment for `secp256k1_fe_add_int` (Sebastian Falbesoner)
ade5b367018a624ff7ca1ecbb4a64889d47b0142 tests: add checks for scalar constants `secp256k1_scalar_{zero,one}` (Sebastian Falbesoner)
654246c63585422a184121a26d42dcae792e87c6 refactor: take use of `secp256k1_scalar_{zero,one}` constants (Sebastian Falbesoner)
e83801f5db2cb63e6343eff0ecfa40b7cd4a9090 test: Warn if both `VERIFY` and `COVERAGE` are defined (Hennadii Stepanov)
1549db0ca5193b8ba5d8f7478d54af2ca4b36c7e build: Level up MSVC warnings (Hennadii Stepanov)
ad846032973cc1afd360613626c4e475bba66f56 release process: clarify change log updates (Jonas Nick)
6348bc7eeed8dbd9cb9bd5df643451a37392bae3 release process: fix process for maintenance release (Jonas Nick)
79fa50b082dd28dd4282d6211d52130db317389b release process: mention targeted release schedule (Jonas Nick)
165206789bc1ff1a95f62d9cd3ed79169b884d67 release process: add sanity checks (Jonas Nick)
27504d5c941df89bc828067248270179c9dcb04b ci: Move wine prefix to /tmp to avoid error D8037 in cl.exe (Tim Ruffing)
6433175ffe2435bcee7333e21480e4194083caae Do not invoke fe_is_zero on failed set_b32_limit (Pieter Wuille)
5768b502291ed4214cf84b7d80ff540ed57d45c4 build: Enable -DVERIFY for precomputation binaries (Tim Ruffing)
31b4bbee1e115865a8a3aff6ccf04f6108371c5d Make fe_cmov take max of magnitudes (Pieter Wuille)
95448ef2f8a162c06b9cd566ce935164b14c6840 release cleanup: bump version after 0.3.2 (Pieter Wuille)
e593ed568572e49b668555e98db1d426952923d5 musig: ensure point_load output is normalized (Jonas Nick)
d490ca2046be118258c6a0617c3461c913d1f208 release: Prepare for 0.3.2 (Tim Ruffing)
697e1ccf4af7672d45d5ce61cd7d07764a1c8b90 changelog: Catch up (Tim Ruffing)
76b43f3443a9f87ff924f3d96fa14ec02576126d changelog: Add entry for #1303 (Tim Ruffing)
3ad1027a4034da674aeee2a92dfba69b347bbe91 Revert "Remove unused scratch space from API" (Jonas Nick)
8c9ae37a5a26cdeb6365624fee43f41b238830e4 Add release note (Pieter Wuille)
350b4bd6e6efd3c62875820fdeb2740738937922 Mark stack variables as early clobber for technical correctness (Pieter Wuille)
0c729ba70d963f2798184b0b8524d7de2f3ced9f Bugfix: mark outputs as early clobber in scalar x86_64 asm (Pieter Wuille)
c6bb29b3037c6b5264f2d2916c5a2d38de25df19 build: Rename `64bit` to `x86_64` (Hennadii Stepanov)
03246457a8f7091e13af13a50d7ae33cf42e08b5 autotools: Add `SECP_ARM32_ASM_CHECK` macro (Hennadii Stepanov)
ed4ba238e2cb2f24301c1add238cf7ff062286c3 cmake: Add `check_arm32_assembly` function (Hennadii Stepanov)
e5cf4bf3ff9aac5b5897a8a9852cfbb84da0bfb1 build: Rename `arm` to `arm32` (Hennadii Stepanov)
5b32602295ff7ad9e1973f96b8ee8344b82f4af0 Split fe_set_b32 into reducing and normalizing variants (Pieter Wuille)
1907f0f1664e3a966daa58be956af18e48834ffd build: Make tests work with external default callbacks (Tim Ruffing)
cd54ac7c1cca509404b62e626a6291f434af88e8 schnorrsig: Improve docs of schnorrsig_sign_custom (Tim Ruffing)
28687b03128fbdd23a3f901297f523dfae2f82e3 schnorrsig: Add BIP340 varlen test vectors (Tim Ruffing)
97a98bed1ed479b1a23d8ae788020d8a6e081cf0 schnorrsig: Refactor test vector code to allow varlen messages (Tim Ruffing)
17fa21733aae97bf671fede3ce528c7a3b2f5f14 ct: Be cautious and use volatile trick in more "conditional" paths (Tim Ruffing)
5fb336f9ce7d287015ada5d1d6be35d63469c9a4 ct: Use volatile trick in scalar_cond_negate (Tim Ruffing)
712e7f8722eba5dec2bc6b37d75aadeb6f6e633b Remove unused scratch space from API (Jonas Nick)
d1e48e5474a2be29e17a477874a4963f8f612a5a refactor: Make 64-bit shift explicit (Hennadii Stepanov)
b2e29e43d0e5e65c1e1199f86f59689a1e736109 ci: Treat all compiler warnings as errors in "Windows (VS 2022)" task (Hennadii Stepanov)
97c63b90390b0b11a5d3530b03855ec9cc0de343 Avoid normalize conditional on VERIFY (Pieter Wuille)
7fc642fa25ad03ebd95cfe237b625dfb6dfdfa94 Simplify secp256k1_fe_{impl_,}verify (Pieter Wuille)
4e176ad5b94f989d5e2c6cdf9b2761a6f6a971e5 Abstract out verify logic for fe_is_square_var (Pieter Wuille)
4371f98346b0a50c0a77e93948fe5e21d9346d06 Abstract out verify logic for fe_add_int (Pieter Wuille)
89e324c6b9d1c74d3636b4ef5b1e5404e3e2053b Abstract out verify logic for fe_half (Pieter Wuille)
283cd80ab471bccb995925eb55865f04e38566f4 Abstract out verify logic for fe_get_bounds (Pieter Wuille)
d5aa2f035802047c45605bfa69fb467000e9288f Abstract out verify logic for fe_inv{,_var} (Pieter Wuille)
316764607257084e714898e07234fdc53150b57a Abstract out verify logic for fe_from_storage (Pieter Wuille)
76d31e5047c1d8dfb83b277421f11460f5126a03 Abstract out verify logic for fe_to_storage (Pieter Wuille)
1e6894bdd74c0b94224f2891c9f5501ac7a3b87a Abstract out verify logic for fe_cmov (Pieter Wuille)
be82bd8e0347e090037ff1d30a22a9d614db8c9f Improve comments/checks for fe_sqrt (Pieter Wuille)
6ab35082efe904cbb7ca5225134a1d3647e35388 Abstract out verify logic for fe_sqr (Pieter Wuille)
4c25f6efbd5f8b4738c1c16daf73906d45c5f579 Abstract out verify logic for fe_mul (Pieter Wuille)
e179e651cbb20031905e01f37596e20ec2cb788a Abstract out verify logic for fe_add (Pieter Wuille)
7e7ad7ff570645304459242104406d6e1f79857c Abstract out verify logic for fe_mul_int (Pieter Wuille)
65d82a3445265767375383a5b68b5f61aeadefca Abstract out verify logic for fe_negate (Pieter Wuille)
144670893eccd84d638951f6c5bae43fc97e3c7b Abstract out verify logic for fe_get_b32 (Pieter Wuille)
f7a7666aeb8db92b9171f4765f7d405b7b73d946 Abstract out verify logic for fe_set_b32 (Pieter Wuille)
ce4d2093e86fedca676dbbe59b50bdcf8c599704 Abstract out verify logic for fe_cmp_var (Pieter Wuille)
7d7d43c6dd2741853de4631881d77ae38a14cd23 Improve comments/check for fe_equal{,_var} (Pieter Wuille)
c5e788d672d78315e7269fd3743eadae6428468e Abstract out verify logic for fe_is_odd (Pieter Wuille)
d3f3fe8616d02bd1c62376c1318be69c64eea982 Abstract out verify logic for fe_is_zero (Pieter Wuille)
c701d9a4719adff20fa83511f946e4abbd4d8cda Abstract out verify logic for fe_clear (Pieter Wuille)
19a2bfeeeac4274bbeca7f8757a2ee73bdf03895 Abstract out verify logic for fe_set_int (Pieter Wuille)
864f9db491b4e1204fda5168174b235f9eefb56e Abstract out verify logic for fe_normalizes_to_zero{,_var} (Pieter Wuille)
6c31371120bb85a397bf1caa73fd1c9b8405d35e Abstract out verify logic for fe_normalize_var (Pieter Wuille)
e28b51f52254b93805350354567a944ca4d79ae2 Abstract out verify logic for fe_normalize_weak (Pieter Wuille)
b6b6f9cb97f6c9313871c278ec73f209ef537a44 Abstract out verify logic for fe_normalize (Pieter Wuille)
7fa51955592ccf4fb424a7a538372ad159e77293 Bugfix: correct SECP256K1_FE_CONST mag/norm fields (Pieter Wuille)
b29566c51b2a47139d610bf686e09ae9f9d24001 Merge magnitude/normalized fields, move/improve comments (Pieter Wuille)
bbc834467c5d14e3e53744211e7c4fa9d8fabe41 Avoid secp256k1_ge_set_gej_zinv with uninitialized z (Pieter Wuille)
0a2e0b2ae456c7ae60e92ddc354071f21fb6aa62 Make secp256k1_{fe,ge,gej}_verify work as no-op if non-VERIFY (Pieter Wuille)
f20266722ac93ca66d1beb0d2f2d2469b95aafea Add invariant checking to group elements (Pieter Wuille)
a18821d5b1d44db0e7c8335f338cc9876bec98cb Always initialize output coordinates in secp256k1_ge_set_gej (Pieter Wuille)
3086cb90acd9d61c5b38e862877fdeacaff74a50 Expose secp256k1_fe_verify to other modules (Pieter Wuille)
a0e696fd4da3788758bb3fdae66c7ae262dbf224 Make secp256k1_ecmult_const handle infinity (Gregory Maxwell)
2e65f1fdbcc87e2ef8c0baf4abc8ee0f56daf7fe Avoid using bench_verify_data as bench_sign_data; merge them (Pieter Wuille)
149c41cee1159fae3928e03be2662b58e9a8e716 docs: complete interface description for `secp256k1_schnorrsig_sign_custom` (Sebastian Falbesoner)
bef448f9af248dba016883401de07b431f3e686e cmake: Fix library ABI versioning (Hennadii Stepanov)
755629bc032af155ff68fa820244d04cb80547c5 cmake: Use full signature of `add_test()` command (Hennadii Stepanov)
7e977b3c5071fc17575ff88ebbc9db7b17c70497 autotools: Take VPATH builds into account when generating testvectors (Tim Ruffing)
2418d3260ac51ba0f148fb20e19c8f41bba8a135 autotools: Create src/wycheproof dir before creating file in it (Tim Ruffing)
8764034ed55bffc8a26fbe377ac505359f8828e9 autotools: Make all "pregenerated" targets .PHONY (Tim Ruffing)
e1b9ce881159e8e2572467f1426f200e987a4d44 autotools: Use same conventions for all pregenerated files (Tim Ruffing)
08f4b1632d0ad976fe00ee606f3a95894555a2e1 autotools: Move code around to tidy Makefile (Tim Ruffing)
529b54d9224e680197e6052b505d2a66398e0d36 autotools: Move Wycheproof header from EXTRA_DIST to noinst_HEADERS (Tim Ruffing)
71f746c057a66d5ae0dfdb5d439bc49592c0d16e cmake: Include `include` directory for subtree builds (Hennadii Stepanov)
5431b9decdbbdf30c5c5f2aed4b59662f5c681a2 cmake: Make `SECP256K1_INSTALL` default depend on `PROJECT_IS_TOP_LEVEL` (Hennadii Stepanov)
162608cc982538906e775d0c549aff2de5dee413 cmake: Emulate `PROJECT_IS_TOP_LEVEL` for CMake<3.21 (Hennadii Stepanov)
a8d059f76cb3429381adda1193c3d1976ba3cab4 cmake, doc: Document compiler flags (Hennadii Stepanov)
6ece1507cb11a897a98052f34a374ec00e83cb86 cmake, refactor: Rename `try_add_compile_option` to `try_append_cflags` (Hennadii Stepanov)
19516ed3e9efe43b00d75820fb6590dcbed548b3 cmake: Use `add_compile_options()` in `try_add_compile_option()` (Hennadii Stepanov)
a273d74b2ea1ef115a7e40fe89a64a6c744018c6 cmake: Improve version comparison (Hennadii Stepanov)
6a58b483efb96de32134611963c16f6bf7e94d51 cmake: Use `if(... IN_LIST ...)` command (Hennadii Stepanov)
2445808c0203215e7182355762944ab909d423d2 cmake: Use dedicated `GENERATOR_IS_MULTI_CONFIG` property (Hennadii Stepanov)
9f8703ef17db0144b320714cd56c1fe0317a5786 cmake: Use dedicated `CMAKE_HOST_APPLE` variable (Hennadii Stepanov)
8c2017035a9c0722aeb7f24162d57d795443fd4c cmake: Use recommended `add_compile_definitions` command (Hennadii Stepanov)
04d4cc071a7aa92ad5edcf970a6cc2a8f415d36c cmake: Add `DESCRIPTION` and `HOMEPAGE_URL` options to `project` command (Hennadii Stepanov)
8a8b6536ef52fbbd9690f859d2f02d7f4b3789f6 cmake: Use `SameMinorVersion` compatibility mode (Hennadii Stepanov)
ce5ba9e24dfcceb49ed7f83a87548fd8b3b0cab2 gitignore: Add CMakeUserPresets.json (Tim Ruffing)
0a446a312fdd6260320eeed51697ecadf61ee11f cmake: Add dev-mode CMake preset (Tim Ruffing)
dc0657c7622f5a13afc3876eca7e2fc7cabb9a10 build: Fix C4005 "macro redefinition" MSVC warnings in examples (Hennadii Stepanov)
c4062d6b5d83572c1932f32003a7c0e901fffc23 debug: move helper for printing buffers into util.h (Jonas Nick)
3858bad2c6493aa66cbfa62540d89da9c5a16040 tests: remove extra semicolon in macro (Jonas Nick)
162da73e9a48875aab1ee6ca1c14f86ca4646946 tests: Add debug helper for printing buffers (Tim Ruffing)
e9fd3dff76e30fcd83d060ad9195cadae9cdc9a2 field: Improve docs and tests of secp256k1_fe_set_b32 (Tim Ruffing)
ca92a35d019730aec9d3ec8097dcbb9633a69874 field: Simplify code in secp256k1_fe_set_b32 (Tim Ruffing)
d93f62e3693d6763891edcad11472f9d475177e5 field: Verify field element even after secp256k1_fe_set_b32 fails (Tim Ruffing)
69e1ec033120497b83dd95d92166fa05c54b8a06 Get rid of secp256k1_fe_const_b (Pieter Wuille)
68b16a1662af2db801a87d6f1afedca93ec2501c bench: Make sys/time.h a system include (Tim Ruffing)
8e142ca4102ade1b90dcb06d6c78405ef3220599 Move `SECP256K1_INLINE` macro definition out from `include/secp256k1.h` (Hennadii Stepanov)
77445898a5852ecd38ab95cfb329333a82673115 Remove `SECP256K1_INLINE` usage from examples (Hennadii Stepanov)
47ac3d63cd5e00a2d50cb489461c8bc349d37912 cmake: Make installation optional (Anna “CyberTailor”)
1ecb94ebe9800900c7dd3a4f9883c600e25eecf7 build: Make `SECP_VALGRIND_CHECK` preserve `CPPFLAGS` (Hennadii Stepanov)
35ada3b954ccc6c54628fb3bcc0365d176297019 tests: lint wycheproof's python script (RandomLattice)
ef49a11d29601e09e94134975c968e92c0214102 build: allow static or shared but not both (Cory Fields)
36b0adf1b90139a41fdcb94390d0bb06e9224795 build: remove warning until it's reproducible (Cory Fields)
a575339c0282ba49a4f46c9c660a4cc3b6bfc703 Remove bits argument from secp256k1_wnaf_const (always 256) (Pieter Wuille)
1b6fb5593c3b0dad8f8ad17ddd29ca30ebd00af3 doc: clarify process for patch releases (Jonas Nick)
06c67dea9f6d46d3e24e810900fbb03045eae641 autotools: Don't regenerate Wycheproof header automatically (Tim Ruffing)
656c6ea8d8ec5b4f1fa91bc7f0a0ecd10c5cf5a0 release cleanup: bump version after 0.3.1 (Jonas Nick)
6a37b2a5ea9075c5dff14b3067c61114a334a2ba changelog: Fix link (Tim Ruffing)
898e1c676e177af73b2c7b540cc93e72a2790fa2 release: Prepare for 0.3.1 (Tim Ruffing)
1d9a13fc2640b9bf870cba65dc69c504c1c9468d changelog: Remove inconsistent newlines (Tim Ruffing)
0e091669a13190289ed9dcc2ea9b8c330412cbc7 changelog: Catch up in preparation of 0.3.1 (Tim Ruffing)
e5de45460953c8ae16521b1928ac14de218998a3 tests: Add Wycheproof ECDSA vectors (RandomLattice)
0f8642079b0f2e4874393792f5854e3c33742cbd Add exhaustive tests for ecmult_const_xonly (Pieter Wuille)
4485926ace489d87929be5218ae1ff3aa8591006 Add x-only ecmult_const version for x=n/d (Pieter Wuille)
3d1f430f9f32d45885b0a10b448c0f15386c423d Make position of * in pointer declarations in include/ consistent (Jonas Nick)
0c07c828340b66d563499a4795844c8325e089e9 Add CMake instructions to release process (Tim Ruffing)
4a496a36fb07d6cc8c99e591994f4ce0c3b1174c ct: Use volatile "trick" in all fe/scalar cmov implementations (Tim Ruffing)
3addb4c1e8a50df7dcf4465a7f149f78bf5af78b build: Improve `SECP_TRY_APPEND_DEFAULT_CFLAGS` macro (Hennadii Stepanov)
5bb03c29116409ace8855e64bf2e2b2d45871469 Replace `SECP256K1_ECMULT_TABLE_VERIFY` macro by a function (Hennadii Stepanov)
4429a8c218d7bf7bc6de1de88bc31c834f771385 Suppress `-Wunused-parameter` when building for coverage analysis (Hennadii Stepanov)
3e43041be68c1288ad9897525a15e21945fb3eb9 No need to subtract 1 before doing a right shift (roconnor-blockstream)
fd2a408647ba0f999b7b217977cc68773fa35257 Set ARM ASM symbol visibility to `hidden` (Hennadii Stepanov)
4ebd82852d3ad00ab579b26173575a4f4642ea76 Apply Checks only in VERIFY mode. (roconnor-blockstream)
d1e7ca192d0aef9c5741c9a8d74ced6366b7a7dc Typo (roconnor-blockstream)
96dd0625112672e841eea723398cc2a1c3489a30 build: bump CMake minimum requirement to 3.13 (Cory Fields)
8e79c7ed11fa50bd6b8a3d3203b2fc330a0c37ea build: Ensure no optimization when building for coverage analysis (Hennadii Stepanov)
647f0a5cb16e71ba1d7bc7aa583d6ca61f8abd78 Update comment for secp256k1_modinv32_inv256 (roconnor-blockstream)
28e63f7ea75af50af0bfde34309993f276bbc0ae release cleanup: bump version after 0.3.0 (Jonas Nick)
b40adf23604d4461f6a5a4af984f4d0c2f337933 release: prepare for 0.3.0 (Jonas Nick)
8be82d43628138553bc126a76d52edf523031792 cmake: Rename project to "libsecp256k1" (Hennadii Stepanov)
756b61d451d2e00c357a6b55863717519164cdb2 readme: Use correct build type in CMake/Windows build instructions (Tim Ruffing)
92098d84cf744cbe3e9cf641af6512ab25aa1e5e changelog: Add entry for CMake (Tim Ruffing)
e1eb33724c2ca47855a8c1dada421cabdb717fe7 ci: Add "x86_64: Windows (VS 2022)" task (Hennadii Stepanov)
10602b0030e67c830596e08ffc775039ee0b2607 cmake: Export config files (Hennadii Stepanov)
5468d709644823b6302141ff93d0b946b70def4a build: Add CMake-based build system (Hennadii Stepanov)
5d8f53e31293c582fb3fe02157bc67d2eeccea77 Remove redudent checks. (Russell O'Connor)
d232112fa7e17fbbed7927bf02e8b1a0c54aeb53 Update Changelog (Tim Ruffing)
b081f7e4cbfd27edc36e823dcd93537a46f7d2a6 Add secp256k1_fe_add_int function (Pieter Wuille)
2ef1c9b38700b7cca2ee1aace2f020ee834729c0 Update overflow check (Russell O'Connor)
5660c137552c657da5265691dea0fb10faae6a76 prevent optimization in algorithms (Harshil Jani)
ce3cfc78a6020d21be299e1e4f22cf8ef089194d doc: Describe Jacobi calculation in safegcd_implementation.md (Elliott Jin)
6be01036c8a6da5043953d055ffb5920728fbff7 Add secp256k1_fe_is_square_var function (Pieter Wuille)
1de2a01c2b22dc8216393ad0471382beaffef525 Native jacobi symbol algorithm (Pieter Wuille)
04c6c1b18162e3dc00d9be5098ee1ccbcb2e78d9 Make secp256k1_modinv64_det_check_pow2 support abs val (Pieter Wuille)
5fffb2c7af5d33223d819283f1a561889a8210d9 Make secp256k1_i128_check_pow2 support -(2^n) (Pieter Wuille)
e4330341bd648e93b60fe70c631e311a98bce549 ci: Shutdown wineserver whenever CI script exits (Tim Ruffing)
9a5a611a21fcdf7bf2dab30964cd0208d8cdf444 build: Suppress stupid MSVC linker warning (Tim Ruffing)
739c53b19a22bd8cd251e25ea286089664a2f0eb examples: Extend sig examples by call that uses static context (Tim Ruffing)
914276e4d27a5f21407744d8016b6d0789e676b1 build: Add SECP256K1_API_VAR to fix importing variables from DLLs (Tim Ruffing)
e089eecc1e54551287b12539d2211da631a6ec5c group: Further simply gej_add_ge (Tim Ruffing)
ac71020ebe052901000e5efa7a59aad77ecfc1a0 group: Save a normalize_to_zero in gej_add_ge (Tim Ruffing)
8c7e0fc1de048be98a1f1bc75557671afc14beaa build: Add -Wreserved-identifier supported by clang (Tim Ruffing)
9b60e3148d8c19562c8c3805bd0cdc55933e912c ci: Do not set git's `user.{email,name}` config options (Hennadii Stepanov)
ef39721cccec344983f09180bcf9c443d491f7cb Do not link `bench` and `ctime_tests` to `COMMON_LIB` (Hennadii Stepanov)
c2415866c7a6769cb29e3db6c5312c1255b37083 ci: Don't fetch git history (Tim Ruffing)
0ecf3188515e46b4da5580b4b9805d2cb927eb91 ci: Use remote pull/merge ref instead of local git merge (Tim Ruffing)
9b7d18669dc2410bde7690d9b04d90b3dc3e25ce Drop no longer used Autoheader macros (Hennadii Stepanov)
eb6bebaee3947f8bca46816fa6bf6182085f1b56 scalar: restrict split_lambda args, improve doc and VERIFY_CHECKs (Jonas Nick)
7f49aa7f2dca595ac8b58d0268dc46a9dfff1e38 ci: add test job with -DVERIFY (Jonas Nick)
620ba3d74bed3095cec7cd8877c8ce14cbf5e329 benchmarks: fix bench_scalar_split (Jonas Nick)
e39d954f118a29db2c33e9a9a507053fff5573ed tests: Add CHECK_ILLEGAL(_VOID) macros and use in static ctx tests (Tim Ruffing)
61841fc9ee5aa1ffde3ccd512660207034125ebd contexts: Forbid randomizing secp256k1_context_static (Tim Ruffing)
4b6df5e33e197a50fd7d9bc4c14b8ba8526013b9 contexts: Forbid cloning/destroying secp256k1_context_static (Tim Ruffing)
8f51229e0348a1524fed541f334cd4f1726d2685 ctime_tests: improve output when CHECKMEM_RUNNING is not defined (Jonas Nick)
2cd4e3c0a976c78c1619fc7456fcc4eaa92897a9 Drop no longer used `SECP_{LIBS,INCLUDE}` variables (Hennadii Stepanov)
613626f94c77a484f6acf22a72ab6cd8ddda00cd Drop no longer used `SECP_TEST_{LIBS,INCLUDE}` variables (Hennadii Stepanov)
d6ff738d5bbdf965590fc07efca23b13c0ea3082 Ensure safety of ctz_debruijn implementation. (Russell O'Connor)
ce60785b2654e60b43577dd75996b7020afbfec8 Introduce SECP256K1_B macro for curve b coefficient (Pieter Wuille)
4934aa79958b506a6e9cfcfe30a8f685db3f5f5f Switch to exhaustive groups with small B coefficient (Pieter Wuille)
e03ef8655933d3e2b4830e7f8fe86deba820a073 Make all non-API functions (except main) static (Pieter Wuille)
0f088ec11263261497661215c110a4c395acc0ac Rename CTIMETEST -> CTIMETESTS (Pieter Wuille)
74b026f05d52216fa4c83cbfada416a30ddfc9b9 Add runtime checking for DECLASSIFY flag (Pieter Wuille)
5e2e6fcfc0ebcdaad96fda9db9b8946d8bcdc8e5 Run ctime test in Linux MSan CI job (Pieter Wuille)
18974061a3ffef514cc393768401b2f104fe6cef Make ctime tests building configurable (Pieter Wuille)
5048be17e93a21ab2e33b939b40339ed4861a692 Rename valgrind_ctime_test -> ctime_tests (Pieter Wuille)
6eed6c18ded7bd89d82fe1ebb13b488a2cf5e567 Update error messages to suggest msan as well (Pieter Wuille)
8e11f89a685063221fa4c2df0ee750d997aee386 Add support for msan integration to checkmem.h (Pieter Wuille)
8dc64079eb1db5abafbc18e335bcf179ae851ae8 Add compile-time error to valgrind_ctime_test (Pieter Wuille)
0db05a770ebd41999b88358ee6ab4bdd6a7d57ee Abstract interactions with valgrind behind new checkmem.h (Pieter Wuille)
4f1a54e41d84a81e4506668bfabed1f3c632973b Move valgrind CPPFLAGS into SECP_CONFIG_DEFINES (Pieter Wuille)
d4a6b58df7490ff9c656e158f246cf396b4cfa72 Add `noverify_tests` to `.gitignore` (Hennadii Stepanov)
e862c4af0c5a7300129700d38eff499a836a108d Makefile: add -I$(top_srcdir)/src to CPPFLAGS for precomputed (Matt Whitlock)
9a93f48f502da7aaa893b90a575434892b23fc9e refactor: Rename STTC to STATIC_CTX in tests (Tim Ruffing)
3385a2648d7e9dd03094bb65065f30f385101fef refactor: Rename global variables to uppercase in tests (Tim Ruffing)
203760023c60d250cb5937e27bcf29e7a829096c tests: Add noverify_tests which is like tests but without VERIFY (Tim Ruffing)
39e8f0e3d7ba7924e9cc5f9e0c56747e942f1eab refactor: Separate run_context_tests into static vs proper contexts (Tim Ruffing)
a4a09379b1a6f65d5a1801cffae0992b49660d82 tests: Clean up and improve run_context_tests() further (Tim Ruffing)
fc90bb569564d552ec0b5706fde6e94bb5313f4e refactor: Tidy up main() (Tim Ruffing)
f32a36f620e979b13040ffd2cd55cfc6fac5bad0 tests: Don't use global context for context tests (Tim Ruffing)
ce4f936c4fa077d0473985479c61bd6544172aae tests: Tidy run_context_tests() by extracting functions (Tim Ruffing)
18e0db30cb4a89989f040a5f212d54b306ffd96e tests: Don't recreate global context in scratch space test (Tim Ruffing)
b19806122e9065c6f434fc6160cd0c57fa3fea8c tests: Use global copy of secp256k1_context_static instead of clone (Tim Ruffing)
2f9ca284e2af0c738e701b3dc3e348b87f26a7a2 Drop `SECP_CONFIG_DEFINES` from examples (Hennadii Stepanov)
c0a555b2ae35d5cca0481ecdd4cff5a1ae314283 Bugfix: pass SECP_CONFIG_DEFINES to bench compilation (Pieter Wuille)
d21647520532957a78027be1ab606b814a2ec720 test secp256k1_i128_to_i64 (Russell O'Connor)
4bc429019dc4bff6af0f9824ad6ab6745f09f8ba Add a secp256k1_i128_to_u64 function. (Russell O'Connor)
a49e0940ad671f96533d5a79f2ca1fa4020abc0a docs: Fix typo (Tim Ruffing)
2551cdac903937c112357d4eb43bc194072a6cc2 tests: Fix code formatting (Tim Ruffing)
c635c1bfd54417487745bbbf518114a962a47bcc Change ARG_CHECK_NO_RETURN to ARG_CHECK_VOID which returns (void) (Tim Ruffing)
cf66f2357c6ad8c5fe219577ad56e6f51301ca5a refactor: Add helper function secp256k1_context_is_proper() (Tim Ruffing)
c30b889f17e0e75b63cdfa2fe021b0d0b59c4526 Clarify that the ABI-incompatible versions are earlier (Pieter Wuille)
881fc33d0c1fcaac8a2c37a72a1db431329de636 Consistency in naming of modules (Pieter Wuille)
9ecf8149a199e12bb8d6c804878931e8b2e403b9 Reduce font size in changelog (Pieter Wuille)
2dc133a67ff74e088a75993fe2ed3d5c6c369915 Add more changelog entries (Pieter Wuille)
ac233e181a5cd96cb3918d669b035221baa18062 Add links to diffs to changelog (Pieter Wuille)
cee8223ef6d6b2d60b0b81762f1aeb0fd40613e0 Mention semantic versioning in changelog (Pieter Wuille)
9c5a4d21bbe820173e361211f42d5fee4765944c Do not define unused `HAVE_VALGRIND` macro (Hennadii Stepanov)
ad8647f548cba9c367f837fcdb76de280fa93c19 Drop no longer relevant files from `.gitignore` (Hennadii Stepanov)
b627ba7050b608e869515a8ef622d71bf8c13b54 Remove dependency on `src/libsecp256k1-config.h` (Hennadii Stepanov)
7a74688201318cbbe30b0d1601aae16dc14ee17a ci: add missing CFLAGS & CPPFLAGS variable to print_environment (Jonas Nick)
c2e0fdadebd2f9bf06fd73b9e89dae03133d71f9 ci: set -u in cirrus.sh to treat unset variables as an error (Jonas Nick)
02ebc290f7413164c14792156e522abd4030e2d1 release cleanup: bump version after 0.2.0 (Jonas Nick)
b6b360efafcb3c0ed95d35c5ca7861769a99fa71 doc: improve message of cleanup commit (Jonas Nick)
e025ccdf7473702a76bb13d763dc096548ffefba release: prepare for initial release 0.2.0 (Jonas Nick)
6d1784a2e2c1c5a8d89ffb08a7f76fa15e84fff5 build: add missing files to EXTRA_DIST (Jonas Nick)
13bf1b6b324f2ed1c1fb4c8d17a4febd3556839e changelog: make order of change types match keepachangelog.com (Jonas Nick)
b1f992a552785395d2e60b10862626fd11f66f84 doc: improve release process (Jonas Nick)
ad39e2dc417f85c1577a6a6a9c519f5c60453def build: change package version to 0.1.0-dev (Jonas Nick)
90618e9263ebc2a0d73d487d6d94fd3af96b973c doc: move CHANGELOG from doc/ to root directory (Jonas Nick)
7e5b22684f4f3e53fa94af84286d21a40dd95525 Don't use compute credits for now (Pieter Wuille)
d6dc0f4ae33d3cd25e9731b9d63b4a34600bc535 tests: Switch to NONE contexts in module tests (Jonas Nick)
0c8a5caddd6cfcb67d974adcab8fe3f049a330dd tests: Switch to NONE contexts in tests.c (Jonas Nick)
86540e9e1fd650315e6a7ec5b117c7ad73a97e29 tests: add test for deprecated flags and rm them from run_context (Jonas Nick)
caa0ad631e20dc91a62d1cccabbfccdb7585081d group: add gej_eq_var (Jonas Nick)
37ba744f5b39368e9c301413b18dedab88007c24 tests: Switch to NONE contexts in exhaustive and ctime tests (Jonas Nick)
8d7a9a8edaaeac1cb6b62c23893c153c0756ecdd benchmarks: Switch to NONE contexts (Jonas Nick)
4386a2306c2b8cf9ad3040d8010e4295f6f01490 examples: Switch to NONE contexts (Tim Ruffing)
7289b51d31bf091330f1bcae397fba8b2b2d54ab docs: Use doxygen style if and only if comment is user-facing (Tim Ruffing)
e7d0185c901dfd6986476ba85aa03f5cfa0951f9 docs: Get rid of "initialized for signing" terminology (Tim Ruffing)
06126364ad988771d762923ce71e63e7f5c56951 docs: Tidy and improve docs about contexts and randomization (Tim Ruffing)
e02d6862bddfc4c18116c22deb86c29380a7bfce selftest: Expose in public API (Tim Ruffing)
e383fbfa66d2c7f48c06a4f4810b5e6db945d2c7 selftest: Rename internal function to make name available for API (Tim Ruffing)
d2c6d48de3c7032fc6d96e8efecb5a933f3c009c tests: Use new name of static context (Tim Ruffing)
53796d2b24e813750feae73e85c0a6eee40dc391 contexts: Rename static context (Tim Ruffing)
72fedf8a6cff9e26882fa0bc923da0429b6916af docs: Improve docs for static context (Tim Ruffing)
316ac7625ad1fbfc5b5b317dfbc7bdab534aaa3e contexts: Deprecate all context flags except SECP256K1_CONTEXT_NONE (Tim Ruffing)
1a553ee8be295f20aca3bc24d85732074b888b87 docs: Change signature "validation" to "verification" (Tim Ruffing)
ee7341fbac1d159a198780c94aa8e0a025e28848 docs: Never require a verification context (Tim Ruffing)
092be61c5e54c31a5747253857b595f3f1945688 gitignore: Add *.sage.py files autogenerated by sage (Tim Ruffing)
a8494b02bfe7578ffb76e66924e76c83556a802d Use compute credits for macOS jobs (Pieter Wuille)
c0ae48c9950a908b637bff27791fabbe2833c4a5 Update macOS image for CI (Pieter Wuille)
41e8704b484652cf5bbb2b7ecc27feedc3cf0ae1 build: Enable some modules by default (Tim Ruffing)
99bd3355994a436e25d148c68e097cca11f3c63e Make int128 overflow test use secp256k1_[ui]128_mul (Pieter Wuille)
3afce0af7c00eb4c5ca6d303e36a48c91a800459 Avoid signed overflow in MSVC AMR64 secp256k1_mul128 (Pieter Wuille)
9b5f589d30c3a86df686aadcde63eaa54eeafe71 Heuristically decide whether to use int128_struct (Pieter Wuille)
63ff064d2f7e67bb8ce3431ca5d7f8f056ba6bbd int128: Add test override for testing __(u)mulh on MSVC X64 (Tim Ruffing)
f2b7e88768f86b2fd506be4a8970ba6d1423d0a5 Add int128 randomized tests (Pieter Wuille)
00a42b91b3477f63d6f9b6fe0df02bda8b09cddd Add MSan CI job (Pieter Wuille)
a340d9500a9c45e5c261174f48b3eb18b3b3647d ci: add int128_struct tests (Jonas Nick)
dceaa1f57963d1a88b24974eab4b49baac6d04cd int128: Tidy #includes of int128.h and int128_impl.h (Tim Ruffing)
2914bccbc0913806ee64425a27d38cdc27b288e8 Simulated int128 type. (Russell O'Connor)
6a965b6b98bc08646c87bcfc826181e317079a9e Remove usage of CHECK from non-test file (Tobin C. Harding)
4e54c03153a307af5cc80c7671ac7eef28138326 ci: print env to allow reproducing the job outside of CI (Jonas Nick)
49ae843592650ca02b33c188cf2aff7aa78985d3 ci: mostly prevent "-v/--version: not found" irrelevant error (Jonas Nick)
5c9f1a5c3774192f77c97474431bb70a124c7b0c ci: always cat all logs_snippets (Jonas Nick)
f5039cb66c9f49d1c78fa59c0e83d0d122292697 Cleanup `.gitignore` file (Hennadii Stepanov)
798727ae1edc1b07257f7a884f8e57021063a089 Revert "Add test logs to gitignore" (Hennadii Stepanov)
88b00897e7ee8dc9bed878082b2277f12136c154 readme: Fix line break (Tim Ruffing)
78f5296da400db8e1034750d79d8cf6d2fd9b045 readme: Sell "no runtime dependencies" (Tim Ruffing)
ef48f088ad95862b6c52781f7ca71cf8535a9b91 readme: Add IRC channel (Tim Ruffing)
cabe085bb4371cc61286023ac9f6a8ce3138d7ea configure: Remove pkgconfig macros again (reintroduced by mismerge) (Tim Ruffing)
c27ae451440bdaf68bf8aaa60edb1f4b4614d492 config: Remove basic-config.h (Tim Ruffing)
da6514a04a0761f973bb7591a7b41fb235747a3d config: Introduce DEBUG_CONFIG macro for debug output of config (Tim Ruffing)
d0cf55e13a7f0914759fe4f3afd003ff37868269 config: Set preprocessor defaults for ECMULT_* config values (Tim Ruffing)
17065f48ae261c6949dab74a7c197ac13b52eb1b tests: Randomize the context with probability 15/16 instead of 1/4 (Tim Ruffing)
55f8bc99dce8846e0da99b92e52353c8cf893287 ecmult_gen: Improve comments about projective blinding (Tim Ruffing)
7a869558004b70803717d8169dd8b090e04df4af ecmult_gen: Simplify code (no observable change) (Tim Ruffing)
4cc0b1b669392d38770f74cb3fb5c801c82f67a0 ecmult_gen: Skip RNG when creating blinding if no seed is available (Tim Ruffing)
40a3473a9d44dc409412e94f70ad0f09bd9da3ac build: Fix #include "..." paths to get rid of further -I arguments (Tim Ruffing)
069aba812542642986786f348a08af697b7e53c7 Fix sepc256k1 -> secp256k1 typo in group.h (henopied)
1827c9bf2b7d4bf6a78c2f387bdb3e885a71e292 scratch_destroy: move VERIFY_CHECK after invalid scrach space check (siv2r)
49e2acd927ce9eb806cc10f3a1fd89a9ddd081e2 configure: Improve rationale for WERROR_CFLAGS (Tim Ruffing)
8dc4b03341c85a3be91e559d05771c51e60b0eba ci: Add a C++ job that compiles the public headers without -fpermissive (Tim Ruffing)
51f296a46c0b318b8dd572ef9ac3bb3a4140ae63 ci: Run persistent wineserver to speed up wine (Tim Ruffing)
3fb3269c22c25de3b720ad139dcf4e3cff9eda1a ci: Add 32-bit MinGW64 build (Tim Ruffing)
9efc2e5221560d19dd750e0ba32c03d4ee091227 ci: Add MSVC builds (Tim Ruffing)
2be6ba0fedd0d2d62ba6f346d7ced7abde0d66e4 configure: Convince autotools to work with MSVC's archiver lib.exe (Tim Ruffing)
bd81f4140a4228b1df3a9f631e2d207a197ae614 schnorrsig bench: Suppress a stupid warning in MSVC (Tim Ruffing)
09f3d71c51a9621653d766e2fe7e657534e57bd6 configure: Add a few CFLAGS for MSVC (Tim Ruffing)
3b4f3d0d46dd278fbe4ffa68b1b6e14e3ea3b17f build: Reject C++ compilers in the preprocessor (Tim Ruffing)
1cc09414149d0c0c6a4a500d83efc3bd66f3ebcd configure: Don't abort if the compiler does not define __STDC__ (Tim Ruffing)
cca8cbbac84624fd350efc4086af25a06dcf8090 configure: Output message when checking for valgrind (Tim Ruffing)
1a6be5745fcf9f90e4218b73712b71ea06361792 bench: Make benchmarks compile on MSVC (Tim Ruffing)
6f6cab9989a4d3f4a28e3cdbfacc4e3e1e55c843 abi: Don't export symbols in static Windows libraries (Cory Fields)
7efc9835a977c6400f0f024f19fda47710151dc1 Fix the false positive of `SECP_64BIT_ASM_CHECK` (Sprite)
2f984ffc45eba89faa9e79da3d5d5bd50a6c1c3d Save negations in var-time group addition (Peter Dettman)

Pull request description:

ACKs for top commit:
  jonasnick:
    ACK 395e65e9f15a614fd81ddd2e8bf12bab1f9c0edf

Tree-SHA512: 95feaf60c5fc8c8cafde8796c50b4b9dfcae87ece3be90286278243a629bcfd91fc4ffdc707a6cc5969fbaf9cd8ea490aa34ca724462b77cd542ebcd7f013eb9
This commit is contained in:
Jonas Nick 2023-08-01 14:32:23 +00:00
commit b2ccc8d9fd
No known key found for this signature in database
GPG Key ID: 4861DBF262123605
153 changed files with 18701 additions and 4880 deletions

View File

@ -1,6 +1,9 @@
env:
### cirrus config
CIRRUS_CLONE_DEPTH: 1
### compiler options
HOST:
WRAPPER_CMD:
# Specific warnings can be disabled with -Wno-error=foo.
# -pedantic-errors is not equivalent to -Werror=pedantic and thus not implied by -Werror according to the GCC manual.
WERROR_CFLAGS: -Werror -pedantic-errors
@ -18,6 +21,7 @@ env:
ECDH: no
RECOVERY: no
SCHNORRSIG: no
ELLSWIFT: no
ECDSA_S2C: no
GENERATOR: no
RANGEPROOF: no
@ -29,21 +33,27 @@ env:
SECP256K1_TEST_ITERS:
BENCH: yes
SECP256K1_BENCH_ITERS: 2
CTIMETEST: yes
CTIMETESTS: yes
# Compile and run the tests
EXAMPLES: yes
# https://cirrus-ci.org/pricing/#compute-credits
credits_snippet: &CREDITS
# Don't use any credits for now.
use_compute_credits: false
cat_logs_snippet: &CAT_LOGS
always:
cat_tests_log_script:
- cat tests.log || true
cat_noverify_tests_log_script:
- cat noverify_tests.log || true
cat_exhaustive_tests_log_script:
- cat exhaustive_tests.log || true
cat_valgrind_ctime_test_log_script:
- cat valgrind_ctime_test.log || true
cat_ctime_tests_log_script:
- cat ctime_tests.log || true
cat_bench_log_script:
- cat bench.log || true
on_failure:
cat_config_log_script:
- cat config.log || true
cat_test_env_script:
@ -51,14 +61,6 @@ cat_logs_snippet: &CAT_LOGS
cat_ci_env_script:
- env
merge_base_script_snippet: &MERGE_BASE
merge_base_script:
- if [ "$CIRRUS_PR" = "" ]; then exit 0; fi
- git fetch $CIRRUS_REPO_CLONE_URL $CIRRUS_BASE_BRANCH
- git config --global user.email "ci@ci.ci"
- git config --global user.name "ci"
- git merge FETCH_HEAD # Merge base to detect silent merge conflicts
linux_container_snippet: &LINUX_CONTAINER
container:
dockerfile: ci/linux-debian.Dockerfile
@ -67,22 +69,25 @@ linux_container_snippet: &LINUX_CONTAINER
# Gives us more CPUs for free if they're available.
greedy: true
# More than enough for our scripts.
memory: 1G
memory: 2G
task:
name: "x86_64: Linux (Debian stable)"
<< : *LINUX_CONTAINER
matrix: &ENV_MATRIX
matrix:
- env: {WIDEMUL: int64, RECOVERY: yes}
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
- env: {WIDEMUL: int64, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
- env: {WIDEMUL: int128}
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128_struct}
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
- env: {WIDEMUL: int128, ASM: x86_64}
- env: {WIDEMUL: int128, ASM: x86_64 , ELLSWIFT: yes}
- env: { RECOVERY: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETEST: no, BENCH: no}
- env: {CTIMETESTS: no, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, EXPERIMENTAL: yes, ECDSA_S2C: yes, RANGEPROOF: yes, WHITELIST: yes, GENERATOR: yes, MUSIG: yes, ECDSAADAPTOR: yes, BPPP: yes, CPPFLAGS: -DVERIFY}
- env: {BUILD: distcheck, WITH_VALGRIND: no, CTIMETESTS: no, BENCH: no}
- env: {CPPFLAGS: -DDETERMINISTIC}
- env: {CFLAGS: -O0, CTIMETEST: no}
- env: {CFLAGS: -O0, CTIMETESTS: no}
- env: {CFLAGS: -O1, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: { ECMULTGENPRECISION: 2, ECMULTWINDOW: 2 }
- env: { ECMULTGENPRECISION: 8, ECMULTWINDOW: 4 }
matrix:
@ -90,7 +95,10 @@ task:
CC: gcc
- env:
CC: clang
<< : *MERGE_BASE
- env:
CC: gcc-snapshot
- env:
CC: clang-snapshot
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
@ -116,7 +124,6 @@ task:
CC: i686-linux-gnu-gcc
- env:
CC: clang --target=i686-pc-linux-gnu -isystem /usr/i686-linux-gnu/include
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
@ -132,23 +139,26 @@ task:
HOMEBREW_NO_INSTALL_CLEANUP: 1
# Cirrus gives us a fixed number of 4 virtual CPUs. Not that we even have that many jobs at the moment...
MAKEFLAGS: -j5
matrix:
<< : *ENV_MATRIX
env:
ASM: no
WITH_VALGRIND: no
CTIMETEST: no
CTIMETESTS: no
CC: clang
matrix:
- env:
CC: gcc
- env:
CC: clang
- env: {WIDEMUL: int64, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int64, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, CC: gcc}
- env: {WIDEMUL: int128_struct, ECMULTGENPRECISION: 2, ECMULTWINDOW: 4}
- env: {WIDEMUL: int128, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes}
- env: {WIDEMUL: int128, RECOVERY: yes, SCHNORRSIG: yes}
- env: {WIDEMUL: int128, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, CC: gcc}
- env: {WIDEMUL: int128, RECOVERY: yes, ECDH: yes, SCHNORRSIG: yes, ELLSWIFT: yes, CPPFLAGS: -DVERIFY}
- env: {BUILD: distcheck}
brew_script:
- brew install automake libtool gcc
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
<< : *CREDITS
task:
name: "s390x (big-endian): Linux (Debian stable, QEMU)"
@ -161,6 +171,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
ELLSWIFT: yes
EXPERIMENTAL: yes
ECDSA_S2C: yes
RANGEPROOF: yes
@ -169,8 +180,7 @@ task:
MUSIG: yes
ECDSAADAPTOR: yes
BPPP: yes
CTIMETEST: no
<< : *MERGE_BASE
CTIMETESTS: no
test_script:
# https://sourceware.org/bugzilla/show_bug.cgi?id=27008
- rm /etc/ld.so.cache
@ -188,11 +198,11 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
CTIMETEST: no
ELLSWIFT: yes
CTIMETESTS: no
matrix:
- env: {}
- env: {EXPERIMENTAL: yes, ASM: arm}
<< : *MERGE_BASE
- env: {EXPERIMENTAL: yes, ASM: arm32}
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
@ -208,8 +218,8 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
ELLSWIFT: yes
CTIMETESTS: no
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
@ -225,25 +235,77 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
ELLSWIFT: yes
CTIMETESTS: no
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
<< : *LINUX_CONTAINER
env:
WRAPPER_CMD: wine64-stable
SECP256K1_TEST_ITERS: 16
HOST: x86_64-w64-mingw32
WRAPPER_CMD: wine
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
CTIMETEST: no
<< : *MERGE_BASE
CTIMETESTS: no
matrix:
- name: "x86_64 (mingw32-w64): Windows (Debian stable, Wine)"
env:
HOST: x86_64-w64-mingw32
- name: "i686 (mingw32-w64): Windows (Debian stable, Wine)"
env:
HOST: i686-w64-mingw32
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
<< : *LINUX_CONTAINER
env:
WRAPPER_CMD: wine
WERROR_CFLAGS: -WX
WITH_VALGRIND: no
ECDH: yes
RECOVERY: yes
EXPERIMENTAL: yes
SCHNORRSIG: yes
ELLSWIFT: yes
ECDSA_S2C: yes
GENERATOR: yes
RANGEPROOF: yes
WHITELIST: yes
MUSIG: yes
ECDSAADAPTOR: yes
BPPP: yes
CTIMETESTS: no
# Use a MinGW-w64 host to tell ./configure we're building for Windows.
# This will detect some MinGW-w64 tools but then make will need only
# the MSVC tools CC, AR and NM as specified below.
HOST: x86_64-w64-mingw32
CC: /opt/msvc/bin/x64/cl
AR: /opt/msvc/bin/x64/lib
NM: /opt/msvc/bin/x64/dumpbin -symbols -headers
# Set non-essential options that affect the CLI messages here.
# (They depend on the user's taste, so we don't want to set them automatically in configure.ac.)
CFLAGS: -nologo -diagnostics:caret
LDFLAGS: -Xlinker -Xlinker -Xlinker -nologo
matrix:
- name: "x86_64 (MSVC): Windows (Debian stable, Wine)"
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct)"
env:
WIDEMUL: int128_struct
- name: "x86_64 (MSVC): Windows (Debian stable, Wine, int128_struct with __(u)mulh)"
env:
WIDEMUL: int128_struct
CPPFLAGS: -DSECP256K1_MSVC_MULH_TEST_OVERRIDE
- name: "i686 (MSVC): Windows (Debian stable, Wine)"
env:
HOST: i686-w64-mingw32
CC: /opt/msvc/bin/x86/cl
AR: /opt/msvc/bin/x86/lib
NM: /opt/msvc/bin/x86/dumpbin -symbols -headers
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
@ -256,6 +318,7 @@ task:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
ELLSWIFT: yes
EXPERIMENTAL: yes
ECDSA_S2C: yes
RANGEPROOF: yes
@ -264,7 +327,7 @@ task:
MUSIG: yes
ECDSAADAPTOR: yes
BPPP: yes
CTIMETEST: no
CTIMETESTS: no
matrix:
- name: "Valgrind (memcheck)"
container:
@ -296,31 +359,104 @@ task:
- env:
HOST: i686-linux-gnu
CC: i686-linux-gnu-gcc
<< : *MERGE_BASE
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
# Memory sanitizers
task:
<< : *LINUX_CONTAINER
name: "MSan"
env:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
EXPERIMENTAL: yes
ECDSA_S2C: yes
GENERATOR: yes
RANGEPROOF: yes
WHITELIST: yes
MUSIG: yes
ECDSAADAPTOR: yes
BPPP: yes
CTIMETESTS: yes
CC: clang
SECP256K1_TEST_ITERS: 32
ASM: no
WITH_VALGRIND: no
container:
memory: 2G
matrix:
- env:
CFLAGS: "-fsanitize=memory -g"
- env:
ECMULTGENPRECISION: 2
ECMULTWINDOW: 2
CFLAGS: "-fsanitize=memory -g -O3"
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "C++ -fpermissive"
name: "C++ -fpermissive (entire project)"
<< : *LINUX_CONTAINER
env:
# ./configure correctly errors out when given CC=g++.
# We hack around this by passing CC=g++ only to make.
CC: gcc
MAKEFLAGS: -j4 CC=g++ CFLAGS=-fpermissive\ -g
CC: g++
CFLAGS: -fpermissive -g
CPPFLAGS: -DSECP256K1_CPLUSPLUS_TEST_OVERRIDE
WERROR_CFLAGS:
ECDH: yes
RECOVERY: yes
SCHNORRSIG: yes
<< : *MERGE_BASE
ELLSWIFT: yes
test_script:
- ./ci/cirrus.sh
<< : *CAT_LOGS
task:
name: "C++ (public headers)"
<< : *LINUX_CONTAINER
test_script:
- g++ -Werror include/*.h
- clang -Werror -x c++-header include/*.h
- /opt/msvc/bin/x64/cl.exe -c -WX -TP include/*.h
task:
name: "sage prover"
<< : *LINUX_CONTAINER
test_script:
- cd sage
- sage prove_group_implementations.sage
task:
name: "x86_64: Windows (VS 2022)"
windows_container:
image: cirrusci/windowsservercore:visualstudio2022
cpu: 4
memory: 3840MB
env:
PATH: '%CIRRUS_WORKING_DIR%\build\src\RelWithDebInfo;%PATH%'
x64_NATIVE_TOOLS: '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvars64.bat"'
# Ignore MSBuild warning MSB8029.
# See: https://learn.microsoft.com/en-us/visualstudio/msbuild/errors/msb8029?view=vs-2022
IgnoreWarnIntDirInTempDetected: 'true'
matrix:
- env:
BUILD_SHARED_LIBS: ON
- env:
BUILD_SHARED_LIBS: OFF
git_show_script:
# Print commit to allow reproducing the job outside of CI.
- git show --no-patch
configure_script:
- '%x64_NATIVE_TOOLS%'
- cmake -E env CFLAGS="/WX" cmake -A x64 -B build -DSECP256K1_ENABLE_MODULE_RECOVERY=ON -DSECP256K1_BUILD_EXAMPLES=ON -DBUILD_SHARED_LIBS=%BUILD_SHARED_LIBS%
build_script:
- '%x64_NATIVE_TOOLS%'
- cmake --build build --config RelWithDebInfo -- -property:UseMultiToolTask=true;CL_MPcount=5
check_script:
- '%x64_NATIVE_TOOLS%'
- ctest -C RelWithDebInfo --test-dir build -j 5
- build\src\RelWithDebInfo\bench_ecmult.exe
- build\src\RelWithDebInfo\bench_internal.exe
- build\src\RelWithDebInfo\bench.exe

15
.gitignore vendored
View File

@ -5,12 +5,13 @@ bench_generator
bench_rangeproof
bench_internal
bench_whitelist
noverify_tests
tests
example_musig
exhaustive_tests
precompute_ecmult_gen
precompute_ecmult
valgrind_ctime_test
ctime_tests
ecdh_example
ecdsa_example
schnorr_example
@ -18,9 +19,9 @@ schnorr_example
*.so
*.a
*.csv
!.gitignore
*.log
*.trs
*.sage.py
Makefile
configure
@ -39,8 +40,6 @@ libtool
*.lo
*.o
*~
*.log
*.trs
coverage/
coverage.html
@ -49,8 +48,6 @@ coverage.*.html
*.gcno
*.gcov
src/libsecp256k1-config.h
src/libsecp256k1-config.h.in
build-aux/ar-lib
build-aux/config.guess
build-aux/config.sub
@ -65,8 +62,12 @@ build-aux/m4/ltversion.m4
build-aux/missing
build-aux/compile
build-aux/test-driver
src/stamp-h1
libsecp256k1.pc
contrib/gh-pr-create.sh
musig_example
### CMake
/CMakeUserPresets.json
# Default CMake build directory.
/build

108
CHANGELOG.md Normal file
View File

@ -0,0 +1,108 @@
**This changelog is not the libsecp256k1-zkp's changelog.**
Instead, it is the changelog of the upstream library [libsecp256k1](https://github.com/bitcoin-core/secp256k1).
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
#### Added
- New module `ellswift` implements ElligatorSwift encoding for public keys and x-only Diffie-Hellman key exchange for them.
ElligatorSwift permits representing secp256k1 public keys as 64-byte arrays which cannot be distinguished from uniformly random. See:
- Header file `include/secp256k1_ellswift.h` which defines the new API.
- Document `doc/ellswift.md` which explains the mathematical background of the scheme.
- The [paper](https://eprint.iacr.org/2022/759) on which the scheme is based.
#### Changed
- When consuming libsecp256k1 as a static library on Windows, the user must now define the `SECP256K1_STATIC` macro before including `secp256k1.h`.
## [0.3.2] - 2023-05-13
We strongly recommend updating to 0.3.2 if you use or plan to use GCC >=13 to compile libsecp256k1. When in doubt, check the GCC version using `gcc -v`.
#### Security
- Module `ecdh`: Fix "constant-timeness" issue with GCC 13.1 (and potentially future versions of GCC) that could leave applications using libsecp256k1's ECDH module vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow during ECDH computations when libsecp256k1 is compiled with GCC 13.1.
#### Fixed
- Fixed an old bug that permitted compilers to potentially output bad assembly code on x86_64. In theory, it could lead to a crash or a read of unrelated memory, but this has never been observed on any compilers so far.
#### Changed
- Various improvements and changes to CMake builds. CMake builds remain experimental.
- Made API versioning consistent with GNU Autotools builds.
- Switched to `BUILD_SHARED_LIBS` variable for controlling whether to build a static or a shared library.
- Added `SECP256K1_INSTALL` variable for the controlling whether to install the build artefacts.
- Renamed asm build option `arm` to `arm32`. Use `--with-asm=arm32` instead of `--with-asm=arm` (GNU Autotools), and `-DSECP256K1_ASM=arm32` instead of `-DSECP256K1_ASM=arm` (CMake).
#### ABI Compatibility
The ABI is compatible with versions 0.3.0 and 0.3.1.
## [0.3.1] - 2023-04-10
We strongly recommend updating to 0.3.1 if you use or plan to use Clang >=14 to compile libsecp256k1, e.g., Xcode >=14 on macOS has Clang >=14. When in doubt, check the Clang version using `clang -v`.
#### Security
- Fix "constant-timeness" issue with Clang >=14 that could leave applications using libsecp256k1 vulnerable to a timing side-channel attack. The fix avoids secret-dependent control flow and secret-dependent memory accesses in conditional moves of memory objects when libsecp256k1 is compiled with Clang >=14.
#### Added
- Added tests against [Project Wycheproof's](https://github.com/google/wycheproof/) set of ECDSA test vectors (Bitcoin "low-S" variant), a fixed set of test cases designed to trigger various edge cases.
#### Changed
- Increased minimum required CMake version to 3.13. CMake builds remain experimental.
#### ABI Compatibility
The ABI is compatible with version 0.3.0.
## [0.3.0] - 2023-03-08
#### Added
- Added experimental support for CMake builds. Traditional GNU Autotools builds (`./configure` and `make`) remain fully supported.
- Usage examples: Added a recommended method for securely clearing sensitive data, e.g., secret keys, from memory.
- Tests: Added a new test binary `noverify_tests`. This binary runs the tests without some additional checks present in the ordinary `tests` binary and is thereby closer to production binaries. The `noverify_tests` binary is automatically run as part of the `make check` target.
#### Fixed
- Fixed declarations of API variables for MSVC (`__declspec(dllimport)`). This fixes MSVC builds of programs which link against a libsecp256k1 DLL dynamically and use API variables (and not only API functions). Unfortunately, the MSVC linker now will emit warning `LNK4217` when trying to link against libsecp256k1 statically. Pass `/ignore:4217` to the linker to suppress this warning.
#### Changed
- Forbade cloning or destroying `secp256k1_context_static`. Create a new context instead of cloning the static context. (If this change breaks your code, your code is probably wrong.)
- Forbade randomizing (copies of) `secp256k1_context_static`. Randomizing a copy of `secp256k1_context_static` did not have any effect and did not provide defense-in-depth protection against side-channel attacks. Create a new context if you want to benefit from randomization.
#### Removed
- Removed the configuration header `src/libsecp256k1-config.h`. We recommend passing flags to `./configure` or `cmake` to set configuration options (see `./configure --help` or `cmake -LH`). If you cannot or do not want to use one of the supported build systems, pass configuration flags such as `-DSECP256K1_ENABLE_MODULE_SCHNORRSIG` manually to the compiler (see the file `configure.ac` for supported flags).
#### ABI Compatibility
Due to changes in the API regarding `secp256k1_context_static` described above, the ABI is *not* compatible with previous versions.
## [0.2.0] - 2022-12-12
#### Added
- Added usage examples for common use cases in a new `examples/` directory.
- Added `secp256k1_selftest`, to be used in conjunction with `secp256k1_context_static`.
- Added support for 128-bit wide multiplication on MSVC for x86_64 and arm64, giving roughly a 20% speedup on those platforms.
#### Changed
- Enabled modules `schnorrsig`, `extrakeys` and `ecdh` by default in `./configure`.
- The `secp256k1_nonce_function_rfc6979` nonce function, used by default by `secp256k1_ecdsa_sign`, now reduces the message hash modulo the group order to match the specification. This only affects improper use of ECDSA signing API.
#### Deprecated
- Deprecated context flags `SECP256K1_CONTEXT_VERIFY` and `SECP256K1_CONTEXT_SIGN`. Use `SECP256K1_CONTEXT_NONE` instead.
- Renamed `secp256k1_context_no_precomp` to `secp256k1_context_static`.
- Module `schnorrsig`: renamed `secp256k1_schnorrsig_sign` to `secp256k1_schnorrsig_sign32`.
#### ABI Compatibility
Since this is the first release, we do not compare application binary interfaces.
However, there are earlier unreleased versions of libsecp256k1 that are *not* ABI compatible with this version.
## [0.1.0] - 2013-03-05 to 2021-12-25
This version was in fact never released.
The number was given by the build system since the introduction of autotools in Jan 2014 (ea0fe5a5bf0c04f9cc955b2966b614f5f378c6f6).
Therefore, this version number does not uniquely identify a set of source files.
[unreleased]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.2...HEAD
[0.3.2]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/bitcoin-core/secp256k1/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/bitcoin-core/secp256k1/compare/v0.2.0...v0.3.0
[0.2.0]: https://github.com/bitcoin-core/secp256k1/compare/423b6d19d373f1224fd671a982584d7e7900bc93..v0.2.0
[0.1.0]: https://github.com/bitcoin-core/secp256k1/commit/423b6d19d373f1224fd671a982584d7e7900bc93

341
CMakeLists.txt Normal file
View File

@ -0,0 +1,341 @@
cmake_minimum_required(VERSION 3.13)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15)
# MSVC runtime library flags are selected by the CMAKE_MSVC_RUNTIME_LIBRARY abstraction.
cmake_policy(SET CMP0091 NEW)
# MSVC warning flags are not in CMAKE_<LANG>_FLAGS by default.
cmake_policy(SET CMP0092 NEW)
endif()
project(libsecp256k1
# The package (a.k.a. release) version is based on semantic versioning 2.0.0 of
# the API. All changes in experimental modules are treated as
# backwards-compatible and therefore at most increase the minor version.
VERSION 0.3.3
DESCRIPTION "Optimized C library for ECDSA signatures and secret/public key operations on curve secp256k1."
HOMEPAGE_URL "https://github.com/bitcoin-core/secp256k1"
LANGUAGES C
)
if(CMAKE_VERSION VERSION_LESS 3.21)
get_directory_property(parent_directory PARENT_DIRECTORY)
if(parent_directory)
set(PROJECT_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
set(${PROJECT_NAME}_IS_TOP_LEVEL OFF CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
else()
set(PROJECT_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
set(${PROJECT_NAME}_IS_TOP_LEVEL ON CACHE INTERNAL "Emulates CMake 3.21+ behavior.")
endif()
unset(parent_directory)
endif()
# The library version is based on libtool versioning of the ABI. The set of
# rules for updating the version can be found here:
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# All changes in experimental modules are treated as if they don't affect the
# interface and therefore only increase the revision.
set(${PROJECT_NAME}_LIB_VERSION_CURRENT 2)
set(${PROJECT_NAME}_LIB_VERSION_REVISION 3)
set(${PROJECT_NAME}_LIB_VERSION_AGE 0)
set(CMAKE_C_STANDARD 90)
set(CMAKE_C_EXTENSIONS OFF)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
option(BUILD_SHARED_LIBS "Build shared libraries." ON)
option(SECP256K1_DISABLE_SHARED "Disable shared library. Overrides BUILD_SHARED_LIBS." OFF)
if(SECP256K1_DISABLE_SHARED)
set(BUILD_SHARED_LIBS OFF)
endif()
option(SECP256K1_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL})
option(SECP256K1_ENABLE_MODULE_ECDH "Enable ECDH module." ON)
if(SECP256K1_ENABLE_MODULE_ECDH)
add_compile_definitions(ENABLE_MODULE_ECDH=1)
endif()
option(SECP256K1_ENABLE_MODULE_RECOVERY "Enable ECDSA pubkey recovery module." OFF)
if(SECP256K1_ENABLE_MODULE_RECOVERY)
add_compile_definitions(ENABLE_MODULE_RECOVERY=1)
endif()
option(SECP256K1_ENABLE_MODULE_EXTRAKEYS "Enable extrakeys module." ON)
option(SECP256K1_ENABLE_MODULE_SCHNORRSIG "Enable schnorrsig module." ON)
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
set(SECP256K1_ENABLE_MODULE_EXTRAKEYS ON)
add_compile_definitions(ENABLE_MODULE_SCHNORRSIG=1)
endif()
if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
add_compile_definitions(ENABLE_MODULE_EXTRAKEYS=1)
endif()
option(SECP256K1_ENABLE_MODULE_ELLSWIFT "Enable ElligatorSwift module." ON)
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
add_compile_definitions(ENABLE_MODULE_ELLSWIFT=1)
endif()
option(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS "Enable external default callback functions." OFF)
if(SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS)
add_compile_definitions(USE_EXTERNAL_DEFAULT_CALLBACKS=1)
endif()
set(SECP256K1_ECMULT_WINDOW_SIZE "AUTO" CACHE STRING "Window size for ecmult precomputation for verification, specified as integer in range [2..24]. \"AUTO\" is a reasonable setting for desktop machines (currently 15). [default=AUTO]")
set_property(CACHE SECP256K1_ECMULT_WINDOW_SIZE PROPERTY STRINGS "AUTO" 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24)
include(CheckStringOptionValue)
check_string_option_value(SECP256K1_ECMULT_WINDOW_SIZE)
if(SECP256K1_ECMULT_WINDOW_SIZE STREQUAL "AUTO")
set(SECP256K1_ECMULT_WINDOW_SIZE 15)
endif()
add_compile_definitions(ECMULT_WINDOW_SIZE=${SECP256K1_ECMULT_WINDOW_SIZE})
set(SECP256K1_ECMULT_GEN_PREC_BITS "AUTO" CACHE STRING "Precision bits to tune the precomputed table size for signing, specified as integer 2, 4 or 8. \"AUTO\" is a reasonable setting for desktop machines (currently 4). [default=AUTO]")
set_property(CACHE SECP256K1_ECMULT_GEN_PREC_BITS PROPERTY STRINGS "AUTO" 2 4 8)
check_string_option_value(SECP256K1_ECMULT_GEN_PREC_BITS)
if(SECP256K1_ECMULT_GEN_PREC_BITS STREQUAL "AUTO")
set(SECP256K1_ECMULT_GEN_PREC_BITS 4)
endif()
add_compile_definitions(ECMULT_GEN_PREC_BITS=${SECP256K1_ECMULT_GEN_PREC_BITS})
set(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY "OFF" CACHE STRING "Test-only override of the (autodetected by the C code) \"widemul\" setting. Legal values are: \"OFF\", \"int128_struct\", \"int128\" or \"int64\". [default=OFF]")
set_property(CACHE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY PROPERTY STRINGS "OFF" "int128_struct" "int128" "int64")
check_string_option_value(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
string(TOUPPER "${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}" widemul_upper_value)
add_compile_definitions(USE_FORCE_WIDEMUL_${widemul_upper_value}=1)
endif()
mark_as_advanced(FORCE SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
set(SECP256K1_ASM "AUTO" CACHE STRING "Assembly optimizations to use: \"AUTO\", \"OFF\", \"x86_64\" or \"arm32\" (experimental). [default=AUTO]")
set_property(CACHE SECP256K1_ASM PROPERTY STRINGS "AUTO" "OFF" "x86_64" "arm32")
check_string_option_value(SECP256K1_ASM)
if(SECP256K1_ASM STREQUAL "arm32")
enable_language(ASM)
include(CheckArm32Assembly)
check_arm32_assembly()
if(HAVE_ARM32_ASM)
add_compile_definitions(USE_EXTERNAL_ASM=1)
else()
message(FATAL_ERROR "ARM32 assembly optimization requested but not available.")
endif()
elseif(SECP256K1_ASM)
include(CheckX86_64Assembly)
check_x86_64_assembly()
if(HAVE_X86_64_ASM)
set(SECP256K1_ASM "x86_64")
add_compile_definitions(USE_ASM_X86_64=1)
elseif(SECP256K1_ASM STREQUAL "AUTO")
set(SECP256K1_ASM "OFF")
else()
message(FATAL_ERROR "x86_64 assembly optimization requested but not available.")
endif()
endif()
option(SECP256K1_EXPERIMENTAL "Allow experimental configuration options." OFF)
if(NOT SECP256K1_EXPERIMENTAL)
if(SECP256K1_ASM STREQUAL "arm32")
message(FATAL_ERROR "ARM32 assembly optimization is experimental. Use -DSECP256K1_EXPERIMENTAL=ON to allow.")
endif()
endif()
set(SECP256K1_VALGRIND "AUTO" CACHE STRING "Build with extra checks for running inside Valgrind. [default=AUTO]")
set_property(CACHE SECP256K1_VALGRIND PROPERTY STRINGS "AUTO" "OFF" "ON")
check_string_option_value(SECP256K1_VALGRIND)
if(SECP256K1_VALGRIND)
find_package(Valgrind MODULE)
if(Valgrind_FOUND)
set(SECP256K1_VALGRIND ON)
include_directories(${Valgrind_INCLUDE_DIR})
add_compile_definitions(VALGRIND)
elseif(SECP256K1_VALGRIND STREQUAL "AUTO")
set(SECP256K1_VALGRIND OFF)
else()
message(FATAL_ERROR "Valgrind support requested but valgrind/memcheck.h header not available.")
endif()
endif()
option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON)
option(SECP256K1_BUILD_TESTS "Build tests." ON)
option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON)
option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND})
option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF)
# Redefine configuration flags.
# We leave assertions on, because they are only used in the examples, and we want them always on there.
if(MSVC)
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
else()
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}")
# Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.)
string(REGEX REPLACE "-O3[ \t\r\n]*" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
endif()
# Define custom "Coverage" build type.
set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage" CACHE STRING
"Flags used by the C compiler during \"Coverage\" builds."
FORCE
)
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING
"Flags used for linking binaries during \"Coverage\" builds."
FORCE
)
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING
"Flags used by the shared libraries linker during \"Coverage\" builds."
FORCE
)
mark_as_advanced(
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE
)
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
set(default_build_type "RelWithDebInfo")
if(is_multi_config)
set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING
"Supported configuration types."
FORCE
)
else()
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY
STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage"
)
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "Setting build type to \"${default_build_type}\" as none was specified")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING
"Choose the type of build."
FORCE
)
endif()
endif()
include(TryAppendCFlags)
if(MSVC)
# Keep the following commands ordered lexicographically.
try_append_c_flags(/W3) # Production quality warning level.
try_append_c_flags(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
try_append_c_flags(/wd4244) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
try_append_c_flags(/wd4267) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
# Eliminate deprecation warnings for the older, less secure functions.
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
else()
# Keep the following commands ordered lexicographically.
try_append_c_flags(-pedantic)
try_append_c_flags(-Wall) # GCC >= 2.95 and probably many other compilers.
try_append_c_flags(-Wcast-align) # GCC >= 2.95.
try_append_c_flags(-Wcast-align=strict) # GCC >= 8.0.
try_append_c_flags(-Wconditional-uninitialized) # Clang >= 3.0 only.
try_append_c_flags(-Wextra) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
try_append_c_flags(-Wnested-externs)
try_append_c_flags(-Wno-long-long) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
try_append_c_flags(-Wno-overlength-strings) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
try_append_c_flags(-Wno-unused-function) # GCC >= 3.0, -Wunused-function is implied by -Wall.
try_append_c_flags(-Wreserved-identifier) # Clang >= 13.0 only.
try_append_c_flags(-Wshadow)
try_append_c_flags(-Wstrict-prototypes)
try_append_c_flags(-Wundef)
endif()
set(CMAKE_C_VISIBILITY_PRESET hidden)
# Ask CTest to create a "check" target (e.g., make check) as alias for the "test" target.
# CTEST_TEST_TARGET_ALIAS is not documented but supposed to be user-facing.
# See: https://gitlab.kitware.com/cmake/cmake/-/commit/816c9d1aa1f2b42d40c81a991b68c96eb12b6d2
set(CTEST_TEST_TARGET_ALIAS check)
include(CTest)
# We do not use CTest's BUILD_TESTING because a single toggle for all tests is too coarse for our needs.
mark_as_advanced(BUILD_TESTING)
if(SECP256K1_BUILD_BENCHMARK OR SECP256K1_BUILD_TESTS OR SECP256K1_BUILD_EXHAUSTIVE_TESTS OR SECP256K1_BUILD_CTIME_TESTS OR SECP256K1_BUILD_EXAMPLES)
enable_testing()
endif()
add_subdirectory(src)
if(SECP256K1_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
message("\n")
message("secp256k1 configure summary")
message("===========================")
message("Build artifacts:")
if(BUILD_SHARED_LIBS)
set(library_type "Shared")
else()
set(library_type "Static")
endif()
message(" library type ........................ ${library_type}")
message("Optional modules:")
message(" ECDH ................................ ${SECP256K1_ENABLE_MODULE_ECDH}")
message(" ECDSA pubkey recovery ............... ${SECP256K1_ENABLE_MODULE_RECOVERY}")
message(" extrakeys ........................... ${SECP256K1_ENABLE_MODULE_EXTRAKEYS}")
message(" schnorrsig .......................... ${SECP256K1_ENABLE_MODULE_SCHNORRSIG}")
message(" ElligatorSwift ...................... ${SECP256K1_ENABLE_MODULE_ELLSWIFT}")
message("Parameters:")
message(" ecmult window size .................. ${SECP256K1_ECMULT_WINDOW_SIZE}")
message(" ecmult gen precision bits ........... ${SECP256K1_ECMULT_GEN_PREC_BITS}")
message("Optional features:")
message(" assembly optimization ............... ${SECP256K1_ASM}")
message(" external callbacks .................. ${SECP256K1_USE_EXTERNAL_DEFAULT_CALLBACKS}")
if(SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY)
message(" wide multiplication (test-only) ..... ${SECP256K1_TEST_OVERRIDE_WIDE_MULTIPLY}")
endif()
message("Optional binaries:")
message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}")
message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}")
set(tests_status "${SECP256K1_BUILD_TESTS}")
if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
set(tests_status OFF)
endif()
message(" tests ............................... ${tests_status}")
message(" exhaustive tests .................... ${SECP256K1_BUILD_EXHAUSTIVE_TESTS}")
message(" ctime_tests ......................... ${SECP256K1_BUILD_CTIME_TESTS}")
message(" examples ............................ ${SECP256K1_BUILD_EXAMPLES}")
message("")
if(CMAKE_CROSSCOMPILING)
set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}")
else()
set(cross_status "FALSE")
endif()
message("Cross compiling ....................... ${cross_status}")
message("Valgrind .............................. ${SECP256K1_VALGRIND}")
get_directory_property(definitions COMPILE_DEFINITIONS)
string(REPLACE ";" " " definitions "${definitions}")
message("Preprocessor defined macros ........... ${definitions}")
message("C compiler ............................ ${CMAKE_C_COMPILER}")
message("CFLAGS ................................ ${CMAKE_C_FLAGS}")
get_directory_property(compile_options COMPILE_OPTIONS)
string(REPLACE ";" " " compile_options "${compile_options}")
message("Compile options ....................... " ${compile_options})
if(NOT is_multi_config)
message("Build type:")
message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}")
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type)
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}")
else()
message("Supported configurations .............. ${CMAKE_CONFIGURATION_TYPES}")
message("RelWithDebInfo configuration:")
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}")
message("Debug configuration:")
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}")
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
endif()
message("\n")
if(SECP256K1_EXPERIMENTAL)
message(
" ******\n"
" WARNING: experimental build\n"
" Experimental features do not have stable APIs or properties, and may not be safe for production use.\n"
" ******\n"
)
endif()

19
CMakePresets.json Normal file
View File

@ -0,0 +1,19 @@
{
"cmakeMinimumRequired": {"major": 3, "minor": 21, "patch": 0},
"version": 3,
"configurePresets": [
{
"name": "dev-mode",
"displayName": "Development mode (intended only for developers of the library)",
"cacheVariables": {
"SECP256K1_EXPERIMENTAL": "ON",
"SECP256K1_ENABLE_MODULE_RECOVERY": "ON",
"SECP256K1_BUILD_EXAMPLES": "ON"
},
"warnings": {
"dev": true,
"uninitialized": true
}
}
]
}

View File

@ -1,5 +1,3 @@
.PHONY: clean-precomp precomp
ACLOCAL_AMFLAGS = -I build-aux/m4
# AM_CFLAGS will be automatically prepended to CFLAGS by Automake when compiling some foo
@ -49,7 +47,14 @@ noinst_HEADERS += src/modinv64_impl.h
noinst_HEADERS += src/precomputed_ecmult.h
noinst_HEADERS += src/precomputed_ecmult_gen.h
noinst_HEADERS += src/assumptions.h
noinst_HEADERS += src/checkmem.h
noinst_HEADERS += src/util.h
noinst_HEADERS += src/int128.h
noinst_HEADERS += src/int128_impl.h
noinst_HEADERS += src/int128_native.h
noinst_HEADERS += src/int128_native_impl.h
noinst_HEADERS += src/int128_struct.h
noinst_HEADERS += src/int128_struct_impl.h
noinst_HEADERS += src/scratch.h
noinst_HEADERS += src/scratch_impl.h
noinst_HEADERS += src/selftest.h
@ -60,17 +65,19 @@ noinst_HEADERS += src/hash_impl.h
noinst_HEADERS += src/field.h
noinst_HEADERS += src/field_impl.h
noinst_HEADERS += src/bench.h
noinst_HEADERS += src/basic-config.h
noinst_HEADERS += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
noinst_HEADERS += contrib/lax_der_parsing.h
noinst_HEADERS += contrib/lax_der_parsing.c
noinst_HEADERS += contrib/lax_der_privatekey_parsing.h
noinst_HEADERS += contrib/lax_der_privatekey_parsing.c
noinst_HEADERS += examples/random.h
noinst_HEADERS += examples/examples_util.h
PRECOMPUTED_LIB = libsecp256k1_precomputed.la
noinst_LTLIBRARIES = $(PRECOMPUTED_LIB)
libsecp256k1_precomputed_la_SOURCES = src/precomputed_ecmult.c src/precomputed_ecmult_gen.c
libsecp256k1_precomputed_la_CPPFLAGS = $(SECP_INCLUDES)
# We need `-I$(top_srcdir)/src` in VPATH builds if libsecp256k1_precomputed_la_SOURCES have been recreated in the build tree.
# This helps users and packagers who insist on recreating the precomputed files (e.g., Gentoo).
libsecp256k1_precomputed_la_CPPFLAGS = -I$(top_srcdir)/src $(SECP_CONFIG_DEFINES)
if USE_EXTERNAL_ASM
COMMON_LIB = libsecp256k1_common.la
@ -89,55 +96,58 @@ endif
endif
libsecp256k1_la_SOURCES = src/secp256k1.c
libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES)
libsecp256k1_la_LIBADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
libsecp256k1_la_CPPFLAGS = $(SECP_CONFIG_DEFINES)
libsecp256k1_la_LIBADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
libsecp256k1_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_CURRENT):$(LIB_VERSION_REVISION):$(LIB_VERSION_AGE)
if VALGRIND_ENABLED
libsecp256k1_la_CPPFLAGS += -DVALGRIND
endif
noinst_PROGRAMS =
if USE_BENCHMARK
noinst_PROGRAMS += bench bench_internal bench_ecmult
bench_SOURCES = src/bench.c
bench_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB)
bench_LDADD = libsecp256k1.la
bench_CPPFLAGS = $(SECP_CONFIG_DEFINES)
bench_internal_SOURCES = src/bench_internal.c
bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
bench_internal_CPPFLAGS = $(SECP_INCLUDES)
bench_internal_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
bench_internal_CPPFLAGS = $(SECP_CONFIG_DEFINES)
bench_ecmult_SOURCES = src/bench_ecmult.c
bench_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
bench_ecmult_CPPFLAGS = $(SECP_INCLUDES)
bench_ecmult_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
bench_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES)
endif
TESTS =
if USE_TESTS
noinst_PROGRAMS += tests
tests_SOURCES = src/tests.c
tests_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES)
if VALGRIND_ENABLED
tests_CPPFLAGS += -DVALGRIND
noinst_PROGRAMS += valgrind_ctime_test
valgrind_ctime_test_SOURCES = src/valgrind_ctime_test.c
valgrind_ctime_test_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB)
endif
TESTS += noverify_tests
noinst_PROGRAMS += noverify_tests
noverify_tests_SOURCES = src/tests.c
noverify_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
noverify_tests_LDADD = $(COMMON_LIB) $(PRECOMPUTED_LIB)
noverify_tests_LDFLAGS = -static
if !ENABLE_COVERAGE
tests_CPPFLAGS += -DVERIFY
endif
tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) $(PRECOMPUTED_LIB)
tests_LDFLAGS = -static
TESTS += tests
noinst_PROGRAMS += tests
tests_SOURCES = $(noverify_tests_SOURCES)
tests_CPPFLAGS = $(noverify_tests_CPPFLAGS) -DVERIFY
tests_LDADD = $(noverify_tests_LDADD)
tests_LDFLAGS = $(noverify_tests_LDFLAGS)
endif
endif
if USE_CTIME_TESTS
noinst_PROGRAMS += ctime_tests
ctime_tests_SOURCES = src/ctime_tests.c
ctime_tests_LDADD = libsecp256k1.la
ctime_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
endif
if USE_EXHAUSTIVE_TESTS
noinst_PROGRAMS += exhaustive_tests
exhaustive_tests_SOURCES = src/tests_exhaustive.c
exhaustive_tests_CPPFLAGS = $(SECP_INCLUDES)
exhaustive_tests_CPPFLAGS = $(SECP_CONFIG_DEFINES)
if !ENABLE_COVERAGE
exhaustive_tests_CPPFLAGS += -DVERIFY
endif
# Note: do not include $(PRECOMPUTED_LIB) in exhaustive_tests (it uses runtime-generated tables).
exhaustive_tests_LDADD = $(SECP_LIBS) $(COMMON_LIB)
exhaustive_tests_LDADD = $(COMMON_LIB)
exhaustive_tests_LDFLAGS = -static
TESTS += exhaustive_tests
endif
@ -145,7 +155,7 @@ endif
if USE_EXAMPLES
noinst_PROGRAMS += ecdsa_example
ecdsa_example_SOURCES = examples/ecdsa.c
ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include
ecdsa_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
ecdsa_example_LDADD = libsecp256k1.la
ecdsa_example_LDFLAGS = -static
if BUILD_WINDOWS
@ -155,7 +165,7 @@ TESTS += ecdsa_example
if ENABLE_MODULE_ECDH
noinst_PROGRAMS += ecdh_example
ecdh_example_SOURCES = examples/ecdh.c
ecdh_example_CPPFLAGS = -I$(top_srcdir)/include
ecdh_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
ecdh_example_LDADD = libsecp256k1.la
ecdh_example_LDFLAGS = -static
if BUILD_WINDOWS
@ -166,7 +176,7 @@ endif
if ENABLE_MODULE_SCHNORRSIG
noinst_PROGRAMS += schnorr_example
schnorr_example_SOURCES = examples/schnorr.c
schnorr_example_CPPFLAGS = -I$(top_srcdir)/include
schnorr_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
schnorr_example_LDADD = libsecp256k1.la
schnorr_example_LDFLAGS = -static
if BUILD_WINDOWS
@ -177,7 +187,7 @@ endif
if ENABLE_MODULE_MUSIG
noinst_PROGRAMS += musig_example
musig_example_SOURCES = examples/musig.c
musig_example_CPPFLAGS = -I$(top_srcdir)/include
musig_example_CPPFLAGS = -I$(top_srcdir)/include -DSECP256K1_STATIC
musig_example_LDADD = libsecp256k1.la
musig_example_LDFLAGS = -static
if BUILD_WINDOWS
@ -192,19 +202,19 @@ EXTRA_PROGRAMS = precompute_ecmult precompute_ecmult_gen
CLEANFILES = $(EXTRA_PROGRAMS)
precompute_ecmult_SOURCES = src/precompute_ecmult.c
precompute_ecmult_CPPFLAGS = $(SECP_INCLUDES)
precompute_ecmult_LDADD = $(SECP_LIBS) $(COMMON_LIB)
precompute_ecmult_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY
precompute_ecmult_LDADD = $(COMMON_LIB)
precompute_ecmult_gen_SOURCES = src/precompute_ecmult_gen.c
precompute_ecmult_gen_CPPFLAGS = $(SECP_INCLUDES)
precompute_ecmult_gen_LDADD = $(SECP_LIBS) $(COMMON_LIB)
precompute_ecmult_gen_CPPFLAGS = $(SECP_CONFIG_DEFINES) -DVERIFY
precompute_ecmult_gen_LDADD = $(COMMON_LIB)
# See Automake manual, Section "Errors with distclean".
# We don't list any dependencies for the prebuilt files here because
# otherwise make's decision whether to rebuild them (even in the first
# build by a normal user) depends on mtimes, and thus is very fragile.
# This means that rebuilds of the prebuilt files always need to be
# forced by deleting them, e.g., by invoking `make clean-precomp`.
# forced by deleting them.
src/precomputed_ecmult.c:
$(MAKE) $(AM_MAKEFLAGS) precompute_ecmult$(EXEEXT)
./precompute_ecmult$(EXEEXT)
@ -219,12 +229,41 @@ precomp: $(PRECOMP)
# e.g., after `make maintainer-clean`).
BUILT_SOURCES = $(PRECOMP)
maintainer-clean-local: clean-precomp
.PHONY: clean-precomp
clean-precomp:
rm -f $(PRECOMP)
maintainer-clean-local: clean-precomp
EXTRA_DIST = autogen.sh SECURITY.md
### Pregenerated test vectors
### (see the comments in the previous section for detailed rationale)
TESTVECTORS = src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h
src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.h:
mkdir -p $(@D)
python3 $(top_srcdir)/tools/tests_wycheproof_generate.py $(top_srcdir)/src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json > $@
testvectors: $(TESTVECTORS)
BUILT_SOURCES += $(TESTVECTORS)
.PHONY: clean-testvectors
clean-testvectors:
rm -f $(TESTVECTORS)
maintainer-clean-local: clean-testvectors
### Additional files to distribute
EXTRA_DIST = autogen.sh CHANGELOG.md SECURITY.md
EXTRA_DIST += doc/release-process.md doc/safegcd_implementation.md
EXTRA_DIST += examples/EXAMPLES_COPYING
EXTRA_DIST += sage/gen_exhaustive_groups.sage
EXTRA_DIST += sage/gen_split_lambda_constants.sage
EXTRA_DIST += sage/group_prover.sage
EXTRA_DIST += sage/prove_group_implementations.sage
EXTRA_DIST += sage/secp256k1_params.sage
EXTRA_DIST += sage/weierstrass_prover.sage
EXTRA_DIST += src/wycheproof/WYCHEPROOF_COPYING
EXTRA_DIST += src/wycheproof/ecdsa_secp256k1_sha256_bitcoin_test.json
EXTRA_DIST += tools/tests_wycheproof_generate.py
if ENABLE_MODULE_BPPP
include src/modules/bppp/Makefile.am.include
@ -266,6 +305,10 @@ if ENABLE_MODULE_SCHNORRSIG
include src/modules/schnorrsig/Makefile.am.include
endif
if ENABLE_MODULE_ELLSWIFT
include src/modules/ellswift/Makefile.am.include
endif
if ENABLE_MODULE_ECDSA_S2C
include src/modules/ecdsa_s2c/Makefile.am.include
endif

View File

@ -2,6 +2,7 @@ libsecp256k1-zkp
================
[![Build Status](https://api.cirrus-ci.com/github/BlockstreamResearch/secp256k1-zkp.svg?branch=master)](https://cirrus-ci.com/github/BlockstreamResearch/secp256k1-zkp)
![Dependencies: None](https://img.shields.io/badge/dependencies-none-success)
A fork of [libsecp256k1](https://github.com/bitcoin-core/secp256k1) with support for advanced and experimental features such as Confidential Assets and MuSig2
@ -30,7 +31,14 @@ To compile optional modules (such as Schnorr signatures), you need to run `./con
Usage examples
-----------
Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
Usage examples can be found in the [examples](examples) directory. To compile them you need to configure with `--enable-examples`.
* [ECDSA example](examples/ecdsa.c)
* [Schnorr signatures example](examples/schnorr.c)
* [Deriving a shared secret (ECDH) example](examples/ecdh.c)
* [MuSig example](examples/musig.c)
To compile the Schnorr signature, ECDH and MuSig examples, you need to enable the corresponding module by providing a flag to the `configure` script, for example `--enable-module-schnorrsig`.
Test coverage
-----------

View File

@ -1,15 +1,35 @@
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_DEFUN([SECP_X86_64_ASM_CHECK],[
AC_MSG_CHECKING(for x86_64 assembly availability)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
#include <stdint.h>]],[[
uint64_t a = 11, tmp;
__asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx");
]])],[has_64bit_asm=yes],[has_64bit_asm=no])
AC_MSG_RESULT([$has_64bit_asm])
]])], [has_x86_64_asm=yes], [has_x86_64_asm=no])
AC_MSG_RESULT([$has_x86_64_asm])
])
AC_DEFUN([SECP_ARM32_ASM_CHECK], [
AC_MSG_CHECKING(for ARM32 assembly availability)
SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS="$CFLAGS"
CFLAGS="-x assembler"
AC_LINK_IFELSE([AC_LANG_SOURCE([[
.syntax unified
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.text
.global main
main:
ldr r0, =0x002A
mov r7, #1
swi 0
]])], [has_arm32_asm=yes], [has_arm32_asm=no])
AC_MSG_RESULT([$has_arm32_asm])
CFLAGS="$SECP_ARM32_ASM_CHECK_CFLAGS_saved_CFLAGS"
])
AC_DEFUN([SECP_VALGRIND_CHECK],[
AC_MSG_CHECKING([for valgrind support])
if test x"$has_valgrind" != x"yes"; then
CPPFLAGS_TEMP="$CPPFLAGS"
CPPFLAGS="$VALGRIND_CPPFLAGS $CPPFLAGS"
@ -19,8 +39,10 @@ if test x"$has_valgrind" != x"yes"; then
#if defined(NVALGRIND)
# error "Valgrind does not support this platform."
#endif
]])], [has_valgrind=yes; AC_DEFINE(HAVE_VALGRIND,1,[Define this symbol if valgrind is installed, and it supports the host platform])])
]])], [has_valgrind=yes])
CPPFLAGS="$CPPFLAGS_TEMP"
fi
AC_MSG_RESULT($has_valgrind)
])
dnl SECP_TRY_APPEND_CFLAGS(flags, VAR)

View File

@ -1,14 +1,75 @@
#!/bin/sh
set -e
set -x
set -eux
export LC_ALL=C
# Print commit and relevant CI environment to allow reproducing the job outside of CI.
git show --no-patch
print_environment() {
# Turn off -x because it messes up the output
set +x
# There are many ways to print variable names and their content. This one
# does not rely on bash.
for var in WERROR_CFLAGS MAKEFLAGS BUILD \
ECMULTWINDOW ECMULTGENPRECISION ASM WIDEMUL WITH_VALGRIND EXTRAFLAGS \
EXPERIMENTAL ECDH RECOVERY SCHNORRSIG ELLSWIFT \
ECDSA_S2C GENERATOR RANGEPROOF WHITELIST MUSIG ECDSAADAPTOR BPPP \
SECP256K1_TEST_ITERS BENCH SECP256K1_BENCH_ITERS CTIMETESTS\
EXAMPLES \
HOST WRAPPER_CMD \
CC CFLAGS CPPFLAGS AR NM
do
eval "isset=\${$var+x}"
if [ -n "$isset" ]; then
eval "val=\${$var}"
# shellcheck disable=SC2154
printf '%s="%s" ' "$var" "$val"
fi
done
echo "$0"
set -x
}
print_environment
# Start persistent wineserver if necessary.
# This speeds up jobs with many invocations of wine (e.g., ./configure with MSVC) tremendously.
case "$WRAPPER_CMD" in
*wine*)
# Make sure to shutdown wineserver whenever we exit.
trap "wineserver -k || true" EXIT INT HUP
wineserver -p
;;
esac
env >> test_env.log
$CC -v || true
valgrind --version || true
if [ -n "${CC+x}" ]; then
# The MSVC compiler "cl" doesn't understand "-v"
$CC -v || true
fi
if [ "$WITH_VALGRIND" = "yes" ]; then
valgrind --version
fi
if [ -n "$WRAPPER_CMD" ]; then
$WRAPPER_CMD --version
fi
# Workaround for https://bugs.kde.org/show_bug.cgi?id=452758 (fixed in valgrind 3.20.0).
case "${CC:-undefined}" in
clang*)
if [ "$CTIMETESTS" = "yes" ] && [ "$WITH_VALGRIND" = "yes" ]
then
export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4"
else
case "$WRAPPER_CMD" in
valgrind*)
export CFLAGS="${CFLAGS:+$CFLAGS }-gdwarf-4"
;;
esac
fi
;;
esac
./autogen.sh
@ -18,12 +79,14 @@ valgrind --version || true
--with-ecmult-window="$ECMULTWINDOW" \
--with-ecmult-gen-precision="$ECMULTGENPRECISION" \
--enable-module-ecdh="$ECDH" --enable-module-recovery="$RECOVERY" \
--enable-module-ellswift="$ELLSWIFT" \
--enable-module-ecdsa-s2c="$ECDSA_S2C" \
--enable-module-bppp="$BPPP" \
--enable-module-rangeproof="$RANGEPROOF" --enable-module-whitelist="$WHITELIST" --enable-module-generator="$GENERATOR" \
--enable-module-schnorrsig="$SCHNORRSIG" --enable-module-musig="$MUSIG" --enable-module-ecdsa-adaptor="$ECDSAADAPTOR" \
--enable-module-schnorrsig="$SCHNORRSIG" \
--enable-examples="$EXAMPLES" \
--enable-ctime-tests="$CTIMETESTS" \
--with-valgrind="$WITH_VALGRIND" \
--host="$HOST" $EXTRAFLAGS
@ -40,14 +103,15 @@ export LOG_COMPILER="$WRAPPER_CMD"
make "$BUILD"
# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
EXEC='./libtool --mode=execute'
if [ -n "$WRAPPER_CMD" ]
then
EXEC="$EXEC $WRAPPER_CMD"
fi
if [ "$BENCH" = "yes" ]
then
# Using the local `libtool` because on macOS the system's libtool has nothing to do with GNU libtool
EXEC='./libtool --mode=execute'
if [ -n "$WRAPPER_CMD" ]
then
EXEC="$EXEC $WRAPPER_CMD"
fi
{
$EXEC ./bench_ecmult
$EXEC ./bench_internal
@ -59,16 +123,20 @@ then
} >> bench.log 2>&1
fi
if [ "$CTIMETEST" = "yes" ]
if [ "$CTIMETESTS" = "yes" ]
then
./libtool --mode=execute valgrind --error-exitcode=42 ./valgrind_ctime_test > valgrind_ctime_test.log 2>&1
if [ "$WITH_VALGRIND" = "yes" ]; then
./libtool --mode=execute valgrind --error-exitcode=42 ./ctime_tests > ctime_tests.log 2>&1
else
$EXEC ./ctime_tests > ctime_tests.log 2>&1
fi
fi
# Rebuild precomputed files (if not cross-compiling).
if [ -z "$HOST" ]
then
make clean-precomp
make precomp
make clean-precomp clean-testvectors
make precomp testvectors
fi
# Check that no repo files have been modified by the build.

View File

@ -1,26 +1,75 @@
FROM debian:stable
RUN dpkg --add-architecture i386
RUN dpkg --add-architecture s390x
RUN dpkg --add-architecture armhf
RUN dpkg --add-architecture arm64
RUN dpkg --add-architecture ppc64el
RUN apt-get update
SHELL ["/bin/bash", "-c"]
RUN dpkg --add-architecture i386 && \
dpkg --add-architecture s390x && \
dpkg --add-architecture armhf && \
dpkg --add-architecture arm64 && \
dpkg --add-architecture ppc64el
# dkpg-dev: to make pkg-config work in cross-builds
# llvm: for llvm-symbolizer, which is used by clang's UBSan for symbolized stack traces
RUN apt-get install --no-install-recommends --no-upgrade -y \
git ca-certificates \
RUN apt-get update && apt-get install --no-install-recommends -y \
git ca-certificates wget \
make automake libtool pkg-config dpkg-dev valgrind qemu-user \
gcc clang llvm libc6-dbg \
gcc clang llvm libclang-rt-dev libc6-dbg \
g++ \
gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan6:i386 \
gcc-i686-linux-gnu libc6-dev-i386-cross libc6-dbg:i386 libubsan1:i386 libasan8:i386 \
gcc-s390x-linux-gnu libc6-dev-s390x-cross libc6-dbg:s390x \
gcc-arm-linux-gnueabihf libc6-dev-armhf-cross libc6-dbg:armhf \
gcc-aarch64-linux-gnu libc6-dev-arm64-cross libc6-dbg:arm64 \
gcc-powerpc64le-linux-gnu libc6-dev-ppc64el-cross libc6-dbg:ppc64el \
wine gcc-mingw-w64-x86-64 \
gcc-mingw-w64-x86-64-win32 wine64 wine \
gcc-mingw-w64-i686-win32 wine32 \
sagemath
# Run a dummy command in wine to make it set up configuration
RUN wine64-stable xcopy || true
WORKDIR /root
# Build and install gcc snapshot
ARG GCC_SNAPSHOT_MAJOR=14
RUN wget --progress=dot:giga --https-only --recursive --accept '*.tar.xz' --level 1 --no-directories "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}" && \
wget "https://gcc.gnu.org/pub/gcc/snapshots/LATEST-${GCC_SNAPSHOT_MAJOR}/sha512.sum" && \
sha512sum --check --ignore-missing sha512.sum && \
# We should have downloaded exactly one tar.xz file
ls && \
[[ $(ls *.tar.xz | wc -l) -eq "1" ]] && \
tar xf *.tar.xz && \
mkdir gcc-build && cd gcc-build && \
apt-get update && apt-get install --no-install-recommends -y libgmp-dev libmpfr-dev libmpc-dev flex && \
../*/configure --prefix=/opt/gcc-snapshot --enable-languages=c --disable-bootstrap --disable-multilib --without-isl && \
make -j $(nproc) && \
make install && \
ln -s /opt/gcc-snapshot/bin/gcc /usr/bin/gcc-snapshot
# Install clang snapshot
RUN wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc && \
# Add repository for this Debian release
. /etc/os-release && echo "deb http://apt.llvm.org/${VERSION_CODENAME} llvm-toolchain-${VERSION_CODENAME} main" >> /etc/apt/sources.list && \
# Install clang snapshot
apt-get update && apt-get install --no-install-recommends -y clang && \
# Remove just the "clang" symlink again
apt-get remove -y clang && \
# We should have exactly two clang versions now
ls /usr/bin/clang* && \
[[ $(ls /usr/bin/clang-?? | sort | wc -l) -eq "2" ]] && \
# Create symlinks for them
ln -s $(ls /usr/bin/clang-?? | sort | tail -1) /usr/bin/clang-snapshot && \
ln -s $(ls /usr/bin/clang-?? | sort | head -1) /usr/bin/clang
# The "wine" package provides a convenience wrapper that we need
RUN apt-get update && apt-get install --no-install-recommends -y \
git ca-certificates wine64 wine python3-simplejson python3-six msitools winbind procps && \
# Workaround for `wine` package failure to employ the Debian alternatives system properly.
ln -s /usr/lib/wine/wine64 /usr/bin/wine64 && \
# Set of tools for using MSVC on Linux.
git clone https://github.com/mstorsjo/msvc-wine && \
mkdir /opt/msvc && \
python3 msvc-wine/vsdownload.py --accept-license --dest /opt/msvc Microsoft.VisualStudio.Workload.VCTools && \
# Since commit 2146cbfaf037e21de56c7157ec40bb6372860f51, the
# msvc-wine effectively initializes the wine prefix when running
# the install.sh script.
msvc-wine/install.sh /opt/msvc && \
# Wait until the wineserver process has exited before closing the session,
# to avoid corrupting the wine prefix.
while (ps -A | grep wineserver) > /dev/null; do sleep 1; done

View File

@ -0,0 +1,6 @@
function(check_arm32_assembly)
try_compile(HAVE_ARM32_ASM
${CMAKE_BINARY_DIR}/check_arm32_assembly
SOURCES ${CMAKE_SOURCE_DIR}/cmake/source_arm32.s
)
endfunction()

View File

@ -0,0 +1,10 @@
function(check_string_option_value option)
get_property(expected_values CACHE ${option} PROPERTY STRINGS)
if(expected_values)
if(${option} IN_LIST expected_values)
return()
endif()
message(FATAL_ERROR "${option} value is \"${${option}}\", but must be one of ${expected_values}.")
endif()
message(AUTHOR_WARNING "The STRINGS property must be set before invoking `check_string_option_value' function.")
endfunction()

View File

@ -0,0 +1,14 @@
include(CheckCSourceCompiles)
function(check_x86_64_assembly)
check_c_source_compiles("
#include <stdint.h>
int main()
{
uint64_t a = 11, tmp;
__asm__ __volatile__(\"movq $0x100000000,%1; mulq %%rsi\" : \"+a\"(a) : \"S\"(tmp) : \"cc\", \"%rdx\");
}
" HAVE_X86_64_ASM)
set(HAVE_X86_64_ASM ${HAVE_X86_64_ASM} PARENT_SCOPE)
endfunction()

41
cmake/FindValgrind.cmake Normal file
View File

@ -0,0 +1,41 @@
if(CMAKE_HOST_APPLE)
find_program(BREW_COMMAND brew)
execute_process(
COMMAND ${BREW_COMMAND} --prefix valgrind
OUTPUT_VARIABLE valgrind_brew_prefix
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
set(hints_paths)
if(valgrind_brew_prefix)
set(hints_paths ${valgrind_brew_prefix}/include)
endif()
find_path(Valgrind_INCLUDE_DIR
NAMES valgrind/memcheck.h
HINTS ${hints_paths}
)
if(Valgrind_INCLUDE_DIR)
include(CheckCSourceCompiles)
set(CMAKE_REQUIRED_INCLUDES ${Valgrind_INCLUDE_DIR})
check_c_source_compiles("
#include <valgrind/memcheck.h>
#if defined(NVALGRIND)
# error \"Valgrind does not support this platform.\"
#endif
int main() {}
" Valgrind_WORKS)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Valgrind
REQUIRED_VARS Valgrind_INCLUDE_DIR Valgrind_WORKS
)
mark_as_advanced(
Valgrind_INCLUDE_DIR
)

View File

@ -0,0 +1,24 @@
include(CheckCCompilerFlag)
function(secp256k1_check_c_flags_internal flags output)
string(MAKE_C_IDENTIFIER "${flags}" result)
string(TOUPPER "${result}" result)
set(result "C_SUPPORTS_${result}")
if(NOT MSVC)
set(CMAKE_REQUIRED_FLAGS "-Werror")
endif()
# This avoids running a linker.
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
check_c_compiler_flag("${flags}" ${result})
set(${output} ${${result}} PARENT_SCOPE)
endfunction()
# Append flags to the COMPILE_OPTIONS directory property if CC accepts them.
macro(try_append_c_flags)
secp256k1_check_c_flags_internal("${ARGV}" result)
if(result)
add_compile_options(${ARGV})
endif()
endmacro()

View File

@ -0,0 +1,3 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)

5
cmake/config.cmake.in Normal file
View File

@ -0,0 +1,5 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@-targets.cmake")
check_required_components(@PROJECT_NAME@)

9
cmake/source_arm32.s Normal file
View File

@ -0,0 +1,9 @@
.syntax unified
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.text
.global main
main:
ldr r0, =0x002A
mov r7, #1
swi 0

View File

@ -0,0 +1,3 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)

View File

@ -5,7 +5,7 @@ AC_PREREQ([2.60])
# backwards-compatible and therefore at most increase the minor version.
define(_PKG_VERSION_MAJOR, 0)
define(_PKG_VERSION_MINOR, 1)
define(_PKG_VERSION_BUILD, 0)
define(_PKG_VERSION_PATCH, 0)
define(_PKG_VERSION_IS_RELEASE, false)
# The library version is based on libtool versioning of the ABI. The set of
@ -17,14 +17,11 @@ define(_LIB_VERSION_CURRENT, 0)
define(_LIB_VERSION_REVISION, 0)
define(_LIB_VERSION_AGE, 0)
AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_BUILD)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-pre]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
AC_INIT([libsecp256k1],m4_join([.], _PKG_VERSION_MAJOR, _PKG_VERSION_MINOR, _PKG_VERSION_PATCH)m4_if(_PKG_VERSION_IS_RELEASE, [true], [], [-dev]),[https://github.com/bitcoin-core/secp256k1/issues],[libsecp256k1],[https://github.com/bitcoin-core/secp256k1])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
AC_CANONICAL_HOST
AH_TOP([#ifndef LIBSECP256K1_CONFIG_H])
AH_TOP([#define LIBSECP256K1_CONFIG_H])
AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/])
# Require Automake 1.11.2 for AM_PROG_AR
AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
@ -32,13 +29,20 @@ AM_INIT_AUTOMAKE([1.11.2 foreign subdir-objects])
# Make the compilation flags quiet unless V=1 is used.
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PROG_CC
if test x"$ac_cv_prog_cc_c89" = x"no"; then
AC_MSG_ERROR([c89 compiler support required])
if test "${CFLAGS+set}" = "set"; then
CFLAGS_overridden=yes
else
CFLAGS_overridden=no
fi
AC_PROG_CC
AM_PROG_AS
AM_PROG_AR
# Clear some cache variables as a workaround for a bug that appears due to a bad
# interaction between AM_PROG_AR and LT_INIT when combining MSVC's archiver lib.exe.
# https://debbugs.gnu.org/cgi/bugreport.cgi?bug=54421
AS_UNSET(ac_cv_prog_AR)
AS_UNSET(ac_cv_prog_ac_ct_AR)
LT_INIT([win32-dll])
build_windows=no
@ -87,23 +91,43 @@ esac
#
# TODO We should analogously not touch CPPFLAGS and LDFLAGS but currently there are no issues.
AC_DEFUN([SECP_TRY_APPEND_DEFAULT_CFLAGS], [
# Try to append -Werror=unknown-warning-option to CFLAGS temporarily. Otherwise clang will
# not error out if it gets unknown warning flags and the checks here will always succeed
# no matter if clang knows the flag or not.
SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
SECP_TRY_APPEND_CFLAGS([-Werror=unknown-warning-option], CFLAGS)
# GCC and compatible (incl. clang)
if test "x$GCC" = "xyes"; then
# Try to append -Werror to CFLAGS temporarily. Otherwise checks for some unsupported
# flags will succeed.
# Note that failure to append -Werror does not necessarily mean that -Werror is not
# supported. The compiler may already be warning about something unrelated, for example
# about some path issue. If that is the case, -Werror cannot be used because all
# of those warnings would be turned into errors.
SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS="$CFLAGS"
SECP_TRY_APPEND_CFLAGS([-Werror], CFLAGS)
SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
SECP_TRY_APPEND_CFLAGS([-std=c89 -pedantic -Wno-long-long -Wnested-externs -Wshadow -Wstrict-prototypes -Wundef], $1) # GCC >= 3.0, -Wlong-long is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wno-overlength-strings], $1) # GCC >= 4.2, -Woverlength-strings is implied by -pedantic.
SECP_TRY_APPEND_CFLAGS([-Wall], $1) # GCC >= 2.95 and probably many other compilers
SECP_TRY_APPEND_CFLAGS([-Wno-unused-function], $1) # GCC >= 3.0, -Wunused-function is implied by -Wall.
SECP_TRY_APPEND_CFLAGS([-Wextra], $1) # GCC >= 3.4, this is the newer name of -W, which we don't use because older GCCs will warn about unused functions.
SECP_TRY_APPEND_CFLAGS([-Wcast-align], $1) # GCC >= 2.95
SECP_TRY_APPEND_CFLAGS([-Wcast-align=strict], $1) # GCC >= 8.0
SECP_TRY_APPEND_CFLAGS([-Wconditional-uninitialized], $1) # Clang >= 3.0 only
SECP_TRY_APPEND_CFLAGS([-Wreserved-identifier], $1) # Clang >= 13.0 only
SECP_TRY_APPEND_CFLAGS([-fvisibility=hidden], $1) # GCC >= 4.0
CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
CFLAGS="$SECP_TRY_APPEND_DEFAULT_CFLAGS_saved_CFLAGS"
fi
# MSVC
# Assume MSVC if we're building for Windows but not with GCC or compatible;
# libtool makes the same assumption internally.
# Note that "/opt" and "-opt" are equivalent for MSVC; we use "-opt" because "/opt" looks like a path.
if test x"$GCC" != x"yes" && test x"$build_windows" = x"yes"; then
SECP_TRY_APPEND_CFLAGS([-W3], $1) # Production quality warning level.
SECP_TRY_APPEND_CFLAGS([-wd4146], $1) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
SECP_TRY_APPEND_CFLAGS([-wd4244], $1) # Disable warning C4244 "'conversion' conversion from 'type1' to 'type2', possible loss of data".
SECP_TRY_APPEND_CFLAGS([-wd4267], $1) # Disable warning C4267 "'var' : conversion from 'size_t' to 'type', possible loss of data".
# Eliminate deprecation warnings for the older, less secure functions.
CPPFLAGS="-D_CRT_SECURE_NO_WARNINGS $CPPFLAGS"
fi
])
SECP_TRY_APPEND_DEFAULT_CFLAGS(SECP_CFLAGS)
@ -128,6 +152,10 @@ AC_ARG_ENABLE(tests,
AS_HELP_STRING([--enable-tests],[compile tests [default=yes]]), [],
[SECP_SET_DEFAULT([enable_tests], [yes], [yes])])
AC_ARG_ENABLE(ctime_tests,
AS_HELP_STRING([--enable-ctime-tests],[compile constant-time tests [default=yes if valgrind enabled]]), [],
[SECP_SET_DEFAULT([enable_ctime_tests], [auto], [auto])])
AC_ARG_ENABLE(experimental,
AS_HELP_STRING([--enable-experimental],[allow experimental configure options [default=no]]), [],
[SECP_SET_DEFAULT([enable_experimental], [no], [yes])])
@ -146,8 +174,8 @@ AC_ARG_ENABLE(module_bppp,
[SECP_SET_DEFAULT([enable_module_bppp], [no], [yes])])
AC_ARG_ENABLE(module_ecdh,
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_ecdh], [no], [yes])])
AS_HELP_STRING([--enable-module-ecdh],[enable ECDH module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_ecdh], [yes], [yes])])
AC_ARG_ENABLE(module_musig,
AS_HELP_STRING([--enable-module-musig],[enable MuSig module (experimental)]),
@ -174,12 +202,16 @@ AC_ARG_ENABLE(module_whitelist,
[SECP_SET_DEFAULT([enable_module_whitelist], [no], [yes])])
AC_ARG_ENABLE(module_extrakeys,
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_extrakeys], [no], [yes])])
AS_HELP_STRING([--enable-module-extrakeys],[enable extrakeys module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_extrakeys], [yes], [yes])])
AC_ARG_ENABLE(module_schnorrsig,
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=no]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [no], [yes])])
AS_HELP_STRING([--enable-module-schnorrsig],[enable schnorrsig module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_schnorrsig], [yes], [yes])])
AC_ARG_ENABLE(module_ellswift,
AS_HELP_STRING([--enable-module-ellswift],[enable ElligatorSwift module [default=yes]]), [],
[SECP_SET_DEFAULT([enable_module_ellswift], [yes], [yes])])
AC_ARG_ENABLE(module_ecdsa_s2c,
AS_HELP_STRING([--enable-module-ecdsa-s2c],[enable ECDSA sign-to-contract module [default=no]]),
@ -206,11 +238,15 @@ AC_ARG_ENABLE(reduced_surjection_proof_size,
[SECP_SET_DEFAULT([use_reduced_surjection_proof_size], [no], [no])])
# Test-only override of the (autodetected by the C code) "widemul" setting.
# Legal values are int64 (for [u]int64_t), int128 (for [unsigned] __int128), and auto (the default).
# Legal values are:
# * int64 (for [u]int64_t),
# * int128 (for [unsigned] __int128),
# * int128_struct (for int128 implemented as a structure),
# * and auto (the default).
AC_ARG_WITH([test-override-wide-multiply], [] ,[set_widemul=$withval], [set_widemul=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|arm32|no|auto],
[assembly optimizations to use (experimental: arm32) [default=auto]])],[req_asm=$withval], [req_asm=auto])
AC_ARG_WITH([ecmult-window], [AS_HELP_STRING([--with-ecmult-window=SIZE|auto],
[window size for ecmult precomputation for verification, specified as integer in range [2..24].]
@ -252,11 +288,20 @@ else
enable_valgrind=yes
fi
fi
AM_CONDITIONAL([VALGRIND_ENABLED],[test "$enable_valgrind" = "yes"])
if test x"$enable_ctime_tests" = x"auto"; then
enable_ctime_tests=$enable_valgrind
fi
if test x"$enable_coverage" = x"yes"; then
AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DCOVERAGE=1"
SECP_CFLAGS="-O0 --coverage $SECP_CFLAGS"
# If coverage is enabled, and the user has not overridden CFLAGS,
# override Autoconf's value "-g -O2" with "-g". Otherwise we'd end up
# with "-O0 --coverage -g -O2".
if test "$CFLAGS_overridden" = "no"; then
CFLAGS="-g"
fi
LDFLAGS="--coverage $LDFLAGS"
else
# Most likely the CFLAGS already contain -O2 because that is autoconf's default.
@ -267,19 +312,19 @@ fi
AC_MSG_CHECKING([for __builtin_popcount])
AC_LINK_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([yes]); SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DHAVE_BUILTIN_POPCOUNT=1"],
[ AC_MSG_RESULT([no])
])
AC_MSG_CHECKING([for __builtin_clzll])
AC_LINK_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([yes]); SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DHAVE_BUILTIN_CLZLL=1"],
[ 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
SECP_X86_64_ASM_CHECK
if test x"$has_x86_64_asm" = x"yes"; then
set_asm=x86_64
fi
if test x"$set_asm" = x; then
@ -289,12 +334,16 @@ else
set_asm=$req_asm
case $set_asm in
x86_64)
SECP_64BIT_ASM_CHECK
if test x"$has_64bit_asm" != x"yes"; then
SECP_X86_64_ASM_CHECK
if test x"$has_x86_64_asm" != x"yes"; then
AC_MSG_ERROR([x86_64 assembly optimization requested but not available])
fi
;;
arm)
arm32)
SECP_ARM32_ASM_CHECK
if test x"$has_arm32_asm" != x"yes"; then
AC_MSG_ERROR([ARM32 assembly optimization requested but not available])
fi
;;
no)
;;
@ -309,9 +358,9 @@ enable_external_asm=no
case $set_asm in
x86_64)
AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_ASM_X86_64=1"
;;
arm)
arm32)
enable_external_asm=yes
;;
no)
@ -322,17 +371,20 @@ no)
esac
if test x"$enable_external_asm" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_ASM=1"
fi
# Select wide multiplication implementation
case $set_widemul in
int128_struct)
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128_STRUCT=1"
;;
int128)
AC_DEFINE(USE_FORCE_WIDEMUL_INT128, 1, [Define this symbol to force the use of the (unsigned) __int128 based wide multiplication implementation])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT128=1"
;;
int64)
AC_DEFINE(USE_FORCE_WIDEMUL_INT64, 1, [Define this symbol to force the use of the (u)int64_t based wide multiplication implementation])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_FORCE_WIDEMUL_INT64=1"
;;
auto)
;;
@ -359,7 +411,7 @@ case $set_ecmult_window in
# 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])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_WINDOW_SIZE=$set_ecmult_window"
;;
esac
@ -372,7 +424,7 @@ 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])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DECMULT_GEN_PREC_BITS=$set_ecmult_gen_precision"
;;
*)
AC_MSG_ERROR(['ecmult gen precision not 2, 4, 8 or "auto"'])
@ -380,10 +432,12 @@ case $set_ecmult_gen_precision in
esac
if test x"$enable_valgrind" = x"yes"; then
SECP_INCLUDES="$SECP_INCLUDES $VALGRIND_CPPFLAGS"
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES $VALGRIND_CPPFLAGS -DVALGRIND"
fi
# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI)
# Add -Werror and similar flags passed from the outside (for testing, e.g., in CI).
# We don't want to set the user variable CFLAGS in CI because this would disable
# autoconf's logic for setting default CFLAGS, which we would like to test in CI.
SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
###
@ -395,65 +449,71 @@ SECP_CFLAGS="$SECP_CFLAGS $WERROR_CFLAGS"
# tested first.
if test x"$enable_module_ecdh" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDH=1"
fi
if test x"$enable_module_musig" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_MUSIG, 1, [Define this symbol to enable the MuSig module])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_MUSIG=1"
enable_module_schnorrsig=yes
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])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RECOVERY=1"
fi
if test x"$enable_module_whitelist" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_WHITELIST=1"
enable_module_rangeproof=yes
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
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SURJECTIONPROOF=1"
enable_module_rangeproof=yes
AC_DEFINE(ENABLE_MODULE_SURJECTIONPROOF, 1, [Define this symbol to enable the surjection proof module])
fi
if test x"$enable_module_rangeproof" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_RANGEPROOF=1"
enable_module_generator=yes
AC_DEFINE(ENABLE_MODULE_RANGEPROOF, 1, [Define this symbol to enable the Pedersen / zero knowledge range proof module])
fi
if test x"$enable_module_bppp" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_BPPP=1"
enable_module_generator=yes
AC_DEFINE(ENABLE_MODULE_BPPP, 1, [Define this symbol to enable the Bulletproofs++ module])
fi
if test x"$enable_module_generator" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_GENERATOR, 1, [Define this symbol to enable the NUMS generator module])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_GENERATOR=1"
fi
if test x"$enable_module_schnorrsig" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_SCHNORRSIG, 1, [Define this symbol to enable the schnorrsig module])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_SCHNORRSIG=1"
enable_module_extrakeys=yes
fi
if test x"$enable_module_ellswift" = x"yes"; then
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ELLSWIFT=1"
fi
# Test if extrakeys is set after the schnorrsig module to allow the schnorrsig
# module to set enable_module_extrakeys=yes
if test x"$enable_module_extrakeys" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_EXTRAKEYS, 1, [Define this symbol to enable the extrakeys module])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_EXTRAKEYS=1"
fi
if test x"$enable_module_ecdsa_s2c" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDSA_S2C, 1, [Define this symbol to enable the ECDSA sign-to-contract module])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDSA_S2C=1"
fi
if test x"$enable_external_default_callbacks" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_EXTERNAL_DEFAULT_CALLBACKS=1"
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])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DUSE_REDUCED_SURJECTION_PROOF_SIZE=1"
fi
if test x"$enable_module_ecdsa_adaptor" = x"yes"; then
AC_DEFINE(ENABLE_MODULE_ECDSA_ADAPTOR, 1, [Define this symbol to enable the ECDSA adaptor module])
SECP_CONFIG_DEFINES="$SECP_CONFIG_DEFINES -DENABLE_MODULE_ECDSA_ADAPTOR=1"
fi
###
@ -494,8 +554,8 @@ else
if test x"$enable_module_ecdsa_adaptor" = x"yes"; then
AC_MSG_ERROR([ecdsa adaptor signatures module is experimental. Use --enable-experimental to allow.])
fi
if test x"$set_asm" = x"arm"; then
AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.])
if test x"$set_asm" = x"arm32"; then
AC_MSG_ERROR([ARM32 assembly optimization is experimental. Use --enable-experimental to allow.])
fi
fi
@ -503,15 +563,12 @@ fi
### Generate output
###
AC_CONFIG_HEADERS([src/libsecp256k1-config.h])
AC_CONFIG_FILES([Makefile libsecp256k1.pc])
AC_SUBST(SECP_INCLUDES)
AC_SUBST(SECP_LIBS)
AC_SUBST(SECP_TEST_LIBS)
AC_SUBST(SECP_TEST_INCLUDES)
AC_SUBST(SECP_CFLAGS)
AC_SUBST(SECP_CONFIG_DEFINES)
AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"])
AM_CONDITIONAL([USE_TESTS], [test x"$enable_tests" != x"no"])
AM_CONDITIONAL([USE_CTIME_TESTS], [test x"$enable_ctime_tests" = x"yes"])
AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$enable_exhaustive_tests" != x"no"])
AM_CONDITIONAL([USE_EXAMPLES], [test x"$enable_examples" != x"no"])
AM_CONDITIONAL([USE_BENCHMARK], [test x"$enable_benchmark" = x"yes"])
@ -524,12 +581,13 @@ AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" =
AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_EXTRAKEYS], [test x"$enable_module_extrakeys" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_SCHNORRSIG], [test x"$enable_module_schnorrsig" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ELLSWIFT], [test x"$enable_module_ellswift" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_S2C], [test x"$enable_module_ecdsa_s2c" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_ECDSA_ADAPTOR], [test x"$enable_module_ecdsa_adaptor" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_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"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$enable_external_asm" = x"yes"])
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm32"])
AM_CONDITIONAL([BUILD_WINDOWS], [test "$build_windows" = "yes"])
AC_SUBST(LIB_VERSION_CURRENT, _LIB_VERSION_CURRENT)
AC_SUBST(LIB_VERSION_REVISION, _LIB_VERSION_REVISION)
@ -542,12 +600,14 @@ echo "Build Options:"
echo " with external callbacks = $enable_external_default_callbacks"
echo " with benchmarks = $enable_benchmark"
echo " with tests = $enable_tests"
echo " with ctime tests = $enable_ctime_tests"
echo " with coverage = $enable_coverage"
echo " with examples = $enable_examples"
echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module extrakeys = $enable_module_extrakeys"
echo " module schnorrsig = $enable_module_schnorrsig"
echo " module ellswift = $enable_module_ellswift"
echo " module generator = $enable_module_generator"
echo " module rangeproof = $enable_module_rangeproof"
echo " module surjectionproof = $enable_module_surjectionproof"

View File

@ -43,8 +43,7 @@ extern "C" {
/** Export a private key in DER format.
*
* Returns: 1 if the private key was valid.
* Args: ctx: pointer to a context object, initialized for signing (cannot
* be NULL)
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: privkey: pointer to an array for storing the private key in BER.
* Should have space for 279 bytes, and cannot be NULL.
* privkeylen: Pointer to an int where the length of the private key in

View File

@ -1,12 +0,0 @@
# Changelog
This file is currently only a template for future use.
Each change falls into one of the following categories: Added, Changed, Deprecated, Removed, Fixed or Security.
## [Unreleased]
## [MAJOR.MINOR.PATCH] - YYYY-MM-DD
### Added/Changed/Deprecated/Removed/Fixed/Security
- [Title with link to Pull Request](https://link-to-pr)

483
doc/ellswift.md Normal file
View File

@ -0,0 +1,483 @@
# ElligatorSwift for secp256k1 explained
In this document we explain how the `ellswift` module implementation is related to the
construction in the
["SwiftEC: Shalluevan de Woestijne Indifferentiable Function To Elliptic Curves"](https://eprint.iacr.org/2022/759)
paper by Jorge Chávez-Saab, Francisco Rodríguez-Henríquez, and Mehdi Tibouchi.
* [1. Introduction](#1-introduction)
* [2. The decoding function](#2-the-decoding-function)
+ [2.1 Decoding for `secp256k1`](#21-decoding-for-secp256k1)
* [3. The encoding function](#3-the-encoding-function)
+ [3.1 Switching to *v, w* coordinates](#31-switching-to-v-w-coordinates)
+ [3.2 Avoiding computing all inverses](#32-avoiding-computing-all-inverses)
+ [3.3 Finding the inverse](#33-finding-the-inverse)
+ [3.4 Dealing with special cases](#34-dealing-with-special-cases)
+ [3.5 Encoding for `secp256k1`](#35-encoding-for-secp256k1)
* [4. Encoding and decoding full *(x, y)* coordinates](#4-encoding-and-decoding-full-x-y-coordinates)
+ [4.1 Full *(x, y)* coordinates for `secp256k1`](#41-full-x-y-coordinates-for-secp256k1)
## 1. Introduction
The `ellswift` module effectively introduces a new 64-byte public key format, with the property
that (uniformly random) public keys can be encoded as 64-byte arrays which are computationally
indistinguishable from uniform byte arrays. The module provides functions to convert public keys
from and to this format, as well as convenience functions for key generation and ECDH that operate
directly on ellswift-encoded keys.
The encoding consists of the concatenation of two (32-byte big endian) encoded field elements $u$
and $t.$ Together they encode an x-coordinate on the curve $x$, or (see further) a full point $(x, y)$ on
the curve.
**Decoding** consists of decoding the field elements $u$ and $t$ (values above the field size $p$
are taken modulo $p$), and then evaluating $F_u(t)$, which for every $u$ and $t$ results in a valid
x-coordinate on the curve. The functions $F_u$ will be defined in [Section 2](#2-the-decoding-function).
**Encoding** a given $x$ coordinate is conceptually done as follows:
* Loop:
* Pick a uniformly random field element $u.$
* Compute the set $L = F_u^{-1}(x)$ of $t$ values for which $F_u(t) = x$, which may have up to *8* elements.
* With probability $1 - \dfrac{\\#L}{8}$, restart the loop.
* Select a uniformly random $t \in L$ and return $(u, t).$
This is the *ElligatorSwift* algorithm, here given for just x-coordinates. An extension to full
$(x, y)$ points will be given in [Section 4](#4-encoding-and-decoding-full-x-y-coordinates).
The algorithm finds a uniformly random $(u, t)$ among (almost all) those
for which $F_u(t) = x.$ Section 3.2 in the paper proves that the number of such encodings for
almost all x-coordinates on the curve (all but at most 39) is close to two times the field size
(specifically, it lies in the range $2q \pm (22\sqrt{q} + O(1))$, where $q$ is the size of the field).
## 2. The decoding function
First some definitions:
* $\mathbb{F}$ is the finite field of size $q$, of characteristic 5 or more, and $q \equiv 1 \mod 3.$
* For `secp256k1`, $q = 2^{256} - 2^{32} - 977$, which satisfies that requirement.
* Let $E$ be the elliptic curve of points $(x, y) \in \mathbb{F}^2$ for which $y^2 = x^3 + ax + b$, with $a$ and $b$
public constants, for which $\Delta_E = -16(4a^3 + 27b^2)$ is a square, and at least one of $(-b \pm \sqrt{-3 \Delta_E} / 36)/2$ is a square.
This implies that the order of $E$ is either odd, or a multiple of *4*.
If $a=0$, this condition is always fulfilled.
* For `secp256k1`, $a=0$ and $b=7.$
* Let the function $g(x) = x^3 + ax + b$, so the $E$ curve equation is also $y^2 = g(x).$
* Let the function $h(x) = 3x^3 + 4a.$
* Define $V$ as the set of solutions $(x_1, x_2, x_3, z)$ to $z^2 = g(x_1)g(x_2)g(x_3).$
* Define $S_u$ as the set of solutions $(X, Y)$ to $X^2 + h(u)Y^2 = -g(u)$ and $Y \neq 0.$
* $P_u$ is a function from $\mathbb{F}$ to $S_u$ that will be defined below.
* $\psi_u$ is a function from $S_u$ to $V$ that will be defined below.
**Note**: In the paper:
* $F_u$ corresponds to $F_{0,u}$ there.
* $P_u(t)$ is called $P$ there.
* All $S_u$ sets together correspond to $S$ there.
* All $\psi_u$ functions together (operating on elements of $S$) correspond to $\psi$ there.
Note that for $V$, the left hand side of the equation $z^2$ is square, and thus the right
hand must also be square. As multiplying non-squares results in a square in $\mathbb{F}$,
out of the three right-hand side factors an even number must be non-squares.
This implies that exactly *1* or exactly *3* out of
$\\{g(x_1), g(x_2), g(x_3)\\}$ must be square, and thus that for any $(x_1,x_2,x_3,z) \in V$,
at least one of $\\{x_1, x_2, x_3\\}$ must be a valid x-coordinate on $E.$ There is one exception
to this, namely when $z=0$, but even then one of the three values is a valid x-coordinate.
**Define** the decoding function $F_u(t)$ as:
* Let $(x_1, x_2, x_3, z) = \psi_u(P_u(t)).$
* Return the first element $x$ of $(x_3, x_2, x_1)$ which is a valid x-coordinate on $E$ (i.e., $g(x)$ is square).
$P_u(t) = (X(u, t), Y(u, t))$, where:
$$
\begin{array}{lcl}
X(u, t) & = & \left\\{\begin{array}{ll}
\dfrac{g(u) - t^2}{2t} & a = 0 \\
\dfrac{g(u) + h(u)(Y_0(u) - X_0(u)t)^2}{X_0(u)(1 + h(u)t^2)} & a \neq 0
\end{array}\right. \\
Y(u, t) & = & \left\\{\begin{array}{ll}
\dfrac{X(u, t) + t}{u \sqrt{-3}} = \dfrac{g(u) + t^2}{2tu\sqrt{-3}} & a = 0 \\
Y_0(u) + t(X(u, t) - X_0(u)) & a \neq 0
\end{array}\right.
\end{array}
$$
$P_u(t)$ is defined:
* For $a=0$, unless:
* $u = 0$ or $t = 0$ (division by zero)
* $g(u) = -t^2$ (would give $Y=0$).
* For $a \neq 0$, unless:
* $X_0(u) = 0$ or $h(u)t^2 = -1$ (division by zero)
* $Y_0(u) (1 - h(u)t^2) = 2X_0(u)t$ (would give $Y=0$).
The functions $X_0(u)$ and $Y_0(u)$ are defined in Appendix A of the paper, and depend on various properties of $E.$
The function $\psi_u$ is the same for all curves: $\psi_u(X, Y) = (x_1, x_2, x_3, z)$, where:
$$
\begin{array}{lcl}
x_1 & = & \dfrac{X}{2Y} - \dfrac{u}{2} && \\
x_2 & = & -\dfrac{X}{2Y} - \dfrac{u}{2} && \\
x_3 & = & u + 4Y^2 && \\
z & = & \dfrac{g(x_3)}{2Y}(u^2 + ux_1 + x_1^2 + a) = \dfrac{-g(u)g(x_3)}{8Y^3}
\end{array}
$$
### 2.1 Decoding for `secp256k1`
Put together and specialized for $a=0$ curves, decoding $(u, t)$ to an x-coordinate is:
**Define** $F_u(t)$ as:
* Let $X = \dfrac{u^3 + b - t^2}{2t}.$
* Let $Y = \dfrac{X + t}{u\sqrt{-3}}.$
* Return the first $x$ in $(u + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u}{2}, \dfrac{X}{2Y} - \dfrac{u}{2})$ for which $g(x)$ is square.
To make sure that every input decodes to a valid x-coordinate, we remap the inputs in case
$P_u$ is not defined (when $u=0$, $t=0$, or $g(u) = -t^2$):
**Define** $F_u(t)$ as:
* Let $u'=u$ if $u \neq 0$; $1$ otherwise (guaranteeing $u' \neq 0$).
* Let $t'=t$ if $t \neq 0$; $1$ otherwise (guaranteeing $t' \neq 0$).
* Let $t''=t'$ if $g(u') \neq -t'^2$; $2t'$ otherwise (guaranteeing $t'' \neq 0$ and $g(u') \neq -t''^2$).
* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
* Return the first $x$ in $(u' + 4Y^2, \dfrac{-X}{2Y} - \dfrac{u'}{2}, \dfrac{X}{2Y} - \dfrac{u'}{2})$ for which $x^3 + b$ is square.
The choices here are not strictly necessary. Just returning a fixed constant in any of the undefined cases would suffice,
but the approach here is simple enough and gives fairly uniform output even in these cases.
**Note**: in the paper these conditions result in $\infty$ as output, due to the use of projective coordinates there.
We wish to avoid the need for callers to deal with this special case.
This is implemented in `secp256k1_ellswift_xswiftec_frac_var` (which decodes to an x-coordinate represented as a fraction), and
in `secp256k1_ellswift_xswiftec_var` (which outputs the actual x-coordinate).
## 3. The encoding function
To implement $F_u^{-1}(x)$, the function to find the set of inverses $t$ for which $F_u(t) = x$, we have to reverse the process:
* Find all the $(X, Y) \in S_u$ that could have given rise to $x$, through the $x_1$, $x_2$, or $x_3$ formulas in $\psi_u.$
* Map those $(X, Y)$ solutions to $t$ values using $P_u^{-1}(X, Y).$
* For each of the found $t$ values, verify that $F_u(t) = x.$
* Return the remaining $t$ values.
The function $P_u^{-1}$, which finds $t$ given $(X, Y) \in S_u$, is significantly simpler than $P_u:$
$$
P_u^{-1}(X, Y) = \left\\{\begin{array}{ll}
Yu\sqrt{-3} - X & a = 0 \\
\dfrac{Y-Y_0(u)}{X-X_0(u)} & a \neq 0 \land X \neq X_0(u) \\
\dfrac{-X_0(u)}{h(u)Y_0(u)} & a \neq 0 \land X = X_0(u) \land Y = Y_0(u)
\end{array}\right.
$$
The third step above, verifying that $F_u(t) = x$, is necessary because for the $(X, Y)$ values found through the $x_1$ and $x_2$ expressions,
it is possible that decoding through $\psi_u(X, Y)$ yields a valid $x_3$ on the curve, which would take precedence over the
$x_1$ or $x_2$ decoding. These $(X, Y)$ solutions must be rejected.
Since we know that exactly one or exactly three out of $\\{x_1, x_2, x_3\\}$ are valid x-coordinates for any $t$,
the case where either $x_1$ or $x_2$ is valid and in addition also $x_3$ is valid must mean that all three are valid.
This means that instead of checking whether $x_3$ is on the curve, it is also possible to check whether the other one out of
$x_1$ and $x_2$ is on the curve. This is significantly simpler, as it turns out.
Observe that $\psi_u$ guarantees that $x_1 + x_2 = -u.$ So given either $x = x_1$ or $x = x_2$, the other one of the two can be computed as
$-u - x.$ Thus, when encoding $x$ through the $x_1$ or $x_2$ expressions, one can simply check whether $g(-u-x)$ is a square,
and if so, not include the corresponding $t$ values in the returned set. As this does not need $X$, $Y$, or $t$, this condition can be determined
before those values are computed.
It is not possible that an encoding found through the $x_1$ expression decodes to a different valid x-coordinate using $x_2$ (which would
take precedence), for the same reason: if both $x_1$ and $x_2$ decodings were valid, $x_3$ would be valid as well, and thus take
precedence over both. Because of this, the $g(-u-x)$ being square test for $x_1$ and $x_2$ is the only test necessary to guarantee the found $t$
values round-trip back to the input $x$ correctly. This is the reason for choosing the $(x_3, x_2, x_1)$ precedence order in the decoder;
any order which does not place $x_3$ first requires more complicated round-trip checks in the encoder.
### 3.1 Switching to *v, w* coordinates
Before working out the formulas for all this, we switch to different variables for $S_u.$ Let $v = (X/Y - u)/2$, and
$w = 2Y.$ Or in the other direction, $X = w(u/2 + v)$ and $Y = w/2:$
* $S_u'$ becomes the set of $(v, w)$ for which $w^2 (u^2 + uv + v^2 + a) = -g(u)$ and $w \neq 0.$
* For $a=0$ curves, $P_u^{-1}$ can be stated for $(v,w)$ as $P_u^{'-1}(v, w) = w\left(\frac{\sqrt{-3}-1}{2}u - v\right).$
* $\psi_u$ can be stated for $(v, w)$ as $\psi_u'(v, w) = (x_1, x_2, x_3, z)$, where
$$
\begin{array}{lcl}
x_1 & = & v \\
x_2 & = & -u - v \\
x_3 & = & u + w^2 \\
z & = & \dfrac{g(x_3)}{w}(u^2 + uv + v^2 + a) = \dfrac{-g(u)g(x_3)}{w^3}
\end{array}
$$
We can now write the expressions for finding $(v, w)$ given $x$ explicitly, by solving each of the $\\{x_1, x_2, x_3\\}$
expressions for $v$ or $w$, and using the $S_u'$ equation to find the other variable:
* Assuming $x = x_1$, we find $v = x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
* Assuming $x = x_2$, we find $v = -u-x$ and $w = \pm\sqrt{-g(u)/(u^2 + uv + v^2 + a)}$ (two solutions).
* Assuming $x = x_3$, we find $w = \pm\sqrt{x-u}$ and $v = -u/2 \pm \sqrt{-w^2(4g(u) + w^2h(u))}/(2w^2)$ (four solutions).
### 3.2 Avoiding computing all inverses
The *ElligatorSwift* algorithm as stated in Section 1 requires the computation of $L = F_u^{-1}(x)$ (the
set of all $t$ such that $(u, t)$ decode to $x$) in full. This is unnecessary.
Observe that the procedure of restarting with probability $(1 - \frac{\\#L}{8})$ and otherwise returning a
uniformly random element from $L$ is actually equivalent to always padding $L$ with $\bot$ values up to length 8,
picking a uniformly random element from that, restarting whenever $\bot$ is picked:
**Define** *ElligatorSwift(x)* as:
* Loop:
* Pick a uniformly random field element $u.$
* Compute the set $L = F_u^{-1}(x).$
* Let $T$ be the 8-element vector consisting of the elements of $L$, plus $8 - \\#L$ times $\\{\bot\\}.$
* Select a uniformly random $t \in T.$
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
Now notice that the order of elements in $T$ does not matter, as all we do is pick a uniformly
random element in it, so we do not need to have all $\bot$ values at the end.
As we have 8 distinct formulas for finding $(v, w)$ (taking the variants due to $\pm$ into account),
we can associate every index in $T$ with exactly one of those formulas, making sure that:
* Formulas that yield no solutions (due to division by zero or non-existing square roots) or invalid solutions are made to return $\bot.$
* For the $x_1$ and $x_2$ cases, if $g(-u-x)$ is a square, $\bot$ is returned instead (the round-trip check).
* In case multiple formulas would return the same non- $\bot$ result, all but one of those must be turned into $\bot$ to avoid biasing those.
The last condition above only occurs with negligible probability for cryptographically-sized curves, but is interesting
to take into account as it allows exhaustive testing in small groups. See [Section 3.4](#34-dealing-with-special-cases)
for an analysis of all the negligible cases.
If we define $T = (G_{0,u}(x), G_{1,u}(x), \ldots, G_{7,u}(x))$, with each $G_{i,u}$ matching one of the formulas,
the loop can be simplified to only compute one of the inverses instead of all of them:
**Define** *ElligatorSwift(x)* as:
* Loop:
* Pick a uniformly random field element $u.$
* Pick a uniformly random integer $c$ in $[0,8).$
* Let $t = G_{c,u}(x).$
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
This is implemented in `secp256k1_ellswift_xelligatorswift_var`.
### 3.3 Finding the inverse
To implement $G_{c,u}$, we map $c=0$ to the $x_1$ formula, $c=1$ to the $x_2$ formula, and $c=2$ and $c=3$ to the $x_3$ formula.
Those are then repeated as $c=4$ through $c=7$ for the other sign of $w$ (noting that in each formula, $w$ is a square root of some expression).
Ignoring the negligible cases, we get:
**Define** $G_{c,u}(x)$ as:
* If $c \in \\{0, 1, 4, 5\\}$ (for $x_1$ and $x_2$ formulas):
* If $g(-u-x)$ is square, return $\bot$ (as $x_3$ would be valid and take precedence).
* If $c \in \\{0, 4\\}$ (the $x_1$ formula) let $v = x$, otherwise let $v = -u-x$ (the $x_2$ formula)
* Let $s = -g(u)/(u^2 + uv + v^2 + a)$ (using $s = w^2$ in what follows).
* Otherwise, when $c \in \\{2, 3, 6, 7\\}$ (for $x_3$ formulas):
* Let $s = x-u.$
* Let $r = \sqrt{-s(4g(u) + sh(u))}.$
* Let $v = (r/s - u)/2$ if $c \in \\{3, 7\\}$; $(-r/s - u)/2$ otherwise.
* Let $w = \sqrt{s}.$
* Depending on $c:$
* If $c \in \\{0, 1, 2, 3\\}:$ return $P_u^{'-1}(v, w).$
* If $c \in \\{4, 5, 6, 7\\}:$ return $P_u^{'-1}(v, -w).$
Whenever a square root of a non-square is taken, $\bot$ is returned; for both square roots this happens with roughly
50% on random inputs. Similarly, when a division by 0 would occur, $\bot$ is returned as well; this will only happen
with negligible probability. A division by 0 in the first branch in fact cannot occur at all, because $u^2 + uv + v^2 + a = 0$
implies $g(-u-x) = g(x)$ which would mean the $g(-u-x)$ is square condition has triggered
and $\bot$ would have been returned already.
**Note**: In the paper, the $case$ variable corresponds roughly to the $c$ above, but only takes on 4 possible values (1 to 4).
The conditional negation of $w$ at the end is done randomly, which is equivalent, but makes testing harder. We choose to
have the $G_{c,u}$ be deterministic, and capture all choices in $c.$
Now observe that the $c \in \\{1, 5\\}$ and $c \in \\{3, 7\\}$ conditions effectively perform the same $v \rightarrow -u-v$
transformation. Furthermore, that transformation has no effect on $s$ in the first branch
as $u^2 + ux + x^2 + a = u^2 + u(-u-x) + (-u-x)^2 + a.$ Thus we can extract it out and move it down:
**Define** $G_{c,u}(x)$ as:
* If $c \in \\{0, 1, 4, 5\\}:$
* If $g(-u-x)$ is square, return $\bot.$
* Let $s = -g(u)/(u^2 + ux + x^2 + a).$
* Let $v = x.$
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
* Let $s = x-u.$
* Let $r = \sqrt{-s(4g(u) + sh(u))}.$
* Let $v = (r/s - u)/2.$
* Let $w = \sqrt{s}.$
* Depending on $c:$
* If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w).$
* If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w).$
* If $c \in \\{4, 6\\}:$ return $P_u^{'-1}(v, -w).$
* If $c \in \\{5, 7\\}:$ return $P_u^{'-1}(-u-v, -w).$
This shows there will always be exactly 0, 4, or 8 $t$ values for a given $(u, x)$ input.
There can be 0, 1, or 2 $(v, w)$ pairs before invoking $P_u^{'-1}$, and each results in 4 distinct $t$ values.
### 3.4 Dealing with special cases
As mentioned before there are a few cases to deal with which only happen in a negligibly small subset of inputs.
For cryptographically sized fields, if only random inputs are going to be considered, it is unnecessary to deal with these. Still, for completeness
we analyse them here. They generally fall into two categories: cases in which the encoder would produce $t$ values that
do not decode back to $x$ (or at least cannot guarantee that they do), and cases in which the encoder might produce the same
$t$ value for multiple $c$ inputs (thereby biasing that encoding):
* In the branch for $x_1$ and $x_2$ (where $c \in \\{0, 1, 4, 5\\}$):
* When $g(u) = 0$, we would have $s=w=Y=0$, which is not on $S_u.$ This is only possible on even-ordered curves.
Excluding this also removes the one condition under which the simplified check for $x_3$ on the curve
fails (namely when $g(x_1)=g(x_2)=0$ but $g(x_3)$ is not square).
This does exclude some valid encodings: when both $g(u)=0$ and $u^2+ux+x^2+a=0$ (also implying $g(x)=0$),
the $S_u'$ equation degenerates to $0 = 0$, and many valid $t$ values may exist. Yet, these cannot be targeted uniformly by the
encoder anyway as there will generally be more than 8.
* When $g(x) = 0$, the same $t$ would be produced as in the $x_3$ branch (where $c \in \\{2, 3, 6, 7\\}$) which we give precedence
as it can deal with $g(u)=0$.
This is again only possible on even-ordered curves.
* In the branch for $x_3$ (where $c \in \\{2, 3, 6, 7\\}$):
* When $s=0$, a division by zero would occur.
* When $v = -u-v$ and $c \in \\{3, 7\\}$, the same $t$ would be returned as in the $c \in \\{2, 6\\}$ cases.
It is equivalent to checking whether $r=0$.
This cannot occur in the $x_1$ or $x_2$ branches, as it would trigger the $g(-u-x)$ is square condition.
A similar concern for $w = -w$ does not exist, as $w=0$ is already impossible in both branches: in the first
it requires $g(u)=0$ which is already outlawed on even-ordered curves and impossible on others; in the second it would trigger division by zero.
* Curve-specific special cases also exist that need to be rejected, because they result in $(u,t)$ which is invalid to the decoder, or because of division by zero in the encoder:
* For $a=0$ curves, when $u=0$ or when $t=0$. The latter can only be reached by the encoder when $g(u)=0$, which requires an even-ordered curve.
* For $a \neq 0$ curves, when $X_0(u)=0$, when $h(u)t^2 = -1$, or when $w(u + 2v) = 2X_0(u)$ while also either $w \neq 2Y_0(u)$ or $h(u)=0$.
**Define** a version of $G_{c,u}(x)$ which deals with all these cases:
* If $a=0$ and $u=0$, return $\bot.$
* If $a \neq 0$ and $X_0(u)=0$, return $\bot.$
* If $c \in \\{0, 1, 4, 5\\}:$
* If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
* If $g(-u-x)$ is square, return $\bot.$
* Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
* Let $v = x.$
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
* Let $s = x-u.$
* Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
* If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
* If $s = 0$, return $\bot.$
* Let $v = (r/s - u)/2.$
* Let $w = \sqrt{s}$; return $\bot$ if not square.
* If $a \neq 0$ and $w(u+2v) = 2X_0(u)$ and either $w \neq 2Y_0(u)$ or $h(u) = 0$, return $\bot.$
* Depending on $c:$
* If $c \in \\{0, 2\\}$, let $t = P_u^{'-1}(v, w).$
* If $c \in \\{1, 3\\}$, let $t = P_u^{'-1}(-u-v, w).$
* If $c \in \\{4, 6\\}$, let $t = P_u^{'-1}(v, -w).$
* If $c \in \\{5, 7\\}$, let $t = P_u^{'-1}(-u-v, -w).$
* If $a=0$ and $t=0$, return $\bot$ (even curves only).
* If $a \neq 0$ and $h(u)t^2 = -1$, return $\bot.$
* Return $t.$
Given any $u$, using this algorithm over all $x$ and $c$ values, every $t$ value will be reached exactly once,
for an $x$ for which $F_u(t) = x$ holds, except for these cases that will not be reached:
* All cases where $P_u(t)$ is not defined:
* For $a=0$ curves, when $u=0$, $t=0$, or $g(u) = -t^2.$
* For $a \neq 0$ curves, when $h(u)t^2 = -1$, $X_0(u) = 0$, or $Y_0(u) (1 - h(u) t^2) = 2X_0(u)t.$
* When $g(u)=0$, the potentially many $t$ values that decode to an $x$ satisfying $g(x)=0$ using the $x_2$ formula. These were excluded by the $g(u)=0$ condition in the $c \in \\{0, 1, 4, 5\\}$ branch.
These cases form a negligible subset of all $(u, t)$ for cryptographically sized curves.
### 3.5 Encoding for `secp256k1`
Specialized for odd-ordered $a=0$ curves:
**Define** $G_{c,u}(x)$ as:
* If $u=0$, return $\bot.$
* If $c \in \\{0, 1, 4, 5\\}:$
* If $(-u-x)^3 + b$ is square, return $\bot$
* Let $s = -(u^3 + b)/(u^2 + ux + x^2)$ (cannot cause division by 0).
* Let $v = x.$
* Otherwise, when $c \in \\{2, 3, 6, 7\\}:$
* Let $s = x-u.$
* Let $r = \sqrt{-s(4(u^3 + b) + 3su^2)}$; return $\bot$ if not square.
* If $c \in \\{3, 7\\}$ and $r=0$, return $\bot.$
* If $s = 0$, return $\bot.$
* Let $v = (r/s - u)/2.$
* Let $w = \sqrt{s}$; return $\bot$ if not square.
* Depending on $c:$
* If $c \in \\{0, 2\\}:$ return $w(\frac{\sqrt{-3}-1}{2}u - v).$
* If $c \in \\{1, 3\\}:$ return $w(\frac{\sqrt{-3}+1}{2}u + v).$
* If $c \in \\{4, 6\\}:$ return $w(\frac{-\sqrt{-3}+1}{2}u + v).$
* If $c \in \\{5, 7\\}:$ return $w(\frac{-\sqrt{-3}-1}{2}u - v).$
This is implemented in `secp256k1_ellswift_xswiftec_inv_var`.
And the x-only ElligatorSwift encoding algorithm is still:
**Define** *ElligatorSwift(x)* as:
* Loop:
* Pick a uniformly random field element $u.$
* Pick a uniformly random integer $c$ in $[0,8).$
* Let $t = G_{c,u}(x).$
* If $t \neq \bot$, return $(u, t)$; restart loop otherwise.
Note that this logic does not take the remapped $u=0$, $t=0$, and $g(u) = -t^2$ cases into account; it just avoids them.
While it is not impossible to make the encoder target them, this would increase the maximum number of $t$ values for a given $(u, x)$
combination beyond 8, and thereby slow down the ElligatorSwift loop proportionally, for a negligible gain in uniformity.
## 4. Encoding and decoding full *(x, y)* coordinates
So far we have only addressed encoding and decoding x-coordinates, but in some cases an encoding
for full points with $(x, y)$ coordinates is desirable. It is possible to encode this information
in $t$ as well.
Note that for any $(X, Y) \in S_u$, $(\pm X, \pm Y)$ are all on $S_u.$ Moreover, all of these are
mapped to the same x-coordinate. Negating $X$ or negating $Y$ just results in $x_1$ and $x_2$
being swapped, and does not affect $x_3.$ This will not change the outcome x-coordinate as the order
of $x_1$ and $x_2$ only matters if both were to be valid, and in that case $x_3$ would be used instead.
Still, these four $(X, Y)$ combinations all correspond to distinct $t$ values, so we can encode
the sign of the y-coordinate in the sign of $X$ or the sign of $Y.$ They correspond to the
four distinct $P_u^{'-1}$ calls in the definition of $G_{u,c}.$
**Note**: In the paper, the sign of the y coordinate is encoded in a separately-coded bit.
To encode the sign of $y$ in the sign of $Y:$
**Define** *Decode(u, t)* for full $(x, y)$ as:
* Let $(X, Y) = P_u(t).$
* Let $x$ be the first value in $(u + 4Y^2, \frac{-X}{2Y} - \frac{u}{2}, \frac{X}{2Y} - \frac{u}{2})$ for which $g(x)$ is square.
* Let $y = \sqrt{g(x)}.$
* If $sign(y) = sign(Y)$, return $(x, y)$; otherwise return $(x, -y).$
And encoding would be done using a $G_{c,u}(x, y)$ function defined as:
**Define** $G_{c,u}(x, y)$ as:
* If $c \in \\{0, 1\\}:$
* If $g(u) = 0$ or $g(x) = 0$, return $\bot$ (even curves only).
* If $g(-u-x)$ is square, return $\bot.$
* Let $s = -g(u)/(u^2 + ux + x^2 + a)$ (cannot cause division by zero).
* Let $v = x.$
* Otherwise, when $c \in \\{2, 3\\}:$
* Let $s = x-u.$
* Let $r = \sqrt{-s(4g(u) + sh(u))}$; return $\bot$ if not square.
* If $c = 3$ and $r = 0$, return $\bot.$
* Let $v = (r/s - u)/2.$
* Let $w = \sqrt{s}$; return $\bot$ if not square.
* Let $w' = w$ if $sign(w/2) = sign(y)$; $-w$ otherwise.
* Depending on $c:$
* If $c \in \\{0, 2\\}:$ return $P_u^{'-1}(v, w').$
* If $c \in \\{1, 3\\}:$ return $P_u^{'-1}(-u-v, w').$
Note that $c$ now only ranges $[0,4)$, as the sign of $w'$ is decided based on that of $y$, rather than on $c.$
This change makes some valid encodings unreachable: when $y = 0$ and $sign(Y) \neq sign(0)$.
In the above logic, $sign$ can be implemented in several ways, such as parity of the integer representation
of the input field element (for prime-sized fields) or the quadratic residuosity (for fields where
$-1$ is not square). The choice does not matter, as long as it only takes on two possible values, and for $x \neq 0$ it holds that $sign(x) \neq sign(-x)$.
### 4.1 Full *(x, y)* coordinates for `secp256k1`
For $a=0$ curves, there is another option. Note that for those,
the $P_u(t)$ function translates negations of $t$ to negations of (both) $X$ and $Y.$ Thus, we can use $sign(t)$ to
encode the y-coordinate directly. Combined with the earlier remapping to guarantee all inputs land on the curve, we get
as decoder:
**Define** *Decode(u, t)* as:
* Let $u'=u$ if $u \neq 0$; $1$ otherwise.
* Let $t'=t$ if $t \neq 0$; $1$ otherwise.
* Let $t''=t'$ if $u'^3 + b + t'^2 \neq 0$; $2t'$ otherwise.
* Let $X = \dfrac{u'^3 + b - t''^2}{2t''}.$
* Let $Y = \dfrac{X + t''}{u'\sqrt{-3}}.$
* Let $x$ be the first element of $(u' + 4Y^2, \frac{-X}{2Y} - \frac{u'}{2}, \frac{X}{2Y} - \frac{u'}{2})$ for which $g(x)$ is square.
* Let $y = \sqrt{g(x)}.$
* Return $(x, y)$ if $sign(y) = sign(t)$; $(x, -y)$ otherwise.
This is implemented in `secp256k1_ellswift_swiftec_var`. The used $sign(x)$ function is the parity of $x$ when represented as in integer in $[0,q).$
The corresponding encoder would invoke the x-only one, but negating the output $t$ if $sign(t) \neq sign(y).$
This is implemented in `secp256k1_ellswift_elligatorswift_var`.
Note that this is only intended for encoding points where both the x-coordinate and y-coordinate are unpredictable. When encoding x-only points
where the y-coordinate is implicitly even (or implicitly square, or implicitly in $[0,q/2]$), the encoder in
[Section 3.5](#35-encoding-for-secp256k1) must be used, or a bias is reintroduced that undoes all the benefit of using ElligatorSwift
in the first place.

View File

@ -1,14 +1,88 @@
# Release Process
1. Open PR to master that
1. adds release notes to `doc/CHANGELOG.md` and
2. if this is **not** a patch release, updates `_PKG_VERSION_{MAJOR,MINOR}` and `_LIB_VERSIONS_*` in `configure.ac`
2. After the PR is merged,
* if this is **not** a patch release, create a release branch with name `MAJOR.MINOR`.
Make sure that the branch contains the right commits.
Create commit on the release branch that sets `_PKG_VERSION_IS_RELEASE` in `configure.ac` to `true`.
* if this **is** a patch release, open a pull request with the bugfixes to the `MAJOR.MINOR` branch.
Also include the release note commit bump `_PKG_VERSION_BUILD` and `_LIB_VERSIONS_*` in `configure.ac`.
4. Tag the commit with `git tag -s vMAJOR.MINOR.PATCH`.
5. Push branch and tag with `git push origin --tags`.
6. Create a new GitHub release with a link to the corresponding entry in `doc/CHANGELOG.md`.
This document outlines the process for releasing versions of the form `$MAJOR.$MINOR.$PATCH`.
We distinguish between two types of releases: *regular* and *maintenance* releases.
Regular releases are releases of a new major or minor version as well as patches of the most recent release.
Maintenance releases, on the other hand, are required for patches of older releases.
You should coordinate with the other maintainers on the release date, if possible.
This date will be part of the release entry in [CHANGELOG.md](../CHANGELOG.md) and it should match the dates of the remaining steps in the release process (including the date of the tag and the GitHub release).
It is best if the maintainers are present during the release, so they can help ensure that the process is followed correctly and, in the case of a regular release, they are aware that they should not modify the master branch between merging the PR in step 1 and the PR in step 3.
This process also assumes that there will be no minor releases for old major releases.
We aim to cut a regular release every 3-4 months, approximately twice as frequent as major Bitcoin Core releases. Every second release should be published one month before the feature freeze of the next major Bitcoin Core release, allowing sufficient time to update the library in Core.
## Sanity Checks
Perform these checks before creating a release:
1. Ensure `make distcheck` doesn't fail.
```shell
./autogen.sh && ./configure --enable-dev-mode && make distcheck
```
2. Check installation with autotools:
```shell
dir=$(mktemp -d)
./autogen.sh && ./configure --prefix=$dir && make clean && make install && ls -l $dir/include $dir/lib
gcc -o ecdsa examples/ecdsa.c $(PKG_CONFIG_PATH=$dir/lib/pkgconfig pkg-config --cflags --libs libsecp256k1) -Wl,-rpath,"$dir/lib" && ./ecdsa
```
3. Check installation with CMake:
```shell
dir=$(mktemp -d)
build=$(mktemp -d)
cmake -B $build -DCMAKE_INSTALL_PREFIX=$dir && cmake --build $build --target install && ls -l $dir/include $dir/lib*
gcc -o ecdsa examples/ecdsa.c -I $dir/include -L $dir/lib*/ -l secp256k1 -Wl,-rpath,"$dir/lib",-rpath,"$dir/lib64" && ./ecdsa
```
## Regular release
1. Open a PR to the master branch with a commit (using message `"release: prepare for $MAJOR.$MINOR.$PATCH"`, for example) that
* finalizes the release notes in [CHANGELOG.md](../CHANGELOG.md) by
* adding a section for the release (make sure that the version number is a link to a diff between the previous and new version),
* removing the `[Unreleased]` section header, and
* including an entry for `### ABI Compatibility` if it doesn't exist that mentions the library soname of the release,
* sets `_PKG_VERSION_IS_RELEASE` to `true` in `configure.ac`, and
* if this is not a patch release
* updates `_PKG_VERSION_*` and `_LIB_VERSION_*` in `configure.ac` and
* updates `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_*` in `CMakeLists.txt`.
2. After the PR is merged, tag the commit and push it:
```
RELEASE_COMMIT=<merge commit of step 1>
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH" $RELEASE_COMMIT
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
```
3. Open a PR to the master branch with a commit (using message `"release cleanup: bump version after $MAJOR.$MINOR.$PATCH"`, for example) that
* sets `_PKG_VERSION_IS_RELEASE` to `false` and increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`,
* increments the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`, and
* adds an `[Unreleased]` section header to the [CHANGELOG.md](../CHANGELOG.md).
If other maintainers are not present to approve the PR, it can be merged without ACKs.
4. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
## Maintenance release
Note that bugfixes only need to be backported to releases for which no compatible release without the bug exists.
1. If there's no maintenance branch `$MAJOR.$MINOR`, create one:
```
git checkout -b $MAJOR.$MINOR v$MAJOR.$MINOR.$((PATCH - 1))
git push git@github.com:bitcoin-core/secp256k1.git $MAJOR.$MINOR
```
2. Open a pull request to the `$MAJOR.$MINOR` branch that
* includes the bugfixes,
* finalizes the release notes similar to a regular release,
* increments `_PKG_VERSION_PATCH` and `_LIB_VERSION_REVISION` in `configure.ac`
and the `$PATCH` component of `project(libsecp256k1 VERSION ...)` and `${PROJECT_NAME}_LIB_VERSION_REVISION` in `CMakeLists.txt`
(with commit message `"release: bump versions for $MAJOR.$MINOR.$PATCH"`, for example).
3. After the PRs are merged, update the release branch and tag the commit:
```
git checkout $MAJOR.$MINOR && git pull
git tag -s v$MAJOR.$MINOR.$PATCH -m "libsecp256k1 $MAJOR.$MINOR.$PATCH"
```
4. Push tag:
```
git push git@github.com:bitcoin-core/secp256k1.git v$MAJOR.$MINOR.$PATCH
```
5. Create a new GitHub release with a link to the corresponding entry in [CHANGELOG.md](../CHANGELOG.md).
6. Open PR to the master branch that includes a commit (with commit message `"release notes: add $MAJOR.$MINOR.$PATCH"`, for example) that adds release notes to [CHANGELOG.md](../CHANGELOG.md).

View File

@ -1,7 +1,7 @@
# The safegcd implementation in libsecp256k1 explained
This document explains the modular inverse implementation in the `src/modinv*.h` files. It is based
on the paper
This document explains the modular inverse and Jacobi symbol implementations in the `src/modinv*.h` files.
It is based on the paper
["Fast constant-time gcd computation and modular inversion"](https://gcd.cr.yp.to/papers.html#safegcd)
by Daniel J. Bernstein and Bo-Yin Yang. The references below are for the Date: 2019.04.13 version.
@ -410,7 +410,7 @@ sufficient even. Given that every loop iteration performs *N* divsteps, it will
To deal with the branches in `divsteps_n_matrix` we will replace them with constant-time bitwise
operations (and hope the C compiler isn't smart enough to turn them back into branches; see
`valgrind_ctime_test.c` for automated tests that this isn't the case). To do so, observe that a
`ctime_tests.c` for automated tests that this isn't the case). To do so, observe that a
divstep can be written instead as (compare to the inner loop of `gcd` in section 1).
```python
@ -769,3 +769,51 @@ def modinv_var(M, Mi, x):
d, e = update_de(d, e, t, M, Mi)
return normalize(f, d, Mi)
```
## 8. From GCDs to Jacobi symbol
We can also use a similar approach to calculate Jacobi symbol *(x | M)* by keeping track of an
extra variable *j*, for which at every step *(x | M) = j (g | f)*. As we update *f* and *g*, we
make corresponding updates to *j* using
[properties of the Jacobi symbol](https://en.wikipedia.org/wiki/Jacobi_symbol#Properties):
* *((g/2) | f)* is either *(g | f)* or *-(g | f)*, depending on the value of *f mod 8* (negating if it's *3* or *5*).
* *(f | g)* is either *(g | f)* or *-(g | f)*, depending on *f mod 4* and *g mod 4* (negating if both are *3*).
These updates depend only on the values of *f* and *g* modulo *4* or *8*, and can thus be applied
very quickly, as long as we keep track of a few additional bits of *f* and *g*. Overall, this
calculation is slightly simpler than the one for the modular inverse because we no longer need to
keep track of *d* and *e*.
However, one difficulty of this approach is that the Jacobi symbol *(a | n)* is only defined for
positive odd integers *n*, whereas in the original safegcd algorithm, *f, g* can take negative
values. We resolve this by using the following modified steps:
```python
# Before
if delta > 0 and g & 1:
delta, f, g = 1 - delta, g, (g - f) // 2
# After
if delta > 0 and g & 1:
delta, f, g = 1 - delta, g, (g + f) // 2
```
The algorithm is still correct, since the changed divstep, called a "posdivstep" (see section 8.4
and E.5 in the paper) preserves *gcd(f, g)*. However, there's no proof that the modified algorithm
will converge. The justification for posdivsteps is completely empirical: in practice, it appears
that the vast majority of nonzero inputs converge to *f=g=gcd(f<sub>0</sub>, g<sub>0</sub>)* in a
number of steps proportional to their logarithm.
Note that:
- We require inputs to satisfy *gcd(x, M) = 1*, as otherwise *f=1* is not reached.
- We require inputs *x &neq; 0*, because applying posdivstep with *g=0* has no effect.
- We need to update the termination condition from *g=0* to *f=1*.
We account for the possibility of nonconvergence by only performing a bounded number of
posdivsteps, and then falling back to square-root based Jacobi calculation if a solution has not
yet been found.
The optimizations in sections 3-7 above are described in the context of the original divsteps, but
in the C implementation we also adapt most of them (not including "avoiding modulus operations",
since it's not necessary to track *d, e*, and "constant-time operation", since we never calculate
Jacobi symbols for secret data) to the posdivsteps version.

24
examples/CMakeLists.txt Normal file
View File

@ -0,0 +1,24 @@
add_library(example INTERFACE)
target_include_directories(example INTERFACE
${PROJECT_SOURCE_DIR}/include
)
target_link_libraries(example INTERFACE
secp256k1
$<$<PLATFORM_ID:Windows>:bcrypt>
)
add_executable(ecdsa_example ecdsa.c)
target_link_libraries(ecdsa_example example)
add_test(NAME ecdsa_example COMMAND ecdsa_example)
if(SECP256K1_ENABLE_MODULE_ECDH)
add_executable(ecdh_example ecdh.c)
target_link_libraries(ecdh_example example)
add_test(NAME ecdh_example COMMAND ecdh_example)
endif()
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
add_executable(schnorr_example schnorr.c)
target_link_libraries(schnorr_example example)
add_test(NAME schnorr_example COMMAND schnorr_example)
endif()

View File

@ -14,8 +14,7 @@
#include <secp256k1.h>
#include <secp256k1_ecdh.h>
#include "random.h"
#include "examples_util.h"
int main(void) {
unsigned char seckey1[32];
@ -30,12 +29,8 @@ int main(void) {
secp256k1_pubkey pubkey1;
secp256k1_pubkey pubkey2;
/* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create`
* needs a context object initialized for signing, which is why we create
* a context with the SECP256K1_CONTEXT_SIGN flag.
* (The docs for `secp256k1_ecdh` don't require any special context, just
* some initialized context) */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
/* Before we can call actual API functions, we need to create a "context". */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;
@ -116,12 +111,12 @@ int main(void) {
* example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
* TODO: Prevent these writes from being optimized out, as any good compiler
* Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
memset(seckey1, 0, sizeof(seckey1));
memset(seckey2, 0, sizeof(seckey2));
memset(shared_secret1, 0, sizeof(shared_secret1));
memset(shared_secret2, 0, sizeof(shared_secret2));
secure_erase(seckey1, sizeof(seckey1));
secure_erase(seckey2, sizeof(seckey2));
secure_erase(shared_secret1, sizeof(shared_secret1));
secure_erase(shared_secret2, sizeof(shared_secret2));
return 0;
}

View File

@ -13,9 +13,7 @@
#include <secp256k1.h>
#include "random.h"
#include "examples_util.h"
int main(void) {
/* Instead of signing the message directly, we must sign a 32-byte hash.
@ -34,16 +32,12 @@ int main(void) {
unsigned char compressed_pubkey[33];
unsigned char serialized_signature[64];
size_t len;
int is_signature_valid;
int is_signature_valid, is_signature_valid2;
int return_val;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
/* The specification in secp256k1.h states that `secp256k1_ec_pubkey_create` needs
* a context object initialized for signing and `secp256k1_ecdsa_verify` needs
* a context initialized for verification, which is why we create a context
* for both signing and verification with the SECP256K1_CONTEXT_SIGN and
* SECP256K1_CONTEXT_VERIFY flags. */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
/* Before we can call actual API functions, we need to create a "context". */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;
@ -120,18 +114,26 @@ int main(void) {
printf("Signature: ");
print_hex(serialized_signature, sizeof(serialized_signature));
/* This will clear everything from the context and free the memory */
secp256k1_context_destroy(ctx);
/* Bonus example: if all we need is signature verification (and no key
generation or signing), we don't need to use a context created via
secp256k1_context_create(). We can simply use the static (i.e., global)
context secp256k1_context_static. See its description in
include/secp256k1.h for details. */
is_signature_valid2 = secp256k1_ecdsa_verify(secp256k1_context_static,
&sig, msg_hash, &pubkey);
assert(is_signature_valid2 == is_signature_valid);
/* It's best practice to try to clear secrets from memory after using them.
* This is done because some bugs can allow an attacker to leak memory, for
* example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
* TODO: Prevent these writes from being optimized out, as any good compiler
* Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
memset(seckey, 0, sizeof(seckey));
secure_erase(seckey, sizeof(seckey));
return 0;
}

View File

@ -17,7 +17,13 @@
*/
#if defined(_WIN32)
/*
* The defined WIN32_NO_STATUS macro disables return code definitions in
* windows.h, which avoids "macro redefinition" MSVC warnings in ntstatus.h.
*/
#define WIN32_NO_STATUS
#include <windows.h>
#undef WIN32_NO_STATUS
#include <ntstatus.h>
#include <bcrypt.h>
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
@ -71,3 +77,32 @@ static void print_hex(unsigned char* data, size_t size) {
}
printf("\n");
}
#if defined(_MSC_VER)
// For SecureZeroMemory
#include <Windows.h>
#endif
/* Cleanses memory to prevent leaking sensitive info. Won't be optimized out. */
static void secure_erase(void *ptr, size_t len) {
#if defined(_MSC_VER)
/* SecureZeroMemory is guaranteed not to be optimized out by MSVC. */
SecureZeroMemory(ptr, len);
#elif defined(__GNUC__)
/* We use a memory barrier that scares the compiler away from optimizing out the memset.
*
* Quoting Adam Langley <agl@google.com> in commit ad1907fe73334d6c696c8539646c21b11178f20f
* in BoringSSL (ISC License):
* As best as we can tell, this is sufficient to break any optimisations that
* might try to eliminate "superfluous" memsets.
* This method used in memzero_explicit() the Linux kernel, too. Its advantage is that it is
* pretty efficient, because the compiler can still implement the memset() efficiently,
* just not remove it entirely. See "Dead Store Elimination (Still) Considered Harmful" by
* Yang et al. (USENIX Security 2017) for more background.
*/
memset(ptr, 0, len);
__asm__ __volatile__("" : : "r"(ptr) : "memory");
#else
void *(*volatile const volatile_memset)(void *, int, size_t) = memset;
volatile_memset(ptr, 0, len);
#endif
}

View File

@ -14,11 +14,13 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <secp256k1.h>
#include <secp256k1_schnorrsig.h>
#include <secp256k1_musig.h>
#include "random.h"
#include "examples_util.h"
struct signer_secrets {
secp256k1_keypair keypair;
@ -34,7 +36,7 @@ struct signer {
/* Number of public keys involved in creating the aggregate signature */
#define N_SIGNERS 3
/* Create a key pair, store it in signer_secrets->keypair and signer->pubkey */
int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {
static int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer) {
unsigned char seckey[32];
while (1) {
if (!fill_random(seckey, sizeof(seckey))) {
@ -53,7 +55,7 @@ int create_keypair(const secp256k1_context* ctx, struct signer_secrets *signer_s
/* Tweak the pubkey corresponding to the provided keyagg cache, update the cache
* and return the tweaked aggregate pk. */
int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) {
static int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k1_musig_keyagg_cache *cache) {
secp256k1_pubkey output_pk;
unsigned char plain_tweak[32] = "this could be a BIP32 tweak....";
unsigned char xonly_tweak[32] = "this could be a taproot tweak..";
@ -91,7 +93,7 @@ int tweak(const secp256k1_context* ctx, secp256k1_xonly_pubkey *agg_pk, secp256k
}
/* Sign a message hash with the given key pairs and store the result in sig */
int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const secp256k1_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) {
static int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, struct signer *signer, const secp256k1_musig_keyagg_cache *cache, const unsigned char *msg32, unsigned char *sig64) {
int i;
const secp256k1_musig_pubnonce *pubnonces[N_SIGNERS];
const secp256k1_musig_partial_sig *partial_sigs[N_SIGNERS];
@ -170,8 +172,8 @@ int sign(const secp256k1_context* ctx, struct signer_secrets *signer_secrets, st
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);
/* Create a secp256k1 context */
ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
printf("Creating key pairs......");
for (i = 0; i < N_SIGNERS; i++) {
if (!create_keypair(ctx, &signer_secrets[i], &signers[i])) {

View File

@ -15,7 +15,7 @@
#include <secp256k1_extrakeys.h>
#include <secp256k1_schnorrsig.h>
#include "random.h"
#include "examples_util.h"
int main(void) {
unsigned char msg[12] = "Hello World!";
@ -26,16 +26,12 @@ int main(void) {
unsigned char auxiliary_rand[32];
unsigned char serialized_pubkey[32];
unsigned char signature[64];
int is_signature_valid;
int is_signature_valid, is_signature_valid2;
int return_val;
secp256k1_xonly_pubkey pubkey;
secp256k1_keypair keypair;
/* The specification in secp256k1_extrakeys.h states that `secp256k1_keypair_create`
* needs a context object initialized for signing. And in secp256k1_schnorrsig.h
* they state that `secp256k1_schnorrsig_verify` needs a context initialized for
* verification, which is why we create a context for both signing and verification
* with the SECP256K1_CONTEXT_SIGN and SECP256K1_CONTEXT_VERIFY flags. */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
/* Before we can call actual API functions, we need to create a "context". */
secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
if (!fill_random(randomize, sizeof(randomize))) {
printf("Failed to generate randomness\n");
return 1;
@ -139,14 +135,22 @@ int main(void) {
/* This will clear everything from the context and free the memory */
secp256k1_context_destroy(ctx);
/* Bonus example: if all we need is signature verification (and no key
generation or signing), we don't need to use a context created via
secp256k1_context_create(). We can simply use the static (i.e., global)
context secp256k1_context_static. See its description in
include/secp256k1.h for details. */
is_signature_valid2 = secp256k1_schnorrsig_verify(secp256k1_context_static,
signature, msg_hash, 32, &pubkey);
assert(is_signature_valid2 == is_signature_valid);
/* It's best practice to try to clear secrets from memory after using them.
* This is done because some bugs can allow an attacker to leak memory, for
* example through "out of bounds" array access (see Heartbleed), Or the OS
* swapping them to disk. Hence, we overwrite the secret key buffer with zeros.
*
* TODO: Prevent these writes from being optimized out, as any good compiler
* Here we are preventing these writes from being optimized out, as any good compiler
* will remove any writes that aren't used. */
memset(seckey, 0, sizeof(seckey));
secure_erase(seckey, sizeof(seckey));
return 0;
}

View File

@ -7,7 +7,7 @@ extern "C" {
#include <stddef.h>
/* Unless explicitly stated all pointer arguments must not be NULL.
/** Unless explicitly stated all pointer arguments must not be NULL.
*
* The following rules specify the order of arguments in API calls:
*
@ -24,15 +24,19 @@ extern "C" {
* 5. Opaque data pointers follow the function pointer they are to be passed to.
*/
/** Opaque data structure that holds context information (precomputed tables etc.).
/** Opaque data structure that holds context information
*
* The purpose of context structures is to cache large precomputed data tables
* that are expensive to construct, and also to maintain the randomization data
* for blinding.
* The primary purpose of context objects is to store randomization data for
* enhanced protection against side-channel leakage. This protection is only
* effective if the context is randomized after its creation. See
* secp256k1_context_create for creation of contexts and
* secp256k1_context_randomize for randomization.
*
* Do not create a new context object for each operation, as construction is
* far slower than all other API calls (~100 times slower than an ECDSA
* verification).
* A secondary purpose of context objects is to store pointers to callback
* functions that the library will call when certain error states arise. See
* secp256k1_context_set_error_callback as well as
* secp256k1_context_set_illegal_callback for details. Future library versions
* may use context objects for additional purposes.
*
* A constructed context can safely be used from multiple threads
* simultaneously, but API calls that take a non-const pointer to a context
@ -45,7 +49,7 @@ extern "C" {
*/
typedef struct secp256k1_context_struct secp256k1_context;
/** Opaque data structure that holds rewriteable "scratch space"
/** Opaque data structure that holds rewritable "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
@ -118,19 +122,7 @@ typedef int (*secp256k1_nonce_function)(
# endif
# endif
# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
# if SECP256K1_GNUC_PREREQ(2,7)
# define SECP256K1_INLINE __inline__
# elif (defined(_MSC_VER))
# define SECP256K1_INLINE __inline
# else
# define SECP256K1_INLINE
# endif
# else
# define SECP256K1_INLINE inline
# endif
/** When this header is used at build-time the SECP256K1_BUILD define needs to be set
/* When this header is used at build-time the SECP256K1_BUILD define needs to be set
* to correctly setup export attributes and nullness checks. This is normally done
* by secp256k1.c but to guard against this header being included before secp256k1.c
* has had a chance to set the define (e.g. via test harnesses that just includes
@ -141,23 +133,41 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_NO_BUILD
#endif
#ifndef SECP256K1_API
# if defined(_WIN32)
# ifdef SECP256K1_BUILD
# define SECP256K1_API __declspec(dllexport)
# else
# define SECP256K1_API
/* Symbol visibility. */
#if defined(_WIN32)
/* GCC for Windows (e.g., MinGW) accepts the __declspec syntax
* for MSVC compatibility. A __declspec declaration implies (but is not
* exactly equivalent to) __attribute__ ((visibility("default"))), and so we
* actually want __declspec even on GCC, see "Microsoft Windows Function
* Attributes" in the GCC manual and the recommendations in
* https://gcc.gnu.org/wiki/Visibility. */
# if defined(SECP256K1_BUILD)
# if defined(DLL_EXPORT) || defined(SECP256K1_DLL_EXPORT)
/* Building libsecp256k1 as a DLL.
* 1. If using Libtool, it defines DLL_EXPORT automatically.
* 2. In other cases, SECP256K1_DLL_EXPORT must be defined. */
# define SECP256K1_API extern __declspec (dllexport)
# endif
# elif defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
# define SECP256K1_API __attribute__ ((visibility ("default")))
/* The user must define SECP256K1_STATIC when consuming libsecp256k1 as a static
* library on Windows. */
# elif !defined(SECP256K1_STATIC)
/* Consuming libsecp256k1 as a DLL. */
# define SECP256K1_API extern __declspec (dllimport)
# endif
#endif
#ifndef SECP256K1_API
# if defined(__GNUC__) && (__GNUC__ >= 4) && defined(SECP256K1_BUILD)
/* Building libsecp256k1 on non-Windows using GCC or compatible. */
# define SECP256K1_API extern __attribute__ ((visibility ("default")))
# else
# define SECP256K1_API
/* All cases not captured above. */
# define SECP256K1_API extern
# endif
#endif
/**Warning attributes
* NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out
* some paranoid null checks. */
/* Warning attributes
* NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out
* some paranoid null checks. */
# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4)
# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
# else
@ -169,7 +179,7 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_ARG_NONNULL(_x)
# endif
/** Attribute for marking functions, types, and variables as deprecated */
/* Attribute for marking functions, types, and variables as deprecated */
#if !defined(SECP256K1_BUILD) && defined(__has_attribute)
# if __has_attribute(__deprecated__)
# define SECP256K1_DEPRECATED(_msg) __attribute__ ((__deprecated__(_msg)))
@ -180,22 +190,26 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_DEPRECATED(_msg)
#endif
/** All flags' lower 8 bits indicate what they're for. Do not use directly. */
/* All flags' lower 8 bits indicate what they're for. Do not use directly. */
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1)
/** The higher bits contain the actual data. Do not use directly. */
/* 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, secp256k1_context_preallocated_size, and
/** Context flags to pass to secp256k1_context_create, secp256k1_context_preallocated_size, and
* secp256k1_context_preallocated_create. */
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
/** Deprecated context flags. These flags are treated equivalent to SECP256K1_CONTEXT_NONE. */
#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)
/* Testing flag. Do not use. */
#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. */
#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
@ -208,25 +222,68 @@ typedef int (*secp256k1_nonce_function)(
#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.
/** A built-in constant secp256k1 context object with static storage duration, to be
* used in conjunction with secp256k1_selftest.
*
* This context object offers *only limited functionality* , i.e., it cannot be used
* for API functions that perform computations involving secret keys, e.g., signing
* and public key generation. If this restriction applies to a specific API function,
* it is mentioned in its documentation. See secp256k1_context_create if you need a
* full context object that supports all functionality offered by the library.
*
* It is highly recommended to call secp256k1_selftest before using this context.
*/
SECP256K1_API extern const secp256k1_context *secp256k1_context_no_precomp;
SECP256K1_API const secp256k1_context *secp256k1_context_static;
/** Deprecated alias for secp256k1_context_static. */
SECP256K1_API const secp256k1_context *secp256k1_context_no_precomp
SECP256K1_DEPRECATED("Use secp256k1_context_static instead");
/** Perform basic self tests (to be used in conjunction with secp256k1_context_static)
*
* This function performs self tests that detect some serious usage errors and
* similar conditions, e.g., when the library is compiled for the wrong endianness.
* This is a last resort measure to be used in production. The performed tests are
* very rudimentary and are not intended as a replacement for running the test
* binaries.
*
* It is highly recommended to call this before using secp256k1_context_static.
* It is not necessary to call this function before using a context created with
* secp256k1_context_create (or secp256k1_context_preallocated_create), which will
* take care of performing the self tests.
*
* If the tests fail, this function will call the default error handler to abort the
* program (see secp256k1_context_set_error_callback).
*/
SECP256K1_API void secp256k1_selftest(void);
/** 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.
* memory allocation entirely, see secp256k1_context_static and the functions in
* secp256k1_preallocated.h.
*
* Returns: a newly created context object.
* In: flags: which parts of the context to initialize.
* In: flags: Always set to SECP256K1_CONTEXT_NONE (see below).
*
* See also secp256k1_context_randomize.
* The only valid non-deprecated flag in recent library versions is
* SECP256K1_CONTEXT_NONE, which will create a context sufficient for all functionality
* offered by the library. All other (deprecated) flags will be treated as equivalent
* to the SECP256K1_CONTEXT_NONE flag. Though the flags parameter primarily exists for
* historical reasons, future versions of the library may introduce new flags.
*
* If the context is intended to be used for API functions that perform computations
* involving secret keys, e.g., signing and public key generation, then it is highly
* recommended to call secp256k1_context_randomize on the context before calling
* those API functions. This will provide enhanced protection against side-channel
* leakage, see secp256k1_context_randomize for details.
*
* Do not create a new context object for each operation, as construction and
* randomization can take non-negligible time.
*/
SECP256K1_API secp256k1_context* secp256k1_context_create(
SECP256K1_API secp256k1_context *secp256k1_context_create(
unsigned int flags
) SECP256K1_WARN_UNUSED_RESULT;
@ -236,11 +293,14 @@ SECP256K1_API secp256k1_context* secp256k1_context_create(
* 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.
*
* Cloning secp256k1_context_static is not possible, and should not be emulated by
* the caller (e.g., using memcpy). Create a new context instead.
*
* Returns: a newly created context object.
* Args: ctx: an existing context to copy
* Args: ctx: an existing context to copy (not secp256k1_context_static)
*/
SECP256K1_API secp256k1_context* secp256k1_context_clone(
const secp256k1_context* ctx
SECP256K1_API secp256k1_context *secp256k1_context_clone(
const secp256k1_context *ctx
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
/** Destroy a secp256k1 context object (created in dynamically allocated memory).
@ -255,9 +315,10 @@ SECP256K1_API secp256k1_context* secp256k1_context_clone(
*
* Args: ctx: an existing context to destroy, constructed using
* secp256k1_context_create or secp256k1_context_clone
* (i.e., not secp256k1_context_static).
*/
SECP256K1_API void secp256k1_context_destroy(
secp256k1_context* ctx
secp256k1_context *ctx
) SECP256K1_ARG_NONNULL(1);
/** Set a callback function to be called when an illegal argument is passed to
@ -281,8 +342,8 @@ SECP256K1_API void secp256k1_context_destroy(
* 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);
* - 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
@ -298,13 +359,16 @@ SECP256K1_API void secp256k1_context_destroy(
* See also secp256k1_context_set_error_callback.
*/
SECP256K1_API void secp256k1_context_set_illegal_callback(
secp256k1_context* ctx,
void (*fun)(const char* message, void* data),
const void* data
secp256k1_context *ctx,
void (*fun)(const char *message, void *data),
const void *data
) SECP256K1_ARG_NONNULL(1);
/** Set a callback function to be called when an internal consistency check
* fails. The default is crashing.
* fails.
*
* The default callback writes an error message to stderr and calls abort
* to abort the program.
*
* This can only trigger in case of a hardware failure, miscompilation,
* memory corruption, serious bug in the library, or other error would can
@ -323,9 +387,9 @@ SECP256K1_API void secp256k1_context_set_illegal_callback(
* See also secp256k1_context_set_illegal_callback.
*/
SECP256K1_API void secp256k1_context_set_error_callback(
secp256k1_context* ctx,
void (*fun)(const char* message, void* data),
const void* data
secp256k1_context *ctx,
void (*fun)(const char *message, void *data),
const void *data
) SECP256K1_ARG_NONNULL(1);
/** Create a secp256k1 scratch space object.
@ -335,8 +399,8 @@ SECP256K1_API void secp256k1_context_set_error_callback(
* 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,
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space *secp256k1_scratch_space_create(
const secp256k1_context *ctx,
size_t size
) SECP256K1_ARG_NONNULL(1);
@ -347,8 +411,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_sc
* scratch: space to destroy
*/
SECP256K1_API void secp256k1_scratch_space_destroy(
const secp256k1_context* ctx,
secp256k1_scratch_space* scratch
const secp256k1_context *ctx,
secp256k1_scratch_space *scratch
) SECP256K1_ARG_NONNULL(1);
/** Parse a variable-length public key into the pubkey object.
@ -366,8 +430,8 @@ SECP256K1_API void secp256k1_scratch_space_destroy(
* byte 0x06 or 0x07) format public keys.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
const secp256k1_context* ctx,
secp256k1_pubkey* pubkey,
const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const unsigned char *input,
size_t inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -388,10 +452,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
* compressed format, otherwise SECP256K1_EC_UNCOMPRESSED.
*/
SECP256K1_API int secp256k1_ec_pubkey_serialize(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *output,
size_t *outputlen,
const secp256k1_pubkey* pubkey,
const secp256k1_pubkey *pubkey,
unsigned int flags
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
@ -405,9 +469,9 @@ SECP256K1_API int secp256k1_ec_pubkey_serialize(
* pubkey2: second public key to compare
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
const secp256k1_context* ctx,
const secp256k1_pubkey* pubkey1,
const secp256k1_pubkey* pubkey2
const secp256k1_context *ctx,
const secp256k1_pubkey *pubkey1,
const secp256k1_pubkey *pubkey2
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Parse an ECDSA signature in compact (64 bytes) format.
@ -422,12 +486,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_cmp(
* encoding is invalid. R and S with value 0 are allowed in the encoding.
*
* After the call, sig will always be initialized. If parsing failed or R or
* S are zero, the resulting sig value is guaranteed to fail validation for any
* message and public key.
* S are zero, the resulting sig value is guaranteed to fail verification for
* any message and public key.
*/
SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
const secp256k1_context *ctx,
secp256k1_ecdsa_signature *sig,
const unsigned char *input64
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -443,12 +507,12 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_compact(
* encoded numbers are out of range.
*
* After the call, sig will always be initialized. If parsing failed or the
* encoded numbers are out of range, signature validation with it is
* encoded numbers are out of range, signature verification with it is
* guaranteed to fail for every message and public key.
*/
SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
const secp256k1_context *ctx,
secp256k1_ecdsa_signature *sig,
const unsigned char *input,
size_t inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -465,10 +529,10 @@ SECP256K1_API int secp256k1_ecdsa_signature_parse_der(
* In: sig: a pointer to an initialized signature object
*/
SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *output,
size_t *outputlen,
const secp256k1_ecdsa_signature* sig
const secp256k1_ecdsa_signature *sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Serialize an ECDSA signature in compact (64 byte) format.
@ -481,16 +545,16 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_der(
* See secp256k1_ecdsa_signature_parse_compact for details about the encoding.
*/
SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *output64,
const secp256k1_ecdsa_signature* sig
const secp256k1_ecdsa_signature *sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Verify an ECDSA signature.
*
* Returns: 1: correct signature
* 0: incorrect or unparseable signature
* Args: ctx: a secp256k1 context object, initialized for verification.
* Args: ctx: a secp256k1 context object.
* In: sig: the signature being verified.
* msghash32: the 32-byte message hash being verified.
* The verifier must make sure to apply a cryptographic
@ -507,12 +571,12 @@ SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact(
*
* If you need to accept ECDSA signatures from sources that do not obey this
* rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to
* validation, but be aware that doing so results in malleable signatures.
* verification, but be aware that doing so results in malleable signatures.
*
* For details, see the comments for that function.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
const secp256k1_ecdsa_signature *sig,
const unsigned char *msghash32,
const secp256k1_pubkey *pubkey
@ -560,7 +624,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
* secp256k1_ecdsa_signature_normalize must be called before verification.
*/
SECP256K1_API int secp256k1_ecdsa_signature_normalize(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_ecdsa_signature *sigout,
const secp256k1_ecdsa_signature *sigin
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3);
@ -569,16 +633,16 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize(
* If a data pointer is passed, it is assumed to be a pointer to 32 bytes of
* extra entropy.
*/
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default;
SECP256K1_API const secp256k1_nonce_function secp256k1_nonce_function_default;
/** Create an ECDSA signature.
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
* Args: ctx: pointer to a context object, initialized for signing.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: sig: pointer to an array where the signature will be placed.
* In: msghash32: the 32-byte message hash being signed.
* seckey: pointer to a 32-byte secret key.
@ -593,7 +657,7 @@ SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_def
* secp256k1_ecdsa_signature_normalize for more details.
*/
SECP256K1_API int secp256k1_ecdsa_sign(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_ecdsa_signature *sig,
const unsigned char *msghash32,
const unsigned char *seckey,
@ -614,7 +678,7 @@ SECP256K1_API int secp256k1_ecdsa_sign(
* In: seckey: pointer to a 32-byte secret key.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
@ -622,12 +686,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
*
* Returns: 1: secret was valid, public key stores.
* 0: secret was invalid, try again.
* Args: ctx: pointer to a context object, initialized for signing.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: pubkey: pointer to the created public key.
* In: seckey: pointer to a 32-byte secret key.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -643,14 +707,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
* seckey will be set to some unspecified value.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_negate(
const secp256k1_context* ctx,
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,
const secp256k1_context *ctx,
unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2)
SECP256K1_DEPRECATED("Use secp256k1_ec_seckey_negate instead");
@ -662,7 +726,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate(
* In/Out: pubkey: pointer to the public key to be negated.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
@ -676,13 +740,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate(
* invalid according to secp256k1_ec_seckey_verify, this
* function returns 0. seckey will be set to some unspecified
* value if this function returns 0.
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128).
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
* random 32-byte tweaks, the chance of being invalid is
* negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *seckey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -690,7 +754,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_add(
/** 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,
const secp256k1_context *ctx,
unsigned char *seckey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
@ -701,16 +765,16 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
* 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.
* Args: ctx: pointer to a context object.
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
* invalid value if this function returns 0.
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
* secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128).
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
* random 32-byte tweaks, the chance of being invalid is
* negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -729,7 +793,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
* is negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *seckey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -737,7 +801,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_tweak_mul(
/** 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,
const secp256k1_context *ctx,
unsigned char *seckey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3)
@ -746,7 +810,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
/** Tweak a public key by multiplying it by a tweak value.
*
* Returns: 0 if the arguments are invalid. 1 otherwise.
* Args: ctx: pointer to a context object initialized for validation.
* Args: ctx: pointer to a context object.
* In/Out: pubkey: pointer to a public key object. pubkey will be set to an
* invalid value if this function returns 0.
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according to
@ -755,38 +819,45 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
* is negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Updates the context randomization to protect against side-channel leakage.
* Returns: 1: randomization successfully updated or nothing to randomize
/** Randomizes the context to provide enhanced protection against side-channel leakage.
*
* Returns: 1: randomization successful
* 0: error
* Args: ctx: pointer to a context object.
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state)
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* In: seed32: pointer to a 32-byte random seed (NULL resets to initial state).
*
* While secp256k1 code is written to be constant-time no matter what secret
* values are, it's possible that a future compiler may output code which isn't,
* While secp256k1 code is written and tested to be constant-time no matter what
* secret values are, it is possible that a compiler may output code which is not,
* and also that the CPU may not emit the same radio frequencies or draw the same
* amount power for all values.
* amount of power for all values. Randomization of the context shields against
* side-channel observations which aim to exploit secret-dependent behaviour in
* certain computations which involve secret keys.
*
* This function provides a seed which is combined into the blinding value: that
* blinding value is added before each multiplication (and removed afterwards) so
* that it does not affect function results, but shields against attacks which
* rely on any input-dependent behaviour.
* It is highly recommended to call this function on contexts returned from
* secp256k1_context_create or secp256k1_context_clone (or from the corresponding
* functions in secp256k1_preallocated.h) before using these contexts to call API
* functions that perform computations involving secret keys, e.g., signing and
* public key generation. It is possible to call this function more than once on
* the same context, and doing so before every few computations involving secret
* keys is recommended as a defense-in-depth measure. Randomization of the static
* context secp256k1_context_static is not supported.
*
* 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 secp256k1_context_preallocated_create or
* secp256k1_context_clone, resp.), and you may call this repeatedly afterwards.
* Currently, the random seed is mainly used for blinding multiplications of a
* secret scalar with the elliptic curve base point. Multiplications of this
* kind are performed by exactly those API functions which are documented to
* require a context that is not secp256k1_context_static. As a rule of thumb,
* these are all functions which take a secret key (or a keypair) as an input.
* A notable exception to that rule is the ECDH module, which relies on a different
* kind of elliptic curve point multiplication and thus does not benefit from
* enhanced protection against side-channel leakage currently.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
secp256k1_context* ctx,
secp256k1_context *ctx,
const unsigned char *seed32
) SECP256K1_ARG_NONNULL(1);
@ -800,9 +871,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize(
* n: the number of public keys to add together (must be at least 1).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *out,
const secp256k1_pubkey * const * ins,
const secp256k1_pubkey * const *ins,
size_t n
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -823,7 +894,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
* msglen: length of the message array
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *hash32,
const unsigned char *tag,
size_t taglen,

View File

@ -22,7 +22,7 @@ typedef struct secp256k1_bppp_generators secp256k1_bppp_generators;
* in a separate commit to make review easier.
*/
SECP256K1_API secp256k1_bppp_generators *secp256k1_bppp_generators_create(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
size_t n
) SECP256K1_ARG_NONNULL(1);
@ -32,9 +32,9 @@ SECP256K1_API secp256k1_bppp_generators *secp256k1_bppp_generators_create(
* In: data: data that came from `secp256k1_bppp_generators_serialize`
* data_len: the length of the `data` buffer
*/
SECP256K1_API secp256k1_bppp_generators* secp256k1_bppp_generators_parse(
const secp256k1_context* ctx,
const unsigned char* data,
SECP256K1_API secp256k1_bppp_generators *secp256k1_bppp_generators_parse(
const secp256k1_context *ctx,
const unsigned char *data,
size_t data_len
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
@ -50,9 +50,9 @@ SECP256K1_API secp256k1_bppp_generators* secp256k1_bppp_generators_parse(
* add it in the follow-up rangeproof PR.
*/
SECP256K1_API int secp256k1_bppp_generators_serialize(
const secp256k1_context* ctx,
const secp256k1_bppp_generators* gen,
unsigned char* data,
const secp256k1_context *ctx,
const secp256k1_bppp_generators *gen,
unsigned char *data,
size_t *data_len
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
@ -62,8 +62,8 @@ SECP256K1_API int secp256k1_bppp_generators_serialize(
* (can be NULL, in which case this function is a no-op)
*/
SECP256K1_API void secp256k1_bppp_generators_destroy(
const secp256k1_context* ctx,
secp256k1_bppp_generators* gen
const secp256k1_context *ctx,
secp256k1_bppp_generators *gen
) SECP256K1_ARG_NONNULL(1);
# ifdef __cplusplus

View File

@ -27,11 +27,11 @@ typedef int (*secp256k1_ecdh_hash_function)(
/** An implementation of SHA256 hash function that applies to compressed public key.
* Populates the output parameter with 32 bytes. */
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_sha256;
/** A default ECDH hash function (currently equal to secp256k1_ecdh_hash_function_sha256).
* Populates the output parameter with 32 bytes. */
SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
SECP256K1_API const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_function_default;
/** Compute an EC Diffie-Hellman secret in constant time
*
@ -48,7 +48,7 @@ SECP256K1_API extern const secp256k1_ecdh_hash_function secp256k1_ecdh_hash_func
* (can be NULL for secp256k1_ecdh_hash_function_sha256).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *output,
const secp256k1_pubkey *pubkey,
const unsigned char *seckey,

View File

@ -5,6 +5,8 @@
extern "C" {
#endif
#include "secp256k1.h"
/** This module implements single signer ECDSA adaptor signatures following
* "One-Time Verifiably Encrypted Signatures A.K.A. Adaptor Signatures" by
* Lloyd Fournier
@ -59,7 +61,7 @@ typedef int (*secp256k1_nonce_function_hardened_ecdsa_adaptor)(
* assumed to be a pointer to 32 bytes of auxiliary random data as defined in BIP-340.
* The hash will be tagged with algo after removing all terminating null bytes.
*/
SECP256K1_API extern const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor;
SECP256K1_API const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor;
/** Encrypted Signing
*
@ -69,7 +71,7 @@ SECP256K1_API extern const secp256k1_nonce_function_hardened_ecdsa_adaptor secp2
* this file and applied the suggested countermeasures.
*
* Returns: 1 on success, 0 on failure
* Args: ctx: a secp256k1 context object, initialized for signing
* Args: ctx: a secp256k1 context object (not secp256k1_context_static)
* Out: adaptor_sig162: pointer to 162 byte to store the returned signature
* In: seckey32: pointer to 32 byte secret key that will be used for
* signing
@ -84,7 +86,7 @@ SECP256K1_API extern const secp256k1_nonce_function_hardened_ecdsa_adaptor secp2
* as per BIP-340.
*/
SECP256K1_API int secp256k1_ecdsa_adaptor_encrypt(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *adaptor_sig162,
unsigned char *seckey32,
const secp256k1_pubkey *enckey,
@ -99,7 +101,7 @@ SECP256K1_API int secp256k1_ecdsa_adaptor_encrypt(
* and the completed ECDSA signature.
*
* Returns: 1 on success, 0 on failure
* Args: ctx: a secp256k1 context object, initialized for verification
* Args: ctx: a secp256k1 context object
* In: adaptor_sig162: pointer to 162-byte signature to verify
* pubkey: pointer to the public key corresponding to the secret key
* used for signing
@ -107,7 +109,7 @@ SECP256K1_API int secp256k1_ecdsa_adaptor_encrypt(
* enckey: pointer to the adaptor encryption public key
*/
SECP256K1_API int secp256k1_ecdsa_adaptor_verify(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
const unsigned char *adaptor_sig162,
const secp256k1_pubkey *pubkey,
const unsigned char *msg32,
@ -126,7 +128,7 @@ SECP256K1_API int secp256k1_ecdsa_adaptor_verify(
* adaptor_sig162: pointer to 162-byte adaptor sig
*/
SECP256K1_API int secp256k1_ecdsa_adaptor_decrypt(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_ecdsa_signature *sig,
const unsigned char *deckey32,
const unsigned char *adaptor_sig162
@ -138,7 +140,7 @@ SECP256K1_API int secp256k1_ecdsa_adaptor_decrypt(
* signature.
*
* Returns: 1 on success, 0 on failure
* Args: ctx: a secp256k1 context object, initialized for signing
* Args: ctx: a secp256k1 context object (not secp256k1_context_static)
* Out: deckey32: pointer to 32-byte adaptor decryption key for the adaptor
* encryption public key
* In: sig: pointer to ECDSA signature to recover the adaptor decryption
@ -148,7 +150,7 @@ SECP256K1_API int secp256k1_ecdsa_adaptor_decrypt(
* enckey: pointer to the adaptor encryption public key
*/
SECP256K1_API int secp256k1_ecdsa_adaptor_recover(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *deckey32,
const secp256k1_ecdsa_signature *sig,
const unsigned char *adaptor_sig162,

View File

@ -40,9 +40,9 @@ typedef struct {
*
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_parse(
const secp256k1_context* ctx,
secp256k1_ecdsa_s2c_opening* opening,
const unsigned char* input33
const secp256k1_context *ctx,
secp256k1_ecdsa_s2c_opening *opening,
const unsigned char *input33
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize a sign-to-contract opening into a byte sequence.
@ -54,16 +54,16 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_parse
* In: opening: a pointer to an initialized `secp256k1_ecdsa_s2c_opening`
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_serialize(
const secp256k1_context* ctx,
unsigned char* output33,
const secp256k1_ecdsa_s2c_opening* opening
const secp256k1_context *ctx,
unsigned char *output33,
const secp256k1_ecdsa_s2c_opening *opening
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Same as secp256k1_ecdsa_sign, but s2c_data32 is committed to inside the nonce
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the private key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Args: ctx: pointer to a context object (not secp256k1_context_static)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* s2c_opening: if non-NULL, pointer to an secp256k1_ecdsa_s2c_opening structure to populate
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
@ -71,12 +71,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_opening_seria
* s2c_data32: pointer to a 32-byte data to commit to in the nonce (cannot be NULL)
*/
SECP256K1_API int secp256k1_ecdsa_s2c_sign(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
secp256k1_ecdsa_s2c_opening* s2c_opening,
const unsigned char* msg32,
const unsigned char* seckey,
const unsigned char* s2c_data32
const secp256k1_context *ctx,
secp256k1_ecdsa_signature *sig,
secp256k1_ecdsa_s2c_opening *s2c_opening,
const unsigned char *msg32,
const unsigned char *seckey,
const unsigned char *s2c_data32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6);
/** Verify a sign-to-contract commitment.
@ -84,13 +84,13 @@ SECP256K1_API int secp256k1_ecdsa_s2c_sign(
* Returns: 1: the signature contains a commitment to data32 (though it does
* not necessarily need to be a valid siganture!)
* 0: incorrect opening
* Args: ctx: a secp256k1 context object, initialized for verification.
* Args: ctx: a secp256k1 context object
* In: sig: the signature containing the sign-to-contract commitment (cannot be NULL)
* data32: the 32-byte data that was committed to (cannot be NULL)
* opening: pointer to the opening created during signing (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_verify_commit(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
const secp256k1_ecdsa_signature *sig,
const unsigned char *data32,
const secp256k1_ecdsa_s2c_opening *opening
@ -165,15 +165,15 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_s2c_verify_commit
* commitment.
*/
SECP256K1_API int secp256k1_ecdsa_anti_exfil_host_commit(
const secp256k1_context* ctx,
unsigned char* rand_commitment32,
const unsigned char* rand32
const secp256k1_context *ctx,
unsigned char *rand_commitment32,
const unsigned char *rand32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Compute signer's original nonce. Part of the ECDSA Anti-Exfil Protocol.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Args: ctx: pointer to a context object (not secp256k1_context_static)
* Out: s2c_opening: pointer to an s2c_opening where the signer's public nonce will be
* placed. (cannot be NULL)
* In: msg32: the 32-byte message hash to be signed (cannot be NULL)
@ -181,11 +181,11 @@ SECP256K1_API int secp256k1_ecdsa_anti_exfil_host_commit(
* rand_commitment32: the 32-byte randomness commitment from the host (cannot be NULL)
*/
SECP256K1_API int secp256k1_ecdsa_anti_exfil_signer_commit(
const secp256k1_context* ctx,
secp256k1_ecdsa_s2c_opening* s2c_opening,
const unsigned char* msg32,
const unsigned char* seckey32,
const unsigned char* rand_commitment32
const secp256k1_context *ctx,
secp256k1_ecdsa_s2c_opening *s2c_opening,
const unsigned char *msg32,
const unsigned char *seckey32,
const unsigned char *rand_commitment32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Same as secp256k1_ecdsa_sign, but commits to host randomness in the nonce. Part of the
@ -193,25 +193,25 @@ SECP256K1_API int secp256k1_ecdsa_anti_exfil_signer_commit(
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the private key was invalid.
* Args: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* Args: ctx: pointer to a context object (not secp256k1_context_static)
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* host_data32: pointer to 32-byte host-provided randomness (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_anti_exfil_sign(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
const unsigned char* msg32,
const unsigned char* seckey,
const unsigned char* host_data32
const secp256k1_context *ctx,
secp256k1_ecdsa_signature *sig,
const unsigned char *msg32,
const unsigned char *seckey,
const unsigned char *host_data32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Verify a signature was correctly constructed using the ECDSA Anti-Exfil Protocol.
*
* Returns: 1: the signature is valid and contains a commitment to host_data32
* 0: incorrect opening
* Args: ctx: a secp256k1 context object, initialized for verification.
* Args: ctx: a secp256k1 context object
* In: sig: the signature produced by the signer (cannot be NULL)
* msghash32: the 32-byte message hash being verified (cannot be NULL)
* pubkey: pointer to the signer's public key (cannot be NULL)
@ -219,7 +219,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_anti_exfil_sign(
* opening: the s2c opening provided by the signer (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_anti_exfil_host_verify(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
const secp256k1_ecdsa_signature *sig,
const unsigned char *msg32,
const secp256k1_pubkey *pubkey,

View File

@ -0,0 +1,200 @@
#ifndef SECP256K1_ELLSWIFT_H
#define SECP256K1_ELLSWIFT_H
#include "secp256k1.h"
#ifdef __cplusplus
extern "C" {
#endif
/* This module provides an implementation of ElligatorSwift as well as a
* version of x-only ECDH using it (including compatibility with BIP324).
*
* ElligatorSwift is described in https://eprint.iacr.org/2022/759 by
* Chavez-Saab, Rodriguez-Henriquez, and Tibouchi. It permits encoding
* uniformly chosen public keys as 64-byte arrays which are indistinguishable
* from uniformly random arrays.
*
* Let f be the function from pairs of field elements to point X coordinates,
* defined as follows (all operations modulo p = 2^256 - 2^32 - 977)
* f(u,t):
* - Let C = 0xa2d2ba93507f1df233770c2a797962cc61f6d15da14ecd47d8d27ae1cd5f852,
* a square root of -3.
* - If u=0, set u=1 instead.
* - If t=0, set t=1 instead.
* - If u^3 + t^2 + 7 = 0, multiply t by 2.
* - Let X = (u^3 + 7 - t^2) / (2 * t)
* - Let Y = (X + t) / (C * u)
* - Return the first in [u + 4 * Y^2, (-X/Y - u) / 2, (X/Y - u) / 2] that is an
* X coordinate on the curve (at least one of them is, for any u and t).
*
* Then an ElligatorSwift encoding of x consists of the 32-byte big-endian
* encodings of field elements u and t concatenated, where f(u,t) = x.
* The encoding algorithm is described in the paper, and effectively picks a
* uniformly random pair (u,t) among those which encode x.
*
* If the Y coordinate is relevant, it is given the same parity as t.
*
* Changes w.r.t. the the paper:
* - The u=0, t=0, and u^3+t^2+7=0 conditions result in decoding to the point
* at infinity in the paper. Here they are remapped to finite points.
* - The paper uses an additional encoding bit for the parity of y. Here the
* parity of t is used (negating t does not affect the decoded x coordinate,
* so this is possible).
*
* For mathematical background about the scheme, see the doc/ellswift.md file.
*/
/** A pointer to a function used by secp256k1_ellswift_xdh to hash the shared X
* coordinate along with the encoded public keys to a uniform shared secret.
*
* Returns: 1 if a shared secret was successfully computed.
* 0 will cause secp256k1_ellswift_xdh to fail and return 0.
* Other return values are not allowed, and the behaviour of
* secp256k1_ellswift_xdh is undefined for other return values.
* Out: output: pointer to an array to be filled by the function
* In: x32: pointer to the 32-byte serialized X coordinate
* of the resulting shared point (will not be NULL)
* ell_a64: pointer to the 64-byte encoded public key of party A
* (will not be NULL)
* ell_b64: pointer to the 64-byte encoded public key of party B
* (will not be NULL)
* data: arbitrary data pointer that is passed through
*/
typedef int (*secp256k1_ellswift_xdh_hash_function)(
unsigned char *output,
const unsigned char *x32,
const unsigned char *ell_a64,
const unsigned char *ell_b64,
void *data
);
/** An implementation of an secp256k1_ellswift_xdh_hash_function which uses
* SHA256(prefix64 || ell_a64 || ell_b64 || x32), where prefix64 is the 64-byte
* array pointed to by data. */
SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_prefix;
/** An implementation of an secp256k1_ellswift_xdh_hash_function compatible with
* BIP324. It returns H_tag(ell_a64 || ell_b64 || x32), where H_tag is the
* BIP340 tagged hash function with tag "bip324_ellswift_xonly_ecdh". Equivalent
* to secp256k1_ellswift_xdh_hash_function_prefix with prefix64 set to
* SHA256("bip324_ellswift_xonly_ecdh")||SHA256("bip324_ellswift_xonly_ecdh").
* The data argument is ignored. */
SECP256K1_API const secp256k1_ellswift_xdh_hash_function secp256k1_ellswift_xdh_hash_function_bip324;
/** Construct a 64-byte ElligatorSwift encoding of a given pubkey.
*
* Returns: 1 always.
* Args: ctx: pointer to a context object
* Out: ell64: pointer to a 64-byte array to be filled
* In: pubkey: a pointer to a secp256k1_pubkey containing an
* initialized public key
* rnd32: pointer to 32 bytes of randomness
*
* It is recommended that rnd32 consists of 32 uniformly random bytes, not
* known to any adversary trying to detect whether public keys are being
* encoded, though 16 bytes of randomness (padded to an array of 32 bytes,
* e.g., with zeros) suffice to make the result indistinguishable from
* uniform. The randomness in rnd32 must not be a deterministic function of
* the pubkey (it can be derived from the private key, though).
*
* It is not guaranteed that the computed encoding is stable across versions
* of the library, even if all arguments to this function (including rnd32)
* are the same.
*
* This function runs in variable time.
*/
SECP256K1_API int secp256k1_ellswift_encode(
const secp256k1_context *ctx,
unsigned char *ell64,
const secp256k1_pubkey *pubkey,
const unsigned char *rnd32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Decode a 64-bytes ElligatorSwift encoded public key.
*
* Returns: always 1
* Args: ctx: pointer to a context object
* Out: pubkey: pointer to a secp256k1_pubkey that will be filled
* In: ell64: pointer to a 64-byte array to decode
*
* This function runs in variable time.
*/
SECP256K1_API int secp256k1_ellswift_decode(
const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const unsigned char *ell64
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Compute an ElligatorSwift public key for a secret key.
*
* Returns: 1: secret was valid, public key was stored.
* 0: secret was invalid, try again.
* Args: ctx: pointer to a context object
* Out: ell64: pointer to a 64-byte array to receive the ElligatorSwift
* public key
* In: seckey32: pointer to a 32-byte secret key
* auxrnd32: (optional) pointer to 32 bytes of randomness
*
* Constant time in seckey and auxrnd32, but not in the resulting public key.
*
* It is recommended that auxrnd32 contains 32 uniformly random bytes, though
* it is optional (and does result in encodings that are indistinguishable from
* uniform even without any auxrnd32). It differs from the (mandatory) rnd32
* argument to secp256k1_ellswift_encode in this regard.
*
* This function can be used instead of calling secp256k1_ec_pubkey_create
* followed by secp256k1_ellswift_encode. It is safer, as it uses the secret
* key as entropy for the encoding (supplemented with auxrnd32, if provided).
*
* Like secp256k1_ellswift_encode, this function does not guarantee that the
* computed encoding is stable across versions of the library, even if all
* arguments (including auxrnd32) are the same.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_create(
const secp256k1_context *ctx,
unsigned char *ell64,
const unsigned char *seckey32,
const unsigned char *auxrnd32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Given a private key, and ElligatorSwift public keys sent in both directions,
* compute a shared secret using x-only Elliptic Curve Diffie-Hellman (ECDH).
*
* Returns: 1: shared secret was successfully computed
* 0: secret was invalid or hashfp returned 0
* Args: ctx: pointer to a context object.
* Out: output: pointer to an array to be filled by hashfp.
* In: ell_a64: pointer to the 64-byte encoded public key of party A
* (will not be NULL)
* ell_b64: pointer to the 64-byte encoded public key of party B
* (will not be NULL)
* seckey32: a pointer to our 32-byte secret key
* party: boolean indicating which party we are: zero if we are
* party A, non-zero if we are party B. seckey32 must be
* the private key corresponding to that party's ell_?64.
* This correspondence is not checked.
* hashfp: pointer to a hash function.
* data: arbitrary data pointer passed through to hashfp.
*
* Constant time in seckey32.
*
* This function is more efficient than decoding the public keys, and performing
* ECDH on them.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ellswift_xdh(
const secp256k1_context *ctx,
unsigned char *output,
const unsigned char *ell_a64,
const unsigned char *ell_b64,
const unsigned char *seckey32,
int party,
secp256k1_ellswift_xdh_hash_function hashfp,
void *data
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7);
#ifdef __cplusplus
}
#endif
#endif /* SECP256K1_ELLSWIFT_H */

View File

@ -45,8 +45,8 @@ typedef struct {
* In: input32: pointer to a serialized xonly_pubkey.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
const secp256k1_context* ctx,
secp256k1_xonly_pubkey* pubkey,
const secp256k1_context *ctx,
secp256k1_xonly_pubkey *pubkey,
const unsigned char *input32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -59,9 +59,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_parse(
* In: pubkey: a pointer to a secp256k1_xonly_pubkey containing an initialized public key.
*/
SECP256K1_API int secp256k1_xonly_pubkey_serialize(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *output32,
const secp256k1_xonly_pubkey* pubkey
const secp256k1_xonly_pubkey *pubkey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Compare two x-only public keys using lexicographic order
@ -74,9 +74,9 @@ SECP256K1_API int secp256k1_xonly_pubkey_serialize(
* pubkey2: second public key to compare
*/
SECP256K1_API int secp256k1_xonly_pubkey_cmp(
const secp256k1_context* ctx,
const secp256k1_xonly_pubkey* pk1,
const secp256k1_xonly_pubkey* pk2
const secp256k1_context *ctx,
const secp256k1_xonly_pubkey *pk1,
const secp256k1_xonly_pubkey *pk2
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Converts a secp256k1_pubkey into a secp256k1_xonly_pubkey.
@ -91,7 +91,7 @@ SECP256K1_API int secp256k1_xonly_pubkey_cmp(
* In: pubkey: pointer to a public key that is converted.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubkey(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_xonly_pubkey *xonly_pubkey,
int *pk_parity,
const secp256k1_pubkey *pubkey
@ -108,17 +108,17 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_from_pubke
* 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.
* Args: ctx: pointer to a context object.
* Out: output_pubkey: pointer to a public key to store the result. Will be set
* to an invalid value if this function returns 0.
* In: internal_pubkey: pointer to an x-only pubkey to apply the tweak to.
* tweak32: pointer to a 32-byte tweak. If the tweak is invalid
* according to secp256k1_ec_seckey_verify, this function
* returns 0. For uniformly random 32-byte arrays the
* chance of being invalid is negligible (around 1 in 2^128).
* tweak32: pointer to a 32-byte tweak, which must be valid
* according to secp256k1_ec_seckey_verify or 32 zero
* bytes. For uniformly random 32-byte tweaks, the chance of
* being invalid is negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *output_pubkey,
const secp256k1_xonly_pubkey *internal_pubkey,
const unsigned char *tweak32
@ -137,7 +137,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
*
* 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.
* Args: ctx: pointer to a context object.
* In: tweaked_pubkey32: pointer to a serialized xonly_pubkey.
* tweaked_pk_parity: the parity of the tweaked pubkey (whose serialization
* is passed in as tweaked_pubkey32). This must match the
@ -148,7 +148,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add(
* tweak32: pointer to a 32-byte tweak.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_check(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
const unsigned char *tweaked_pubkey32,
int tweaked_pk_parity,
const secp256k1_xonly_pubkey *internal_pubkey,
@ -159,12 +159,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_xonly_pubkey_tweak_add_
*
* 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.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: keypair: pointer to the created keypair.
* In: seckey: pointer to a 32-byte secret key.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_keypair *keypair,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -177,7 +177,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_create(
* In: keypair: pointer to a keypair.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *seckey,
const secp256k1_keypair *keypair
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -185,13 +185,12 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_sec(
/** Get the public key from a keypair.
*
* Returns: 1 always.
* Args: ctx: pointer to a context object.
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to
* the keypair public key. If not, it's set to an invalid value.
* Args: ctx: pointer to a context object.
* Out: pubkey: pointer to a pubkey object, set to the keypair public key.
* In: keypair: pointer to a keypair.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const secp256k1_keypair *keypair
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -203,15 +202,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_pub(
*
* Returns: 1 always.
* Args: ctx: pointer to a context object.
* Out: pubkey: pointer to an xonly_pubkey object. If 1 is returned, it is set
* to the keypair public key after converting it to an
* xonly_pubkey. If not, it's set to an invalid value.
* Out: pubkey: pointer to an xonly_pubkey object, set to the keypair
* public key after converting it to an xonly_pubkey.
* pk_parity: Ignored if NULL. Otherwise, pointer to an integer that will be set to the
* pk_parity argument of secp256k1_xonly_pubkey_from_pubkey.
* In: keypair: pointer to a keypair.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_xonly_pubkey *pubkey,
int *pk_parity,
const secp256k1_keypair *keypair
@ -228,16 +226,16 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_pub(
* 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.
* Args: ctx: pointer to a context object.
* In/Out: keypair: pointer to a keypair to apply the tweak to. Will be set to
* an invalid value if this function returns 0.
* In: tweak32: pointer to a 32-byte tweak. If the tweak is invalid according
* to secp256k1_ec_seckey_verify, this function returns 0. For
* uniformly random 32-byte arrays the chance of being invalid
* is negligible (around 1 in 2^128).
* In: tweak32: pointer to a 32-byte tweak, which must be valid according to
* secp256k1_ec_seckey_verify or 32 zero bytes. For uniformly
* random 32-byte tweaks, the chance of being invalid is
* negligible (around 1 in 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_keypair *keypair,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -253,9 +251,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_keypair_xonly_tweak_add
* pubkey2: second public key to compare
*/
SECP256K1_API int secp256k1_pubkey_cmp(
const secp256k1_context* ctx,
const secp256k1_pubkey* pk1,
const secp256k1_pubkey* pk2
const secp256k1_context *ctx,
const secp256k1_pubkey *pk1,
const secp256k1_pubkey *pk2
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Sort public keys using lexicographic order of their compressed
@ -268,7 +266,7 @@ SECP256K1_API int secp256k1_pubkey_cmp(
* n_pubkeys: number of elements in the pubkeys array
*/
SECP256K1_API int secp256k1_pubkey_sort(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
const secp256k1_pubkey **pubkeys,
size_t n_pubkeys
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);

View File

@ -24,7 +24,7 @@ typedef struct {
/**
* Static constant generator 'h' maintained for historical reasons.
*/
SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h;
SECP256K1_API const secp256k1_generator *secp256k1_generator_h;
/** Parse a 33-byte generator byte sequence into a generator object.
*
@ -34,8 +34,8 @@ SECP256K1_API extern const secp256k1_generator *secp256k1_generator_h;
* 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 secp256k1_context *ctx,
secp256k1_generator *gen,
const unsigned char *input
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -47,9 +47,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_parse(
* In: gen: a pointer to a generator
*/
SECP256K1_API int secp256k1_generator_serialize(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *output,
const secp256k1_generator* gen
const secp256k1_generator *gen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Generate a generator for the curve.
@ -66,8 +66,8 @@ SECP256K1_API int secp256k1_generator_serialize(
* or to the base generator G.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate(
const secp256k1_context* ctx,
secp256k1_generator* gen,
const secp256k1_context *ctx,
secp256k1_generator *gen,
const unsigned char *seed32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -75,7 +75,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate(
*
* Returns: 0 in the highly unlikely case the seed is not acceptable or when
* blind is out of range. 1 otherwise.
* Args: ctx: a secp256k1 context object, initialized for signing
* Args: ctx: a secp256k1 context object (not secp256k1_context_static)
* Out: gen: a generator object
* In: seed32: a 32-byte seed
* blind32: a 32-byte secret value to blind the generator with.
@ -85,8 +85,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_generator_generate(
* 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 secp256k1_context *ctx,
secp256k1_generator *gen,
const unsigned char *seed32,
const unsigned char *blind32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
@ -112,8 +112,8 @@ typedef struct {
* 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 secp256k1_context *ctx,
secp256k1_pedersen_commitment *commit,
const unsigned char *input
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -126,9 +126,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commitment_par
* initialized commitment
*/
SECP256K1_API int secp256k1_pedersen_commitment_serialize(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *output,
const secp256k1_pedersen_commitment* commit
const secp256k1_pedersen_commitment *commit
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Generate a pedersen commitment.
@ -136,7 +136,7 @@ SECP256K1_API int secp256k1_pedersen_commitment_serialize(
* 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)
* In: ctx: pointer to a context object (not secp256k1_context_static)
* blind: pointer to a 32-byte blinding factor (cannot be NULL)
* value: unsigned 64-bit integer value to commit to.
* gen: additional generator 'h'
@ -145,7 +145,7 @@ SECP256K1_API int secp256k1_pedersen_commitment_serialize(
* 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,
const secp256k1_context *ctx,
secp256k1_pedersen_commitment *commit,
const unsigned char *blind,
uint64_t value,
@ -164,7 +164,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_commit(
* 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,
const secp256k1_context *ctx,
unsigned char *blind_out,
const unsigned char * const *blinds,
size_t n,
@ -188,10 +188,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum(
*
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
const secp256k1_context* ctx,
const secp256k1_pedersen_commitment * const* commits,
const secp256k1_context *ctx,
const secp256k1_pedersen_commitment * const *commits,
size_t pcnt,
const secp256k1_pedersen_commitment * const* ncommits,
const secp256k1_pedersen_commitment * const *ncommits,
size_t ncnt
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
@ -226,10 +226,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_verify_tally(
* 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 secp256k1_context *ctx,
const uint64_t *value,
const unsigned char* const* generator_blind,
unsigned char* const* blinding_factor,
const unsigned char * const *generator_blind,
unsigned char * const *blinding_factor,
size_t n_total,
size_t n_inputs
);

View File

@ -108,8 +108,8 @@ typedef struct {
* In: in66: pointer to the 66-byte nonce to be parsed
*/
SECP256K1_API int secp256k1_musig_pubnonce_parse(
const secp256k1_context* ctx,
secp256k1_musig_pubnonce* nonce,
const secp256k1_context *ctx,
secp256k1_musig_pubnonce *nonce,
const unsigned char *in66
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -121,9 +121,9 @@ SECP256K1_API int secp256k1_musig_pubnonce_parse(
* In: nonce: pointer to the nonce
*/
SECP256K1_API int secp256k1_musig_pubnonce_serialize(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *out66,
const secp256k1_musig_pubnonce* nonce
const secp256k1_musig_pubnonce *nonce
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Parse an aggregate public nonce.
@ -134,8 +134,8 @@ SECP256K1_API int secp256k1_musig_pubnonce_serialize(
* In: in66: pointer to the 66-byte nonce to be parsed
*/
SECP256K1_API int secp256k1_musig_aggnonce_parse(
const secp256k1_context* ctx,
secp256k1_musig_aggnonce* nonce,
const secp256k1_context *ctx,
secp256k1_musig_aggnonce *nonce,
const unsigned char *in66
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -147,9 +147,9 @@ SECP256K1_API int secp256k1_musig_aggnonce_parse(
* In: nonce: pointer to the nonce
*/
SECP256K1_API int secp256k1_musig_aggnonce_serialize(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *out66,
const secp256k1_musig_aggnonce* nonce
const secp256k1_musig_aggnonce *nonce
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize a MuSig partial signature
@ -160,9 +160,9 @@ SECP256K1_API int secp256k1_musig_aggnonce_serialize(
* In: sig: pointer to the signature
*/
SECP256K1_API int secp256k1_musig_partial_sig_serialize(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *out32,
const secp256k1_musig_partial_sig* sig
const secp256k1_musig_partial_sig *sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Parse a MuSig partial signature.
@ -177,8 +177,8 @@ SECP256K1_API int secp256k1_musig_partial_sig_serialize(
* guaranteed to fail for every message and public key.
*/
SECP256K1_API int secp256k1_musig_partial_sig_parse(
const secp256k1_context* ctx,
secp256k1_musig_partial_sig* sig,
const secp256k1_context *ctx,
secp256k1_musig_partial_sig *sig,
const unsigned char *in32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -192,7 +192,7 @@ SECP256K1_API int secp256k1_musig_partial_sig_parse(
* does not affect the aggregate public key.
*
* Returns: 0 if the arguments are invalid, 1 otherwise
* Args: ctx: pointer to a context object initialized for verification
* Args: ctx: pointer to a context object
* scratch: should be NULL because it is not yet implemented. If it
* was implemented then the scratch space would be used to
* compute the aggregate pubkey by multiexponentiation.
@ -211,11 +211,11 @@ SECP256K1_API int secp256k1_musig_partial_sig_parse(
* n_pubkeys: length of pubkeys array. Must be greater than 0.
*/
SECP256K1_API int secp256k1_musig_pubkey_agg(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_scratch_space *scratch,
secp256k1_xonly_pubkey *agg_pk,
secp256k1_musig_keyagg_cache *keyagg_cache,
const secp256k1_pubkey * const* pubkeys,
const secp256k1_pubkey * const *pubkeys,
size_t n_pubkeys
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(5);
@ -232,7 +232,7 @@ SECP256K1_API int secp256k1_musig_pubkey_agg(
* `musig_pubkey_agg`
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *agg_pk,
secp256k1_musig_keyagg_cache *keyagg_cache
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -260,7 +260,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(
* 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
* Args: ctx: pointer to a context object
* Out: output_pubkey: pointer to a public key to store the result. Will be set
* to an invalid value if this function returns 0. If you
* do not need it, this arg can be NULL.
@ -273,7 +273,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_get(
* 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_add(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *output_pubkey,
secp256k1_musig_keyagg_cache *keyagg_cache,
const unsigned char *tweak32
@ -300,7 +300,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_a
* 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
* Args: ctx: pointer to a context object
* Out: output_pubkey: pointer to a public key to store the result. Will be set
* to an invalid value if this function returns 0. If you
* do not need it, this arg can be NULL.
@ -313,7 +313,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_ec_tweak_a
* 2^128).
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_tweak_add(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *output_pubkey,
secp256k1_musig_keyagg_cache *keyagg_cache,
const unsigned char *tweak32
@ -345,7 +345,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea
* Note that using the same seckey for multiple MuSig sessions is fine.
*
* Returns: 0 if the arguments are invalid and 1 otherwise
* Args: ctx: pointer to a context object, initialized for signing
* Args: ctx: pointer to a context object (not secp256k1_context_static)
* Out: secnonce: pointer to a structure to store the secret nonce
* pubnonce: pointer to a structure to store the public nonce
* In: session_id32: a 32-byte session_id32 as explained above. Must be unique to this
@ -365,7 +365,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_pubkey_xonly_twea
* derivation function (can be NULL)
*/
SECP256K1_API int secp256k1_musig_nonce_gen(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_musig_secnonce *secnonce,
secp256k1_musig_pubnonce *pubnonce,
const unsigned char *session_id32,
@ -393,9 +393,9 @@ SECP256K1_API int secp256k1_musig_nonce_gen(
* greater than 0.
*/
SECP256K1_API int secp256k1_musig_nonce_agg(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_musig_aggnonce *aggnonce,
const secp256k1_musig_pubnonce * const* pubnonces,
const secp256k1_musig_pubnonce * const *pubnonces,
size_t n_pubnonces
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -409,7 +409,7 @@ SECP256K1_API int secp256k1_musig_nonce_agg(
*
* Returns: 0 if the arguments are invalid or if some signer sent invalid
* pubnonces, 1 otherwise
* Args: ctx: pointer to a context object, initialized for verification
* Args: ctx: pointer to a context object
* Out: session: pointer to a struct to store the session
* In: aggnonce: pointer to an aggregate public nonce object that is the
* output of musig_nonce_agg
@ -421,7 +421,7 @@ SECP256K1_API int secp256k1_musig_nonce_agg(
* signature protocol (can be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_musig_session *session,
const secp256k1_musig_aggnonce *aggnonce,
const unsigned char *msg32,
@ -462,7 +462,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_nonce_process(
* musig_nonce_process
*/
SECP256K1_API int secp256k1_musig_partial_sign(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_musig_partial_sig *partial_sig,
secp256k1_musig_secnonce *secnonce,
const secp256k1_keypair *keypair,
@ -492,7 +492,7 @@ SECP256K1_API int secp256k1_musig_partial_sign(
*
* Returns: 0 if the arguments are invalid or the partial signature does not
* verify, 1 otherwise
* Args ctx: pointer to a context object, initialized for verification
* Args ctx: pointer to a context object
* In: partial_sig: pointer to partial signature to verify, sent by
* the signer associated with `pubnonce` and `pubkey`
* pubnonce: public nonce of the signer in the signing session
@ -503,7 +503,7 @@ SECP256K1_API int secp256k1_musig_partial_sign(
* `musig_nonce_process`
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verify(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
const secp256k1_musig_partial_sig *partial_sig,
const secp256k1_musig_pubnonce *pubnonce,
const secp256k1_pubkey *pubkey,
@ -524,10 +524,10 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif
* greater than 0.
*/
SECP256K1_API int secp256k1_musig_partial_sig_agg(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *sig64,
const secp256k1_musig_session *session,
const secp256k1_musig_partial_sig * const* partial_sigs,
const secp256k1_musig_partial_sig * const *partial_sigs,
size_t n_sigs
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
@ -544,7 +544,7 @@ SECP256K1_API int secp256k1_musig_partial_sig_agg(
* musig_nonce_process
*/
SECP256K1_API int secp256k1_musig_nonce_parity(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
int *nonce_parity,
const secp256k1_musig_session *session
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -566,7 +566,7 @@ SECP256K1_API int secp256k1_musig_nonce_parity(
* session used for producing the pre-signature
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_adapt(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *sig64,
const unsigned char *pre_sig64,
const unsigned char *sec_adaptor32,
@ -595,7 +595,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_adapt(
* session used for producing sig64
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_adaptor(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *sec_adaptor32,
const unsigned char *sig64,
const unsigned char *pre_sig64,

View File

@ -58,11 +58,13 @@ SECP256K1_API size_t secp256k1_context_preallocated_size(
* bytes, as detailed above.
* flags: which parts of the context to initialize.
*
* See secp256k1_context_create (in secp256k1.h) for further details.
*
* See also secp256k1_context_randomize (in secp256k1.h)
* and secp256k1_context_preallocated_destroy.
*/
SECP256K1_API secp256k1_context* secp256k1_context_preallocated_create(
void* prealloc,
SECP256K1_API secp256k1_context *secp256k1_context_preallocated_create(
void *prealloc,
unsigned int flags
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
@ -73,7 +75,7 @@ SECP256K1_API secp256k1_context* secp256k1_context_preallocated_create(
* In: ctx: an existing context to copy.
*/
SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
const secp256k1_context* ctx
const secp256k1_context *ctx
) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT;
/** Copy a secp256k1 context object into caller-provided memory.
@ -86,15 +88,18 @@ SECP256K1_API size_t secp256k1_context_preallocated_clone_size(
* the lifetime of this context object, see the description of
* secp256k1_context_preallocated_create for details.
*
* Cloning secp256k1_context_static is not possible, and should not be emulated by
* the caller (e.g., using memcpy). Create a new context instead.
*
* Returns: a newly created context object.
* Args: ctx: an existing context to copy.
* Args: ctx: an existing context to copy (not secp256k1_context_static).
* In: prealloc: a pointer to a rewritable contiguous block of memory of
* size at least secp256k1_context_preallocated_size(flags)
* bytes, as detailed above.
*/
SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
const secp256k1_context* ctx,
void* prealloc
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
@ -115,10 +120,11 @@ SECP256K1_API secp256k1_context* secp256k1_context_preallocated_clone(
*
* Args: ctx: an existing context to destroy, constructed using
* secp256k1_context_preallocated_create or
* secp256k1_context_preallocated_clone.
* secp256k1_context_preallocated_clone
* (i.e., not secp256k1_context_static).
*/
SECP256K1_API void secp256k1_context_preallocated_destroy(
secp256k1_context* ctx
secp256k1_context *ctx
) SECP256K1_ARG_NONNULL(1);
#ifdef __cplusplus

View File

@ -22,7 +22,7 @@ extern "C" {
/** 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)
* In: ctx: pointer to a context object (not secp256k1_context_static)
* 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.
@ -33,7 +33,7 @@ extern "C" {
* 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,
const secp256k1_context *ctx,
uint64_t *min_value,
uint64_t *max_value,
const secp256k1_pedersen_commitment *commit,
@ -41,13 +41,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
size_t plen,
const unsigned char *extra_commit,
size_t extra_commit_len,
const secp256k1_generator* gen
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)
* In: ctx: pointer to a context object (not secp256k1_context_static)
* 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.
@ -65,7 +65,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_verify(
* 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,
const secp256k1_context *ctx,
unsigned char *blind_out,
uint64_t *value_out,
unsigned char *message_out,
@ -84,7 +84,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
/** 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)
* In: ctx: pointer to a context object (not secp256k1_context_static)
* 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.
@ -110,7 +110,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_rewind(
*
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *proof,
size_t *plen,
uint64_t min_value,
@ -139,7 +139,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_sign(
* 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,
const secp256k1_context *ctx,
int *exp,
int *mantissa,
uint64_t *min_value,
@ -170,7 +170,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_rangeproof_info(
* min_bits: the value that will be passed as `min_bits` for the proof.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT size_t secp256k1_rangeproof_max_size(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
uint64_t max_value,
int min_bits
) SECP256K1_ARG_NONNULL(1);

View File

@ -34,8 +34,8 @@ typedef struct {
* recid: the recovery id (0, 1, 2 or 3)
*/
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
const secp256k1_context* ctx,
secp256k1_ecdsa_recoverable_signature* sig,
const secp256k1_context *ctx,
secp256k1_ecdsa_recoverable_signature *sig,
const unsigned char *input64,
int recid
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
@ -48,9 +48,9 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact(
* In: sigin: a pointer to a recoverable signature.
*/
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
const secp256k1_context* ctx,
secp256k1_ecdsa_signature* sig,
const secp256k1_ecdsa_recoverable_signature* sigin
const secp256k1_context *ctx,
secp256k1_ecdsa_signature *sig,
const secp256k1_ecdsa_recoverable_signature *sigin
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
@ -62,17 +62,17 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert(
* In: sig: a pointer to an initialized signature object.
*/
SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *output64,
int *recid,
const secp256k1_ecdsa_recoverable_signature* sig
const secp256k1_ecdsa_recoverable_signature *sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Create a recoverable ECDSA signature.
*
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
* Args: ctx: pointer to a context object, initialized for signing.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: sig: pointer to an array where the signature will be placed.
* In: msghash32: the 32-byte message hash being signed.
* seckey: pointer to a 32-byte secret key.
@ -82,7 +82,7 @@ SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact(
* (can be NULL for secp256k1_nonce_function_default).
*/
SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_ecdsa_recoverable_signature *sig,
const unsigned char *msghash32,
const unsigned char *seckey,
@ -94,13 +94,13 @@ SECP256K1_API int secp256k1_ecdsa_sign_recoverable(
*
* Returns: 1: public key successfully recovered (which guarantees a correct signature).
* 0: otherwise.
* Args: ctx: pointer to a context object, initialized for verification.
* Args: ctx: pointer to a context object.
* Out: pubkey: pointer to the recovered public key.
* In: sig: pointer to initialized signature that supports pubkey recovery.
* msghash32: the 32-byte message hash assumed to be signed.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_pubkey *pubkey,
const secp256k1_ecdsa_recoverable_signature *sig,
const unsigned char *msghash32

View File

@ -61,7 +61,7 @@ typedef int (*secp256k1_nonce_function_hardened)(
* Therefore, to create BIP-340 compliant signatures, algo must be set to
* "BIP0340/nonce" and algolen to 13.
*/
SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
SECP256K1_API const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;
/** Data structure that contains additional arguments for schnorrsig_sign_custom.
*
@ -82,7 +82,7 @@ SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_fun
typedef struct {
unsigned char magic[4];
secp256k1_nonce_function_hardened noncefp;
void* ndata;
void *ndata;
} secp256k1_schnorrsig_extraparams;
#define SECP256K1_SCHNORRSIG_EXTRAPARAMS_MAGIC { 0xda, 0x6f, 0xb3, 0x8c }
@ -106,7 +106,7 @@ typedef struct {
* signatures from being valid in multiple contexts by accident.
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object, initialized for signing.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: sig64: pointer to a 64-byte array to store the serialized signature.
* In: msg32: the 32-byte message being signed.
* keypair: pointer to an initialized keypair.
@ -117,7 +117,7 @@ typedef struct {
* argument and for guidance if randomness is expensive.
*/
SECP256K1_API int secp256k1_schnorrsig_sign32(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *sig64,
const unsigned char *msg32,
const secp256k1_keypair *keypair,
@ -127,7 +127,7 @@ SECP256K1_API int secp256k1_schnorrsig_sign32(
/** Same as secp256k1_schnorrsig_sign32, but DEPRECATED. Will be removed in
* future versions. */
SECP256K1_API int secp256k1_schnorrsig_sign(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *sig64,
const unsigned char *msg32,
const secp256k1_keypair *keypair,
@ -141,15 +141,23 @@ SECP256K1_API int secp256k1_schnorrsig_sign(
* variable length messages and accepts a pointer to an extraparams object that
* allows customizing signing by passing additional arguments.
*
* Creates the same signatures as schnorrsig_sign if msglen is 32 and the
* extraparams.ndata is the same as aux_rand32.
* Equivalent to secp256k1_schnorrsig_sign32(..., aux_rand32) if msglen is 32
* and extraparams is initialized as follows:
* ```
* secp256k1_schnorrsig_extraparams extraparams = SECP256K1_SCHNORRSIG_EXTRAPARAMS_INIT;
* extraparams.ndata = (unsigned char*)aux_rand32;
* ```
*
* Returns 1 on success, 0 on failure.
* Args: ctx: pointer to a context object (not secp256k1_context_static).
* Out: sig64: pointer to a 64-byte array to store the serialized signature.
* In: msg: the message being signed. Can only be NULL if msglen is 0.
* msglen: length of the message
* extraparams: pointer to a extraparams object (can be NULL)
* msglen: length of the message.
* keypair: pointer to an initialized keypair.
* extraparams: pointer to an extraparams object (can be NULL).
*/
SECP256K1_API int secp256k1_schnorrsig_sign_custom(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *sig64,
const unsigned char *msg,
size_t msglen,
@ -161,14 +169,14 @@ SECP256K1_API int secp256k1_schnorrsig_sign_custom(
*
* Returns: 1: correct signature
* 0: incorrect signature
* Args: ctx: a secp256k1 context object, initialized for verification.
* Args: ctx: a secp256k1 context object.
* In: sig64: pointer to the 64-byte signature to verify.
* msg: the message being verified. Can only be NULL if msglen is 0.
* msglen: length of the message
* pubkey: pointer to an x-only public key to verify with (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
const unsigned char *sig64,
const unsigned char *msg,
size_t msglen,

View File

@ -69,7 +69,7 @@ typedef struct {
* is the number of set bits in the bitmap
*/
SECP256K1_API int secp256k1_surjectionproof_parse(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_surjectionproof *proof,
const unsigned char *input,
size_t inputlen
@ -89,7 +89,7 @@ SECP256K1_API int secp256k1_surjectionproof_parse(
* See secp256k1_surjectionproof_parse for details about the encoding.
*/
SECP256K1_API int secp256k1_surjectionproof_serialize(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *output,
size_t *outputlen,
const secp256k1_surjectionproof *proof
@ -112,8 +112,8 @@ typedef struct {
* proof: a pointer to a proof object
*/
SECP256K1_API size_t secp256k1_surjectionproof_n_total_inputs(
const secp256k1_context* ctx,
const secp256k1_surjectionproof* proof
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
@ -123,8 +123,8 @@ SECP256K1_API size_t secp256k1_surjectionproof_n_total_inputs(
* proof: a pointer to a proof object
*/
SECP256K1_API size_t secp256k1_surjectionproof_n_used_inputs(
const secp256k1_context* ctx,
const secp256k1_surjectionproof* proof
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
@ -134,8 +134,8 @@ SECP256K1_API size_t secp256k1_surjectionproof_n_used_inputs(
* proof: a pointer to a proof object
*/
SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
const secp256k1_context* ctx,
const secp256k1_surjectionproof* proof
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
@ -162,13 +162,13 @@ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
* 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,
const secp256k1_context *ctx,
secp256k1_surjectionproof *proof,
size_t *input_index,
const secp256k1_fixed_asset_tag* fixed_input_tags,
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 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);
@ -198,13 +198,13 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_initial
* 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,
const secp256k1_context *ctx,
secp256k1_surjectionproof **proof_out_p,
size_t *input_index,
const secp256k1_fixed_asset_tag* fixed_input_tags,
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 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);
@ -215,14 +215,14 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_allocat
* In: proof: pointer to secp256k1_surjectionproof struct
*/
SECP256K1_API void secp256k1_surjectionproof_destroy(
secp256k1_surjectionproof* proof
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
* In: ctx: pointer to a context object (not secp256k1_context_static)
* 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
@ -232,11 +232,11 @@ SECP256K1_API void secp256k1_surjectionproof_destroy(
* 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,
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,
const secp256k1_generator *ephemeral_output_tag,
size_t input_index,
const unsigned char *input_blinding_key,
const unsigned char *output_blinding_key
@ -248,18 +248,18 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_generat
* Returns 0: proof was invalid
* 1: proof was valid
*
* In: ctx: pointer to a context object, initialized for signing and verification
* In: ctx: pointer to a context object (not secp256k1_context_static)
* 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,
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
const secp256k1_generator *ephemeral_output_tag
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
#endif

View File

@ -58,7 +58,7 @@ typedef struct {
* to fail validation for any set of keys.
*/
SECP256K1_API int secp256k1_whitelist_signature_parse(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_whitelist_signature *sig,
const unsigned char *input,
size_t input_len
@ -84,7 +84,7 @@ SECP256K1_API size_t secp256k1_whitelist_signature_n_keys(
* See secp256k1_whitelist_signature_parse for details about the encoding.
*/
SECP256K1_API int secp256k1_whitelist_signature_serialize(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
unsigned char *output,
size_t *output_len,
const secp256k1_whitelist_signature *sig
@ -93,7 +93,7 @@ SECP256K1_API int secp256k1_whitelist_signature_serialize(
/** 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
* In: ctx: pointer to a context object (not secp256k1_context_static)
* 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
@ -111,7 +111,7 @@ SECP256K1_API int secp256k1_whitelist_signature_serialize(
* compressed serialization of the key.
*/
SECP256K1_API int secp256k1_whitelist_sign(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
secp256k1_whitelist_signature *sig,
const secp256k1_pubkey *online_pubkeys,
const secp256k1_pubkey *offline_pubkeys,
@ -125,7 +125,7 @@ SECP256K1_API int secp256k1_whitelist_sign(
/** 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
* In: ctx: pointer to a context object (not secp256k1_context_static)
* sig: the signature to be verified
* online_pubkeys: list of all online pubkeys
* offline_pubkeys: list of all offline pubkeys
@ -133,7 +133,7 @@ SECP256K1_API int secp256k1_whitelist_sign(
* sub_pubkey: the key to be whitelisted
*/
SECP256K1_API int secp256k1_whitelist_verify(
const secp256k1_context* ctx,
const secp256k1_context *ctx,
const secp256k1_whitelist_signature *sig,
const secp256k1_pubkey *online_pubkeys,
const secp256k1_pubkey *offline_pubkeys,

View File

@ -9,5 +9,4 @@ URL: https://github.com/bitcoin-core/secp256k1
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -lsecp256k1
Libs.private: @SECP_LIBS@

View File

@ -1,124 +1,156 @@
load("secp256k1_params.sage")
MAX_ORDER = 1000
# Set of (curve) orders we have encountered so far.
orders_done = set()
results = {}
first = True
# Map from (subgroup) orders to [b, int(gen.x), int(gen.y), gen, lambda] for those subgroups.
solutions = {}
# Iterate over curves of the form y^2 = x^3 + B.
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.
# 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")
print()
continue
orders_done.add(n)
# Skip curves isomorphic to the real secp256k1
if n.is_pseudoprime():
print(" - Isomorphic to secp256k1")
assert E.is_isomorphic(C)
print("- Isomorphic to secp256k1")
print()
continue
print("- Finding subgroups")
print("- Finding prime 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
# Map from group_order to a set of independent generators for that order.
curve_gens = {}
# 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):
for g in E.gens():
# Find what prime subgroups of group generated by g exist.
g_order = g.order()
for f, _ in g.order().factor():
# Skip subgroups that have bad size.
if f < 4:
print(f" - Subgroup of size {f}: too small")
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")
if f > MAX_ORDER:
print(f" - Subgroup of size {f}: too large")
continue
G = G * (G.order() // f)
# Construct a generator for that subgroup.
gen = g * (g_order // f)
assert(gen.order() == f)
# Add to set the minimal multiple of gen.
curve_gens.setdefault(f, set()).add(min([j*gen for j in range(1, f)]))
print(f" - Subgroup of size {f}: ok")
for f in sorted(curve_gens.keys()):
print(f"- Constructing group of order {f}")
cbrts = sorted([int(c) for c in Integers(f)(1).nth_root(3, all=true) if c != 1])
gens = list(curve_gens[f])
sol_count = 0
no_endo_count = 0
# Consider all non-zero linear combinations of the independent generators.
for j in range(1, f**len(gens)):
gen = sum(gens[k] * ((j // f**k) % f) for k in range(len(gens)))
assert not gen.is_zero()
assert (f*gen).is_zero()
# 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)
for l in cbrts:
if l*gen == E(BETA*gen[0], gen[1]):
lam = l
break
if lam is None:
print(" - No endomorphism for this subgroup")
break
no_endo_count += 1
else:
sol_count += 1
solutions.setdefault(f, []).append((b, int(gen[0]), int(gen[1]), gen, lam))
# 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])
print(f" - Found {sol_count} generators (plus {no_endo_count} without endomorphism)")
# 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]))
print()
# 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
def output_generator(g, name):
print(f"#define {name} 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("")
def output_b(b):
print(f"#define SECP256K1_B {int(b)}")
print("")
print("")
print("/* To be put in src/group_impl.h: */")
print()
print("To be put in src/group_impl.h:")
print()
print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */")
for f in sorted(solutions.keys()):
# Use as generator/2 the one with lowest b, and lowest (x, y) generator (interpreted as non-negative integers).
b, _, _, HALF_G, lam = min(solutions[f])
output_generator(2 * HALF_G, f"SECP256K1_G_ORDER_{f}")
print("/** Generator for secp256k1, value 'g' defined in")
print(" * \"Standards for Efficient Cryptography\" (SEC2) 2.7.1.")
print(" */")
output_generator(G, "SECP256K1_G")
print("/* These exhaustive group test orders and generators are chosen such that:")
print(" * - The field size is equal to that of secp256k1, so field code is the same.")
print(" * - The curve equation is of the form y^2=x^3+B for some small constant B.")
print(" * - The subgroup has a generator 2*P, where P.x is as small as possible.")
print(f" * - The subgroup has size less than {MAX_ORDER} to permit exhaustive testing.")
print(" * - The subgroup admits an endomorphism of the form lambda*(x,y) == (beta*x,y).")
print(" */")
print("#if defined(EXHAUSTIVE_TEST_ORDER)")
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))
for f in sorted(solutions.keys()):
b, _, _, _, lam = min(solutions[f])
print(f"# {'if' if first else 'elif'} EXHAUSTIVE_TEST_ORDER == {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()
print(f"static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_{f};")
output_b(b)
print()
print("# else")
print("# error No known generator for the specified exhaustive test group order.")
print("# endif")
print("#else")
print()
print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;")
output_b(7)
print()
print("#endif")
print("/* End of section generated by sage/gen_exhaustive_groups.sage. */")
print("")
print("")
print("/* To be put in src/scalar_impl.h: */")
print()
print()
print("To be put in src/scalar_impl.h:")
print()
print("/* Begin of section generated by sage/gen_exhaustive_groups.sage. */")
first = True
for f in sorted(results.keys()):
lam = results[f]["lambda"]
for f in sorted(solutions.keys()):
_, _, _, _, lam = min(solutions[f])
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("")
print("/* End of section generated by sage/gen_exhaustive_groups.sage. */")

View File

@ -198,7 +198,7 @@ def normalize_factor(p):
(8) * (-bx + ax)^3
```
"""
# Assert p is not 0 and that its non-zero coeffients are coprime.
# Assert p is not 0 and that its non-zero coefficients are coprime.
# (We could just work with the primitive part p/p.content() but we want to be
# aware if factor() does not return a primitive part in future sage versions.)
assert p.content() == 1

View File

@ -40,29 +40,26 @@ def formula_secp256k1_gej_add_var(branch, a, b):
s2 = s2 * a.Z
h = -u1
h = h + u2
i = -s1
i = i + s2
i = -s2
i = i + s1
if branch == 2:
r = formula_secp256k1_gej_double_var(a)
return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r)
if branch == 3:
return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity())
i2 = i^2
t = h * b.Z
rz = a.Z * t
h2 = h^2
h2 = -h2
h3 = h2 * h
h = h * b.Z
rz = a.Z * h
t = u1 * h2
rx = t
rx = rx * 2
rx = i^2
rx = rx + h3
rx = -rx
rx = rx + i2
ry = -rx
ry = ry + t
ry = ry * i
rx = rx + t
rx = rx + t
t = t + rx
ry = t * i
h3 = h3 * s1
h3 = -h3
ry = ry + h3
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
@ -80,28 +77,25 @@ def formula_secp256k1_gej_add_ge_var(branch, a, b):
s2 = s2 * a.Z
h = -u1
h = h + u2
i = -s1
i = i + s2
i = -s2
i = i + s1
if (branch == 2):
r = formula_secp256k1_gej_double_var(a)
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)
if (branch == 3):
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())
i2 = i^2
h2 = h^2
h3 = h * h2
rz = a.Z * h
h2 = h^2
h2 = -h2
h3 = h2 * h
t = u1 * h2
rx = t
rx = rx * 2
rx = i^2
rx = rx + h3
rx = -rx
rx = rx + i2
ry = -rx
ry = ry + t
ry = ry * i
rx = rx + t
rx = rx + t
t = t + rx
ry = t * i
h3 = h3 * s1
h3 = -h3
ry = ry + h3
return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
@ -109,14 +103,15 @@ def formula_secp256k1_gej_add_zinv_var(branch, a, b):
"""libsecp256k1's secp256k1_gej_add_zinv_var"""
bzinv = b.Z^(-1)
if branch == 0:
return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a)
if branch == 1:
rinf = b.Infinity
bzinv2 = bzinv^2
bzinv3 = bzinv2 * bzinv
rx = b.X * bzinv2
ry = b.Y * bzinv3
rz = 1
return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz))
return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz, rinf))
if branch == 1:
return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a)
azz = a.Z * bzinv
z12 = azz^2
u1 = a.X
@ -126,29 +121,25 @@ def formula_secp256k1_gej_add_zinv_var(branch, a, b):
s2 = s2 * azz
h = -u1
h = h + u2
i = -s1
i = i + s2
i = -s2
i = i + s1
if branch == 2:
r = formula_secp256k1_gej_double_var(a)
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r)
if branch == 3:
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity())
i2 = i^2
rz = a.Z * h
h2 = h^2
h3 = h * h2
rz = a.Z
rz = rz * h
h2 = -h2
h3 = h2 * h
t = u1 * h2
rx = t
rx = rx * 2
rx = i^2
rx = rx + h3
rx = -rx
rx = rx + i2
ry = -rx
ry = ry + t
ry = ry * i
rx = rx + t
rx = rx + t
t = t + rx
ry = t * i
h3 = h3 * s1
h3 = -h3
ry = ry + h3
return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz))
@ -157,7 +148,7 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
zeroes = {}
nonzeroes = {}
a_infinity = False
if (branch & 4) != 0:
if (branch & 2) != 0:
nonzeroes.update({a.Infinity : 'a_infinite'})
a_infinity = True
else:
@ -176,15 +167,11 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
m_alt = -u2
tt = u1 * m_alt
rr = rr + tt
degenerate = (branch & 3) == 3
if (branch & 1) != 0:
degenerate = (branch & 1) != 0
if degenerate:
zeroes.update({m : 'm_zero'})
else:
nonzeroes.update({m : 'm_nonzero'})
if (branch & 2) != 0:
zeroes.update({rr : 'rr_zero'})
else:
nonzeroes.update({rr : 'rr_nonzero'})
rr_alt = s1
rr_alt = rr_alt * 2
m_alt = m_alt + u1
@ -199,13 +186,6 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
n = m
t = rr_alt^2
rz = a.Z * m_alt
infinity = False
if (branch & 8) != 0:
if not a_infinity:
infinity = True
zeroes.update({rz : 'r.z=0'})
else:
nonzeroes.update({rz : 'r.z!=0'})
t = t + q
rx = t
t = t * 2
@ -218,8 +198,11 @@ def formula_secp256k1_gej_add_ge(branch, a, b):
rx = b.X
ry = b.Y
rz = 1
if infinity:
if (branch & 4) != 0:
zeroes.update({rz : 'r.z = 0'})
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity())
else:
nonzeroes.update({rz : 'r.z != 0'})
return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz))
def formula_secp256k1_gej_add_ge_old(branch, a, b):
@ -289,14 +272,14 @@ if __name__ == "__main__":
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge)
success = success & check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge)
success = success & (not check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old))
if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive":
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43)
success = success & check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 8, formula_secp256k1_gej_add_ge, 43)
success = success & (not check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43))
sys.exit(int(not success))

165
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,165 @@
# Must be included before CMAKE_INSTALL_INCLUDEDIR is used.
include(GNUInstallDirs)
add_library(secp256k1_precomputed OBJECT EXCLUDE_FROM_ALL
precomputed_ecmult.c
precomputed_ecmult_gen.c
)
# Add objects explicitly rather than linking to the object libs to keep them
# from being exported.
add_library(secp256k1 secp256k1.c $<TARGET_OBJECTS:secp256k1_precomputed>)
add_library(secp256k1_asm INTERFACE)
if(SECP256K1_ASM STREQUAL "arm32")
add_library(secp256k1_asm_arm OBJECT EXCLUDE_FROM_ALL)
target_sources(secp256k1_asm_arm PUBLIC
asm/field_10x26_arm.s
)
target_sources(secp256k1 PRIVATE $<TARGET_OBJECTS:secp256k1_asm_arm>)
target_link_libraries(secp256k1_asm INTERFACE secp256k1_asm_arm)
endif()
if(WIN32)
# Define our export symbol only for shared libs.
set_target_properties(secp256k1 PROPERTIES DEFINE_SYMBOL SECP256K1_DLL_EXPORT)
target_compile_definitions(secp256k1 INTERFACE $<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:SECP256K1_STATIC>)
endif()
# Object libs don't know if they're being built for a shared or static lib.
# Grab the PIC property from secp256k1 which knows.
get_target_property(use_pic secp256k1 POSITION_INDEPENDENT_CODE)
set_target_properties(secp256k1_precomputed PROPERTIES POSITION_INDEPENDENT_CODE ${use_pic})
target_include_directories(secp256k1 INTERFACE
# Add the include path for parent projects so that they don't have to manually add it.
$<BUILD_INTERFACE:$<$<NOT:$<BOOL:${PROJECT_IS_TOP_LEVEL}>>:${PROJECT_SOURCE_DIR}/include>>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
# This emulates Libtool to make sure Libtool and CMake agree on the ABI version,
# see below "Calculate the version variables" in build-aux/ltmain.sh.
math(EXPR ${PROJECT_NAME}_soversion "${${PROJECT_NAME}_LIB_VERSION_CURRENT} - ${${PROJECT_NAME}_LIB_VERSION_AGE}")
set_target_properties(secp256k1 PROPERTIES
SOVERSION ${${PROJECT_NAME}_soversion}
)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set_target_properties(secp256k1 PROPERTIES
VERSION ${${PROJECT_NAME}_soversion}.${${PROJECT_NAME}_LIB_VERSION_AGE}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
)
elseif(APPLE)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17)
math(EXPR ${PROJECT_NAME}_compatibility_version "${${PROJECT_NAME}_LIB_VERSION_CURRENT} + 1")
set_target_properties(secp256k1 PROPERTIES
MACHO_COMPATIBILITY_VERSION ${${PROJECT_NAME}_compatibility_version}
MACHO_CURRENT_VERSION ${${PROJECT_NAME}_compatibility_version}.${${PROJECT_NAME}_LIB_VERSION_REVISION}
)
unset(${PROJECT_NAME}_compatibility_version)
elseif(BUILD_SHARED_LIBS)
message(WARNING
"The 'compatibility version' and 'current version' values of the DYLIB "
"will diverge from the values set by the GNU Libtool. To ensure "
"compatibility, it is recommended to upgrade CMake to at least version 3.17."
)
endif()
elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(${PROJECT_NAME}_windows "secp256k1")
if(MSVC)
set(${PROJECT_NAME}_windows "${PROJECT_NAME}")
endif()
set_target_properties(secp256k1 PROPERTIES
ARCHIVE_OUTPUT_NAME "${${PROJECT_NAME}_windows}"
RUNTIME_OUTPUT_NAME "${${PROJECT_NAME}_windows}-${${PROJECT_NAME}_soversion}"
)
unset(${PROJECT_NAME}_windows)
endif()
unset(${PROJECT_NAME}_soversion)
if(SECP256K1_BUILD_BENCHMARK)
add_executable(bench bench.c)
target_link_libraries(bench secp256k1)
add_executable(bench_internal bench_internal.c)
target_link_libraries(bench_internal secp256k1_precomputed secp256k1_asm)
add_executable(bench_ecmult bench_ecmult.c)
target_link_libraries(bench_ecmult secp256k1_precomputed secp256k1_asm)
endif()
if(SECP256K1_BUILD_TESTS)
add_executable(noverify_tests tests.c)
target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm)
add_test(NAME noverify_tests COMMAND noverify_tests)
if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage")
add_executable(tests tests.c)
target_compile_definitions(tests PRIVATE VERIFY)
target_link_libraries(tests secp256k1_precomputed secp256k1_asm)
add_test(NAME tests COMMAND tests)
endif()
endif()
if(SECP256K1_BUILD_EXHAUSTIVE_TESTS)
# Note: do not include secp256k1_precomputed in exhaustive_tests (it uses runtime-generated tables).
add_executable(exhaustive_tests tests_exhaustive.c)
target_link_libraries(exhaustive_tests secp256k1_asm)
target_compile_definitions(exhaustive_tests PRIVATE $<$<NOT:$<CONFIG:Coverage>>:VERIFY>)
add_test(NAME exhaustive_tests COMMAND exhaustive_tests)
endif()
if(SECP256K1_BUILD_CTIME_TESTS)
add_executable(ctime_tests ctime_tests.c)
target_link_libraries(ctime_tests secp256k1)
endif()
if(SECP256K1_INSTALL)
install(TARGETS secp256k1
EXPORT ${PROJECT_NAME}-targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
set(${PROJECT_NAME}_headers
"${PROJECT_SOURCE_DIR}/include/secp256k1.h"
"${PROJECT_SOURCE_DIR}/include/secp256k1_preallocated.h"
)
if(SECP256K1_ENABLE_MODULE_ECDH)
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ecdh.h")
endif()
if(SECP256K1_ENABLE_MODULE_RECOVERY)
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_recovery.h")
endif()
if(SECP256K1_ENABLE_MODULE_EXTRAKEYS)
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_extrakeys.h")
endif()
if(SECP256K1_ENABLE_MODULE_SCHNORRSIG)
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_schnorrsig.h")
endif()
if(SECP256K1_ENABLE_MODULE_ELLSWIFT)
list(APPEND ${PROJECT_NAME}_headers "${PROJECT_SOURCE_DIR}/include/secp256k1_ellswift.h")
endif()
install(FILES ${${PROJECT_NAME}_headers}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
install(EXPORT ${PROJECT_NAME}-targets
FILE ${PROJECT_NAME}-targets.cmake
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
include(CMakePackageConfigHelpers)
configure_package_config_file(
${PROJECT_SOURCE_DIR}/cmake/config.cmake.in
${PROJECT_NAME}-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
NO_SET_AND_CHECK_MACRO
)
write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake
COMPATIBILITY SameMinorVersion
)
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
)
endif()

View File

@ -29,6 +29,7 @@ Note:
.align 2
.global secp256k1_fe_mul_inner
.type secp256k1_fe_mul_inner, %function
.hidden secp256k1_fe_mul_inner
@ Arguments:
@ r0 r Restrict: can overlap with a, not with b
@ r1 a
@ -516,6 +517,7 @@ secp256k1_fe_mul_inner:
.align 2
.global secp256k1_fe_sqr_inner
.type secp256k1_fe_sqr_inner, %function
.hidden secp256k1_fe_sqr_inner
@ Arguments:
@ r0 r Can overlap with a
@ r1 a

View File

@ -10,6 +10,9 @@
#include <limits.h>
#include "util.h"
#if defined(SECP256K1_INT128_NATIVE)
#include "int128_native.h"
#endif
/* 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
@ -55,7 +58,7 @@ struct secp256k1_assumption_checker {
/* To int64_t. */
((int64_t)(uint64_t)0xB123C456D789E012ULL == (int64_t)-(int64_t)0x4EDC3BA928761FEEULL) &&
#if defined(SECP256K1_WIDEMUL_INT128)
#if defined(SECP256K1_INT128_NATIVE)
((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) &&
@ -71,7 +74,7 @@ struct secp256k1_assumption_checker {
((((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)
#if defined(SECP256K1_INT128_NATIVE)
((((int128_t)(((uint128_t)0xCD833A65684A0DBCULL << 64) + 0xB349312F71EA7637ULL)) >> 39) == (int128_t)(((uint128_t)0xFFFFFFFFFF9B0674ULL << 64) + 0xCAD0941B79669262ULL)) &&
#endif
1) * 2 - 1];

View File

@ -1,17 +0,0 @@
/***********************************************************************
* Copyright (c) 2013, 2014 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#ifndef SECP256K1_BASIC_CONFIG_H
#define SECP256K1_BASIC_CONFIG_H
#ifdef USE_BASIC_CONFIG
#define ECMULT_WINDOW_SIZE 15
#define ECMULT_GEN_PREC_BITS 4
#endif /* USE_BASIC_CONFIG */
#endif /* SECP256K1_BASIC_CONFIG_H */

View File

@ -11,7 +11,7 @@
#include "util.h"
#include "bench.h"
void help(int default_iters) {
static void help(int default_iters) {
printf("Benchmarks the following algorithms:\n");
printf(" - ECDSA signing/verification\n");
@ -38,6 +38,8 @@ void help(int default_iters) {
printf(" ecdsa : all ECDSA algorithms--sign, verify, recovery (if enabled)\n");
printf(" ecdsa_sign : ECDSA siging algorithm\n");
printf(" ecdsa_verify : ECDSA verification algorithm\n");
printf(" ec : all EC public key algorithms (keygen)\n");
printf(" ec_keygen : EC public key generation\n");
#ifdef ENABLE_MODULE_RECOVERY
printf(" ecdsa_recover : ECDSA public key recovery algorithm\n");
@ -53,6 +55,14 @@ void help(int default_iters) {
printf(" schnorrsig_verify : Schnorr verification algorithm\n");
#endif
#ifdef ENABLE_MODULE_ELLSWIFT
printf(" ellswift : all ElligatorSwift benchmarks (encode, decode, keygen, ecdh)\n");
printf(" ellswift_encode : ElligatorSwift encoding\n");
printf(" ellswift_decode : ElligatorSwift decoding\n");
printf(" ellswift_keygen : ElligatorSwift key generation\n");
printf(" ellswift_ecdh : ECDH on ElligatorSwift keys\n");
#endif
printf("\n");
}
@ -64,11 +74,11 @@ typedef struct {
size_t siglen;
unsigned char pubkey[33];
size_t pubkeylen;
} bench_verify_data;
} bench_data;
static void bench_verify(void* arg, int iters) {
int i;
bench_verify_data* data = (bench_verify_data*)arg;
bench_data* data = (bench_data*)arg;
for (i = 0; i < iters; i++) {
secp256k1_pubkey pubkey;
@ -85,15 +95,9 @@ static void bench_verify(void* arg, int iters) {
}
}
typedef struct {
secp256k1_context* ctx;
unsigned char msg[32];
unsigned char key[32];
} bench_sign_data;
static void bench_sign_setup(void* arg) {
int i;
bench_sign_data *data = (bench_sign_data*)arg;
bench_data *data = (bench_data*)arg;
for (i = 0; i < 32; i++) {
data->msg[i] = i + 1;
@ -105,7 +109,7 @@ static void bench_sign_setup(void* arg) {
static void bench_sign_run(void* arg, int iters) {
int i;
bench_sign_data *data = (bench_sign_data*)arg;
bench_data *data = (bench_data*)arg;
unsigned char sig[74];
for (i = 0; i < iters; i++) {
@ -121,6 +125,30 @@ static void bench_sign_run(void* arg, int iters) {
}
}
static void bench_keygen_setup(void* arg) {
int i;
bench_data *data = (bench_data*)arg;
for (i = 0; i < 32; i++) {
data->key[i] = i + 65;
}
}
static void bench_keygen_run(void *arg, int iters) {
int i;
bench_data *data = (bench_data*)arg;
for (i = 0; i < iters; i++) {
unsigned char pub33[33];
size_t len = 33;
secp256k1_pubkey pubkey;
CHECK(secp256k1_ec_pubkey_create(data->ctx, &pubkey, data->key));
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pub33, &len, &pubkey, SECP256K1_EC_COMPRESSED));
memcpy(data->key, pub33 + 1, 32);
}
}
#ifdef ENABLE_MODULE_ECDH
# include "modules/ecdh/bench_impl.h"
#endif
@ -133,11 +161,15 @@ static void bench_sign_run(void* arg, int iters) {
# include "modules/schnorrsig/bench_impl.h"
#endif
#ifdef ENABLE_MODULE_ELLSWIFT
# include "modules/ellswift/bench_impl.h"
#endif
int main(int argc, char** argv) {
int i;
secp256k1_pubkey pubkey;
secp256k1_ecdsa_signature sig;
bench_verify_data data;
bench_data data;
int d = argc == 1;
int default_iters = 20000;
@ -145,7 +177,9 @@ int main(int argc, char** argv) {
/* Check for invalid user arguments */
char* valid_args[] = {"ecdsa", "verify", "ecdsa_verify", "sign", "ecdsa_sign", "ecdh", "recover",
"ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign"};
"ecdsa_recover", "schnorrsig", "schnorrsig_verify", "schnorrsig_sign", "ec",
"keygen", "ec_keygen", "ellswift", "encode", "ellswift_encode", "decode",
"ellswift_decode", "ellswift_keygen", "ellswift_ecdh"};
size_t valid_args_size = sizeof(valid_args)/sizeof(valid_args[0]);
int invalid_args = have_invalid_args(argc, argv, valid_args, valid_args_size);
@ -164,7 +198,7 @@ int main(int argc, char** argv) {
/* Check if the user tries to benchmark optional module without building it */
#ifndef ENABLE_MODULE_ECDH
if (have_flag(argc, argv, "ecdh")) {
if (have_flag(argc, argv, "ecdh")) {
fprintf(stderr, "./bench: ECDH module not enabled.\n");
fprintf(stderr, "Use ./configure --enable-module-ecdh.\n\n");
return 1;
@ -172,7 +206,7 @@ int main(int argc, char** argv) {
#endif
#ifndef ENABLE_MODULE_RECOVERY
if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) {
if (have_flag(argc, argv, "recover") || have_flag(argc, argv, "ecdsa_recover")) {
fprintf(stderr, "./bench: Public key recovery module not enabled.\n");
fprintf(stderr, "Use ./configure --enable-module-recovery.\n\n");
return 1;
@ -180,15 +214,25 @@ int main(int argc, char** argv) {
#endif
#ifndef ENABLE_MODULE_SCHNORRSIG
if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) {
if (have_flag(argc, argv, "schnorrsig") || have_flag(argc, argv, "schnorrsig_sign") || have_flag(argc, argv, "schnorrsig_verify")) {
fprintf(stderr, "./bench: Schnorr signatures module not enabled.\n");
fprintf(stderr, "Use ./configure --enable-module-schnorrsig.\n\n");
return 1;
}
#endif
/* ECDSA verification benchmark */
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
#ifndef ENABLE_MODULE_ELLSWIFT
if (have_flag(argc, argv, "ellswift") || have_flag(argc, argv, "ellswift_encode") || have_flag(argc, argv, "ellswift_decode") ||
have_flag(argc, argv, "encode") || have_flag(argc, argv, "decode") || have_flag(argc, argv, "ellswift_keygen") ||
have_flag(argc, argv, "ellswift_ecdh")) {
fprintf(stderr, "./bench: ElligatorSwift module not enabled.\n");
fprintf(stderr, "Use ./configure --enable-module-ellswift.\n\n");
return 1;
}
#endif
/* ECDSA benchmark */
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
for (i = 0; i < 32; i++) {
data.msg[i] = 1 + i;
@ -206,12 +250,8 @@ int main(int argc, char** argv) {
print_output_table_header_row();
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);
secp256k1_context_destroy(data.ctx);
/* ECDSA signing benchmark */
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "sign") || have_flag(argc, argv, "ecdsa_sign")) run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "ec") || have_flag(argc, argv, "keygen") || have_flag(argc, argv, "ec_keygen")) run_benchmark("ec_keygen", bench_keygen_run, bench_keygen_setup, NULL, &data, 10, iters);
secp256k1_context_destroy(data.ctx);
@ -230,5 +270,10 @@ int main(int argc, char** argv) {
run_schnorrsig_bench(iters, argc, argv);
#endif
#ifdef ENABLE_MODULE_ELLSWIFT
/* ElligatorSwift benchmarks */
run_ellswift_bench(iters, argc, argv);
#endif
return 0;
}

View File

@ -7,22 +7,38 @@
#ifndef SECP256K1_BENCH_H
#define SECP256K1_BENCH_H
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "sys/time.h"
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
# include <time.h>
#else
# include <sys/time.h>
#endif
static int64_t gettime_i64(void) {
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
/* C11 way to get wallclock time */
struct timespec tv;
if (!timespec_get(&tv, TIME_UTC)) {
fputs("timespec_get failed!", stderr);
exit(1);
}
return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
#endif
}
#define FP_EXP (6)
#define FP_MULT (1000000LL)
/* Format fixed point number. */
void print_number(const int64_t x) {
static void print_number(const int64_t x) {
int64_t x_abs, y;
int c, i, rounding, g; /* g = integer part size, c = fractional part size */
size_t ptr;
@ -79,7 +95,7 @@ void print_number(const int64_t x) {
printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */
}
void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
int i;
int64_t min = INT64_MAX;
int64_t sum = 0;
@ -113,7 +129,7 @@ void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void
printf("\n");
}
int have_flag(int argc, char** argv, char *flag) {
static int have_flag(int argc, char** argv, char *flag) {
char** argm = argv + argc;
argv++;
while (argv != argm) {
@ -129,7 +145,7 @@ int have_flag(int argc, char** argv, char *flag) {
returns:
- 1 if the user entered an invalid argument
- 0 if all the user entered arguments are valid */
int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
size_t i;
int found_valid;
char** argm = argv + argc;
@ -151,7 +167,7 @@ int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
return 0;
}
int get_iters(int default_iters) {
static int get_iters(int default_iters) {
char* env = getenv("SECP256K1_BENCH_ITERS");
if (env) {
return strtol(env, NULL, 0);
@ -160,7 +176,7 @@ int get_iters(int default_iters) {
}
}
void print_output_table_header_row(void) {
static void print_output_table_header_row(void) {
char* bench_str = "Benchmark"; /* left justified */
char* min_str = " Min(us) "; /* center alignment */
char* avg_str = " Avg(us) ";

View File

@ -29,7 +29,7 @@ int main(void) {
bench_bppp_data data;
int iters = get_iters(32);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
run_benchmark("bppp_verify_bit", bench_bppp, bench_bppp_setup, NULL, &data, 10, iters);

View File

@ -18,7 +18,7 @@
#define POINTS 32768
void help(char **argv) {
static void help(char **argv) {
printf("Benchmark EC multiplication algorithms\n");
printf("\n");
printf("Usage: %s <help|pippenger_wnaf|strauss_wnaf|simple>\n", argv[0]);
@ -84,9 +84,7 @@ static void bench_ecmult_teardown_helper(bench_data* data, size_t* seckey_offset
}
}
secp256k1_ecmult_gen(&data->ctx->ecmult_gen_ctx, &tmp, &sum_scalars);
secp256k1_gej_neg(&tmp, &tmp);
secp256k1_gej_add_var(&tmp, &tmp, &sum_output, NULL);
CHECK(secp256k1_gej_is_infinity(&tmp));
CHECK(secp256k1_gej_eq_var(&tmp, &sum_output));
}
static void bench_ecmult_setup(void* arg) {
@ -115,7 +113,7 @@ static void bench_ecmult_const(void* arg, int iters) {
int i;
for (i = 0; i < iters; ++i) {
secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS], 256);
secp256k1_ecmult_const(&data->output[i], &data->pubkeys[(data->offset1+i) % POINTS], &data->scalars[(data->offset2+i) % POINTS]);
}
}
@ -140,12 +138,10 @@ static void bench_ecmult_1p_teardown(void* arg, int iters) {
static void bench_ecmult_0p_g(void* arg, int iters) {
bench_data* data = (bench_data*)arg;
secp256k1_scalar zero;
int i;
secp256k1_scalar_set_int(&zero, 0);
for (i = 0; i < iters; ++i) {
secp256k1_ecmult(&data->output[i], NULL, &zero, &data->scalars[(data->offset1+i) % POINTS]);
secp256k1_ecmult(&data->output[i], NULL, &secp256k1_scalar_zero, &data->scalars[(data->offset1+i) % POINTS]);
}
}
@ -308,7 +304,7 @@ int main(int argc, char **argv) {
}
}
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
if (!have_flag(argc, argv, "simple")) {
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);

View File

@ -50,7 +50,7 @@ int main(void) {
bench_generator_t data;
int iters = get_iters(20000);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
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);

View File

@ -27,7 +27,7 @@ typedef struct {
int wnaf[256];
} bench_inv;
void bench_setup(void* arg) {
static void bench_setup(void* arg) {
bench_inv *data = (bench_inv*)arg;
static const unsigned char init[4][32] = {
@ -65,10 +65,10 @@ void bench_setup(void* arg) {
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]);
secp256k1_fe_set_b32_limit(&data->fe[0], init[0]);
secp256k1_fe_set_b32_limit(&data->fe[1], init[1]);
secp256k1_fe_set_b32_limit(&data->fe[2], init[2]);
secp256k1_fe_set_b32_limit(&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]);
@ -79,7 +79,7 @@ void bench_setup(void* arg) {
memcpy(data->data + 32, init[1], 32);
}
void bench_scalar_add(void* arg, int iters) {
static void bench_scalar_add(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
@ -89,7 +89,7 @@ void bench_scalar_add(void* arg, int iters) {
CHECK(j <= iters);
}
void bench_scalar_negate(void* arg, int iters) {
static void bench_scalar_negate(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -98,7 +98,7 @@ void bench_scalar_negate(void* arg, int iters) {
}
}
void bench_scalar_sqr(void* arg, int iters) {
static void bench_scalar_sqr(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -107,7 +107,7 @@ void bench_scalar_sqr(void* arg, int iters) {
}
}
void bench_scalar_mul(void* arg, int iters) {
static void bench_scalar_mul(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -116,18 +116,19 @@ void bench_scalar_mul(void* arg, int iters) {
}
}
void bench_scalar_split(void* arg, int iters) {
static void bench_scalar_split(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
secp256k1_scalar tmp;
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]);
secp256k1_scalar_split_lambda(&tmp, &data->scalar[1], &data->scalar[0]);
j += secp256k1_scalar_add(&data->scalar[0], &tmp, &data->scalar[1]);
}
CHECK(j <= iters);
}
void bench_scalar_inverse(void* arg, int iters) {
static void bench_scalar_inverse(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
@ -138,7 +139,7 @@ void bench_scalar_inverse(void* arg, int iters) {
CHECK(j <= iters);
}
void bench_scalar_inverse_var(void* arg, int iters) {
static void bench_scalar_inverse_var(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
@ -149,7 +150,7 @@ void bench_scalar_inverse_var(void* arg, int iters) {
CHECK(j <= iters);
}
void bench_field_half(void* arg, int iters) {
static void bench_field_half(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -158,7 +159,7 @@ void bench_field_half(void* arg, int iters) {
}
}
void bench_field_normalize(void* arg, int iters) {
static void bench_field_normalize(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -167,7 +168,7 @@ void bench_field_normalize(void* arg, int iters) {
}
}
void bench_field_normalize_weak(void* arg, int iters) {
static void bench_field_normalize_weak(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -176,7 +177,7 @@ void bench_field_normalize_weak(void* arg, int iters) {
}
}
void bench_field_mul(void* arg, int iters) {
static void bench_field_mul(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -185,7 +186,7 @@ void bench_field_mul(void* arg, int iters) {
}
}
void bench_field_sqr(void* arg, int iters) {
static void bench_field_sqr(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -194,7 +195,7 @@ void bench_field_sqr(void* arg, int iters) {
}
}
void bench_field_inverse(void* arg, int iters) {
static void bench_field_inverse(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -204,7 +205,7 @@ void bench_field_inverse(void* arg, int iters) {
}
}
void bench_field_inverse_var(void* arg, int iters) {
static void bench_field_inverse_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -214,7 +215,7 @@ void bench_field_inverse_var(void* arg, int iters) {
}
}
void bench_field_sqrt(void* arg, int iters) {
static void bench_field_sqrt(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
secp256k1_fe t;
@ -227,7 +228,20 @@ void bench_field_sqrt(void* arg, int iters) {
CHECK(j <= iters);
}
void bench_group_double_var(void* arg, int iters) {
static void bench_field_is_square_var(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
secp256k1_fe t = data->fe[0];
for (i = 0; i < iters; i++) {
j += secp256k1_fe_is_square_var(&t);
secp256k1_fe_add(&t, &data->fe[1]);
secp256k1_fe_normalize_var(&t);
}
CHECK(j <= iters);
}
static void bench_group_double_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -236,7 +250,7 @@ void bench_group_double_var(void* arg, int iters) {
}
}
void bench_group_add_var(void* arg, int iters) {
static void bench_group_add_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -245,7 +259,7 @@ void bench_group_add_var(void* arg, int iters) {
}
}
void bench_group_add_affine(void* arg, int iters) {
static void bench_group_add_affine(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -254,7 +268,7 @@ void bench_group_add_affine(void* arg, int iters) {
}
}
void bench_group_add_affine_var(void* arg, int iters) {
static void bench_group_add_affine_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -263,7 +277,7 @@ void bench_group_add_affine_var(void* arg, int iters) {
}
}
void bench_group_jacobi_var(void* arg, int iters) {
static void bench_group_jacobi_var(void* arg, int iters) {
int i, j = 0;
bench_inv *data = (bench_inv*)arg;
@ -283,7 +297,16 @@ void bench_group_jacobi_var(void* arg, int iters) {
CHECK(j <= iters);
}
void bench_group_to_affine_var(void* arg, int iters) {
static void bench_group_add_zinv_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < iters; i++) {
secp256k1_gej_add_zinv_var(&data->gej[0], &data->gej[0], &data->ge[1], &data->gej[0].y);
}
}
static void bench_group_to_affine_var(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
@ -301,7 +324,7 @@ void bench_group_to_affine_var(void* arg, int iters) {
}
}
void bench_ecmult_wnaf(void* arg, int iters) {
static void bench_ecmult_wnaf(void* arg, int iters) {
int i, bits = 0, overflow = 0;
bench_inv *data = (bench_inv*)arg;
@ -313,7 +336,7 @@ void bench_ecmult_wnaf(void* arg, int iters) {
CHECK(bits <= 256*iters);
}
void bench_wnaf_const(void* arg, int iters) {
static void bench_wnaf_const(void* arg, int iters) {
int i, bits = 0, overflow = 0;
bench_inv *data = (bench_inv*)arg;
@ -325,8 +348,7 @@ void bench_wnaf_const(void* arg, int iters) {
CHECK(bits <= 256*iters);
}
void bench_sha256(void* arg, int iters) {
static void bench_sha256(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_sha256 sha;
@ -338,7 +360,7 @@ void bench_sha256(void* arg, int iters) {
}
}
void bench_hmac_sha256(void* arg, int iters) {
static void bench_hmac_sha256(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_hmac_sha256 hmac;
@ -350,7 +372,7 @@ void bench_hmac_sha256(void* arg, int iters) {
}
}
void bench_rfc6979_hmac_sha256(void* arg, int iters) {
static void bench_rfc6979_hmac_sha256(void* arg, int iters) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_rfc6979_hmac_sha256 rng;
@ -361,19 +383,11 @@ void bench_rfc6979_hmac_sha256(void* arg, int iters) {
}
}
void bench_context_verify(void* arg, int iters) {
static void bench_context(void* arg, int iters) {
int i;
(void)arg;
for (i = 0; i < iters; i++) {
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY));
}
}
void bench_context_sign(void* arg, int iters) {
int i;
(void)arg;
for (i = 0; i < iters; i++) {
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN));
secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_NONE));
}
}
@ -398,6 +412,7 @@ int main(int argc, char **argv) {
if (d || 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 (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters);
if (d || 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 (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "issquare")) run_benchmark("field_is_square_var", bench_field_is_square_var, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters);
if (d || 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);
@ -405,6 +420,7 @@ int main(int argc, char **argv) {
if (d || 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 (d || 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 (d || 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 (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_zinv_var", bench_group_add_zinv_var, bench_setup, NULL, &data, 10, iters*10);
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "to_affine")) run_benchmark("group_to_affine_var", bench_group_to_affine_var, bench_setup, NULL, &data, 10, iters);
if (d || have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, iters);
@ -414,8 +430,7 @@ int main(int argc, char **argv) {
if (d || 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 (d || 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 (d || 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 (d || 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);
if (d || have_flag(argc, argv, "context")) run_benchmark("context_create", bench_context, bench_setup, NULL, &data, 10, iters);
return 0;
}

View File

@ -53,7 +53,7 @@ int main(void) {
bench_rangeproof_t data;
int iters;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
data.min_bits = 32;
iters = data.min_bits*get_iters(32);

View File

@ -11,6 +11,7 @@
#include "util.h"
#include "bench.h"
#include "hash_impl.h"
#include "int128_impl.h"
#include "scalar_impl.h"
#include "testrand_impl.h"
@ -48,7 +49,7 @@ static void run_test(bench_data* data, int iters) {
run_benchmark(str, bench_whitelist, bench_whitelist_setup, NULL, data, 100, iters);
}
void random_scalar_order(secp256k1_scalar *num) {
static void random_scalar_order(secp256k1_scalar *num) {
do {
unsigned char b32[32];
int overflow = 0;
@ -68,7 +69,7 @@ int main(void) {
secp256k1_scalar ssub;
int iters = get_iters(5);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
/* Start with subkey */
random_scalar_order(&ssub);

88
src/checkmem.h Normal file
View File

@ -0,0 +1,88 @@
/***********************************************************************
* Copyright (c) 2022 Pieter Wuille *
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
/* The code here is inspired by Kris Kwiatkowski's approach in
* https://github.com/kriskwiatkowski/pqc/blob/main/src/common/ct_check.h
* to provide a general interface for memory-checking mechanisms, primarily
* for constant-time checking.
*/
/* These macros are defined by this header file:
*
* - SECP256K1_CHECKMEM_ENABLED:
* - 1 if memory-checking integration is available, 0 otherwise.
* This is just a compile-time macro. Use the next macro to check it is actually
* available at runtime.
* - SECP256K1_CHECKMEM_RUNNING():
* - Acts like a function call, returning 1 if memory checking is available
* at runtime.
* - SECP256K1_CHECKMEM_CHECK(p, len):
* - Assert or otherwise fail in case the len-byte memory block pointed to by p is
* not considered entirely defined.
* - SECP256K1_CHECKMEM_CHECK_VERIFY(p, len):
* - Like SECP256K1_CHECKMEM_CHECK, but only works in VERIFY mode.
* - SECP256K1_CHECKMEM_UNDEFINE(p, len):
* - marks the len-byte memory block pointed to by p as undefined data (secret data,
* in the context of constant-time checking).
* - SECP256K1_CHECKMEM_DEFINE(p, len):
* - marks the len-byte memory pointed to by p as defined data (public data, in the
* context of constant-time checking).
*
*/
#ifndef SECP256K1_CHECKMEM_H
#define SECP256K1_CHECKMEM_H
/* Define a statement-like macro that ignores the arguments. */
#define SECP256K1_CHECKMEM_NOOP(p, len) do { (void)(p); (void)(len); } while(0)
/* If compiling under msan, map the SECP256K1_CHECKMEM_* functionality to msan.
* Choose this preferentially, even when VALGRIND is defined, as msan-compiled
* binaries can't be run under valgrind anyway. */
#if defined(__has_feature)
# if __has_feature(memory_sanitizer)
# include <sanitizer/msan_interface.h>
# define SECP256K1_CHECKMEM_ENABLED 1
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) __msan_allocated_memory((p), (len))
# define SECP256K1_CHECKMEM_DEFINE(p, len) __msan_unpoison((p), (len))
# define SECP256K1_CHECKMEM_CHECK(p, len) __msan_check_mem_is_initialized((p), (len))
# define SECP256K1_CHECKMEM_RUNNING() (1)
# endif
#endif
/* If valgrind integration is desired (through the VALGRIND define), implement the
* SECP256K1_CHECKMEM_* macros using valgrind. */
#if !defined SECP256K1_CHECKMEM_ENABLED
# if defined VALGRIND
# include <stddef.h>
# include <valgrind/memcheck.h>
# define SECP256K1_CHECKMEM_ENABLED 1
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) VALGRIND_MAKE_MEM_UNDEFINED((p), (len))
# define SECP256K1_CHECKMEM_DEFINE(p, len) VALGRIND_MAKE_MEM_DEFINED((p), (len))
# define SECP256K1_CHECKMEM_CHECK(p, len) VALGRIND_CHECK_MEM_IS_DEFINED((p), (len))
/* VALGRIND_MAKE_MEM_DEFINED returns 0 iff not running on memcheck.
* This is more precise than the RUNNING_ON_VALGRIND macro, which
* checks for valgrind in general instead of memcheck specifically. */
# define SECP256K1_CHECKMEM_RUNNING() (VALGRIND_MAKE_MEM_DEFINED(NULL, 0) != 0)
# endif
#endif
/* As a fall-back, map these macros to dummy statements. */
#if !defined SECP256K1_CHECKMEM_ENABLED
# define SECP256K1_CHECKMEM_ENABLED 0
# define SECP256K1_CHECKMEM_UNDEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
# define SECP256K1_CHECKMEM_DEFINE(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
# define SECP256K1_CHECKMEM_CHECK(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
# define SECP256K1_CHECKMEM_RUNNING() (0)
#endif
#if defined VERIFY
#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_CHECK((p), (len))
#else
#define SECP256K1_CHECKMEM_CHECK_VERIFY(p, len) SECP256K1_CHECKMEM_NOOP((p), (len))
#endif
#endif /* SECP256K1_CHECKMEM_H */

View File

@ -4,13 +4,16 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/
#include <valgrind/memcheck.h>
#include <stdio.h>
#include <string.h>
#include "../include/secp256k1.h"
#include "assumptions.h"
#include "util.h"
#include "checkmem.h"
#if !SECP256K1_CHECKMEM_ENABLED
# error "This tool cannot be compiled without memory-checking interface (valgrind or msan)"
#endif
#ifdef ENABLE_MODULE_ECDH
# include "../include/secp256k1_ecdh.h"
@ -28,6 +31,10 @@
#include "../include/secp256k1_schnorrsig.h"
#endif
#ifdef ENABLE_MODULE_ELLSWIFT
#include "../include/secp256k1_ellswift.h"
#endif
#ifdef ENABLE_MODULE_ECDSA_S2C
#include "../include/secp256k1_ecdsa_s2c.h"
#endif
@ -40,21 +47,19 @@
#include "../include/secp256k1_musig.h"
#endif
void run_tests(secp256k1_context *ctx, unsigned char *key);
static void run_tests(secp256k1_context *ctx, unsigned char *key);
int main(void) {
secp256k1_context* ctx;
unsigned char key[32];
int ret, i;
if (!RUNNING_ON_VALGRIND) {
fprintf(stderr, "This test can only usefully be run inside valgrind.\n");
fprintf(stderr, "Usage: libtool --mode=execute valgrind ./valgrind_ctime_test\n");
if (!SECP256K1_CHECKMEM_RUNNING()) {
fprintf(stderr, "This test can only usefully be run inside valgrind because it was not compiled under msan.\n");
fprintf(stderr, "Usage: libtool --mode=execute valgrind ./ctime_tests\n");
return 1;
}
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN
| SECP256K1_CONTEXT_VERIFY
| SECP256K1_CONTEXT_DECLASSIFY);
ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY);
/** In theory, testing with a single secret input should be sufficient:
* If control flow depended on secrets the tool would generate an error.
*/
@ -66,16 +71,16 @@ int main(void) {
/* Test context randomisation. Do this last because it leaves the context
* tainted. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_context_randomize(ctx, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret);
secp256k1_context_destroy(ctx);
return 0;
}
void run_tests(secp256k1_context *ctx, unsigned char *key) {
static void run_tests(secp256k1_context *ctx, unsigned char *key) {
secp256k1_ecdsa_signature signature;
secp256k1_pubkey pubkey;
size_t siglen = 74;
@ -92,119 +97,145 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
#ifdef ENABLE_MODULE_EXTRAKEYS
secp256k1_keypair keypair;
#endif
#ifdef ENABLE_MODULE_ELLSWIFT
unsigned char ellswift[64];
static const unsigned char prefix[64] = {'t', 'e', 's', 't'};
#endif
for (i = 0; i < 32; i++) {
msg[i] = i + 1;
}
/* Test keygen. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key);
VALGRIND_MAKE_MEM_DEFINED(&pubkey, sizeof(secp256k1_pubkey));
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&pubkey, sizeof(secp256k1_pubkey));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret);
CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);
/* Test signing. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL);
VALGRIND_MAKE_MEM_DEFINED(&signature, sizeof(secp256k1_ecdsa_signature));
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&signature, sizeof(secp256k1_ecdsa_signature));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret);
CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature));
#ifdef ENABLE_MODULE_ECDH
/* Test ECDH. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
#endif
#ifdef ENABLE_MODULE_RECOVERY
/* Test signing a recoverable signature. */
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL);
VALGRIND_MAKE_MEM_DEFINED(&recoverable_signature, sizeof(recoverable_signature));
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&recoverable_signature, sizeof(recoverable_signature));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret);
CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature));
CHECK(recid >= 0 && recid <= 3);
#endif
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ec_seckey_verify(ctx, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ec_seckey_negate(ctx, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
VALGRIND_MAKE_MEM_UNDEFINED(msg, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(msg, 32);
ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
VALGRIND_MAKE_MEM_UNDEFINED(msg, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(msg, 32);
ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
/* Test keypair_create and keypair_xonly_tweak_add. */
#ifdef ENABLE_MODULE_EXTRAKEYS
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_keypair_create(ctx, &keypair, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
/* The tweak is not treated as a secret in keypair_tweak_add */
VALGRIND_MAKE_MEM_DEFINED(msg, 32);
SECP256K1_CHECKMEM_DEFINE(msg, 32);
ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
VALGRIND_MAKE_MEM_UNDEFINED(&keypair, sizeof(keypair));
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(&keypair, sizeof(keypair));
ret = secp256k1_keypair_sec(ctx, key, &keypair);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
#endif
#ifdef ENABLE_MODULE_SCHNORRSIG
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_keypair_create(ctx, &keypair, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
#endif
#ifdef ENABLE_MODULE_ELLSWIFT
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ellswift_create(ctx, ellswift, key, ellswift);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
for (i = 0; i < 2; i++) {
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift));
ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_bip324, NULL);
SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift));
ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_prefix, (void *)prefix);
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
}
#endif
#ifdef ENABLE_MODULE_ECDSA_S2C
{
unsigned char s2c_data[32] = {0};
unsigned char s2c_data_comm[32] = {0};
secp256k1_ecdsa_s2c_opening s2c_opening;
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
VALGRIND_MAKE_MEM_UNDEFINED(s2c_data, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(s2c_data, 32);
ret = secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, msg, key, s2c_data);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(s2c_data, 32);
SECP256K1_CHECKMEM_UNDEFINE(s2c_data, 32);
ret = secp256k1_ecdsa_anti_exfil_host_commit(ctx, s2c_data_comm, s2c_data);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
VALGRIND_MAKE_MEM_UNDEFINED(s2c_data, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(s2c_data, 32);
ret = secp256k1_ecdsa_anti_exfil_signer_commit(ctx, &s2c_opening, msg, key, s2c_data);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
}
#endif
@ -223,26 +254,26 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
ret = secp256k1_ec_pubkey_create(ctx, &enckey, deckey);
CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
ret = secp256k1_ecdsa_adaptor_encrypt(ctx, adaptor_sig, key, &enckey, msg, NULL, NULL);
VALGRIND_MAKE_MEM_DEFINED(adaptor_sig, sizeof(adaptor_sig));
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(adaptor_sig, sizeof(adaptor_sig));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(deckey, 32);
SECP256K1_CHECKMEM_UNDEFINE(deckey, 32);
ret = secp256k1_ecdsa_adaptor_decrypt(ctx, &signature, deckey, adaptor_sig);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
VALGRIND_MAKE_MEM_UNDEFINED(&signature, 32);
SECP256K1_CHECKMEM_UNDEFINE(&signature, 32);
ret = secp256k1_ecdsa_adaptor_recover(ctx, expected_deckey, &signature, adaptor_sig, &enckey);
VALGRIND_MAKE_MEM_DEFINED(expected_deckey, sizeof(expected_deckey));
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(expected_deckey, sizeof(expected_deckey));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
VALGRIND_MAKE_MEM_DEFINED(deckey, sizeof(deckey));
SECP256K1_CHECKMEM_DEFINE(deckey, sizeof(deckey));
ret = secp256k1_memcmp_var(deckey, expected_deckey, sizeof(expected_deckey));
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 0);
}
#endif
@ -269,7 +300,7 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
pk_ptr[0] = &pk;
pubnonce_ptr[0] = &pubnonce;
VALGRIND_MAKE_MEM_DEFINED(key, 32);
SECP256K1_CHECKMEM_DEFINE(key, 32);
memcpy(session_id, key, sizeof(session_id));
session_id[0] = session_id[0] + 1;
memcpy(extra_input, key, sizeof(extra_input));
@ -282,33 +313,35 @@ void run_tests(secp256k1_context *ctx, unsigned char *key) {
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair));
CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &agg_pk, &cache, pk_ptr, 1));
CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor));
VALGRIND_MAKE_MEM_UNDEFINED(key, 32);
VALGRIND_MAKE_MEM_UNDEFINED(session_id, sizeof(session_id));
VALGRIND_MAKE_MEM_UNDEFINED(extra_input, sizeof(extra_input));
VALGRIND_MAKE_MEM_UNDEFINED(sec_adaptor, sizeof(sec_adaptor));
SECP256K1_CHECKMEM_UNDEFINE(key, 32);
SECP256K1_CHECKMEM_UNDEFINE(session_id, sizeof(session_id));
SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input));
SECP256K1_CHECKMEM_UNDEFINE(sec_adaptor, sizeof(sec_adaptor));
ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_id, key, &pk, msg, &cache, extra_input);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1));
/* Make sure that previous tests don't undefine msg. It's not used as a secret here. */
SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg));
CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache, &adaptor) == 1);
ret = secp256k1_keypair_create(ctx, &keypair, key);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
VALGRIND_MAKE_MEM_DEFINED(&partial_sig, sizeof(partial_sig));
SECP256K1_CHECKMEM_DEFINE(&partial_sig, sizeof(partial_sig));
CHECK(secp256k1_musig_partial_sig_agg(ctx, pre_sig, &session, partial_sig_ptr, 1));
VALGRIND_MAKE_MEM_DEFINED(pre_sig, sizeof(pre_sig));
SECP256K1_CHECKMEM_DEFINE(pre_sig, sizeof(pre_sig));
CHECK(secp256k1_musig_nonce_parity(ctx, &nonce_parity, &session));
ret = secp256k1_musig_adapt(ctx, sig, pre_sig, sec_adaptor, nonce_parity);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
ret = secp256k1_musig_extract_adaptor(ctx, sec_adaptor, sig, pre_sig, nonce_parity);
VALGRIND_MAKE_MEM_DEFINED(&ret, sizeof(ret));
SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret));
CHECK(ret == 1);
}
#endif

View File

@ -16,17 +16,8 @@
#include "ecdsa.h"
/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1
* sage: for t in xrange(1023, -1, -1):
* .. p = 2**256 - 2**32 - t
* .. if p.is_prime():
* .. print '%x'%p
* .. break
* 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f'
* sage: a = 0
* sage: b = 7
* sage: F = FiniteField (p)
* sage: '%x' % (EllipticCurve ([F (a), F (b)]).order())
* 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141'
* $ sage -c 'load("secp256k1_params.sage"); print(hex(N))'
* 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
*/
static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST(
0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL,
@ -35,12 +26,8 @@ static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST
/** Difference between field and order, values 'p' and 'n' values defined in
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
* sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
* sage: a = 0
* sage: b = 7
* sage: F = FiniteField (p)
* sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order())
* '14551231950b75fc4402da1722fc9baee'
* $ sage -c 'load("secp256k1_params.sage"); print(hex(P-N))'
* 0x14551231950b75fc4402da1722fc9baee
*/
static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST(
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
@ -239,7 +226,8 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_scalar *sigr, const secp25
}
#else
secp256k1_scalar_get_b32(c, sigr);
secp256k1_fe_set_b32(&xr, c);
/* we can ignore the fe_set_b32_limit return value, because we know the input is in range */
(void)secp256k1_fe_set_b32_limit(&xr, c);
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
* in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p),

View File

@ -17,10 +17,10 @@
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) {
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] == SECP256K1_TAG_PUBKEY_ODD);
return secp256k1_fe_set_b32_limit(&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)) {
if (!secp256k1_fe_set_b32_limit(&x, pub+1) || !secp256k1_fe_set_b32_limit(&y, pub+33)) {
return 0;
}
secp256k1_ge_set_xy(elem, &x, &y);
@ -59,10 +59,8 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp25
static int secp256k1_eckey_pubkey_tweak_add(secp256k1_ge *key, const secp256k1_scalar *tweak) {
secp256k1_gej pt;
secp256k1_scalar one;
secp256k1_gej_set_ge(&pt, key);
secp256k1_scalar_set_int(&one, 1);
secp256k1_ecmult(&pt, &pt, &one, tweak);
secp256k1_ecmult(&pt, &pt, &secp256k1_scalar_one, tweak);
if (secp256k1_gej_is_infinity(&pt)) {
return 0;
@ -80,15 +78,13 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp25
}
static int secp256k1_eckey_pubkey_tweak_mul(secp256k1_ge *key, const secp256k1_scalar *tweak) {
secp256k1_scalar zero;
secp256k1_gej pt;
if (secp256k1_scalar_is_zero(tweak)) {
return 0;
}
secp256k1_scalar_set_int(&zero, 0);
secp256k1_gej_set_ge(&pt, key);
secp256k1_ecmult(&pt, &pt, tweak, &zero);
secp256k1_ecmult(&pt, &pt, tweak, &secp256k1_scalar_zero);
secp256k1_ge_set_gej(key, &pt);
return 1;
}

View File

@ -11,7 +11,18 @@
#include "scalar.h"
#include "scratch.h"
/* Noone will ever need more than a window size of 24. The code might
#ifndef ECMULT_WINDOW_SIZE
# define ECMULT_WINDOW_SIZE 15
# ifdef DEBUG_CONFIG
# pragma message DEBUG_CONFIG_MSG("ECMULT_WINDOW_SIZE undefined, assuming default value")
# endif
#endif
#ifdef DEBUG_CONFIG
# pragma message DEBUG_CONFIG_DEF(ECMULT_WINDOW_SIZE)
#endif
/* No one will ever need more than a window size of 24. The code might
* be correct for larger values of ECMULT_WINDOW_SIZE but this is not
* tested.
*

View File

@ -11,11 +11,28 @@
#include "group.h"
/**
* Multiply: R = q*A (in constant-time)
* Here `bits` should be set to the maximum bitlength of the _absolute value_ of `q`, plus
* one because we internally sometimes add 2 to the number during the WNAF conversion.
* A must not be infinity.
* Multiply: R = q*A (in constant-time for q)
*/
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q, int bits);
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q);
/**
* Same as secp256k1_ecmult_const, but takes in an x coordinate of the base point
* only, specified as fraction n/d (numerator/denominator). Only the x coordinate of the result is
* returned.
*
* If known_on_curve is 0, a verification is performed that n/d is a valid X
* coordinate, and 0 is returned if not. Otherwise, 1 is returned.
*
* d being NULL is interpreted as d=1. If non-NULL, d must not be zero. q must not be zero.
*
* Constant time in the value of q, but not any other inputs.
*/
static int secp256k1_ecmult_const_xonly(
secp256k1_fe *r,
const secp256k1_fe *n,
const secp256k1_fe *d,
const secp256k1_scalar *q,
int known_on_curve
);
#endif /* SECP256K1_ECMULT_CONST_H */

View File

@ -130,7 +130,7 @@ static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w
return skew;
}
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar, int size) {
static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) {
secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)];
secp256k1_ge tmpa;
secp256k1_fe Z;
@ -144,20 +144,17 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
int i;
/* build wnaf representation for q. */
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;
if (secp256k1_ge_is_infinity(a)) {
secp256k1_gej_set_infinity(r);
return;
}
/* build wnaf representation for q. */
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar);
skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128);
skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128);
/* Calculate odd multiples of a.
* All multiples are brought to the same Z 'denominator', which is stored
* in Z. Due to secp256k1' isomorphism we can do all operations pretending
@ -170,28 +167,23 @@ 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);
}
if (size > 128) {
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
}
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]);
}
/* first loop iteration (separated out so we can directly set r, rather
* than having it start at infinity, get doubled several times, then have
* its new value added to it) */
i = wnaf_1[WNAF_SIZE_BITS(rsize, WINDOW_A - 1)];
i = wnaf_1[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A);
secp256k1_gej_set_ge(r, &tmpa);
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);
}
i = wnaf_lam[WNAF_SIZE_BITS(128, WINDOW_A - 1)];
VERIFY_CHECK(i != 0);
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A);
secp256k1_gej_add_ge(r, r, &tmpa);
/* remaining loop iterations */
for (i = WNAF_SIZE_BITS(rsize, WINDOW_A - 1) - 1; i >= 0; i--) {
for (i = WNAF_SIZE_BITS(128, WINDOW_A - 1) - 1; i >= 0; i--) {
int n;
int j;
for (j = 0; j < WINDOW_A - 1; ++j) {
@ -202,12 +194,10 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A);
VERIFY_CHECK(n != 0);
secp256k1_gej_add_ge(r, r, &tmpa);
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);
}
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);
}
{
@ -218,14 +208,147 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
secp256k1_gej_add_ge(&tmpj, r, &tmpa);
secp256k1_gej_cmov(r, &tmpj, skew_1);
if (size > 128) {
secp256k1_ge_neg(&tmpa, &pre_a_lam[0]);
secp256k1_gej_add_ge(&tmpj, r, &tmpa);
secp256k1_gej_cmov(r, &tmpj, skew_lam);
}
secp256k1_ge_neg(&tmpa, &pre_a_lam[0]);
secp256k1_gej_add_ge(&tmpj, r, &tmpa);
secp256k1_gej_cmov(r, &tmpj, skew_lam);
}
secp256k1_fe_mul(&r->z, &r->z, &Z);
}
static int secp256k1_ecmult_const_xonly(secp256k1_fe* r, const secp256k1_fe *n, const secp256k1_fe *d, const secp256k1_scalar *q, int known_on_curve) {
/* This algorithm is a generalization of Peter Dettman's technique for
* avoiding the square root in a random-basepoint x-only multiplication
* on a Weierstrass curve:
* https://mailarchive.ietf.org/arch/msg/cfrg/7DyYY6gg32wDgHAhgSb6XxMDlJA/
*
*
* === Background: the effective affine technique ===
*
* Let phi_u be the isomorphism that maps (x, y) on secp256k1 curve y^2 = x^3 + 7 to
* x' = u^2*x, y' = u^3*y on curve y'^2 = x'^3 + u^6*7. This new curve has the same order as
* the original (it is isomorphic), but moreover, has the same addition/doubling formulas, as
* the curve b=7 coefficient does not appear in those formulas (or at least does not appear in
* the formulas implemented in this codebase, both affine and Jacobian). See also Example 9.5.2
* in https://www.math.auckland.ac.nz/~sgal018/crypto-book/ch9.pdf.
*
* This means any linear combination of secp256k1 points can be computed by applying phi_u
* (with non-zero u) on all input points (including the generator, if used), computing the
* linear combination on the isomorphic curve (using the same group laws), and then applying
* phi_u^{-1} to get back to secp256k1.
*
* Switching to Jacobian coordinates, note that phi_u applied to (X, Y, Z) is simply
* (X, Y, Z/u). Thus, if we want to compute (X1, Y1, Z) + (X2, Y2, Z), with identical Z
* coordinates, we can use phi_Z to transform it to (X1, Y1, 1) + (X2, Y2, 1) on an isomorphic
* curve where the affine addition formula can be used instead.
* If (X3, Y3, Z3) = (X1, Y1) + (X2, Y2) on that curve, then our answer on secp256k1 is
* (X3, Y3, Z3*Z).
*
* This is the effective affine technique: if we have a linear combination of group elements
* to compute, and all those group elements have the same Z coordinate, we can simply pretend
* that all those Z coordinates are 1, perform the computation that way, and then multiply the
* original Z coordinate back in.
*
* The technique works on any a=0 short Weierstrass curve. It is possible to generalize it to
* other curves too, but there the isomorphic curves will have different 'a' coefficients,
* which typically does affect the group laws.
*
*
* === Avoiding the square root for x-only point multiplication ===
*
* In this function, we want to compute the X coordinate of q*(n/d, y), for
* y = sqrt((n/d)^3 + 7). Its negation would also be a valid Y coordinate, but by convention
* we pick whatever sqrt returns (which we assume to be a deterministic function).
*
* Let g = y^2*d^3 = n^3 + 7*d^3. This also means y = sqrt(g/d^3).
* Further let v = sqrt(d*g), which must exist as d*g = y^2*d^4 = (y*d^2)^2.
*
* The input point (n/d, y) also has Jacobian coordinates:
*
* (n/d, y, 1)
* = (n/d * v^2, y * v^3, v)
* = (n/d * d*g, y * sqrt(d^3*g^3), v)
* = (n/d * d*g, sqrt(y^2 * d^3*g^3), v)
* = (n*g, sqrt(g/d^3 * d^3*g^3), v)
* = (n*g, sqrt(g^4), v)
* = (n*g, g^2, v)
*
* It is easy to verify that both (n*g, g^2, v) and its negation (n*g, -g^2, v) have affine X
* coordinate n/d, and this holds even when the square root function doesn't have a
* deterministic sign. We choose the (n*g, g^2, v) version.
*
* Now switch to the effective affine curve using phi_v, where the input point has coordinates
* (n*g, g^2). Compute (X, Y, Z) = q * (n*g, g^2) there.
*
* Back on secp256k1, that means q * (n*g, g^2, v) = (X, Y, v*Z). This last point has affine X
* coordinate X / (v^2*Z^2) = X / (d*g*Z^2). Determining the affine Y coordinate would involve
* a square root, but as long as we only care about the resulting X coordinate, no square root
* is needed anywhere in this computation.
*/
secp256k1_fe g, i;
secp256k1_ge p;
secp256k1_gej rj;
/* Compute g = (n^3 + B*d^3). */
secp256k1_fe_sqr(&g, n);
secp256k1_fe_mul(&g, &g, n);
if (d) {
secp256k1_fe b;
#ifdef VERIFY
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero(d));
#endif
secp256k1_fe_sqr(&b, d);
VERIFY_CHECK(SECP256K1_B <= 8); /* magnitude of b will be <= 8 after the next call */
secp256k1_fe_mul_int(&b, SECP256K1_B);
secp256k1_fe_mul(&b, &b, d);
secp256k1_fe_add(&g, &b);
if (!known_on_curve) {
/* We need to determine whether (n/d)^3 + 7 is square.
*
* is_square((n/d)^3 + 7)
* <=> is_square(((n/d)^3 + 7) * d^4)
* <=> is_square((n^3 + 7*d^3) * d)
* <=> is_square(g * d)
*/
secp256k1_fe c;
secp256k1_fe_mul(&c, &g, d);
if (!secp256k1_fe_is_square_var(&c)) return 0;
}
} else {
secp256k1_fe_add_int(&g, SECP256K1_B);
if (!known_on_curve) {
/* g at this point equals x^3 + 7. Test if it is square. */
if (!secp256k1_fe_is_square_var(&g)) return 0;
}
}
/* Compute base point P = (n*g, g^2), the effective affine version of (n*g, g^2, v), which has
* corresponding affine X coordinate n/d. */
secp256k1_fe_mul(&p.x, &g, n);
secp256k1_fe_sqr(&p.y, &g);
p.infinity = 0;
/* Perform x-only EC multiplication of P with q. */
#ifdef VERIFY
VERIFY_CHECK(!secp256k1_scalar_is_zero(q));
#endif
secp256k1_ecmult_const(&rj, &p, q);
#ifdef VERIFY
VERIFY_CHECK(!secp256k1_gej_is_infinity(&rj));
#endif
/* The resulting (X, Y, Z) point on the effective-affine isomorphic curve corresponds to
* (X, Y, Z*v) on the secp256k1 curve. The affine version of that has X coordinate
* (X / (Z^2*d*g)). */
secp256k1_fe_sqr(&i, &rj.z);
secp256k1_fe_mul(&i, &i, &g);
if (d) secp256k1_fe_mul(&i, &i, d);
secp256k1_fe_inv(&i, &i);
secp256k1_fe_mul(r, &rj.x, &i);
return 1;
}
#endif /* SECP256K1_ECMULT_CONST_IMPL_H */

View File

@ -10,9 +10,21 @@
#include "scalar.h"
#include "group.h"
#ifndef ECMULT_GEN_PREC_BITS
# define ECMULT_GEN_PREC_BITS 4
# ifdef DEBUG_CONFIG
# pragma message DEBUG_CONFIG_MSG("ECMULT_GEN_PREC_BITS undefined, assuming default value")
# endif
#endif
#ifdef DEBUG_CONFIG
# pragma message DEBUG_CONFIG_DEF(ECMULT_GEN_PREC_BITS)
#endif
#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_G(bits) (1 << bits)
#define ECMULT_GEN_PREC_N(bits) (256 / bits)

View File

@ -22,6 +22,9 @@ static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, cons
secp256k1_gej nums_gej;
int i, j;
VERIFY_CHECK(g > 0);
VERIFY_CHECK(n > 0);
/* get the generator */
secp256k1_gej_set_ge(&gj, gen);
@ -31,7 +34,7 @@ static void secp256k1_ecmult_gen_compute_table(secp256k1_ge_storage* table, cons
secp256k1_fe nums_x;
secp256k1_ge nums_ge;
int r;
r = secp256k1_fe_set_b32(&nums_x, nums_b32);
r = secp256k1_fe_set_b32_limit(&nums_x, nums_b32);
(void)r;
VERIFY_CHECK(r);
r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0);

View File

@ -87,32 +87,29 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_fe s;
unsigned char nonce32[32];
secp256k1_rfc6979_hmac_sha256 rng;
int overflow;
unsigned char keydata[64] = {0};
unsigned char keydata[64];
if (seed32 == NULL) {
/* When seed is NULL, reset the initial point and blinding value. */
secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g);
secp256k1_gej_neg(&ctx->initial, &ctx->initial);
secp256k1_scalar_set_int(&ctx->blind, 1);
return;
}
/* The prior blinding value (if not reset) is chained forward by including it in the hash. */
secp256k1_scalar_get_b32(nonce32, &ctx->blind);
secp256k1_scalar_get_b32(keydata, &ctx->blind);
/** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data,
* and guards against weak or adversarial seeds. This is a simpler and safer interface than
* asking the caller for blinding values directly and expecting them to retry on failure.
*/
memcpy(keydata, nonce32, 32);
if (seed32 != NULL) {
memcpy(keydata + 32, seed32, 32);
}
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32);
VERIFY_CHECK(seed32 != NULL);
memcpy(keydata + 32, seed32, 32);
secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, 64);
memset(keydata, 0, sizeof(keydata));
/* Accept unobservably small non-uniformity. */
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
overflow = !secp256k1_fe_set_b32(&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_fe_set_b32_mod(&s, nonce32);
secp256k1_fe_cmov(&s, &secp256k1_fe_one, secp256k1_fe_normalizes_to_zero(&s));
/* Randomize the projection to defend against multiplier sidechannels.
Do this before our own call to secp256k1_ecmult_gen below. */
secp256k1_gej_rescale(&ctx->initial, &s);
secp256k1_fe_clear(&s);
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
@ -121,6 +118,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_scalar_cmov(&b, &secp256k1_scalar_one, secp256k1_scalar_is_zero(&b));
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
memset(nonce32, 0, 32);
/* The random projection in ctx->initial ensures that gb will have a random projection. */
secp256k1_ecmult_gen(ctx, &gb, &b);
secp256k1_scalar_negate(&b, &b);
ctx->blind = b;

View File

@ -97,7 +97,7 @@ static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, sec
secp256k1_gej_set_ge(&ai, &pre_a[0]);
ai.z = a->z;
/* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equvalent to a.
/* pre_a[0] is the point (a.x*C^2, a.y*C^3, a.z*C) which is equivalent to a.
* Set zr[0] to C, which is the ratio between the omitted z(pre_a[0]) value and a.z.
*/
zr[0] = d.z;
@ -114,13 +114,16 @@ static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_ge *pre_a, sec
secp256k1_fe_mul(z, &ai.z, &d.z);
}
#define SECP256K1_ECMULT_TABLE_VERIFY(n,w) \
VERIFY_CHECK(((n) & 1) == 1); \
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \
SECP256K1_INLINE static void secp256k1_ecmult_table_verify(int n, int w) {
(void)n;
(void)w;
VERIFY_CHECK(((n) & 1) == 1);
VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1));
VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1));
}
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, const secp256k1_ge *pre, int n, int w) {
SECP256K1_ECMULT_TABLE_VERIFY(n,w)
secp256k1_ecmult_table_verify(n,w);
if (n > 0) {
*r = pre[(n-1)/2];
} else {
@ -130,7 +133,7 @@ SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge(secp256k1_ge *r, cons
}
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *r, const secp256k1_ge *pre, const secp256k1_fe *x, int n, int w) {
SECP256K1_ECMULT_TABLE_VERIFY(n,w)
secp256k1_ecmult_table_verify(n,w);
if (n > 0) {
secp256k1_ge_set_xy(r, &x[(n-1)/2], &pre[(n-1)/2].y);
} else {
@ -140,7 +143,7 @@ SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_lambda(secp256k1_ge *
}
SECP256K1_INLINE static void secp256k1_ecmult_table_get_ge_storage(secp256k1_ge *r, const secp256k1_ge_storage *pre, int n, int w) {
SECP256K1_ECMULT_TABLE_VERIFY(n,w)
secp256k1_ecmult_table_verify(n,w);
if (n > 0) {
secp256k1_ge_from_storage(r, &pre[(n-1)/2]);
} else {
@ -200,9 +203,15 @@ static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a,
bit += now;
}
#ifdef VERIFY
CHECK(carry == 0);
while (bit < 256) {
CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0);
{
int verify_bit = bit;
VERIFY_CHECK(carry == 0);
while (verify_bit < 256) {
VERIFY_CHECK(secp256k1_scalar_get_bits(&s, verify_bit, 1) == 0);
verify_bit++;
}
}
#endif
return last_set_bit + 1;
@ -270,9 +279,6 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
*/
tmp = a[np];
if (no) {
#ifdef VERIFY
secp256k1_fe_normalize_var(&Z);
#endif
secp256k1_gej_rescale(&tmp, &Z);
}
secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), state->pre_a + no * ECMULT_TABLE_SIZE(WINDOW_A), state->aux + no * ECMULT_TABLE_SIZE(WINDOW_A), &Z, &tmp);
@ -282,7 +288,9 @@ static void secp256k1_ecmult_strauss_wnaf(const struct secp256k1_strauss_state *
}
/* Bring them to the same Z denominator. */
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux);
if (no) {
secp256k1_ge_table_set_globalz(ECMULT_TABLE_SIZE(WINDOW_A) * no, state->pre_a, state->aux);
}
for (np = 0; np < no; ++np) {
for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) {
@ -674,7 +682,7 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_call
}
state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*state_space->ps));
state_space->wnaf_na = (int *) secp256k1_scratch_alloc(error_callback, scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int));
buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, (1<<bucket_window) * sizeof(*buckets));
buckets = (secp256k1_gej *) secp256k1_scratch_alloc(error_callback, scratch, ((size_t)1 << bucket_window) * sizeof(*buckets));
if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) {
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 0;
@ -764,14 +772,12 @@ static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_cal
* require a scratch space */
static int secp256k1_ecmult_multi_simple_var(secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) {
size_t point_idx;
secp256k1_scalar szero;
secp256k1_gej tmpj;
secp256k1_scalar_set_int(&szero, 0);
secp256k1_gej_set_infinity(r);
secp256k1_gej_set_infinity(&tmpj);
/* r = inp_g_sc*G */
secp256k1_ecmult(r, &tmpj, &szero, inp_g_sc);
secp256k1_ecmult(r, &tmpj, &secp256k1_scalar_zero, inp_g_sc);
for (point_idx = 0; point_idx < n_points; point_idx++) {
secp256k1_ge point;
secp256k1_gej pointj;
@ -819,9 +825,7 @@ static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback,
if (inp_g_sc == NULL && n == 0) {
return 1;
} else if (n == 0) {
secp256k1_scalar szero;
secp256k1_scalar_set_int(&szero, 0);
secp256k1_ecmult(r, r, &szero, inp_g_sc);
secp256k1_ecmult(r, r, &secp256k1_scalar_zero, inp_g_sc);
return 1;
}
if (scratch == NULL) {

View File

@ -7,23 +7,36 @@
#ifndef SECP256K1_FIELD_H
#define SECP256K1_FIELD_H
/** Field element module.
*
* Field elements can be represented in several ways, but code accessing
* it (and implementations) need to take certain properties into account:
* - Each field element can be normalized or not.
* - Each field element has a magnitude, which represents how far away
* its representation is away from normalization. Normalized elements
* always have a magnitude of 0 or 1, but a magnitude of 1 doesn't
* imply normality.
*/
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h"
/* This file defines the generic interface for working with secp256k1_fe
* objects, which represent field elements (integers modulo 2^256 - 2^32 - 977).
*
* The actual definition of the secp256k1_fe type depends on the chosen field
* implementation; see the field_5x52.h and field_10x26.h files for details.
*
* All secp256k1_fe objects have implicit properties that determine what
* operations are permitted on it. These are purely a function of what
* secp256k1_fe_ operations are applied on it, generally (implicitly) fixed at
* compile time, and do not depend on the chosen field implementation. Despite
* that, what these properties actually entail for the field representation
* values depends on the chosen field implementation. These properties are:
* - magnitude: an integer in [0,32]
* - normalized: 0 or 1; normalized=1 implies magnitude <= 1.
*
* In VERIFY mode, they are materialized explicitly as fields in the struct,
* allowing run-time verification of these properties. In that case, the field
* implementation also provides a secp256k1_fe_verify routine to verify that
* these fields match the run-time value and perform internal consistency
* checks. */
#ifdef VERIFY
# define SECP256K1_FE_VERIFY_FIELDS \
int magnitude; \
int normalized;
#else
# define SECP256K1_FE_VERIFY_FIELDS
#endif
#if defined(SECP256K1_WIDEMUL_INT128)
#include "field_5x52.h"
#elif defined(SECP256K1_WIDEMUL_INT64)
@ -32,114 +45,311 @@
#error "Please select wide multiplication implementation"
#endif
#ifdef VERIFY
/* Magnitude and normalized value for constants. */
#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0) \
/* Magnitude is 0 for constant 0; 1 otherwise. */ \
, (((d7) | (d6) | (d5) | (d4) | (d3) | (d2) | (d1) | (d0)) != 0) \
/* Normalized is 1 unless sum(d_i<<(32*i) for i=0..7) exceeds field modulus. */ \
, (!(((d7) & (d6) & (d5) & (d4) & (d3) & (d2)) == 0xfffffffful && ((d1) == 0xfffffffful || ((d1) == 0xfffffffe && (d0 >= 0xfffffc2f)))))
#else
#define SECP256K1_FE_VERIFY_CONST(d7, d6, d5, d4, d3, d2, d1, d0)
#endif
/** This expands to an initializer for a secp256k1_fe valued sum((i*32) * d_i, i=0..7) mod p.
*
* It has magnitude 1, unless d_i are all 0, in which case the magnitude is 0.
* It is normalized, unless sum(2^(i*32) * d_i, i=0..7) >= p.
*
* SECP256K1_FE_CONST_INNER is provided by the implementation.
*/
#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) SECP256K1_FE_VERIFY_CONST((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)) }
static const secp256k1_fe secp256k1_fe_one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1);
static const secp256k1_fe secp256k1_const_beta = SECP256K1_FE_CONST(
0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul,
0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul
);
/** Normalize a field element. This brings the field element to a canonical representation, reduces
* its magnitude to 1, and reduces it modulo field size `p`.
#ifndef VERIFY
/* In non-VERIFY mode, we #define the fe operations to be identical to their
* internal field implementation, to avoid the potential overhead of a
* function call (even though presumably inlinable). */
# define secp256k1_fe_normalize secp256k1_fe_impl_normalize
# define secp256k1_fe_normalize_weak secp256k1_fe_impl_normalize_weak
# define secp256k1_fe_normalize_var secp256k1_fe_impl_normalize_var
# define secp256k1_fe_normalizes_to_zero secp256k1_fe_impl_normalizes_to_zero
# define secp256k1_fe_normalizes_to_zero_var secp256k1_fe_impl_normalizes_to_zero_var
# define secp256k1_fe_set_int secp256k1_fe_impl_set_int
# define secp256k1_fe_clear secp256k1_fe_impl_clear
# define secp256k1_fe_is_zero secp256k1_fe_impl_is_zero
# define secp256k1_fe_is_odd secp256k1_fe_impl_is_odd
# define secp256k1_fe_cmp_var secp256k1_fe_impl_cmp_var
# define secp256k1_fe_set_b32_mod secp256k1_fe_impl_set_b32_mod
# define secp256k1_fe_set_b32_limit secp256k1_fe_impl_set_b32_limit
# define secp256k1_fe_get_b32 secp256k1_fe_impl_get_b32
# define secp256k1_fe_negate_unchecked secp256k1_fe_impl_negate_unchecked
# define secp256k1_fe_mul_int_unchecked secp256k1_fe_impl_mul_int_unchecked
# define secp256k1_fe_add secp256k1_fe_impl_add
# define secp256k1_fe_mul secp256k1_fe_impl_mul
# define secp256k1_fe_sqr secp256k1_fe_impl_sqr
# define secp256k1_fe_cmov secp256k1_fe_impl_cmov
# define secp256k1_fe_to_storage secp256k1_fe_impl_to_storage
# define secp256k1_fe_from_storage secp256k1_fe_impl_from_storage
# define secp256k1_fe_inv secp256k1_fe_impl_inv
# define secp256k1_fe_inv_var secp256k1_fe_impl_inv_var
# define secp256k1_fe_get_bounds secp256k1_fe_impl_get_bounds
# define secp256k1_fe_half secp256k1_fe_impl_half
# define secp256k1_fe_add_int secp256k1_fe_impl_add_int
# define secp256k1_fe_is_square_var secp256k1_fe_impl_is_square_var
#endif /* !defined(VERIFY) */
/** Normalize a field element.
*
* On input, r must be a valid field element.
* On output, r represents the same value but has normalized=1 and magnitude=1.
*/
static void secp256k1_fe_normalize(secp256k1_fe *r);
/** Weakly normalize a field element: reduce its magnitude to 1, but don't fully normalize. */
/** Give a field element magnitude 1.
*
* On input, r must be a valid field element.
* On output, r represents the same value but has magnitude=1. Normalized is unchanged.
*/
static void secp256k1_fe_normalize_weak(secp256k1_fe *r);
/** Normalize a field element, without constant-time guarantee. */
/** Normalize a field element, without constant-time guarantee.
*
* Identical in behavior to secp256k1_fe_normalize, but not constant time in r.
*/
static void secp256k1_fe_normalize_var(secp256k1_fe *r);
/** Verify whether a field element represents zero i.e. would normalize to a zero value. */
/** Determine whether r represents field element 0.
*
* On input, r must be a valid field element.
* Returns whether r = 0 (mod p).
*/
static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r);
/** Verify whether a field element represents zero i.e. would normalize to a zero value,
* without constant-time guarantee. */
/** Determine whether r represents field element 0, without constant-time guarantee.
*
* Identical in behavior to secp256k1_normalizes_to_zero, but not constant time in r.
*/
static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r);
/** Set a field element equal to a small (not greater than 0x7FFF), non-negative integer.
* Resulting field element is normalized; it has magnitude 0 if a == 0, and magnitude 1 otherwise.
/** Set a field element to an integer in range [0,0x7FFF].
*
* On input, r does not need to be initialized, a must be in [0,0x7FFF].
* On output, r represents value a, is normalized and has magnitude (a!=0).
*/
static void secp256k1_fe_set_int(secp256k1_fe *r, int a);
/** Sets a field element equal to zero, initializing all fields. */
/** Set a field element to 0.
*
* On input, a does not need to be initialized.
* On output, a represents 0, is normalized and has magnitude 0.
*/
static void secp256k1_fe_clear(secp256k1_fe *a);
/** Verify whether a field element is zero. Requires the input to be normalized. */
/** Determine whether a represents field element 0.
*
* On input, a must be a valid normalized field element.
* Returns whether a = 0 (mod p).
*
* This behaves identical to secp256k1_normalizes_to_zero{,_var}, but requires
* normalized input (and is much faster).
*/
static int secp256k1_fe_is_zero(const secp256k1_fe *a);
/** Check the "oddness" of a field element. Requires the input to be normalized. */
/** Determine whether a (mod p) is odd.
*
* On input, a must be a valid normalized field element.
* Returns (int(a) mod p) & 1.
*/
static int secp256k1_fe_is_odd(const secp256k1_fe *a);
/** Compare two field elements. Requires magnitude-1 inputs. */
/** Determine whether two field elements are equal.
*
* On input, a and b must be valid field elements with magnitudes not exceeding
* 1 and 31, respectively.
* Returns a = b (mod p).
*/
static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b);
/** Same as secp256k1_fe_equal, but may be variable time. */
/** Determine whether two field elements are equal, without constant-time guarantee.
*
* Identical in behavior to secp256k1_fe_equal, but not constant time in either a or b.
*/
static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b);
/** Compare two field elements. Requires both inputs to be normalized */
/** Compare the values represented by 2 field elements, without constant-time guarantee.
*
* On input, a and b must be valid normalized field elements.
* Returns 1 if a > b, -1 if a < b, and 0 if a = b (comparisons are done as integers
* in range 0..p-1).
*/
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a);
/** Set a field element equal to a provided 32-byte big endian value, reducing it.
*
* On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array.
* On output, r = a (mod p). It will have magnitude 1, and not be normalized.
*/
static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */
/** Set a field element equal to a provided 32-byte big endian value, checking for overflow.
*
* On input, r does not need to be initialized. a must be a pointer to an initialized 32-byte array.
* On output, r = a if (a < p), it will be normalized with magnitude 1, and 1 is returned.
* If a >= p, 0 is returned, and r will be made invalid (and must not be used without overwriting).
*/
static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
/** Convert a field element to 32-byte big endian byte array.
* On input, a must be a valid normalized field element, and r a pointer to a 32-byte array.
* On output, r = a (mod p).
*/
static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a);
/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input
* as an argument. The magnitude of the output is one higher. */
static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m);
/** Negate a field element.
*
* On input, r does not need to be initialized. a must be a valid field element with
* magnitude not exceeding m. m must be an integer constant expression in [0,31].
* Performs {r = -a}.
* On output, r will not be normalized, and will have magnitude m+1.
*/
#define secp256k1_fe_negate(r, a, m) ASSERT_INT_CONST_AND_DO(m, secp256k1_fe_negate_unchecked(r, a, m))
/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that
* small integer. */
static void secp256k1_fe_mul_int(secp256k1_fe *r, int a);
/** Like secp256k1_fe_negate_unchecked but m is not checked to be an integer constant expression.
*
* Should not be called directly outside of tests.
*/
static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */
/** Add a small integer to a field element.
*
* Performs {r += a}. The magnitude of r increases by 1, and normalized is cleared.
* a must be in range [0,0x7FFF].
*/
static void secp256k1_fe_add_int(secp256k1_fe *r, int a);
/** Multiply a field element with a small integer.
*
* On input, r must be a valid field element. a must be an integer constant expression in [0,32].
* The magnitude of r times a must not exceed 32.
* Performs {r *= a}.
* On output, r's magnitude is multiplied by a, and r will not be normalized.
*/
#define secp256k1_fe_mul_int(r, a) ASSERT_INT_CONST_AND_DO(a, secp256k1_fe_mul_int_unchecked(r, a))
/** Like secp256k1_fe_mul_int but a is not checked to be an integer constant expression.
*
* Should not be called directly outside of tests.
*/
static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a);
/** Increment a field element by another.
*
* On input, r and a must be valid field elements, not necessarily normalized.
* The sum of their magnitudes must not exceed 32.
* Performs {r += a}.
* On output, r will not be normalized, and will have magnitude incremented by a's.
*/
static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a);
/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8.
* The output magnitude is 1 (but not guaranteed to be normalized). */
/** Multiply two field elements.
*
* On input, a and b must be valid field elements; r does not need to be initialized.
* r and a may point to the same object, but neither can be equal to b. The magnitudes
* of a and b must not exceed 8.
* Performs {r = a * b}
* On output, r will have magnitude 1, but won't be normalized.
*/
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8.
* The output magnitude is 1 (but not guaranteed to be normalized). */
/** Square a field element.
*
* On input, a must be a valid field element; r does not need to be initialized. The magnitude
* of a must not exceed 8.
* Performs {r = a**2}
* On output, r will have magnitude 1, but won't be normalized.
*/
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
/** If a has a square root, it is computed in r and 1 is returned. If a does not
* have a square root, the root of its negation is computed and 0 is returned.
* The input's magnitude can be at most 8. The output magnitude is 1 (but not
* guaranteed to be normalized). The result in r will always be a square
* itself. */
static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a);
/** Compute a square root of a field element.
*
* On input, a must be a valid field element with magnitude<=8; r need not be initialized.
* If sqrt(a) exists, performs {r = sqrt(a)} and returns 1.
* Otherwise, sqrt(-a) exists. The function performs {r = sqrt(-a)} and returns 0.
* The resulting value represented by r will be a square itself.
* Variables r and a must not point to the same object.
* On output, r will have magnitude 1 but will not be normalized.
*/
static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a);
/** Checks whether a field element is a quadratic residue. */
static int secp256k1_fe_is_quad_var(const secp256k1_fe *a);
/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
* at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */
/** Compute the modular inverse of a field element.
*
* On input, a must be a valid field element; r need not be initialized.
* Performs {r = a**(p-2)} (which maps 0 to 0, and every other element to its
* inverse).
* On output, r will have magnitude (a.magnitude != 0) and be normalized.
*/
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a);
/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */
/** Compute the modular inverse of a field element, without constant-time guarantee.
*
* Behaves identically to secp256k1_fe_inv, but is not constant-time in a.
*/
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a);
/** Convert a field element to the storage type. */
/** Convert a field element to secp256k1_fe_storage.
*
* On input, a must be a valid normalized field element.
* Performs {r = a}.
*/
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
/** Convert a field element back from the storage type. */
/** Convert a field element back from secp256k1_fe_storage.
*
* On input, r need not be initialized.
* Performs {r = a}.
* On output, r will be normalized and will have magnitude 1.
*/
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. 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. Both *r and *a must be initialized.*/
/** Conditionally move a field element in constant time.
*
* On input, both r and a must be valid field elements. Flag must be 0 or 1.
* Performs {r = flag ? a : r}.
*
* On output, r's magnitude will be the maximum of both input magnitudes.
* It will be normalized if and only if both inputs were normalized.
*/
static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
/** Halves the value of a field element modulo the field prime. Constant-time.
* For an input magnitude 'm', the output magnitude is set to 'floor(m/2) + 1'.
* The output is not guaranteed to be normalized, regardless of the input. */
/** Halve the value of a field element modulo the field prime in constant-time.
*
* On input, r must be a valid field element.
* On output, r will be normalized and have magnitude floor(m/2) + 1 where m is
* the magnitude of r on input.
*/
static void secp256k1_fe_half(secp256k1_fe *r);
/** Sets each limb of 'r' to its upper bound at magnitude 'm'. The output will also have its
* magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */
/** Sets r to a field element with magnitude m, normalized if (and only if) m==0.
* The value is chosen so that it is likely to trigger edge cases related to
* internal overflows. */
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
/** Determine whether a is a square (modulo p).
*
* On input, a must be a valid field element.
*/
static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
/** Check invariants on a field element (no-op unless VERIFY is enabled). */
static void secp256k1_fe_verify(const secp256k1_fe *a);
#endif /* SECP256K1_FIELD_H */

View File

@ -9,15 +9,28 @@
#include <stdint.h>
/** This field implementation represents the value as 10 uint32_t limbs in base
* 2^26. */
typedef struct {
/* X = sum(i=0..9, n[i]*2^(i*26)) mod p
* where p = 2^256 - 0x1000003D1
*/
/* A field element f represents the sum(i=0..9, f.n[i] << (i*26)) mod p,
* where p is the field modulus, 2^256 - 2^32 - 977.
*
* The individual limbs f.n[i] can exceed 2^26; the field's magnitude roughly
* corresponds to how much excess is allowed. The value
* sum(i=0..9, f.n[i] << (i*26)) may exceed p, unless the field element is
* normalized. */
uint32_t n[10];
#ifdef VERIFY
int magnitude;
int normalized;
#endif
/*
* Magnitude m requires:
* n[i] <= 2 * m * (2^26 - 1) for i=0..8
* n[9] <= 2 * m * (2^22 - 1)
*
* Normalized requires:
* n[i] <= (2^26 - 1) for i=0..8
* sum(i=0..9, n[i] << (i*26)) < p
* (together these imply n[9] <= 2^22 - 1)
*/
SECP256K1_FE_VERIFY_FIELDS
} secp256k1_fe;
/* Unpacks a constant into a overlapping multi-limbed FE element. */
@ -34,12 +47,6 @@ typedef struct {
(((uint32_t)d7) >> 10) \
}
#ifdef VERIFY
#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
#else
#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
#endif
typedef struct {
uint32_t n[8];
} secp256k1_fe_storage;

View File

@ -7,51 +7,37 @@
#ifndef SECP256K1_FIELD_REPR_IMPL_H
#define SECP256K1_FIELD_REPR_IMPL_H
#include "checkmem.h"
#include "util.h"
#include "field.h"
#include "modinv32_impl.h"
/** See the comment at the top of field_5x52_impl.h for more details.
*
* Here, we represent field elements as 10 uint32_t's in base 2^26, least significant first,
* where limbs can contain >26 bits.
* A magnitude M means:
* - 2*M*(2^22-1) is the max (inclusive) of the most significant limb
* - 2*M*(2^26-1) is the max (inclusive) of the remaining limbs
*/
#ifdef VERIFY
static void secp256k1_fe_verify(const secp256k1_fe *a) {
static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
const uint32_t *d = a->n;
int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
r &= (d[0] <= 0x3FFFFFFUL * m);
r &= (d[1] <= 0x3FFFFFFUL * m);
r &= (d[2] <= 0x3FFFFFFUL * m);
r &= (d[3] <= 0x3FFFFFFUL * m);
r &= (d[4] <= 0x3FFFFFFUL * m);
r &= (d[5] <= 0x3FFFFFFUL * m);
r &= (d[6] <= 0x3FFFFFFUL * m);
r &= (d[7] <= 0x3FFFFFFUL * m);
r &= (d[8] <= 0x3FFFFFFUL * m);
r &= (d[9] <= 0x03FFFFFUL * m);
r &= (a->magnitude >= 0);
r &= (a->magnitude <= 32);
int m = a->normalized ? 1 : 2 * a->magnitude;
VERIFY_CHECK(d[0] <= 0x3FFFFFFUL * m);
VERIFY_CHECK(d[1] <= 0x3FFFFFFUL * m);
VERIFY_CHECK(d[2] <= 0x3FFFFFFUL * m);
VERIFY_CHECK(d[3] <= 0x3FFFFFFUL * m);
VERIFY_CHECK(d[4] <= 0x3FFFFFFUL * m);
VERIFY_CHECK(d[5] <= 0x3FFFFFFUL * m);
VERIFY_CHECK(d[6] <= 0x3FFFFFFUL * m);
VERIFY_CHECK(d[7] <= 0x3FFFFFFUL * m);
VERIFY_CHECK(d[8] <= 0x3FFFFFFUL * m);
VERIFY_CHECK(d[9] <= 0x03FFFFFUL * m);
if (a->normalized) {
r &= (a->magnitude <= 1);
if (r && (d[9] == 0x03FFFFFUL)) {
if (d[9] == 0x03FFFFFUL) {
uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2];
if (mid == 0x3FFFFFFUL) {
r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL);
VERIFY_CHECK((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL);
}
}
}
VERIFY_CHECK(r == 1);
}
#endif
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
VERIFY_CHECK(m >= 0);
VERIFY_CHECK(m <= 2048);
static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) {
r->n[0] = 0x3FFFFFFUL * 2 * m;
r->n[1] = 0x3FFFFFFUL * 2 * m;
r->n[2] = 0x3FFFFFFUL * 2 * m;
@ -62,14 +48,9 @@ static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
r->n[7] = 0x3FFFFFFUL * 2 * m;
r->n[8] = 0x3FFFFFFUL * 2 * m;
r->n[9] = 0x03FFFFFUL * 2 * m;
#ifdef VERIFY
r->magnitude = m;
r->normalized = (m == 0);
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_normalize(secp256k1_fe *r) {
static void secp256k1_fe_impl_normalize(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@ -116,15 +97,9 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) {
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@ -148,14 +123,9 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
#ifdef VERIFY
r->magnitude = 1;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@ -203,15 +173,9 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
@ -240,7 +204,7 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
}
static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
uint32_t z0, z1;
uint32_t x;
@ -292,53 +256,29 @@ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0x3FFFFFFUL);
}
SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0;
#ifdef VERIFY
r->magnitude = (a != 0);
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) {
const uint32_t *t = a->n;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0;
}
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
return a->n[0] & 1;
}
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
int i;
#ifdef VERIFY
a->magnitude = 0;
a->normalized = 1;
#endif
for (i=0; i<10; i++) {
a->n[i] = 0;
}
}
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
VERIFY_CHECK(b->normalized);
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
#endif
for (i = 9; i >= 0; i--) {
if (a->n[i] > b->n[i]) {
return 1;
@ -350,8 +290,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
return 0;
}
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
int ret;
static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
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);
@ -362,26 +301,15 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
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;
if (ret) {
r->normalized = 1;
secp256k1_fe_verify(r);
} else {
r->normalized = 0;
}
#endif
return ret;
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
secp256k1_fe_impl_set_b32_mod(r, a);
return !((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));
}
/** 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) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
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);
@ -416,15 +344,15 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[31] = a->n[0] & 0xff;
}
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= m);
secp256k1_fe_verify(a);
SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
/* For all legal values of m (0..31), the following properties hold: */
VERIFY_CHECK(0x3FFFC2FUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
VERIFY_CHECK(0x3FFFFBFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
VERIFY_CHECK(0x3FFFFFFUL * 2 * (m + 1) >= 0x3FFFFFFUL * 2 * m);
VERIFY_CHECK(0x03FFFFFUL * 2 * (m + 1) >= 0x03FFFFFUL * 2 * m);
#endif
/* Due to the properties above, the left hand in the subtractions below is never less than
* the right hand. */
r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0];
r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1];
r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2];
@ -435,14 +363,9 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k
r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7];
r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8];
r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9];
#ifdef VERIFY
r->magnitude = m + 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) {
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
@ -453,17 +376,9 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
r->n[7] *= a;
r->n[8] *= a;
r->n[9] *= a;
#ifdef VERIFY
r->magnitude *= a;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
secp256k1_fe_verify(a);
#endif
SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) {
r->n[0] += a->n[0];
r->n[1] += a->n[1];
r->n[2] += a->n[2];
@ -474,11 +389,10 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_f
r->n[7] += a->n[7];
r->n[8] += a->n[8];
r->n[9] += a->n[9];
#ifdef VERIFY
r->magnitude += a->magnitude;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) {
r->n[0] += a;
}
#if defined(USE_EXTERNAL_ASM)
@ -1100,40 +1014,18 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t
}
#endif
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8);
VERIFY_CHECK(b->magnitude <= 8);
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(r != b);
VERIFY_CHECK(a != b);
#endif
SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
secp256k1_fe_mul_inner(r->n, a->n, b->n);
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8);
secp256k1_fe_verify(a);
#endif
SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe_sqr_inner(r->n, a->n);
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint32_t mask0, mask1;
volatile int vflag = flag;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@ -1146,25 +1038,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
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 (flag) {
r->magnitude = a->magnitude;
r->normalized = a->normalized;
}
#endif
}
static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4],
t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9];
uint32_t one = (uint32_t)1;
uint32_t mask = -(t0 & one) >> 6;
#ifdef VERIFY
secp256k1_fe_verify(r);
VERIFY_CHECK(r->magnitude < 32);
#endif
/* Bounds analysis (over the rationals).
*
* Let m = r->magnitude
@ -1211,10 +1092,8 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
*
* Current bounds: t0..t8 <= C * (m/2 + 1/2)
* t9 <= D * (m/2 + 1/4)
*/
#ifdef VERIFY
/* Therefore the output magnitude (M) has to be set such that:
*
* Therefore the output magnitude (M) has to be set such that:
* t0..t8: C * M >= C * (m/2 + 1/2)
* t9: D * M >= D * (m/2 + 1/4)
*
@ -1224,16 +1103,12 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
* and since we want the smallest such integer value for M:
* M == floor(m/2) + 1
*/
r->magnitude = (r->magnitude >> 1) + 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint32_t mask0, mask1;
volatile int vflag = flag;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = vflag + ~((uint32_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@ -1246,10 +1121,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r,
r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1);
}
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
#endif
static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
r->n[0] = a->n[0] | a->n[1] << 26;
r->n[1] = a->n[1] >> 6 | a->n[2] << 20;
r->n[2] = a->n[2] >> 12 | a->n[3] << 14;
@ -1260,7 +1132,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe
r->n[7] = a->n[8] >> 16 | a->n[9] << 10;
}
static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
r->n[0] = a->n[0] & 0x3FFFFFFUL;
r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL);
r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL);
@ -1271,11 +1143,6 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const se
r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL);
r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL);
r->n[9] = a->n[7] >> 10;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32_signed30 *a) {
@ -1306,12 +1173,6 @@ static void secp256k1_fe_from_signed30(secp256k1_fe *r, const secp256k1_modinv32
r->n[7] = (a6 >> 2 ) & M26;
r->n[8] = (a6 >> 28 | a7 << 2) & M26;
r->n[9] = (a7 >> 24 | a8 << 6);
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp256k1_fe *a) {
@ -1319,10 +1180,6 @@ static void secp256k1_fe_to_signed30(secp256k1_modinv32_signed30 *r, const secp2
const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4],
a5 = a->n[5], a6 = a->n[6], a7 = a->n[7], a8 = a->n[8], a9 = a->n[9];
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
#endif
r->v[0] = (a0 | a1 << 26) & M30;
r->v[1] = (a1 >> 4 | a2 << 22) & M30;
r->v[2] = (a2 >> 8 | a3 << 18) & M30;
@ -1340,30 +1197,47 @@ static const secp256k1_modinv32_modinfo secp256k1_const_modinfo_fe = {
0x2DDACACFL
};
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp;
static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp = *x;
secp256k1_modinv32_signed30 s;
tmp = *x;
secp256k1_fe_normalize(&tmp);
secp256k1_fe_to_signed30(&s, &tmp);
secp256k1_modinv32(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed30(r, &s);
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
}
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp;
static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp = *x;
secp256k1_modinv32_signed30 s;
tmp = *x;
secp256k1_fe_normalize_var(&tmp);
secp256k1_fe_to_signed30(&s, &tmp);
secp256k1_modinv32_var(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed30(r, &s);
}
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv32_signed30 s;
int jac, ret;
tmp = *x;
secp256k1_fe_normalize_var(&tmp);
/* secp256k1_jacobi32_maybe_var cannot deal with input 0. */
if (secp256k1_fe_is_zero(&tmp)) return 1;
secp256k1_fe_to_signed30(&s, &tmp);
jac = secp256k1_jacobi32_maybe_var(&s, &secp256k1_const_modinfo_fe);
if (jac == 0) {
/* secp256k1_jacobi32_maybe_var failed to compute the Jacobi symbol. Fall back
* to computing a square root. This should be extremely rare with random
* input (except in VERIFY mode, where a lower iteration count is used). */
secp256k1_fe dummy;
ret = secp256k1_fe_sqrt(&dummy, &tmp);
} else {
ret = jac >= 0;
}
return ret;
}
#endif /* SECP256K1_FIELD_REPR_IMPL_H */

View File

@ -9,15 +9,28 @@
#include <stdint.h>
/** This field implementation represents the value as 5 uint64_t limbs in base
* 2^52. */
typedef struct {
/* X = sum(i=0..4, n[i]*2^(i*52)) mod p
* where p = 2^256 - 0x1000003D1
*/
/* A field element f represents the sum(i=0..4, f.n[i] << (i*52)) mod p,
* where p is the field modulus, 2^256 - 2^32 - 977.
*
* The individual limbs f.n[i] can exceed 2^52; the field's magnitude roughly
* corresponds to how much excess is allowed. The value
* sum(i=0..4, f.n[i] << (i*52)) may exceed p, unless the field element is
* normalized. */
uint64_t n[5];
#ifdef VERIFY
int magnitude;
int normalized;
#endif
/*
* Magnitude m requires:
* n[i] <= 2 * m * (2^52 - 1) for i=0..3
* n[4] <= 2 * m * (2^48 - 1)
*
* Normalized requires:
* n[i] <= (2^52 - 1) for i=0..3
* sum(i=0..4, n[i] << (i*52)) < p
* (together these imply n[4] <= 2^48 - 1)
*/
SECP256K1_FE_VERIFY_FIELDS
} secp256k1_fe;
/* Unpacks a constant into a overlapping multi-limbed FE element. */
@ -29,12 +42,6 @@ typedef struct {
((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \
}
#ifdef VERIFY
#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1}
#else
#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))}
#endif
typedef struct {
uint64_t n[4];
} secp256k1_fe_storage;

View File

@ -14,6 +14,8 @@
#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H
#define SECP256K1_FIELD_INNER5X52_IMPL_H
#include "util.h"
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
/**
* Registers: rdx:rax = multiplication accumulator

View File

@ -7,10 +7,7 @@
#ifndef SECP256K1_FIELD_REPR_IMPL_H
#define SECP256K1_FIELD_REPR_IMPL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "checkmem.h"
#include "util.h"
#include "field.h"
#include "modinv64_impl.h"
@ -21,59 +18,33 @@
#include "field_5x52_int128_impl.h"
#endif
/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F,
* represented as 5 uint64_t's in base 2^52, least significant first. Note that the limbs are allowed to
* contain >52 bits each.
*
* Each field element has a 'magnitude' associated with it. Internally, a magnitude M means:
* - 2*M*(2^48-1) is the max (inclusive) of the most significant limb
* - 2*M*(2^52-1) is the max (inclusive) of the remaining limbs
*
* Operations have different rules for propagating magnitude to their outputs. If an operation takes a
* magnitude M as a parameter, that means the magnitude of input field elements can be at most M (inclusive).
*
* Each field element also has a 'normalized' flag. A field element is normalized if its magnitude is either
* 0 or 1, and its value is already reduced modulo the order of the field.
*/
#ifdef VERIFY
static void secp256k1_fe_verify(const secp256k1_fe *a) {
static void secp256k1_fe_impl_verify(const secp256k1_fe *a) {
const uint64_t *d = a->n;
int m = a->normalized ? 1 : 2 * a->magnitude, r = 1;
int m = a->normalized ? 1 : 2 * a->magnitude;
/* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */
r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m);
r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m);
r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m);
r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m);
r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m);
r &= (a->magnitude >= 0);
r &= (a->magnitude <= 2048);
VERIFY_CHECK(d[0] <= 0xFFFFFFFFFFFFFULL * m);
VERIFY_CHECK(d[1] <= 0xFFFFFFFFFFFFFULL * m);
VERIFY_CHECK(d[2] <= 0xFFFFFFFFFFFFFULL * m);
VERIFY_CHECK(d[3] <= 0xFFFFFFFFFFFFFULL * m);
VERIFY_CHECK(d[4] <= 0x0FFFFFFFFFFFFULL * m);
if (a->normalized) {
r &= (a->magnitude <= 1);
if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {
r &= (d[0] < 0xFFFFEFFFFFC2FULL);
if ((d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) {
VERIFY_CHECK(d[0] < 0xFFFFEFFFFFC2FULL);
}
}
VERIFY_CHECK(r == 1);
}
#endif
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m) {
VERIFY_CHECK(m >= 0);
VERIFY_CHECK(m <= 2048);
static void secp256k1_fe_impl_get_bounds(secp256k1_fe *r, int m) {
r->n[0] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * m;
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * m;
#ifdef VERIFY
r->magnitude = m;
r->normalized = (m == 0);
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_normalize(secp256k1_fe *r) {
static void secp256k1_fe_impl_normalize(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@ -108,15 +79,9 @@ static void secp256k1_fe_normalize(secp256k1_fe *r) {
t4 &= 0x0FFFFFFFFFFFFULL;
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@ -133,14 +98,9 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
VERIFY_CHECK(t4 >> 49 == 0);
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
#ifdef VERIFY
r->magnitude = 1;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* Reduce t4 at the start so there will be at most a single carry from the first pass */
@ -176,15 +136,9 @@ static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
}
r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
/* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */
@ -207,7 +161,7 @@ static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
}
static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r) {
uint64_t t0, t1, t2, t3, t4;
uint64_t z0, z1;
uint64_t x;
@ -248,53 +202,29 @@ static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL);
}
SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
SECP256K1_INLINE static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a) {
r->n[0] = a;
r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0;
#ifdef VERIFY
r->magnitude = (a != 0);
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
SECP256K1_INLINE static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a) {
const uint64_t *t = a->n;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0;
}
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
SECP256K1_INLINE static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a) {
return a->n[0] & 1;
}
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
SECP256K1_INLINE static void secp256k1_fe_impl_clear(secp256k1_fe *a) {
int i;
#ifdef VERIFY
a->magnitude = 0;
a->normalized = 1;
#endif
for (i=0; i<5; i++) {
a->n[i] = 0;
}
}
static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
int i;
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
VERIFY_CHECK(b->normalized);
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
#endif
for (i = 4; i >= 0; i--) {
if (a->n[i] > b->n[i]) {
return 1;
@ -306,8 +236,7 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
return 0;
}
static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
int ret;
static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
r->n[0] = (uint64_t)a[31]
| ((uint64_t)a[30] << 8)
| ((uint64_t)a[29] << 16)
@ -342,25 +271,15 @@ static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) {
| ((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;
if (ret) {
r->normalized = 1;
secp256k1_fe_verify(r);
} else {
r->normalized = 0;
}
#endif
return ret;
}
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
secp256k1_fe_impl_set_b32_mod(r, a);
return !((r->n[4] == 0x0FFFFFFFFFFFFULL) & ((r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL) & (r->n[0] >= 0xFFFFEFFFFFC2FULL));
}
/** 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) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
secp256k1_fe_verify(a);
#endif
static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[0] = (a->n[4] >> 40) & 0xFF;
r[1] = (a->n[4] >> 32) & 0xFF;
r[2] = (a->n[4] >> 24) & 0xFF;
@ -395,89 +314,53 @@ static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
r[31] = a->n[0] & 0xFF;
}
SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= m);
secp256k1_fe_verify(a);
SECP256K1_INLINE static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
/* For all legal values of m (0..31), the following properties hold: */
VERIFY_CHECK(0xFFFFEFFFFFC2FULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
VERIFY_CHECK(0xFFFFFFFFFFFFFULL * 2 * (m + 1) >= 0xFFFFFFFFFFFFFULL * 2 * m);
VERIFY_CHECK(0x0FFFFFFFFFFFFULL * 2 * (m + 1) >= 0x0FFFFFFFFFFFFULL * 2 * m);
#endif
/* Due to the properties above, the left hand in the subtractions below is never less than
* the right hand. */
r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0];
r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1];
r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2];
r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3];
r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4];
#ifdef VERIFY
r->magnitude = m + 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) {
SECP256K1_INLINE static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a) {
r->n[0] *= a;
r->n[1] *= a;
r->n[2] *= a;
r->n[3] *= a;
r->n[4] *= a;
#ifdef VERIFY
r->magnitude *= a;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
secp256k1_fe_verify(a);
#endif
SECP256K1_INLINE static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a) {
r->n[0] += a;
}
SECP256K1_INLINE static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a) {
r->n[0] += a->n[0];
r->n[1] += a->n[1];
r->n[2] += a->n[2];
r->n[3] += a->n[3];
r->n[4] += a->n[4];
#ifdef VERIFY
r->magnitude += a->magnitude;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8);
VERIFY_CHECK(b->magnitude <= 8);
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(r != b);
VERIFY_CHECK(a != b);
#endif
SECP256K1_INLINE static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
secp256k1_fe_mul_inner(r->n, a->n, b->n);
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->magnitude <= 8);
secp256k1_fe_verify(a);
#endif
SECP256K1_INLINE static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe_sqr_inner(r->n, a->n);
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
SECP256K1_INLINE static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
uint64_t mask0, mask1;
volatile int vflag = flag;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = vflag + ~((uint64_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@ -485,24 +368,13 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_
r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1);
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 (flag) {
r->magnitude = a->magnitude;
r->normalized = a->normalized;
}
#endif
}
static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
static SECP256K1_INLINE void secp256k1_fe_impl_half(secp256k1_fe *r) {
uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4];
uint64_t one = (uint64_t)1;
uint64_t mask = -(t0 & one) >> 12;
#ifdef VERIFY
secp256k1_fe_verify(r);
VERIFY_CHECK(r->magnitude < 32);
#endif
/* Bounds analysis (over the rationals).
*
* Let m = r->magnitude
@ -539,10 +411,8 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
*
* Current bounds: t0..t3 <= C * (m/2 + 1/2)
* t4 <= D * (m/2 + 1/4)
*/
#ifdef VERIFY
/* Therefore the output magnitude (M) has to be set such that:
*
* Therefore the output magnitude (M) has to be set such that:
* t0..t3: C * M >= C * (m/2 + 1/2)
* t4: D * M >= D * (m/2 + 1/4)
*
@ -552,16 +422,12 @@ static SECP256K1_INLINE void secp256k1_fe_half(secp256k1_fe *r) {
* and since we want the smallest such integer value for M:
* M == floor(m/2) + 1
*/
r->magnitude = (r->magnitude >> 1) + 1;
r->normalized = 0;
secp256k1_fe_verify(r);
#endif
}
static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) {
uint64_t mask0, mask1;
volatile int vflag = flag;
VG_CHECK_VERIFY(r->n, sizeof(r->n));
SECP256K1_CHECKMEM_CHECK_VERIFY(r->n, sizeof(r->n));
mask0 = vflag + ~((uint64_t)0);
mask1 = ~mask0;
r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1);
@ -570,27 +436,19 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r,
r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1);
}
static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
#endif
static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
r->n[0] = a->n[0] | a->n[1] << 52;
r->n[1] = a->n[1] >> 12 | a->n[2] << 40;
r->n[2] = a->n[2] >> 24 | a->n[3] << 28;
r->n[3] = a->n[3] >> 36 | a->n[4] << 16;
}
static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
static SECP256K1_INLINE void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL;
r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL);
r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL);
r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL);
r->n[4] = a->n[3] >> 16;
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64_signed62 *a) {
@ -611,22 +469,12 @@ static void secp256k1_fe_from_signed62(secp256k1_fe *r, const secp256k1_modinv64
r->n[2] = (a1 >> 42 | a2 << 20) & M52;
r->n[3] = (a2 >> 32 | a3 << 30) & M52;
r->n[4] = (a3 >> 22 | a4 << 40);
#ifdef VERIFY
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
#endif
}
static void secp256k1_fe_to_signed62(secp256k1_modinv64_signed62 *r, const secp256k1_fe *a) {
const uint64_t M62 = UINT64_MAX >> 2;
const uint64_t a0 = a->n[0], a1 = a->n[1], a2 = a->n[2], a3 = a->n[3], a4 = a->n[4];
#ifdef VERIFY
VERIFY_CHECK(a->normalized);
#endif
r->v[0] = (a0 | a1 << 52) & M62;
r->v[1] = (a1 >> 10 | a2 << 42) & M62;
r->v[2] = (a2 >> 20 | a3 << 32) & M62;
@ -639,34 +487,47 @@ static const secp256k1_modinv64_modinfo secp256k1_const_modinfo_fe = {
0x27C7F6E22DDACACFLL
};
static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp;
static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp = *x;
secp256k1_modinv64_signed62 s;
tmp = *x;
secp256k1_fe_normalize(&tmp);
secp256k1_fe_to_signed62(&s, &tmp);
secp256k1_modinv64(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed62(r, &s);
#ifdef VERIFY
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
#endif
}
static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp;
static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
secp256k1_fe tmp = *x;
secp256k1_modinv64_signed62 s;
tmp = *x;
secp256k1_fe_normalize_var(&tmp);
secp256k1_fe_to_signed62(&s, &tmp);
secp256k1_modinv64_var(&s, &secp256k1_const_modinfo_fe);
secp256k1_fe_from_signed62(r, &s);
}
#ifdef VERIFY
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
#endif
static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x) {
secp256k1_fe tmp;
secp256k1_modinv64_signed62 s;
int jac, ret;
tmp = *x;
secp256k1_fe_normalize_var(&tmp);
/* secp256k1_jacobi64_maybe_var cannot deal with input 0. */
if (secp256k1_fe_is_zero(&tmp)) return 1;
secp256k1_fe_to_signed62(&s, &tmp);
jac = secp256k1_jacobi64_maybe_var(&s, &secp256k1_const_modinfo_fe);
if (jac == 0) {
/* secp256k1_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back
* to computing a square root. This should be extremely rare with random
* input (except in VERIFY mode, where a lower iteration count is used). */
secp256k1_fe dummy;
ret = secp256k1_fe_sqrt(&dummy, &tmp);
} else {
ret = jac >= 0;
}
return ret;
}
#endif /* SECP256K1_FIELD_REPR_IMPL_H */

View File

@ -9,14 +9,19 @@
#include <stdint.h>
#include "int128.h"
#include "util.h"
#ifdef VERIFY
#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0)
#define VERIFY_BITS_128(x, n) VERIFY_CHECK(secp256k1_u128_check_bits((x), (n)))
#else
#define VERIFY_BITS(x, n) do { } while(0)
#define VERIFY_BITS_128(x, n) do { } while(0)
#endif
SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) {
uint128_t c, d;
secp256k1_uint128 c, d;
uint64_t t3, t4, tx, u0;
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
@ -40,121 +45,119 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
* Note that [x 0 0 0 0 0] = [x*R].
*/
d = (uint128_t)a0 * b[3]
+ (uint128_t)a1 * b[2]
+ (uint128_t)a2 * b[1]
+ (uint128_t)a3 * b[0];
VERIFY_BITS(d, 114);
secp256k1_u128_mul(&d, a0, b[3]);
secp256k1_u128_accum_mul(&d, a1, b[2]);
secp256k1_u128_accum_mul(&d, a2, b[1]);
secp256k1_u128_accum_mul(&d, a3, b[0]);
VERIFY_BITS_128(&d, 114);
/* [d 0 0 0] = [p3 0 0 0] */
c = (uint128_t)a4 * b[4];
VERIFY_BITS(c, 112);
secp256k1_u128_mul(&c, a4, b[4]);
VERIFY_BITS_128(&c, 112);
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (uint128_t)R * (uint64_t)c; c >>= 64;
VERIFY_BITS(d, 115);
VERIFY_BITS(c, 48);
secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64);
VERIFY_BITS_128(&d, 115);
VERIFY_BITS_128(&c, 48);
/* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
t3 = d & M; d >>= 52;
t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t3, 52);
VERIFY_BITS(d, 63);
VERIFY_BITS_128(&d, 63);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (uint128_t)a0 * b[4]
+ (uint128_t)a1 * b[3]
+ (uint128_t)a2 * b[2]
+ (uint128_t)a3 * b[1]
+ (uint128_t)a4 * b[0];
VERIFY_BITS(d, 115);
secp256k1_u128_accum_mul(&d, a0, b[4]);
secp256k1_u128_accum_mul(&d, a1, b[3]);
secp256k1_u128_accum_mul(&d, a2, b[2]);
secp256k1_u128_accum_mul(&d, a3, b[1]);
secp256k1_u128_accum_mul(&d, a4, b[0]);
VERIFY_BITS_128(&d, 115);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
d += (uint128_t)(R << 12) * (uint64_t)c;
VERIFY_BITS(d, 116);
secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c));
VERIFY_BITS_128(&d, 116);
/* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
t4 = d & M; d >>= 52;
t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t4, 52);
VERIFY_BITS(d, 64);
VERIFY_BITS_128(&d, 64);
/* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
tx = (t4 >> 48); t4 &= (M >> 4);
VERIFY_BITS(tx, 4);
VERIFY_BITS(t4, 48);
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
c = (uint128_t)a0 * b[0];
VERIFY_BITS(c, 112);
secp256k1_u128_mul(&c, a0, b[0]);
VERIFY_BITS_128(&c, 112);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
d += (uint128_t)a1 * b[4]
+ (uint128_t)a2 * b[3]
+ (uint128_t)a3 * b[2]
+ (uint128_t)a4 * b[1];
VERIFY_BITS(d, 115);
secp256k1_u128_accum_mul(&d, a1, b[4]);
secp256k1_u128_accum_mul(&d, a2, b[3]);
secp256k1_u128_accum_mul(&d, a3, b[2]);
secp256k1_u128_accum_mul(&d, a4, b[1]);
VERIFY_BITS_128(&d, 115);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = d & M; d >>= 52;
u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(u0, 52);
VERIFY_BITS(d, 63);
VERIFY_BITS_128(&d, 63);
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = (u0 << 4) | tx;
VERIFY_BITS(u0, 56);
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
c += (uint128_t)u0 * (R >> 4);
VERIFY_BITS(c, 115);
secp256k1_u128_accum_mul(&c, u0, R >> 4);
VERIFY_BITS_128(&c, 115);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
r[0] = c & M; c >>= 52;
r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[0], 52);
VERIFY_BITS(c, 61);
VERIFY_BITS_128(&c, 61);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
c += (uint128_t)a0 * b[1]
+ (uint128_t)a1 * b[0];
VERIFY_BITS(c, 114);
secp256k1_u128_accum_mul(&c, a0, b[1]);
secp256k1_u128_accum_mul(&c, a1, b[0]);
VERIFY_BITS_128(&c, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
d += (uint128_t)a2 * b[4]
+ (uint128_t)a3 * b[3]
+ (uint128_t)a4 * b[2];
VERIFY_BITS(d, 114);
secp256k1_u128_accum_mul(&d, a2, b[4]);
secp256k1_u128_accum_mul(&d, a3, b[3]);
secp256k1_u128_accum_mul(&d, a4, b[2]);
VERIFY_BITS_128(&d, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (d & M) * R; d >>= 52;
VERIFY_BITS(c, 115);
VERIFY_BITS(d, 62);
secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52);
VERIFY_BITS_128(&c, 115);
VERIFY_BITS_128(&d, 62);
/* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
r[1] = c & M; c >>= 52;
r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[1], 52);
VERIFY_BITS(c, 63);
VERIFY_BITS_128(&c, 63);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (uint128_t)a0 * b[2]
+ (uint128_t)a1 * b[1]
+ (uint128_t)a2 * b[0];
VERIFY_BITS(c, 114);
secp256k1_u128_accum_mul(&c, a0, b[2]);
secp256k1_u128_accum_mul(&c, a1, b[1]);
secp256k1_u128_accum_mul(&c, a2, b[0]);
VERIFY_BITS_128(&c, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
d += (uint128_t)a3 * b[4]
+ (uint128_t)a4 * b[3];
VERIFY_BITS(d, 114);
secp256k1_u128_accum_mul(&d, a3, b[4]);
secp256k1_u128_accum_mul(&d, a4, b[3]);
VERIFY_BITS_128(&d, 114);
/* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (uint128_t)R * (uint64_t)d; d >>= 64;
VERIFY_BITS(c, 115);
VERIFY_BITS(d, 50);
secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64);
VERIFY_BITS_128(&c, 115);
VERIFY_BITS_128(&d, 50);
/* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[2] = c & M; c >>= 52;
r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[2], 52);
VERIFY_BITS(c, 63);
VERIFY_BITS_128(&c, 63);
/* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (uint128_t)(R << 12) * (uint64_t)d + t3;
VERIFY_BITS(c, 100);
secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d));
secp256k1_u128_accum_u64(&c, t3);
VERIFY_BITS_128(&c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[3] = c & M; c >>= 52;
r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[3], 52);
VERIFY_BITS(c, 48);
VERIFY_BITS_128(&c, 48);
/* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += t4;
VERIFY_BITS(c, 49);
/* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[4] = c;
r[4] = secp256k1_u128_to_u64(&c) + t4;
VERIFY_BITS(r[4], 49);
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}
SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) {
uint128_t c, d;
secp256k1_uint128 c, d;
uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4];
int64_t t3, t4, tx, u0;
const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL;
@ -170,107 +173,105 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t
* Note that [x 0 0 0 0 0] = [x*R].
*/
d = (uint128_t)(a0*2) * a3
+ (uint128_t)(a1*2) * a2;
VERIFY_BITS(d, 114);
secp256k1_u128_mul(&d, a0*2, a3);
secp256k1_u128_accum_mul(&d, a1*2, a2);
VERIFY_BITS_128(&d, 114);
/* [d 0 0 0] = [p3 0 0 0] */
c = (uint128_t)a4 * a4;
VERIFY_BITS(c, 112);
secp256k1_u128_mul(&c, a4, a4);
VERIFY_BITS_128(&c, 112);
/* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
d += (uint128_t)R * (uint64_t)c; c >>= 64;
VERIFY_BITS(d, 115);
VERIFY_BITS(c, 48);
secp256k1_u128_accum_mul(&d, R, secp256k1_u128_to_u64(&c)); secp256k1_u128_rshift(&c, 64);
VERIFY_BITS_128(&d, 115);
VERIFY_BITS_128(&c, 48);
/* [(c<<12) 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
t3 = d & M; d >>= 52;
t3 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t3, 52);
VERIFY_BITS(d, 63);
VERIFY_BITS_128(&d, 63);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */
a4 *= 2;
d += (uint128_t)a0 * a4
+ (uint128_t)(a1*2) * a3
+ (uint128_t)a2 * a2;
VERIFY_BITS(d, 115);
secp256k1_u128_accum_mul(&d, a0, a4);
secp256k1_u128_accum_mul(&d, a1*2, a3);
secp256k1_u128_accum_mul(&d, a2, a2);
VERIFY_BITS_128(&d, 115);
/* [(c<<12) 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
d += (uint128_t)(R << 12) * (uint64_t)c;
VERIFY_BITS(d, 116);
secp256k1_u128_accum_mul(&d, R << 12, secp256k1_u128_to_u64(&c));
VERIFY_BITS_128(&d, 116);
/* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
t4 = d & M; d >>= 52;
t4 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(t4, 52);
VERIFY_BITS(d, 64);
VERIFY_BITS_128(&d, 64);
/* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
tx = (t4 >> 48); t4 &= (M >> 4);
VERIFY_BITS(tx, 4);
VERIFY_BITS(t4, 48);
/* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */
c = (uint128_t)a0 * a0;
VERIFY_BITS(c, 112);
secp256k1_u128_mul(&c, a0, a0);
VERIFY_BITS_128(&c, 112);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */
d += (uint128_t)a1 * a4
+ (uint128_t)(a2*2) * a3;
VERIFY_BITS(d, 114);
secp256k1_u128_accum_mul(&d, a1, a4);
secp256k1_u128_accum_mul(&d, a2*2, a3);
VERIFY_BITS_128(&d, 114);
/* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = d & M; d >>= 52;
u0 = secp256k1_u128_to_u64(&d) & M; secp256k1_u128_rshift(&d, 52);
VERIFY_BITS(u0, 52);
VERIFY_BITS(d, 62);
VERIFY_BITS_128(&d, 62);
/* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
/* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
u0 = (u0 << 4) | tx;
VERIFY_BITS(u0, 56);
/* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
c += (uint128_t)u0 * (R >> 4);
VERIFY_BITS(c, 113);
secp256k1_u128_accum_mul(&c, u0, R >> 4);
VERIFY_BITS_128(&c, 113);
/* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */
r[0] = c & M; c >>= 52;
r[0] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[0], 52);
VERIFY_BITS(c, 61);
VERIFY_BITS_128(&c, 61);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */
a0 *= 2;
c += (uint128_t)a0 * a1;
VERIFY_BITS(c, 114);
secp256k1_u128_accum_mul(&c, a0, a1);
VERIFY_BITS_128(&c, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */
d += (uint128_t)a2 * a4
+ (uint128_t)a3 * a3;
VERIFY_BITS(d, 114);
secp256k1_u128_accum_mul(&d, a2, a4);
secp256k1_u128_accum_mul(&d, a3, a3);
VERIFY_BITS_128(&d, 114);
/* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (d & M) * R; d >>= 52;
VERIFY_BITS(c, 115);
VERIFY_BITS(d, 62);
secp256k1_u128_accum_mul(&c, secp256k1_u128_to_u64(&d) & M, R); secp256k1_u128_rshift(&d, 52);
VERIFY_BITS_128(&c, 115);
VERIFY_BITS_128(&d, 62);
/* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
r[1] = c & M; c >>= 52;
r[1] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[1], 52);
VERIFY_BITS(c, 63);
VERIFY_BITS_128(&c, 63);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */
c += (uint128_t)a0 * a2
+ (uint128_t)a1 * a1;
VERIFY_BITS(c, 114);
secp256k1_u128_accum_mul(&c, a0, a2);
secp256k1_u128_accum_mul(&c, a1, a1);
VERIFY_BITS_128(&c, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */
d += (uint128_t)a3 * a4;
VERIFY_BITS(d, 114);
secp256k1_u128_accum_mul(&d, a3, a4);
VERIFY_BITS_128(&d, 114);
/* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (uint128_t)R * (uint64_t)d; d >>= 64;
VERIFY_BITS(c, 115);
VERIFY_BITS(d, 50);
secp256k1_u128_accum_mul(&c, R, secp256k1_u128_to_u64(&d)); secp256k1_u128_rshift(&d, 64);
VERIFY_BITS_128(&c, 115);
VERIFY_BITS_128(&d, 50);
/* [(d<<12) 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[2] = c & M; c >>= 52;
r[2] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[2], 52);
VERIFY_BITS(c, 63);
VERIFY_BITS_128(&c, 63);
/* [(d<<12) 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += (uint128_t)(R << 12) * (uint64_t)d + t3;
VERIFY_BITS(c, 100);
secp256k1_u128_accum_mul(&c, R << 12, secp256k1_u128_to_u64(&d));
secp256k1_u128_accum_u64(&c, t3);
VERIFY_BITS_128(&c, 100);
/* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[3] = c & M; c >>= 52;
r[3] = secp256k1_u128_to_u64(&c) & M; secp256k1_u128_rshift(&c, 52);
VERIFY_BITS(r[3], 52);
VERIFY_BITS(c, 48);
VERIFY_BITS_128(&c, 48);
/* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
c += t4;
VERIFY_BITS(c, 49);
/* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
r[4] = c;
r[4] = secp256k1_u128_to_u64(&c) + t4;
VERIFY_BITS(r[4], 49);
/* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */
}

View File

@ -7,10 +7,7 @@
#ifndef SECP256K1_FIELD_IMPL_H
#define SECP256K1_FIELD_IMPL_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "field.h"
#include "util.h"
#if defined(SECP256K1_WIDEMUL_INT128)
@ -23,6 +20,12 @@
SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
#ifdef VERIFY
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(a->magnitude <= 1);
VERIFY_CHECK(b->magnitude <= 31);
#endif
secp256k1_fe_negate(&na, a, 1);
secp256k1_fe_add(&na, b);
return secp256k1_fe_normalizes_to_zero(&na);
@ -30,12 +33,18 @@ SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp
SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe na;
#ifdef VERIFY
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(a->magnitude <= 1);
VERIFY_CHECK(b->magnitude <= 31);
#endif
secp256k1_fe_negate(&na, a, 1);
secp256k1_fe_add(&na, b);
return secp256k1_fe_normalizes_to_zero_var(&na);
}
static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
static int secp256k1_fe_sqrt(secp256k1_fe * SECP256K1_RESTRICT r, const secp256k1_fe * SECP256K1_RESTRICT a) {
/** Given that p is congruent to 3 mod 4, we can compute the square root of
* a mod p as the (p+1)/4'th power of a.
*
@ -46,9 +55,13 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
* itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)).
*/
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
int j;
int j, ret;
#ifdef VERIFY
VERIFY_CHECK(r != a);
secp256k1_fe_verify(a);
VERIFY_CHECK(a->magnitude <= 8);
#endif
/** 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:
@ -132,12 +145,286 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
/* Check that a square root was actually calculated */
secp256k1_fe_sqr(&t1, r);
return secp256k1_fe_equal(&t1, a);
ret = secp256k1_fe_equal(&t1, a);
#ifdef VERIFY
if (!ret) {
secp256k1_fe_negate(&t1, &t1, 1);
secp256k1_fe_normalize_var(&t1);
VERIFY_CHECK(secp256k1_fe_equal_var(&t1, a));
}
#endif
return ret;
}
static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) {
secp256k1_fe r;
return secp256k1_fe_sqrt(&r, a);
#ifndef VERIFY
static void secp256k1_fe_verify(const secp256k1_fe *a) { (void)a; }
#else
static void secp256k1_fe_impl_verify(const secp256k1_fe *a);
static void secp256k1_fe_verify(const secp256k1_fe *a) {
/* Magnitude between 0 and 32. */
VERIFY_CHECK((a->magnitude >= 0) && (a->magnitude <= 32));
/* Normalized is 0 or 1. */
VERIFY_CHECK((a->normalized == 0) || (a->normalized == 1));
/* If normalized, magnitude must be 0 or 1. */
if (a->normalized) VERIFY_CHECK(a->magnitude <= 1);
/* Invoke implementation-specific checks. */
secp256k1_fe_impl_verify(a);
}
static void secp256k1_fe_impl_normalize(secp256k1_fe *r);
SECP256K1_INLINE static void secp256k1_fe_normalize(secp256k1_fe *r) {
secp256k1_fe_verify(r);
secp256k1_fe_impl_normalize(r);
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_normalize_weak(secp256k1_fe *r);
SECP256K1_INLINE static void secp256k1_fe_normalize_weak(secp256k1_fe *r) {
secp256k1_fe_verify(r);
secp256k1_fe_impl_normalize_weak(r);
r->magnitude = 1;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_normalize_var(secp256k1_fe *r);
SECP256K1_INLINE static void secp256k1_fe_normalize_var(secp256k1_fe *r) {
secp256k1_fe_verify(r);
secp256k1_fe_impl_normalize_var(r);
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
}
static int secp256k1_fe_impl_normalizes_to_zero(const secp256k1_fe *r);
SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero(const secp256k1_fe *r) {
secp256k1_fe_verify(r);
return secp256k1_fe_impl_normalizes_to_zero(r);
}
static int secp256k1_fe_impl_normalizes_to_zero_var(const secp256k1_fe *r);
SECP256K1_INLINE static int secp256k1_fe_normalizes_to_zero_var(const secp256k1_fe *r) {
secp256k1_fe_verify(r);
return secp256k1_fe_impl_normalizes_to_zero_var(r);
}
static void secp256k1_fe_impl_set_int(secp256k1_fe *r, int a);
SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) {
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
secp256k1_fe_impl_set_int(r, a);
r->magnitude = (a != 0);
r->normalized = 1;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_add_int(secp256k1_fe *r, int a);
SECP256K1_INLINE static void secp256k1_fe_add_int(secp256k1_fe *r, int a) {
VERIFY_CHECK(0 <= a && a <= 0x7FFF);
secp256k1_fe_verify(r);
secp256k1_fe_impl_add_int(r, a);
r->magnitude += 1;
r->normalized = 0;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_clear(secp256k1_fe *a);
SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) {
a->magnitude = 0;
a->normalized = 1;
secp256k1_fe_impl_clear(a);
secp256k1_fe_verify(a);
}
static int secp256k1_fe_impl_is_zero(const secp256k1_fe *a);
SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) {
secp256k1_fe_verify(a);
VERIFY_CHECK(a->normalized);
return secp256k1_fe_impl_is_zero(a);
}
static int secp256k1_fe_impl_is_odd(const secp256k1_fe *a);
SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) {
secp256k1_fe_verify(a);
VERIFY_CHECK(a->normalized);
return secp256k1_fe_impl_is_odd(a);
}
static int secp256k1_fe_impl_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b);
SECP256K1_INLINE static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) {
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(a->normalized);
VERIFY_CHECK(b->normalized);
return secp256k1_fe_impl_cmp_var(a, b);
}
static void secp256k1_fe_impl_set_b32_mod(secp256k1_fe *r, const unsigned char *a);
SECP256K1_INLINE static void secp256k1_fe_set_b32_mod(secp256k1_fe *r, const unsigned char *a) {
secp256k1_fe_impl_set_b32_mod(r, a);
r->magnitude = 1;
r->normalized = 0;
secp256k1_fe_verify(r);
}
static int secp256k1_fe_impl_set_b32_limit(secp256k1_fe *r, const unsigned char *a);
SECP256K1_INLINE static int secp256k1_fe_set_b32_limit(secp256k1_fe *r, const unsigned char *a) {
if (secp256k1_fe_impl_set_b32_limit(r, a)) {
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
return 1;
} else {
/* Mark the output field element as invalid. */
r->magnitude = -1;
return 0;
}
}
static void secp256k1_fe_impl_get_b32(unsigned char *r, const secp256k1_fe *a);
SECP256K1_INLINE static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) {
secp256k1_fe_verify(a);
VERIFY_CHECK(a->normalized);
secp256k1_fe_impl_get_b32(r, a);
}
static void secp256k1_fe_impl_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m);
SECP256K1_INLINE static void secp256k1_fe_negate_unchecked(secp256k1_fe *r, const secp256k1_fe *a, int m) {
secp256k1_fe_verify(a);
VERIFY_CHECK(m >= 0 && m <= 31);
VERIFY_CHECK(a->magnitude <= m);
secp256k1_fe_impl_negate_unchecked(r, a, m);
r->magnitude = m + 1;
r->normalized = 0;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_mul_int_unchecked(secp256k1_fe *r, int a);
SECP256K1_INLINE static void secp256k1_fe_mul_int_unchecked(secp256k1_fe *r, int a) {
secp256k1_fe_verify(r);
VERIFY_CHECK(a >= 0 && a <= 32);
VERIFY_CHECK(a*r->magnitude <= 32);
secp256k1_fe_impl_mul_int_unchecked(r, a);
r->magnitude *= a;
r->normalized = 0;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_add(secp256k1_fe *r, const secp256k1_fe *a);
SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe_verify(r);
secp256k1_fe_verify(a);
VERIFY_CHECK(r->magnitude + a->magnitude <= 32);
secp256k1_fe_impl_add(r, a);
r->magnitude += a->magnitude;
r->normalized = 0;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b);
SECP256K1_INLINE static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) {
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(a->magnitude <= 8);
VERIFY_CHECK(b->magnitude <= 8);
VERIFY_CHECK(r != b);
VERIFY_CHECK(a != b);
secp256k1_fe_impl_mul(r, a, b);
r->magnitude = 1;
r->normalized = 0;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_sqr(secp256k1_fe *r, const secp256k1_fe *a);
SECP256K1_INLINE static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe_verify(a);
VERIFY_CHECK(a->magnitude <= 8);
secp256k1_fe_impl_sqr(r, a);
r->magnitude = 1;
r->normalized = 0;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag);
SECP256K1_INLINE static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) {
VERIFY_CHECK(flag == 0 || flag == 1);
secp256k1_fe_verify(a);
secp256k1_fe_verify(r);
secp256k1_fe_impl_cmov(r, a, flag);
if (a->magnitude > r->magnitude) r->magnitude = a->magnitude;
if (!a->normalized) r->normalized = 0;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a);
SECP256K1_INLINE static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) {
secp256k1_fe_verify(a);
VERIFY_CHECK(a->normalized);
secp256k1_fe_impl_to_storage(r, a);
}
static void secp256k1_fe_impl_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a);
SECP256K1_INLINE static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) {
secp256k1_fe_impl_from_storage(r, a);
r->magnitude = 1;
r->normalized = 1;
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_inv(secp256k1_fe *r, const secp256k1_fe *x);
SECP256K1_INLINE static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *x) {
int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
secp256k1_fe_verify(x);
secp256k1_fe_impl_inv(r, x);
r->magnitude = x->magnitude > 0;
r->normalized = 1;
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_inv_var(secp256k1_fe *r, const secp256k1_fe *x);
SECP256K1_INLINE static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
int input_is_zero = secp256k1_fe_normalizes_to_zero(x);
secp256k1_fe_verify(x);
secp256k1_fe_impl_inv_var(r, x);
r->magnitude = x->magnitude > 0;
r->normalized = 1;
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == input_is_zero);
secp256k1_fe_verify(r);
}
static int secp256k1_fe_impl_is_square_var(const secp256k1_fe *x);
SECP256K1_INLINE static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
int ret;
secp256k1_fe tmp = *x, sqrt;
secp256k1_fe_verify(x);
ret = secp256k1_fe_impl_is_square_var(x);
secp256k1_fe_normalize_weak(&tmp);
VERIFY_CHECK(ret == secp256k1_fe_sqrt(&sqrt, &tmp));
return ret;
}
static void secp256k1_fe_impl_get_bounds(secp256k1_fe* r, int m);
SECP256K1_INLINE static void secp256k1_fe_get_bounds(secp256k1_fe* r, int m) {
VERIFY_CHECK(m >= 0);
VERIFY_CHECK(m <= 32);
secp256k1_fe_impl_get_bounds(r, m);
r->magnitude = m;
r->normalized = (m == 0);
secp256k1_fe_verify(r);
}
static void secp256k1_fe_impl_half(secp256k1_fe *r);
SECP256K1_INLINE static void secp256k1_fe_half(secp256k1_fe *r) {
secp256k1_fe_verify(r);
VERIFY_CHECK(r->magnitude < 32);
secp256k1_fe_impl_half(r);
r->magnitude = (r->magnitude >> 1) + 1;
r->normalized = 0;
secp256k1_fe_verify(r);
}
#endif /* defined(VERIFY) */
#endif /* SECP256K1_FIELD_IMPL_H */

View File

@ -23,7 +23,7 @@ typedef struct {
#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1}
/** A group element of the secp256k1 curve, in jacobian coordinates.
* Note: For exhastive test mode, sepc256k1 is replaced by a small subgroup of a different curve.
* Note: For exhastive test mode, secp256k1 is replaced by a small subgroup of a different curve.
*/
typedef struct {
secp256k1_fe x; /* actual X: x/z^2 */
@ -57,6 +57,12 @@ static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x);
* for Y. Return value indicates whether the result is valid. */
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
/** Determine whether x is a valid X coordinate on the curve. */
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x);
/** Determine whether fraction xn/xd is a valid X coordinate on the curve (xd != 0). */
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd);
/** Check whether a group element is the point at infinity. */
static int secp256k1_ge_is_infinity(const secp256k1_ge *a);
@ -103,7 +109,11 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r);
/** Set a group element (jacobian) equal to another which is given in affine coordinates. */
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a);
/** Compare the X coordinate of a group element (jacobian). */
/** Check two group elements (jacobian) for equality in variable time. */
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b);
/** Compare the X coordinate of a group element (jacobian).
* The magnitude of the group element's X coordinate must not exceed 31. */
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a);
/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */
@ -170,4 +180,10 @@ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b);
*/
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge);
/** Check invariants on an affine group element (no-op unless VERIFY is enabled). */
static void secp256k1_ge_verify(const secp256k1_ge *a);
/** Check invariants on a Jacobian group element (no-op unless VERIFY is enabled). */
static void secp256k1_gej_verify(const secp256k1_gej *a);
#endif /* SECP256K1_GROUP_H */

View File

@ -9,90 +9,144 @@
#include "field.h"
#include "group.h"
#include "util.h"
/* Begin of section generated by sage/gen_exhaustive_groups.sage. */
#define SECP256K1_G_ORDER_7 SECP256K1_GE_CONST(\
0x66625d13, 0x317ffe44, 0x63d32cff, 0x1ca02b9b,\
0xe5c6d070, 0x50b4b05e, 0x81cc30db, 0xf5166f0a,\
0x1e60e897, 0xa7c00c7c, 0x2df53eb6, 0x98274ff4,\
0x64252f42, 0x8ca44e17, 0x3b25418c, 0xff4ab0cf\
)
#define SECP256K1_G_ORDER_13 SECP256K1_GE_CONST(\
0xc3459c3d, 0x35326167, 0xcd86cce8, 0x07a2417f,\
0x5b8bd567, 0xde8538ee, 0x0d507b0c, 0xd128f5bb,\
0x8e467fec, 0xcd30000a, 0x6cc1184e, 0x25d382c2,\
0xa2f4494e, 0x2fbe9abc, 0x8b64abac, 0xd005fb24\
0xa2482ff8, 0x4bf34edf, 0xa51262fd, 0xe57921db,\
0xe0dd2cb7, 0xa5914790, 0xbc71631f, 0xc09704fb,\
0x942536cb, 0xa3e49492, 0x3a701cc3, 0xee3e443f,\
0xdf182aa9, 0x15b8aa6a, 0x166d3b19, 0xba84b045\
)
#define SECP256K1_G_ORDER_199 SECP256K1_GE_CONST(\
0x226e653f, 0xc8df7744, 0x9bacbf12, 0x7d1dcbf9,\
0x87f05b2a, 0xe7edbd28, 0x1f564575, 0xc48dcf18,\
0xa13872c2, 0xe933bb17, 0x5d9ffd5b, 0xb5b6e10c,\
0x57fe3c00, 0xbaaaa15a, 0xe003ec3e, 0x9c269bae\
0x7fb07b5c, 0xd07c3bda, 0x553902e2, 0x7a87ea2c,\
0x35108a7f, 0x051f41e5, 0xb76abad5, 0x1f2703ad,\
0x0a251539, 0x5b4c4438, 0x952a634f, 0xac10dd4d,\
0x6d6f4745, 0x98990c27, 0x3a4f3116, 0xd32ff969\
)
/** Generator for secp256k1, value 'g' defined in
* "Standards for Efficient Cryptography" (SEC2) 2.7.1.
*/
#define SECP256K1_G SECP256K1_GE_CONST(\
0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL,\
0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL,\
0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL,\
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL\
0x79be667e, 0xf9dcbbac, 0x55a06295, 0xce870b07,\
0x029bfcdb, 0x2dce28d9, 0x59f2815b, 0x16f81798,\
0x483ada77, 0x26a3c465, 0x5da4fbfc, 0x0e1108a8,\
0xfd17b448, 0xa6855419, 0x9c47d08f, 0xfb10d4b8\
)
/* 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 curve equation is of the form y^2=x^3+B for some small constant B.
* - The subgroup has a generator 2*P, where P.x is as small as possible.
* - 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).
*
* These parameters are generated using sage/gen_exhaustive_groups.sage.
*/
#if defined(EXHAUSTIVE_TEST_ORDER)
# if EXHAUSTIVE_TEST_ORDER == 13
# if EXHAUSTIVE_TEST_ORDER == 7
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_7;
#define SECP256K1_B 6
# elif EXHAUSTIVE_TEST_ORDER == 13
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_13;
#define SECP256K1_B 2
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_G_ORDER_199;
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(
0x2cca28fa, 0xfc614b80, 0x2a3db42b, 0x00ba00b1,
0xbea8d943, 0xdace9ab2, 0x9536daea, 0x0074defb
);
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G_ORDER_199;
#define SECP256K1_B 4
# else
# error No known generator for the specified exhaustive test group order.
# endif
#else
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_G;
#define SECP256K1_B 7
static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 7);
#endif
/* End of section generated by sage/gen_exhaustive_groups.sage. */
static void secp256k1_ge_verify(const secp256k1_ge *a) {
#ifdef VERIFY
secp256k1_fe_verify(&a->x);
secp256k1_fe_verify(&a->y);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
#endif
(void)a;
}
static void secp256k1_gej_verify(const secp256k1_gej *a) {
#ifdef VERIFY
secp256k1_fe_verify(&a->x);
secp256k1_fe_verify(&a->y);
secp256k1_fe_verify(&a->z);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
#endif
(void)a;
}
/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
secp256k1_fe zi2;
secp256k1_fe zi3;
secp256k1_gej_verify(a);
secp256k1_fe_verify(zi);
VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&zi2, zi);
secp256k1_fe_mul(&zi3, &zi2, zi);
secp256k1_fe_mul(&r->x, &a->x, &zi2);
secp256k1_fe_mul(&r->y, &a->y, &zi3);
r->infinity = a->infinity;
secp256k1_ge_verify(r);
}
/* Set r to the affine coordinates of Jacobian point (a.x, a.y, 1/zi). */
static void secp256k1_ge_set_ge_zinv(secp256k1_ge *r, const secp256k1_ge *a, const secp256k1_fe *zi) {
secp256k1_fe zi2;
secp256k1_fe zi3;
secp256k1_ge_verify(a);
secp256k1_fe_verify(zi);
VERIFY_CHECK(!a->infinity);
secp256k1_fe_sqr(&zi2, zi);
secp256k1_fe_mul(&zi3, &zi2, zi);
secp256k1_fe_mul(&r->x, &a->x, &zi2);
secp256k1_fe_mul(&r->y, &a->y, &zi3);
r->infinity = a->infinity;
secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) {
secp256k1_fe_verify(x);
secp256k1_fe_verify(y);
r->infinity = 0;
r->x = *x;
r->y = *y;
secp256k1_ge_verify(r);
}
static int secp256k1_ge_is_infinity(const secp256k1_ge *a) {
secp256k1_ge_verify(a);
return a->infinity;
}
static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) {
secp256k1_ge_verify(a);
*r = *a;
secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3;
secp256k1_gej_verify(a);
r->infinity = a->infinity;
secp256k1_fe_inv(&a->z, &a->z);
secp256k1_fe_sqr(&z2, &a->z);
@ -102,14 +156,17 @@ static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe_set_int(&a->z, 1);
r->x = a->x;
r->y = a->y;
secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe z2, z3;
if (a->infinity) {
secp256k1_gej_verify(a);
if (secp256k1_gej_is_infinity(a)) {
secp256k1_ge_set_infinity(r);
return;
}
r->infinity = 0;
secp256k1_fe_inv_var(&a->z, &a->z);
secp256k1_fe_sqr(&z2, &a->z);
secp256k1_fe_mul(&z3, &a->z, &z2);
@ -117,6 +174,7 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) {
secp256k1_fe_mul(&a->y, &a->y, &z3);
secp256k1_fe_set_int(&a->z, 1);
secp256k1_ge_set_xy(r, &a->x, &a->y);
secp256k1_ge_verify(r);
}
static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len) {
@ -125,6 +183,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
size_t last_i = SIZE_MAX;
for (i = 0; i < len; i++) {
secp256k1_gej_verify(&a[i]);
if (a[i].infinity) {
secp256k1_ge_set_infinity(&r[i]);
} else {
@ -158,6 +217,7 @@ static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a
if (!a[i].infinity) {
secp256k1_ge_set_gej_zinv(&r[i], &a[i], &r[i].x);
}
secp256k1_ge_verify(&r[i]);
}
}
@ -166,21 +226,25 @@ static void secp256k1_ge_table_set_globalz(size_t len, secp256k1_ge *a, const se
secp256k1_fe zs;
if (len > 0) {
/* Verify inputs a[len-1] and zr[len-1]. */
secp256k1_ge_verify(&a[i]);
secp256k1_fe_verify(&zr[i]);
/* Ensure all y values are in weak normal form for fast negation of points */
secp256k1_fe_normalize_weak(&a[i].y);
zs = zr[i];
/* Work our way backwards, using the z-ratios to scale the x/y values. */
while (i > 0) {
secp256k1_gej tmpa;
/* Verify all inputs a[i] and zr[i]. */
secp256k1_fe_verify(&zr[i]);
secp256k1_ge_verify(&a[i]);
if (i != len - 1) {
secp256k1_fe_mul(&zs, &zs, &zr[i]);
}
i--;
tmpa.x = a[i].x;
tmpa.y = a[i].y;
tmpa.infinity = 0;
secp256k1_ge_set_gej_zinv(&a[i], &tmpa, &zs);
secp256k1_ge_set_ge_zinv(&a[i], &a[i], &zs);
/* Verify the output a[i]. */
secp256k1_ge_verify(&a[i]);
}
}
}
@ -190,12 +254,14 @@ static void secp256k1_gej_set_infinity(secp256k1_gej *r) {
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
secp256k1_fe_clear(&r->z);
secp256k1_gej_verify(r);
}
static void secp256k1_ge_set_infinity(secp256k1_ge *r) {
r->infinity = 1;
secp256k1_fe_clear(&r->x);
secp256k1_fe_clear(&r->y);
secp256k1_ge_verify(r);
}
static void secp256k1_gej_clear(secp256k1_gej *r) {
@ -213,64 +279,84 @@ 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;
secp256k1_fe_verify(x);
r->x = *x;
secp256k1_fe_sqr(&x2, x);
secp256k1_fe_mul(&x3, x, &x2);
r->infinity = 0;
secp256k1_fe_add(&x3, &secp256k1_fe_const_b);
secp256k1_fe_add_int(&x3, SECP256K1_B);
return secp256k1_fe_sqrt(&r->y, &x3);
}
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
if (!secp256k1_ge_set_xquad(r, x)) {
return 0;
}
int ret;
ret = secp256k1_ge_set_xquad(r, x);
secp256k1_fe_normalize_var(&r->y);
if (secp256k1_fe_is_odd(&r->y) != odd) {
secp256k1_fe_negate(&r->y, &r->y, 1);
}
return 1;
secp256k1_ge_verify(r);
return ret;
}
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
secp256k1_ge_verify(a);
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
secp256k1_fe_set_int(&r->z, 1);
secp256k1_gej_verify(r);
}
static int secp256k1_gej_eq_var(const secp256k1_gej *a, const secp256k1_gej *b) {
secp256k1_gej tmp;
secp256k1_gej_verify(b);
secp256k1_gej_verify(a);
secp256k1_gej_neg(&tmp, a);
secp256k1_gej_add_var(&tmp, &tmp, b, NULL);
return secp256k1_gej_is_infinity(&tmp);
}
static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) {
secp256k1_fe r, r2;
secp256k1_fe r;
#ifdef VERIFY
secp256k1_fe_verify(x);
VERIFY_CHECK(a->x.magnitude <= 31);
secp256k1_gej_verify(a);
VERIFY_CHECK(!a->infinity);
#endif
secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x);
r2 = a->x; secp256k1_fe_normalize_weak(&r2);
return secp256k1_fe_equal_var(&r, &r2);
return secp256k1_fe_equal_var(&r, &a->x);
}
static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) {
secp256k1_gej_verify(a);
r->infinity = a->infinity;
r->x = a->x;
r->y = a->y;
r->z = a->z;
secp256k1_fe_normalize_weak(&r->y);
secp256k1_fe_negate(&r->y, &r->y, 1);
secp256k1_gej_verify(r);
}
static int secp256k1_gej_is_infinity(const secp256k1_gej *a) {
secp256k1_gej_verify(a);
return a->infinity;
}
static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) {
secp256k1_fe y2, x3;
secp256k1_ge_verify(a);
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_add(&x3, &secp256k1_fe_const_b);
secp256k1_fe_normalize_weak(&x3);
secp256k1_fe_add_int(&x3, SECP256K1_B);
return secp256k1_fe_equal_var(&y2, &x3);
}
@ -278,6 +364,7 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
/* Operations: 3 mul, 4 sqr, 8 add/half/mul_int/negate */
secp256k1_fe l, s, t;
secp256k1_gej_verify(a);
r->infinity = a->infinity;
/* Formula used:
@ -304,6 +391,7 @@ static SECP256K1_INLINE void secp256k1_gej_double(secp256k1_gej *r, const secp25
secp256k1_fe_mul(&r->y, &t, &l); /* Y3 = L*(X3 + T) (1) */
secp256k1_fe_add(&r->y, &s); /* Y3 = L*(X3 + T) + S^2 (2) */
secp256k1_fe_negate(&r->y, &r->y, 2); /* Y3 = -(L*(X3 + T) + S^2) (3) */
secp256k1_gej_verify(r);
}
static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) {
@ -317,6 +405,7 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
* the infinity flag even though the point doubles to infinity, and the result
* point will be gibberish (z = 0 but infinity = 0).
*/
secp256k1_gej_verify(a);
if (a->infinity) {
secp256k1_gej_set_infinity(r);
if (rzr != NULL) {
@ -331,18 +420,20 @@ static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, s
}
secp256k1_gej_double(r, a);
secp256k1_gej_verify(r);
}
static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) {
/* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */
secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
/* 12 mul, 4 sqr, 11 add/negate/normalizes_to_zero (ignoring special cases) */
secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, h2, h3, t;
secp256k1_gej_verify(a);
secp256k1_gej_verify(b);
if (a->infinity) {
VERIFY_CHECK(rzr == NULL);
*r = *b;
return;
}
if (b->infinity) {
if (rzr != NULL) {
secp256k1_fe_set_int(rzr, 1);
@ -351,7 +442,6 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
return;
}
r->infinity = 0;
secp256k1_fe_sqr(&z22, &b->z);
secp256k1_fe_sqr(&z12, &a->z);
secp256k1_fe_mul(&u1, &a->x, &z22);
@ -359,7 +449,7 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z);
secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1);
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
secp256k1_gej_double_var(r, a, rzr);
@ -371,24 +461,36 @@ static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, cons
}
return;
}
secp256k1_fe_sqr(&i2, &i);
secp256k1_fe_sqr(&h2, &h);
secp256k1_fe_mul(&h3, &h, &h2);
secp256k1_fe_mul(&h, &h, &b->z);
r->infinity = 0;
secp256k1_fe_mul(&t, &h, &b->z);
if (rzr != NULL) {
*rzr = h;
*rzr = t;
}
secp256k1_fe_mul(&r->z, &a->z, &h);
secp256k1_fe_mul(&r->z, &a->z, &t);
secp256k1_fe_sqr(&h2, &h);
secp256k1_fe_negate(&h2, &h2, 1);
secp256k1_fe_mul(&h3, &h2, &h);
secp256k1_fe_mul(&t, &u1, &h2);
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
secp256k1_fe_sqr(&r->x, &i);
secp256k1_fe_add(&r->x, &h3);
secp256k1_fe_add(&r->x, &t);
secp256k1_fe_add(&r->x, &t);
secp256k1_fe_add(&t, &r->x);
secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
secp256k1_gej_verify(r);
}
static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) {
/* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */
secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
/* 8 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
secp256k1_fe z12, u1, u2, s1, s2, h, i, h2, h3, t;
secp256k1_gej_verify(a);
secp256k1_ge_verify(b);
if (a->infinity) {
VERIFY_CHECK(rzr == NULL);
secp256k1_gej_set_ge(r, b);
@ -401,7 +503,6 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
*r = *a;
return;
}
r->infinity = 0;
secp256k1_fe_sqr(&z12, &a->z);
u1 = a->x; secp256k1_fe_normalize_weak(&u1);
@ -409,7 +510,7 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
s1 = a->y; secp256k1_fe_normalize_weak(&s1);
secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z);
secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1);
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
secp256k1_gej_double_var(r, a, rzr);
@ -421,28 +522,37 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, c
}
return;
}
secp256k1_fe_sqr(&i2, &i);
secp256k1_fe_sqr(&h2, &h);
secp256k1_fe_mul(&h3, &h, &h2);
r->infinity = 0;
if (rzr != NULL) {
*rzr = h;
}
secp256k1_fe_mul(&r->z, &a->z, &h);
secp256k1_fe_sqr(&h2, &h);
secp256k1_fe_negate(&h2, &h2, 1);
secp256k1_fe_mul(&h3, &h2, &h);
secp256k1_fe_mul(&t, &u1, &h2);
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
secp256k1_fe_sqr(&r->x, &i);
secp256k1_fe_add(&r->x, &h3);
secp256k1_fe_add(&r->x, &t);
secp256k1_fe_add(&r->x, &t);
secp256k1_fe_add(&t, &r->x);
secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
secp256k1_gej_verify(r);
if (rzr != NULL) secp256k1_fe_verify(rzr);
}
static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) {
/* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */
secp256k1_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t;
/* 9 mul, 3 sqr, 13 add/negate/normalize_weak/normalizes_to_zero (ignoring special cases) */
secp256k1_fe az, z12, u1, u2, s1, s2, h, i, h2, h3, t;
if (b->infinity) {
*r = *a;
return;
}
secp256k1_ge_verify(b);
secp256k1_fe_verify(bzinv);
if (a->infinity) {
secp256k1_fe bzinv2, bzinv3;
r->infinity = b->infinity;
@ -453,7 +563,10 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
secp256k1_fe_set_int(&r->z, 1);
return;
}
r->infinity = 0;
if (b->infinity) {
*r = *a;
return;
}
/** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to
* secp256k1's isomorphism we can multiply the Z coordinates on both sides
@ -471,7 +584,7 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
s1 = a->y; secp256k1_fe_normalize_weak(&s1);
secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az);
secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2);
secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2);
secp256k1_fe_negate(&i, &s2, 1); secp256k1_fe_add(&i, &s1);
if (secp256k1_fe_normalizes_to_zero_var(&h)) {
if (secp256k1_fe_normalizes_to_zero_var(&i)) {
secp256k1_gej_double_var(r, a, NULL);
@ -480,15 +593,25 @@ static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a,
}
return;
}
secp256k1_fe_sqr(&i2, &i);
r->infinity = 0;
secp256k1_fe_mul(&r->z, &a->z, &h);
secp256k1_fe_sqr(&h2, &h);
secp256k1_fe_mul(&h3, &h, &h2);
r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h);
secp256k1_fe_negate(&h2, &h2, 1);
secp256k1_fe_mul(&h3, &h2, &h);
secp256k1_fe_mul(&t, &u1, &h2);
r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2);
secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i);
secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1);
secp256k1_fe_sqr(&r->x, &i);
secp256k1_fe_add(&r->x, &h3);
secp256k1_fe_add(&r->x, &t);
secp256k1_fe_add(&r->x, &t);
secp256k1_fe_add(&t, &r->x);
secp256k1_fe_mul(&r->y, &t, &i);
secp256k1_fe_mul(&h3, &h3, &s1);
secp256k1_fe_add(&r->y, &h3);
secp256k1_gej_verify(r);
}
@ -496,11 +619,13 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
/* Operations: 7 mul, 5 sqr, 24 add/cmov/half/mul_int/negate/normalize_weak/normalizes_to_zero */
secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr;
secp256k1_fe m_alt, rr_alt;
int infinity, degenerate;
int degenerate;
secp256k1_gej_verify(a);
secp256k1_ge_verify(b);
VERIFY_CHECK(!b->infinity);
VERIFY_CHECK(a->infinity == 0 || a->infinity == 1);
/** In:
/* In:
* Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks.
* In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002.
* we find as solution for a unified addition/doubling formula:
@ -562,10 +687,9 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */
secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */
secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */
/** If lambda = R/M = 0/0 we have a problem (except in the "trivial"
* case that Z = z1z2 = 0, and this is special-cased later on). */
degenerate = secp256k1_fe_normalizes_to_zero(&m) &
secp256k1_fe_normalizes_to_zero(&rr);
/* If lambda = R/M = R/0 we have a problem (except in the "trivial"
* case that Z = z1z2 = 0, and this is special-cased later on). */
degenerate = secp256k1_fe_normalizes_to_zero(&m);
/* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2.
* This means either x1 == beta*x2 or beta*x1 == x2, where beta is
* a nontrivial cube root of one. In either case, an alternate
@ -577,7 +701,7 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_cmov(&rr_alt, &rr, !degenerate);
secp256k1_fe_cmov(&m_alt, &m, !degenerate);
/* Now Ralt / Malt = lambda and is guaranteed not to be 0/0.
/* Now Ralt / Malt = lambda and is guaranteed not to be Ralt / 0.
* From here on out Ralt and Malt represent the numerator
* and denominator of lambda; R and M represent the explicit
* expressions x1^2 + x2^2 + x1x2 and y1 + y2. */
@ -592,7 +716,6 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */
secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */
secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Z3 = Malt*Z (1) */
infinity = secp256k1_fe_normalizes_to_zero(&r->z) & ~a->infinity;
secp256k1_fe_add(&t, &q); /* t = Ralt^2 + Q (2) */
r->x = t; /* r->x = X3 = Ralt^2 + Q (2) */
secp256k1_fe_mul_int(&t, 2); /* t = 2*X3 (4) */
@ -602,26 +725,50 @@ static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const
secp256k1_fe_negate(&r->y, &t, 3); /* r->y = -(Ralt*(2*X3 + Q) + M^3*Malt) (4) */
secp256k1_fe_half(&r->y); /* r->y = Y3 = -(Ralt*(2*X3 + Q) + M^3*Malt)/2 (3) */
/** In case a->infinity == 1, replace r with (b->x, b->y, 1). */
/* In case a->infinity == 1, replace r with (b->x, b->y, 1). */
secp256k1_fe_cmov(&r->x, &b->x, a->infinity);
secp256k1_fe_cmov(&r->y, &b->y, a->infinity);
secp256k1_fe_cmov(&r->z, &secp256k1_fe_one, a->infinity);
r->infinity = infinity;
/* Set r->infinity if r->z is 0.
*
* If a->infinity is set, then r->infinity = (r->z == 0) = (1 == 0) = false,
* which is correct because the function assumes that b is not infinity.
*
* Now assume !a->infinity. This implies Z = Z1 != 0.
*
* Case y1 = -y2:
* In this case we could have a = -b, namely if x1 = x2.
* We have degenerate = true, r->z = (x1 - x2) * Z.
* Then r->infinity = ((x1 - x2)Z == 0) = (x1 == x2) = (a == -b).
*
* Case y1 != -y2:
* In this case, we can't have a = -b.
* We have degenerate = false, r->z = (y1 + y2) * Z.
* Then r->infinity = ((y1 + y2)Z == 0) = (y1 == -y2) = false. */
r->infinity = secp256k1_fe_normalizes_to_zero(&r->z);
secp256k1_gej_verify(r);
}
static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) {
/* Operations: 4 mul, 1 sqr */
secp256k1_fe zz;
VERIFY_CHECK(!secp256k1_fe_is_zero(s));
secp256k1_gej_verify(r);
secp256k1_fe_verify(s);
#ifdef VERIFY
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(s));
#endif
secp256k1_fe_sqr(&zz, s);
secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */
secp256k1_fe_mul(&r->y, &r->y, &zz);
secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */
secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */
secp256k1_gej_verify(r);
}
static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) {
secp256k1_fe x, y;
secp256k1_ge_verify(a);
VERIFY_CHECK(!a->infinity);
x = a->x;
secp256k1_fe_normalize(&x);
@ -635,14 +782,18 @@ static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storag
secp256k1_fe_from_storage(&r->x, &a->x);
secp256k1_fe_from_storage(&r->y, &a->y);
r->infinity = 0;
secp256k1_ge_verify(r);
}
static SECP256K1_INLINE void secp256k1_gej_cmov(secp256k1_gej *r, const secp256k1_gej *a, int flag) {
secp256k1_gej_verify(r);
secp256k1_gej_verify(a);
secp256k1_fe_cmov(&r->x, &a->x, flag);
secp256k1_fe_cmov(&r->y, &a->y, flag);
secp256k1_fe_cmov(&r->z, &a->z, flag);
r->infinity ^= (r->infinity ^ a->infinity) & flag;
secp256k1_gej_verify(r);
}
static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) {
@ -652,7 +803,9 @@ static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r,
static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) {
*r = *a;
secp256k1_ge_verify(a);
secp256k1_fe_mul(&r->x, &r->x, &secp256k1_const_beta);
secp256k1_ge_verify(r);
}
static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
@ -666,7 +819,7 @@ static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) {
* that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z
is */
secp256k1_fe_mul(&yz, &a->y, &a->z);
return secp256k1_fe_is_quad_var(&yz);
return secp256k1_fe_is_square_var(&yz);
}
static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
@ -674,6 +827,7 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
secp256k1_gej out;
int i;
secp256k1_ge_verify(ge);
/* A very simple EC multiplication ladder that avoids a dependency on ecmult. */
secp256k1_gej_set_infinity(&out);
for (i = 0; i < 32; ++i) {
@ -690,4 +844,32 @@ static int secp256k1_ge_is_in_correct_subgroup(const secp256k1_ge* ge) {
#endif
}
static int secp256k1_ge_x_on_curve_var(const secp256k1_fe *x) {
secp256k1_fe c;
secp256k1_fe_sqr(&c, x);
secp256k1_fe_mul(&c, &c, x);
secp256k1_fe_add_int(&c, SECP256K1_B);
return secp256k1_fe_is_square_var(&c);
}
static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp256k1_fe *xd) {
/* We want to determine whether (xn/xd) is on the curve.
*
* (xn/xd)^3 + 7 is square <=> xd*xn^3 + 7*xd^4 is square (multiplying by xd^4, a square).
*/
secp256k1_fe r, t;
#ifdef VERIFY
VERIFY_CHECK(!secp256k1_fe_normalizes_to_zero_var(xd));
#endif
secp256k1_fe_mul(&r, xd, xn); /* r = xd*xn */
secp256k1_fe_sqr(&t, xn); /* t = xn^2 */
secp256k1_fe_mul(&r, &r, &t); /* r = xd*xn^3 */
secp256k1_fe_sqr(&t, xd); /* t = xd^2 */
secp256k1_fe_sqr(&t, &t); /* t = xd^4 */
VERIFY_CHECK(SECP256K1_B <= 31);
secp256k1_fe_mul_int(&t, SECP256K1_B); /* t = 7*xd^4 */
secp256k1_fe_add(&r, &t); /* r = xd*xn^3 + 7*xd^4 */
return secp256k1_fe_is_square_var(&r);
}
#endif /* SECP256K1_GROUP_IMPL_H */

View File

@ -138,7 +138,7 @@ static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *
}
if (len) {
/* Fill the buffer with what remains. */
memcpy(((unsigned char*)hash->buf) + bufsize, data, len);
memcpy(hash->buf + bufsize, data, len);
}
}

90
src/int128.h Normal file
View File

@ -0,0 +1,90 @@
#ifndef SECP256K1_INT128_H
#define SECP256K1_INT128_H
#include "util.h"
#if defined(SECP256K1_WIDEMUL_INT128)
# if defined(SECP256K1_INT128_NATIVE)
# include "int128_native.h"
# elif defined(SECP256K1_INT128_STRUCT)
# include "int128_struct.h"
# else
# error "Please select int128 implementation"
# endif
/* Construct an unsigned 128-bit value from a high and a low 64-bit value. */
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo);
/* Multiply two unsigned 64-bit values a and b and write the result to r. */
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
/* Multiply two unsigned 64-bit values a and b and add the result to r.
* The final result is taken modulo 2^128.
*/
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b);
/* Add an unsigned 64-bit value a to r.
* The final result is taken modulo 2^128.
*/
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a);
/* Unsigned (logical) right shift.
* Non-constant time in n.
*/
static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n);
/* Return the low 64-bits of a 128-bit value as an unsigned 64-bit value. */
static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a);
/* Return the high 64-bits of a 128-bit value as an unsigned 64-bit value. */
static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a);
/* Write an unsigned 64-bit value to r. */
static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a);
/* Tests if r is strictly less than to 2^n.
* n must be strictly less than 128.
*/
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n);
/* Construct an signed 128-bit value from a high and a low 64-bit value. */
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo);
/* Multiply two signed 64-bit values a and b and write the result to r. */
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b);
/* Multiply two signed 64-bit values a and b and add the result to r.
* Overflow or underflow from the addition is undefined behaviour.
*/
static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b);
/* Compute a*d - b*c from signed 64-bit values and write the result to r. */
static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d);
/* Signed (arithmetic) right shift.
* Non-constant time in b.
*/
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int b);
/* Return the input value modulo 2^64. */
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a);
/* Return the value as a signed 64-bit value.
* Requires the input to be between INT64_MIN and INT64_MAX.
*/
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a);
/* Write a signed 64-bit value to r. */
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a);
/* Compare two 128-bit values for equality. */
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b);
/* Tests if r is equal to sign*2^n (sign must be 1 or -1).
* n must be strictly less than 127.
*/
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign);
#endif
#endif

18
src/int128_impl.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef SECP256K1_INT128_IMPL_H
#define SECP256K1_INT128_IMPL_H
#include "util.h"
#include "int128.h"
#if defined(SECP256K1_WIDEMUL_INT128)
# if defined(SECP256K1_INT128_NATIVE)
# include "int128_native_impl.h"
# elif defined(SECP256K1_INT128_STRUCT)
# include "int128_struct_impl.h"
# else
# error "Please select int128 implementation"
# endif
#endif
#endif

19
src/int128_native.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef SECP256K1_INT128_NATIVE_H
#define SECP256K1_INT128_NATIVE_H
#include <stdint.h>
#include "util.h"
#if !defined(UINT128_MAX) && defined(__SIZEOF_INT128__)
SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t;
SECP256K1_GNUC_EXT typedef __int128 int128_t;
# define UINT128_MAX ((uint128_t)(-1))
# define INT128_MAX ((int128_t)(UINT128_MAX >> 1))
# define INT128_MIN (-INT128_MAX - 1)
/* No (U)INT128_C macros because compilers providing __int128 do not support 128-bit literals. */
#endif
typedef uint128_t secp256k1_uint128;
typedef int128_t secp256k1_int128;
#endif

94
src/int128_native_impl.h Normal file
View File

@ -0,0 +1,94 @@
#ifndef SECP256K1_INT128_NATIVE_IMPL_H
#define SECP256K1_INT128_NATIVE_IMPL_H
#include "int128.h"
#include "util.h"
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
*r = (((uint128_t)hi) << 64) + lo;
}
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
*r = (uint128_t)a * b;
}
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
*r += (uint128_t)a * b;
}
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) {
*r += a;
}
static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
*r >>= n;
}
static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) {
return (uint64_t)(*a);
}
static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) {
return (uint64_t)(*a >> 64);
}
static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) {
*r = a;
}
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
return (*r >> n == 0);
}
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
*r = (((uint128_t)(uint64_t)hi) << 64) + lo;
}
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
*r = (int128_t)a * b;
}
static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
int128_t ab = (int128_t)a * b;
VERIFY_CHECK(0 <= ab ? *r <= INT128_MAX - ab : INT128_MIN - ab <= *r);
*r += ab;
}
static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) {
int128_t ad = (int128_t)a * d;
int128_t bc = (int128_t)b * c;
VERIFY_CHECK(0 <= bc ? INT128_MIN + bc <= ad : ad <= INT128_MAX + bc);
*r = ad - bc;
}
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
*r >>= n;
}
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
return (uint64_t)*a;
}
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
VERIFY_CHECK(INT64_MIN <= *a && *a <= INT64_MAX);
return *a;
}
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {
*r = a;
}
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) {
return *a == *b;
}
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) {
VERIFY_CHECK(n < 127);
VERIFY_CHECK(sign == 1 || sign == -1);
return (*r == (int128_t)((uint128_t)sign << n));
}
#endif

14
src/int128_struct.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef SECP256K1_INT128_STRUCT_H
#define SECP256K1_INT128_STRUCT_H
#include <stdint.h>
#include "util.h"
typedef struct {
uint64_t lo;
uint64_t hi;
} secp256k1_uint128;
typedef secp256k1_uint128 secp256k1_int128;
#endif

205
src/int128_struct_impl.h Normal file
View File

@ -0,0 +1,205 @@
#ifndef SECP256K1_INT128_STRUCT_IMPL_H
#define SECP256K1_INT128_STRUCT_IMPL_H
#include "int128.h"
#include "util.h"
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) /* MSVC */
# include <intrin.h>
# if defined(_M_ARM64) || defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
/* On ARM64 MSVC, use __(u)mulh for the upper half of 64x64 multiplications.
(Define SECP256K1_MSVC_MULH_TEST_OVERRIDE to test this code path on X64,
which supports both __(u)mulh and _umul128.) */
# if defined(SECP256K1_MSVC_MULH_TEST_OVERRIDE)
# pragma message(__FILE__ ": SECP256K1_MSVC_MULH_TEST_OVERRIDE is defined, forcing use of __(u)mulh.")
# endif
static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
*hi = __umulh(a, b);
return a * b;
}
static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
*hi = __mulh(a, b);
return (uint64_t)a * (uint64_t)b;
}
# else
/* On x84_64 MSVC, use native _(u)mul128 for 64x64->128 multiplications. */
# define secp256k1_umul128 _umul128
# define secp256k1_mul128 _mul128
# endif
#else
/* On other systems, emulate 64x64->128 multiplications using 32x32->64 multiplications. */
static SECP256K1_INLINE uint64_t secp256k1_umul128(uint64_t a, uint64_t b, uint64_t* hi) {
uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;
uint64_t lh = (uint32_t)a * (b >> 32);
uint64_t hl = (a >> 32) * (uint32_t)b;
uint64_t hh = (a >> 32) * (b >> 32);
uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
*hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);
return (mid34 << 32) + (uint32_t)ll;
}
static SECP256K1_INLINE int64_t secp256k1_mul128(int64_t a, int64_t b, int64_t* hi) {
uint64_t ll = (uint64_t)(uint32_t)a * (uint32_t)b;
int64_t lh = (uint32_t)a * (b >> 32);
int64_t hl = (a >> 32) * (uint32_t)b;
int64_t hh = (a >> 32) * (b >> 32);
uint64_t mid34 = (ll >> 32) + (uint32_t)lh + (uint32_t)hl;
*hi = hh + (lh >> 32) + (hl >> 32) + (mid34 >> 32);
return (mid34 << 32) + (uint32_t)ll;
}
#endif
static SECP256K1_INLINE void secp256k1_u128_load(secp256k1_uint128 *r, uint64_t hi, uint64_t lo) {
r->hi = hi;
r->lo = lo;
}
static SECP256K1_INLINE void secp256k1_u128_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
r->lo = secp256k1_umul128(a, b, &r->hi);
}
static SECP256K1_INLINE void secp256k1_u128_accum_mul(secp256k1_uint128 *r, uint64_t a, uint64_t b) {
uint64_t lo, hi;
lo = secp256k1_umul128(a, b, &hi);
r->lo += lo;
r->hi += hi + (r->lo < lo);
}
static SECP256K1_INLINE void secp256k1_u128_accum_u64(secp256k1_uint128 *r, uint64_t a) {
r->lo += a;
r->hi += r->lo < a;
}
/* Unsigned (logical) right shift.
* Non-constant time in n.
*/
static SECP256K1_INLINE void secp256k1_u128_rshift(secp256k1_uint128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
if (n >= 64) {
r->lo = r->hi >> (n-64);
r->hi = 0;
} else if (n > 0) {
#if defined(_MSC_VER) && defined(_M_X64)
VERIFY_CHECK(n < 64);
r->lo = __shiftright128(r->lo, r->hi, n);
#else
r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
#endif
r->hi >>= n;
}
}
static SECP256K1_INLINE uint64_t secp256k1_u128_to_u64(const secp256k1_uint128 *a) {
return a->lo;
}
static SECP256K1_INLINE uint64_t secp256k1_u128_hi_u64(const secp256k1_uint128 *a) {
return a->hi;
}
static SECP256K1_INLINE void secp256k1_u128_from_u64(secp256k1_uint128 *r, uint64_t a) {
r->hi = 0;
r->lo = a;
}
static SECP256K1_INLINE int secp256k1_u128_check_bits(const secp256k1_uint128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
return n >= 64 ? r->hi >> (n - 64) == 0
: r->hi == 0 && r->lo >> n == 0;
}
static SECP256K1_INLINE void secp256k1_i128_load(secp256k1_int128 *r, int64_t hi, uint64_t lo) {
r->hi = hi;
r->lo = lo;
}
static SECP256K1_INLINE void secp256k1_i128_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
int64_t hi;
r->lo = (uint64_t)secp256k1_mul128(a, b, &hi);
r->hi = (uint64_t)hi;
}
static SECP256K1_INLINE void secp256k1_i128_accum_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
int64_t hi;
uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi);
r->lo += lo;
hi += r->lo < lo;
/* Verify no overflow.
* If r represents a positive value (the sign bit is not set) and the value we are adding is a positive value (the sign bit is not set),
* then we require that the resulting value also be positive (the sign bit is not set).
* Note that (X <= Y) means (X implies Y) when X and Y are boolean values (i.e. 0 or 1).
*/
VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi <= 0x7fffffffffffffffu));
/* Verify no underflow.
* If r represents a negative value (the sign bit is set) and the value we are adding is a negative value (the sign bit is set),
* then we require that the resulting value also be negative (the sign bit is set).
*/
VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi + (uint64_t)hi > 0x7fffffffffffffffu));
r->hi += hi;
}
static SECP256K1_INLINE void secp256k1_i128_dissip_mul(secp256k1_int128 *r, int64_t a, int64_t b) {
int64_t hi;
uint64_t lo = (uint64_t)secp256k1_mul128(a, b, &hi);
hi += r->lo < lo;
/* Verify no overflow.
* If r represents a positive value (the sign bit is not set) and the value we are subtracting is a negative value (the sign bit is set),
* then we require that the resulting value also be positive (the sign bit is not set).
*/
VERIFY_CHECK((r->hi <= 0x7fffffffffffffffu && (uint64_t)hi > 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi <= 0x7fffffffffffffffu));
/* Verify no underflow.
* If r represents a negative value (the sign bit is set) and the value we are subtracting is a positive value (the sign sign bit is not set),
* then we require that the resulting value also be negative (the sign bit is set).
*/
VERIFY_CHECK((r->hi > 0x7fffffffffffffffu && (uint64_t)hi <= 0x7fffffffffffffffu) <= (r->hi - (uint64_t)hi > 0x7fffffffffffffffu));
r->hi -= hi;
r->lo -= lo;
}
static SECP256K1_INLINE void secp256k1_i128_det(secp256k1_int128 *r, int64_t a, int64_t b, int64_t c, int64_t d) {
secp256k1_i128_mul(r, a, d);
secp256k1_i128_dissip_mul(r, b, c);
}
/* Signed (arithmetic) right shift.
* Non-constant time in n.
*/
static SECP256K1_INLINE void secp256k1_i128_rshift(secp256k1_int128 *r, unsigned int n) {
VERIFY_CHECK(n < 128);
if (n >= 64) {
r->lo = (uint64_t)((int64_t)(r->hi) >> (n-64));
r->hi = (uint64_t)((int64_t)(r->hi) >> 63);
} else if (n > 0) {
r->lo = ((1U * r->hi) << (64-n)) | r->lo >> n;
r->hi = (uint64_t)((int64_t)(r->hi) >> n);
}
}
static SECP256K1_INLINE uint64_t secp256k1_i128_to_u64(const secp256k1_int128 *a) {
return a->lo;
}
static SECP256K1_INLINE int64_t secp256k1_i128_to_i64(const secp256k1_int128 *a) {
/* Verify that a represents a 64 bit signed value by checking that the high bits are a sign extension of the low bits. */
VERIFY_CHECK(a->hi == -(a->lo >> 63));
return (int64_t)secp256k1_i128_to_u64(a);
}
static SECP256K1_INLINE void secp256k1_i128_from_i64(secp256k1_int128 *r, int64_t a) {
r->hi = (uint64_t)(a >> 63);
r->lo = (uint64_t)a;
}
static SECP256K1_INLINE int secp256k1_i128_eq_var(const secp256k1_int128 *a, const secp256k1_int128 *b) {
return a->hi == b->hi && a->lo == b->lo;
}
static SECP256K1_INLINE int secp256k1_i128_check_pow2(const secp256k1_int128 *r, unsigned int n, int sign) {
VERIFY_CHECK(n < 127);
VERIFY_CHECK(sign == 1 || sign == -1);
return n >= 64 ? r->hi == (uint64_t)sign << (n - 64) && r->lo == 0
: r->hi == (uint64_t)(sign >> 1) && r->lo == (uint64_t)sign << n;
}
#endif

View File

@ -7,10 +7,6 @@
#ifndef SECP256K1_MODINV32_H
#define SECP256K1_MODINV32_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h"
/* A signed 30-bit limb representation of integers.
@ -39,4 +35,9 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
/* Same as secp256k1_modinv32_var, but constant time in x (not in the modulus). */
static void secp256k1_modinv32(secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus
* cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result
* cannot be computed. */
static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo);
#endif /* SECP256K1_MODINV32_H */

View File

@ -235,6 +235,21 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
return zeta;
}
/* secp256k1_modinv32_inv256[i] = -(2*i+1)^-1 (mod 256) */
static const uint8_t secp256k1_modinv32_inv256[128] = {
0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59,
0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31,
0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89,
0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61,
0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9,
0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91,
0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9,
0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1,
0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19,
0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1,
0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01
};
/* Compute the transition matrix and eta for 30 divsteps (variable time).
*
* Input: eta: initial eta
@ -246,21 +261,6 @@ static int32_t secp256k1_modinv32_divsteps_30(int32_t zeta, uint32_t f0, uint32_
* Implements the divsteps_n_matrix_var function from the explanation.
*/
static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t) {
/* inv256[i] = -(2*i+1)^-1 (mod 256) */
static const uint8_t inv256[128] = {
0xFF, 0x55, 0x33, 0x49, 0xC7, 0x5D, 0x3B, 0x11, 0x0F, 0xE5, 0xC3, 0x59,
0xD7, 0xED, 0xCB, 0x21, 0x1F, 0x75, 0x53, 0x69, 0xE7, 0x7D, 0x5B, 0x31,
0x2F, 0x05, 0xE3, 0x79, 0xF7, 0x0D, 0xEB, 0x41, 0x3F, 0x95, 0x73, 0x89,
0x07, 0x9D, 0x7B, 0x51, 0x4F, 0x25, 0x03, 0x99, 0x17, 0x2D, 0x0B, 0x61,
0x5F, 0xB5, 0x93, 0xA9, 0x27, 0xBD, 0x9B, 0x71, 0x6F, 0x45, 0x23, 0xB9,
0x37, 0x4D, 0x2B, 0x81, 0x7F, 0xD5, 0xB3, 0xC9, 0x47, 0xDD, 0xBB, 0x91,
0x8F, 0x65, 0x43, 0xD9, 0x57, 0x6D, 0x4B, 0xA1, 0x9F, 0xF5, 0xD3, 0xE9,
0x67, 0xFD, 0xDB, 0xB1, 0xAF, 0x85, 0x63, 0xF9, 0x77, 0x8D, 0x6B, 0xC1,
0xBF, 0x15, 0xF3, 0x09, 0x87, 0x1D, 0xFB, 0xD1, 0xCF, 0xA5, 0x83, 0x19,
0x97, 0xAD, 0x8B, 0xE1, 0xDF, 0x35, 0x13, 0x29, 0xA7, 0x3D, 0x1B, 0xF1,
0xEF, 0xC5, 0xA3, 0x39, 0xB7, 0xCD, 0xAB, 0x01
};
/* Transformation matrix; see comments in secp256k1_modinv32_divsteps_30. */
uint32_t u = 1, v = 0, q = 0, r = 1;
uint32_t f = f0, g = g0, m;
@ -300,7 +300,7 @@ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint
VERIFY_CHECK(limit > 0 && limit <= 30);
m = (UINT32_MAX >> (32 - limit)) & 255U;
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
w = (g * inv256[(f >> 1) & 127]) & m;
w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m;
/* Do so. */
g += f * w;
q += u * w;
@ -320,6 +320,86 @@ static int32_t secp256k1_modinv32_divsteps_30_var(int32_t eta, uint32_t f0, uint
return eta;
}
/* Compute the transition matrix and eta for 30 posdivsteps (variable time, eta=-delta), and keeps track
* of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^32 rather than 2^30, because
* Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
*
* Input: eta: initial eta
* f0: bottom limb of initial f
* g0: bottom limb of initial g
* Output: t: transition matrix
* Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign
* by applying the returned transformation matrix to it. The other bits of *jacp may
* change, but are meaningless.
* Return: final eta
*/
static int32_t secp256k1_modinv32_posdivsteps_30_var(int32_t eta, uint32_t f0, uint32_t g0, secp256k1_modinv32_trans2x2 *t, int *jacp) {
/* Transformation matrix. */
uint32_t u = 1, v = 0, q = 0, r = 1;
uint32_t f = f0, g = g0, m;
uint16_t w;
int i = 30, limit, zeros;
int jac = *jacp;
for (;;) {
/* Use a sentinel bit to count zeros only up to i. */
zeros = secp256k1_ctz32_var(g | (UINT32_MAX << i));
/* Perform zeros divsteps at once; they all just divide g by two. */
g >>= zeros;
u <<= zeros;
v <<= zeros;
eta -= zeros;
i -= zeros;
/* Update the bottom bit of jac: when dividing g by an odd power of 2,
* if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
jac ^= (zeros & ((f >> 1) ^ (f >> 2)));
/* We're done once we've done 30 posdivsteps. */
if (i == 0) break;
VERIFY_CHECK((f & 1) == 1);
VERIFY_CHECK((g & 1) == 1);
VERIFY_CHECK((u * f0 + v * g0) == f << (30 - i));
VERIFY_CHECK((q * f0 + r * g0) == g << (30 - i));
/* If eta is negative, negate it and replace f,g with g,f. */
if (eta < 0) {
uint32_t tmp;
eta = -eta;
/* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
* if both f and g are 3 mod 4. */
jac ^= ((f & g) >> 1);
tmp = f; f = g; g = tmp;
tmp = u; u = q; q = tmp;
tmp = v; v = r; r = tmp;
}
/* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more
* than i can be cancelled out (as we'd be done before that point), and no more than eta+1
* can be done as its sign will flip once that happens. */
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
/* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */
VERIFY_CHECK(limit > 0 && limit <= 30);
m = (UINT32_MAX >> (32 - limit)) & 255U;
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
w = (g * secp256k1_modinv32_inv256[(f >> 1) & 127]) & m;
/* Do so. */
g += f * w;
q += u * w;
r += v * w;
VERIFY_CHECK((g & m) == 0);
}
/* Return data in t and return value. */
t->u = (int32_t)u;
t->v = (int32_t)v;
t->q = (int32_t)q;
t->r = (int32_t)r;
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
* the aggregate of 30 of them will have determinant 2^30 or -2^30. */
VERIFY_CHECK((int64_t)t->u * t->r - (int64_t)t->v * t->q == ((int64_t)1) << 30 ||
(int64_t)t->u * t->r - (int64_t)t->v * t->q == -(((int64_t)1) << 30));
*jacp = jac;
return eta;
}
/* Compute (t/2^30) * [d, e] mod modulus, where t is a transition matrix for 30 divsteps.
*
* On input and output, d and e are in range (-2*modulus,modulus). All output limbs will be in range
@ -338,10 +418,8 @@ static void secp256k1_modinv32_update_de_30(secp256k1_modinv32_signed30 *d, secp
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(d, 9, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(e, 9, &modinfo->modulus, 1) < 0); /* e < modulus */
VERIFY_CHECK((labs(u) + labs(v)) >= 0); /* |u|+|v| doesn't overflow */
VERIFY_CHECK((labs(q) + labs(r)) >= 0); /* |q|+|r| doesn't overflow */
VERIFY_CHECK((labs(u) + labs(v)) <= M30 + 1); /* |u|+|v| <= 2^30 */
VERIFY_CHECK((labs(q) + labs(r)) <= M30 + 1); /* |q|+|r| <= 2^30 */
VERIFY_CHECK(labs(u) <= (M30 + 1 - labs(v))); /* |u|+|v| <= 2^30 */
VERIFY_CHECK(labs(q) <= (M30 + 1 - labs(r))); /* |q|+|r| <= 2^30 */
#endif
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d->v[8] >> 31;
@ -587,4 +665,74 @@ static void secp256k1_modinv32_var(secp256k1_modinv32_signed30 *x, const secp256
*x = d;
}
/* Do up to 50 iterations of 30 posdivsteps (up to 1500 steps; more is extremely rare) each until f=1.
* In VERIFY mode use a lower number of iterations (750, close to the median 756), so failure actually occurs. */
#ifdef VERIFY
#define JACOBI32_ITERATIONS 25
#else
#define JACOBI32_ITERATIONS 50
#endif
/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */
static int secp256k1_jacobi32_maybe_var(const secp256k1_modinv32_signed30 *x, const secp256k1_modinv32_modinfo *modinfo) {
/* Start with f=modulus, g=x, eta=-1. */
secp256k1_modinv32_signed30 f = modinfo->modulus;
secp256k1_modinv32_signed30 g = *x;
int j, len = 9;
int32_t eta = -1; /* eta = -delta; delta is initially 1 */
int32_t cond, fn, gn;
int jac = 0;
int count;
/* The input limbs must all be non-negative. */
VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0 && g.v[5] >= 0 && g.v[6] >= 0 && g.v[7] >= 0 && g.v[8] >= 0);
/* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we
* require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or
* time out). */
VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4] | g.v[5] | g.v[6] | g.v[7] | g.v[8]) != 0);
for (count = 0; count < JACOBI32_ITERATIONS; ++count) {
/* Compute transition matrix and new eta after 30 posdivsteps. */
secp256k1_modinv32_trans2x2 t;
eta = secp256k1_modinv32_posdivsteps_30_var(eta, f.v[0] | ((uint32_t)f.v[1] << 30), g.v[0] | ((uint32_t)g.v[1] << 30), &t, &jac);
/* Update f,g using that transition matrix. */
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
secp256k1_modinv32_update_fg_30_var(len, &f, &g, &t);
/* If the bottom limb of f is 1, there is a chance that f=1. */
if (f.v[0] == 1) {
cond = 0;
/* Check if the other limbs are also 0. */
for (j = 1; j < len; ++j) {
cond |= f.v[j];
}
/* If so, we're done. If f=1, the Jacobi symbol (g | f)=1. */
if (cond == 0) return 1 - 2*(jac & 1);
}
/* Determine if len>1 and limb (len-1) of both f and g is 0. */
fn = f.v[len - 1];
gn = g.v[len - 1];
cond = ((int32_t)len - 2) >> 31;
cond |= fn;
cond |= gn;
/* If so, reduce length. */
if (cond == 0) --len;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv32_mul_cmp_30(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
}
/* The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result. */
return 0;
}
#endif /* SECP256K1_MODINV32_IMPL_H */

View File

@ -7,10 +7,6 @@
#ifndef SECP256K1_MODINV64_H
#define SECP256K1_MODINV64_H
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "util.h"
#ifndef SECP256K1_WIDEMUL_INT128
@ -43,4 +39,9 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
/* Same as secp256k1_modinv64_var, but constant time in x (not in the modulus). */
static void secp256k1_modinv64(secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
/* Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus
* cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result
* cannot be computed. */
static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo);
#endif /* SECP256K1_MODINV64_H */

View File

@ -7,10 +7,9 @@
#ifndef SECP256K1_MODINV64_IMPL_H
#define SECP256K1_MODINV64_IMPL_H
#include "int128.h"
#include "modinv64.h"
#include "util.h"
/* This file implements modular inversion based on the paper "Fast constant-time gcd computation and
* modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
*
@ -18,6 +17,15 @@
* implementation for N=62, using 62-bit signed limbs represented as int64_t.
*/
/* Data type for transition matrices (see section 3 of explanation).
*
* t = [ u v ]
* [ q r ]
*/
typedef struct {
int64_t u, v, q, r;
} secp256k1_modinv64_trans2x2;
#ifdef VERIFY
/* Helper function to compute the absolute value of an int64_t.
* (we don't use abs/labs/llabs as it depends on the int sizes). */
@ -31,16 +39,18 @@ static const secp256k1_modinv64_signed62 SECP256K1_SIGNED62_ONE = {{1}};
/* Compute a*factor and put it in r. All but the top limb in r will be in range [0,2^62). */
static void secp256k1_modinv64_mul_62(secp256k1_modinv64_signed62 *r, const secp256k1_modinv64_signed62 *a, int alen, int64_t factor) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
int128_t c = 0;
const uint64_t M62 = UINT64_MAX >> 2;
secp256k1_int128 c, d;
int i;
secp256k1_i128_from_i64(&c, 0);
for (i = 0; i < 4; ++i) {
if (i < alen) c += (int128_t)a->v[i] * factor;
r->v[i] = (int64_t)c & M62; c >>= 62;
if (i < alen) secp256k1_i128_accum_mul(&c, a->v[i], factor);
r->v[i] = secp256k1_i128_to_u64(&c) & M62; secp256k1_i128_rshift(&c, 62);
}
if (4 < alen) c += (int128_t)a->v[4] * factor;
VERIFY_CHECK(c == (int64_t)c);
r->v[4] = (int64_t)c;
if (4 < alen) secp256k1_i128_accum_mul(&c, a->v[4], factor);
secp256k1_i128_from_i64(&d, secp256k1_i128_to_i64(&c));
VERIFY_CHECK(secp256k1_i128_eq_var(&c, &d));
r->v[4] = secp256k1_i128_to_i64(&c);
}
/* Return -1 for a<b*factor, 0 for a==b*factor, 1 for a>b*factor. A has alen limbs; b has 5. */
@ -60,6 +70,15 @@ static int secp256k1_modinv64_mul_cmp_62(const secp256k1_modinv64_signed62 *a, i
}
return 0;
}
/* Check if the determinant of t is equal to 1 << n. If abs, check if |det t| == 1 << n. */
static int secp256k1_modinv64_det_check_pow2(const secp256k1_modinv64_trans2x2 *t, unsigned int n, int abs) {
secp256k1_int128 a;
secp256k1_i128_det(&a, t->u, t->v, t->q, t->r);
if (secp256k1_i128_check_pow2(&a, n, 1)) return 1;
if (abs && secp256k1_i128_check_pow2(&a, n, -1)) return 1;
return 0;
}
#endif
/* Take as input a signed62 number in range (-2*modulus,modulus), and add a multiple of the modulus
@ -136,15 +155,6 @@ static void secp256k1_modinv64_normalize_62(secp256k1_modinv64_signed62 *r, int6
#endif
}
/* Data type for transition matrices (see section 3 of explanation).
*
* t = [ u v ]
* [ q r ]
*/
typedef struct {
int64_t u, v, q, r;
} secp256k1_modinv64_trans2x2;
/* Compute the transition matrix and eta for 59 divsteps (where zeta=-(delta+1/2)).
* Note that the transformation matrix is scaled by 2^62 and not 2^59.
*
@ -206,13 +216,15 @@ static int64_t secp256k1_modinv64_divsteps_59(int64_t zeta, uint64_t f0, uint64_
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
#ifdef VERIFY
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the
* aggregate of 59 of them will have determinant 2^59. Multiplying with the initial
* 8*identity (which has determinant 2^6) means the overall outputs has determinant
* 2^65. */
VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 65);
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 65, 0));
#endif
return zeta;
}
@ -259,7 +271,7 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
tmp = v; v = r; r = -tmp;
/* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled
* out (as we'd be done before that point), and no more than eta+1 can be done as its
* will flip again once that happens. */
* sign will flip again once that happens. */
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
VERIFY_CHECK(limit > 0 && limit <= 62);
/* m is a mask for the bottom min(limit, 6) bits. */
@ -289,11 +301,105 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
#ifdef VERIFY
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2, the
* aggregate of 62 of them will have determinant 2^62. */
VERIFY_CHECK((int128_t)t->u * t->r - (int128_t)t->v * t->q == ((int128_t)1) << 62);
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 0));
#endif
return eta;
}
/* Compute the transition matrix and eta for 62 posdivsteps (variable time, eta=-delta), and keeps track
* of the Jacobi symbol along the way. f0 and g0 must be f and g mod 2^64 rather than 2^62, because
* Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
*
* Input: eta: initial eta
* f0: bottom limb of initial f
* g0: bottom limb of initial g
* Output: t: transition matrix
* Input/Output: (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign
* by applying the returned transformation matrix to it. The other bits of *jacp may
* change, but are meaningless.
* Return: final eta
*/
static int64_t secp256k1_modinv64_posdivsteps_62_var(int64_t eta, uint64_t f0, uint64_t g0, secp256k1_modinv64_trans2x2 *t, int *jacp) {
/* Transformation matrix; see comments in secp256k1_modinv64_divsteps_62. */
uint64_t u = 1, v = 0, q = 0, r = 1;
uint64_t f = f0, g = g0, m;
uint32_t w;
int i = 62, limit, zeros;
int jac = *jacp;
for (;;) {
/* Use a sentinel bit to count zeros only up to i. */
zeros = secp256k1_ctz64_var(g | (UINT64_MAX << i));
/* Perform zeros divsteps at once; they all just divide g by two. */
g >>= zeros;
u <<= zeros;
v <<= zeros;
eta -= zeros;
i -= zeros;
/* Update the bottom bit of jac: when dividing g by an odd power of 2,
* if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
jac ^= (zeros & ((f >> 1) ^ (f >> 2)));
/* We're done once we've done 62 posdivsteps. */
if (i == 0) break;
VERIFY_CHECK((f & 1) == 1);
VERIFY_CHECK((g & 1) == 1);
VERIFY_CHECK((u * f0 + v * g0) == f << (62 - i));
VERIFY_CHECK((q * f0 + r * g0) == g << (62 - i));
/* If eta is negative, negate it and replace f,g with g,f. */
if (eta < 0) {
uint64_t tmp;
eta = -eta;
tmp = f; f = g; g = tmp;
tmp = u; u = q; q = tmp;
tmp = v; v = r; r = tmp;
/* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
* if both f and g are 3 mod 4. */
jac ^= ((f & g) >> 1);
/* Use a formula to cancel out up to 6 bits of g. Also, no more than i can be cancelled
* out (as we'd be done before that point), and no more than eta+1 can be done as its
* sign will flip again once that happens. */
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
VERIFY_CHECK(limit > 0 && limit <= 62);
/* m is a mask for the bottom min(limit, 6) bits. */
m = (UINT64_MAX >> (64 - limit)) & 63U;
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 6)
* bits. */
w = (f * g * (f * f - 2)) & m;
} else {
/* In this branch, use a simpler formula that only lets us cancel up to 4 bits of g, as
* eta tends to be smaller here. */
limit = ((int)eta + 1) > i ? i : ((int)eta + 1);
VERIFY_CHECK(limit > 0 && limit <= 62);
/* m is a mask for the bottom min(limit, 4) bits. */
m = (UINT64_MAX >> (64 - limit)) & 15U;
/* Find what multiple of f must be added to g to cancel its bottom min(limit, 4)
* bits. */
w = f + (((f + 1) & 4) << 1);
w = (-w * g) & m;
}
g += f * w;
q += u * w;
r += v * w;
VERIFY_CHECK((g & m) == 0);
}
/* Return data in t and return value. */
t->u = (int64_t)u;
t->v = (int64_t)v;
t->q = (int64_t)q;
t->r = (int64_t)r;
#ifdef VERIFY
/* The determinant of t must be a power of two. This guarantees that multiplication with t
* does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
* will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
* the aggregate of 62 of them will have determinant 2^62 or -2^62. */
VERIFY_CHECK(secp256k1_modinv64_det_check_pow2(t, 62, 1));
#endif
*jacp = jac;
return eta;
}
@ -305,21 +411,19 @@ static int64_t secp256k1_modinv64_divsteps_62_var(int64_t eta, uint64_t f0, uint
* This implements the update_de function from the explanation.
*/
static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp256k1_modinv64_signed62 *e, const secp256k1_modinv64_trans2x2 *t, const secp256k1_modinv64_modinfo* modinfo) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
const uint64_t M62 = UINT64_MAX >> 2;
const int64_t d0 = d->v[0], d1 = d->v[1], d2 = d->v[2], d3 = d->v[3], d4 = d->v[4];
const int64_t e0 = e->v[0], e1 = e->v[1], e2 = e->v[2], e3 = e->v[3], e4 = e->v[4];
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int64_t md, me, sd, se;
int128_t cd, ce;
secp256k1_int128 cd, ce;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, -2) > 0); /* e > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(e, 5, &modinfo->modulus, 1) < 0); /* e < modulus */
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) >= 0); /* |u|+|v| doesn't overflow */
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) >= 0); /* |q|+|r| doesn't overflow */
VERIFY_CHECK((secp256k1_modinv64_abs(u) + secp256k1_modinv64_abs(v)) <= M62 + 1); /* |u|+|v| <= 2^62 */
VERIFY_CHECK((secp256k1_modinv64_abs(q) + secp256k1_modinv64_abs(r)) <= M62 + 1); /* |q|+|r| <= 2^62 */
VERIFY_CHECK(secp256k1_modinv64_abs(u) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(v))); /* |u|+|v| <= 2^62 */
VERIFY_CHECK(secp256k1_modinv64_abs(q) <= (((int64_t)1 << 62) - secp256k1_modinv64_abs(r))); /* |q|+|r| <= 2^62 */
#endif
/* [md,me] start as zero; plus [u,q] if d is negative; plus [v,r] if e is negative. */
sd = d4 >> 63;
@ -327,54 +431,64 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
md = (u & sd) + (v & se);
me = (q & sd) + (r & se);
/* Begin computing t*[d,e]. */
cd = (int128_t)u * d0 + (int128_t)v * e0;
ce = (int128_t)q * d0 + (int128_t)r * e0;
secp256k1_i128_mul(&cd, u, d0);
secp256k1_i128_accum_mul(&cd, v, e0);
secp256k1_i128_mul(&ce, q, d0);
secp256k1_i128_accum_mul(&ce, r, e0);
/* Correct md,me so that t*[d,e]+modulus*[md,me] has 62 zero bottom bits. */
md -= (modinfo->modulus_inv62 * (uint64_t)cd + md) & M62;
me -= (modinfo->modulus_inv62 * (uint64_t)ce + me) & M62;
md -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&cd) + md) & M62;
me -= (modinfo->modulus_inv62 * secp256k1_i128_to_u64(&ce) + me) & M62;
/* Update the beginning of computation for t*[d,e]+modulus*[md,me] now md,me are known. */
cd += (int128_t)modinfo->modulus.v[0] * md;
ce += (int128_t)modinfo->modulus.v[0] * me;
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[0], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[0], me);
/* Verify that the low 62 bits of the computation are indeed zero, and then throw them away. */
VERIFY_CHECK(((int64_t)cd & M62) == 0); cd >>= 62;
VERIFY_CHECK(((int64_t)ce & M62) == 0); ce >>= 62;
VERIFY_CHECK((secp256k1_i128_to_u64(&cd) & M62) == 0); secp256k1_i128_rshift(&cd, 62);
VERIFY_CHECK((secp256k1_i128_to_u64(&ce) & M62) == 0); secp256k1_i128_rshift(&ce, 62);
/* Compute limb 1 of t*[d,e]+modulus*[md,me], and store it as output limb 0 (= down shift). */
cd += (int128_t)u * d1 + (int128_t)v * e1;
ce += (int128_t)q * d1 + (int128_t)r * e1;
secp256k1_i128_accum_mul(&cd, u, d1);
secp256k1_i128_accum_mul(&cd, v, e1);
secp256k1_i128_accum_mul(&ce, q, d1);
secp256k1_i128_accum_mul(&ce, r, e1);
if (modinfo->modulus.v[1]) { /* Optimize for the case where limb of modulus is zero. */
cd += (int128_t)modinfo->modulus.v[1] * md;
ce += (int128_t)modinfo->modulus.v[1] * me;
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[1], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[1], me);
}
d->v[0] = (int64_t)cd & M62; cd >>= 62;
e->v[0] = (int64_t)ce & M62; ce >>= 62;
d->v[0] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[0] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 2 of t*[d,e]+modulus*[md,me], and store it as output limb 1. */
cd += (int128_t)u * d2 + (int128_t)v * e2;
ce += (int128_t)q * d2 + (int128_t)r * e2;
secp256k1_i128_accum_mul(&cd, u, d2);
secp256k1_i128_accum_mul(&cd, v, e2);
secp256k1_i128_accum_mul(&ce, q, d2);
secp256k1_i128_accum_mul(&ce, r, e2);
if (modinfo->modulus.v[2]) { /* Optimize for the case where limb of modulus is zero. */
cd += (int128_t)modinfo->modulus.v[2] * md;
ce += (int128_t)modinfo->modulus.v[2] * me;
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[2], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[2], me);
}
d->v[1] = (int64_t)cd & M62; cd >>= 62;
e->v[1] = (int64_t)ce & M62; ce >>= 62;
d->v[1] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[1] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 3 of t*[d,e]+modulus*[md,me], and store it as output limb 2. */
cd += (int128_t)u * d3 + (int128_t)v * e3;
ce += (int128_t)q * d3 + (int128_t)r * e3;
secp256k1_i128_accum_mul(&cd, u, d3);
secp256k1_i128_accum_mul(&cd, v, e3);
secp256k1_i128_accum_mul(&ce, q, d3);
secp256k1_i128_accum_mul(&ce, r, e3);
if (modinfo->modulus.v[3]) { /* Optimize for the case where limb of modulus is zero. */
cd += (int128_t)modinfo->modulus.v[3] * md;
ce += (int128_t)modinfo->modulus.v[3] * me;
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[3], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[3], me);
}
d->v[2] = (int64_t)cd & M62; cd >>= 62;
e->v[2] = (int64_t)ce & M62; ce >>= 62;
d->v[2] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[2] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* Compute limb 4 of t*[d,e]+modulus*[md,me], and store it as output limb 3. */
cd += (int128_t)u * d4 + (int128_t)v * e4;
ce += (int128_t)q * d4 + (int128_t)r * e4;
cd += (int128_t)modinfo->modulus.v[4] * md;
ce += (int128_t)modinfo->modulus.v[4] * me;
d->v[3] = (int64_t)cd & M62; cd >>= 62;
e->v[3] = (int64_t)ce & M62; ce >>= 62;
secp256k1_i128_accum_mul(&cd, u, d4);
secp256k1_i128_accum_mul(&cd, v, e4);
secp256k1_i128_accum_mul(&ce, q, d4);
secp256k1_i128_accum_mul(&ce, r, e4);
secp256k1_i128_accum_mul(&cd, modinfo->modulus.v[4], md);
secp256k1_i128_accum_mul(&ce, modinfo->modulus.v[4], me);
d->v[3] = secp256k1_i128_to_u64(&cd) & M62; secp256k1_i128_rshift(&cd, 62);
e->v[3] = secp256k1_i128_to_u64(&ce) & M62; secp256k1_i128_rshift(&ce, 62);
/* What remains is limb 5 of t*[d,e]+modulus*[md,me]; store it as output limb 4. */
d->v[4] = (int64_t)cd;
e->v[4] = (int64_t)ce;
d->v[4] = secp256k1_i128_to_i64(&cd);
e->v[4] = secp256k1_i128_to_i64(&ce);
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, -2) > 0); /* d > -2*modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(d, 5, &modinfo->modulus, 1) < 0); /* d < modulus */
@ -388,40 +502,50 @@ static void secp256k1_modinv64_update_de_62(secp256k1_modinv64_signed62 *d, secp
* This implements the update_fg function from the explanation.
*/
static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
const uint64_t M62 = UINT64_MAX >> 2;
const int64_t f0 = f->v[0], f1 = f->v[1], f2 = f->v[2], f3 = f->v[3], f4 = f->v[4];
const int64_t g0 = g->v[0], g1 = g->v[1], g2 = g->v[2], g3 = g->v[3], g4 = g->v[4];
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int128_t cf, cg;
secp256k1_int128 cf, cg;
/* Start computing t*[f,g]. */
cf = (int128_t)u * f0 + (int128_t)v * g0;
cg = (int128_t)q * f0 + (int128_t)r * g0;
secp256k1_i128_mul(&cf, u, f0);
secp256k1_i128_accum_mul(&cf, v, g0);
secp256k1_i128_mul(&cg, q, f0);
secp256k1_i128_accum_mul(&cg, r, g0);
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62;
VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62;
VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
/* Compute limb 1 of t*[f,g], and store it as output limb 0 (= down shift). */
cf += (int128_t)u * f1 + (int128_t)v * g1;
cg += (int128_t)q * f1 + (int128_t)r * g1;
f->v[0] = (int64_t)cf & M62; cf >>= 62;
g->v[0] = (int64_t)cg & M62; cg >>= 62;
secp256k1_i128_accum_mul(&cf, u, f1);
secp256k1_i128_accum_mul(&cf, v, g1);
secp256k1_i128_accum_mul(&cg, q, f1);
secp256k1_i128_accum_mul(&cg, r, g1);
f->v[0] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[0] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 2 of t*[f,g], and store it as output limb 1. */
cf += (int128_t)u * f2 + (int128_t)v * g2;
cg += (int128_t)q * f2 + (int128_t)r * g2;
f->v[1] = (int64_t)cf & M62; cf >>= 62;
g->v[1] = (int64_t)cg & M62; cg >>= 62;
secp256k1_i128_accum_mul(&cf, u, f2);
secp256k1_i128_accum_mul(&cf, v, g2);
secp256k1_i128_accum_mul(&cg, q, f2);
secp256k1_i128_accum_mul(&cg, r, g2);
f->v[1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 3 of t*[f,g], and store it as output limb 2. */
cf += (int128_t)u * f3 + (int128_t)v * g3;
cg += (int128_t)q * f3 + (int128_t)r * g3;
f->v[2] = (int64_t)cf & M62; cf >>= 62;
g->v[2] = (int64_t)cg & M62; cg >>= 62;
secp256k1_i128_accum_mul(&cf, u, f3);
secp256k1_i128_accum_mul(&cf, v, g3);
secp256k1_i128_accum_mul(&cg, q, f3);
secp256k1_i128_accum_mul(&cg, r, g3);
f->v[2] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[2] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* Compute limb 4 of t*[f,g], and store it as output limb 3. */
cf += (int128_t)u * f4 + (int128_t)v * g4;
cg += (int128_t)q * f4 + (int128_t)r * g4;
f->v[3] = (int64_t)cf & M62; cf >>= 62;
g->v[3] = (int64_t)cg & M62; cg >>= 62;
secp256k1_i128_accum_mul(&cf, u, f4);
secp256k1_i128_accum_mul(&cf, v, g4);
secp256k1_i128_accum_mul(&cg, q, f4);
secp256k1_i128_accum_mul(&cg, r, g4);
f->v[3] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[3] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
/* What remains is limb 5 of t*[f,g]; store it as output limb 4. */
f->v[4] = (int64_t)cf;
g->v[4] = (int64_t)cg;
f->v[4] = secp256k1_i128_to_i64(&cf);
g->v[4] = secp256k1_i128_to_i64(&cg);
}
/* Compute (t/2^62) * [f, g], where t is a transition matrix for 62 divsteps.
@ -431,33 +555,37 @@ static void secp256k1_modinv64_update_fg_62(secp256k1_modinv64_signed62 *f, secp
* This implements the update_fg function from the explanation.
*/
static void secp256k1_modinv64_update_fg_62_var(int len, secp256k1_modinv64_signed62 *f, secp256k1_modinv64_signed62 *g, const secp256k1_modinv64_trans2x2 *t) {
const int64_t M62 = (int64_t)(UINT64_MAX >> 2);
const uint64_t M62 = UINT64_MAX >> 2;
const int64_t u = t->u, v = t->v, q = t->q, r = t->r;
int64_t fi, gi;
int128_t cf, cg;
secp256k1_int128 cf, cg;
int i;
VERIFY_CHECK(len > 0);
/* Start computing t*[f,g]. */
fi = f->v[0];
gi = g->v[0];
cf = (int128_t)u * fi + (int128_t)v * gi;
cg = (int128_t)q * fi + (int128_t)r * gi;
secp256k1_i128_mul(&cf, u, fi);
secp256k1_i128_accum_mul(&cf, v, gi);
secp256k1_i128_mul(&cg, q, fi);
secp256k1_i128_accum_mul(&cg, r, gi);
/* Verify that the bottom 62 bits of the result are zero, and then throw them away. */
VERIFY_CHECK(((int64_t)cf & M62) == 0); cf >>= 62;
VERIFY_CHECK(((int64_t)cg & M62) == 0); cg >>= 62;
VERIFY_CHECK((secp256k1_i128_to_u64(&cf) & M62) == 0); secp256k1_i128_rshift(&cf, 62);
VERIFY_CHECK((secp256k1_i128_to_u64(&cg) & M62) == 0); secp256k1_i128_rshift(&cg, 62);
/* Now iteratively compute limb i=1..len of t*[f,g], and store them in output limb i-1 (shifting
* down by 62 bits). */
for (i = 1; i < len; ++i) {
fi = f->v[i];
gi = g->v[i];
cf += (int128_t)u * fi + (int128_t)v * gi;
cg += (int128_t)q * fi + (int128_t)r * gi;
f->v[i - 1] = (int64_t)cf & M62; cf >>= 62;
g->v[i - 1] = (int64_t)cg & M62; cg >>= 62;
secp256k1_i128_accum_mul(&cf, u, fi);
secp256k1_i128_accum_mul(&cf, v, gi);
secp256k1_i128_accum_mul(&cg, q, fi);
secp256k1_i128_accum_mul(&cg, r, gi);
f->v[i - 1] = secp256k1_i128_to_u64(&cf) & M62; secp256k1_i128_rshift(&cf, 62);
g->v[i - 1] = secp256k1_i128_to_u64(&cg) & M62; secp256k1_i128_rshift(&cg, 62);
}
/* What remains is limb (len) of t*[f,g]; store it as output limb (len-1). */
f->v[len - 1] = (int64_t)cf;
g->v[len - 1] = (int64_t)cg;
f->v[len - 1] = secp256k1_i128_to_i64(&cf);
g->v[len - 1] = secp256k1_i128_to_i64(&cg);
}
/* Compute the inverse of x modulo modinfo->modulus, and replace x with it (constant time in x). */
@ -593,4 +721,74 @@ static void secp256k1_modinv64_var(secp256k1_modinv64_signed62 *x, const secp256
*x = d;
}
/* Do up to 25 iterations of 62 posdivsteps (up to 1550 steps; more is extremely rare) each until f=1.
* In VERIFY mode use a lower number of iterations (744, close to the median 756), so failure actually occurs. */
#ifdef VERIFY
#define JACOBI64_ITERATIONS 12
#else
#define JACOBI64_ITERATIONS 25
#endif
/* Compute the Jacobi symbol of x modulo modinfo->modulus (variable time). gcd(x,modulus) must be 1. */
static int secp256k1_jacobi64_maybe_var(const secp256k1_modinv64_signed62 *x, const secp256k1_modinv64_modinfo *modinfo) {
/* Start with f=modulus, g=x, eta=-1. */
secp256k1_modinv64_signed62 f = modinfo->modulus;
secp256k1_modinv64_signed62 g = *x;
int j, len = 5;
int64_t eta = -1; /* eta = -delta; delta is initially 1 */
int64_t cond, fn, gn;
int jac = 0;
int count;
/* The input limbs must all be non-negative. */
VERIFY_CHECK(g.v[0] >= 0 && g.v[1] >= 0 && g.v[2] >= 0 && g.v[3] >= 0 && g.v[4] >= 0);
/* If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we
* require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or
* time out). */
VERIFY_CHECK((g.v[0] | g.v[1] | g.v[2] | g.v[3] | g.v[4]) != 0);
for (count = 0; count < JACOBI64_ITERATIONS; ++count) {
/* Compute transition matrix and new eta after 62 posdivsteps. */
secp256k1_modinv64_trans2x2 t;
eta = secp256k1_modinv64_posdivsteps_62_var(eta, f.v[0] | ((uint64_t)f.v[1] << 62), g.v[0] | ((uint64_t)g.v[1] << 62), &t, &jac);
/* Update f,g using that transition matrix. */
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
secp256k1_modinv64_update_fg_62_var(len, &f, &g, &t);
/* If the bottom limb of f is 1, there is a chance that f=1. */
if (f.v[0] == 1) {
cond = 0;
/* Check if the other limbs are also 0. */
for (j = 1; j < len; ++j) {
cond |= f.v[j];
}
/* If so, we're done. When f=1, the Jacobi symbol (g | f)=1. */
if (cond == 0) return 1 - 2*(jac & 1);
}
/* Determine if len>1 and limb (len-1) of both f and g is 0. */
fn = f.v[len - 1];
gn = g.v[len - 1];
cond = ((int64_t)len - 2) >> 63;
cond |= fn;
cond |= gn;
/* If so, reduce length. */
if (cond == 0) --len;
#ifdef VERIFY
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 0) > 0); /* f > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&f, len, &modinfo->modulus, 1) <= 0); /* f <= modulus */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 0) > 0); /* g > 0 */
VERIFY_CHECK(secp256k1_modinv64_mul_cmp_62(&g, len, &modinfo->modulus, 1) < 0); /* g < modulus */
#endif
}
/* The loop failed to converge to f=g after 1550 iterations. Return 0, indicating unknown result. */
return 0;
}
#endif /* SECP256K1_MODINV64_IMPL_H */

View File

@ -8,6 +8,6 @@ noinst_HEADERS += src/modules/bppp/tests_impl.h
if USE_BENCHMARK
noinst_PROGRAMS += bench_bppp
bench_bppp_SOURCES = src/bench_bppp.c
bench_bppp_LDADD = libsecp256k1.la $(SECP_LIBS)
bench_bppp_LDFLAGS = -static
bench_bppp_LDADD = libsecp256k1.la
bench_bppp_CPPFLAGS = $(SECP_CONFIG_DEFINES)
endif

View File

@ -17,9 +17,6 @@
#include "test_vectors/prove.h"
static void test_bppp_generators_api(void) {
/* The BP generator API requires no precomp */
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_bppp_generators *gens;
secp256k1_bppp_generators *gens_orig;
unsigned char gens_ser[330];
@ -27,51 +24,52 @@ static void test_bppp_generators_api(void) {
int32_t ecount = 0;
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
/* The BP generator API requires no precomp */
secp256k1_context_set_error_callback(CTX, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_illegal_callback(CTX, counting_illegal_callback_fn, &ecount);
/* Create */
gens = secp256k1_bppp_generators_create(none, 10);
gens = secp256k1_bppp_generators_create(CTX, 10);
CHECK(gens != NULL && ecount == 0);
gens_orig = gens; /* Preserve for round-trip test */
/* Serialize */
ecount = 0;
CHECK(!secp256k1_bppp_generators_serialize(none, NULL, gens_ser, &len));
CHECK(!secp256k1_bppp_generators_serialize(CTX, NULL, gens_ser, &len));
CHECK(ecount == 1);
CHECK(!secp256k1_bppp_generators_serialize(none, gens, NULL, &len));
CHECK(!secp256k1_bppp_generators_serialize(CTX, gens, NULL, &len));
CHECK(ecount == 2);
CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, NULL));
CHECK(!secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, NULL));
CHECK(ecount == 3);
len = 0;
CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len));
CHECK(!secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len));
CHECK(ecount == 4);
len = sizeof(gens_ser) - 1;
CHECK(!secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len));
CHECK(!secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len));
CHECK(ecount == 5);
len = sizeof(gens_ser);
{
/* Output buffer can be greater than minimum needed */
unsigned char gens_ser_tmp[331];
size_t len_tmp = sizeof(gens_ser_tmp);
CHECK(secp256k1_bppp_generators_serialize(none, gens, gens_ser_tmp, &len_tmp));
CHECK(secp256k1_bppp_generators_serialize(CTX, gens, gens_ser_tmp, &len_tmp));
CHECK(len_tmp == sizeof(gens_ser_tmp) - 1);
CHECK(ecount == 5);
}
/* Parse */
CHECK(secp256k1_bppp_generators_serialize(none, gens, gens_ser, &len));
CHECK(secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len));
ecount = 0;
gens = secp256k1_bppp_generators_parse(none, NULL, sizeof(gens_ser));
gens = secp256k1_bppp_generators_parse(CTX, NULL, sizeof(gens_ser));
CHECK(gens == NULL && ecount == 1);
/* Not a multiple of 33 */
gens = secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser) - 1);
gens = secp256k1_bppp_generators_parse(CTX, gens_ser, sizeof(gens_ser) - 1);
CHECK(gens == NULL && ecount == 1);
gens = secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser));
gens = secp256k1_bppp_generators_parse(CTX, gens_ser, sizeof(gens_ser));
CHECK(gens != NULL && ecount == 1);
/* Not valid generators */
memset(gens_ser, 1, sizeof(gens_ser));
CHECK(secp256k1_bppp_generators_parse(none, gens_ser, sizeof(gens_ser)) == NULL);
CHECK(secp256k1_bppp_generators_parse(CTX, gens_ser, sizeof(gens_ser)) == NULL);
CHECK(ecount == 1);
/* Check that round-trip succeeded */
@ -82,16 +80,17 @@ static void test_bppp_generators_api(void) {
/* Destroy (we allow destroying a NULL context, it's just a noop. like free().) */
ecount = 0;
secp256k1_bppp_generators_destroy(none, NULL);
secp256k1_bppp_generators_destroy(none, gens);
secp256k1_bppp_generators_destroy(none, gens_orig);
secp256k1_bppp_generators_destroy(CTX, NULL);
secp256k1_bppp_generators_destroy(CTX, gens);
secp256k1_bppp_generators_destroy(CTX, gens_orig);
CHECK(ecount == 0);
secp256k1_context_destroy(none);
secp256k1_context_set_error_callback(CTX, NULL, NULL);
secp256k1_context_set_illegal_callback(CTX, NULL, NULL);
}
static void test_bppp_generators_fixed(void) {
secp256k1_bppp_generators *gens = secp256k1_bppp_generators_create(ctx, 3);
secp256k1_bppp_generators *gens = secp256k1_bppp_generators_create(CTX, 3);
unsigned char gens_ser[330];
const unsigned char fixed_first_3[99] = {
0x0b,
@ -113,14 +112,14 @@ static void test_bppp_generators_fixed(void) {
size_t len;
len = 99;
CHECK(secp256k1_bppp_generators_serialize(ctx, gens, gens_ser, &len));
CHECK(secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len));
CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0);
len = sizeof(gens_ser);
CHECK(secp256k1_bppp_generators_serialize(ctx, gens, gens_ser, &len));
CHECK(secp256k1_bppp_generators_serialize(CTX, gens, gens_ser, &len));
CHECK(memcmp(gens_ser, fixed_first_3, sizeof(fixed_first_3)) == 0);
secp256k1_bppp_generators_destroy(ctx, gens);
secp256k1_bppp_generators_destroy(CTX, gens);
}
static void test_bppp_tagged_hash(void) {
@ -161,7 +160,7 @@ static void test_bppp_tagged_hash(void) {
}
}
void test_log_exp(void) {
static void test_log_exp(void) {
CHECK(secp256k1_is_power_of_two(0) == 0);
CHECK(secp256k1_is_power_of_two(1) == 1);
CHECK(secp256k1_is_power_of_two(2) == 1);
@ -176,7 +175,7 @@ void test_log_exp(void) {
CHECK(secp256k1_bppp_log2(257) == 8);
}
void test_norm_util_helpers(void) {
static void test_norm_util_helpers(void) {
secp256k1_scalar a_vec[4], b_vec[4], rho_pows[4], res, res2, mu, rho;
int i;
/* a = {1, 2, 3, 4} b = {5, 6, 7, 8}, mu = 4, rho = 2 */
@ -214,7 +213,7 @@ void test_norm_util_helpers(void) {
}
void test_serialize_two_points_roundtrip(secp256k1_ge *X, secp256k1_ge *R) {
static void test_serialize_two_points_roundtrip(secp256k1_ge *X, secp256k1_ge *R) {
secp256k1_ge X_tmp, R_tmp;
unsigned char buf[65];
secp256k1_bppp_serialize_points(buf, X, R);
@ -224,23 +223,23 @@ void test_serialize_two_points_roundtrip(secp256k1_ge *X, secp256k1_ge *R) {
ge_equals_ge(R, &R_tmp);
}
void test_serialize_two_points(void) {
static void test_serialize_two_points(void) {
secp256k1_ge X, R;
int i;
for (i = 0; i < count; i++) {
for (i = 0; i < COUNT; i++) {
random_group_element_test(&X);
random_group_element_test(&R);
test_serialize_two_points_roundtrip(&X, &R);
}
for (i = 0; i < count; i++) {
for (i = 0; i < COUNT; i++) {
random_group_element_test(&X);
secp256k1_ge_set_infinity(&R);
test_serialize_two_points_roundtrip(&X, &R);
}
for (i = 0; i < count; i++) {
for (i = 0; i < COUNT; i++) {
secp256k1_ge_set_infinity(&X);
random_group_element_test(&R);
test_serialize_two_points_roundtrip(&X, &R);
@ -266,7 +265,7 @@ void test_serialize_two_points(void) {
CHECK(!secp256k1_bppp_parse_one_of_points(&R_tmp, buf, 0));
}
/* Check that sign bit is 0 for point at infinity */
for (i = 0; i < count; i++) {
for (i = 0; i < COUNT; i++) {
secp256k1_ge X_tmp, R_tmp;
unsigned char buf[65];
int expect;
@ -341,10 +340,10 @@ static void copy_vectors_into_scratch(secp256k1_scratch_space* scratch,
const secp256k1_ge *gens_vec,
size_t g_len,
size_t h_len) {
*ns = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, g_len * sizeof(secp256k1_scalar));
*ls = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
*cs = (secp256k1_scalar*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
*gs = (secp256k1_ge*)secp256k1_scratch_alloc(&ctx->error_callback, scratch, (g_len + h_len) * sizeof(secp256k1_ge));
*ns = (secp256k1_scalar*)secp256k1_scratch_alloc(&CTX->error_callback, scratch, g_len * sizeof(secp256k1_scalar));
*ls = (secp256k1_scalar*)secp256k1_scratch_alloc(&CTX->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
*cs = (secp256k1_scalar*)secp256k1_scratch_alloc(&CTX->error_callback, scratch, h_len * sizeof(secp256k1_scalar));
*gs = (secp256k1_ge*)secp256k1_scratch_alloc(&CTX->error_callback, scratch, (g_len + h_len) * sizeof(secp256k1_ge));
CHECK(ns != NULL && ls != NULL && cs != NULL && gs != NULL);
memcpy(*ns, n_vec, g_len * sizeof(secp256k1_scalar));
memcpy(*ls, l_vec, h_len * sizeof(secp256k1_scalar));
@ -374,10 +373,10 @@ static int secp256k1_bppp_rangeproof_norm_product_prove_const(
size_t g_len = n_vec_len, h_len = l_vec_len;
int res;
scratch_checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
scratch_checkpoint = secp256k1_scratch_checkpoint(&CTX->error_callback, scratch);
copy_vectors_into_scratch(scratch, &ns, &ls, &cs, &gs, n_vec, l_vec, c_vec, g_vec, g_len, h_len);
res = secp256k1_bppp_rangeproof_norm_product_prove(
ctx,
CTX,
scratch,
proof,
proof_len,
@ -392,7 +391,7 @@ static int secp256k1_bppp_rangeproof_norm_product_prove_const(
cs,
c_vec_len
);
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, scratch_checkpoint);
secp256k1_scratch_apply_checkpoint(&CTX->error_callback, scratch, scratch_checkpoint);
return res;
}
@ -442,7 +441,7 @@ static int secp256k1_norm_arg_verify(
secp256k1_norm_arg_commit_initial_data(&transcript, rho, gens_vec, g_len, c_vec, c_vec_len, &comm);
res = secp256k1_bppp_rangeproof_norm_product_verify(
ctx,
CTX,
scratch,
proof,
proof_len,
@ -458,15 +457,15 @@ static int secp256k1_norm_arg_verify(
}
/* Verify |c| = 0 */
void norm_arg_verify_zero_len(void) {
static void norm_arg_verify_zero_len(void) {
secp256k1_scalar n_vec[64], l_vec[64], c_vec[64];
secp256k1_scalar rho, mu;
secp256k1_ge commit;
secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*10); /* shouldn't need much */
secp256k1_scratch *scratch = secp256k1_scratch_space_create(CTX, 1000*10); /* shouldn't need much */
unsigned char proof[1000];
unsigned int n_vec_len = 1;
unsigned int c_vec_len = 1;
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n_vec_len + c_vec_len);
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(CTX, n_vec_len + c_vec_len);
size_t plen = sizeof(proof);
random_scalar_order(&rho);
@ -475,24 +474,24 @@ void norm_arg_verify_zero_len(void) {
random_scalar_order(&n_vec[0]);
random_scalar_order(&c_vec[0]);
random_scalar_order(&l_vec[0]);
CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
CHECK(secp256k1_bppp_commit(CTX, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
CHECK(secp256k1_norm_arg_prove(scratch, proof, &plen, &rho, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &commit));
CHECK(secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit));
CHECK(!secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n_vec_len, c_vec, 0, &commit));
secp256k1_bppp_generators_destroy(ctx, gs);
secp256k1_bppp_generators_destroy(CTX, gs);
secp256k1_scratch_space_destroy(ctx, scratch);
secp256k1_scratch_space_destroy(CTX, scratch);
}
void norm_arg_test(unsigned int n, unsigned int m) {
static void norm_arg_test(unsigned int n, unsigned int m) {
secp256k1_scalar n_vec[64], l_vec[64], c_vec[64];
secp256k1_scalar rho, mu;
secp256k1_ge commit;
size_t i, plen;
int res;
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(ctx, n + m);
secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */
secp256k1_bppp_generators *gs = secp256k1_bppp_generators_create(CTX, n + m);
secp256k1_scratch *scratch = secp256k1_scratch_space_create(CTX, 1000*1000); /* shouldn't need much */
unsigned char proof[1000];
plen = 1000;
random_scalar_order(&rho);
@ -507,7 +506,7 @@ void norm_arg_test(unsigned int n, unsigned int m) {
random_scalar_order(&c_vec[i]);
}
res = secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n, l_vec, m, c_vec, m, &mu);
res = secp256k1_bppp_commit(CTX, scratch, &commit, gs, n_vec, n, l_vec, m, c_vec, m, &mu);
CHECK(res == 1);
res = secp256k1_norm_arg_prove(scratch, proof, &plen, &rho, gs, n_vec, n, l_vec, m, c_vec, m, &commit);
CHECK(res == 1);
@ -523,8 +522,8 @@ void norm_arg_test(unsigned int n, unsigned int m) {
res = secp256k1_norm_arg_verify(scratch, proof, plen, &rho, gs, n, c_vec, m, &commit);
CHECK(res == 0);
secp256k1_scratch_space_destroy(ctx, scratch);
secp256k1_bppp_generators_destroy(ctx, gs);
secp256k1_scratch_space_destroy(CTX, scratch);
secp256k1_bppp_generators_destroy(CTX, gs);
}
/* Parses generators from points compressed as pubkeys */
@ -532,19 +531,16 @@ secp256k1_bppp_generators* bppp_generators_parse_regular(const unsigned char* da
size_t n = data_len / 33;
secp256k1_bppp_generators* ret;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(data != NULL);
if (data_len % 33 != 0) {
return NULL;
}
ret = (secp256k1_bppp_generators *)checked_malloc(&ctx->error_callback, sizeof(*ret));
ret = (secp256k1_bppp_generators *)checked_malloc(&CTX->error_callback, sizeof(*ret));
if (ret == NULL) {
return NULL;
}
ret->n = n;
ret->gens = (secp256k1_ge*)checked_malloc(&ctx->error_callback, n * sizeof(*ret->gens));
ret->gens = (secp256k1_ge*)checked_malloc(&CTX->error_callback, n * sizeof(*ret->gens));
if (ret->gens == NULL) {
free(ret);
return NULL;
@ -580,16 +576,16 @@ int norm_arg_verify_vectors_helper(secp256k1_scratch *scratch, const unsigned ch
CHECK(!overflow);
}
CHECK(secp256k1_ge_parse_ext(&commit, commit33));
ret = secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit);
ret = secp256k1_bppp_rangeproof_norm_product_verify(CTX, scratch, proof, plen, &transcript, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit);
secp256k1_bppp_generators_destroy(ctx, gs);
secp256k1_bppp_generators_destroy(CTX, gs);
return ret;
}
#define IDX_TO_TEST(i) (norm_arg_verify_vectors_helper(scratch, verify_vector_gens, verify_vector_##i##_proof, sizeof(verify_vector_##i##_proof), verify_vector_##i##_r32, verify_vector_##i##_n_vec_len, verify_vector_##i##_c_vec32, verify_vector_##i##_c_vec, sizeof(verify_vector_##i##_c_vec)/sizeof(secp256k1_scalar), verify_vector_##i##_commit33) == verify_vector_##i##_result)
void norm_arg_verify_vectors(void) {
secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */
static void norm_arg_verify_vectors(void) {
secp256k1_scratch *scratch = secp256k1_scratch_space_create(CTX, 1000*1000); /* shouldn't need much */
size_t alloc = scratch->alloc_size;
CHECK(IDX_TO_TEST(0));
@ -607,11 +603,11 @@ void norm_arg_verify_vectors(void) {
CHECK(IDX_TO_TEST(12));
CHECK(alloc == scratch->alloc_size);
secp256k1_scratch_space_destroy(ctx, scratch);
secp256k1_scratch_space_destroy(CTX, scratch);
}
#undef IDX_TO_TEST
void norm_arg_prove_vectors_helper(secp256k1_scratch *scratch, const unsigned char *gens, const unsigned char *proof, size_t plen, const unsigned char *r32, const unsigned char n_vec32[][32], secp256k1_scalar *n_vec, size_t n_vec_len, const unsigned char l_vec32[][32], secp256k1_scalar *l_vec, const unsigned char c_vec32[][32], secp256k1_scalar *c_vec, size_t c_vec_len, int result) {
static void norm_arg_prove_vectors_helper(secp256k1_scratch *scratch, const unsigned char *gens, const unsigned char *proof, size_t plen, const unsigned char *r32, const unsigned char n_vec32[][32], secp256k1_scalar *n_vec, size_t n_vec_len, const unsigned char l_vec32[][32], secp256k1_scalar *l_vec, const unsigned char c_vec32[][32], secp256k1_scalar *c_vec, size_t c_vec_len, int result) {
secp256k1_sha256 transcript;
secp256k1_bppp_generators *gs = bppp_generators_parse_regular(gens, 33*(n_vec_len + c_vec_len));
secp256k1_scalar rho, mu;
@ -640,16 +636,16 @@ void norm_arg_prove_vectors_helper(secp256k1_scratch *scratch, const unsigned ch
CHECK(secp256k1_bppp_rangeproof_norm_product_prove_const(scratch, myproof, &myplen, &transcript, &rho, gs->gens, gs->n, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len) == result);
if (!result) {
secp256k1_bppp_generators_destroy(ctx, gs);
secp256k1_bppp_generators_destroy(CTX, gs);
return;
}
CHECK(plen == myplen);
CHECK(secp256k1_memcmp_var(proof, myproof, plen) == 0);
CHECK(secp256k1_bppp_commit(ctx, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
CHECK(secp256k1_bppp_commit(CTX, scratch, &commit, gs, n_vec, n_vec_len, l_vec, c_vec_len, c_vec, c_vec_len, &mu));
secp256k1_sha256_initialize(&transcript);
CHECK(secp256k1_bppp_rangeproof_norm_product_verify(ctx, scratch, proof, plen, &transcript, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit));
secp256k1_bppp_generators_destroy(ctx, gs);
CHECK(secp256k1_bppp_rangeproof_norm_product_verify(CTX, scratch, proof, plen, &transcript, &rho, gs, n_vec_len, c_vec, c_vec_len, &commit));
secp256k1_bppp_generators_destroy(CTX, gs);
}
@ -659,8 +655,8 @@ void norm_arg_prove_vectors_helper(secp256k1_scratch *scratch, const unsigned ch
prove_vector_##i##_c_vec32, prove_vector_##i##_c_vec, sizeof(prove_vector_##i##_c_vec)/sizeof(secp256k1_scalar), \
prove_vector_##i##_result))
void norm_arg_prove_vectors(void) {
secp256k1_scratch *scratch = secp256k1_scratch_space_create(ctx, 1000*1000); /* shouldn't need much */
static void norm_arg_prove_vectors(void) {
secp256k1_scratch *scratch = secp256k1_scratch_space_create(CTX, 1000*1000); /* shouldn't need much */
size_t alloc = scratch->alloc_size;
IDX_TO_TEST(0);
@ -670,12 +666,12 @@ void norm_arg_prove_vectors(void) {
IDX_TO_TEST(4);
CHECK(alloc == scratch->alloc_size);
secp256k1_scratch_space_destroy(ctx, scratch);
secp256k1_scratch_space_destroy(CTX, scratch);
}
#undef IDX_TO_TEST
void run_bppp_tests(void) {
static void run_bppp_tests(void) {
test_log_exp();
test_norm_util_helpers();
test_serialize_two_points();

View File

@ -7,7 +7,7 @@
#ifndef SECP256K1_MODULE_ECDH_BENCH_H
#define SECP256K1_MODULE_ECDH_BENCH_H
#include "../include/secp256k1_ecdh.h"
#include "../../../include/secp256k1_ecdh.h"
typedef struct {
secp256k1_context *ctx;
@ -42,7 +42,7 @@ static void bench_ecdh(void* arg, int iters) {
}
}
void run_ecdh_bench(int iters, int argc, char** argv) {
static void run_ecdh_bench(int iters, int argc, char** argv) {
bench_ecdh_data data;
int d = argc == 1;

View File

@ -50,7 +50,7 @@ int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *output, const se
overflow |= secp256k1_scalar_is_zero(&s);
secp256k1_scalar_cmov(&s, &secp256k1_scalar_one, overflow);
secp256k1_ecmult_const(&res, &pt, &s, 256);
secp256k1_ecmult_const(&res, &pt, &s);
secp256k1_ge_set_gej(&pt, &res);
/* Compute a hash of the point */

View File

@ -7,7 +7,7 @@
#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) {
static 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;
@ -15,7 +15,7 @@ int ecdh_hash_function_test_fail(unsigned char *output, const unsigned char *x,
return 0;
}
int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, const unsigned char *y, void *data) {
static 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;
@ -24,9 +24,9 @@ int ecdh_hash_function_custom(unsigned char *output, const unsigned char *x, con
return 1;
}
void test_ecdh_api(void) {
static void test_ecdh_api(void) {
/* Setup context that just counts errors */
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_pubkey point;
unsigned char res[32];
unsigned char s_one[32] = { 0 };
@ -53,14 +53,14 @@ void test_ecdh_api(void) {
secp256k1_context_destroy(tctx);
}
void test_ecdh_generator_basepoint(void) {
static void test_ecdh_generator_basepoint(void) {
unsigned char s_one[32] = { 0 };
secp256k1_pubkey point[2];
int i;
s_one[31] = 1;
/* Check against pubkey creation when the basepoint is the generator */
for (i = 0; i < 2 * count; ++i) {
for (i = 0; i < 2 * COUNT; ++i) {
secp256k1_sha256 sha;
unsigned char s_b32[32];
unsigned char output_ecdh[65];
@ -72,20 +72,20 @@ void test_ecdh_generator_basepoint(void) {
random_scalar_order(&s);
secp256k1_scalar_get_b32(s_b32, &s);
CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1);
CHECK(secp256k1_ec_pubkey_create(CTX, &point[0], s_one) == 1);
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);
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);
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);
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(secp256k1_ec_pubkey_serialize(CTX, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1);
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, point_ser, point_ser_len);
secp256k1_sha256_finalize(&sha, output_ser);
@ -94,7 +94,7 @@ void test_ecdh_generator_basepoint(void) {
}
}
void test_bad_scalar(void) {
static void test_bad_scalar(void) {
unsigned char s_zero[32] = { 0 };
unsigned char s_overflow[32] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@ -110,21 +110,21 @@ void test_bad_scalar(void) {
/* Create random point */
random_scalar_order(&rand);
secp256k1_scalar_get_b32(s_rand, &rand);
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1);
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, NULL, NULL) == 0);
CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow, NULL, NULL) == 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, NULL, NULL) == 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);
CHECK(secp256k1_ecdh(CTX, output, &point, s_overflow, ecdh_hash_function_test_fail, NULL) == 0);
}
/** Test that ECDH(sG, 1/s) == ECDH((1/s)G, s) == ECDH(G, 1) for a few random s. */
void test_result_basepoint(void) {
static void test_result_basepoint(void) {
secp256k1_pubkey point;
secp256k1_scalar rand;
unsigned char s[32];
@ -136,26 +136,26 @@ void test_result_basepoint(void) {
unsigned char s_one[32] = { 0 };
s_one[31] = 1;
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_one) == 1);
CHECK(secp256k1_ecdh(ctx, out_base, &point, s_one, NULL, NULL) == 1);
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_one) == 1);
CHECK(secp256k1_ecdh(CTX, out_base, &point, s_one, NULL, NULL) == 1);
for (i = 0; i < 2 * count; i++) {
for (i = 0; i < 2 * COUNT; i++) {
random_scalar_order(&rand);
secp256k1_scalar_get_b32(s, &rand);
secp256k1_scalar_inverse(&rand, &rand);
secp256k1_scalar_get_b32(s_inv, &rand);
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s) == 1);
CHECK(secp256k1_ecdh(ctx, out, &point, s_inv, NULL, NULL) == 1);
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s) == 1);
CHECK(secp256k1_ecdh(CTX, out, &point, s_inv, NULL, NULL) == 1);
CHECK(secp256k1_memcmp_var(out, out_base, 32) == 0);
CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_inv) == 1);
CHECK(secp256k1_ecdh(ctx, out_inv, &point, s, NULL, NULL) == 1);
CHECK(secp256k1_ec_pubkey_create(CTX, &point, s_inv) == 1);
CHECK(secp256k1_ecdh(CTX, out_inv, &point, s, NULL, NULL) == 1);
CHECK(secp256k1_memcmp_var(out_inv, out_base, 32) == 0);
}
}
void run_ecdh_tests(void) {
static void run_ecdh_tests(void) {
test_ecdh_api();
test_ecdh_generator_basepoint();
test_bad_scalar();

View File

@ -81,7 +81,7 @@ static void secp256k1_dleq_pair(const secp256k1_ecmult_gen_context *ecmult_gen_c
secp256k1_ecmult_gen(ecmult_gen_ctx, &p1j, sk);
secp256k1_ge_set_gej(p1, &p1j);
secp256k1_ecmult_const(&p2j, gen2, sk, 256);
secp256k1_ecmult_const(&p2j, gen2, sk);
secp256k1_ge_set_gej(p2, &p2j);
}

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