diff --git a/starky2/src/all_stark.rs b/starky2/src/all_stark.rs index d00f5b8c..b4687a89 100644 --- a/starky2/src/all_stark.rs +++ b/starky2/src/all_stark.rs @@ -1,15 +1,11 @@ -use std::marker::PhantomData; - -use plonky2::field::extension_field::{Extendable, FieldExtension}; -use plonky2::field::packed_field::PackedField; +use plonky2::field::extension_field::Extendable; use plonky2::hash::hash_types::RichField; use crate::config::StarkConfig; -use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use crate::cpu::cpu_stark::CpuStark; use crate::cross_table_lookup::CrossTableLookup; -use crate::permutation::PermutationPair; +use crate::keccak::keccak_stark::KeccakStark; use crate::stark::Stark; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; #[derive(Clone)] pub struct AllStark, const D: usize> { @@ -27,88 +23,12 @@ impl, const D: usize> AllStark { } } -#[derive(Copy, Clone)] -pub struct CpuStark { - #[allow(dead_code)] - num_rows: usize, - f: PhantomData, -} - -#[derive(Copy, Clone)] -pub struct KeccakStark { - #[allow(dead_code)] - num_rows: usize, - f: PhantomData, -} - #[derive(Copy, Clone)] pub enum Table { Cpu = 0, Keccak = 1, } -impl, const D: usize> Stark for CpuStark { - const COLUMNS: usize = 10; - const PUBLIC_INPUTS: usize = 0; - - fn eval_packed_generic( - &self, - _vars: StarkEvaluationVars, - _yield_constr: &mut ConstraintConsumer

