2022-06-30 13:30:24 +00:00
|
|
|
use ff::PrimeFieldBits;
|
2022-06-07 04:02:10 +00:00
|
|
|
use group::Group;
|
2022-05-03 11:42:09 +00:00
|
|
|
|
2022-06-07 04:02:10 +00:00
|
|
|
mod straus;
|
|
|
|
use straus::*;
|
2022-05-27 04:52:44 +00:00
|
|
|
|
2022-06-07 04:02:10 +00:00
|
|
|
mod pippenger;
|
|
|
|
use pippenger::*;
|
2022-05-27 04:52:44 +00:00
|
|
|
|
2022-06-07 04:02:10 +00:00
|
|
|
#[cfg(feature = "batch")]
|
|
|
|
mod batch;
|
|
|
|
#[cfg(feature = "batch")]
|
|
|
|
pub use batch::BatchVerifier;
|
2022-05-03 11:42:09 +00:00
|
|
|
|
2022-06-30 13:30:24 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests;
|
|
|
|
|
|
|
|
pub(crate) fn prep_bits<G: Group>(
|
|
|
|
pairs: &[(G::Scalar, G)],
|
|
|
|
window: u8
|
|
|
|
) -> Vec<Vec<u8>> where G::Scalar: PrimeFieldBits {
|
|
|
|
let w_usize = usize::from(window);
|
|
|
|
|
|
|
|
let mut groupings = vec![];
|
|
|
|
for pair in pairs {
|
|
|
|
let p = groupings.len();
|
|
|
|
let bits = pair.0.to_le_bits();
|
|
|
|
groupings.push(vec![0; (bits.len() + (w_usize - 1)) / w_usize]);
|
|
|
|
|
|
|
|
for (i, bit) in bits.into_iter().enumerate() {
|
|
|
|
let bit = bit as u8;
|
|
|
|
debug_assert_eq!(bit | 1, 1);
|
|
|
|
groupings[p][i / w_usize] |= bit << (i % w_usize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
groupings
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(crate) fn prep_tables<G: Group>(
|
|
|
|
pairs: &[(G::Scalar, G)],
|
|
|
|
window: u8
|
|
|
|
) -> Vec<Vec<G>> {
|
|
|
|
let mut tables = Vec::with_capacity(pairs.len());
|
|
|
|
for pair in pairs {
|
|
|
|
let p = tables.len();
|
|
|
|
tables.push(vec![G::identity(); 2_usize.pow(window.into())]);
|
|
|
|
let mut accum = G::identity();
|
|
|
|
for i in 1 .. tables[p].len() {
|
|
|
|
accum += pair.1;
|
|
|
|
tables[p][i] = accum;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tables
|
|
|
|
}
|
|
|
|
|
2022-06-07 04:02:10 +00:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
|
|
enum Algorithm {
|
2022-07-07 04:22:19 +00:00
|
|
|
Null,
|
|
|
|
Single,
|
2022-06-30 13:30:24 +00:00
|
|
|
Straus(u8),
|
|
|
|
Pippenger(u8)
|
2022-05-27 04:52:44 +00:00
|
|
|
}
|
|
|
|
|
2022-06-30 13:30:24 +00:00
|
|
|
/*
|
|
|
|
Release (with runs 20, so all of these are off by 20x):
|
|
|
|
|
|
|
|
k256
|
|
|
|
Straus 3 is more efficient at 5 with 678µs per
|
|
|
|
Straus 4 is more efficient at 10 with 530µs per
|
|
|
|
Straus 5 is more efficient at 35 with 467µs per
|
|
|
|
|
|
|
|
Pippenger 5 is more efficient at 125 with 431µs per
|
|
|
|
Pippenger 6 is more efficient at 275 with 349µs per
|
|
|
|
Pippenger 7 is more efficient at 375 with 360µs per
|
|
|
|
|
|
|
|
dalek
|
|
|
|
Straus 3 is more efficient at 5 with 519µs per
|
|
|
|
Straus 4 is more efficient at 10 with 376µs per
|
|
|
|
Straus 5 is more efficient at 170 with 330µs per
|
|
|
|
|
|
|
|
Pippenger 5 is more efficient at 125 with 305µs per
|
|
|
|
Pippenger 6 is more efficient at 275 with 250µs per
|
|
|
|
Pippenger 7 is more efficient at 450 with 205µs per
|
|
|
|
Pippenger 8 is more efficient at 800 with 213µs per
|
|
|
|
|
|
|
|
Debug (with runs 5, so...):
|
|
|
|
|
|
|
|
k256
|
|
|
|
Straus 3 is more efficient at 5 with 2532µs per
|
|
|
|
Straus 4 is more efficient at 10 with 1930µs per
|
|
|
|
Straus 5 is more efficient at 80 with 1632µs per
|
|
|
|
|
|
|
|
Pippenger 5 is more efficient at 150 with 1441µs per
|
|
|
|
Pippenger 6 is more efficient at 300 with 1235µs per
|
|
|
|
Pippenger 7 is more efficient at 475 with 1182µs per
|
|
|
|
Pippenger 8 is more efficient at 625 with 1170µs per
|
|
|
|
|
|
|
|
dalek:
|
|
|
|
Straus 3 is more efficient at 5 with 971µs per
|
|
|
|
Straus 4 is more efficient at 10 with 782µs per
|
|
|
|
Straus 5 is more efficient at 75 with 778µs per
|
|
|
|
Straus 6 is more efficient at 165 with 867µs per
|
|
|
|
|
|
|
|
Pippenger 5 is more efficient at 125 with 677µs per
|
|
|
|
Pippenger 6 is more efficient at 250 with 655µs per
|
|
|
|
Pippenger 7 is more efficient at 475 with 500µs per
|
|
|
|
Pippenger 8 is more efficient at 875 with 499µs per
|
|
|
|
*/
|
|
|
|
fn algorithm(len: usize) -> Algorithm {
|
|
|
|
#[cfg(not(debug_assertions))]
|
2022-07-07 04:22:19 +00:00
|
|
|
if len == 0 {
|
|
|
|
Algorithm::Null
|
|
|
|
} else if len == 1 {
|
|
|
|
Algorithm::Single
|
|
|
|
} else if len < 10 {
|
2022-06-30 13:30:24 +00:00
|
|
|
// Straus 2 never showed a performance benefit, even with just 2 elements
|
|
|
|
Algorithm::Straus(3)
|
|
|
|
} else if len < 20 {
|
|
|
|
Algorithm::Straus(4)
|
|
|
|
} else if len < 50 {
|
|
|
|
Algorithm::Straus(5)
|
|
|
|
} else if len < 100 {
|
|
|
|
Algorithm::Pippenger(4)
|
|
|
|
} else if len < 125 {
|
|
|
|
Algorithm::Pippenger(5)
|
|
|
|
} else if len < 275 {
|
|
|
|
Algorithm::Pippenger(6)
|
|
|
|
} else if len < 400 {
|
|
|
|
Algorithm::Pippenger(7)
|
|
|
|
} else {
|
|
|
|
Algorithm::Pippenger(8)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(debug_assertions)]
|
2022-07-07 06:40:04 +00:00
|
|
|
if len == 0 {
|
|
|
|
Algorithm::Null
|
|
|
|
} else if len == 1 {
|
|
|
|
Algorithm::Single
|
|
|
|
} else if len < 10 {
|
2022-06-30 13:30:24 +00:00
|
|
|
Algorithm::Straus(3)
|
|
|
|
} else if len < 80 {
|
|
|
|
Algorithm::Straus(4)
|
|
|
|
} else if len < 100 {
|
|
|
|
Algorithm::Straus(5)
|
|
|
|
} else if len < 125 {
|
|
|
|
Algorithm::Pippenger(4)
|
|
|
|
} else if len < 275 {
|
|
|
|
Algorithm::Pippenger(5)
|
|
|
|
} else if len < 475 {
|
|
|
|
Algorithm::Pippenger(6)
|
|
|
|
} else if len < 750 {
|
|
|
|
Algorithm::Pippenger(7)
|
2022-06-07 04:02:10 +00:00
|
|
|
} else {
|
2022-06-30 13:30:24 +00:00
|
|
|
Algorithm::Pippenger(8)
|
2022-05-03 11:42:09 +00:00
|
|
|
}
|
2022-05-27 04:52:44 +00:00
|
|
|
}
|
|
|
|
|
2022-06-07 04:02:10 +00:00
|
|
|
// Performs a multiexp, automatically selecting the optimal algorithm based on amount of pairs
|
2022-06-30 13:30:24 +00:00
|
|
|
pub fn multiexp<G: Group>(pairs: &[(G::Scalar, G)]) -> G where G::Scalar: PrimeFieldBits {
|
2022-06-07 04:02:10 +00:00
|
|
|
match algorithm(pairs.len()) {
|
2022-07-07 04:22:19 +00:00
|
|
|
Algorithm::Null => Group::identity(),
|
|
|
|
Algorithm::Single => pairs[0].1 * pairs[0].0,
|
2022-06-30 13:30:24 +00:00
|
|
|
Algorithm::Straus(window) => straus(pairs, window),
|
|
|
|
Algorithm::Pippenger(window) => pippenger(pairs, window)
|
2022-05-03 11:42:09 +00:00
|
|
|
}
|
|
|
|
}
|
2022-05-27 04:52:44 +00:00
|
|
|
|
2022-06-30 13:30:24 +00:00
|
|
|
pub fn multiexp_vartime<G: Group>(pairs: &[(G::Scalar, G)]) -> G where G::Scalar: PrimeFieldBits {
|
2022-06-07 04:02:10 +00:00
|
|
|
match algorithm(pairs.len()) {
|
2022-07-07 04:22:19 +00:00
|
|
|
Algorithm::Null => Group::identity(),
|
|
|
|
Algorithm::Single => pairs[0].1 * pairs[0].0,
|
2022-06-30 13:30:24 +00:00
|
|
|
Algorithm::Straus(window) => straus_vartime(pairs, window),
|
|
|
|
Algorithm::Pippenger(window) => pippenger_vartime(pairs, window)
|
2022-05-27 04:52:44 +00:00
|
|
|
}
|
|
|
|
}
|