-
Notifications
You must be signed in to change notification settings - Fork 478
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pippenger multiscalar multiplication algorithm #249
Pippenger multiscalar multiplication algorithm #249
Conversation
@hdevalence could you please take a look at this line? https://github.com/dalek-cryptography/curve25519-dalek/pull/249/files#diff-40c9945ba2b4ac799c45803abe9da3bdR1031 If i remove it, the pseudo-random tests still pass. Even for |
Benchmarks:
|
Looks great! I'll check about the radix question. |
src/scalar.rs
Outdated
/// $$ | ||
/// with \\(-2\^w/2 \leq a_i < 2\^w/2\\) for \\(0 \leq i < (n-1)\\) and \\(-2\^w/2 \leq a_{n-1} \leq 2\^w/2\\). | ||
/// | ||
pub(crate) fn to_pippenger_radix(&self, w: usize) -> ([i8; 43], usize) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub(crate) fn to_pippenger_radix(&self, w: usize) -> ([i8; 43], usize) { | |
pub(crate) fn to_radix_2w(&self, w: usize) -> ([i8; 43], usize) { |
would match the naming scheme for to_radix_16
better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2w
also reads as 2*w
. I intentionally placed "pippenger" there to bring attention to it being highly specialized and not accepting arbitrary w
as an input. Any moment someone needs a slightly more general-purpose implementation, they should create a new method and not use this one.
How about to_radix_64_128_256
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried a few variants, and to_radix_2w
is the cleanest. It's private API anyway.
/// For large `n`, dominant factor is (n*256/w) additions. | ||
/// However, if `w` is too big and `n` is not too big, then `(2^w/2)*A` could dominate. | ||
/// Therefore, the optimal choice of `w` grows slowly as `n` grows. | ||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This documentation should maybe link to section 4 of https://eprint.iacr.org/2012/549.pdf which I believe is the original source of this special case of Pippenger's technique (which is very general).
Co-Authored-By: Henry de Valence <[email protected]>
@oleganza what's the issue with |
This branch looks good and I'd like to merge it and ship it as 1.2! |
i think it's that, yeah |
i'm fine with merging |
Currently supported Straus algorithm does not improve performance as input size grows and saturates at ≈4x improvement over naïve multiplication. Pippenger’s algorithm takes advantage of very large amount of points (>190) by avoiding premultiplication of points and instead placing points in the buckets indexed by the multiplication factor. Then, buckets are cleverly added up to have their multipliers applied automatically. The process is repeated for each "digit" (that are 6 to 8 bits wide, depending on number of input points). As a result, the cost of multiplication grows slower than linearly with respect to the input size. For 1024 points Pippenger is >40% faster than Straus.
To make the gains more relatable:
This patch adds:
VartimeMultiscalarMul
using Pippenger algorithm.size_hint()
from Straus to Pippenger (at 190 points).to_pippenger_radix
internal API to convert scalars into digits in radix 64, 128, or 256.This addresses issue #130 and replaces previous PR #129.