continue to integrate helped SONIC. Now only verifier left

This commit is contained in:
Alex Vlasov 2019-02-10 01:36:40 +03:00
parent 614d486b99
commit 3f766246de
20 changed files with 947 additions and 630 deletions

@ -30,3 +30,5 @@ rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
[features]
default = []
singlecore = []

@ -24,7 +24,12 @@ use super::{
SynthesisError
};
use super::multicore::Worker;
pub use super::group::*;
#[feature(not(singlecore))]
use super::parallel_fft::*;
pub struct EvaluationDomain<E: Engine, G: Group<E>> {
coeffs: Vec<G>,
@ -149,6 +154,7 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
})
}
pub fn fft(&mut self, worker: &Worker)
{
best_fft(&mut self.coeffs, worker, &self.omega, self.exp);
@ -258,190 +264,6 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
}
}
pub trait Group<E: Engine>: Sized + Copy + Clone + Send + Sync {
fn group_zero() -> Self;
fn group_mul_assign(&mut self, by: &E::Fr);
fn group_add_assign(&mut self, other: &Self);
fn group_sub_assign(&mut self, other: &Self);
}
pub struct Point<G: CurveProjective>(pub G);
impl<G: CurveProjective> PartialEq for Point<G> {
fn eq(&self, other: &Point<G>) -> bool {
self.0 == other.0
}
}
impl<G: CurveProjective> Copy for Point<G> { }
impl<G: CurveProjective> Clone for Point<G> {
fn clone(&self) -> Point<G> {
*self
}
}
impl<G: CurveProjective> Group<G::Engine> for Point<G> {
fn group_zero() -> Self {
Point(G::zero())
}
fn group_mul_assign(&mut self, by: &G::Scalar) {
self.0.mul_assign(by.into_repr());
}
fn group_add_assign(&mut self, other: &Self) {
self.0.add_assign(&other.0);
}
fn group_sub_assign(&mut self, other: &Self) {
self.0.sub_assign(&other.0);
}
}
pub struct Scalar<E: Engine>(pub E::Fr);
impl<E: Engine> PartialEq for Scalar<E> {
fn eq(&self, other: &Scalar<E>) -> bool {
self.0 == other.0
}
}
impl<E: Engine> Copy for Scalar<E> { }
impl<E: Engine> Clone for Scalar<E> {
fn clone(&self) -> Scalar<E> {
*self
}
}
impl<E: Engine> Group<E> for Scalar<E> {
fn group_zero() -> Self {
Scalar(E::Fr::zero())
}
fn group_mul_assign(&mut self, by: &E::Fr) {
self.0.mul_assign(by);
}
fn group_add_assign(&mut self, other: &Self) {
self.0.add_assign(&other.0);
}
fn group_sub_assign(&mut self, other: &Self) {
self.0.sub_assign(&other.0);
}
}
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]

82
src/group.rs Normal file

@ -0,0 +1,82 @@
use pairing::{
Engine,
CurveProjective
};
use ff::{
Field,
PrimeField
};
use super::{
SynthesisError
};
pub trait Group<E: Engine>: Sized + Copy + Clone + Send + Sync {
fn group_zero() -> Self;
fn group_mul_assign(&mut self, by: &E::Fr);
fn group_add_assign(&mut self, other: &Self);
fn group_sub_assign(&mut self, other: &Self);
}
pub struct Point<G: CurveProjective>(pub G);
impl<G: CurveProjective> PartialEq for Point<G> {
fn eq(&self, other: &Point<G>) -> bool {
self.0 == other.0
}
}
impl<G: CurveProjective> Copy for Point<G> { }
impl<G: CurveProjective> Clone for Point<G> {
fn clone(&self) -> Point<G> {
*self
}
}
impl<G: CurveProjective> Group<G::Engine> for Point<G> {
fn group_zero() -> Self {
Point(G::zero())
}
fn group_mul_assign(&mut self, by: &G::Scalar) {
self.0.mul_assign(by.into_repr());
}
fn group_add_assign(&mut self, other: &Self) {
self.0.add_assign(&other.0);
}
fn group_sub_assign(&mut self, other: &Self) {
self.0.sub_assign(&other.0);
}
}
pub struct Scalar<E: Engine>(pub E::Fr);
impl<E: Engine> PartialEq for Scalar<E> {
fn eq(&self, other: &Scalar<E>) -> bool {
self.0 == other.0
}
}
impl<E: Engine> Copy for Scalar<E> { }
impl<E: Engine> Clone for Scalar<E> {
fn clone(&self) -> Scalar<E> {
*self
}
}
impl<E: Engine> Group<E> for Scalar<E> {
fn group_zero() -> Self {
Scalar(E::Fr::zero())
}
fn group_mul_assign(&mut self, by: &E::Fr) {
self.0.mul_assign(by);
}
fn group_add_assign(&mut self, other: &Self) {
self.0.add_assign(&other.0);
}
fn group_sub_assign(&mut self, other: &Self) {
self.0.sub_assign(&other.0);
}
}

@ -10,13 +10,23 @@ extern crate crossbeam;
extern crate byteorder;
extern crate ff;
pub mod multicore;
mod multiexp;
pub mod domain;
pub mod groth16;
pub mod gm17;
pub mod sonic;
mod group;
mod source;
#[feature(not(singlecore))]
mod parallel_fft;
mod multicore;
mod parallel_multiexp;
#[feature(singlecore)]
mod serial_fft;
mod serial_multiexp;
#[cfg(test)]
mod tests;
@ -29,6 +39,16 @@ use std::error::Error;
use std::io;
use std::marker::PhantomData;
pub mod multiexp {
pub use source::*;
#[feature(not(singlecore))]
pub use parallel_multiexp::*;
#[feature(singlecore)]
pub use serial_multiexp::*;
}
/// 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

