191 Commits

Author SHA1 Message Date
Tim Ruffing
dc4181ae30 Merge pull request #90 from plutomonkey/typo
Fix typo in MuSig documentation.
2020-05-06 14:12:45 +02:00
Jason Davies
a3ef354b24 Fix typo in MuSig documentation. 2020-05-06 11:17:29 +01:00
Andrew Poelstra
cad7cc8f34 Merge pull request #73 from jonasnick/fix-musig-message
Require message in musig protocol in an earlier state
2019-10-18 20:42:30 +00:00
Jonas Nick
85bcb7c951 Merge #84: port of secp256k1#566 "jni: Use only Guava for hex encoding and decoding"
682a821759 jni: Use only Guava for hex encoding and decoding (Tim Ruffing)

Pull request description:

  This removes a dependency on javax.xml.bind, which is no longer
  available in JDK >= 11, see
  https://openjdk.java.net/jeps/320#Java-EE-modules .

  This fixes Travis, whose Java builds were failing recently.

ACKs for top commit:
  jonasnick:
    ACK 682a821759

Tree-SHA512: 16f7e6cd47c77973c66c2dc26ad3b75399f4d161f127f8f6d7ee31863c101f1a50222209710948f53d36ca60a9364912cd1d1dc88147dd418e42a133cec39869
2019-08-21 08:31:19 +00:00
Tim Ruffing
682a821759 jni: Use only Guava for hex encoding and decoding
This removes a dependency on javax.xml.bind, which is no longer
available in JDK >= 11, see
https://openjdk.java.net/jeps/320#Java-EE-modules .
2019-08-20 15:40:28 +02:00
Tim Ruffing
1a1a803b7f Merge pull request #83 from jonasnick/fixder
Remove mentions of DER in H derivation.
2019-08-19 16:02:27 +02:00
Jonas Nick
48089ce788 Remove mentions of DER in H derivation. 2019-08-19 14:02:29 +00:00
Tim Ruffing
cfb14a5d0f Merge pull request #82 from jonasnick/fixes
Musig: add cplusplus directive and fix ARG_NONNULL macro
2019-08-19 15:51:00 +02:00
Tim Ruffing
13aa54e3af Merge pull request #80 from jonasnick/f-H
Fix explanation of H derivation. It doesn't use DER encoding.
2019-08-19 15:50:08 +02:00
Jonas Nick
217151df1c Fix ARG_NONNULL macro usage in musig include 2019-08-19 08:35:28 +00:00
Jonas Nick
6ba31b8cee Add cplusplus directive to musig include 2019-08-19 08:29:11 +00:00
Jonas Nick
b1fb2ce625 Fix explanation of H derivation. It doesn't use DER encoding. 2019-08-18 15:56:44 +00:00
Jonas Nick
6a57be09e3 Require message in musig protocol in an earlier state. In particular,
remove the set_msg function and require the message in get_public_nonce
at the latest.
2019-07-09 11:33:13 +00:00
Jonas Nick
57ce5882ad Fix my_index in musig state machine tests 2019-07-09 09:47:56 +00:00
Andrew Poelstra
e3a10f4677 Merge pull request #74 from jonasnick/sig_combine_tweak
Add tweak32 parameter to musig_partial_sig_combine
2019-07-03 22:02:15 +00:00
Tim Ruffing
8df2c952f1 Merge pull request #75 from jonasnick/musig-travis
Add musig module to travis
2019-07-03 01:21:06 +02:00
Jonas Nick
a0a4b4212c Add tweak32 parameter to musig_partial_sig_combine which allows to sign for p2c/taproot commitments 2019-07-02 18:31:12 +00:00
Jonas Nick
996e84c4cd Add musig module tests to travis 2019-06-25 12:35:24 +00:00
Tim Ruffing
11af7015de Merge pull request #58 from jonasnick/schnorrsig-fix
Add fixups from upstream schnorrsig PR
2019-06-25 14:31:15 +02:00
Jonas Nick
cb8f059724 Add fixups from upstream schnorrsig PR
f make helper functions static
f hash noncedata into nonce in nonce_function_bipschnorr
f expose nonce_function_bipschnorr
f fix undefined behavior when shifting an int 31 places
f add cplusplus ifdef to schnorrsig include file
f hash complete pubkey into batch seed
f chacha20 for bigendians
f add schnorrsig to travis
f show in configure if schnorrsig is enabled
2019-06-25 12:20:06 +00:00
Jonas Nick
2f6c3353ab Merge pull request #72 from jonasnick/fix-upstream-rebase
Fix schnorrsig and musig modules after rebase
2019-06-21 12:28:15 +00:00
Jonas Nick
99e1fb271c Fix musig module after rebase on upstream e541a90e 2019-06-21 09:11:57 +00:00
Jonas Nick
6303e3b0ca Fix schnorrsig module after rebase on upstream e541a90e 2019-06-21 09:11:54 +00:00
Andrew Poelstra
44db4d801f Merge pull request #57 from apoelstra/2019-04-surjectionproof-stack
surjectionproof: reduce stack usage and limit proofs to anonymity set of 16
2019-06-06 09:29:39 +00:00
Tim Ruffing
f7e4d08dae surjection proof: Reject proofs with too many used inputs in reduced mode 2019-06-05 12:25:34 +02:00
Roman Zeyde
112edb2c6a allow reducing surjection proof size (to lower generation stack usage) 2019-06-04 16:37:48 +00:00
Andrew Poelstra
d512d78653 surjectionproof: introduce SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS constant and set it to 16 2019-06-04 16:37:48 +00:00
Andrew Poelstra
a118acc02b surjectionproof: reduce stack usage 2019-06-04 16:37:48 +00:00
Andrew Poelstra
e7f4ff4c62 Merge pull request #70 from apoelstra/2019-06-surjection-count
surjectionproof: fix malleability in surjection proof parsing
2019-06-04 16:35:35 +00:00
Andrew Poelstra
f94d46e652 Merge pull request #71 from real-or-random/fix-trailing-test
Fix read of wrong buffer (and OOB) in surjectionproof tests
2019-06-04 15:46:56 +00:00
Andrew Poelstra
49a1e01731 surjectionproof: fix malleability in surjection proof parsing 2019-06-04 15:44:47 +00:00
Tim Ruffing
55311b0e03 Fix read of wrong buffer (and OOB) in surjectionproof tests 2019-06-04 14:33:08 +02:00
Andrew Poelstra
290a27bb75 surjectionproof: add test vectors for "set padding bits" 2019-06-03 21:45:48 +00:00
Andrew Poelstra
7bc3daa482 surjectionproof: add fixed test vectors 2019-06-03 21:20:21 +00:00
Dmitry Petukhov
6f3b0c05c2 Improve comments for surctionproof init+alloc/destroy funcs
The comments with 'XXX' was intended to indicate that the listed
concerns was subject to review and change, but the code with these
comments was merged straight away. This commit replaces comments
with more complete text describing the issues.

This also signifies that the commit that this code was introduced in is
not anymore 'work in progress'.
2019-05-30 14:08:30 +00:00
Dmitry Petukhov
250ebb364e work in progress: add _allocate_initialized/destroy funcs 2019-05-30 14:08:30 +00:00
Jonas Nick
4a7763361d Improve explanation of key cancellation attack in whitelist.md 2019-05-30 14:08:30 +00:00
Jonas Nick
898c9f05bb Clarify how to derive alternative generator H 2019-05-30 14:08:30 +00:00
Roman Zeyde
15d92782d3 Add bench_generator and bench_rangeproof to .gitignore 2019-05-30 14:08:30 +00:00
Tim Ruffing
86240b207d Clean up ./configure help strings (zkp extensions) 2019-05-30 14:08:30 +00:00
Roman Zeyde
865b76186c Fix a small typo in the generator parameter name 2019-05-30 14:08:30 +00:00
Andrew Poelstra
cd5ba5c3b9 generator: remove CHECK abort calls exposed by public API 2019-05-30 14:08:30 +00:00
Andrew Poelstra
ff16651273 musig: add user documentation 2019-05-30 14:08:21 +00:00
Jonas Nick
0ad6b6036f Add 3-of-3 MuSig example 2019-05-30 14:04:38 +00:00
Jonas Nick
b61a1a9d98 Add MuSig module which allows creating n-of-n multisignatures and adaptor signatures. 2019-05-30 14:04:38 +00:00
Andrew Poelstra
5d5374f92c Add schnorrsig module which implements BIP-schnorr [0] compatible signing, verification and batch verification.
[0] https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki
2019-05-30 14:04:38 +00:00
Andrew Poelstra
a8ae6baff3 add chacha20 function 2019-05-30 14:04:38 +00:00
Gregory Sanders
9a8a71e8bb use proper types for rangeproof min/max 2019-05-30 14:04:38 +00:00
Andrew Poelstra
14769b9648 rangeproof: reduce iteration count in unit tests 2019-05-30 14:04:38 +00:00
Gregory Sanders
0593861cc5 Enable more builds with rest of experimental flags 2019-05-30 14:04:38 +00:00
Jonas Nick
e9fea74278 Add explanation about how BIP32 unhardened derivation can be used to simplify whitelisting 2019-05-30 14:04:38 +00:00
Jonas Nick
dec1b9ce27 Add comment to explain effect of max_n_iterations in surjectionproof_init 2019-05-30 14:04:38 +00:00
Andrew Poelstra
ea62bfe221 add unit test for generator and pedersen commitment roundtripping 2019-05-30 14:04:38 +00:00
Andrew Poelstra
e32924f0ee rangeproof: fix serialization of pedersen commintments 2019-05-30 14:04:38 +00:00
Andrew Poelstra
972d056fac rangeproof: verify correctness of pedersen commitments when parsing 2019-05-30 14:04:38 +00:00
Andrew Poelstra
2cc4c6fef1 generator: verify correctness of point when parsing 2019-05-30 14:04:38 +00:00
Andrew Poelstra
65ffea43d5 rangeproof: check that points deserialize correctly when verifying rangeproof 2019-05-30 14:04:38 +00:00
Andrew Poelstra
cb786d6d1a rangeproof: add fixed vector test case 2019-05-30 14:04:38 +00:00
Frank V. Castellucci
b387ba0389 Expose generator in shared library
Was failing linking to `*.so` library
2019-05-30 14:04:38 +00:00
Gregory Sanders
8da432855c fix spelling in documentation 2019-05-30 14:04:38 +00:00
Tim Ruffing
6f14fe40d9 Test for rejection of trailing bytes in range proofs 2019-05-30 14:04:38 +00:00
Tim Ruffing
ab4fbc1be8 Test for rejection of trailing bytes in surjection proofs 2019-05-30 14:04:38 +00:00
Tim Ruffing
c908c97d67 Reject surjection proofs with trailing garbage 2019-05-30 14:04:38 +00:00
datavetaren
f723bf5b37 Minor bugfix. Wrong length due to NUL character. 2019-05-30 14:04:38 +00:00
Jonas Nick
6872069de9 Add whitelisting benchmark 2019-05-30 14:04:38 +00:00
Gregory Sanders
6ceccb75be add whitelist_impl.h to include for dist 2019-05-30 14:04:38 +00:00
Andrew Poelstra
a3ad4a8668 generator: add API tests 2019-05-30 14:04:38 +00:00
Andrew Poelstra
e93e886cb4 generator: remove unnecessary ARG_CHECK from generate() 2019-05-30 14:04:38 +00:00
Gregory Sanders
f1d6e4b831 Fix generator makefile
Include test_impl.h
2019-05-30 14:04:38 +00:00
Jonas Nick
68be611317 Fix pedersen_blind_generator_blind_sum return value documentation 2019-05-30 14:04:38 +00:00
Jonas Nick
51fc58ae6b Add n_keys argument to whitelist_verify 2019-05-30 14:04:38 +00:00
Jonas Nick
36b100c779 Fix checks of whitelist serialize/parse arguments 2019-05-30 14:04:38 +00:00
Andrew Poelstra
c8f54e12ec whitelist: fix serialize/parse API to take serialized length 2019-05-30 14:04:38 +00:00
Jonas Nick
56fca50778 Fix include/secp256k1_rangeproof.h function argument documentation. 2019-05-30 14:04:38 +00:00
Andrew Poelstra
4617f04784 rangeproof: add API tests 2019-05-30 14:04:38 +00:00
Andrew Poelstra
cd4e438a3a surjectionproof: rename unit test functions to be more consistent with other modules 2019-05-30 14:04:38 +00:00
Andrew Poelstra
2cc7f1e045 surjectionproof: add API unit tests 2019-05-30 14:04:38 +00:00
Andrew Poelstra
c4097f758f surjectionproof: tests_impl.h s/assert/CHECK/g 2019-05-30 14:04:38 +00:00
Andrew Poelstra
5ee6bf3418 rangeproof: fix memory leak in unit tests 2019-05-30 14:04:38 +00:00
Andrew Poelstra
94e81a250e add surjection proof module
Includes fix and tests by Jonas Nick.
2019-05-30 14:04:38 +00:00
Andrew Poelstra
a66ea35227 Implement ring-signature based whitelist delegation scheme 2019-05-30 14:04:38 +00:00
Andrew Poelstra
2bb5133615 rangeproof: several API changes
* add summing function for blinded generators
* drop `excess` and `gen` from `verify_tally`
* add extra_commit to rangeproof sign and verify
2019-05-30 14:04:38 +00:00
Pieter Wuille
9b00b61d9d Expose generator in pedersen/rangeproof API 2019-05-30 14:04:38 +00:00
Pieter Wuille
54fa2639e1 Constant-time generator module 2019-05-30 14:04:38 +00:00
Andrew Poelstra
023aa86ac0 rangeproof: expose sidechannel message field in the signing API
Including a fix by Jonas Nick.
2019-05-30 14:04:38 +00:00
Andrew Poelstra
89e7451d42 [RANGEPROOF BREAK] Use quadratic residue for tie break and modularity cleanup
Switch to secp256k1_pedersen_commitment by Andrew Poelstra.
Switch to quadratic residue based disambiguation by Pieter Wuille.
2019-05-30 14:04:38 +00:00
Gregory Maxwell
f126331bc9 Pedersen commitments, borromean ring signatures, and ZK range proofs.
This commit adds three new cryptosystems to libsecp256k1:

Pedersen commitments are a system for making blinded commitments
 to a value.  Functionally they work like:
  commit_b,v = H(blind_b || value_v),
 except they are additively homorphic, e.g.
  C(b1, v1) - C(b2, v2) = C(b1 - b2, v1 - v2) and
  C(b1, v1) - C(b1, v1) = 0, etc.
 The commitments themselves are EC points, serialized as 33 bytes.
 In addition to the commit function this implementation includes
 utility functions for verifying that a set of commitments sums
 to zero, and for picking blinding factors that sum to zero.
 If the blinding factors are uniformly random, pedersen commitments
 have information theoretic privacy.

Borromean ring signatures are a novel efficient ring signature
 construction for AND/OR admissions policies (the code here implements
 an AND of ORs, each of any size).  This construction requires
 32 bytes of signature per pubkey used plus 32 bytes of constant
 overhead. With these you can construct signatures like "Given pubkeys
 A B C D E F G, the signer knows the discrete logs
 satisifying (A || B) & (C || D || E) & (F || G)".

ZK range proofs allow someone to prove a pedersen commitment is in
 a particular range (e.g. [0..2^64)) without revealing the specific
 value.  The construction here is based on the above borromean
 ring signature and uses a radix-4 encoding and other optimizations
 to maximize efficiency.  It also supports encoding proofs with a
 non-private base-10 exponent and minimum-value to allow trading
 off secrecy for size and speed (or just avoiding wasting space
 keeping data private that was already public due to external
 constraints).

A proof for a 32-bit mantissa takes 2564 bytes, but 2048 bytes of
 this can be used to communicate a private message to a receiver
 who shares a secret random seed with the prover.

Also: get rid of precomputed H tables (Pieter Wuille)
2019-05-30 14:04:38 +00:00
Greg Maxwell
e1fb4af90b Add 64-bit integer utilities 2019-05-30 14:04:38 +00:00
Gregory Maxwell
e541a90ef6 Merge #629: Avoid calling _is_zero when _set_b32 fails.
cd473e0 Avoid calling secp256k1_*_is_zero when secp256k1_*_set_b32 fails. (Gregory Maxwell)

Pull request description:

  Most of the codebase correctly used short-cutting to avoid calling
   _is_zero on possibly incompletely initialized elements, but a few
   places were missed.

ACKs for commit cd473e:
  sipa:
    utACK cd473e02c3
  jonasnick:
    utACK cd473e02c3

Tree-SHA512: d6af2863f6795d2df26f2bd05a4e33085e88c45f7794601ea57e67238a2073ef1ee3ba0feab62a7fcbc0636c48dfd80eea07d0ca4f194414127f914b0478c732
2019-05-29 21:47:45 +00:00
Gregory Maxwell
f34b0c3f35 Merge #630: Note intention of timing sidechannel freeness.
8d1563b Note intention of timing sidechannel freeness. (Gregory Maxwell)

Pull request description:

  Resolves #238

ACKs for commit 8d1563:

Tree-SHA512: 2b0ca945d70e5975291ed9a0884eddfd771fd06dfed37c9711f8b57d431c28b974e5a5d86ae6e70e5e37c5f208bcb74e9ab18fcf9d7b78849fcf3cff9ba7623b
2019-05-29 20:30:35 +00:00
Gregory Maxwell
8d1563b0ff Note intention of timing sidechannel freeness.
Resolves #238
2019-05-29 18:43:13 +00:00
Gregory Maxwell
1669bb2865 Merge #628: Fix ability to compile tests without -DVERIFY.
dcf3920 Fix ability to compile tests without -DVERIFY. (Gregory Maxwell)

Pull request description:

  Broken by 3f3964e4.

  It's important that the tests are also run without -DVERIFY due to
   the possibility that side-effects of a VERIFY_CHECK fix a bug that
   would otherwise be detected.

  Use of the verify_check macro in tests isn't sufficient.

ACKs for commit dcf392:

Tree-SHA512: ff7ca0e89e33f845656a4d7d18c0195d1378b020d67f89e900b18cf3d702aa81dd91ffd05a98953a481b83e4247eaf0c484bea12eab020efb3c966a456e8129f
2019-05-29 14:24:42 +00:00
Gregory Maxwell
ecc94abcc8 Merge #627: Guard memcmp in tests against mixed size inputs.
248bffb Guard memcmp in tests against mixed size inputs. (Gregory Maxwell)

Pull request description:

  Reported by real-or-random.

  Fixes #623.

ACKs for commit 248bff:
  practicalswift:
    utACK 248bffb052

Tree-SHA512: 29867c79d2d6852f495334a5a9129c7feac2df639dd7f752067380689b0ce9f9b35e94524834c01e698df5c0b83dc9855204ec09f5dfe488a388b509c9b861d9
2019-05-29 14:23:58 +00:00
Gregory Maxwell
544435fc90 Merge #578: Avoid implementation-defined and undefined behavior when dealing with sizes
14c7dbd Simplify control flow in DER parsing (Tim Ruffing)
ec8f20b Avoid out-of-bound pointers and integer overflows in size comparisons (Tim Ruffing)
01ee1b3 Parse DER-enconded length into a size_t instead of an int (Tim Ruffing)
3cb057f Fix possible integer overflow in DER parsing (Tim Ruffing)

Pull request description:

  This is a result of auditing the code for overflow issues at random places. None of this is critical but I think all of it should be fixed.

  I know this touches "red" code. I double-checked and triple-checked this but I can understand if some of the changes are not desirable because they change well-tested code.

  Best reviewed in individual commits.

ACKs for commit 14c7db:

Tree-SHA512: 312dd3f961739752e1a861e75bd755920f634f87ee9668793e102c224434e8d21367452e114de729322c71a89f4fa82126aa5d32742f2bbbc091777c99515e10
2019-05-29 11:06:19 +00:00
Gregory Maxwell
143dc6e9ee Merge #595: Allow to use external default callbacks
e49f799 Add missing #(un)defines to base-config.h (Tim Ruffing)
77defd2 Add secp256k1_ prefix to default callback functions (Tim Ruffing)
908bdce Include stdio.h and stdlib.h explicitly in secp256k1.c (Tim Ruffing)
5db782e Allow usage of external default callbacks (Tim Ruffing)
6095a86 Replace CHECKs for no_precomp ctx by ARG_CHECKs without a return (Tim Ruffing)

Pull request description:

  This is intended for environments without implementations for `abort()`, `fprintf()`, and `stderr`. e.g., embedded systems. Those can provide their own implementations of `default_illegal_callback_fn` and `default_error_callback_fn` at compile time.

  If you want to use your own default callback, things will be somewhat inconsistent unfortunately: We cannot make the callback data `extern` too, because then the initialization lists for `default_illegal_callback` won't contain only constants. (`const` variables are not compile-time constants). So you cannot take callback data in your own default callback function.

  As a more drastic/breaking alternative I suggest to remove the callback data entirely. I don't think it's a big loss and I would be surprised if anyone uses it. Additionally, we could even remove the possibility to set the callback function at runtime after this PR. This will simplify things a lot, and again I don't think it's a big loss.

  Note that `abort()`, `fprintf()`, and `stderr` are also used in `CHECK`, which is still used in production code if we rely on gmp for scalar and field inversions (e.g.,  https://github.com/bitcoin-core/secp256k1/blob/master/src/scalar_impl.h#L240). This is not an issue for embedded system which probably don't want to use gmp anyway, but it is probably an issue for the reasons explained in https://github.com/bitcoin-core/secp256k1/pull/566#issuecomment-469111901.

  (related downstream: https://github.com/rust-bitcoin/rust-secp256k1/pull/100 @elichai)

ACKs for commit e49f79:

Tree-SHA512: 4dec0821eef4156cbe162bd8cdf0531c1fae8c98cd9db8438170ff1aa0e59b199739eeab293695bb582246812bea5309959f02f1fb74bb57872da54ebc52313f
2019-05-27 07:43:07 +00:00
Tim Ruffing
e49f7991c2 Add missing #(un)defines to base-config.h 2019-05-26 22:32:36 +02:00
Tim Ruffing
77defd2c3b Add secp256k1_ prefix to default callback functions 2019-05-26 22:32:36 +02:00
Tim Ruffing
908bdce64e Include stdio.h and stdlib.h explicitly in secp256k1.c 2019-05-26 22:32:36 +02:00
Tim Ruffing
5db782e655 Allow usage of external default callbacks 2019-05-26 22:32:36 +02:00
Tim Ruffing
6095a863fa Replace CHECKs for no_precomp ctx by ARG_CHECKs without a return 2019-05-26 22:31:36 +02:00
Gregory Maxwell
cd473e02c3 Avoid calling secp256k1_*_is_zero when secp256k1_*_set_b32 fails.
Most of the codebase correctly used short-cutting to avoid calling
 _is_zero on possibly incompletely initialized elements, but a few
 places were missed.
2019-05-26 10:28:49 +00:00
Gregory Maxwell
6c36de7a33 Merge #600: scratch space: use single allocation
98836b1 scratch: replace frames with "checkpoint" system (Andrew Poelstra)
7623cf2 scratch: save a couple bytes of unnecessarily-allocated memory (Andrew Poelstra)
a7a164f scratch: rename `max_size` to `size`, document that extra will actually be allocated (Andrew Poelstra)
5a4bc0b scratch: unify allocations (Andrew Poelstra)
c2b028a scratch space: thread `error_callback` into all scratch space functions (Andrew Poelstra)
0be1a4a scratch: add magic bytes to beginning of structure (Andrew Poelstra)
92a48a7 scratch space: use single allocation (Andrew Poelstra)

Pull request description:

ACKs for commit 98836b:

Tree-SHA512: 6e251f704644a5f61b24aa05c6f7a31ad8c58d147195079d52fe45daacd28a9fd2f4aaf71273183b99b3795a01a88f8389170d4280489b2a28a14a56e03153d7
2019-05-26 10:08:58 +00:00
Andrew Poelstra
98836b11f0 scratch: replace frames with "checkpoint" system 2019-05-26 01:05:09 +00:00
Andrew Poelstra
7623cf2b97 scratch: save a couple bytes of unnecessarily-allocated memory 2019-05-25 23:01:08 +00:00
Andrew Poelstra
a7a164f2c6 scratch: rename max_size to size, document that extra will actually be allocated 2019-05-25 23:01:07 +00:00
Andrew Poelstra
5a4bc0bb95 scratch: unify allocations 2019-05-25 22:59:51 +00:00
Andrew Poelstra
c2b028a281 scratch space: thread error_callback into all scratch space functions
Use it when checking magic bytes
2019-05-25 22:59:50 +00:00
Andrew Poelstra
0be1a4ae62 scratch: add magic bytes to beginning of structure 2019-05-25 22:55:39 +00:00
Andrew Poelstra
92a48a764d scratch space: use single allocation 2019-05-25 22:53:50 +00:00
Gregory Maxwell
40839e21b9 Merge #592: Use trivial algorithm in ecmult_multi if scratch space is small
9ab96f7 Use trivial algorithm in ecmult_multi if scratch space is small (Jonas Nick)

Pull request description:

  `ecmult_multi` already selects the trivial algorithm if the scratch space is NULL. With this PR the trivial algorithm is also selected if the scratch space is too small to use pippenger or strauss instead of returning 0. That makes it more easier to avoid consensus relevant inconsistencies just because scratch space construction was messed up.

ACKs for commit 9ab96f:
  real-or-random:
    utACK 9ab96f7

Tree-SHA512: aa451adf8880af15cf167a59cb07fc411edc43f26c8eb0873bdae2774382ba182e2a1c54487912f8f2999cb0402d554b9d293e2fb9483234471348a1f43c6653
2019-05-25 22:41:35 +00:00
Gregory Maxwell
dcf392027b Fix ability to compile tests without -DVERIFY.
Broken by 3f3964e4.

It's important that the tests are also run without -DVERIFY due to
 the possibility that side-effects of a VERIFY_CHECK fix a bug that
 would otherwise be detected.

Use of the verify_check macro in tests isn't sufficient.
2019-05-25 21:49:45 +00:00
Gregory Maxwell
a484e0008b Merge #566: Enable context creation in preallocated memory
0522caa Explain caller's obligations for preallocated memory (Tim Ruffing)
238305f Move _preallocated functions to separate header (Tim Ruffing)
695feb6 Export _preallocated functions (Tim Ruffing)
814cc78 Add tests for contexts in preallocated memory (Tim Ruffing)
ba12dd0 Check arguments of _preallocated functions (Tim Ruffing)
5feadde Support cloning a context into preallocated memory (Tim Ruffing)
c4fd5da Switch to a single malloc call (Tim Ruffing)
ef020de Add size constants for preallocated memory (Tim Ruffing)
1bf7c05 Prepare for manual memory management in preallocated memory (Tim Ruffing)

Pull request description:

  @apoelstra

  This builds on #557.

  Manually managing memory is always a pain in the ass in some way. I tried to keep the pain manageable. I'm open to suggestions to make this less ugly or error-prone.

  to do:
   * tests
   * export functions

ACKs for commit 0522ca:

Tree-SHA512: 8ddb5b70219b6f095e780a9812d2387ab2a7f399803ce4101e27da504b479a61ebe08b6380568c7ba6f1e73d7d0b1f58a3c0a66fa0fdec7a64cd0740e156ce38
2019-05-25 21:44:37 +00:00
Tim Ruffing
0522caac8f Explain caller's obligations for preallocated memory 2019-05-25 14:01:09 +02:00
Tim Ruffing
238305fdbb Move _preallocated functions to separate header 2019-05-25 14:01:09 +02:00
Tim Ruffing
695feb6fbd Export _preallocated functions 2019-05-25 14:01:09 +02:00
Tim Ruffing
814cc78d71 Add tests for contexts in preallocated memory 2019-05-25 14:01:09 +02:00
Tim Ruffing
ba12dd08da Check arguments of _preallocated functions 2019-05-25 14:01:09 +02:00
Tim Ruffing
5feadde462 Support cloning a context into preallocated memory 2019-05-25 14:01:09 +02:00
Tim Ruffing
c4fd5dab45 Switch to a single malloc call 2019-05-25 14:01:09 +02:00
Tim Ruffing
ef020de16f Add size constants for preallocated memory 2019-05-25 13:58:09 +02:00
Tim Ruffing
1bf7c056ba Prepare for manual memory management in preallocated memory
* Determine ALIGNMENT more cleverly and move it to util.h
 * Implement manual_malloc() helper function
2019-05-25 13:58:09 +02:00
Gregory Maxwell
248bffb052 Guard memcmp in tests against mixed size inputs.
Reported by real-or-random.

Fixes #623.
2019-05-25 11:54:08 +00:00
Gregory Maxwell
36698dcfee Merge #596: Make WINDOW_G configurable
a61a93f Clean up ./configure help strings (Tim Ruffing)
2842dc5 Make WINDOW_G configurable (Tim Ruffing)

Pull request description:

  This makes WINDOW_G a configurable value in the range of [2..24].
  The upper limit of 24 is a defensive choice. The code is probably
  correct for values up to 33 but those larger values yield in huge
  tables (>= 256MiB), which are i) unlikely to be really beneficial
  in practice and ii) increasingly difficult to test.

  The main point of this is not to make the window size configurable (using ./configure) but rather to use an external #define for the window size, which makes it configurable for embedded system that rely on their own build system (like in #595).

