arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/examples/multi_inputs.rs
examples/multi_inputs.rsRaw
  1#![allow(non_snake_case)]
  2#![allow(non_upper_case_globals)]
  3#![allow(non_camel_case_types)]
  4#![allow(clippy::upper_case_acronyms)]
  5
  6use ark_ff::PrimeField;
  7use ark_r1cs_std::alloc::AllocVar;
  8use ark_r1cs_std::fields::fp::FpVar;
  9use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
 10use core::marker::PhantomData;
 11use std::time::Instant;
 12
 13use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
 14use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
 15
 16use folding_schemes::commitment::{kzg::KZG, pedersen::Pedersen};
 17use folding_schemes::folding::nova::{Nova, PreprocessorParam};
 18use folding_schemes::frontend::FCircuit;
 19use folding_schemes::transcript::poseidon::poseidon_canonical_config;
 20use folding_schemes::{Error, FoldingScheme};
 21
 22/// This is the circuit that we want to fold, it implements the FCircuit trait. The parameter z_i
 23/// denotes the current state which contains 5 elements, and z_{i+1} denotes the next state which
 24/// we get by applying the step.
 25/// In this example we set z_i and z_{i+1} to have five elements, and at each step we do different
 26/// operations on each of them.
 27#[derive(Clone, Copy, Debug)]
 28pub struct MultiInputsFCircuit<F: PrimeField> {
 29    _f: PhantomData<F>,
 30}
 31impl<F: PrimeField> FCircuit<F> for MultiInputsFCircuit<F> {
 32    type Params = ();
 33
 34    fn new(_params: Self::Params) -> Result<Self, Error> {
 35        Ok(Self { _f: PhantomData })
 36    }
 37    fn state_len(&self) -> usize {
 38        5
 39    }
 40    fn external_inputs_len(&self) -> usize {
 41        0
 42    }
 43
 44    /// computes the next state values in place, assigning z_{i+1} into z_i, and computing the new
 45    /// z_{i+1}
 46    fn step_native(
 47        &self,
 48        _i: usize,
 49        z_i: Vec<F>,
 50        _external_inputs: Vec<F>,
 51    ) -> Result<Vec<F>, Error> {
 52        let a = z_i[0] + F::from(4_u32);
 53        let b = z_i[1] + F::from(40_u32);
 54        let c = z_i[2] * F::from(4_u32);
 55        let d = z_i[3] * F::from(40_u32);
 56        let e = z_i[4] + F::from(100_u32);
 57
 58        Ok(vec![a, b, c, d, e])
 59    }
 60
 61    /// generates the constraints for the step of F for the given z_i
 62    fn generate_step_constraints(
 63        &self,
 64        cs: ConstraintSystemRef<F>,
 65        _i: usize,
 66        z_i: Vec<FpVar<F>>,
 67        _external_inputs: Vec<FpVar<F>>,
 68    ) -> Result<Vec<FpVar<F>>, SynthesisError> {
 69        let four = FpVar::<F>::new_constant(cs.clone(), F::from(4u32))?;
 70        let forty = FpVar::<F>::new_constant(cs.clone(), F::from(40u32))?;
 71        let onehundred = FpVar::<F>::new_constant(cs.clone(), F::from(100u32))?;
 72        let a = z_i[0].clone() + four.clone();
 73        let b = z_i[1].clone() + forty.clone();
 74        let c = z_i[2].clone() * four;
 75        let d = z_i[3].clone() * forty;
 76        let e = z_i[4].clone() + onehundred;
 77
 78        Ok(vec![a, b, c, d, e])
 79    }
 80}
 81
 82/// cargo test --example multi_inputs
 83#[cfg(test)]
 84pub mod tests {
 85    use super::*;
 86    use ark_r1cs_std::{alloc::AllocVar, R1CSVar};
 87    use ark_relations::r1cs::ConstraintSystem;
 88
 89    // test to check that the MultiInputsFCircuit computes the same values inside and outside the circuit
 90    #[test]
 91    fn test_f_circuit() {
 92        let cs = ConstraintSystem::<Fr>::new_ref();
 93
 94        let circuit = MultiInputsFCircuit::<Fr>::new(()).unwrap();
 95        let z_i = vec![
 96            Fr::from(1_u32),
 97            Fr::from(1_u32),
 98            Fr::from(1_u32),
 99            Fr::from(1_u32),
100            Fr::from(1_u32),
101        ];
102
103        let z_i1 = circuit.step_native(0, z_i.clone(), vec![]).unwrap();
104
105        let z_iVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_i)).unwrap();
106        let computed_z_i1Var = circuit
107            .generate_step_constraints(cs.clone(), 0, z_iVar.clone(), vec![])
108            .unwrap();
109        assert_eq!(computed_z_i1Var.value().unwrap(), z_i1);
110    }
111}
112
113/// cargo run --release --example multi_inputs
114fn main() {
115    let num_steps = 10;
116    let initial_state = vec![
117        Fr::from(1_u32),
118        Fr::from(1_u32),
119        Fr::from(1_u32),
120        Fr::from(1_u32),
121        Fr::from(1_u32),
122    ];
123
124    let F_circuit = MultiInputsFCircuit::<Fr>::new(()).unwrap();
125
126    let poseidon_config = poseidon_canonical_config::<Fr>();
127    let mut rng = rand::rngs::OsRng;
128
129    /// The idea here is that eventually we could replace the next line chunk that defines the
130    /// `type N = Nova<...>` by using another folding scheme that fulfills the `FoldingScheme`
131    /// trait, and the rest of our code would be working without needing to be updated.
132    type N = Nova<
133        Projective,
134        GVar,
135        Projective2,
136        GVar2,
137        MultiInputsFCircuit<Fr>,
138        KZG<'static, Bn254>,
139        Pedersen<Projective2>,
140    >;
141
142    println!("Prepare Nova ProverParams & VerifierParams");
143    let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit);
144    let (nova_pp, nova_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
145
146    println!("Initialize FoldingScheme");
147    let mut folding_scheme = N::init(&nova_pp, F_circuit, initial_state.clone()).unwrap();
148
149    // compute a step of the IVC
150    for i in 0..num_steps {
151        let start = Instant::now();
152        folding_scheme.prove_step(rng, vec![]).unwrap();
153        println!("Nova::prove_step {}: {:?}", i, start.elapsed());
154    }
155
156    let (running_instance, incoming_instance, cyclefold_instance) = folding_scheme.instances();
157
158    println!("Run the Nova's IVC verifier");
159    N::verify(
160        nova_vp,
161        initial_state.clone(),
162        folding_scheme.state(), // latest state
163        Fr::from(num_steps as u32),
164        running_instance,
165        incoming_instance,
166        cyclefold_instance,
167    )
168    .unwrap();
169}