2017-11-21 10:04:49 +03:00
|
|
|
extern crate pairing;
|
2018-02-14 22:31:43 +03:00
|
|
|
extern crate rand;
|
|
|
|
extern crate num_cpus;
|
|
|
|
extern crate futures;
|
|
|
|
extern crate futures_cpupool;
|
|
|
|
extern crate bit_vec;
|
|
|
|
extern crate crossbeam;
|
2018-03-05 03:49:05 +03:00
|
|
|
extern crate byteorder;
|
2018-02-14 22:31:43 +03:00
|
|
|
|
2018-03-05 05:27:33 +03:00
|
|
|
mod multicore;
|
|
|
|
mod multiexp;
|
2018-02-14 22:31:43 +03:00
|
|
|
pub mod domain;
|
|
|
|
pub mod groth16;
|
2017-11-21 10:04:49 +03:00
|
|
|
|
|
|
|
use pairing::{Engine, Field};
|
2018-02-14 22:31:43 +03:00
|
|
|
|
2017-11-21 10:04:49 +03:00
|
|
|
use std::ops::{Add, Sub};
|
|
|
|
use std::fmt;
|
|
|
|
use std::error::Error;
|
2018-02-14 22:31:43 +03:00
|
|
|
use std::io;
|
|
|
|
use std::marker::PhantomData;
|
|
|
|
|
|
|
|
/// Computations are expressed in terms of arithmetic circuits, in particular
|
|
|
|
/// rank-1 quadratic constraint systems. The `Circuit` trait represents a
|
|
|
|
/// circuit that can be synthesized. The `synthesize` method is called during
|
|
|
|
/// CRS generation and during proving.
|
|
|
|
pub trait Circuit<E: Engine> {
|
|
|
|
/// Synthesize the circuit into a rank-1 quadratic constraint system
|
|
|
|
fn synthesize<CS: ConstraintSystem<E>>(
|
|
|
|
self,
|
|
|
|
cs: &mut CS
|
|
|
|
) -> Result<(), SynthesisError>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Represents a variable in our constraint system.
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub struct Variable(Index);
|
|
|
|
|
|
|
|
impl Variable {
|
|
|
|
/// This constructs a variable with an arbitrary index.
|
|
|
|
/// Circuit implementations are not recommended to use this.
|
|
|
|
pub fn new_unchecked(idx: Index) -> Variable {
|
|
|
|
Variable(idx)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This returns the index underlying the variable.
|
|
|
|
/// Circuit implementations are not recommended to use this.
|
|
|
|
pub fn get_unchecked(&self) -> Index {
|
|
|
|
self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Represents the index of either an input variable or
|
|
|
|
/// auxillary variable.
|
|
|
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
|
|
|
pub enum Index {
|
|
|
|
Input(usize),
|
|
|
|
Aux(usize)
|
|
|
|
}
|
2017-11-21 10:04:49 +03:00
|
|
|
|
|
|
|
/// This represents a linear combination of some variables, with coefficients
|
|
|
|
/// in the scalar field of a pairing-friendly elliptic curve group.
|
2018-01-07 21:31:35 +03:00
|
|
|
#[derive(Clone)]
|
2018-02-14 22:31:43 +03:00
|
|
|
pub struct LinearCombination<E: Engine>(Vec<(Variable, E::Fr)>);
|
2017-11-21 10:04:49 +03:00
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<E: Engine> AsRef<[(Variable, E::Fr)]> for LinearCombination<E> {
|
|
|
|
fn as_ref(&self) -> &[(Variable, E::Fr)] {
|
2017-11-23 07:11:41 +03:00
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<E: Engine> LinearCombination<E> {
|
|
|
|
pub fn zero() -> LinearCombination<E> {
|
2017-11-21 10:04:49 +03:00
|
|
|
LinearCombination(vec![])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<E: Engine> Add<(E::Fr, Variable)> for LinearCombination<E> {
|
|
|
|
type Output = LinearCombination<E>;
|
2017-11-21 10:04:49 +03:00
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn add(mut self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
|
2017-11-21 10:04:49 +03:00
|
|
|
self.0.push((var, coeff));
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<E: Engine> Sub<(E::Fr, Variable)> for LinearCombination<E> {
|
|
|
|
type Output = LinearCombination<E>;
|
2017-11-21 10:04:49 +03:00
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn sub(self, (mut coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
|
2017-11-21 10:04:49 +03:00
|
|
|
coeff.negate();
|
|
|
|
|
|
|
|
self + (coeff, var)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<E: Engine> Add<Variable> for LinearCombination<E> {
|
|
|
|
type Output = LinearCombination<E>;
|
2017-11-21 10:04:49 +03:00
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn add(self, other: Variable) -> LinearCombination<E> {
|
2017-11-21 10:04:49 +03:00
|
|
|
self + (E::Fr::one(), other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<E: Engine> Sub<Variable> for LinearCombination<E> {
|
|
|
|
type Output = LinearCombination<E>;
|
2017-11-21 10:04:49 +03:00
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn sub(self, other: Variable) -> LinearCombination<E> {
|
2017-11-21 10:04:49 +03:00
|
|
|
self - (E::Fr::one(), other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<'a, E: Engine> Add<&'a LinearCombination<E>> for LinearCombination<E> {
|
|
|
|
type Output = LinearCombination<E>;
|
2017-12-15 02:11:24 +03:00
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn add(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
|
2017-12-15 02:11:24 +03:00
|
|
|
for s in &other.0 {
|
|
|
|
self = self + (s.1, s.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<'a, E: Engine> Sub<&'a LinearCombination<E>> for LinearCombination<E> {
|
|
|
|
type Output = LinearCombination<E>;
|
2017-12-15 02:11:24 +03:00
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn sub(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
|
2017-12-15 02:11:24 +03:00
|
|
|
for s in &other.0 {
|
|
|
|
self = self - (s.1, s.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<'a, E: Engine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
|
|
|
|
type Output = LinearCombination<E>;
|
2018-01-07 21:31:35 +03:00
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn add(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
|
2018-01-07 21:31:35 +03:00
|
|
|
for s in &other.0 {
|
|
|
|
let mut tmp = s.1;
|
|
|
|
tmp.mul_assign(&coeff);
|
|
|
|
self = self + (tmp, s.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<'a, E: Engine> Sub<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
|
|
|
|
type Output = LinearCombination<E>;
|
2018-01-07 21:31:35 +03:00
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn sub(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
|
2018-01-07 21:31:35 +03:00
|
|
|
for s in &other.0 {
|
|
|
|
let mut tmp = s.1;
|
|
|
|
tmp.mul_assign(&coeff);
|
|
|
|
self = self - (tmp, s.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-21 10:04:49 +03:00
|
|
|
/// This is an error that could occur during circuit synthesis contexts,
|
|
|
|
/// such as CRS generation, proving or verification.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum SynthesisError {
|
2018-02-14 22:31:43 +03:00
|
|
|
/// During synthesis, we lacked knowledge of a variable assignment.
|
|
|
|
AssignmentMissing,
|
|
|
|
/// During synthesis, we divided by zero.
|
|
|
|
DivisionByZero,
|
|
|
|
/// During synthesis, we constructed an unsatisfiable constraint system.
|
|
|
|
Unsatisfiable,
|
|
|
|
/// During synthesis, our polynomials ended up being too high of degree
|
|
|
|
PolynomialDegreeTooLarge,
|
|
|
|
/// During proof generation, we encountered an identity in the CRS
|
|
|
|
UnexpectedIdentity,
|
|
|
|
/// During proof generation, we encountered an I/O error with the CRS
|
|
|
|
IoError(io::Error),
|
|
|
|
/// During verification, our verifying key was malformed.
|
|
|
|
MalformedVerifyingKey,
|
|
|
|
/// During CRS generation, we observed an unconstrained auxillary variable
|
|
|
|
UnconstrainedVariable
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<io::Error> for SynthesisError {
|
|
|
|
fn from(e: io::Error) -> SynthesisError {
|
|
|
|
SynthesisError::IoError(e)
|
|
|
|
}
|
2017-11-21 10:04:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Error for SynthesisError {
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
match *self {
|
2018-02-14 22:31:43 +03:00
|
|
|
SynthesisError::AssignmentMissing => "an assignment for a variable could not be computed",
|
|
|
|
SynthesisError::DivisionByZero => "division by zero",
|
|
|
|
SynthesisError::Unsatisfiable => "unsatisfiable constraint system",
|
|
|
|
SynthesisError::PolynomialDegreeTooLarge => "polynomial degree is too large",
|
|
|
|
SynthesisError::UnexpectedIdentity => "encountered an identity element in the CRS",
|
|
|
|
SynthesisError::IoError(_) => "encountered an I/O error",
|
|
|
|
SynthesisError::MalformedVerifyingKey => "malformed verifying key",
|
|
|
|
SynthesisError::UnconstrainedVariable => "auxillary variable was unconstrained"
|
2017-11-21 10:04:49 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for SynthesisError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
2018-02-14 22:31:43 +03:00
|
|
|
if let &SynthesisError::IoError(ref e) = self {
|
|
|
|
write!(f, "I/O error: ")?;
|
|
|
|
e.fmt(f)
|
|
|
|
} else {
|
|
|
|
write!(f, "{}", self.description())
|
|
|
|
}
|
2017-11-21 10:04:49 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
/// Represents a constraint system which can have new variables
|
|
|
|
/// allocated and constrains between them formed.
|
2017-11-21 10:04:49 +03:00
|
|
|
pub trait ConstraintSystem<E: Engine>: Sized {
|
|
|
|
/// Represents the type of the "root" of this constraint system
|
|
|
|
/// so that nested namespaces can minimize indirection.
|
2018-02-14 22:31:43 +03:00
|
|
|
type Root: ConstraintSystem<E>;
|
2017-11-21 10:04:49 +03:00
|
|
|
|
|
|
|
/// Return the "one" input variable
|
2018-02-14 22:31:43 +03:00
|
|
|
fn one() -> Variable {
|
|
|
|
Variable::new_unchecked(Index::Input(0))
|
|
|
|
}
|
2017-11-21 10:04:49 +03:00
|
|
|
|
|
|
|
/// Allocate a private variable in the constraint system. The provided function is used to
|
|
|
|
/// determine the assignment of the variable. The given `annotation` function is invoked
|
|
|
|
/// in testing contexts in order to derive a unique name for this variable in the current
|
|
|
|
/// namespace.
|
|
|
|
fn alloc<F, A, AR>(
|
|
|
|
&mut self,
|
|
|
|
annotation: A,
|
|
|
|
f: F
|
2018-02-14 22:31:43 +03:00
|
|
|
) -> Result<Variable, SynthesisError>
|
|
|
|
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>;
|
|
|
|
|
|
|
|
/// Allocate a public variable in the constraint system. The provided function is used to
|
|
|
|
/// determine the assignment of the variable.
|
|
|
|
fn alloc_input<F, A, AR>(
|
|
|
|
&mut self,
|
|
|
|
annotation: A,
|
|
|
|
f: F
|
|
|
|
) -> Result<Variable, SynthesisError>
|
2017-11-21 10:04:49 +03:00
|
|
|
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>;
|
|
|
|
|
|
|
|
/// Enforce that `A` * `B` = `C`. The `annotation` function is invoked in testing contexts
|
|
|
|
/// in order to derive a unique name for the constraint in the current namespace.
|
2018-02-14 22:31:43 +03:00
|
|
|
fn enforce<A, AR, LA, LB, LC>(
|
2017-11-21 10:04:49 +03:00
|
|
|
&mut self,
|
|
|
|
annotation: A,
|
2018-02-14 22:31:43 +03:00
|
|
|
a: LA,
|
|
|
|
b: LB,
|
|
|
|
c: LC
|
2017-11-21 10:04:49 +03:00
|
|
|
)
|
2018-02-14 22:31:43 +03:00
|
|
|
where A: FnOnce() -> AR, AR: Into<String>,
|
|
|
|
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
|
|
|
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
|
|
|
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>;
|
2017-11-21 10:04:49 +03:00
|
|
|
|
|
|
|
/// Create a new (sub)namespace and enter into it. Not intended
|
|
|
|
/// for downstream use; use `namespace` instead.
|
|
|
|
fn push_namespace<NR, N>(&mut self, name_fn: N)
|
|
|
|
where NR: Into<String>, N: FnOnce() -> NR;
|
|
|
|
|
|
|
|
/// Exit out of the existing namespace. Not intended for
|
|
|
|
/// downstream use; use `namespace` instead.
|
|
|
|
fn pop_namespace(&mut self);
|
|
|
|
|
|
|
|
/// Gets the "root" constraint system, bypassing the namespacing.
|
|
|
|
/// Not intended for downstream use; use `namespace` instead.
|
|
|
|
fn get_root(&mut self) -> &mut Self::Root;
|
|
|
|
|
|
|
|
/// Begin a namespace for this constraint system.
|
|
|
|
fn namespace<'a, NR, N>(
|
|
|
|
&'a mut self,
|
|
|
|
name_fn: N
|
|
|
|
) -> Namespace<'a, E, Self::Root>
|
|
|
|
where NR: Into<String>, N: FnOnce() -> NR
|
|
|
|
{
|
|
|
|
self.get_root().push_namespace(name_fn);
|
|
|
|
|
|
|
|
Namespace(self.get_root(), PhantomData)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This is a "namespaced" constraint system which borrows a constraint system (pushing
|
|
|
|
/// a namespace context) and, when dropped, pops out of the namespace context.
|
|
|
|
pub struct Namespace<'a, E: Engine, CS: ConstraintSystem<E> + 'a>(&'a mut CS, PhantomData<E>);
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
impl<'cs, E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Namespace<'cs, E, CS> {
|
|
|
|
type Root = CS::Root;
|
|
|
|
|
|
|
|
fn one() -> Variable {
|
|
|
|
CS::one()
|
|
|
|
}
|
2017-11-21 23:44:56 +03:00
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn alloc<F, A, AR>(
|
2017-11-21 10:04:49 +03:00
|
|
|
&mut self,
|
|
|
|
annotation: A,
|
|
|
|
f: F
|
2018-02-14 22:31:43 +03:00
|
|
|
) -> Result<Variable, SynthesisError>
|
2017-11-21 10:04:49 +03:00
|
|
|
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
|
|
|
{
|
2018-02-14 22:31:43 +03:00
|
|
|
self.0.alloc(annotation, f)
|
2017-11-21 10:04:49 +03:00
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn alloc_input<F, A, AR>(
|
2017-11-21 10:04:49 +03:00
|
|
|
&mut self,
|
|
|
|
annotation: A,
|
|
|
|
f: F
|
2018-02-14 22:31:43 +03:00
|
|
|
) -> Result<Variable, SynthesisError>
|
2017-11-21 10:04:49 +03:00
|
|
|
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
|
|
|
{
|
2018-02-14 22:31:43 +03:00
|
|
|
self.0.alloc_input(annotation, f)
|
2017-11-21 10:04:49 +03:00
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn enforce<A, AR, LA, LB, LC>(
|
2017-11-21 10:04:49 +03:00
|
|
|
&mut self,
|
|
|
|
annotation: A,
|
2018-02-14 22:31:43 +03:00
|
|
|
a: LA,
|
|
|
|
b: LB,
|
|
|
|
c: LC
|
2017-11-21 10:04:49 +03:00
|
|
|
)
|
2018-02-14 22:31:43 +03:00
|
|
|
where A: FnOnce() -> AR, AR: Into<String>,
|
|
|
|
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
|
|
|
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
|
|
|
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
|
2017-11-21 10:04:49 +03:00
|
|
|
{
|
|
|
|
self.0.enforce(annotation, a, b, c)
|
|
|
|
}
|
|
|
|
|
2017-11-21 23:44:56 +03:00
|
|
|
// Downstream users who use `namespace` will never interact with these
|
|
|
|
// functions and they will never be invoked because the namespace is
|
|
|
|
// never a root constraint system.
|
|
|
|
|
|
|
|
fn push_namespace<NR, N>(&mut self, _: N)
|
2017-11-21 10:04:49 +03:00
|
|
|
where NR: Into<String>, N: FnOnce() -> NR
|
|
|
|
{
|
2017-11-21 23:44:56 +03:00
|
|
|
panic!("only the root's push_namespace should be called");
|
2017-11-21 10:04:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn pop_namespace(&mut self)
|
|
|
|
{
|
2017-11-21 23:44:56 +03:00
|
|
|
panic!("only the root's pop_namespace should be called");
|
2017-11-21 10:04:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_root(&mut self) -> &mut Self::Root
|
|
|
|
{
|
|
|
|
self.0.get_root()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, E: Engine, CS: ConstraintSystem<E>> Drop for Namespace<'a, E, CS> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
self.get_root().pop_namespace()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Convenience implementation of ConstraintSystem<E> for mutable references to
|
|
|
|
/// constraint systems.
|
|
|
|
impl<'cs, E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for &'cs mut CS {
|
|
|
|
type Root = CS::Root;
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn one() -> Variable {
|
|
|
|
CS::one()
|
2017-11-21 10:04:49 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
fn alloc<F, A, AR>(
|
|
|
|
&mut self,
|
|
|
|
annotation: A,
|
|
|
|
f: F
|
2018-02-14 22:31:43 +03:00
|
|
|
) -> Result<Variable, SynthesisError>
|
2017-11-21 10:04:49 +03:00
|
|
|
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
|
|
|
{
|
|
|
|
(**self).alloc(annotation, f)
|
|
|
|
}
|
|
|
|
|
2018-02-14 22:31:43 +03:00
|
|
|
fn alloc_input<F, A, AR>(
|
|
|
|
&mut self,
|
|
|
|
annotation: A,
|
|
|
|
f: F
|
|
|
|
) -> Result<Variable, SynthesisError>
|
|
|
|
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
|
|
|
|
{
|
|
|
|
(**self).alloc_input(annotation, f)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn enforce<A, AR, LA, LB, LC>(
|
2017-11-21 10:04:49 +03:00
|
|
|
&mut self,
|
|
|
|
annotation: A,
|
2018-02-14 22:31:43 +03:00
|
|
|
a: LA,
|
|
|
|
b: LB,
|
|
|
|
c: LC
|
2017-11-21 10:04:49 +03:00
|
|
|
)
|
2018-02-14 22:31:43 +03:00
|
|
|
where A: FnOnce() -> AR, AR: Into<String>,
|
|
|
|
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
|
|
|
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
|
|
|
|
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
|
2017-11-21 10:04:49 +03:00
|
|
|
{
|
|
|
|
(**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()
|
|
|
|
}
|
|
|
|
}
|