ACKs for commit a61a93:

Tree-SHA512: 0d58fdf4763340ddab992e95f6302a33d891476a7ac1748202ee99808e72b20754bb6935cbeaf0bb36077abaaff7d65f4848b1af64f1a0a5258239ba0d27020c
2019-05-25 10:57:27 +00:00
Tim Ruffing
a61a93ff50 Clean up ./configure help strings 2019-05-24 21:02:31 +02:00
Tim Ruffing
2842dc523e Make WINDOW_G configurable
This makes WINDOW_G a configurable value in the range of [2..24].
The upper limit of 24 is a defensive choice. The code is probably
correct for values up to 27 but those larger values yield in huge
tables (>= 256MiB), which are i) unlikely to be really beneficial
in practice and ii) increasingly difficult to test.
2019-05-24 21:02:31 +02:00
Gregory Maxwell
1a02d6ce51 Merge #626: Revert "Merge #620: Install headers automatically"
662918c Revert "Merge #620: Install headers automatically" (ian)

Pull request description:

  This reverts commit 91fae3ace0, reversing
  changes made to 5df77a0eda.

  See discussion in https://github.com/bitcoin-core/secp256k1/pull/625

  After the change, if we enable any module, `make install` fails because of the
  duplicated files in the command line arguments.

  Closes https://github.com/bitcoin-core/secp256k1/issues/624

Tree-SHA512: 7769ede527ac307bff094603e5974c56b19e41bc2ef55113173d3dbc8e545d6add7ae044753fa0361595e5e7a746d6c8d641f98caa3381b683aa2b61a1742097
2019-05-24 01:01:04 +00:00
ian
662918cb29 Revert "Merge #620: Install headers automatically"
This reverts commit 91fae3ace0, reversing
changes made to 5df77a0eda.

See discussion in https://github.com/bitcoin-core/secp256k1/pull/625

After the change, if we enable any module, `make install` fails because of the
duplicated files in the command line arguments.
2019-05-24 08:35:26 +08:00
Tim Ruffing
14c7dbd444 Simplify control flow in DER parsing 2019-05-23 15:22:29 +02:00
Tim Ruffing
ec8f20babd Avoid out-of-bound pointers and integer overflows in size comparisons
This changes pointer calculations in size comparions to a form that
ensures that no out-of-bound pointers are computed, because even their
computation yields undefined behavior.
Also, this changes size comparions to a form that ensures that neither
the left-hand side nor the right-hand side can overflow.
2019-05-23 15:22:29 +02:00
Tim Ruffing
01ee1b3b3c Parse DER-enconded length into a size_t instead of an int
This avoids a possibly implementation-defined signed (int) to unsigned
(size_t) conversion portably.
2019-05-23 15:22:29 +02:00
Gregory Maxwell
912680ed86 Merge #561: Respect LDFLAGS and #undef STATIC_PRECOMPUTATION if using basic config
dbed75d Undefine `STATIC_PRECOMPUTATION` if using the basic config (DesWurstes)
310111e Keep LDFLAGS if `--coverage` (DesWurstes)

Pull request description:

  Update: **This is a trimmed pull request with strong rationale.**

  - Adding `--coverage` shouldn't reset `LDFLAGS`, this is definitely a typo
  - The basic configuration should undefine `STATIC_PRECOMPUTATION`, as generating it is not supported and it complicates #549

Tree-SHA512: 29f0dd4c870ec60d535346446b453da459ca843ed1265c2bc966bf0fcbdf3c5c79f9e48a419662e81d790a7003f8877a16e2a5a74aa5c0b79645e15ad56a0f66
2019-05-23 00:38:30 +00:00
Gregory Maxwell
91fae3ace0 Merge #620: Install headers automatically
16e8615 Install headers automatically (Víctor Mayoral Vilches)

Pull request description:

  This fix install all the headers under include/ into
  /usr/local/include. The fix solves problems that arise
  when building libraries that depend on secp256k1 such
  as libbitcoin-system which require all the headers

Tree-SHA512: 8a5dc664b278e47340bf7478ad278306c44c4c8ad17a023b198c6a927c67c7a7a50100357388342129078afdf7606d2ed06579ce1fc14195fa974510b933021b
2019-05-23 00:01:01 +00:00
Gregory Maxwell
5df77a0eda Merge #533: Make sure we're not using an uninitialized variable in secp256k1_wnaf_const(...)
248f046 Make sure we're not using an uninitialized variable in secp256k1_wnaf_const(...) (practicalswift)

Pull request description:

  Make sure we're not using an uninitialized variable in `secp256k1_wnaf_const(...)`:

  ```
  In file included from src/secp256k1.c:15:0,
                   from src/tests.c:17:
  src/ecmult_const_impl.h: In function ‘secp256k1_wnaf_const’:
  src/ecmult_const_impl.h:117:20: warning: ‘u’ may be used uninitialized in this function [-Wmaybe-uninitialized]
       wnaf[word] = u * global_sign;
                      ^
  ```

  **Note to reviewers:** Perhaps an `assert(…);` is a bit drastic. What would be a more graceful way to handle this? :-)

Tree-SHA512: 536cd7cc5b87a84fbaac578cecbba81b8d82e4672a30a2db9a674b82856132e79b0158a6a88609bc24942ebdbf1fcd2c4399a4c31ab0654b88ace9c0e6f1eaf3
2019-05-22 04:44:29 +00:00
Gregory Maxwell
975e51e0d9 Merge #617: Pass scalar by reference in secp256k1_wnaf_const()
8979ec0 Pass scalar by reference in secp256k1_wnaf_const() (Tim Ruffing)

Pull request description:

  After this change, no struct or union is passed by value in the
  entire codebase. This makes it easier to compile the library with
  CompCert.

Tree-SHA512: 6b23e2b39701c3eeb6ae8c8d660cabe8872ac8f13141504c1ec55c47f2009e206129b34b31796e618114b60350598187df6df4c2be0e5c1b138a6126ad6a7484
2019-05-22 04:40:08 +00:00
Gregory Maxwell
735fbde04e Merge #619: Clear a copied secret key after negation
069870d Clear a copied secret key after negation (Seonpyo Kim)

Pull request description:

  It closes #618

Tree-SHA512: 05299597c886c5d1a913fd0ce8c698d2e513eb80fbd33d571a02fc6910cfd337324c6f0f27175eaf125eb3478d38187763680e859ece9a469a034c9b8a8d6920
2019-05-16 08:38:30 +00:00
Víctor Mayoral Vilches
16e86150d0 Install headers automatically
This fix install all the headers under include/ into
/usr/local/include. The fix solves problems that arise
when building libraries that depend on secp256k1 such
as bitcoin-system which require all the headers
2019-05-15 09:54:35 +02:00
Seonpyo Kim
069870d92a Clear a copied secret key after negation 2019-05-15 15:55:01 +09:00
Tim Ruffing
8979ec0d9a Pass scalar by reference in secp256k1_wnaf_const()
After this change, no struct or union is passed by value in the
entire codebase. This makes it easier to compile the library with
CompCert.
2019-05-14 11:43:54 +02:00
Gregory Maxwell
84a808598b Merge #612: Allow field_10x26_arm.s to compile for ARMv7 architecture
d4d270a Allow field_10x26_arm.s to compile for ARMv7 architecture (Roman Zeyde)

Pull request description:

  It would allow using optimized field operations on the TREZOR device, which is using ARMv7 Cortex-M4.
  Following https://github.com/trezor/trezor-core/pull/500 and part of https://github.com/trezor/trezor-firmware/issues/66.

Tree-SHA512: 73c0f03503feff01c6f4efd884e916ae1f43f55d525e8c3ea9372cf777aef6901585b74774c316dd7937abfff5e86be5b1acb569f9eeee9b73ae088f0f6b589d
2019-05-09 22:23:49 +00:00
Roman Zeyde
d4d270a59c Allow field_10x26_arm.s to compile for ARMv7 architecture 2019-05-07 22:37:35 +03:00
Gregory Maxwell
b19c000063 Merge #607: Use size_t shifts when computing a size_t
e6d01e9 Use size_t shifts when computing a size_t (Pieter Wuille)

Pull request description:

  This was detected by compiling with MSVC; it triggers warning C4334.

  I don't think this is necessary, as we know the maximum shift is a very small integer, but this makes the code more obviously correct.

Tree-SHA512: 3c0cf412c75b4361d01e78bf13fe81c3f28b82abd40b0706285cc691124381cb1ff1f1c3512420250180b7612a471ce48357b282b1e34a08f5359e58af25e198
2019-03-31 09:37:33 +00:00
Gregory Maxwell
4d01bc2d9c Merge #606: travis: Remove unused sudo:false
7667532 travis: Remove unused sudo:false (MarcoFalke)

Pull request description:

  Builds in sudo-disabled docker containers are no longer available as of last year and all builds happen on sudo enabled vms.

  Source: https://blog.travis-ci.com/2018-11-19-required-linux-infrastructure-migration#timeline---its-happening-fast

Tree-SHA512: 882585ba4e1596ad34ddf163acecd043da63443fa95653fba63b03dacf3a669128f1ed142527484cc8dab98de341b425425f418b8151cf7303b0e906ae259a9a
2019-03-31 00:41:54 +00:00
Pieter Wuille
e6d01e9347 Use size_t shifts when computing a size_t 2019-03-30 16:09:17 -07:00
MarcoFalke
7667532bd7 travis: Remove unused sudo:false 2019-03-30 12:35:32 -04:00
practicalswift
248f046611 Make sure we're not using an uninitialized variable in secp256k1_wnaf_const(...) 2019-03-21 19:06:08 +01:00
Jonas Nick
9ab96f7b12 Use trivial algorithm in ecmult_multi if scratch space is small 2019-03-18 15:15:35 +00:00
Gregory Maxwell
ee99f12f3d Merge #599: Switch x86_64 asm to use "i" instead of "n" for immediate values.
d58bc93 Switch x86_64 asm to use "i" instead of "n" for immediate values. (Gregory Maxwell)

Pull request description:

  The constraint "n" is a more obscure setting which is needed for
   special cases that don't apply to our use.

  Use of "n" exposed some bugs in pre-release versions of clang.
  This fixes #594

Tree-SHA512: 1ffba02aa6bfcd0b6f731196e5d007f4ddb0f03f53b30a2633f0e376578cf7f828570579502f2de721dcda8034fd8e7bea822542bf36032d98ef802b4cf27725
2019-03-11 18:31:03 +00:00
Gregory Maxwell
d58bc93f2c Switch x86_64 asm to use "i" instead of "n" for immediate values.
The constraint "n" is a more obscure setting which is needed for
 special cases that don't apply to our use.

Use of "n" exposed some bugs in pre-release versions of clang.
This fixes #594
2019-03-10 22:52:12 +00:00
Gregory Maxwell
05362ee042 Merge #597: Add $(COMMON_LIB) to exhaustive tests to fix ARM asm build
8348386 Add $(COMMON_LIB) to exhaustive tests to fix ARM asm build (Gregory Maxwell)

Pull request description:

Tree-SHA512: ef091b86189a2235710866689024f2b190ebcc5741667be0921e6b4a50d53ddf9a63f4c90b1509f25e46631d75338913143a2a1335a74c842f84b98739a9d306
2019-03-10 22:44:45 +00:00
Gregory Maxwell
83483869ac Add $(COMMON_LIB) to exhaustive tests to fix ARM asm build 2019-03-09 06:17:27 +00:00
Gregory Maxwell
aa15154a48 Merge #568: Fix integer overflow in ecmult_multi_var when n is large
2277af5 Fix integer overflow in ecmult_multi_var when n is large (Jonas Nick)

Pull request description:

  Without this PR ecmult_multi could return wrong results. If the number of points `n` is large enough then some or all multiplications could be skipped or the function could end up in an infinite loop. This PR adds two checks to prevent `n` from wrapping around.

Tree-SHA512: 342944369b24776fa3ec0694eee159259ff67e94d2d8176c1d3159875f387d943d5bfdff7cde59f058e13f07fd09bde1cbc609426e63c8a5b8040e382dd865d8
2019-02-25 21:09:17 +00:00
Jonas Nick
2277af5ff0 Fix integer overflow in ecmult_multi_var when n is large 2019-02-25 16:13:17 +00:00
DesWurstes
dbed75d969 Undefine STATIC_PRECOMPUTATION if using the basic config 2019-02-25 11:36:39 +03:00
DesWurstes
310111e093 Keep LDFLAGS if --coverage 2019-02-25 11:34:52 +03:00
Gregory Maxwell
85d0e1bcce Merge #591: Make bench_internal obey secp256k1_fe_sqrt's contract wrt aliasing.
b76e45d Make bench_internal obey secp256k1_fe_sqrt's contract wrt aliasing. (Gregory Maxwell)

Pull request description:

  Bench_internal was previously incorrect but wasn't detected by -DVERIFY until PR #551.

Tree-SHA512: 5ecb9e3ba63ddf28cde4012154dbb1dda9b7178016d970dba58a4af20c31aa1ec3458ba2623541233fb16fceff7b3053054d6eee0229d0bfb6281d1a10554e9f
2019-02-24 19:20:54 +00:00
Gregory Maxwell
14196379ec Merge #580: Add trivial ecmult_multi algorithm which does not require a scratch space
a697d82 Add trivial ecmult_multi to the benchmark tool (Jonas Nick)
bade617 Add trivial ecmult_multi algorithm. It is selected when no scratch space is given and just multiplies and adds the points. (Jonas Nick)

Pull request description:

  This commit adds a new ecmult_multi algorithm that is automatically selected when `ecmult_multi_var` is called with scratch space set to `NULL`. This is a trivial algorithm that simply multiplies the points with the corresponding scalars and adds them up.

  The use case is to allow creating exposed function that uses `ecmult_multi` but without requiring a scratch space argument. For example, in MuSig when computing the combined public key we need to compute a weighted sum of points but we most likely don't care about the performance. And if we do we can still provide a scratch space. Having the option of not providing a scratch space is useful because creating a scratch space is not entirely trivial. One needs to decide on a size and it needs to be destroyed.

Tree-SHA512: 2de20feeff00902ca0936ec1f8d81cf7a95d0917f80e76e9eacbd739c8c2e248fbdaeb468a0aeaf715ec251c2c79b5e271ff4d77456218d02332e26e003d796e
2019-02-24 03:06:54 +00:00
Jonas Nick
a697d82da9 Add trivial ecmult_multi to the benchmark tool 2019-02-23 20:30:31 +00:00
Jonas Nick
bade617417 Add trivial ecmult_multi algorithm. It is selected when no scratch space is given and just multiplies and adds the points. 2019-02-23 20:24:28 +00:00
Gregory Maxwell
5545e13dea Merge #584: configure: Use CFLAGS_FOR_BUILD when checking native compiler
a34bcaa Actually pass CFLAGS_FOR_BUILD and LDFLAGS_FOR_BUILD to linker (Tim Ruffing)
2d5f4ce configure: Use CFLAGS_FOR_BUILD when checking native compiler (Tim Ruffing)

Pull request description:

  This fixes a bug where configure would fail or disable static
  ecmult tables because it wrongly checks the native compiler using
  the target CFLAGS (instead of the native CFLAGS_FOR_BUILD).

  Moreover, this commit adds tests to figure out whether the native
  compiler supports the warning flags passed during the build, and it
  contains a few minor improvements to the code that checks the native
  compiler.

Tree-SHA512: 31a92a5516cf2f9801c918edfba0059aa4f8549b0c1de94fc166b5e92ad1868a480c48cdc5ff62679ba20e26f4a0e2948c71fd2b3e80766673d2bf7512da3875
2019-02-22 01:29:02 +00:00
Gregory Maxwell
20c5869df2 Merge #516: improvements to random seed in src/tests.c
be40c4d Fixup for C90 mixed declarations. (Gregory Maxwell)
8b3841c fix bug in fread() failure check (Don Viszneki)
cddef0c tests: add warning message when /dev/urandom fails (Don Viszneki)

Pull request description:

  I've made two small changes to `src/tests.c` circa random seed generation.

  Added a warning when `/dev/urandom` fails, mostly to defend against the case that someone should use the code verbatim, but also to enhance its illustrative power.

  Also I fixed a bug with how the return value of `fread()` was being evaluated. In fact, `/dev/urandom` was never being applied before as the check on the return value of `fread()` always failed!

Tree-SHA512: 239dbe8316220c2f0e5b370bf9a18f78196e96cc4a7edea58cf2521b2c9cbc8da065be96aa859f90324d57e388d30f7670ce6bc1cca52e5162e5ca66b1a55b34
2019-02-21 11:46:13 +00:00
Gregory Maxwell
b76e45d5d6 Make bench_internal obey secp256k1_fe_sqrt's contract wrt aliasing.
Bench_internal was previously incorrect but wasn't detected by
 -DVERIFY until PR #551.
2019-02-21 05:58:33 +00:00
Gregory Maxwell
870a977644 Merge #562: Make use of TAG_PUBKEY constants in secp256k1_eckey_pubkey_parse
d3cb1f9 Make use of TAG_PUBKEY constants in secp256k1_eckey_pubkey_parse (Ben Woosley)

Pull request description:

  This results in more self-documenting code.

  Constants defined here:
  1e6f1f5ad5/include/secp256k1.h (L175-L180)

Tree-SHA512: 2026103c487a5ebdea9a2f5ec2be96d74e38d5b2269b4df11e354bb54aba2925b47c3185f530205019840b00fc3501121acfa5234faf1d095d71777826414f69
2019-02-21 05:35:10 +00:00
Gregory Maxwell
be40c4d0b5 Fixup for C90 mixed declarations.
Reported-by: Jonas Nick <jonasd.nick@gmail.com>
2019-02-21 05:00:29 +00:00
Gregory Maxwell
c71dd2c08f Merge #509: Fix algorithm selection in bench_ecmult
0f05173 Fix algorithm selection in bench_ecmult (Jonas Nick)

Pull request description:

  Without this commit using an unknown argument results in a segmentation fault.

Tree-SHA512: 85b8f977e62fa360ff6dc923bd86f08725c30e178d58f43d33cbd8eb69e54fa4ec76e4407624611a80554cf9961689bce6b216da735ac95b256d0d2f60fe3328
2019-02-21 04:47:12 +00:00
Gregory Maxwell
6492bf88cc Merge #518: Summarize build options after running configure
3965027 Summarize build options in configure script (Evan Klitzke)

Pull request description:

  This is a trivial build system change to summarize the build options after running configure.

  Example output:
  ```
  $ ./configure
  ....
  <many lines omitted>
  ...
  config.status: src/libsecp256k1-config.h is unchanged
  config.status: executing depfiles commands
  config.status: executing libtool commands

  Build Options:
    with endomorphism   = no
    with ecmult precomp = yes
    with jni            = no
    module ecdh         = no
    module recovery     = no

    asm                 = x86_64
    bignum              = gmp
    field               = 64bit
    scalar              = 64bit

    CC                  = gcc
    CFLAGS              = -g -O2 -W -std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings -fvisibility=hidden -O3
    CPPFLAGS            =
    LDFLAGS             =
  ```

  I tried to just include the configure options that looked interesting; let me know if there are any I didn't include that I should have.

Tree-SHA512: 428381654d772f76bc81210d39ba5c3f07a94dc6a6378a02ccc6f23ebce7f501896268bcd2e94e2b0d8aea54c9c70c44a9238a0f0960600f463b1e2847c7ed1f
2019-02-21 04:44:01 +00:00
Gregory Maxwell
0e9ada1941 Merge #567: Correct order of libs returned on pkg-config --libs --static libsecp2…
89a20a8 Correct order of libs returned on pkg-config --libs --static libsecp256k1 call. (Phillip Mienk)

Pull request description:

  …56k1 call.

Tree-SHA512: 095f5e71837e63a2bb6e9cf04cabe7f1ec55cf0fc32b44c80a89c232efb7d74bf0f148a8cd29f9fa2999f02bbc638d9a086ffd50888aab6f9fd5db74e37ae4d4
2019-02-21 04:36:40 +00:00
Gregory Maxwell
e96901a4b9 Merge #587: Make randomization of a non-signing context a noop
6198375 Make randomization of a non-signing context a noop (Tim Ruffing)

Pull request description:

  Before this commit secp256k1_context_randomize called illegal_callback
  when called on a context not initialized for signing. This is not
  documented. Moreover, it is not desirable because non-signing contexts
  may use randomization in the future.

  This commit makes secp256k1_context_randomize a noop in this case. This
  is safe because the context cannot be used for signing anyway.

  This fixes #573 and it fixes rust-bitcoin/rust-secp256k1#82.

Tree-SHA512: 34ddfeb004d9da8f4a77c739fa2110544c28939378e779226da52f410a0e36b3aacb3ebd2e3f3918832a9027684c161789cfdc27a133f2f0e0f1c47e8363029c
2019-02-21 04:33:59 +00:00
Gregory Maxwell
58df8d03ad Merge #511: Portability fix for the configure scripts generated
270f6c8 Portability fix for the configure scripts generated (Pierre Pronchery)

Pull request description:

  Found thanks to the developer checks from the pkgsrc software
  distribution (for NetBSD, SmartOS, Minix, MacOS X, Linux, and more).

Tree-SHA512: 2589545aa4d0620db66e79df1dc148a487384b5169ba7323937490d802973388859d30d45b35ee3e614be6d49cb694f37f585a16caa87ad1e500a0b7368dcc0a
2019-02-21 04:28:20 +00:00
Gregory Maxwell
2ebdad772a Merge #552: Make constants static:
496c5b4 Make constants static: static const secp256k1_ge secp256k1_ge_const_g; static const int CURVE_B; (Russell O'Connor)

Pull request description:

  static const secp256k1_ge secp256k1_ge_const_g;
  static const int CURVE_B;

Tree-SHA512: df8d34777d3b1b90eef875d50c2870e2480f08685b399a22eaf584ce294766e0de3a41523757a23e311e633886c89400313421282beca791326a06695f348940
2019-02-21 04:26:40 +00:00
Gregory Maxwell
1c131affd3 Merge #551: secp256k1_fe_sqrt: Verify that the arguments don't alias.
bf8b86c secp256k1_fe_sqrt: Verify that the arguments don't alias. (Russell O'Connor)

Pull request description:

