Skip to content

Commit

Permalink
optimize LCCCS::check_relation & CCCS::check_relation, and remove unn…
Browse files Browse the repository at this point in the history
…essary methods after last reimplementations
  • Loading branch information
arnaucube committed Jun 5, 2024
1 parent 80b4948 commit ad51c01
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 149 deletions.
69 changes: 20 additions & 49 deletions folding-schemes/src/folding/hypernova/cccs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,17 @@ use ark_ec::CurveGroup;
use ark_ff::PrimeField;
use ark_std::One;
use ark_std::Zero;
use std::ops::Add;
use std::sync::Arc;

use ark_std::rand::Rng;

use super::utils::compute_sum_Mz;
use crate::ccs::CCS;
use crate::commitment::{
pedersen::{Params as PedersenParams, Pedersen},
CommitmentScheme,
};
use crate::utils::hypercube::BooleanHypercube;
use crate::utils::mle::dense_vec_to_dense_mle;
use crate::utils::mle::matrix_to_dense_mle;
use crate::utils::mle::vec_to_dense_mle;
use crate::utils::vec::mat_vec_mul;
use crate::utils::virtual_polynomial::{build_eq_x_r_vec, VirtualPolynomial};
use crate::Error;
Expand Down Expand Up @@ -63,61 +59,35 @@ impl<F: PrimeField> CCS<F> {

/// Computes q(x) = \sum^q c_i * \prod_{j \in S_i} ( \sum_{y \in {0,1}^s'} M_j(x, y) * z(y) )
/// polynomial over x
pub fn compute_q(&self, z: &[F]) -> VirtualPolynomial<F> {
let z_mle = vec_to_dense_mle(self.s_prime, z);
let mut q = VirtualPolynomial::<F>::new(self.s);

pub fn compute_q(&self, z: &[F]) -> Result<VirtualPolynomial<F>, Error> {
let mut q_x = VirtualPolynomial::<F>::new(self.s);
for i in 0..self.q {
let mut prod: VirtualPolynomial<F> = VirtualPolynomial::<F>::new(self.s);
for j in self.S[i].clone() {
let M_j = matrix_to_dense_mle(self.M[j].clone());

let sum_Mz = compute_sum_Mz(M_j, &z_mle, self.s_prime);

// Fold this sum into the running product
if prod.products.is_empty() {
// If this is the first time we are adding something to this virtual polynomial, we need to
// explicitly add the products using add_mle_list()
// XXX is this true? improve API
prod.add_mle_list([Arc::new(sum_Mz)], F::one()).unwrap();
} else {
prod.mul_by_mle(Arc::new(sum_Mz), F::one()).unwrap();
}
let mut Q_k = vec![];
for &j in self.S[i].iter() {
Q_k.push(dense_vec_to_dense_mle(self.s, &mat_vec_mul(&self.M[j], z)?));
}
// Multiply by the product by the coefficient c_i
prod.scalar_mul(&self.c[i]);
// Add it to the running sum
q = q.add(&prod);
q_x.add_mle_list(Q_k.iter().map(|v| Arc::new(v.clone())), self.c[i])?;
}
q
}

pub fn compute_Q_OLD(&self, z: &[F], beta: &[F]) -> VirtualPolynomial<F> {
let q = self.compute_q(z);
q.build_f_hat(beta).unwrap()
Ok(q_x)
}

/// Computes Q(x) = eq(beta, x) * q(x)
/// = eq(beta, x) * \sum^q c_i * \prod_{j \in S_i} ( \sum_{y \in {0,1}^s'} M_j(x, y) * z(y) )
/// polynomial over x
pub fn compute_Q(&self, z: &[F], beta: &[F]) -> VirtualPolynomial<F> {
let eq_beta = build_eq_x_r_vec(beta).unwrap();
pub fn compute_Q(&self, z: &[F], beta: &[F]) -> Result<VirtualPolynomial<F>, Error> {
let eq_beta = build_eq_x_r_vec(beta)?;
let eq_beta_mle = dense_vec_to_dense_mle(self.s, &eq_beta);

let mut Q = VirtualPolynomial::<F>::new(self.s);
for i in 0..self.q {
let mut Q_k = vec![];
for &j in self.S[i].iter() {
Q_k.push(dense_vec_to_dense_mle(
self.s,
&mat_vec_mul(&self.M[j], z).unwrap(),
));
Q_k.push(dense_vec_to_dense_mle(self.s, &mat_vec_mul(&self.M[j], z)?));
}
Q_k.push(eq_beta_mle.clone());
Q.add_mle_list(Q_k.iter().map(|v| Arc::new(v.clone())), self.c[i])
.unwrap();
Q.add_mle_list(Q_k.iter().map(|v| Arc::new(v.clone())), self.c[i])?;
}
Q
Ok(Q)
}
}

Expand All @@ -140,9 +110,10 @@ impl<C: CurveGroup> CCCS<C> {
[vec![C::ScalarField::one()], self.x.clone(), w.w.to_vec()].concat();

// A CCCS relation is satisfied if the q(x) multivariate polynomial evaluates to zero in the hypercube
let q_x = ccs.compute_q(&z);
let q_x = ccs.compute_q(&z)?;

for x in BooleanHypercube::new(ccs.s) {
if !q_x.evaluate(&x).unwrap().is_zero() {
if !q_x.evaluate(&x)?.is_zero() {
return Err(Error::NotSatisfied);
}
}
Expand All @@ -169,7 +140,7 @@ pub mod tests {
let ccs = get_test_ccs::<Fr>();
let z = get_test_z(3);

let q = ccs.compute_q(&z);
let q = ccs.compute_q(&z).unwrap();

// Evaluate inside the hypercube
for x in BooleanHypercube::new(ccs.s) {
Expand All @@ -193,7 +164,7 @@ pub mod tests {
let beta: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();

// Compute Q(x) = eq(beta, x) * q(x).
let Q = ccs.compute_Q(&z, &beta);
let Q = ccs.compute_Q(&z, &beta).unwrap();

// Let's consider the multilinear polynomial G(x) = \sum_{y \in {0, 1}^s} eq(x, y) q(y)
// which interpolates the multivariate polynomial q(x) inside the hypercube.
Expand Down Expand Up @@ -226,9 +197,9 @@ pub mod tests {

// Now test that if we create Q(x) with eq(d,y) where d is inside the hypercube, \sum Q(x) should be G(d) which
// should be equal to q(d), since G(x) interpolates q(x) inside the hypercube
let q = ccs.compute_q(&z);
let q = ccs.compute_q(&z).unwrap();
for d in BooleanHypercube::new(ccs.s) {
let Q_at_d = ccs.compute_Q(&z, &d);
let Q_at_d = ccs.compute_Q(&z, &d).unwrap();

// Get G(d) by summing over Q_d(x) over the hypercube
let G_at_d = BooleanHypercube::new(ccs.s)
Expand All @@ -239,7 +210,7 @@ pub mod tests {

// Now test that they should disagree outside of the hypercube
let r: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();
let Q_at_r = ccs.compute_Q(&z, &r);
let Q_at_r = ccs.compute_Q(&z, &r).unwrap();

// Get G(d) by summing over Q_d(x) over the hypercube
let G_at_r = BooleanHypercube::new(ccs.s)
Expand Down
3 changes: 2 additions & 1 deletion folding-schemes/src/folding/hypernova/circuits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,8 @@ mod tests {
.map(|lcccs| lcccs.r_x.clone())
.collect(),
&r_x_prime,
);
)
.unwrap();

let cs = ConstraintSystem::<Fr>::new_ref();
let mut vec_sigmas = Vec::new();
Expand Down
18 changes: 9 additions & 9 deletions folding-schemes/src/folding/hypernova/lcccs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use ark_poly::MultilinearExtension;
use ark_std::rand::Rng;

use super::cccs::Witness;
use super::utils::compute_all_sum_Mz_evals;
use crate::ccs::CCS;
use crate::commitment::{
pedersen::{Params as PedersenParams, Pedersen},
Expand All @@ -32,9 +31,6 @@ pub struct LCCCS<C: CurveGroup> {
}

impl<F: PrimeField> CCS<F> {
/// Compute v_j values of the linearized committed CCS form
/// Given `r`, compute: \sum_{y \in {0,1}^s'} M_j(r, y) * z(y)
pub fn to_lcccs<R: Rng, C: CurveGroup>(
&self,
rng: &mut R,
Expand All @@ -51,10 +47,6 @@ impl<F: PrimeField> CCS<F> {

let r_x: Vec<C::ScalarField> = (0..self.s).map(|_| C::ScalarField::rand(rng)).collect();

let mut Mzs = vec![];
for M_j in self.M.iter() {
Mzs.push(dense_vec_to_dense_mle(self.s, &mat_vec_mul(M_j, z)?));
}
let Mzs: Vec<DenseMultilinearExtension<F>> = self
.M
.iter()
Expand Down Expand Up @@ -96,7 +88,15 @@ impl<C: CurveGroup> LCCCS<C> {

// check CCS relation
let z: Vec<C::ScalarField> = [vec![self.u], self.x.clone(), w.w.to_vec()].concat();
let computed_v = compute_all_sum_Mz_evals(&ccs.M, &z, &self.r_x, ccs.s_prime);

let computed_v: Vec<C::ScalarField> = ccs
.M
.iter()
.map(|M_j| {
let Mz_mle = dense_vec_to_dense_mle(ccs.s, &mat_vec_mul(M_j, &z)?);
Mz_mle.evaluate(&self.r_x).ok_or(Error::EvaluationFail)
})
.collect::<Result<_, Error>>()?;
if computed_v != self.v {
return Err(Error::NotSatisfied);
}
Expand Down
9 changes: 5 additions & 4 deletions folding-schemes/src/folding/hypernova/nimfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ where
.map(|lcccs| lcccs.r_x.clone())
.collect(),
&r_x_prime,
);
)?;

// check that the g(r_x') from the sumcheck proof is equal to the computed c from sigmas&thetas
if c != sumcheck_subclaim.expected_evaluation {
Expand All @@ -345,9 +345,10 @@ where

// Sanity check: we can also compute g(r_x') from the proof last evaluation value, and
// should be equal to the previously obtained values.
let g_on_rxprime_from_sumcheck_last_eval =
DensePolynomial::from_coefficients_slice(&proof.sc_proof.proofs.last().unwrap().coeffs)
.evaluate(r_x_prime.last().unwrap());
let g_on_rxprime_from_sumcheck_last_eval = DensePolynomial::from_coefficients_slice(
&proof.sc_proof.proofs.last().ok_or(Error::Empty)?.coeffs,
)
.evaluate(r_x_prime.last().ok_or(Error::Empty)?);
if g_on_rxprime_from_sumcheck_last_eval != c {
return Err(Error::NotEqual);
}
Expand Down
Loading

0 comments on commit ad51c01

Please sign in to comment.