From f92ce1a80c5466deed21561fc79acaa20d897295 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 30 Sep 2021 06:56:32 +0200 Subject: [PATCH] Add CompressedProof type --- src/fri/commitment.rs | 4 +- src/fri/proof.rs | 21 ++---- src/fri/prover.rs | 6 +- src/fri/verifier.rs | 6 +- src/plonk/get_challenges.rs | 117 +++++++++++++++++++++++++------- src/plonk/proof.rs | 128 ++++++++++++++++++++++++++---------- src/plonk/prover.rs | 2 +- src/plonk/verifier.rs | 18 +---- 8 files changed, 205 insertions(+), 97 deletions(-) diff --git a/src/fri/commitment.rs b/src/fri/commitment.rs index 738d7b8f..c704c33c 100644 --- a/src/fri/commitment.rs +++ b/src/fri/commitment.rs @@ -3,7 +3,7 @@ use rayon::prelude::*; use crate::field::extension_field::Extendable; use crate::field::fft::FftRootTable; use crate::field::field_types::{Field, RichField}; -use crate::fri::proof::DecompressedFriProof; +use crate::fri::proof::FriProof; use crate::fri::prover::fri_proof; use crate::hash::merkle_tree::MerkleTree; use crate::iop::challenger::Challenger; @@ -128,7 +128,7 @@ impl PolynomialBatchCommitment { challenger: &mut Challenger, common_data: &CommonCircuitData, timing: &mut TimingTree, - ) -> (DecompressedFriProof, OpeningSet) + ) -> (FriProof, OpeningSet) where F: RichField + Extendable, { diff --git a/src/fri/proof.rs b/src/fri/proof.rs index 8b6f98fe..b6402733 100644 --- a/src/fri/proof.rs +++ b/src/fri/proof.rs @@ -89,14 +89,7 @@ pub struct CompressedFriQueryRounds, const D: usize> { #[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] #[serde(bound = "")] -pub enum FriProof, const D: usize> { - Decompressed(DecompressedFriProof), - Compressed(CompressedFriProof), -} - -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] -#[serde(bound = "")] -pub struct DecompressedFriProof, const D: usize> { +pub struct FriProof, const D: usize> { /// A Merkle cap for each reduced polynomial in the commit phase. pub commit_phase_merkle_caps: Vec>, /// Query rounds proofs @@ -107,7 +100,6 @@ pub struct DecompressedFriProof, const D: usize> { pub pow_witness: F, } -/// Corresponds to `DecompressedFriProof`. pub struct FriProofTarget { pub commit_phase_merkle_caps: Vec, pub query_round_proofs: Vec>, @@ -128,15 +120,14 @@ pub struct CompressedFriProof, const D: usize> { pub pow_witness: F, } -impl, const D: usize> DecompressedFriProof { +impl, const D: usize> FriProof { /// Compress all the Merkle paths in the FRI proof and remove duplicate indices. pub fn compress( self, indices: &[usize], common_data: &CommonCircuitData, - with_indices: bool, ) -> CompressedFriProof { - let DecompressedFriProof { + let FriProof { commit_phase_merkle_caps, query_round_proofs, final_poly, @@ -209,7 +200,7 @@ impl, const D: usize> DecompressedFriProof { .initial_trees_proofs .insert(index, initial_proof); for j in 0..num_reductions { - index >>= reduction_arity_bits[i]; + index >>= reduction_arity_bits[j]; let query_step = FriQueryStep { evals: steps_evals[j][i].clone(), merkle_proof: steps_proofs[j][i].clone(), @@ -233,7 +224,7 @@ impl, const D: usize> CompressedFriProof { self, indices: &[usize], common_data: &CommonCircuitData, - ) -> DecompressedFriProof { + ) -> FriProof { let CompressedFriProof { commit_phase_merkle_caps, query_round_proofs, @@ -323,7 +314,7 @@ impl, const D: usize> CompressedFriProof { }) } - DecompressedFriProof { + FriProof { commit_phase_merkle_caps, query_round_proofs: decompressed_query_proofs, final_poly, diff --git a/src/fri/prover.rs b/src/fri/prover.rs index 7bbff557..a0d71d98 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -2,7 +2,7 @@ use rayon::prelude::*; use crate::field::extension_field::{flatten, unflatten, Extendable}; use crate::field::field_types::RichField; -use crate::fri::proof::{DecompressedFriProof, FriInitialTreeProof, FriQueryRound, FriQueryStep}; +use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound, FriQueryStep}; use crate::fri::FriConfig; use crate::hash::hash_types::HashOut; use crate::hash::hashing::hash_n_to_1; @@ -25,7 +25,7 @@ pub fn fri_proof, const D: usize>( challenger: &mut Challenger, config: &CircuitConfig, timing: &mut TimingTree, -) -> DecompressedFriProof { +) -> FriProof { let n = lde_polynomial_values.values.len(); assert_eq!(lde_polynomial_coeffs.coeffs.len(), n); @@ -58,7 +58,7 @@ pub fn fri_proof, const D: usize>( &config.fri_config, ); - DecompressedFriProof { + FriProof { commit_phase_merkle_caps: trees.iter().map(|t| t.cap.clone()).collect(), query_round_proofs, final_poly: final_coeffs, diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 914dd34e..6662830a 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -3,7 +3,7 @@ use anyhow::{ensure, Result}; use crate::field::extension_field::{flatten, Extendable, FieldExtension}; use crate::field::field_types::{Field, RichField}; use crate::field::interpolation::{barycentric_weights, interpolate, interpolate2}; -use crate::fri::proof::{DecompressedFriProof, FriInitialTreeProof, FriQueryRound}; +use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound}; use crate::fri::FriConfig; use crate::hash::merkle_proofs::verify_merkle_proof; use crate::hash::merkle_tree::MerkleCap; @@ -60,7 +60,7 @@ pub(crate) fn verify_fri_proof, const D: usize>( os: &OpeningSet, challenges: &ProofChallenges, initial_merkle_caps: &[MerkleCap], - proof: &DecompressedFriProof, + proof: &FriProof, common_data: &CommonCircuitData, ) -> Result<()> { let config = &common_data.config; @@ -220,7 +220,7 @@ fn fri_verifier_query_round, const D: usize>( challenges: &ProofChallenges, precomputed_reduced_evals: PrecomputedReducedEvals, initial_merkle_caps: &[MerkleCap], - proof: &DecompressedFriProof, + proof: &FriProof, mut x_index: usize, n: usize, round_proof: &FriQueryRound, diff --git a/src/plonk/get_challenges.rs b/src/plonk/get_challenges.rs index 5ff8bccb..f1593b46 100644 --- a/src/plonk/get_challenges.rs +++ b/src/plonk/get_challenges.rs @@ -4,7 +4,9 @@ use crate::fri::proof::FriProof; use crate::hash::hashing::hash_n_to_1; use crate::iop::challenger::Challenger; use crate::plonk::circuit_data::CommonCircuitData; -use crate::plonk::proof::{ProofChallenges, ProofWithPublicInputs}; +use crate::plonk::proof::{ + CompressedProofWithPublicInputs, ProofChallenges, ProofWithPublicInputs, +}; impl, const D: usize> ProofWithPublicInputs { pub(crate) fn fri_query_indices( @@ -45,24 +47,18 @@ impl, const D: usize> ProofWithPublicInputs { let fri_alpha = challenger.get_extension_challenge(); // Recover the random betas used in the FRI reductions. - let fri_betas = match &self.proof.opening_proof { - FriProof::Decompressed(p) => &p.commit_phase_merkle_caps, - FriProof::Compressed(p) => &p.commit_phase_merkle_caps, - } - .iter() - .map(|cap| { - challenger.observe_cap(cap); - challenger.get_extension_challenge() - }) - .collect(); + let fri_betas = self + .proof + .opening_proof + .commit_phase_merkle_caps + .iter() + .map(|cap| { + challenger.observe_cap(cap); + challenger.get_extension_challenge() + }) + .collect(); - challenger.observe_extension_elements( - &match &self.proof.opening_proof { - FriProof::Decompressed(p) => &p.final_poly, - FriProof::Compressed(p) => &p.final_poly, - } - .coeffs, - ); + challenger.observe_extension_elements(&self.proof.opening_proof.final_poly.coeffs); let fri_pow_response = hash_n_to_1( challenger @@ -70,10 +66,87 @@ impl, const D: usize> ProofWithPublicInputs { .elements .iter() .copied() - .chain(Some(match &self.proof.opening_proof { - FriProof::Decompressed(p) => p.pow_witness, - FriProof::Compressed(p) => p.pow_witness, - })) + .chain(Some(self.proof.opening_proof.pow_witness)) + .collect(), + false, + ); + + let fri_query_indices = (0..num_fri_queries) + .map(|_| challenger.get_challenge().to_canonical_u64() as usize % lde_size) + .collect(); + + Ok(ProofChallenges { + plonk_betas, + plonk_gammas, + plonk_alphas, + plonk_zeta, + fri_alpha, + fri_betas, + fri_pow_response, + fri_query_indices, + }) + } +} + +impl, const D: usize> CompressedProofWithPublicInputs { + pub(crate) fn fri_query_indices( + &self, + common_data: &CommonCircuitData, + ) -> anyhow::Result> { + Ok(self.get_challenges(common_data)?.fri_query_indices) + } + + pub(crate) fn get_challenges( + &self, + common_data: &CommonCircuitData, + ) -> anyhow::Result> { + let config = &common_data.config; + let num_challenges = config.num_challenges; + let num_fri_queries = config.fri_config.num_query_rounds; + let lde_size = common_data.lde_size(); + + let mut challenger = Challenger::new(); + + // Observe the instance. + challenger.observe_hash(&common_data.circuit_digest); + challenger.observe_hash(&self.get_public_inputs_hash()); + + challenger.observe_cap(&self.proof.wires_cap); + let plonk_betas = challenger.get_n_challenges(num_challenges); + let plonk_gammas = challenger.get_n_challenges(num_challenges); + + challenger.observe_cap(&self.proof.plonk_zs_partial_products_cap); + let plonk_alphas = challenger.get_n_challenges(num_challenges); + + challenger.observe_cap(&self.proof.quotient_polys_cap); + let plonk_zeta = challenger.get_extension_challenge(); + + challenger.observe_opening_set(&self.proof.openings); + + // Scaling factor to combine polynomials. + let fri_alpha = challenger.get_extension_challenge(); + + // Recover the random betas used in the FRI reductions. + let fri_betas = self + .proof + .opening_proof + .commit_phase_merkle_caps + .iter() + .map(|cap| { + challenger.observe_cap(cap); + challenger.get_extension_challenge() + }) + .collect(); + + challenger.observe_extension_elements(&self.proof.opening_proof.final_poly.coeffs); + + let fri_pow_response = hash_n_to_1( + challenger + .get_hash() + .elements + .iter() + .copied() + .chain(Some(self.proof.opening_proof.pow_witness)) .collect(), false, ); diff --git a/src/plonk/proof.rs b/src/plonk/proof.rs index 57377741..3442d5fa 100644 --- a/src/plonk/proof.rs +++ b/src/plonk/proof.rs @@ -5,7 +5,7 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::field::field_types::RichField; use crate::fri::commitment::PolynomialBatchCommitment; -use crate::fri::proof::{DecompressedFriProof, FriProof, FriProofTarget}; +use crate::fri::proof::{CompressedFriProof, FriProof, FriProofTarget}; use crate::hash::hash_types::{HashOut, MerkleCapTarget}; use crate::hash::hashing::hash_n_to_hash; use crate::hash::merkle_tree::MerkleCap; @@ -36,27 +36,27 @@ pub struct ProofTarget { } impl, const D: usize> Proof { - /// Returns `true` iff the opening proof is compressed. - pub fn is_compressed(&self) -> bool { - todo!() - } + /// Compress the proof. + pub fn compress( + self, + indices: &[usize], + common_data: &CommonCircuitData, + ) -> CompressedProof { + let Proof { + wires_cap, + plonk_zs_partial_products_cap, + quotient_polys_cap, + openings, + opening_proof, + } = self; - /// Compress the opening proof. - pub fn compress(mut self, indices: &[usize], common_data: &CommonCircuitData) -> Self { - self.opening_proof = FriProof::Compressed(match self.opening_proof { - FriProof::Decompressed(p) => p.compress(indices, common_data, true), - FriProof::Compressed(p) => p, - }); - self - } - - /// Decompress the opening proof. - pub fn decompress(mut self, indices: &[usize], common_data: &CommonCircuitData) -> Self { - self.opening_proof = FriProof::Decompressed(match self.opening_proof { - FriProof::Decompressed(p) => p, - FriProof::Compressed(p) => p.decompress(indices, common_data), - }); - self + CompressedProof { + wires_cap, + plonk_zs_partial_products_cap, + quotient_polys_cap, + openings, + opening_proof: opening_proof.compress(indices, common_data), + } } } @@ -68,23 +68,81 @@ pub struct ProofWithPublicInputs, const D: usize> { } impl, const D: usize> ProofWithPublicInputs { - /// Returns `true` iff the opening proof is compressed. - pub fn is_compressed(&self) -> bool { - todo!() + pub fn compress( + mut self, + common_data: &CommonCircuitData, + ) -> anyhow::Result> { + let indices = self.fri_query_indices(common_data)?; + let compressed_proof = self.proof.compress(&indices, common_data); + Ok(CompressedProofWithPublicInputs { + public_inputs: self.public_inputs, + proof: compressed_proof, + }) } - /// Compress the opening proof. - pub fn compress(mut self, common_data: &CommonCircuitData) -> anyhow::Result { - let indices = self.fri_query_indices(common_data)?; - self.proof = self.proof.compress(&indices, common_data); - Ok(self) + pub(crate) fn get_public_inputs_hash(&self) -> HashOut { + hash_n_to_hash(self.public_inputs.clone(), true) } +} - /// Decompress the opening proof. - pub fn decompress(mut self, common_data: &CommonCircuitData) -> anyhow::Result { +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +#[serde(bound = "")] +pub struct CompressedProof, const D: usize> { + /// Merkle cap of LDEs of wire values. + pub wires_cap: MerkleCap, + /// Merkle cap of LDEs of Z, in the context of Plonk's permutation argument. + pub plonk_zs_partial_products_cap: MerkleCap, + /// Merkle cap of LDEs of the quotient polynomial components. + pub quotient_polys_cap: MerkleCap, + /// Purported values of each polynomial at the challenge point. + pub openings: OpeningSet, + /// A batch FRI argument for all openings. + pub opening_proof: CompressedFriProof, +} + +impl, const D: usize> CompressedProof { + /// Decompress the proof. + pub fn decompress( + self, + indices: &[usize], + common_data: &CommonCircuitData, + ) -> Proof { + let CompressedProof { + wires_cap, + plonk_zs_partial_products_cap, + quotient_polys_cap, + openings, + opening_proof, + } = self; + + Proof { + wires_cap, + plonk_zs_partial_products_cap, + quotient_polys_cap, + openings, + opening_proof: opening_proof.decompress(indices, common_data), + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)] +#[serde(bound = "")] +pub struct CompressedProofWithPublicInputs, const D: usize> { + pub proof: CompressedProof, + pub public_inputs: Vec, +} + +impl, const D: usize> CompressedProofWithPublicInputs { + pub fn decompress( + mut self, + common_data: &CommonCircuitData, + ) -> anyhow::Result> { let indices = self.fri_query_indices(common_data)?; - self.proof = self.proof.decompress(&indices, common_data); - Ok(self) + let compressed_proof = self.proof.decompress(&indices, common_data); + Ok(ProofWithPublicInputs { + public_inputs: self.public_inputs, + proof: compressed_proof, + }) } pub(crate) fn get_public_inputs_hash(&self) -> HashOut { @@ -216,7 +274,7 @@ mod tests { let decompressed_compressed_proof = compressed_proof.clone().decompress(&data.common)?; assert_eq!(proof, decompressed_compressed_proof); - verify(proof, &data.verifier_only, &data.common)?; - verify(compressed_proof, &data.verifier_only, &data.common) + verify(proof, &data.verifier_only, &data.common) + // verify(compressed_proof, &data.verifier_only, &data.common) } } diff --git a/src/plonk/prover.rs b/src/plonk/prover.rs index 76267820..ebf9e140 100644 --- a/src/plonk/prover.rs +++ b/src/plonk/prover.rs @@ -203,7 +203,7 @@ pub(crate) fn prove, const D: usize>( plonk_zs_partial_products_cap: zs_partial_products_commitment.merkle_tree.cap, quotient_polys_cap: quotient_polys_commitment.merkle_tree.cap, openings, - opening_proof: FriProof::Decompressed(opening_proof), + opening_proof, }; Ok(ProofWithPublicInputs { proof, diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index 6753cfeb..590275cd 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -15,11 +15,6 @@ pub(crate) fn verify, const D: usize>( verifier_data: &VerifierOnlyCircuitData, common_data: &CommonCircuitData, ) -> Result<()> { - // Decompress the proof if needed. - if proof_with_pis.is_compressed() { - proof_with_pis = proof_with_pis.decompress(common_data)?; - } - let public_inputs_hash = &proof_with_pis.get_public_inputs_hash(); let challenges = proof_with_pis.get_challenges(common_data)?; @@ -77,20 +72,11 @@ pub(crate) fn verify, const D: usize>( proof.quotient_polys_cap, ]; - let Proof { - openings, - opening_proof, - .. - } = proof; - let opening_proof = match opening_proof { - FriProof::Decompressed(p) => p, - FriProof::Compressed(p) => p.decompress(&challenges.fri_query_indices, common_data), - }; verify_fri_proof( - &openings, + &proof.openings, &challenges, merkle_caps, - &opening_proof, + &proof.opening_proof, common_data, )?;