start transitioning to versioning + more elegant re-exports

This commit is contained in:
Alex Vlasov 2019-03-04 23:04:39 +03:00
parent 04454890b9
commit 810bb92cee
47 changed files with 758 additions and 699 deletions

@ -6,7 +6,8 @@ homepage = "https://github.com/matterinc/bellman"
license = "MIT/Apache-2.0"
name = "bellman"
repository = "https://github.com/matterinc/bellman"
version = "0.1.3"
version = "0.2.0"
edition = "2018"
[lib]
crate-type = ["cdylib", "lib", "staticlib"]
@ -15,20 +16,25 @@ crate-type = ["cdylib", "lib", "staticlib"]
rand = "0.4"
bit-vec = "0.4.4"
futures = "0.1"
futures-cpupool = "0.1"
num_cpus = "1"
crossbeam = "0.7.1"
pairing = { git = 'https://github.com/matterinc/pairing' }
byteorder = "1"
ff = { git = 'https://github.com/matterinc/ff', features = ["derive"] }
tiny-keccak = "1.4.2"
#pairing = { git = 'https://github.com/matterinc/pairing', tag = "0.16.2" }
pairing = { path = "../pairing" }
byteorder = "1"
futures-cpupool = {version = "0.1", optional = true}
num_cpus = {version = "1", optional = true}
crossbeam = {version = "0.7.1", optional = true}
tiny-keccak = {version = "1.4.2", optional = true}
[dependencies.blake2-rfc]
git = "https://github.com/gtank/blake2-rfc"
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
[features]
default = []
singlecore = []
default = ["multicore", "gm17", "sonic"]
#default = ["singlecore"]
multicore = ["futures-cpupool", "num_cpus", "crossbeam"]
sonic = ["tiny-keccak"]
gm17 = []
singlecore = ["futures-cpupool"]

411
src/cs.rs Normal file

@ -0,0 +1,411 @@
use pairing::{Engine};
use pairing::ff::Field;
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<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(pub(crate) 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)
}
/// 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<E: Engine>(pub(crate) Vec<(Variable, E::Fr)>);
impl<E: Engine> AsRef<[(Variable, E::Fr)]> for LinearCombination<E> {
fn as_ref(&self) -> &[(Variable, E::Fr)] {
&self.0
}
}
impl<E: Engine> LinearCombination<E> {
pub fn zero() -> LinearCombination<E> {
LinearCombination(vec![])
}
}
impl<E: Engine> Add<(E::Fr, Variable)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(mut self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
self.0.push((var, coeff));
self
}
}
impl<E: Engine> Sub<(E::Fr, Variable)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(self, (mut coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
coeff.negate();
self + (coeff, var)
}
}
impl<E: Engine> Add<Variable> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(self, other: Variable) -> LinearCombination<E> {
self + (E::Fr::one(), other)
}
}
impl<E: Engine> Sub<Variable> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(self, other: Variable) -> LinearCombination<E> {
self - (E::Fr::one(), other)
}
}
impl<'a, E: Engine> Add<&'a LinearCombination<E>> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
for s in &other.0 {
self = self + (s.1, s.0);
}
self
}
}
impl<'a, E: Engine> Sub<&'a LinearCombination<E>> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
for s in &other.0 {
self = self - (s.1, s.0);
}
self
}
}
impl<'a, E: Engine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
for s in &other.0 {
let mut tmp = s.1;
tmp.mul_assign(&coeff);
self = self + (tmp, s.0);
}
self
}
}
impl<'a, E: Engine> Sub<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
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 auxillary variable
UnconstrainedVariable
}
impl From<io::Error> 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 => "auxillary 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<E: Engine>: Sized {
/// Represents the type of the "root" of this constraint system
/// so that nested namespaces can minimize indirection.
type Root: ConstraintSystem<E>;
/// 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<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>;
/// 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>
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.
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<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>;
/// 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>);
impl<'cs, E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Namespace<'cs, E, 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<E::Fr, 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<E::Fr, 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<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
{
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<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()
}
}
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;
fn one() -> Variable {
CS::one()
}
fn alloc<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(annotation, f)
}
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>(
&mut self,
annotation: A,
a: LA,
b: LB,
c: LC
)
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>
{
(**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()
}
}

