This commit is contained in:
wborgeaud 2021-10-11 16:40:31 +02:00
parent d2a5e67980
commit ea69a87338
5 changed files with 79 additions and 35 deletions

View File

@ -249,8 +249,8 @@ impl<F: RichField + Extendable<D>, const D: usize> CompressedFriProof<F, D> {
fri_query_inferred_elements, fri_query_inferred_elements,
.. ..
} = challenges; } = challenges;
let fri_query_inferred_elements = if let Some(v) = fri_query_inferred_elements { let mut fri_query_inferred_elements = if let Some(v) = fri_query_inferred_elements {
v v.iter().copied()
} else { } else {
panic!() panic!()
}; };
@ -281,6 +281,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CompressedFriProof<F, D> {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut evals_by_depth = vec![
HashMap::<usize, Vec<_>>::new();
common_data.fri_params.reduction_arity_bits.len()
];
for (round, mut index) in indices.iter().copied().enumerate() { for (round, mut index) in indices.iter().copied().enumerate() {
let initial_trees_proof = query_round_proofs.initial_trees_proofs[&index].clone(); let initial_trees_proof = query_round_proofs.initial_trees_proofs[&index].clone();
for (i, (leaves_data, proof)) in for (i, (leaves_data, proof)) in
@ -298,7 +302,15 @@ impl<F: RichField + Extendable<D>, const D: usize> CompressedFriProof<F, D> {
merkle_proof, merkle_proof,
} = query_round_proofs.steps[i][&index].clone(); } = query_round_proofs.steps[i][&index].clone();
steps_indices[i].push(index); steps_indices[i].push(index);
evals.insert(index_within_coset, fri_query_inferred_elements[round][i]); if let Some(v) = evals_by_depth[i].get(&index) {
evals = v.to_vec();
} else {
evals.insert(
index_within_coset,
fri_query_inferred_elements.next().unwrap(),
);
evals_by_depth[i].insert(index, evals.clone());
}
steps_evals[i].push(flatten(&evals)); steps_evals[i].push(flatten(&evals));
steps_proofs[i].push(merkle_proof); steps_proofs[i].push(merkle_proof);
} }

View File