Tree-SHA512: 4e9128625817be83a1259e7dbdb82c4be8ee0174af7d5e76eeac3245d23d6bf01378d9697dcb870eb61577afd7c0556cb3c6633e3b27504add14c10b18f7c607
2019-02-21 04:23:50 +00:00
Gregory Maxwell
ba698f883b Merge #539: Assorted minor corrections
52ab96f clean dependendies in field_*_impl.h (Russell O'Connor)
deff5ed Correct math typos in field_*.h (Russell O'Connor)
4efb3f8 Add check that restrict pointers don't alias with all parameters. (Russell O'Connor)

Pull request description:

  * add more checks for restrict pointers.
  * correct math typos.
  * refine dependencies on "num.h"

Tree-SHA512: c368f577927db2ace3e7f46850cb2fdf9d7d169b698a9697767e1f82e9e7091f2b2fea0f7cf173048eb4c1bb56824c884fa849c04c595ee97766c01f346a54ec
2019-02-21 04:20:35 +00:00
Gregory Maxwell
949e85b009 Merge #550: Optimize secp256k1_fe_normalize_weak calls.
9bd89c8 Optimize secp256k1_fe_normalize_weak calls. Move secp256k1_fe_normalize_weak calls out of ECMULT_TABLE_GET_GE and ECMULT_TABLE_GET_GE_STORAGE and into secp256k1_ge_globalz_set_table_gej instead. (Russell O'Connor)

Pull request description:

  Move secp256k1_fe_normalize_weak calls out of ECMULT_TABLE_GET_GE and ECMULT_TABLE_GET_GE_STORAGE and into secp256k1_ge_globalz_set_table_gej instead.

Tree-SHA512: 7bbb1aca8e37a268a26d7061bd1f390db129e697792f1d5ddd10ea34927616edc26ef118b500c3e5e14d1d463196033ef64e4d34b765380325c24835458b7a9b
2019-02-21 04:14:40 +00:00
Tim Ruffing
a34bcaadf1 Actually pass CFLAGS_FOR_BUILD and LDFLAGS_FOR_BUILD to linker 2019-02-10 11:58:52 +01:00
Tim Ruffing
2d5f4cebdc configure: Use CFLAGS_FOR_BUILD when checking native compiler
This fixes a bug where configure would fail or disable static
ecmult tables because it wrongly checks the native compiler using
the target CFLAGS (instead of the native CFLAGS_FOR_BUILD), and
similar for CPPFLAGS and LDFLAGS.

Moreover, this commit adds tests to figure out whether the native
compiler supports the warning flags passed during the build, and it
contains a few minor improvements to the code that checks the native
compiler.
2019-02-10 11:56:36 +01:00
Pieter Wuille
b408c6a8b2 Merge #579: Use __GNUC_PREREQ for detecting __builtin_expect
c663397 Use __GNUC_PREREQ for detecting __builtin_expect (Tim Ruffing)

Pull request description:

Tree-SHA512: 659a721da835eb15966a2a5386d6ae4c3defbb6ad473905f14161a3cf36d1556d44d887602019c89ebeffdfd82ed469ff27914dc2aaee6648d1e0c8a22151c27
2019-02-04 14:33:03 -08:00
Tim Ruffing
6198375218 Make randomization of a non-signing context a noop
Before this commit secp256k1_context_randomize called illegal_callback
when called on a context not initialized for signing. This is not
documented. Moreover, it is not desirable because non-signing contexts
may use randomization in the future.

This commit makes secp256k1_context_randomize a noop in this case. This
is safe because the context cannot be used for signing anyway.

This fixes #573 and it fixes rust-bitcoin/rust-secp256k1#82.
2019-01-27 13:33:52 +01:00
Tim Ruffing
c663397f46 Use __GNUC_PREREQ for detecting __builtin_expect 2018-12-17 11:47:25 +01:00
Tim Ruffing
3cb057f842 Fix possible integer overflow in DER parsing
If we’re in the last loop iteration, then `lenleft == 1` and it could
be the case that `ret == MAX_SIZE`, and so `ret +  lenleft` will
overflow to 0 and the sanity check will not catch it. Then we will
return `(int) MAX_SIZE`, which should be avoided because this value is
implementation-defined. (However, this is harmless because
`(int) MAX_SIZE == -1` on all supported platforms.)
2018-12-14 11:43:47 +01:00
Phillip Mienk
89a20a8945 Correct order of libs returned on pkg-config --libs --static libsecp256k1 call. 2018-10-22 17:24:45 -07:00
Ben Woosley
d3cb1f95eb Make use of TAG_PUBKEY constants in secp256k1_eckey_pubkey_parse
This results in more self-documenting code.
2018-10-09 15:40:41 +09:00
Russell O'Connor
496c5b43b8 Make constants static:
static const secp256k1_ge secp256k1_ge_const_g;
static const int CURVE_B;
2018-08-15 15:42:06 -04:00
Russell O'Connor
bf8b86cc07 secp256k1_fe_sqrt: Verify that the arguments don't alias. 2018-08-14 18:21:13 -04:00
Russell O'Connor
9bd89c836b Optimize secp256k1_fe_normalize_weak calls.
Move secp256k1_fe_normalize_weak calls out of ECMULT_TABLE_GET_GE and ECMULT_TABLE_GET_GE_STORAGE and into secp256k1_ge_globalz_set_table_gej instead.
2018-08-12 23:47:38 -04:00
Russell O'Connor
52ab96fedb clean dependendies in field_*_impl.h 2018-07-06 08:40:35 -04:00
Russell O'Connor
deff5edd42 Correct math typos in field_*.h 2018-07-06 08:40:35 -04:00
Russell O'Connor
4efb3f8dd1 Add check that restrict pointers don't alias with all parameters. 2018-07-06 08:40:34 -04:00
Evan Klitzke
3965027c81 Summarize build options in configure script 2018-03-27 16:10:15 -07:00
Jonas Nick
0f0517369c Fix algorithm selection in bench_ecmult 2018-03-27 09:21:11 +00:00
Don Viszneki
8b3841c91d fix bug in fread() failure check
the two middle arguments to fread() are easily confused, and cause the
checking of return value to fail incorrectly (and possibly succeed
incorrectly.)
2018-03-05 18:45:00 -08:00
Don Viszneki
cddef0c0be tests: add warning message when /dev/urandom fails
in case this code should ever be used as an example, a warning is a nice
way of helping ensure insecure keys are not generated
2018-03-05 18:43:31 -08:00
Pierre Pronchery
270f6c80db Portability fix for the configure scripts generated
Found thanks to the developer checks from the pkgsrc software
distribution (for NetBSD, SmartOS, Minix, MacOS X, Linux, and more).
2018-02-26 02:22:11 +01:00
48 changed files with 1197 additions and 560 deletions

View File

@@ -1,5 +1,5 @@
language: c
sudo: false
os: linux
addons:
apt:
packages: libgmp-dev
@@ -11,22 +11,22 @@ cache:
- src/java/guava/
env:
global:
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no GENERATOR=no RANGEPROOF=no WHITELIST=no
- FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no JNI=no GENERATOR=no RANGEPROOF=no WHITELIST=no SCHNORRSIG=no MUSIG=no
- GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar
matrix:
- SCALAR=32bit FIELD=32bit EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes
- FIELD=64bit EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes
- SCALAR=32bit FIELD=32bit EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
- FIELD=64bit EXPERIMENTAL=yes RANGEPROOF=yes WHITELIST=yes GENERATOR=yes SCHNORRSIG=yes MUSIG=yes
- SCALAR=32bit RECOVERY=yes
- SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes
- SCALAR=64bit
- FIELD=64bit RECOVERY=yes
- FIELD=64bit ENDOMORPHISM=yes
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes
- FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
- FIELD=64bit ASM=x86_64
- FIELD=64bit ENDOMORPHISM=yes ASM=x86_64
- FIELD=32bit ENDOMORPHISM=yes
- BIGNUM=no
- BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes
- BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes SCHNORRSIG=yes MUSIG=yes
- BIGNUM=no STATICPRECOMPUTATION=no
- BUILD=distcheck
- EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC
@@ -67,5 +67,4 @@ before_script: ./autogen.sh
script:
- if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi
- if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-rangeproof=$RANGEPROOF --enable-module-whitelist=$WHITELIST --enable-module-generator=$GENERATOR --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD
os: linux
- ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY --enable-module-rangeproof=$RANGEPROOF --enable-module-whitelist=$WHITELIST --enable-module-generator=$GENERATOR --enable-module-schnorrsig=$SCHNORRSIG --enable-module-musig=$MUSIG --enable-jni=$JNI $EXTRAFLAGS $USE_HOST && make -j2 $BUILD

View File

@@ -45,8 +45,10 @@ Implementation details
* Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones.
* Point multiplication for signing
* Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions.
* Access the table with branch-free conditional moves so memory access is uniform.
* No data-dependent branches
* Intended to be completely free of timing sidechannels for secret-key operations (on reasonable hardware/toolchains)
* Access the table with branch-free conditional moves so memory access is uniform.
* No data-dependent branches
* Optional runtime blinding which attempts to frustrate differential power analysis.
* The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally.
Build steps

View File

@@ -174,6 +174,11 @@ AC_ARG_ENABLE(module_surjectionproof,
[enable_module_surjectionproof=$enableval],
[enable_module_surjectionproof=no])
AC_ARG_ENABLE(reduced_surjection_proof_size,
AS_HELP_STRING([--enable-reduced-surjection-proof-size],[use reduced surjection proof size (disabling parsing and verification) [default=no]]),
[use_reduced_surjection_proof_size=$enableval],
[use_reduced_surjection_proof_size=no])
AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto],
[finite field implementation to use [default=auto]])],[req_field=$withval], [req_field=auto])
@@ -186,28 +191,21 @@ AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|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])
# Default is window size 16 (or window size 15 with endomorphism) which needs 1.375 MiB. */
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 [3..24].]
[window size for ecmult precomputation for verification, specified as integer in range [2..24].]
[Larger values result in possibly better performance at the cost of an exponentially larger precomputed table.]
[The table will store 2^(SIZE-2) * 64 bytes of data but can be larger in memory due]
[to platform-specific padding and alignment. "auto" is a reasonable setting for desktop machines]
[(currently 15 if the endomorphism optimization is disabled and 16 if it is enabled). [default=auto]]
[The table will store 2^(SIZE-2) * 64 bytes of data but can be larger in memory due to platform-specific padding and alignment.]
[If the endomorphism optimization is enabled, two tables of this size are used instead of only one.]
["auto" is a reasonable setting for desktop machines (currently 15). [default=auto]]
)],
[req_ecmult_window=$withval], [req_ecmult_window=auto])
AC_CHECK_TYPES([__int128])
AC_MSG_CHECKING([for __builtin_expect])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])],
[ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ],
[ AC_MSG_RESULT([no])
])
if test x"$enable_coverage" = x"yes"; then
AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code])
CFLAGS="$CFLAGS -O0 --coverage"
LDFLAGS="--coverage"
LDFLAGS="$LDFLAGS --coverage"
else
CFLAGS="$CFLAGS -O3"
fi
@@ -452,23 +450,19 @@ esac
#set ecmult window size
if test x"$req_ecmult_window" = x"auto"; then
if test x"$use_endomorphism" = x"yes"; then
set_ecmult_window=16
else
set_ecmult_window=15
fi
set_ecmult_window=15
else
set_ecmult_window=$req_ecmult_window
fi
error_window_size=['window size for ecmult precomputation not an integer in range [3..24] or "auto"']
error_window_size=['window size for ecmult precomputation not an integer in range [2..24] or "auto"']
case $set_ecmult_window in
''|*[[!0-9]]*)
# no valid integer
AC_MSG_ERROR($error_window_size)
;;
*)
if test "$set_ecmult_window" -lt 3 -o "$set_ecmult_window" -gt 24 ; then
if test "$set_ecmult_window" -lt 2 -o "$set_ecmult_window" -gt 24 ; then
# not in range
AC_MSG_ERROR($error_window_size)
fi
@@ -579,6 +573,10 @@ if test x"$use_external_default_callbacks" = x"yes"; then
AC_DEFINE(USE_EXTERNAL_DEFAULT_CALLBACKS, 1, [Define this symbol if an external implementation of the default callbacks is used])
fi
if test x"$use_reduced_surjection_proof_size" = x"yes"; then
AC_DEFINE(USE_REDUCED_SURJECTION_PROOF_SIZE, 1, [Define this symbol to reduce SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS to 16, disabling parsing and verification])
fi
if test x"$enable_experimental" = x"yes"; then
AC_MSG_NOTICE([******])
AC_MSG_NOTICE([WARNING: experimental build])
@@ -659,10 +657,11 @@ AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"ye
AM_CONDITIONAL([ENABLE_MODULE_GENERATOR], [test x"$enable_module_generator" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_RANGEPROOF], [test x"$enable_module_rangeproof" = x"yes"])
AM_CONDITIONAL([ENABLE_MODULE_WHITELIST], [test x"$enable_module_whitelist" = x"yes"])
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"])
AM_CONDITIONAL([USE_JNI], [test x"$use_jni" = x"yes"])
AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"])
AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"])
AM_CONDITIONAL([ENABLE_MODULE_SURJECTIONPROOF], [test x"$enable_module_surjectionproof" = x"yes"])
AM_CONDITIONAL([USE_REDUCED_SURJECTION_PROOF_SIZE], [test x"$use_reduced_surjection_proof_size" = x"yes"])
dnl make sure nothing new is exported so that we don't break the cache
PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH"
@@ -681,6 +680,7 @@ echo " with benchmarks = $use_benchmark"
echo " with coverage = $enable_coverage"
echo " module ecdh = $enable_module_ecdh"
echo " module recovery = $enable_module_recovery"
echo " module schnorrsig = $enable_module_schnorrsig"
echo
echo " asm = $set_asm"
echo " bignum = $set_bignum"

View File

