use snarkvm_curves::traits::PairingEngine;
use snarkvm_fields::Field;
use snarkvm_r1cs::{ConstraintSystem, Index, LinearCombination, OptionalVec, SynthesisError, Variable};
#[derive(Default)]
pub struct Namespace {
constraint_indices: Vec<usize>,
public_var_indices: Vec<usize>,
private_var_indices: Vec<usize>,
}
pub struct ConstraintSet<E: PairingEngine> {
pub at: Vec<(E::Fr, Index)>,
pub bt: Vec<(E::Fr, Index)>,
pub ct: Vec<(E::Fr, Index)>,
}
impl<E: PairingEngine> Default for ConstraintSet<E> {
fn default() -> Self {
ConstraintSet {
at: Default::default(),
bt: Default::default(),
ct: Default::default(),
}
}
}
pub struct CircuitSynthesizer<E: PairingEngine> {
pub constraints: OptionalVec<ConstraintSet<E>>,
pub public_variables: OptionalVec<E::Fr>,
pub private_variables: OptionalVec<E::Fr>,
pub namespaces: Vec<Namespace>,
}
impl<E: PairingEngine> ConstraintSystem<E::Fr> for CircuitSynthesizer<E> {
type Root = Self;
#[inline]
fn alloc<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: AsRef<str>,
{
let index = self.private_variables.insert(f()?);
if let Some(ref mut ns) = self.namespaces.last_mut() {
ns.private_var_indices.push(index);
}
Ok(Variable::new_unchecked(Index::Private(index)))
}
#[inline]
fn alloc_input<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: AsRef<str>,
{
let index = self.public_variables.insert(f()?);
if let Some(ref mut ns) = self.namespaces.last_mut() {
ns.public_var_indices.push(index);
}
Ok(Variable::new_unchecked(Index::Public(index)))
}
#[inline]
fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: AsRef<str>,
LA: FnOnce(LinearCombination<E::Fr>) -> LinearCombination<E::Fr>,
LB: FnOnce(LinearCombination<E::Fr>) -> LinearCombination<E::Fr>,
LC: FnOnce(LinearCombination<E::Fr>) -> LinearCombination<E::Fr>,
{
let index = self.constraints.insert(Default::default());
push_constraints(a(LinearCombination::zero()), &mut self.constraints[index].at);
push_constraints(b(LinearCombination::zero()), &mut self.constraints[index].bt);
push_constraints(c(LinearCombination::zero()), &mut self.constraints[index].ct);
if let Some(ref mut ns) = self.namespaces.last_mut() {
ns.constraint_indices.push(index);
}
}
fn push_namespace<NR, N>(&mut self, _: N)
where
NR: AsRef<str>,
N: FnOnce() -> NR,
{
self.namespaces.push(Namespace::default());
}
fn pop_namespace(&mut self) {
}
fn get_root(&mut self) -> &mut Self::Root {
self
}
fn num_constraints(&self) -> usize {
self.constraints.len()
}
fn num_public_variables(&self) -> usize {
self.public_variables.len()
}
fn num_private_variables(&self) -> usize {
self.private_variables.len()
}
}
fn push_constraints<F: Field>(l: LinearCombination<F>, constraint: &mut Vec<(F, Index)>) {
for (var, coeff) in l.as_ref() {
match var.get_unchecked() {
Index::Public(i) => constraint.push((*coeff, Index::Public(i))),
Index::Private(i) => constraint.push((*coeff, Index::Private(i))),
}
}
}