, - ) where - FE: FieldExtension, - P: PackedField, - { - } - - fn eval_ext_recursively( - &self, - _builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder, - _vars: StarkEvaluationTargets, - _yield_constr: &mut RecursiveConstraintConsumer, - ) { - } - - fn constraint_degree(&self) -> usize { - 3 - } - - fn permutation_pairs(&self) -> Vec { - vec![PermutationPair::singletons(8, 9)] - } -} - -impl, const D: usize> Stark for KeccakStark { - const COLUMNS: usize = 7; - const PUBLIC_INPUTS: usize = 0; - - fn eval_packed_generic( - &self, - _vars: StarkEvaluationVars, - _yield_constr: &mut ConstraintConsumer

, - ) where - FE: FieldExtension, - P: PackedField, - { - } - - fn eval_ext_recursively( - &self, - _builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder, - _vars: StarkEvaluationTargets, - _yield_constr: &mut RecursiveConstraintConsumer, - ) { - } - - fn constraint_degree(&self) -> usize { - 3 - } - - fn permutation_pairs(&self) -> Vec { - vec![PermutationPair::singletons(0, 6)] - } -} - #[cfg(test)] mod tests { use anyhow::Result; @@ -118,9 +38,11 @@ mod tests { use plonky2::util::timing::TimingTree; use rand::{thread_rng, Rng}; - use crate::all_stark::{AllStark, CpuStark, KeccakStark, Table}; + use crate::all_stark::{AllStark, Table}; use crate::config::StarkConfig; + use crate::cpu::cpu_stark::CpuStark; use crate::cross_table_lookup::CrossTableLookup; + use crate::keccak::keccak_stark::KeccakStark; use crate::prover::prove; use crate::verifier::verify_proof; @@ -133,34 +55,32 @@ mod tests { let config = StarkConfig::standard_fast_config(); let cpu_stark = CpuStark:: { - num_rows: 1 << 4, f: Default::default(), }; + let cpu_rows = 1 << 4; + let keccak_stark = KeccakStark:: { - num_rows: 1 << 3, f: Default::default(), }; + let keccak_rows = 1 << 3; - // let mut cpu_trace = vec![PolynomialValues::zero(cpu_stark.num_rows); CpuStark::COLUMNS]; - let mut cpu_trace = vec![PolynomialValues::zero(cpu_stark.num_rows); 10]; - // let mut keccak_trace = - // vec![PolynomialValues::zero(keccak_stark.num_rows); KeccakStark::COLUMNS]; - let mut keccak_trace = vec![PolynomialValues::zero(keccak_stark.num_rows); 7]; + let mut cpu_trace = vec![PolynomialValues::zero(cpu_rows); 10]; + let mut keccak_trace = vec![PolynomialValues::zero(keccak_rows); 7]; - let vs0 = (0..keccak_stark.num_rows) + let vs0 = (0..keccak_rows) .map(F::from_canonical_usize) .collect::>(); - let vs1 = (1..=keccak_stark.num_rows) + let vs1 = (1..=keccak_rows) .map(F::from_canonical_usize) .collect::>(); - let start = thread_rng().gen_range(0..cpu_stark.num_rows - keccak_stark.num_rows); + let start = thread_rng().gen_range(0..cpu_rows - keccak_rows); let default = vec![F::ONE; 2]; - cpu_trace[2].values = vec![default[0]; cpu_stark.num_rows]; - cpu_trace[2].values[start..start + keccak_stark.num_rows].copy_from_slice(&vs0); - cpu_trace[4].values = vec![default[1]; cpu_stark.num_rows]; - cpu_trace[4].values[start..start + keccak_stark.num_rows].copy_from_slice(&vs1); + cpu_trace[2].values = vec![default[0]; cpu_rows]; + cpu_trace[2].values[start..start + keccak_rows].copy_from_slice(&vs0); + cpu_trace[4].values = vec![default[1]; cpu_rows]; + cpu_trace[4].values[start..start + keccak_rows].copy_from_slice(&vs1); keccak_trace[3].values[..].copy_from_slice(&vs0); keccak_trace[5].values[..].copy_from_slice(&vs1); diff --git a/starky2/src/cpu/cpu_stark.rs b/starky2/src/cpu/cpu_stark.rs new file mode 100644 index 00000000..710c9df5 --- /dev/null +++ b/starky2/src/cpu/cpu_stark.rs @@ -0,0 +1,46 @@ +use std::marker::PhantomData; + +use plonky2::field::extension_field::{Extendable, FieldExtension}; +use plonky2::field::packed_field::PackedField; +use plonky2::hash::hash_types::RichField; + +use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use crate::permutation::PermutationPair; +use crate::stark::Stark; +use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; + +#[derive(Copy, Clone)] +pub struct CpuStark { + pub f: PhantomData, +} + +impl, const D: usize> Stark for CpuStark { + const COLUMNS: usize = 10; + const PUBLIC_INPUTS: usize = 0; + + fn eval_packed_generic( + &self, + _vars: StarkEvaluationVars, + _yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + } + + fn eval_ext_circuit( + &self, + _builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder, + _vars: StarkEvaluationTargets, + _yield_constr: &mut RecursiveConstraintConsumer, + ) { + } + + fn constraint_degree(&self) -> usize { + 3 + } + + fn permutation_pairs(&self) -> Vec { + vec![PermutationPair::singletons(8, 9)] + } +} diff --git a/starky2/src/cpu/mod.rs b/starky2/src/cpu/mod.rs new file mode 100644 index 00000000..fe991a17 --- /dev/null +++ b/starky2/src/cpu/mod.rs @@ -0,0 +1 @@ +pub mod cpu_stark; diff --git a/starky2/src/cross_table_lookup.rs b/starky2/src/cross_table_lookup.rs index de58273f..2f6ac84c 100644 --- a/starky2/src/cross_table_lookup.rs +++ b/starky2/src/cross_table_lookup.rs @@ -6,8 +6,6 @@ use plonky2::field::polynomial::PolynomialValues; use plonky2::hash::hash_types::RichField; use plonky2::iop::challenger::Challenger; use plonky2::plonk::config::GenericConfig; -use plonky2::plonk::plonk_common::reduce_with_powers; -use plonky2::util::reducing::ReducingFactor; use crate::all_stark::Table; use crate::config::StarkConfig; @@ -84,64 +82,57 @@ pub fn cross_table_lookup_data, const D challenger: &mut Challenger, ) -> Vec> { let challenges = get_grand_product_challenge_set(challenger, config.num_challenges); - cross_table_lookups.iter().fold( - vec![CtlData::new(challenges.clone()); trace_poly_values.len()], - |mut acc, cross_table_lookup| { - let CrossTableLookup { - looking_table, + let mut ctl_data_per_table = vec![CtlData::new(challenges.clone()); trace_poly_values.len()]; + for CrossTableLookup { + looking_table, + looking_columns, + looked_table, + looked_columns, + default, + } in cross_table_lookups + { + for &challenge in &challenges.challenges { + let z_looking = partial_products( + &trace_poly_values[*looking_table as usize], looking_columns, - looked_table, + challenge, + ); + let z_looked = partial_products( + &trace_poly_values[*looked_table as usize], looked_columns, - default, - } = cross_table_lookup; + challenge, + ); - for &GrandProductChallenge { beta, gamma } in &challenges.challenges { - let z_looking = partial_products( - &trace_poly_values[*looking_table as usize], - looking_columns, - beta, - gamma, - ); - let z_looked = partial_products( - &trace_poly_values[*looked_table as usize], - looked_columns, - beta, - gamma, - ); + debug_assert_eq!( + *z_looking.values.last().unwrap(), + *z_looked.values.last().unwrap() + * challenge.combine(default).exp_u64( + trace_poly_values[*looking_table as usize][0].len() as u64 + - trace_poly_values[*looked_table as usize][0].len() as u64 + ) + ); - debug_assert_eq!( - *z_looking.values.last().unwrap(), - *z_looked.values.last().unwrap() - * (gamma + reduce_with_powers(default.iter(), beta)).exp_u64( - trace_poly_values[*looking_table as usize][0].len() as u64 - - trace_poly_values[*looked_table as usize][0].len() as u64 - ) - ); - - acc[*looking_table as usize] - .zs_columns - .push((z_looking, looking_columns.clone())); - acc[*looked_table as usize] - .zs_columns - .push((z_looked, looked_columns.clone())); - } - acc - }, - ) + ctl_data_per_table[*looking_table as usize] + .zs_columns + .push((z_looking, looking_columns.clone())); + ctl_data_per_table[*looked_table as usize] + .zs_columns + .push((z_looked, looked_columns.clone())); + } + } + ctl_data_per_table } fn partial_products( trace: &[PolynomialValues], columns: &[usize], - beta: F, - gamma: F, + challenge: GrandProductChallenge, ) -> PolynomialValues { let mut partial_prod = F::ONE; let degree = trace[0].len(); let mut res = Vec::with_capacity(degree); for i in 0..degree { - partial_prod *= - gamma + reduce_with_powers(columns.iter().map(|&j| &trace[j].values[i]), beta); + partial_prod *= challenge.combine(columns.iter().map(|&j| &trace[j].values[i])); res.push(partial_prod); } res.into() @@ -173,53 +164,42 @@ impl<'a, F: RichField + Extendable, const D: usize> let mut ctl_zs = proofs .iter() .zip(num_permutation_zs) - .map(|(p, &num_permutation)| { - p.proof - .openings - .permutation_ctl_zs - .iter() - .skip(num_permutation) - .zip( - p.proof - .openings - .permutation_ctl_zs_right - .iter() - .skip(num_permutation), - ) + .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::>(); - cross_table_lookups - .iter() - .fold(vec![vec![]; proofs.len()], |mut acc, ctl| { - let CrossTableLookup { - looking_table, - looking_columns, - looked_table, - looked_columns, - .. - } = ctl; + 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, + }); - for &challenges in &ctl_challenges.challenges { - let (looking_z, looking_z_next) = - ctl_zs[*looking_table as usize].next().unwrap(); - acc[*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(); - acc[*looked_table as usize].push(Self { - local_z: *looked_z, - next_z: *looked_z_next, - challenges, - columns: looked_columns, - }); - } - acc - }) + 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 } } @@ -241,10 +221,7 @@ pub(crate) fn eval_cross_table_lookup_checks P { - factor.reduce_ext(columns.iter().map(|&i| v[i])) + FE::from_basefield(challenges.gamma) - }; + let combine = |v: &[P]| -> P { challenges.combine(columns.iter().map(|&i| &v[i])) }; // Check value of `Z(1)` consumer.constraint_first_row(*local_z - combine(vars.local_values)); @@ -285,9 +262,8 @@ pub(crate) fn verify_cross_table_lookups< 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 GrandProductChallenge { beta, gamma } = - challenges.challenges[i % config.num_challenges]; - let combined_default = gamma + reduce_with_powers(default.iter(), beta); + let challenge = challenges.challenges[i % config.num_challenges]; + let combined_default = challenge.combine(default.iter()); ensure!( looking_z == looked_z * combined_default.exp_u64(looking_degree - looked_degree), diff --git a/starky2/src/get_challenges.rs b/starky2/src/get_challenges.rs index ecde68ee..64eaeb53 100644 --- a/starky2/src/get_challenges.rs +++ b/starky2/src/get_challenges.rs @@ -1,11 +1,7 @@ use plonky2::field::extension_field::Extendable; -use plonky2::field::polynomial::PolynomialCoeffs; -use plonky2::fri::proof::{FriProof, FriProofTarget}; -use plonky2::gadgets::polynomial::PolynomialCoeffsExtTarget; -use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; -use plonky2::hash::merkle_tree::MerkleCap; +use plonky2::fri::proof::FriProof; +use plonky2::hash::hash_types::RichField; use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; -use plonky2::iop::target::Target; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; @@ -18,56 +14,6 @@ use crate::permutation::{ use crate::proof::*; use crate::stark::Stark; -fn get_challenges( - challenger: &mut Challenger, - stark: &S, - permutation_ctl_zs_cap: &MerkleCap, - quotient_polys_cap: &MerkleCap, - openings: &StarkOpeningSet, - commit_phase_merkle_caps: &[MerkleCap], - final_poly: &PolynomialCoeffs, - pow_witness: F, - config: &StarkConfig, - degree_bits: usize, -) -> StarkProofChallenges -where - F: RichField + Extendable, - C: GenericConfig, - S: Stark, -{ - let num_challenges = config.num_challenges; - - let permutation_challenge_sets = stark.uses_permutation_args().then(|| { - get_n_grand_product_challenge_sets( - challenger, - num_challenges, - stark.permutation_batch_size(), - ) - }); - - challenger.observe_cap(permutation_ctl_zs_cap); - - let stark_alphas = challenger.get_n_challenges(num_challenges); - - challenger.observe_cap(quotient_polys_cap); - let stark_zeta = challenger.get_extension_challenge::(); - - challenger.observe_openings(&openings.to_fri_openings()); - - StarkProofChallenges { - permutation_challenge_sets, - stark_alphas, - stark_zeta, - fri_challenges: challenger.fri_challenges::( - commit_phase_merkle_caps, - final_poly, - pow_witness, - degree_bits, - &config.fri_config, - ), - } -} - impl, C: GenericConfig, const D: usize> AllProof { /// Computes all Fiat-Shamir challenges used in the STARK proof. pub(crate) fn get_challenges( @@ -105,19 +51,6 @@ where F: RichField + Extendable, C: GenericConfig, { - // TODO: Should be used later in compression? - #![allow(dead_code)] - pub(crate) fn fri_query_indices>( - &self, - stark: &S, - config: &StarkConfig, - ) -> Vec { - let mut challenger = Challenger::new(); - self.get_challenges(&mut challenger, stark, config) - .fri_challenges - .fri_query_indices - } - /// Computes all Fiat-Shamir challenges used in the STARK proof. pub(crate) fn get_challenges>( &self, @@ -141,77 +74,37 @@ where .. } = &self.proof; - get_challenges::( - challenger, - stark, - permutation_ctl_zs_cap, - quotient_polys_cap, - openings, - commit_phase_merkle_caps, - final_poly, - *pow_witness, - config, - degree_bits, - ) - } -} + let num_challenges = config.num_challenges; -#[allow(clippy::too_many_arguments)] -pub(crate) fn get_challenges_target< - F: RichField + Extendable, - C: GenericConfig, - S: Stark, - const D: usize, ->( - builder: &mut CircuitBuilder, - stark: &S, - trace_cap: &MerkleCapTarget, - permutation_zs_cap: Option<&MerkleCapTarget>, - quotient_polys_cap: &MerkleCapTarget, - openings: &StarkOpeningSetTarget, - commit_phase_merkle_caps: &[MerkleCapTarget], - final_poly: &PolynomialCoeffsExtTarget, - pow_witness: Target, - config: &StarkConfig, -) -> StarkProofChallengesTarget -where - C::Hasher: AlgebraicHasher, -{ - let num_challenges = config.num_challenges; + let permutation_challenge_sets = stark.uses_permutation_args().then(|| { + get_n_grand_product_challenge_sets( + challenger, + num_challenges, + stark.permutation_batch_size(), + ) + }); - let mut challenger = RecursiveChallenger::::new(builder); + challenger.observe_cap(permutation_ctl_zs_cap); - challenger.observe_cap(trace_cap); + let stark_alphas = challenger.get_n_challenges(num_challenges); - let permutation_challenge_sets = permutation_zs_cap.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 - }); + challenger.observe_cap(quotient_polys_cap); + let stark_zeta = challenger.get_extension_challenge::(); - let stark_alphas = challenger.get_n_challenges(builder, num_challenges); + challenger.observe_openings(&openings.to_fri_openings()); - challenger.observe_cap(quotient_polys_cap); - let stark_zeta = challenger.get_extension_challenge(builder); - - challenger.observe_openings(&openings.to_fri_openings()); - - StarkProofChallengesTarget { - permutation_challenge_sets, - stark_alphas, - stark_zeta, - fri_challenges: challenger.fri_challenges::( - builder, - commit_phase_merkle_caps, - final_poly, - pow_witness, - &config.fri_config, - ), + StarkProofChallenges { + permutation_challenge_sets, + stark_alphas, + stark_zeta, + fri_challenges: challenger.fri_challenges::( + commit_phase_merkle_caps, + final_poly, + *pow_witness, + degree_bits, + &config.fri_config, + ), + } } } @@ -229,139 +122,37 @@ impl StarkProofWithPublicInputsTarget { where C::Hasher: AlgebraicHasher, { - let StarkProofTarget { - trace_cap, - permutation_zs_cap, - quotient_polys_cap, - openings, - opening_proof: - FriProofTarget { - commit_phase_merkle_caps, - final_poly, - pow_witness, - .. - }, - } = &self.proof; - - get_challenges_target::( - builder, - stark, - trace_cap, - permutation_zs_cap.as_ref(), - quotient_polys_cap, - openings, - commit_phase_merkle_caps, - final_poly, - *pow_witness, - config, - ) + let proof = &self.proof; + let opening_proof = &proof.opening_proof; + let num_challenges = config.num_challenges; + let mut challenger = RecursiveChallenger::::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 stark_alphas = challenger.get_n_challenges(builder, num_challenges); + challenger.observe_cap(&proof.quotient_polys_cap); + let stark_zeta = challenger.get_extension_challenge(builder); + challenger.observe_openings(&proof.openings.to_fri_openings()); + StarkProofChallengesTarget { + permutation_challenge_sets, + stark_alphas, + stark_zeta, + fri_challenges: challenger.fri_challenges::( + builder, + &opening_proof.commit_phase_merkle_caps, + &opening_proof.final_poly, + opening_proof.pow_witness, + &config.fri_config, + ), + } } } - -// TODO: Deal with the compressed stuff. -// impl, C: GenericConfig, const D: usize> -// CompressedProofWithPublicInputs -// { -// /// Computes all Fiat-Shamir challenges used in the Plonk proof. -// pub(crate) fn get_challenges( -// &self, -// common_data: &CommonCircuitData, -// ) -> anyhow::Result> { -// let CompressedProof { -// wires_cap, -// plonk_zs_partial_products_cap, -// quotient_polys_cap, -// openings, -// opening_proof: -// CompressedFriProof { -// commit_phase_merkle_caps, -// final_poly, -// pow_witness, -// .. -// }, -// } = &self.proof; -// -// get_challenges( -// self.get_public_inputs_hash(), -// wires_cap, -// plonk_zs_partial_products_cap, -// quotient_polys_cap, -// openings, -// commit_phase_merkle_caps, -// final_poly, -// *pow_witness, -// common_data, -// ) -// } -// -// /// Computes all coset elements that can be inferred in the FRI reduction steps. -// pub(crate) fn get_inferred_elements( -// &self, -// challenges: &ProofChallenges, -// common_data: &CommonCircuitData, -// ) -> FriInferredElements { -// let ProofChallenges { -// plonk_zeta, -// fri_alpha, -// fri_betas, -// fri_query_indices, -// .. -// } = challenges; -// let mut fri_inferred_elements = Vec::new(); -// // Holds the indices that have already been seen at each reduction depth. -// let mut seen_indices_by_depth = -// vec![HashSet::new(); common_data.fri_params.reduction_arity_bits.len()]; -// let precomputed_reduced_evals = PrecomputedReducedOpenings::from_os_and_alpha( -// &self.proof.openings.to_fri_openings(), -// *fri_alpha, -// ); -// let log_n = common_data.degree_bits + common_data.config.fri_config.rate_bits; -// // Simulate the proof verification and collect the inferred elements. -// // The content of the loop is basically the same as the `fri_verifier_query_round` function. -// for &(mut x_index) in fri_query_indices { -// let mut subgroup_x = F::MULTIPLICATIVE_GROUP_GENERATOR -// * F::primitive_root_of_unity(log_n).exp_u64(reverse_bits(x_index, log_n) as u64); -// let mut old_eval = fri_combine_initial::( -// &common_data.get_fri_instance(*plonk_zeta), -// &self -// .proof -// .opening_proof -// .query_round_proofs -// .initial_trees_proofs[&x_index], -// *fri_alpha, -// subgroup_x, -// &precomputed_reduced_evals, -// &common_data.fri_params, -// ); -// for (i, &arity_bits) in common_data -// .fri_params -// .reduction_arity_bits -// .iter() -// .enumerate() -// { -// let coset_index = x_index >> arity_bits; -// if !seen_indices_by_depth[i].insert(coset_index) { -// // If this index has already been seen, we can skip the rest of the reductions. -// break; -// } -// fri_inferred_elements.push(old_eval); -// let arity = 1 << arity_bits; -// let mut evals = self.proof.opening_proof.query_round_proofs.steps[i][&coset_index] -// .evals -// .clone(); -// let x_index_within_coset = x_index & (arity - 1); -// evals.insert(x_index_within_coset, old_eval); -// old_eval = compute_evaluation( -// subgroup_x, -// x_index_within_coset, -// arity_bits, -// &evals, -// fri_betas[i], -// ); -// subgroup_x = subgroup_x.exp_power_of_2(arity_bits); -// x_index = coset_index; -// } -// } -// FriInferredElements(fri_inferred_elements) -// } -// } diff --git a/starky2/src/keccak/keccak_stark.rs b/starky2/src/keccak/keccak_stark.rs new file mode 100644 index 00000000..cf75bf96 --- /dev/null +++ b/starky2/src/keccak/keccak_stark.rs @@ -0,0 +1,46 @@ +use std::marker::PhantomData; + +use plonky2::field::extension_field::{Extendable, FieldExtension}; +use plonky2::field::packed_field::PackedField; +use plonky2::hash::hash_types::RichField; + +use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; +use crate::permutation::PermutationPair; +use crate::stark::Stark; +use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; + +#[derive(Copy, Clone)] +pub struct KeccakStark { + pub(crate) f: PhantomData, +} + +impl, const D: usize> Stark for KeccakStark { + const COLUMNS: usize = 7; + const PUBLIC_INPUTS: usize = 0; + + fn eval_packed_generic( + &self, + _vars: StarkEvaluationVars, + _yield_constr: &mut ConstraintConsumer

