The NAF computation can generate a 1 in the last digit (only) when s = 2^255-1,
so someone who manually constructed the value s = 2^255-1 and fed it into a NAF-using
computation could generate an incorrect result. Some version of this bug has
been present from the beginning of the library, but it has no security content,
because the NAF computations are not applied to secret data, and the error
occurs only on one value which is not constructed by any client caller.
When using Scalar::from_bits to manually create unreduced Scalars (e.g.,
X/Ed25519 keys with specified bit patterns), it's possible to construct Scalar
values that range up to 2^255-1. These shouldn't ever end up in a vartime
multiscalar mul call anyways, because it doesn't handle secret data, but it is
technically allowed by the type system and should be handled. When w=8, these
can generate terminal carries that can't be folded into the last digit, but
this can be handled by folding them into an extra digit instead.
This fixes a bug in the Pippenger implementation reported by Fernando Krell and
diagnosed by Oleg Andreev. The problem is that at the largest problem sizes
(using w=8), the signed digits fill the value range of an i8, and so doing
computation on them to calculate the bucket index can hit an overflow.
This was not caught in CI because the test suite didn't check all problem
sizes; tests for these sizes which expose this bug were added in the previous
commit.
This saves 4 point doublings by unwrapping the first loop iteration,
as well as 63 field multiplications (one per iteration) by managing
curve model choice explicitly.
Building the docs currently doesn't work, because rustdoc enables parts of the
code (to document them) which then don't check (because there are missing
exports or dependencies). This **should** fix the issue, but there's no way to
test without publishing a new version.
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.
Since computation of the 0 term in reduction requires a multiplication with a
4-cycle latency, this ensures that the rest of the computation can start before
the 0 term is finished
This splits the `FieldElement51x4` type into two types:
- `F51x4Reduced` (with reduced limbs)
- `F51x4Unreduced` (with unreduced limbs)
The reduction is implemented as a `From` impl to convert one type to the other.
The output of a multiplication is now a `F51x4Unreduced`. The reason is that
the inputs to IFMA operations must be at most 52 bits, so it's not possible to
perform an addition of (51+epsilon)-bit values and still be small enough to be
used as an input to multiplication. So, it doesn't make sense to perform a
reduction at the end of a multiplication, because the reduced values will be
fed into an addition or subtraction, which then needs to be re-reduced.