arnaucube
arnaucube/hash-chain-sonobePublic Self-hosted repository
hash-chain-sonobe/src/poseidon_chain.rs
src/poseidon_chain.rsRaw
  1///
  2/// This example performs the IVC:
  3/// - define the circuit to be folded
  4/// - fold the circuit with Nova+CycleFold's IVC
  5/// - verify the IVC proof
  6///
  7
  8#[cfg(test)]
  9mod tests {
 10    use ark_pallas::{constraints::GVar, Fr, Projective as G1};
 11    use ark_vesta::{constraints::GVar as GVar2, Projective as G2};
 12
 13    use ark_crypto_primitives::sponge::{
 14        constraints::CryptographicSpongeVar,
 15        poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig, PoseidonSponge},
 16        Absorb, CryptographicSponge,
 17    };
 18    use ark_r1cs_std::fields::fp::FpVar;
 19
 20    use ark_ff::PrimeField;
 21    use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
 22    use std::time::Instant;
 23
 24    use folding_schemes::{
 25        commitment::pedersen::Pedersen,
 26        folding::nova::{Nova, PreprocessorParam},
 27        frontend::FCircuit,
 28        transcript::poseidon::poseidon_canonical_config,
 29        Error, FoldingScheme,
 30    };
 31
 32    /// Test circuit to be folded
 33    #[derive(Clone, Debug)]
 34    pub struct PoseidonFoldStepCircuit<F: PrimeField, const HASHES_PER_STEP: usize> {
 35        config: PoseidonConfig<F>,
 36    }
 37    impl<F: PrimeField, const HASHES_PER_STEP: usize> FCircuit<F>
 38        for PoseidonFoldStepCircuit<F, HASHES_PER_STEP>
 39    where
 40        F: Absorb,
 41    {
 42        type Params = PoseidonConfig<F>;
 43        fn new(config: Self::Params) -> Result<Self, Error> {
 44            Ok(Self { config })
 45        }
 46        fn state_len(&self) -> usize {
 47            1
 48        }
 49        fn external_inputs_len(&self) -> usize {
 50            0
 51        }
 52        fn step_native(
 53            &self,
 54            _i: usize,
 55            z_i: Vec<F>,
 56            _external_inputs: Vec<F>,
 57        ) -> Result<Vec<F>, Error> {
 58            let mut sponge = PoseidonSponge::<F>::new(&self.config);
 59
 60            let mut v = z_i.clone();
 61            for _ in 0..HASHES_PER_STEP {
 62                sponge.absorb(&v);
 63                v = sponge.squeeze_field_elements(1);
 64            }
 65            Ok(v)
 66        }
 67        fn generate_step_constraints(
 68            &self,
 69            cs: ConstraintSystemRef<F>,
 70            _i: usize,
 71            z_i: Vec<FpVar<F>>,
 72            _external_inputs: Vec<FpVar<F>>,
 73        ) -> Result<Vec<FpVar<F>>, SynthesisError> {
 74            let mut sponge = PoseidonSpongeVar::<F>::new(cs.clone(), &self.config);
 75
 76            let mut v = z_i.clone();
 77            for _ in 0..HASHES_PER_STEP {
 78                sponge.absorb(&v)?;
 79                v = sponge.squeeze_field_elements(1)?;
 80            }
 81            Ok(v)
 82        }
 83    }
 84
 85    #[test]
 86    fn full_flow() {
 87        // set how many steps of folding we want to compute
 88        const N_STEPS: usize = 10;
 89        const HASHES_PER_STEP: usize = 400;
 90        println!("running Nova folding scheme on PoseidonFoldStepCircuit, with N_STEPS={}, HASHES_PER_STEP={}. Total hashes = {}", N_STEPS, HASHES_PER_STEP, N_STEPS* HASHES_PER_STEP);
 91
 92        // set the initial state
 93        // let z_0_aux: Vec<u32> = vec![0_u32; 32 * 8];
 94        let z_0_aux: Vec<u8> = vec![0_u8; 1];
 95        let z_0: Vec<Fr> = z_0_aux.iter().map(|v| Fr::from(*v)).collect::<Vec<Fr>>();
 96
 97        let poseidon_config = poseidon_canonical_config::<Fr>();
 98        let f_circuit =
 99            PoseidonFoldStepCircuit::<Fr, HASHES_PER_STEP>::new(poseidon_config).unwrap();
100
101        // ----------------
102        // Sanity check
103        // check that the f_circuit produces valid R1CS constraints
104        use ark_r1cs_std::alloc::AllocVar;
105        use ark_r1cs_std::fields::fp::FpVar;
106        use ark_r1cs_std::R1CSVar;
107        use ark_relations::r1cs::ConstraintSystem;
108        let cs = ConstraintSystem::<Fr>::new_ref();
109        let z_0_var = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_0.clone())).unwrap();
110        let z_1_var = f_circuit
111            .generate_step_constraints(cs.clone(), 1, z_0_var, vec![])
112            .unwrap();
113        // check z_1_var against the native z_1
114        let z_1_native = f_circuit.step_native(1, z_0.clone(), vec![]).unwrap();
115        assert_eq!(z_1_var.value().unwrap(), z_1_native);
116        // check that the constraint system is satisfied
117        assert!(cs.is_satisfied().unwrap());
118        println!(
119            "number of constraints of a single instantiation of the PoseidonFoldStepCircuit: {}",
120            cs.num_constraints()
121        );
122        // ----------------
123
124        // define type aliases for the FoldingScheme (FS) and Decider (D), to avoid writting the
125        // whole type each time
126        pub type FS = Nova<
127            G1,
128            GVar,
129            G2,
130            GVar2,
131            PoseidonFoldStepCircuit<Fr, HASHES_PER_STEP>,
132            Pedersen<G1>,
133            Pedersen<G2>,
134            false,
135        >;
136
137        let mut rng = rand::rngs::OsRng;
138
139        // prepare the Nova prover & verifier params
140        let nova_preprocess_params = PreprocessorParam::new(poseidon_config, f_circuit.clone());
141        let start = Instant::now();
142        let nova_params = FS::preprocess(&mut rng, &nova_preprocess_params).unwrap();
143        println!("Nova params generated: {:?}", start.elapsed());
144
145        // initialize the folding scheme engine, in our case we use Nova
146        let mut nova = FS::init(&nova_params, f_circuit, z_0.clone()).unwrap();
147
148        // run n steps of the folding iteration
149        let start_full = Instant::now();
150        for _ in 0..N_STEPS {
151            let start = Instant::now();
152            nova.prove_step(rng, vec![], None).unwrap();
153            println!(
154                "Nova::prove_step (poseidon) {}: {:?}",
155                nova.i,
156                start.elapsed()
157            );
158        }
159        println!(
160            "Nova's all {} steps time: {:?}",
161            N_STEPS,
162            start_full.elapsed()
163        );
164
165        // verify the last IVC proof
166        let ivc_proof = nova.ivc_proof();
167        FS::verify(
168            nova_params.1.clone(), // Nova's verifier params
169            ivc_proof,
170        )
171        .unwrap();
172    }
173}