Merge branch 'main' into recursive_starks

This commit is contained in:
wborgeaud 2022-02-08 07:20:24 +01:00
commit a2dbcf2ff1
9 changed files with 257 additions and 129 deletions

View File

@ -1,12 +1,16 @@
use plonky2_field::extension_field::Extendable; use plonky2_field::extension_field::Extendable;
use plonky2_field::polynomial::PolynomialCoeffs; use plonky2_field::polynomial::PolynomialCoeffs;
use crate::fri::proof::FriChallenges; use crate::fri::proof::{FriChallenges, FriChallengesTarget};
use crate::fri::structure::{FriOpenings, FriOpeningsTarget}; use crate::fri::structure::{FriOpenings, FriOpeningsTarget};
use crate::fri::FriConfig; use crate::fri::FriConfig;
use crate::hash::hash_types::RichField; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget;
use crate::hash::hash_types::{MerkleCapTarget, RichField};
use crate::hash::merkle_tree::MerkleCap; use crate::hash::merkle_tree::MerkleCap;
use crate::iop::challenger::{Challenger, RecursiveChallenger}; use crate::iop::challenger::{Challenger, RecursiveChallenger};
use crate::iop::target::Target;
use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::circuit_data::CommonCircuitData;
use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher}; use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher};
impl<F: RichField, H: Hasher<F>> Challenger<F, H> { impl<F: RichField, H: Hasher<F>> Challenger<F, H> {
@ -78,4 +82,50 @@ impl<F: RichField + Extendable<D>, H: AlgebraicHasher<F>, const D: usize>
self.observe_extension_elements(&v.values); self.observe_extension_elements(&v.values);
} }
} }
pub fn fri_challenges<C: GenericConfig<D, F = F>>(
&mut self,
builder: &mut CircuitBuilder<F, D>,
commit_phase_merkle_caps: &[MerkleCapTarget],
final_poly: &PolynomialCoeffsExtTarget<D>,
pow_witness: Target,
inner_common_data: &CommonCircuitData<F, C, D>,
) -> FriChallengesTarget<D> {
let num_fri_queries = inner_common_data.config.fri_config.num_query_rounds;
// Scaling factor to combine polynomials.
let fri_alpha = self.get_extension_challenge(builder);
// Recover the random betas used in the FRI reductions.
let fri_betas = commit_phase_merkle_caps
.iter()
.map(|cap| {
self.observe_cap(cap);
self.get_extension_challenge(builder)
})
.collect();
self.observe_extension_elements(&final_poly.0);
let pow_inputs = self
.get_hash(builder)
.elements
.iter()
.copied()
.chain(Some(pow_witness))
.collect();
let fri_pow_response = builder
.hash_n_to_hash_no_pad::<C::InnerHasher>(pow_inputs)
.elements[0];
let fri_query_indices = (0..num_fri_queries)
.map(|_| self.get_challenge(builder))
.collect();
FriChallengesTarget {
fri_alpha,
fri_betas,
fri_pow_response,
fri_query_indices,
}
}
} }

View File

@ -375,3 +375,10 @@ pub struct FriChallenges<F: RichField + Extendable<D>, const D: usize> {
// Indices at which the oracle is queried in FRI. // Indices at which the oracle is queried in FRI.
pub fri_query_indices: Vec<usize>, pub fri_query_indices: Vec<usize>,
} }
pub struct FriChallengesTarget<const D: usize> {
pub fri_alpha: ExtensionTarget<D>,
pub fri_betas: Vec<ExtensionTarget<D>>,
pub fri_pow_response: Target,
pub fri_query_indices: Vec<Target>,
}

View File

