Assume every STARK in AllStark is part of a CTL

This commit is contained in:
wborgeaud 2022-05-17 09:41:06 +02:00
parent db2aae515f
commit 2ffd22acf5
6 changed files with 85 additions and 158 deletions

View File

@ -173,29 +173,19 @@ impl<'a, F: RichField + Extendable<D>, const D: usize>
let mut ctl_zs = proofs let mut ctl_zs = proofs
.iter() .iter()
.zip(num_permutation_zs) .zip(num_permutation_zs)
.map(|(p, &num_permutation)| -> Box<dyn Iterator<Item = _>> { .map(|(p, &num_permutation)| {
if p.proof.openings.permutation_ctl_zs.is_some() { p.proof
Box::new( .openings
.permutation_ctl_zs
.iter()
.skip(num_permutation)
.zip(
p.proof p.proof
.openings .openings
.permutation_ctl_zs .permutation_ctl_zs_right
.as_ref()
.unwrap()
.iter() .iter()
.skip(num_permutation) .skip(num_permutation),
.zip(
p.proof
.openings
.permutation_ctl_zs_right
.as_ref()
.unwrap()
.iter()
.skip(num_permutation),
),
) )
} else {
Box::new(std::iter::empty())
}
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View File

@ -21,7 +21,7 @@ use crate::stark::Stark;
fn get_challenges<F, C, S, const D: usize>( fn get_challenges<F, C, S, const D: usize>(
challenger: &mut Challenger<F, C::Hasher>, challenger: &mut Challenger<F, C::Hasher>,
stark: &S, stark: &S,
permutation_ctl_zs_cap: Option<&MerkleCap<F, C::Hasher>>, permutation_ctl_zs_cap: &MerkleCap<F, C::Hasher>,
quotient_polys_cap: &MerkleCap<F, C::Hasher>, quotient_polys_cap: &MerkleCap<F, C::Hasher>,
openings: &StarkOpeningSet<F, D>, openings: &StarkOpeningSet<F, D>,
commit_phase_merkle_caps: &[MerkleCap<F, C::Hasher>], commit_phase_merkle_caps: &[MerkleCap<F, C::Hasher>],
@ -45,9 +45,7 @@ where
) )
}); });
if let Some(cap) = permutation_ctl_zs_cap { challenger.observe_cap(permutation_ctl_zs_cap);
challenger.observe_cap(cap);
}
let stark_alphas = challenger.get_n_challenges(num_challenges); let stark_alphas = challenger.get_n_challenges(num_challenges);
@ -146,7 +144,7 @@ where
get_challenges::<F, C, S, D>( get_challenges::<F, C, S, D>(
challenger, challenger,
stark, stark,
permutation_ctl_zs_cap.as_ref(), permutation_ctl_zs_cap,
quotient_polys_cap, quotient_polys_cap,
openings, openings,
commit_phase_merkle_caps, commit_phase_merkle_caps,

View File

@ -40,7 +40,7 @@ pub struct StarkProof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>,
/// Merkle cap of LDEs of trace values. /// Merkle cap of LDEs of trace values.
pub trace_cap: MerkleCap<F, C::Hasher>, pub trace_cap: MerkleCap<F, C::Hasher>,
/// Merkle cap of LDEs of permutation Z values. /// Merkle cap of LDEs of permutation Z values.
pub permutation_ctl_zs_cap: Option<MerkleCap<F, C::Hasher>>, pub permutation_ctl_zs_cap: MerkleCap<F, C::Hasher>,
/// Merkle cap of LDEs of trace values. /// Merkle cap of LDEs of trace values.
pub quotient_polys_cap: MerkleCap<F, C::Hasher>, pub quotient_polys_cap: MerkleCap<F, C::Hasher>,
/// Purported values of each polynomial at the challenge point. /// Purported values of each polynomial at the challenge point.
@ -147,9 +147,9 @@ pub struct StarkOpeningSet<F: RichField + Extendable<D>, const D: usize> {
/// Openings of trace polynomials at `g * zeta`. /// Openings of trace polynomials at `g * zeta`.
pub next_values: Vec<F::Extension>, pub next_values: Vec<F::Extension>,
/// Openings of permutations and cross-table lookups `Z` polynomials at `zeta`. /// Openings of permutations and cross-table lookups `Z` polynomials at `zeta`.
pub permutation_ctl_zs: Option<Vec<F::Extension>>, pub permutation_ctl_zs: Vec<F::Extension>,
/// Openings of permutations and cross-table lookups `Z` polynomials at `g * zeta`. /// Openings of permutations and cross-table lookups `Z` polynomials at `g * zeta`.
pub permutation_ctl_zs_right: Option<Vec<F::Extension>>, pub permutation_ctl_zs_right: Vec<F::Extension>,
/// Openings of cross-table lookups `Z` polynomials at `g^-1`. /// Openings of cross-table lookups `Z` polynomials at `g^-1`.
pub ctl_zs_last: Vec<F>, pub ctl_zs_last: Vec<F>,
/// Openings of quotient polynomials at `zeta`. /// Openings of quotient polynomials at `zeta`.
@ -161,7 +161,7 @@ impl<F: RichField + Extendable<D>, const D: usize> StarkOpeningSet<F, D> {
zeta: F::Extension, zeta: F::Extension,
g: F, g: F,
trace_commitment: &PolynomialBatch<F, C, D>, trace_commitment: &PolynomialBatch<F, C, D>,
permutation_ctl_zs_commitment: Option<&PolynomialBatch<F, C, D>>, permutation_ctl_zs_commitment: &PolynomialBatch<F, C, D>,
quotient_commitment: &PolynomialBatch<F, C, D>, quotient_commitment: &PolynomialBatch<F, C, D>,
degree_bits: usize, degree_bits: usize,
num_permutation_zs: usize, num_permutation_zs: usize,
@ -182,16 +182,13 @@ impl<F: RichField + Extendable<D>, const D: usize> StarkOpeningSet<F, D> {
Self { Self {
local_values: eval_commitment(zeta, trace_commitment), local_values: eval_commitment(zeta, trace_commitment),
next_values: eval_commitment(zeta_right, trace_commitment), next_values: eval_commitment(zeta_right, trace_commitment),
permutation_ctl_zs: permutation_ctl_zs_commitment.map(|c| eval_commitment(zeta, c)), permutation_ctl_zs: eval_commitment(zeta, permutation_ctl_zs_commitment),
permutation_ctl_zs_right: permutation_ctl_zs_commitment permutation_ctl_zs_right: eval_commitment(zeta_right, permutation_ctl_zs_commitment),
.map(|c| eval_commitment(zeta_right, c)), ctl_zs_last: eval_commitment_base(
ctl_zs_last: permutation_ctl_zs_commitment F::primitive_root_of_unity(degree_bits).inverse(),
.map(|c| { permutation_ctl_zs_commitment,
eval_commitment_base(F::primitive_root_of_unity(degree_bits).inverse(), c) )[num_permutation_zs..]
[num_permutation_zs..] .to_vec(),
.to_vec()
})
.unwrap_or_default(),
quotient_polys: eval_commitment(zeta, quotient_commitment), quotient_polys: eval_commitment(zeta, quotient_commitment),
} }
} }
@ -201,7 +198,7 @@ impl<F: RichField + Extendable<D>, const D: usize> StarkOpeningSet<F, D> {
values: self values: self
.local_values .local_values
.iter() .iter()
.chain(self.permutation_ctl_zs.iter().flatten()) .chain(&self.permutation_ctl_zs)
.chain(&self.quotient_polys) .chain(&self.quotient_polys)
.copied() .copied()
.collect_vec(), .collect_vec(),
@ -210,7 +207,7 @@ impl<F: RichField + Extendable<D>, const D: usize> StarkOpeningSet<F, D> {
values: self values: self
.next_values .next_values
.iter() .iter()
.chain(self.permutation_ctl_zs_right.iter().flatten()) .chain(&self.permutation_ctl_zs_right)
.copied() .copied()
.collect_vec(), .collect_vec(),
}; };

View File

@ -1,7 +1,4 @@
use std::iter::once;
use anyhow::{ensure, Result}; use anyhow::{ensure, Result};
use itertools::Itertools;
use plonky2::field::extension_field::Extendable; use plonky2::field::extension_field::Extendable;
use plonky2::field::field_types::Field; use plonky2::field::field_types::Field;
use plonky2::field::packable::Packable; use plonky2::field::packable::Packable;
@ -175,30 +172,26 @@ where
permutation_zs permutation_zs
} }
}; };
assert!(!z_polys.is_empty(), "No CTL?");
let permutation_ctl_zs_commitment = (!z_polys.is_empty()).then(|| { let permutation_ctl_zs_commitment = PolynomialBatch::from_values(
PolynomialBatch::from_values( z_polys,
z_polys, rate_bits,
rate_bits, false,
false, config.fri_config.cap_height,
config.fri_config.cap_height, timing,
timing, None,
None, );
)
}); let permutation_ctl_zs_cap = permutation_ctl_zs_commitment.merkle_tree.cap.clone();
let permutation_ctl_zs_cap = permutation_ctl_zs_commitment challenger.observe_cap(&permutation_ctl_zs_cap);
.as_ref()
.map(|commit| commit.merkle_tree.cap.clone());
if let Some(cap) = &permutation_ctl_zs_cap {
challenger.observe_cap(cap);
}
let alphas = challenger.get_n_challenges(config.num_challenges); let alphas = challenger.get_n_challenges(config.num_challenges);
if cfg!(test) { if cfg!(test) {
check_constraints( check_constraints(
stark, stark,
trace_commitment, trace_commitment,
permutation_ctl_zs_commitment.as_ref(), &permutation_ctl_zs_commitment,
permutation_challenges.as_ref(), permutation_challenges.as_ref(),
ctl_data, ctl_data,
public_inputs, public_inputs,
@ -211,7 +204,7 @@ where
let quotient_polys = compute_quotient_polys::<F, <F as Packable>::Packing, C, S, D>( let quotient_polys = compute_quotient_polys::<F, <F as Packable>::Packing, C, S, D>(
stark, stark,
trace_commitment, trace_commitment,
permutation_ctl_zs_commitment.as_ref(), &permutation_ctl_zs_commitment,
permutation_challenges.as_ref(), permutation_challenges.as_ref(),
ctl_data, ctl_data,
public_inputs, public_inputs,
@ -259,17 +252,18 @@ where
zeta, zeta,
g, g,
trace_commitment, trace_commitment,
permutation_ctl_zs_commitment.as_ref(), &permutation_ctl_zs_commitment,
&quotient_commitment, &quotient_commitment,
degree_bits, degree_bits,
stark.num_permutation_batches(config), stark.num_permutation_batches(config),
); );
challenger.observe_openings(&openings.to_fri_openings()); challenger.observe_openings(&openings.to_fri_openings());
let initial_merkle_trees = once(trace_commitment) let initial_merkle_trees = vec![
.chain(&permutation_ctl_zs_commitment) trace_commitment,
.chain(once(&quotient_commitment)) &permutation_ctl_zs_commitment,
.collect_vec(); &quotient_commitment,
];
let opening_proof = timed!( let opening_proof = timed!(
timing, timing,
@ -301,7 +295,7 @@ where
fn compute_quotient_polys<'a, F, P, C, S, const D: usize>( fn compute_quotient_polys<'a, F, P, C, S, const D: usize>(
stark: &S, stark: &S,
trace_commitment: &'a PolynomialBatch<F, C, D>, trace_commitment: &'a PolynomialBatch<F, C, D>,
permutation_ctl_zs_commitment: Option<&'a PolynomialBatch<F, C, D>>, permutation_ctl_zs_commitment: &'a PolynomialBatch<F, C, D>,
permutation_challenges: Option<&'a Vec<GrandProductChallengeSet<F>>>, permutation_challenges: Option<&'a Vec<GrandProductChallengeSet<F>>>,
ctl_data: &CtlData<F>, ctl_data: &CtlData<F>,
public_inputs: [F; S::PUBLIC_INPUTS], public_inputs: [F; S::PUBLIC_INPUTS],
@ -381,33 +375,25 @@ where
next_values: &get_trace_values_packed(i_next_start), next_values: &get_trace_values_packed(i_next_start),
public_inputs: &public_inputs, public_inputs: &public_inputs,
}; };
let permutation_check_data = let permutation_check_vars =
if let (Some(permutation_zs_commitment), Some(permutation_challenge_sets)) = permutation_challenges.map(|permutation_challenge_sets| PermutationCheckVars {
(permutation_ctl_zs_commitment, permutation_challenges) local_zs: permutation_ctl_zs_commitment.get_lde_values_packed(i_start, step)
{ [..num_permutation_zs]
Some(PermutationCheckVars { .to_vec(),
local_zs: permutation_zs_commitment.get_lde_values_packed(i_start, step) next_zs: permutation_ctl_zs_commitment
[..num_permutation_zs] .get_lde_values_packed(i_next_start, step)[..num_permutation_zs]
.to_vec(), .to_vec(),
next_zs: permutation_zs_commitment permutation_challenge_sets: permutation_challenge_sets.to_vec(),
.get_lde_values_packed(i_next_start, step)[..num_permutation_zs] });
.to_vec(),
permutation_challenge_sets: permutation_challenge_sets.to_vec(),
})
} else {
None
};
let ctl_vars = ctl_data let ctl_vars = ctl_data
.zs_columns .zs_columns
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, (_, columns))| CtlCheckVars::<F, F, P, 1> { .map(|(i, (_, columns))| CtlCheckVars::<F, F, P, 1> {
local_z: permutation_ctl_zs_commitment local_z: permutation_ctl_zs_commitment.get_lde_values_packed(i_start, step)
.unwrap() [num_permutation_zs + i],
.get_lde_values_packed(i_start, step)[num_permutation_zs + i], next_z: permutation_ctl_zs_commitment.get_lde_values_packed(i_next_start, step)
next_z: permutation_ctl_zs_commitment [num_permutation_zs + i],
.unwrap()
.get_lde_values_packed(i_next_start, step)[num_permutation_zs + i],
challenges: ctl_data.challenges.challenges[i % config.num_challenges], challenges: ctl_data.challenges.challenges[i % config.num_challenges],
columns, columns,
}) })
@ -416,7 +402,7 @@ where
stark, stark,
config, config,
vars, vars,
permutation_check_data, permutation_check_vars,
&ctl_vars, &ctl_vars,
&mut consumer, &mut consumer,
); );
@ -442,7 +428,7 @@ where
fn check_constraints<'a, F, C, S, const D: usize>( fn check_constraints<'a, F, C, S, const D: usize>(
stark: &S, stark: &S,
trace_commitment: &'a PolynomialBatch<F, C, D>, trace_commitment: &'a PolynomialBatch<F, C, D>,
permutation_ctl_zs_commitment: Option<&'a PolynomialBatch<F, C, D>>, permutation_ctl_zs_commitment: &'a PolynomialBatch<F, C, D>,
permutation_challenges: Option<&'a Vec<GrandProductChallengeSet<F>>>, permutation_challenges: Option<&'a Vec<GrandProductChallengeSet<F>>>,
ctl_data: &CtlData<F>, ctl_data: &CtlData<F>,
public_inputs: [F; S::PUBLIC_INPUTS], public_inputs: [F; S::PUBLIC_INPUTS],
@ -503,30 +489,25 @@ fn check_constraints<'a, F, C, S, const D: usize>(
.unwrap(), .unwrap(),
public_inputs: &public_inputs, public_inputs: &public_inputs,
}; };
let permutation_check_data = let permutation_check_vars =
if let (Some(permutation_zs_commitment), Some(permutation_challenge_sets)) = permutation_challenges.map(|permutation_challenge_sets| PermutationCheckVars {
(permutation_ctl_zs_commitment, permutation_challenges) local_zs: permutation_ctl_zs_commitment.get_lde_values_packed(i, step)
{ [..num_permutation_zs]
Some(PermutationCheckVars { .to_vec(),
local_zs: get_comm_values(permutation_zs_commitment, i) next_zs: permutation_ctl_zs_commitment.get_lde_values_packed(i_next, step)
[..num_permutation_zs] [..num_permutation_zs]
.to_vec(), .to_vec(),
next_zs: get_comm_values(permutation_zs_commitment, i_next) permutation_challenge_sets: permutation_challenge_sets.to_vec(),
[..num_permutation_zs] });
.to_vec(),
permutation_challenge_sets: permutation_challenge_sets.to_vec(),
})
} else {
None
};
let ctl_vars = ctl_data let ctl_vars = ctl_data
.zs_columns .zs_columns
.iter() .iter()
.enumerate() .enumerate()
.map(|(iii, (_, columns))| CtlCheckVars::<F, F, F, 1> { .map(|(iii, (_, columns))| CtlCheckVars::<F, F, F, 1> {
local_z: get_comm_values(permutation_ctl_zs_commitment.unwrap(), i) local_z: get_comm_values(permutation_ctl_zs_commitment, i)
[num_permutation_zs + iii], [num_permutation_zs + iii],
next_z: get_comm_values(permutation_ctl_zs_commitment.unwrap(), i_next) next_z: get_comm_values(permutation_ctl_zs_commitment, i_next)
[num_permutation_zs + iii], [num_permutation_zs + iii],
challenges: ctl_data.challenges.challenges[iii % config.num_challenges], challenges: ctl_data.challenges.challenges[iii % config.num_challenges],
columns, columns,
@ -536,7 +517,7 @@ fn check_constraints<'a, F, C, S, const D: usize>(
stark, stark,
config, config,
vars, vars,
permutation_check_data, permutation_check_vars,
&ctl_vars, &ctl_vars,
&mut consumer, &mut consumer,
); );

View File

@ -301,11 +301,8 @@ pub fn set_stark_proof_target<F, C: GenericConfig<D, F = F>, W, const D: usize>(
&proof.openings.to_fri_openings(), &proof.openings.to_fri_openings(),
); );
if let (Some(permutation_zs_cap_target), Some(permutation_zs_cap)) = ( if let Some(permutation_zs_cap_target) = &proof_target.permutation_zs_cap {
&proof_target.permutation_zs_cap, witness.set_cap_target(permutation_zs_cap_target, &proof.permutation_ctl_zs_cap);
&proof.permutation_ctl_zs_cap,
) {
witness.set_cap_target(permutation_zs_cap_target, permutation_zs_cap);
} }
set_fri_proof_target(witness, &proof_target.opening_proof, &proof.opening_proof); set_fri_proof_target(witness, &proof_target.opening_proof, &proof.opening_proof);

View File

@ -1,7 +1,4 @@
use std::iter::once;
use anyhow::{ensure, Result}; use anyhow::{ensure, Result};
use itertools::Itertools;
use plonky2::field::extension_field::{Extendable, FieldExtension}; use plonky2::field::extension_field::{Extendable, FieldExtension};
use plonky2::field::field_types::Field; use plonky2::field::field_types::Field;
use plonky2::fri::verifier::verify_fri_proof; use plonky2::fri::verifier::verify_fri_proof;
@ -93,8 +90,6 @@ where
[(); S::PUBLIC_INPUTS]:, [(); S::PUBLIC_INPUTS]:,
[(); C::Hasher::HASH_SIZE]:, [(); C::Hasher::HASH_SIZE]:,
{ {
// TODO: Fix this to take CTLs into account
// check_permutation_options(&stark, proof_with_pis, &challenges)?;
let StarkProofWithPublicInputs { let StarkProofWithPublicInputs {
proof, proof,
public_inputs, public_inputs,
@ -135,8 +130,8 @@ where
); );
let num_permutation_zs = stark.num_permutation_batches(config); let num_permutation_zs = stark.num_permutation_batches(config);
let permutation_data = stark.uses_permutation_args().then(|| PermutationCheckVars { let permutation_data = stark.uses_permutation_args().then(|| PermutationCheckVars {
local_zs: permutation_ctl_zs.as_ref().unwrap()[..num_permutation_zs].to_vec(), local_zs: permutation_ctl_zs[..num_permutation_zs].to_vec(),
next_zs: permutation_ctl_zs_right.as_ref().unwrap()[..num_permutation_zs].to_vec(), next_zs: permutation_ctl_zs_right[..num_permutation_zs].to_vec(),
permutation_challenge_sets: challenges.permutation_challenge_sets.unwrap(), permutation_challenge_sets: challenges.permutation_challenge_sets.unwrap(),
}); });
eval_vanishing_poly::<F, F::Extension, F::Extension, C, S, D, D>( eval_vanishing_poly::<F, F::Extension, F::Extension, C, S, D, D>(
@ -167,10 +162,11 @@ where
); );
} }
let merkle_caps = once(proof.trace_cap.clone()) let merkle_caps = vec![
.chain(proof.permutation_ctl_zs_cap.clone()) proof.trace_cap.clone(),
.chain(once(proof.quotient_polys_cap.clone())) proof.permutation_ctl_zs_cap.clone(),
.collect_vec(); proof.quotient_polys_cap.clone(),
];
verify_fri_proof::<F, C, D>( verify_fri_proof::<F, C, D>(
&stark.fri_instance( &stark.fri_instance(
@ -202,38 +198,6 @@ fn eval_l_1_and_l_last<F: Field>(log_n: usize, x: F) -> (F, F) {
(z_x * invs[0], z_x * invs[1]) (z_x * invs[0], z_x * invs[1])
} }
/// Utility function to check that all permutation data wrapped in `Option`s are `Some` iff
/// the Stark uses a permutation argument.
#[allow(dead_code)]
fn check_permutation_options<
F: RichField + Extendable<D>,
C: GenericConfig<D, F = F>,
S: Stark<F, D>,
const D: usize,
>(
stark: &S,
proof_with_pis: &StarkProofWithPublicInputs<F, C, D>,
challenges: &StarkProofChallenges<F, D>,
) -> Result<()> {
let options_is_some = [
proof_with_pis.proof.permutation_ctl_zs_cap.is_some(),
proof_with_pis.proof.openings.permutation_ctl_zs.is_some(),
proof_with_pis
.proof
.openings
.permutation_ctl_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(())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use plonky2::field::field_types::Field; use plonky2::field::field_types::Field;