cleanup succinct arguments for batched verification

This commit is contained in:
Alex Vlasov 2019-06-06 22:12:38 +03:00
parent da501f4572
commit d4dd7d27fa
5 changed files with 306 additions and 107 deletions

@ -31,7 +31,7 @@ use crate::{
SynthesisError
};
const MIMC_ROUNDS: usize = 2;
const MIMC_ROUNDS: usize = 322;
fn mimc<E: Engine>(
mut xl: E::Fr,
@ -544,8 +544,8 @@ fn test_succinct_sonic_mimc() {
let s1_srs = perm_structure.create_permutation_special_reference(&srs);
let s2_srs = perm_structure.calculate_s2_commitment_value(&srs);
// let info = get_circuit_parameters_for_succinct_sonic::<Bls12, _>(circuit.clone()).expect("Must get circuit info");
// println!("{:?}", info);
let info = get_circuit_parameters_for_succinct_sonic::<Bls12, _>(circuit.clone()).expect("Must get circuit info");
println!("{:?}", info);
println!("creating proof");
let start = Instant::now();
@ -609,36 +609,38 @@ fn test_succinct_sonic_mimc() {
{
use rand::{XorShiftRng, SeedableRng, Rand, Rng};
let mut rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let start = Instant::now();
let (perm_commitments, s_prime_challenges, perm_proof, perm_arg_proof, z_prime, num_poly, s1_naive) = perm_structure.create_permutation_arguments(aggregate.w, aggregate.z, &mut rng, &srs);
let s2_proof = perm_structure.calculate_s2_proof(aggregate.z, aggregate.w, &srs);
let n = perm_structure.n;
let z = aggregate.z;
let y = aggregate.w;
let z_inv = z.inverse().unwrap();
let z_inv_n_plus_1 = z_inv.pow([(n+1) as u64]);
let z_n = z.pow([n as u64]);
let y_n = y.pow([n as u64]);
println!("Permutation argument done in {:?}", start.elapsed());
println!("S_1 naive = {}", s1_naive);
// let n = perm_structure.n;
// let z = aggregate.z;
// let y = aggregate.w;
// let z_inv = z.inverse().unwrap();
// let z_inv_n_plus_1 = z_inv.pow([(n+1) as u64]);
// let z_n = z.pow([n as u64]);
// let y_n = y.pow([n as u64]);
let mut s_1 = s1_naive;
s_1.mul_assign(&z_inv_n_plus_1);
s_1.mul_assign(&y_n);
// println!("S_1 naive = {}", s1_naive);
println!("S_1 multiplied = {}", s_1);
// let mut s_1 = s1_naive;
// s_1.mul_assign(&z_inv_n_plus_1);
// s_1.mul_assign(&y_n);
let mut s_2 = s2_proof.c_value;
s_2.add_assign(&s2_proof.d_value);
s_2.mul_assign(&z_n);
// println!("S_1 multiplied = {}", s_1);
s_1.sub_assign(&s_2);
println!("S naive = {}", s_1);
// let mut s_2 = s2_proof.c_value;
// s_2.add_assign(&s2_proof.d_value);
// s_2.mul_assign(&z_n);
// s_1.sub_assign(&s_2);
// println!("S naive = {}", s_1);
let mut verifier = SuccinctMultiVerifier::<Bls12, _, Permutation3, _>::new(AdaptorCircuit(circuit.clone()), &srs, rng).unwrap();
println!("verifying 100 proofs with advice");
println!("verifying 100 proofs with succinct advice");
let start = Instant::now();
{
for (ref proof, ref advice) in &proofs {

@ -8,6 +8,8 @@ use std::marker::PhantomData;
use crate::sonic::srs::SRS;
use crate::sonic::util::*;
use crate::sonic::transcript::{Transcript, TranscriptProtocol};
use super::wellformed_argument::{WellformednessSignature, WellformednessArgument};
#[derive(Clone)]
pub struct GrandProductArgument<E: Engine> {
@ -27,7 +29,82 @@ pub struct GrandProductProof<E: Engine> {
f_opening: E::G1Affine,
}
#[derive(Clone)]
pub struct GrandProductSignature<E: Engine> {
pub a_commitments: Vec<E::G1Affine>,
pub b_commitments: Vec<E::G1Affine>,
pub c_commitments: Vec<(E::G1Affine, E::Fr)>,
pub t_commitment: E::G1Affine,
pub grand_product_openings: Vec<(E::Fr, E::G1Affine)>,
// pub a_zy: Vec<E::Fr>,
pub proof: GrandProductProof<E>,
pub wellformedness_signature: WellformednessSignature<E>,
}
impl<E: Engine> GrandProductArgument<E> {
pub fn create_signature(
grand_products: Vec<(Vec<E::Fr>, Vec<E::Fr>)>,
y: E::Fr,
z: E::Fr,
srs: &SRS<E>,
) -> GrandProductSignature<E> {
let mut a_commitments = vec![];
let mut b_commitments = vec![];
let mut transcript = Transcript::new(&[]);
let mut grand_product_challenges = vec![];
for (a, b) in grand_products.iter() {
let (c_a, c_b) = GrandProductArgument::commit_for_individual_products(& a[..], & b[..], &srs);
{
let mut transcript = Transcript::new(&[]);
transcript.commit_point(&c_a);
let challenge = transcript.get_challenge_scalar();
grand_product_challenges.push(challenge);
transcript.commit_point(&c_b);
let challenge = transcript.get_challenge_scalar();
grand_product_challenges.push(challenge);
}
a_commitments.push(c_a);
b_commitments.push(c_b);
transcript.commit_point(&c_a);
transcript.commit_point(&c_b);
}
let mut all_polys = vec![];
for p in grand_products.iter() {
let (a, b) = p;
all_polys.push(a.clone());
all_polys.push(b.clone());
}
let wellformedness_signature = WellformednessArgument::create_signature(
all_polys,
&srs
);
let mut grand_product_argument = GrandProductArgument::new(grand_products);
let c_commitments = grand_product_argument.commit_to_individual_c_polynomials(&srs);
let t_commitment = grand_product_argument.commit_to_t_polynomial(&grand_product_challenges, y, &srs);
let grand_product_openings = grand_product_argument.open_commitments_for_grand_product(y, z, &srs);
let a_zy: Vec<E::Fr> = grand_product_openings.iter().map(|el| el.0.clone()).collect();
let proof = grand_product_argument.make_argument(&a_zy, &grand_product_challenges, y, z, &srs);
GrandProductSignature {
a_commitments,
b_commitments,
c_commitments,
t_commitment,
grand_product_openings,
// a_zy,
proof,
wellformedness_signature
}
}
pub fn new(polynomials: Vec<(Vec<E::Fr>, Vec<E::Fr>)>) -> Self {
assert!(polynomials.len() > 0);

@ -9,7 +9,9 @@ use std::marker::PhantomData;
use crate::sonic::srs::SRS;
use crate::sonic::util::*;
use super::wellformed_argument::{WellformednessArgument, WellformednessProof};
use super::grand_product_argument::{GrandProductArgument, GrandProductProof};
use super::grand_product_argument::{GrandProductArgument, GrandProductSignature};
use crate::sonic::transcript::{Transcript, TranscriptProtocol};
#[derive(Clone)]
pub struct SpecializedSRS<E: Engine> {
@ -43,6 +45,15 @@ pub struct PermutationArgumentProof<E: Engine> {
pub s_zy: E::Fr
}
#[derive(Clone)]
pub struct SignatureOfCorrectComputation<E: Engine> {
pub s_commitments: Vec<E::G1Affine>,
pub s_prime_commitments: Vec<E::G1Affine>,
pub perm_argument_proof: PermutationArgumentProof<E>,
pub perm_proof: PermutationProof<E>,
pub grand_product_signature: GrandProductSignature<E>
}
fn permute<F: Field>(coeffs: &[F], permutation: & [usize]) -> Vec<F>{
assert_eq!(coeffs.len(), permutation.len());
let mut result: Vec<F> = vec![F::zero(); coeffs.len()];
@ -158,7 +169,6 @@ impl<E: Engine> PermutationArgument<E> {
let mut permuted_coefficients = vec![];
let mut permuted_at_y_coefficients = vec![];
// naive algorithms
// for every permutation poly
// -- go throught all variable_idx
@ -311,8 +321,6 @@ impl<E: Engine> PermutationArgument<E> {
let s_polynomial = s_polynomial.unwrap();
// evaluate at z
let s_zy = evaluate_at_consequitive_powers(& s_polynomial[..], z, z);
println!("In permutation argument S1_(z, y) = {}", s_zy);
let mut s_zy_neg = s_zy;
s_zy_neg.negate();
@ -449,82 +457,6 @@ impl<E: Engine> PermutationArgument<E> {
assert_eq!(randomness.len(), 2);
assert_eq!(challenges.len(), commitments.len());
// let g = srs.g_positive_x[0];
// let h_alpha_x_precomp = srs.h_positive_x_alpha[1].prepare();
// let h_alpha_precomp = srs.h_positive_x_alpha[0].prepare();
// let mut h_prep = srs.h_positive_x[0];
// h_prep.negate();
// let h_prep = h_prep.prepare();
// let value = proof.v_zy;
// let g_v = g.mul(value.into_repr());
// {
// let mut minus_z_prime = z_prime;
// minus_z_prime.negate();
// let e_z = proof.e_opening.mul(minus_z_prime.into_repr());
// let mut h_alpha_term = e_z;
// h_alpha_term.add_assign(&g_v);
// let h_alpha_x_term = proof.e_opening;
// let s_r = multiexp(
// commitments.iter(),
// challenges.iter()
// ).into_affine();
// let h_term = s_r;
// let valid = E::final_exponentiation(&E::miller_loop(&[
// (&h_alpha_x_term.prepare(), &h_alpha_x_precomp),
// (&h_alpha_term.into_affine().prepare(), &h_alpha_precomp),
// (&h_term.prepare(), &h_prep),
// ])).unwrap() == E::Fqk::one();
// if !valid {
// return false;
// }
// }
// {
// let mut minus_yz = z_prime;
// minus_yz.mul_assign(&y);
// minus_yz.negate();
// let f_yz = proof.f_opening.mul(minus_yz.into_repr());
// let p2_r = multiexp(
// specialized_srs.p_2.iter(),
// challenges.iter()
// ).into_affine();
// let mut h_alpha_term = f_yz;
// h_alpha_term.add_assign(&g_v);
// let h_alpha_x_term = proof.f_opening;
// let h_term = p2_r;
// let valid = E::final_exponentiation(&E::miller_loop(&[
// (&h_alpha_x_term.prepare(), &h_alpha_x_precomp),
// (&h_alpha_term.into_affine().prepare(), &h_alpha_precomp),
// (&h_term.prepare(), &h_prep),
// ])).unwrap() == E::Fqk::one();
// if !valid {
// return false;
// }
// }
// true
// e(E,hαx)e(Ez,hα) = e(􏰗Mj=1Sjrj,h)e(gv,hα)
// e(F,hαx)e(Fyz,hα) = e(􏰗Mj=1P2jrj,h)e(gv,hα)
@ -635,6 +567,162 @@ impl<E: Engine> PermutationArgument<E> {
(&h_term.prepare(), &h_prep),
])).unwrap() == E::Fqk::one()
}
pub fn make_signature(
coefficients: Vec<Vec<E::Fr>>,
permutations: Vec<Vec<usize>>,
y: E::Fr,
z: E::Fr,
srs: &SRS<E>
) -> SignatureOfCorrectComputation<E> {
let mut argument = PermutationArgument::new(coefficients, permutations);
let commitments = argument.commit(y, &srs);
let mut transcript = Transcript::new(&[]);
let mut s_commitments = vec![];
let mut s_prime_commitments = vec![];
let mut challenges = vec![];
for (s, s_prime) in commitments.into_iter() {
{
let mut transcript = Transcript::new(&[]);
transcript.commit_point(&s);
transcript.commit_point(&s_prime);
let challenge = transcript.get_challenge_scalar();
challenges.push(challenge);
}
transcript.commit_point(&s);
transcript.commit_point(&s_prime);
s_commitments.push(s);
s_prime_commitments.push(s_prime);
}
let z_prime = transcript.get_challenge_scalar();
// TODO: create better way to get few distinct challenges from the transcript
let mut transcript = Transcript::new(&[]);
transcript.commit_scalar(&z_prime);
let beta: E::Fr = transcript.get_challenge_scalar();
let mut transcript = Transcript::new(&[]);
transcript.commit_scalar(&beta);
let gamma: E::Fr = transcript.get_challenge_scalar();
let s_prime_commitments_opening = argument.open_commitments_to_s_prime(&challenges, y, z_prime, &srs);
let (proof, grand_product_signature) = argument.make_argument_with_transcript(
beta,
gamma,
y,
z,
&srs
);
SignatureOfCorrectComputation {
s_commitments,
s_prime_commitments,
perm_argument_proof: proof,
perm_proof: s_prime_commitments_opening,
grand_product_signature
}
}
// Argument a permutation argument. Current implementation consumes, cause extra arguments are required
pub fn make_argument_with_transcript(self,
beta: E::Fr,
gamma: E::Fr,
y: E::Fr,
z: E::Fr,
srs: &SRS<E>
) -> (PermutationArgumentProof<E>, GrandProductSignature<E>) {
// Sj(P4j)β(P1j)γ is equal to the product of the coefficients of Sj(P3j)β(P1j)γ
// also open s = \sum self.permuted_coefficients(X, y) at z
let n = self.n;
let j = self.non_permuted_coefficients.len();
let mut s_polynomial: Option<Vec<E::Fr>> = None;
for c in self.permuted_at_y_coefficients.iter()
{
if s_polynomial.is_some() {
if let Some(poly) = s_polynomial.as_mut() {
add_polynomials(&mut poly[..], & c[..]);
}
} else {
s_polynomial = Some(c.clone());
}
}
let s_polynomial = s_polynomial.unwrap();
// evaluate at z
let s_zy = evaluate_at_consequitive_powers(& s_polynomial[..], z, z);
let mut s_zy_neg = s_zy;
s_zy_neg.negate();
let s_zy_opening = polynomial_commitment_opening(
0,
n,
Some(s_zy_neg).iter().chain_ext(s_polynomial.iter()),
z,
&srs
);
// Sj(P4j)^β (P1j)^γ is equal to the product of the coefficients of Sj(P3j)^β (P1j)^γ
let p_1_values = vec![E::Fr::one(); n];
let p_3_values: Vec<E::Fr> = (1..=n).map(|el| {
let mut repr = <<E as ScalarEngine>::Fr as PrimeField>::Repr::default();
repr.as_mut()[0] = el as u64;
let fe = E::Fr::from_repr(repr).unwrap();
fe
}).collect();
let mut grand_products = vec![];
for (i, ((non_permuted, permuted), permutation)) in self.non_permuted_coefficients.into_iter()
.zip(self.permuted_coefficients.into_iter())
.zip(self.permutations.into_iter()).enumerate()
{
// \prod si+βσi+γ = \prod s'i + β*i + γ
let mut s_j_combination = non_permuted;
{
let p_4_values: Vec<E::Fr> = permutation.into_iter().map(|el| {
let mut repr = <<E as ScalarEngine>::Fr as PrimeField>::Repr::default();
repr.as_mut()[0] = el as u64;
let fe = E::Fr::from_repr(repr).unwrap();
fe
}).collect();
mul_add_polynomials(&mut s_j_combination[..], & p_4_values[..], beta);
mul_add_polynomials(&mut s_j_combination[..], & p_1_values[..], gamma);
}
let mut s_prime_j_combination = permuted;
{
mul_add_polynomials(&mut s_prime_j_combination[..], & p_3_values[..], beta);
mul_add_polynomials(&mut s_prime_j_combination[..], & p_1_values[..], gamma);
}
grand_products.push((s_j_combination, s_prime_j_combination));
}
let grand_product_signature = GrandProductArgument::create_signature(
grand_products,
y,
z,
&srs
);
let proof = PermutationArgumentProof {
j: j,
s_opening: s_zy_opening,
s_zy: s_zy
};
(proof, grand_product_signature)
}
}
#[test]

@ -56,7 +56,7 @@ pub fn create_permutation_structure<E: Engine, C: Circuit<E>>(
let n = backend.n;
let q = backend.q;
println!("Will have {} gates and {} linear constraints", n, q);
// println!("Will have {} gates and {} linear constraints", n, q);
PermutationStructure::<E> {
n: n,
@ -369,8 +369,6 @@ impl<E: Engine> PermutationStructure<E> {
}
}
println!("naive s eval = {}", s_contrib);
let mut argument = PermutationArgument::new(non_permuted_coeffs, permutations);
let challenges = (0..m).map(|_| E::Fr::rand(rng)).collect::<Vec<_>>();

@ -7,6 +7,7 @@ use std::marker::PhantomData;
use crate::sonic::srs::SRS;
use crate::sonic::util::*;
use crate::sonic::transcript::{Transcript, TranscriptProtocol};
#[derive(Clone)]
pub struct WellformednessArgument<E: Engine> {
@ -15,11 +16,44 @@ pub struct WellformednessArgument<E: Engine> {
#[derive(Clone)]
pub struct WellformednessProof<E: Engine> {
l: E::G1Affine,
r: E::G1Affine
pub l: E::G1Affine,
pub r: E::G1Affine
}
#[derive(Clone)]
pub struct WellformednessSignature<E: Engine> {
pub commitments: Vec<E::G1Affine>,
pub proof: WellformednessProof<E>
}
impl<E: Engine> WellformednessArgument<E> {
pub fn create_signature(
all_polys: Vec<Vec<E::Fr>>,
srs: &SRS<E>
) -> WellformednessSignature<E> {
let j = all_polys.len();
let mut transcript = Transcript::new(&[]);
let wellformed_argument = WellformednessArgument::new(all_polys);
let commitments = wellformed_argument.commit(&srs);
let mut wellformed_challenges = vec![];
for c in commitments.iter() {
transcript.commit_point(c);
}
for _ in 0..j {
let challenge = transcript.get_challenge_scalar();
wellformed_challenges.push(challenge);
}
let proof = wellformed_argument.make_argument(wellformed_challenges, &srs);
WellformednessSignature {
commitments,
proof
}
}
pub fn new(polynomials: Vec<Vec<E::Fr>>) -> Self {
assert!(polynomials.len() > 0);