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},
 16        Absorb,
 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 generate_step_constraints(
 53            &self,
 54            cs: ConstraintSystemRef<F>,
 55            _i: usize,
 56            z_i: Vec<FpVar<F>>,
 57            _external_inputs: Vec<FpVar<F>>,
 58        ) -> Result<Vec<FpVar<F>>, SynthesisError> {
 59            let mut sponge = PoseidonSpongeVar::<F>::new(cs.clone(), &self.config);
 60
 61            let mut v = z_i.clone();
 62            for _ in 0..HASHES_PER_STEP {
 63                sponge.absorb(&v)?;
 64                v = sponge.squeeze_field_elements(1)?;
 65            }
 66            Ok(v)
 67        }
 68    }
 69
 70    #[test]
 71    fn full_flow() {
 72        // set how many steps of folding we want to compute
 73        const N_STEPS: usize = 10;
 74        const HASHES_PER_STEP: usize = 400;
 75        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);
 76
 77        // set the initial state
 78        // let z_0_aux: Vec<u32> = vec![0_u32; 32 * 8];
 79        let z_0_aux: Vec<u8> = vec![0_u8; 1];
 80        let z_0: Vec<Fr> = z_0_aux.iter().map(|v| Fr::from(*v)).collect::<Vec<Fr>>();
 81
 82        let poseidon_config = poseidon_canonical_config::<Fr>();
 83        let f_circuit =
 84            PoseidonFoldStepCircuit::<Fr, HASHES_PER_STEP>::new(poseidon_config.clone()).unwrap();
 85
 86        // ----------------
 87        // Sanity check
 88        // check that the f_circuit produces valid R1CS constraints
 89        use ark_r1cs_std::alloc::AllocVar;
 90        use ark_r1cs_std::fields::fp::FpVar;
 91        use ark_relations::r1cs::ConstraintSystem;
 92        let cs = ConstraintSystem::<Fr>::new_ref();
 93        let z_0_var = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_0.clone())).unwrap();
 94        let _z_1_var = f_circuit
 95            .generate_step_constraints(cs.clone(), 1, z_0_var, vec![])
 96            .unwrap();
 97        // check that the constraint system is satisfied
 98        assert!(cs.is_satisfied().unwrap());
 99        println!(
100            "number of constraints of a single instantiation of the PoseidonFoldStepCircuit: {}",
101            cs.num_constraints()
102        );
103        // ----------------
104
105        // define type aliases for the FoldingScheme (FS) and Decider (D), to avoid writting the
106        // whole type each time
107        pub type FS = Nova<
108            G1,
109            GVar,
110            G2,
111            GVar2,
112            PoseidonFoldStepCircuit<Fr, HASHES_PER_STEP>,
113            Pedersen<G1>,
114            Pedersen<G2>,
115            false,
116        >;
117
118        let mut rng = rand::rngs::OsRng;
119
120        // prepare the Nova prover & verifier params
121        let nova_preprocess_params =
122            PreprocessorParam::new(poseidon_config.clone(), f_circuit.clone());
123        let start = Instant::now();
124        let nova_params = FS::preprocess(&mut rng, &nova_preprocess_params).unwrap();
125        println!("Nova params generated: {:?}", start.elapsed());
126
127        // initialize the folding scheme engine, in our case we use Nova
128        let mut nova = FS::init(&nova_params, f_circuit, z_0.clone()).unwrap();
129
130        // run n steps of the folding iteration
131        let start_full = Instant::now();
132        for _ in 0..N_STEPS {
133            let start = Instant::now();
134            nova.prove_step(rng, vec![], None).unwrap();
135            println!(
136                "Nova::prove_step (poseidon) {}: {:?}",
137                nova.i,
138                start.elapsed()
139            );
140        }
141        println!(
142            "Nova's all {} steps time: {:?}",
143            N_STEPS,
144            start_full.elapsed()
145        );
146
147        // verify the last IVC proof
148        let ivc_proof = nova.ivc_proof();
149        FS::verify(
150            nova_params.1.clone(), // Nova's verifier params
151            ivc_proof,
152        )
153        .unwrap();
154    }
155}