diff --git a/Cargo.lock b/Cargo.lock index 7f1ceb9..767cd17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3330,6 +3330,7 @@ dependencies = [ "ark-grumpkin", "ark-serialize 0.4.1", "folding-schemes", + "itertools 0.13.0", "num-traits", "rand 0.8.5", ] diff --git a/Cargo.toml b/Cargo.toml index 57865a2..94da79b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ ark-crypto-primitives = { version = "0.4.0" } ark-grumpkin = { version = "0.4.0", features = ["r1cs"] } ark-groth16 = { version = "0.4.0", features = ["parallel"] } ark-serialize = { version = "0.4.0" } +itertools = { version = "0.13.0" } rand = { version = "0.8.5" } sonobe = { git = "https://github.com/privacy-scaling-explorations/sonobe", rev = "f1d82418ba047cf90805f2d0505370246df24d68", package = "folding-schemes" } num-traits = { version = "0.2.15" } diff --git a/src/folding.rs b/src/folding.rs index 7fc0e57..43157d2 100644 --- a/src/folding.rs +++ b/src/folding.rs @@ -1,17 +1,18 @@ 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, + FoldingScheme, MultiFolding, }; pub type NovaFolding = Nova, KZG<'static, Bn254>, Pedersen, false>; -pub type HyperNovaFolding = HyperNova< +pub type HyperNovaFolding = HyperNova< G1, GVar, G2, @@ -19,8 +20,8 @@ pub type HyperNovaFolding = HyperNova< CircomFCircuit, KZG<'static, Bn254>, Pedersen, - 1, - 1, + N, + M, false, >; @@ -36,8 +37,11 @@ pub trait FoldingSchemeExt: FoldingScheme> { ) -> Self::PreprocessorParam; fn transform_inputs( + &self, full_input: Vec>, - ) -> impl Iterator>; + initial_state: Vec, + rng: &mut impl rand::RngCore, + ) -> Vec>; } impl FoldingSchemeExt for NovaFolding { @@ -49,16 +53,22 @@ impl FoldingSchemeExt for NovaFolding { } fn transform_inputs( + &self, full_input: Vec>, - ) -> impl Iterator> { - full_input.into_iter().map(|input| StepInput { - external_inputs: input, - other_instances: None, - }) + _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 { +impl FoldingSchemeExt for HyperNovaFolding { fn prepreprocess( poseidon_config: PoseidonConfig, circuit: CircomFCircuit, @@ -67,12 +77,52 @@ impl FoldingSchemeExt for HyperNovaFolding { } fn transform_inputs( + &self, full_input: Vec>, - ) -> impl Iterator> { - full_input.into_iter().map(|input| StepInput { - external_inputs: input, - other_instances: Some((vec![], 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() } } diff --git a/src/main.rs b/src/main.rs index 1753ab0..c69f089 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use std::time::Instant; use scenario_config::ScenarioConfig; use crate::folding::{ - FoldingSchemeExt, HyperNovaFolding, NovaFolding, prepare_folding, verify_folding, + prepare_folding, verify_folding, FoldingSchemeExt, HyperNovaFolding, NovaFolding, }; mod circuit; @@ -22,14 +22,17 @@ fn measure T>(action_name: &str, action: Action) -> T { fn scenario(config: ScenarioConfig, rng: &mut impl rand::RngCore) { // ============== FOLDING PREPARATION ========================================================== + let start_state = config.start_ivc_state.clone(); let (mut folding, folding_vp) = measure("Prepare folding", || { - prepare_folding::(&config.circuit, config.start_ivc_state.clone(), rng) + prepare_folding::(&config.circuit, start_state.clone(), rng) }); // ============== FOLDING ====================================================================== - let input = config.input().to_vec(); - for (i, step_input) in FS::transform_inputs(input).enumerate() { + let input = measure("Transform input", || { + folding.transform_inputs(config.input().to_vec(), start_state.clone(), &mut *rng) + }); + for (i, step_input) in input.into_iter().enumerate() { measure(&format!("Prove_step {i}"), || { folding .prove_step( @@ -57,9 +60,12 @@ fn main() { let mut rng = rand::rngs::OsRng; let config = ScenarioConfig::new(); - println!("========== Nova folding scheme =========="); + println!("========== Nova folding scheme ===================="); scenario::(config.clone(), &mut rng); - println!("========== HyperNova folding scheme =========="); - scenario::(config, &mut rng); + println!("========== HyperNova<1,1> folding scheme =========="); + scenario::>(config.clone(), &mut rng); + + println!("========== HyperNova<2,2> folding scheme =========="); + scenario::>(config, &mut rng); } diff --git a/src/scenario_config.rs b/src/scenario_config.rs index 23a0050..6d3c7d1 100644 --- a/src/scenario_config.rs +++ b/src/scenario_config.rs @@ -15,7 +15,7 @@ pub struct ScenarioConfig { impl ScenarioConfig { pub fn new() -> Self { Self { - num_steps: 5, + num_steps: 6, start_ivc_state: vec![Fr::zero(); 2], circuit: measure("Prepare circuit", create_circuit), input: measure("Prepare input", prepare_input),