@@ -32,7 +32,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (pos + lenbyte > inputlen) {
if (lenbyte > inputlen - pos) {
return 0;
}
pos += lenbyte;
@@ -51,7 +51,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (pos + lenbyte > inputlen) {
if (lenbyte > inputlen - pos) {
return 0;
}
while (lenbyte > 0 && input[pos] == 0) {
@@ -89,7 +89,7 @@ int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_
lenbyte = input[pos++];
if (lenbyte & 0x80) {
lenbyte -= 0x80;
if (pos + lenbyte > inputlen) {
if (lenbyte > inputlen - pos) {
return 0;
}
while (lenbyte > 0 && input[pos] == 0) {

View File

@@ -247,7 +247,7 @@ SECP256K1_API void secp256k1_context_destroy(
* to cause a crash, though its return value and output arguments are
* undefined.
*
* When this function has not been called (or called with fn=NULL), then the
* When this function has not been called (or called with fn==NULL), then the
* default handler will be used. The library provides a default handler which
* writes the message to stderr and calls abort. This default handler can be
* replaced at link time if the preprocessor macro
@@ -257,7 +257,7 @@ SECP256K1_API void secp256k1_context_destroy(
* - 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 using secp256k1_context_set_illegal_callback or
* pointer could have been set using secp256k1_context_set_illegal_callback or
* secp256k1_context_set_illegal_callback, e.g., when the creation of a context
* fails. In this case, the corresponding default handler will be called with
* the data pointer argument set to NULL.
@@ -305,21 +305,24 @@ SECP256K1_API void secp256k1_context_set_error_callback(
*
* Returns: a newly created scratch space.
* Args: ctx: an existing context object (cannot be NULL)
* In: max_size: maximum amount of memory to allocate
* In: size: amount of memory to be available as scratch space. Some extra
* (<100 bytes) will be allocated for extra accounting.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT secp256k1_scratch_space* secp256k1_scratch_space_create(
const secp256k1_context* ctx,
size_t max_size
size_t size
) SECP256K1_ARG_NONNULL(1);
/** Destroy a secp256k1 scratch space.
*
* The pointer may not be used afterwards.
* Args: scratch: space to destroy
* Args: ctx: a secp256k1 context object.
* scratch: space to destroy
*/
SECP256K1_API void secp256k1_scratch_space_destroy(
const secp256k1_context* ctx,
secp256k1_scratch_space* scratch
);
) SECP256K1_ARG_NONNULL(1);
/** Parse a variable-length public key into the pubkey object.
*
@@ -520,6 +523,12 @@ SECP256K1_API int secp256k1_ecdsa_signature_normalize(
*/
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979;
/** An implementation of the nonce generation function as defined in BIP-schnorr.
* 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_bipschnorr;
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default;

View File

@@ -1,6 +1,10 @@
#ifndef SECP256K1_MUSIG_H
#define SECP256K1_MUSIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/** This module implements a Schnorr-based multi-signature scheme called MuSig
@@ -147,9 +151,9 @@ SECP256K1_API int secp256k1_musig_pubkey_combine(
* NULL). If a non-unique session_id32 was given then a partial
* signature will LEAK THE SECRET KEY.
* msg32: the 32-byte message to be signed. Shouldn't be NULL unless you
* require sharing public nonces before the message is known
* require sharing nonce commitments before the message is known
* because it reduces nonce misuse resistance. If NULL, must be
* set with `musig_session_set_msg` before signing and verifying.
* set with `musig_session_get_public_nonce`.
* combined_pk: the combined public key of all signers (cannot be NULL)
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be
* NULL)
@@ -186,6 +190,8 @@ SECP256K1_API int secp256k1_musig_session_initialize(
* In: commitments: array of 32-byte nonce commitments (cannot be NULL)
* n_commitments: the length of commitments and signers array. Must be the total
* number of signers participating in the MuSig.
* msg32: the 32-byte message to be signed. Must be NULL if already
* set with `musig_session_initialize` otherwise can not be NULL.
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_public_nonce(
const secp256k1_context* ctx,
@@ -193,7 +199,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_publi
secp256k1_musig_session_signer_data *signers,
secp256k1_pubkey *nonce,
const unsigned char *const *commitments,
size_t n_commitments
size_t n_commitments,
const unsigned char *msg32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Initializes a verifier session that can be used for verifying nonce commitments
@@ -205,9 +212,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_get_publi
* Out: session: the session structure to initialize (cannot be NULL)
* signers: an array of signers' data to be initialized. Array length must
* equal to `n_signers`(cannot be NULL)
* In: msg32: the 32-byte message to be signed If NULL, must be set with
* `musig_session_set_msg` before using the session for verifying
* partial signatures.
* In: msg32: the 32-byte message to be signed (cannot be NULL)
* combined_pk: the combined public key of all signers (cannot be NULL)
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be NULL)
* commitments: array of 32-byte nonce commitments. Array length must equal to
@@ -225,7 +230,7 @@ SECP256K1_API int secp256k1_musig_session_initialize_verifier(
const unsigned char *pk_hash32,
const unsigned char *const *commitments,
size_t n_signers
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(6) SECP256K1_ARG_NONNULL(7);
/** Checks a signer's public nonce against a commitment to said nonce, and update
* data structure if they match
@@ -269,20 +274,6 @@ SECP256K1_API int secp256k1_musig_session_combine_nonces(
size_t n_signers,
int *nonce_is_negated,
const secp256k1_pubkey *adaptor
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
/** Sets the message of a session if previously unset
*
* Returns 1 if the message was not set yet and is now successfully set
* 0 otherwise
* Args: ctx: pointer to a context object (cannot be NULL)
* session: the session structure to update with the message (cannot be NULL)
* In: msg32: the 32-byte message to be signed (cannot be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_session_set_msg(
const secp256k1_context* ctx,
secp256k1_musig_session *session,
const unsigned char *msg32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize a MuSig partial signature or adaptor signature
@@ -366,13 +357,20 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_verif
* Out: sig: complete signature (cannot be NULL)
* In: partial_sigs: array of partial signatures to combine (cannot be NULL)
* n_sigs: number of signatures in the partial_sigs array
* tweak32: if `combined_pk` was tweaked with `ec_pubkey_tweak_add` after
* `musig_pubkey_combine` and before `musig_session_initialize` then
* the same tweak must be provided here in order to get a valid
* signature for the tweaked key. Otherwise `tweak` should be NULL.
* If the tweak is larger than the group order or 0 this function will
* return 0. (can be NULL)
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_partial_sig_combine(
const secp256k1_context* ctx,
const secp256k1_musig_session *session,
secp256k1_schnorrsig *sig,
const secp256k1_musig_partial_signature *partial_sigs,
size_t n_sigs
size_t n_sigs,
const unsigned char *tweak32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Converts a partial signature to an adaptor signature by adding a given secret
@@ -419,4 +417,8 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_musig_extract_secret_ad
int nonce_is_negated
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,6 +1,12 @@
#ifndef SECP256K1_SCHNORRSIG_H
#define SECP256K1_SCHNORRSIG_H
#include "secp256k1.h"
#ifdef __cplusplus
extern "C" {
#endif
/** This module implements a variant of Schnorr signatures compliant with
* BIP-schnorr
* (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki).
@@ -115,4 +121,9 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_schnorrsig_verify_batch
const secp256k1_pubkey *const *pk,
size_t n_sigs
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
#ifdef __cplusplus
}
#endif
#endif /* SECP256K1_SCHNORRSIG_H */

View File

@@ -11,6 +11,9 @@ extern "C" {
/** Maximum number of inputs that may be given in a surjection proof */
#define SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS 256
/** Maximum number of inputs that may be used in a surjection proof */
#define SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS 256
/** Number of bytes a serialized surjection proof requires given the
* number of inputs and the number of used inputs.
*/
@@ -19,7 +22,7 @@ extern "C" {
/** Maximum number of bytes a serialized surjection proof requires. */
#define SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX \
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)
SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS)
/** Opaque data structure that holds a parsed surjection proof
*
@@ -46,9 +49,10 @@ typedef struct {
/** Bitmap of which input tags are used in the surjection proof */
unsigned char used_inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS / 8];
/** Borromean signature: e0, scalars */
unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS)];
unsigned char data[32 * (1 + SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS)];
} secp256k1_surjectionproof;
#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE
/** Parse a surjection proof
*
* Returns: 1 when the proof could be parsed, 0 otherwise.
@@ -70,6 +74,7 @@ SECP256K1_API int secp256k1_surjectionproof_parse(
const unsigned char *input,
size_t inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
#endif
/** Serialize a surjection proof
*
@@ -134,6 +139,7 @@ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Surjection proof initialization function; decides on inputs to use
* To be used to initialize stack-allocated secp256k1_surjectionproof struct
* Returns 0: inputs could not be selected
* n: inputs were selected after n iterations of random selection
*
@@ -142,7 +148,8 @@ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size(
* e.g. in a coinjoin with others' inputs, an ephemeral tag can be given;
* this won't match the output tag but might be used in the anonymity set.)
* n_input_tags: the number of entries in the fixed_input_tags array
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
* Must be <= SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS
* fixed_output_tag: fixed output tag
* max_n_iterations: the maximum number of iterations to do before giving up. Because the
* maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is
@@ -166,6 +173,51 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_initial
const unsigned char *random_seed32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7);
/** Surjection proof allocation and initialization function; decides on inputs to use
* Returns 0: inputs could not be selected, or malloc failure
* n: inputs were selected after n iterations of random selection
*
* In: ctx: pointer to a context object
* proof_out_p: a pointer to a pointer to `secp256k1_surjectionproof*`.
* the newly-allocated struct pointer will be saved here.
* fixed_input_tags: fixed input tags `A_i` for all inputs. (If the fixed tag is not known,
* e.g. in a coinjoin with others' inputs, an ephemeral tag can be given;
* this won't match the output tag but might be used in the anonymity set.)
* n_input_tags: the number of entries in the fixed_input_tags array
* n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set
* fixed_output_tag: fixed output tag
* max_n_iterations: the maximum number of iterations to do before giving up. Because the
* maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is
* limited to 256 the probability of giving up is smaller than
* (255/256)^(n_input_tags_to_use*max_n_iterations).
*
* random_seed32: a random seed to be used for input selection
* Out: proof_out_p: The pointer to newly-allocated proof whose bitvector will be initialized.
* In case of failure, the pointer will be NULL.
* input_index: The index of the actual input that is secretly mapped to the output
*/
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_allocate_initialized(
const secp256k1_context* ctx,
secp256k1_surjectionproof** proof_out_p,
size_t *input_index,
const secp256k1_fixed_asset_tag* fixed_input_tags,
const size_t n_input_tags,
const size_t n_input_tags_to_use,
const secp256k1_fixed_asset_tag* fixed_output_tag,
const size_t n_max_iterations,
const unsigned char *random_seed32
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7);
/** Surjection proof destroy function
* deallocates the struct that was allocated with secp256k1_surjectionproof_allocate_initialized
*
* In: proof: pointer to secp256k1_surjectionproof struct
*/
SECP256K1_API void secp256k1_surjectionproof_destroy(
secp256k1_surjectionproof* proof
) SECP256K1_ARG_NONNULL(1);
/** Surjection proof generation function
* Returns 0: proof could not be created
* 1: proof was successfully created
@@ -191,6 +243,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_generat
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5) SECP256K1_ARG_NONNULL(7) SECP256K1_ARG_NONNULL(8);
#ifndef USE_REDUCED_SURJECTION_PROOF_SIZE
/** Surjection proof verification function
* Returns 0: proof was invalid
* 1: proof was valid
@@ -208,6 +261,7 @@ SECP256K1_API int secp256k1_surjectionproof_verify(
size_t n_ephemeral_input_tags,
const secp256k1_generator* ephemeral_output_tag
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
#endif
#ifdef __cplusplus
}

View File

@@ -8,6 +8,6 @@ Description: Optimized C library for EC operations on curve secp256k1
URL: https://github.com/bitcoin-core/secp256k1
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs.private: @SECP_LIBS@
Libs: -L${libdir} -lsecp256k1
Libs.private: @SECP_LIBS@

View File

@@ -30,6 +30,7 @@
#define USE_SCALAR_INV_BUILTIN 1
#define USE_FIELD_10X26 1
#define USE_SCALAR_8X32 1
#define ECMULT_WINDOW_SIZE 15
#endif /* USE_BASIC_CONFIG */

View File

@@ -64,7 +64,7 @@ static void bench_ecmult(void* arg) {
size_t iter;
for (iter = 0; iter < iters; ++iter) {
data->ecmult_multi(&data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g);
data->ecmult_multi(&data->ctx->error_callback, &data->ctx->ecmult_ctx, data->scratch, &data->output[iter], data->includes_g ? &data->scalars[data->offset1] : NULL, bench_callback, arg, count - includes_g);
data->offset1 = (data->offset1 + count) % POINTS;
data->offset2 = (data->offset2 + count - 1) % POINTS;
}
@@ -139,6 +139,11 @@ int main(int argc, char **argv) {
secp256k1_gej* pubkeys_gej;
size_t scratch_size;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
data.ecmult_multi = secp256k1_ecmult_multi_var;
if (argc > 1) {
if(have_flag(argc, argv, "pippenger_wnaf")) {
printf("Using pippenger_wnaf:\n");
@@ -146,15 +151,19 @@ int main(int argc, char **argv) {
} else if(have_flag(argc, argv, "strauss_wnaf")) {
printf("Using strauss_wnaf:\n");
data.ecmult_multi = secp256k1_ecmult_strauss_batch_single;
} else if(have_flag(argc, argv, "simple")) {
printf("Using simple algorithm:\n");
data.ecmult_multi = secp256k1_ecmult_multi_var;
secp256k1_scratch_space_destroy(data.ctx, data.scratch);
data.scratch = NULL;
} else {
fprintf(stderr, "%s: unrecognized argument '%s'.\n", argv[0], argv[1]);
fprintf(stderr, "Use 'pippenger_wnaf', 'strauss_wnaf', 'simple' or no argument to benchmark a combined algorithm.\n");
return 1;
}
} else {
data.ecmult_multi = secp256k1_ecmult_multi_var;
}
/* Allocate stuff */
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
scratch_size = secp256k1_strauss_scratch_size(POINTS) + STRAUSS_SCRATCH_OBJECTS*16;
data.scratch = secp256k1_scratch_space_create(data.ctx, scratch_size);
data.scalars = malloc(sizeof(secp256k1_scalar) * POINTS);
data.seckeys = malloc(sizeof(secp256k1_scalar) * POINTS);
data.pubkeys = malloc(sizeof(secp256k1_ge) * POINTS);
@@ -184,8 +193,10 @@ int main(int argc, char **argv) {
run_test(&data, i << p, 1);
}
}
if (data.scratch != NULL) {
secp256k1_scratch_space_destroy(data.ctx, data.scratch);
}
secp256k1_context_destroy(data.ctx);
secp256k1_scratch_space_destroy(data.scratch);
free(data.scalars);
free(data.pubkeys);
free(data.seckeys);

View File

@@ -184,9 +184,11 @@ void bench_field_inverse_var(void* arg) {
void bench_field_sqrt(void* arg) {
int i;
bench_inv *data = (bench_inv*)arg;
secp256k1_fe t;
for (i = 0; i < 20000; i++) {
secp256k1_fe_sqrt(&data->fe_x, &data->fe_x);
t = data->fe_x;
secp256k1_fe_sqrt(&data->fe_x, &t);
secp256k1_fe_add(&data->fe_x, &data->fe_y);
}
}
@@ -251,7 +253,7 @@ void bench_wnaf_const(void* arg) {
bench_inv *data = (bench_inv*)arg;
for (i = 0; i < 20000; i++) {
secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A, 256);
secp256k1_wnaf_const(data->wnaf, &data->scalar_x, WINDOW_A, 256);
secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y);
}
}

View File

@@ -122,7 +122,7 @@ int main(void) {
free(data.msgs);
free(data.sigs);
secp256k1_scratch_space_destroy(data.scratch);
secp256k1_scratch_space_destroy(data.ctx, data.scratch);
secp256k1_context_destroy(data.ctx);
return 0;
}

View File

@@ -46,68 +46,73 @@ static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CON
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
);
static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) {
int lenleft, b1;
size_t ret = 0;
static int secp256k1_der_read_len(size_t *len, const unsigned char **sigp, const unsigned char *sigend) {
size_t lenleft;
unsigned char b1;
VERIFY_CHECK(len != NULL);
*len = 0;
if (*sigp >= sigend) {
return -1;
return 0;
}
b1 = *((*sigp)++);
if (b1 == 0xFF) {
/* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */
return -1;
return 0;
}
if ((b1 & 0x80) == 0) {
/* X.690-0207 8.1.3.4 short form length octets */
return b1;
*len = b1;
return 1;
}
if (b1 == 0x80) {
/* Indefinite length is not allowed in DER. */
return -1;
return 0;
}
/* X.690-207 8.1.3.5 long form length octets */
lenleft = b1 & 0x7F;
if (lenleft > sigend - *sigp) {
return -1;
lenleft = b1 & 0x7F; /* lenleft is at least 1 */
if (lenleft > (size_t)(sigend - *sigp)) {
return 0;
}
if (**sigp == 0) {
/* Not the shortest possible length encoding. */
return -1;
return 0;
}
if ((size_t)lenleft > sizeof(size_t)) {
if (lenleft > sizeof(size_t)) {
/* The resulting length would exceed the range of a size_t, so
* certainly longer than the passed array size.
*/
return -1;
return 0;
}
while (lenleft > 0) {
ret = (ret << 8) | **sigp;
if (ret + lenleft > (size_t)(sigend - *sigp)) {
/* Result exceeds the length of the passed array. */
return -1;
}
*len = (*len << 8) | **sigp;
(*sigp)++;
lenleft--;
}
if (ret < 128) {
/* Not the shortest possible length encoding. */
return -1;
if (*len > (size_t)(sigend - *sigp)) {
/* Result exceeds the length of the passed array. */
return 0;
}
return ret;
if (*len < 128) {
/* Not the shortest possible length encoding. */
return 0;
}
return 1;
}
static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) {
int overflow = 0;
unsigned char ra[32] = {0};
int rlen;
size_t rlen;
if (*sig == sigend || **sig != 0x02) {
/* Not a primitive integer (X.690-0207 8.3.1). */
return 0;
}
(*sig)++;
rlen = secp256k1_der_read_len(sig, sigend);
if (rlen <= 0 || (*sig) + rlen > sigend) {
if (secp256k1_der_read_len(&rlen, sig, sigend) == 0) {
return 0;
}
if (rlen == 0 || *sig + rlen > sigend) {
/* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */
return 0;
}
@@ -123,8 +128,11 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char
/* Negative. */
overflow = 1;
}
while (rlen > 0 && **sig == 0) {
/* Skip leading zero bytes */
/* There is at most one leading zero byte:
* if there were two leading zero bytes, we would have failed and returned 0
* because of excessive 0x00 padding already. */
if (rlen > 0 && **sig == 0) {
/* Skip leading zero byte */
rlen--;
(*sig)++;
}
@@ -144,18 +152,16 @@ static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char
static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) {
const unsigned char *sigend = sig + size;
int rlen;
size_t rlen;
if (sig == sigend || *(sig++) != 0x30) {
/* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */
return 0;
}
rlen = secp256k1_der_read_len(&sig, sigend);
if (rlen < 0 || sig + rlen > sigend) {
/* Tuple exceeds bounds */
if (secp256k1_der_read_len(&rlen, &sig, sigend) == 0) {
return 0;
}
if (sig + rlen != sigend) {
/* Garbage after tuple. */
if (rlen != (size_t)(sigend - sig)) {
/* Tuple exceeds bounds or garage after tuple. */
return 0;
}

View File

@@ -18,7 +18,7 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char
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);
} else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) {
} else if (size == 65 && (pub[0] == SECP256K1_TAG_PUBKEY_UNCOMPRESSED || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) {
secp256k1_fe x, y;
if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) {
return 0;

View File

@@ -43,6 +43,6 @@ typedef int (secp256k1_ecmult_multi_callback)(secp256k1_scalar *sc, secp256k1_ge
* 0 if there is not enough scratch space for a single point or
* callback returns 0
*/
static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n);
static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n);
#endif /* SECP256K1_ECMULT_H */

View File

@@ -48,7 +48,7 @@
*
* Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335
*/
static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size) {
static int secp256k1_wnaf_const(int *wnaf, const secp256k1_scalar *scalar, int w, int size) {
int global_sign;
int skew = 0;
int word = 0;
@@ -59,7 +59,7 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size)
int flip;
int bit;
secp256k1_scalar neg_s;
secp256k1_scalar s;
int not_neg_one;
VERIFY_CHECK(w > 0);
@@ -79,12 +79,13 @@ static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w, int size)
* {1, 2} we want to add to the scalar when ensuring that it's odd. Further
* complicating things, -1 interacts badly with `secp256k1_scalar_cadd_bit` and
* we need to special-case it in this logic. */
flip = secp256k1_scalar_is_high(&s);
flip = secp256k1_scalar_is_high(scalar);
/* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */
bit = flip ^ !secp256k1_scalar_is_even(&s);
bit = flip ^ !secp256k1_scalar_is_even(scalar);
/* We check for negative one, since adding 2 to it will cause an overflow */
secp256k1_scalar_negate(&neg_s, &s);
not_neg_one = !secp256k1_scalar_is_one(&neg_s);
secp256k1_scalar_negate(&s, scalar);
not_neg_one = !secp256k1_scalar_is_one(&s);
s = *scalar;
secp256k1_scalar_cadd_bit(&s, bit, not_neg_one);
/* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects
* that we added two to it and flipped it. In fact for -1 these operations are
@@ -136,7 +137,6 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)];
int i;
secp256k1_scalar sc = *scalar;
/* build wnaf representation for q. */
int rsize = size;
@@ -144,13 +144,13 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons
if (size > 128) {
rsize = 128;
/* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */
secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc);
skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1, 128);
skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1, 128);
secp256k1_scalar_split_lambda(&q_1, &q_lam, scalar);
skew_1 = secp256k1_wnaf_const(wnaf_1, &q_1, WINDOW_A - 1, 128);
skew_lam = secp256k1_wnaf_const(wnaf_lam, &q_lam, WINDOW_A - 1, 128);
} else
#endif
{
skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1, size);
skew_1 = secp256k1_wnaf_const(wnaf_1, scalar, WINDOW_A - 1, size);
#ifdef USE_ENDOMORPHISM
skew_lam = 0;
#endif

View File

@@ -108,7 +108,7 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont
static void secp256k1_ecmult_gen_context_finalize_memcpy(secp256k1_ecmult_gen_context *dst, const secp256k1_ecmult_gen_context *src) {
#ifndef USE_ECMULT_STATIC_PRECOMPUTATION
if (src->prec != NULL) {
/* We cast to void* first to suppress a -Wcast-align warning in clang. */
/* We cast to void* first to suppress a -Wcast-align warning. */
dst->prec = (secp256k1_ge_storage (*)[64][16])(void*)((unsigned char*)dst + ((unsigned char*)src->prec - (unsigned char*)src));
}
#else
@@ -187,7 +187,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
do {
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
retry = !secp256k1_fe_set_b32(&s, nonce32);
retry |= secp256k1_fe_is_zero(&s);
retry = retry || secp256k1_fe_is_zero(&s);
} while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */
/* Randomize the projection to defend against multiplier sidechannels. */
secp256k1_gej_rescale(&ctx->initial, &s);
@@ -196,7 +196,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const
secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32);
secp256k1_scalar_set_b32(&b, nonce32, &retry);
/* A blinding value of 0 works, but would undermine the projection hardening. */
retry |= secp256k1_scalar_is_zero(&b);
retry = retry || secp256k1_scalar_is_zero(&b);
} while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
memset(nonce32, 0, 32);

View File

@@ -33,17 +33,15 @@
/* optimal for 128-bit and 256-bit exponents. */
# define WINDOW_A 5
/** Larger values for ECMULT_WINDOW_SIZE result in possibly better
* performance at the cost of an exponentially larger precomputed
* table. The exact table size is
* (1 << (WINDOW_G - 2)) * sizeof(secp256k1_ge_storage) bytes,
* where sizeof(secp256k1_ge_storage) is typically 64 bytes but can
* be larger due to platform-specific padding and alignment.
* performance at the cost of an exponentially larger precomputed
* table. The exact table size is
* (1 << (WINDOW_G - 2)) * sizeof(secp256k1_ge_storage) bytes,
* where sizeof(secp256k1_ge_storage) is typically 64 bytes but can
* be larger due to platform-specific padding and alignment.
* If the endomorphism optimization is enabled (USE_ENDOMORMPHSIM)
* two tables of this size are used instead of only one.
*/
# ifdef USE_ENDOMORPHISM
# define WINDOW_G ((ECMULT_WINDOW_SIZE)-1)
# else
# define WINDOW_G (ECMULT_WINDOW_SIZE)
# endif
# define WINDOW_G ECMULT_WINDOW_SIZE
#endif
/* Noone will ever need more than a window size of 24. The code might
@@ -56,9 +54,9 @@
* will not fit in a size_t.
* If WINDOW_G > 31 and int has 32 bits, then the code is incorrect
* because certain expressions will overflow.
* */
#if ECMULT_WINDOW_SIZE < 3 || ECMULT_WINDOW_SIZE > 24
# error Set ECMULT_WINDOW_SIZE to an integer in range [3..24].
*/
#if ECMULT_WINDOW_SIZE < 2 || ECMULT_WINDOW_SIZE > 24
# error Set ECMULT_WINDOW_SIZE to an integer in range [2..24].
#endif
#ifdef USE_ENDOMORPHISM
@@ -296,7 +294,8 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
if ((n) > 0) { \
*(r) = (pre)[((n)-1)/2]; \
} else { \
secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \
*(r) = (pre)[(-(n)-1)/2]; \
secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
} \
} while(0)
@@ -308,7 +307,7 @@ static void secp256k1_ecmult_odd_multiples_table_storage_var(const int n, secp25
secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \
} else { \
secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \
secp256k1_ge_neg((r), (r)); \
secp256k1_fe_negate(&((r)->y), &((r)->y), 1); \
} \
} while(0)
@@ -342,7 +341,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void *
size_t size = sizeof((*ctx->pre_g)[0]) * ((size_t)ECMULT_TABLE_SIZE(WINDOW_G));
/* check for overflow */
VERIFY_CHECK(size / sizeof((*ctx->pre_g)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)));
ctx->pre_g = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, size, base, prealloc_size);
ctx->pre_g = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G), base, prealloc_size);
}
/* precompute the tables with odd multiples */
@@ -356,7 +355,7 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void *
size_t size = sizeof((*ctx->pre_g_128)[0]) * ((size_t) ECMULT_TABLE_SIZE(WINDOW_G));
/* check for overflow */
VERIFY_CHECK(size / sizeof((*ctx->pre_g_128)[0]) == ((size_t)ECMULT_TABLE_SIZE(WINDOW_G)));
ctx->pre_g_128 = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, size, base, prealloc_size);
ctx->pre_g_128 = (secp256k1_ge_storage (*)[])manual_alloc(prealloc, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G), base, prealloc_size);
/* calculate 2^128*generator */
g_128j = gj;
@@ -370,11 +369,12 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, void *
static void secp256k1_ecmult_context_finalize_memcpy(secp256k1_ecmult_context *dst, const secp256k1_ecmult_context *src) {
if (src->pre_g != NULL) {
dst->pre_g = (secp256k1_ge_storage (*)[])((unsigned char*)dst + ((unsigned char*)(src->pre_g) - (unsigned char*)src));
/* We cast to void* first to suppress a -Wcast-align warning. */
dst->pre_g = (secp256k1_ge_storage (*)[])(void*)((unsigned char*)dst + ((unsigned char*)(src->pre_g) - (unsigned char*)src));
}
#ifdef USE_ENDOMORPHISM
if (src->pre_g_128 != NULL) {
dst->pre_g_128 = (secp256k1_ge_storage (*)[])((unsigned char*)dst + ((unsigned char*)(src->pre_g_128) - (unsigned char*)src));
dst->pre_g_128 = (secp256k1_ge_storage (*)[])(void*)((unsigned char*)dst + ((unsigned char*)(src->pre_g_128) - (unsigned char*)src));
}
#endif
}
@@ -648,52 +648,55 @@ static size_t secp256k1_strauss_scratch_size(size_t n_points) {
return n_points*point_size;
}
static int secp256k1_ecmult_strauss_batch(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) {
static int secp256k1_ecmult_strauss_batch(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) {
secp256k1_gej* points;
secp256k1_scalar* scalars;
struct secp256k1_strauss_state state;
size_t i;
const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch);
secp256k1_gej_set_infinity(r);
if (inp_g_sc == NULL && n_points == 0) {
return 1;
}
if (!secp256k1_scratch_allocate_frame(scratch, secp256k1_strauss_scratch_size(n_points), STRAUSS_SCRATCH_OBJECTS)) {
return 0;
}
points = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_gej));
scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(scratch, n_points * sizeof(secp256k1_scalar));
state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej));
state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
points = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_gej));
scalars = (secp256k1_scalar*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(secp256k1_scalar));
state.prej = (secp256k1_gej*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_gej));
state.zr = (secp256k1_fe*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_fe));
#ifdef USE_ENDOMORPHISM
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, n_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * 2 * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
state.pre_a_lam = state.pre_a + n_points * ECMULT_TABLE_SIZE(WINDOW_A);
#else
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
state.pre_a = (secp256k1_ge*)secp256k1_scratch_alloc(error_callback, scratch, n_points * ECMULT_TABLE_SIZE(WINDOW_A) * sizeof(secp256k1_ge));
#endif
state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(scratch, n_points * sizeof(struct secp256k1_strauss_point_state));
state.ps = (struct secp256k1_strauss_point_state*)secp256k1_scratch_alloc(error_callback, scratch, n_points * sizeof(struct secp256k1_strauss_point_state));
if (points == NULL || scalars == NULL || state.prej == NULL || state.zr == NULL || state.pre_a == NULL) {
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 0;
}
for (i = 0; i < n_points; i++) {
secp256k1_ge point;
if (!cb(&scalars[i], &point, i+cb_offset, cbdata)) {
secp256k1_scratch_deallocate_frame(scratch);
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 0;
}
secp256k1_gej_set_ge(&points[i], &point);
}
secp256k1_ecmult_strauss_wnaf(ctx, &state, r, n_points, points, scalars, inp_g_sc);
secp256k1_scratch_deallocate_frame(scratch);
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 1;
}
/* Wrapper for secp256k1_ecmult_multi_func interface */
static int secp256k1_ecmult_strauss_batch_single(const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
return secp256k1_ecmult_strauss_batch(actx, scratch, r, inp_g_sc, cb, cbdata, n, 0);
static int secp256k1_ecmult_strauss_batch_single(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
return secp256k1_ecmult_strauss_batch(error_callback, actx, scratch, r, inp_g_sc, cb, cbdata, n, 0);
}
static size_t secp256k1_strauss_max_points(secp256k1_scratch *scratch) {
return secp256k1_scratch_max_allocation(scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1);
static size_t secp256k1_strauss_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) {
return secp256k1_scratch_max_allocation(error_callback, scratch, STRAUSS_SCRATCH_OBJECTS) / secp256k1_strauss_scratch_size(1);
}
/** Convert a number to WNAF notation.
@@ -982,10 +985,11 @@ static size_t secp256k1_pippenger_scratch_size(size_t n_points, int bucket_windo
size_t entries = n_points + 1;
#endif
size_t entry_size = sizeof(secp256k1_ge) + sizeof(secp256k1_scalar) + sizeof(struct secp256k1_pippenger_point_state) + (WNAF_SIZE(bucket_window+1)+1)*sizeof(int);
return ((1<<bucket_window) * sizeof(secp256k1_gej) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size);
return (sizeof(secp256k1_gej) << bucket_window) + sizeof(struct secp256k1_pippenger_state) + entries * entry_size;
}
static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) {
static int secp256k1_ecmult_pippenger_batch(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points, size_t cb_offset) {
const size_t scratch_checkpoint = secp256k1_scratch_checkpoint(error_callback, scratch);
/* Use 2(n+1) with the endomorphism, n+1 without, when calculating batch
* sizes. The reason for +1 is that we add the G scalar to the list of
* other scalars. */
@@ -1010,15 +1014,21 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx,
}
bucket_window = secp256k1_pippenger_bucket_window(n_points);
if (!secp256k1_scratch_allocate_frame(scratch, secp256k1_pippenger_scratch_size(n_points, bucket_window), PIPPENGER_SCRATCH_OBJECTS)) {
points = (secp256k1_ge *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*points));
scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(error_callback, scratch, entries * sizeof(*scalars));
state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(error_callback, scratch, sizeof(*state_space));
if (points == NULL || scalars == NULL || state_space == NULL) {
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 0;
}
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));
if (state_space->ps == NULL || state_space->wnaf_na == NULL || buckets == NULL) {
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 0;
}
points = (secp256k1_ge *) secp256k1_scratch_alloc(scratch, entries * sizeof(*points));
scalars = (secp256k1_scalar *) secp256k1_scratch_alloc(scratch, entries * sizeof(*scalars));
state_space = (struct secp256k1_pippenger_state *) secp256k1_scratch_alloc(scratch, sizeof(*state_space));
state_space->ps = (struct secp256k1_pippenger_point_state *) secp256k1_scratch_alloc(scratch, entries * sizeof(*state_space->ps));
state_space->wnaf_na = (int *) secp256k1_scratch_alloc(scratch, entries*(WNAF_SIZE(bucket_window+1)) * sizeof(int));
buckets = (secp256k1_gej *) secp256k1_scratch_alloc(scratch, (1<<bucket_window) * sizeof(*buckets));
if (inp_g_sc != NULL) {
scalars[0] = *inp_g_sc;
@@ -1032,7 +1042,7 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx,
while (point_idx < n_points) {
if (!cb(&scalars[idx], &points[idx], point_idx + cb_offset, cbdata)) {
secp256k1_scratch_deallocate_frame(scratch);
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 0;
}
idx++;
@@ -1056,13 +1066,13 @@ static int secp256k1_ecmult_pippenger_batch(const secp256k1_ecmult_context *ctx,
for(i = 0; i < 1<<bucket_window; i++) {
secp256k1_gej_clear(&buckets[i]);
}
secp256k1_scratch_deallocate_frame(scratch);
secp256k1_scratch_apply_checkpoint(error_callback, scratch, scratch_checkpoint);
return 1;
}
/* Wrapper for secp256k1_ecmult_multi_func interface */
static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
return secp256k1_ecmult_pippenger_batch(actx, scratch, r, inp_g_sc, cb, cbdata, n, 0);
static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *actx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
return secp256k1_ecmult_pippenger_batch(error_callback, actx, scratch, r, inp_g_sc, cb, cbdata, n, 0);
}
/**
@@ -1070,8 +1080,8 @@ static int secp256k1_ecmult_pippenger_batch_single(const secp256k1_ecmult_contex
* a given scratch space. The function ensures that fewer points may also be
* used.
*/
static size_t secp256k1_pippenger_max_points(secp256k1_scratch *scratch) {
size_t max_alloc = secp256k1_scratch_max_allocation(scratch, PIPPENGER_SCRATCH_OBJECTS);
static size_t secp256k1_pippenger_max_points(const secp256k1_callback* error_callback, secp256k1_scratch *scratch) {
size_t max_alloc = secp256k1_scratch_max_allocation(error_callback, scratch, PIPPENGER_SCRATCH_OBJECTS);
int bucket_window;
size_t res = 0;
@@ -1085,7 +1095,7 @@ static size_t secp256k1_pippenger_max_points(secp256k1_scratch *scratch) {
#ifdef USE_ENDOMORPHISM
entry_size = 2*entry_size;
#endif
space_overhead = ((1<<bucket_window) * sizeof(secp256k1_gej) + entry_size + sizeof(struct secp256k1_pippenger_state));
space_overhead = (sizeof(secp256k1_gej) << bucket_window) + entry_size + sizeof(struct secp256k1_pippenger_state);
if (space_overhead > max_alloc) {
break;
}
@@ -1108,14 +1118,15 @@ static size_t secp256k1_pippenger_max_points(secp256k1_scratch *scratch) {
/* Computes ecmult_multi by simply multiplying and adding each point. Does not
* require a scratch space */
static int secp256k1_ecmult_multi_var_simple(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n_points) {
static int secp256k1_ecmult_multi_simple_var(const secp256k1_ecmult_context *ctx, 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);
/* r = inp_g_sc*G */
secp256k1_gej_set_infinity(r);
secp256k1_gej_set_infinity(&tmpj);
/* r = inp_g_sc*G */
secp256k1_ecmult(ctx, r, &tmpj, &szero, inp_g_sc);
for (point_idx = 0; point_idx < n_points; point_idx++) {
secp256k1_ge point;
@@ -1132,12 +1143,31 @@ static int secp256k1_ecmult_multi_var_simple(const secp256k1_ecmult_context *ctx
return 1;
}
typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t);
static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
/* Compute the number of batches and the batch size given the maximum batch size and the
* total number of points */
static int secp256k1_ecmult_multi_batch_size_helper(size_t *n_batches, size_t *n_batch_points, size_t max_n_batch_points, size_t n) {
if (max_n_batch_points == 0) {
return 0;
}
if (max_n_batch_points > ECMULT_MAX_POINTS_PER_BATCH) {
max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH;
}
if (n == 0) {
*n_batches = 0;
*n_batch_points = 0;
return 1;
}
/* Compute ceil(n/max_n_batch_points) and ceil(n/n_batches) */
*n_batches = 1 + (n - 1) / max_n_batch_points;
*n_batch_points = 1 + (n - 1) / *n_batches;
return 1;
}
typedef int (*secp256k1_ecmult_multi_func)(const secp256k1_callback* error_callback, const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t);
static int secp256k1_ecmult_multi_var(const secp256k1_callback* error_callback, const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n) {
size_t i;
int (*f)(const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t);
size_t max_points;
int (*f)(const secp256k1_callback* error_callback, const secp256k1_ecmult_context*, secp256k1_scratch*, secp256k1_gej*, const secp256k1_scalar*, secp256k1_ecmult_multi_callback cb, void*, size_t, size_t);
size_t n_batches;
size_t n_batch_points;
@@ -1151,34 +1181,29 @@ static int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp2
return 1;
}
if (scratch == NULL) {
return secp256k1_ecmult_multi_var_simple(ctx, r, inp_g_sc, cb, cbdata, n);
return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
}
max_points = secp256k1_pippenger_max_points(scratch);
if (max_points == 0) {
return 0;
} else if (max_points > ECMULT_MAX_POINTS_PER_BATCH) {
max_points = ECMULT_MAX_POINTS_PER_BATCH;
/* Compute the batch sizes for Pippenger's algorithm given a scratch space. If it's greater than
* a threshold use Pippenger's algorithm. Otherwise use Strauss' algorithm.
* As a first step check if there's enough space for Pippenger's algo (which requires less space
* than Strauss' algo) and if not, use the simple algorithm. */
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_pippenger_max_points(error_callback, scratch), n)) {
return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
}
n_batches = (n+max_points-1)/max_points;
n_batch_points = (n+n_batches-1)/n_batches;
if (n_batch_points >= ECMULT_PIPPENGER_THRESHOLD) {
f = secp256k1_ecmult_pippenger_batch;
} else {
max_points = secp256k1_strauss_max_points(scratch);
if (max_points == 0) {
return 0;
if (!secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, secp256k1_strauss_max_points(error_callback, scratch), n)) {
return secp256k1_ecmult_multi_simple_var(ctx, r, inp_g_sc, cb, cbdata, n);
}
n_batches = (n+max_points-1)/max_points;
n_batch_points = (n+n_batches-1)/n_batches;
f = secp256k1_ecmult_strauss_batch;
}
for(i = 0; i < n_batches; i++) {
size_t nbp = n < n_batch_points ? n : n_batch_points;
size_t offset = n_batch_points*i;
secp256k1_gej tmp;
if (!f(ctx, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) {
if (!f(error_callback, ctx, scratch, &tmp, i == 0 ? inp_g_sc : NULL, cb, cbdata, nbp, offset)) {
return 0;
}
secp256k1_gej_add_var(r, r, &tmp, NULL);

View File

@@ -10,7 +10,9 @@
#include <stdint.h>
typedef struct {
/* X = sum(i=0..9, elem[i]*2^26) mod n */
/* X = sum(i=0..9, n[i]*2^(i*26)) mod p
* where p = 2^256 - 0x1000003D1
*/
uint32_t n[10];
#ifdef VERIFY
int magnitude;

View File

@@ -8,7 +8,6 @@
#define SECP256K1_FIELD_REPR_IMPL_H
#include "util.h"
#include "num.h"
#include "field.h"
#ifdef VERIFY
@@ -486,7 +485,8 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t
VERIFY_BITS(b[9], 26);
/** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n.
* px is a shorthand for sum(a[i]*b[x-i], i=0..x).
* for 0 <= x <= 9, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
* for 9 <= x <= 18, px is a shorthand for sum(a[i]*b[x-i], i=(x-9)..9)
* Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0].
*/
@@ -1069,6 +1069,7 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(r != b);
VERIFY_CHECK(a != b);
#endif
secp256k1_fe_mul_inner(r->n, a->n, b->n);
#ifdef VERIFY

View File

@@ -10,7 +10,9 @@
#include <stdint.h>
typedef struct {
/* X = sum(i=0..4, elem[i]*2^52) mod n */
/* X = sum(i=0..4, n[i]*2^(i*52)) mod p
* where p = 2^256 - 0x1000003D1
*/
uint64_t n[5];
#ifdef VERIFY
int magnitude;

View File

@@ -12,7 +12,6 @@
#endif
#include "util.h"
#include "num.h"
#include "field.h"
#if defined(USE_ASM_X86_64)
@@ -422,6 +421,7 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
secp256k1_fe_verify(a);
secp256k1_fe_verify(b);
VERIFY_CHECK(r != b);
VERIFY_CHECK(a != b);
#endif
secp256k1_fe_mul_inner(r->n, a->n, b->n);
#ifdef VERIFY

View File

@@ -32,9 +32,11 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t
VERIFY_BITS(b[3], 56);
VERIFY_BITS(b[4], 52);
VERIFY_CHECK(r != b);
VERIFY_CHECK(a != b);
/* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n.
* px is a shorthand for sum(a[i]*b[x-i], i=0..x).
* for 0 <= x <= 4, px is a shorthand for sum(a[i]*b[x-i], i=0..x).
* for 4 <= x <= 8, px is a shorthand for sum(a[i]*b[x-i], i=(x-4)..4)
* Note that [x 0 0 0 0 0] = [x*R].
*/

View File

@@ -12,6 +12,7 @@
#endif
#include "util.h"
#include "num.h"
#if defined(USE_FIELD_10X26)
#include "field_10x26_impl.h"
@@ -48,6 +49,8 @@ static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) {
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
int j;
VERIFY_CHECK(r != a);
/** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in
* { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block:
* 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223]

View File

@@ -38,22 +38,22 @@
*/
#if defined(EXHAUSTIVE_TEST_ORDER)
# if EXHAUSTIVE_TEST_ORDER == 199
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069,
0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18,
0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868,
0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED
);
const int CURVE_B = 4;
static const int CURVE_B = 4;
# elif EXHAUSTIVE_TEST_ORDER == 13
const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0,
0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15,
0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e,
0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac
);
const int CURVE_B = 2;
static const int CURVE_B = 2;
# else
# error No known generator for the specified exhaustive test group order.
# endif
@@ -68,7 +68,7 @@ static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(
0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL
);
const int CURVE_B = 7;
static const int CURVE_B = 7;
#endif
static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) {
@@ -175,6 +175,8 @@ static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp
/* The z of the final point gives us the "global Z" for the table. */
r[i].x = a[i].x;
r[i].y = a[i].y;
/* Ensure all y values are in weak normal form for fast negation of points */
secp256k1_fe_normalize_weak(&r[i].y);
*globalz = a[i].z;
r[i].infinity = 0;
zs = zr[i];

View File

@@ -131,7 +131,8 @@ static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) {
static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) {
size_t bufsize = hash->bytes & 0x3F;
hash->bytes += len;
while (bufsize + len >= 64) {
VERIFY_CHECK(hash->bytes >= len);
while (len >= 64 - bufsize) {
/* Fill the buffer, and process it. */
size_t chunk_len = 64 - bufsize;
memcpy(((unsigned char*)hash->buf) + bufsize, data, chunk_len);

View File

@@ -3,7 +3,6 @@ package org.bitcoin;
import com.google.common.io.BaseEncoding;
import java.util.Arrays;
import java.math.BigInteger;
import javax.xml.bind.DatatypeConverter;
import static org.bitcoin.NativeSecp256k1Util.*;
/**
@@ -70,7 +69,7 @@ public class NativeSecp256k1Test {
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
String pubkeyString = BaseEncoding.base16().encode(resultArr);
assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos");
}
@@ -81,7 +80,7 @@ public class NativeSecp256k1Test {
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
byte[] resultArr = NativeSecp256k1.computePubkey( sec);
String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
String pubkeyString = BaseEncoding.base16().encode(resultArr);
assertEquals( pubkeyString, "" , "testPubKeyCreateNeg");
}
@@ -94,7 +93,7 @@ public class NativeSecp256k1Test {
byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase());
byte[] resultArr = NativeSecp256k1.sign(data, sec);
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
String sigString = BaseEncoding.base16().encode(resultArr);
assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos");
}
@@ -106,7 +105,7 @@ public class NativeSecp256k1Test {
byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase());
byte[] resultArr = NativeSecp256k1.sign(data, sec);
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
String sigString = BaseEncoding.base16().encode(resultArr);
assertEquals( sigString, "" , "testSignNeg");
}
@@ -118,7 +117,7 @@ public class NativeSecp256k1Test {
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data );
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
String sigString = BaseEncoding.base16().encode(resultArr);
assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1");
}
@@ -130,7 +129,7 @@ public class NativeSecp256k1Test {
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data );
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
String sigString = BaseEncoding.base16().encode(resultArr);
assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1");
}
@@ -142,7 +141,7 @@ public class NativeSecp256k1Test {
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data );
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
String sigString = BaseEncoding.base16().encode(resultArr);
assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2");
}
@@ -154,7 +153,7 @@ public class NativeSecp256k1Test {
byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak"
byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data );
String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
String sigString = BaseEncoding.base16().encode(resultArr);
assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2");
}
@@ -173,7 +172,7 @@ public class NativeSecp256k1Test {
byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase());
byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub);
String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr);
String ecdhString = BaseEncoding.base16().encode(resultArr);
assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret");
}

View File

@@ -77,7 +77,7 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
/* Communication round 1: Exchange nonce commitments */
for (i = 0; i < N_SIGNERS; i++) {
/* Set nonce commitments in the signer data and get the own public nonce */
if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], &nonce[i], nonce_commitment_ptr, N_SIGNERS)) {
if (!secp256k1_musig_session_get_public_nonce(ctx, &musig_session[i], signer_data[i], &nonce[i], nonce_commitment_ptr, N_SIGNERS, NULL)) {
return 0;
}
}
@@ -119,7 +119,7 @@ int sign(const secp256k1_context* ctx, unsigned char seckeys[][32], const secp25
}
}
}
return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig, partial_sig, N_SIGNERS);
return secp256k1_musig_partial_sig_combine(ctx, &musig_session[0], sig, partial_sig, N_SIGNERS, NULL);
}
int main(void) {

View File

@@ -113,7 +113,7 @@ int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scrat
if (!secp256k1_musig_compute_ell(ctx, ecmult_data.ell, pubkeys, n_pubkeys)) {
return 0;
}
if (!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &pkj, NULL, secp256k1_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) {
if (!secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &pkj, NULL, secp256k1_musig_pubkey_combine_callback, (void *) &ecmult_data, n_pubkeys)) {
return 0;
}
secp256k1_ge_set_gej(&pkp, &pkj);
@@ -211,7 +211,7 @@ int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_m
return 1;
}
int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, secp256k1_pubkey *nonce, const unsigned char *const *commitments, size_t n_commitments) {
int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, secp256k1_pubkey *nonce, const unsigned char *const *commitments, size_t n_commitments, const unsigned char *msg32) {
secp256k1_sha256 sha;
unsigned char nonce_commitments_hash[32];
size_t i;
@@ -222,6 +222,10 @@ int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp2
ARG_CHECK(signers != NULL);
ARG_CHECK(nonce != NULL);
ARG_CHECK(commitments != NULL);
/* If the message was not set during initialization it must be set now. */
ARG_CHECK(!(!session->msg_is_set && msg32 == NULL));
/* The message can only be set once. */
ARG_CHECK(!(session->msg_is_set && msg32 != NULL));
if (!session->has_secret_data || n_commitments != session->n_signers) {
return 0;
@@ -230,6 +234,10 @@ int secp256k1_musig_session_get_public_nonce(const secp256k1_context* ctx, secp2
ARG_CHECK(commitments[i] != NULL);
}
if (msg32 != NULL) {
memcpy(session->msg, msg32, 32);
session->msg_is_set = 1;
}
secp256k1_sha256_initialize(&sha);
for (i = 0; i < n_commitments; i++) {
memcpy(signers[i].nonce_commitment, commitments[i], 32);
@@ -254,6 +262,7 @@ int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, se
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(signers != NULL);
ARG_CHECK(msg32 != NULL);
ARG_CHECK(combined_pk != NULL);
ARG_CHECK(pk_hash32 != NULL);
ARG_CHECK(commitments != NULL);
@@ -278,11 +287,8 @@ int secp256k1_musig_session_initialize_verifier(const secp256k1_context* ctx, se
memcpy(session->pk_hash, pk_hash32, 32);
session->nonce_is_set = 0;
session->msg_is_set = 0;
if (msg32 != NULL) {
memcpy(session->msg, msg32, 32);
session->msg_is_set = 1;
}
session->msg_is_set = 1;
memcpy(session->msg, msg32, 32);
session->has_secret_data = 0;
session->nonce_commitments_hash_is_set = 0;
@@ -373,19 +379,6 @@ int secp256k1_musig_session_combine_nonces(const secp256k1_context* ctx, secp256
return 1;
}
int secp256k1_musig_session_set_msg(const secp256k1_context* ctx, secp256k1_musig_session *session, const unsigned char *msg32) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(session != NULL);
ARG_CHECK(msg32 != NULL);
if (session->msg_is_set) {
return 0;
}
memcpy(session->msg, msg32, 32);
session->msg_is_set = 1;
return 1;
}
int secp256k1_musig_partial_signature_serialize(const secp256k1_context* ctx, unsigned char *out32, const secp256k1_musig_partial_signature* sig) {
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(out32 != NULL);
@@ -473,7 +466,7 @@ int secp256k1_musig_partial_sign(const secp256k1_context* ctx, const secp256k1_m
return 1;
}
int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs) {
int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp256k1_musig_session *session, secp256k1_schnorrsig *sig, const secp256k1_musig_partial_signature *partial_sigs, size_t n_sigs, const unsigned char *tweak32) {
size_t i;
secp256k1_scalar s;
secp256k1_ge noncep;
@@ -502,6 +495,25 @@ int secp256k1_musig_partial_sig_combine(const secp256k1_context* ctx, const secp
secp256k1_scalar_add(&s, &s, &term);
}
/* If there is a tweak then add `msghash` times `tweak` to `s`.*/
if (tweak32 != NULL) {
unsigned char msghash[32];
secp256k1_scalar e, scalar_tweak;
int overflow = 0;
if (!secp256k1_musig_compute_messagehash(ctx, msghash, session)) {
return 0;
}
secp256k1_scalar_set_b32(&e, msghash, NULL);
secp256k1_scalar_set_b32(&scalar_tweak, tweak32, &overflow);
if (overflow || !secp256k1_eckey_privkey_tweak_mul(&e, &scalar_tweak)) {
/* This mimics the behavior of secp256k1_ec_privkey_tweak_mul regarding
* overflow and tweak32 being 0. */
return 0;
}
secp256k1_scalar_add(&s, &s, &e);
}
secp256k1_pubkey_load(ctx, &noncep, &session->combined_nonce);
VERIFY_CHECK(secp256k1_fe_is_quad_var(&noncep.y));
secp256k1_fe_normalize(&noncep.x);

View File

@@ -14,7 +14,7 @@ The resulting signatures are valid Schnorr signatures as described in [2].
In MuSig all signers contribute key material to a single signing key,
using the equation
P = sum_i µ_i - P_i
P = sum_i µ_i * P_i
where `P_i` is the public key of the `i`th signer and `µ_i` is a so-called
_MuSig coefficient_ computed according to the following equation
@@ -91,6 +91,8 @@ signature process, which is also a supported mode) acts as follows.
length-32 byte arrays which can be communicated however is communicated.
3. Once all signers nonce commitments have been received, the signer records
these commitments with the function `secp256k1_musig_session_get_public_nonce`.
If the signer did not provide a message to `secp256k1_musig_session_initialize`,
a message must be provided now.
This function updates in place
- the session state `session`
- the array of signer data `signers`
@@ -111,9 +113,6 @@ signature process, which is also a supported mode) acts as follows.
- the array of signer data `signers`
It outputs an auxiliary integer `nonce_is_negated` and has an auxiliary input
`adaptor`. Both of these may be set to NULL for ordinary signing purposes.
If the signer did not provide a message to `secp256k1_musig_session_initialize`,
a message must be provided now by calling `secp256k1_musig_session_set_msg` which
updates the session state in place.
6. The signer computes a partial signature `s_i` using the function
`secp256k1_musig_partial_sign` which takes the session state as input and
partial signature as output.

View File

@@ -34,6 +34,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_pubkey combined_pk;
unsigned char pk_hash[32];
secp256k1_pubkey pk[2];
unsigned char tweak[32];
unsigned char sec_adaptor[32];
unsigned char sec_adaptor1[32];
@@ -60,6 +61,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_rand256(sk[1]);
secp256k1_rand256(msg);
secp256k1_rand256(sec_adaptor);
secp256k1_rand256(tweak);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1);
@@ -78,10 +80,10 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
/* pubkey_combine does not require a scratch space */
CHECK(secp256k1_musig_pubkey_combine(vrfy, NULL, &combined_pk, pk_hash, pk, 2) == 1);
CHECK(ecount == 2);
/* If a scratch space is given it shouldn't be too small */
/* A small scratch space works too, but will result in using an ineffecient algorithm */
scratch_small = secp256k1_scratch_space_create(ctx, 1);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, pk_hash, pk, 2) == 0);
secp256k1_scratch_space_destroy(scratch_small);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch_small, &combined_pk, pk_hash, pk, 2) == 1);
secp256k1_scratch_space_destroy(ctx, scratch_small);
CHECK(ecount == 2);
CHECK(secp256k1_musig_pubkey_combine(vrfy, scratch, NULL, pk_hash, pk, 2) == 0);
CHECK(ecount == 3);
@@ -134,13 +136,6 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, ones) == 0);
CHECK(ecount == 9);
{
secp256k1_musig_session session_without_msg;
CHECK(secp256k1_musig_session_initialize(sign, &session_without_msg, signer0, nonce_commitment[0], session_id[0], NULL, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_set_msg(none, &session_without_msg, msg) == 1);
CHECK(secp256k1_musig_session_set_msg(none, &session_without_msg, msg) == 0);
}
CHECK(secp256k1_musig_session_initialize(sign, &session[0], signer0, nonce_commitment[0], session_id[0], msg, &combined_pk, pk_hash, 2, 0, sk[0]) == 1);
CHECK(secp256k1_musig_session_initialize(sign, &session[1], signer1, nonce_commitment[1], session_id[1], msg, &combined_pk, pk_hash, 2, 1, sk[1]) == 1);
ncs[0] = nonce_commitment[0];
@@ -151,20 +146,20 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
CHECK(ecount == 0);
CHECK(secp256k1_musig_session_initialize_verifier(none, NULL, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, pk_hash, ncs, 2) == 1);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, pk_hash, ncs, 2) == 0);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, NULL, &combined_pk, pk_hash, ncs, 2) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, NULL, ncs, 2) == 0);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, NULL, pk_hash, ncs, 2) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, NULL, ncs, 2) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, NULL, 2) == 0);
CHECK(ecount == 4);
CHECK(ecount == 5);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 0) == 0);
CHECK(ecount == 4);
CHECK(ecount == 5);
if (SIZE_MAX > UINT32_MAX) {
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, ((size_t) UINT32_MAX) + 2) == 0);
}
CHECK(ecount == 4);
CHECK(ecount == 5);
CHECK(secp256k1_musig_session_initialize_verifier(none, &verifier_session, verifier_signer_data, msg, &combined_pk, pk_hash, ncs, 2) == 1);
CHECK(secp256k1_musig_compute_messagehash(none, msghash, &verifier_session) == 0);
@@ -176,7 +171,7 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
secp256k1_pubkey nonce;
/* Can obtain public nonce after commitments have been exchanged; still can't sign */
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &nonce, ncs, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &nonce, ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_partial_sign(none, &session[0], &partial_sig[0]) == 0);
CHECK(ecount == 0);
}
@@ -186,22 +181,22 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
{
secp256k1_pubkey public_nonce[3];
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2, NULL) == 1);
CHECK(ecount == 0);
CHECK(secp256k1_musig_session_get_public_nonce(none, NULL, signer0, &public_nonce[0], ncs, 2) == 0);
CHECK(secp256k1_musig_session_get_public_nonce(none, NULL, signer0, &public_nonce[0], ncs, 2, NULL) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], NULL, &public_nonce[0], ncs, 2) == 0);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], NULL, &public_nonce[0], ncs, 2, NULL) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, NULL, ncs, 2) == 0);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, NULL, ncs, 2, NULL) == 0);
CHECK(ecount == 3);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], NULL, 2) == 0);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], NULL, 2, NULL) == 0);
CHECK(ecount == 4);
/* Number of commitments and number of signers are different */
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 1) == 0);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 1, NULL) == 0);
CHECK(ecount == 4);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[1], signer1, &public_nonce[1], ncs, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[0], signer0, &public_nonce[0], ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(none, &session[1], signer1, &public_nonce[1], ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_set_nonce(none, &signer0[0], &public_nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(none, &signer0[1], &public_nonce[0]) == 0);
@@ -311,27 +306,36 @@ void musig_api_tests(secp256k1_scratch_space *scratch) {
/** Signing combining and verification */
ecount = 0;
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2) == 1);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2) == 1);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2, NULL) == 1);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2, NULL) == 1);
CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2) == 1);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig_cmp, partial_sig_adapted, 2, NULL) == 1);
CHECK(memcmp(&final_sig, &final_sig_cmp, sizeof(final_sig)) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, NULL, &final_sig, partial_sig_adapted, 2) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, NULL, &final_sig, partial_sig_adapted, 2, tweak) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], NULL, partial_sig_adapted, 2, tweak) == 0);
CHECK(ecount == 2);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, NULL, 2) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, NULL, 2, tweak) == 0);
CHECK(ecount == 3);
{
secp256k1_musig_partial_signature partial_sig_tmp[2];
partial_sig_tmp[0] = partial_sig_adapted[0];
partial_sig_tmp[1] = partial_sig_overflow;
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_tmp, 2) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_tmp, 2, tweak) == 0);
}
CHECK(ecount == 3);
/* Wrong number of partial sigs */
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 1) == 0);
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 1, tweak) == 0);
CHECK(ecount == 3);
{
/* Overflowing tweak */
unsigned char overflowing_tweak[32];
memset(overflowing_tweak, 0xff, sizeof(overflowing_tweak));
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2, overflowing_tweak) == 0);
CHECK(ecount == 3);
}
CHECK(secp256k1_musig_partial_sig_combine(none, &session[0], &final_sig, partial_sig_adapted, 2, NULL) == 1);
CHECK(ecount == 3);
CHECK(secp256k1_schnorrsig_verify(vrfy, &final_sig, msg, &combined_pk) == 1);
@@ -393,14 +397,14 @@ int musig_state_machine_diff_signer_msghash_test(unsigned char *msghash, secp256
pks_tmp[0] = pks[0];
CHECK(secp256k1_ec_pubkey_create(ctx, &pks_tmp[1], sk_dummy) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, NULL, &combined_pk_tmp, pk_hash_tmp, pks_tmp, 2) == 1);
CHECK(secp256k1_musig_session_initialize(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, pk_hash_tmp, 2, 0, sk_dummy) == 1);
CHECK(secp256k1_musig_session_initialize(ctx, &session_tmp, signers_tmp, nonce_commitment, session_id, msg, &combined_pk_tmp, pk_hash_tmp, 2, 1, sk_dummy) == 1);
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1);
CHECK(memcmp(nonce_commitment, nonce_commitments[1], 32) == 0);
/* Call get_public_nonce with different signers than the signers the session was
* initialized with. */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session_tmp, signers, &nonce, nonce_commitments, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers_tmp, &nonce, nonce_commitments, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session_tmp, signers, &nonce, nonce_commitments, 2, NULL) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers_tmp, &nonce, nonce_commitments, 2, NULL) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
@@ -427,7 +431,7 @@ int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_pubkey *combin
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 1, sk) == 1);
ncs[0] = nonce_commitment_other;
ncs[1] = nonce_commitment;
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1);
@@ -440,34 +444,44 @@ int musig_state_machine_diff_signers_combine_nonce_test(secp256k1_pubkey *combin
return secp256k1_musig_session_combine_nonces(ctx, &session, signers_to_use, 2, NULL, NULL);
}
/* Recreates a session with the given session_id, signers, pk, msg etc. parameters
* and tries to sign and verify the other signers partial signature. Both should fail
* if msg is NULL. */
int musig_state_machine_missing_msg_test(secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, secp256k1_musig_partial_signature *partial_sig_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) {
/* Initializaes a session with the given session_id, signers, pk, msg etc.
* parameters but without a message. Will test that the message must be
* provided with `get_public_nonce`.
*/
void musig_state_machine_late_msg_test(secp256k1_pubkey *pks, secp256k1_pubkey *combined_pk, unsigned char *pk_hash, unsigned char *nonce_commitment_other, secp256k1_pubkey *nonce_other, unsigned char *sk, unsigned char *session_id, unsigned char *msg) {
/* Create context for testing ARG_CHECKs by setting an illegal_callback. */
secp256k1_context *ctx_tmp = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
int ecount = 0;
secp256k1_musig_session session;
secp256k1_musig_session_signer_data signers[2];
unsigned char nonce_commitment[32];
const unsigned char *ncs[2];
secp256k1_pubkey nonce;
secp256k1_musig_partial_signature partial_sig;
int partial_sign, partial_verify;
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1);
secp256k1_context_set_illegal_callback(ctx_tmp, counting_illegal_callback_fn, &ecount);
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, NULL, combined_pk, pk_hash, 2, 1, sk) == 1);
ncs[0] = nonce_commitment_other;
ncs[1] = nonce_commitment;
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1);
/* Trying to get the nonce without providing a message fails. */
CHECK(ecount == 0);
CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session, signers, &nonce, ncs, 2, NULL) == 0);
CHECK(ecount == 1);
/* Providing a message should make get_public_nonce succeed. */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2, msg) == 1);
/* Trying to set the message again fails. */
CHECK(ecount == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx_tmp, &session, signers, &nonce, ncs, 2, msg) == 0);
CHECK(ecount == 2);
/* Check that it's working */
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
partial_sign = secp256k1_musig_partial_sign(ctx, &session, &partial_sig);
partial_verify = secp256k1_musig_partial_sig_verify(ctx, &session, &signers[0], partial_sig_other, &pks[0]);
if (msg != NULL) {
/* Return 1 if both succeeded */
return partial_sign && partial_verify;
}
/* Return 0 if both failed */
return partial_sign || partial_verify;
CHECK(secp256k1_musig_partial_sign(ctx, &session, &partial_sig));
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session, &signers[1], &partial_sig, &pks[1]));
}
/* Recreates a session with the given session_id, signers, pk, msg etc. parameters
@@ -484,10 +498,10 @@ int musig_state_machine_missing_combine_test(secp256k1_pubkey *pks, secp256k1_pu
secp256k1_schnorrsig sig;
int partial_verify, sig_combine;
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 0, sk) == 1);
CHECK(secp256k1_musig_session_initialize(ctx, &session, signers, nonce_commitment, session_id, msg, combined_pk, pk_hash, 2, 1, sk) == 1);
ncs[0] = nonce_commitment_other;
ncs[1] = nonce_commitment;
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session, signers, &nonce, ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[0], nonce_other) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers[1], &nonce) == 1);
@@ -497,7 +511,7 @@ int musig_state_machine_missing_combine_test(secp256k1_pubkey *pks, secp256k1_pu
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session, signers, 2, NULL, NULL) == 1);
}
partial_verify = secp256k1_musig_partial_sig_verify(ctx, &session, signers, partial_sig_other, &pks[0]);
sig_combine = secp256k1_musig_partial_sig_combine(ctx, &session, &sig, partial_sigs, 2);
sig_combine = secp256k1_musig_partial_sig_combine(ctx, &session, &sig, partial_sigs, 2, NULL);
if (do_combine != 0) {
/* Return 1 if both succeeded */
return partial_verify && sig_combine;
@@ -542,16 +556,16 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
/* Set nonce commitments */
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2, NULL) == 1);
/* Changing a nonce commitment is not okay */
ncs[1] = (unsigned char*) "this isn't a nonce commitment...";
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 0);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2, NULL) == 0);
/* Repeating with the same nonce commitments is okay */
ncs[1] = nonce_commitment[1];
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2, NULL) == 1);
/* Get nonce for signer 1 */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, &nonce[1], ncs, 2) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, &nonce[1], ncs, 2, NULL) == 1);
/* Set nonces */
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[0], &nonce[0]) == 1);
@@ -586,12 +600,12 @@ void musig_state_machine_tests(secp256k1_scratch_space *scratch) {
CHECK(musig_state_machine_diff_signer_msghash_test(msghash2, pk, &combined_pk, pk_hash, ncs, msg, &nonce[0], sk[1], session_id[1]) == 1);
CHECK(memcmp(msghash1, msghash2, 32) == 0);
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[1], &pk[1]) == 1);
/* Wrong signature */
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[1], &partial_sig[0], &pk[1]) == 0);
/* Can't sign or verify until msg is set */
CHECK(musig_state_machine_missing_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], sk[1], session_id[1], NULL) == 0);
CHECK(musig_state_machine_missing_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], sk[1], session_id[1], msg) == 1);
/* Can't get the public nonce until msg is set */
musig_state_machine_late_msg_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], sk[1], session_id[1], msg);
/* Can't verify and combine partial sigs until nonces are combined */
CHECK(musig_state_machine_missing_combine_test(pk, &combined_pk, pk_hash, nonce_commitment[0], &nonce[0], &partial_sig[0], msg, sk[1], session_id[1], &partial_sig[1], 0) == 0);
@@ -665,10 +679,10 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
noncommit_b_ptr[1] = noncommit_b[1];
/* Step 2: Exchange nonces */
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[0], data_a, &pubnon_a[0], noncommit_a_ptr, 2));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[1], data_a, &pubnon_a[1], noncommit_a_ptr, 2));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[0], data_b, &pubnon_b[0], noncommit_b_ptr, 2));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[1], data_b, &pubnon_b[1], noncommit_b_ptr, 2));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[0], data_a, &pubnon_a[0], noncommit_a_ptr, 2, NULL));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_a[1], data_a, &pubnon_a[1], noncommit_a_ptr, 2, NULL));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[0], data_b, &pubnon_b[0], noncommit_b_ptr, 2, NULL));
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &musig_session_b[1], data_b, &pubnon_b[1], noncommit_b_ptr, 2, NULL));
CHECK(secp256k1_musig_set_nonce(ctx, &data_a[0], &pubnon_a[0]));
CHECK(secp256k1_musig_set_nonce(ctx, &data_a[1], &pubnon_a[1]));
CHECK(secp256k1_musig_set_nonce(ctx, &data_b[0], &pubnon_b[0]));
@@ -693,7 +707,7 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
* is broadcasted by signer 0 to take B-coins. */
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_b_adapted[0], &partial_sig_b[0], sec_adaptor, nonce_is_negated_b));
memcpy(&partial_sig_b_adapted[1], &partial_sig_b[1], sizeof(partial_sig_b_adapted[1]));
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], &final_sig_b, partial_sig_b_adapted, 2) == 1);
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_b[0], &final_sig_b, partial_sig_b_adapted, 2, NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig_b, msg32_b, &combined_pk_b) == 1);
/* Step 6: Signer 1 extracts adaptor from the published signature, applies it to
@@ -702,7 +716,7 @@ void scriptless_atomic_swap(secp256k1_scratch_space *scratch) {
CHECK(memcmp(sec_adaptor_extracted, sec_adaptor, sizeof(sec_adaptor)) == 0); /* in real life we couldn't check this, of course */
CHECK(secp256k1_musig_partial_sig_adapt(ctx, &partial_sig_a[0], &partial_sig_a[0], sec_adaptor_extracted, nonce_is_negated_a));
CHECK(secp256k1_musig_partial_sign(ctx, &musig_session_a[1], &partial_sig_a[1]));
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], &final_sig_a, partial_sig_a, 2) == 1);
CHECK(secp256k1_musig_partial_sig_combine(ctx, &musig_session_a[1], &final_sig_a, partial_sig_a, 2, NULL) == 1);
CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig_a, msg32_a, &combined_pk_a) == 1);
}
@@ -739,6 +753,89 @@ void sha256_tag_test(void) {
CHECK(memcmp(buf, buf2, 32) == 0);
}
void musig_tweak_test_helper(const secp256k1_pubkey* combined_pubkey, const unsigned char *ec_commit_tweak, const unsigned char *sk0, const unsigned char *sk1, const unsigned char *pk_hash) {
secp256k1_musig_session session[2];
secp256k1_musig_session_signer_data signers0[2];
secp256k1_musig_session_signer_data signers1[2];
secp256k1_pubkey pk[2];
unsigned char session_id[2][32];
unsigned char msg[32];
unsigned char nonce_commitment[2][32];
secp256k1_pubkey nonce[2];
const unsigned char *ncs[2];
secp256k1_musig_partial_signature partial_sig[2];
secp256k1_schnorrsig final_sig;
secp256k1_rand256(session_id[0]);
secp256k1_rand256(session_id[1]);
secp256k1_rand256(msg);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk0) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk1) == 1);
/* want to show that can both sign for Q and P */
CHECK(secp256k1_musig_session_initialize(ctx, &session[0], signers0, nonce_commitment[0], session_id[0], msg, combined_pubkey, pk_hash, 2, 0, sk0) == 1);
CHECK(secp256k1_musig_session_initialize(ctx, &session[1], signers1, nonce_commitment[1], session_id[1], msg, combined_pubkey, pk_hash, 2, 1, sk1) == 1);
/* Set nonce commitments */
ncs[0] = nonce_commitment[0];
ncs[1] = nonce_commitment[1];
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[0], signers0, &nonce[0], ncs, 2, NULL) == 1);
CHECK(secp256k1_musig_session_get_public_nonce(ctx, &session[1], signers1, &nonce[1], ncs, 2, NULL) == 1);
/* Set nonces */
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[0], &nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers0[1], &nonce[1]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[0], &nonce[0]) == 1);
CHECK(secp256k1_musig_set_nonce(ctx, &signers1[1], &nonce[1]) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[0], signers0, 2, NULL, NULL) == 1);
CHECK(secp256k1_musig_session_combine_nonces(ctx, &session[1], signers1, 2, NULL, NULL) == 1);
CHECK(secp256k1_musig_partial_sign(ctx, &session[0], &partial_sig[0]) == 1);
CHECK(secp256k1_musig_partial_sign(ctx, &session[1], &partial_sig[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[0], &signers0[1], &partial_sig[1], &pk[1]) == 1);
CHECK(secp256k1_musig_partial_sig_verify(ctx, &session[1], &signers1[0], &partial_sig[0], &pk[0]) == 1);
CHECK(secp256k1_musig_partial_sig_combine(ctx, &session[0], &final_sig, partial_sig, 2, ec_commit_tweak));
CHECK(secp256k1_schnorrsig_verify(ctx, &final_sig, msg, combined_pubkey) == 1);
}
/* In this test we create a combined public key P and a commitment Q = P +
* hash(P, contract)*G. Then we test that we can sign for both public keys. In
* order to sign for Q we use the tweak32 argument of partial_sig_combine. */
void musig_tweak_test(secp256k1_scratch_space *scratch) {
unsigned char sk[2][32];
secp256k1_pubkey pk[2];
unsigned char pk_hash[32];
secp256k1_pubkey P;
unsigned char P_serialized[33];
size_t compressed_size = 33;
secp256k1_pubkey Q;
secp256k1_sha256 sha;
unsigned char contract[32];
unsigned char ec_commit_tweak[32];
/* Setup */
secp256k1_rand256(sk[0]);
secp256k1_rand256(sk[1]);
secp256k1_rand256(contract);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[0], sk[0]) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, &pk[1], sk[1]) == 1);
CHECK(secp256k1_musig_pubkey_combine(ctx, scratch, &P, pk_hash, pk, 2) == 1);
CHECK(secp256k1_ec_pubkey_serialize(ctx, P_serialized, &compressed_size, &P, SECP256K1_EC_COMPRESSED) == 1);
secp256k1_sha256_initialize(&sha);
secp256k1_sha256_write(&sha, P_serialized, 33);
secp256k1_sha256_write(&sha, contract, 32);
secp256k1_sha256_finalize(&sha, ec_commit_tweak);
memcpy(&Q, &P, sizeof(secp256k1_pubkey));
CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &Q, ec_commit_tweak));
/* Test signing for P */
musig_tweak_test_helper(&P, NULL, sk[0], sk[1], pk_hash);
/* Test signing for Q */
musig_tweak_test_helper(&Q, ec_commit_tweak, sk[0], sk[1], pk_hash);
}
void run_musig_tests(void) {
int i;
secp256k1_scratch_space *scratch = secp256k1_scratch_space_create(ctx, 1024 * 1024);
@@ -750,8 +847,9 @@ void run_musig_tests(void) {
scriptless_atomic_swap(scratch);
}
sha256_tag_test();
musig_tweak_test(scratch);
secp256k1_scratch_space_destroy(scratch);
secp256k1_scratch_space_destroy(ctx, scratch);
}
#endif

