Skip to content

Commit

Permalink
Optimize HyperNova's compute_sigmas_thetas and compute_Q
Browse files Browse the repository at this point in the history
| method                | matrix size   | old version seconds | new version seconds |
| -------------         | ------------- | ------------------- | ------------------- |
| compute_sigmas_thetas | 2^8 x 2^8     | 12.86               | 0.13                |
| compute_sigmas_thetas | 2^9 x 2^9     | 100.01              | 0.51                |
| compute_Q             | 2^8 x 2^8     | 4.49                | 0.07                |
| compute_Q             | 2^9 x 2^9     | 70.77               | 0.55                |
  • Loading branch information
arnaucube committed Jun 3, 2024
1 parent 41f9d23 commit 80b4948
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 19 deletions.
28 changes: 25 additions & 3 deletions folding-schemes/src/folding/hypernova/cccs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ use crate::commitment::{
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::virtual_polynomial::VirtualPolynomial;
use crate::utils::vec::mat_vec_mul;
use crate::utils::virtual_polynomial::{build_eq_x_r_vec, VirtualPolynomial};
use crate::Error;

/// Witness for the LCCCS & CCCS, containing the w vector, and the r_w used as randomness in the Pedersen commitment.
Expand Down Expand Up @@ -90,12 +92,32 @@ impl<F: PrimeField> CCS<F> {
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()
}

/// 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 q = self.compute_q(z);
q.build_f_hat(beta).unwrap()
let eq_beta = build_eq_x_r_vec(beta).unwrap();
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(eq_beta_mle.clone());
Q.add_mle_list(Q_k.iter().map(|v| Arc::new(v.clone())), self.c[i])
.unwrap();
}
Q
}
}

