mirror of https://github.com/zcash/halo2.git
Reduce number of inversions by batch inverting when possible.
This commit is contained in:
parent
45491a21c9
commit
ff8f9eb20e
|
@ -32,6 +32,43 @@ pub trait Group: Copy + Clone + Send + Sync + 'static {
|
||||||
fn group_scale(&mut self, by: &Self::Scalar);
|
fn group_scale(&mut self, by: &Self::Scalar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extension trait for iterators over mutable field elements which allows those
|
||||||
|
/// field elements to be inverted in a batch.
|
||||||
|
pub trait BatchInvert<F: Field> {
|
||||||
|
/// Consume this iterator and invert each field element (when nonzero),
|
||||||
|
/// returning the inverse of all nonzero field elements.
|
||||||
|
fn batch_invert(self) -> F;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, F, I> BatchInvert<F> for I
|
||||||
|
where
|
||||||
|
F: Field,
|
||||||
|
I: IntoIterator<Item = &'a mut F>,
|
||||||
|
{
|
||||||
|
fn batch_invert(self) -> F {
|
||||||
|
let mut acc = F::one();
|
||||||
|
let mut iter = self.into_iter();
|
||||||
|
let mut tmp = Vec::with_capacity(iter.size_hint().0);
|
||||||
|
while let Some(p) = iter.next() {
|
||||||
|
let q = *p;
|
||||||
|
tmp.push((acc, p));
|
||||||
|
acc = F::conditional_select(&(acc * q), &acc, q.is_zero());
|
||||||
|
}
|
||||||
|
acc = acc.invert().unwrap();
|
||||||
|
let allinv = acc;
|
||||||
|
|
||||||
|
for (tmp, p) in tmp.into_iter().rev() {
|
||||||
|
let skip = p.is_zero();
|
||||||
|
|
||||||
|
let tmp = tmp * acc;
|
||||||
|
acc = F::conditional_select(&(acc * *p), &acc, skip);
|
||||||
|
*p = F::conditional_select(&tmp, p, skip);
|
||||||
|
}
|
||||||
|
|
||||||
|
allinv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is a 128-bit verifier challenge.
|
/// This is a 128-bit verifier challenge.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Challenge(pub(crate) u128);
|
pub struct Challenge(pub(crate) u128);
|
||||||
|
|
|
@ -4,8 +4,8 @@ use super::{
|
||||||
hash_point, Error, Proof, SRS,
|
hash_point, Error, Proof, SRS,
|
||||||
};
|
};
|
||||||
use crate::arithmetic::{
|
use crate::arithmetic::{
|
||||||
eval_polynomial, get_challenge_scalar, kate_division, parallelize, Challenge, Curve,
|
eval_polynomial, get_challenge_scalar, kate_division, parallelize, BatchInvert, Challenge,
|
||||||
CurveAffine, Field,
|
Curve, CurveAffine, Field,
|
||||||
};
|
};
|
||||||
use crate::polycommit::Params;
|
use crate::polycommit::Params;
|
||||||
use crate::transcript::Hasher;
|
use crate::transcript::Hasher;
|
||||||
|
@ -83,12 +83,16 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
|
|
||||||
// Compute commitments to advice wire polynomials
|
// Compute commitments to advice wire polynomials
|
||||||
let advice_blinds: Vec<_> = witness.advice.iter().map(|_| C::Scalar::random()).collect();
|
let advice_blinds: Vec<_> = witness.advice.iter().map(|_| C::Scalar::random()).collect();
|
||||||
let advice_commitments = witness
|
let advice_commitments_projective: Vec<_> = witness
|
||||||
.advice
|
.advice
|
||||||
.iter()
|
.iter()
|
||||||
.zip(advice_blinds.iter())
|
.zip(advice_blinds.iter())
|
||||||
.map(|(poly, blind)| params.commit_lagrange(poly, *blind).to_affine())
|
.map(|(poly, blind)| params.commit_lagrange(poly, *blind))
|
||||||
.collect();
|
.collect();
|
||||||
|
let mut advice_commitments = vec![C::zero(); advice_commitments_projective.len()];
|
||||||
|
C::Projective::batch_to_affine(&advice_commitments_projective, &mut advice_commitments);
|
||||||
|
let advice_commitments = advice_commitments;
|
||||||
|
drop(advice_commitments_projective);
|
||||||
|
|
||||||
for commitment in &advice_commitments {
|
for commitment in &advice_commitments {
|
||||||
hash_point(&mut transcript, commitment)?;
|
hash_point(&mut transcript, commitment)?;
|
||||||
|
@ -122,10 +126,11 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
let mut permutation_product_polys = vec![];
|
let mut permutation_product_polys = vec![];
|
||||||
let mut permutation_product_cosets = vec![];
|
let mut permutation_product_cosets = vec![];
|
||||||
let mut permutation_product_cosets_inv = vec![];
|
let mut permutation_product_cosets_inv = vec![];
|
||||||
let mut permutation_product_commitments = vec![];
|
let mut permutation_product_commitments_projective = vec![];
|
||||||
let mut permutation_product_blinds = vec![];
|
let mut permutation_product_blinds = vec![];
|
||||||
|
|
||||||
// Iterate over each permutation
|
// Iterate over each permutation
|
||||||
|
let mut permutation_modified_advice = vec![];
|
||||||
for (wires, permuted_values) in srs.meta.permutations.iter().zip(srs.permutations.iter()) {
|
for (wires, permuted_values) in srs.meta.permutations.iter().zip(srs.permutations.iter()) {
|
||||||
// Goal is to compute the fraction
|
// Goal is to compute the fraction
|
||||||
//
|
//
|
||||||
|
@ -154,12 +159,23 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
modified_advice.push(tmp_advice_values);
|
modified_advice.push(tmp_advice_values);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Batch invert to obtain the denominators for the permutation product
|
permutation_modified_advice.push(modified_advice);
|
||||||
// polynomial
|
}
|
||||||
for v in &mut modified_advice {
|
|
||||||
C::Scalar::batch_invert(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Batch invert to obtain the denominators for the permutation product
|
||||||
|
// polynomials
|
||||||
|
permutation_modified_advice
|
||||||
|
.iter_mut()
|
||||||
|
.flat_map(|v| v.iter_mut())
|
||||||
|
.flat_map(|v| v.iter_mut())
|
||||||
|
.batch_invert();
|
||||||
|
|
||||||
|
for (wires, mut modified_advice) in srs
|
||||||
|
.meta
|
||||||
|
.permutations
|
||||||
|
.iter()
|
||||||
|
.zip(permutation_modified_advice.into_iter())
|
||||||
|
{
|
||||||
// Iterate over each wire again, this time finishing the computation
|
// Iterate over each wire again, this time finishing the computation
|
||||||
// of the entire fraction by computing the numerators
|
// of the entire fraction by computing the numerators
|
||||||
let mut deltaomega = C::Scalar::one();
|
let mut deltaomega = C::Scalar::one();
|
||||||
|
@ -210,13 +226,21 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
|
|
||||||
let blind = C::Scalar::random();
|
let blind = C::Scalar::random();
|
||||||
|
|
||||||
permutation_product_commitments.push(params.commit_lagrange(&z, blind).to_affine());
|
permutation_product_commitments_projective.push(params.commit_lagrange(&z, blind));
|
||||||
permutation_product_blinds.push(blind);
|
permutation_product_blinds.push(blind);
|
||||||
let z = domain.obtain_poly(z);
|
let z = domain.obtain_poly(z);
|
||||||
permutation_product_polys.push(z.clone());
|
permutation_product_polys.push(z.clone());
|
||||||
permutation_product_cosets.push(domain.obtain_coset(z.clone(), Rotation::default()));
|
permutation_product_cosets.push(domain.obtain_coset(z.clone(), Rotation::default()));
|
||||||
permutation_product_cosets_inv.push(domain.obtain_coset(z, Rotation(-1)));
|
permutation_product_cosets_inv.push(domain.obtain_coset(z, Rotation(-1)));
|
||||||
}
|
}
|
||||||
|
let mut permutation_product_commitments =
|
||||||
|
vec![C::zero(); permutation_product_commitments_projective.len()];
|
||||||
|
C::Projective::batch_to_affine(
|
||||||
|
&permutation_product_commitments_projective,
|
||||||
|
&mut permutation_product_commitments,
|
||||||
|
);
|
||||||
|
let permutation_product_commitments = permutation_product_commitments;
|
||||||
|
drop(permutation_product_commitments_projective);
|
||||||
|
|
||||||
// Hash each permutation product commitment
|
// Hash each permutation product commitment
|
||||||
for c in &permutation_product_commitments {
|
for c in &permutation_product_commitments {
|
||||||
|
@ -351,11 +375,15 @@ impl<C: CurveAffine> Proof<C> {
|
||||||
let h_blinds: Vec<_> = h_pieces.iter().map(|_| C::Scalar::random()).collect();
|
let h_blinds: Vec<_> = h_pieces.iter().map(|_| C::Scalar::random()).collect();
|
||||||
|
|
||||||
// Compute commitments to each h(X) piece
|
// Compute commitments to each h(X) piece
|
||||||
let h_commitments: Vec<_> = h_pieces
|
let h_commitments_projective: Vec<_> = h_pieces
|
||||||
.iter()
|
.iter()
|
||||||
.zip(h_blinds.iter())
|
.zip(h_blinds.iter())
|
||||||
.map(|(h_piece, blind)| params.commit(&h_piece, *blind).to_affine())
|
.map(|(h_piece, blind)| params.commit(&h_piece, *blind))
|
||||||
.collect();
|
.collect();
|
||||||
|
let mut h_commitments = vec![C::zero(); h_commitments_projective.len()];
|
||||||
|
C::Projective::batch_to_affine(&h_commitments_projective, &mut h_commitments);
|
||||||
|
let h_commitments = h_commitments;
|
||||||
|
drop(h_commitments_projective);
|
||||||
|
|
||||||
// Hash each h(X) piece
|
// Hash each h(X) piece
|
||||||
for c in h_commitments.iter() {
|
for c in h_commitments.iter() {
|
||||||
|
|
Loading…
Reference in New Issue