start real integration

This commit is contained in:
Alex Vlasov 2019-02-05 14:14:17 +03:00
parent e41e3624f7
commit e51284e754
4 changed files with 244 additions and 7 deletions

@ -97,6 +97,58 @@ impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
})
}
// this one does expect coefficients to be smaller than `num_roots_of_unity/2` as we expect multiplication
pub fn from_coeffs_for_multiplication(mut coeffs: Vec<G>, expected_power: usize) -> Result<EvaluationDomain<E, G>, SynthesisError>
{
use ff::PrimeField;
// Compute the size of our evaluation domain
assert!(expected_power >= coeffs.len());
let coeffs_len = expected_power;
// m is a size of domain where Z polynomial does NOT vanish
// in normal domain Z is in a form of (X-1)(X-2)...(X-N)
let mut m = 1;
let mut exp = 0;
let mut omega = E::Fr::root_of_unity();
let max_degree = (1 << E::Fr::S) - 1;
if coeffs_len > max_degree {
return Err(SynthesisError::PolynomialDegreeTooLarge)
}
while m < coeffs_len {
m *= 2;
exp += 1;
// The pairing-friendly curve may not be able to support
// large enough (radix2) evaluation domains.
if exp > E::Fr::S {
return Err(SynthesisError::PolynomialDegreeTooLarge)
}
}
// If full domain is not needed - limit it,
// e.g. if (2^N)th power is not required, just double omega and get 2^(N-1)th
// Compute omega, the 2^exp primitive root of unity
for _ in exp..E::Fr::S {
omega.square();
}
// Extend the coeffs vector with zeroes if necessary
coeffs.resize(m, G::group_zero());
Ok(EvaluationDomain {
coeffs: coeffs,
exp: exp,
omega: omega,
omegainv: omega.inverse().unwrap(),
geninv: E::Fr::multiplicative_generator().inverse().unwrap(),
minv: E::Fr::from_str(&format!("{}", m)).unwrap().inverse().unwrap()
})
}
pub fn fft(&mut self, worker: &Worker)
{
best_fft(&mut self.coeffs, worker, &self.omega, self.exp);
@ -275,7 +327,7 @@ impl<E: Engine> Group<E> for Scalar<E> {
}
}
fn best_fft<E: Engine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32)
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();
@ -286,7 +338,7 @@ fn best_fft<E: Engine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr,
}
}
fn serial_fft<E: Engine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32)
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;
@ -331,7 +383,7 @@ fn serial_fft<E: Engine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32)
}
}
fn parallel_fft<E: Engine, T: Group<E>>(
pub(crate) fn parallel_fft<E: Engine, T: Group<E>>(
a: &mut [T],
worker: &Worker,
omega: &E::Fr,

@ -12,8 +12,11 @@ Initial SONIC proof system integration using the code from the [original impleme
## TODO Plan
- [ ] Parallelize using existing primitives
- [ ] Put public inputs into the account
- [x] Test with public inputs
- [x] Test on BN256
- [x] Parallelize using existing primitives
- [ ] Implement polynomial parallelized evaluation
- [ ] Make custom transcriptor that is easy to transform into the smart-contract
- [ ] Basic Ethereum smart-contract
- [ ] Add blinding factors
- [ ] Implement unhelped version

@ -80,6 +80,43 @@ pub fn multiexp<
g: IB,
s: IS,
) -> G::Projective
where
IB::IntoIter: ExactSizeIterator + Clone,
IS::IntoIter: ExactSizeIterator,
{
use std::sync::Arc;
use futures::Future;
use ff::PrimeFieldRepr;
use pairing::CurveAffine;
use crate::multicore::Worker;
use crate::multiexp;
use crate::multiexp::FullDensity;
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 pool = Worker::new();
let result = multiexp::multiexp(
&pool,
(g, 0),
FullDensity,
s
).wait().unwrap();
result
}
pub fn multiexp_serial<
'a,
G: CurveAffine,
IB: IntoIterator<Item = &'a G>,
IS: IntoIterator<Item = &'a G::Scalar>,
>(
g: IB,
s: IS,
) -> G::Projective
where
IB::IntoIter: ExactSizeIterator + Clone,
IS::IntoIter: ExactSizeIterator,
@ -232,6 +269,34 @@ fn laurent_division() {
pub fn multiply_polynomials<E: Engine>(mut a: Vec<E::Fr>, mut b: Vec<E::Fr>) -> Vec<E::Fr> {
let result_len = a.len() + b.len() - 1;
use crate::multicore::Worker;
use crate::domain::{EvaluationDomain, Scalar};
let worker = Worker::new();
let scalars_a: Vec<Scalar<E>> = a.into_iter().map(|e| Scalar::<E>(e)).collect();
let mut domain_a = EvaluationDomain::from_coeffs_for_multiplication(scalars_a, result_len).unwrap();
let scalars_b: Vec<Scalar<E>> = b.into_iter().map(|e| Scalar::<E>(e)).collect();
let mut domain_b = EvaluationDomain::from_coeffs_for_multiplication(scalars_b, result_len).unwrap();
domain_a.fft(&worker);
domain_b.fft(&worker);
domain_a.mul_assign(&worker, &domain_b);
drop(domain_b);
domain_a.ifft(&worker);
let mut mul_result: Vec<E::Fr> = domain_a.into_coeffs().iter().map(|e| e.0).collect();
mul_result.truncate(result_len);
mul_result
}
pub fn multiply_polynomials_serial<E: Engine>(mut a: Vec<E::Fr>, mut b: Vec<E::Fr>) -> Vec<E::Fr> {
let result_len = a.len() + b.len() - 1;
// Compute the size of our evaluation domain
let mut m = 1;
let mut exp = 0;
@ -335,3 +400,23 @@ impl<T> OptionExt<T> for Option<T> {
}
}
}
#[test]
fn test_mul() {
use rand::{self, Rand};
use pairing::bls12_381::Bls12;
use pairing::bls12_381::Fr;
const SAMPLES: usize = 100;
let rng = &mut rand::thread_rng();
let a = (0..SAMPLES).map(|_| Fr::rand(rng)).collect::<Vec<_>>();
let b = (0..SAMPLES).map(|_| Fr::rand(rng)).collect::<Vec<_>>();
let serial_res = multiply_polynomials_serial::<Bls12>(a.clone(), b.clone());
let parallel_res = multiply_polynomials::<Bls12>(a, b);
assert_eq!(serial_res.len(), parallel_res.len());
assert_eq!(serial_res, parallel_res);
}

@ -464,8 +464,6 @@ fn test_sonic_mimc() {
let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::<Vec<_>>();
let samples: usize = 100;
const NUM_BITS: usize = 384;
let xl = rng.gen();
let xr = rng.gen();
let image = mimc::<Bls12>(xl, xr, &constants);
@ -540,3 +538,102 @@ fn test_sonic_mimc() {
}
}
}
#[test]
fn test_inputs_into_sonic_mimc() {
use ff::{Field, PrimeField};
use pairing::{Engine, CurveAffine, CurveProjective};
use pairing::bn256::{Bn256, Fr};
// use pairing::bls12_381::{Bls12, Fr};
use std::time::{Instant};
use bellman::sonic::srs::SRS;
let srs_x = Fr::from_str("23923").unwrap();
let srs_alpha = Fr::from_str("23728792").unwrap();
println!("making srs");
let start = Instant::now();
let srs = SRS::<Bn256>::dummy(830564, srs_x, srs_alpha);
println!("done in {:?}", start.elapsed());
{
// This may not be cryptographically safe, use
// `OsRng` (for example) in production software.
let rng = &mut thread_rng();
// Generate the MiMC round constants
let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::<Vec<_>>();
let samples: usize = 100;
let xl = rng.gen();
let xr = rng.gen();
let image = mimc::<Bn256>(xl, xr, &constants);
// Create an instance of our circuit (with the
// witness)
let circuit = MiMCDemo {
xl: Some(xl),
xr: Some(xr),
constants: &constants
};
use bellman::sonic::cs::Basic;
use bellman::sonic::sonic::AdaptorCircuit;
use bellman::sonic::helped::{create_proof, create_advice, create_aggregate, MultiVerifier};
println!("creating proof");
let start = Instant::now();
let proof = create_proof::<Bn256, _, Basic>(&AdaptorCircuit(circuit.clone()), &srs).unwrap();
println!("done in {:?}", start.elapsed());
println!("creating advice");
let start = Instant::now();
let advice = create_advice::<Bn256, _, Basic>(&AdaptorCircuit(circuit.clone()), &proof, &srs);
println!("done in {:?}", start.elapsed());
println!("creating aggregate for {} proofs", samples);
let start = Instant::now();
let proofs: Vec<_> = (0..samples).map(|_| (proof.clone(), advice.clone())).collect();
let aggregate = create_aggregate::<Bn256, _, Basic>(&AdaptorCircuit(circuit.clone()), &proofs, &srs);
println!("done in {:?}", start.elapsed());
{
let mut verifier = MultiVerifier::<Bn256, _, Basic>::new(AdaptorCircuit(circuit.clone()), &srs).unwrap();
println!("verifying 1 proof without advice");
let start = Instant::now();
{
for _ in 0..1 {
verifier.add_proof(&proof, &[image], |_, _| None);
}
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 {} proofs without advice", samples);
let start = Instant::now();
{
for _ in 0..samples {
verifier.add_proof(&proof, &[image], |_, _| None);
}
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 (ref proof, ref advice) in &proofs {
verifier.add_proof_with_advice(proof, &[image], advice);
}
verifier.add_aggregate(&proofs, &aggregate);
assert_eq!(verifier.check_all(), true); // TODO
}
println!("done in {:?}", start.elapsed());
}
}
}