From 9aa9e2fe8d16fcd2c73a01c7eb14a6210d4a6952 Mon Sep 17 00:00:00 2001 From: Arasu Arun Date: Thu, 12 Oct 2023 22:46:32 -0400 Subject: [PATCH 1/5] circom interface with tests --- Cargo.toml | 1 + examples/cube/cube.circom | 10 +++ examples/cube/cube.r1cs | Bin 0 -> 384 bytes examples/cube/cube.wasm | Bin 0 -> 34338 bytes src/circom/mod.rs | 126 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 6 files changed, 138 insertions(+) create mode 100644 examples/cube/cube.circom create mode 100644 examples/cube/cube.r1cs create mode 100644 examples/cube/cube.wasm create mode 100644 src/circom/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 89994ef..2b004fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ thiserror = "1.0" halo2curves = { version = "0.4.0", features = ["derive_serde"] } group = "0.13.0" once_cell = "1.18.0" +circom-scotia = "0.1.2" [target.'cfg(any(target_arch = "x86_64", target_arch = "aarch64"))'.dependencies] pasta-msm = { version = "0.1.4" } diff --git a/examples/cube/cube.circom b/examples/cube/cube.circom new file mode 100644 index 0000000..ddc2639 --- /dev/null +++ b/examples/cube/cube.circom @@ -0,0 +1,10 @@ +pragma circom 2.0.6; + +template cube() { + signal input x; + signal input y; + signal x_sq <== x * x; + y === x_sq * x; +} + +component main { public [x, y] } = cube(); \ No newline at end of file diff --git a/examples/cube/cube.r1cs b/examples/cube/cube.r1cs new file mode 100644 index 0000000000000000000000000000000000000000..843e4212fe6d5fbb7b156e6eb0404b7704af0b3a GIT binary patch literal 384 zcmXRiOfF_*U|?VdVkRK|0K^~w5(8l%_%QkFL+6PFJ1ae27;D5vG&XK?4cMW%!0=&_ zUy1=t9aJqu2Nn_}53&OY2%1N%I+)!MW3iJUH6VWh0YQ5mz{(gH6o52PA71q=P_2f?@DO^ literal 0 HcmV?d00001 diff --git a/examples/cube/cube.wasm b/examples/cube/cube.wasm new file mode 100644 index 0000000000000000000000000000000000000000..ae0dbb97c311b901c8a736b6f5c26a7e0f52a907 GIT binary patch literal 34338 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 { + r1cs: R1CS, + witness: Option>, // this is actually z = [1 || x || w] +} + +#[allow(dead_code)] +impl SpartanCircuit { + pub fn new(r1cs_path: PathBuf) -> Self { + SpartanCircuit { + r1cs: load_r1cs(r1cs_path), + witness: None, + } + } + + pub fn compute_witness(&mut self, input: Vec<(String, Vec)>, wtns_path: PathBuf) { + let mut witness_calculator = WitnessCalculator::new(wtns_path).unwrap(); + let witness = witness_calculator + .calculate_witness(input.clone(), true) + .expect("msg"); + + self.witness = Some(witness); + } +} + +impl Circuit for SpartanCircuit { + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { + let _ = circom_scotia::synthesize( + cs, //.namespace(|| "spartan_snark"), + self.r1cs.clone(), + self.witness, + ) + .unwrap(); + + Ok(()) + } +} + +#[allow(dead_code)] +pub fn generate_keys>( + circuit: SpartanCircuit<::Scalar>, +) -> (ProverKey, VerifierKey) { + SNARK::::Scalar>>::setup(circuit).unwrap() +} + +#[allow(dead_code)] +pub fn generate_proof>( + pk: ProverKey, + circuit: SpartanCircuit<::Scalar>, +) -> Result::Scalar>>, SpartanError> { + SNARK::prove(&pk, circuit) +} + +#[cfg(test)] +mod test { + use super::{generate_keys, generate_proof, SpartanCircuit}; + use crate::{provider::bn256_grumpkin::bn256, traits::Group}; + use std::env::current_dir; + + #[test] + fn test_spartan_snark() { + type G = bn256::Point; + type EE = crate::provider::ipa_pc::EvaluationEngine; + type S = crate::spartan::snark::RelaxedR1CSSNARK; + + let root = current_dir().unwrap().join("examples/cube"); + let r1cs_path = root.join("cube.r1cs"); + let wtns_path = root.join("cube.wasm"); + let mut circuit = SpartanCircuit::new(r1cs_path); + + let (pk, vk) = generate_keys(circuit.clone()); + + let arg_x = ("x".into(), vec![::Scalar::from(2)]); + let arg_y = ("y".into(), vec![::Scalar::from(8)]); + let input = vec![arg_x, arg_y]; + + circuit.compute_witness(input, wtns_path); + + let res = generate_proof::(pk, circuit); + assert!(res.is_ok()); + + let snark = res.unwrap(); + assert!(snark.verify(&vk).is_ok()); + } + + #[test] + fn test_spartan_snark_fail() { + type G = bn256::Point; + type EE = crate::provider::ipa_pc::EvaluationEngine; + type S = crate::spartan::snark::RelaxedR1CSSNARK; + + let root = current_dir().unwrap().join("examples/cube"); + let r1cs_path = root.join("cube.r1cs"); + let wtns_path = root.join("cube.wasm"); + let mut circuit = SpartanCircuit::new(r1cs_path); + + let (pk, vk) = generate_keys(circuit.clone()); + + // setting y to 9 shouldn't satisfy + let arg_x = ("x".into(), vec![::Scalar::from(2)]); + let arg_y = ("y".into(), vec![::Scalar::from(9)]); + let input = vec![arg_x, arg_y]; + + circuit.compute_witness(input, wtns_path); + + let res = generate_proof::(pk, circuit); + assert!(res.is_ok()); + + let snark = res.unwrap(); + // check that it fails + assert!(snark.verify(&vk).is_err()); + } +} diff --git a/src/lib.rs b/src/lib.rs index 37e9641..43c3f5e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ // private modules mod bellpepper; +mod circom; mod constants; mod digest; mod r1cs; From bbe9577032f573eab25f5861a00c357d493bf8de Mon Sep 17 00:00:00 2001 From: Arasu Arun Date: Sun, 15 Oct 2023 22:30:17 -0400 Subject: [PATCH 2/5] incorporated comments --- src/circom/mod.rs | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/circom/mod.rs b/src/circom/mod.rs index b4c78b5..22f0e4e 100644 --- a/src/circom/mod.rs +++ b/src/circom/mod.rs @@ -38,19 +38,14 @@ impl SpartanCircuit { impl Circuit for SpartanCircuit { fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { - let _ = circom_scotia::synthesize( - cs, //.namespace(|| "spartan_snark"), - self.r1cs.clone(), - self.witness, - ) - .unwrap(); + let _ = circom_scotia::synthesize(cs, self.r1cs.clone(), self.witness).unwrap(); Ok(()) } } #[allow(dead_code)] -pub fn generate_keys>( +pub fn setup>( circuit: SpartanCircuit<::Scalar>, ) -> (ProverKey, VerifierKey) { SNARK::::Scalar>>::setup(circuit).unwrap() @@ -59,14 +54,17 @@ pub fn generate_keys>( #[allow(dead_code)] pub fn generate_proof>( pk: ProverKey, - circuit: SpartanCircuit<::Scalar>, + circuit: &mut SpartanCircuit<::Scalar>, + input: Vec<(String, Vec<::Scalar>)>, + wtns_path: PathBuf, ) -> Result::Scalar>>, SpartanError> { - SNARK::prove(&pk, circuit) + circuit.compute_witness(input, wtns_path); + SNARK::prove(&pk, circuit.clone()) } #[cfg(test)] mod test { - use super::{generate_keys, generate_proof, SpartanCircuit}; + use super::{generate_proof, setup, SpartanCircuit}; use crate::{provider::bn256_grumpkin::bn256, traits::Group}; use std::env::current_dir; @@ -81,15 +79,13 @@ mod test { let wtns_path = root.join("cube.wasm"); let mut circuit = SpartanCircuit::new(r1cs_path); - let (pk, vk) = generate_keys(circuit.clone()); + let (pk, vk) = setup(circuit.clone()); let arg_x = ("x".into(), vec![::Scalar::from(2)]); let arg_y = ("y".into(), vec![::Scalar::from(8)]); let input = vec![arg_x, arg_y]; - circuit.compute_witness(input, wtns_path); - - let res = generate_proof::(pk, circuit); + let res = generate_proof::(pk, &mut circuit, input, wtns_path); assert!(res.is_ok()); let snark = res.unwrap(); @@ -107,16 +103,14 @@ mod test { let wtns_path = root.join("cube.wasm"); let mut circuit = SpartanCircuit::new(r1cs_path); - let (pk, vk) = generate_keys(circuit.clone()); + let (pk, vk) = setup(circuit.clone()); // setting y to 9 shouldn't satisfy let arg_x = ("x".into(), vec![::Scalar::from(2)]); let arg_y = ("y".into(), vec![::Scalar::from(9)]); let input = vec![arg_x, arg_y]; - circuit.compute_witness(input, wtns_path); - - let res = generate_proof::(pk, circuit); + let res = generate_proof::(pk, &mut circuit, input, wtns_path); assert!(res.is_ok()); let snark = res.unwrap(); From 231408f2290bbb52f130a637d68a59857916c73c Mon Sep 17 00:00:00 2001 From: Arasu Arun Date: Sun, 15 Oct 2023 22:47:03 -0400 Subject: [PATCH 3/5] added simplified interface fucntion --- src/circom/mod.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/circom/mod.rs b/src/circom/mod.rs index 22f0e4e..a020889 100644 --- a/src/circom/mod.rs +++ b/src/circom/mod.rs @@ -62,9 +62,27 @@ pub fn generate_proof>( SNARK::prove(&pk, circuit.clone()) } +#[allow(dead_code)] +pub fn create_snark>( + r1cs_path: PathBuf, + wtns_path: PathBuf, + input: Vec<(String, Vec<::Scalar>)>, +) -> ( + ProverKey, + VerifierKey, + Result::Scalar>>, SpartanError>, +) { + let mut circuit = SpartanCircuit::new(r1cs_path); + let (pk, vk) = + SNARK::::Scalar>>::setup(circuit.clone()).unwrap(); + circuit.compute_witness(input, wtns_path); + let proof = SNARK::prove(&pk, circuit.clone()); + (pk, vk, proof) +} + #[cfg(test)] mod test { - use super::{generate_proof, setup, SpartanCircuit}; + use super::{create_snark, generate_proof, setup, SpartanCircuit}; use crate::{provider::bn256_grumpkin::bn256, traits::Group}; use std::env::current_dir; @@ -77,15 +95,12 @@ mod test { let root = current_dir().unwrap().join("examples/cube"); let r1cs_path = root.join("cube.r1cs"); let wtns_path = root.join("cube.wasm"); - let mut circuit = SpartanCircuit::new(r1cs_path); - - let (pk, vk) = setup(circuit.clone()); let arg_x = ("x".into(), vec![::Scalar::from(2)]); let arg_y = ("y".into(), vec![::Scalar::from(8)]); let input = vec![arg_x, arg_y]; - let res = generate_proof::(pk, &mut circuit, input, wtns_path); + let (_, vk, res) = create_snark::(r1cs_path, wtns_path, input); assert!(res.is_ok()); let snark = res.unwrap(); From 67e834af1274f1e4b11da8322926f61331cf4150 Mon Sep 17 00:00:00 2001 From: Arasu Arun Date: Mon, 16 Oct 2023 15:31:30 -0400 Subject: [PATCH 4/5] removed struct from interface --- src/circom/mod.rs | 52 +++++++++++++++++------------------------------ src/lib.rs | 2 +- 2 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/circom/mod.rs b/src/circom/mod.rs index a020889..9769752 100644 --- a/src/circom/mod.rs +++ b/src/circom/mod.rs @@ -1,3 +1,4 @@ +//! This module provides an interface to generate spartan proofs with circom circuits. use std::path::PathBuf; use crate::{ @@ -11,22 +12,22 @@ use ff::PrimeField; use circom_scotia::{r1cs::R1CS, reader::load_r1cs, witness::WitnessCalculator}; +/// Wrapper around an R1CS object to implement the Circuit trait #[derive(Clone, Debug)] pub struct SpartanCircuit { r1cs: R1CS, - witness: Option>, // this is actually z = [1 || x || w] + witness: Option>, // this is [1 || inputs || witnesses] } -#[allow(dead_code)] impl SpartanCircuit { - pub fn new(r1cs_path: PathBuf) -> Self { + fn new(r1cs_path: PathBuf) -> Self { SpartanCircuit { r1cs: load_r1cs(r1cs_path), witness: None, } } - pub fn compute_witness(&mut self, input: Vec<(String, Vec)>, wtns_path: PathBuf) { + fn compute_witness(&mut self, input: Vec<(String, Vec)>, wtns_path: PathBuf) { let mut witness_calculator = WitnessCalculator::new(wtns_path).unwrap(); let witness = witness_calculator .calculate_witness(input.clone(), true) @@ -44,45 +45,29 @@ impl Circuit for SpartanCircuit { } } -#[allow(dead_code)] +/// Produces prover and verifier keys pub fn setup>( - circuit: SpartanCircuit<::Scalar>, + r1cs_path: PathBuf, ) -> (ProverKey, VerifierKey) { - SNARK::::Scalar>>::setup(circuit).unwrap() + SNARK::::Scalar>>::setup(SpartanCircuit::new(r1cs_path)) + .unwrap() } -#[allow(dead_code)] -pub fn generate_proof>( +/// Produces proof in the form of a SNARK object +pub fn prove>( pk: ProverKey, - circuit: &mut SpartanCircuit<::Scalar>, - input: Vec<(String, Vec<::Scalar>)>, - wtns_path: PathBuf, -) -> Result::Scalar>>, SpartanError> { - circuit.compute_witness(input, wtns_path); - SNARK::prove(&pk, circuit.clone()) -} - -#[allow(dead_code)] -pub fn create_snark>( r1cs_path: PathBuf, wtns_path: PathBuf, input: Vec<(String, Vec<::Scalar>)>, -) -> ( - ProverKey, - VerifierKey, - Result::Scalar>>, SpartanError>, -) { +) -> Result::Scalar>>, SpartanError> { let mut circuit = SpartanCircuit::new(r1cs_path); - let (pk, vk) = - SNARK::::Scalar>>::setup(circuit.clone()).unwrap(); circuit.compute_witness(input, wtns_path); - let proof = SNARK::prove(&pk, circuit.clone()); - (pk, vk, proof) + SNARK::prove(&pk, circuit.clone()) } #[cfg(test)] mod test { - use super::{create_snark, generate_proof, setup, SpartanCircuit}; + use super::{prove, setup}; use crate::{provider::bn256_grumpkin::bn256, traits::Group}; use std::env::current_dir; @@ -100,7 +85,9 @@ mod test { let arg_y = ("y".into(), vec![::Scalar::from(8)]); let input = vec![arg_x, arg_y]; - let (_, vk, res) = create_snark::(r1cs_path, wtns_path, input); + let (pk, vk) = setup::(r1cs_path.clone()); + + let res = prove::(pk, r1cs_path, wtns_path, input); assert!(res.is_ok()); let snark = res.unwrap(); @@ -116,16 +103,15 @@ mod test { let root = current_dir().unwrap().join("examples/cube"); let r1cs_path = root.join("cube.r1cs"); let wtns_path = root.join("cube.wasm"); - let mut circuit = SpartanCircuit::new(r1cs_path); - let (pk, vk) = setup(circuit.clone()); + let (pk, vk) = setup::(r1cs_path.clone()); // setting y to 9 shouldn't satisfy let arg_x = ("x".into(), vec![::Scalar::from(2)]); let arg_y = ("y".into(), vec![::Scalar::from(9)]); let input = vec![arg_x, arg_y]; - let res = generate_proof::(pk, &mut circuit, input, wtns_path); + let res = prove::(pk, r1cs_path, wtns_path, input); assert!(res.is_ok()); let snark = res.unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 43c3f5e..87c0f92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,12 +13,12 @@ // private modules mod bellpepper; -mod circom; mod constants; mod digest; mod r1cs; // public modules +pub mod circom; pub mod errors; pub mod provider; pub mod spartan; From af8a5b3f72bbd539d1c35e33ef9abbce5e8fdd6d Mon Sep 17 00:00:00 2001 From: Arasu Arun Date: Tue, 17 Oct 2023 14:02:46 -0400 Subject: [PATCH 5/5] moved to new verifier --- src/circom/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/circom/mod.rs b/src/circom/mod.rs index 9769752..a497d39 100644 --- a/src/circom/mod.rs +++ b/src/circom/mod.rs @@ -85,13 +85,15 @@ mod test { let arg_y = ("y".into(), vec![::Scalar::from(8)]); let input = vec![arg_x, arg_y]; + let io: Vec<::Scalar> = input.iter().flat_map(|v| v.1.iter().cloned()).collect(); + let (pk, vk) = setup::(r1cs_path.clone()); let res = prove::(pk, r1cs_path, wtns_path, input); assert!(res.is_ok()); let snark = res.unwrap(); - assert!(snark.verify(&vk).is_ok()); + assert!(snark.verify(&vk, &io).is_ok()); } #[test] @@ -111,11 +113,13 @@ mod test { let arg_y = ("y".into(), vec![::Scalar::from(9)]); let input = vec![arg_x, arg_y]; + let io: Vec<::Scalar> = input.iter().flat_map(|v| v.1.iter().cloned()).collect(); + let res = prove::(pk, r1cs_path, wtns_path, input); assert!(res.is_ok()); let snark = res.unwrap(); // check that it fails - assert!(snark.verify(&vk).is_err()); + assert!(snark.verify(&vk, &io).is_err()); } }