mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-03 22:33:06 +00:00
Merge pull request #551 from mir-protocol/starkevm_recursive_verifier
`evm` recursive verifier
This commit is contained in:
commit
e8fc5b5752
@ -51,6 +51,9 @@ mod tests {
|
||||
use anyhow::Result;
|
||||
use plonky2::field::field_types::Field;
|
||||
use plonky2::field::polynomial::PolynomialValues;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2::util::timing::TimingTree;
|
||||
use rand::{thread_rng, Rng};
|
||||
@ -60,17 +63,18 @@ mod tests {
|
||||
use crate::cpu::cpu_stark::CpuStark;
|
||||
use crate::cross_table_lookup::CrossTableLookup;
|
||||
use crate::keccak::keccak_stark::KeccakStark;
|
||||
use crate::proof::AllProof;
|
||||
use crate::prover::prove;
|
||||
use crate::recursive_verifier::{
|
||||
add_virtual_all_proof, set_all_proof_target, verify_proof_circuit,
|
||||
};
|
||||
use crate::verifier::verify_proof;
|
||||
|
||||
#[test]
|
||||
fn test_all_stark() -> Result<()> {
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
let config = StarkConfig::standard_fast_config();
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
|
||||
fn get_proof(config: &StarkConfig) -> Result<(AllStark<F, D>, AllProof<F, C, D>)> {
|
||||
let cpu_stark = CpuStark::<F, D> {
|
||||
f: Default::default(),
|
||||
};
|
||||
@ -118,12 +122,65 @@ mod tests {
|
||||
|
||||
let proof = prove::<F, C, D>(
|
||||
&all_stark,
|
||||
&config,
|
||||
config,
|
||||
vec![cpu_trace, keccak_trace],
|
||||
vec![vec![]; 2],
|
||||
&mut TimingTree::default(),
|
||||
)?;
|
||||
|
||||
Ok((all_stark, proof))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_stark() -> Result<()> {
|
||||
let config = StarkConfig::standard_fast_config();
|
||||
let (all_stark, proof) = get_proof(&config)?;
|
||||
verify_proof(all_stark, proof, &config)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_stark_recursive_verifier() -> Result<()> {
|
||||
init_logger();
|
||||
|
||||
let config = StarkConfig::standard_fast_config();
|
||||
let (all_stark, proof) = get_proof(&config)?;
|
||||
verify_proof(all_stark.clone(), proof.clone(), &config)?;
|
||||
|
||||
recursive_proof(all_stark, proof, &config, true)
|
||||
}
|
||||
|
||||
fn recursive_proof(
|
||||
inner_all_stark: AllStark<F, D>,
|
||||
inner_proof: AllProof<F, C, D>,
|
||||
inner_config: &StarkConfig,
|
||||
print_gate_counts: bool,
|
||||
) -> Result<()> {
|
||||
let circuit_config = CircuitConfig::standard_recursion_config();
|
||||
let mut builder = CircuitBuilder::<F, D>::new(circuit_config);
|
||||
let mut pw = PartialWitness::new();
|
||||
let degree_bits = inner_proof.degree_bits(inner_config);
|
||||
let nums_ctl_zs = inner_proof.nums_ctl_zs();
|
||||
let pt = add_virtual_all_proof(
|
||||
&mut builder,
|
||||
&inner_all_stark,
|
||||
inner_config,
|
||||
°ree_bits,
|
||||
&nums_ctl_zs,
|
||||
);
|
||||
set_all_proof_target(&mut pw, &pt, &inner_proof, builder.zero());
|
||||
|
||||
verify_proof_circuit::<F, C, D>(&mut builder, inner_all_stark, pt, inner_config);
|
||||
|
||||
if print_gate_counts {
|
||||
builder.print_gate_counts(0);
|
||||
}
|
||||
|
||||
let data = builder.build::<C>();
|
||||
let proof = data.prove(pw)?;
|
||||
data.verify(proof)
|
||||
}
|
||||
|
||||
fn init_logger() {
|
||||
let _ = env_logger::builder().format_timestamp(None).try_init();
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,17 +5,20 @@ use plonky2::field::packed_field::PackedField;
|
||||
use plonky2::field::polynomial::PolynomialValues;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::challenger::Challenger;
|
||||
use plonky2::iop::ext_target::ExtensionTarget;
|
||||
use plonky2::iop::target::Target;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::config::GenericConfig;
|
||||
|
||||
use crate::all_stark::Table;
|
||||
use crate::config::StarkConfig;
|
||||
use crate::constraint_consumer::ConstraintConsumer;
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::permutation::{
|
||||
get_grand_product_challenge_set, GrandProductChallenge, GrandProductChallengeSet,
|
||||
};
|
||||
use crate::proof::StarkProofWithPublicInputs;
|
||||
use crate::proof::{StarkProofWithPublicInputs, StarkProofWithPublicInputsTarget};
|
||||
use crate::stark::Stark;
|
||||
use crate::vars::StarkEvaluationVars;
|
||||
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CrossTableLookup<F: Field> {
|
||||
@ -230,6 +233,106 @@ pub(crate) fn eval_cross_table_lookup_checks<F, FE, P, C, S, const D: usize, con
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CtlCheckVarsTarget<'a, const D: usize> {
|
||||
pub(crate) local_z: ExtensionTarget<D>,
|
||||
pub(crate) next_z: ExtensionTarget<D>,
|
||||
pub(crate) challenges: GrandProductChallenge<Target>,
|
||||
pub(crate) columns: &'a [usize],
|
||||
}
|
||||
|
||||
impl<'a, const D: usize> CtlCheckVarsTarget<'a, D> {
|
||||
pub(crate) fn from_proofs<F: Field>(
|
||||
proofs: &[StarkProofWithPublicInputsTarget<D>],
|
||||
cross_table_lookups: &'a [CrossTableLookup<F>],
|
||||
ctl_challenges: &'a GrandProductChallengeSet<Target>,
|
||||
num_permutation_zs: &[usize],
|
||||
) -> Vec<Vec<Self>> {
|
||||
debug_assert_eq!(proofs.len(), num_permutation_zs.len());
|
||||
let mut ctl_zs = proofs
|
||||
.iter()
|
||||
.zip(num_permutation_zs)
|
||||
.map(|(p, &num_perms)| {
|
||||
let openings = &p.proof.openings;
|
||||
let ctl_zs = openings.permutation_ctl_zs.iter().skip(num_perms);
|
||||
let ctl_zs_right = openings.permutation_ctl_zs_right.iter().skip(num_perms);
|
||||
ctl_zs.zip(ctl_zs_right)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut ctl_vars_per_table = vec![vec![]; proofs.len()];
|
||||
for CrossTableLookup {
|
||||
looking_table,
|
||||
looking_columns,
|
||||
looked_table,
|
||||
looked_columns,
|
||||
..
|
||||
} in cross_table_lookups
|
||||
{
|
||||
for &challenges in &ctl_challenges.challenges {
|
||||
let (looking_z, looking_z_next) = ctl_zs[*looking_table as usize].next().unwrap();
|
||||
ctl_vars_per_table[*looking_table as usize].push(Self {
|
||||
local_z: *looking_z,
|
||||
next_z: *looking_z_next,
|
||||
challenges,
|
||||
columns: looking_columns,
|
||||
});
|
||||
|
||||
let (looked_z, looked_z_next) = ctl_zs[*looked_table as usize].next().unwrap();
|
||||
ctl_vars_per_table[*looked_table as usize].push(Self {
|
||||
local_z: *looked_z,
|
||||
next_z: *looked_z_next,
|
||||
challenges,
|
||||
columns: looked_columns,
|
||||
});
|
||||
}
|
||||
}
|
||||
ctl_vars_per_table
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn eval_cross_table_lookup_checks_circuit<
|
||||
S: Stark<F, D>,
|
||||
F: RichField + Extendable<D>,
|
||||
const D: usize,
|
||||
>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
vars: StarkEvaluationTargets<D, { S::COLUMNS }, { S::PUBLIC_INPUTS }>,
|
||||
ctl_vars: &[CtlCheckVarsTarget<D>],
|
||||
consumer: &mut RecursiveConstraintConsumer<F, D>,
|
||||
) {
|
||||
for lookup_vars in ctl_vars {
|
||||
let CtlCheckVarsTarget {
|
||||
local_z,
|
||||
next_z,
|
||||
challenges,
|
||||
columns,
|
||||
} = lookup_vars;
|
||||
|
||||
// Check value of `Z(1)`
|
||||
let combined_local = challenges.combine_circuit(
|
||||
builder,
|
||||
&columns
|
||||
.iter()
|
||||
.map(|&i| vars.local_values[i])
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
let first_row = builder.sub_extension(*local_z, combined_local);
|
||||
consumer.constraint_first_row(builder, first_row);
|
||||
// Check `Z(gw) = combination * Z(w)`
|
||||
let combined_next = challenges.combine_circuit(
|
||||
builder,
|
||||
&columns
|
||||
.iter()
|
||||
.map(|&i| vars.next_values[i])
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
let mut transition = builder.mul_extension(*local_z, combined_next);
|
||||
transition = builder.sub_extension(*next_z, transition);
|
||||
consumer.constraint_transition(builder, transition);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn verify_cross_table_lookups<
|
||||
F: RichField + Extendable<D>,
|
||||
C: GenericConfig<D, F = F>,
|
||||
@ -273,3 +376,49 @@ pub(crate) fn verify_cross_table_lookups<
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn verify_cross_table_lookups_circuit<
|
||||
F: RichField + Extendable<D>,
|
||||
C: GenericConfig<D, F = F>,
|
||||
const D: usize,
|
||||
>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
cross_table_lookups: Vec<CrossTableLookup<F>>,
|
||||
proofs: &[StarkProofWithPublicInputsTarget<D>],
|
||||
challenges: GrandProductChallengeSet<Target>,
|
||||
inner_config: &StarkConfig,
|
||||
) {
|
||||
let degrees_bits = proofs
|
||||
.iter()
|
||||
.map(|p| p.proof.recover_degree_bits(inner_config))
|
||||
.collect::<Vec<_>>();
|
||||
let mut ctl_zs_openings = proofs
|
||||
.iter()
|
||||
.map(|p| p.proof.openings.ctl_zs_last.iter())
|
||||
.collect::<Vec<_>>();
|
||||
for (
|
||||
i,
|
||||
CrossTableLookup {
|
||||
looking_table,
|
||||
looked_table,
|
||||
default,
|
||||
..
|
||||
},
|
||||
) in cross_table_lookups.into_iter().enumerate()
|
||||
{
|
||||
let looking_degree = 1 << degrees_bits[looking_table as usize];
|
||||
let looked_degree = 1 << degrees_bits[looked_table as usize];
|
||||
let looking_z = *ctl_zs_openings[looking_table as usize].next().unwrap();
|
||||
let looked_z = *ctl_zs_openings[looked_table as usize].next().unwrap();
|
||||
let challenge = challenges.challenges[i % inner_config.num_challenges];
|
||||
let default = default
|
||||
.into_iter()
|
||||
.map(|x| builder.constant(x))
|
||||
.collect::<Vec<_>>();
|
||||
let combined_default = challenge.combine_base_circuit(builder, &default);
|
||||
|
||||
let pad = builder.exp_u64(combined_default, looking_degree - looked_degree);
|
||||
let padded_looked_z = builder.mul(looked_z, pad);
|
||||
builder.connect(looking_z, padded_looked_z);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use itertools::izip;
|
||||
use plonky2::field::extension_field::Extendable;
|
||||
use plonky2::fri::proof::FriProof;
|
||||
use plonky2::fri::proof::{FriProof, FriProofTarget};
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::challenger::{Challenger, RecursiveChallenger};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
@ -9,11 +9,10 @@ use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
|
||||
use crate::all_stark::AllStark;
|
||||
use crate::config::StarkConfig;
|
||||
use crate::permutation::{
|
||||
get_grand_product_challenge_set, get_n_grand_product_challenge_sets,
|
||||
get_n_permutation_challenge_sets_target,
|
||||
get_grand_product_challenge_set, get_grand_product_challenge_set_target,
|
||||
get_n_grand_product_challenge_sets, get_n_grand_product_challenge_sets_target,
|
||||
};
|
||||
use crate::proof::*;
|
||||
use crate::stark::Stark;
|
||||
|
||||
impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> AllProof<F, C, D> {
|
||||
/// Computes all Fiat-Shamir challenges used in the STARK proof.
|
||||
@ -46,6 +45,46 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> A
|
||||
}
|
||||
}
|
||||
|
||||
impl<const D: usize> AllProofTarget<D> {
|
||||
pub(crate) fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>>(
|
||||
&self,
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
all_stark: &AllStark<F, D>,
|
||||
config: &StarkConfig,
|
||||
) -> AllProofChallengesTarget<D>
|
||||
where
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
{
|
||||
let mut challenger = RecursiveChallenger::<F, C::Hasher, D>::new(builder);
|
||||
|
||||
for proof in &self.stark_proofs {
|
||||
challenger.observe_cap(&proof.proof.trace_cap);
|
||||
}
|
||||
|
||||
let ctl_challenges =
|
||||
get_grand_product_challenge_set_target(builder, &mut challenger, config.num_challenges);
|
||||
|
||||
AllProofChallengesTarget {
|
||||
stark_challenges: izip!(
|
||||
&self.stark_proofs,
|
||||
all_stark.nums_permutation_zs(config),
|
||||
all_stark.permutation_batch_sizes()
|
||||
)
|
||||
.map(|(proof, num_perm, batch_size)| {
|
||||
proof.get_challenges::<F, C>(
|
||||
builder,
|
||||
&mut challenger,
|
||||
num_perm > 0,
|
||||
batch_size,
|
||||
config,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
ctl_challenges,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F, C, const D: usize> StarkProofWithPublicInputs<F, C, D>
|
||||
where
|
||||
F: RichField + Extendable<D>,
|
||||
@ -110,48 +149,60 @@ where
|
||||
}
|
||||
|
||||
impl<const D: usize> StarkProofWithPublicInputsTarget<D> {
|
||||
pub(crate) fn get_challenges<
|
||||
F: RichField + Extendable<D>,
|
||||
C: GenericConfig<D, F = F>,
|
||||
S: Stark<F, D>,
|
||||
>(
|
||||
pub(crate) fn get_challenges<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>>(
|
||||
&self,
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
stark: &S,
|
||||
challenger: &mut RecursiveChallenger<F, C::Hasher, D>,
|
||||
stark_use_permutation: bool,
|
||||
stark_permutation_batch_size: usize,
|
||||
config: &StarkConfig,
|
||||
) -> StarkProofChallengesTarget<D>
|
||||
where
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
{
|
||||
let proof = &self.proof;
|
||||
let opening_proof = &proof.opening_proof;
|
||||
let StarkProofTarget {
|
||||
permutation_ctl_zs_cap,
|
||||
quotient_polys_cap,
|
||||
openings,
|
||||
opening_proof:
|
||||
FriProofTarget {
|
||||
commit_phase_merkle_caps,
|
||||
final_poly,
|
||||
pow_witness,
|
||||
..
|
||||
},
|
||||
..
|
||||
} = &self.proof;
|
||||
|
||||
let num_challenges = config.num_challenges;
|
||||
let mut challenger = RecursiveChallenger::<F, C::Hasher, D>::new(builder);
|
||||
challenger.observe_cap(&proof.trace_cap);
|
||||
let permutation_challenge_sets =
|
||||
proof.permutation_zs_cap.as_ref().map(|permutation_zs_cap| {
|
||||
let tmp = get_n_permutation_challenge_sets_target(
|
||||
builder,
|
||||
&mut challenger,
|
||||
num_challenges,
|
||||
stark.permutation_batch_size(),
|
||||
);
|
||||
challenger.observe_cap(permutation_zs_cap);
|
||||
tmp
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
let stark_alphas = challenger.get_n_challenges(builder, num_challenges);
|
||||
challenger.observe_cap(&proof.quotient_polys_cap);
|
||||
|
||||
challenger.observe_cap(quotient_polys_cap);
|
||||
let stark_zeta = challenger.get_extension_challenge(builder);
|
||||
challenger.observe_openings(&proof.openings.to_fri_openings());
|
||||
|
||||
challenger.observe_openings(&openings.to_fri_openings(builder.zero()));
|
||||
|
||||
StarkProofChallengesTarget {
|
||||
permutation_challenge_sets,
|
||||
stark_alphas,
|
||||
stark_zeta,
|
||||
fri_challenges: challenger.fri_challenges::<C>(
|
||||
builder,
|
||||
&opening_proof.commit_phase_merkle_caps,
|
||||
&opening_proof.final_poly,
|
||||
opening_proof.pow_witness,
|
||||
commit_phase_merkle_caps,
|
||||
final_poly,
|
||||
*pow_witness,
|
||||
&config.fri_config,
|
||||
),
|
||||
}
|
||||
|
||||
@ -12,7 +12,9 @@ use plonky2::iop::ext_target::ExtensionTarget;
|
||||
use plonky2::iop::target::Target;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher};
|
||||
use plonky2::plonk::plonk_common::reduce_with_powers;
|
||||
use plonky2::plonk::plonk_common::{
|
||||
reduce_with_powers, reduce_with_powers_circuit, reduce_with_powers_ext_circuit,
|
||||
};
|
||||
use plonky2::util::reducing::{ReducingFactor, ReducingFactorTarget};
|
||||
use rayon::prelude::*;
|
||||
|
||||
@ -68,6 +70,27 @@ impl<F: Field> GrandProductChallenge<F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl GrandProductChallenge<Target> {
|
||||
pub(crate) fn combine_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
&self,
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
terms: &[ExtensionTarget<D>],
|
||||
) -> ExtensionTarget<D> {
|
||||
let reduced = reduce_with_powers_ext_circuit(builder, terms, self.beta);
|
||||
let gamma = builder.convert_to_ext(self.gamma);
|
||||
builder.add_extension(reduced, gamma)
|
||||
}
|
||||
|
||||
pub(crate) fn combine_base_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
&self,
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
terms: &[Target],
|
||||
) -> Target {
|
||||
let reduced = reduce_with_powers_circuit(builder, terms, self.beta);
|
||||
builder.add(reduced, self.gamma)
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `PermutationChallenge`, but with `num_challenges` copies to boost soundness.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct GrandProductChallengeSet<T: Copy> {
|
||||
@ -190,7 +213,7 @@ pub(crate) fn get_n_grand_product_challenge_sets<F: RichField, H: Hasher<F>>(
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn get_permutation_challenge_target<
|
||||
fn get_grand_product_challenge_target<
|
||||
F: RichField + Extendable<D>,
|
||||
H: AlgebraicHasher<F>,
|
||||
const D: usize,
|
||||
@ -203,7 +226,7 @@ fn get_permutation_challenge_target<
|
||||
GrandProductChallenge { beta, gamma }
|
||||
}
|
||||
|
||||
fn get_permutation_challenge_set_target<
|
||||
pub(crate) fn get_grand_product_challenge_set_target<
|
||||
F: RichField + Extendable<D>,
|
||||
H: AlgebraicHasher<F>,
|
||||
const D: usize,
|
||||
@ -213,12 +236,12 @@ fn get_permutation_challenge_set_target<
|
||||
num_challenges: usize,
|
||||
) -> GrandProductChallengeSet<Target> {
|
||||
let challenges = (0..num_challenges)
|
||||
.map(|_| get_permutation_challenge_target(builder, challenger))
|
||||
.map(|_| get_grand_product_challenge_target(builder, challenger))
|
||||
.collect();
|
||||
GrandProductChallengeSet { challenges }
|
||||
}
|
||||
|
||||
pub(crate) fn get_n_permutation_challenge_sets_target<
|
||||
pub(crate) fn get_n_grand_product_challenge_sets_target<
|
||||
F: RichField + Extendable<D>,
|
||||
H: AlgebraicHasher<F>,
|
||||
const D: usize,
|
||||
@ -229,7 +252,7 @@ pub(crate) fn get_n_permutation_challenge_sets_target<
|
||||
num_sets: usize,
|
||||
) -> Vec<GrandProductChallengeSet<Target>> {
|
||||
(0..num_sets)
|
||||
.map(|_| get_permutation_challenge_set_target(builder, challenger, num_challenges))
|
||||
.map(|_| get_grand_product_challenge_set_target(builder, challenger, num_challenges))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
@ -22,11 +22,36 @@ pub struct AllProof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, co
|
||||
pub stark_proofs: Vec<StarkProofWithPublicInputs<F, C, D>>,
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> AllProof<F, C, D> {
|
||||
pub fn degree_bits(&self, config: &StarkConfig) -> Vec<usize> {
|
||||
self.stark_proofs
|
||||
.iter()
|
||||
.map(|proof| proof.proof.recover_degree_bits(config))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn nums_ctl_zs(&self) -> Vec<usize> {
|
||||
self.stark_proofs
|
||||
.iter()
|
||||
.map(|proof| proof.proof.openings.ctl_zs_last.len())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct AllProofChallenges<F: RichField + Extendable<D>, const D: usize> {
|
||||
pub stark_challenges: Vec<StarkProofChallenges<F, D>>,
|
||||
pub ctl_challenges: GrandProductChallengeSet<F>,
|
||||
}
|
||||
|
||||
pub struct AllProofTarget<const D: usize> {
|
||||
pub stark_proofs: Vec<StarkProofWithPublicInputsTarget<D>>,
|
||||
}
|
||||
|
||||
pub(crate) struct AllProofChallengesTarget<const D: usize> {
|
||||
pub stark_challenges: Vec<StarkProofChallengesTarget<D>>,
|
||||
pub ctl_challenges: GrandProductChallengeSet<Target>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StarkProof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> {
|
||||
/// Merkle cap of LDEs of trace values.
|
||||
@ -55,7 +80,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize> S
|
||||
|
||||
pub struct StarkProofTarget<const D: usize> {
|
||||
pub trace_cap: MerkleCapTarget,
|
||||
pub permutation_zs_cap: Option<MerkleCapTarget>,
|
||||
pub permutation_ctl_zs_cap: MerkleCapTarget,
|
||||
pub quotient_polys_cap: MerkleCapTarget,
|
||||
pub openings: StarkOpeningSetTarget<D>,
|
||||
pub opening_proof: FriProofTarget<D>,
|
||||
@ -203,38 +228,38 @@ impl<F: RichField + Extendable<D>, const D: usize> StarkOpeningSet<F, D> {
|
||||
.copied()
|
||||
.collect_vec(),
|
||||
};
|
||||
let mut batches = vec![zeta_batch, zeta_right_batch];
|
||||
debug_assert!(!self.ctl_zs_last.is_empty());
|
||||
let ctl_last_batch = FriOpeningBatch {
|
||||
values: self
|
||||
.ctl_zs_last
|
||||
.iter()
|
||||
.copied()
|
||||
.map(F::Extension::from_basefield)
|
||||
.collect(),
|
||||
};
|
||||
|
||||
if !self.ctl_zs_last.is_empty() {
|
||||
batches.push(FriOpeningBatch {
|
||||
values: self
|
||||
.ctl_zs_last
|
||||
.iter()
|
||||
.copied()
|
||||
.map(F::Extension::from_basefield)
|
||||
.collect(),
|
||||
});
|
||||
FriOpenings {
|
||||
batches: vec![zeta_batch, zeta_right_batch, ctl_last_batch],
|
||||
}
|
||||
|
||||
FriOpenings { batches }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StarkOpeningSetTarget<const D: usize> {
|
||||
pub local_values: Vec<ExtensionTarget<D>>,
|
||||
pub next_values: Vec<ExtensionTarget<D>>,
|
||||
pub permutation_zs: Option<Vec<ExtensionTarget<D>>>,
|
||||
pub permutation_zs_right: Option<Vec<ExtensionTarget<D>>>,
|
||||
pub permutation_ctl_zs: Vec<ExtensionTarget<D>>,
|
||||
pub permutation_ctl_zs_right: Vec<ExtensionTarget<D>>,
|
||||
pub ctl_zs_last: Vec<Target>,
|
||||
pub quotient_polys: Vec<ExtensionTarget<D>>,
|
||||
}
|
||||
|
||||
impl<const D: usize> StarkOpeningSetTarget<D> {
|
||||
pub(crate) fn to_fri_openings(&self) -> FriOpeningsTarget<D> {
|
||||
pub(crate) fn to_fri_openings(&self, zero: Target) -> FriOpeningsTarget<D> {
|
||||
let zeta_batch = FriOpeningBatchTarget {
|
||||
values: self
|
||||
.local_values
|
||||
.iter()
|
||||
.chain(self.permutation_zs.iter().flatten())
|
||||
.chain(&self.permutation_ctl_zs)
|
||||
.chain(&self.quotient_polys)
|
||||
.copied()
|
||||
.collect_vec(),
|
||||
@ -243,12 +268,22 @@ impl<const D: usize> StarkOpeningSetTarget<D> {
|
||||
values: self
|
||||
.next_values
|
||||
.iter()
|
||||
.chain(self.permutation_zs_right.iter().flatten())
|
||||
.chain(&self.permutation_ctl_zs_right)
|
||||
.copied()
|
||||
.collect_vec(),
|
||||
};
|
||||
debug_assert!(!self.ctl_zs_last.is_empty());
|
||||
let ctl_last_batch = FriOpeningBatchTarget {
|
||||
values: self
|
||||
.ctl_zs_last
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|t| t.to_ext_target(zero))
|
||||
.collect(),
|
||||
};
|
||||
|
||||
FriOpeningsTarget {
|
||||
batches: vec![zeta_batch, zeta_right_batch],
|
||||
batches: vec![zeta_batch, zeta_right_batch, ctl_last_batch],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,60 +1,92 @@
|
||||
use std::iter::once;
|
||||
|
||||
use anyhow::{ensure, Result};
|
||||
use itertools::Itertools;
|
||||
use plonky2::field::extension_field::Extendable;
|
||||
use plonky2::field::field_types::Field;
|
||||
use plonky2::fri::witness_util::set_fri_proof_target;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::ext_target::ExtensionTarget;
|
||||
use plonky2::iop::target::Target;
|
||||
use plonky2::iop::witness::Witness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
|
||||
use plonky2::util::reducing::ReducingFactorTarget;
|
||||
use plonky2::with_context;
|
||||
|
||||
use crate::all_stark::{AllStark, Table};
|
||||
use crate::config::StarkConfig;
|
||||
use crate::constraint_consumer::RecursiveConstraintConsumer;
|
||||
use crate::cpu::cpu_stark::CpuStark;
|
||||
use crate::cross_table_lookup::{verify_cross_table_lookups_circuit, CtlCheckVarsTarget};
|
||||
use crate::keccak::keccak_stark::KeccakStark;
|
||||
use crate::permutation::PermutationCheckDataTarget;
|
||||
use crate::proof::{
|
||||
StarkOpeningSetTarget, StarkProof, StarkProofChallengesTarget, StarkProofTarget,
|
||||
StarkProofWithPublicInputs, StarkProofWithPublicInputsTarget,
|
||||
AllProof, AllProofChallengesTarget, AllProofTarget, StarkOpeningSetTarget, StarkProof,
|
||||
StarkProofChallengesTarget, StarkProofTarget, StarkProofWithPublicInputs,
|
||||
StarkProofWithPublicInputsTarget,
|
||||
};
|
||||
use crate::stark::Stark;
|
||||
use crate::vanishing_poly::eval_vanishing_poly_circuit;
|
||||
use crate::vars::StarkEvaluationTargets;
|
||||
|
||||
pub fn verify_stark_proof_circuit<
|
||||
pub fn verify_proof_circuit<
|
||||
F: RichField + Extendable<D>,
|
||||
C: GenericConfig<D, F = F>,
|
||||
S: Stark<F, D>,
|
||||
const D: usize,
|
||||
>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
stark: S,
|
||||
proof_with_pis: StarkProofWithPublicInputsTarget<D>,
|
||||
all_stark: AllStark<F, D>,
|
||||
all_proof: AllProofTarget<D>,
|
||||
inner_config: &StarkConfig,
|
||||
) where
|
||||
[(); CpuStark::<F, D>::COLUMNS]:,
|
||||
[(); CpuStark::<F, D>::PUBLIC_INPUTS]:,
|
||||
[(); KeccakStark::<F, D>::COLUMNS]:,
|
||||
[(); KeccakStark::<F, D>::PUBLIC_INPUTS]:,
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
[(); S::COLUMNS]:,
|
||||
[(); S::PUBLIC_INPUTS]:,
|
||||
{
|
||||
assert_eq!(proof_with_pis.public_inputs.len(), S::PUBLIC_INPUTS);
|
||||
let degree_bits = proof_with_pis.proof.recover_degree_bits(inner_config);
|
||||
let challenges = with_context!(
|
||||
builder,
|
||||
"compute challenges",
|
||||
proof_with_pis.get_challenges::<F, C, S>(builder, &stark, inner_config)
|
||||
let AllProofChallengesTarget {
|
||||
stark_challenges,
|
||||
ctl_challenges,
|
||||
} = all_proof.get_challenges::<F, C>(builder, &all_stark, inner_config);
|
||||
|
||||
let nums_permutation_zs = all_stark.nums_permutation_zs(inner_config);
|
||||
|
||||
let AllStark {
|
||||
cpu_stark,
|
||||
keccak_stark,
|
||||
cross_table_lookups,
|
||||
} = all_stark;
|
||||
|
||||
let ctl_vars_per_table = CtlCheckVarsTarget::from_proofs(
|
||||
&all_proof.stark_proofs,
|
||||
&cross_table_lookups,
|
||||
&ctl_challenges,
|
||||
&nums_permutation_zs,
|
||||
);
|
||||
|
||||
verify_stark_proof_with_challenges_circuit::<F, C, S, D>(
|
||||
verify_stark_proof_with_challenges_circuit::<F, C, _, D>(
|
||||
builder,
|
||||
stark,
|
||||
proof_with_pis,
|
||||
challenges,
|
||||
cpu_stark,
|
||||
&all_proof.stark_proofs[Table::Cpu as usize],
|
||||
&stark_challenges[Table::Cpu as usize],
|
||||
&ctl_vars_per_table[Table::Cpu as usize],
|
||||
inner_config,
|
||||
degree_bits,
|
||||
);
|
||||
verify_stark_proof_with_challenges_circuit::<F, C, _, D>(
|
||||
builder,
|
||||
keccak_stark,
|
||||
&all_proof.stark_proofs[Table::Keccak as usize],
|
||||
&stark_challenges[Table::Keccak as usize],
|
||||
&ctl_vars_per_table[Table::Keccak as usize],
|
||||
inner_config,
|
||||
);
|
||||
|
||||
verify_cross_table_lookups_circuit::<F, C, D>(
|
||||
builder,
|
||||
cross_table_lookups,
|
||||
&all_proof.stark_proofs,
|
||||
ctl_challenges,
|
||||
inner_config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Recursively verifies an inner proof.
|
||||
@ -66,40 +98,43 @@ fn verify_stark_proof_with_challenges_circuit<
|
||||
>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
stark: S,
|
||||
proof_with_pis: StarkProofWithPublicInputsTarget<D>,
|
||||
challenges: StarkProofChallengesTarget<D>,
|
||||
proof_with_pis: &StarkProofWithPublicInputsTarget<D>,
|
||||
challenges: &StarkProofChallengesTarget<D>,
|
||||
ctl_vars: &[CtlCheckVarsTarget<D>],
|
||||
inner_config: &StarkConfig,
|
||||
degree_bits: usize,
|
||||
) where
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
[(); S::COLUMNS]:,
|
||||
[(); S::PUBLIC_INPUTS]:,
|
||||
{
|
||||
check_permutation_options(&stark, &proof_with_pis, &challenges).unwrap();
|
||||
let zero = builder.zero();
|
||||
let one = builder.one_extension();
|
||||
|
||||
let StarkProofWithPublicInputsTarget {
|
||||
proof,
|
||||
public_inputs,
|
||||
} = proof_with_pis;
|
||||
assert_eq!(public_inputs.len(), S::PUBLIC_INPUTS);
|
||||
let StarkOpeningSetTarget {
|
||||
local_values,
|
||||
next_values,
|
||||
permutation_zs,
|
||||
permutation_zs_right,
|
||||
permutation_ctl_zs,
|
||||
permutation_ctl_zs_right,
|
||||
ctl_zs_last,
|
||||
quotient_polys,
|
||||
} = &proof.openings;
|
||||
let vars = StarkEvaluationTargets {
|
||||
local_values: &local_values.to_vec().try_into().unwrap(),
|
||||
next_values: &next_values.to_vec().try_into().unwrap(),
|
||||
public_inputs: &public_inputs
|
||||
.into_iter()
|
||||
.map(|t| builder.convert_to_ext(t))
|
||||
.iter()
|
||||
.map(|&t| builder.convert_to_ext(t))
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
};
|
||||
|
||||
let degree_bits = proof.recover_degree_bits(inner_config);
|
||||
let zeta_pow_deg = builder.exp_power_of_2_extension(challenges.stark_zeta, degree_bits);
|
||||
let z_h_zeta = builder.sub_extension(zeta_pow_deg, one);
|
||||
let (l_1, l_last) =
|
||||
@ -110,18 +145,19 @@ fn verify_stark_proof_with_challenges_circuit<
|
||||
|
||||
let mut consumer = RecursiveConstraintConsumer::<F, D>::new(
|
||||
builder.zero_extension(),
|
||||
challenges.stark_alphas,
|
||||
challenges.stark_alphas.clone(),
|
||||
z_last,
|
||||
l_1,
|
||||
l_last,
|
||||
);
|
||||
|
||||
let num_permutation_zs = stark.num_permutation_batches(inner_config);
|
||||
let permutation_data = stark
|
||||
.uses_permutation_args()
|
||||
.then(|| PermutationCheckDataTarget {
|
||||
local_zs: permutation_zs.as_ref().unwrap().clone(),
|
||||
next_zs: permutation_zs_right.as_ref().unwrap().clone(),
|
||||
permutation_challenge_sets: challenges.permutation_challenge_sets.unwrap(),
|
||||
local_zs: permutation_ctl_zs[..num_permutation_zs].to_vec(),
|
||||
next_zs: permutation_ctl_zs_right[..num_permutation_zs].to_vec(),
|
||||
permutation_challenge_sets: challenges.permutation_challenge_sets.clone().unwrap(),
|
||||
});
|
||||
|
||||
with_context!(
|
||||
@ -133,6 +169,7 @@ fn verify_stark_proof_with_challenges_circuit<
|
||||
inner_config,
|
||||
vars,
|
||||
permutation_data,
|
||||
ctl_vars,
|
||||
&mut consumer,
|
||||
)
|
||||
);
|
||||
@ -149,20 +186,23 @@ fn verify_stark_proof_with_challenges_circuit<
|
||||
builder.connect_extension(vanishing_polys_zeta[i], computed_vanishing_poly);
|
||||
}
|
||||
|
||||
let merkle_caps = once(proof.trace_cap)
|
||||
.chain(proof.permutation_zs_cap)
|
||||
.chain(once(proof.quotient_polys_cap))
|
||||
.collect_vec();
|
||||
let merkle_caps = vec![
|
||||
proof.trace_cap.clone(),
|
||||
proof.permutation_ctl_zs_cap.clone(),
|
||||
proof.quotient_polys_cap.clone(),
|
||||
];
|
||||
|
||||
let fri_instance = stark.fri_instance_target(
|
||||
builder,
|
||||
challenges.stark_zeta,
|
||||
F::primitive_root_of_unity(degree_bits),
|
||||
degree_bits,
|
||||
ctl_zs_last.len(),
|
||||
inner_config,
|
||||
);
|
||||
builder.verify_fri_proof::<C>(
|
||||
&fri_instance,
|
||||
&proof.openings.to_fri_openings(),
|
||||
&proof.openings.to_fri_openings(zero),
|
||||
&challenges.fri_challenges,
|
||||
&merkle_caps,
|
||||
&proof.opening_proof,
|
||||
@ -189,6 +229,48 @@ fn eval_l_1_and_l_last_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add_virtual_all_proof<F: RichField + Extendable<D>, const D: usize>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
all_stark: &AllStark<F, D>,
|
||||
config: &StarkConfig,
|
||||
degree_bits: &[usize],
|
||||
nums_ctl_zs: &[usize],
|
||||
) -> AllProofTarget<D> {
|
||||
let stark_proofs = vec![
|
||||
{
|
||||
let proof = add_virtual_stark_proof(
|
||||
builder,
|
||||
all_stark.cpu_stark,
|
||||
config,
|
||||
degree_bits[Table::Cpu as usize],
|
||||
nums_ctl_zs[Table::Cpu as usize],
|
||||
);
|
||||
let public_inputs = builder.add_virtual_targets(CpuStark::<F, D>::PUBLIC_INPUTS);
|
||||
StarkProofWithPublicInputsTarget {
|
||||
proof,
|
||||
public_inputs,
|
||||
}
|
||||
},
|
||||
{
|
||||
let proof = add_virtual_stark_proof(
|
||||
builder,
|
||||
all_stark.keccak_stark,
|
||||
config,
|
||||
degree_bits[Table::Keccak as usize],
|
||||
nums_ctl_zs[Table::Keccak as usize],
|
||||
);
|
||||
let public_inputs = builder.add_virtual_targets(KeccakStark::<F, D>::PUBLIC_INPUTS);
|
||||
StarkProofWithPublicInputsTarget {
|
||||
proof,
|
||||
public_inputs,
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
assert_eq!(stark_proofs.len(), Table::num_tables());
|
||||
AllProofTarget { stark_proofs }
|
||||
}
|
||||
|
||||
pub fn add_virtual_stark_proof_with_pis<
|
||||
F: RichField + Extendable<D>,
|
||||
S: Stark<F, D>,
|
||||
@ -198,8 +280,9 @@ pub fn add_virtual_stark_proof_with_pis<
|
||||
stark: S,
|
||||
config: &StarkConfig,
|
||||
degree_bits: usize,
|
||||
num_ctl_zs: usize,
|
||||
) -> StarkProofWithPublicInputsTarget<D> {
|
||||
let proof = add_virtual_stark_proof::<F, S, D>(builder, stark, config, degree_bits);
|
||||
let proof = add_virtual_stark_proof::<F, S, D>(builder, stark, config, degree_bits, num_ctl_zs);
|
||||
let public_inputs = builder.add_virtual_targets(S::PUBLIC_INPUTS);
|
||||
StarkProofWithPublicInputsTarget {
|
||||
proof,
|
||||
@ -212,28 +295,24 @@ pub fn add_virtual_stark_proof<F: RichField + Extendable<D>, S: Stark<F, D>, con
|
||||
stark: S,
|
||||
config: &StarkConfig,
|
||||
degree_bits: usize,
|
||||
num_ctl_zs: usize,
|
||||
) -> StarkProofTarget<D> {
|
||||
let fri_params = config.fri_params(degree_bits);
|
||||
let cap_height = fri_params.config.cap_height;
|
||||
|
||||
let num_leaves_per_oracle = once(S::COLUMNS)
|
||||
.chain(
|
||||
stark
|
||||
.uses_permutation_args()
|
||||
.then(|| stark.num_permutation_batches(config)),
|
||||
)
|
||||
.chain(once(stark.quotient_degree_factor() * config.num_challenges))
|
||||
.collect_vec();
|
||||
let num_leaves_per_oracle = vec![
|
||||
S::COLUMNS,
|
||||
stark.num_permutation_batches(config) + num_ctl_zs,
|
||||
stark.quotient_degree_factor() * config.num_challenges,
|
||||
];
|
||||
|
||||
let permutation_zs_cap = stark
|
||||
.uses_permutation_args()
|
||||
.then(|| builder.add_virtual_cap(cap_height));
|
||||
let permutation_zs_cap = builder.add_virtual_cap(cap_height);
|
||||
|
||||
StarkProofTarget {
|
||||
trace_cap: builder.add_virtual_cap(cap_height),
|
||||
permutation_zs_cap,
|
||||
permutation_ctl_zs_cap: permutation_zs_cap,
|
||||
quotient_polys_cap: builder.add_virtual_cap(cap_height),
|
||||
openings: add_stark_opening_set::<F, S, D>(builder, stark, config),
|
||||
openings: add_stark_opening_set::<F, S, D>(builder, stark, num_ctl_zs, config),
|
||||
opening_proof: builder.add_virtual_fri_proof(&num_leaves_per_oracle, &fri_params),
|
||||
}
|
||||
}
|
||||
@ -241,27 +320,47 @@ pub fn add_virtual_stark_proof<F: RichField + Extendable<D>, S: Stark<F, D>, con
|
||||
fn add_stark_opening_set<F: RichField + Extendable<D>, S: Stark<F, D>, const D: usize>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
stark: S,
|
||||
num_ctl_zs: usize,
|
||||
config: &StarkConfig,
|
||||
) -> StarkOpeningSetTarget<D> {
|
||||
let num_challenges = config.num_challenges;
|
||||
StarkOpeningSetTarget {
|
||||
local_values: builder.add_virtual_extension_targets(S::COLUMNS),
|
||||
next_values: builder.add_virtual_extension_targets(S::COLUMNS),
|
||||
permutation_zs: stark
|
||||
.uses_permutation_args()
|
||||
.then(|| builder.add_virtual_extension_targets(stark.num_permutation_batches(config))),
|
||||
permutation_zs_right: stark
|
||||
.uses_permutation_args()
|
||||
.then(|| builder.add_virtual_extension_targets(stark.num_permutation_batches(config))),
|
||||
permutation_ctl_zs: builder
|
||||
.add_virtual_extension_targets(stark.num_permutation_batches(config) + num_ctl_zs),
|
||||
permutation_ctl_zs_right: builder
|
||||
.add_virtual_extension_targets(stark.num_permutation_batches(config) + num_ctl_zs),
|
||||
ctl_zs_last: builder.add_virtual_targets(num_ctl_zs),
|
||||
quotient_polys: builder
|
||||
.add_virtual_extension_targets(stark.quotient_degree_factor() * num_challenges),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_all_proof_target<F, C: GenericConfig<D, F = F>, W, const D: usize>(
|
||||
witness: &mut W,
|
||||
all_proof_target: &AllProofTarget<D>,
|
||||
all_proof: &AllProof<F, C, D>,
|
||||
zero: Target,
|
||||
) where
|
||||
F: RichField + Extendable<D>,
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
W: Witness<F>,
|
||||
{
|
||||
for (pt, p) in all_proof_target
|
||||
.stark_proofs
|
||||
.iter()
|
||||
.zip_eq(&all_proof.stark_proofs)
|
||||
{
|
||||
set_stark_proof_with_pis_target(witness, pt, p, zero);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_stark_proof_with_pis_target<F, C: GenericConfig<D, F = F>, W, const D: usize>(
|
||||
witness: &mut W,
|
||||
stark_proof_with_pis_target: &StarkProofWithPublicInputsTarget<D>,
|
||||
stark_proof_with_pis: &StarkProofWithPublicInputs<F, C, D>,
|
||||
zero: Target,
|
||||
) where
|
||||
F: RichField + Extendable<D>,
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
@ -281,13 +380,14 @@ pub fn set_stark_proof_with_pis_target<F, C: GenericConfig<D, F = F>, W, const D
|
||||
witness.set_target(pi_t, pi);
|
||||
}
|
||||
|
||||
set_stark_proof_target(witness, pt, proof);
|
||||
set_stark_proof_target(witness, pt, proof, zero);
|
||||
}
|
||||
|
||||
pub fn set_stark_proof_target<F, C: GenericConfig<D, F = F>, W, const D: usize>(
|
||||
witness: &mut W,
|
||||
proof_target: &StarkProofTarget<D>,
|
||||
proof: &StarkProof<F, C, D>,
|
||||
zero: Target,
|
||||
) where
|
||||
F: RichField + Extendable<D>,
|
||||
C::Hasher: AlgebraicHasher<F>,
|
||||
@ -297,35 +397,14 @@ pub fn set_stark_proof_target<F, C: GenericConfig<D, F = F>, W, const D: usize>(
|
||||
witness.set_cap_target(&proof_target.quotient_polys_cap, &proof.quotient_polys_cap);
|
||||
|
||||
witness.set_fri_openings(
|
||||
&proof_target.openings.to_fri_openings(),
|
||||
&proof_target.openings.to_fri_openings(zero),
|
||||
&proof.openings.to_fri_openings(),
|
||||
);
|
||||
|
||||
if let Some(permutation_zs_cap_target) = &proof_target.permutation_zs_cap {
|
||||
witness.set_cap_target(permutation_zs_cap_target, &proof.permutation_ctl_zs_cap);
|
||||
}
|
||||
witness.set_cap_target(
|
||||
&proof_target.permutation_ctl_zs_cap,
|
||||
&proof.permutation_ctl_zs_cap,
|
||||
);
|
||||
|
||||
set_fri_proof_target(witness, &proof_target.opening_proof, &proof.opening_proof);
|
||||
}
|
||||
|
||||
/// Utility function to check that all permutation data wrapped in `Option`s are `Some` iff
|
||||
/// the Stark uses a permutation argument.
|
||||
fn check_permutation_options<F: RichField + Extendable<D>, S: Stark<F, D>, const D: usize>(
|
||||
stark: &S,
|
||||
proof_with_pis: &StarkProofWithPublicInputsTarget<D>,
|
||||
challenges: &StarkProofChallengesTarget<D>,
|
||||
) -> Result<()> {
|
||||
let options_is_some = [
|
||||
proof_with_pis.proof.permutation_zs_cap.is_some(),
|
||||
proof_with_pis.proof.openings.permutation_zs.is_some(),
|
||||
proof_with_pis.proof.openings.permutation_zs_right.is_some(),
|
||||
challenges.permutation_challenge_sets.is_some(),
|
||||
];
|
||||
ensure!(
|
||||
options_is_some
|
||||
.into_iter()
|
||||
.all(|b| b == stark.uses_permutation_args()),
|
||||
"Permutation data doesn't match with Stark configuration."
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
use std::iter::once;
|
||||
|
||||
use plonky2::field::extension_field::{Extendable, FieldExtension};
|
||||
use plonky2::field::field_types::Field;
|
||||
use plonky2::field::packed_field::PackedField;
|
||||
@ -97,24 +95,16 @@ pub trait Stark<F: RichField + Extendable<D>, const D: usize>: Sync {
|
||||
FriPolynomialInfo::from_range(oracle_indices.next().unwrap(), 0..Self::COLUMNS);
|
||||
|
||||
let num_permutation_batches = self.num_permutation_batches(config);
|
||||
let permutation_ctl_zs_info = (num_permutation_batches + num_ctl_zs > 0).then(|| {
|
||||
let permutation_ctl_index = oracle_indices.next().unwrap();
|
||||
FriPolynomialInfo::from_range(
|
||||
permutation_ctl_index,
|
||||
0..num_permutation_batches + num_ctl_zs,
|
||||
)
|
||||
});
|
||||
let permutation_ctl_index = oracle_indices.next().unwrap();
|
||||
let permutation_ctl_zs_info = FriPolynomialInfo::from_range(
|
||||
permutation_ctl_index,
|
||||
0..num_permutation_batches + num_ctl_zs,
|
||||
);
|
||||
|
||||
let ctl_zs_info = (num_ctl_zs > 0).then(|| {
|
||||
let index = permutation_ctl_zs_info
|
||||
.as_ref()
|
||||
.map(|info| info[0].oracle_index)
|
||||
.unwrap_or_else(|| oracle_indices.next().unwrap());
|
||||
FriPolynomialInfo::from_range(
|
||||
index,
|
||||
num_permutation_batches..num_permutation_batches + num_ctl_zs,
|
||||
)
|
||||
});
|
||||
let ctl_zs_info = FriPolynomialInfo::from_range(
|
||||
permutation_ctl_index,
|
||||
num_permutation_batches..num_permutation_batches + num_ctl_zs,
|
||||
);
|
||||
|
||||
let quotient_info = FriPolynomialInfo::from_range(
|
||||
oracle_indices.next().unwrap(),
|
||||
@ -123,29 +113,24 @@ pub trait Stark<F: RichField + Extendable<D>, const D: usize>: Sync {
|
||||
|
||||
let zeta_batch = FriBatchInfo {
|
||||
point: zeta,
|
||||
polynomials: once(trace_info.clone())
|
||||
.chain(permutation_ctl_zs_info.clone())
|
||||
.chain(once(quotient_info))
|
||||
.collect::<Vec<_>>()
|
||||
.concat(),
|
||||
polynomials: [
|
||||
trace_info.clone(),
|
||||
permutation_ctl_zs_info.clone(),
|
||||
quotient_info,
|
||||
]
|
||||
.concat(),
|
||||
};
|
||||
let zeta_right_batch = FriBatchInfo {
|
||||
point: zeta.scalar_mul(g),
|
||||
polynomials: once(trace_info)
|
||||
.chain(permutation_ctl_zs_info)
|
||||
.collect::<Vec<_>>()
|
||||
.concat(),
|
||||
polynomials: [trace_info, permutation_ctl_zs_info].concat(),
|
||||
};
|
||||
let ctl_last_batch = ctl_zs_info.map(|info| FriBatchInfo {
|
||||
let ctl_last_batch = FriBatchInfo {
|
||||
point: F::Extension::primitive_root_of_unity(degree_bits).inverse(),
|
||||
polynomials: info,
|
||||
});
|
||||
polynomials: ctl_zs_info,
|
||||
};
|
||||
FriInstanceInfo {
|
||||
oracles: vec![no_blinding_oracle; oracle_indices.next().unwrap()],
|
||||
batches: once(zeta_batch)
|
||||
.chain(once(zeta_right_batch))
|
||||
.chain(ctl_last_batch)
|
||||
.collect::<Vec<_>>(),
|
||||
batches: vec![zeta_batch, zeta_right_batch, ctl_last_batch],
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,7 +140,9 @@ pub trait Stark<F: RichField + Extendable<D>, const D: usize>: Sync {
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
zeta: ExtensionTarget<D>,
|
||||
g: F,
|
||||
config: &StarkConfig,
|
||||
degree_bits: usize,
|
||||
num_ctl_zs: usize,
|
||||
inner_config: &StarkConfig,
|
||||
) -> FriInstanceInfoTarget<D> {
|
||||
let no_blinding_oracle = FriOracleInfo { blinding: false };
|
||||
let mut oracle_indices = 0..;
|
||||
@ -163,25 +150,28 @@ pub trait Stark<F: RichField + Extendable<D>, const D: usize>: Sync {
|
||||
let trace_info =
|
||||
FriPolynomialInfo::from_range(oracle_indices.next().unwrap(), 0..Self::COLUMNS);
|
||||
|
||||
let permutation_zs_info = if self.uses_permutation_args() {
|
||||
FriPolynomialInfo::from_range(
|
||||
oracle_indices.next().unwrap(),
|
||||
0..self.num_permutation_batches(config),
|
||||
)
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
let num_permutation_batches = self.num_permutation_batches(inner_config);
|
||||
let permutation_ctl_index = oracle_indices.next().unwrap();
|
||||
let permutation_ctl_zs_info = FriPolynomialInfo::from_range(
|
||||
permutation_ctl_index,
|
||||
0..num_permutation_batches + num_ctl_zs,
|
||||
);
|
||||
|
||||
let ctl_zs_info = FriPolynomialInfo::from_range(
|
||||
permutation_ctl_index,
|
||||
num_permutation_batches..num_permutation_batches + num_ctl_zs,
|
||||
);
|
||||
|
||||
let quotient_info = FriPolynomialInfo::from_range(
|
||||
oracle_indices.next().unwrap(),
|
||||
0..self.quotient_degree_factor() * config.num_challenges,
|
||||
0..self.quotient_degree_factor() * inner_config.num_challenges,
|
||||
);
|
||||
|
||||
let zeta_batch = FriBatchInfoTarget {
|
||||
point: zeta,
|
||||
polynomials: [
|
||||
trace_info.clone(),
|
||||
permutation_zs_info.clone(),
|
||||
permutation_ctl_zs_info.clone(),
|
||||
quotient_info,
|
||||
]
|
||||
.concat(),
|
||||
@ -189,11 +179,16 @@ pub trait Stark<F: RichField + Extendable<D>, const D: usize>: Sync {
|
||||
let zeta_right = builder.mul_const_extension(g, zeta);
|
||||
let zeta_right_batch = FriBatchInfoTarget {
|
||||
point: zeta_right,
|
||||
polynomials: [trace_info, permutation_zs_info].concat(),
|
||||
polynomials: [trace_info, permutation_ctl_zs_info].concat(),
|
||||
};
|
||||
let ctl_last_batch = FriBatchInfoTarget {
|
||||
point: builder
|
||||
.constant_extension(F::Extension::primitive_root_of_unity(degree_bits).inverse()),
|
||||
polynomials: ctl_zs_info,
|
||||
};
|
||||
FriInstanceInfoTarget {
|
||||
oracles: vec![no_blinding_oracle; oracle_indices.next().unwrap()],
|
||||
batches: vec![zeta_batch, zeta_right_batch],
|
||||
batches: vec![zeta_batch, zeta_right_batch, ctl_last_batch],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,10 @@ use plonky2::plonk::config::GenericConfig;
|
||||
|
||||
use crate::config::StarkConfig;
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::cross_table_lookup::{eval_cross_table_lookup_checks, CtlCheckVars};
|
||||
use crate::cross_table_lookup::{
|
||||
eval_cross_table_lookup_checks, eval_cross_table_lookup_checks_circuit, CtlCheckVars,
|
||||
CtlCheckVarsTarget,
|
||||
};
|
||||
use crate::permutation::{
|
||||
eval_permutation_checks, eval_permutation_checks_circuit, PermutationCheckDataTarget,
|
||||
PermutationCheckVars,
|
||||
@ -47,6 +50,7 @@ pub(crate) fn eval_vanishing_poly_circuit<F, C, S, const D: usize>(
|
||||
config: &StarkConfig,
|
||||
vars: StarkEvaluationTargets<D, { S::COLUMNS }, { S::PUBLIC_INPUTS }>,
|
||||
permutation_data: Option<PermutationCheckDataTarget<D>>,
|
||||
ctl_vars: &[CtlCheckVarsTarget<D>],
|
||||
consumer: &mut RecursiveConstraintConsumer<F, D>,
|
||||
) where
|
||||
F: RichField + Extendable<D>,
|
||||
@ -66,4 +70,5 @@ pub(crate) fn eval_vanishing_poly_circuit<F, C, S, const D: usize>(
|
||||
consumer,
|
||||
);
|
||||
}
|
||||
eval_cross_table_lookup_checks_circuit::<S, F, D>(builder, vars, ctl_vars, consumer);
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ where
|
||||
[(); CpuStark::<F, D>::COLUMNS]:,
|
||||
[(); CpuStark::<F, D>::PUBLIC_INPUTS]:,
|
||||
[(); KeccakStark::<F, D>::COLUMNS]:,
|
||||
[(); KeccakStark::<F, D>::PUBLIC_INPUTS]:,
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
let AllProofChallenges {
|
||||
@ -95,6 +96,7 @@ where
|
||||
proof,
|
||||
public_inputs,
|
||||
} = proof_with_pis;
|
||||
ensure!(public_inputs.len() == S::PUBLIC_INPUTS);
|
||||
let StarkOpeningSet {
|
||||
local_values,
|
||||
next_values,
|
||||
|
||||
@ -120,9 +120,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
|
||||
|
||||
pub fn convert_to_ext(&mut self, t: Target) -> ExtensionTarget<D> {
|
||||
let zero = self.zero();
|
||||
let mut arr = [zero; D];
|
||||
arr[0] = t;
|
||||
ExtensionTarget(arr)
|
||||
t.to_ext_target(zero)
|
||||
}
|
||||
|
||||
pub fn convert_to_ext_algebra(&mut self, et: ExtensionTarget<D>) -> ExtensionAlgebraTarget<D> {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::iop::ext_target::ExtensionTarget;
|
||||
use crate::iop::wire::Wire;
|
||||
use crate::plonk::circuit_data::CircuitConfig;
|
||||
|
||||
@ -37,6 +38,13 @@ impl Target {
|
||||
Target::VirtualTarget { index } => degree * num_wires + index,
|
||||
}
|
||||
}
|
||||
|
||||
/// Conversion to an `ExtensionTarget`.
|
||||
pub fn to_ext_target<const D: usize>(self, zero: Self) -> ExtensionTarget<D> {
|
||||
let mut arr = [zero; D];
|
||||
arr[0] = self;
|
||||
ExtensionTarget(arr)
|
||||
}
|
||||
}
|
||||
|
||||
/// A `Target` which has already been constrained such that it can only be 0 or 1.
|
||||
|
||||
@ -4,6 +4,7 @@ use plonky2_field::packed_field::PackedField;
|
||||
|
||||
use crate::fri::oracle::SALT_SIZE;
|
||||
use crate::fri::structure::FriOracleInfo;
|
||||
use crate::gates::arithmetic_base::ArithmeticGate;
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::iop::ext_target::ExtensionTarget;
|
||||
use crate::iop::target::Target;
|
||||
@ -138,6 +139,23 @@ where
|
||||
sum
|
||||
}
|
||||
|
||||
pub fn reduce_with_powers_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
terms: &[Target],
|
||||
alpha: Target,
|
||||
) -> Target {
|
||||
if terms.len() <= ArithmeticGate::new_from_config(&builder.config).num_ops + 1 {
|
||||
terms
|
||||
.iter()
|
||||
.rev()
|
||||
.fold(builder.zero(), |acc, &t| builder.mul_add(alpha, acc, t))
|
||||
} else {
|
||||
let alpha = builder.convert_to_ext(alpha);
|
||||
let mut alpha = ReducingFactorTarget::new(alpha);
|
||||
alpha.reduce_base(terms, builder).0[0]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reduce_with_powers_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
builder: &mut CircuitBuilder<F, D>,
|
||||
terms: &[ExtensionTarget<D>],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user