@ -35,10 +35,6 @@ impl Worker {
log2_floor(self.cpus)
}
pub(crate) fn num_cpus(&self) -> usize {
self.cpus
}
pub fn compute<F, R>(
&self, f: F
) -> WorkerFuture<R::Item, R::Error>

143
src/parallel_fft.rs Normal file

@ -0,0 +1,143 @@
//! 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;
}
});
}
});
}

@ -11,137 +11,12 @@ use ff::{
ScalarEngine};
use std::sync::Arc;
use std::io;
use bit_vec::{self, BitVec};
use std::iter;
use super::source::*;
use futures::{Future};
use super::multicore::Worker;
use super::SynthesisError;
/// An object that builds a source of bases.
pub trait SourceBuilder<G: CurveAffine>: Send + Sync + 'static + Clone {
type Source: Source<G>;
fn new(self) -> Self::Source;
}
/// A source of bases, like an iterator.
pub trait Source<G: CurveAffine> {
/// Parses the element from the source. Fails if the point is at infinity.
fn add_assign_mixed(&mut self, to: &mut <G as CurveAffine>::Projective) -> Result<(), SynthesisError>;
/// Skips `amt` elements from the source, avoiding deserialization.
fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>;
}
impl<G: CurveAffine> SourceBuilder<G> for (Arc<Vec<G>>, usize) {
type Source = (Arc<Vec<G>>, usize);
fn new(self) -> (Arc<Vec<G>>, usize) {
(self.0.clone(), self.1)
}
}
impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
fn add_assign_mixed(&mut self, to: &mut <G as CurveAffine>::Projective) -> Result<(), SynthesisError> {
if self.0.len() <= self.1 {
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases when adding from source").into());
}
if self.0[self.1].is_zero() {
return Err(SynthesisError::UnexpectedIdentity)
}
to.add_assign_mixed(&self.0[self.1]);
self.1 += 1;
Ok(())
}
fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> {
if self.0.len() <= self.1 {
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases skipping from source").into());
}
self.1 += amt;
Ok(())
}
}
pub trait QueryDensity {
/// Returns whether the base exists.
type Iter: Iterator<Item=bool>;
fn iter(self) -> Self::Iter;
fn get_query_size(self) -> Option<usize>;
}
#[derive(Clone)]
pub struct FullDensity;
impl AsRef<FullDensity> for FullDensity {
fn as_ref(&self) -> &FullDensity {
self
}
}
impl<'a> QueryDensity for &'a FullDensity {
type Iter = iter::Repeat<bool>;
fn iter(self) -> Self::Iter {
iter::repeat(true)
}
fn get_query_size(self) -> Option<usize> {
None
}
}
#[derive(Clone)]
pub struct DensityTracker {
bv: BitVec,
total_density: usize
}
impl<'a> QueryDensity for &'a DensityTracker {
type Iter = bit_vec::Iter<'a>;
fn iter(self) -> Self::Iter {
self.bv.iter()
}
fn get_query_size(self) -> Option<usize> {
Some(self.bv.len())
}
}
impl DensityTracker {
pub fn new() -> DensityTracker {
DensityTracker {
bv: BitVec::new(),
total_density: 0
}
}
pub fn add_element(&mut self) {
self.bv.push(false);
}
pub fn inc(&mut self, idx: usize) {
if !self.bv.get(idx).unwrap() {
self.bv.set(idx, true);
self.total_density += 1;
}
}
pub fn get_total_density(&self) -> usize {
self.total_density
}
}
/// This genious piece of code works in the following way:
/// - choose `c` - the bit length of the region that one thread works on
/// - make `2^c - 1` buckets and initialize them with `G = infinity` (that's equivalent of zero)
@ -307,6 +182,114 @@ pub fn multiexp<Q, D, G, S>(
multiexp_inner(pool, bases, density_map, exponents, 0, c, true)
}
/// Perform multi-exponentiation. The caller is responsible for ensuring that
/// the number of bases is the same as the number of exponents.
pub fn dense_multiexp<G: CurveAffine>(
pool: &Worker,
bases: & [G],
exponents: & [<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr]
) -> Result<<G as CurveAffine>::Projective, SynthesisError>
{
if exponents.len() != bases.len() {
return Err(SynthesisError::AssignmentMissing);
}
let c = if exponents.len() < 32 {
3u32
} else {
(f64::from(exponents.len() as u32)).ln().ceil() as u32
};
dense_multiexp_inner(pool, bases, exponents, 0, c, true)
}
fn dense_multiexp_inner<G: CurveAffine>(
pool: &Worker,
bases: & [G],
exponents: & [<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr],
mut skip: u32,
c: u32,
handle_trivial: bool
) -> Result<<G as CurveAffine>::Projective, SynthesisError>
{
// 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 this_region = pool.scope(bases.len(), |scope, chunk| {
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 handle = scope.spawn(move |_| {
let mut buckets = vec![<G as CurveAffine>::Projective::zero(); (1 << c) - 1];
// Accumulate the result
let mut acc = G::Projective::zero();
let zero = <G::Engine as ScalarEngine>::Fr::zero().into_repr();
let one = <G::Engine as ScalarEngine>::Fr::one().into_repr();
for (base, &exp) in base.iter().zip(exp.iter()) {
if exp != zero {
if exp == one {
if handle_trivial {
acc.add_assign_mixed(base);
}
} else {
let mut exp = exp;
exp.shr(skip);
let exp = exp.as_ref()[0] % (1 << c);
if exp != 0 {
buckets[(exp - 1) as usize].add_assign_mixed(base);
}
}
}
}
// buckets are filled with the corresponding accumulated value, now sum
let mut running_sum = G::Projective::zero();
for exp in buckets.into_iter().rev() {
running_sum.add_assign(&exp);
acc.add_assign(&running_sum);
}
// acc contains values over this region
acc
});
handles.push(handle);
}
// wait for all threads to finish
for r in handles.into_iter().rev() {
let thread_result = r.join().unwrap();
this_acc.add_assign(&thread_result);
}
this_acc
});
this_region
};
skip += c;
if skip >= <G::Engine as ScalarEngine>::Fr::NUM_BITS {
// There isn't another region, and this will be the highest region
return Ok(this);
} else {
// next region is actually higher than this one, so double it enough times
let mut next_region = dense_multiexp_inner(
pool, bases, exponents, skip, c, false).unwrap();
for _ in 0..c {
next_region.double();
}
next_region.add_assign(&this);
return Ok(next_region);
}
}
#[test]
fn test_with_bls12() {
fn naive_multiexp<G: CurveAffine>(
@ -378,3 +361,41 @@ fn test_speed_with_bn256() {
let time_per_sample = duration_ns/(SAMPLES as f64);
println!("Tested on {} samples on {} CPUs with {} ns per multiplication", SAMPLES, cpus, time_per_sample);
}
#[test]
fn test_dense_multiexp() {
use rand::{self, Rand};
use pairing::bn256::Bn256;
use num_cpus;
const SAMPLES: usize = 1 << 22;
let rng = &mut rand::thread_rng();
let v = (0..SAMPLES).map(|_| <Bn256 as ScalarEngine>::Fr::rand(rng).into_repr()).collect::<Vec<_>>();
let g = (0..SAMPLES).map(|_| <Bn256 as Engine>::G1::rand(rng).into_affine()).collect::<Vec<_>>();
let pool = Worker::new();
let start = std::time::Instant::now();
let dense = dense_multiexp(
&pool, &g, &v).unwrap();
let duration_ns = start.elapsed().as_nanos() as f64;
println!("{} ns for dense for {} samples", duration_ns, SAMPLES);
let start = std::time::Instant::now();
let sparse = multiexp(
&pool,
(Arc::new(g), 0),
FullDensity,
Arc::new(v)
).wait().unwrap();
let duration_ns = start.elapsed().as_nanos() as f64;
println!("{} ns for sparse for {} samples", duration_ns, SAMPLES);
assert_eq!(dense, sparse);
}

0
src/serial_fft.rs Normal file

0
src/serial_multiexp.rs Normal file

@ -217,3 +217,111 @@ impl SynthesisDriver for Basic {
Ok(())
}
}
pub struct Nonassigning;
impl SynthesisDriver for Nonassigning {
fn synthesize<E: Engine, C: Circuit<E>, B: Backend<E>>(backend: B, circuit: &C) -> Result<(), SynthesisError> {
struct NonassigningSynthesizer<E: Engine, B: Backend<E>> {
backend: B,
current_variable: Option<usize>,
_marker: PhantomData<E>,
q: usize,
n: usize,
}
impl<E: Engine, B: Backend<E>> ConstraintSystem<E> for NonassigningSynthesizer<E, B> {
const ONE: Variable = Variable::A(1);
fn alloc<F>(&mut self, _value: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>
{
match self.current_variable.take() {
Some(index) => {
let var_b = Variable::B(index);
self.current_variable = None;
Ok(var_b)
},
None => {
self.n += 1;
let index = self.n;
self.backend.new_multiplication_gate();
let var_a = Variable::A(index);
self.current_variable = Some(index);
Ok(var_a)
}
}
}
fn alloc_input<F>(&mut self, value: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>
{
let input_var = self.alloc(value)?;
self.enforce_zero(LinearCombination::zero() + input_var);
self.backend.new_k_power(self.q);
Ok(input_var)
}
fn enforce_zero(&mut self, lc: LinearCombination<E>)
{
self.q += 1;
self.backend.new_linear_constraint();
for (var, coeff) in lc.as_ref() {
self.backend.insert_coefficient(*var, *coeff);
}
}
fn multiply<F>(&mut self, _values: F) -> Result<(Variable, Variable, Variable), SynthesisError>
where
F: FnOnce() -> Result<(E::Fr, E::Fr, E::Fr), SynthesisError>
{
self.n += 1;
let index = self.n;
self.backend.new_multiplication_gate();
let a = Variable::A(index);
let b = Variable::B(index);
let c = Variable::C(index);
Ok((a, b, c))
}
fn get_value(&self, var: Variable) -> Result<E::Fr, ()> {
self.backend.get_var(var).ok_or(())
}
}
let mut tmp: NonassigningSynthesizer<E, B> = NonassigningSynthesizer {
backend: backend,
current_variable: None,
_marker: PhantomData,
q: 0,
n: 0,
};
let one = tmp.alloc_input(|| Ok(E::Fr::one())).expect("should have no issues");
match (one, <NonassigningSynthesizer<E, B> as ConstraintSystem<E>>::ONE) {
(Variable::A(1), Variable::A(1)) => {},
_ => panic!("one variable is incorrect")
}
circuit.synthesize(&mut tmp)?;
// TODO: add blinding factors so we actually get zero-knowledge
// println!("n = {}", tmp.n);
Ok(())
}
}

@ -0,0 +1,146 @@
use ff::{Field};
use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;
use super::{Proof, SxyAdvice};
use super::batch::Batch;
use super::poly::{SxEval, SyEval};
use super::parameters::{Parameters};
use crate::SynthesisError;
use crate::sonic::transcript::{Transcript, TranscriptProtocol};
use crate::sonic::util::*;
use crate::sonic::cs::{Backend, SynthesisDriver};
use crate::{Circuit};
use crate::sonic::sonic::AdaptorCircuit;
use crate::sonic::srs::SRS;
use crate::sonic::cs::Basic;
use super::prover::create_advice as create_advice_sonic_circuit;
use super::prover::create_advice_on_information_and_srs as create_advice_on_information_and_srs_sonic_circuit;
use super::prover::create_proof_on_srs as create_proof_on_srs_sonic_circuit;
// pub fn create_advice_on_information_and_srs<E: Engine, C: Circuit<E> + Clone, S: SynthesisDriver>(
pub fn create_advice_on_information_and_srs<E: Engine, C: Circuit<E> + Clone>(
circuit: C,
proof: &Proof<E>,
srs: &SRS<E>,
n: usize
) -> Result<SxyAdvice<E>, SynthesisError>
{
let adapted_circuit = AdaptorCircuit(circuit);
create_advice_on_information_and_srs_sonic_circuit::<_, _, Basic>(&adapted_circuit, proof, srs, n)
}
// pub fn create_advice<E: Engine, C: Circuit<E> + Clone, S: SynthesisDriver>(
pub fn create_advice<E: Engine, C: Circuit<E> + Clone>(
circuit: C,
proof: &Proof<E>,
parameters: &Parameters<E>,
) -> Result<SxyAdvice<E>, SynthesisError>
{
let n = parameters.vk.n;
create_advice_on_information_and_srs::<E, C>(circuit, proof, &parameters.srs, n)
}
// pub fn create_advice_on_srs<E: Engine, C: Circuit<E> + Clone, S: SynthesisDriver>(
pub fn create_advice_on_srs<E: Engine, C: Circuit<E> + Clone>(
circuit: C,
proof: &Proof<E>,
srs: &SRS<E>
) -> Result<SxyAdvice<E>, SynthesisError>
{
use crate::sonic::cs::Nonassigning;
let adapted_circuit = AdaptorCircuit(circuit.clone());
// annoying, but we need n to compute s(z, y), and this isn't
// precomputed anywhere yet
let n = {
struct CountN {
n: usize
}
impl<'a, E: Engine> Backend<E> for &'a mut CountN {
fn new_multiplication_gate(&mut self) {
self.n += 1;
}
}
let mut tmp = CountN{n:0};
Nonassigning::synthesize(&mut tmp, &adapted_circuit)?;
tmp.n
};
create_advice_on_information_and_srs::<E, C>(circuit, proof, srs, n)
}
// pub fn create_proof<E: Engine, C: Circuit<E> + Clone, S: SynthesisDriver>(
pub fn create_proof<E: Engine, C: Circuit<E> + Clone>(
circuit: C,
parameters: &Parameters<E>
) -> Result<Proof<E>, SynthesisError> {
create_proof_on_srs::<E, C>(circuit, &parameters.srs)
}
// pub fn create_proof_on_srs<E: Engine, C: Circuit<E> + Clone, S: SynthesisDriver>(
pub fn create_proof_on_srs<E: Engine, C: Circuit<E> + Clone>(
circuit: C,
srs: &SRS<E>
) -> Result<Proof<E>, SynthesisError>
{
let adapted_circuit = AdaptorCircuit(circuit);
create_proof_on_srs_sonic_circuit::<_, _, Basic>(&adapted_circuit, srs)
}
// #[test]
// fn my_fun_circuit_test() {
// use ff::PrimeField;
// use pairing::bls12_381::{Bls12, Fr};
// use super::*;
// use crate::sonic::cs::{Basic, ConstraintSystem, LinearCombination};
// struct MyCircuit;
// impl<E: Engine> Circuit<E> for MyCircuit {
// fn synthesize<CS: ConstraintSystem<E>>(&self, cs: &mut CS) -> Result<(), SynthesisError> {
// let (a, b, _) = cs.multiply(|| {
// Ok((
// E::Fr::from_str("10").unwrap(),
// E::Fr::from_str("20").unwrap(),
// E::Fr::from_str("200").unwrap(),
// ))
// })?;
// cs.enforce_zero(LinearCombination::from(a) + a - b);
// //let multiplier = cs.alloc_input(|| Ok(E::Fr::from_str("20").unwrap()))?;
// //cs.enforce_zero(LinearCombination::from(b) - multiplier);
// Ok(())
// }
// }
// let srs = SRS::<Bls12>::new(
// 20,
// Fr::from_str("22222").unwrap(),
// Fr::from_str("33333333").unwrap(),
// );
// let proof = create_proof_on_srs::<Bls12, _, Basic>(&MyCircuit, &srs).unwrap();
// use std::time::{Instant};
// let start = Instant::now();
// let mut batch = MultiVerifier::<Bls12, _, Basic>::new(MyCircuit, &srs).unwrap();
// for _ in 0..1 {
// batch.add_proof(&proof, &[/*Fr::from_str("20").unwrap()*/], |_, _| None);
// }
// assert!(batch.check_all());
// let elapsed = start.elapsed();
// println!("time to verify: {:?}", elapsed);
// }

@ -689,103 +689,3 @@ pub fn generate_srs<E: Engine>(
}
)
}
#[test]
fn parameters_generation() {
use pairing::bls12_381::{Bls12, Fr};
struct MySillyCircuit<E: Engine> {
a: Option<E::Fr>,
b: Option<E::Fr>
}
impl<E: Engine> Circuit<E> for MySillyCircuit<E> {
fn synthesize<CS: ConstraintSystem<E>>(
self,
cs: &mut CS
) -> Result<(), SynthesisError>
{
let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?;
let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?;
let c = cs.alloc_input(|| "c", || {
let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
a.mul_assign(&b);
Ok(a)
})?;
cs.enforce(
|| "a*b=c",
|lc| lc + a,
|lc| lc + b,
|lc| lc + c
);
Ok(())
}
}
use rand::{Rand, thread_rng};
let info = get_circuit_parameters::<Bls12, _>(MySillyCircuit { a: None, b: None }).expect("Must get circuit info");
println!("{:?}", info);
let rng = &mut thread_rng();
let x: Fr = rng.gen();
let alpha: Fr = rng.gen();
let params = generate_parameters::<Bls12, _>(MySillyCircuit { a: None, b: None }, alpha, x).unwrap();
let srs = generate_srs::<Bls12>(alpha, x, info.n * 100).unwrap();
let naive_srs = SRS::<Bls12>::new(
info.n * 100,
x,
alpha,
);
assert!(srs == naive_srs);
let params_on_srs = generate_parameters_on_srs_and_information::<Bls12>(&srs, info.clone()).unwrap();
assert!(params == params_on_srs);
{
let mut v = vec![];
params.write(&mut v).unwrap();
let de_params = Parameters::read(&v[..], true).unwrap();
assert!(params == de_params);
let de_params = Parameters::read(&v[..], false).unwrap();
assert!(params == de_params);
}
// let pvk = prepare_verifying_key::<Bls12>(&params.vk);
// for _ in 0..100 {
// let a = Fr::rand(rng);
// let b = Fr::rand(rng);
// let mut c = a;
// c.mul_assign(&b);
// let proof = create_random_proof(
// MySillyCircuit {
// a: Some(a),
// b: Some(b)
// },
// &params,
// rng
// ).unwrap();
// let mut v = vec![];
// proof.write(&mut v).unwrap();
// assert_eq!(v.len(), 192);
// let de_proof = Proof::read(&v[..]).unwrap();
// assert!(proof == de_proof);
// assert!(verify_proof(&pvk, &proof, &[c]).unwrap());
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
// }
}

@ -6,22 +6,18 @@ use pairing::{Engine, CurveProjective};
use std::marker::PhantomData;
mod verifier;
mod prover;
mod batch;
mod poly;
mod helper;
mod parameters;
mod generator;
mod adapted_prover;
pub mod prover;
pub use self::batch::{Batch};
pub use self::helper::{Aggregate, create_aggregate};
pub use self::verifier::{MultiVerifier};
pub use self::prover::{
create_advice,
create_advice_on_information_and_srs,
create_advice_on_srs,
create_proof
};
pub use self::generator::{
CircuitParameters,
@ -33,3 +29,10 @@ pub use self::generator::{
get_circuit_parameters
};
pub use self::parameters::{Proof, SxyAdvice, Parameters, VerifyingKey, PreparedVerifyingKey};
pub use self::adapted_prover::{
create_advice,
create_advice_on_srs,
create_advice_on_information_and_srs,
create_proof,
create_proof_on_srs,
};

@ -19,15 +19,23 @@ use std::io::{self, Read, Write};
use std::sync::Arc;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, Eq)]
pub struct SxyAdvice<E: Engine> {
pub s: E::G1Affine,
pub opening: E::G1Affine,
pub szy: E::Fr,
}
impl<E: Engine> PartialEq for SxyAdvice<E> {
fn eq(&self, other: &SxyAdvice<E>) -> bool {
self.s == other.s &&
self.opening == other.opening &&
self.szy == other.szy
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, Eq)]
pub struct Proof<E: Engine> {
pub r: E::G1Affine,
pub t: E::G1Affine,
@ -37,6 +45,17 @@ pub struct Proof<E: Engine> {
pub zy_opening: E::G1Affine
}
impl<E: Engine> PartialEq for Proof<E> {
fn eq(&self, other: &Proof<E>) -> bool {
self.r == other.r &&
self.t == other.t &&
self.rz == other.rz &&
self.rzy == other.rzy &&
self.z_opening == other.z_opening &&
self.zy_opening == other.zy_opening
}
}
impl<E: Engine> Proof<E> {
pub fn write<W: Write>(
&self,
@ -49,6 +68,7 @@ impl<E: Engine> Proof<E> {
let mut buffer = vec![];
self.rz.into_repr().write_be(&mut buffer)?;
writer.write_all(&buffer[..])?;
let mut buffer = vec![];
self.rzy.into_repr().write_be(&mut buffer)?;
writer.write_all(&buffer[..])?;
writer.write_all(self.z_opening.into_compressed().as_ref())?;
@ -362,185 +382,105 @@ impl<E: Engine> Parameters<E> {
}
}
// pub trait ParameterSource<E: Engine> {
// type G1Builder: SourceBuilder<E::G1Affine>;
// type G2Builder: SourceBuilder<E::G2Affine>;
#[test]
fn parameters_generation() {
use crate::{ConstraintSystem, Circuit};
// fn get_vk(
// &mut self,
// num_ic: usize
// ) -> Result<VerifyingKey<E>, SynthesisError>;
// fn get_h(
// &mut self,
// num_h: usize
// ) -> Result<Self::G1Builder, SynthesisError>;
// fn get_l(
// &mut self,
// num_l: usize
// ) -> Result<Self::G1Builder, SynthesisError>;
// fn get_a(
// &mut self,
// num_inputs: usize,
// num_aux: usize
// ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>;
// fn get_b_g1(
// &mut self,
// num_inputs: usize,
// num_aux: usize
// ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>;
// fn get_b_g2(
// &mut self,
// num_inputs: usize,
// num_aux: usize
// ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>;
// }
use pairing::bls12_381::{Bls12, Fr};
// impl<'a, E: Engine> ParameterSource<E> for &'a Parameters<E> {
// type G1Builder = (Arc<Vec<E::G1Affine>>, usize);
// type G2Builder = (Arc<Vec<E::G2Affine>>, usize);
#[derive(Clone)]
struct MySillyCircuit<E: Engine> {
a: Option<E::Fr>,
b: Option<E::Fr>
}
// fn get_vk(
// &mut self,
// _: usize
// ) -> Result<VerifyingKey<E>, SynthesisError>
// {
// Ok(self.vk.clone())
// }
impl<E: Engine> Circuit<E> for MySillyCircuit<E> {
fn synthesize<CS: ConstraintSystem<E>>(
self,
cs: &mut CS
) -> Result<(), SynthesisError>
{
let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?;
let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?;
let c = cs.alloc_input(|| "c", || {
let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
// fn get_h(
// &mut self,
// _: usize
// ) -> Result<Self::G1Builder, SynthesisError>
// {
// Ok((self.h.clone(), 0))
// }
a.mul_assign(&b);
Ok(a)
})?;
// fn get_l(
// &mut self,
// _: usize
// ) -> Result<Self::G1Builder, SynthesisError>
// {
// Ok((self.l.clone(), 0))
// }
cs.enforce(
|| "a*b=c",
|lc| lc + a,
|lc| lc + b,
|lc| lc + c
);
// fn get_a(
// &mut self,
// num_inputs: usize,
// _: usize
// ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>
// {
// Ok(((self.a.clone(), 0), (self.a.clone(), num_inputs)))
// }
Ok(())
}
}
// fn get_b_g1(
// &mut self,
// num_inputs: usize,
// _: usize
// ) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>
// {
// Ok(((self.b_g1.clone(), 0), (self.b_g1.clone(), num_inputs)))
// }
use rand::{Rng, Rand, thread_rng};
use super::{generate_parameters, get_circuit_parameters, generate_srs, generate_parameters_on_srs_and_information};
use super::adapted_prover::create_proof;
// fn get_b_g2(
// &mut self,
// num_inputs: usize,
// _: usize
// ) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>
// {
// Ok(((self.b_g2.clone(), 0), (self.b_g2.clone(), num_inputs)))
// }
// }
let info = get_circuit_parameters::<Bls12, _>(MySillyCircuit { a: None, b: None }).expect("Must get circuit info");
println!("{:?}", info);
let rng = &mut thread_rng();
// #[cfg(test)]
// mod test_with_bls12_381 {
// use super::*;
// use {Circuit, SynthesisError, ConstraintSystem};
let x: Fr = rng.gen();
let alpha: Fr = rng.gen();
// use rand::{Rand, thread_rng};
// use ff::{Field};
// use pairing::bls12_381::{Bls12, Fr};
let params = generate_parameters::<Bls12, _>(MySillyCircuit { a: None, b: None }, alpha, x).unwrap();
let srs = generate_srs::<Bls12>(alpha, x, info.n * 100).unwrap();
let naive_srs = SRS::<Bls12>::new(
info.n * 100,
x,
alpha,
);
// #[test]
// fn serialization() {
// struct MySillyCircuit<E: Engine> {
// a: Option<E::Fr>,
// b: Option<E::Fr>
// }
assert!(srs == naive_srs);
// impl<E: Engine> Circuit<E> for MySillyCircuit<E> {
// fn synthesize<CS: ConstraintSystem<E>>(
// self,
// cs: &mut CS
// ) -> Result<(), SynthesisError>
// {
// let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?;
// let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?;
// let c = cs.alloc_input(|| "c", || {
// let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
// let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
let params_on_srs = generate_parameters_on_srs_and_information::<Bls12>(&srs, info.clone()).unwrap();
// a.mul_assign(&b);
// Ok(a)
// })?;
assert!(params == params_on_srs);
// cs.enforce(
// || "a*b=c",
// |lc| lc + a,
// |lc| lc + b,
// |lc| lc + c
// );
{
let mut v = vec![];
// Ok(())
// }
// }
params.write(&mut v).unwrap();
// let rng = &mut thread_rng();
let de_params = Parameters::read(&v[..], true).unwrap();
assert!(params == de_params);
// let params = generate_random_parameters::<Bls12, _, _>(
// MySillyCircuit { a: None, b: None },
// rng
// ).unwrap();
let de_params = Parameters::read(&v[..], false).unwrap();
assert!(params == de_params);
}
// {
// let mut v = vec![];
for _ in 0..100 {
let a = Fr::rand(rng);
let b = Fr::rand(rng);
let mut c = a;
c.mul_assign(&b);
// params.write(&mut v).unwrap();
// assert_eq!(v.len(), 2136);
let proof = create_proof (
MySillyCircuit {
a: Some(a),
b: Some(b)
},
&params,
).unwrap();
// let de_params = Parameters::read(&v[..], true).unwrap();
// assert!(params == de_params);
let mut v = vec![];
proof.write(&mut v).unwrap();
// let de_params = Parameters::read(&v[..], false).unwrap();
// assert!(params == de_params);
// }
assert_eq!(v.len(), 256);
// let pvk = prepare_verifying_key::<Bls12>(&params.vk);
let de_proof = Proof::read(&v[..]).unwrap();
assert!(proof == de_proof);
// for _ in 0..100 {
// let a = Fr::rand(rng);
// let b = Fr::rand(rng);
// let mut c = a;
// c.mul_assign(&b);
// let proof = create_random_proof(
// MySillyCircuit {
// a: Some(a),
// b: Some(b)
// },
// &params,
// rng
// ).unwrap();
// let mut v = vec![];
// proof.write(&mut v).unwrap();
// assert_eq!(v.len(), 192);
// let de_proof = Proof::read(&v[..]).unwrap();
// assert!(proof == de_proof);
// assert!(verify_proof(&pvk, &proof, &[c]).unwrap());
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
// }
// }
// }
// assert!(verify_proof(&pvk, &proof, &[c]).unwrap());
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
}
}

@ -133,6 +133,13 @@ pub fn create_advice_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
}
pub fn create_proof<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
circuit: &C,
parameters: &Parameters<E>
) -> Result<Proof<E>, SynthesisError> {
create_proof_on_srs::<E, C, S>(circuit, &parameters.srs)
}
pub fn create_proof_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
circuit: &C,
srs: &SRS<E>
) -> Result<Proof<E>, SynthesisError>
@ -209,6 +216,10 @@ pub fn create_proof<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
let y: E::Fr = transcript.get_challenge_scalar();
// create r(X, 1) by observation that it's just a series of coefficients.
// Used representation is for powers X^{-2n}...X^{-n-1}, X^{-n}...X^{-1}, X^{1}...X^{n}
// Same representation is ok for r(X, Y) too cause powers always match
// TODO: add blindings c_{n+1}*X^{-2n - 1}, c_{n+2}*X^{-2n - 2}, c_{n+3}*X^{-2n - 3}, c_{n+4}*X^{-2n - 4}
let mut rx1 = wires.b;
rx1.extend(wires.c);
rx1.reverse();
@ -219,11 +230,13 @@ pub fn create_proof<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
let y_inv = y.inverse().ok_or(SynthesisError::DivisionByZero)?;
let mut tmp = y.pow(&[n as u64]);
// evaluate r(X, y)
for rxy in rxy.iter_mut().rev() {
rxy.mul_assign(&tmp);
tmp.mul_assign(&y_inv);
}
// negative powers [-n, -1], positive [1, 2n]
let (s_poly_negative, s_poly_positive) = {
let mut tmp = SxEval::new(y, n);
S::synthesize(&mut tmp, circuit)?;
@ -231,10 +244,11 @@ pub fn create_proof<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
tmp.poly()
};
// r'(X, y) = r(X, y) + s(X, y). Note `y` - those are evaluated at the point already
let mut rxy_prime = rxy.clone();
{
rxy_prime.resize(4 * n + 1, E::Fr::zero());
// Add s(x, y)
// add coefficients in front of X^{-2n}...X^{-n-1}, X^{-n}...X^{-1}
for (r, s) in rxy_prime[0..(2 * n)]
.iter_mut()
.rev()
@ -242,14 +256,18 @@ pub fn create_proof<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
{
r.add_assign(&s);
}
// add coefficients in front of X^{1}...X^{n}, X^{n+1}...X^{2*n}
for (r, s) in rxy_prime[(2 * n + 1)..].iter_mut().zip(s_poly_positive) {
r.add_assign(&s);
}
}
// t(X, y) = r'(X, y)*r(X, 1) and will be later evaluated at z
// contained degree in respect to X are from -4*n to 3*n including X^0
let mut txy = multiply_polynomials::<E>(rx1.clone(), rxy_prime);
txy[4 * n] = E::Fr::zero(); // -k(y)
// commit to t(X, y) to later open at z
let t = multiexp(
srs.g_positive_x_alpha[0..(3 * n)]
.iter()
@ -392,7 +410,7 @@ fn my_fun_circuit_test() {
Fr::from_str("22222").unwrap(),
Fr::from_str("33333333").unwrap(),
);
let proof = create_proof::<Bls12, _, Basic>(&MyCircuit, &srs).unwrap();
let proof = self::create_proof_on_srs::<Bls12, _, Basic>(&MyCircuit, &srs).unwrap();
use std::time::{Instant};
let start = Instant::now();

@ -226,6 +226,7 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
});
// Finally, compute t(z, y)
// t(z, y) = (r(z, y) + s(z,y))*r(z, 1) - k(y)
let mut tzy = proof.rzy;
tzy.add_assign(&szy);
tzy.mul_assign(&proof.rz);