, + ) where + FE: FieldExtension, + P: PackedField, + { + } + + fn eval_ext_circuit( + &self, + _builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder, + _vars: StarkEvaluationTargets, + _yield_constr: &mut RecursiveConstraintConsumer, + ) { + } + + fn constraint_degree(&self) -> usize { + 3 + } + + fn permutation_pairs(&self) -> Vec { + vec![PermutationPair::singletons(0, 6)] + } +} diff --git a/starky2/src/keccak/mod.rs b/starky2/src/keccak/mod.rs new file mode 100644 index 00000000..4c31c32b --- /dev/null +++ b/starky2/src/keccak/mod.rs @@ -0,0 +1 @@ +pub mod keccak_stark; diff --git a/starky2/src/lib.rs b/starky2/src/lib.rs index aa14ac73..bd8ca5f3 100644 --- a/starky2/src/lib.rs +++ b/starky2/src/lib.rs @@ -3,12 +3,13 @@ #![allow(clippy::type_complexity)] #![feature(generic_const_exprs)] +pub mod all_stark; pub mod config; pub mod constraint_consumer; +pub mod cpu; pub mod cross_table_lookup; mod get_challenges; -// pub mod mock_stark; -pub mod all_stark; +pub mod keccak; pub mod permutation; pub mod proof; pub mod prover; diff --git a/starky2/src/mock_stark.rs b/starky2/src/mock_stark.rs deleted file mode 100644 index ba415a12..00000000 --- a/starky2/src/mock_stark.rs +++ /dev/null @@ -1,362 +0,0 @@ -use std::marker::PhantomData; - -use plonky2::field::extension_field::{Extendable, FieldExtension}; -use plonky2::field::packed_field::PackedField; -use plonky2::field::polynomial::PolynomialValues; -use plonky2::hash::hash_types::RichField; -use plonky2::plonk::circuit_builder::CircuitBuilder; - -use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; -use crate::permutation::PermutationPair; -use crate::stark::Stark; -use crate::util::trace_rows_to_poly_values; -use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; - -struct AllStarks, const D: usize> { - fibonacci: FibonacciStark, - multiplications: MultiplicationStark, -} - -/// Toy STARK system used for testing. -/// Computes a Fibonacci sequence with state `[x0, x1, i, j]` using the state transition -/// `x0' <- x1, x1' <- x0 + x1, i' <- i+1, j' <- j+1`. -/// Note: The `i, j` columns are only used to test the permutation argument. -#[derive(Copy, Clone)] -struct FibonacciStark, const D: usize> { - num_rows: usize, - _phantom: PhantomData, -} - -impl, const D: usize> FibonacciStark { - // The first public input is `x0`. - const PI_INDEX_X0: usize = 0; - // The second public input is `x1`. - const PI_INDEX_X1: usize = 1; - // The third public input is the second element of the last row, which should be equal to the - // `num_rows`-th Fibonacci number. - const PI_INDEX_RES: usize = 2; - - fn new(num_rows: usize) -> Self { - Self { - num_rows, - _phantom: PhantomData, - } - } - - /// Generate the trace using `x0, x1, 0, 1` as initial state values. - fn generate_trace(&self, x0: F, x1: F) -> Vec> { - let mut trace_rows = (0..self.num_rows) - .scan([x0, x1, F::ZERO, F::ONE], |acc, _| { - let tmp = *acc; - acc[0] = tmp[1]; - acc[1] = tmp[0] + tmp[1]; - acc[2] = tmp[2] + F::ONE; - acc[3] = tmp[3] + F::ONE; - Some(tmp) - }) - .collect::>(); - trace_rows[self.num_rows - 1][3] = F::ZERO; // So that column 2 and 3 are permutation of one another. - trace_rows_to_poly_values(trace_rows) - } -} - -impl, const D: usize> Stark for FibonacciStark { - const COLUMNS: usize = 4; - const PUBLIC_INPUTS: usize = 3; - - fn eval_packed_generic( - &self, - vars: StarkEvaluationVars, - yield_constr: &mut ConstraintConsumer

