From f2fc068db0ef0c2429812c3a0154b82c8334dfc5 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 15 Sep 2020 18:49:12 +0800 Subject: [PATCH] Implement small_multiexp() in arithmetic.rs --- src/arithmetic.rs | 33 +++++++++++++++++++++++++++++++++ src/poly/commitment/prover.rs | 18 +++++++----------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 312cfe5..afb186c 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -180,6 +180,39 @@ fn multiexp_serial(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(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. diff --git a/src/poly/commitment/prover.rs b/src/poly/commitment/prover.rs index 3acddc2..0349b28 100644 --- a/src/poly/commitment/prover.rs +++ b/src/poly/commitment/prover.rs @@ -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( 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); }