Skip to content

Commit

Permalink
Merge pull request #56 from privacy-scaling-explorations/dev/hypernov…
Browse files Browse the repository at this point in the history
…a-nimfs-verifier-circuit/sum_c_i_mul_prod_theta_j

A gadget to compute the second term of the sum in section 5, step 5
  • Loading branch information
dmpierre authored Jan 11, 2024
2 parents 11066b1 + ac92a8b commit 9e19848
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/folding/circuits/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ark_r1cs_std::fields::{fp::FpVar, FieldVar};
use ark_relations::r1cs::SynthesisError;
use std::marker::PhantomData;

/// EqEval is a gadget for computing $\tilde{eq}(a, b) = \Pi_{i=1}^{l}(a_i \cdot b_i + (1 - a_i)(1 - b_i))$
/// EqEval is a gadget for computing $\tilde{eq}(a, b) = \prod_{i=1}^{l}(a_i \cdot b_i + (1 - a_i)(1 - b_i))$
/// :warning: This is not the ark_r1cs_std::eq::EqGadget
pub struct EqEvalGadget<F: PrimeField> {
_f: PhantomData<F>,
Expand Down
75 changes: 72 additions & 3 deletions src/folding/hypernova/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub struct SumMulsGammaPowsEqSigmaGadget<F: PrimeField> {
}

impl<F: PrimeField> SumMulsGammaPowsEqSigmaGadget<F> {
/// Computes the sum $\Sigma_{j}^{j + n} \gamma^{j} \cdot eq_eval \cdot \sigma_{j}$, where $n$ is the length of the `sigmas` vector
/// Computes the sum $\sum_{j}^{j + n} \gamma^{j} \cdot eq_eval \cdot \sigma_{j}$, where $n$ is the length of the `sigmas` vector
/// It corresponds to the first term of the sum that $\mathcal{V}$ has to compute at section 5, step 5 of "A multi-folding scheme for CCS".
///
/// # Arguments
Expand All @@ -42,15 +42,44 @@ impl<F: PrimeField> SumMulsGammaPowsEqSigmaGadget<F> {
}
}

/// Gadget to compute $\sum_{i=1}^{q} c_i * \prod_{j \in S_i} theta_j$.
pub struct SumCiMulProdThetajGadget<F: PrimeField> {
_f: PhantomData<F>,
}

impl<F: PrimeField> SumCiMulProdThetajGadget<F> {
/// Computes $\sum_{i=1}^{q} c_i * \prod_{j \in S_i} theta_j$
///
/// # Arguments
/// - `c_i`: vector of $c_i$ values
/// - `thetas`: vector of pre-processed $\thetas[j]$ values corresponding to a particular `ccs.S[i]`
///
/// # Notes
/// This is a part of the second term of the sum that $\mathcal{V}$ has to compute at section 5, step 5 of "A multi-folding scheme for CCS".
/// The first term is computed by `SumMulsGammaPowsEqSigmaGadget::sum_muls_gamma_pows_eq_sigma`.
/// This is a doct product between a vector of c_i values and a vector of pre-processed $\theta_j$ values, where $j$ is a value from $S_i$.
/// Hence, this requires some pre-processing of the $\theta_j$ values, before running this gadget.
pub fn sum_ci_mul_prod_thetaj(c_i: Vec<FpVar<F>>, thetas: Vec<Vec<FpVar<F>>>) -> FpVar<F> {
let mut result = FpVar::<F>::zero();
for (i, c_i) in c_i.iter().enumerate() {
let prod = &thetas[i].iter().fold(FpVar::one(), |acc, e| acc * e);
result += c_i * prod;
}
result
}
}

#[cfg(test)]
mod tests {
use super::SumMulsGammaPowsEqSigmaGadget;
use super::{SumCiMulProdThetajGadget, SumMulsGammaPowsEqSigmaGadget};
use crate::{
ccs::{
tests::{get_test_ccs, get_test_z},
CCS,
},
folding::hypernova::utils::{compute_sigmas_and_thetas, sum_muls_gamma_pows_eq_sigma},
folding::hypernova::utils::{
compute_sigmas_and_thetas, sum_ci_mul_prod_thetaj, sum_muls_gamma_pows_eq_sigma,
},
pedersen::Pedersen,
utils::virtual_polynomial::eq_eval,
};
Expand Down Expand Up @@ -102,4 +131,44 @@ mod tests {
assert_eq!(expected, computed.value().unwrap());
}
}

#[test]
pub fn test_sum_ci_mul_prod_thetaj_gadget() {
let mut rng = test_rng();
let ccs: CCS<Projective> = get_test_ccs();
let z1 = get_test_z(3);
let z2 = get_test_z(4);

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

// Initialize a multifolding object
let pedersen_params = Pedersen::new_params(&mut rng, ccs.n - ccs.l - 1);
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);

let mut e_lcccs = Vec::new();
for r_x in &vec![lcccs_instance.r_x] {
e_lcccs.push(eq_eval(r_x, &r_x_prime).unwrap());
}

// Initialize cs
let cs = ConstraintSystem::<Fr>::new_ref();
let vec_thetas = sigmas_thetas.1;
for (_, thetas) in vec_thetas.iter().enumerate() {
// sum c_i * prod theta_j
let expected = sum_ci_mul_prod_thetaj(&ccs, thetas); // from `compute_c_from_sigmas_and_thetas`
let mut prepared_thetas = Vec::new();
for i in 0..ccs.q {
let prepared: Vec<Fr> = ccs.S[i].iter().map(|j| thetas[*j]).collect();
prepared_thetas
.push(Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(prepared)).unwrap());
}
let computed = SumCiMulProdThetajGadget::sum_ci_mul_prod_thetaj(
Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(ccs.c.clone())).unwrap(),
prepared_thetas,
);
assert_eq!(expected, computed.value().unwrap());
}
}
}
27 changes: 18 additions & 9 deletions src/folding/hypernova/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub fn compute_sigmas_and_thetas<C: CurveGroup>(
SigmasThetas(sigmas, thetas)
}