@ -3,7 +3,8 @@ use plonky2_field::extension_field::Extendable;
use plonky2_util::{log2_strict, reverse_index_bits_in_place}; use plonky2_util::{log2_strict, reverse_index_bits_in_place};
use crate::fri::proof::{ use crate::fri::proof::{
FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget, FriQueryStepTarget, FriChallengesTarget, FriInitialTreeProofTarget, FriProofTarget, FriQueryRoundTarget,
FriQueryStepTarget,
}; };
use crate::fri::structure::{FriBatchInfoTarget, FriInstanceInfoTarget, FriOpeningsTarget}; use crate::fri::structure::{FriBatchInfoTarget, FriInstanceInfoTarget, FriOpeningsTarget};
use crate::fri::{FriConfig, FriParams}; use crate::fri::{FriConfig, FriParams};
@ -14,12 +15,10 @@ use crate::gates::low_degree_interpolation::LowDegreeInterpolationGate;
use crate::gates::random_access::RandomAccessGate; use crate::gates::random_access::RandomAccessGate;
use crate::hash::hash_types::MerkleCapTarget; use crate::hash::hash_types::MerkleCapTarget;
use crate::hash::hash_types::RichField; use crate::hash::hash_types::RichField;
use crate::iop::challenger::RecursiveChallenger;
use crate::iop::ext_target::{flatten_target, ExtensionTarget}; use crate::iop::ext_target::{flatten_target, ExtensionTarget};
use crate::iop::target::{BoolTarget, Target}; use crate::iop::target::{BoolTarget, Target};
use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::config::{AlgebraicHasher, GenericConfig}; use crate::plonk::config::{AlgebraicHasher, GenericConfig};
use crate::plonk::proof::OpeningSetTarget;
use crate::util::reducing::ReducingFactorTarget; use crate::util::reducing::ReducingFactorTarget;
use crate::with_context; use crate::with_context;
@ -107,16 +106,11 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
fn fri_verify_proof_of_work<H: AlgebraicHasher<F>>( fn fri_verify_proof_of_work<H: AlgebraicHasher<F>>(
&mut self, &mut self,
proof: &FriProofTarget<D>, fri_pow_response: Target,
challenger: &mut RecursiveChallenger<F, H, D>,
config: &FriConfig, config: &FriConfig,
) { ) {
let mut inputs = challenger.get_hash(self).elements.to_vec();
inputs.push(proof.pow_witness);
let hash = self.hash_n_to_m_no_pad::<H>(inputs, 1)[0];
self.assert_leading_zeros( self.assert_leading_zeros(
hash, fri_pow_response,
config.proof_of_work_bits + (64 - F::order().bits()) as u32, config.proof_of_work_bits + (64 - F::order().bits()) as u32,
); );
} }
@ -124,11 +118,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
pub fn verify_fri_proof<C: GenericConfig<D, F = F>>( pub fn verify_fri_proof<C: GenericConfig<D, F = F>>(
&mut self, &mut self,
instance: &FriInstanceInfoTarget<D>, instance: &FriInstanceInfoTarget<D>,
// Openings of the PLONK polynomials. openings: &FriOpeningsTarget<D>,
os: &OpeningSetTarget<D>, challenges: &FriChallengesTarget<D>,
initial_merkle_caps: &[MerkleCapTarget], initial_merkle_caps: &[MerkleCapTarget],
proof: &FriProofTarget<D>, proof: &FriProofTarget<D>,
challenger: &mut RecursiveChallenger<F, C::Hasher, D>,
params: &FriParams, params: &FriParams,
) where ) where
C::Hasher: AlgebraicHasher<F>, C::Hasher: AlgebraicHasher<F>,
@ -146,29 +139,10 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
// Size of the LDE domain. // Size of the LDE domain.
let n = params.lde_size(); let n = params.lde_size();
challenger.observe_openings(&os.to_fri_openings());
// Scaling factor to combine polynomials.
let alpha = challenger.get_extension_challenge(self);
let betas = with_context!(
self,
"recover the random betas used in the FRI reductions.",
proof
.commit_phase_merkle_caps
.iter()
.map(|cap| {
challenger.observe_cap(cap);
challenger.get_extension_challenge(self)
})
.collect::<Vec<_>>()
);
challenger.observe_extension_elements(&proof.final_poly.0);
with_context!( with_context!(
self, self,
"check PoW", "check PoW",
self.fri_verify_proof_of_work::<C::Hasher>(proof, challenger, &params.config) self.fri_verify_proof_of_work::<C::Hasher>(challenges.fri_pow_response, &params.config)
); );
// Check that parameters are coherent. // Check that parameters are coherent.
@ -181,7 +155,11 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let precomputed_reduced_evals = with_context!( let precomputed_reduced_evals = with_context!(
self, self,
"precompute reduced evaluations", "precompute reduced evaluations",
PrecomputedReducedOpeningsTarget::from_os_and_alpha(&os.to_fri_openings(), alpha, self) PrecomputedReducedOpeningsTarget::from_os_and_alpha(
openings,
challenges.fri_alpha,
self
)
); );
for (i, round_proof) in proof.query_round_proofs.iter().enumerate() { for (i, round_proof) in proof.query_round_proofs.iter().enumerate() {
@ -201,13 +179,12 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
&format!("verify one (of {}) query rounds", num_queries), &format!("verify one (of {}) query rounds", num_queries),
self.fri_verifier_query_round::<C>( self.fri_verifier_query_round::<C>(
instance, instance,
alpha, challenges,
&precomputed_reduced_evals, &precomputed_reduced_evals,
initial_merkle_caps, initial_merkle_caps,
proof, proof,
challenger, challenges.fri_query_indices[i],
n, n,
&betas,
round_proof, round_proof,
params, params,
) )
@ -291,13 +268,12 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
fn fri_verifier_query_round<C: GenericConfig<D, F = F>>( fn fri_verifier_query_round<C: GenericConfig<D, F = F>>(
&mut self, &mut self,
instance: &FriInstanceInfoTarget<D>, instance: &FriInstanceInfoTarget<D>,
alpha: ExtensionTarget<D>, challenges: &FriChallengesTarget<D>,
precomputed_reduced_evals: &PrecomputedReducedOpeningsTarget<D>, precomputed_reduced_evals: &PrecomputedReducedOpeningsTarget<D>,
initial_merkle_caps: &[MerkleCapTarget], initial_merkle_caps: &[MerkleCapTarget],
proof: &FriProofTarget<D>, proof: &FriProofTarget<D>,
challenger: &mut RecursiveChallenger<F, C::Hasher, D>, x_index: Target,
n: usize, n: usize,
betas: &[ExtensionTarget<D>],
round_proof: &FriQueryRoundTarget<D>, round_proof: &FriQueryRoundTarget<D>,
params: &FriParams, params: &FriParams,
) where ) where
@ -308,7 +284,6 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
// Note that this `low_bits` decomposition permits non-canonical binary encodings. Here we // Note that this `low_bits` decomposition permits non-canonical binary encodings. Here we
// verify that this has a negligible impact on soundness error. // verify that this has a negligible impact on soundness error.
Self::assert_noncanonical_indices_ok(&params.config); Self::assert_noncanonical_indices_ok(&params.config);
let x_index = challenger.get_challenge(self);
let mut x_index_bits = self.low_bits(x_index, n_log, F::BITS); let mut x_index_bits = self.low_bits(x_index, n_log, F::BITS);
let cap_index = let cap_index =
@ -341,7 +316,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
self.fri_combine_initial::<C>( self.fri_combine_initial::<C>(
instance, instance,
&round_proof.initial_trees_proof, &round_proof.initial_trees_proof,
alpha, challenges.fri_alpha,
subgroup_x, subgroup_x,
precomputed_reduced_evals, precomputed_reduced_evals,
params, params,
@ -368,7 +343,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
x_index_within_coset_bits, x_index_within_coset_bits,
arity_bits, arity_bits,
evals, evals,
betas[i], challenges.fri_betas[i],
) )
); );

