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