start eliminating excessive commitments

This commit is contained in:
Alex Vlasov 2019-06-07 20:07:01 +03:00
parent d4dd7d27fa
commit eaaff874fc
4 changed files with 150 additions and 54 deletions

@ -22,11 +22,11 @@ pub struct GrandProductArgument<E: Engine> {
#[derive(Clone)] #[derive(Clone)]
pub struct GrandProductProof<E: Engine> { pub struct GrandProductProof<E: Engine> {
t_opening: E::G1Affine, pub t_opening: E::G1Affine,
e_zinv: E::Fr, pub e_zinv: E::Fr,
e_opening: E::G1Affine, pub e_opening: E::G1Affine,
f_y: E::Fr, pub f_y: E::Fr,
f_opening: E::G1Affine, pub f_opening: E::G1Affine,
} }
#[derive(Clone)] #[derive(Clone)]
@ -43,6 +43,7 @@ pub struct GrandProductSignature<E: Engine> {
impl<E: Engine> GrandProductArgument<E> { impl<E: Engine> GrandProductArgument<E> {
pub fn create_signature( pub fn create_signature(
transcript: &mut Transcript,
grand_products: Vec<(Vec<E::Fr>, Vec<E::Fr>)>, grand_products: Vec<(Vec<E::Fr>, Vec<E::Fr>)>,
y: E::Fr, y: E::Fr,
z: E::Fr, z: E::Fr,
@ -51,27 +52,27 @@ impl<E: Engine> GrandProductArgument<E> {
let mut a_commitments = vec![]; let mut a_commitments = vec![];
let mut b_commitments = vec![]; let mut b_commitments = vec![];
let mut transcript = Transcript::new(&[]);
let mut grand_product_challenges = vec![]; let mut grand_product_challenges = vec![];
// TODO: Remove
for (a, b) in grand_products.iter() { for (a, b) in grand_products.iter() {
let (c_a, c_b) = GrandProductArgument::commit_for_individual_products(& a[..], & b[..], &srs); 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); a_commitments.push(c_a);
b_commitments.push(c_b); b_commitments.push(c_b);
transcript.commit_point(&c_a); }
transcript.commit_point(&c_b);
for _ in 0..grand_products.len() {
let c = transcript.get_challenge_scalar();
grand_product_challenges.push(c);
} }
let mut all_polys = vec![]; let mut all_polys = vec![];
let mut wellformed_challenges = vec![];
for c in 0..(grand_products.len()*2) {
let c = transcript.get_challenge_scalar();
wellformed_challenges.push(c);
}
for p in grand_products.iter() { for p in grand_products.iter() {
let (a, b) = p; let (a, b) = p;
all_polys.push(a.clone()); all_polys.push(a.clone());
@ -80,9 +81,22 @@ impl<E: Engine> GrandProductArgument<E> {
let wellformedness_signature = WellformednessArgument::create_signature( let wellformedness_signature = WellformednessArgument::create_signature(
all_polys, all_polys,
wellformed_challenges,
&srs &srs
); );
// sanity check
for (j, (a, b)) in a_commitments.iter()
.zip(b_commitments.iter())
.enumerate()
{
let a_corr = wellformedness_signature.commitments[2*j];
let b_corr = wellformedness_signature.commitments[2*j + 1];
assert!(a_corr == *a);
assert!(b_corr == *b);
}
let mut grand_product_argument = GrandProductArgument::new(grand_products); let mut grand_product_argument = GrandProductArgument::new(grand_products);
let c_commitments = grand_product_argument.commit_to_individual_c_polynomials(&srs); let c_commitments = grand_product_argument.commit_to_individual_c_polynomials(&srs);
@ -121,7 +135,7 @@ impl<E: Engine> GrandProductArgument<E> {
// c_3 = a_3 * c_2 = a_3 * a_2 * a_1 // c_3 = a_3 * c_2 = a_3 * a_2 * a_1
// ... // ...
// c_n = a_n * c_{n-1} = \prod a_i // c_n = a_n * c_{n-1} = \prod a_i
// a_{n+1} = c_{n-1}^-1 // a_{n+1} = c_{n}^-1
// c_{n+1} = 1 // c_{n+1} = 1
// c_{n+1} = a_{n+2} * c_{n+1} = a_{n+2} // c_{n+1} = a_{n+2} * c_{n+1} = a_{n+2}
// ... // ...
@ -144,8 +158,14 @@ impl<E: Engine> GrandProductArgument<E> {
} }
assert_eq!(c_poly.len(), n); assert_eq!(c_poly.len(), n);
a_poly.extend(p0); a_poly.extend(p0);
assert_eq!(a_poly.len(), n);
// v = a_{n+1} = c_{n}^-1 // v = a_{n+1} = c_{n}^-1
let v = c_poly[n-1].inverse().unwrap(); // let v = c_poly[n-1].inverse().unwrap();
let v = c_coeff.inverse().unwrap();
// ! IMPORTANT
// This line is indeed assigning a_{n+1} to zero instead of v
// for the practical purpose later we manually evaluate T polynomial
// and assign v to the term X^{n+1}
a_poly.push(E::Fr::zero()); a_poly.push(E::Fr::zero());
// a_poly.push(v); // a_poly.push(v);
// add c_{n+1} // add c_{n+1}
@ -160,6 +180,7 @@ impl<E: Engine> GrandProductArgument<E> {
a_poly.extend(p1); a_poly.extend(p1);
assert_eq!(c_poly[n-1], c_poly[2*n]); assert_eq!(c_poly[n-1], c_poly[2*n]);
assert_eq!(c_poly[n], E::Fr::one());
a_polynomials.push(a_poly); a_polynomials.push(a_poly);
c_polynomials.push(c_poly); c_polynomials.push(c_poly);
@ -280,7 +301,7 @@ impl<E: Engine> GrandProductArgument<E> {
.zip(challenges.iter()) .zip(challenges.iter())
{ {
let mut a_xy = a.clone(); let mut a_xy = a.clone();
let mut c_xy = c.clone(); let c_xy = c.clone();
let v = *v; let v = *v;
assert_eq!(a_xy.len(), 2*n + 1); assert_eq!(a_xy.len(), 2*n + 1);
@ -356,7 +377,7 @@ impl<E: Engine> GrandProductArgument<E> {
val.add_assign(&E::Fr::one()); val.add_assign(&E::Fr::one());
// subtract at constant term // subtract a constant term
assert_eq!(t[2*n+1], val); assert_eq!(t[2*n+1], val);
t[2*n+1].sub_assign(&val); t[2*n+1].sub_assign(&val);

@ -25,6 +25,7 @@ pub struct SpecializedSRS<E: Engine> {
#[derive(Clone)] #[derive(Clone)]
pub struct PermutationArgument<E: Engine> { pub struct PermutationArgument<E: Engine> {
non_permuted_coefficients: Vec<Vec<E::Fr>>, non_permuted_coefficients: Vec<Vec<E::Fr>>,
non_permuted_at_y_coefficients: Vec<Vec<E::Fr>>,
permuted_coefficients: Vec<Vec<E::Fr>>, permuted_coefficients: Vec<Vec<E::Fr>>,
permuted_at_y_coefficients: Vec<Vec<E::Fr>>, permuted_at_y_coefficients: Vec<Vec<E::Fr>>,
permutations: Vec<Vec<usize>>, permutations: Vec<Vec<usize>>,
@ -96,6 +97,7 @@ impl<E: Engine> PermutationArgument<E> {
PermutationArgument { PermutationArgument {
non_permuted_coefficients: coefficients, non_permuted_coefficients: coefficients,
non_permuted_at_y_coefficients: vec![vec![]],
permuted_coefficients: vec![vec![]], permuted_coefficients: vec![vec![]],
permuted_at_y_coefficients: vec![vec![]], permuted_at_y_coefficients: vec![vec![]],
permutations: permutations, permutations: permutations,
@ -166,6 +168,7 @@ impl<E: Engine> PermutationArgument<E> {
let n = self.non_permuted_coefficients[0].len(); let n = self.non_permuted_coefficients[0].len();
let mut non_permuted_at_y_coefficients = vec![];
let mut permuted_coefficients = vec![]; let mut permuted_coefficients = vec![];
let mut permuted_at_y_coefficients = vec![]; let mut permuted_at_y_coefficients = vec![];
@ -206,7 +209,6 @@ impl<E: Engine> PermutationArgument<E> {
mut_distribute_consequitive_powers(&mut non_permuted_at_y[..], y, y); mut_distribute_consequitive_powers(&mut non_permuted_at_y[..], y, y);
// and commit to S' // and commit to S'
let s_prime = multiexp(srs.g_positive_x_alpha[0..n].iter(), non_permuted_at_y.iter()).into_affine(); let s_prime = multiexp(srs.g_positive_x_alpha[0..n].iter(), non_permuted_at_y.iter()).into_affine();
drop(non_permuted_at_y);
// this construction has already moved coeff[i] to the corresponding constraint k, so term is coeff[i]*Y^{K} for place K // this construction has already moved coeff[i] to the corresponding constraint k, so term is coeff[i]*Y^{K} for place K
mut_distribute_consequitive_powers(&mut permuted_at_y[..], y, y); mut_distribute_consequitive_powers(&mut permuted_at_y[..], y, y);
@ -219,10 +221,12 @@ impl<E: Engine> PermutationArgument<E> {
result.push((s, s_prime)); result.push((s, s_prime));
non_permuted_at_y_coefficients.push(non_permuted_at_y);
permuted_coefficients.push(permuted); permuted_coefficients.push(permuted);
permuted_at_y_coefficients.push(permuted_at_y); permuted_at_y_coefficients.push(permuted_at_y);
} }
self.non_permuted_at_y_coefficients = non_permuted_at_y_coefficients;
self.permuted_coefficients = permuted_coefficients; self.permuted_coefficients = permuted_coefficients;
self.permuted_at_y_coefficients = permuted_at_y_coefficients; self.permuted_at_y_coefficients = permuted_at_y_coefficients;
@ -573,7 +577,8 @@ impl<E: Engine> PermutationArgument<E> {
permutations: Vec<Vec<usize>>, permutations: Vec<Vec<usize>>,
y: E::Fr, y: E::Fr,
z: E::Fr, z: E::Fr,
srs: &SRS<E> srs: &SRS<E>,
specialized_srs: &SpecializedSRS<E>,
) -> SignatureOfCorrectComputation<E> { ) -> SignatureOfCorrectComputation<E> {
let mut argument = PermutationArgument::new(coefficients, permutations); let mut argument = PermutationArgument::new(coefficients, permutations);
let commitments = argument.commit(y, &srs); let commitments = argument.commit(y, &srs);
@ -597,24 +602,46 @@ impl<E: Engine> PermutationArgument<E> {
} }
let z_prime = transcript.get_challenge_scalar(); 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 s_prime_commitments_opening = argument.open_commitments_to_s_prime(&challenges, y, z_prime, &srs);
let (proof, grand_product_signature) = {
// TODO: create better way to get few distinct challenges from the transcript
let (proof, grand_product_signature) = argument.make_argument_with_transcript( let (proof, grand_product_signature) = argument.make_argument_with_transcript(
beta, &mut transcript,
gamma,
y, y,
z, z,
&srs &srs
); );
(proof, grand_product_signature)
};
// TODO: sanity check for now,
// later eliminate a and b commitments
// for (j, (((a, b), s), s_prime)) in grand_product_signature.a_commitments.iter()
// .zip(grand_product_signature.b_commitments.iter())
// .zip(s_commitments.iter())
// .zip(s_prime_commitments.iter())
// .enumerate()
// {
// // Sj(P4j)β(P1j)γ
// let mut lhs = s.into_projective();
// lhs.add_assign(&specialized_srs.p_4[j].mul(beta.into_repr()));
// lhs.add_assign(&specialized_srs.p_1.mul(gamma.into_repr()));
// assert!(lhs.into_affine() == *a);
// // Sj(P3j)β(P1j)γ
// let mut rhs = s_prime.into_projective();
// rhs.add_assign(&specialized_srs.p_3.mul(beta.into_repr()));
// rhs.add_assign(&specialized_srs.p_1.mul(gamma.into_repr()));
// assert!(rhs.into_affine() == *b);
// }
SignatureOfCorrectComputation { SignatureOfCorrectComputation {
s_commitments, s_commitments,
s_prime_commitments, s_prime_commitments,
@ -627,12 +654,14 @@ impl<E: Engine> PermutationArgument<E> {
// Argument a permutation argument. Current implementation consumes, cause extra arguments are required // Argument a permutation argument. Current implementation consumes, cause extra arguments are required
pub fn make_argument_with_transcript(self, pub fn make_argument_with_transcript(self,
beta: E::Fr, transcript: &mut Transcript,
gamma: E::Fr,
y: E::Fr, y: E::Fr,
z: E::Fr, z: E::Fr,
srs: &SRS<E> srs: &SRS<E>
) -> (PermutationArgumentProof<E>, GrandProductSignature<E>) { ) -> (PermutationArgumentProof<E>, GrandProductSignature<E>) {
let beta: E::Fr = transcript.get_challenge_scalar();
let gamma: E::Fr = transcript.get_challenge_scalar();
// Sj(P4j)β(P1j)γ is equal to the product of the coefficients of Sj(P3j)β(P1j)γ // 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 // also open s = \sum self.permuted_coefficients(X, y) at z
@ -679,13 +708,22 @@ impl<E: Engine> PermutationArgument<E> {
let mut grand_products = vec![]; let mut grand_products = vec![];
for (i, ((non_permuted, permuted), permutation)) in self.non_permuted_coefficients.into_iter() // TODO: Check the validity!
for ((non_permuted, permuted), permutation) in self.non_permuted_coefficients.into_iter()
.zip(self.permuted_coefficients.into_iter()) .zip(self.permuted_coefficients.into_iter())
.zip(self.permutations.into_iter()).enumerate() .zip(self.permutations.into_iter())
// for ((non_permuted, permuted), permutation) in self.non_permuted_at_y_coefficients.into_iter()
// .zip(self.permuted_at_y_coefficients.into_iter())
// .zip(self.permutations.into_iter())
{ {
// \prod si+βσi+γ = \prod s'i + β*i + γ // \prod si+βσi+γ = \prod s'i + β*i + γ
// s combination is coeff[sigma(i)]*Y^{sigma(i)} + beta*sigma(i) + gamma
let mut s_j_combination = non_permuted; let mut s_j_combination = non_permuted;
// let mut s_j_combination = permuted;
{ {
let p_4_values: Vec<E::Fr> = permutation.into_iter().map(|el| { let p_4_values: Vec<E::Fr> = permutation.into_iter().map(|el| {
let mut repr = <<E as ScalarEngine>::Fr as PrimeField>::Repr::default(); let mut repr = <<E as ScalarEngine>::Fr as PrimeField>::Repr::default();
@ -699,15 +737,35 @@ impl<E: Engine> PermutationArgument<E> {
} }
let mut s_prime_j_combination = permuted; let mut s_prime_j_combination = permuted;
// let mut s_prime_j_combination = non_permuted;
// s' combination is coeff[i]*Y^{i} + beta*i + gamma
{ {
mul_add_polynomials(&mut s_prime_j_combination[..], & p_3_values[..], beta); mul_add_polynomials(&mut s_prime_j_combination[..], & p_3_values[..], beta);
mul_add_polynomials(&mut s_prime_j_combination[..], & p_1_values[..], gamma); mul_add_polynomials(&mut s_prime_j_combination[..], & p_1_values[..], gamma);
} }
// Sanity check
let product = s_j_combination.iter().fold(E::Fr::one(), |mut sum, x|
{
sum.mul_assign(&x);
sum
});
let product_prime = s_prime_j_combination.iter().fold(E::Fr::one(), |mut sum, x|
{
sum.mul_assign(&x);
sum
});
assert_eq!(product, product_prime);
grand_products.push((s_j_combination, s_prime_j_combination)); grand_products.push((s_j_combination, s_prime_j_combination));
} }
let grand_product_signature = GrandProductArgument::create_signature( let grand_product_signature = GrandProductArgument::create_signature(
transcript,
grand_products, grand_products,
y, y,
z, z,

@ -335,6 +335,25 @@ impl<E: Engine> PermutationStructure<E> {
specialized_srs specialized_srs
} }
pub fn make_signature(&self, y: E::Fr, z: E::Fr, srs: &SRS<E>) {
let (non_permuted_coeffs, permutations) = self.create_permutation_vectors();
let specialized_srs = PermutationArgument::make_specialized_srs(
&non_permuted_coeffs,
&permutations,
&srs
);
let signature = PermutationArgument::make_signature(
non_permuted_coeffs,
permutations,
y,
z,
&srs,
&specialized_srs
);
}
pub fn create_permutation_arguments<R: Rng>(&self, y: E::Fr, z: E::Fr, rng: &mut R, srs: &SRS<E>) pub fn create_permutation_arguments<R: Rng>(&self, y: E::Fr, z: E::Fr, rng: &mut R, srs: &SRS<E>)
-> (Vec<(E::G1Affine, E::G1Affine)>, Vec<E::Fr>, PermutationProof<E>, PermutationArgumentProof<E>, E::Fr, usize, E::Fr) -> (Vec<(E::G1Affine, E::G1Affine)>, Vec<E::Fr>, PermutationProof<E>, PermutationArgumentProof<E>, E::Fr, usize, E::Fr)
{ {
@ -496,6 +515,7 @@ fn test_simple_succinct_sonic() {
let perm_structure = create_permutation_structure::<Bls12, _>(&MyCircuit); let perm_structure = create_permutation_structure::<Bls12, _>(&MyCircuit);
perm_structure.create_permutation_arguments(x, y, rng, &srs); perm_structure.create_permutation_arguments(x, y, rng, &srs);
perm_structure.make_signature(x, y, &srs);
let s2 = S2Eval::new(perm_structure.n); let s2 = S2Eval::new(perm_structure.n);
let s2 = s2.evaluate(x, y, &srs); let s2 = s2.evaluate(x, y, &srs);
let mut s2_value = s2.c_value; let mut s2_value = s2.c_value;
@ -521,13 +541,8 @@ fn test_simple_succinct_sonic() {
expected_s2_value.add_assign(&p2); expected_s2_value.add_assign(&p2);
println!("s2 value = {}", s2_value);
println!("expected s2 value = {}", expected_s2_value);
assert!(expected_s2_value == s2_value); assert!(expected_s2_value == s2_value);
println!("N = {}, Q = {}", perm_structure.n, perm_structure.q); println!("N = {}, Q = {}", perm_structure.n, perm_structure.q);
} }
} }

@ -30,21 +30,23 @@ impl<E: Engine> WellformednessArgument<E> {
pub fn create_signature( pub fn create_signature(
all_polys: Vec<Vec<E::Fr>>, all_polys: Vec<Vec<E::Fr>>,
wellformed_challenges: Vec<E::Fr>,
srs: &SRS<E> srs: &SRS<E>
) -> WellformednessSignature<E> { ) -> WellformednessSignature<E> {
let j = all_polys.len(); let j = all_polys.len();
let mut transcript = Transcript::new(&[]); let mut transcript = Transcript::new(&[]);
let wellformed_argument = WellformednessArgument::new(all_polys); let wellformed_argument = WellformednessArgument::new(all_polys);
let commitments = wellformed_argument.commit(&srs); let commitments = wellformed_argument.commit(&srs);
let mut wellformed_challenges = vec![]; // let mut wellformed_challenges = vec![];
for c in commitments.iter() { // for c in commitments.iter() {
transcript.commit_point(c); // transcript.commit_point(c);
} // }
for _ in 0..j { // // TODO
let challenge = transcript.get_challenge_scalar(); // for _ in 0..j {
wellformed_challenges.push(challenge); // let challenge = transcript.get_challenge_scalar();
} // wellformed_challenges.push(challenge);
// }
let proof = wellformed_argument.make_argument(wellformed_challenges, &srs); let proof = wellformed_argument.make_argument(wellformed_challenges, &srs);