View File

@@ -14,10 +14,15 @@
#include "modules/rangeproof/rangeproof_impl.h"
/** Alternative generator for secp256k1.
* This is the sha256 of 'g' after DER encoding (without compression),
* which happens to be a point on the curve.
* sage: G2 = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256('0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'.decode('hex')).hexdigest(),16)))
* sage: '%x %x' % G2.xy()
* This is the sha256 of 'g' after standard encoding (without compression),
* which happens to be a point on the curve. More precisely, the generator is
* derived by running the following script with the sage mathematics software.
import hashlib
F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F)
G = '0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'
H = EllipticCurve ([F (0), F (7)]).lift_x(F(int(hashlib.sha256(G.decode('hex')).hexdigest(),16)))
print('%x %x' % H.xy())
*/
static const secp256k1_generator secp256k1_generator_h_internal = {{
0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, 0x5e,

View File

@@ -147,7 +147,7 @@ int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecd
break;
}
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
if (!overflow && !secp256k1_scalar_is_zero(&non)) {
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
break;
}

View File

@@ -240,7 +240,7 @@ static int secp256k1_schnorrsig_verify_batch_ecmult_callback(secp256k1_scalar *s
* pk: array of public keys, or NULL if there are no signatures
* n_sigs: number of signatures in above arrays (must be 0 if they are NULL)
*/
int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *ctx, secp256k1_schnorrsig_verify_ecmult_context *ecmult_context, secp256k1_sha256 *sha, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) {
static int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *ctx, secp256k1_schnorrsig_verify_ecmult_context *ecmult_context, secp256k1_sha256 *sha, const secp256k1_schnorrsig *const *sig, const unsigned char *const *msg32, const secp256k1_pubkey *const *pk, size_t n_sigs) {
size_t i;
if (n_sigs > 0) {
@@ -255,7 +255,7 @@ int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *c
secp256k1_sha256_write(sha, sig[i]->data, 64);
secp256k1_sha256_write(sha, msg32[i], 32);
secp256k1_ec_pubkey_serialize(ctx, buf, &buflen, pk[i], SECP256K1_EC_COMPRESSED);
secp256k1_sha256_write(sha, buf, 32);
secp256k1_sha256_write(sha, buf, buflen);
}
ecmult_context->ctx = ctx;
ecmult_context->sig = sig;
@@ -276,7 +276,7 @@ int secp256k1_schnorrsig_verify_batch_init_randomizer(const secp256k1_context *c
* sig: array of signatures, or NULL if there are no signatures
* n_sigs: number of signatures in above array (must be 0 if they are NULL)
*/
int secp256k1_schnorrsig_verify_batch_sum_s(secp256k1_scalar *s, unsigned char *chacha_seed, const secp256k1_schnorrsig *const *sig, size_t n_sigs) {
static int secp256k1_schnorrsig_verify_batch_sum_s(secp256k1_scalar *s, unsigned char *chacha_seed, const secp256k1_schnorrsig *const *sig, size_t n_sigs) {
secp256k1_scalar randomizer_cache[2];
size_t i;
@@ -316,7 +316,7 @@ int secp256k1_schnorrsig_verify_batch(const secp256k1_context *ctx, secp256k1_sc
ARG_CHECK(n_sigs <= SIZE_MAX / 2);
/* Check that n_sigs is less than 2^31 to ensure the same behavior of this function on 32-bit
* and 64-bit platforms. */
ARG_CHECK(n_sigs < (size_t)(1 << 31));
ARG_CHECK(n_sigs < ((uint32_t)1 << 31));
secp256k1_sha256_initialize(&sha);
if (!secp256k1_schnorrsig_verify_batch_init_randomizer(ctx, &ecmult_context, &sha, sig, msg32, pk, n_sigs)) {
@@ -331,7 +331,7 @@ int secp256k1_schnorrsig_verify_batch(const secp256k1_context *ctx, secp256k1_sc
}
secp256k1_scalar_negate(&s, &s);
return secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &rj, &s, secp256k1_schnorrsig_verify_batch_ecmult_callback, (void *) &ecmult_context, 2 * n_sigs)
return secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &rj, &s, secp256k1_schnorrsig_verify_batch_ecmult_callback, (void *) &ecmult_context, 2 * n_sigs)
&& secp256k1_gej_is_infinity(&rj);
}

View File

@@ -119,7 +119,7 @@ void test_schnorrsig_api(secp256k1_scratch_space *scratch) {
CHECK(ecount == 5);
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, (size_t)1 << (sizeof(size_t)*8-1)) == 0);
CHECK(ecount == 6);
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, 1 << 31) == 0);
CHECK(secp256k1_schnorrsig_verify_batch(vrfy, scratch, &sigptr, &msgptr, &pkptr, (uint32_t)1 << 31) == 0);
CHECK(ecount == 7);
secp256k1_context_destroy(none);
@@ -720,7 +720,7 @@ void run_schnorrsig_tests(void) {
test_schnorrsig_sign();
test_schnorrsig_sign_verify(scratch);
secp256k1_scratch_space_destroy(scratch);
secp256k1_scratch_space_destroy(ctx, scratch);
}
#endif

View File

@@ -9,11 +9,20 @@
#include <assert.h>
#include <string.h>
#if defined HAVE_CONFIG_H
#include "libsecp256k1-config.h"
#endif
#include "include/secp256k1_rangeproof.h"
#include "include/secp256k1_surjectionproof.h"
#include "modules/rangeproof/borromean.h"
#include "modules/surjection/surjection_impl.h"
#include "hash.h"
#include "include/secp256k1_rangeproof.h"
#include "include/secp256k1_surjectionproof.h"
#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE
#undef SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS
#define SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS 16
#endif
static size_t secp256k1_count_bits_set(const unsigned char* data, size_t count) {
size_t ret = 0;
@@ -35,6 +44,9 @@ static size_t secp256k1_count_bits_set(const unsigned char* data, size_t count)
return ret;
}
#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE
static
#endif
int secp256k1_surjectionproof_parse(const secp256k1_context* ctx, secp256k1_surjectionproof *proof, const unsigned char *input, size_t inputlen) {
size_t n_inputs;
size_t signature_len;
@@ -55,6 +67,15 @@ int secp256k1_surjectionproof_parse(const secp256k1_context* ctx, secp256k1_surj
return 0;
}
/* Check that the bitvector of used inputs is of the claimed
* length; i.e. the final byte has no "padding bits" set */
if (n_inputs % 8 != 0) {
const unsigned char padding_mask = (~0U) << (n_inputs % 8);
if ((input[2 + (n_inputs + 7) / 8 - 1] & padding_mask) != 0) {
return 0;
}
}
signature_len = 32 * (1 + secp256k1_count_bits_set(&input[2], (n_inputs + 7) / 8));
if (inputlen != 2 + (n_inputs + 7) / 8 + signature_len) {
return 0;
@@ -151,6 +172,48 @@ static size_t secp256k1_surjectionproof_csprng_next(secp256k1_surjectionproof_cs
}
}
/* While '_allocate_initialized' may be a wordy suffix for this function, and '_create'
* may have been more appropriate, '_create' could be confused with '_generate',
* as the meanings for the words are close. Therefore, more wordy, but less
* ambiguous suffix was chosen. */
int secp256k1_surjectionproof_allocate_initialized(const secp256k1_context* ctx, secp256k1_surjectionproof** proof_out_p, size_t *input_index, const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) {
int ret = 0;
secp256k1_surjectionproof* proof;
VERIFY_CHECK(ctx != NULL);
ARG_CHECK(proof_out_p != NULL);
*proof_out_p = 0;
proof = (secp256k1_surjectionproof*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_surjectionproof));
if (proof != NULL) {
ret = secp256k1_surjectionproof_initialize(ctx, proof, input_index, fixed_input_tags, n_input_tags, n_input_tags_to_use, fixed_output_tag, n_max_iterations, random_seed32);
if (ret) {
*proof_out_p = proof;
}
else {
free(proof);
}
}
return ret;
}
/* secp256k1_surjectionproof structure may also be allocated on the stack,
* and initialized explicitly via secp256k1_surjectionproof_initialize().
* Supplying stack-allocated struct to _destroy() will result in calling
* free() with the pointer that points at the stack, with disasterous
* consequences. Thus, it is not advised to mix heap- and stack-allocating
* approaches to working with this struct. It is possible to detect this
* situation by using additional field in the struct that can be set to
* special value depending on the allocation path, and check it here.
* But currently, it is not seen as big enough concern to warrant this extra code .*/
void secp256k1_surjectionproof_destroy(secp256k1_surjectionproof* proof) {
if (proof != NULL) {
VERIFY_CHECK(proof->n_inputs <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
free(proof);
}
}
int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1_surjectionproof* proof, size_t *input_index, const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) {
secp256k1_surjectionproof_csprng csprng;
size_t n_iterations = 0;
@@ -162,6 +225,7 @@ int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1
ARG_CHECK(fixed_output_tag != NULL);
ARG_CHECK(random_seed32 != NULL);
ARG_CHECK(n_input_tags <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
ARG_CHECK(n_input_tags_to_use <= SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS);
ARG_CHECK(n_input_tags_to_use <= n_input_tags);
(void) ctx;
@@ -219,10 +283,8 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
size_t n_total_pubkeys;
size_t n_used_pubkeys;
size_t ring_input_index = 0;
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
secp256k1_ge inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
secp256k1_ge output;
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
unsigned char msg32[32];
VERIFY_CHECK(ctx != NULL);
@@ -261,17 +323,14 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
return 0;
}
secp256k1_generator_load(&output, ephemeral_output_tag);
for (i = 0; i < n_total_pubkeys; i++) {
secp256k1_generator_load(&inputs[i], &ephemeral_input_tags[i]);
if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, ephemeral_input_tags, n_total_pubkeys, proof->used_inputs, ephemeral_output_tag, input_index, &ring_input_index) == 0) {
return 0;
}
secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, input_index, &ring_input_index);
/* Produce signature */
rsizes[0] = (int) n_used_pubkeys;
indices[0] = (int) ring_input_index;
secp256k1_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output);
secp256k1_surjection_genmessage(msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag);
if (secp256k1_surjection_genrand(borromean_s, n_used_pubkeys, &blinding_key) == 0) {
return 0;
}
@@ -289,15 +348,16 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
return 1;
}
#ifdef USE_REDUCED_SURJECTION_PROOF_SIZE
static
#endif
int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256k1_surjectionproof* proof, const secp256k1_generator* ephemeral_input_tags, size_t n_ephemeral_input_tags, const secp256k1_generator* ephemeral_output_tag) {
size_t rsizes[1]; /* array needed for borromean sig API */
size_t i;
size_t n_total_pubkeys;
size_t n_used_pubkeys;
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
secp256k1_ge inputs[SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS];
secp256k1_ge output;
secp256k1_gej ring_pubkeys[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
secp256k1_scalar borromean_s[SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS];
unsigned char msg32[32];
VERIFY_CHECK(ctx != NULL);
@@ -313,12 +373,12 @@ int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256
return 0;
}
secp256k1_generator_load(&output, ephemeral_output_tag);
for (i = 0; i < n_total_pubkeys; i++) {
secp256k1_generator_load(&inputs[i], &ephemeral_input_tags[i]);
/* Reject proofs with too many used inputs in USE_REDUCED_SURJECTION_PROOF_SIZE mode */
if (n_used_pubkeys > SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS) {
return 0;
}
if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, inputs, n_total_pubkeys, proof->used_inputs, &output, 0, NULL) == 0) {
if (secp256k1_surjection_compute_public_keys(ring_pubkeys, n_used_pubkeys, ephemeral_input_tags, n_total_pubkeys, proof->used_inputs, ephemeral_output_tag, 0, NULL) == 0) {
return 0;
}
@@ -331,7 +391,7 @@ int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256
return 0;
}
}
secp256k1_surjection_genmessage(msg32, inputs, n_total_pubkeys, &output);
secp256k1_surjection_genmessage(msg32, ephemeral_input_tags, n_total_pubkeys, ephemeral_output_tag);
return secp256k1_borromean_verify(&ctx->ecmult_ctx, NULL, &proof->data[0], borromean_s, ring_pubkeys, rsizes, 1, msg32, 32);
}