Expand Down
4 changes: 2 additions & 2 deletions folding-schemes/src/folding/hypernova/circuits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ mod tests {
commitment::{pedersen::Pedersen, CommitmentScheme},
folding::hypernova::{
nimfs::NIMFS,
utils::{compute_c, compute_sigmas_and_thetas},
utils::{compute_c, compute_sigmas_thetas},
},
transcript::{
poseidon::{poseidon_canonical_config, PoseidonTranscript, PoseidonTranscriptVar},
Expand Down Expand Up @@ -409,7 +409,7 @@ mod tests {
cccs_instances.push(inst);
}

let sigmas_thetas = compute_sigmas_and_thetas(&ccs, &z_lcccs, &z_cccs, &r_x_prime);
let sigmas_thetas = compute_sigmas_thetas(&ccs, &z_lcccs, &z_cccs, &r_x_prime).unwrap();

let expected_c = compute_c(
&ccs,
Expand Down
6 changes: 3 additions & 3 deletions folding-schemes/src/folding/hypernova/nimfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use ark_std::{One, Zero};

use super::cccs::{Witness, CCCS};
use super::lcccs::LCCCS;
use super::utils::{compute_c, compute_g, compute_sigmas_and_thetas};
use super::utils::{compute_c, compute_g, compute_sigmas_thetas};
use crate::ccs::CCS;
use crate::transcript::Transcript;
use crate::utils::hypercube::BooleanHypercube;
Expand Down Expand Up @@ -244,7 +244,7 @@ where
let r_x_prime = sumcheck_proof.point.clone();

// Step 4: compute sigmas and thetas
let sigmas_thetas = compute_sigmas_and_thetas(ccs, &z_lcccs, &z_cccs, &r_x_prime);
let sigmas_thetas = compute_sigmas_thetas(ccs, &z_lcccs, &z_cccs, &r_x_prime)?;

// Step 6: Get the folding challenge
let rho_scalar = C::ScalarField::from_le_bytes_mod_order(b"rho");
Expand Down Expand Up @@ -395,7 +395,7 @@ pub mod tests {
let r_x_prime: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();

let sigmas_thetas =
compute_sigmas_and_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime);
compute_sigmas_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime).unwrap();

let (pedersen_params, _) =
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
Expand Down
33 changes: 24 additions & 9 deletions folding-schemes/src/folding/hypernova/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,40 @@ pub fn compute_sum_Mz<F: PrimeField>(

/// Compute the arrays of sigma_i and theta_i from step 4 corresponding to the LCCCS and CCCS
/// instances
pub fn compute_sigmas_and_thetas<F: PrimeField>(
pub fn compute_sigmas_thetas<F: PrimeField>(
ccs: &CCS<F>,
z_lcccs: &[Vec<F>],
z_cccs: &[Vec<F>],
r_x_prime: &[F],
) -> SigmasThetas<F> {
) -> Result<SigmasThetas<F>, Error> {
// sigmas
let mut sigmas: Vec<Vec<F>> = Vec::new();
for z_lcccs_i in z_lcccs {
// sigmas
let sigma_i = compute_all_sum_Mz_evals(&ccs.M, z_lcccs_i, r_x_prime, ccs.s_prime);
let mut Mzs: Vec<DenseMultilinearExtension<F>> = vec![];
for M_j in ccs.M.iter() {
Mzs.push(dense_vec_to_dense_mle(ccs.s, &mat_vec_mul(M_j, z_lcccs_i)?));
}
let sigma_i = Mzs
.iter()
.map(|Mz| Mz.evaluate(r_x_prime).ok_or(Error::EvaluationFail))
.collect::<Result<_, Error>>()?;
sigmas.push(sigma_i);
}

// thetas
let mut thetas: Vec<Vec<F>> = Vec::new();
for z_cccs_i in z_cccs {
// thetas
let theta_i = compute_all_sum_Mz_evals(&ccs.M, z_cccs_i, r_x_prime, ccs.s_prime);
let mut Mzs: Vec<DenseMultilinearExtension<F>> = vec![];
for M_j in ccs.M.iter() {
Mzs.push(dense_vec_to_dense_mle(ccs.s, &mat_vec_mul(M_j, z_cccs_i)?));
}
let theta_i = Mzs
.iter()
.map(|Mz| Mz.evaluate(r_x_prime).ok_or(Error::EvaluationFail))
.collect::<Result<_, Error>>()?;
thetas.push(theta_i);
}
SigmasThetas(sigmas, thetas)
Ok(SigmasThetas(sigmas, thetas))
}

/// computes c from the step 5 in section 5 of HyperNova, adapted to multiple LCCCS & CCCS
Expand Down Expand Up @@ -285,7 +300,7 @@ pub mod tests {
}

#[test]
fn test_compute_sigmas_and_thetas() {
fn test_compute_sigmas_thetas() {
let ccs = get_test_ccs();
let z1 = get_test_z(3);
let z2 = get_test_z(4);
Expand All @@ -303,7 +318,7 @@ pub mod tests {
let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();

let sigmas_thetas =
compute_sigmas_and_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime);
compute_sigmas_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime).unwrap();

let g = compute_g(
&ccs,
Expand Down
6 changes: 4 additions & 2 deletions folding-schemes/src/utils/mle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ mod tests {
]);

let A_mle = matrix_to_mle(A);
assert_eq!(A_mle.evaluations.len(), 16); // 4x4 matrix, thus 2bit x 2bit, thus 2^4=16 evals
assert_eq!(A_mle.evaluations.len(), 15); // 15 non-zero elements
assert_eq!(A_mle.num_vars, 4); // 4x4 matrix, thus 2bit x 2bit, thus 2^4=16 evals

let A = to_F_matrix::<Fr>(vec![
vec![2, 3, 4, 4, 1],
Expand All @@ -134,7 +135,8 @@ mod tests {
vec![420, 4, 2, 0, 5],
]);
let A_mle = matrix_to_mle(A.clone());
assert_eq!(A_mle.evaluations.len(), 64); // 5x5 matrix, thus 3bit x 3bit, thus 2^6=64 evals
assert_eq!(A_mle.evaluations.len(), 23); // 23 non-zero elements
assert_eq!(A_mle.num_vars, 6); // 5x5 matrix, thus 3bit x 3bit, thus 2^6=64 evals

// check that the A_mle evaluated over the boolean hypercube equals the matrix A_i_j values
let bhc = BooleanHypercube::new(A_mle.num_vars);
Expand Down

0 comments on commit 80b4948

Please sign in to comment.