Skip to content

Commit

Permalink
Merge pull request #53 from privacy-scaling-explorations/dev/hypernov…
Browse files Browse the repository at this point in the history
…a-nimfs-verifier-circuit/mul-gammapow-eq-sigma-gadget

A gadget to compute the first term of the sum in section 5, step 5
  • Loading branch information
dmpierre authored Jan 10, 2024
2 parents 72ac59c + 06806c8 commit 11066b1
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 4 deletions.
103 changes: 103 additions & 0 deletions src/folding/hypernova/circuit.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,105 @@
// hypernova nimfs verifier circuit
// see section 5 in https://eprint.iacr.org/2023/573.pdf

use ark_ff::PrimeField;
use ark_r1cs_std::{
fields::{fp::FpVar, FieldVar},
ToBitsGadget,
};
use ark_relations::r1cs::SynthesisError;
use std::marker::PhantomData;

/// Gadget to compute the sum of all $\gamma^{j} \cdot eq(r_{x_j}, r_x^{\prime}) \cdot \sigma_j$.
pub struct SumMulsGammaPowsEqSigmaGadget<F: PrimeField> {
_f: PhantomData<F>,
}

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
/// 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
/// - `sigmas`: vector of $\sigma_j$ values
/// - `eq_eval`: the value of $\tilde{eq}(x_j, x^{\prime})$
/// - `gamma`: value $\gamma$
/// - `j`: the power at which we start to compute $\gamma^{j}$. This is needed in the contexxt of multifolding.
///
/// # Notes
/// In the context of multifolding, `j` corresponds to `ccs.t` in `compute_c_from_sigmas_and_thetas`
pub fn sum_muls_gamma_pows_eq_sigma(
sigmas: Vec<FpVar<F>>,
eq_eval: FpVar<F>,
gamma: FpVar<F>,
j: FpVar<F>,
) -> Result<FpVar<F>, SynthesisError> {
let mut result = FpVar::<F>::zero();
let mut gamma_pow = gamma.pow_le(&j.to_bits_le()?)?;
for sigma in sigmas {
result += gamma_pow.clone() * eq_eval.clone() * sigma;
gamma_pow *= gamma.clone();
}
Ok(result)
}
}

#[cfg(test)]
mod tests {
use super::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},
pedersen::Pedersen,
utils::virtual_polynomial::eq_eval,
};
use ark_pallas::{Fr, Projective};
use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar};
use ark_relations::r1cs::ConstraintSystem;
use ark_std::{test_rng, UniformRand};

#[test]
pub fn test_sum_muls_gamma_pow_eq_sigma_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 gamma: Fr = Fr::rand(&mut rng);
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 and gamma
let cs = ConstraintSystem::<Fr>::new_ref();
let gamma_var = FpVar::<Fr>::new_witness(cs.clone(), || Ok(gamma)).unwrap();

for (i, sigmas) in sigmas_thetas.0.iter().enumerate() {
let expected =
sum_muls_gamma_pows_eq_sigma(gamma, e_lcccs[i], sigmas, (i * ccs.t) as u64);
let sigmas_var =
Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(sigmas.clone())).unwrap();
let eq_var = FpVar::<Fr>::new_witness(cs.clone(), || Ok(e_lcccs[i])).unwrap();
let pow =
FpVar::<Fr>::new_witness(cs.clone(), || Ok(Fr::from((i * ccs.t) as u64))).unwrap();
let computed = SumMulsGammaPowsEqSigmaGadget::sum_muls_gamma_pows_eq_sigma(
sigmas_var,
eq_var,
gamma_var.clone(),
pow,
)
.unwrap();
assert_eq!(expected, computed.value().unwrap());
}
}
}
21 changes: 17 additions & 4 deletions src/folding/hypernova/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@ 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}$
/// `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,
eq_eval: F,
sigmas: &[F],
pow: u64,
) -> F {
let mut result = F::zero();
for (j, sigma_j) in sigmas.iter().enumerate() {
let gamma_j = gamma.pow([(pow + (j as u64))]);
result += gamma_j * eq_eval * sigma_j;
}
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 @@ -104,10 +120,7 @@ pub fn compute_c_from_sigmas_and_thetas<C: CurveGroup>(
}
for (i, sigmas) in vec_sigmas.iter().enumerate() {
// (sum gamma^j * e_i * sigma_j)
for (j, sigma_j) in sigmas.iter().enumerate() {
let gamma_j = gamma.pow([(i * ccs.t + j) as u64]);
c += gamma_j * e_lcccs[i] * sigma_j;
}
c += sum_muls_gamma_pows_eq_sigma(gamma, e_lcccs[i], sigmas, (i * ccs.t) as u64);
}

let mu = vec_sigmas.len();
Expand Down

0 comments on commit 11066b1

Please sign in to comment.