View File

@@ -15,7 +15,7 @@
#include "scalar.h"
#include "hash.h"
SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg32, secp256k1_ge *ephemeral_input_tags, size_t n_input_tags, secp256k1_ge *ephemeral_output_tag) {
SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg32, const secp256k1_generator *ephemeral_input_tags, size_t n_input_tags, const secp256k1_generator *ephemeral_output_tag) {
/* compute message */
size_t i;
unsigned char pk_ser[33];
@@ -24,12 +24,12 @@ SECP256K1_INLINE static void secp256k1_surjection_genmessage(unsigned char *msg3
secp256k1_sha256_initialize(&sha256_en);
for (i = 0; i < n_input_tags; i++) {
secp256k1_eckey_pubkey_serialize(&ephemeral_input_tags[i], pk_ser, &pk_len, 1);
assert(pk_len == sizeof(pk_ser));
pk_ser[0] = 2 + (ephemeral_input_tags[i].data[63] & 1);
memcpy(&pk_ser[1], &ephemeral_input_tags[i].data[0], 32);
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
}
secp256k1_eckey_pubkey_serialize(ephemeral_output_tag, pk_ser, &pk_len, 1);
assert(pk_len == sizeof(pk_ser));
pk_ser[0] = 2 + (ephemeral_output_tag->data[63] & 1);
memcpy(&pk_ser[1], &ephemeral_output_tag->data[0], 32);
secp256k1_sha256_write(&sha256_en, pk_ser, pk_len);
secp256k1_sha256_finalize(&sha256_en, msg32);
}
@@ -61,24 +61,29 @@ SECP256K1_INLINE static int secp256k1_surjection_genrand(secp256k1_scalar *s, si
return 1;
}
SECP256K1_INLINE static int secp256k1_surjection_compute_public_keys(secp256k1_gej *pubkeys, size_t n_pubkeys, const secp256k1_ge *input_tags, size_t n_input_tags, const unsigned char *used_tags, const secp256k1_ge *output_tag, size_t input_index, size_t *ring_input_index) {
SECP256K1_INLINE static int secp256k1_surjection_compute_public_keys(secp256k1_gej *pubkeys, size_t n_pubkeys, const secp256k1_generator *input_tags, size_t n_input_tags, const unsigned char *used_tags, const secp256k1_generator *output_tag, size_t input_index, size_t *ring_input_index) {
size_t i;
size_t j = 0;
for (i = 0; i < n_input_tags; i++) {
if (used_tags[i / 8] & (1 << (i % 8))) {
secp256k1_ge tmpge;
secp256k1_ge_neg(&tmpge, &input_tags[i]);
secp256k1_generator_load(&tmpge, &input_tags[i]);
secp256k1_ge_neg(&tmpge, &tmpge);
VERIFY_CHECK(j < SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS);
VERIFY_CHECK(j < n_pubkeys);
secp256k1_gej_set_ge(&pubkeys[j], &tmpge);
secp256k1_gej_add_ge_var(&pubkeys[j], &pubkeys[j], output_tag, NULL);
secp256k1_generator_load(&tmpge, output_tag);
secp256k1_gej_add_ge_var(&pubkeys[j], &pubkeys[j], &tmpge, NULL);
if (ring_input_index != NULL && input_index == i) {
*ring_input_index = j;
}
j++;
if (j > n_pubkeys) {
return 0;
}
}
}
/* Caller needs to ensure that the number of set bits in used_tags (which we counted in j) equals n_pubkeys. */
VERIFY_CHECK(j == n_pubkeys);
return 1;
}

View File

@@ -28,6 +28,7 @@ static void test_surjectionproof_api(void) {
unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX];
size_t serialized_len;
secp256k1_surjectionproof proof;
secp256k1_surjectionproof* proof_on_heap;
size_t n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]);
size_t input_index;
int32_t ecount = 0;
@@ -52,6 +53,46 @@ static void test_surjectionproof_api(void) {
memcpy(&fixed_output_tag, &fixed_input_tags[0], sizeof(fixed_input_tags[0]));
CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, output_blinding_key));
/* check allocate_initialized */
CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0);
CHECK(proof_on_heap == 0);
CHECK(ecount == 0);
CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0);
CHECK(proof_on_heap != 0);
secp256k1_surjectionproof_destroy(proof_on_heap);
CHECK(ecount == 0);
CHECK(secp256k1_surjectionproof_allocate_initialized(none, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0);
CHECK(ecount == 1);
CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0);
CHECK(proof_on_heap == 0);
CHECK(ecount == 2);
CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0);
CHECK(proof_on_heap == 0);
CHECK(ecount == 3);
CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed) == 0);
CHECK(proof_on_heap == 0);
CHECK(ecount == 4);
CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], 100, seed) != 0);
CHECK(proof_on_heap != 0);
secp256k1_surjectionproof_destroy(proof_on_heap);
CHECK(ecount == 4);
CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed) == 0);
CHECK(proof_on_heap == 0);
CHECK(ecount == 5);
CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed) == 0);
CHECK(proof_on_heap == 0);
CHECK(ecount == 6);
CHECK((secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 0, seed) & 1) == 0);
CHECK(proof_on_heap == 0);
CHECK(ecount == 6);
CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL) == 0);
CHECK(proof_on_heap == 0);
CHECK(ecount == 7);
/* we are now going to test essentially the same functions, just without heap allocation.
* reset ecount. */
ecount = 0;
/* check initialize */
CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0);
CHECK(ecount == 0);
@@ -381,11 +422,12 @@ static void test_gen_verify(size_t n_inputs, size_t n_used) {
/* trailing garbage */
memcpy(&serialized_proof_trailing, &serialized_proof, serialized_len);
serialized_proof_trailing[serialized_len] = seed[0];
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len + 1) == 0);
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof_trailing, serialized_len + 1) == 0);
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len));
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs]);
CHECK(result == 1);
/* various fail cases */
if (n_inputs > 1) {
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]);
@@ -400,6 +442,15 @@ static void test_gen_verify(size_t n_inputs, size_t n_used) {
n_inputs += 1;
}
for (i = 0; i < n_inputs; i++) {
/* flip bit */
proof.used_inputs[i / 8] ^= (1 << (i % 8));
result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs]);
CHECK(result == 0);
/* reset the bit */
proof.used_inputs[i / 8] ^= (1 << (i % 8));
}
/* cleanup */
for (i = 0; i < n_inputs + 1; i++) {
free(input_blinding_key[i]);
@@ -415,7 +466,6 @@ static void test_no_used_inputs_verify(void) {
size_t n_ephemeral_input_tags = 1;
secp256k1_generator ephemeral_output_tag;
unsigned char blinding_key[32];
secp256k1_ge inputs[1];
secp256k1_ge output;
secp256k1_sha256 sha256_e0;
int result;
@@ -436,8 +486,7 @@ static void test_no_used_inputs_verify(void) {
/* create "borromean signature" which is just a hash of metadata (pubkeys, etc) in this case */
secp256k1_generator_load(&output, &ephemeral_output_tag);
secp256k1_generator_load(&inputs[0], &ephemeral_input_tags[0]);
secp256k1_surjection_genmessage(proof.data, inputs, 1, &output);
secp256k1_surjection_genmessage(proof.data, ephemeral_input_tags, 1, &ephemeral_output_tag);
secp256k1_sha256_initialize(&sha256_e0);
secp256k1_sha256_write(&sha256_e0, proof.data, 32);
secp256k1_sha256_finalize(&sha256_e0, proof.data);
@@ -471,21 +520,167 @@ void test_bad_parse(void) {
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof2, sizeof(serialized_proof2)) == 0);
}
void test_fixed_vectors(void) {
const unsigned char tag0_ser[] = {
0x0a,
0x1c, 0xa3, 0xdd, 0x12, 0x48, 0xdd, 0x4d, 0xd0, 0x04, 0x30, 0x47, 0x48, 0x75, 0xf5, 0xf5, 0xff,
0x2a, 0xd5, 0x0d, 0x1d, 0x86, 0x2b, 0xa4, 0xa4, 0x2f, 0x46, 0xe9, 0xb4, 0x54, 0x21, 0xf0, 0x85
};
const unsigned char tag1_ser[] = {
0x0a,
0x09, 0x0d, 0x5a, 0xd4, 0xed, 0xae, 0x9c, 0x0c, 0x69, 0x79, 0xf3, 0x8d, 0x22, 0x03, 0x0a, 0x3d,
0x38, 0xd4, 0x78, 0xe1, 0x03, 0x0d, 0x70, 0x57, 0xd9, 0x9a, 0x23, 0x03, 0xf0, 0x7f, 0xfb, 0xef
};
const unsigned char tag2_ser[] = {
0x0a,
0xfd, 0xed, 0xba, 0x15, 0x20, 0x8a, 0xb2, 0xaf, 0x0b, 0x76, 0x6d, 0xd2, 0x5f, 0xd4, 0x15, 0x11,
0x90, 0xec, 0xcb, 0x3f, 0xcd, 0x08, 0xb5, 0x35, 0xd9, 0x24, 0x18, 0xb1, 0xd3, 0x47, 0x83, 0x54
};
const unsigned char tag3_ser[] = {
0x0b,
0x8b, 0x47, 0xca, 0xee, 0x20, 0x52, 0x17, 0xbf, 0xee, 0xcc, 0x84, 0xcd, 0x34, 0x32, 0x6c, 0x36,
0xf1, 0xd9, 0x3f, 0xe1, 0x6f, 0x77, 0xfe, 0x89, 0x3e, 0x4a, 0xc8, 0x2a, 0x75, 0xfa, 0x2d, 0x36
};
const unsigned char tag4_ser[] = {
0x0b,
0x3c, 0x5c, 0xf4, 0x61, 0x45, 0xa8, 0x53, 0xc1, 0x64, 0x32, 0x0e, 0x92, 0x68, 0x52, 0xbd, 0x12,
0xe9, 0x45, 0x31, 0xeb, 0x04, 0x4c, 0xf4, 0xe2, 0x9e, 0x9f, 0x60, 0x26, 0x50, 0xbf, 0xd6, 0x9f
};
const unsigned char output_tag_ser[] = {
0x0b,
0xf7, 0x3c, 0x03, 0xed, 0xae, 0x83, 0xa1, 0xa6, 0x94, 0x8c, 0xe3, 0xb8, 0x54, 0x02, 0xa8, 0xbd,
0x66, 0xca, 0x28, 0xef, 0x44, 0xf5, 0x3a, 0xcb, 0xc7, 0x5b, 0x16, 0xac, 0xce, 0x29, 0x4b, 0xc6
};
const unsigned char total1_used1[] = {
0x01, 0x00, 0x01, 0x8e, 0x6b, 0x8d, 0x8b, 0x96, 0x29, 0x10, 0x29, 0xcb, 0xf8, 0x48, 0xd9, 0xc8,
0x5b, 0x77, 0xdc, 0xdf, 0x16, 0x67, 0x19, 0xfe, 0x8d, 0xee, 0x8f, 0x56, 0x6f, 0x9c, 0xe9, 0xae,
0xb9, 0xd9, 0x12, 0xb8, 0x95, 0x6c, 0xf1, 0x48, 0x07, 0x7d, 0x49, 0xe4, 0x3e, 0x7f, 0xc1, 0x2c,
0xe2, 0xe1, 0x94, 0x10, 0xb1, 0xda, 0x86, 0x5f, 0xbc, 0x03, 0x59, 0xe1, 0x09, 0xd2, 0x1b, 0x18,
0xce, 0x58, 0x15
};
const size_t total1_used1_len = sizeof(total1_used1);
const unsigned char total2_used1[] = {
0x02, 0x00, 0x01, 0x35, 0x3a, 0x29, 0x4b, 0xe4, 0x99, 0xc6, 0xbf, 0x99, 0x4d, 0x6c, 0xc8, 0x18,
0x14, 0xad, 0x10, 0x22, 0x3a, 0xb8, 0x1c, 0xb9, 0xc5, 0x77, 0xda, 0xe0, 0x8a, 0x71, 0x2d, 0x0d,
0x8e, 0x80, 0xf5, 0x8d, 0x74, 0xf9, 0x01, 0x6b, 0x35, 0x88, 0xf4, 0x8e, 0x43, 0xa5, 0x9c, 0x0f,
0x7e, 0x37, 0x86, 0x77, 0x44, 0x72, 0x7c, 0xaa, 0xff, 0x14, 0x5b, 0x7a, 0x42, 0x41, 0x75, 0xb2,
0x5e, 0x3d, 0x6c
};
const size_t total2_used1_len = sizeof(total2_used1);
const unsigned char total3_used2[] = {
0x03, 0x00, 0x03, 0xf2, 0x3f, 0xca, 0x49, 0x52, 0x05, 0xaf, 0x81, 0x83, 0x01, 0xd7, 0xf4, 0x92,
0xc0, 0x50, 0xe3, 0x15, 0xfc, 0x94, 0xc1, 0x27, 0x10, 0xd7, 0x8f, 0x57, 0xb1, 0x23, 0xcf, 0x68,
0x31, 0xf8, 0xcb, 0x58, 0x3d, 0xca, 0x2f, 0x7a, 0x3b, 0x0b, 0xb6, 0x10, 0x52, 0x94, 0xc8, 0x5f,
0x0a, 0xf8, 0xca, 0x5d, 0x4c, 0x38, 0x44, 0x92, 0xb3, 0xc7, 0xe4, 0x46, 0x9f, 0x96, 0x64, 0xbd,
0xd2, 0xda, 0x40, 0xdb, 0x63, 0x76, 0x87, 0x48, 0xdc, 0x55, 0x0b, 0x82, 0x9c, 0xa5, 0x96, 0xbe,
0xe9, 0x0d, 0xe4, 0x98, 0x80, 0x8e, 0x58, 0x38, 0xdc, 0x13, 0x59, 0x1d, 0x5c, 0x8e, 0xda, 0x90,
0x4c, 0xa4, 0x91
};
const size_t total3_used2_len = sizeof(total3_used2);
const unsigned char total5_used3[] = {
0x05, 0x00, 0x15, 0x36, 0x3b, 0x92, 0x97, 0x84, 0x25, 0x75, 0xd6, 0xa6, 0xaf, 0xb7, 0x32, 0x5b,
0x2c, 0xf8, 0x31, 0xe2, 0x15, 0x3a, 0x9b, 0xb7, 0x20, 0x14, 0xc0, 0x67, 0x96, 0x7d, 0xa9, 0xc4,
0xa2, 0xb4, 0x22, 0x57, 0x5f, 0xb8, 0x20, 0xf1, 0xe8, 0x82, 0xaf, 0xbc, 0x8a, 0xbc, 0x01, 0xc9,
0x35, 0xf2, 0x7f, 0x6f, 0x0c, 0x0d, 0xba, 0x87, 0xa4, 0xc3, 0xec, 0x60, 0x54, 0x49, 0x35, 0xeb,
0x1e, 0x48, 0x2c, 0xdb, 0x63, 0x76, 0x87, 0x48, 0xdc, 0x55, 0x0b, 0x82, 0x9c, 0xa5, 0x96, 0xbe,
0xe9, 0x0d, 0xe4, 0x98, 0x80, 0x8e, 0x58, 0x38, 0xdc, 0x13, 0x59, 0x1d, 0x5c, 0x8e, 0xda, 0x90,
0x4c, 0xa4, 0x91, 0x5e, 0x8f, 0xcf, 0x2e, 0xc7, 0x5f, 0xfc, 0xca, 0x42, 0xd8, 0x80, 0xe4, 0x3b,
0x90, 0xa5, 0xd2, 0x07, 0x7d, 0xd1, 0xc9, 0x5c, 0x69, 0xc2, 0xd7, 0xef, 0x8a, 0xae, 0x0a, 0xee,
0x9c, 0xf5, 0xb9
};
const size_t total5_used3_len = sizeof(total5_used3);
const unsigned char total5_used5[] = {
0x05, 0x00, 0x1f, 0xfd, 0xbb, 0xb6, 0xc2, 0x78, 0x82, 0xad, 0xe1, 0x66, 0x6d, 0x20, 0x4d, 0xfe,
0x6b, 0xd2, 0x0b, 0x21, 0x6e, 0xa8, 0x5b, 0xc8, 0xe4, 0x88, 0x42, 0x11, 0x30, 0x3b, 0x6b, 0x02,
0xc9, 0x7f, 0x44, 0x1c, 0xee, 0xd8, 0x37, 0x6a, 0xf8, 0xfd, 0xc8, 0x4b, 0x0b, 0xa1, 0x43, 0x1f,
0x68, 0x77, 0x8d, 0x1b, 0xac, 0x9e, 0xc1, 0xc1, 0xda, 0x60, 0xa8, 0xcf, 0x10, 0x9d, 0x80, 0x07,
0x90, 0x57, 0xb6, 0xdb, 0x63, 0x76, 0x87, 0x48, 0xdc, 0x55, 0x0b, 0x82, 0x9c, 0xa5, 0x96, 0xbe,
0xe9, 0x0d, 0xe4, 0x98, 0x80, 0x8e, 0x58, 0x38, 0xdc, 0x13, 0x59, 0x1d, 0x5c, 0x8e, 0xda, 0x90,
0x4c, 0xa4, 0x91, 0x5e, 0x8f, 0xcf, 0x2e, 0xc7, 0x5f, 0xfc, 0xca, 0x42, 0xd8, 0x80, 0xe4, 0x3b,
0x90, 0xa5, 0xd2, 0x07, 0x7d, 0xd1, 0xc9, 0x5c, 0x69, 0xc2, 0xd7, 0xef, 0x8a, 0xae, 0x0a, 0xee,
0x9c, 0xf5, 0xb9, 0x5a, 0xc8, 0x03, 0x8d, 0x4f, 0xe3, 0x1d, 0x79, 0x38, 0x5a, 0xfa, 0xe5, 0xa8,
0x9d, 0x56, 0x77, 0xb3, 0xf9, 0xa8, 0x70, 0x46, 0x27, 0x26, 0x6c, 0x6e, 0x54, 0xaf, 0xf9, 0xd0,
0x37, 0xa4, 0x86, 0x68, 0x8f, 0xac, 0x3e, 0x78, 0xaa, 0x3d, 0x83, 0x1a, 0xca, 0x05, 0xfe, 0x10,
0x95, 0xa4, 0x6a, 0x10, 0xc6, 0x62, 0xf3, 0xf7, 0xf3, 0x4d, 0x0b, 0xd4, 0x94, 0xe5, 0x51, 0x6c,
0x85, 0xd7, 0xc7
};
const size_t total5_used5_len = sizeof(total5_used5);
unsigned char bad[sizeof(total5_used5) + 32] = { 0 };
secp256k1_generator input_tags[5];
secp256k1_generator output_tag;
secp256k1_surjectionproof proof;
CHECK(secp256k1_generator_parse(ctx, &input_tags[0], tag0_ser));
CHECK(secp256k1_generator_parse(ctx, &input_tags[1], tag1_ser));
CHECK(secp256k1_generator_parse(ctx, &input_tags[2], tag2_ser));
CHECK(secp256k1_generator_parse(ctx, &input_tags[3], tag3_ser));
CHECK(secp256k1_generator_parse(ctx, &input_tags[4], tag4_ser));
CHECK(secp256k1_generator_parse(ctx, &output_tag, output_tag_ser));
/* check 1-of-1 */
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, total1_used1, total1_used1_len));
CHECK(secp256k1_surjectionproof_verify(ctx, &proof, input_tags, 1, &output_tag));
/* check 1-of-2 */
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, total2_used1, total2_used1_len));
CHECK(secp256k1_surjectionproof_verify(ctx, &proof, input_tags, 2, &output_tag));
/* check 2-of-3 */
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, total3_used2, total3_used2_len));
CHECK(secp256k1_surjectionproof_verify(ctx, &proof, input_tags, 3, &output_tag));
/* check 3-of-5 */
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, total5_used3, total5_used3_len));
CHECK(secp256k1_surjectionproof_verify(ctx, &proof, input_tags, 5, &output_tag));
/* check 5-of-5 */
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, total5_used5, total5_used5_len));
CHECK(secp256k1_surjectionproof_verify(ctx, &proof, input_tags, 5, &output_tag));
/* check invalid length fails */
CHECK(!secp256k1_surjectionproof_parse(ctx, &proof, total5_used5, total5_used3_len));
/* check invalid keys fail */
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, total1_used1, total1_used1_len));
CHECK(!secp256k1_surjectionproof_verify(ctx, &proof, &input_tags[1], 1, &output_tag));
CHECK(!secp256k1_surjectionproof_verify(ctx, &proof, input_tags, 1, &input_tags[0]));
/* Try setting 6 bits on the total5-used-5; check that parsing fails */
memcpy(bad, total5_used5, total5_used5_len);
bad[2] = 0x3f; /* 0x1f -> 0x3f */
CHECK(!secp256k1_surjectionproof_parse(ctx, &proof, bad, total5_used5_len));
/* Correct for the length */
CHECK(!secp256k1_surjectionproof_parse(ctx, &proof, bad, total5_used5_len + 32));
/* Alternately just turn off one of the "legit" bits */
bad[2] = 0x37; /* 0x1f -> 0x37 */
CHECK(!secp256k1_surjectionproof_parse(ctx, &proof, bad, total5_used5_len));
/* Similarly try setting 4 bits on the total5-used-3, with one bit out of range */
memcpy(bad, total5_used3, total5_used3_len);
bad[2] = 0x35; /* 0x15 -> 0x35 */
CHECK(!secp256k1_surjectionproof_parse(ctx, &proof, bad, total5_used3_len));
CHECK(!secp256k1_surjectionproof_parse(ctx, &proof, bad, total5_used3_len + 32));
bad[2] = 0x34; /* 0x15 -> 0x34 */
CHECK(!secp256k1_surjectionproof_parse(ctx, &proof, bad, total5_used3_len));
}
void run_surjection_tests(void) {
int i;
for (i = 0; i < count; i++) {
test_surjectionproof_api();
}
test_fixed_vectors();
test_input_selection(0);
test_input_selection(1);
test_input_selection(5);
test_input_selection(100);
test_input_selection(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
test_input_selection(SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS);
test_input_selection_distribution();
test_gen_verify(10, 3);
test_gen_verify(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS);
test_gen_verify(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_USED_INPUTS);
test_no_used_inputs_verify();
test_bad_serialize();
test_bad_parse();

View File

@@ -34,11 +34,13 @@ A less obvious scheme is to have a participant sign an arbitrary message with
the sum of her key `P` and the whitelisted key `W`. Such a signature with the key
`P + W` proves knowledge of either (a) discrete logarithms of both `P` and `W`;
or (b) neither. This makes directly attacking participants' signing schemes much
harder, but allows an attacker to whitelist arbitrary "garbage" keys by computing
`W` as the difference between an attacker-controlled key and `P`. For Bitcoin,
the effect of garbage keys is to "burn" stolen coins, destroying them.
harder, but allows an attacker to whitelist arbitrary "cancellation" keys by
computing `W` as the difference between an attacker-controlled key and `P`.
Because to spend the funds the attacker must produce a signature with `W`, the
coins will be unspendable until attacker and the legitimate participant owning
`P` cooperate.
In an important sense, this "burning coins" attack is a good thing: it enables
In an important sense, this "cancellation" attack is a good thing: it enables
*offline delegation*. That is, the key `P` does not need to be available at the
time of delegation. Instead, participants could choose `S = P + W`, sign with
this to delegate, and only later compute the discrete logarithm of `W = P - S`.
@@ -47,7 +49,7 @@ the overall system security.
#### Signing with Tweaked-Difference-of-Keys
A modification of this scheme, which prevents this "garbage key" attack, is to
A modification of this scheme, which prevents this "cancellation" attack, is to
instead have participants sign some message with the key `P + H(W)W`, for `H`
some random-oracle hash that maps group elements to scalars. This key, and its
discrete logarithm, cannot be known until after `W` is chosen, so `W` cannot
@@ -60,8 +62,8 @@ delegation. However, we can get this back by introducing a new key, `P'`,
and signing with the key `P + H(W + P')(W + P')`. This gives us the best
of both worlds: `P'` does not need to be online to delegate, allowing it
to be securely stored and preventing real-time attacks; `P` does need to
be online, but its compromise only allows an attacker to whitelist "garbage
keys", not attacker-controlled ones.
be online, but its compromise only allows an attacker to whitelist keys he does
not control alone.
### Our Scheme
@@ -78,8 +80,8 @@ knows:
1. The discrete logarithms of all of `W`, `P_i` and `Q_i`; or
2. The discrete logarithm of `P_i` but of *neither* `W` nor `Q_i`.
In other words, compromise of the online key `P_i` allows an attacker to whitelist
"garbage keys" for which nobody knows the discrete logarithm; to whitelist an
attacker-controlled key, he must compromise both `P_i` and `Q_i`. This is difficult
"cancellation keys" for which the attacker alone does not know the discrete logarithm;
to whitelist an attacker-controlled key, he must compromise both `P_i` and `Q_i`. This is difficult
because by design, only the sum `S = W + Q_i` is used when signing; then by choosing
`S` freely, a participant can delegate without the secret key to `Q_i` ever being online.
(Later, when she wants to actually use `W`, she will need to compute its key as the

View File

@@ -386,7 +386,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
/* extract m6 */
"movq %%r8, %q6\n"
: "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6)
: "S"(l), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
: "S"(l), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc");
/* Reduce 385 bits into 258. */
@@ -465,7 +465,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
/* extract p4 */
"movq %%r9, %q4\n"
: "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4)
: "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
: "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc");
/* Reduce 258 bits into 256. */
@@ -511,7 +511,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l)
/* Extract c */
"movq %%r9, %q0\n"
: "=g"(c)
: "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1)
: "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "i"(SECP256K1_N_C_0), "i"(SECP256K1_N_C_1)
: "rax", "rdx", "r8", "r9", "r10", "cc", "memory");
#else
uint128_t c;
@@ -965,9 +965,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
#ifdef WORDS_BIGENDIAN
#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#define BE32(p) (p)
#else
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#define LE32(p) (p)
#endif
@@ -1026,14 +1024,14 @@ static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2
x14 += 0;
x15 += over_count;
r1->d[3] = LE32((uint64_t) x0) << 32 | LE32(x1);
r1->d[2] = LE32((uint64_t) x2) << 32 | LE32(x3);
r1->d[1] = LE32((uint64_t) x4) << 32 | LE32(x5);
r1->d[0] = LE32((uint64_t) x6) << 32 | LE32(x7);
r2->d[3] = LE32((uint64_t) x8) << 32 | LE32(x9);
r2->d[2] = LE32((uint64_t) x10) << 32 | LE32(x11);
r2->d[1] = LE32((uint64_t) x12) << 32 | LE32(x13);
r2->d[0] = LE32((uint64_t) x14) << 32 | LE32(x15);
r1->d[3] = (((uint64_t) x0) << 32) | x1;
r1->d[2] = (((uint64_t) x2) << 32) | x3;
r1->d[1] = (((uint64_t) x4) << 32) | x5;
r1->d[0] = (((uint64_t) x6) << 32) | x7;
r2->d[3] = (((uint64_t) x8) << 32) | x9;
r2->d[2] = (((uint64_t) x10) << 32) | x11;
r2->d[1] = (((uint64_t) x12) << 32) | x13;
r2->d[0] = (((uint64_t) x14) << 32) | x15;
over1 = secp256k1_scalar_check_overflow(r1);
over2 = secp256k1_scalar_check_overflow(r2);
@@ -1043,7 +1041,6 @@ static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2
#undef ROTL32
#undef QUARTERROUND
#undef BE32
#undef LE32
#endif /* SECP256K1_SCALAR_REPR_IMPL_H */

