2022-06-27 07:18:21 -07:00
|
|
|
use plonky2::field::extension::Extendable;
|
2022-05-20 11:21:13 +02:00
|
|
|
use plonky2::fri::proof::{FriProof, FriProofTarget};
|
2022-05-18 09:22:58 +02:00
|
|
|
use plonky2::hash::hash_types::RichField;
|
2022-05-04 20:57:07 +02:00
|
|
|
use plonky2::iop::challenger::{Challenger, RecursiveChallenger};
|
|
|
|
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
|
|
|
|
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
|
|
|
|
|
|
2022-09-22 11:01:27 +02:00
|
|
|
use crate::all_stark::{AllStark, NUM_TABLES};
|
2022-05-04 20:57:07 +02:00
|
|
|
use crate::config::StarkConfig;
|
|
|
|
|
use crate::permutation::{
|
2022-09-23 16:28:20 +02:00
|
|
|
get_grand_product_challenge_set, get_n_grand_product_challenge_sets,
|
|
|
|
|
get_n_grand_product_challenge_sets_target,
|
2022-05-04 20:57:07 +02:00
|
|
|
};
|
|
|
|
|
use crate::proof::*;
|
|
|
|
|
|
2023-05-11 02:59:02 +10:00
|
|
|
impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> AllProof<F, C, D> {
|
2022-05-11 14:35:33 +02:00
|
|
|
/// Computes all Fiat-Shamir challenges used in the STARK proof.
|
|
|
|
|
pub(crate) fn get_challenges(
|
|
|
|
|
&self,
|
|
|
|
|
all_stark: &AllStark<F, D>,
|
|
|
|
|
config: &StarkConfig,
|
2023-05-11 02:59:02 +10:00
|
|
|
) -> AllProofChallenges<F, D> {
|
|
|
|
|
let mut challenger = Challenger::<F, C::Hasher>::new();
|
2022-05-11 14:35:33 +02:00
|
|
|
|
2022-05-19 09:41:15 +02:00
|
|
|
for proof in &self.stark_proofs {
|
Shrink STARK proofs to a constant degree
The goal here is to end up with a single "root" circuit representing any EVM proof. I.e. it must verify each STARK, but be general enough to work with any combination of STARK sizes (within some range of sizes that we chose to support). This root circuit can then be plugged into our aggregation circuit.
In particular, for each STARK, and for each initial `degree_bits` (within a range that we choose to support), this adds a "shrinking chain" of circuits. Such a chain shrinks a STARK proof from that initial `degree_bits` down to a constant, `THRESHOLD_DEGREE_BITS`.
The root circuit then combines these shrunk-to-constant proofs for each table. It's similar to `RecursiveAllProof::verify_circuit`; I adapted the code from there and I think we can remove it after. The main difference is that now instead of having one verification key per STARK, we have several possible VKs, one per initial `degree_bits`. We bake the list of possible VKs into the root circuit, and have the prover indicate the index of the VK they're actually using.
This also partially removes the default feature of CTLs. So far we've used filters instead of defaults. Until now it was easy to keep supporting defaults just in case, but here maintaining support would require some more work. E.g. we couldn't use `exp_u64` any more, since the size delta is now dynamic, it can't be hardcoded. If there are no concerns, I'll fully remove the feature after.
2022-12-27 18:15:18 -08:00
|
|
|
challenger.observe_cap(&proof.proof.trace_cap);
|
2022-05-11 14:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
2022-08-25 12:24:22 -07:00
|
|
|
// TODO: Observe public values.
|
|
|
|
|
|
2022-05-12 13:51:02 +02:00
|
|
|
let ctl_challenges =
|
|
|
|
|
get_grand_product_challenge_set(&mut challenger, config.num_challenges);
|
2022-05-11 14:35:33 +02:00
|
|
|
|
2022-08-26 10:12:45 +02:00
|
|
|
let num_permutation_zs = all_stark.nums_permutation_zs(config);
|
|
|
|
|
let num_permutation_batch_sizes = all_stark.permutation_batch_sizes();
|
|
|
|
|
|
2022-05-11 14:35:33 +02:00
|
|
|
AllProofChallenges {
|
2023-01-30 08:51:33 -08:00
|
|
|
stark_challenges: core::array::from_fn(|i| {
|
2022-10-03 10:53:33 +02:00
|
|
|
challenger.compact();
|
Shrink STARK proofs to a constant degree
The goal here is to end up with a single "root" circuit representing any EVM proof. I.e. it must verify each STARK, but be general enough to work with any combination of STARK sizes (within some range of sizes that we chose to support). This root circuit can then be plugged into our aggregation circuit.
In particular, for each STARK, and for each initial `degree_bits` (within a range that we choose to support), this adds a "shrinking chain" of circuits. Such a chain shrinks a STARK proof from that initial `degree_bits` down to a constant, `THRESHOLD_DEGREE_BITS`.
The root circuit then combines these shrunk-to-constant proofs for each table. It's similar to `RecursiveAllProof::verify_circuit`; I adapted the code from there and I think we can remove it after. The main difference is that now instead of having one verification key per STARK, we have several possible VKs, one per initial `degree_bits`. We bake the list of possible VKs into the root circuit, and have the prover indicate the index of the VK they're actually using.
This also partially removes the default feature of CTLs. So far we've used filters instead of defaults. Until now it was easy to keep supporting defaults just in case, but here maintaining support would require some more work. E.g. we couldn't use `exp_u64` any more, since the size delta is now dynamic, it can't be hardcoded. If there are no concerns, I'll fully remove the feature after.
2022-12-27 18:15:18 -08:00
|
|
|
self.stark_proofs[i].proof.get_challenges(
|
2022-08-26 10:12:45 +02:00
|
|
|
&mut challenger,
|
|
|
|
|
num_permutation_zs[i] > 0,
|
|
|
|
|
num_permutation_batch_sizes[i],
|
|
|
|
|
config,
|
|
|
|
|
)
|
|
|
|
|
}),
|
2022-05-11 14:35:33 +02:00
|
|
|
ctl_challenges,
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-06 16:40:03 +02:00
|
|
|
|
|
|
|
|
#[allow(unused)] // TODO: should be used soon
|
2022-09-22 11:01:27 +02:00
|
|
|
pub(crate) fn get_challenger_states(
|
|
|
|
|
&self,
|
|
|
|
|
all_stark: &AllStark<F, D>,
|
|
|
|
|
config: &StarkConfig,
|
2023-05-11 02:59:02 +10:00
|
|
|
) -> AllChallengerState<F, C::Hasher, D> {
|
|
|
|
|
let mut challenger = Challenger::<F, C::Hasher>::new();
|
2022-09-22 11:01:27 +02:00
|
|
|
|
|
|
|
|
for proof in &self.stark_proofs {
|
Shrink STARK proofs to a constant degree
The goal here is to end up with a single "root" circuit representing any EVM proof. I.e. it must verify each STARK, but be general enough to work with any combination of STARK sizes (within some range of sizes that we chose to support). This root circuit can then be plugged into our aggregation circuit.
In particular, for each STARK, and for each initial `degree_bits` (within a range that we choose to support), this adds a "shrinking chain" of circuits. Such a chain shrinks a STARK proof from that initial `degree_bits` down to a constant, `THRESHOLD_DEGREE_BITS`.
The root circuit then combines these shrunk-to-constant proofs for each table. It's similar to `RecursiveAllProof::verify_circuit`; I adapted the code from there and I think we can remove it after. The main difference is that now instead of having one verification key per STARK, we have several possible VKs, one per initial `degree_bits`. We bake the list of possible VKs into the root circuit, and have the prover indicate the index of the VK they're actually using.
This also partially removes the default feature of CTLs. So far we've used filters instead of defaults. Until now it was easy to keep supporting defaults just in case, but here maintaining support would require some more work. E.g. we couldn't use `exp_u64` any more, since the size delta is now dynamic, it can't be hardcoded. If there are no concerns, I'll fully remove the feature after.
2022-12-27 18:15:18 -08:00
|
|
|
challenger.observe_cap(&proof.proof.trace_cap);
|
2022-09-22 11:01:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: Observe public values.
|
|
|
|
|
|
|
|
|
|
let ctl_challenges =
|
|
|
|
|
get_grand_product_challenge_set(&mut challenger, config.num_challenges);
|
|
|
|
|
|
|
|
|
|
let num_permutation_zs = all_stark.nums_permutation_zs(config);
|
|
|
|
|
let num_permutation_batch_sizes = all_stark.permutation_batch_sizes();
|
|
|
|
|
|
2022-10-03 10:53:33 +02:00
|
|
|
let mut challenger_states = vec![challenger.compact()];
|
2022-09-22 11:01:27 +02:00
|
|
|
for i in 0..NUM_TABLES {
|
Shrink STARK proofs to a constant degree
The goal here is to end up with a single "root" circuit representing any EVM proof. I.e. it must verify each STARK, but be general enough to work with any combination of STARK sizes (within some range of sizes that we chose to support). This root circuit can then be plugged into our aggregation circuit.
In particular, for each STARK, and for each initial `degree_bits` (within a range that we choose to support), this adds a "shrinking chain" of circuits. Such a chain shrinks a STARK proof from that initial `degree_bits` down to a constant, `THRESHOLD_DEGREE_BITS`.
The root circuit then combines these shrunk-to-constant proofs for each table. It's similar to `RecursiveAllProof::verify_circuit`; I adapted the code from there and I think we can remove it after. The main difference is that now instead of having one verification key per STARK, we have several possible VKs, one per initial `degree_bits`. We bake the list of possible VKs into the root circuit, and have the prover indicate the index of the VK they're actually using.
This also partially removes the default feature of CTLs. So far we've used filters instead of defaults. Until now it was easy to keep supporting defaults just in case, but here maintaining support would require some more work. E.g. we couldn't use `exp_u64` any more, since the size delta is now dynamic, it can't be hardcoded. If there are no concerns, I'll fully remove the feature after.
2022-12-27 18:15:18 -08:00
|
|
|
self.stark_proofs[i].proof.get_challenges(
|
2022-09-22 11:01:27 +02:00
|
|
|
&mut challenger,
|
|
|
|
|
num_permutation_zs[i] > 0,
|
|
|
|
|
num_permutation_batch_sizes[i],
|
|
|
|
|
config,
|
|
|
|
|
);
|
2022-10-03 10:53:33 +02:00
|
|
|
challenger_states.push(challenger.compact());
|
2022-09-22 11:01:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AllChallengerState {
|
|
|
|
|
states: challenger_states.try_into().unwrap(),
|
|
|
|
|
ctl_challenges,
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-11 14:35:33 +02:00
|
|
|
}
|
|
|
|
|
|
2023-04-01 09:34:13 -04:00
|
|
|
impl<F, C, const D: usize> StarkProof<F, C, D>
|
2022-05-04 20:57:07 +02:00
|
|
|
where
|
|
|
|
|
F: RichField + Extendable<D>,
|
2023-04-01 09:34:13 -04:00
|
|
|
C: GenericConfig<D, F = F>,
|
2022-05-04 20:57:07 +02:00
|
|
|
{
|
|
|
|
|
/// Computes all Fiat-Shamir challenges used in the STARK proof.
|
2022-05-19 09:41:15 +02:00
|
|
|
pub(crate) fn get_challenges(
|
2022-05-04 20:57:07 +02:00
|
|
|
&self,
|
2023-05-11 02:59:02 +10:00
|
|
|
challenger: &mut Challenger<F, C::Hasher>,
|
2022-05-20 08:37:18 +02:00
|
|
|
stark_use_permutation: bool,
|
|
|
|
|
stark_permutation_batch_size: usize,
|
2022-05-04 20:57:07 +02:00
|
|
|
config: &StarkConfig,
|
2023-05-11 02:59:02 +10:00
|
|
|
) -> StarkProofChallenges<F, D> {
|
2022-08-25 12:24:22 -07:00
|
|
|
let degree_bits = self.recover_degree_bits(config);
|
2022-05-11 14:35:33 +02:00
|
|
|
|
2022-05-04 20:57:07 +02:00
|
|
|
let StarkProof {
|
2022-05-12 22:29:10 +02:00
|
|
|
permutation_ctl_zs_cap,
|
2022-05-04 20:57:07 +02:00
|
|
|
quotient_polys_cap,
|
|
|
|
|
openings,
|
|
|
|
|
opening_proof:
|
|
|
|
|
FriProof {
|
|
|
|
|
commit_phase_merkle_caps,
|
|
|
|
|
final_poly,
|
|
|
|
|
pow_witness,
|
|
|
|
|
..
|
|
|
|
|
},
|
2022-05-12 22:35:13 +02:00
|
|
|
..
|
2022-08-25 12:24:22 -07:00
|
|
|
} = &self;
|
2022-05-04 20:57:07 +02:00
|
|
|
|
2022-05-18 09:22:58 +02:00
|
|
|
let num_challenges = config.num_challenges;
|
2022-05-04 20:57:07 +02:00
|
|
|
|
2022-05-20 08:37:18 +02:00
|
|
|
let permutation_challenge_sets = stark_use_permutation.then(|| {
|
|
|
|
|
get_n_grand_product_challenge_sets(
|
|
|
|
|
challenger,
|
|
|
|
|
num_challenges,
|
|
|
|
|
stark_permutation_batch_size,
|
|
|
|
|
)
|
2022-05-18 09:22:58 +02:00
|
|
|
});
|
2022-05-04 20:57:07 +02:00
|
|
|
|
2022-05-18 09:22:58 +02:00
|
|
|
challenger.observe_cap(permutation_ctl_zs_cap);
|
2022-05-04 20:57:07 +02:00
|
|
|
|
2022-05-18 09:22:58 +02:00
|
|
|
let stark_alphas = challenger.get_n_challenges(num_challenges);
|
2022-05-04 20:57:07 +02:00
|
|
|
|
2022-05-18 09:22:58 +02:00
|
|
|
challenger.observe_cap(quotient_polys_cap);
|
|
|
|
|
let stark_zeta = challenger.get_extension_challenge::<D>();
|
2022-05-04 20:57:07 +02:00
|
|
|
|
2022-05-18 09:22:58 +02:00
|
|
|
challenger.observe_openings(&openings.to_fri_openings());
|
2022-05-04 20:57:07 +02:00
|
|
|
|
2022-05-18 09:22:58 +02:00
|
|
|
StarkProofChallenges {
|
|
|
|
|
permutation_challenge_sets,
|
|
|
|
|
stark_alphas,
|
|
|
|
|
stark_zeta,
|
2023-04-01 09:34:13 -04:00
|
|
|
fri_challenges: challenger.fri_challenges::<C, D>(
|
2022-05-18 09:22:58 +02:00
|
|
|
commit_phase_merkle_caps,
|
|
|
|
|
final_poly,
|
|
|
|
|
*pow_witness,
|
|
|
|
|
degree_bits,
|
|
|
|
|
&config.fri_config,
|
|
|
|
|
),
|
|
|
|
|
}
|
2022-05-04 20:57:07 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-25 12:24:22 -07:00
|
|
|
impl<const D: usize> StarkProofTarget<D> {
|
2023-04-01 09:34:13 -04:00
|
|
|
pub(crate) fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>>(
|
2022-05-04 20:57:07 +02:00
|
|
|
&self,
|
|
|
|
|
builder: &mut CircuitBuilder<F, D>,
|
2023-05-11 02:59:02 +10:00
|
|
|
challenger: &mut RecursiveChallenger<F, C::Hasher, D>,
|
2022-05-20 11:21:13 +02:00
|
|
|
stark_use_permutation: bool,
|
|
|
|
|
stark_permutation_batch_size: usize,
|
2022-05-04 20:57:07 +02:00
|
|
|
config: &StarkConfig,
|
|
|
|
|
) -> StarkProofChallengesTarget<D>
|
|
|
|
|
where
|
2023-05-11 02:59:02 +10:00
|
|
|
C::Hasher: AlgebraicHasher<F>,
|
2022-05-04 20:57:07 +02:00
|
|
|
{
|
2022-05-20 11:21:13 +02:00
|
|
|
let StarkProofTarget {
|
|
|
|
|
permutation_ctl_zs_cap,
|
|
|
|
|
quotient_polys_cap,
|
|
|
|
|
openings,
|
|
|
|
|
opening_proof:
|
|
|
|
|
FriProofTarget {
|
|
|
|
|
commit_phase_merkle_caps,
|
|
|
|
|
final_poly,
|
|
|
|
|
pow_witness,
|
|
|
|
|
..
|
|
|
|
|
},
|
|
|
|
|
..
|
2022-08-25 12:24:22 -07:00
|
|
|
} = &self;
|
2022-05-20 11:21:13 +02:00
|
|
|
|
2022-05-18 09:22:58 +02:00
|
|
|
let num_challenges = config.num_challenges;
|
2022-05-20 11:21:13 +02:00
|
|
|
|
|
|
|
|
let permutation_challenge_sets = stark_use_permutation.then(|| {
|
|
|
|
|
get_n_grand_product_challenge_sets_target(
|
|
|
|
|
builder,
|
|
|
|
|
challenger,
|
|
|
|
|
num_challenges,
|
|
|
|
|
stark_permutation_batch_size,
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
challenger.observe_cap(permutation_ctl_zs_cap);
|
|
|
|
|
|
2022-05-18 09:22:58 +02:00
|
|
|
let stark_alphas = challenger.get_n_challenges(builder, num_challenges);
|
2022-05-20 11:21:13 +02:00
|
|
|
|
|
|
|
|
challenger.observe_cap(quotient_polys_cap);
|
2022-05-18 09:22:58 +02:00
|
|
|
let stark_zeta = challenger.get_extension_challenge(builder);
|
2022-05-20 11:21:13 +02:00
|
|
|
|
|
|
|
|
challenger.observe_openings(&openings.to_fri_openings(builder.zero()));
|
|
|
|
|
|
2022-05-18 09:22:58 +02:00
|
|
|
StarkProofChallengesTarget {
|
|
|
|
|
permutation_challenge_sets,
|
|
|
|
|
stark_alphas,
|
|
|
|
|
stark_zeta,
|
2023-02-25 08:55:55 -08:00
|
|
|
fri_challenges: challenger.fri_challenges(
|
2022-05-18 09:22:58 +02:00
|
|
|
builder,
|
2022-05-20 11:21:13 +02:00
|
|
|
commit_phase_merkle_caps,
|
|
|
|
|
final_poly,
|
|
|
|
|
*pow_witness,
|
2022-05-18 09:22:58 +02:00
|
|
|
&config.fri_config,
|
|
|
|
|
),
|
|
|
|
|
}
|
2022-05-04 20:57:07 +02:00
|
|
|
}
|
|
|
|
|
}
|