use itertools::Itertools; use plonky2::field::extension_field::{Extendable, FieldExtension}; use plonky2::fri::oracle::PolynomialBatch; use plonky2::fri::proof::{ CompressedFriProof, FriChallenges, FriChallengesTarget, FriProof, FriProofTarget, }; use plonky2::fri::structure::{ FriOpeningBatch, FriOpeningBatchTarget, FriOpenings, FriOpeningsTarget, }; use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; use plonky2::plonk::config::GenericConfig; use rayon::prelude::*; use crate::config::StarkConfig; use crate::permutation::PermutationChallengeSet; #[derive(Debug, Clone)] pub struct AllProof, C: GenericConfig, const D: usize> { pub cpu_proof: StarkProofWithPublicInputs, pub keccak_proof: StarkProofWithPublicInputs, } impl, C: GenericConfig, const D: usize> AllProof { pub fn proofs(&self) -> [&StarkProofWithPublicInputs; 2] { [&self.cpu_proof, &self.keccak_proof] } } pub(crate) struct AllProofChallenges, const D: usize> { pub cpu_challenges: StarkProofChallenges, pub keccak_challenges: StarkProofChallenges, pub ctl_challenges: PermutationChallengeSet, } #[derive(Debug, Clone)] pub struct StarkProof, C: GenericConfig, const D: usize> { /// Merkle cap of LDEs of trace values. pub trace_cap: MerkleCap, /// Merkle cap of LDEs of permutation Z values. pub permutation_zs_cap: Option>, /// Merkle cap of LDEs of trace values. pub quotient_polys_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: StarkOpeningSet, /// A batch FRI argument for all openings. pub opening_proof: FriProof, } impl, C: GenericConfig, const D: usize> StarkProof { /// Recover the length of the trace from a STARK proof and a STARK config. pub fn recover_degree_bits(&self, config: &StarkConfig) -> usize { let initial_merkle_proof = &self.opening_proof.query_round_proofs[0] .initial_trees_proof .evals_proofs[0] .1; let lde_bits = config.fri_config.cap_height + initial_merkle_proof.siblings.len(); lde_bits - config.fri_config.rate_bits } } pub struct StarkProofTarget { pub trace_cap: MerkleCapTarget, pub permutation_zs_cap: Option, pub quotient_polys_cap: MerkleCapTarget, pub openings: StarkOpeningSetTarget, pub opening_proof: FriProofTarget, } impl StarkProofTarget { /// Recover the length of the trace from a STARK proof and a STARK config. pub fn recover_degree_bits(&self, config: &StarkConfig) -> usize { let initial_merkle_proof = &self.opening_proof.query_round_proofs[0] .initial_trees_proof .evals_proofs[0] .1; let lde_bits = config.fri_config.cap_height + initial_merkle_proof.siblings.len(); lde_bits - config.fri_config.rate_bits } } #[derive(Debug, Clone)] pub struct StarkProofWithPublicInputs< F: RichField + Extendable, C: GenericConfig, const D: usize, > { pub proof: StarkProof, // TODO: Maybe make it generic over a `S: Stark` and replace with `[F; S::PUBLIC_INPUTS]`. pub public_inputs: Vec, } pub struct StarkProofWithPublicInputsTarget { pub proof: StarkProofTarget, pub public_inputs: Vec, } pub struct CompressedStarkProof< F: RichField + Extendable, C: GenericConfig, const D: usize, > { /// Merkle cap of LDEs of trace values. pub trace_cap: MerkleCap, /// Purported values of each polynomial at the challenge point. pub openings: StarkOpeningSet, /// A batch FRI argument for all openings. pub opening_proof: CompressedFriProof, } pub struct CompressedStarkProofWithPublicInputs< F: RichField + Extendable, C: GenericConfig, const D: usize, > { pub proof: CompressedStarkProof, pub public_inputs: Vec, } pub(crate) struct StarkProofChallenges, const D: usize> { /// Randomness used in any permutation arguments. pub permutation_challenge_sets: Option>>, /// Random values used to combine STARK constraints. pub stark_alphas: Vec, /// Point at which the STARK polynomials are opened. pub stark_zeta: F::Extension, pub fri_challenges: FriChallenges, } pub(crate) struct StarkProofChallengesTarget { pub permutation_challenge_sets: Option>>, pub stark_alphas: Vec, pub stark_zeta: ExtensionTarget, pub fri_challenges: FriChallengesTarget, } /// Purported values of each polynomial at the challenge point. #[derive(Debug, Clone)] pub struct StarkOpeningSet, const D: usize> { pub local_values: Vec, pub next_values: Vec, pub permutation_lookup_zs: Option>, pub permutation_lookup_zs_right: Option>, pub lookup_zs_last: Vec, pub quotient_polys: Vec, } impl, const D: usize> StarkOpeningSet { pub fn new>( zeta: F::Extension, g: F, trace_commitment: &PolynomialBatch, permutation_lookup_zs_commitment: Option<&PolynomialBatch>, quotient_commitment: &PolynomialBatch, degree_bits: usize, num_permutation_zs: usize, ) -> Self { let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.to_extension().eval(z)) .collect::>() }; let eval_commitment_base = |z: F, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.eval(z)) .collect::>() }; let zeta_right = zeta.scalar_mul(g); Self { local_values: eval_commitment(zeta, trace_commitment), next_values: eval_commitment(zeta_right, trace_commitment), permutation_lookup_zs: permutation_lookup_zs_commitment .map(|c| eval_commitment(zeta, c)), permutation_lookup_zs_right: permutation_lookup_zs_commitment .map(|c| eval_commitment(zeta_right, c)), lookup_zs_last: permutation_lookup_zs_commitment .map(|c| { eval_commitment_base(F::primitive_root_of_unity(degree_bits).inverse(), c) [num_permutation_zs..] .to_vec() }) .unwrap_or_default(), quotient_polys: eval_commitment(zeta, quotient_commitment), } } pub(crate) fn to_fri_openings(&self) -> FriOpenings { let zeta_batch = FriOpeningBatch { values: self .local_values .iter() .chain(self.permutation_lookup_zs.iter().flatten()) .chain(&self.quotient_polys) .copied() .collect_vec(), }; let zeta_right_batch = FriOpeningBatch { values: self .next_values .iter() .chain(self.permutation_lookup_zs_right.iter().flatten()) .copied() .collect_vec(), }; let mut batches = vec![zeta_batch, zeta_right_batch]; if !self.lookup_zs_last.is_empty() { batches.push(FriOpeningBatch { values: self .lookup_zs_last .iter() .copied() .map(F::Extension::from_basefield) .collect(), }); } FriOpenings { batches } } } pub struct StarkOpeningSetTarget { pub local_values: Vec>, pub next_values: Vec>, pub permutation_zs: Option>>, pub permutation_zs_right: Option>>, pub quotient_polys: Vec>, } impl StarkOpeningSetTarget { pub(crate) fn to_fri_openings(&self) -> FriOpeningsTarget { let zeta_batch = FriOpeningBatchTarget { values: self .local_values .iter() .chain(self.permutation_zs.iter().flatten()) .chain(&self.quotient_polys) .copied() .collect_vec(), }; let zeta_right_batch = FriOpeningBatchTarget { values: self .next_values .iter() .chain(self.permutation_zs_right.iter().flatten()) .copied() .collect_vec(), }; FriOpeningsTarget { batches: vec![zeta_batch, zeta_right_batch], } } }