mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-04 23:03:08 +00:00
Add CompressedProof type
This commit is contained in:
parent
a97b9a7112
commit
f92ce1a80c
@ -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<F: RichField> PolynomialBatchCommitment<F> {
|
||||
challenger: &mut Challenger<F>,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
timing: &mut TimingTree,
|
||||
) -> (DecompressedFriProof<F, D>, OpeningSet<F, D>)
|
||||
) -> (FriProof<F, D>, OpeningSet<F, D>)
|
||||
where
|
||||
F: RichField + Extendable<D>,
|
||||
{
|
||||
|
||||
@ -89,14 +89,7 @@ pub struct CompressedFriQueryRounds<F: Extendable<D>, const D: usize> {
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
|
||||
#[serde(bound = "")]
|
||||
pub enum FriProof<F: Extendable<D>, const D: usize> {
|
||||
Decompressed(DecompressedFriProof<F, D>),
|
||||
Compressed(CompressedFriProof<F, D>),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
|
||||
#[serde(bound = "")]
|
||||
pub struct DecompressedFriProof<F: Extendable<D>, const D: usize> {
|
||||
pub struct FriProof<F: Extendable<D>, const D: usize> {
|
||||
/// A Merkle cap for each reduced polynomial in the commit phase.
|
||||
pub commit_phase_merkle_caps: Vec<MerkleCap<F>>,
|
||||
/// Query rounds proofs
|
||||
@ -107,7 +100,6 @@ pub struct DecompressedFriProof<F: Extendable<D>, const D: usize> {
|
||||
pub pow_witness: F,
|
||||
}
|
||||
|
||||
/// Corresponds to `DecompressedFriProof`.
|
||||
pub struct FriProofTarget<const D: usize> {
|
||||
pub commit_phase_merkle_caps: Vec<MerkleCapTarget>,
|
||||
pub query_round_proofs: Vec<FriQueryRoundTarget<D>>,
|
||||
@ -128,15 +120,14 @@ pub struct CompressedFriProof<F: Extendable<D>, const D: usize> {
|
||||
pub pow_witness: F,
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> DecompressedFriProof<F, D> {
|
||||
impl<F: RichField + Extendable<D>, const D: usize> FriProof<F, D> {
|
||||
/// Compress all the Merkle paths in the FRI proof and remove duplicate indices.
|
||||
pub fn compress(
|
||||
self,
|
||||
indices: &[usize],
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
with_indices: bool,
|
||||
) -> CompressedFriProof<F, D> {
|
||||
let DecompressedFriProof {
|
||||
let FriProof {
|
||||
commit_phase_merkle_caps,
|
||||
query_round_proofs,
|
||||
final_poly,
|
||||
@ -209,7 +200,7 @@ impl<F: RichField + Extendable<D>, const D: usize> DecompressedFriProof<F, D> {
|
||||
.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<F: RichField + Extendable<D>, const D: usize> CompressedFriProof<F, D> {
|
||||
self,
|
||||
indices: &[usize],
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> DecompressedFriProof<F, D> {
|
||||
) -> FriProof<F, D> {
|
||||
let CompressedFriProof {
|
||||
commit_phase_merkle_caps,
|
||||
query_round_proofs,
|
||||
@ -323,7 +314,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CompressedFriProof<F, D> {
|
||||
})
|
||||
}
|
||||
|
||||
DecompressedFriProof {
|
||||
FriProof {
|
||||
commit_phase_merkle_caps,
|
||||
query_round_proofs: decompressed_query_proofs,
|
||||
final_poly,
|
||||
|
||||
@ -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<F: RichField + Extendable<D>, const D: usize>(
|
||||
challenger: &mut Challenger<F>,
|
||||
config: &CircuitConfig,
|
||||
timing: &mut TimingTree,
|
||||
) -> DecompressedFriProof<F, D> {
|
||||
) -> FriProof<F, D> {
|
||||
let n = lde_polynomial_values.values.len();
|
||||
assert_eq!(lde_polynomial_coeffs.coeffs.len(), n);
|
||||
|
||||
@ -58,7 +58,7 @@ pub fn fri_proof<F: RichField + Extendable<D>, 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,
|
||||
|
||||
@ -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<F: RichField + Extendable<D>, const D: usize>(
|
||||
os: &OpeningSet<F, D>,
|
||||
challenges: &ProofChallenges<F, D>,
|
||||
initial_merkle_caps: &[MerkleCap<F>],
|
||||
proof: &DecompressedFriProof<F, D>,
|
||||
proof: &FriProof<F, D>,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> Result<()> {
|
||||
let config = &common_data.config;
|
||||
@ -220,7 +220,7 @@ fn fri_verifier_query_round<F: RichField + Extendable<D>, const D: usize>(
|
||||
challenges: &ProofChallenges<F, D>,
|
||||
precomputed_reduced_evals: PrecomputedReducedEvals<F, D>,
|
||||
initial_merkle_caps: &[MerkleCap<F>],
|
||||
proof: &DecompressedFriProof<F, D>,
|
||||
proof: &FriProof<F, D>,
|
||||
mut x_index: usize,
|
||||
n: usize,
|
||||
round_proof: &FriQueryRound<F, D>,
|
||||
|
||||
@ -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<F: RichField + Extendable<D>, const D: usize> ProofWithPublicInputs<F, D> {
|
||||
pub(crate) fn fri_query_indices(
|
||||
@ -45,24 +47,18 @@ impl<F: RichField + Extendable<D>, const D: usize> ProofWithPublicInputs<F, D> {
|
||||
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<F: RichField + Extendable<D>, const D: usize> ProofWithPublicInputs<F, D> {
|
||||
.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<F: RichField + Extendable<D>, const D: usize> CompressedProofWithPublicInputs<F, D> {
|
||||
pub(crate) fn fri_query_indices(
|
||||
&self,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> anyhow::Result<Vec<usize>> {
|
||||
Ok(self.get_challenges(common_data)?.fri_query_indices)
|
||||
}
|
||||
|
||||
pub(crate) fn get_challenges(
|
||||
&self,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> anyhow::Result<ProofChallenges<F, D>> {
|
||||
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,
|
||||
);
|
||||
|
||||
@ -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<const D: usize> {
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> Proof<F, D> {
|
||||
/// 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<F, D>,
|
||||
) -> CompressedProof<F, D> {
|
||||
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<F, D>) -> 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<F, D>) -> 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<F: RichField + Extendable<D>, const D: usize> {
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> ProofWithPublicInputs<F, D> {
|
||||
/// Returns `true` iff the opening proof is compressed.
|
||||
pub fn is_compressed(&self) -> bool {
|
||||
todo!()
|
||||
pub fn compress(
|
||||
mut self,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> anyhow::Result<CompressedProofWithPublicInputs<F, D>> {
|
||||
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<F, D>) -> anyhow::Result<Self> {
|
||||
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<F> {
|
||||
hash_n_to_hash(self.public_inputs.clone(), true)
|
||||
}
|
||||
}
|
||||
|
||||
/// Decompress the opening proof.
|
||||
pub fn decompress(mut self, common_data: &CommonCircuitData<F, D>) -> anyhow::Result<Self> {
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
|
||||
#[serde(bound = "")]
|
||||
pub struct CompressedProof<F: Extendable<D>, const D: usize> {
|
||||
/// Merkle cap of LDEs of wire values.
|
||||
pub wires_cap: MerkleCap<F>,
|
||||
/// Merkle cap of LDEs of Z, in the context of Plonk's permutation argument.
|
||||
pub plonk_zs_partial_products_cap: MerkleCap<F>,
|
||||
/// Merkle cap of LDEs of the quotient polynomial components.
|
||||
pub quotient_polys_cap: MerkleCap<F>,
|
||||
/// Purported values of each polynomial at the challenge point.
|
||||
pub openings: OpeningSet<F, D>,
|
||||
/// A batch FRI argument for all openings.
|
||||
pub opening_proof: CompressedFriProof<F, D>,
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> CompressedProof<F, D> {
|
||||
/// Decompress the proof.
|
||||
pub fn decompress(
|
||||
self,
|
||||
indices: &[usize],
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> Proof<F, D> {
|
||||
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<F: RichField + Extendable<D>, const D: usize> {
|
||||
pub proof: CompressedProof<F, D>,
|
||||
pub public_inputs: Vec<F>,
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> CompressedProofWithPublicInputs<F, D> {
|
||||
pub fn decompress(
|
||||
mut self,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> anyhow::Result<ProofWithPublicInputs<F, D>> {
|
||||
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<F> {
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -203,7 +203,7 @@ pub(crate) fn prove<F: RichField + Extendable<D>, 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,
|
||||
|
||||
@ -15,11 +15,6 @@ pub(crate) fn verify<F: RichField + Extendable<D>, const D: usize>(
|
||||
verifier_data: &VerifierOnlyCircuitData<F>,
|
||||
common_data: &CommonCircuitData<F, D>,
|
||||
) -> 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<F: RichField + Extendable<D>, 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,
|
||||
)?;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user