@ -120,14 +120,14 @@ fn fri_verify_initial_proof<F: RichField>(
/// Holds the reduced (by `alpha`) evaluations at `zeta` for the polynomial opened just at /// Holds the reduced (by `alpha`) evaluations at `zeta` for the polynomial opened just at
/// zeta, for `Z` at zeta and for `Z` at `g*zeta`. /// zeta, for `Z` at zeta and for `Z` at `g*zeta`.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
struct PrecomputedReducedEvals<F: Extendable<D>, const D: usize> { pub(crate) struct PrecomputedReducedEvals<F: Extendable<D>, const D: usize> {
pub single: F::Extension, pub single: F::Extension,
pub zs: F::Extension, pub zs: F::Extension,
pub zs_right: F::Extension, pub zs_right: F::Extension,
} }
impl<F: Extendable<D>, const D: usize> PrecomputedReducedEvals<F, D> { impl<F: Extendable<D>, const D: usize> PrecomputedReducedEvals<F, D> {
fn from_os_and_alpha(os: &OpeningSet<F, D>, alpha: F::Extension) -> Self { pub(crate) fn from_os_and_alpha(os: &OpeningSet<F, D>, alpha: F::Extension) -> Self {
let mut alpha = ReducingFactor::new(alpha); let mut alpha = ReducingFactor::new(alpha);
let single = alpha.reduce( let single = alpha.reduce(
os.constants os.constants
@ -148,7 +148,7 @@ impl<F: Extendable<D>, const D: usize> PrecomputedReducedEvals<F, D> {
} }
} }
fn fri_combine_initial<F: RichField + Extendable<D>, const D: usize>( pub(crate) fn fri_combine_initial<F: RichField + Extendable<D>, const D: usize>(
proof: &FriInitialTreeProof<F>, proof: &FriInitialTreeProof<F>,
alpha: F::Extension, alpha: F::Extension,
zeta: F::Extension, zeta: F::Extension,
@ -159,10 +159,10 @@ fn fri_combine_initial<F: RichField + Extendable<D>, const D: usize>(
let config = &common_data.config; let config = &common_data.config;
assert!(D > 1, "Not implemented for D=1."); assert!(D > 1, "Not implemented for D=1.");
let degree_log = common_data.degree_bits; let degree_log = common_data.degree_bits;
debug_assert_eq!( // debug_assert_eq!(
degree_log, // degree_log,
common_data.config.cap_height + proof.evals_proofs[0].1.siblings.len() - config.rate_bits // common_data.config.cap_height + proof.evals_proofs[0].1.siblings.len() - config.rate_bits
); // );
let subgroup_x = F::Extension::from_basefield(subgroup_x); let subgroup_x = F::Extension::from_basefield(subgroup_x);
let mut alpha = ReducingFactor::new(alpha); let mut alpha = ReducingFactor::new(alpha);
let mut sum = F::Extension::ZERO; let mut sum = F::Extension::ZERO;
@ -262,18 +262,13 @@ fn fri_verifier_query_round<F: RichField + Extendable<D>, const D: usize>(
ensure!(evals[x_index_within_coset] == old_eval); ensure!(evals[x_index_within_coset] == old_eval);
// Infer P(y) from {P(x)}_{x^arity=y}. // Infer P(y) from {P(x)}_{x^arity=y}.
old_eval = if let Some(v) = &challenges.fri_query_inferred_elements { old_eval = compute_evaluation(
dbg!("yo"); subgroup_x,
v[round][i] x_index_within_coset,
} else { arity_bits,
compute_evaluation( evals,
subgroup_x, challenges.fri_betas[i],
x_index_within_coset, );
arity_bits,
evals,
challenges.fri_betas[i],
)
};
verify_merkle_proof( verify_merkle_proof(
flatten(evals), flatten(evals),

View File

@ -1,6 +1,8 @@
use std::collections::HashSet;
use crate::field::extension_field::Extendable; use crate::field::extension_field::Extendable;
use crate::field::field_types::{Field, RichField}; use crate::field::field_types::{Field, RichField};
use crate::fri::verifier::compute_evaluation; use crate::fri::verifier::{compute_evaluation, fri_combine_initial, PrecomputedReducedEvals};
use crate::hash::hashing::hash_n_to_1; use crate::hash::hashing::hash_n_to_1;
use crate::iop::challenger::Challenger; use crate::iop::challenger::Challenger;
use crate::plonk::circuit_data::CommonCircuitData; use crate::plonk::circuit_data::CommonCircuitData;
@ -157,36 +159,55 @@ impl<F: RichField + Extendable<D>, const D: usize> CompressedProofWithPublicInpu
.map(|_| challenger.get_challenge().to_canonical_u64() as usize % lde_size) .map(|_| challenger.get_challenge().to_canonical_u64() as usize % lde_size)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut seen_indices_by_depth =
vec![HashSet::new(); common_data.fri_params.reduction_arity_bits.len()];
let precomputed_reduced_evals =
PrecomputedReducedEvals::from_os_and_alpha(&self.proof.openings, fri_alpha);
let mut fri_query_inferred_elements = Vec::new(); let mut fri_query_inferred_elements = Vec::new();
let log_n = common_data.degree_bits + common_data.config.rate_bits; let log_n = common_data.degree_bits + common_data.config.rate_bits;
for query_round in 0..common_data.config.fri_config.num_query_rounds { for query_round in 0..common_data.config.fri_config.num_query_rounds {
let mut query_round_inferred_elements = Vec::new();
let mut x_index = fri_query_indices[query_round]; let mut x_index = fri_query_indices[query_round];
let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR
* F::primitive_root_of_unity(log_n).exp_u64(reverse_bits(x_index, log_n) as u64); * F::primitive_root_of_unity(log_n).exp_u64(reverse_bits(x_index, log_n) as u64);
let mut old_eval = fri_combine_initial(
&self
.proof
.opening_proof
.query_round_proofs
.initial_trees_proofs[&x_index],
fri_alpha,
plonk_zeta,
subgroup_x,
precomputed_reduced_evals,
common_data,
);
for (i, &arity_bits) in common_data for (i, &arity_bits) in common_data
.fri_params .fri_params
.reduction_arity_bits .reduction_arity_bits
.iter() .iter()
.enumerate() .enumerate()
{ {
if !seen_indices_by_depth[i].insert(x_index >> arity_bits) {
break;
}
fri_query_inferred_elements.push(old_eval);
let arity = 1 << arity_bits; let arity = 1 << arity_bits;
let evals = &self.proof.opening_proof.query_round_proofs.steps[i] let mut evals = self.proof.opening_proof.query_round_proofs.steps[i]
[&(x_index >> arity_bits)] [&(x_index >> arity_bits)]
.evals; .evals
.clone();
let x_index_within_coset = x_index & (arity - 1); let x_index_within_coset = x_index & (arity - 1);
let elmt = compute_evaluation( evals.insert(x_index_within_coset, old_eval);
old_eval = compute_evaluation(
subgroup_x, subgroup_x,
x_index_within_coset, x_index_within_coset,
arity_bits, arity_bits,
evals, &evals,
fri_betas[i], fri_betas[i],
); );
query_round_inferred_elements.push(elmt);
subgroup_x = subgroup_x.exp_power_of_2(arity_bits); subgroup_x = subgroup_x.exp_power_of_2(arity_bits);
x_index >>= arity_bits; x_index >>= arity_bits;
} }
fri_query_inferred_elements.push(query_round_inferred_elements);
} }
Ok(ProofChallenges { Ok(ProofChallenges {

View File

@ -224,7 +224,7 @@ pub(crate) struct ProofChallenges<F: RichField + Extendable<D>, const D: usize>
pub fri_query_indices: Vec<usize>, pub fri_query_indices: Vec<usize>,
pub fri_query_inferred_elements: Option<Vec<Vec<F::Extension>>>, pub fri_query_inferred_elements: Option<Vec<F::Extension>>,
} }
pub struct ProofWithPublicInputsTarget<const D: usize> { pub struct ProofWithPublicInputsTarget<const D: usize> {
@ -307,7 +307,7 @@ mod tests {
const D: usize = 4; const D: usize = 4;
let mut config = CircuitConfig::large_config(); let mut config = CircuitConfig::large_config();
config.fri_config.reduction_strategy = FriReductionStrategy::Fixed(vec![1]); config.fri_config.reduction_strategy = FriReductionStrategy::Fixed(vec![2, 1]);
config.fri_config.num_query_rounds = 50; config.fri_config.num_query_rounds = 50;
let pw = PartialWitness::new(); let pw = PartialWitness::new();
@ -324,10 +324,23 @@ mod tests {
builder.connect(zt, comp_zt); builder.connect(zt, comp_zt);
let data = builder.build(); let data = builder.build();
let proof = data.prove(pw)?; let proof = data.prove(pw)?;
verify(proof.clone(), &data.verifier_only, &data.common)?;
// Verify that `decompress ∘ compress = identity`. // Verify that `decompress ∘ compress = identity`.
let compressed_proof = proof.clone().compress(&data.common)?; let compressed_proof = proof.clone().compress(&data.common)?;
let decompressed_compressed_proof = compressed_proof.clone().decompress(&data.common)?; let decompressed_compressed_proof = compressed_proof.clone().decompress(&data.common)?;
for i in 0..proof.proof.opening_proof.query_round_proofs.len() {
let qrp = proof.proof.opening_proof.query_round_proofs[i].clone();
let dqrp = decompressed_compressed_proof
.proof
.opening_proof
.query_round_proofs[i]
.clone();
for j in 0..qrp.steps.len() {
dbg!(&qrp.steps[j].evals);
dbg!(&dqrp.steps[j].evals);
}
}
assert_eq!(proof, decompressed_compressed_proof); assert_eq!(proof, decompressed_compressed_proof);
verify(proof, &data.verifier_only, &data.common)?; verify(proof, &data.verifier_only, &data.common)?;

View File

@ -242,14 +242,17 @@ impl Buffer {
&mut self, &mut self,
fqs: &FriQueryStep<F, D>, fqs: &FriQueryStep<F, D>,
) -> Result<()> { ) -> Result<()> {
dbg!(self.0.position());
self.write_field_ext_vec::<F, D>(&fqs.evals)?; self.write_field_ext_vec::<F, D>(&fqs.evals)?;
self.write_merkle_proof(&fqs.merkle_proof) self.write_merkle_proof(&fqs.merkle_proof)
} }
fn read_fri_query_step<F: Extendable<D>, const D: usize>( fn read_fri_query_step<F: Extendable<D>, const D: usize>(
&mut self, &mut self,
arity: usize, arity: usize,
compressed: bool,
) -> Result<FriQueryStep<F, D>> { ) -> Result<FriQueryStep<F, D>> {
let evals = self.read_field_ext_vec::<F, D>(arity)?; dbg!(self.0.position());
let evals = self.read_field_ext_vec::<F, D>(arity - if compressed { 1 } else { 0 })?;
let merkle_proof = self.read_merkle_proof()?; let merkle_proof = self.read_merkle_proof()?;
Ok(FriQueryStep { Ok(FriQueryStep {
evals, evals,
@ -281,7 +284,7 @@ impl Buffer {
.fri_params .fri_params
.reduction_arity_bits .reduction_arity_bits
.iter() .iter()
.map(|&ar| self.read_fri_query_step(1 << ar)) .map(|&ar| self.read_fri_query_step(1 << ar, false))
.collect::<Result<_>>()?; .collect::<Result<_>>()?;
fqrs.push(FriQueryRound { fqrs.push(FriQueryRound {
initial_trees_proof, initial_trees_proof,
@ -424,7 +427,7 @@ impl Buffer {
}); });
indices.dedup(); indices.dedup();
let query_steps = (0..indices.len()) let query_steps = (0..indices.len())
.map(|_| self.read_fri_query_step(1 << a)) .map(|_| self.read_fri_query_step(1 << a, true))
.collect::<Result<Vec<_>>>()?; .collect::<Result<Vec<_>>>()?;
steps.push( steps.push(
indices indices