@ -146,6 +146,7 @@ impl<'a, E: Engine, CS: SonicConstraintSystem<E> + 'a> crate::ConstraintSystem<E
}
}
#[derive(Clone)]
pub struct AdaptorCircuit<T>(pub T);
impl<'a, E: Engine, C: crate::Circuit<E> + Clone> SonicCircuit<E> for AdaptorCircuit<C> {

@ -202,20 +202,18 @@ where
use pairing::CurveAffine;
use crate::multicore::Worker;
use crate::multiexp;
use crate::multiexp::FullDensity;
use crate::multiexp::dense_multiexp;
let s: Arc<Vec<<G::Scalar as PrimeField>::Repr>> = Arc::new(s.into_iter().map(|e| e.into_repr()).collect::<Vec<_>>());
let g: Arc<Vec<G>> = Arc::new(g.into_iter().map(|e| *e).collect::<Vec<_>>());
let s: Vec<<G::Scalar as PrimeField>::Repr> = s.into_iter().map(|e| e.into_repr()).collect::<Vec<_>>();
let g: Vec<G> = g.into_iter().map(|e| *e).collect::<Vec<_>>();
let pool = Worker::new();
let result = multiexp::multiexp(
let result = dense_multiexp(
&pool,
(g, 0),
FullDensity,
s
).wait().unwrap();
&g,
&s
).unwrap();
result
}
@ -379,7 +377,6 @@ fn laurent_division() {
}
pub fn multiply_polynomials<E: Engine>(a: Vec<E::Fr>, b: Vec<E::Fr>) -> Vec<E::Fr> {
println!("Multiplying polynomails of degrees {} and {}", a.len(), b.len());
let result_len = a.len() + b.len() - 1;
use crate::multicore::Worker;

141
src/source.rs Normal file

@ -0,0 +1,141 @@
use pairing::{
CurveAffine,
CurveProjective,
Engine
};
use ff::{
PrimeField,
Field,
PrimeFieldRepr,
ScalarEngine};
use std::sync::Arc;
use std::io;
use bit_vec::{self, BitVec};
use std::iter;
use super::SynthesisError;
/// An object that builds a source of bases.
pub trait SourceBuilder<G: CurveAffine>: Send + Sync + 'static + Clone {
type Source: Source<G>;
fn new(self) -> Self::Source;
}
/// A source of bases, like an iterator.
pub trait Source<G: CurveAffine> {
/// Parses the element from the source. Fails if the point is at infinity.
fn add_assign_mixed(&mut self, to: &mut <G as CurveAffine>::Projective) -> Result<(), SynthesisError>;
/// Skips `amt` elements from the source, avoiding deserialization.
fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>;
}
impl<G: CurveAffine> SourceBuilder<G> for (Arc<Vec<G>>, usize) {
type Source = (Arc<Vec<G>>, usize);
fn new(self) -> (Arc<Vec<G>>, usize) {
(self.0.clone(), self.1)
}
}
impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
fn add_assign_mixed(&mut self, to: &mut <G as CurveAffine>::Projective) -> Result<(), SynthesisError> {
if self.0.len() <= self.1 {
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases when adding from source").into());
}
if self.0[self.1].is_zero() {
return Err(SynthesisError::UnexpectedIdentity)
}
to.add_assign_mixed(&self.0[self.1]);
self.1 += 1;
Ok(())
}
fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> {
if self.0.len() <= self.1 {
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases skipping from source").into());
}
self.1 += amt;
Ok(())
}
}
pub trait QueryDensity {
/// Returns whether the base exists.
type Iter: Iterator<Item=bool>;
fn iter(self) -> Self::Iter;
fn get_query_size(self) -> Option<usize>;
}
#[derive(Clone)]
pub struct FullDensity;
impl AsRef<FullDensity> for FullDensity {
fn as_ref(&self) -> &FullDensity {
self
}
}
impl<'a> QueryDensity for &'a FullDensity {
type Iter = iter::Repeat<bool>;
fn iter(self) -> Self::Iter {
iter::repeat(true)
}
fn get_query_size(self) -> Option<usize> {
None
}
}
#[derive(Clone)]
pub struct DensityTracker {
bv: BitVec,
total_density: usize
}
impl<'a> QueryDensity for &'a DensityTracker {
type Iter = bit_vec::Iter<'a>;
fn iter(self) -> Self::Iter {
self.bv.iter()
}
fn get_query_size(self) -> Option<usize> {
Some(self.bv.len())
}
}
impl DensityTracker {
pub fn new() -> DensityTracker {
DensityTracker {
bv: BitVec::new(),
total_density: 0
}
}
pub fn add_element(&mut self) {
self.bv.push(false);
}
pub fn inc(&mut self, idx: usize) {
if !self.bv.get(idx).unwrap() {
self.bv.set(idx, true);
self.total_density += 1;
}
}
pub fn get_total_density(&self) -> usize {
self.total_density
}
}

