Implement small_multiexp() in arithmetic.rs

This commit is contained in:
therealyingtong 2020-09-15 18:49:12 +08:00
parent 153f721c1d
commit f2fc068db0
No known key found for this signature in database
GPG key ID: 179F32A1503D607E
2 changed files with 40 additions and 11 deletions

View file

@ -180,6 +180,39 @@ fn multiexp_serial<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C], acc: &mut
}
}
/// Performs a small multi-exponentiation operation.
/// Uses the double-and-add algorithm with doublings shared across points.
pub fn small_multiexp<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C]) -> C::Projective {
// Gets the bit at position `i`. Bits are numbered from 0 (least significant) to 7 (most significant).
fn get_bit_at(byte: u8, i: usize) -> bool {
if i < 8 {
((byte >> i) & 1u8) != 0
} else {
false
}
}
let coeffs: Vec<[u8; 32]> = coeffs.iter().map(|a| a.to_bytes()).collect();
let mut acc = C::Projective::zero();
// for byte idx
for byte_idx in (0..32).rev() {
// for bit idx
for bit_idx in (0..8).rev() {
acc = acc.double();
// for each coeff
for coeff_idx in 0..coeffs.len() {
if get_bit_at(coeffs[coeff_idx][byte_idx], bit_idx) {
acc = acc + &bases[coeff_idx].to_projective();
}
}
}
}
acc
}
/// Performs a multi-exponentiation operation.
///
/// This function will panic if coeffs and bases have a different length.

View file

@ -1,7 +1,7 @@
use super::super::{Coeff, Polynomial};
use super::{Blind, OpeningProof, Params};
use crate::arithmetic::{
best_multiexp, compute_inner_product, get_challenge_scalar, parallelize, Challenge, Curve,
best_multiexp, compute_inner_product, get_challenge_scalar, small_multiexp, Challenge, Curve,
CurveAffine, Field,
};
use crate::transcript::Hasher;
@ -220,15 +220,11 @@ fn parallel_generator_collapse<C: CurveAffine>(
challenge_inv: C::Scalar,
) {
let len = g.len() / 2;
let (mut g_lo, g_hi) = g.split_at_mut(len);
let (g_lo, g_hi) = g.split_at_mut(len);
parallelize(&mut g_lo, |g_lo, start| {
let g_hi = &g_hi[start..];
let mut tmp = Vec::with_capacity(g_lo.len());
for (g_lo, g_hi) in g_lo.iter().zip(g_hi.iter()) {
// TODO: could use multiexp
tmp.push(((*g_lo) * challenge_inv) + &((*g_hi) * challenge));
}
C::Projective::batch_to_affine(&tmp, g_lo);
});
let mut tmp = Vec::with_capacity(g_lo.len());
for (g_lo, g_hi) in g_lo.iter().zip(g_hi.iter()) {
tmp.push(small_multiexp(&[challenge_inv, challenge], &[*g_lo, *g_hi]));
}
C::Projective::batch_to_affine(&tmp, g_lo);
}