use crate::pairing::ff::Field;
use crate::pairing::{CurveProjective, Engine};
use std::marker::PhantomData;
use super::batch::Batch;
use super::parameters::{Parameters, NUM_BLINDINGS};
use super::poly::{SxEval, SyEval};
use super::{Proof, SxyAdvice};
use crate::SynthesisError;
use crate::sonic::cs::{Backend, SynthesisDriver};
use crate::sonic::cs::{Circuit, Coeff, Variable};
use crate::sonic::sonic::{Basic, CountN};
use crate::sonic::srs::SRS;
use crate::sonic::transcript::{Transcript, TranscriptProtocol};
use crate::sonic::util::*;
pub fn create_advice_on_information_and_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver>(circuit: &C, proof: &Proof<E>, srs: &SRS<E>, n: usize) -> Result<SxyAdvice<E>, SynthesisError> {
let z: E::Fr;
let y: E::Fr;
{
let mut transcript = Transcript::new(&[]);
transcript.commit_point(&proof.r);
y = transcript.get_challenge_scalar();
transcript.commit_point(&proof.t);
z = transcript.get_challenge_scalar();
}
let z_inv = z.inverse().ok_or(SynthesisError::DivisionByZero)?;
let (s_poly_negative, s_poly_positive) = {
let mut tmp = SxEval::new(y, n);
S::synthesize(&mut tmp, circuit)?;
tmp.poly()
};
let s = multiexp(
srs.g_positive_x_alpha[0..(2 * n)].iter().chain_ext(srs.g_negative_x_alpha[0..(n)].iter()),
s_poly_positive.iter().chain_ext(s_poly_negative.iter()),
)
.into_affine();
let mut szy = E::Fr::zero();
{
szy.add_assign(&evaluate_at_consequitive_powers(&s_poly_positive[..], z, z));
szy.add_assign(&evaluate_at_consequitive_powers(&s_poly_negative[..], z_inv, z_inv));
}
let opening = {
let mut open = szy;
open.negate();
let poly = kate_divison(s_poly_negative.iter().rev().chain_ext(Some(open).iter()).chain_ext(s_poly_positive.iter()), z);
let negative_poly = poly[0..n].iter().rev();
let positive_poly = poly[n..].iter();
multiexp(
srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(srs.g_positive_x[0..positive_poly.len()].iter()),
negative_poly.chain_ext(positive_poly),
)
.into_affine()
};
Ok(SxyAdvice { s, szy, opening })
}
pub fn create_advice<E: Engine, C: Circuit<E>, S: SynthesisDriver>(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, S>(circuit, proof, ¶meters.srs, n)
}
pub fn create_advice_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver>(circuit: &C, proof: &Proof<E>, srs: &SRS<E>) -> Result<SxyAdvice<E>, SynthesisError> {
let n = {
let mut tmp = CountN::<S>::new();
S::synthesize(&mut tmp, circuit)?;
tmp.n
};
create_advice_on_information_and_srs::<E, C, S>(circuit, proof, srs, n)
}
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)
}
extern crate rand;
use self::rand::{thread_rng, Rand, Rng};
use crate::sonic::sonic::Wires;
pub fn create_proof_on_srs<E: Engine, C: Circuit<E>, S: SynthesisDriver>(circuit: &C, srs: &SRS<E>) -> Result<Proof<E>, SynthesisError> {
let mut wires = Wires::new();
S::synthesize(&mut wires, circuit)?;
let n = wires.a.len();
let mut transcript = Transcript::new(&[]);
let rng = &mut thread_rng();
let blindings: Vec<E::Fr> = (0..NUM_BLINDINGS).into_iter().map(|_| E::Fr::rand(rng)).collect();
let r = polynomial_commitment::<E, _>(
n,
2 * n + NUM_BLINDINGS,
n,
&srs,
blindings
.iter()
.rev()
.chain_ext(wires.c.iter().rev())
.chain_ext(wires.b.iter().rev())
.chain_ext(Some(E::Fr::zero()).iter())
.chain_ext(wires.a.iter()),
);
transcript.commit_point(&r);
let y: E::Fr = transcript.get_challenge_scalar();
let mut rx1 = wires.b;
rx1.extend(wires.c);
rx1.extend(blindings.clone());
rx1.reverse();
rx1.push(E::Fr::zero());
rx1.extend(wires.a);
let mut rxy = rx1.clone();
let y_inv = y.inverse().ok_or(SynthesisError::DivisionByZero)?;
let tmp = y_inv.pow(&[(2 * n + NUM_BLINDINGS) as u64]);
mut_distribute_consequitive_powers(&mut rxy, tmp, y);
let (mut s_poly_negative, s_poly_positive) = {
let mut tmp = SxEval::new(y, n);
S::synthesize(&mut tmp, circuit)?;
tmp.poly()
};
let mut rxy_prime = rxy.clone();
{
rxy_prime.resize(4 * n + 1 + NUM_BLINDINGS, E::Fr::zero());
s_poly_negative.reverse();
let neg_poly_len = s_poly_negative.len();
add_polynomials(&mut rxy_prime[(NUM_BLINDINGS + neg_poly_len)..(2 * n + NUM_BLINDINGS)], &s_poly_negative[..]);
s_poly_negative.reverse();
add_polynomials(&mut rxy_prime[(2 * n + 1 + NUM_BLINDINGS)..], &s_poly_positive[..])
}
let mut txy = multiply_polynomials::<E>(rx1.clone(), rxy_prime);
txy[4 * n + 2 * NUM_BLINDINGS] = E::Fr::zero();
let t = polynomial_commitment(
srs.d,
(4 * n) + 2 * NUM_BLINDINGS,
3 * n,
srs,
txy[0..(4 * n) + 2 * NUM_BLINDINGS].iter().chain_ext(txy[(4 * n + 2 * NUM_BLINDINGS + 1)..].iter()),
);
transcript.commit_point(&t);
let z: E::Fr = transcript.get_challenge_scalar();
let z_inv = z.inverse().ok_or(SynthesisError::DivisionByZero)?;
let rz = {
let tmp = z_inv.pow(&[(2 * n + NUM_BLINDINGS) as u64]);
evaluate_at_consequitive_powers(&rx1, tmp, z)
};
let rzy = {
let tmp = z_inv.pow(&[(2 * n + NUM_BLINDINGS) as u64]);
evaluate_at_consequitive_powers(&rxy, tmp, z)
};
transcript.commit_scalar(&rz);
transcript.commit_scalar(&rzy);
let r1: E::Fr = transcript.get_challenge_scalar();
let zy_opening = {
rx1[(2 * n + NUM_BLINDINGS)].sub_assign(&rzy);
let mut point = y;
point.mul_assign(&z);
polynomial_commitment_opening(2 * n + NUM_BLINDINGS, n, &rx1, point, srs)
};
assert_eq!(rx1.len(), 3 * n + NUM_BLINDINGS + 1);
let z_opening = {
rx1[(2 * n + NUM_BLINDINGS)].add_assign(&rzy);
let rx1_len = rx1.len();
mul_add_polynomials(&mut txy[(2 * n + NUM_BLINDINGS)..(2 * n + NUM_BLINDINGS + rx1_len)], &rx1[..], r1);
let val = {
let tmp = z_inv.pow(&[(4 * n + 2 * NUM_BLINDINGS) as u64]);
evaluate_at_consequitive_powers(&txy, tmp, z)
};
txy[(4 * n + 2 * NUM_BLINDINGS)].sub_assign(&val);
polynomial_commitment_opening(4 * n + 2 * NUM_BLINDINGS, 3 * n, &txy, z, srs)
};
Ok(Proof { r, rz, rzy, t, z_opening, zy_opening })
}
#[test]
fn my_fun_circuit_test() {
use super::*;
use crate::pairing::bls12_381::{Bls12, Fr};
use crate::pairing::ff::PrimeField;
use crate::sonic::cs::{ConstraintSystem, LinearCombination};
use crate::sonic::sonic::Basic;
use rand::thread_rng;
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);
Ok(())
}
}
let srs = SRS::<Bls12>::new(20, Fr::from_str("22222").unwrap(), Fr::from_str("33333333").unwrap());
let proof = self::create_proof_on_srs::<Bls12, _, Basic>(&MyCircuit, &srs).unwrap();
use std::time::Instant;
let start = Instant::now();
let rng = thread_rng();
let mut batch = MultiVerifier::<Bls12, _, Basic, _>::new(MyCircuit, &srs, rng).unwrap();
for _ in 0..1 {
batch.add_proof(&proof, &[], |_, _| None);
}
assert!(batch.check_all());
let elapsed = start.elapsed();
println!("time to verify: {:?}", elapsed);
}
#[test]
fn polynomial_commitment_test() {
use super::*;
use crate::pairing::bls12_381::{Bls12, Fr};
use crate::pairing::ff::PrimeField;
use crate::pairing::ff::PrimeFieldRepr;
use crate::pairing::CurveAffine;
use crate::sonic::cs::{ConstraintSystem, LinearCombination};
use crate::sonic::sonic::Basic;
use rand::thread_rng;
let srs = SRS::<Bls12>::new(20, Fr::from_str("22222").unwrap(), Fr::from_str("33333333").unwrap());
let mut rng = thread_rng();
let mut poly = vec![Fr::one(), Fr::one(), Fr::one(), Fr::one(), Fr::zero(), Fr::one(), Fr::one()];
let commitment = polynomial_commitment(2, 4, 2, &srs, poly.iter());
let point: Fr = rng.gen();
let mut tmp = point.inverse().unwrap();
tmp.square();
let value = evaluate_at_consequitive_powers(&poly, tmp, point);
poly[4] = value;
poly[4].negate();
let opening = polynomial_commitment_opening(4, 2, poly.iter(), point, &srs);
let alpha_x_precomp = srs.h_positive_x_alpha[1].prepare();
let alpha_precomp = srs.h_positive_x_alpha[0].prepare();
let mut neg_x_n_minus_d_precomp = srs.h_negative_x[srs.d - 2];
neg_x_n_minus_d_precomp.negate();
let neg_x_n_minus_d_precomp = neg_x_n_minus_d_precomp.prepare();
let w = opening.prepare();
let mut gv = srs.g_positive_x[0].mul(value.into_repr());
let mut z_neg = point;
z_neg.negate();
let w_minus_z = opening.mul(z_neg.into_repr());
gv.add_assign(&w_minus_z);
let gv = gv.into_affine().prepare();
assert!(
Bls12::final_exponentiation(&Bls12::miller_loop(
&[(&w, &alpha_x_precomp), (&gv, &alpha_precomp), (&commitment.prepare(), &neg_x_n_minus_d_precomp),]
))
.unwrap()
== <Bls12 as Engine>::Fqk::one()
);
}