Add WnafBase::multiscalar_mul#82
Conversation
Computes a sum-of-products `aA + bB + ...` in variable time with w-NAF
multi-exponentiation using the interleaved window method, also known
as Straus' method.
The key insight is that when computing this sum by means of additions
and doublings, the doublings can be shared by performing the additions
within an inner loop.
The API and implementation are inspired in part by `curve25519-dalek`,
namely the `VartimeMultiscalarMul` trait and corresponding
implementation in `straus.rs`.
This results in ~28% speedup on `p256` for a 3 scalar/point input:
ProjectivePoint operations/point-scalar lincomb (variable-time)
time: [149.13 µs 149.80 µs 150.84 µs]
change: [−27.999% −27.645% −27.267%] (p = 0.00 < 0.05)
WnafBase::multiscalar_mul (#14)WnafBase::multiscalar_mul
| /// Perform a multiscalar multiplication. | ||
| pub fn multiscalar_mul<'a, I, J>(scalars: I, bases: J) -> G |
There was a problem hiding this comment.
referencing dalek (VartimeMultiscalarMul trait and corresponding impl in straus.rs), there's explicit timing language there. suggest a timing note that this runs in variable time and not be used with secret scalars (dalek frames it as operating on "public scalars"). maybe also rename to vartime_multiscalar_mul?
There was a problem hiding this comment.
We tend to put vartime at the end of the method names BTW.
There was a problem hiding this comment.
gotcha, suggestion was matching dalek's naming convention.
There was a problem hiding this comment.
FWIW we also use *_vartime as a suffix in @RustCrypto projects. When looking at something like rustdoc it makes it easier to discover operations have constant time and variable time versions
| /// This function must be provided with `tables` and `wnafs` that were constructed with | ||
| /// the same window size; otherwise, it may panic or produce invalid results. | ||
| pub(crate) fn wnaf_multi_exp<G: Group>(tables: &[&[G]], wnafs: &[&[i64]]) -> G { | ||
| debug_assert_eq!(tables.len(), wnafs.len()); |
There was a problem hiding this comment.
promote to release assertion for mismatched lengths.
There was a problem hiding this comment.
At least for now it's not possible to trip this assertion as the equality is enforced at the type system level where WnafBase and WnafScalar have a const generic WINDOW_SIZE that's ensured equal by bounds.
I can promote it, but really it's belt-and-suspenders.
| /// | ||
| /// This function must be provided with `tables` and `wnafs` that were constructed with | ||
| /// the same window size; otherwise, it may panic or produce invalid results. | ||
| pub(crate) fn wnaf_multi_exp<G: Group>(tables: &[&[G]], wnafs: &[&[i64]]) -> G { |
There was a problem hiding this comment.
ACK – traced the impl; extends wNAF to MSM via Straus' method: (N * (doublings + adds)) to (doublings + (N * adds)), where N is # LC terms. doubling savings from interleaving windows (and it stacks on existing addition savings that use signed digits). fine for small MSMs, but obviously for larger N a hand rolled Pippenger impl downstream.
generated some of my own test vectors locally, but suggesting multiscalar coverage for wnaf_multi_exp / multiscalar_mul in the diff.
There was a problem hiding this comment.
The wNAF implementations in both curve25519-dalek and libsecp256k1 provide both Straus and Pippenger and select between them at runtime, which would probably be ideal here as well, but that first needs a generic implementation of Pippenger
| /// the same window size; otherwise, it may panic or produce invalid results. | ||
| pub(crate) fn wnaf_multi_exp<G: Group>(tables: &[&[G]], wnafs: &[&[i64]]) -> G { | ||
| debug_assert_eq!(tables.len(), wnafs.len()); | ||
| let window_size = wnafs.iter().map(|w| w.len()).max().unwrap_or(0); |
There was a problem hiding this comment.
What would you suggest instead?
| where | ||
| I: Iterator<Item = &'a WnafScalar<G::Scalar, WINDOW_SIZE>>, | ||
| J: Iterator<Item = &'a Self>, |
|
we can reopen this and target base branch to a |
|
@TalDerei do you mean retarget to Edit: oh, 0.14.1. Every patch release is getting its own branch? |
|
Reopened as #85 |
Computes a sum-of-products
aA + bB + ...in variable time with w-NAF multi-exponentiation using the interleaved window method, also known as Straus' method.The key insight is that when computing this sum by means of additions and doublings, the doublings can be shared by performing the additions within an inner loop.
The API and implementation are inspired in part by
curve25519-dalek, namely theVartimeMultiscalarMultrait and corresponding implementation instraus.rs.This results in ~28% speedup on
p256for a 3 scalar/point input:See also: RustCrypto#14