diff --git a/examples/circom_full_flow.rs b/examples/circom_full_flow.rs index a78dfa4..8db4a16 100644 --- a/examples/circom_full_flow.rs +++ b/examples/circom_full_flow.rs @@ -61,7 +61,7 @@ fn main() { "./folding-schemes/src/frontend/circom/test_folder/with_external_inputs_js/with_external_inputs.wasm", ); - let f_circuit_params = (r1cs_path, wasm_path, 1, 2); + let f_circuit_params = (r1cs_path.into(), wasm_path.into(), 1, 2); let f_circuit = CircomFCircuit::::new(f_circuit_params).unwrap(); pub type N = diff --git a/folding-schemes/Cargo.toml b/folding-schemes/Cargo.toml index 067b6e1..6fc5bc3 100644 --- a/folding-schemes/Cargo.toml +++ b/folding-schemes/Cargo.toml @@ -25,12 +25,12 @@ num-bigint = "0.4" num-integer = "0.1" color-eyre = "=0.6.2" sha3 = "0.10" -ark-noname = { git = "https://github.com/dmpierre/ark-noname", branch="feat/sonobe-integration" } +ark-noname = { git = "https://github.com/dmpierre/ark-noname", branch = "feat/sonobe-integration" } noname = { git = "https://github.com/dmpierre/noname" } serde_json = "1.0.85" # to (de)serialize JSON serde = "1.0.203" acvm = { git = "https://github.com/noir-lang/noir", rev="2b4853e", default-features = false } -arkworks_backend = { git = "https://github.com/dmpierre/arkworks_backend", branch="feat/sonobe-integration" } +arkworks_backend = { git = "https://github.com/dmpierre/arkworks_backend", branch = "feat/sonobe-integration" } log = "0.4" # tmp import for espresso's sumcheck diff --git a/folding-schemes/src/frontend/circom/mod.rs b/folding-schemes/src/frontend/circom/mod.rs index 303a5de..11d900e 100644 --- a/folding-schemes/src/frontend/circom/mod.rs +++ b/folding-schemes/src/frontend/circom/mod.rs @@ -1,5 +1,6 @@ use crate::frontend::FCircuit; use crate::frontend::FpVar::Var; +use crate::utils::PathOrBin; use crate::Error; use ark_circom::circom::{CircomCircuit, R1CS as CircomR1CS}; use ark_ff::PrimeField; @@ -9,7 +10,6 @@ use ark_r1cs_std::R1CSVar; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; use ark_std::fmt::Debug; use num_bigint::BigInt; -use std::path::PathBuf; use std::rc::Rc; use std::{fmt, usize}; @@ -93,11 +93,11 @@ impl CircomFCircuit { impl FCircuit for CircomFCircuit { /// (r1cs_path, wasm_path, state_len, external_inputs_len) - type Params = (PathBuf, PathBuf, usize, usize); + type Params = (PathOrBin, PathOrBin, usize, usize); fn new(params: Self::Params) -> Result { let (r1cs_path, wasm_path, state_len, external_inputs_len) = params; - let circom_wrapper = CircomWrapper::new(r1cs_path, wasm_path); + let circom_wrapper = CircomWrapper::new(r1cs_path, wasm_path)?; let r1cs = circom_wrapper.extract_r1cs()?; Ok(Self { @@ -208,6 +208,7 @@ pub mod tests { use super::*; use ark_bn254::Fr; use ark_relations::r1cs::ConstraintSystem; + use std::path::PathBuf; // Tests the step_native function of CircomFCircuit. #[test] @@ -216,7 +217,8 @@ pub mod tests { let wasm_path = PathBuf::from("./src/frontend/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); - let circom_fcircuit = CircomFCircuit::::new((r1cs_path, wasm_path, 1, 0)).unwrap(); // state_len:1, external_inputs_len:0 + let circom_fcircuit = + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 0)).unwrap(); // state_len:1, external_inputs_len:0 let z_i = vec![Fr::from(3u32)]; let z_i1 = circom_fcircuit.step_native(1, z_i, vec![]).unwrap(); @@ -230,7 +232,8 @@ pub mod tests { let wasm_path = PathBuf::from("./src/frontend/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); - let circom_fcircuit = CircomFCircuit::::new((r1cs_path, wasm_path, 1, 0)).unwrap(); // state_len:1, external_inputs_len:0 + let circom_fcircuit = + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 0)).unwrap(); // state_len:1, external_inputs_len:0 let cs = ConstraintSystem::::new_ref(); @@ -250,7 +253,8 @@ pub mod tests { let wasm_path = PathBuf::from("./src/frontend/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); - let circom_fcircuit = CircomFCircuit::::new((r1cs_path, wasm_path, 1, 0)).unwrap(); // state_len:1, external_inputs_len:0 + let circom_fcircuit = + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 0)).unwrap(); // state_len:1, external_inputs_len:0 // Allocates z_i1 by using step_native function. let z_i = vec![Fr::from(3_u32)]; @@ -276,7 +280,8 @@ pub mod tests { let wasm_path = PathBuf::from( "./src/frontend/circom/test_folder/with_external_inputs_js/with_external_inputs.wasm", ); - let circom_fcircuit = CircomFCircuit::::new((r1cs_path, wasm_path, 1, 2)).unwrap(); // state_len:1, external_inputs_len:2 + let circom_fcircuit = + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 2)).unwrap(); // 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)]; @@ -319,7 +324,8 @@ pub mod tests { let wasm_path = PathBuf::from( "./src/frontend/circom/test_folder/no_external_inputs_js/no_external_inputs.wasm", ); - let circom_fcircuit = CircomFCircuit::::new((r1cs_path, wasm_path, 3, 0)).unwrap(); + let circom_fcircuit = + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 3, 0)).unwrap(); 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())).unwrap(); @@ -351,7 +357,8 @@ pub mod tests { let wasm_path = PathBuf::from("./src/frontend/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); - let mut circom_fcircuit = CircomFCircuit::::new((r1cs_path, wasm_path, 1, 0)).unwrap(); // state_len:1, external_inputs_len:0 + let mut circom_fcircuit = + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 0)).unwrap(); // state_len:1, external_inputs_len:0 circom_fcircuit.set_custom_step_native(Rc::new(|_i, z_i, _external| { let z = z_i[0]; diff --git a/folding-schemes/src/frontend/circom/utils.rs b/folding-schemes/src/frontend/circom/utils.rs index 9ee7dfb..f2c8919 100644 --- a/folding-schemes/src/frontend/circom/utils.rs +++ b/folding-schemes/src/frontend/circom/utils.rs @@ -3,40 +3,64 @@ use ark_circom::{ WitnessCalculator, }; use ark_ff::{BigInteger, PrimeField}; +use ark_serialize::Read; use color_eyre::Result; use num_bigint::{BigInt, Sign}; -use std::{fs::File, io::BufReader, marker::PhantomData, path::PathBuf}; +use std::{fs::File, io::Cursor, marker::PhantomData, path::PathBuf}; -use crate::Error; +use crate::{utils::PathOrBin, Error}; // A struct that wraps Circom functionalities, allowing for extraction of R1CS and witnesses // based on file paths to Circom's .r1cs and .wasm. #[derive(Clone, Debug)] pub struct CircomWrapper { - r1cs_filepath: PathBuf, - wasm_filepath: PathBuf, + r1csfile_bytes: Vec, + wasmfile_bytes: Vec, _marker: PhantomData, } impl CircomWrapper { // Creates a new instance of the CircomWrapper with the file paths. - pub fn new(r1cs_filepath: PathBuf, wasm_filepath: PathBuf) -> Self { - CircomWrapper { - r1cs_filepath, - wasm_filepath, - _marker: PhantomData, + pub fn new(r1cs: PathOrBin, wasm: PathOrBin) -> Result { + match (r1cs, wasm) { + (PathOrBin::Path(r1cs_path), PathOrBin::Path(wasm_path)) => { + Self::new_from_path(r1cs_path, wasm_path) + } + (PathOrBin::Bin(r1cs_bin), PathOrBin::Bin(wasm_bin)) => Ok(Self { + r1csfile_bytes: r1cs_bin, + wasmfile_bytes: wasm_bin, + _marker: PhantomData, + }), + _ => unreachable!("You should pass the same enum branch for both inputs"), } } + // Creates a new instance of the CircomWrapper with the file paths. + fn new_from_path(r1cs_file_path: PathBuf, wasm_file_path: PathBuf) -> Result { + let mut file = File::open(r1cs_file_path)?; + let metadata = File::metadata(&file)?; + let mut r1csfile_bytes = vec![0; metadata.len() as usize]; + file.read_exact(&mut r1csfile_bytes)?; + + let mut file = File::open(wasm_file_path)?; + let metadata = File::metadata(&file)?; + let mut wasmfile_bytes = vec![0; metadata.len() as usize]; + file.read_exact(&mut wasmfile_bytes)?; + + Ok(CircomWrapper { + r1csfile_bytes, + wasmfile_bytes, + _marker: PhantomData, + }) + } + // Aggregated function to obtain R1CS and witness from Circom. pub fn extract_r1cs_and_witness( &self, inputs: &[(String, Vec)], ) -> Result<(R1CS, Option>), Error> { // Extracts the R1CS - let file = File::open(&self.r1cs_filepath)?; - let reader = BufReader::new(file); - let r1cs_file = r1cs_reader::R1CSFile::::new(reader)?; + let r1cs_file = r1cs_reader::R1CSFile::::new(Cursor::new(&self.r1csfile_bytes))?; let r1cs = r1cs_reader::R1CS::::from(r1cs_file); // Extracts the witness vector @@ -46,9 +70,7 @@ impl CircomWrapper { } pub fn extract_r1cs(&self) -> Result, Error> { - let file = File::open(&self.r1cs_filepath)?; - let reader = BufReader::new(file); - let r1cs_file = r1cs_reader::R1CSFile::::new(reader)?; + let r1cs_file = r1cs_reader::R1CSFile::::new(Cursor::new(&self.r1csfile_bytes))?; let mut r1cs = r1cs_reader::R1CS::::from(r1cs_file); r1cs.wire_mapping = None; Ok(r1cs) @@ -75,7 +97,7 @@ impl CircomWrapper { &self, inputs: &[(String, Vec)], ) -> Result, Error> { - let mut calculator = WitnessCalculator::new(&self.wasm_filepath).map_err(|e| { + let mut calculator = WitnessCalculator::from_binary(&self.wasmfile_bytes).map_err(|e| { Error::WitnessCalculationError(format!("Failed to create WitnessCalculator: {}", e)) })?; calculator @@ -139,7 +161,7 @@ mod tests { PathBuf::from("./src/frontend/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); let inputs = vec![("ivc_input".to_string(), vec![BigInt::from(3)])]; - let wrapper = CircomWrapper::::new(r1cs_path, wasm_path); + let wrapper = CircomWrapper::::new(r1cs_path.into(), wasm_path.into()).unwrap(); let (r1cs, witness) = wrapper.extract_r1cs_and_witness(&inputs).unwrap(); diff --git a/folding-schemes/src/frontend/noir/mod.rs b/folding-schemes/src/frontend/noir/mod.rs index f069c22..6709b20 100644 --- a/folding-schemes/src/frontend/noir/mod.rs +++ b/folding-schemes/src/frontend/noir/mod.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::Error; +use crate::{utils::PathOrBin, Error}; use super::FCircuit; use acvm::{ @@ -16,7 +16,9 @@ use ark_ff::PrimeField; use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar}; use ark_relations::r1cs::ConstraintSynthesizer; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; -use arkworks_backend::{read_program_from_file, sonobe_bridge::AcirCircuitSonobe}; +use arkworks_backend::{ + read_program_from_binary, read_program_from_file, sonobe_bridge::AcirCircuitSonobe, +}; #[derive(Clone, Debug)] pub struct NoirFCircuit { @@ -26,12 +28,15 @@ pub struct NoirFCircuit { } impl FCircuit for NoirFCircuit { - type Params = (String, usize, usize); + type Params = (PathOrBin, usize, usize); fn new(params: Self::Params) -> Result { - let (path, state_len, external_inputs_len) = params; - let program = - read_program_from_file(path).map_err(|ee| Error::Other(format!("{:?}", ee)))?; + let (source, state_len, external_inputs_len) = params; + let program = match source { + PathOrBin::Path(path) => read_program_from_file(path), + PathOrBin::Bin(bytes) => read_program_from_binary(&bytes), + } + .map_err(|ee| Error::Other(format!("{:?}", ee)))?; let circuit: Circuit> = program.functions[0].clone(); let ivc_input_length = circuit.public_parameters.0.len(); let ivc_return_length = circuit.return_values.0.len(); diff --git a/folding-schemes/src/utils/mod.rs b/folding-schemes/src/utils/mod.rs index c2fdc3a..b1bad97 100644 --- a/folding-schemes/src/utils/mod.rs +++ b/folding-schemes/src/utils/mod.rs @@ -1,3 +1,6 @@ +use std::path::Path; +use std::path::PathBuf; + use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; use ark_ec::{AffineRepr, CurveGroup}; use ark_ff::PrimeField; @@ -100,3 +103,31 @@ where &public_params_hash, )) } + +/// Tiny utility enum that allows to import circuits and wasm modules from files by passing their path +/// or passing their content already read. +/// +/// This enum implements the [`From`] trait for both [`Path`], [`PathBuf`] and [`Vec`]. +#[derive(Debug, Clone)] +pub enum PathOrBin { + Path(PathBuf), + Bin(Vec), +} + +impl From<&Path> for PathOrBin { + fn from(value: &Path) -> Self { + PathOrBin::Path(value.into()) + } +} + +impl From for PathOrBin { + fn from(value: PathBuf) -> Self { + PathOrBin::Path(value) + } +} + +impl From> for PathOrBin { + fn from(value: Vec) -> Self { + PathOrBin::Bin(value) + } +}