arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes/src/folding/hypernova/circuit.rs
folding-schemes/src/folding/hypernova/circuit.rsRaw
  1/// Implementation of [HyperNova](https://eprint.iacr.org/2023/573.pdf) NIMFS verifier circuit
  2use ark_ff::PrimeField;
  3use ark_r1cs_std::{
  4    alloc::AllocVar,
  5    fields::{fp::FpVar, FieldVar},
  6};
  7use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
  8
  9use crate::ccs::CCS;
 10use crate::folding::circuits::utils::EqEvalGadget;
 11
 12/// computes c from the step 5 in section 5 of HyperNova, adapted to multiple LCCCS & CCCS
 13/// instances:
 14/// $$
 15/// c = \sum_{i \in [\mu]} \left(\sum_{j \in [t]} \gamma^{i \cdot t + j} \cdot e_i \cdot \sigma_{i,j} \right)
 16/// + \sum_{k \in [\nu]} \gamma^{\mu \cdot t+k} \cdot e_k \cdot \left( \sum_{i=1}^q c_i \cdot \prod_{j \in S_i}
 17/// \theta_{k,j} \right)
 18/// $$
 19#[allow(dead_code)] // TMP while the other circuits are not ready
 20#[allow(clippy::too_many_arguments)]
 21fn compute_c_gadget<F: PrimeField>(
 22    cs: ConstraintSystemRef<F>,
 23    ccs: &CCS<F>,
 24    vec_sigmas: Vec<Vec<FpVar<F>>>,
 25    vec_thetas: Vec<Vec<FpVar<F>>>,
 26    gamma: FpVar<F>,
 27    beta: Vec<FpVar<F>>,
 28    vec_r_x: Vec<Vec<FpVar<F>>>,
 29    vec_r_x_prime: Vec<FpVar<F>>,
 30) -> Result<FpVar<F>, SynthesisError> {
 31    let mut e_lcccs = Vec::new();
 32    for r_x in vec_r_x.iter() {
 33        e_lcccs.push(EqEvalGadget::eq_eval(r_x, &vec_r_x_prime)?);
 34    }
 35
 36    let mut c = FpVar::<F>::zero();
 37    let mut current_gamma = FpVar::<F>::one();
 38    for i in 0..vec_sigmas.len() {
 39        for j in 0..ccs.t {
 40            c += current_gamma.clone() * e_lcccs[i].clone() * vec_sigmas[i][j].clone();
 41            current_gamma *= gamma.clone();
 42        }
 43    }
 44
 45    let ccs_c = Vec::<FpVar<F>>::new_constant(cs.clone(), ccs.c.clone())?;
 46    let e_k = EqEvalGadget::eq_eval(&beta, &vec_r_x_prime)?;
 47    #[allow(clippy::needless_range_loop)]
 48    for k in 0..vec_thetas.len() {
 49        let mut sum = FpVar::<F>::zero();
 50        for i in 0..ccs.q {
 51            let mut prod = FpVar::<F>::one();
 52            for j in ccs.S[i].clone() {
 53                prod *= vec_thetas[k][j].clone();
 54            }
 55            sum += ccs_c[i].clone() * prod;
 56        }
 57        c += current_gamma.clone() * e_k.clone() * sum;
 58        current_gamma *= gamma.clone();
 59    }
 60    Ok(c)
 61}
 62
 63#[cfg(test)]
 64mod tests {
 65    use ark_pallas::{Fr, Projective};
 66    use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar};
 67    use ark_relations::r1cs::ConstraintSystem;
 68    use ark_std::{test_rng, UniformRand};
 69
 70    use super::*;
 71    use crate::{
 72        ccs::{
 73            tests::{get_test_ccs, get_test_z},
 74            CCS,
 75        },
 76        commitment::{pedersen::Pedersen, CommitmentScheme},
 77        folding::hypernova::utils::{compute_c, compute_sigmas_and_thetas},
 78    };
 79
 80    #[test]
 81    pub fn test_compute_c_gadget() {
 82        // number of LCCCS & CCCS instances to fold in a single step
 83        let mu = 32;
 84        let nu = 42;
 85
 86        let mut z_lcccs = Vec::new();
 87        for i in 0..mu {
 88            let z = get_test_z(i + 3);
 89            z_lcccs.push(z);
 90        }
 91        let mut z_cccs = Vec::new();
 92        for i in 0..nu {
 93            let z = get_test_z(i + 3);
 94            z_cccs.push(z);
 95        }
 96
 97        let ccs: CCS<Fr> = get_test_ccs();
 98
 99        let mut rng = test_rng();
100        let gamma: Fr = Fr::rand(&mut rng);
101        let beta: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();
102        let r_x_prime: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();
103
104        let (pedersen_params, _) =
105            Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
106
107        // Create the LCCCS instances out of z_lcccs
108        let mut lcccs_instances = Vec::new();
109        for z_i in z_lcccs.iter() {
110            let (inst, _) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i).unwrap();
111            lcccs_instances.push(inst);
112        }
113        // Create the CCCS instance out of z_cccs
114        let mut cccs_instances = Vec::new();
115        for z_i in z_cccs.iter() {
116            let (inst, _) = ccs.to_cccs(&mut rng, &pedersen_params, z_i).unwrap();
117            cccs_instances.push(inst);
118        }
119
120        let sigmas_thetas = compute_sigmas_and_thetas(&ccs, &z_lcccs, &z_cccs, &r_x_prime);
121
122        let expected_c = compute_c(
123            &ccs,
124            &sigmas_thetas,
125            gamma,
126            &beta,
127            &lcccs_instances
128                .iter()
129                .map(|lcccs| lcccs.r_x.clone())
130                .collect(),
131            &r_x_prime,
132        );
133
134        let cs = ConstraintSystem::<Fr>::new_ref();
135        let mut vec_sigmas = Vec::new();
136        let mut vec_thetas = Vec::new();
137        for sigmas in sigmas_thetas.0 {
138            vec_sigmas
139                .push(Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(sigmas.clone())).unwrap());
140        }
141        for thetas in sigmas_thetas.1 {
142            vec_thetas
143                .push(Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(thetas.clone())).unwrap());
144        }
145        let vec_r_x: Vec<Vec<FpVar<Fr>>> = lcccs_instances
146            .iter()
147            .map(|lcccs| {
148                Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(lcccs.r_x.clone())).unwrap()
149            })
150            .collect();
151        let vec_r_x_prime =
152            Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(r_x_prime.clone())).unwrap();
153        let gamma_var = FpVar::<Fr>::new_witness(cs.clone(), || Ok(gamma)).unwrap();
154        let beta_var = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(beta.clone())).unwrap();
155        let computed_c = compute_c_gadget(
156            cs.clone(),
157            &ccs,
158            vec_sigmas,
159            vec_thetas,
160            gamma_var,
161            beta_var,
162            vec_r_x,
163            vec_r_x_prime,
164        )
165        .unwrap();
166
167        assert_eq!(expected_c, computed_c.value().unwrap());
168    }
169}