Skip to content

Commit

Permalink
refactor: Implement and integrate rlc function for simplified combi…
Browse files Browse the repository at this point in the history
…nation semantics

- Introduced a new function `rlc`, which implements Horner's scheme,
- Applied traits `Borrow`, `MulAssign`, and `AddAssign` to define it, which exist on `UniPoly`,
- Used `rlc` function in `evaluate` method and `kzg_compute_batch_polynomial`,
- Updated closures in `mlkzg.rs` file to directly handle vector arguments, simplifying the overall operations.
- Streamlined the code by eliminating unnecessary assertions in `kzg_verify_batch` closure and redundant inner function in `kzg_compute_batch_polynomial`.
  • Loading branch information
huitseeker committed Jan 13, 2024
1 parent 605f899 commit 37b8ee7
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 31 deletions.
19 changes: 19 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,32 @@ use r1cs::{
CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness,
};
use serde::{Deserialize, Serialize};
use std::borrow::Borrow;
use std::ops::{MulAssign, AddAssign};
use traits::{
circuit::StepCircuit,
commitment::{CommitmentEngineTrait, CommitmentTrait},
snark::RelaxedR1CSSNARKTrait,
AbsorbInROTrait, Engine, ROConstants, ROConstantsCircuit, ROTrait,
};

/// This function employs Horner's scheme and core traits to create a combination of an iterator input with the powers
/// of a provided coefficient.
pub(crate) fn rlc<T: Clone, F, K: Borrow<T>>(iter: impl DoubleEndedIterator<Item = K> , coefficient: F) -> T
where T: MulAssign<F> + for<'r> AddAssign<&'r T>, F: Copy,
{
let mut iter = iter.rev();
let Some(fst) = iter.next() else {
panic!("input iterator should not be empty")
};

iter.fold(fst.borrow().clone(), |mut acc, item| {
acc *= coefficient;
acc += item.borrow();
acc
})
}

/// A type that holds parameters for the primary and secondary circuits of Nova and SuperNova
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Abomonation)]
#[serde(bound = "")]
Expand Down
31 changes: 8 additions & 23 deletions src/provider/mlkzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
pedersen::Commitment,
traits::DlogGroup,
},
rlc,
spartan::polys::univariate::UniPoly,
traits::{
commitment::{CommitmentEngineTrait, Len},
Expand Down Expand Up @@ -164,30 +165,14 @@ where
.to_affine()
};

let kzg_open_batch = |f: &[Vec<E::Fr>],
let kzg_open_batch = |f: Vec<Vec<E::Fr>>,
u: &[E::Fr],
transcript: &mut <NE as NovaEngine>::TE|
-> (Vec<E::G1Affine>, Vec<Vec<E::Fr>>) {
let scalar_vector_muladd = |a: &mut Vec<E::Fr>, v: &Vec<E::Fr>, s: E::Fr| {
assert!(a.len() >= v.len());
#[allow(clippy::disallowed_methods)]
a.par_iter_mut()
.zip(v.par_iter())
.for_each(|(c, v)| *c += s * v);
};

let kzg_compute_batch_polynomial = |f: &[Vec<E::Fr>], q: E::Fr| -> Vec<E::Fr> {
let k = f.len(); // Number of polynomials we're batching

let q_powers = Self::batch_challenge_powers(q, k);

// Compute B(x) = f[0] + q*f[1] + q^2 * f[2] + ... q^(k-1) * f[k-1]
let mut B = f[0].clone();
for i in 1..k {
scalar_vector_muladd(&mut B, &f[i], q_powers[i]); // B += q_powers[i] * f[i]
}

B
let kzg_compute_batch_polynomial = |f: Vec<Vec<E::Fr>>, q: E::Fr| -> Vec<E::Fr> {
// Compute B(x) = f_0(x) + q * f_1(x) + ... + q^(k-1) * f_{k-1}(x)
let B: UniPoly<E::Fr> = rlc(f.into_iter().map(|poly| UniPoly::new(poly)), &q);
B.coeffs
};
///////// END kzg_open_batch closure helpers

Expand All @@ -199,7 +184,7 @@ where
let mut v = vec![vec!(E::Fr::ZERO; k); t];
v.par_iter_mut().enumerate().for_each(|(i, v_i)| {
// for each point u
v_i.par_iter_mut().zip_eq(f).for_each(|(v_ij, f)| {
v_i.par_iter_mut().zip_eq(&f).for_each(|(v_ij, f)| {
// for each poly f (except the last one - since it is constant)
*v_ij = UniPoly::ref_cast(f).evaluate(&u[i]);
});
Expand Down Expand Up @@ -259,7 +244,7 @@ where
let u = vec![r, -r, r * r];

// Phase 3 -- create response
let (w, evals) = kzg_open_batch(&polys, &u, transcript);
let (w, evals) = kzg_open_batch(polys, &u, transcript);

Ok(EvaluationArgument { comms, w, evals })
}
Expand Down
10 changes: 2 additions & 8 deletions src/spartan/polys/univariate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rayon::prelude::{IntoParallelIterator, IntoParallelRefMutIterator, ParallelI
use ref_cast::RefCast;
use serde::{Deserialize, Serialize};

use crate::traits::{Group, TranscriptReprTrait};
use crate::{traits::{Group, TranscriptReprTrait}, rlc};

// ax^2 + bx + c stored as vec![c, b, a]
// ax^3 + bx^2 + cx + d stored as vec![d, c, b, a]
Expand Down Expand Up @@ -131,13 +131,7 @@ impl<Scalar: PrimeField> UniPoly<Scalar> {
}

pub fn evaluate(&self, r: &Scalar) -> Scalar {
let mut eval = self.coeffs[0];
let mut power = *r;
for coeff in self.coeffs.iter().skip(1) {
eval += power * coeff;
power *= r;
}
eval
rlc(self.coeffs.iter(), *r)
}

pub fn compress(&self) -> CompressedUniPoly<Scalar> {
Expand Down

0 comments on commit 37b8ee7

Please sign in to comment.