use ark_ec::pairing::Pairing; use std::{fs::File, path::Path}; use wasmer::Store; use super::{CircomCircuit, R1CS}; use num_bigint::BigInt; use std::collections::HashMap; use crate::{ circom::R1CSFile, witness::{Wasm, WitnessCalculator}, }; use color_eyre::Result; #[derive(Debug)] 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 wtns: WitnessCalculator, pub store: Store, pub sanity_check: bool, } 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(); let reader = File::open(r1cs)?; let r1cs = R1CSFile::new(reader)?.into(); Ok(Self { wtns, r1cs, store, sanity_check: false, }) } pub fn new_from_wasm(wasm: Wasm, r1cs: impl AsRef) -> Result { let mut store = Store::default(); let wtns = WitnessCalculator::new_from_wasm(&mut store, wasm).unwrap(); let reader = File::open(r1cs)?; let r1cs = R1CSFile::new(reader)?.into(); Ok(Self { wtns, r1cs, store, sanity_check: false, }) } } impl CircomBuilder { /// Instantiates a new builder using the provided WitnessGenerator and R1CS files /// for your circuit pub fn new(cfg: CircomConfig) -> Self { Self { cfg, inputs: HashMap::new(), } } /// Pushes a Circom input at the specified name. pub fn push_input>(&mut self, name: impl ToString, val: T) { let values = self.inputs.entry(name.to_string()).or_default(); values.push(val.into()); } /// Generates an empty circom circuit with no witness set, to be used for /// generation of the trusted setup parameters pub fn setup(&self) -> CircomCircuit { let mut circom = CircomCircuit { r1cs: self.cfg.r1cs.clone(), witness: None, }; // Disable the wire mapping circom.r1cs.wire_mapping = None; circom } /// Creates the circuit populated with the witness corresponding to the previously /// provided inputs pub fn build(mut self) -> Result> { let mut circom = self.setup(); // calculate the witness let witness = self.cfg.wtns.calculate_witness_element::( &mut self.cfg.store, self.inputs, self.cfg.sanity_check, )?; circom.witness = Some(witness); // sanity check debug_assert!({ use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; let cs = ConstraintSystem::::new_ref(); circom.clone().generate_constraints(cs.clone()).unwrap(); let is_satisfied = cs.is_satisfied().unwrap(); if !is_satisfied { println!( "Unsatisfied constraint: {:?}", cs.which_is_unsatisfied().unwrap() ); } is_satisfied }); Ok(circom) } }