diff --git a/Cargo.lock b/Cargo.lock index e8f1c13..3dfb8b0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -665,9 +665,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" dependencies = [ "jobserver", "libc", diff --git a/benches/groth16.rs b/benches/groth16.rs index e18af15..51847c9 100644 --- a/benches/groth16.rs +++ b/benches/groth16.rs @@ -4,7 +4,7 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use ark_circom::{read_zkey, CircomReduction, WitnessCalculator}; use ark_std::rand::thread_rng; -use ark_bn254::Bn254; +use ark_bn254::{Bn254, Fr}; use ark_groth16::Groth16; use wasmer::Store; @@ -39,7 +39,7 @@ fn bench_groth(c: &mut Criterion, num_validators: u32, num_constraints: u32) { ) .unwrap(); let full_assignment = wtns - .calculate_witness_element::(&mut store, inputs, false) + .calculate_witness_element::(&mut store, inputs, false) .unwrap(); let mut rng = thread_rng(); diff --git a/src/circom/builder.rs b/src/circom/builder.rs index 2b1ab5d..f1842a0 100644 --- a/src/circom/builder.rs +++ b/src/circom/builder.rs @@ -1,7 +1,8 @@ -use ark_ec::pairing::Pairing; use std::{fs::File, path::Path}; use wasmer::Store; +use ark_ff::PrimeField; + use super::{CircomCircuit, R1CS}; use num_bigint::BigInt; @@ -14,21 +15,21 @@ use crate::{ use color_eyre::Result; #[derive(Debug)] -pub struct CircomBuilder { - pub cfg: CircomConfig, +pub struct CircomBuilder { + pub cfg: CircomConfig, pub inputs: HashMap>, } // Add utils for creating this from files / directly from bytes #[derive(Debug)] -pub struct CircomConfig { - pub r1cs: R1CS, +pub struct CircomConfig { + pub r1cs: R1CS, pub wtns: WitnessCalculator, pub store: Store, pub sanity_check: bool, } -impl CircomConfig { +impl CircomConfig { pub fn new(wtns: impl AsRef, r1cs: impl AsRef) -> Result { let mut store = Store::default(); let wtns = WitnessCalculator::new(&mut store, wtns).unwrap(); @@ -56,10 +57,10 @@ impl CircomConfig { } } -impl CircomBuilder { +impl CircomBuilder { /// Instantiates a new builder using the provided WitnessGenerator and R1CS files /// for your circuit - pub fn new(cfg: CircomConfig) -> Self { + pub fn new(cfg: CircomConfig) -> Self { Self { cfg, inputs: HashMap::new(), @@ -74,7 +75,7 @@ impl CircomBuilder { /// Generates an empty circom circuit with no witness set, to be used for /// generation of the trusted setup parameters - pub fn setup(&self) -> CircomCircuit { + pub fn setup(&self) -> CircomCircuit { let mut circom = CircomCircuit { r1cs: self.cfg.r1cs.clone(), witness: None, @@ -88,11 +89,11 @@ impl CircomBuilder { /// Creates the circuit populated with the witness corresponding to the previously /// provided inputs - pub fn build(mut self) -> Result> { + pub fn build(mut self) -> Result> { let mut circom = self.setup(); // calculate the witness - let witness = self.cfg.wtns.calculate_witness_element::( + let witness = self.cfg.wtns.calculate_witness_element::( &mut self.cfg.store, self.inputs, self.cfg.sanity_check, @@ -102,7 +103,7 @@ impl CircomBuilder { // sanity check debug_assert!({ use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; - let cs = ConstraintSystem::::new_ref(); + let cs = ConstraintSystem::::new_ref(); circom.clone().generate_constraints(cs.clone()).unwrap(); let is_satisfied = cs.is_satisfied().unwrap(); if !is_satisfied { diff --git a/src/circom/circuit.rs b/src/circom/circuit.rs index 05c4b33..be76518 100644 --- a/src/circom/circuit.rs +++ b/src/circom/circuit.rs @@ -1,20 +1,21 @@ -use ark_ec::pairing::Pairing; use ark_relations::r1cs::{ ConstraintSynthesizer, ConstraintSystemRef, LinearCombination, SynthesisError, Variable, }; +use ark_ff::PrimeField; + use super::R1CS; use color_eyre::Result; #[derive(Clone, Debug)] -pub struct CircomCircuit { - pub r1cs: R1CS, - pub witness: Option>, +pub struct CircomCircuit { + pub r1cs: R1CS, + pub witness: Option>, } -impl CircomCircuit { - pub fn get_public_inputs(&self) -> Option> { +impl CircomCircuit { + pub fn get_public_inputs(&self) -> Option> { match &self.witness { None => None, Some(w) => match &self.r1cs.wire_mapping { @@ -25,11 +26,8 @@ impl CircomCircuit { } } -impl ConstraintSynthesizer for CircomCircuit { - fn generate_constraints( - self, - cs: ConstraintSystemRef, - ) -> Result<(), SynthesisError> { +impl ConstraintSynthesizer for CircomCircuit { + fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { let witness = &self.witness; let wire_mapping = &self.r1cs.wire_mapping; @@ -37,7 +35,7 @@ impl ConstraintSynthesizer for CircomCircuit { for i in 1..self.r1cs.num_inputs { cs.new_input_variable(|| { Ok(match witness { - None => E::ScalarField::from(1u32), + None => F::from(1u32), Some(w) => match wire_mapping { Some(m) => w[m[i]], None => w[i], @@ -49,7 +47,7 @@ impl ConstraintSynthesizer for CircomCircuit { for i in 0..self.r1cs.num_aux { cs.new_witness_variable(|| { Ok(match witness { - None => E::ScalarField::from(1u32), + None => F::from(1u32), Some(w) => match wire_mapping { Some(m) => w[m[i + self.r1cs.num_inputs]], None => w[i + self.r1cs.num_inputs], @@ -65,12 +63,10 @@ impl ConstraintSynthesizer for CircomCircuit { Variable::Witness(index - self.r1cs.num_inputs) } }; - let make_lc = |lc_data: &[(usize, E::ScalarField)]| { + let make_lc = |lc_data: &[(usize, F)]| { lc_data.iter().fold( - LinearCombination::::zero(), - |lc: LinearCombination, (index, coeff)| { - lc + (*coeff, make_index(*index)) - }, + LinearCombination::::zero(), + |lc: LinearCombination, (index, coeff)| lc + (*coeff, make_index(*index)), ) }; @@ -90,12 +86,12 @@ impl ConstraintSynthesizer for CircomCircuit { mod tests { use super::*; use crate::{CircomBuilder, CircomConfig}; - use ark_bn254::{Bn254, Fr}; + use ark_bn254::Fr; use ark_relations::r1cs::ConstraintSystem; #[tokio::test] async fn satisfied() { - let cfg = CircomConfig::::new( + let cfg = CircomConfig::::new( "./test-vectors/mycircuit_js/mycircuit.wasm", "./test-vectors/mycircuit.r1cs", ) diff --git a/src/circom/mod.rs b/src/circom/mod.rs index 6ad7fd0..080eb2d 100644 --- a/src/circom/mod.rs +++ b/src/circom/mod.rs @@ -1,5 +1,3 @@ -use ark_ec::pairing::Pairing; - pub mod r1cs_reader; pub use r1cs_reader::{R1CSFile, R1CS}; @@ -12,5 +10,5 @@ pub use builder::{CircomBuilder, CircomConfig}; mod qap; pub use qap::CircomReduction; -pub type Constraints = (ConstraintVec, ConstraintVec, ConstraintVec); -pub type ConstraintVec = Vec<(usize, ::ScalarField)>; +pub type Constraints = (ConstraintVec, ConstraintVec, ConstraintVec); +pub type ConstraintVec = Vec<(usize, F)>; diff --git a/src/circom/r1cs_reader.rs b/src/circom/r1cs_reader.rs index b5db104..95d3336 100644 --- a/src/circom/r1cs_reader.rs +++ b/src/circom/r1cs_reader.rs @@ -1,11 +1,11 @@ //! R1CS circom file reader //! Copied from //! Spec: +use ark_ff::PrimeField; use byteorder::{LittleEndian, ReadBytesExt}; use std::io::{Error, ErrorKind}; -use ark_ec::pairing::Pairing; -use ark_serialize::{CanonicalDeserialize, SerializationError, SerializationError::IoError}; +use ark_serialize::{SerializationError, SerializationError::IoError}; use ark_std::io::{Read, Seek, SeekFrom}; use std::collections::HashMap; @@ -15,16 +15,16 @@ type IoResult = Result; use super::{ConstraintVec, Constraints}; #[derive(Clone, Debug)] -pub struct R1CS { +pub struct R1CS { pub num_inputs: usize, pub num_aux: usize, pub num_variables: usize, - pub constraints: Vec>, + pub constraints: Vec>, pub wire_mapping: Option>, } -impl From> for R1CS { - fn from(file: R1CSFile) -> Self { +impl From> for R1CS { + fn from(file: R1CSFile) -> Self { let num_inputs = (1 + file.header.n_pub_in + file.header.n_pub_out) as usize; let num_variables = file.header.n_wires as usize; let num_aux = num_variables - num_inputs; @@ -38,20 +38,20 @@ impl From> for R1CS { } } -pub struct R1CSFile { +pub struct R1CSFile { pub version: u32, pub header: Header, - pub constraints: Vec>, + pub constraints: Vec>, pub wire_mapping: Vec, } -impl R1CSFile { +impl R1CSFile { /// reader must implement the Seek trait, for example with a Cursor /// /// ```rust,ignore /// let reader = BufReader::new(Cursor::new(&data[..])); /// ``` - pub fn new(mut reader: R) -> IoResult> { + pub fn new(mut reader: R) -> IoResult> { let mut magic = [0u8; 4]; reader.read_exact(&mut magic)?; if magic != [0x72, 0x31, 0x63, 0x73] { @@ -117,7 +117,7 @@ impl R1CSFile { reader.seek(SeekFrom::Start(*constraint_offset?))?; - let constraints = read_constraints::<&mut R, E>(&mut reader, &header)?; + let constraints = read_constraints::<&mut R, F>(&mut reader, &header)?; let wire2label_offset = sec_offsets.get(&wire2label_type).ok_or_else(|| { Error::new( @@ -200,29 +200,29 @@ impl Header { } } -fn read_constraint_vec(mut reader: R) -> IoResult> { +fn read_constraint_vec(mut reader: R) -> IoResult> { let n_vec = reader.read_u32::()? as usize; let mut vec = Vec::with_capacity(n_vec); for _ in 0..n_vec { vec.push(( reader.read_u32::()? as usize, - E::ScalarField::deserialize_uncompressed(&mut reader)?, + F::deserialize_uncompressed(&mut reader)?, )); } Ok(vec) } -fn read_constraints( +fn read_constraints( mut reader: R, header: &Header, -) -> IoResult>> { +) -> IoResult>> { // todo check section size let mut vec = Vec::with_capacity(header.n_constraints as usize); for _ in 0..header.n_constraints { vec.push(( - read_constraint_vec::<&mut R, E>(&mut reader)?, - read_constraint_vec::<&mut R, E>(&mut reader)?, - read_constraint_vec::<&mut R, E>(&mut reader)?, + read_constraint_vec::<&mut R, F>(&mut reader)?, + read_constraint_vec::<&mut R, F>(&mut reader)?, + read_constraint_vec::<&mut R, F>(&mut reader)?, )); } Ok(vec) @@ -251,7 +251,7 @@ fn read_map(mut reader: R, size: u64, header: &Header) -> IoResult::new(reader).unwrap(); + let file = R1CSFile::::new(reader).unwrap(); assert_eq!(file.version, 1); assert_eq!(file.header.field_size, 32); diff --git a/src/witness/witness_calculator.rs b/src/witness/witness_calculator.rs index 48d2429..e5fca61 100644 --- a/src/witness/witness_calculator.rs +++ b/src/witness/witness_calculator.rs @@ -1,4 +1,5 @@ use super::{fnv, SafeMemory, Wasm}; +use ark_ff::PrimeField; use color_eyre::Result; use num_bigint::BigInt; use num_traits::Zero; @@ -151,17 +152,16 @@ impl WitnessCalculator { } pub fn calculate_witness_element< - E: ark_ec::pairing::Pairing, + F: PrimeField, I: IntoIterator)>, >( &mut self, store: &mut Store, inputs: I, sanity_check: bool, - ) -> Result> { - use ark_ff::PrimeField; + ) -> Result> { + let modulus = F::MODULUS; let witness = self.calculate_witness(store, inputs, sanity_check)?; - let modulus = ::MODULUS; // convert it to field elements use num_traits::Signed; @@ -174,7 +174,7 @@ impl WitnessCalculator { } else { w.to_biguint().unwrap() }; - E::ScalarField::from(w) + F::from(w) }) .collect::>(); diff --git a/src/zkey.rs b/src/zkey.rs index d44283c..88bebb6 100644 --- a/src/zkey.rs +++ b/src/zkey.rs @@ -849,7 +849,7 @@ mod tests { let mut file = File::open(path).unwrap(); let (params, _matrices) = read_zkey(&mut file).unwrap(); // binfile.proving_key().unwrap(); - let cfg = CircomConfig::::new( + let cfg = CircomConfig::::new( "./test-vectors/mycircuit_js/mycircuit.wasm", "./test-vectors/mycircuit.r1cs", ) @@ -898,7 +898,7 @@ mod tests { let s = ark_bn254::Fr::rand(rng); let full_assignment = wtns - .calculate_witness_element::(&mut store, inputs, false) + .calculate_witness_element::(&mut store, inputs, false) .unwrap(); let proof = Groth16::::create_proof_with_reduction_and_matrices( ¶ms, diff --git a/tests/groth16.rs b/tests/groth16.rs index f0bc7fd..494cad8 100644 --- a/tests/groth16.rs +++ b/tests/groth16.rs @@ -10,7 +10,7 @@ type GrothBn = Groth16; #[tokio::test] async fn groth16_proof() -> Result<()> { - let cfg = CircomConfig::::new( + let cfg = CircomConfig::::new( "./test-vectors/mycircuit_js/mycircuit.wasm", "./test-vectors/mycircuit.r1cs", )?; @@ -41,7 +41,7 @@ async fn groth16_proof() -> Result<()> { #[tokio::test] async fn groth16_proof_wrong_input() -> Result<()> { - let cfg = CircomConfig::::new( + let cfg = CircomConfig::::new( "./test-vectors/mycircuit_js/mycircuit.wasm", "./test-vectors/mycircuit.r1cs", ) @@ -74,7 +74,7 @@ async fn groth16_proof_wrong_input() -> Result<()> { #[tokio::test] async fn groth16_proof_circom() -> Result<()> { - let cfg = CircomConfig::::new( + let cfg = CircomConfig::::new( "test-vectors/circuit2_js/circuit2.wasm", "test-vectors/circuit2.r1cs", )?; @@ -105,7 +105,7 @@ async fn groth16_proof_circom() -> Result<()> { #[tokio::test] async fn witness_generation_circom() -> Result<()> { - let cfg = CircomConfig::::new( + let cfg = CircomConfig::::new( "test-vectors/circuit2_js/circuit2.wasm", "test-vectors/circuit2.r1cs", )?; diff --git a/tests/solidity.rs b/tests/solidity.rs index 244557b..f22a1bb 100644 --- a/tests/solidity.rs +++ b/tests/solidity.rs @@ -2,7 +2,7 @@ use ark_circom::{ethereum, CircomBuilder, CircomConfig}; use ark_std::rand::thread_rng; use color_eyre::Result; -use ark_bn254::Bn254; +use ark_bn254::{Bn254, Fr}; use ark_crypto_primitives::snark::SNARK; use ark_groth16::Groth16; @@ -16,7 +16,7 @@ use std::{convert::TryFrom, sync::Arc}; #[tokio::test] async fn solidity_verifier() -> Result<()> { - let cfg = CircomConfig::::new( + let cfg = CircomConfig::::new( "./test-vectors/mycircuit_js/mycircuit.wasm", "./test-vectors/mycircuit.r1cs", )?; @@ -61,7 +61,6 @@ async fn solidity_verifier() -> Result<()> { // the ones expected by the abigen'd types. Could we maybe provide a convenience // macro for these, given that there's room for implementation error? abigen!(Groth16Verifier, "./tests/verifier_artifact.json"); -use groth_16_verifier::{G1Point, G2Point, Proof, VerifyingKey}; impl From for G1Point { fn from(src: ethereum::G1) -> Self { Self { x: src.x, y: src.y }