From a312c3853a853c0149c5a393113f6848d5e941a4 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 1 Jul 2022 01:31:42 +0800 Subject: [PATCH 1/3] mask splitting polys for zk --- plonk/src/proof_system/prover.rs | 37 ++++++++++++++++++++++++++------ plonk/src/proof_system/snark.rs | 1 + 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/plonk/src/proof_system/prover.rs b/plonk/src/proof_system/prover.rs index 43d59994d..ba58baf34 100644 --- a/plonk/src/proof_system/prover.rs +++ b/plonk/src/proof_system/prover.rs @@ -17,7 +17,7 @@ use crate::{ proof_system::structs::CommitKey, }; use ark_ec::PairingEngine; -use ark_ff::{FftField, Field, One, Zero}; +use ark_ff::{FftField, Field, One, UniformRand, Zero}; use ark_poly::{ univariate::DensePolynomial, EvaluationDomain, GeneralEvaluationDomain, Polynomial, Radix2EvaluationDomain, UVPolynomial, @@ -162,8 +162,9 @@ impl Prover { /// Round 3: Return the splitted quotient polynomials and their commitments. /// Note that the first `num_wire_types`-1 splitted quotient polynomials /// have degree `domain_size`+1. - pub(crate) fn run_3rd_round( + pub(crate) fn run_3rd_round( &self, + prng: &mut R, ck: &CommitKey, pks: &[&ProvingKey], challenges: &Challenges, @@ -172,7 +173,7 @@ impl Prover { ) -> Result, PlonkError> { let quot_poly = self.compute_quotient_polynomial(challenges, pks, online_oracles, num_wire_types)?; - let split_quot_polys = self.split_quotient_polynomial("_poly, num_wire_types)?; + let split_quot_polys = self.split_quotient_polynomial(prng, "_poly, num_wire_types)?; let split_quot_poly_comms = Self::commit_polynomials(ck, &split_quot_polys)?; Ok((split_quot_poly_comms, split_quot_polys)) @@ -895,8 +896,9 @@ impl Prover { /// Split the quotient polynomial into `num_wire_types` polynomials. /// The first `num_wire_types`-1 polynomials have degree `domain_size`+1. - fn split_quotient_polynomial( + fn split_quotient_polynomial( &self, + prng: &mut R, quot_poly: &DensePolynomial, num_wire_types: usize, ) -> Result>, PlonkError> { @@ -905,7 +907,7 @@ impl Prover { return Err(WrongQuotientPolyDegree(quot_poly.degree(), expected_degree).into()); } let n = self.domain.size(); - let split_quot_polys = (0..num_wire_types) + let mut split_quot_polys: Vec> = (0..num_wire_types) .into_par_iter() .map(|i| { let end = if i < num_wire_types - 1 { @@ -919,6 +921,29 @@ impl Prover { ) }) .collect(); + + // mask splitting polynomials + // t'(X) = t(X) - b_last + b_now * X^(n+2) + // with t'_lowest(X) = t_lowest(X) - 0 + b_now * X^(n+2) + // and t'_highest(X) = t_highest(X) - b_last + let mut last_randomizer = E::Fr::zero(); + split_quot_polys + .iter_mut() + .take(num_wire_types - 1) + .for_each(|poly| { + let now_randomizer = E::Fr::rand(prng); + + let mut coeffs = vec![E::Fr::zero(); n + 3]; + coeffs[0] = last_randomizer.neg(); + coeffs[n + 2] = now_randomizer; + *poly += &DensePolynomial::from_coefficients_vec(coeffs); + + last_randomizer = now_randomizer; + }); + // mask the highest splitting poly + split_quot_polys[num_wire_types - 1] += + &DensePolynomial::from_coefficients_vec(vec![last_randomizer.neg()]); + Ok(split_quot_polys) } @@ -1108,7 +1133,7 @@ mod test { let rng = &mut test_rng(); let bad_quot_poly = DensePolynomial::::rand(25, rng); assert!(prover - .split_quotient_polynomial(&bad_quot_poly, GATE_WIDTH + 1) + .split_quotient_polynomial(rng, &bad_quot_poly, GATE_WIDTH + 1) .is_err()); Ok(()) } diff --git a/plonk/src/proof_system/snark.rs b/plonk/src/proof_system/snark.rs index c18330658..44f9798b5 100644 --- a/plonk/src/proof_system/snark.rs +++ b/plonk/src/proof_system/snark.rs @@ -429,6 +429,7 @@ where // Round 3 challenges.alpha = transcript.get_and_append_challenge::(b"alpha")?; let (split_quot_poly_comms, split_quot_polys) = prover.run_3rd_round( + prng, &prove_keys[0].commit_key, prove_keys, &challenges, From 789b40fee48c8794f1dcc39c2e5fc3e1fd6166ff Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 1 Jul 2022 23:04:39 +0800 Subject: [PATCH 2/3] better readability --- plonk/src/proof_system/prover.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/plonk/src/proof_system/prover.rs b/plonk/src/proof_system/prover.rs index ba58baf34..4974cdea6 100644 --- a/plonk/src/proof_system/prover.rs +++ b/plonk/src/proof_system/prover.rs @@ -896,6 +896,14 @@ impl Prover { /// Split the quotient polynomial into `num_wire_types` polynomials. /// The first `num_wire_types`-1 polynomials have degree `domain_size`+1. + /// + /// Let t(X) be the input quotient polynomial, t_i(X) be the output + /// splitting polynomials. t(X) = \sum_{i=0}^{num_wire_types} + /// X^{i*(n+2)} * t_i(X) + /// + /// NOTE: we have a step polynomial of X^(n+2) instead of X^n as in the + /// GWC19 paper to achieve better balance among degrees of all splitting + /// polynomials (especially the highest-degree/last one). fn split_quotient_polynomial( &self, prng: &mut R, @@ -907,6 +915,8 @@ impl Prover { return Err(WrongQuotientPolyDegree(quot_poly.degree(), expected_degree).into()); } let n = self.domain.size(); + // compute the splitting polynomials t'_i(X) s.t. t(X) = + // \sum_{i=0}^{num_wire_types} X^{i*(n+2)} * t'_i(X) let mut split_quot_polys: Vec> = (0..num_wire_types) .into_par_iter() .map(|i| { @@ -922,10 +932,10 @@ impl Prover { }) .collect(); - // mask splitting polynomials - // t'(X) = t(X) - b_last + b_now * X^(n+2) - // with t'_lowest(X) = t_lowest(X) - 0 + b_now * X^(n+2) - // and t'_highest(X) = t_highest(X) - b_last + // mask splitting polynomials t_i(X), for i in {0..num_wire_types}. + // t_i(X) = t'_i(X) - b_last_i + b_now_i * X^(n+2) + // with t_lowest_i(X) = t_lowest_i(X) - 0 + b_now_i * X^(n+2) + // and t_highest_i(X) = t_highest_i(X) - b_last_i let mut last_randomizer = E::Fr::zero(); split_quot_polys .iter_mut() @@ -933,16 +943,14 @@ impl Prover { .for_each(|poly| { let now_randomizer = E::Fr::rand(prng); - let mut coeffs = vec![E::Fr::zero(); n + 3]; - coeffs[0] = last_randomizer.neg(); - coeffs[n + 2] = now_randomizer; - *poly += &DensePolynomial::from_coefficients_vec(coeffs); + poly.coeffs[0] -= last_randomizer; + assert_eq!(poly.degree(), n + 1); + poly.coeffs.push(now_randomizer); last_randomizer = now_randomizer; }); // mask the highest splitting poly - split_quot_polys[num_wire_types - 1] += - &DensePolynomial::from_coefficients_vec(vec![last_randomizer.neg()]); + split_quot_polys[num_wire_types - 1].coeffs[0] -= last_randomizer; Ok(split_quot_polys) } From f1d0db6ebecdec217a0a6df57ce7bf58d5e7f29c Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Fri, 1 Jul 2022 23:25:16 +0800 Subject: [PATCH 3/3] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eeecfeb24..ac4b00037 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Pending +- Splitting polynomials are masked to ensure zero-knowledge of Plonk (#76) + ## v0.1.2 ### Improvements