use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1}; use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2}; use itertools::Itertools; use sonobe::{ commitment::{kzg::KZG, pedersen::Pedersen}, folding::{hypernova::HyperNova, nova::Nova}, frontend::circom::CircomFCircuit, transcript::poseidon::poseidon_canonical_config, FoldingScheme, MultiFolding, }; pub type NovaFolding = Nova, KZG<'static, Bn254>, Pedersen, false>; pub type HyperNovaFolding = HyperNova< G1, GVar, G2, GVar2, CircomFCircuit, KZG<'static, Bn254>, Pedersen, N, M, false, >; pub struct StepInput { pub external_inputs: Vec, pub other_instances: Option, } pub trait FoldingSchemeExt: FoldingScheme> { fn prepreprocess( poseidon_config: PoseidonConfig, circuit: CircomFCircuit, ) -> Self::PreprocessorParam; fn transform_inputs( &self, full_input: Vec>, initial_state: Vec, rng: &mut impl rand::RngCore, ) -> Vec>; } impl FoldingSchemeExt for NovaFolding { fn prepreprocess( poseidon_config: PoseidonConfig, circuit: CircomFCircuit, ) -> Self::PreprocessorParam { Self::PreprocessorParam::new(poseidon_config, circuit) } fn transform_inputs( &self, full_input: Vec>, _initial_state: Vec, _rng: &mut impl rand::RngCore, ) -> Vec> { full_input .into_iter() .map(|input| StepInput { external_inputs: input, other_instances: None, }) .collect() } } impl FoldingSchemeExt for HyperNovaFolding { fn prepreprocess( poseidon_config: PoseidonConfig, circuit: CircomFCircuit, ) -> Self::PreprocessorParam { Self::PreprocessorParam::new(poseidon_config, circuit) } fn transform_inputs( &self, full_input: Vec>, initial_state: Vec, rng: &mut impl rand::RngCore, ) -> Vec> { full_input .into_iter() .chunks(M + N - 1) .into_iter() .map(|chunk| { let chunk = chunk.collect::>(); let (running, rest) = chunk.split_at(M - 1); let (incoming, [single]) = rest.split_at(N - 1) else { panic!("Invalid input chunk size"); }; let lcccs = running .iter() .map(|instance| { self.new_running_instance( &mut *rng, initial_state.clone(), instance.clone(), ) .expect("Failed to create running instance") }) .collect(); let cccs = incoming .iter() .map(|instance| { self.new_incoming_instance( &mut *rng, initial_state.clone(), instance.clone(), ) .expect("Failed to create incoming instance") }) .collect(); StepInput { external_inputs: single.clone(), other_instances: Some((lcccs, cccs)), } }) .collect() } } pub fn prepare_folding( circuit: &CircomFCircuit, start_ivc_state: Vec, rng: &mut impl rand::RngCore, ) -> (FS, FS::VerifierParam) { let preprocess_params = FS::prepreprocess(poseidon_canonical_config::(), circuit.clone()); let params = FS::preprocess(&mut *rng, &preprocess_params).expect("Failed to preprocess folding scheme"); let folding = FS::init(¶ms, circuit.clone(), start_ivc_state).expect("Failed to init folding scheme"); (folding, params.1) } pub fn verify_folding( folding: &FS, folding_vp: FS::VerifierParam, start_ivc_state: Vec, num_steps: u32, ) { let (running_instance, incoming_instance, cyclefold_instance) = folding.instances(); FS::verify( folding_vp, start_ivc_state, folding.state(), Fr::from(num_steps), running_instance, incoming_instance, cyclefold_instance, ) .expect("Failed to verify folded proof"); }