use ethereum_types::{Address, H256, U256}; use itertools::Itertools; use maybe_rayon::*; use plonky2::field::extension::{Extendable, FieldExtension}; use plonky2::fri::oracle::PolynomialBatch; use plonky2::fri::proof::{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 serde::{Deserialize, Serialize}; use crate::all_stark::NUM_TABLES; use crate::config::StarkConfig; use crate::permutation::GrandProductChallengeSet; #[derive(Debug, Clone)] pub struct AllProof, C: GenericConfig, const D: usize> { pub stark_proofs: [StarkProof; NUM_TABLES], pub public_values: PublicValues, } impl, C: GenericConfig, const D: usize> AllProof { pub fn degree_bits(&self, config: &StarkConfig) -> [usize; NUM_TABLES] { std::array::from_fn(|i| self.stark_proofs[i].recover_degree_bits(config)) } pub fn nums_ctl_zs(&self) -> [usize; NUM_TABLES] { std::array::from_fn(|i| self.stark_proofs[i].openings.ctl_zs_last.len()) } } pub(crate) struct AllProofChallenges, const D: usize> { pub stark_challenges: [StarkProofChallenges; NUM_TABLES], pub ctl_challenges: GrandProductChallengeSet, } pub struct AllProofTarget { pub stark_proofs: [StarkProofTarget; NUM_TABLES], pub public_values: PublicValuesTarget, } /// Memory values which are public. #[derive(Debug, Clone, Default)] pub struct PublicValues { pub trie_roots_before: TrieRoots, pub trie_roots_after: TrieRoots, pub block_metadata: BlockMetadata, } #[derive(Debug, Clone, Default)] pub struct TrieRoots { pub state_root: H256, pub transactions_root: H256, pub receipts_root: H256, } #[derive(Debug, Clone, Default, Deserialize, Serialize)] pub struct BlockMetadata { pub block_beneficiary: Address, pub block_timestamp: U256, pub block_number: U256, pub block_difficulty: U256, pub block_gaslimit: U256, pub block_chain_id: U256, pub block_base_fee: U256, } /// Memory values which are public. /// Note: All the larger integers are encoded with 32-bit limbs in little-endian order. pub struct PublicValuesTarget { pub trie_roots_before: TrieRootsTarget, pub trie_roots_after: TrieRootsTarget, pub block_metadata: BlockMetadataTarget, } pub struct TrieRootsTarget { pub state_root: [Target; 8], pub transactions_root: [Target; 8], pub receipts_root: [Target; 8], } pub struct BlockMetadataTarget { pub block_beneficiary: [Target; 5], pub block_timestamp: Target, pub block_number: Target, pub block_difficulty: Target, pub block_gaslimit: Target, pub block_chain_id: Target, pub block_base_fee: Target, } pub(crate) struct AllProofChallengesTarget { pub stark_challenges: [StarkProofChallengesTarget; NUM_TABLES], pub ctl_challenges: GrandProductChallengeSet, } #[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_ctl_zs_cap: MerkleCap, /// 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_ctl_zs_cap: MerkleCapTarget, 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 } } 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> { /// Openings of trace polynomials at `zeta`. pub local_values: Vec, /// Openings of trace polynomials at `g * zeta`. pub next_values: Vec, /// Openings of permutations and cross-table lookups `Z` polynomials at `zeta`. pub permutation_ctl_zs: Vec, /// Openings of permutations and cross-table lookups `Z` polynomials at `g * zeta`. pub permutation_ctl_zs_next: Vec, /// Openings of cross-table lookups `Z` polynomials at `g^-1`. pub ctl_zs_last: Vec, /// Openings of quotient polynomials at `zeta`. pub quotient_polys: Vec, } impl, const D: usize> StarkOpeningSet { pub fn new>( zeta: F::Extension, g: F, trace_commitment: &PolynomialBatch, permutation_ctl_zs_commitment: &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_next = zeta.scalar_mul(g); Self { local_values: eval_commitment(zeta, trace_commitment), next_values: eval_commitment(zeta_next, trace_commitment), permutation_ctl_zs: eval_commitment(zeta, permutation_ctl_zs_commitment), permutation_ctl_zs_next: eval_commitment(zeta_next, permutation_ctl_zs_commitment), ctl_zs_last: eval_commitment_base( F::primitive_root_of_unity(degree_bits).inverse(), permutation_ctl_zs_commitment, )[num_permutation_zs..] .to_vec(), 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_ctl_zs) .chain(&self.quotient_polys) .copied() .collect_vec(), }; let zeta_next_batch = FriOpeningBatch { values: self .next_values .iter() .chain(&self.permutation_ctl_zs_next) .copied() .collect_vec(), }; 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(), }; FriOpenings { batches: vec![zeta_batch, zeta_next_batch, ctl_last_batch], } } } pub struct StarkOpeningSetTarget { pub local_values: Vec>, pub next_values: Vec>, pub permutation_ctl_zs: Vec>, pub permutation_ctl_zs_next: Vec>, pub ctl_zs_last: Vec, pub quotient_polys: Vec>, } impl StarkOpeningSetTarget { pub(crate) fn to_fri_openings(&self, zero: Target) -> FriOpeningsTarget { let zeta_batch = FriOpeningBatchTarget { values: self .local_values .iter() .chain(&self.permutation_ctl_zs) .chain(&self.quotient_polys) .copied() .collect_vec(), }; let zeta_next_batch = FriOpeningBatchTarget { values: self .next_values .iter() .chain(&self.permutation_ctl_zs_next) .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_next_batch, ctl_last_batch], } } }