Skip to content

Commit

Permalink
Improve API and possible speedup
Browse files Browse the repository at this point in the history
  • Loading branch information
Pratyush committed Dec 29, 2020
1 parent 3856133 commit e0a9ff4
Showing 1 changed file with 32 additions and 43 deletions.
75 changes: 32 additions & 43 deletions ec/src/msm/variable_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@ use rayon::prelude::*;
pub struct VariableBaseMSM;

impl VariableBaseMSM {
fn msm_inner<G: AffineCurve>(
pub fn multi_scalar_mul<G: AffineCurve>(
bases: &[G],
scalars: &[<G::ScalarField as PrimeField>::BigInt],
) -> G::Projective
where
G::Projective: ProjectiveCurve<Affine = G>,
{
) -> G::Projective {
let c = if scalars.len() < 32 {
3
} else {
Expand All @@ -28,6 +25,11 @@ impl VariableBaseMSM {
let zero = G::Projective::zero();
let window_starts: Vec<_> = (0..num_bits).step_by(c).collect();

let size = ark_std::cmp::min(bases.len(), scalars.len());
let scalars = &scalars[..size];
let bases = &bases[..size];
let scalars_and_bases = scalars.iter().zip(bases).filter(|(s, _)| !s.is_zero());

// Each window is of size `c`.
// We divide up the bits 0..num_bits into windows of size `c`, and
// in parallel process each such window.
Expand All @@ -36,42 +38,36 @@ impl VariableBaseMSM {
let mut res = zero;
// We don't need the "zero" bucket, so we only have 2^c - 1 buckets
let mut buckets = vec![zero; (1 << c) - 1];
scalars
.iter()
.zip(bases)
.filter(|(s, _)| !s.is_zero())
.for_each(|(&scalar, base)| {
if scalar == fr_one {
// We only process unit scalars once in the first window.
if w_start == 0 {
res.add_assign_mixed(base);
}
} else {
let mut scalar = scalar;
scalars_and_bases.clone().for_each(|(&scalar, base)| {
if scalar == fr_one {
// We only process unit scalars once in the first window.
if w_start == 0 {
res.add_assign_mixed(base);
}
} else {
let mut scalar = scalar;

// We right-shift by w_start, thus getting rid of the
// lower bits.
scalar.divn(w_start as u32);
// We right-shift by w_start, thus getting rid of the
// lower bits.
scalar.divn(w_start as u32);

// We mod the remaining bits by the window size.
let scalar = scalar.as_ref()[0] % (1 << c);
// We mod the remaining bits by the window size.
let scalar = scalar.as_ref()[0] % (1 << c);

// If the scalar is non-zero, we update the corresponding
// bucket.
// (Recall that `buckets` doesn't have a zero bucket.)
if scalar != 0 {
buckets[(scalar - 1) as usize].add_assign_mixed(base);
}
// If the scalar is non-zero, we update the corresponding
// bucket.
// (Recall that `buckets` doesn't have a zero bucket.)
if scalar != 0 {
buckets[(scalar - 1) as usize].add_assign_mixed(base);
}
});
let buckets = G::Projective::batch_normalization_into_affine(&buckets);
}
});

let mut running_sum = G::Projective::zero();
for b in buckets.into_iter().rev() {
running_sum.add_assign_mixed(&b);
res += running_sum;
}

buckets.into_iter().rev().for_each(|b| {
running_sum += &b;
res += &running_sum;
});
res
})
.collect();
Expand All @@ -81,7 +77,7 @@ impl VariableBaseMSM {

// We're traversing windows from high to low.
lowest
+ window_sums[1..]
+ &window_sums[1..]
.iter()
.rev()
.fold(zero, |mut total, sum_i| {
Expand All @@ -92,11 +88,4 @@ impl VariableBaseMSM {
total
})
}

pub fn multi_scalar_mul<G: AffineCurve>(
bases: &[G],
scalars: &[<G::ScalarField as PrimeField>::BigInt],
) -> G::Projective {
Self::msm_inner(bases, scalars)
}
}

0 comments on commit e0a9ff4

Please sign in to comment.