View File

@ -9,8 +9,8 @@ use crate::plonk::config::AlgebraicHasher;
/// Set the targets in a `FriProofTarget` to their corresponding values in a `FriProof`. /// Set the targets in a `FriProofTarget` to their corresponding values in a `FriProof`.
pub fn set_fri_proof_target<F, W, H, const D: usize>( pub fn set_fri_proof_target<F, W, H, const D: usize>(
witness: &mut W, witness: &mut W,
fri_proof: &FriProof<F, H, D>,
fri_proof_target: &FriProofTarget<D>, fri_proof_target: &FriProofTarget<D>,
fri_proof: &FriProof<F, H, D>,
) where ) where
F: RichField + Extendable<D>, F: RichField + Extendable<D>,
W: Witness<F> + ?Sized, W: Witness<F> + ?Sized,

View File

@ -162,8 +162,8 @@ pub trait Witness<F: Field> {
/// `ProofWithPublicInputs`. /// `ProofWithPublicInputs`.
fn set_proof_with_pis_target<C: GenericConfig<D, F = F>, const D: usize>( fn set_proof_with_pis_target<C: GenericConfig<D, F = F>, const D: usize>(
&mut self, &mut self,
proof_with_pis: &ProofWithPublicInputs<F, C, D>,
proof_with_pis_target: &ProofWithPublicInputsTarget<D>, proof_with_pis_target: &ProofWithPublicInputsTarget<D>,
proof_with_pis: &ProofWithPublicInputs<F, C, D>,
) where ) where
F: RichField + Extendable<D>, F: RichField + Extendable<D>,
C::Hasher: AlgebraicHasher<F>, C::Hasher: AlgebraicHasher<F>,
@ -182,14 +182,14 @@ pub trait Witness<F: Field> {
self.set_target(pi_t, pi); self.set_target(pi_t, pi);
} }
self.set_proof_target(proof, pt); self.set_proof_target(pt, proof);
} }
/// Set the targets in a `ProofTarget` to their corresponding values in a `Proof`. /// Set the targets in a `ProofTarget` to their corresponding values in a `Proof`.
fn set_proof_target<C: GenericConfig<D, F = F>, const D: usize>( fn set_proof_target<C: GenericConfig<D, F = F>, const D: usize>(
&mut self, &mut self,
proof: &Proof<F, C, D>,
proof_target: &ProofTarget<D>, proof_target: &ProofTarget<D>,
proof: &Proof<F, C, D>,
) where ) where
F: RichField + Extendable<D>, F: RichField + Extendable<D>,
C::Hasher: AlgebraicHasher<F>, C::Hasher: AlgebraicHasher<F>,
@ -258,7 +258,7 @@ pub trait Witness<F: Field> {
self.set_extension_target(t, x); self.set_extension_target(t, x);
} }
set_fri_proof_target(self, &proof.opening_proof, &proof_target.opening_proof); set_fri_proof_target(self, &proof_target.opening_proof, &proof.opening_proof);
} }
fn set_wire(&mut self, wire: Wire, value: F) { fn set_wire(&mut self, wire: Wire, value: F) {

View File

@ -3,16 +3,20 @@ use std::collections::HashSet;
use plonky2_field::extension_field::Extendable; use plonky2_field::extension_field::Extendable;
use plonky2_field::polynomial::PolynomialCoeffs; use plonky2_field::polynomial::PolynomialCoeffs;
use crate::fri::proof::{CompressedFriProof, FriChallenges, FriProof}; use crate::fri::proof::{CompressedFriProof, FriChallenges, FriProof, FriProofTarget};
use crate::fri::verifier::{compute_evaluation, fri_combine_initial, PrecomputedReducedOpenings}; use crate::fri::verifier::{compute_evaluation, fri_combine_initial, PrecomputedReducedOpenings};
use crate::hash::hash_types::RichField; use crate::gadgets::polynomial::PolynomialCoeffsExtTarget;
use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField};
use crate::hash::merkle_tree::MerkleCap; use crate::hash::merkle_tree::MerkleCap;
use crate::iop::challenger::Challenger; use crate::iop::challenger::{Challenger, RecursiveChallenger};
use crate::iop::target::Target;
use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::circuit_data::CommonCircuitData; use crate::plonk::circuit_data::CommonCircuitData;
use crate::plonk::config::{GenericConfig, Hasher}; use crate::plonk::config::{AlgebraicHasher, GenericConfig, Hasher};
use crate::plonk::proof::{ use crate::plonk::proof::{
CompressedProof, CompressedProofWithPublicInputs, FriInferredElements, OpeningSet, Proof, CompressedProof, CompressedProofWithPublicInputs, FriInferredElements, OpeningSet,
ProofChallenges, ProofWithPublicInputs, OpeningSetTarget, Proof, ProofChallenges, ProofChallengesTarget, ProofTarget,
ProofWithPublicInputs, ProofWithPublicInputsTarget,
}; };
use crate::util::reverse_bits; use crate::util::reverse_bits;
@ -71,7 +75,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> anyhow::Result<Vec<usize>> { ) -> anyhow::Result<Vec<usize>> {
Ok(self Ok(self
.get_challenges(common_data)? .get_challenges(self.get_public_inputs_hash(), common_data)?
.fri_challenges .fri_challenges
.fri_query_indices) .fri_query_indices)
} }
@ -79,6 +83,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
/// Computes all Fiat-Shamir challenges used in the Plonk proof. /// Computes all Fiat-Shamir challenges used in the Plonk proof.
pub(crate) fn get_challenges( pub(crate) fn get_challenges(
&self, &self,
public_inputs_hash: <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash,
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> anyhow::Result<ProofChallenges<F, D>> { ) -> anyhow::Result<ProofChallenges<F, D>> {
let Proof { let Proof {
@ -96,7 +101,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
} = &self.proof; } = &self.proof;
get_challenges( get_challenges(
self.get_public_inputs_hash(), public_inputs_hash,
wires_cap, wires_cap,
plonk_zs_partial_products_cap, plonk_zs_partial_products_cap,
quotient_polys_cap, quotient_polys_cap,
@ -115,6 +120,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
/// Computes all Fiat-Shamir challenges used in the Plonk proof. /// Computes all Fiat-Shamir challenges used in the Plonk proof.
pub(crate) fn get_challenges( pub(crate) fn get_challenges(
&self, &self,
public_inputs_hash: <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash,
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> anyhow::Result<ProofChallenges<F, D>> { ) -> anyhow::Result<ProofChallenges<F, D>> {
let CompressedProof { let CompressedProof {
@ -132,7 +138,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
} = &self.proof; } = &self.proof;
get_challenges( get_challenges(
self.get_public_inputs_hash(), public_inputs_hash,
wires_cap, wires_cap,
plonk_zs_partial_products_cap, plonk_zs_partial_products_cap,
quotient_polys_cap, quotient_polys_cap,
@ -219,3 +225,96 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
FriInferredElements(fri_inferred_elements) FriInferredElements(fri_inferred_elements)
} }
} }
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
fn get_challenges<C: GenericConfig<D, F = F>>(
&mut self,
public_inputs_hash: HashOutTarget,
wires_cap: &MerkleCapTarget,
plonk_zs_partial_products_cap: &MerkleCapTarget,
quotient_polys_cap: &MerkleCapTarget,
openings: &OpeningSetTarget<D>,
commit_phase_merkle_caps: &[MerkleCapTarget],
final_poly: &PolynomialCoeffsExtTarget<D>,
pow_witness: Target,
inner_common_data: &CommonCircuitData<F, C, D>,
) -> ProofChallengesTarget<D>
where
C::Hasher: AlgebraicHasher<F>,
{
let config = &inner_common_data.config;
let num_challenges = config.num_challenges;
let mut challenger = RecursiveChallenger::<F, C::Hasher, D>::new(self);
// Observe the instance.
let digest =
HashOutTarget::from_vec(self.constants(&inner_common_data.circuit_digest.elements));
challenger.observe_hash(&digest);
challenger.observe_hash(&public_inputs_hash);
challenger.observe_cap(wires_cap);
let plonk_betas = challenger.get_n_challenges(self, num_challenges);
let plonk_gammas = challenger.get_n_challenges(self, num_challenges);
challenger.observe_cap(plonk_zs_partial_products_cap);
let plonk_alphas = challenger.get_n_challenges(self, num_challenges);
challenger.observe_cap(quotient_polys_cap);
let plonk_zeta = challenger.get_extension_challenge(self);
challenger.observe_openings(&openings.to_fri_openings());
ProofChallengesTarget {
plonk_betas,
plonk_gammas,
plonk_alphas,
plonk_zeta,
fri_challenges: challenger.fri_challenges::<C>(
self,
commit_phase_merkle_caps,
final_poly,
pow_witness,
inner_common_data,
),
}
}
}
impl<const D: usize> ProofWithPublicInputsTarget<D> {
pub(crate) fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>>(
&self,
builder: &mut CircuitBuilder<F, D>,
public_inputs_hash: HashOutTarget,
inner_common_data: &CommonCircuitData<F, C, D>,
) -> ProofChallengesTarget<D>
where
C::Hasher: AlgebraicHasher<F>,
{
let ProofTarget {
wires_cap,
plonk_zs_partial_products_cap,
quotient_polys_cap,
openings,
opening_proof:
FriProofTarget {
commit_phase_merkle_caps,
final_poly,
pow_witness,
..
},
} = &self.proof;
builder.get_challenges(
public_inputs_hash,
wires_cap,
plonk_zs_partial_products_cap,
quotient_polys_cap,
openings,
commit_phase_merkle_caps,
final_poly,
*pow_witness,
inner_common_data,
)
}
}

View File

@ -1,9 +1,12 @@
use anyhow::ensure;
use plonky2_field::extension_field::Extendable; use plonky2_field::extension_field::Extendable;
use rayon::prelude::*; use rayon::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::fri::oracle::PolynomialBatch; use crate::fri::oracle::PolynomialBatch;
use crate::fri::proof::{CompressedFriProof, FriChallenges, FriProof, FriProofTarget}; use crate::fri::proof::{
CompressedFriProof, FriChallenges, FriChallengesTarget, FriProof, FriProofTarget,
};
use crate::fri::structure::{ use crate::fri::structure::{
FriOpeningBatch, FriOpeningBatchTarget, FriOpenings, FriOpeningsTarget, FriOpeningBatch, FriOpeningBatchTarget, FriOpenings, FriOpeningsTarget,
}; };
@ -172,7 +175,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
self, self,
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> anyhow::Result<ProofWithPublicInputs<F, C, D>> { ) -> anyhow::Result<ProofWithPublicInputs<F, C, D>> {
let challenges = self.get_challenges(common_data)?; let challenges = self.get_challenges(self.get_public_inputs_hash(), common_data)?;
let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data); let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data);
let decompressed_proof = let decompressed_proof =
self.proof self.proof
@ -188,16 +191,19 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
verifier_data: &VerifierOnlyCircuitData<C, D>, verifier_data: &VerifierOnlyCircuitData<C, D>,
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let challenges = self.get_challenges(common_data)?; ensure!(
self.public_inputs.len() == common_data.num_public_inputs,
"Number of public inputs doesn't match circuit data."
);
let public_inputs_hash = self.get_public_inputs_hash();
let challenges = self.get_challenges(public_inputs_hash, common_data)?;
let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data); let fri_inferred_elements = self.get_inferred_elements(&challenges, common_data);
let decompressed_proof = let decompressed_proof =
self.proof self.proof
.decompress(&challenges, fri_inferred_elements, &common_data.fri_params); .decompress(&challenges, fri_inferred_elements, &common_data.fri_params);
verify_with_challenges( verify_with_challenges(
ProofWithPublicInputs { decompressed_proof,
public_inputs: self.public_inputs, public_inputs_hash,
proof: decompressed_proof,
},
challenges, challenges,
verifier_data, verifier_data,
common_data, common_data,
@ -242,6 +248,14 @@ pub(crate) struct ProofChallenges<F: RichField + Extendable<D>, const D: usize>
pub fri_challenges: FriChallenges<F, D>, pub fri_challenges: FriChallenges<F, D>,
} }
pub(crate) struct ProofChallengesTarget<const D: usize> {
pub plonk_betas: Vec<Target>,
pub plonk_gammas: Vec<Target>,
pub plonk_alphas: Vec<Target>,
pub plonk_zeta: ExtensionTarget<D>,
pub fri_challenges: FriChallengesTarget<D>,
}
/// Coset elements that can be inferred in the FRI reduction steps. /// Coset elements that can be inferred in the FRI reduction steps.
pub(crate) struct FriInferredElements<F: RichField + Extendable<D>, const D: usize>( pub(crate) struct FriInferredElements<F: RichField + Extendable<D>, const D: usize>(
pub Vec<F::Extension>, pub Vec<F::Extension>,

View File

@ -1,11 +1,12 @@
use plonky2_field::extension_field::Extendable; use plonky2_field::extension_field::Extendable;
use crate::hash::hash_types::{HashOutTarget, RichField}; use crate::hash::hash_types::{HashOutTarget, RichField};
use crate::iop::challenger::RecursiveChallenger;
use crate::plonk::circuit_builder::CircuitBuilder; use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::circuit_data::{CommonCircuitData, VerifierCircuitTarget}; use crate::plonk::circuit_data::{CommonCircuitData, VerifierCircuitTarget};
use crate::plonk::config::{AlgebraicHasher, GenericConfig}; use crate::plonk::config::{AlgebraicHasher, GenericConfig};
use crate::plonk::proof::{OpeningSetTarget, ProofTarget, ProofWithPublicInputsTarget}; use crate::plonk::proof::{
OpeningSetTarget, ProofChallengesTarget, ProofTarget, ProofWithPublicInputsTarget,
};
use crate::plonk::vanishing_poly::eval_vanishing_poly_recursively; use crate::plonk::vanishing_poly::eval_vanishing_poly_recursively;
use crate::plonk::vars::EvaluationTargets; use crate::plonk::vars::EvaluationTargets;
use crate::util::reducing::ReducingFactorTarget; use crate::util::reducing::ReducingFactorTarget;
@ -13,7 +14,7 @@ use crate::with_context;
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> { impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
/// Recursively verifies an inner proof. /// Recursively verifies an inner proof.
pub fn verify_proof_with_pis<C: GenericConfig<D, F = F>>( pub fn verify_proof<C: GenericConfig<D, F = F>>(
&mut self, &mut self,
proof_with_pis: ProofWithPublicInputsTarget<D>, proof_with_pis: ProofWithPublicInputsTarget<D>,
inner_verifier_data: &VerifierCircuitTarget, inner_verifier_data: &VerifierCircuitTarget,
@ -21,27 +22,29 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
) where ) where
C::Hasher: AlgebraicHasher<F>, C::Hasher: AlgebraicHasher<F>,
{ {
let ProofWithPublicInputsTarget { assert_eq!(
proof, proof_with_pis.public_inputs.len(),
public_inputs, inner_common_data.num_public_inputs
} = proof_with_pis; );
let public_inputs_hash =
self.hash_n_to_hash_no_pad::<C::InnerHasher>(proof_with_pis.public_inputs.clone());
let challenges = proof_with_pis.get_challenges(self, public_inputs_hash, inner_common_data);
assert_eq!(public_inputs.len(), inner_common_data.num_public_inputs); self.verify_proof_with_challenges(
let public_inputs_hash = self.hash_n_to_hash_no_pad::<C::InnerHasher>(public_inputs); proof_with_pis.proof,
self.verify_proof(
proof,
public_inputs_hash, public_inputs_hash,
challenges,
inner_verifier_data, inner_verifier_data,
inner_common_data, inner_common_data,
); );
} }
/// Recursively verifies an inner proof. /// Recursively verifies an inner proof.
pub fn verify_proof<C: GenericConfig<D, F = F>>( fn verify_proof_with_challenges<C: GenericConfig<D, F = F>>(
&mut self, &mut self,
proof: ProofTarget<D>, proof: ProofTarget<D>,
public_inputs_hash: HashOutTarget, public_inputs_hash: HashOutTarget,
challenges: ProofChallengesTarget<D>,
inner_verifier_data: &VerifierCircuitTarget, inner_verifier_data: &VerifierCircuitTarget,
inner_common_data: &CommonCircuitData<F, C, D>, inner_common_data: &CommonCircuitData<F, C, D>,
) where ) where
@ -49,32 +52,6 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
{ {
let one = self.one_extension(); let one = self.one_extension();
let num_challenges = inner_common_data.config.num_challenges;
let mut challenger = RecursiveChallenger::<F, C::Hasher, D>::new(self);
let (betas, gammas, alphas, zeta) =
with_context!(self, "observe proof and generates challenges", {
// Observe the instance.
let digest = HashOutTarget::from_vec(
self.constants(&inner_common_data.circuit_digest.elements),
);
challenger.observe_hash(&digest);
challenger.observe_hash(&public_inputs_hash);
challenger.observe_cap(&proof.wires_cap);
let betas = challenger.get_n_challenges(self, num_challenges);
let gammas = challenger.get_n_challenges(self, num_challenges);
challenger.observe_cap(&proof.plonk_zs_partial_products_cap);
let alphas = challenger.get_n_challenges(self, num_challenges);
challenger.observe_cap(&proof.quotient_polys_cap);
let zeta = challenger.get_extension_challenge(self);
(betas, gammas, alphas, zeta)
});
let local_constants = &proof.openings.constants; let local_constants = &proof.openings.constants;
let local_wires = &proof.openings.wires; let local_wires = &proof.openings.wires;
let vars = EvaluationTargets { let vars = EvaluationTargets {
@ -87,23 +64,24 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let s_sigmas = &proof.openings.plonk_sigmas; let s_sigmas = &proof.openings.plonk_sigmas;
let partial_products = &proof.openings.partial_products; let partial_products = &proof.openings.partial_products;
let zeta_pow_deg = self.exp_power_of_2_extension(zeta, inner_common_data.degree_bits); let zeta_pow_deg =
self.exp_power_of_2_extension(challenges.plonk_zeta, inner_common_data.degree_bits);
let vanishing_polys_zeta = with_context!( let vanishing_polys_zeta = with_context!(
self, self,
"evaluate the vanishing polynomial at our challenge point, zeta.", "evaluate the vanishing polynomial at our challenge point, zeta.",
eval_vanishing_poly_recursively( eval_vanishing_poly_recursively(
self, self,
inner_common_data, inner_common_data,
zeta, challenges.plonk_zeta,
zeta_pow_deg, zeta_pow_deg,
vars, vars,
local_zs, local_zs,
next_zs, next_zs,
partial_products, partial_products,
s_sigmas, s_sigmas,
&betas, &challenges.plonk_betas,
&gammas, &challenges.plonk_gammas,
&alphas, &challenges.plonk_alphas,
) )
); );
@ -128,16 +106,16 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
proof.quotient_polys_cap, proof.quotient_polys_cap,
]; ];
let fri_instance = inner_common_data.get_fri_instance_target(self, zeta); let fri_instance = inner_common_data.get_fri_instance_target(self, challenges.plonk_zeta);
with_context!( with_context!(
self, self,
"verify FRI proof", "verify FRI proof",
self.verify_fri_proof::<C>( self.verify_fri_proof::<C>(
&fri_instance, &fri_instance,
&proof.openings, &proof.openings.to_fri_openings(),
&challenges.fri_challenges,
merkle_caps, merkle_caps,
&proof.opening_proof, &proof.opening_proof,
&mut challenger,
&inner_common_data.fri_params, &inner_common_data.fri_params,
) )
); );
@ -382,7 +360,7 @@ mod tests {
let mut builder = CircuitBuilder::<F, D>::new(config.clone()); let mut builder = CircuitBuilder::<F, D>::new(config.clone());
let mut pw = PartialWitness::new(); let mut pw = PartialWitness::new();
let pt = builder.add_virtual_proof_with_pis(&inner_cd); let pt = builder.add_virtual_proof_with_pis(&inner_cd);
pw.set_proof_with_pis_target(&inner_proof, &pt); pw.set_proof_with_pis_target(&pt, &inner_proof);
let inner_data = VerifierCircuitTarget { let inner_data = VerifierCircuitTarget {
constants_sigmas_cap: builder.add_virtual_cap(inner_cd.config.fri_config.cap_height), constants_sigmas_cap: builder.add_virtual_cap(inner_cd.config.fri_config.cap_height),
@ -392,7 +370,7 @@ mod tests {
&inner_vd.constants_sigmas_cap, &inner_vd.constants_sigmas_cap,
); );
builder.verify_proof_with_pis(pt, &inner_data, &inner_cd); builder.verify_proof(pt, &inner_data, &inner_cd);
if print_gate_counts { if print_gate_counts {
builder.print_gate_counts(0); builder.print_gate_counts(0);

View File

@ -5,9 +5,9 @@ use plonky2_field::field_types::Field;
use crate::fri::verifier::verify_fri_proof; use crate::fri::verifier::verify_fri_proof;
use crate::hash::hash_types::RichField; use crate::hash::hash_types::RichField;
use crate::plonk::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData}; use crate::plonk::circuit_data::{CommonCircuitData, VerifierOnlyCircuitData};
use crate::plonk::config::GenericConfig; use crate::plonk::config::{GenericConfig, Hasher};
use crate::plonk::plonk_common::reduce_with_powers; use crate::plonk::plonk_common::reduce_with_powers;
use crate::plonk::proof::{ProofChallenges, ProofWithPublicInputs}; use crate::plonk::proof::{Proof, ProofChallenges, ProofWithPublicInputs};
use crate::plonk::vanishing_poly::eval_vanishing_poly; use crate::plonk::vanishing_poly::eval_vanishing_poly;
use crate::plonk::vars::EvaluationVars; use crate::plonk::vars::EvaluationVars;
@ -16,8 +16,20 @@ pub(crate) fn verify<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, c
verifier_data: &VerifierOnlyCircuitData<C, D>, verifier_data: &VerifierOnlyCircuitData<C, D>,
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> Result<()> { ) -> Result<()> {
let challenges = proof_with_pis.get_challenges(common_data)?; ensure!(
verify_with_challenges(proof_with_pis, challenges, verifier_data, common_data) proof_with_pis.public_inputs.len() == common_data.num_public_inputs,
"Number of public inputs doesn't match circuit data."
);
let public_inputs_hash = proof_with_pis.get_public_inputs_hash();
let challenges = proof_with_pis.get_challenges(public_inputs_hash, common_data)?;
verify_with_challenges(
proof_with_pis.proof,
public_inputs_hash,
challenges,
verifier_data,
common_data,
)
} }
pub(crate) fn verify_with_challenges< pub(crate) fn verify_with_challenges<
@ -25,25 +37,18 @@ pub(crate) fn verify_with_challenges<
C: GenericConfig<D, F = F>, C: GenericConfig<D, F = F>,
const D: usize, const D: usize,
>( >(
proof_with_pis: ProofWithPublicInputs<F, C, D>, proof: Proof<F, C, D>,
public_inputs_hash: <<C as GenericConfig<D>>::InnerHasher as Hasher<F>>::Hash,
challenges: ProofChallenges<F, D>, challenges: ProofChallenges<F, D>,
verifier_data: &VerifierOnlyCircuitData<C, D>, verifier_data: &VerifierOnlyCircuitData<C, D>,
common_data: &CommonCircuitData<F, C, D>, common_data: &CommonCircuitData<F, C, D>,
) -> Result<()> { ) -> Result<()> {
assert_eq!(
proof_with_pis.public_inputs.len(),
common_data.num_public_inputs
);
let public_inputs_hash = &proof_with_pis.get_public_inputs_hash();
let ProofWithPublicInputs { proof, .. } = proof_with_pis;
let local_constants = &proof.openings.constants; let local_constants = &proof.openings.constants;
let local_wires = &proof.openings.wires; let local_wires = &proof.openings.wires;
let vars = EvaluationVars { let vars = EvaluationVars {
local_constants, local_constants,
local_wires, local_wires,
public_inputs_hash, public_inputs_hash: &public_inputs_hash,
}; };
let local_zs = &proof.openings.plonk_zs; let local_zs = &proof.openings.plonk_zs;
let next_zs = &proof.openings.plonk_zs_right; let next_zs = &proof.openings.plonk_zs_right;