use ark_ff::PrimeField;
|
|
use std::{fs::File, path::Path};
|
|
|
|
use super::{CircomCircuit, R1CS};
|
|
|
|
use num_bigint::BigInt;
|
|
use std::collections::HashMap;
|
|
|
|
use crate::{circom::R1CSFile, witness::WitnessCalculator};
|
|
use color_eyre::Result;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct CircomBuilder<F: PrimeField> {
|
|
pub cfg: CircomConfig<F>,
|
|
pub inputs: HashMap<String, Vec<BigInt>>,
|
|
}
|
|
|
|
// Add utils for creating this from files / directly from bytes
|
|
#[derive(Clone, Debug)]
|
|
pub struct CircomConfig<F: PrimeField> {
|
|
pub r1cs: R1CS<F>,
|
|
pub wtns: WitnessCalculator,
|
|
pub sanity_check: bool,
|
|
}
|
|
|
|
impl<F: PrimeField> CircomConfig<F> {
|
|
pub fn new(wtns: impl AsRef<Path>, r1cs: impl AsRef<Path>) -> Result<Self> {
|
|
let wtns = WitnessCalculator::new(wtns).unwrap();
|
|
let reader = File::open(r1cs)?;
|
|
let r1cs = R1CSFile::new(reader)?.into();
|
|
Ok(Self {
|
|
wtns,
|
|
r1cs,
|
|
sanity_check: false,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl<F: PrimeField> CircomBuilder<F> {
|
|
/// Instantiates a new builder using the provided WitnessGenerator and R1CS files
|
|
/// for your circuit
|
|
pub fn new(cfg: CircomConfig<F>) -> Self {
|
|
Self {
|
|
cfg,
|
|
inputs: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
/// Pushes a Circom input at the specified name.
|
|
pub fn push_input<T: Into<BigInt>>(&mut self, name: impl ToString, val: T) {
|
|
let values = self.inputs.entry(name.to_string()).or_insert_with(Vec::new);
|
|
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<F> {
|
|
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<CircomCircuit<F>> {
|
|
let mut circom = self.setup();
|
|
|
|
// calculate the witness
|
|
let witness = self
|
|
.cfg
|
|
.wtns
|
|
.calculate_witness_element::<F, _>(self.inputs, self.cfg.sanity_check)?;
|
|
circom.witness = Some(witness);
|
|
|
|
// sanity check
|
|
debug_assert!({
|
|
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
|
|
let cs = ConstraintSystem::<F>::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)
|
|
}
|
|
}
|