, - ) where - FE: FieldExtension, - P: PackedField, - { - // Check public inputs. - yield_constr - .constraint_first_row(vars.local_values[0] - vars.public_inputs[Self::PI_INDEX_X0]); - yield_constr - .constraint_first_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_X1]); - yield_constr - .constraint_last_row(vars.local_values[1] - vars.public_inputs[Self::PI_INDEX_RES]); - - // x0' <- x1 - yield_constr.constraint_transition(vars.next_values[0] - vars.local_values[1]); - // x1' <- x0 + x1 - yield_constr.constraint_transition( - vars.next_values[1] - vars.local_values[0] - vars.local_values[1], - ); - } - - fn eval_ext_recursively( - &self, - builder: &mut CircuitBuilder, - vars: StarkEvaluationTargets, - yield_constr: &mut RecursiveConstraintConsumer, - ) { - // Check public inputs. - let pis_constraints = [ - builder.sub_extension(vars.local_values[0], vars.public_inputs[Self::PI_INDEX_X0]), - builder.sub_extension(vars.local_values[1], vars.public_inputs[Self::PI_INDEX_X1]), - builder.sub_extension(vars.local_values[1], vars.public_inputs[Self::PI_INDEX_RES]), - ]; - yield_constr.constraint_first_row(builder, pis_constraints[0]); - yield_constr.constraint_first_row(builder, pis_constraints[1]); - yield_constr.constraint_last_row(builder, pis_constraints[2]); - - // x0' <- x1 - let first_col_constraint = builder.sub_extension(vars.next_values[0], vars.local_values[1]); - yield_constr.constraint_transition(builder, first_col_constraint); - // x1' <- x0 + x1 - let second_col_constraint = { - let tmp = builder.sub_extension(vars.next_values[1], vars.local_values[0]); - builder.sub_extension(tmp, vars.local_values[1]) - }; - yield_constr.constraint_transition(builder, second_col_constraint); - } - - fn constraint_degree(&self) -> usize { - 2 - } - - fn permutation_pairs(&self) -> Vec { - vec![PermutationPair::singletons(2, 3)] - } -} - -#[derive(Copy, Clone)] -struct MultiplicationStark< - F: RichField + Extendable, - const D: usize, - const NUM_MULTIPLICANDS: usize, -> { - num_rows: usize, - _phantom: PhantomData, -} - -impl, const D: usize, const W: usize> MultiplicationStark { - fn multiplicand(&self, i: usize) -> usize { - debug_assert!(i < W); - i - } - - // Product of the first `i` multiplicands - fn intermediate_product(&self, i: usize) -> usize { - debug_assert!(i < W && i > 0); - W + i - 1 - } - - fn product(&self) -> usize { - 2 * W - 2 - } - - const fn num_columns() -> usize { - 2 * W - 1 - } - - fn new(num_rows: usize) -> Self { - Self { - num_rows, - _phantom: PhantomData, - } - } - - fn generate_trace(&self, multiplicands: &[Vec]) -> Vec> - where - [(); Self::num_columns()]:, - { - debug_assert_eq!(multiplicands.len(), self.num_rows); - let mut trace_rows = multiplicands - .iter() - .map(|row| { - debug_assert_eq!(row.len(), W); - let mut result = [F::ZERO; Self::num_columns()]; - for i in 0..W { - result[self.multiplicand(i)] = row[i]; - } - let mut acc = row[0] * row[1]; - for i in 1..W - 1 { - result[self.intermediate_product(i)] = acc; - acc *= row[i + 1]; - } - result[self.product()] = acc; - result - }) - .collect::>(); - trace_rows_to_poly_values(trace_rows) - } -} - -impl, const D: usize, const W: usize> Stark - for MultiplicationStark -{ - const COLUMNS: usize = 2 * W - 1; - const PUBLIC_INPUTS: usize = 0; - - fn eval_packed_generic( - &self, - vars: StarkEvaluationVars, - yield_constr: &mut ConstraintConsumer

, - ) where - FE: FieldExtension, - P: PackedField, - { - yield_constr.constraint( - vars.local_values[self.intermediate_product(1)] - - vars.local_values[self.multiplicand(0)] * vars.local_values[self.multiplicand(1)], - ); - for i in 2..W - 1 { - yield_constr.constraint( - vars.local_values[self.intermediate_product(i)] - - vars.local_values[self.intermediate_product(i - 1)] - * vars.local_values[self.multiplicand(i)], - ) - } - } - - fn eval_ext_recursively( - &self, - builder: &mut CircuitBuilder, - vars: StarkEvaluationTargets, - yield_constr: &mut RecursiveConstraintConsumer, - ) { - todo!() - } - - fn constraint_degree(&self) -> usize { - 2 - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - use plonky2::field::extension_field::Extendable; - use plonky2::field::field_types::Field; - use plonky2::hash::hash_types::RichField; - use plonky2::iop::witness::PartialWitness; - use plonky2::plonk::circuit_builder::CircuitBuilder; - use plonky2::plonk::circuit_data::CircuitConfig; - use plonky2::plonk::config::{ - AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig, - }; - use plonky2::util::timing::TimingTree; - - use crate::config::StarkConfig; - use crate::mock_stark::FibonacciStark; - use crate::proof::StarkProofWithPublicInputs; - use crate::prover::prove; - use crate::recursive_verifier::{ - add_virtual_stark_proof_with_pis, recursively_verify_stark_proof, - set_stark_proof_with_pis_target, - }; - use crate::stark::Stark; - use crate::stark_testing::test_stark_low_degree; - use crate::verifier::verify_stark_proof; - - fn fibonacci(n: usize, x0: F, x1: F) -> F { - (0..n).fold((x0, x1), |x, _| (x.1, x.0 + x.1)).1 - } - - #[test] - fn test_fibonacci_stark() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - type S = FibonacciStark; - - let config = StarkConfig::standard_fast_config(); - let num_rows = 1 << 5; - let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; - let stark = S::new(num_rows); - let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); - // let proof = prove::( - // stark, - // &config, - // trace, - // public_inputs, - // &mut TimingTree::default(), - // )?; - - // verify_stark_proof(stark, proof, &config) - Ok(()) - } - - #[test] - fn test_fibonacci_stark_degree() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - type S = FibonacciStark; - - let num_rows = 1 << 5; - let stark = S::new(num_rows); - test_stark_low_degree(stark) - } - - #[test] - fn test_recursive_stark_verifier() -> Result<()> { - init_logger(); - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - type S = FibonacciStark; - - let config = StarkConfig::standard_fast_config(); - let num_rows = 1 << 5; - let public_inputs = [F::ZERO, F::ONE, fibonacci(num_rows - 1, F::ZERO, F::ONE)]; - let stark = S::new(num_rows); - let trace = stark.generate_trace(public_inputs[0], public_inputs[1]); - // let proof = prove::( - // stark, - // &config, - // trace, - // public_inputs, - // &mut TimingTree::default(), - // )?; - // verify_stark_proof(stark, proof.clone(), &config)?; - // - // recursive_proof::(stark, proof, &config, true) - Ok(()) - } - - fn recursive_proof< - F: RichField + Extendable, - C: GenericConfig, - S: Stark + Copy, - InnerC: GenericConfig, - const D: usize, - >( - stark: S, - inner_proof: StarkProofWithPublicInputs, - inner_config: &StarkConfig, - print_gate_counts: bool, - ) -> Result<()> - where - InnerC::Hasher: AlgebraicHasher, - [(); S::COLUMNS]:, - [(); S::PUBLIC_INPUTS]:, - [(); C::Hasher::HASH_SIZE]:, - { - let circuit_config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(circuit_config); - let mut pw = PartialWitness::new(); - let degree_bits = inner_proof.proof.recover_degree_bits(inner_config); - let pt = add_virtual_stark_proof_with_pis(&mut builder, stark, inner_config, degree_bits); - set_stark_proof_with_pis_target(&mut pw, &pt, &inner_proof); - - recursively_verify_stark_proof::(&mut builder, stark, pt, inner_config); - - if print_gate_counts { - builder.print_gate_counts(0); - } - - let data = builder.build::(); - let proof = data.prove(pw)?; - data.verify(proof) - } - - fn init_logger() { - let _ = env_logger::builder().format_timestamp(None).try_init(); - } -} diff --git a/starky2/src/permutation.rs b/starky2/src/permutation.rs index 56784f8f..6f4c6ca2 100644 --- a/starky2/src/permutation.rs +++ b/starky2/src/permutation.rs @@ -12,6 +12,7 @@ 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::util::reducing::{ReducingFactor, ReducingFactorTarget}; use rayon::prelude::*; @@ -53,6 +54,20 @@ pub(crate) struct GrandProductChallenge { pub(crate) gamma: T, } +impl GrandProductChallenge { + pub(crate) fn combine<'a, FE, P, T: IntoIterator, const D2: usize>( + &self, + terms: T, + ) -> P + where + FE: FieldExtension, + P: PackedField, + T::IntoIter: DoubleEndedIterator, + { + reduce_with_powers(terms, FE::from_basefield(self.beta)) + FE::from_basefield(self.gamma) + } +} + /// Like `PermutationChallenge`, but with `num_challenges` copies to boost soundness. #[derive(Clone)] pub(crate) struct GrandProductChallengeSet { @@ -323,7 +338,7 @@ pub struct PermutationCheckDataTarget { pub(crate) permutation_challenge_sets: Vec>, } -pub(crate) fn eval_permutation_checks_recursively( +pub(crate) fn eval_permutation_checks_circuit( builder: &mut CircuitBuilder, stark: &S, config: &StarkConfig, diff --git a/starky2/src/prover.rs b/starky2/src/prover.rs index c9f2f0ab..bc6cd99b 100644 --- a/starky2/src/prover.rs +++ b/starky2/src/prover.rs @@ -15,10 +15,12 @@ use plonky2::util::transpose; use plonky2_util::{log2_ceil, log2_strict}; use rayon::prelude::*; -use crate::all_stark::{AllStark, CpuStark, KeccakStark, Table}; +use crate::all_stark::{AllStark, Table}; use crate::config::StarkConfig; use crate::constraint_consumer::ConstraintConsumer; +use crate::cpu::cpu_stark::CpuStark; use crate::cross_table_lookup::{cross_table_lookup_data, CtlCheckVars, CtlData}; +use crate::keccak::keccak_stark::KeccakStark; use crate::permutation::PermutationCheckVars; use crate::permutation::{ compute_permutation_z_polys, get_n_grand_product_challenge_sets, GrandProductChallengeSet, diff --git a/starky2/src/recursive_verifier.rs b/starky2/src/recursive_verifier.rs index b0021ac6..af395fdb 100644 --- a/starky2/src/recursive_verifier.rs +++ b/starky2/src/recursive_verifier.rs @@ -21,10 +21,10 @@ use crate::proof::{ StarkProofWithPublicInputs, StarkProofWithPublicInputsTarget, }; use crate::stark::Stark; -use crate::vanishing_poly::eval_vanishing_poly_recursively; +use crate::vanishing_poly::eval_vanishing_poly_circuit; use crate::vars::StarkEvaluationTargets; -pub fn recursively_verify_stark_proof< +pub fn verify_stark_proof_circuit< F: RichField + Extendable, C: GenericConfig, S: Stark, @@ -47,7 +47,7 @@ pub fn recursively_verify_stark_proof< proof_with_pis.get_challenges::(builder, &stark, inner_config) ); - recursively_verify_stark_proof_with_challenges::( + verify_stark_proof_with_challenges_circuit::( builder, stark, proof_with_pis, @@ -58,7 +58,7 @@ pub fn recursively_verify_stark_proof< } /// Recursively verifies an inner proof. -fn recursively_verify_stark_proof_with_challenges< +fn verify_stark_proof_with_challenges_circuit< F: RichField + Extendable, C: GenericConfig, S: Stark, @@ -103,7 +103,7 @@ fn recursively_verify_stark_proof_with_challenges< 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) = - eval_l_1_and_l_last_recursively(builder, degree_bits, challenges.stark_zeta, z_h_zeta); + eval_l_1_and_l_last_circuit(builder, degree_bits, challenges.stark_zeta, z_h_zeta); let last = builder.constant_extension(F::Extension::primitive_root_of_unity(degree_bits).inverse()); let z_last = builder.sub_extension(challenges.stark_zeta, last); @@ -127,7 +127,7 @@ fn recursively_verify_stark_proof_with_challenges< with_context!( builder, "evaluate vanishing polynomial", - eval_vanishing_poly_recursively::( + eval_vanishing_poly_circuit::( builder, &stark, inner_config, @@ -170,7 +170,7 @@ fn recursively_verify_stark_proof_with_challenges< ); } -fn eval_l_1_and_l_last_recursively, const D: usize>( +fn eval_l_1_and_l_last_circuit, const D: usize>( builder: &mut CircuitBuilder, log_n: usize, x: ExtensionTarget, diff --git a/starky2/src/stark.rs b/starky2/src/stark.rs index dcf1a73f..20404341 100644 --- a/starky2/src/stark.rs +++ b/starky2/src/stark.rs @@ -66,7 +66,7 @@ pub trait Stark, const D: usize>: Sync { /// `eval_ext`, except in the context of a recursive circuit. /// Note: constraints must be added through`yeld_constr.constraint(builder, constraint)` in the /// same order as they are given in `eval_packed_generic`. - fn eval_ext_recursively( + fn eval_ext_circuit( &self, builder: &mut CircuitBuilder, vars: StarkEvaluationTargets, diff --git a/starky2/src/vanishing_poly.rs b/starky2/src/vanishing_poly.rs index aac8fc80..37b1b5ab 100644 --- a/starky2/src/vanishing_poly.rs +++ b/starky2/src/vanishing_poly.rs @@ -8,7 +8,7 @@ use crate::config::StarkConfig; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cross_table_lookup::{eval_cross_table_lookup_checks, CtlCheckVars}; use crate::permutation::{ - eval_permutation_checks, eval_permutation_checks_recursively, PermutationCheckDataTarget, + eval_permutation_checks, eval_permutation_checks_circuit, PermutationCheckDataTarget, PermutationCheckVars, }; use crate::stark::Stark; @@ -41,7 +41,7 @@ pub(crate) fn eval_vanishing_poly(vars, ctl_vars, consumer); } -pub(crate) fn eval_vanishing_poly_recursively( +pub(crate) fn eval_vanishing_poly_circuit( builder: &mut CircuitBuilder, stark: &S, config: &StarkConfig, @@ -55,9 +55,9 @@ pub(crate) fn eval_vanishing_poly_recursively( [(); S::COLUMNS]:, [(); S::PUBLIC_INPUTS]:, { - stark.eval_ext_recursively(builder, vars, consumer); + stark.eval_ext_circuit(builder, vars, consumer); if let Some(permutation_data) = permutation_data { - eval_permutation_checks_recursively::( + eval_permutation_checks_circuit::( builder, stark, config, diff --git a/starky2/src/verifier.rs b/starky2/src/verifier.rs index d8f24e97..52882488 100644 --- a/starky2/src/verifier.rs +++ b/starky2/src/verifier.rs @@ -6,10 +6,12 @@ use plonky2::hash::hash_types::RichField; use plonky2::plonk::config::{GenericConfig, Hasher}; use plonky2::plonk::plonk_common::reduce_with_powers; -use crate::all_stark::{AllStark, CpuStark, KeccakStark, Table}; +use crate::all_stark::{AllStark, Table}; use crate::config::StarkConfig; use crate::constraint_consumer::ConstraintConsumer; +use crate::cpu::cpu_stark::CpuStark; use crate::cross_table_lookup::{verify_cross_table_lookups, CtlCheckVars}; +use crate::keccak::keccak_stark::KeccakStark; use crate::permutation::PermutationCheckVars; use crate::proof::{ AllProof, AllProofChallenges, StarkOpeningSet, StarkProofChallenges, StarkProofWithPublicInputs,