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 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_zs: Option>, pub permutation_zs_right: Option>, pub quotient_polys: Vec, } impl, const D: usize> StarkOpeningSet { pub fn new>( zeta: F::Extension, g: F, trace_commitment: &PolynomialBatch, permutation_zs_commitment: Option<&PolynomialBatch>, quotient_commitment: &PolynomialBatch, ) -> Self { let eval_commitment = |z: F::Extension, c: &PolynomialBatch| { c.polynomials .par_iter() .map(|p| p.to_extension().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_zs: permutation_zs_commitment.map(|c| eval_commitment(zeta, c)), permutation_zs_right: permutation_zs_commitment.map(|c| eval_commitment(zeta_right, c)), 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_zs.iter().flatten()) .chain(&self.quotient_polys) .copied() .collect_vec(), }; let zeta_right_batch = FriOpeningBatch { values: self .next_values .iter() .chain(self.permutation_zs_right.iter().flatten()) .copied() .collect_vec(), }; FriOpenings { batches: vec![zeta_batch, zeta_right_batch], } } } 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], } } }