View File

@@ -740,9 +740,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r,
#ifdef WORDS_BIGENDIAN
#define LE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#define BE32(p) (p)
#else
#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24))
#define LE32(p) (p)
#endif
@@ -801,22 +799,22 @@ static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2
x14 += 0;
x15 += over_count;
r1->d[7] = LE32(x0);
r1->d[6] = LE32(x1);
r1->d[5] = LE32(x2);
r1->d[4] = LE32(x3);
r1->d[3] = LE32(x4);
r1->d[2] = LE32(x5);
r1->d[1] = LE32(x6);
r1->d[0] = LE32(x7);
r2->d[7] = LE32(x8);
r2->d[6] = LE32(x9);
r2->d[5] = LE32(x10);
r2->d[4] = LE32(x11);
r2->d[3] = LE32(x12);
r2->d[2] = LE32(x13);
r2->d[1] = LE32(x14);
r2->d[0] = LE32(x15);
r1->d[7] = x0;
r1->d[6] = x1;
r1->d[5] = x2;
r1->d[4] = x3;
r1->d[3] = x4;
r1->d[2] = x5;
r1->d[1] = x6;
r1->d[0] = x7;
r2->d[7] = x8;
r2->d[6] = x9;
r2->d[5] = x10;
r2->d[4] = x11;
r2->d[3] = x12;
r2->d[2] = x13;
r2->d[1] = x14;
r2->d[0] = x15;
over1 = secp256k1_scalar_check_overflow(r1);
over2 = secp256k1_scalar_check_overflow(r2);
@@ -826,7 +824,6 @@ static void secp256k1_scalar_chacha20(secp256k1_scalar *r1, secp256k1_scalar *r2
#undef ROTL32
#undef QUARTERROUND
#undef BE32
#undef LE32
#endif /* SECP256K1_SCALAR_REPR_IMPL_H */

View File

@@ -7,33 +7,36 @@
#ifndef _SECP256K1_SCRATCH_
#define _SECP256K1_SCRATCH_
#define SECP256K1_SCRATCH_MAX_FRAMES 5
/* The typedef is used internally; the struct name is used in the public API
* (where it is exposed as a different typedef) */
typedef struct secp256k1_scratch_space_struct {
void *data[SECP256K1_SCRATCH_MAX_FRAMES];
size_t offset[SECP256K1_SCRATCH_MAX_FRAMES];
size_t frame_size[SECP256K1_SCRATCH_MAX_FRAMES];
size_t frame;
/** guard against interpreting this object as other types */
unsigned char magic[8];
/** actual allocated data */
void *data;
/** amount that has been allocated (i.e. `data + offset` is the next
* available pointer) */
size_t alloc_size;
/** maximum size available to allocate */
size_t max_size;
const secp256k1_callback* error_callback;
} secp256k1_scratch;
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size);
static void secp256k1_scratch_destroy(secp256k1_scratch* scratch);
static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch);
/** Attempts to allocate a new stack frame with `n` available bytes. Returns 1 on success, 0 on failure */
static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects);
/** Returns an opaque object used to "checkpoint" a scratch space. Used
* with `secp256k1_scratch_apply_checkpoint` to undo allocations. */
static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch);
/** Deallocates a stack frame */
static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch);
/** Applies a check point received from `secp256k1_scratch_checkpoint`,
* undoing all allocations since that point. */
static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint);
/** Returns the maximum allocation the scratch space will allow */
static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t n_objects);
static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t n_objects);
/** Returns a pointer into the most recently allocated frame, or NULL if there is insufficient available space */
static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t n);
static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t n);
#endif

View File

