use std::marker::PhantomData;
use ff::PrimeField;
use super::lc::{Index, LinearCombination, Variable};
pub trait Circuit<Scalar: PrimeField> {
fn synthesize<CS: ConstraintSystem<Scalar>>(self, cs: &mut CS) -> Result<(), SynthesisError>;
}
#[allow(clippy::upper_case_acronyms)]
#[derive(thiserror::Error, Debug, Clone)]
pub enum SynthesisError {
#[error("an assignment for a variable could not be computed")]
AssignmentMissing,
#[error("division by zero")]
DivisionByZero,
#[error("unsatisfiable constraint system: {0}")]
Unsatisfiable(String),
#[error("polynomial degree is too large")]
PolynomialDegreeTooLarge,
#[error("encountered an identity element in the CRS")]
UnexpectedIdentity,
#[error("malformed verifying key")]
MalformedVerifyingKey,
#[error("auxiliary variable was unconstrained")]
UnconstrainedVariable,
#[error("attempted to aggregate malformed proofs: {0}")]
MalformedProofs(String),
#[error("non power of two proofs given for aggregation")]
NonPowerOfTwo,
#[error("incompatible vector length: {0}")]
IncompatibleLengthVector(String),
}
pub trait ConstraintSystem<Scalar: PrimeField>: Sized + Send {
type Root: ConstraintSystem<Scalar>;
fn new() -> Self {
unimplemented!(
"ConstraintSystem::new must be implemented for extensible types implementing ConstraintSystem"
);
}
fn one() -> Variable {
Variable::new_unchecked(Index::Input(0))
}
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>;
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>;
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>;
fn push_namespace<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR;
fn pop_namespace(&mut self);
fn get_root(&mut self) -> &mut Self::Root;
fn namespace<NR, N>(&mut self, name_fn: N) -> Namespace<'_, Scalar, Self::Root>
where
NR: Into<String>,
N: FnOnce() -> NR,
{
self.get_root().push_namespace(name_fn);
Namespace(self.get_root(), Default::default())
}
fn is_extensible() -> bool {
false
}
fn extend(&mut self, _other: &Self) {
unimplemented!(
"ConstraintSystem::extend must be implemented for types implementing ConstraintSystem"
);
}
fn is_witness_generator(&self) -> bool {
false
}
fn extend_inputs(&mut self, _new_inputs: &[Scalar]) {
assert!(self.is_witness_generator());
unimplemented!("ConstraintSystem::extend_inputs must be implemented for witness generators implementing ConstraintSystem")
}
fn extend_aux(&mut self, _new_aux: &[Scalar]) {
assert!(self.is_witness_generator());
unimplemented!("ConstraintSystem::extend_aux must be implemented for witness generators implementing ConstraintSystem")
}
fn allocate_empty(&mut self, _aux_n: usize, _inputs_n: usize) -> (&mut [Scalar], &mut [Scalar]) {
assert!(self.is_witness_generator());
unimplemented!("ConstraintSystem::allocate_empty must be implemented for witness generators implementing ConstraintSystem")
}
fn allocate_empty_inputs(&mut self, _n: usize) -> &mut [Scalar] {
assert!(self.is_witness_generator());
unimplemented!("ConstraintSystem::allocate_empty_inputs must be implemented for witness generators implementing ConstraintSystem")
}
fn allocate_empty_aux(&mut self, _n: usize) -> &mut [Scalar] {
assert!(self.is_witness_generator());
unimplemented!("ConstraintSystem::allocate_empty_aux must be implemented for witness generators implementing ConstraintSystem")
}
fn inputs_slice(&self) -> &[Scalar] {
assert!(self.is_witness_generator());
unimplemented!("ConstraintSystem::inputs_slice must be implemented for witness generators implementing ConstraintSystem")
}
fn aux_slice(&self) -> &[Scalar] {
assert!(self.is_witness_generator());
unimplemented!("ConstraintSystem::aux_slice must be implemented for witness generators implementing ConstraintSystem")
}
}
#[derive(Debug)]
pub struct Namespace<'a, Scalar: PrimeField, CS: ConstraintSystem<Scalar>>(
&'a mut CS,
PhantomData<Scalar>,
);
impl<Scalar: PrimeField, CS: ConstraintSystem<Scalar>> ConstraintSystem<Scalar>
for Namespace<'_, Scalar, CS>
{
type Root = CS::Root;
fn one() -> Variable {
CS::one()
}
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
self.0.alloc(annotation, f)
}
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
self.0.alloc_input(annotation, f)
}
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
{
self.0.enforce(annotation, a, b, c)
}
fn push_namespace<NR, N>(&mut self, _: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
panic!("only the root's push_namespace should be called");
}
fn pop_namespace(&mut self) {
panic!("only the root's pop_namespace should be called");
}
fn get_root(&mut self) -> &mut Self::Root {
self.0.get_root()
}
fn is_witness_generator(&self) -> bool {
self.0.is_witness_generator()
}
fn extend_inputs(&mut self, new_inputs: &[Scalar]) {
self.0.extend_inputs(new_inputs)
}
fn extend_aux(&mut self, new_aux: &[Scalar]) {
self.0.extend_aux(new_aux)
}
fn allocate_empty(&mut self, aux_n: usize, inputs_n: usize) -> (&mut [Scalar], &mut [Scalar]) {
self.0.allocate_empty(aux_n, inputs_n)
}
fn inputs_slice(&self) -> &[Scalar] {
self.0.inputs_slice()
}
fn aux_slice(&self) -> &[Scalar] {
self.0.aux_slice()
}
}
impl<Scalar: PrimeField, CS: ConstraintSystem<Scalar>> Drop for Namespace<'_, Scalar, CS> {
fn drop(&mut self) {
self.get_root().pop_namespace()
}
}
impl<Scalar: PrimeField, CS: ConstraintSystem<Scalar>> ConstraintSystem<Scalar> for &'_ mut CS {
type Root = CS::Root;
fn one() -> Variable {
CS::one()
}
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
(**self).alloc(annotation, f)
}
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<Scalar, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
(**self).alloc_input(annotation, f)
}
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LB: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
LC: FnOnce(LinearCombination<Scalar>) -> LinearCombination<Scalar>,
{
(**self).enforce(annotation, a, b, c)
}
fn push_namespace<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
(**self).push_namespace(name_fn)
}
fn pop_namespace(&mut self) {
(**self).pop_namespace()
}
fn get_root(&mut self) -> &mut Self::Root {
(**self).get_root()
}
fn namespace<NR, N>(&mut self, name_fn: N) -> Namespace<'_, Scalar, Self::Root>
where
NR: Into<String>,
N: FnOnce() -> NR,
{
(**self).namespace(name_fn)
}
fn is_extensible() -> bool {
CS::is_extensible()
}
fn extend(&mut self, other: &Self) {
(**self).extend(other)
}
fn is_witness_generator(&self) -> bool {
(**self).is_witness_generator()
}
fn extend_inputs(&mut self, new_inputs: &[Scalar]) {
(**self).extend_inputs(new_inputs)
}
fn extend_aux(&mut self, new_aux: &[Scalar]) {
(**self).extend_aux(new_aux)
}
fn allocate_empty(&mut self, aux_n: usize, inputs_n: usize) -> (&mut [Scalar], &mut [Scalar]) {
(**self).allocate_empty(aux_n, inputs_n)
}
fn allocate_empty_inputs(&mut self, n: usize) -> &mut [Scalar] {
(**self).allocate_empty_inputs(n)
}
fn allocate_empty_aux(&mut self, n: usize) -> &mut [Scalar] {
(**self).allocate_empty_aux(n)
}
fn inputs_slice(&self) -> &[Scalar] {
(**self).inputs_slice()
}
fn aux_slice(&self) -> &[Scalar] {
(**self).aux_slice()
}
}