Skip to content

Commit

Permalink
HyperNova: move CCS struct outside of LCCCS & CCCS
Browse files Browse the repository at this point in the history
HyperNova nimfs: move CCS structure outside of LCCCS & CCCS, to avoid
carrying around the whole CCS and duplicating data when is not needed.

Also add feature flags for the folding schemes.
  • Loading branch information
arnaucube committed Sep 7, 2023
1 parent 87a6466 commit b2c2f3f
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 122 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ ark-vesta = {version="0.4.0"}
ark-crypto-primitives = { version = "^0.4.0", default-features = false, features = ["crh"] }

[features]
default = ["parallel"]
default = ["parallel", "nova", "hypernova"]
hypernova=[]
nova=[]

parallel = [
"ark-std/parallel",
Expand Down
2 changes: 1 addition & 1 deletion src/folding/circuits/cyclefold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl<C: CurveGroup, GC: CurveVar<C, CF<C>>> ECRLC<C, GC> {
}

#[cfg(test)]
mod test {
mod tests {
use super::*;
use ark_ff::{BigInteger, PrimeField};
use ark_pallas::{constraints::GVar, Fq, Fr, Projective};
Expand Down
58 changes: 23 additions & 35 deletions src/folding/hypernova/cccs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@ use std::sync::Arc;

use ark_std::{rand::Rng, UniformRand};

use super::utils::compute_sum_Mz;
use crate::ccs::CCS;
use crate::folding::hypernova::utils::compute_sum_Mz;
use crate::Error;

use crate::pedersen::{Params as PedersenParams, Pedersen};
use crate::utils::hypercube::BooleanHypercube;
use crate::utils::mle::matrix_to_mle;
use crate::utils::mle::vec_to_mle;
use crate::utils::virtual_polynomial::VirtualPolynomial;
use crate::Error;

/// Witness for the LCCCS & CCCS, containing the w vector, and the r_w used as randomness in the Pedersen commitment.
#[derive(Debug, Clone)]
Expand All @@ -27,9 +26,6 @@ pub struct Witness<F: PrimeField> {
/// Committed CCS instance
#[derive(Debug, Clone)]
pub struct CCCS<C: CurveGroup> {
// Underlying CCS structure
pub ccs: CCS<C>,

// Commitment to witness
pub C: C,
// Public input/output
Expand All @@ -49,29 +45,26 @@ impl<C: CurveGroup> CCS<C> {

(
CCCS::<C> {
ccs: self.clone(),
C,
x: z[1..(1 + self.l)].to_vec(),
},
Witness::<C::ScalarField> { w, r_w },
)
}
}

impl<C: CurveGroup> CCCS<C> {
/// 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: &Vec<C::ScalarField>) -> VirtualPolynomial<C::ScalarField> {
let z_mle = vec_to_mle(self.ccs.s_prime, z);
let mut q = VirtualPolynomial::<C::ScalarField>::new(self.ccs.s);
let z_mle = vec_to_mle(self.s_prime, z);
let mut q = VirtualPolynomial::<C::ScalarField>::new(self.s);

for i in 0..self.ccs.q {
for i in 0..self.q {
let mut prod: VirtualPolynomial<C::ScalarField> =
VirtualPolynomial::<C::ScalarField>::new(self.ccs.s);
for j in self.ccs.S[i].clone() {
let M_j = matrix_to_mle(self.ccs.M[j].clone());
VirtualPolynomial::<C::ScalarField>::new(self.s);
for j in self.S[i].clone() {
let M_j = matrix_to_mle(self.M[j].clone());

let sum_Mz = compute_sum_Mz(M_j, &z_mle, self.ccs.s_prime);
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() {
Expand All @@ -86,7 +79,7 @@ impl<C: CurveGroup> CCCS<C> {
}
}
// Multiply by the product by the coefficient c_i
prod.scalar_mul(&self.ccs.c[i]);
prod.scalar_mul(&self.c[i]);
// Add it to the running sum
q = q.add(&prod);
}
Expand All @@ -104,11 +97,14 @@ impl<C: CurveGroup> CCCS<C> {
let q = self.compute_q(z);
q.build_f_hat(beta).unwrap()
}
}

impl<C: CurveGroup> CCCS<C> {
/// Perform the check of the CCCS instance described at section 4.1
pub fn check_relation(
&self,
pedersen_params: &PedersenParams<C>,
ccs: &CCS<C>,
w: &Witness<C::ScalarField>,
) -> Result<(), Error> {
// check that C is the commitment of w. Notice that this is not verifying a Pedersen
Expand All @@ -120,8 +116,8 @@ 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 = self.compute_q(&z);
for x in BooleanHypercube::new(self.ccs.s) {
let q_x = ccs.compute_q(&z);
for x in BooleanHypercube::new(ccs.s) {
if !q_x.evaluate(&x).unwrap().is_zero() {
return Err(Error::NotSatisfied);
}
Expand All @@ -132,7 +128,7 @@ impl<C: CurveGroup> CCCS<C> {
}

#[cfg(test)]
pub mod test {
pub mod tests {
use super::*;
use crate::ccs::tests::{get_test_ccs, get_test_z};
use ark_std::test_rng;
Expand All @@ -149,9 +145,7 @@ pub mod test {
let ccs = get_test_ccs::<Projective>();
let z = get_test_z(3);

let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
let (cccs, _) = ccs.to_cccs(&mut rng, &pedersen_params, &z);
let q = cccs.compute_q(&z);
let q = ccs.compute_q(&z);

// Evaluate inside the hypercube
for x in BooleanHypercube::new(ccs.s) {
Expand All @@ -168,17 +162,14 @@ pub mod test {
fn test_compute_Q() {
let mut rng = test_rng();

let ccs = get_test_ccs();
let ccs: CCS<Projective> = get_test_ccs();
let z = get_test_z(3);
ccs.check_relation(&z).unwrap();

let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
let (cccs, _) = ccs.to_cccs(&mut rng, &pedersen_params, &z);

let beta: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();

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

// 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 All @@ -205,18 +196,15 @@ pub mod test {
fn test_Q_against_q() {
let mut rng = test_rng();

let ccs = get_test_ccs();
let ccs: CCS<Projective> = get_test_ccs();
let z = get_test_z(3);
ccs.check_relation(&z).unwrap();

let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
let (cccs, _) = ccs.to_cccs(&mut rng, &pedersen_params, &z);

// 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 = cccs.compute_q(&z);
let q = ccs.compute_q(&z);
for d in BooleanHypercube::new(ccs.s) {
let Q_at_d = cccs.compute_Q(&z, &d);
let Q_at_d = ccs.compute_Q(&z, &d);

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

// 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 = cccs.compute_Q(&z, &r);
let Q_at_r = ccs.compute_Q(&z, &r);

// Get G(d) by summing over Q_d(x) over the hypercube
let G_at_r = BooleanHypercube::new(ccs.s)
Expand Down
34 changes: 17 additions & 17 deletions src/folding/hypernova/lcccs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,17 @@ use std::sync::Arc;

use ark_std::{rand::Rng, UniformRand};

use super::cccs::Witness;
use super::utils::{compute_all_sum_Mz_evals, compute_sum_Mz};
use crate::ccs::CCS;
use crate::folding::hypernova::cccs::Witness;
use crate::folding::hypernova::utils::{compute_all_sum_Mz_evals, compute_sum_Mz};
use crate::Error;

use crate::pedersen::{Params as PedersenParams, Pedersen};
use crate::utils::mle::{matrix_to_mle, vec_to_mle};
use crate::utils::virtual_polynomial::VirtualPolynomial;
use crate::Error;

/// Linearized Committed CCS instance
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct LCCCS<C: CurveGroup> {
// Underlying CCS structure
pub ccs: CCS<C>, // TODO maybe move CCS structure outside of LCCCS

// Commitment to witness
pub C: C,
// Relaxation factor of z for folded LCCCS
Expand Down Expand Up @@ -54,7 +50,6 @@ impl<C: CurveGroup> CCS<C> {

(
LCCCS::<C> {
ccs: self.clone(),
C,
u: C::ScalarField::one(),
x: z[1..(1 + self.l)].to_vec(),
Expand All @@ -68,15 +63,19 @@ impl<C: CurveGroup> CCS<C> {

impl<C: CurveGroup> LCCCS<C> {
/// Compute all L_j(x) polynomials
pub fn compute_Ls(&self, z: &Vec<C::ScalarField>) -> Vec<VirtualPolynomial<C::ScalarField>> {
let z_mle = vec_to_mle(self.ccs.s_prime, z);
pub fn compute_Ls(
&self,
ccs: &CCS<C>,
z: &Vec<C::ScalarField>,
) -> Vec<VirtualPolynomial<C::ScalarField>> {
let z_mle = vec_to_mle(ccs.s_prime, z);
// Convert all matrices to MLE
let M_x_y_mle: Vec<DenseMultilinearExtension<C::ScalarField>> =
self.ccs.M.clone().into_iter().map(matrix_to_mle).collect();
ccs.M.clone().into_iter().map(matrix_to_mle).collect();

let mut vec_L_j_x = Vec::with_capacity(self.ccs.t);
let mut vec_L_j_x = Vec::with_capacity(ccs.t);
for M_j in M_x_y_mle {
let sum_Mz = compute_sum_Mz(M_j, &z_mle, self.ccs.s_prime);
let sum_Mz = compute_sum_Mz(M_j, &z_mle, ccs.s_prime);
let sum_Mz_virtual =
VirtualPolynomial::new_from_mle(&Arc::new(sum_Mz.clone()), C::ScalarField::one());
let L_j_x = sum_Mz_virtual.build_f_hat(&self.r_x).unwrap();
Expand All @@ -90,6 +89,7 @@ impl<C: CurveGroup> LCCCS<C> {
pub fn check_relation(
&self,
pedersen_params: &PedersenParams<C>,
ccs: &CCS<C>,
w: &Witness<C::ScalarField>,
) -> Result<(), Error> {
// check that C is the commitment of w. Notice that this is not verifying a Pedersen
Expand All @@ -98,14 +98,14 @@ 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(&self.ccs.M, &z, &self.r_x, self.ccs.s_prime);
let computed_v = compute_all_sum_Mz_evals(&ccs.M, &z, &self.r_x, ccs.s_prime);
assert_eq!(computed_v, self.v);
Ok(())
}
}

#[cfg(test)]
pub mod test {
pub mod tests {
use super::*;
use ark_std::Zero;

Expand All @@ -129,7 +129,7 @@ pub mod test {
// with our test vector comming from R1CS, v should have length 3
assert_eq!(lcccs.v.len(), 3);

let vec_L_j_x = lcccs.compute_Ls(&z);
let vec_L_j_x = lcccs.compute_Ls(&ccs, &z);
assert_eq!(vec_L_j_x.len(), lcccs.v.len());

for (v_i, L_j_x) in lcccs.v.into_iter().zip(vec_L_j_x) {
Expand Down Expand Up @@ -161,7 +161,7 @@ pub mod test {
assert_eq!(lcccs.v.len(), 3);

// Bad compute L_j(x) with the bad z
let vec_L_j_x = lcccs.compute_Ls(&bad_z);
let vec_L_j_x = lcccs.compute_Ls(&ccs, &bad_z);
assert_eq!(vec_L_j_x.len(), lcccs.v.len());

// Make sure that the LCCCS is not satisfied given these L_j(x)
Expand Down
1 change: 1 addition & 0 deletions src/folding/hypernova/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/// Implements the scheme described in [HyperNova](https://eprint.iacr.org/2023/573.pdf)
pub mod cccs;
pub mod lcccs;
pub mod nimfs;
Expand Down
Loading

0 comments on commit b2c2f3f

Please sign in to comment.