@ -15,7 +15,7 @@ use pairing::{
CurveProjective
};
use ff::{
use pairing::ff::{
Field,
PrimeField
};
@ -24,13 +24,9 @@ use super::{
SynthesisError
};
use super::multicore::Worker;
use super::worker::Worker;
pub use super::group::*;
#[cfg(not(feature = "singlecore"))]
use super::parallel_fft::*;
pub struct EvaluationDomain<E: Engine, G: Group<E>> {
coeffs: Vec<G>,
exp: u32,
@ -55,7 +51,7 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
pub fn from_coeffs(mut coeffs: Vec<G>) -> Result<EvaluationDomain<E, G>, SynthesisError>
{
use ff::PrimeField;
use pairing::ff::PrimeField;
// Compute the size of our evaluation domain
let coeffs_len = coeffs.len();
@ -105,7 +101,7 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
// this one does expect coefficients to be smaller than `num_roots_of_unity/2` as we expect multiplication
pub fn from_coeffs_into_sized(mut coeffs: Vec<G>, size: usize) -> Result<EvaluationDomain<E, G>, SynthesisError>
{
use ff::PrimeField;
use pairing::ff::PrimeField;
// Compute the size of our evaluation domain
assert!(size >= coeffs.len());
@ -264,6 +260,121 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
}
}
pub(crate) fn best_fft<E: Engine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32)
{
let log_cpus = worker.log_num_cpus();
if log_n <= log_cpus {
serial_fft(a, omega, log_n);
} else {
parallel_fft(a, worker, omega, log_n, log_cpus);
}
}
pub(crate) fn serial_fft<E: Engine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32)
{
fn bitreverse(mut n: u32, l: u32) -> u32 {
let mut r = 0;
for _ in 0..l {
r = (r << 1) | (n & 1);
n >>= 1;
}
r
}
let n = a.len() as u32;
assert_eq!(n, 1 << log_n);
for k in 0..n {
let rk = bitreverse(k, log_n);
if k < rk {
a.swap(rk as usize, k as usize);
}
}
let mut m = 1;
for _ in 0..log_n {
let w_m = omega.pow(&[(n / (2*m)) as u64]);
let mut k = 0;
while k < n {
let mut w = E::Fr::one();
for j in 0..m {
let mut t = a[(k+j+m) as usize];
t.group_mul_assign(&w);
let mut tmp = a[(k+j) as usize];
tmp.group_sub_assign(&t);
a[(k+j+m) as usize] = tmp;
a[(k+j) as usize].group_add_assign(&t);
w.mul_assign(&w_m);
}
k += 2*m;
}
m *= 2;
}
}
pub(crate) fn parallel_fft<E: Engine, T: Group<E>>(
a: &mut [T],
worker: &Worker,
omega: &E::Fr,
log_n: u32,
log_cpus: u32
)
{
assert!(log_n >= log_cpus);
let num_cpus = 1 << log_cpus;
let log_new_n = log_n - log_cpus;
let mut tmp = vec![vec![T::group_zero(); 1 << log_new_n]; num_cpus];
let new_omega = omega.pow(&[num_cpus as u64]);
worker.scope(0, |scope, _| {
let a = &*a;
for (j, tmp) in tmp.iter_mut().enumerate() {
scope.spawn(move |_| {
// Shuffle into a sub-FFT
let omega_j = omega.pow(&[j as u64]);
let omega_step = omega.pow(&[(j as u64) << log_new_n]);
let mut elt = E::Fr::one();
for i in 0..(1 << log_new_n) {
for s in 0..num_cpus {
let idx = (i + (s << log_new_n)) % (1 << log_n);
let mut t = a[idx];
t.group_mul_assign(&elt);
tmp[i].group_add_assign(&t);
elt.mul_assign(&omega_step);
}
elt.mul_assign(&omega_j);
}
// Perform sub-FFT
serial_fft(tmp, &new_omega, log_new_n);
});
}
});
// TODO: does this hurt or help?
worker.scope(a.len(), |scope, chunk| {
let tmp = &tmp;
for (idx, a) in a.chunks_mut(chunk).enumerate() {
scope.spawn(move |_| {
let mut idx = idx * chunk;
let mask = (1 << log_cpus) - 1;
for a in a {
*a = tmp[idx & mask][idx >> log_cpus];
idx += 1;
}
});
}
});
}
// Test multiplying various (low degree) polynomials together and
// comparing with naive evaluations.
#[test]

