2021-10-11 16:40:31 +02:00
|
|
|
use std::collections::HashSet;
|
|
|
|
|
|
2021-09-25 19:41:48 -07:00
|
|
|
use crate::field::extension_field::Extendable;
|
2021-10-11 16:51:30 +02:00
|
|
|
use crate::field::field_types::RichField;
|
2021-10-11 16:40:31 +02:00
|
|
|
use crate::fri::verifier::{compute_evaluation, fri_combine_initial, PrecomputedReducedEvals};
|
2021-09-25 19:41:48 -07:00
|
|
|
use crate::hash::hashing::hash_n_to_1;
|
|
|
|
|
use crate::iop::challenger::Challenger;
|
|
|
|
|
use crate::plonk::circuit_data::CommonCircuitData;
|
2021-09-30 06:56:32 +02:00
|
|
|
use crate::plonk::proof::{
|
2021-10-12 08:38:43 +02:00
|
|
|
CompressedProofWithPublicInputs, FriInferredElements, ProofChallenges, ProofWithPublicInputs,
|
2021-09-30 06:56:32 +02:00
|
|
|
};
|
2021-10-06 15:50:56 +02:00
|
|
|
use crate::util::reverse_bits;
|
2021-09-25 19:41:48 -07:00
|
|
|
|
|
|
|
|
impl<F: RichField + Extendable<D>, const D: usize> ProofWithPublicInputs<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.
|
2021-09-30 06:56:32 +02:00
|
|
|
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,
|
2021-09-29 21:01:15 +02:00
|
|
|
);
|
2021-09-25 19:41:48 -07:00
|
|
|
|
2021-09-30 06:56:32 +02:00
|
|
|
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 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()
|
|
|
|
|
})
|
2021-10-07 19:30:39 +02:00
|
|
|
.collect::<Vec<_>>();
|
2021-09-30 06:56:32 +02:00
|
|
|
|
|
|
|
|
challenger.observe_extension_elements(&self.proof.opening_proof.final_poly.coeffs);
|
|
|
|
|
|
2021-09-25 19:41:48 -07:00
|
|
|
let fri_pow_response = hash_n_to_1(
|
|
|
|
|
challenger
|
|
|
|
|
.get_hash()
|
|
|
|
|
.elements
|
|
|
|
|
.iter()
|
|
|
|
|
.copied()
|
2021-09-30 06:56:32 +02:00
|
|
|
.chain(Some(self.proof.opening_proof.pow_witness))
|
2021-09-25 19:41:48 -07:00
|
|
|
.collect(),
|
|
|
|
|
false,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let fri_query_indices = (0..num_fri_queries)
|
|
|
|
|
.map(|_| challenger.get_challenge().to_canonical_u64() as usize % lde_size)
|
2021-10-07 19:30:39 +02:00
|
|
|
.collect::<Vec<_>>();
|
2021-09-25 19:41:48 -07:00
|
|
|
|
2021-10-12 08:38:43 +02:00
|
|
|
Ok(ProofChallenges {
|
|
|
|
|
plonk_betas,
|
|
|
|
|
plonk_gammas,
|
|
|
|
|
plonk_alphas,
|
|
|
|
|
plonk_zeta,
|
|
|
|
|
fri_alpha,
|
|
|
|
|
fri_betas,
|
|
|
|
|
fri_pow_response,
|
|
|
|
|
fri_query_indices,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
pub(crate) fn get_inferred_elements(
|
|
|
|
|
&self,
|
|
|
|
|
challenges: &ProofChallenges<F, D>,
|
|
|
|
|
common_data: &CommonCircuitData<F, D>,
|
|
|
|
|
) -> FriInferredElements<F, D> {
|
|
|
|
|
let ProofChallenges {
|
|
|
|
|
plonk_zeta,
|
|
|
|
|
fri_alpha,
|
|
|
|
|
fri_betas,
|
|
|
|
|
fri_query_indices,
|
|
|
|
|
..
|
|
|
|
|
} = challenges;
|
|
|
|
|
let mut fri_inferred_elements = Vec::new();
|
2021-10-11 17:24:06 +02:00
|
|
|
// Holds the indices that have already been seen at each reduction depth.
|
2021-10-11 16:40:31 +02:00
|
|
|
let mut seen_indices_by_depth =
|
|
|
|
|
vec![HashSet::new(); common_data.fri_params.reduction_arity_bits.len()];
|
|
|
|
|
let precomputed_reduced_evals =
|
2021-10-12 08:38:43 +02:00
|
|
|
PrecomputedReducedEvals::from_os_and_alpha(&self.proof.openings, *fri_alpha);
|
2021-10-06 15:50:56 +02:00
|
|
|
let log_n = common_data.degree_bits + common_data.config.rate_bits;
|
2021-10-11 18:45:55 +02:00
|
|
|
// Simulate the proof verification and collect the inferred elements.
|
|
|
|
|
// The content of the loop is basically the same as the `fri_verifier_query_round` function.
|
2021-10-12 08:38:43 +02:00
|
|
|
for &(mut x_index) in fri_query_indices {
|
2021-10-06 15:50:56 +02:00
|
|
|
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);
|
2021-10-11 16:40:31 +02:00
|
|
|
let mut old_eval = fri_combine_initial(
|
|
|
|
|
&self
|
|
|
|
|
.proof
|
|
|
|
|
.opening_proof
|
|
|
|
|
.query_round_proofs
|
|
|
|
|
.initial_trees_proofs[&x_index],
|
2021-10-12 08:38:43 +02:00
|
|
|
*fri_alpha,
|
|
|
|
|
*plonk_zeta,
|
2021-10-11 16:40:31 +02:00
|
|
|
subgroup_x,
|
|
|
|
|
precomputed_reduced_evals,
|
|
|
|
|
common_data,
|
|
|
|
|
);
|
2021-10-07 19:30:39 +02:00
|
|
|
for (i, &arity_bits) in common_data
|
|
|
|
|
.fri_params
|
|
|
|
|
.reduction_arity_bits
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
{
|
2021-10-12 20:21:29 +02:00
|
|
|
let coset_index = x_index >> arity_bits;
|
|
|
|
|
if !seen_indices_by_depth[i].insert(coset_index) {
|
2021-10-11 17:24:06 +02:00
|
|
|
// If this index has already been seen, we can skip the rest of the reductions.
|
2021-10-11 16:40:31 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2021-10-12 08:38:43 +02:00
|
|
|
fri_inferred_elements.push(old_eval);
|
2021-10-06 15:50:56 +02:00
|
|
|
let arity = 1 << arity_bits;
|
2021-10-12 08:40:56 +02:00
|
|
|
let mut evals = self.proof.opening_proof.query_round_proofs.steps[i][&coset_index]
|
2021-10-11 16:40:31 +02:00
|
|
|
.evals
|
|
|
|
|
.clone();
|
2021-10-06 15:50:56 +02:00
|
|
|
let x_index_within_coset = x_index & (arity - 1);
|
2021-10-11 16:40:31 +02:00
|
|
|
evals.insert(x_index_within_coset, old_eval);
|
|
|
|
|
old_eval = compute_evaluation(
|
2021-10-06 15:50:56 +02:00
|
|
|
subgroup_x,
|
|
|
|
|
x_index_within_coset,
|
|
|
|
|
arity_bits,
|
2021-10-11 16:40:31 +02:00
|
|
|
&evals,
|
2021-10-07 19:30:39 +02:00
|
|
|
fri_betas[i],
|
2021-10-06 15:50:56 +02:00
|
|
|
);
|
|
|
|
|
subgroup_x = subgroup_x.exp_power_of_2(arity_bits);
|
2021-10-12 20:21:29 +02:00
|
|
|
x_index = coset_index;
|
2021-10-06 15:50:56 +02:00
|
|
|
}
|
|
|
|
|
}
|
2021-10-12 08:38:43 +02:00
|
|
|
FriInferredElements(fri_inferred_elements)
|
2021-09-25 19:41:48 -07:00
|
|
|
}
|
|
|
|
|
}
|