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