Skip to content

Commit

Permalink
circom interface with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Arasu Arun authored and Arasu Arun committed Oct 13, 2023
1 parent fbafa3a commit 9aa9e2f
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
10 changes: 10 additions & 0 deletions examples/cube/cube.circom
Original file line number Diff line number Diff line change
@@ -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();
Binary file added examples/cube/cube.r1cs
Binary file not shown.
Binary file added examples/cube/cube.wasm
Binary file not shown.
126 changes: 126 additions & 0 deletions src/circom/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use std::path::PathBuf;

use crate::{
errors::SpartanError,
traits::{self, snark::RelaxedR1CSSNARKTrait, Group},
ProverKey, VerifierKey, SNARK,
};

use bellpepper_core::{Circuit, ConstraintSystem, SynthesisError};
use ff::PrimeField;

use circom_scotia::{r1cs::R1CS, reader::load_r1cs, witness::WitnessCalculator};

#[derive(Clone, Debug)]
pub struct SpartanCircuit<F: PrimeField> {
r1cs: R1CS<F>,
witness: Option<Vec<F>>, // this is actually z = [1 || x || w]
}

#[allow(dead_code)]
impl<F: PrimeField> SpartanCircuit<F> {
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<F>)>, 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<F: PrimeField> Circuit<F> for SpartanCircuit<F> {
fn synthesize<CS: ConstraintSystem<F>>(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<G: Group, S: RelaxedR1CSSNARKTrait<G>>(
circuit: SpartanCircuit<<G as Group>::Scalar>,
) -> (ProverKey<G, S>, VerifierKey<G, S>) {
SNARK::<G, S, SpartanCircuit<<G as Group>::Scalar>>::setup(circuit).unwrap()
}

#[allow(dead_code)]
pub fn generate_proof<G: Group, S: RelaxedR1CSSNARKTrait<G>>(
pk: ProverKey<G, S>,
circuit: SpartanCircuit<<G as Group>::Scalar>,
) -> Result<SNARK<G, S, SpartanCircuit<<G as traits::Group>::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<G>;
type S = crate::spartan::snark::RelaxedR1CSSNARK<G, EE>;

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![<G as Group>::Scalar::from(2)]);
let arg_y = ("y".into(), vec![<G as Group>::Scalar::from(8)]);
let input = vec![arg_x, arg_y];

circuit.compute_witness(input, wtns_path);

let res = generate_proof::<G, S>(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<G>;
type S = crate::spartan::snark::RelaxedR1CSSNARK<G, EE>;

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![<G as Group>::Scalar::from(2)]);
let arg_y = ("y".into(), vec![<G as Group>::Scalar::from(9)]);
let input = vec![arg_x, arg_y];

circuit.compute_witness(input, wtns_path);

let res = generate_proof::<G, S>(pk, circuit);
assert!(res.is_ok());

let snark = res.unwrap();
// check that it fails
assert!(snark.verify(&vk).is_err());
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

// private modules
mod bellpepper;
mod circom;
mod constants;
mod digest;
mod r1cs;
Expand Down

0 comments on commit 9aa9e2f

Please sign in to comment.