diff --git a/src/bin/bench_recursion.rs b/src/bin/bench_recursion.rs index 05bbe52f..577a88cc 100644 --- a/src/bin/bench_recursion.rs +++ b/src/bin/bench_recursion.rs @@ -26,9 +26,9 @@ fn bench_prove, const D: usize>() -> Result<()> { security_bits: 128, rate_bits: 3, num_challenges: 3, + zero_knowledge: false, fri_config: FriConfig { proof_of_work_bits: 20, - rate_bits: 3, reduction_arity_bits: vec![2, 2, 2, 2, 2, 2], num_query_rounds: 35, }, diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index cc47d290..86a10132 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -333,7 +333,9 @@ impl, const D: usize> CircuitBuilder { let final_poly_coeffs: usize = degree_estimate / arities.iter().product::(); let fri_openings = fri_queries * (1 + D * total_fri_folding_points + D * final_poly_coeffs); + // We add D for openings at zeta. let regular_poly_openings = D + fri_openings; + // We add 2 * D for openings at zeta and g * zeta. let z_openings = 2 * D + fri_openings; (regular_poly_openings, z_openings) @@ -364,6 +366,16 @@ impl, const D: usize> CircuitBuilder { } fn blind_and_pad(&mut self) { + if self.config.zero_knowledge { + self.blind(); + } + + while !self.gate_instances.len().is_power_of_two() { + self.add_gate_no_constants(NoopGate::get()); + } + } + + fn blind(&mut self) { let (regular_poly_openings, z_openings) = self.blinding_counts(); info!( "Adding {} blinding terms for witness polynomials, and {}*2 for Z polynomials", @@ -410,10 +422,6 @@ impl, const D: usize> CircuitBuilder { ); } } - - while !self.gate_instances.len().is_power_of_two() { - self.add_gate_no_constants(NoopGate::get()); - } } fn constant_polys( @@ -508,8 +516,8 @@ impl, const D: usize> CircuitBuilder { let constants_sigmas_vecs = [constant_vecs, sigma_vecs.clone()].concat(); let constants_sigmas_commitment = ListPolynomialCommitment::new( constants_sigmas_vecs, - self.config.fri_config.rate_bits, - PlonkPolynomials::CONSTANTS_SIGMAS.blinding, + self.config.rate_bits, + self.config.zero_knowledge & PlonkPolynomials::CONSTANTS_SIGMAS.blinding, ); let constants_sigmas_root = constants_sigmas_commitment.merkle_tree.root; diff --git a/src/circuit_data.rs b/src/circuit_data.rs index 3874f25b..b810347c 100644 --- a/src/circuit_data.rs +++ b/src/circuit_data.rs @@ -24,6 +24,7 @@ pub struct CircuitConfig { /// The number of challenge points to generate, for IOPs that have soundness errors of (roughly) /// `degree / |F|`. pub num_challenges: usize, + pub zero_knowledge: bool, // TODO: Find a better place for this. pub fri_config: FriConfig, @@ -37,9 +38,9 @@ impl Default for CircuitConfig { security_bits: 128, rate_bits: 3, num_challenges: 3, + zero_knowledge: true, fri_config: FriConfig { proof_of_work_bits: 1, - rate_bits: 3, reduction_arity_bits: vec![1, 1, 1, 1], num_query_rounds: 1, }, @@ -59,9 +60,9 @@ impl CircuitConfig { security_bits: 128, rate_bits: 3, num_challenges: 3, + zero_knowledge: true, fri_config: FriConfig { proof_of_work_bits: 1, - rate_bits: 3, reduction_arity_bits: vec![1, 1, 1, 1], num_query_rounds: 1, }, diff --git a/src/fri/mod.rs b/src/fri/mod.rs index 87fe3db5..ab7137c2 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -10,8 +10,6 @@ const EPSILON: f64 = 0.01; pub struct FriConfig { pub proof_of_work_bits: u32, - pub rate_bits: usize, - /// The arity of each FRI reduction step, expressed (i.e. the log2 of the actual arity). /// For example, `[3, 2, 1]` would describe a FRI reduction tree with 8-to-1 reduction, then /// a 4-to-1 reduction, then a 2-to-1 reduction. After these reductions, the reduced polynomial diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 056cc78d..bf4956a4 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -1,4 +1,5 @@ use crate::circuit_builder::CircuitBuilder; +use crate::circuit_data::CircuitConfig; use crate::circuit_data::CommonCircuitData; use crate::field::extension_field::target::{flatten_target, ExtensionTarget}; use crate::field::extension_field::Extendable; @@ -75,8 +76,8 @@ impl, const D: usize> CircuitBuilder { challenger: &mut RecursiveChallenger, common_data: &CommonCircuitData, ) { - let config = &common_data.config.fri_config; - let total_arities = config.reduction_arity_bits.iter().sum::(); + let config = &common_data.config; + let total_arities = config.fri_config.reduction_arity_bits.iter().sum::(); debug_assert_eq!( purported_degree_log, log2_strict(proof.final_poly.len()) + total_arities - config.rate_bits, @@ -98,16 +99,16 @@ impl, const D: usize> CircuitBuilder { challenger.observe_extension_elements(&proof.final_poly.0); self.set_context("Check PoW"); - self.fri_verify_proof_of_work(proof, challenger, config); + self.fri_verify_proof_of_work(proof, challenger, &config.fri_config); // Check that parameters are coherent. debug_assert_eq!( - config.num_query_rounds, + config.fri_config.num_query_rounds, proof.query_round_proofs.len(), "Number of query rounds does not match config." ); debug_assert!( - !config.reduction_arity_bits.is_empty(), + !config.fri_config.reduction_arity_bits.is_empty(), "Number of reductions should be non-zero." ); @@ -154,7 +155,7 @@ impl, const D: usize> CircuitBuilder { common_data: &CommonCircuitData, ) -> ExtensionTarget { assert!(D > 1, "Not implemented for D=1."); - let config = &self.config.fri_config.clone(); + let config = self.config.clone(); let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits; let subgroup_x = self.convert_to_ext(subgroup_x); let mut alpha = ReducingFactorTarget::new(alpha); @@ -171,9 +172,9 @@ impl, const D: usize> CircuitBuilder { PlonkPolynomials::QUOTIENT, ] .iter() - .flat_map(|&p| proof.unsalted_evals(p)) + .flat_map(|&p| proof.unsalted_evals(p, config.zero_knowledge)) .chain( - &proof.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS) + &proof.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge) [common_data.partial_products_range()], ) .map(|&e| self.convert_to_ext(e)) @@ -197,7 +198,7 @@ impl, const D: usize> CircuitBuilder { // Polynomials opened at `x` and `g x`, i.e., the Zs polynomials. let zs_evals = proof - .unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS) + .unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge) .iter() .take(common_data.zs_range().end) .map(|&e| self.convert_to_ext(e)) @@ -222,7 +223,7 @@ impl, const D: usize> CircuitBuilder { // Polynomials opened at `x` and `x.frobenius()`, i.e., the wires polynomials. let wire_evals = proof - .unsalted_evals(PlonkPolynomials::WIRES) + .unsalted_evals(PlonkPolynomials::WIRES, config.zero_knowledge) .iter() .map(|&e| self.convert_to_ext(e)) .collect::>(); diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 90fc907f..c13a0500 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -78,8 +78,8 @@ pub fn verify_fri_proof, const D: usize>( challenger: &mut Challenger, common_data: &CommonCircuitData, ) -> Result<()> { - let config = &common_data.config.fri_config; - let total_arities = config.reduction_arity_bits.iter().sum::(); + let config = &common_data.config; + let total_arities = config.fri_config.reduction_arity_bits.iter().sum::(); ensure!( purported_degree_log == log2_strict(proof.final_poly.len()) + total_arities - config.rate_bits, @@ -101,15 +101,15 @@ pub fn verify_fri_proof, const D: usize>( challenger.observe_extension_elements(&proof.final_poly.coeffs); // Check PoW. - fri_verify_proof_of_work(proof, challenger, config)?; + fri_verify_proof_of_work(proof, challenger, &config.fri_config)?; // Check that parameters are coherent. ensure!( - config.num_query_rounds == proof.query_round_proofs.len(), + config.fri_config.num_query_rounds == proof.query_round_proofs.len(), "Number of query rounds does not match config." ); ensure!( - !config.reduction_arity_bits.is_empty(), + !config.fri_config.reduction_arity_bits.is_empty(), "Number of reductions should be non-zero." ); @@ -151,7 +151,7 @@ fn fri_combine_initial, const D: usize>( subgroup_x: F, common_data: &CommonCircuitData, ) -> F::Extension { - let config = &common_data.config.fri_config; + let config = &common_data.config; assert!(D > 1, "Not implemented for D=1."); let degree_log = proof.evals_proofs[0].1.siblings.len() - config.rate_bits; let subgroup_x = F::Extension::from_basefield(subgroup_x); @@ -169,9 +169,9 @@ fn fri_combine_initial, const D: usize>( PlonkPolynomials::QUOTIENT, ] .iter() - .flat_map(|&p| proof.unsalted_evals(p)) + .flat_map(|&p| proof.unsalted_evals(p, config.zero_knowledge)) .chain( - &proof.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS) + &proof.unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge) [common_data.partial_products_range()], ) .map(|&e| F::Extension::from_basefield(e)); @@ -193,7 +193,7 @@ fn fri_combine_initial, const D: usize>( // Polynomials opened at `x` and `g x`, i.e., the Zs polynomials. let zs_evals = proof - .unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS) + .unsalted_evals(PlonkPolynomials::ZS_PARTIAL_PRODUCTS, config.zero_knowledge) .iter() .map(|&e| F::Extension::from_basefield(e)) .take(common_data.zs_range().end); @@ -213,7 +213,7 @@ fn fri_combine_initial, const D: usize>( // Polynomials opened at `x` and `x.frobenius()`, i.e., the wires polynomials. let wire_evals = proof - .unsalted_evals(PlonkPolynomials::WIRES) + .unsalted_evals(PlonkPolynomials::WIRES, config.zero_knowledge) .iter() .map(|&e| F::Extension::from_basefield(e)); let wire_composition_eval = alpha.clone().reduce(wire_evals); diff --git a/src/plonk_common.rs b/src/plonk_common.rs index 6fd0c393..62552c0a 100644 --- a/src/plonk_common.rs +++ b/src/plonk_common.rs @@ -15,8 +15,8 @@ pub struct PolynomialsIndexBlinding { pub(crate) blinding: bool, } impl PolynomialsIndexBlinding { - pub fn salt_size(&self) -> usize { - if self.blinding { + pub fn salt_size(&self, zero_knowledge: bool) -> usize { + if zero_knowledge & self.blinding { SALT_SIZE } else { 0 diff --git a/src/polynomial/commitment.rs b/src/polynomial/commitment.rs index 0b9e5bb0..756fec0a 100644 --- a/src/polynomial/commitment.rs +++ b/src/polynomial/commitment.rs @@ -18,6 +18,7 @@ use crate::timed; use crate::util::scaling::ReducingFactor; use crate::util::{log2_ceil, log2_strict, reverse_bits, reverse_index_bits_in_place, transpose}; +/// Two (~64 bit) field elements gives ~128 bit security. pub const SALT_SIZE: usize = 2; pub struct ListPolynomialCommitment { @@ -121,7 +122,7 @@ impl ListPolynomialCommitment { where F: Extendable, { - let config = &common_data.config.fri_config; + let config = &common_data.config; assert!(D > 1, "Not implemented for D=1."); let degree_log = commitments[0].degree_log; let g = F::Extension::primitive_root_of_unity(degree_log); @@ -208,7 +209,7 @@ impl ListPolynomialCommitment { &lde_final_poly, &lde_final_values, challenger, - &config, + &config.fri_config, ); ( @@ -351,7 +352,6 @@ mod tests { let degree_log = 11; let fri_config = FriConfig { proof_of_work_bits: 2, - rate_bits: 2, reduction_arity_bits: vec![2, 3, 1, 2], num_query_rounds: 3, }; @@ -376,7 +376,7 @@ mod tests { .map(|i| { ListPolynomialCommitment::::new( gen_random_test_case(ks[i], degree_log), - common_data.config.fri_config.rate_bits, + common_data.config.rate_bits, PlonkPolynomials::polynomials(i).blinding, ) }) diff --git a/src/proof.rs b/src/proof.rs index 85ef44b5..71edba03 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -110,9 +110,13 @@ pub struct FriInitialTreeProof { } impl FriInitialTreeProof { - pub(crate) fn unsalted_evals(&self, polynomials: PolynomialsIndexBlinding) -> &[F] { + pub(crate) fn unsalted_evals( + &self, + polynomials: PolynomialsIndexBlinding, + zero_knowledge: bool, + ) -> &[F] { let evals = &self.evals_proofs[polynomials.index].0; - &evals[..evals.len() - polynomials.salt_size()] + &evals[..evals.len() - polynomials.salt_size(zero_knowledge)] } } @@ -122,9 +126,13 @@ pub struct FriInitialTreeProofTarget { } impl FriInitialTreeProofTarget { - pub(crate) fn unsalted_evals(&self, polynomials: PolynomialsIndexBlinding) -> &[Target] { + pub(crate) fn unsalted_evals( + &self, + polynomials: PolynomialsIndexBlinding, + zero_knowledge: bool, + ) -> &[Target] { let evals = &self.evals_proofs[polynomials.index].0; - &evals[..evals.len() - polynomials.salt_size()] + &evals[..evals.len() - polynomials.salt_size(zero_knowledge)] } } diff --git a/src/prover.rs b/src/prover.rs index 5174362d..e7c85130 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -24,7 +24,6 @@ pub(crate) fn prove, const D: usize>( common_data: &CommonCircuitData, inputs: PartialWitness, ) -> Result> { - let fri_config = &common_data.config.fri_config; let config = &common_data.config; let num_wires = config.num_wires; let num_challenges = config.num_challenges; @@ -70,8 +69,8 @@ pub(crate) fn prove, const D: usize>( let wires_commitment = timed!( ListPolynomialCommitment::new( wires_values, - fri_config.rate_bits, - PlonkPolynomials::WIRES.blinding + config.rate_bits, + config.zero_knowledge & PlonkPolynomials::WIRES.blinding ), "to compute wires commitment" ); @@ -106,8 +105,8 @@ pub(crate) fn prove, const D: usize>( let zs_partial_products_commitment = timed!( ListPolynomialCommitment::new( zs_partial_products, - fri_config.rate_bits, - PlonkPolynomials::ZS_PARTIAL_PRODUCTS.blinding + config.rate_bits, + config.zero_knowledge & PlonkPolynomials::ZS_PARTIAL_PRODUCTS.blinding ), "to commit to Z's" ); @@ -149,8 +148,8 @@ pub(crate) fn prove, const D: usize>( let quotient_polys_commitment = timed!( ListPolynomialCommitment::new_from_polys( all_quotient_poly_chunks, - fri_config.rate_bits, - PlonkPolynomials::QUOTIENT.blinding + config.rate_bits, + config.zero_knowledge & PlonkPolynomials::QUOTIENT.blinding ), "to commit to quotient polys" ); diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 346ba3e8..4a33e521 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -326,9 +326,9 @@ mod tests { security_bits: 128, rate_bits: 3, num_challenges: 3, + zero_knowledge: false, fri_config: FriConfig { proof_of_work_bits: 1, - rate_bits: 3, reduction_arity_bits: vec![2, 2, 2, 2, 2, 2, 2], num_query_rounds: 40, },