extern crate ff; extern crate group; #[cfg(feature = "pairing")] extern crate pairing; extern crate rand; extern crate futures; extern crate bit_vec; extern crate byteorder; #[cfg(feature = "multicore")] extern crate crossbeam; #[cfg(feature = "multicore")] extern crate futures_cpupool; #[cfg(feature = "multicore")] extern crate num_cpus; pub mod multicore; mod multiexp; pub mod domain; #[cfg(feature = "groth16")] pub mod groth16; use ff::{Field, ScalarEngine}; use std::ops::{Add, Sub}; use std::fmt; use std::error::Error; 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 { /// Synthesize the circuit into a rank-1 quadratic constraint system fn synthesize>( 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 /// auxiliary variable. #[derive(Copy, Clone, PartialEq, Debug)] pub enum Index { Input(usize), Aux(usize) } /// This represents a linear combination of some variables, with coefficients /// in the scalar field of a pairing-friendly elliptic curve group. #[derive(Clone)] pub struct LinearCombination(Vec<(Variable, E::Fr)>); impl AsRef<[(Variable, E::Fr)]> for LinearCombination { fn as_ref(&self) -> &[(Variable, E::Fr)] { &self.0 } } impl LinearCombination { pub fn zero() -> LinearCombination { LinearCombination(vec![]) } } impl Add<(E::Fr, Variable)> for LinearCombination { type Output = LinearCombination; fn add(mut self, (coeff, var): (E::Fr, Variable)) -> LinearCombination { self.0.push((var, coeff)); self } } impl Sub<(E::Fr, Variable)> for LinearCombination { type Output = LinearCombination; fn sub(self, (mut coeff, var): (E::Fr, Variable)) -> LinearCombination { coeff.negate(); self + (coeff, var) } } impl Add for LinearCombination { type Output = LinearCombination; fn add(self, other: Variable) -> LinearCombination { self + (E::Fr::one(), other) } } impl Sub for LinearCombination { type Output = LinearCombination; fn sub(self, other: Variable) -> LinearCombination { self - (E::Fr::one(), other) } } impl<'a, E: ScalarEngine> Add<&'a LinearCombination> for LinearCombination { type Output = LinearCombination; fn add(mut self, other: &'a LinearCombination) -> LinearCombination { for s in &other.0 { self = self + (s.1, s.0); } self } } impl<'a, E: ScalarEngine> Sub<&'a LinearCombination> for LinearCombination { type Output = LinearCombination; fn sub(mut self, other: &'a LinearCombination) -> LinearCombination { for s in &other.0 { self = self - (s.1, s.0); } self } } impl<'a, E: ScalarEngine> Add<(E::Fr, &'a LinearCombination)> for LinearCombination { type Output = LinearCombination; fn add(mut self, (coeff, other): (E::Fr, &'a LinearCombination)) -> LinearCombination { for s in &other.0 { let mut tmp = s.1; tmp.mul_assign(&coeff); self = self + (tmp, s.0); } self } } impl<'a, E: ScalarEngine> Sub<(E::Fr, &'a LinearCombination)> for LinearCombination { type Output = LinearCombination; fn sub(mut self, (coeff, other): (E::Fr, &'a LinearCombination)) -> LinearCombination { for s in &other.0 { let mut tmp = s.1; tmp.mul_assign(&coeff); self = self - (tmp, s.0); } self } } /// This is an error that could occur during circuit synthesis contexts, /// such as CRS generation, proving or verification. #[derive(Debug)] pub enum SynthesisError { /// 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 auxiliary variable UnconstrainedVariable } impl From for SynthesisError { fn from(e: io::Error) -> SynthesisError { SynthesisError::IoError(e) } } impl Error for SynthesisError { fn description(&self) -> &str { match *self { 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 => "auxiliary variable was unconstrained" } } } impl fmt::Display for SynthesisError { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { if let &SynthesisError::IoError(ref e) = self { write!(f, "I/O error: ")?; e.fmt(f) } else { write!(f, "{}", self.description()) } } } /// Represents a constraint system which can have new variables /// allocated and constrains between them formed. pub trait ConstraintSystem: Sized { /// Represents the type of the "root" of this constraint system /// so that nested namespaces can minimize indirection. type Root: ConstraintSystem; /// Return the "one" input variable fn one() -> Variable { Variable::new_unchecked(Index::Input(0)) } /// 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( &mut self, annotation: A, f: F ) -> Result where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into; /// Allocate a public variable in the constraint system. The provided function is used to /// determine the assignment of the variable. fn alloc_input( &mut self, annotation: A, f: F ) -> Result where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into; /// 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. fn enforce( &mut self, annotation: A, a: LA, b: LB, c: LC ) where A: FnOnce() -> AR, AR: Into, LA: FnOnce(LinearCombination) -> LinearCombination, LB: FnOnce(LinearCombination) -> LinearCombination, LC: FnOnce(LinearCombination) -> LinearCombination; /// Create a new (sub)namespace and enter into it. Not intended /// for downstream use; use `namespace` instead. fn push_namespace(&mut self, name_fn: N) where NR: Into, 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, 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: ScalarEngine, CS: ConstraintSystem + 'a>(&'a mut CS, PhantomData); impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for Namespace<'cs, E, CS> { type Root = CS::Root; fn one() -> Variable { CS::one() } fn alloc( &mut self, annotation: A, f: F ) -> Result where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into { self.0.alloc(annotation, f) } fn alloc_input( &mut self, annotation: A, f: F ) -> Result where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into { self.0.alloc_input(annotation, f) } fn enforce( &mut self, annotation: A, a: LA, b: LB, c: LC ) where A: FnOnce() -> AR, AR: Into, LA: FnOnce(LinearCombination) -> LinearCombination, LB: FnOnce(LinearCombination) -> LinearCombination, LC: FnOnce(LinearCombination) -> LinearCombination { self.0.enforce(annotation, a, b, c) } // 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(&mut self, _: N) where NR: Into, 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() } } impl<'a, E: ScalarEngine, CS: ConstraintSystem> Drop for Namespace<'a, E, CS> { fn drop(&mut self) { self.get_root().pop_namespace() } } /// Convenience implementation of ConstraintSystem for mutable references to /// constraint systems. impl<'cs, E: ScalarEngine, CS: ConstraintSystem> ConstraintSystem for &'cs mut CS { type Root = CS::Root; fn one() -> Variable { CS::one() } fn alloc( &mut self, annotation: A, f: F ) -> Result where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into { (**self).alloc(annotation, f) } fn alloc_input( &mut self, annotation: A, f: F ) -> Result where F: FnOnce() -> Result, A: FnOnce() -> AR, AR: Into { (**self).alloc_input(annotation, f) } fn enforce( &mut self, annotation: A, a: LA, b: LB, c: LC ) where A: FnOnce() -> AR, AR: Into, LA: FnOnce(LinearCombination) -> LinearCombination, LB: FnOnce(LinearCombination) -> LinearCombination, LC: FnOnce(LinearCombination) -> LinearCombination { (**self).enforce(annotation, a, b, c) } fn push_namespace(&mut self, name_fn: N) where NR: Into, 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() } }