continue to integrate helped SONIC. Now only verifier left
This commit is contained in:
parent
614d486b99
commit
3f766246de
@ -30,3 +30,5 @@ rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
singlecore = []
|
||||
|
190
src/domain.rs
190
src/domain.rs
@ -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
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);
|
||||
}
|
||||
}
|
24
src/lib.rs
24
src/lib.rs
@ -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
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_fft.rs
Normal file
0
src/serial_multiexp.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(())
|
||||
}
|
||||
}
|
146
src/sonic/helped/adapted_prover.rs
Normal file
146
src/sonic/helped/adapted_prover.rs
Normal file
@ -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, ¶meters.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, ¶meters.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>(¶ms.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)
|
||||
// },
|
||||
// ¶ms,
|
||||
// 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)
|
||||
},
|
||||
¶ms,
|
||||
).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>(¶ms.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)
|
||||
// },
|
||||
// ¶ms,
|
||||
// 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, ¶meters.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
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");
|
||||
|
Loading…
Reference in New Issue
Block a user