/// Computes the sum $\Sigma_{j = 0}^{n} \gamma^{\text{pow} + j} \cdot eq_eval \cdot \sigma_{j}$
/// Computes the sum $\sum_{j = 0}^{n} \gamma^{\text{pow} + j} \cdot eq_eval \cdot \sigma_{j}$
/// `pow` corresponds to `i * ccs.t` in `compute_c_from_sigmas_and_thetas`
pub fn sum_muls_gamma_pows_eq_sigma<F: PrimeField>(
gamma: F,
Expand All @@ -102,6 +102,22 @@ pub fn sum_muls_gamma_pows_eq_sigma<F: PrimeField>(
result
}

/// Computes $\sum_{i=1}^{q} c_i * \prod_{j \in S_i} theta_j$
pub fn sum_ci_mul_prod_thetaj<C: CurveGroup>(
ccs: &CCS<C>,
thetas: &[C::ScalarField],
) -> C::ScalarField {
let mut result = C::ScalarField::zero();
for i in 0..ccs.q {
let mut prod = C::ScalarField::one();
for j in ccs.S[i].clone() {
prod *= thetas[j];
}
result += ccs.c[i] * prod;
}
result
}

/// Compute the right-hand-side of step 5 of the multifolding scheme
pub fn compute_c_from_sigmas_and_thetas<C: CurveGroup>(
ccs: &CCS<C>,
Expand All @@ -127,14 +143,7 @@ pub fn compute_c_from_sigmas_and_thetas<C: CurveGroup>(
let e2 = eq_eval(beta, r_x_prime).unwrap();
for (k, thetas) in vec_thetas.iter().enumerate() {
// + gamma^{t+1} * e2 * sum c_i * prod theta_j
let mut lhs = C::ScalarField::zero();
for i in 0..ccs.q {
let mut prod = C::ScalarField::one();
for j in ccs.S[i].clone() {
prod *= thetas[j];
}
lhs += ccs.c[i] * prod;
}
let lhs = sum_ci_mul_prod_thetaj(ccs, thetas);
let gamma_t1 = gamma.pow([(mu * ccs.t + k) as u64]);
c += gamma_t1 * e2 * lhs;
}
Expand Down

0 comments on commit 9e19848

Please sign in to comment.