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}