sonobe-playground/src/folding.rs
src/folding.rsRaw
1use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1};
2use ark_crypto_primitives::sponge::poseidon::PoseidonConfig;
3use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2};
4use sonobe::{
5 commitment::{kzg::KZG, pedersen::Pedersen},
6 folding::{hypernova::HyperNova, nova::Nova},
7 frontend::circom::CircomFCircuit,
8 transcript::poseidon::poseidon_canonical_config,
9 Error, FoldingScheme, MultiFolding,
10};
11
12pub type NovaFolding =
13 Nova<G1, GVar, G2, GVar2, CircomFCircuit<Fr>, KZG<'static, Bn254>, Pedersen<G2>, false>;
14pub type HyperNovaFolding<const M: usize, const N: usize> = HyperNova<
15 G1,
16 GVar,
17 G2,
18 GVar2,
19 CircomFCircuit<Fr>,
20 KZG<'static, Bn254>,
21 Pedersen<G2>,
22 M,
23 N,
24 false,
25>;
26
27pub struct StepInput<OtherInstances> {
28 pub external_inputs: Vec<Fr>,
29 pub other_instances: Option<OtherInstances>,
30}
31
32pub trait FoldingSchemeExt: FoldingScheme<G1, G2, CircomFCircuit<Fr>> {
33 const MULTISTEP_SIZE: usize;
34
35 fn num_steps(num_inputs: usize) -> usize {
36 assert_eq!(num_inputs % Self::MULTISTEP_SIZE, 0);
37 num_inputs / Self::MULTISTEP_SIZE
38 }
39
40 fn prepreprocess(
41 poseidon_config: PoseidonConfig<Fr>,
42 circuit: CircomFCircuit<Fr>,
43 ) -> Self::PreprocessorParam;
44
45 fn transform_multi_input(
46 &self,
47 multi_input: Vec<Vec<Fr>>,
48 initial_state: Vec<Fr>,
49 rng: &mut impl rand::RngCore,
50 ) -> StepInput<Self::MultiCommittedInstanceWithWitness>;
51
52 fn prove_multistep(
53 &mut self,
54 multi_input: Vec<Vec<Fr>>,
55 initial_state: Vec<Fr>,
56 rng: &mut impl rand::RngCore,
57 ) -> Result<(), Error> {
58 let step_input = self.transform_multi_input(multi_input, initial_state, rng);
59 self.prove_step(rng, step_input.external_inputs, step_input.other_instances)
60 }
61}
62
63impl FoldingSchemeExt for NovaFolding {
64 const MULTISTEP_SIZE: usize = 1;
65
66 fn prepreprocess(
67 poseidon_config: PoseidonConfig<Fr>,
68 circuit: CircomFCircuit<Fr>,
69 ) -> Self::PreprocessorParam {
70 Self::PreprocessorParam::new(poseidon_config, circuit)
71 }
72
73 fn transform_multi_input(
74 &self,
75 input: Vec<Vec<Fr>>,
76 _initial_state: Vec<Fr>,
77 _rng: &mut impl rand::RngCore,
78 ) -> StepInput<Self::MultiCommittedInstanceWithWitness> {
79 assert_eq!(input.len(), 1);
80 StepInput {
81 external_inputs: input[0].clone(),
82 other_instances: None,
83 }
84 }
85}
86
87impl<const M: usize, const N: usize> FoldingSchemeExt for HyperNovaFolding<M, N> {
88 const MULTISTEP_SIZE: usize = M + N - 1;
89
90 fn prepreprocess(
91 poseidon_config: PoseidonConfig<Fr>,
92 circuit: CircomFCircuit<Fr>,
93 ) -> Self::PreprocessorParam {
94 Self::PreprocessorParam::new(poseidon_config, circuit)
95 }
96
97 fn transform_multi_input(
98 &self,
99 multi_input: Vec<Vec<Fr>>,
100 initial_state: Vec<Fr>,
101 rng: &mut impl rand::RngCore,
102 ) -> StepInput<Self::MultiCommittedInstanceWithWitness> {
103 let (running, rest) = multi_input.split_at(M - 1);
104 let (incoming, [single]) = rest.split_at(N - 1) else {
105 panic!("Invalid input chunk size");
106 };
107
108 let new_running = |instance| {
109 self.new_running_instance(&mut *rng, initial_state.clone(), instance)
110 .expect("Failed to create running instance")
111 };
112
113 let new_instances =
114 |instances: Vec<Vec<Fr>>, maker| instances.into_iter().map(maker).collect();
115
116 let lcccs = new_instances(running.to_vec(), new_running);
117
118 let cccs = incoming
119 .iter()
120 .map(|instance| {
121 self.new_incoming_instance(&mut *rng, initial_state.clone(), instance.clone())
122 .expect("Failed to create incoming instance")
123 })
124 .collect();
125
126 StepInput {
127 external_inputs: single.clone(),
128 other_instances: Some((lcccs, cccs)),
129 }
130 }
131}
132
133pub fn prepare_folding<FS: FoldingSchemeExt>(
134 circuit: &CircomFCircuit<Fr>,
135 start_ivc_state: Vec<Fr>,
136 rng: &mut impl rand::RngCore,
137) -> (FS, FS::VerifierParam) {
138 let preprocess_params = FS::prepreprocess(poseidon_canonical_config::<Fr>(), circuit.clone());
139 let params =
140 FS::preprocess(&mut *rng, &preprocess_params).expect("Failed to preprocess folding scheme");
141 let folding =
142 FS::init(¶ms, circuit.clone(), start_ivc_state).expect("Failed to init folding scheme");
143
144 (folding, params.1)
145}
146
147pub fn verify_folding<FS: FoldingSchemeExt>(
148 folding: &FS,
149 folding_vp: FS::VerifierParam,
150 start_ivc_state: Vec<Fr>,
151 num_inputs: usize,
152) {
153 let (running_instance, incoming_instance, cyclefold_instance) = folding.instances();
154 FS::verify(
155 folding_vp,
156 start_ivc_state,
157 folding.state(),
158 Fr::from(FS::num_steps(num_inputs) as u32),
159 running_instance,
160 incoming_instance,
161 cyclefold_instance,
162 )
163 .expect("Failed to verify folded proof");
164}