@@ -10,70 +10,77 @@
#include "util.h"
#include "scratch.h"
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t max_size) {
secp256k1_scratch* ret = (secp256k1_scratch*)checked_malloc(error_callback, sizeof(*ret));
static secp256k1_scratch* secp256k1_scratch_create(const secp256k1_callback* error_callback, size_t size) {
const size_t base_alloc = ((sizeof(secp256k1_scratch) + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
void *alloc = checked_malloc(error_callback, base_alloc + size);
secp256k1_scratch* ret = (secp256k1_scratch *)alloc;
if (ret != NULL) {
memset(ret, 0, sizeof(*ret));
ret->max_size = max_size;
ret->error_callback = error_callback;
memcpy(ret->magic, "scratch", 8);
ret->data = (void *) ((char *) alloc + base_alloc);
ret->max_size = size;
}
return ret;
}
static void secp256k1_scratch_destroy(secp256k1_scratch* scratch) {
static void secp256k1_scratch_destroy(const secp256k1_callback* error_callback, secp256k1_scratch* scratch) {
if (scratch != NULL) {
VERIFY_CHECK(scratch->frame == 0);
VERIFY_CHECK(scratch->alloc_size == 0); /* all checkpoints should be applied */
if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return;
}
memset(scratch->magic, 0, sizeof(scratch->magic));
free(scratch);
}
}
static size_t secp256k1_scratch_max_allocation(const secp256k1_scratch* scratch, size_t objects) {
size_t i = 0;
size_t allocated = 0;
for (i = 0; i < scratch->frame; i++) {
allocated += scratch->frame_size[i];
}
if (scratch->max_size - allocated <= objects * ALIGNMENT) {
static size_t secp256k1_scratch_checkpoint(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch) {
if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return 0;
}
return scratch->max_size - allocated - objects * ALIGNMENT;
return scratch->alloc_size;
}
static int secp256k1_scratch_allocate_frame(secp256k1_scratch* scratch, size_t n, size_t objects) {
VERIFY_CHECK(scratch->frame < SECP256K1_SCRATCH_MAX_FRAMES);
static void secp256k1_scratch_apply_checkpoint(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t checkpoint) {
if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return;
}
if (checkpoint > scratch->alloc_size) {
secp256k1_callback_call(error_callback, "invalid checkpoint");
return;
}
scratch->alloc_size = checkpoint;
}
if (n <= secp256k1_scratch_max_allocation(scratch, objects)) {
n += objects * ALIGNMENT;
scratch->data[scratch->frame] = checked_malloc(scratch->error_callback, n);
if (scratch->data[scratch->frame] == NULL) {
return 0;
}
scratch->frame_size[scratch->frame] = n;
scratch->offset[scratch->frame] = 0;
scratch->frame++;
return 1;
} else {
static size_t secp256k1_scratch_max_allocation(const secp256k1_callback* error_callback, const secp256k1_scratch* scratch, size_t objects) {
if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return 0;
}
if (scratch->max_size - scratch->alloc_size <= objects * (ALIGNMENT - 1)) {
return 0;
}
return scratch->max_size - scratch->alloc_size - objects * (ALIGNMENT - 1);
}
static void secp256k1_scratch_deallocate_frame(secp256k1_scratch* scratch) {
VERIFY_CHECK(scratch->frame > 0);
scratch->frame -= 1;
free(scratch->data[scratch->frame]);
}
static void *secp256k1_scratch_alloc(secp256k1_scratch* scratch, size_t size) {
static void *secp256k1_scratch_alloc(const secp256k1_callback* error_callback, secp256k1_scratch* scratch, size_t size) {
void *ret;
size_t frame = scratch->frame - 1;
size = ROUND_TO_ALIGN(size);
if (scratch->frame == 0 || size + scratch->offset[frame] > scratch->frame_size[frame]) {
if (memcmp(scratch->magic, "scratch", 8) != 0) {
secp256k1_callback_call(error_callback, "invalid scratch space");
return NULL;
}
ret = (void *) ((unsigned char *) scratch->data[frame] + scratch->offset[frame]);
if (size > scratch->max_size - scratch->alloc_size) {
return NULL;
}
ret = (void *) ((char *) scratch->data + scratch->alloc_size);
memset(ret, 0, size);
scratch->offset[frame] += size;
scratch->alloc_size += size;
return ret;
}

View File

@@ -220,8 +220,9 @@ secp256k1_scratch_space* secp256k1_scratch_space_create(const secp256k1_context*
return secp256k1_scratch_create(&ctx->error_callback, max_size);
}
void secp256k1_scratch_space_destroy(secp256k1_scratch_space* scratch) {
secp256k1_scratch_destroy(scratch);
void secp256k1_scratch_space_destroy(const secp256k1_context *ctx, secp256k1_scratch_space* scratch) {
VERIFY_CHECK(ctx != NULL);
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
}
static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) {
@@ -424,9 +425,8 @@ static SECP256K1_INLINE void buffer_append(unsigned char *buf, unsigned int *off
/* This nonce function is described in BIP-schnorr
* (https://github.com/sipa/bips/blob/bip-schnorr/bip-schnorr.mediawiki) */
static int secp256k1_nonce_function_bipschnorr(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
static int nonce_function_bipschnorr(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) {
secp256k1_sha256 sha;
(void) data;
(void) counter;
VERIFY_CHECK(counter == 0);
@@ -439,6 +439,9 @@ static int secp256k1_nonce_function_bipschnorr(unsigned char *nonce32, const uns
if (algo16 != NULL) {
secp256k1_sha256_write(&sha, algo16, 16);
}
if (data != NULL) {
secp256k1_sha256_write(&sha, data, 32);
}
secp256k1_sha256_finalize(&sha, nonce32);
return 1;
}
@@ -473,6 +476,7 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
return 1;
}
const secp256k1_nonce_function secp256k1_nonce_function_bipschnorr = nonce_function_bipschnorr;
const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979;
@@ -548,7 +552,7 @@ int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *p
ARG_CHECK(seckey != NULL);
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec));
ret = !overflow && !secp256k1_scalar_is_zero(&sec);
if (ret) {
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
secp256k1_ge_set_gej(&p, &pj);

View File

@@ -83,7 +83,9 @@ void random_field_element_magnitude(secp256k1_fe *fe) {
secp256k1_fe_negate(&zero, &zero, 0);
secp256k1_fe_mul_int(&zero, n - 1);
secp256k1_fe_add(fe, &zero);
VERIFY_CHECK(fe->magnitude == n);
#ifdef VERIFY
CHECK(fe->magnitude == n);
#endif
}
void random_group_element_test(secp256k1_ge *ge) {
@@ -379,40 +381,73 @@ void run_context_tests(int use_prealloc) {
}
void run_scratch_tests(void) {
const size_t adj_alloc = ((500 + ALIGNMENT - 1) / ALIGNMENT) * ALIGNMENT;
int32_t ecount = 0;
size_t checkpoint;
size_t checkpoint_2;
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_scratch_space *scratch;
secp256k1_scratch_space local_scratch;
/* Test public API */
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount);
scratch = secp256k1_scratch_space_create(none, 1000);
CHECK(scratch != NULL);
CHECK(ecount == 0);
/* Test internal API */
CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000);
CHECK(secp256k1_scratch_max_allocation(scratch, 1) < 1000);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - (ALIGNMENT - 1));
CHECK(scratch->alloc_size == 0);
CHECK(scratch->alloc_size % ALIGNMENT == 0);
/* Allocating 500 bytes with no frame fails */
CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL);
CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000);
/* Allocating 500 bytes succeeds */
checkpoint = secp256k1_scratch_checkpoint(&none->error_callback, scratch);
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
CHECK(scratch->alloc_size != 0);
CHECK(scratch->alloc_size % ALIGNMENT == 0);
/* ...but pushing a new stack frame does affect the max allocation */
CHECK(secp256k1_scratch_allocate_frame(scratch, 500, 1 == 1));
CHECK(secp256k1_scratch_max_allocation(scratch, 1) < 500); /* 500 - ALIGNMENT */
CHECK(secp256k1_scratch_alloc(scratch, 500) != NULL);
CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL);
/* Allocating another 500 bytes fails */
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000 - adj_alloc);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 1) == 1000 - adj_alloc - (ALIGNMENT - 1));
CHECK(scratch->alloc_size != 0);
CHECK(scratch->alloc_size % ALIGNMENT == 0);
CHECK(secp256k1_scratch_allocate_frame(scratch, 500, 1) == 0);
/* ...but it succeeds once we apply the checkpoint to undo it */
secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint);
CHECK(scratch->alloc_size == 0);
CHECK(secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0) == 1000);
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) != NULL);
CHECK(scratch->alloc_size != 0);
/* ...and this effect is undone by popping the frame */
secp256k1_scratch_deallocate_frame(scratch);
CHECK(secp256k1_scratch_max_allocation(scratch, 0) == 1000);
CHECK(secp256k1_scratch_alloc(scratch, 500) == NULL);
/* try to apply a bad checkpoint */
checkpoint_2 = secp256k1_scratch_checkpoint(&none->error_callback, scratch);
secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint);
CHECK(ecount == 0);
secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, checkpoint_2); /* checkpoint_2 is after checkpoint */
CHECK(ecount == 1);
secp256k1_scratch_apply_checkpoint(&none->error_callback, scratch, (size_t) -1); /* this is just wildly invalid */
CHECK(ecount == 2);
/* try to use badly initialized scratch space */
secp256k1_scratch_space_destroy(none, scratch);
memset(&local_scratch, 0, sizeof(local_scratch));
scratch = &local_scratch;
CHECK(!secp256k1_scratch_max_allocation(&none->error_callback, scratch, 0));
CHECK(ecount == 3);
CHECK(secp256k1_scratch_alloc(&none->error_callback, scratch, 500) == NULL);
CHECK(ecount == 4);
secp256k1_scratch_space_destroy(none, scratch);
CHECK(ecount == 5);
/* cleanup */
secp256k1_scratch_space_destroy(scratch);
secp256k1_scratch_space_destroy(none, NULL); /* no-op */
secp256k1_context_destroy(none);
}
@@ -1942,24 +1977,32 @@ void run_field_misc(void) {
/* Test fe conditional move; z is not normalized here. */
q = x;
secp256k1_fe_cmov(&x, &z, 0);
VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude);
#ifdef VERIFY
CHECK(!x.normalized && x.magnitude == z.magnitude);
#endif
secp256k1_fe_cmov(&x, &x, 1);
CHECK(fe_memcmp(&x, &z) != 0);
CHECK(fe_memcmp(&x, &q) == 0);
secp256k1_fe_cmov(&q, &z, 1);
VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude);
#ifdef VERIFY
CHECK(!q.normalized && q.magnitude == z.magnitude);
#endif
CHECK(fe_memcmp(&q, &z) == 0);
secp256k1_fe_normalize_var(&x);
secp256k1_fe_normalize_var(&z);
CHECK(!secp256k1_fe_equal_var(&x, &z));
secp256k1_fe_normalize_var(&q);
secp256k1_fe_cmov(&q, &z, (i&1));
VERIFY_CHECK(q.normalized && q.magnitude == 1);
#ifdef VERIFY
CHECK(q.normalized && q.magnitude == 1);
#endif
for (j = 0; j < 6; j++) {
secp256k1_fe_negate(&z, &z, j+1);
secp256k1_fe_normalize_var(&q);
secp256k1_fe_cmov(&q, &z, (j&1));
VERIFY_CHECK(!q.normalized && q.magnitude == (j+2));
#ifdef VERIFY
CHECK(!q.normalized && q.magnitude == (j+2));
#endif
}
secp256k1_fe_normalize_var(&z);
/* Test storage conversion and conditional moves. */
@@ -2805,14 +2848,13 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_gej r;
secp256k1_gej r2;
ecmult_multi_data data;
secp256k1_scratch *scratch_empty;
data.sc = sc;
data.pt = pt;
secp256k1_scalar_set_int(&szero, 0);
/* No points to multiply */
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, 0));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, NULL, ecmult_multi_callback, &data, 0));
/* Check 1- and 2-point multiplies against ecmult */
for (ncount = 0; ncount < count; ncount++) {
@@ -2828,36 +2870,31 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
/* only G scalar */
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &szero, &sc[0]);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &sc[0], ecmult_multi_callback, &data, 0));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
/* 1-point */
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &szero);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 1));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 1));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
/* Try to multiply 1 point, but scratch space is empty */
scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0);
CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
secp256k1_scratch_destroy(scratch_empty);
/* Try to multiply 1 point, but callback returns false */
CHECK(!ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
CHECK(!ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_false_callback, &data, 1));
/* 2-point */
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 2));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 2));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
/* 2-point with G scalar */
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &ptgj, &sc[0], &sc[1]);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &sc[1], ecmult_multi_callback, &data, 1));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
@@ -2874,7 +2911,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
random_scalar_order(&sc[i]);
secp256k1_ge_set_infinity(&pt[i]);
}
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -2884,7 +2921,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
pt[i] = ptg;
secp256k1_scalar_set_int(&sc[i], 0);
}
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -2897,7 +2934,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
pt[2 * i + 1] = ptg;
}
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
random_scalar_order(&sc[0]);
@@ -2910,7 +2947,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_ge_neg(&pt[2*i+1], &pt[2*i]);
}
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, sizes[j]));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -2925,7 +2962,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_scalar_negate(&sc[i], &sc[i]);
}
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 32));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 32));
CHECK(secp256k1_gej_is_infinity(&r));
}
@@ -2944,7 +2981,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
}
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &r, &sc[0], &szero);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
@@ -2967,7 +3004,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_gej_set_ge(&p0j, &pt[0]);
secp256k1_ecmult(&ctx->ecmult_ctx, &r2, &p0j, &rs, &szero);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
secp256k1_gej_neg(&r2, &r2);
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
@@ -2980,13 +3017,13 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
}
secp256k1_scalar_clear(&sc[0]);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 20));
secp256k1_scalar_clear(&sc[1]);
secp256k1_scalar_clear(&sc[2]);
secp256k1_scalar_clear(&sc[3]);
secp256k1_scalar_clear(&sc[4]);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 6));
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 5));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 6));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &szero, ecmult_multi_callback, &data, 5));
CHECK(secp256k1_gej_is_infinity(&r));
/* Run through s0*(t0*P) + s1*(t1*P) exhaustively for many small values of s0, s1, t0, t1 */
@@ -3031,7 +3068,7 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
secp256k1_scalar_add(&tmp1, &tmp1, &tmp2);
secp256k1_ecmult(&ctx->ecmult_ctx, &expected, &ptgj, &tmp1, &szero);
CHECK(ecmult_multi(&ctx->ecmult_ctx, scratch, &actual, &szero, ecmult_multi_callback, &data, 2));
CHECK(ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &actual, &szero, ecmult_multi_callback, &data, 2));
secp256k1_gej_neg(&expected, &expected);
secp256k1_gej_add_var(&actual, &actual, &expected, NULL);
CHECK(secp256k1_gej_is_infinity(&actual));
@@ -3042,6 +3079,24 @@ void test_ecmult_multi(secp256k1_scratch *scratch, secp256k1_ecmult_multi_func e
}
}
void test_ecmult_multi_batch_single(secp256k1_ecmult_multi_func ecmult_multi) {
secp256k1_scalar szero;
secp256k1_scalar sc[32];
secp256k1_ge pt[32];
secp256k1_gej r;
ecmult_multi_data data;
secp256k1_scratch *scratch_empty;
data.sc = sc;
data.pt = pt;
secp256k1_scalar_set_int(&szero, 0);
/* Try to multiply 1 point, but scratch space is empty.*/
scratch_empty = secp256k1_scratch_create(&ctx->error_callback, 0);
CHECK(!ecmult_multi(&ctx->error_callback, &ctx->ecmult_ctx, scratch_empty, &r, &szero, ecmult_multi_callback, &data, 1));
secp256k1_scratch_destroy(&ctx->error_callback, scratch_empty);
}
void test_secp256k1_pippenger_bucket_window_inv(void) {
int i;
@@ -3072,21 +3127,75 @@ void test_ecmult_multi_pippenger_max_points(void) {
int bucket_window = 0;
for(; scratch_size < max_size; scratch_size+=256) {
size_t i;
size_t total_alloc;
size_t checkpoint;
scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size);
CHECK(scratch != NULL);
n_points_supported = secp256k1_pippenger_max_points(scratch);
checkpoint = secp256k1_scratch_checkpoint(&ctx->error_callback, scratch);
n_points_supported = secp256k1_pippenger_max_points(&ctx->error_callback, scratch);
if (n_points_supported == 0) {
secp256k1_scratch_destroy(scratch);
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
continue;
}
bucket_window = secp256k1_pippenger_bucket_window(n_points_supported);
CHECK(secp256k1_scratch_allocate_frame(scratch, secp256k1_pippenger_scratch_size(n_points_supported, bucket_window), PIPPENGER_SCRATCH_OBJECTS));
secp256k1_scratch_deallocate_frame(scratch);
secp256k1_scratch_destroy(scratch);
/* allocate `total_alloc` bytes over `PIPPENGER_SCRATCH_OBJECTS` many allocations */
total_alloc = secp256k1_pippenger_scratch_size(n_points_supported, bucket_window);
for (i = 0; i < PIPPENGER_SCRATCH_OBJECTS - 1; i++) {
CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, 1));
total_alloc--;
}
CHECK(secp256k1_scratch_alloc(&ctx->error_callback, scratch, total_alloc));
secp256k1_scratch_apply_checkpoint(&ctx->error_callback, scratch, checkpoint);
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
}
CHECK(bucket_window == PIPPENGER_MAX_BUCKET_WINDOW);
}
void test_ecmult_multi_batch_size_helper(void) {
size_t n_batches, n_batch_points, max_n_batch_points, n;
max_n_batch_points = 0;
n = 1;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 0);
max_n_batch_points = 1;
n = 0;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == 0);
CHECK(n_batch_points == 0);
max_n_batch_points = 2;
n = 5;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == 3);
CHECK(n_batch_points == 2);
max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH;
n = ECMULT_MAX_POINTS_PER_BATCH;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == 1);
CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH);
max_n_batch_points = ECMULT_MAX_POINTS_PER_BATCH + 1;
n = ECMULT_MAX_POINTS_PER_BATCH + 1;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == 2);
CHECK(n_batch_points == ECMULT_MAX_POINTS_PER_BATCH/2 + 1);
max_n_batch_points = 1;
n = SIZE_MAX;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == SIZE_MAX);
CHECK(n_batch_points == 1);
max_n_batch_points = 2;
n = SIZE_MAX;
CHECK(secp256k1_ecmult_multi_batch_size_helper(&n_batches, &n_batch_points, max_n_batch_points, n) == 1);
CHECK(n_batches == SIZE_MAX/2 + 1);
CHECK(n_batch_points == 2);
}
/**
* Run secp256k1_ecmult_multi_var with num points and a scratch space restricted to
* 1 <= i <= num points.
@@ -3121,19 +3230,25 @@ void test_ecmult_multi_batching(void) {
}
data.sc = sc;
data.pt = pt;
secp256k1_gej_neg(&r2, &r2);
/* Test with empty scratch space */
/* Test with empty scratch space. It should compute the correct result using
* ecmult_mult_simple algorithm which doesn't require a scratch space. */
scratch = secp256k1_scratch_create(&ctx->error_callback, 0);
CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1));
secp256k1_scratch_destroy(scratch);
CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
/* Test with space for 1 point in pippenger. That's not enough because
* ecmult_multi selects strauss which requires more memory. */
* ecmult_multi selects strauss which requires more memory. It should
* therefore select the simple algorithm. */
scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_pippenger_scratch_size(1, 1) + PIPPENGER_SCRATCH_OBJECTS*ALIGNMENT);
CHECK(!secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, 1));
secp256k1_scratch_destroy(scratch);
CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
secp256k1_gej_neg(&r2, &r2);
for(i = 1; i <= n_points; i++) {
if (i > ECMULT_PIPPENGER_THRESHOLD) {
int bucket_window = secp256k1_pippenger_bucket_window(i);
@@ -3143,10 +3258,10 @@ void test_ecmult_multi_batching(void) {
size_t scratch_size = secp256k1_strauss_scratch_size(i);
scratch = secp256k1_scratch_create(&ctx->error_callback, scratch_size + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
}
CHECK(secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
CHECK(secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &r, &scG, ecmult_multi_callback, &data, n_points));
secp256k1_gej_add_var(&r, &r, &r2, NULL);
CHECK(secp256k1_gej_is_infinity(&r));
secp256k1_scratch_destroy(scratch);
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
}
free(sc);
free(pt);
@@ -3161,14 +3276,17 @@ void run_ecmult_multi_tests(void) {
test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
test_ecmult_multi(NULL, secp256k1_ecmult_multi_var);
test_ecmult_multi(scratch, secp256k1_ecmult_pippenger_batch_single);
test_ecmult_multi_batch_single(secp256k1_ecmult_pippenger_batch_single);
test_ecmult_multi(scratch, secp256k1_ecmult_strauss_batch_single);
secp256k1_scratch_destroy(scratch);
test_ecmult_multi_batch_single(secp256k1_ecmult_strauss_batch_single);
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
/* Run test_ecmult_multi with space for exactly one point */
scratch = secp256k1_scratch_create(&ctx->error_callback, secp256k1_strauss_scratch_size(1) + STRAUSS_SCRATCH_OBJECTS*ALIGNMENT);
test_ecmult_multi(scratch, secp256k1_ecmult_multi_var);
secp256k1_scratch_destroy(scratch);
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
test_ecmult_multi_batch_size_helper();
test_ecmult_multi_batching();
}
@@ -3238,7 +3356,7 @@ void test_constant_wnaf(const secp256k1_scalar *number, int w) {
}
bits = 128;
#endif
skew = secp256k1_wnaf_const(wnaf, num, w, bits);
skew = secp256k1_wnaf_const(wnaf, &num, w, bits);
for (i = WNAF_SIZE_BITS(bits, w); i >= 0; --i) {
secp256k1_scalar t;
@@ -4503,7 +4621,7 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_
if (valid_der) {
ret |= (!roundtrips_der_lax) << 12;
ret |= (len_der != len_der_lax) << 13;
ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14;
ret |= ((len_der != len_der_lax) || (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0)) << 14;
}
ret |= (roundtrips_der != roundtrips_der_lax) << 15;
if (parsed_der) {
@@ -4544,7 +4662,7 @@ int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_
ret |= (roundtrips_der != roundtrips_openssl) << 7;
if (roundtrips_openssl) {
ret |= (len_der != (size_t)len_openssl) << 8;
ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9;
ret |= ((len_der != (size_t)len_openssl) || (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0)) << 9;
}
#endif
return ret;
@@ -5252,8 +5370,9 @@ int main(int argc, char **argv) {
}
} else {
FILE *frand = fopen("/dev/urandom", "r");
if ((frand == NULL) || fread(&seed16, sizeof(seed16), 1, frand) != sizeof(seed16)) {
if ((frand == NULL) || fread(&seed16, 1, sizeof(seed16), frand) != sizeof(seed16)) {
uint64_t t = time(NULL) * (uint64_t)1337;
fprintf(stderr, "WARNING: could not read 16 bytes from /dev/urandom; falling back to insecure PRNG\n");
seed16[0] ^= t;
seed16[1] ^= t >> 8;
seed16[2] ^= t >> 16;

View File

@@ -212,14 +212,14 @@ void test_exhaustive_ecmult_multi(const secp256k1_context *ctx, const secp256k1_
data.pt[0] = group[x];
data.pt[1] = group[y];
secp256k1_ecmult_multi_var(&ctx->ecmult_ctx, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2);
secp256k1_ecmult_multi_var(&ctx->error_callback, &ctx->ecmult_ctx, scratch, &tmp, &g_sc, ecmult_multi_callback, &data, 2);
ge_equals_gej(&group[(i * x + j * y + k) % order], &tmp);
}
}
}
}
}
secp256k1_scratch_destroy(scratch);
secp256k1_scratch_destroy(&ctx->error_callback, scratch);
}
void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) {

View File

@@ -36,7 +36,7 @@ static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback *
} while(0)
#endif
#ifdef HAVE_BUILTIN_EXPECT
#if SECP256K1_GNUC_PREREQ(3, 0)
#define EXPECT(x,c) __builtin_expect((x),(c))
#else
#define EXPECT(x,c) (x)
@@ -84,32 +84,6 @@ static SECP256K1_INLINE void *checked_realloc(const secp256k1_callback* cb, void
return ret;
}
/* Extract the sign of an int64, take the abs and return a uint64, constant time. */
SECP256K1_INLINE static int secp256k1_sign_and_abs64(uint64_t *out, int64_t in) {
uint64_t mask0, mask1;
int ret;
ret = in < 0;
mask0 = ret + ~((uint64_t)0);
mask1 = ~mask0;
*out = (uint64_t)in;
*out = (*out & mask0) | ((~*out + 1) & mask1);
return ret;
}
SECP256K1_INLINE static int secp256k1_clz64_var(uint64_t x) {
int ret;
if (!x) {
return 64;
}
# if defined(HAVE_BUILTIN_CLZLL)
ret = __builtin_clzll(x);
# else
/*FIXME: debruijn fallback. */
for (ret = 0; ((x & (1ULL << 63)) == 0); x <<= 1, ret++);
# endif
return ret;
}
#if defined(__BIGGEST_ALIGNMENT__)
#define ALIGNMENT __BIGGEST_ALIGNMENT__
#else
@@ -151,6 +125,32 @@ static SECP256K1_INLINE void *manual_alloc(void** prealloc_ptr, size_t alloc_siz
return ret;
}
/* Extract the sign of an int64, take the abs and return a uint64, constant time. */
SECP256K1_INLINE static int secp256k1_sign_and_abs64(uint64_t *out, int64_t in) {
uint64_t mask0, mask1;
int ret;
ret = in < 0;
mask0 = ret + ~((uint64_t)0);
mask1 = ~mask0;
*out = (uint64_t)in;
*out = (*out & mask0) | ((~*out + 1) & mask1);
return ret;
}
SECP256K1_INLINE static int secp256k1_clz64_var(uint64_t x) {
int ret;
if (!x) {
return 64;
}
# if defined(HAVE_BUILTIN_CLZLL)
ret = __builtin_clzll(x);
# else
/*FIXME: debruijn fallback. */
for (ret = 0; ((x & (1ULL << 63)) == 0); x <<= 1, ret++);
# endif
return ret;
}
/* Macro for restrict, when available and not in a VERIFY build. */
#if defined(SECP256K1_BUILD) && defined(VERIFY)
# define SECP256K1_RESTRICT