@ -479,16 +479,17 @@ fn test_sonic_mimc() {
use bellman::sonic::cs::Basic;
use bellman::sonic::sonic::AdaptorCircuit;
use bellman::sonic::helped::{create_proof, create_advice, create_aggregate, MultiVerifier, create_advice_on_srs};
use bellman::sonic::helped::prover::{create_advice_on_srs, create_proof_on_srs};
use bellman::sonic::helped::{create_aggregate, MultiVerifier};
println!("creating proof");
let start = Instant::now();
let proof = create_proof::<Bls12, _, Basic>(&AdaptorCircuit(circuit.clone()), &srs).unwrap();
let proof = create_proof_on_srs::<Bls12, _, Basic>(&AdaptorCircuit(circuit.clone()), &srs).unwrap();
println!("done in {:?}", start.elapsed());
println!("creating advice");
let start = Instant::now();
let advice = create_advice_on_srs::<Bls12, _, Basic>(&AdaptorCircuit(circuit.clone()), &proof, &srs);
let advice = create_advice_on_srs::<Bls12, _, Basic>(&AdaptorCircuit(circuit.clone()), &proof, &srs).unwrap();
println!("done in {:?}", start.elapsed());
println!("creating aggregate for {} proofs", samples);
@ -578,19 +579,20 @@ fn test_inputs_into_sonic_mimc() {
use bellman::sonic::cs::Basic;
use bellman::sonic::sonic::AdaptorCircuit;
use bellman::sonic::helped::{create_proof, get_circuit_parameters, create_advice, create_aggregate, MultiVerifier, create_advice_on_srs};
use bellman::sonic::helped::prover::{create_advice_on_srs, create_proof_on_srs};
use bellman::sonic::helped::{create_aggregate, MultiVerifier, get_circuit_parameters};
let info = get_circuit_parameters::<Bn256, _>(circuit.clone()).expect("Must get circuit info");
println!("{:?}", info);
println!("creating proof");
let start = Instant::now();
let proof = create_proof::<Bn256, _, Basic>(&AdaptorCircuit(circuit.clone()), &srs).unwrap();
let proof = create_proof_on_srs::<Bn256, _, Basic>(&AdaptorCircuit(circuit.clone()), &srs).unwrap();
println!("done in {:?}", start.elapsed());
println!("creating advice");
let start = Instant::now();
let advice = create_advice_on_srs::<Bn256, _, Basic>(&AdaptorCircuit(circuit.clone()), &proof, &srs);
let advice = create_advice_on_srs::<Bn256, _, Basic>(&AdaptorCircuit(circuit.clone()), &proof, &srs).unwrap();
println!("done in {:?}", start.elapsed());
println!("creating aggregate for {} proofs", samples);
@ -625,32 +627,6 @@ fn test_inputs_into_sonic_mimc() {
println!("done in {:?}", start.elapsed());
}
{
let mut verifier = MultiVerifier::<Bn256, _, Basic>::new(AdaptorCircuit(circuit.clone()), &srs).unwrap();
println!("verifying 1 proof with advice");
let start = Instant::now();
{
for _ in 0..1 {
verifier.add_proof_with_advice(&proof, &[image], &advice);
}
assert_eq!(verifier.check_all(), true); // TODO
}
println!("done in {:?}", start.elapsed());
}
{
let mut verifier = MultiVerifier::<Bn256, _, Basic>::new(AdaptorCircuit(circuit.clone()), &srs).unwrap();
println!("verifying 100 proofs with advice");
let start = Instant::now();
{
for _ in 0..samples {
verifier.add_proof_with_advice(&proof, &[image], &advice);
}
assert_eq!(verifier.check_all(), true); // TODO
}
println!("done in {:?}", start.elapsed());
}
{
let mut verifier = MultiVerifier::<Bn256, _, Basic>::new(AdaptorCircuit(circuit.clone()), &srs).unwrap();
println!("verifying 100 proofs with advice and aggregate");