* Apply Zeroize to nonces used in Bulletproofs
Also makes bit decomposition constant time for a given amount of
outputs.
* Fix nonce reuse for single-signer CLSAG
* Attach Zeroize to most structures in Monero, and ZOnDrop to anything with private data
* Zeroize private keys and nonces
* Merge prepare_outputs and prepare_transactions
* Ensure CLSAG is constant time
* Pass by borrow where needed, bug fixes
The past few commitments have been one in-progress chunk which I've
broken up as best read.
* Add Zeroize to FROST structs
Still needs to zeroize internally, yet next step. Not quite as
aggressive as Monero, partially due to the limitations of HashMaps,
partially due to less concern about metadata, yet does still delete a
few smaller items of metadata (group key, context string...).
* Remove Zeroize from most Monero multisig structs
These structs largely didn't have private data, just fields with private
data, yet those fields implemented ZeroizeOnDrop making them already
covered. While there is still traces of the transaction left in RAM,
fully purging that was never the intent.
* Use Zeroize within dleq
bitvec doesn't offer Zeroize, so a manual zeroing has been implemented.
* Use Zeroize for random_nonce
It isn't perfect, due to the inability to zeroize the digest, and due to
kp256 requiring a few transformations. It does the best it can though.
Does move the per-curve random_nonce to a provided one, which is allowed
as of https://github.com/cfrg/draft-irtf-cfrg-frost/pull/231.
* Use Zeroize on FROST keygen/signing
* Zeroize constant time multiexp.
* Correct when FROST keygen zeroizes
* Move the FROST keys Arc into FrostKeys
Reduces amount of instances in memory.
* Manually implement Debug for FrostCore to not leak the secret share
* Misc bug fixes
* clippy + multiexp test bug fixes
* Correct FROST key gen share summation
It leaked our own share for ourself.
* Fix cross-group DLEq tests
* Use a struct in an enum for Bulletproofs
* verification bp working for just one proof
* add some more assert tests
* Clean BP verification
* Implement batch verification
* Add a debug assertion w_cache isn't 0
It's initially set to 0 and if not updated, this would be broken.
* Correct Monero workflow yaml
* Again try to corrent Monero workflow yaml
* Again
* Finally
* Re-apply weights as required by Bulletproofs
Removing these was insecure and my fault.
Co-authored-by: DangerousFreedom <dangfreed@tutanota.com>
* Initial attempt at Bulletproofs
I don't know why this doesn't work. The generators and hash_cache lines
up without issue. AFAICT, the inner product proof is valid as well, as
are all included formulas.
* Add yinvpow asserts
* Clean code
* Correct bad imports
* Fix the definition of TWO_N
Bulletproofs work now :D
* Tidy up a bit
* fmt + clippy
* Compile a variety of XMR dependencies with optimizations, even under dev
The Rust bulletproof implementation is 8% slower than C right now, under
release. This is acceptable, even if suboptimal. Under debug, they take
a quarter of a second to two seconds though, depending on the amount of
outputs, which justifies this move.
* Remove unnecessary deref in BPs
Currently intended to be done with:
cargo clippy --features "recommended merlin batch serialize experimental
ed25519 ristretto p256 secp256k1 multisig" -- -A clippy::type_complexity
-A dead_code
The two-generator limit wasn't required nor beneficial. This does
theoretically optimize FROST, yet not for any current constructions. A
follow up proof which would optimize current constructions has been
noted in #38.
Adds explicit no_std support to the core DLEq proof.
Closes#34.
Removes from_canonical_bytes, which is offered by from_repr, and
from_bytes_mod_order, which frequently leads to security issues.
Removes the pointless Compressed type.
Adds From u8/u16/u32 as they're pleasant.
While all of Serai can be argued as experimental, the DLEq proof is
especially so, as it's lacking any formal proofs over its theory.
Also adds doc(hidden) to the generic DLEqProof, now prefixed with __.
This enabled getting the proof sizes, which are:
- ConciseLinear had a proof size of 44607 bytes
- CompromiseLinear had a proof size of 48765 bytes
- ClassicLinear had a proof size of 56829 bytes
- EfficientLinear had a proof size of 65145 byte
Formatted results from my laptop:
EfficientLinear had a average prove time of 188ms
EfficientLinear had a average verify time of 126ms
CompromiseLinear had a average prove time of 176ms
CompromiseLinear had a average verify time of 141ms
ConciseLinear had a average prove time of 191ms
ConciseLinear had a average verify time of 160ms
ClassicLinear had a average prove time of 214ms
ClassicLinear had a average verify time of 159ms
There is a decent error margin here. Concise is a drop-in replacement
for Classic, in practice *not* theory. Efficient is optimal for
performance, yet largest. Compromise is a middleground.
The batch verified one offers ~23% faster verification. While this
massively refactors for modularity, I'm still not happy with the DLEq
proofs at the top level, nor am I happy with the AOS signatures. I'll
work on cleaning them up more later.
Reduces proof size by 21.5% without notable computational complexity
changes. I wouldn't be surprised if it has minor ones, yet I can't
comment in which way they go without further review.
Bit now verifies it can successfully complete the ring under debug,
slightly increasing debug times.
Few percent faster. Enables accumulating the current bit's point
representation, whereas the blinding keys can't be accumulated. Also
theoretically enables pre-computation of the bit points, removing
hundreds of additions from the proof. When tested, this was less
performant, possibly due to cache/heap allocation.