diff --git a/Cargo.toml b/Cargo.toml index 761c6c5..43d1f21 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] diff --git a/src/cs.rs b/src/cs.rs new file mode 100644 index 0000000..a84e606 --- /dev/null +++ b/src/cs.rs @@ -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 { + /// 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(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(pub(crate) 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: Engine> 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: Engine> 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: Engine> 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: Engine> 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 auxillary 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 => "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: 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: Engine, CS: ConstraintSystem + 'a>(&'a mut CS, PhantomData); + +impl<'cs, E: Engine, 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: Engine, 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: Engine, 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() + } +} \ No newline at end of file diff --git a/src/domain.rs b/src/domain.rs index 1d0203a..9622219 100644 --- a/src/domain.rs +++ b/src/domain.rs @@ -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> { coeffs: Vec, exp: u32, @@ -55,7 +51,7 @@ impl> EvaluationDomain { pub fn from_coeffs(mut coeffs: Vec) -> Result, 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> EvaluationDomain { // 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, size: usize) -> Result, SynthesisError> { - use ff::PrimeField; + use pairing::ff::PrimeField; // Compute the size of our evaluation domain assert!(size >= coeffs.len()); @@ -264,6 +260,121 @@ impl> EvaluationDomain { } } +pub(crate) fn best_fft>(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>(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>( + 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] diff --git a/src/gm17/generator.rs b/src/gm17/generator.rs index 059a041..320ab07 100644 --- a/src/gm17/generator.rs +++ b/src/gm17/generator.rs @@ -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 }; diff --git a/src/gm17/mod.rs b/src/gm17/mod.rs index b8c5b7f..aee5de6 100644 --- a/src/gm17/mod.rs +++ b/src/gm17/mod.rs @@ -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 PartialEq for Parameters { // use {Circuit, SynthesisError, ConstraintSystem}; // use rand::{Rand, thread_rng}; -// use ff::{Field}; +// use pairing::ff::{Field}; // use pairing::bls12_381::{Bls12, Fr}; // #[test] diff --git a/src/gm17/tests/mod.rs b/src/gm17/tests/mod.rs index 4440b19..ee34ec6 100644 --- a/src/gm17/tests/mod.rs +++ b/src/gm17/tests/mod.rs @@ -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 diff --git a/src/groth16/generator.rs b/src/groth16/generator.rs index 0d597a6..3d4cb1f 100644 --- a/src/groth16/generator.rs +++ b/src/groth16/generator.rs @@ -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 }; diff --git a/src/groth16/mod.rs b/src/groth16/mod.rs index 7dcc8ab..14fb642 100644 --- a/src/groth16/mod.rs +++ b/src/groth16/mod.rs @@ -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 for &'a Parameters { #[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] diff --git a/src/groth16/prover.rs b/src/groth16/prover.rs index 98f2b62..f66e251 100644 --- a/src/groth16/prover.rs +++ b/src/groth16/prover.rs @@ -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 }; diff --git a/src/groth16/tests/mod.rs b/src/groth16/tests/mod.rs index 5a2bb2c..7442501 100644 --- a/src/groth16/tests/mod.rs +++ b/src/groth16/tests/mod.rs @@ -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 diff --git a/src/groth16/verifier.rs b/src/groth16/verifier.rs index 6d30915..ad1c210 100644 --- a/src/groth16/verifier.rs +++ b/src/groth16/verifier.rs @@ -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 }; diff --git a/src/group.rs b/src/group.rs index 7b4fe2e..f66b776 100644 --- a/src/group.rs +++ b/src/group.rs @@ -3,7 +3,7 @@ use pairing::{ CurveProjective }; -use ff::{ +use pairing::ff::{ Field, PrimeField }; diff --git a/src/lib.rs b/src/lib.rs index e7f17e3..690219a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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 { - /// Synthesize the circuit into a rank-1 quadratic constraint system - fn synthesize>( - 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(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: Engine> 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: Engine> 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: Engine> 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: Engine> 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 auxillary 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 => "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: 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: Engine, CS: ConstraintSystem + 'a>(&'a mut CS, PhantomData); - -impl<'cs, E: Engine, 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: Engine, 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: Engine, 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() - } -} +mod cs; +pub use self::cs::*; static mut VERBOSE_SWITCH: i8 = -1; diff --git a/src/multicore.rs b/src/multicore.rs index 84055d7..bb113c6 100644 --- a/src/multicore.rs +++ b/src/multicore.rs @@ -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 { diff --git a/src/parallel_multiexp.rs b/src/multiexp.rs similarity index 93% rename from src/parallel_multiexp.rs rename to src/multiexp.rs index 8b3d3bb..1e114d9 100644 --- a/src/parallel_multiexp.rs +++ b/src/multiexp.rs @@ -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( handle_trivial: bool ) -> Result<::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 = ::Projective::zero(); + let mut handles = vec![]; + let mut this_acc = ::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![::Projective::zero(); (1 << c) - 1]; // Accumulate the result @@ -265,32 +262,32 @@ fn dense_multiexp_inner( } // 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 = ::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 = ::Projective::zero(); + // loop { + // if r.is_empty() { + // break; + // } + // let value = r.recv().expect("must have value"); + // this_region.add_assign(&value); + // } this_region }; diff --git a/src/parallel_fft.rs b/src/parallel_fft.rs deleted file mode 100644 index 687d146..0000000 --- a/src/parallel_fft.rs +++ /dev/null @@ -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>(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>(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>( - 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; - } - }); - } - }); -} \ No newline at end of file diff --git a/src/serial_fft.rs b/src/serial_fft.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/serial_multiexp.rs b/src/serial_multiexp.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/singlecore.rs b/src/singlecore.rs new file mode 100644 index 0000000..e669ac6 --- /dev/null +++ b/src/singlecore.rs @@ -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( + &self, f: F + ) -> WorkerFuture + 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( + &self, + f: F + ) -> R + where F: FnOnce(&Scope<'a>) -> R + { + f(&self) + } +} + +pub struct WorkerFuture { + future: CpuFuture +} + +impl Future for WorkerFuture { + type Item = T; + type Error = E; + + fn poll(&mut self) -> Poll + { + self.future.poll() + } +} \ No newline at end of file diff --git a/src/sonic/cs/lc.rs b/src/sonic/cs/lc.rs index 806eb61..8730473 100644 --- a/src/sonic/cs/lc.rs +++ b/src/sonic/cs/lc.rs @@ -1,4 +1,4 @@ -use ff::{Field}; +use pairing::ff::{Field}; use pairing::{Engine}; use std::ops::{Add, Sub, Neg}; diff --git a/src/sonic/cs/mod.rs b/src/sonic/cs/mod.rs index a2069e3..0a42dfa 100644 --- a/src/sonic/cs/mod.rs +++ b/src/sonic/cs/mod.rs @@ -1,7 +1,6 @@ -extern crate ff; extern crate pairing; -use ff::{Field}; +use pairing::ff::{Field}; use pairing::{Engine}; use crate::{SynthesisError}; diff --git a/src/sonic/helped/adapted_helper.rs b/src/sonic/helped/adapted_helper.rs index 87e99da..0243298 100644 --- a/src/sonic/helped/adapted_helper.rs +++ b/src/sonic/helped/adapted_helper.rs @@ -1,4 +1,4 @@ -use ff::{Field}; +use pairing::ff::{Field}; use pairing::{Engine, CurveProjective}; use std::marker::PhantomData; diff --git a/src/sonic/helped/adapted_prover.rs b/src/sonic/helped/adapted_prover.rs index 2811db4..68f9565 100644 --- a/src/sonic/helped/adapted_prover.rs +++ b/src/sonic/helped/adapted_prover.rs @@ -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 + 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}; diff --git a/src/sonic/helped/adapted_verifier.rs b/src/sonic/helped/adapted_verifier.rs index 0c4b0c8..0a4b159 100644 --- a/src/sonic/helped/adapted_verifier.rs +++ b/src/sonic/helped/adapted_verifier.rs @@ -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 + 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}; diff --git a/src/sonic/helped/batch.rs b/src/sonic/helped/batch.rs index 9af97c2..3cec29c 100644 --- a/src/sonic/helped/batch.rs +++ b/src/sonic/helped/batch.rs @@ -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; diff --git a/src/sonic/helped/generator.rs b/src/sonic/helped/generator.rs index a1fb6de..652c501 100644 --- a/src/sonic/helped/generator.rs +++ b/src/sonic/helped/generator.rs @@ -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 }; diff --git a/src/sonic/helped/helper.rs b/src/sonic/helped/helper.rs index 5b11f11..a8a853a 100644 --- a/src/sonic/helped/helper.rs +++ b/src/sonic/helped/helper.rs @@ -1,4 +1,4 @@ -use ff::{Field}; +use pairing::ff::{Field}; use pairing::{Engine, CurveProjective}; use std::marker::PhantomData; diff --git a/src/sonic/helped/mod.rs b/src/sonic/helped/mod.rs index 3a0be60..0135b66 100644 --- a/src/sonic/helped/mod.rs +++ b/src/sonic/helped/mod.rs @@ -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; diff --git a/src/sonic/helped/parameters.rs b/src/sonic/helped/parameters.rs index 488c186..2e000e6 100644 --- a/src/sonic/helped/parameters.rs +++ b/src/sonic/helped/parameters.rs @@ -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 Proof { 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![]; diff --git a/src/sonic/helped/poly.rs b/src/sonic/helped/poly.rs index 6001061..22ce7e7 100644 --- a/src/sonic/helped/poly.rs +++ b/src/sonic/helped/poly.rs @@ -1,4 +1,4 @@ -use ff::{Field}; +use pairing::ff::{Field}; use pairing::{Engine, CurveProjective}; use std::marker::PhantomData; diff --git a/src/sonic/helped/prover.rs b/src/sonic/helped/prover.rs index 79cc0ec..f3f4645 100644 --- a/src/sonic/helped/prover.rs +++ b/src/sonic/helped/prover.rs @@ -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, 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}; diff --git a/src/sonic/helped/verifier.rs b/src/sonic/helped/verifier.rs index 2bded1b..9a520b7 100644 --- a/src/sonic/helped/verifier.rs +++ b/src/sonic/helped/verifier.rs @@ -1,4 +1,4 @@ -use ff::{Field}; +use pairing::ff::{Field}; use pairing::{Engine, CurveProjective}; use std::marker::PhantomData; use rand::{Rand, Rng}; diff --git a/src/sonic/mod.rs b/src/sonic/mod.rs index 6786a7f..2241a62 100644 --- a/src/sonic/mod.rs +++ b/src/sonic/mod.rs @@ -1,4 +1,3 @@ -extern crate ff; extern crate pairing; pub use crate::{SynthesisError}; diff --git a/src/sonic/sonic/adaptor.rs b/src/sonic/sonic/adaptor.rs index f38eaed..87cd9e7 100644 --- a/src/sonic/sonic/adaptor.rs +++ b/src/sonic/sonic/adaptor.rs @@ -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 diff --git a/src/sonic/sonic/mod.rs b/src/sonic/sonic/mod.rs index 8b3e220..aa16edb 100644 --- a/src/sonic/sonic/mod.rs +++ b/src/sonic/sonic/mod.rs @@ -1,4 +1,3 @@ -extern crate ff; extern crate pairing; mod adaptor; diff --git a/src/sonic/srs/mod.rs b/src/sonic/srs/mod.rs index d2eae6e..e93d24f 100644 --- a/src/sonic/srs/mod.rs +++ b/src/sonic/srs/mod.rs @@ -1,4 +1,3 @@ -extern crate ff; extern crate pairing; mod srs; diff --git a/src/sonic/srs/srs.rs b/src/sonic/srs/srs.rs index b8d5831..7833ab8 100644 --- a/src/sonic/srs/srs.rs +++ b/src/sonic/srs/srs.rs @@ -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}; diff --git a/src/sonic/transcript/mod.rs b/src/sonic/transcript/mod.rs index fc5035f..4525030 100644 --- a/src/sonic/transcript/mod.rs +++ b/src/sonic/transcript/mod.rs @@ -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; diff --git a/src/sonic/unhelped/grand_product_argument.rs b/src/sonic/unhelped/grand_product_argument.rs index dad9505..61c914d 100644 --- a/src/sonic/unhelped/grand_product_argument.rs +++ b/src/sonic/unhelped/grand_product_argument.rs @@ -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; diff --git a/src/sonic/unhelped/permutation_argument.rs b/src/sonic/unhelped/permutation_argument.rs index 96c6039..1813ae6 100644 --- a/src/sonic/unhelped/permutation_argument.rs +++ b/src/sonic/unhelped/permutation_argument.rs @@ -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; diff --git a/src/sonic/unhelped/s2_proof.rs b/src/sonic/unhelped/s2_proof.rs index 72f9eb7..77bb8a8 100644 --- a/src/sonic/unhelped/s2_proof.rs +++ b/src/sonic/unhelped/s2_proof.rs @@ -1,4 +1,4 @@ -use ff::{Field, PrimeField, PrimeFieldRepr}; +use pairing::ff::{Field, PrimeField, PrimeFieldRepr}; use pairing::{Engine, CurveProjective, CurveAffine}; use std::marker::PhantomData; diff --git a/src/sonic/unhelped/wellformed_argument.rs b/src/sonic/unhelped/wellformed_argument.rs index 5e707f1..a321278 100644 --- a/src/sonic/unhelped/wellformed_argument.rs +++ b/src/sonic/unhelped/wellformed_argument.rs @@ -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; diff --git a/src/sonic/util.rs b/src/sonic/util.rs index 9e9f6b1..9f3e055 100644 --- a/src/sonic/util.rs +++ b/src/sonic/util.rs @@ -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( #[test] fn laurent_division() { - use ff::PrimeField; + use pairing::ff::PrimeField; use pairing::bls12_381::{Fr}; let mut poly = vec![ diff --git a/src/source.rs b/src/source.rs index 5a77d8f..8fa8a94 100644 --- a/src/source.rs +++ b/src/source.rs @@ -4,7 +4,7 @@ use pairing::{ Engine }; -use ff::{ +use pairing::ff::{ PrimeField, Field, PrimeFieldRepr, diff --git a/src/tests/dummy_engine.rs b/src/tests/dummy_engine.rs index a436533..0cc5cdc 100644 --- a/src/tests/dummy_engine.rs +++ b/src/tests/dummy_engine.rs @@ -6,7 +6,7 @@ use pairing::{ EncodedPoint }; -use ff::{ +use pairing::ff::{ PrimeField, PrimeFieldRepr, Field, diff --git a/src/tests/mod.rs b/src/tests/mod.rs index f9f6ce9..e72f954 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -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 diff --git a/tests/mimc.rs b/tests/mimc.rs index c0dce24..9446145 100644 --- a/tests/mimc.rs +++ b/tests/mimc.rs @@ -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 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};