This doesn't (yet) give any speedup over the non-precomputed multiscalar
multiplication, and it's not clear that it's a good idea to commit to
supporting it in the future. Removing it means that it's not committed-to as
part of the public API, but the source is still there in the tree if we want to
revisit it later.
This begins to attempt to restructure the source tree so that the common parts
are common and the different parts are different.
The backend is now split into two parts:
- serial (containing the implementation using serial formulas and mixed-model arithmetic).
- vector (containing the implementation using parallel formulas and single-model arithmetic).
The serial scalar_mul tree is now under backend::serial::scalar_mul.
The avx2 scalar_mul tree is now under backend::avx2::scalar_mul.
This partially re-adds functionality removed in commit
d2ce1ce5dc
We would like to require ExactSizeIterator, but unfortunately we can't
do that, since ExactSizeIterators aren't chainable, for (in my opinion)
silly reasons (chaining two 4-billion-element ExactSizeIterators could
overflow on 32-bit systems). Instead we inspect the size hints manually
and assert that the lower and upper bounds are all equal.
This change provides a common convention for using allocator-dependent
features with:
#![cfg(feature = "alloc")]
When available, `Vec` is imported consistently as `prelude::Vec`, which
means modules that need access to `Vec` can simply do:
use prelude::*;
and if an allocator is available, `Vec` will be in the crate prelude.
This allows all `alloc` vs `std` gating to be handled in `lib.rs`,
`build.rs`, and `prelude.rs` so the rest of the codebase doesn't have to
do any gating whatsoever.
Unfortunately, Rust selects `i32` as the type for an integer literal
when the literal has no other type constraints. This means that someone
cannot write `Scalar::from(1)`, as Rust will choose `i32` as the type for
`1`, and we don't `impl From<i32> for Scalar`.
We could implement `From` conversions for signed integers, but since
`Scalar` operations should be constant-time by default, this would
require us to extract the sign bit of the integer and use it to
conditionally select between the positive and negative of Scalar
constructed from the value bits. This is more expensive than the
unsigned operation, and I don't think it's what anyone really wants.
Making API consumers specify that their literals are unsigned is
slightly annoying, but better than the above alternative.
It would also be nice to change `Scalar::from_hash` to be
`impl<D: Digest<OutputSize = U64>> From<D> for Scalar`,
but this isn't currently allowed by Rust (since that `impl` "could"
conflict with the `impl From<u8>` if someone decided that `u8` should
`impl Digest`).
This changes the primary function for the `VartimeMultiscalarMul` trait
to an `optional_multiscalar_mul` trait that accepts
`Option<Self::Point>` (and returns `None` if any input points are
`None`).
The existing `vartime_multiscalar_mul` is changed to be a wrapper around
this function to avoid code duplication. This may result in an
extra copy of each input point, but that cost is probably not
significant compared to the cost of the multiscalar multiplication.
The motivation is to allow performing multiscalar multiplications with
inline decompression. Currently, API consumers have to allocate
temporary buffers for all of their points, decompress into those
buffers, then pass (iterators over) those buffers into the multiscalar
multiplication code, which then creates new buffers for lookup tables.
These traits have the same interface, but with different names, so that it's
not possible to use them interchangeably. (Constant-time and variable-time
routines should not be used interchangeably).
This commit changes the external API to use these traits, replacing
```
edwards::multiscalar_mul
edwards::vartime::multiscalar_mul
```
with
```
EdwardsPoint::multiscalar_mul (as an impl)
EdwardsPoint::vartime_multiscalar_mul (as an impl)
```
and similarly for Ristretto.
Refactoring the backend is for a later commit.
Multiscalar multiplication with precomputation is for a later commit.
The `edwards::vartime` module is retained since it's used for
`vartime_double_base_scalar_mul`.
It should be subsumed into the precomputation API in a later commit.
Each backend can now be selected by an individual feature:
- `u32_backend` for `backend::u32`;
- `u64_backend` for `backend::u64`;
- `avx2_backend` for `backend::avx2`;
The `u64_backend` is selected by default, since most people use X64 and we have
no way to select based on target (see discussion in #126). However, these
changes mean that it is possible to select the backend explicitly, and if we
had the ability to select target-default features, we could do so easily.
The serial (`u32`/`u64`) implementations use a multiple curve models, passing
between extended and projective coordinates when performing addition and
doubling (respectively). But the AVX2 backend doesn't, so in order to write a
single scalar mult implementation, we have to either abstract over the curve
models or have two implementations.
A generic solution is possible but extremely unreadable: the scalar mul
implementation would be parameterized over the point types used by the serial
implementations, with many where clauses describing how the types relate. The
AVX2 types could then be substituted in the appropriate places.
Instead we just duplicate the code into the `avx2` backend.
This should contain generic implementations of scalar multiplication algorithms
that can be used with multiple backends. The goal is to move the existing
scalar multiplication code into this submodule, then call it from the
user-facing API. This can also contain code for things we can't do now, like
multiscalar multiplication with precomputation.
Since Criterion can only benchmark public API, these changes just drop
all internal benchmarks (e.g., benchmarks for field operations). But
those are usually microbenchmarks whose meaning is kind of questionable
anyways, so I don't think this is a big loss.
The `bench` feature disappears, since Criterion works on stable Rust.