@ -11,7 +11,7 @@ use pairing::{
CurveAffine
};
use ff::{
use pairing::ff::{
PrimeField,
Field
};
@ -21,7 +21,7 @@ use super::{
VerifyingKey
};
use ::{
use crate::{
SynthesisError,
Circuit,
ConstraintSystem,
@ -30,12 +30,12 @@ use ::{
Index
};
use ::domain::{
use crate::domain::{
EvaluationDomain,
Scalar
};
use ::multicore::{
use crate::worker::{
Worker
};

@ -4,11 +4,11 @@ use pairing::{
EncodedPoint
};
use ::{
use crate::{
SynthesisError
};
use multiexp::SourceBuilder;
use crate::source::SourceBuilder;
use std::io::{self, Read, Write};
use std::sync::Arc;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
@ -474,7 +474,7 @@ impl<E: Engine> PartialEq for Parameters<E> {
// use {Circuit, SynthesisError, ConstraintSystem};
// use rand::{Rand, thread_rng};
// use ff::{Field};
// use pairing::ff::{Field};
// use pairing::bls12_381::{Bls12, Fr};
// #[test]

@ -2,7 +2,7 @@ use pairing::{
Engine
};
use ff:: {
use pairing::ff:: {
Field,
PrimeField,
};
@ -12,7 +12,7 @@ use super::super::tests::XORDemo;
use std::marker::PhantomData;
use ::{
use crate::{
Circuit,
ConstraintSystem,
SynthesisError

@ -11,7 +11,7 @@ use pairing::{
CurveAffine
};
use ff::{
use pairing::ff::{
PrimeField,
Field
};
@ -21,7 +21,7 @@ use super::{
VerifyingKey
};
use ::{
use crate::{
SynthesisError,
Circuit,
ConstraintSystem,
@ -30,12 +30,12 @@ use ::{
Index
};
use ::domain::{
use crate::domain::{
EvaluationDomain,
Scalar
};
use ::multicore::{
use crate::worker::{
Worker
};

@ -4,11 +4,11 @@ use pairing::{
EncodedPoint
};
use ::{
use crate::{
SynthesisError
};
use multiexp::SourceBuilder;
use crate::source::SourceBuilder;
use std::io::{self, Read, Write};
use std::sync::Arc;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
@ -484,10 +484,10 @@ impl<'a, E: Engine> ParameterSource<E> for &'a Parameters<E> {
#[cfg(test)]
mod test_with_bls12_381 {
use super::*;
use {Circuit, SynthesisError, ConstraintSystem};
use crate::{Circuit, SynthesisError, ConstraintSystem};
use rand::{Rand, thread_rng};
use ff::{Field};
use pairing::ff::{Field};
use pairing::bls12_381::{Bls12, Fr};
#[test]

@ -12,7 +12,7 @@ use pairing::{
CurveAffine
};
use ff::{
use pairing::ff::{
PrimeField,
Field
};
@ -22,7 +22,7 @@ use super::{
Proof
};
use ::{
use crate::{
SynthesisError,
Circuit,
ConstraintSystem,
@ -31,18 +31,19 @@ use ::{
Index
};
use ::domain::{
use crate::domain::{
EvaluationDomain,
Scalar
};
use ::multiexp::{
use crate::source::{
DensityTracker,
FullDensity,
multiexp
FullDensity
};
use ::multicore::{
use crate::multiexp::*;
use crate::worker::{
Worker
};

@ -2,7 +2,7 @@ use pairing::{
Engine
};
use ff:: {
use pairing::ff:: {
Field,
PrimeField,
};
@ -12,7 +12,7 @@ use super::super::tests::XORDemo;
use std::marker::PhantomData;
use ::{
use crate::{
Circuit,
ConstraintSystem,
SynthesisError

@ -4,7 +4,7 @@ use pairing::{
CurveAffine
};
use ff::{PrimeField};
use pairing::ff::{PrimeField};
use super::{
Proof,
@ -12,7 +12,7 @@ use super::{
PreparedVerifyingKey
};
use ::{
use crate::{
SynthesisError
};

@ -3,7 +3,7 @@ use pairing::{
CurveProjective
};
use ff::{
use pairing::ff::{
Field,
PrimeField
};

@ -1,458 +1,45 @@
#![allow(unused_imports)]
extern crate pairing;
extern crate pairing as pairing_import;
extern crate rand;
extern crate bit_vec;
extern crate byteorder;
extern crate ff;
#[cfg(not(feature = "singlecore"))]
extern crate num_cpus;
extern crate futures;
extern crate futures_cpupool;
extern crate crossbeam;
pub mod domain;
pub mod groth16;
#[cfg(feature = "gm17")]
pub mod gm17;
#[cfg(feature = "sonic")]
pub mod sonic;
mod group;
mod source;
#[cfg(not(feature = "singlecore"))]
mod parallel_fft;
mod multicore;
mod parallel_multiexp;
#[cfg(feature = "singlecore")]
mod serial_fft;
mod serial_multiexp;
mod multiexp;
#[cfg(test)]
mod tests;
use pairing::{Engine};
use ff::Field;
#[cfg(feature = "multicore")]
mod multicore;
use std::ops::{Add, Sub};
use std::fmt;
use std::error::Error;
use std::io;
use std::marker::PhantomData;
#[cfg(feature = "singlecore")]
mod singlecore;
pub mod multiexp {
pub use source::*;
#[cfg(not(feature = "singlecore"))]
pub use parallel_multiexp::*;
mod worker {
#[cfg(feature = "multicore")]
pub use crate::multicore::*;
#[cfg(feature = "singlecore")]
pub use serial_multiexp::*;
pub use crate::singlecore::*;
}
/// 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>;
pub mod pairing {
pub use pairing_import::*;
}
/// 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)
}
/// 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<E: Engine>(Vec<(Variable, E::Fr)>);
impl<E: Engine> AsRef<[(Variable, E::Fr)]> for LinearCombination<E> {
fn as_ref(&self) -> &[(Variable, E::Fr)] {
&self.0
}
}
impl<E: Engine> LinearCombination<E> {
pub fn zero() -> LinearCombination<E> {
LinearCombination(vec![])
}
}
impl<E: Engine> Add<(E::Fr, Variable)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(mut self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
self.0.push((var, coeff));
self
}
}
impl<E: Engine> Sub<(E::Fr, Variable)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(self, (mut coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
coeff.negate();
self + (coeff, var)
}
}
impl<E: Engine> Add<Variable> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(self, other: Variable) -> LinearCombination<E> {
self + (E::Fr::one(), other)
}
}
impl<E: Engine> Sub<Variable> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(self, other: Variable) -> LinearCombination<E> {
self - (E::Fr::one(), other)
}
}
impl<'a, E: Engine> Add<&'a LinearCombination<E>> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
for s in &other.0 {
self = self + (s.1, s.0);
}
self
}
}
impl<'a, E: Engine> Sub<&'a LinearCombination<E>> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
for s in &other.0 {
self = self - (s.1, s.0);
}
self
}
}
impl<'a, E: Engine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
for s in &other.0 {
let mut tmp = s.1;
tmp.mul_assign(&coeff);
self = self + (tmp, s.0);
}
self
}
}
impl<'a, E: Engine> Sub<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
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 auxillary variable
UnconstrainedVariable
}
impl From<io::Error> 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 => "auxillary 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<E: Engine>: Sized {
/// Represents the type of the "root" of this constraint system
/// so that nested namespaces can minimize indirection.
type Root: ConstraintSystem<E>;
/// 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<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>;
/// 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>
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.
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<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>;
/// 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>);
impl<'cs, E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Namespace<'cs, E, 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<E::Fr, 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<E::Fr, 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<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
{
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<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()
}
}
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;
fn one() -> Variable {
CS::one()
}
fn alloc<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(annotation, f)
}
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>(
&mut self,
annotation: A,
a: LA,
b: LB,
c: LC
)
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>
{
(**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()
}
}
mod cs;
pub use self::cs::*;
static mut VERBOSE_SWITCH: i8 = -1;

@ -4,11 +4,14 @@
//! crossbeam but may be extended in the future to
//! allow for various parallelism strategies.
use num_cpus;
use futures::{Future, IntoFuture, Poll};
use futures_cpupool::{CpuPool, CpuFuture};
use crossbeam::{self};
use crossbeam::thread::{Scope};
extern crate num_cpus;
extern crate futures;
extern crate futures_cpupool;
extern crate crossbeam;
use self::futures::{Future, IntoFuture, Poll};
use self::futures_cpupool::{CpuPool, CpuFuture};
use self::crossbeam::thread::{Scope};
#[derive(Clone)]
pub struct Worker {

@ -4,7 +4,7 @@ use pairing::{
Engine
};
use ff::{
use pairing::ff::{
PrimeField,
Field,
PrimeFieldRepr,
@ -13,7 +13,7 @@ use ff::{
use std::sync::Arc;
use super::source::*;
use futures::{Future};
use super::multicore::Worker;
use super::worker::Worker;
use super::SynthesisError;
@ -212,19 +212,16 @@ fn dense_multiexp_inner<G: CurveAffine>(
handle_trivial: bool
) -> Result<<G as CurveAffine>::Projective, SynthesisError>
{
use crossbeam::channel::{unbounded, RecvError};
// Perform this region of the multiexp. We use a different strategy - go over region in parallel,
// then over another region, etc. No Arc required
let this = {
// let mask = (1u64 << c) - 1u64;
let (s, r) = unbounded();
// let this_region =
let this_region =
pool.scope(bases.len(), |scope, chunk| {
// let mut handles = vec![];
// let mut this_acc = <G as CurveAffine>::Projective::zero();
let mut handles = vec![];
let mut this_acc = <G as CurveAffine>::Projective::zero();
for (base, exp) in bases.chunks(chunk).zip(exponents.chunks(chunk)) {
let s = s.clone();
// let handle =
let handle =
scope.spawn(move |_| {
let mut buckets = vec![<G as CurveAffine>::Projective::zero(); (1 << c) - 1];
// Accumulate the result
@ -265,32 +262,32 @@ fn dense_multiexp_inner<G: CurveAffine>(
}
// acc contains values over this region
s.send(acc).expect("must send result");
// s.send(acc).expect("must send result");
// acc
acc
});
// handles.push(handle);
handles.push(handle);
}
// // wait for all threads to finish
// for r in handles.into_iter() {
// let thread_result = r.join().unwrap();
// this_acc.add_assign(&thread_result);
// }
// wait for all threads to finish
for r in handles.into_iter() {
let thread_result = r.join().unwrap();
this_acc.add_assign(&thread_result);
}
// this_acc
this_acc
});
let mut this_region = <G as CurveAffine>::Projective::zero();
loop {
if r.is_empty() {
break;
}
let value = r.recv().expect("must have value");
this_region.add_assign(&value);
}
// let mut this_region = <G as CurveAffine>::Projective::zero();
// loop {
// if r.is_empty() {
// break;
// }
// let value = r.recv().expect("must have value");
// this_region.add_assign(&value);
// }
this_region
};

@ -1,143 +0,0 @@
//! This module contains an `EvaluationDomain` abstraction for
//! performing various kinds of polynomial arithmetic on top of
//! the scalar field.
//!
//! In pairing-based SNARKs like Groth16, we need to calculate
//! a quotient polynomial over a target polynomial with roots
//! at distinct points associated with each constraint of the
//! constraint system. In order to be efficient, we choose these
//! roots to be the powers of a 2^n root of unity in the field.
//! This allows us to perform polynomial operations in O(n)
//! by performing an O(n log n) FFT over such a domain.
use pairing::{
Engine,
CurveProjective
};
use ff::{
Field,
PrimeField
};
use super::{
SynthesisError
};
use super::multicore::Worker;
use super::group::*;
pub(crate) fn best_fft<E: Engine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32)
{
let log_cpus = worker.log_num_cpus();
if log_n <= log_cpus {
serial_fft(a, omega, log_n);
} else {
parallel_fft(a, worker, omega, log_n, log_cpus);
}
}
pub(crate) fn serial_fft<E: Engine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32)
{
fn bitreverse(mut n: u32, l: u32) -> u32 {
let mut r = 0;
for _ in 0..l {
r = (r << 1) | (n & 1);
n >>= 1;
}
r
}
let n = a.len() as u32;
assert_eq!(n, 1 << log_n);
for k in 0..n {
let rk = bitreverse(k, log_n);
if k < rk {
a.swap(rk as usize, k as usize);
}
}
let mut m = 1;
for _ in 0..log_n {
let w_m = omega.pow(&[(n / (2*m)) as u64]);
let mut k = 0;
while k < n {
let mut w = E::Fr::one();
for j in 0..m {
let mut t = a[(k+j+m) as usize];
t.group_mul_assign(&w);
let mut tmp = a[(k+j) as usize];
tmp.group_sub_assign(&t);
a[(k+j+m) as usize] = tmp;
a[(k+j) as usize].group_add_assign(&t);
w.mul_assign(&w_m);
}
k += 2*m;
}
m *= 2;
}
}
pub(crate) fn parallel_fft<E: Engine, T: Group<E>>(
a: &mut [T],
worker: &Worker,
omega: &E::Fr,
log_n: u32,
log_cpus: u32
)
{
assert!(log_n >= log_cpus);
let num_cpus = 1 << log_cpus;
let log_new_n = log_n - log_cpus;
let mut tmp = vec![vec![T::group_zero(); 1 << log_new_n]; num_cpus];
let new_omega = omega.pow(&[num_cpus as u64]);
worker.scope(0, |scope, _| {
let a = &*a;
for (j, tmp) in tmp.iter_mut().enumerate() {
scope.spawn(move |_| {
// Shuffle into a sub-FFT
let omega_j = omega.pow(&[j as u64]);
let omega_step = omega.pow(&[(j as u64) << log_new_n]);
let mut elt = E::Fr::one();
for i in 0..(1 << log_new_n) {
for s in 0..num_cpus {
let idx = (i + (s << log_new_n)) % (1 << log_n);
let mut t = a[idx];
t.group_mul_assign(&elt);
tmp[i].group_add_assign(&t);
elt.mul_assign(&omega_step);
}
elt.mul_assign(&omega_j);
}
// Perform sub-FFT
serial_fft(tmp, &new_omega, log_new_n);
});
}
});
// TODO: does this hurt or help?
worker.scope(a.len(), |scope, chunk| {
let tmp = &tmp;
for (idx, a) in a.chunks_mut(chunk).enumerate() {
scope.spawn(move |_| {
let mut idx = idx * chunk;
let mask = (1 << log_cpus) - 1;
for a in a {
*a = tmp[idx & mask][idx >> log_cpus];
idx += 1;
}
});
}
});
}

94
src/singlecore.rs Normal file

@ -0,0 +1,94 @@
//! This is a dummy interface to substitute multicore worker
//! in environments like WASM
extern crate futures;
extern crate futures_cpupool;
use std::marker::PhantomData;
use self::futures::{Future, IntoFuture, Poll};
use self::futures_cpupool::{CpuFuture, CpuPool};
#[derive(Clone)]
pub struct Worker {
cpus: usize,
pool: CpuPool
}
impl Worker {
// We don't expose this outside the library so that
// all `Worker` instances have the same number of
// CPUs configured.
pub(crate) fn new_with_cpus(cpus: usize) -> Worker {
Worker {
cpus: 1,
pool: CpuPool::new(1)
}
}
pub fn new() -> Worker {
Self::new_with_cpus(1)
}
pub fn log_num_cpus(&self) -> u32 {
0u32
}
pub fn compute<F, R>(
&self, f: F
) -> WorkerFuture<R::Item, R::Error>
where F: FnOnce() -> R + Send + 'static,
R: IntoFuture + 'static,
R::Future: Send + 'static,
R::Item: Send + 'static,
R::Error: Send + 'static
{
WorkerFuture {
future: self.pool.spawn_fn(f)
}
}
pub fn scope<'a, F, R>(
&self,
elements: usize,
f: F
) -> R
where F: FnOnce(&Scope<'a>, usize) -> R
{
let chunk_size = elements;
let scope = Scope{
_marker: PhantomData
};
f(&scope, chunk_size)
}
}
#[derive(Clone)]
pub struct Scope<'a> {
_marker: PhantomData<& 'a usize>
}
impl<'a> Scope<'a> {
pub fn spawn<F, R>(
&self,
f: F
) -> R
where F: FnOnce(&Scope<'a>) -> R
{
f(&self)
}
}
pub struct WorkerFuture<T, E> {
future: CpuFuture<T, E>
}
impl<T: Send + 'static, E: Send + 'static> Future for WorkerFuture<T, E> {
type Item = T;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error>
{
self.future.poll()
}
}

@ -1,4 +1,4 @@
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine};
use std::ops::{Add, Sub, Neg};

@ -1,7 +1,6 @@
extern crate ff;
extern crate pairing;
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine};
use crate::{SynthesisError};

@ -1,4 +1,4 @@
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;

@ -1,4 +1,4 @@
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;
@ -97,7 +97,7 @@ pub fn create_proof_on_srs<E: Engine, C: Circuit<E> + Clone>(
// #[test]
// fn my_fun_circuit_test() {
// use ff::PrimeField;
// use pairing::ff::PrimeField;
// use pairing::bls12_381::{Bls12, Fr};
// use super::*;
// use crate::sonic::cs::{Basic, ConstraintSystem, LinearCombination};

@ -1,4 +1,4 @@
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;
@ -53,7 +53,7 @@ pub fn verify_aggregate<E: Engine, C: Circuit<E> + Clone, R: Rng>(
// #[test]
// fn my_fun_circuit_test() {
// use ff::PrimeField;
// use pairing::ff::PrimeField;
// use pairing::bls12_381::{Bls12, Fr};
// use super::*;
// use crate::sonic::cs::{Basic, ConstraintSystem, LinearCombination};

@ -8,7 +8,7 @@
//! This submodule contains the `Batch` abstraction for creating a
//! context for batch verification.
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine, CurveAffine, CurveProjective};
use crate::SynthesisError;

@ -9,7 +9,7 @@ use pairing::{
CurveAffine
};
use ff::{
use pairing::ff::{
PrimeField,
Field
};
@ -19,7 +19,7 @@ use super::{
VerifyingKey
};
use ::{
use crate::{
SynthesisError,
Circuit,
ConstraintSystem,
@ -32,7 +32,7 @@ use crate::domain::{
Scalar
};
use ::multicore::{
use crate::multicore::{
Worker
};

@ -1,4 +1,4 @@
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;

@ -1,7 +1,6 @@
extern crate ff;
extern crate pairing;
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;

@ -1,4 +1,4 @@
use ff::{
use pairing::ff::{
Field,
PrimeField,
PrimeFieldRepr
@ -10,11 +10,11 @@ use pairing::{
EncodedPoint
};
use ::{
use crate::{
SynthesisError
};
use multiexp::SourceBuilder;
use crate::source::SourceBuilder;
use std::io::{self, Read, Write};
use std::sync::Arc;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
@ -64,7 +64,7 @@ impl<E: Engine> Proof<E> {
mut writer: W
) -> io::Result<()>
{
use ff::{PrimeField, PrimeFieldRepr};
use pairing::ff::{PrimeField, PrimeFieldRepr};
writer.write_all(self.r.into_compressed().as_ref())?;
writer.write_all(self.t.into_compressed().as_ref())?;
let mut buffer = vec![];

@ -1,4 +1,4 @@
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;

@ -1,4 +1,4 @@
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;
@ -397,7 +397,7 @@ pub fn create_proof_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
#[test]
fn my_fun_circuit_test() {
use ff::PrimeField;
use pairing::ff::PrimeField;
use pairing::bls12_381::{Bls12, Fr};
use super::*;
use crate::sonic::cs::{Basic, ConstraintSystem, LinearCombination};
@ -449,8 +449,8 @@ fn my_fun_circuit_test() {
#[test]
fn polynomial_commitment_test() {
use ff::PrimeField;
use ff::PrimeFieldRepr;
use pairing::ff::PrimeField;
use pairing::ff::PrimeFieldRepr;
use pairing::bls12_381::{Bls12, Fr};
use super::*;
use crate::sonic::cs::{Basic, ConstraintSystem, LinearCombination};

@ -1,4 +1,4 @@
use ff::{Field};
use pairing::ff::{Field};
use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;
use rand::{Rand, Rng};

@ -1,4 +1,3 @@
extern crate ff;
extern crate pairing;
pub use crate::{SynthesisError};

@ -1,8 +1,7 @@
extern crate ff;
extern crate pairing;
extern crate rand;
use ff::{Field, PrimeField};
use pairing::ff::{Field, PrimeField};
use pairing::{Engine, CurveProjective};
// this one is for all external interfaces

@ -1,4 +1,3 @@
extern crate ff;
extern crate pairing;
mod adaptor;

@ -1,4 +1,3 @@
extern crate ff;
extern crate pairing;
mod srs;

@ -1,4 +1,4 @@
use ff::{Field, PrimeField};
use pairing::ff::{Field, PrimeField};
use pairing::{CurveAffine, CurveProjective, Engine, Wnaf};
use std::io::{self, Read, Write};

@ -1,7 +1,6 @@
extern crate ff;
extern crate pairing;
use ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::{CurveAffine, CurveProjective, Engine};
use std::io;

@ -2,7 +2,7 @@
/// in those two polynomials are equal (part of the permutation argument) with additional assumption that
/// those coefficients are never equal to zero
use ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::{Engine, CurveProjective, CurveAffine};
use std::marker::PhantomData;

@ -2,7 +2,7 @@
/// actually a commitment to a vector of values that are equal to `(s^{perm})_i * y^{perm(i)}`
/// for some fixed permutation `perm`
use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine};
use pairing::ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine};
use pairing::{Engine, CurveProjective, CurveAffine};
use std::marker::PhantomData;

@ -1,4 +1,4 @@
use ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::{Engine, CurveProjective, CurveAffine};
use std::marker::PhantomData;

@ -1,7 +1,7 @@
/// Wellformedness argument allows to verify that some committment was to multivariate polynomial of degree n,
/// with no constant term and negative powers
use ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::{Engine, CurveProjective, CurveAffine};
use std::marker::PhantomData;

@ -1,5 +1,5 @@
use crate::SynthesisError;
use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine};
use pairing::ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine};
use pairing::{CurveAffine, CurveProjective, Engine};
use super::srs::SRS;
@ -437,7 +437,7 @@ pub fn check_polynomial_commitment<E: Engine>(
#[test]
fn laurent_division() {
use ff::PrimeField;
use pairing::ff::PrimeField;
use pairing::bls12_381::{Fr};
let mut poly = vec![

@ -4,7 +4,7 @@ use pairing::{
Engine
};
use ff::{
use pairing::ff::{
PrimeField,
Field,
PrimeFieldRepr,

@ -6,7 +6,7 @@ use pairing::{
EncodedPoint
};
use ff::{
use pairing::ff::{
PrimeField,
PrimeFieldRepr,
Field,

@ -2,7 +2,7 @@ use pairing::{
Engine
};
use ff:: {
use pairing::ff:: {
Field,
PrimeField,
};
@ -12,7 +12,7 @@ use self::dummy_engine::*;
use std::marker::PhantomData;
use ::{
use crate::{
Circuit,
ConstraintSystem,
SynthesisError

@ -1,7 +1,6 @@
extern crate bellman;
extern crate pairing;
extern crate rand;
extern crate ff;
// For randomness (during paramgen and proof generation)
use rand::{thread_rng, Rng};
@ -14,7 +13,7 @@ use pairing::{
Engine
};
use ff::{
use pairing::ff::{
Field,
};
@ -442,7 +441,7 @@ impl<'a, E: Engine> Circuit<E> for MiMCDemoNoInputs<'a, E> {
#[test]
fn test_sonic_mimc() {
use ff::{Field, PrimeField};
use pairing::ff::{Field, PrimeField};
use pairing::{Engine, CurveAffine, CurveProjective};
use pairing::bls12_381::{Bls12, Fr};
use std::time::{Instant};
@ -546,7 +545,7 @@ fn test_sonic_mimc() {
#[test]
fn test_inputs_into_sonic_mimc() {
use ff::{Field, PrimeField};
use pairing::ff::{Field, PrimeField};
use pairing::{Engine, CurveAffine, CurveProjective};
use pairing::bn256::{Bn256, Fr};
// use pairing::bls12_381::{Bls12, Fr};