From c6f1a246e0705582a75de6becf4ad21f325fa5a1 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Fri, 27 Dec 2024 15:38:56 +0100 Subject: [PATCH] Update the FCircuit trait, so that it supports custom data structures for the external inputs. (#191) * Update the FCircuit trait, so that it supports custom data structures for the external inputs. This also eliminates the need of having the `external_inputs_len` method in the `FCircuit`. The motivation for this change is that in most practical use cases, the external inputs have a not-naive structure, and the old interface required that to convert the external inputs structure into a vector of finite field elements, which inside the FCircuit would be converted back into a custom data structure. This is specially tedious when dealing with curve points, which converting them from point to field elements and back to the point (both outside (rust native) and inside the circuit (constraints)) is a bit cumbersome. With this update, it's much more straight forward to define the FCircuit with custom external inputs data structures. For the experimental-frontends, the external inputs keep being an array of field elements. * remove Default from FCircuit::ExternalInputsVar, remove VecF & VecFpVar in examples/external_inputs.rs --- .gitignore | 4 +- benches/common.rs | 4 +- examples/circom_full_flow.rs | 14 +-- examples/external_inputs.rs | 22 ++--- examples/full_flow.rs | 10 +-- examples/multi_inputs.rs | 11 ++- examples/noir_full_flow.rs | 21 +++-- examples/noname_full_flow.rs | 20 +++-- examples/sha256.rs | 11 ++- experimental-frontends/src/circom/mod.rs | 59 +++++++------ experimental-frontends/src/lib.rs | 1 + experimental-frontends/src/noir/mod.rs | 56 ++++++------ experimental-frontends/src/noname/mod.rs | 61 ++++++------- experimental-frontends/src/utils.rs | 38 +++++++++ .../src/folding/circuits/nonnative/uint.rs | 4 +- .../src/folding/hypernova/circuits.rs | 14 ++- .../src/folding/hypernova/decider_eth.rs | 8 +- .../folding/hypernova/decider_eth_circuit.rs | 2 +- folding-schemes/src/folding/hypernova/mod.rs | 22 ++--- folding-schemes/src/folding/mod.rs | 6 +- folding-schemes/src/folding/nova/circuits.rs | 8 +- folding-schemes/src/folding/nova/decider.rs | 4 +- .../src/folding/nova/decider_circuits.rs | 2 +- .../src/folding/nova/decider_eth.rs | 8 +- .../src/folding/nova/decider_eth_circuit.rs | 2 +- folding-schemes/src/folding/nova/mod.rs | 14 +-- .../src/folding/protogalaxy/circuits.rs | 6 +- .../src/folding/protogalaxy/decider_eth.rs | 12 +-- .../protogalaxy/decider_eth_circuit.rs | 2 +- .../src/folding/protogalaxy/mod.rs | 85 ++++++++----------- folding-schemes/src/frontend/mod.rs | 14 +-- folding-schemes/src/frontend/utils.rs | 41 ++++----- folding-schemes/src/lib.rs | 6 +- solidity-verifiers/Cargo.toml | 4 +- .../src/verifiers/nova_cyclefold.rs | 17 ++-- 35 files changed, 319 insertions(+), 294 deletions(-) create mode 100644 experimental-frontends/src/utils.rs diff --git a/.gitignore b/.gitignore index e2e3afdc..d3ba383d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,12 +2,12 @@ Cargo.lock # Circom generated files -frontends/src/circom/test_folder/*_js/ +experimental-frontends/src/circom/test_folder/*_js/ *.r1cs *.sym # Noir generated files -frontends/src/noir/test_folder/*/target/* +experimental-frontends/src/noir/test_folder/*/target/* # generated contracts data solidity-verifiers/generated diff --git a/benches/common.rs b/benches/common.rs index 6c632b4b..163dbbfc 100644 --- a/benches/common.rs +++ b/benches/common.rs @@ -29,7 +29,7 @@ pub(crate) fn bench_ivc_opt< // warmup steps for _ in 0..5 { - fs.prove_step(rng, vec![], None)?; + fs.prove_step(rng, (), None)?; } let mut group = c.benchmark_group(format!( @@ -38,7 +38,7 @@ pub(crate) fn bench_ivc_opt< )); group.significance_level(0.1).sample_size(10); group.bench_function("prove_step", |b| { - b.iter(|| -> Result<_, _> { black_box(fs.clone()).prove_step(rng, vec![], None) }) + b.iter(|| -> Result<_, _> { black_box(fs.clone()).prove_step(rng, (), None) }) }); // verify the IVCProof diff --git a/examples/circom_full_flow.rs b/examples/circom_full_flow.rs index b0d92fb2..67aaad43 100644 --- a/examples/circom_full_flow.rs +++ b/examples/circom_full_flow.rs @@ -17,7 +17,7 @@ use ark_grumpkin::Projective as G2; use std::path::PathBuf; use std::time::Instant; -use experimental_frontends::circom::CircomFCircuit; +use experimental_frontends::{circom::CircomFCircuit, utils::VecF}; use folding_schemes::{ commitment::{kzg::KZG, pedersen::Pedersen}, folding::{ @@ -64,14 +64,16 @@ fn main() -> Result<(), Error> { "./experimental-frontends/src/circom/test_folder/with_external_inputs_js/with_external_inputs.wasm", ); - let f_circuit_params = (r1cs_path.into(), wasm_path.into(), 1, 2); - let f_circuit = CircomFCircuit::::new(f_circuit_params)?; + let f_circuit_params = (r1cs_path.into(), wasm_path.into(), 1); // state len = 1 + const EXT_INP_LEN: usize = 2; // external inputs len = 2 + let f_circuit = CircomFCircuit::::new(f_circuit_params)?; - pub type N = Nova, KZG<'static, Bn254>, Pedersen, false>; + pub type N = + Nova, KZG<'static, Bn254>, Pedersen, false>; pub type D = DeciderEth< G1, G2, - CircomFCircuit, + CircomFCircuit, KZG<'static, Bn254>, Pedersen, Groth16, @@ -94,7 +96,7 @@ fn main() -> Result<(), Error> { // run n steps of the folding iteration for (i, external_inputs_at_step) in external_inputs.iter().enumerate() { let start = Instant::now(); - nova.prove_step(rng, external_inputs_at_step.clone(), None)?; + nova.prove_step(rng, VecF(external_inputs_at_step.clone()), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/examples/external_inputs.rs b/examples/external_inputs.rs index 60427b00..79ebc86c 100644 --- a/examples/external_inputs.rs +++ b/examples/external_inputs.rs @@ -74,6 +74,8 @@ where F: Absorb, { type Params = PoseidonConfig; + type ExternalInputs = [F; 1]; + type ExternalInputsVar = [FpVar; 1]; fn new(params: Self::Params) -> Result { Ok(Self { @@ -84,9 +86,6 @@ where fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 1 - } /// generates the constraints and returns the next state value for the step of F for the given /// z_i and external_inputs fn generate_step_constraints( @@ -94,7 +93,7 @@ where cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - external_inputs: Vec>, + external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let crh_params = CRHParametersVar::::new_constant(cs.clone(), self.poseidon_config.clone())?; @@ -137,7 +136,10 @@ pub mod tests { external_inputs_step_native(z_i.clone(), external_inputs.clone(), &poseidon_config); let z_iVar = Vec::>::new_witness(cs.clone(), || Ok(z_i))?; - let external_inputsVar = Vec::>::new_witness(cs.clone(), || Ok(external_inputs))?; + let external_inputsVar: [FpVar; 1] = + Vec::>::new_witness(cs.clone(), || Ok(external_inputs))? + .try_into() + .unwrap(); let computed_z_i1Var = circuit.generate_step_constraints(cs.clone(), 0, z_iVar, external_inputsVar)?; @@ -153,11 +155,11 @@ fn main() -> Result<(), Error> { // prepare the external inputs to be used at each folding step let external_inputs = vec![ - vec![Fr::from(3_u32)], - vec![Fr::from(33_u32)], - vec![Fr::from(73_u32)], - vec![Fr::from(103_u32)], - vec![Fr::from(125_u32)], + [Fr::from(3_u32)], + [Fr::from(33_u32)], + [Fr::from(73_u32)], + [Fr::from(103_u32)], + [Fr::from(125_u32)], ]; assert_eq!(external_inputs.len(), num_steps); diff --git a/examples/full_flow.rs b/examples/full_flow.rs index 648171f0..4d84bd01 100644 --- a/examples/full_flow.rs +++ b/examples/full_flow.rs @@ -46,21 +46,21 @@ pub struct CubicFCircuit { } impl FCircuit for CubicFCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); + fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) } fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 0 - } fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let five = FpVar::::new_constant(cs.clone(), F::from(5u32))?; let z_i = z_i[0].clone(); @@ -96,7 +96,7 @@ fn main() -> Result<(), Error> { // run n steps of the folding iteration for i in 0..n_steps { let start = Instant::now(); - nova.prove_step(rng, vec![], None)?; + nova.prove_step(rng, (), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/examples/multi_inputs.rs b/examples/multi_inputs.rs index 67b32cf4..ff56bd9d 100644 --- a/examples/multi_inputs.rs +++ b/examples/multi_inputs.rs @@ -30,6 +30,8 @@ pub struct MultiInputsFCircuit { } impl FCircuit for MultiInputsFCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) @@ -37,16 +39,13 @@ impl FCircuit for MultiInputsFCircuit { fn state_len(&self) -> usize { 5 } - fn external_inputs_len(&self) -> usize { - 0 - } /// generates the constraints for the step of F for the given z_i fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let four = FpVar::::new_constant(cs.clone(), F::from(4u32))?; let forty = FpVar::::new_constant(cs.clone(), F::from(40u32))?; @@ -96,7 +95,7 @@ pub mod tests { let z_iVar = Vec::>::new_witness(cs.clone(), || Ok(z_i))?; let computed_z_i1Var = - circuit.generate_step_constraints(cs.clone(), 0, z_iVar.clone(), vec![])?; + circuit.generate_step_constraints(cs.clone(), 0, z_iVar.clone(), ())?; assert_eq!(computed_z_i1Var.value()?, z_i1); Ok(()) } @@ -140,7 +139,7 @@ fn main() -> Result<(), Error> { // compute a step of the IVC for i in 0..num_steps { let start = Instant::now(); - folding_scheme.prove_step(rng, vec![], None)?; + folding_scheme.prove_step(rng, (), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/examples/noir_full_flow.rs b/examples/noir_full_flow.rs index 147903e1..17c1f919 100644 --- a/examples/noir_full_flow.rs +++ b/examples/noir_full_flow.rs @@ -14,7 +14,7 @@ use ark_bn254::{Bn254, Fr, G1Projective as G1}; use ark_groth16::Groth16; use ark_grumpkin::Projective as G2; -use experimental_frontends::noir::NoirFCircuit; +use experimental_frontends::{noir::NoirFCircuit, utils::VecF}; use folding_schemes::{ commitment::{kzg::KZG, pedersen::Pedersen}, folding::{ @@ -42,16 +42,23 @@ fn main() -> Result<(), Error> { let z_0 = vec![Fr::from(1)]; // initialize the noir fcircuit - let f_circuit = NoirFCircuit::new(( + const EXT_INP_LEN: usize = 0; + let f_circuit = NoirFCircuit::::new(( Path::new("./experimental-frontends/src/noir/test_folder/test_mimc/target/test_mimc.json") .into(), 1, - 0, ))?; - pub type N = Nova, KZG<'static, Bn254>, Pedersen>; - pub type D = - DeciderEth, KZG<'static, Bn254>, Pedersen, Groth16, N>; + pub type N = Nova, KZG<'static, Bn254>, Pedersen>; + pub type D = DeciderEth< + G1, + G2, + NoirFCircuit, + KZG<'static, Bn254>, + Pedersen, + Groth16, + N, + >; let poseidon_config = poseidon_canonical_config::(); let mut rng = ark_std::rand::rngs::OsRng; @@ -69,7 +76,7 @@ fn main() -> Result<(), Error> { // run n steps of the folding iteration for i in 0..5 { let start = Instant::now(); - nova.prove_step(rng, vec![], None)?; + nova.prove_step(rng, VecF(vec![]), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } // verify the last IVC proof diff --git a/examples/noname_full_flow.rs b/examples/noname_full_flow.rs index 6bfb80bd..e42244ef 100644 --- a/examples/noname_full_flow.rs +++ b/examples/noname_full_flow.rs @@ -15,7 +15,7 @@ use noname::backends::r1cs::R1csBn254Field; use ark_groth16::Groth16; use ark_grumpkin::Projective as G2; -use experimental_frontends::noname::NonameFCircuit; +use experimental_frontends::{noname::NonameFCircuit, utils::VecF}; use folding_schemes::{ commitment::{kzg::KZG, pedersen::Pedersen}, folding::{ @@ -58,15 +58,21 @@ fn main() -> Result<(), Error> { ]; // initialize the noname circuit - let f_circuit_params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2, 2); - let f_circuit = NonameFCircuit::::new(f_circuit_params)?; + let f_circuit_params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2); // state len = 2 + const EXT_INP_LEN: usize = 2; + let f_circuit = NonameFCircuit::::new(f_circuit_params)?; - pub type N = - Nova, KZG<'static, Bn254>, Pedersen>; + pub type N = Nova< + G1, + G2, + NonameFCircuit, + KZG<'static, Bn254>, + Pedersen, + >; pub type D = DeciderEth< G1, G2, - NonameFCircuit, + NonameFCircuit, KZG<'static, Bn254>, Pedersen, Groth16, @@ -89,7 +95,7 @@ fn main() -> Result<(), Error> { // run n steps of the folding iteration for (i, external_inputs_at_step) in external_inputs.iter().enumerate() { let start = Instant::now(); - nova.prove_step(rng, external_inputs_at_step.clone(), None)?; + nova.prove_step(rng, VecF(external_inputs_at_step.clone()), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/examples/sha256.rs b/examples/sha256.rs index 95f75d16..22a5a104 100644 --- a/examples/sha256.rs +++ b/examples/sha256.rs @@ -36,6 +36,8 @@ pub struct Sha256FCircuit { } impl FCircuit for Sha256FCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) @@ -43,16 +45,13 @@ impl FCircuit for Sha256FCircuit { fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 0 - } /// generates the constraints for the step of F for the given z_i fn generate_step_constraints( &self, _cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let unit_var = UnitVar::default(); let out_bytes = Sha256Gadget::evaluate(&unit_var, &z_i[0].to_bytes_le()?)?; @@ -89,7 +88,7 @@ pub mod tests { let z_iVar = Vec::>::new_witness(cs.clone(), || Ok(z_i))?; let computed_z_i1Var = - circuit.generate_step_constraints(cs.clone(), 0, z_iVar.clone(), vec![])?; + circuit.generate_step_constraints(cs.clone(), 0, z_iVar.clone(), ())?; assert_eq!(computed_z_i1Var.value()?, z_i1); Ok(()) } @@ -126,7 +125,7 @@ fn main() -> Result<(), Error> { // compute a step of the IVC for i in 0..num_steps { let start = Instant::now(); - folding_scheme.prove_step(rng, vec![], None)?; + folding_scheme.prove_step(rng, (), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/experimental-frontends/src/circom/mod.rs b/experimental-frontends/src/circom/mod.rs index 4c62e01f..ed7a76a7 100644 --- a/experimental-frontends/src/circom/mod.rs +++ b/experimental-frontends/src/circom/mod.rs @@ -10,30 +10,32 @@ use folding_schemes::{frontend::FCircuit, utils::PathOrBin, Error}; use num_bigint::BigInt; pub mod utils; +use crate::utils::{VecF, VecFpVar}; use utils::CircomWrapper; -/// Define CircomFCircuit +/// Define CircomFCircuit. The parameter `L` indicates the length of the ExternalInputs vector of +/// field elements. #[derive(Clone, Debug)] -pub struct CircomFCircuit { +pub struct CircomFCircuit { circom_wrapper: CircomWrapper, pub state_len: usize, - pub external_inputs_len: usize, r1cs: CircomR1CS, } -impl FCircuit for CircomFCircuit { - /// (r1cs_path, wasm_path, state_len, external_inputs_len) - type Params = (PathOrBin, PathOrBin, usize, usize); +impl FCircuit for CircomFCircuit { + /// (r1cs_path, wasm_path, state_len) + type Params = (PathOrBin, PathOrBin, usize); + type ExternalInputs = VecF; + type ExternalInputsVar = VecFpVar; fn new(params: Self::Params) -> Result { - let (r1cs_path, wasm_path, state_len, external_inputs_len) = params; + let (r1cs_path, wasm_path, state_len) = params; let circom_wrapper = CircomWrapper::new(r1cs_path, wasm_path)?; let r1cs = circom_wrapper.extract_r1cs()?; Ok(Self { circom_wrapper, state_len, - external_inputs_len, r1cs, }) } @@ -41,27 +43,24 @@ impl FCircuit for CircomFCircuit { fn state_len(&self) -> usize { self.state_len } - fn external_inputs_len(&self) -> usize { - self.external_inputs_len - } fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - external_inputs: Vec>, + external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { #[cfg(test)] assert_eq!(z_i.len(), self.state_len()); #[cfg(test)] - assert_eq!(external_inputs.len(), self.external_inputs_len()); + assert_eq!(external_inputs.0.len(), L); let input_values = self.fpvars_to_bigints(&z_i)?; let mut inputs_map = vec![("ivc_input".to_string(), input_values)]; - if self.external_inputs_len() > 0 { - let external_inputs_bi = self.fpvars_to_bigints(&external_inputs)?; + if L > 0 { + let external_inputs_bi = self.fpvars_to_bigints(&external_inputs.0)?; inputs_map.push(("external_inputs".to_string(), external_inputs_bi)); } @@ -106,7 +105,7 @@ impl FCircuit for CircomFCircuit { } } -impl CircomFCircuit { +impl CircomFCircuit { fn fpvars_to_bigints(&self, fpvars: &[FpVar]) -> Result, SynthesisError> { let mut input_values = Vec::new(); // converts each FpVar to PrimeField value, then to num_bigint::BigInt. @@ -171,14 +170,15 @@ pub mod tests { PathBuf::from("./src/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); let circom_fcircuit = - CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 0))?; // state_len:1, external_inputs_len:0 + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1))?; // state_len:1, external_inputs_len:0 let cs = ConstraintSystem::::new_ref(); let z_i = vec![Fr::from(3u32)]; let z_i_var = Vec::>::new_witness(cs.clone(), || Ok(z_i))?; - let z_i1_var = circom_fcircuit.generate_step_constraints(cs.clone(), 1, z_i_var, vec![])?; + let z_i1_var = + circom_fcircuit.generate_step_constraints(cs.clone(), 1, z_i_var, VecFpVar(vec![]))?; assert_eq!(z_i1_var.value()?, vec![Fr::from(35u32)]); Ok(()) } @@ -191,7 +191,7 @@ pub mod tests { PathBuf::from("./src/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); let circom_fcircuit = - CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 0))?; // state_len:1, external_inputs_len:0 + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1))?; // state_len:1, external_inputs_len:0 // Allocates z_i1 by using step_native function. let z_i = vec![Fr::from(3_u32)]; @@ -215,7 +215,7 @@ pub mod tests { "./src/circom/test_folder/with_external_inputs_js/with_external_inputs.wasm", ); let circom_fcircuit = - CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 2))?; // state_len:1, external_inputs_len:2 + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1))?; // state_len:1, external_inputs_len:2 let cs = ConstraintSystem::::new_ref(); let z_i = vec![Fr::from(3u32)]; let external_inputs = vec![Fr::from(6u32), Fr::from(7u32)]; @@ -231,7 +231,7 @@ pub mod tests { cs.clone(), 1, z_i_var, - external_inputs_var, + VecFpVar(external_inputs_var), )?; assert_eq!(z_i1_var.value()?, z_i1_native); @@ -246,7 +246,7 @@ pub mod tests { cs.clone(), 1, wrong_z_i_var, - external_inputs_var, + VecFpVar(external_inputs_var), ); // TODO:: https://github.com/privacy-scaling-explorations/sonobe/issues/104 // Disable check for now @@ -260,7 +260,7 @@ pub mod tests { let wasm_path = PathBuf::from("./src/circom/test_folder/no_external_inputs_js/no_external_inputs.wasm"); let circom_fcircuit = - CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 3, 0))?; + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 3))?; let cs = ConstraintSystem::::new_ref(); let z_i = vec![Fr::from(3u32), Fr::from(4u32), Fr::from(5u32)]; let z_i_var = Vec::>::new_witness(cs.clone(), || Ok(z_i.clone()))?; @@ -269,7 +269,8 @@ pub mod tests { let z_i1_native = no_external_inputs_step_native(z_i.clone()); // run gadget step - let z_i1_var = circom_fcircuit.generate_step_constraints(cs.clone(), 1, z_i_var, vec![])?; + let z_i1_var = + circom_fcircuit.generate_step_constraints(cs.clone(), 1, z_i_var, VecFpVar(vec![]))?; assert_eq!(z_i1_var.value()?, z_i1_native); @@ -277,8 +278,12 @@ pub mod tests { let cs = ConstraintSystem::::new_ref(); let wrong_z_i = vec![Fr::from(0u32), Fr::from(4u32), Fr::from(5u32)]; let wrong_z_i_var = Vec::>::new_witness(cs.clone(), || Ok(wrong_z_i))?; - let _z_i1_var = - circom_fcircuit.generate_step_constraints(cs.clone(), 1, wrong_z_i_var, vec![]); + let _z_i1_var = circom_fcircuit.generate_step_constraints( + cs.clone(), + 1, + wrong_z_i_var, + VecFpVar(vec![]), + ); // TODO:: https://github.com/privacy-scaling-explorations/sonobe/issues/104 // Disable check for now // assert!(z_i1_var.is_err()) @@ -292,7 +297,7 @@ pub mod tests { PathBuf::from("./src/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); let circom_fcircuit = - CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 0))?; // state_len:1, external_inputs_len:0 + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1))?; // state_len:1, external_inputs_len:0 // Allocates z_i1 by using step_native function. let z_i = vec![Fr::from(3_u32)]; diff --git a/experimental-frontends/src/lib.rs b/experimental-frontends/src/lib.rs index f6b56f35..da1a1786 100644 --- a/experimental-frontends/src/lib.rs +++ b/experimental-frontends/src/lib.rs @@ -1,3 +1,4 @@ pub mod circom; pub mod noir; pub mod noname; +pub mod utils; diff --git a/experimental-frontends/src/noir/mod.rs b/experimental-frontends/src/noir/mod.rs index 1fcaa5b8..83228c8e 100644 --- a/experimental-frontends/src/noir/mod.rs +++ b/experimental-frontends/src/noir/mod.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use acvm::{ acir::{ acir_field::GenericFieldElement, @@ -12,18 +10,19 @@ use acvm::{ use ark_ff::PrimeField; use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar}; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; -use folding_schemes::{frontend::FCircuit, utils::PathOrBin, Error}; use serde::{self, Deserialize, Serialize}; +use std::collections::HashMap; use self::bridge::AcirCircuitSonobe; +use crate::utils::{VecF, VecFpVar}; +use folding_schemes::{frontend::FCircuit, utils::PathOrBin, Error}; mod bridge; #[derive(Clone, Debug)] -pub struct NoirFCircuit { +pub struct NoirFCircuit { pub circuit: Circuit>, pub state_len: usize, - pub external_inputs_len: usize, } #[derive(Clone, Serialize, Deserialize, Debug)] @@ -35,11 +34,13 @@ pub struct ProgramArtifactGeneric { pub bytecode: Program>, } -impl FCircuit for NoirFCircuit { - type Params = (PathOrBin, usize, usize); +impl FCircuit for NoirFCircuit { + type Params = (PathOrBin, usize); + type ExternalInputs = VecF; + type ExternalInputsVar = VecFpVar; fn new(params: Self::Params) -> Result { - let (source, state_len, external_inputs_len) = params; + let (source, state_len) = params; let input_string = match source { PathOrBin::Path(path) => { let file_path = path.with_extension("json"); @@ -62,27 +63,19 @@ impl FCircuit for NoirFCircuit { )); } - Ok(NoirFCircuit { - circuit, - state_len, - external_inputs_len, - }) + Ok(NoirFCircuit { circuit, state_len }) } fn state_len(&self) -> usize { self.state_len } - fn external_inputs_len(&self) -> usize { - self.external_inputs_len - } - fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - external_inputs: Vec>, // inputs that are not part of the state + external_inputs: Self::ExternalInputsVar, // inputs that are not part of the state ) -> Result>, SynthesisError> { let mut acvm = ACVM::new( &StubbedBlackBoxSolver, @@ -123,9 +116,9 @@ impl FCircuit for NoirFCircuit { .map(|witness| { let idx = witness.as_usize() - z_i.len(); let witness = AcvmWitness(witness.witness_index()); - already_assigned_witness_values.insert(witness, &external_inputs[idx]); + already_assigned_witness_values.insert(witness, &external_inputs.0[idx]); - let val = external_inputs[idx].value()?; + let val = external_inputs.0[idx].value()?; let value = if val == F::zero() { "0".to_string() } else { @@ -178,6 +171,7 @@ mod tests { use std::env; use crate::noir::NoirFCircuit; + use crate::utils::VecFpVar; /// Native implementation of `src/noir/test_folder/test_circuit` fn external_inputs_step_native(z_i: Vec, external_inputs: Vec) -> Vec { @@ -198,17 +192,22 @@ mod tests { fn test_step_constraints() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); let cur_path = env::current_dir()?; - let noirfcircuit = NoirFCircuit::new(( + // external inputs length: 2, state length: 2 + let noirfcircuit = NoirFCircuit::::new(( cur_path .join("src/noir/test_folder/test_circuit/target/test_circuit.json") .into(), 2, - 2, ))?; let inputs = vec![Fr::from(2), Fr::from(5)]; let z_i = Vec::>::new_witness(cs.clone(), || Ok(inputs.clone()))?; let external_inputs = Vec::>::new_witness(cs.clone(), || Ok(inputs))?; - let output = noirfcircuit.generate_step_constraints(cs.clone(), 0, z_i, external_inputs)?; + let output = noirfcircuit.generate_step_constraints( + cs.clone(), + 0, + z_i, + VecFpVar(external_inputs), + )?; assert_eq!(output[0].value()?, Fr::from(4)); assert_eq!(output[1].value()?, Fr::from(25)); Ok(()) @@ -218,18 +217,23 @@ mod tests { fn test_step_constraints_no_external_inputs() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); let cur_path = env::current_dir()?; - let noirfcircuit = NoirFCircuit::new(( + // external inputs length: 0, state length: 2 + let noirfcircuit = NoirFCircuit::::new(( cur_path .join("src/noir/test_folder/test_no_external_inputs/target/test_no_external_inputs.json") .into(), 2, - 0, )) ?; let inputs = vec![Fr::from(2), Fr::from(5)]; let z_i = Vec::>::new_witness(cs.clone(), || Ok(inputs.clone()))?; let external_inputs = vec![]; - let output = noirfcircuit.generate_step_constraints(cs.clone(), 0, z_i, external_inputs)?; + let output = noirfcircuit.generate_step_constraints( + cs.clone(), + 0, + z_i, + VecFpVar(external_inputs), + )?; assert_eq!(output[0].value()?, Fr::from(4)); assert_eq!(output[1].value()?, Fr::from(25)); Ok(()) diff --git a/experimental-frontends/src/noname/mod.rs b/experimental-frontends/src/noname/mod.rs index 5ec6ed18..897b49b0 100644 --- a/experimental-frontends/src/noname/mod.rs +++ b/experimental-frontends/src/noname/mod.rs @@ -1,39 +1,41 @@ +use ark_ff::PrimeField; use ark_r1cs_std::alloc::AllocVar; use ark_r1cs_std::fields::fp::FpVar; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; +use noname::backends::{r1cs::R1CS as R1CSNoname, BackendField}; +use noname::witness::CompiledCircuit; use num_bigint::BigUint; use std::marker::PhantomData; -use self::bridge::NonameSonobeCircuit; -use self::utils::{compile_source_code, NonameInputs}; - -use ark_ff::PrimeField; use folding_schemes::{frontend::FCircuit, Error}; -use noname::backends::{r1cs::R1CS as R1CSNoname, BackendField}; -use noname::witness::CompiledCircuit; pub mod bridge; pub mod utils; +use crate::utils::{VecF, VecFpVar}; +use self::bridge::NonameSonobeCircuit; +use self::utils::{compile_source_code, NonameInputs}; + +// `L` indicates the length of the ExternalInputs vector of field elements. #[derive(Debug, Clone)] -pub struct NonameFCircuit { +pub struct NonameFCircuit { pub state_len: usize, - pub external_inputs_len: usize, pub circuit: CompiledCircuit>, _f: PhantomData, } -impl FCircuit for NonameFCircuit { - type Params = (String, usize, usize); +impl FCircuit for NonameFCircuit { + type Params = (String, usize); + type ExternalInputs = VecF; + type ExternalInputsVar = VecFpVar; fn new(params: Self::Params) -> Result { - let (code, state_len, external_inputs_len) = params; + let (code, state_len) = params; let compiled_circuit = compile_source_code::(&code).map_err(|_| { Error::Other("Encountered an error while compiling a noname circuit".to_owned()) })?; Ok(NonameFCircuit { state_len, - external_inputs_len, circuit: compiled_circuit, _f: PhantomData, }) @@ -43,19 +45,15 @@ impl FCircuit for NonameFCircuit { self.state_len } - fn external_inputs_len(&self) -> usize { - self.external_inputs_len - } - fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - external_inputs: Vec>, + external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let wtns_external_inputs = - NonameInputs::from_fpvars((&external_inputs, "external_inputs".to_string()))?; + NonameInputs::from_fpvars((&external_inputs.0, "external_inputs".to_string()))?; let wtns_ivc_inputs = NonameInputs::from_fpvars((&z_i, "ivc_inputs".to_string()))?; let noname_witness = self .circuit @@ -78,7 +76,7 @@ impl FCircuit for NonameFCircuit { compiled_circuit: self.circuit.clone(), witness: noname_witness, assigned_z_i: &z_i, - assigned_external_inputs: &external_inputs, + assigned_external_inputs: &external_inputs.0, assigned_z_i1: &assigned_z_i1, }; noname_circuit.generate_constraints(cs.clone())?; @@ -89,16 +87,16 @@ impl FCircuit for NonameFCircuit { #[cfg(test)] mod tests { - use ark_bn254::Fr; use ark_ff::PrimeField; use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar}; + use ark_relations::r1cs::ConstraintSystem; use noname::backends::r1cs::R1csBn254Field; use folding_schemes::{frontend::FCircuit, Error}; use super::NonameFCircuit; - use ark_relations::r1cs::ConstraintSystem; + use crate::utils::VecFpVar; /// Native implementation of `NONAME_CIRCUIT_EXTERNAL_INPUTS` fn external_inputs_step_native(z_i: Vec, external_inputs: Vec) -> Vec { @@ -125,8 +123,9 @@ mod tests { #[test] fn test_step_native() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); - let params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2, 2); - let circuit = NonameFCircuit::::new(params)?; + // state length = 2, external inputs length= 2 + let params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2); + let circuit = NonameFCircuit::::new(params)?; let inputs_public = vec![Fr::from(2), Fr::from(5)]; let inputs_private = vec![Fr::from(8), Fr::from(2)]; @@ -139,7 +138,7 @@ mod tests { cs.clone(), 0, ivc_inputs_var, - external_inputs_var, + VecFpVar(external_inputs_var), )?; let z_i1_native = external_inputs_step_native(inputs_public, inputs_private); @@ -151,8 +150,9 @@ mod tests { #[test] fn test_step_constraints() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); - let params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2, 2); - let circuit = NonameFCircuit::::new(params)?; + // external inputs length= 2 + let params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2); + let circuit = NonameFCircuit::::new(params)?; let inputs_public = vec![Fr::from(2), Fr::from(5)]; let inputs_private = vec![Fr::from(8), Fr::from(2)]; @@ -163,7 +163,7 @@ mod tests { cs.clone(), 0, ivc_inputs_var, - external_inputs_var, + VecFpVar(external_inputs_var), )?; assert!(cs.is_satisfied()?); assert_eq!(z_i1[0].value()?, Fr::from(10_u8)); @@ -174,13 +174,14 @@ mod tests { #[test] fn test_generate_constraints_no_external_inputs() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); - let params = (NONAME_CIRCUIT_NO_EXTERNAL_INPUTS.to_owned(), 2, 0); + let params = (NONAME_CIRCUIT_NO_EXTERNAL_INPUTS.to_owned(), 2); // state length = 2 let inputs_public = vec![Fr::from(2), Fr::from(5)]; let ivc_inputs_var = Vec::>::new_witness(cs.clone(), || Ok(inputs_public))?; - let f_circuit = NonameFCircuit::::new(params)?; - f_circuit.generate_step_constraints(cs.clone(), 0, ivc_inputs_var, vec![])?; + // external inputs length = 0 + let f_circuit = NonameFCircuit::::new(params)?; + f_circuit.generate_step_constraints(cs.clone(), 0, ivc_inputs_var, VecFpVar(vec![]))?; assert!(cs.is_satisfied()?); Ok(()) } diff --git a/experimental-frontends/src/utils.rs b/experimental-frontends/src/utils.rs new file mode 100644 index 00000000..769c5ae7 --- /dev/null +++ b/experimental-frontends/src/utils.rs @@ -0,0 +1,38 @@ +use ark_ff::PrimeField; +use ark_r1cs_std::{ + alloc::{AllocVar, AllocationMode}, + fields::fp::FpVar, +}; +use ark_relations::r1cs::{Namespace, SynthesisError}; +use ark_std::fmt::Debug; +use core::borrow::Borrow; + +#[derive(Clone, Debug)] +pub struct VecF(pub Vec); +impl Default for VecF { + fn default() -> Self { + VecF(vec![F::zero(); L]) + } +} +#[derive(Clone, Debug)] +pub struct VecFpVar(pub Vec>); +impl AllocVar, F> for VecFpVar { + fn new_variable>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + f().and_then(|val| { + let cs = cs.into(); + + let v = Vec::>::new_variable(cs.clone(), || Ok(val.borrow().0.clone()), mode)?; + + Ok(VecFpVar(v)) + }) + } +} +impl Default for VecFpVar { + fn default() -> Self { + VecFpVar(vec![FpVar::::Constant(F::zero()); L]) + } +} diff --git a/folding-schemes/src/folding/circuits/nonnative/uint.rs b/folding-schemes/src/folding/circuits/nonnative/uint.rs index 033244f2..eafd8fa4 100644 --- a/folding-schemes/src/folding/circuits/nonnative/uint.rs +++ b/folding-schemes/src/folding/circuits/nonnative/uint.rs @@ -203,8 +203,8 @@ impl NonNativeUintVar { // Thus, 55 allows us to compute `Az∘Bz` without the expensive alignment // operation. // - // TODO (@winderica): either make it a global const, or compute an - // optimal value based on the modulus size + // TODO: either make it a global const, or compute an optimal value + // based on the modulus size. 55 } } diff --git a/folding-schemes/src/folding/hypernova/circuits.rs b/folding-schemes/src/folding/hypernova/circuits.rs index f7b34690..808ea49f 100644 --- a/folding-schemes/src/folding/hypernova/circuits.rs +++ b/folding-schemes/src/folding/hypernova/circuits.rs @@ -479,7 +479,7 @@ pub struct AugmentedFCircuit< pub(super) i_usize: Option, pub(super) z_0: Option>, pub(super) z_i: Option>, - pub(super) external_inputs: Option>, + pub(super) external_inputs: Option, pub(super) U_i: Option>, pub(super) Us: Option>>, // other U_i's to be folded that are not the main running instance pub(super) u_i_C: Option, // u_i.C @@ -602,7 +602,7 @@ where i_usize: Some(0), z_0: Some(z_0.clone()), z_i: Some(z_0.clone()), - external_inputs: Some(vec![C1::ScalarField::zero(); self.F.external_inputs_len()]), + external_inputs: Some(FC::ExternalInputs::default()), U_i: Some(U_i.clone()), Us: Some(Us), u_i_C: Some(u_i.C), @@ -681,10 +681,8 @@ where .z_i .unwrap_or(vec![CF1::::zero(); self.F.state_len()])) })?; - let external_inputs = Vec::>>::new_witness(cs.clone(), || { - Ok(self - .external_inputs - .unwrap_or(vec![CF1::::zero(); self.F.external_inputs_len()])) + let external_inputs = FC::ExternalInputsVar::new_witness(cs.clone(), || { + Ok(self.external_inputs.unwrap_or_default()) })?; let U_dummy = LCCCS::::dummy(&self.ccs); @@ -1278,7 +1276,7 @@ mod tests { i_usize: Some(0), z_0: Some(z_0.clone()), z_i: Some(z_i.clone()), - external_inputs: Some(vec![]), + external_inputs: Some(()), U_i: Some(U_i.clone()), Us: Some(Us.clone()), u_i_C: Some(u_i.C), @@ -1362,7 +1360,7 @@ mod tests { i_usize: Some(i), z_0: Some(z_0.clone()), z_i: Some(z_i.clone()), - external_inputs: Some(vec![]), + external_inputs: Some(()), U_i: Some(U_i.clone()), Us: Some(Us.clone()), u_i_C: Some(u_i.C), diff --git a/folding-schemes/src/folding/hypernova/decider_eth.rs b/folding-schemes/src/folding/hypernova/decider_eth.rs index 1a3346fc..d4bffd77 100644 --- a/folding-schemes/src/folding/hypernova/decider_eth.rs +++ b/folding-schemes/src/folding/hypernova/decider_eth.rs @@ -260,8 +260,8 @@ pub mod tests { let hypernova_params = HN::preprocess(&mut rng, &prep_param)?; let mut hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone())?; - hypernova.prove_step(&mut rng, vec![], Some((vec![], vec![])))?; - hypernova.prove_step(&mut rng, vec![], Some((vec![], vec![])))?; // do a 2nd step + hypernova.prove_step(&mut rng, (), Some((vec![], vec![])))?; + hypernova.prove_step(&mut rng, (), Some((vec![], vec![])))?; // do a 2nd step // prepare the Decider prover & verifier params let (decider_pp, decider_vp) = @@ -356,8 +356,8 @@ pub mod tests { let hypernova_params = (hypernova_pp_deserialized, hypernova_vp_deserialized); let mut hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone())?; - hypernova.prove_step(&mut rng, vec![], Some((vec![], vec![])))?; - hypernova.prove_step(&mut rng, vec![], Some((vec![], vec![])))?; + hypernova.prove_step(&mut rng, (), Some((vec![], vec![])))?; + hypernova.prove_step(&mut rng, (), Some((vec![], vec![])))?; // decider proof generation let proof = D::prove(rng, decider_pp, hypernova.clone())?; diff --git a/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs b/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs index 067c5501..099e2146 100644 --- a/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs @@ -301,7 +301,7 @@ pub mod tests { // generate a Nova instance and do a step of it let mut hypernova = HN::init(&hn_params, F_circuit, z_0.clone())?; - hypernova.prove_step(&mut rng, vec![], None)?; + hypernova.prove_step(&mut rng, (), None)?; let ivc_proof = hypernova.ivc_proof(); HN::verify(hn_params.1, ivc_proof)?; diff --git a/folding-schemes/src/folding/hypernova/mod.rs b/folding-schemes/src/folding/hypernova/mod.rs index ecba05a4..e6b5ae31 100644 --- a/folding-schemes/src/folding/hypernova/mod.rs +++ b/folding-schemes/src/folding/hypernova/mod.rs @@ -279,7 +279,7 @@ where &self, mut rng: impl RngCore, state: Vec, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, ) -> Result { let r1cs_z = self.new_instance_generic(state, external_inputs)?; // compute committed instances, w_{i+1}, u_{i+1}, which will be used as w_i, u_i, so we @@ -301,7 +301,7 @@ where &self, mut rng: impl RngCore, state: Vec, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, ) -> Result { let r1cs_z = self.new_instance_generic(state, external_inputs)?; // compute committed instances, w_{i+1}, u_{i+1}, which will be used as w_i, u_i, so we @@ -332,7 +332,7 @@ where fn new_instance_generic( &self, state: Vec, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, ) -> Result, Error> { // prepare the initial dummy instances let U_i = LCCCS::::dummy(&self.ccs); @@ -599,7 +599,7 @@ where fn prove_step( &mut self, mut rng: impl RngCore, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, other_instances: Option, ) -> Result<(), Error> { // ensure that commitments are blinding if user has specified so. @@ -665,14 +665,6 @@ where self.F.state_len(), )); } - if external_inputs.len() != self.F.external_inputs_len() { - return Err(Error::NotSameLength( - "F.external_inputs_len()".to_string(), - self.F.external_inputs_len(), - "external_inputs.len()".to_string(), - external_inputs.len(), - )); - } if self.i > C1::ScalarField::from_le_bytes_mod_order(&usize::MAX.to_le_bytes()) { return Err(Error::MaxStep); @@ -1045,17 +1037,17 @@ mod tests { let mut lcccs = vec![]; for j in 0..MU - 1 { let instance_state = vec![Fr::from(j as u32 + 85_u32)]; - let (U, W) = hypernova.new_running_instance(&mut rng, instance_state, vec![])?; + let (U, W) = hypernova.new_running_instance(&mut rng, instance_state, ())?; lcccs.push((U, W)); } let mut cccs = vec![]; for j in 0..NU - 1 { let instance_state = vec![Fr::from(j as u32 + 15_u32)]; - let (u, w) = hypernova.new_incoming_instance(&mut rng, instance_state, vec![])?; + let (u, w) = hypernova.new_incoming_instance(&mut rng, instance_state, ())?; cccs.push((u, w)); } - hypernova.prove_step(&mut rng, vec![], Some((lcccs, cccs)))?; + hypernova.prove_step(&mut rng, (), Some((lcccs, cccs)))?; } assert_eq!(Fr::from(num_steps as u32), hypernova.i); diff --git a/folding-schemes/src/folding/mod.rs b/folding-schemes/src/folding/mod.rs index 3de2751c..a2b23a8d 100644 --- a/folding-schemes/src/folding/mod.rs +++ b/folding-schemes/src/folding/mod.rs @@ -77,7 +77,7 @@ pub mod tests { // perform multiple IVC steps (internally folding) let num_steps: usize = 3; for _ in 0..num_steps { - fs.prove_step(&mut rng, vec![], None)?; + fs.prove_step(&mut rng, FC::ExternalInputs::default(), None)?; } // verify the IVCProof @@ -121,8 +121,8 @@ pub mod tests { // serialization new FS instance let num_steps: usize = 3; for _ in 0..num_steps { - new_fs.prove_step(&mut rng, vec![], None)?; - fs.prove_step(&mut rng, vec![], None)?; + new_fs.prove_step(&mut rng, FC::ExternalInputs::default(), None)?; + fs.prove_step(&mut rng, FC::ExternalInputs::default(), None)?; } // check that the IVCProofs from both FS instances are equal diff --git a/folding-schemes/src/folding/nova/circuits.rs b/folding-schemes/src/folding/nova/circuits.rs index 1989148c..6b7f8fa1 100644 --- a/folding-schemes/src/folding/nova/circuits.rs +++ b/folding-schemes/src/folding/nova/circuits.rs @@ -55,7 +55,7 @@ pub struct AugmentedFCircuit>> { pub(super) i_usize: Option, pub(super) z_0: Option>, pub(super) z_i: Option>, - pub(super) external_inputs: Option>, + pub(super) external_inputs: Option, pub(super) u_i_cmW: Option, pub(super) U_i: Option>, pub(super) U_i1_cmE: Option, @@ -125,10 +125,8 @@ where .z_i .unwrap_or(vec![CF1::::zero(); self.F.state_len()])) })?; - let external_inputs = Vec::>>::new_witness(cs.clone(), || { - Ok(self - .external_inputs - .unwrap_or(vec![CF1::::zero(); self.F.external_inputs_len()])) + let external_inputs = FC::ExternalInputsVar::new_witness(cs.clone(), || { + Ok(self.external_inputs.unwrap_or_default()) })?; let u_dummy = CommittedInstance::dummy(2); diff --git a/folding-schemes/src/folding/nova/decider.rs b/folding-schemes/src/folding/nova/decider.rs index f270aefa..8068dec4 100644 --- a/folding-schemes/src/folding/nova/decider.rs +++ b/folding-schemes/src/folding/nova/decider.rs @@ -371,9 +371,9 @@ pub mod tests { let mut nova = N::init(&nova_params, F_circuit, z_0.clone())?; println!("Nova initialized, {:?}", start.elapsed()); let start = Instant::now(); - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; println!("prove_step, {:?}", start.elapsed()); - nova.prove_step(&mut rng, vec![], None)?; // do a 2nd step + nova.prove_step(&mut rng, (), None)?; // do a 2nd step let mut rng = rand::rngs::OsRng; diff --git a/folding-schemes/src/folding/nova/decider_circuits.rs b/folding-schemes/src/folding/nova/decider_circuits.rs index f91537fa..db9a686d 100644 --- a/folding-schemes/src/folding/nova/decider_circuits.rs +++ b/folding-schemes/src/folding/nova/decider_circuits.rs @@ -192,7 +192,7 @@ pub mod tests { // generate a Nova instance and do a step of it let mut nova = N::init(&nova_params, F_circuit, z_0.clone())?; - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; // verify the IVC let ivc_proof = nova.ivc_proof(); N::verify(nova_params.1, ivc_proof)?; diff --git a/folding-schemes/src/folding/nova/decider_eth.rs b/folding-schemes/src/folding/nova/decider_eth.rs index b7a4a79c..55d05a94 100644 --- a/folding-schemes/src/folding/nova/decider_eth.rs +++ b/folding-schemes/src/folding/nova/decider_eth.rs @@ -319,9 +319,9 @@ pub mod tests { let (decider_pp, decider_vp) = D::preprocess(&mut rng, nova_params, nova.clone())?; let start = Instant::now(); - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; println!("prove_step, {:?}", start.elapsed()); - nova.prove_step(&mut rng, vec![], None)?; // do a 2nd step + nova.prove_step(&mut rng, (), None)?; // do a 2nd step // decider proof generation let start = Instant::now(); @@ -431,9 +431,9 @@ pub mod tests { let mut nova = N::init(&nova_params, F_circuit, z_0)?; let start = Instant::now(); - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; println!("prove_step, {:?}", start.elapsed()); - nova.prove_step(&mut rng, vec![], None)?; // do a 2nd step + nova.prove_step(&mut rng, (), None)?; // do a 2nd step // decider proof generation let start = Instant::now(); diff --git a/folding-schemes/src/folding/nova/decider_eth_circuit.rs b/folding-schemes/src/folding/nova/decider_eth_circuit.rs index b11c9b05..e3f7fdba 100644 --- a/folding-schemes/src/folding/nova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/nova/decider_eth_circuit.rs @@ -240,7 +240,7 @@ pub mod tests { // generate a Nova instance and do a step of it let mut nova = N::init(&nova_params, F_circuit, z_0.clone())?; - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; let ivc_proof = nova.ivc_proof(); N::verify(nova_params.1, ivc_proof)?; diff --git a/folding-schemes/src/folding/nova/mod.rs b/folding-schemes/src/folding/nova/mod.rs index d1e1540e..cae1782a 100644 --- a/folding-schemes/src/folding/nova/mod.rs +++ b/folding-schemes/src/folding/nova/mod.rs @@ -620,8 +620,8 @@ where fn prove_step( &mut self, mut rng: impl RngCore, - external_inputs: Vec, - // Nova does not support multi-instances folding + external_inputs: FC::ExternalInputs, + // Nova does not support multi-instances folding (by design) _other_instances: Option, ) -> Result<(), Error> { // ensure that commitments are blinding if user has specified so. @@ -659,14 +659,6 @@ where self.F.state_len(), )); } - if external_inputs.len() != self.F.external_inputs_len() { - return Err(Error::NotSameLength( - "F.external_inputs_len()".to_string(), - self.F.external_inputs_len(), - "external_inputs.len()".to_string(), - external_inputs.len(), - )); - } if self.i > C1::ScalarField::from_le_bytes_mod_order(&usize::MAX.to_le_bytes()) { return Err(Error::MaxStep); @@ -1123,7 +1115,7 @@ pub mod tests { )?; for _ in 0..num_steps { - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; } assert_eq!(Fr::from(num_steps as u32), nova.i); diff --git a/folding-schemes/src/folding/protogalaxy/circuits.rs b/folding-schemes/src/folding/protogalaxy/circuits.rs index d46afac1..3bfac847 100644 --- a/folding-schemes/src/folding/protogalaxy/circuits.rs +++ b/folding-schemes/src/folding/protogalaxy/circuits.rs @@ -238,7 +238,7 @@ pub struct AugmentedFCircuit>> { pub(super) i_usize: usize, pub(super) z_0: Vec>, pub(super) z_i: Vec>, - pub(super) external_inputs: Vec>, + pub(super) external_inputs: FC::ExternalInputs, pub(super) F: FC, // F circuit pub(super) u_i_phi: C1, pub(super) U_i: CommittedInstance, @@ -274,7 +274,7 @@ impl>> AugmentedFCircuit i_usize: 0, z_0: vec![CF1::::zero(); F_circuit.state_len()], z_i: vec![CF1::::zero(); F_circuit.state_len()], - external_inputs: vec![CF1::::zero(); F_circuit.external_inputs_len()], + external_inputs: FC::ExternalInputs::default(), u_i_phi: C1::zero(), U_i: u_dummy, U_i1_phi: C1::zero(), @@ -307,7 +307,7 @@ where let z_0 = Vec::>>::new_witness(cs.clone(), || Ok(self.z_0))?; let z_i = Vec::>>::new_witness(cs.clone(), || Ok(self.z_i))?; let external_inputs = - Vec::>>::new_witness(cs.clone(), || Ok(self.external_inputs))?; + FC::ExternalInputsVar::new_witness(cs.clone(), || Ok(self.external_inputs))?; let u_dummy = CommittedInstance::::dummy((2, self.U_i.betas.len())); let U_i = CommittedInstanceVar::::new_witness(cs.clone(), || Ok(self.U_i))?; diff --git a/folding-schemes/src/folding/protogalaxy/decider_eth.rs b/folding-schemes/src/folding/protogalaxy/decider_eth.rs index ddb843bc..4ea7e07a 100644 --- a/folding-schemes/src/folding/protogalaxy/decider_eth.rs +++ b/folding-schemes/src/folding/protogalaxy/decider_eth.rs @@ -285,8 +285,8 @@ pub mod tests { let start = Instant::now(); let mut protogalaxy = PG::init(&protogalaxy_params, F_circuit, z_0.clone())?; println!("ProtoGalaxy initialized, {:?}", start.elapsed()); - protogalaxy.prove_step(&mut rng, vec![], None)?; - protogalaxy.prove_step(&mut rng, vec![], None)?; // do a 2nd step + protogalaxy.prove_step(&mut rng, (), None)?; + protogalaxy.prove_step(&mut rng, (), None)?; // do a 2nd step // prepare the Decider prover & verifier params let (decider_pp, decider_vp) = @@ -360,8 +360,8 @@ pub mod tests { let start = Instant::now(); let mut protogalaxy = PG::init(&protogalaxy_params, F_circuit, z_0.clone())?; println!("ProtoGalaxy initialized, {:?}", start.elapsed()); - protogalaxy.prove_step(&mut rng, vec![], None)?; - protogalaxy.prove_step(&mut rng, vec![], None)?; // do a 2nd step + protogalaxy.prove_step(&mut rng, (), None)?; + protogalaxy.prove_step(&mut rng, (), None)?; // do a 2nd step // prepare the Decider prover & verifier params let (decider_pp, decider_vp) = @@ -402,9 +402,9 @@ pub mod tests { let mut protogalaxy = PG::init(&protogalaxy_params, F_circuit, z_0)?; let start = Instant::now(); - protogalaxy.prove_step(&mut rng, vec![], None)?; + protogalaxy.prove_step(&mut rng, (), None)?; println!("prove_step, {:?}", start.elapsed()); - protogalaxy.prove_step(&mut rng, vec![], None)?; // do a 2nd step + protogalaxy.prove_step(&mut rng, (), None)?; // do a 2nd step // decider proof generation let start = Instant::now(); diff --git a/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs b/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs index 483d7f9b..da9ce4e3 100644 --- a/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs @@ -222,7 +222,7 @@ pub mod tests { // generate a Nova instance and do a step of it let mut protogalaxy = PG::init(&pg_params, F_circuit, z_0.clone())?; - protogalaxy.prove_step(&mut rng, vec![], None)?; + protogalaxy.prove_step(&mut rng, (), None)?; let ivc_proof = protogalaxy.ivc_proof(); PG::verify(pg_params.1, ivc_proof)?; diff --git a/folding-schemes/src/folding/protogalaxy/mod.rs b/folding-schemes/src/folding/protogalaxy/mod.rs index 8e1e3090..32fa797f 100644 --- a/folding-schemes/src/folding/protogalaxy/mod.rs +++ b/folding-schemes/src/folding/protogalaxy/mod.rs @@ -455,9 +455,8 @@ where { /// returns the hash of the public parameters of ProtoGalaxy pub fn pp_hash(&self) -> Result { - // TODO (@winderica): support hiding commitments in ProtoGalaxy. - // For now, `H` is set to false. - // Tracking issue: https://github.com/privacy-scaling-explorations/sonobe/issues/82 + // TODO: support hiding commitments in ProtoGalaxy. For now, `H` is set to false. Tracking + // issue: https://github.com/privacy-scaling-explorations/sonobe/issues/82 pp_hash::( &self.r1cs, &self.cf_r1cs, @@ -557,7 +556,6 @@ where // For `t_lower_bound`, we configure `F'` with `t = 1` and compute log2 // of the size of `F'`. let state_len = F.state_len(); - let external_inputs_len = F.external_inputs_len(); // `F'` includes `F` and `ProtoGalaxy.V`, where `F` might be costly. // Observing that the cost of `F` is constant with respect to `t`, we @@ -569,14 +567,13 @@ where cs.clone(), 0, Vec::new_witness(cs.clone(), || Ok(vec![Zero::zero(); state_len]))?, - Vec::new_witness(cs.clone(), || Ok(vec![Zero::zero(); external_inputs_len]))?, + FC::ExternalInputsVar::new_witness(cs.clone(), || Ok(FC::ExternalInputs::default()))?, )?; let step_constraints = cs.num_constraints(); // Create a dummy circuit with the same state length and external inputs // length as `F`, which replaces `F` in the augmented circuit `F'`. - let dummy_circuit: DummyCircuit = - FCircuit::::new((state_len, external_inputs_len))?; + let dummy_circuit: DummyCircuit = FCircuit::::new(state_len)?; // Compute `augmentation_constraints`, the size of `F'` without `F`. let cs = ConstraintSystem::::new_ref(); @@ -700,9 +697,9 @@ where ) -> Result<(Self::ProverParam, Self::VerifierParam), Error> { // We fix `k`, the number of incoming instances, to 1, because // multi-instances folding is not supported yet. - // TODO (@winderica): Support multi-instances folding and make `k` a - // constant generic parameter (as in HyperNova) - // Tracking issue: https://github.com/privacy-scaling-explorations/sonobe/issues/82 + // TODO: Support multi-instances folding and make `k` a constant generic parameter (as in + // HyperNova). Tracking issue: + // https://github.com/privacy-scaling-explorations/sonobe/issues/82 let k = 1; // `d`, the degree of the constraint system, is set to 2, as we only // support R1CS for now, whose highest degree is 2. @@ -788,7 +785,7 @@ where fn prove_step( &mut self, mut rng: impl RngCore, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, _other_instances: Option, ) -> Result<(), Error> { // Multi-instances folding is not supported yet. @@ -797,9 +794,9 @@ where } // We fix `k`, the number of incoming instances, to 1, because // multi-instances folding is not supported yet. - // TODO (@winderica): Support multi-instances folding and make `k` a - // constant generic parameter (as in HyperNova) - // Tracking issue: https://github.com/privacy-scaling-explorations/sonobe/issues/82 + // TODO: Support multi-instances folding and make `k` a constant generic parameter (as in + // HyperNova). Tracking issue: + // https://github.com/privacy-scaling-explorations/sonobe/issues/82 let k = 1; // `d`, the degree of the constraint system, is set to 2, as we only // support R1CS for now, whose highest degree is 2. @@ -820,14 +817,6 @@ where self.F.state_len(), )); } - if external_inputs.len() != self.F.external_inputs_len() { - return Err(Error::NotSameLength( - "F.external_inputs_len()".to_string(), - self.F.external_inputs_len(), - "external_inputs.len()".to_string(), - external_inputs.len(), - )); - } let i_bn: BigUint = self.i.into(); let i_usize: usize = i_bn.try_into().map_err(|_| Error::MaxStep)?; @@ -847,7 +836,7 @@ where .external_inputs .clone_from(&external_inputs); - // There is no need to update `self.U_i` etc. as they are unchanged. + // There is no need to update `self.U_i` etc. as they are unchanged. } else { // Primary part: // Compute `U_{i+1}` by folding `u_i` into `U_i`. @@ -1167,7 +1156,7 @@ mod tests { let num_steps: usize = 3; for _ in 0..num_steps { - protogalaxy.prove_step(&mut test_rng(), vec![], None)?; + protogalaxy.prove_step(&mut test_rng(), (), None)?; } assert_eq!(Fr::from(num_steps as u32), protogalaxy.i); @@ -1184,32 +1173,28 @@ mod tests { let poseidon_config = poseidon_canonical_config::(); for state_len in [1, 10, 100] { - for external_inputs_len in [1, 10, 100] { - let dummy_circuit: DummyCircuit = - FCircuit::::new((state_len, external_inputs_len))?; - - let costs: Vec = (1..32) - .into_par_iter() - .map(|t| { - let cs = ConstraintSystem::::new_ref(); - AugmentedFCircuit::::empty( - &poseidon_config, - dummy_circuit.clone(), - t, - d, - k, - ) - .generate_constraints(cs.clone())?; - Ok(cs.num_constraints()) - }) - .collect::, Error>>()?; - - for t_lower_bound in log2(costs[0]) as usize..32 { - let num_constraints = - (1 << t_lower_bound) - costs[0] + costs[t_lower_bound - 1]; - let t = log2(num_constraints) as usize; - assert!(t == t_lower_bound || t == t_lower_bound + 1); - } + let dummy_circuit: DummyCircuit = FCircuit::::new(state_len)?; + + let costs: Vec = (1..32) + .into_par_iter() + .map(|t| { + let cs = ConstraintSystem::::new_ref(); + AugmentedFCircuit::::empty( + &poseidon_config, + dummy_circuit.clone(), + t, + d, + k, + ) + .generate_constraints(cs.clone())?; + Ok(cs.num_constraints()) + }) + .collect::, Error>>()?; + + for t_lower_bound in log2(costs[0]) as usize..32 { + let num_constraints = (1 << t_lower_bound) - costs[0] + costs[t_lower_bound - 1]; + let t = log2(num_constraints) as usize; + assert!(t == t_lower_bound || t == t_lower_bound + 1); } } Ok(()) diff --git a/folding-schemes/src/frontend/mod.rs b/folding-schemes/src/frontend/mod.rs index b5a352f5..43191e61 100644 --- a/folding-schemes/src/frontend/mod.rs +++ b/folding-schemes/src/frontend/mod.rs @@ -1,6 +1,6 @@ use crate::Error; use ark_ff::PrimeField; -use ark_r1cs_std::fields::fp::FpVar; +use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar}; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use ark_std::fmt::Debug; @@ -10,8 +10,14 @@ pub mod utils; /// inside the agmented F' function). /// The parameter z_i denotes the current state, and z_{i+1} denotes the next state after applying /// the step. +/// Note that the external inputs for the specific circuit are defined at the implementation of +/// both `FCircuit::ExternalInputs` and `FCircuit::ExternalInputsVar`, where the `Default` trait +/// implementation for the `ExternalInputs` returns the initialized data structure (ie. if the type +/// contains a vector, it is initialized at the expected length). pub trait FCircuit: Clone + Debug { type Params: Debug; + type ExternalInputs: Clone + Default + Debug; + type ExternalInputsVar: Clone + Debug + AllocVar; /// returns a new FCircuit instance fn new(params: Self::Params) -> Result; @@ -20,10 +26,6 @@ pub trait FCircuit: Clone + Debug { /// FCircuit inputs. fn state_len(&self) -> usize; - /// returns the number of elements in the external inputs used by the FCircuit. External inputs - /// are optional, and in case no external inputs are used, this method should return 0. - fn external_inputs_len(&self) -> usize; - /// generates the constraints for the step of F for the given z_i fn generate_step_constraints( // this method uses self, so that each FCircuit implementation (and different frontends) @@ -32,7 +34,7 @@ pub trait FCircuit: Clone + Debug { cs: ConstraintSystemRef, i: usize, z_i: Vec>, - external_inputs: Vec>, // inputs that are not part of the state + external_inputs: Self::ExternalInputsVar, // inputs that are not part of the state ) -> Result>, SynthesisError>; } diff --git a/folding-schemes/src/frontend/utils.rs b/folding-schemes/src/frontend/utils.rs index e4d3d749..51bceacc 100644 --- a/folding-schemes/src/frontend/utils.rs +++ b/folding-schemes/src/frontend/utils.rs @@ -10,35 +10,29 @@ use ark_std::{fmt::Debug, Zero}; use super::FCircuit; use crate::Error; -/// DummyCircuit is a circuit that has dummy state and external inputs whose -/// lengths are specified in the `state_len` and `external_inputs_len` -/// parameters, without any constraints. +/// DummyCircuit is a circuit that has dummy state whose length is specified in the `state_len` +/// parameter, without any constraints. #[derive(Clone, Debug)] pub struct DummyCircuit { state_len: usize, - external_inputs_len: usize, } impl FCircuit for DummyCircuit { - type Params = (usize, usize); + type Params = usize; + type ExternalInputs = (); + type ExternalInputsVar = (); - fn new((state_len, external_inputs_len): Self::Params) -> Result { - Ok(Self { - state_len, - external_inputs_len, - }) + fn new(state_len: Self::Params) -> Result { + Ok(Self { state_len }) } fn state_len(&self) -> usize { self.state_len } - fn external_inputs_len(&self) -> usize { - self.external_inputs_len - } fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, _z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { Vec::new_witness(cs.clone(), || Ok(vec![Zero::zero(); self.state_len])) } @@ -57,21 +51,21 @@ pub struct CubicFCircuit { #[cfg(test)] impl FCircuit for CubicFCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); + fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) } fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 0 - } fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let five = FpVar::::new_constant(cs.clone(), F::from(5u32))?; let z_i = z_i[0].clone(); @@ -97,6 +91,8 @@ pub struct CustomFCircuit { impl FCircuit for CustomFCircuit { type Params = usize; + type ExternalInputs = (); + type ExternalInputsVar = (); fn new(params: Self::Params) -> Result { Ok(Self { @@ -107,15 +103,12 @@ impl FCircuit for CustomFCircuit { fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 0 - } fn generate_step_constraints( &self, _cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let mut z_i1 = z_i[0].clone(); for _ in 0..self.n_constraints - 1 { @@ -153,9 +146,11 @@ impl> ConstraintSynthesizer for WrapperCircuit Vec::>::new_witness(cs.clone(), || Ok(self.z_i.unwrap_or(vec![F::zero()])))?; let z_i1 = Vec::>::new_input(cs.clone(), || Ok(self.z_i1.unwrap_or(vec![F::zero()])))?; + let external_inputs = + FC::ExternalInputsVar::new_input(cs.clone(), || Ok(FC::ExternalInputs::default()))?; let computed_z_i1 = self.FC - .generate_step_constraints(cs.clone(), 0, z_i.clone(), vec![])?; + .generate_step_constraints(cs.clone(), 0, z_i.clone(), external_inputs)?; use ark_r1cs_std::eq::EqGadget; computed_z_i1.enforce_equal(&z_i1)?; diff --git a/folding-schemes/src/lib.rs b/folding-schemes/src/lib.rs index aeb97c41..b3b132a6 100644 --- a/folding-schemes/src/lib.rs +++ b/folding-schemes/src/lib.rs @@ -197,7 +197,7 @@ pub trait FoldingScheme< fn prove_step( &mut self, rng: impl RngCore, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, other_instances: Option, ) -> Result<(), Error>; @@ -237,7 +237,7 @@ pub trait MultiFolding< &self, rng: impl RngCore, state: Vec, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, ) -> Result; /// Creates a new IncomingInstance for the given state, to be folded in the multi-folding step. @@ -245,7 +245,7 @@ pub trait MultiFolding< &self, rng: impl RngCore, state: Vec, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, ) -> Result; } diff --git a/solidity-verifiers/Cargo.toml b/solidity-verifiers/Cargo.toml index 2228d5cd..db26d064 100644 --- a/solidity-verifiers/Cargo.toml +++ b/solidity-verifiers/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] ark-groth16 = "^0.5.0" -ark-bn254 = "^0.5.0" +ark-bn254 = { version = "^0.5.0", default-features = false, features = ["r1cs"] } ark-poly-commit = "^0.5.0" ark-serialize = "^0.5.0" askama = { version = "0.12.0", features = ["config"], default-features = false } @@ -22,7 +22,7 @@ ark-crypto-primitives = { version = "^0.5.0", default-features = false, features ark-snark = { version = "^0.5.0", default-features = false } ark-relations = { version = "^0.5.0", default-features = false } ark-r1cs-std = { version = "^0.5.0", default-features = false, features = ["parallel"] } -ark-grumpkin = { version = "^0.5.0", default-features = false } +ark-grumpkin = { version = "^0.5.0", default-features = false, features = ["r1cs"] } folding-schemes = { path = "../folding-schemes/", features=["light-test"]} experimental-frontends = { path = "../experimental-frontends/"} noname = { git = "https://github.com/dmpierre/noname" } diff --git a/solidity-verifiers/src/verifiers/nova_cyclefold.rs b/solidity-verifiers/src/verifiers/nova_cyclefold.rs index 95a9b794..26a6397a 100644 --- a/solidity-verifiers/src/verifiers/nova_cyclefold.rs +++ b/solidity-verifiers/src/verifiers/nova_cyclefold.rs @@ -190,21 +190,20 @@ mod tests { } impl FCircuit for CubicFCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) } fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 0 - } fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let five = FpVar::::new_constant(cs.clone(), F::from(5u32))?; let z_i = z_i[0].clone(); @@ -224,6 +223,8 @@ mod tests { } impl FCircuit for MultiInputsFCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) @@ -231,16 +232,13 @@ mod tests { fn state_len(&self) -> usize { 5 } - fn external_inputs_len(&self) -> usize { - 0 - } /// generates the constraints for the step of F for the given z_i fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let four = FpVar::::new_constant(cs.clone(), F::from(4u32))?; let forty = FpVar::::new_constant(cs.clone(), F::from(40u32))?; @@ -344,7 +342,8 @@ mod tests { let mut nova = NOVA::::init(&fs_params, f_circuit, z_0).unwrap(); for _ in 0..n_steps { - nova.prove_step(&mut rng, vec![], None).unwrap(); + nova.prove_step(&mut rng, FC::ExternalInputs::default(), None) + .unwrap(); } let start = Instant::now();