From 9e9ff9872ba18599cf5465c1db746d8db50d50fd Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 25 Aug 2022 22:04:28 +0200 Subject: [PATCH 01/28] Per table recursion --- evm/src/all_stark.rs | 2 +- evm/src/cross_table_lookup.rs | 53 +++++++++++++++++++++++ evm/src/proof.rs | 6 ++- evm/src/recursive_verifier.rs | 79 ++++++++++++++++++++++++++++++++++- 4 files changed, 136 insertions(+), 4 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 1131d529..77af0119 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -59,7 +59,7 @@ impl, const D: usize> AllStark { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Table { Cpu = 0, Keccak = 1, diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index b4b8d6fb..899b46d7 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -474,6 +474,59 @@ impl<'a, F: Field, const D: usize> CtlCheckVarsTarget<'a, F, D> { } ctl_vars_per_table } + + pub(crate) fn from_proof( + table: Table, + proof: &StarkProofWithPublicInputsTarget, + cross_table_lookups: &'a [CrossTableLookup], + ctl_challenges: &'a GrandProductChallengeSet, + num_permutation_zs: usize, + ) -> Vec { + let mut ctl_zs = { + let openings = &proof.proof.openings; + let ctl_zs = openings.permutation_ctl_zs.iter().skip(num_permutation_zs); + let ctl_zs_next = openings + .permutation_ctl_zs_next + .iter() + .skip(num_permutation_zs); + ctl_zs.zip(ctl_zs_next) + }; + + let mut ctl_vars = vec![]; + for CrossTableLookup { + looking_tables, + looked_table, + .. + } in cross_table_lookups + { + for &challenges in &ctl_challenges.challenges { + for looking_table in looking_tables { + if looking_table.table == table { + let (looking_z, looking_z_next) = ctl_zs.next().unwrap(); + ctl_vars.push(Self { + local_z: *looking_z, + next_z: *looking_z_next, + challenges, + columns: &looking_table.columns, + filter_column: &looking_table.filter_column, + }); + } + } + + if looked_table.table == table { + let (looked_z, looked_z_next) = ctl_zs.next().unwrap(); + ctl_vars.push(Self { + local_z: *looked_z, + next_z: *looked_z_next, + challenges, + columns: &looked_table.columns, + filter_column: &looked_table.filter_column, + }); + } + } + } + ctl_vars + } } pub(crate) fn eval_cross_table_lookup_checks_circuit< diff --git a/evm/src/proof.rs b/evm/src/proof.rs index 4f81308d..e81514eb 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -33,7 +33,7 @@ impl, C: GenericConfig, const D: usize> A pub fn nums_ctl_zs(&self) -> Vec { self.stark_proofs .iter() - .map(|proof| proof.proof.openings.ctl_zs_last.len()) + .map(|proof| proof.proof.num_ctl_zs()) .collect() } } @@ -76,6 +76,10 @@ impl, C: GenericConfig, const D: usize> S let lde_bits = config.fri_config.cap_height + initial_merkle_proof.siblings.len(); lde_bits - config.fri_config.rate_bits } + + pub fn num_ctl_zs(&self) -> usize { + self.openings.ctl_zs_last.len() + } } pub struct StarkProofTarget { diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index b69a5519..cfd1b36a 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -1,3 +1,4 @@ +use anyhow::Result; use itertools::Itertools; use plonky2::field::extension::Extendable; use plonky2::field::types::Field; @@ -5,9 +6,12 @@ use plonky2::fri::witness_util::set_fri_proof_target; use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; -use plonky2::iop::witness::Witness; +use plonky2::iop::witness::{PartialWitness, Witness}; use plonky2::plonk::circuit_builder::CircuitBuilder; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::config::Hasher; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; +use plonky2::plonk::proof::ProofWithPublicInputs; use plonky2::util::reducing::ReducingFactorTarget; use plonky2::with_context; @@ -15,7 +19,9 @@ use crate::all_stark::{AllStark, Table}; use crate::config::StarkConfig; use crate::constraint_consumer::RecursiveConstraintConsumer; use crate::cpu::cpu_stark::CpuStark; -use crate::cross_table_lookup::{verify_cross_table_lookups_circuit, CtlCheckVarsTarget}; +use crate::cross_table_lookup::{ + verify_cross_table_lookups_circuit, CrossTableLookup, CtlCheckVarsTarget, +}; use crate::keccak::keccak_stark::KeccakStark; use crate::logic::LogicStark; use crate::memory::memory_stark::MemoryStark; @@ -29,6 +35,75 @@ use crate::stark::Stark; use crate::vanishing_poly::eval_vanishing_poly_circuit; use crate::vars::StarkEvaluationTargets; +pub(crate) struct AllRecursiveProofs< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, +> { + pub recursive_proofs: Vec>, +} + +pub(crate) fn recursively_prove_stark_proof< + F: RichField + Extendable, + C: GenericConfig, + S: Stark, + const D: usize, +>( + table: Table, + stark: S, + all_stark: &AllStark, + all_proof: &AllProof, + cross_table_lookups: &[CrossTableLookup], + inner_config: &StarkConfig, + circuit_config: CircuitConfig, +) -> Result> +where + [(); S::COLUMNS]:, + [(); S::PUBLIC_INPUTS]:, + [(); C::Hasher::HASH_SIZE]:, + C::Hasher: AlgebraicHasher, +{ + let mut builder = CircuitBuilder::::new(circuit_config); + let mut pw = PartialWitness::new(); + + let nums_ctl_zs = all_proof.nums_ctl_zs(); + let degree_bits = all_proof.degree_bits(inner_config); + let num_permutation_zs = stark.num_permutation_batches(inner_config); + let all_proof_target = add_virtual_all_proof( + &mut builder, + all_stark, + inner_config, + °ree_bits, + &nums_ctl_zs, + ); + set_all_proof_target(&mut pw, &all_proof_target, all_proof, builder.zero()); + + let AllProofChallengesTarget { + stark_challenges, + ctl_challenges, + } = all_proof_target.get_challenges::(&mut builder, all_stark, inner_config); + + let ctl_vars = CtlCheckVarsTarget::from_proof( + table, + &all_proof_target.stark_proofs[table as usize], + cross_table_lookups, + &ctl_challenges, + num_permutation_zs, + ); + + verify_stark_proof_with_challenges_circuit::( + &mut builder, + stark, + &all_proof_target.stark_proofs[table as usize], + &stark_challenges[table as usize], + &ctl_vars, + inner_config, + ); + + let data = builder.build::(); + data.prove(pw) +} + pub fn verify_proof_circuit< F: RichField + Extendable, C: GenericConfig, From c4fc9b0ae492f3b9cf0a91ce4836200be3d6302c Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 26 Aug 2022 09:42:55 +0200 Subject: [PATCH 02/28] Merge conflicts --- evm/src/cross_table_lookup.rs | 4 ++-- evm/src/recursive_verifier.rs | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 40089ecd..5d242ced 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -492,13 +492,13 @@ impl<'a, F: Field, const D: usize> CtlCheckVarsTarget<'a, F, D> { pub(crate) fn from_proof( table: Table, - proof: &StarkProofWithPublicInputsTarget, + proof: &StarkProofTarget, cross_table_lookups: &'a [CrossTableLookup], ctl_challenges: &'a GrandProductChallengeSet, num_permutation_zs: usize, ) -> Vec { let mut ctl_zs = { - let openings = &proof.proof.openings; + let openings = &proof.openings; let ctl_zs = openings.permutation_ctl_zs.iter().skip(num_permutation_zs); let ctl_zs_next = openings .permutation_ctl_zs_next diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index f845c364..22347dab 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -61,7 +61,6 @@ pub(crate) fn recursively_prove_stark_proof< ) -> Result> where [(); S::COLUMNS]:, - [(); S::PUBLIC_INPUTS]:, [(); C::Hasher::HASH_SIZE]:, C::Hasher: AlgebraicHasher, { From 2fa347128f4ec94e5abf023799b96630444614ea Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 26 Aug 2022 09:49:59 +0200 Subject: [PATCH 03/28] All recursive proofs --- evm/src/all_stark.rs | 2 +- evm/src/recursive_verifier.rs | 73 ++++++++++++++++++++++++++++++++++- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index a47b5b7c..0d822ec6 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -76,7 +76,7 @@ pub enum Table { } impl Table { - pub(crate) fn num_tables() -> usize { + pub(crate) const fn num_tables() -> usize { Table::Memory as usize + 1 } } diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 22347dab..9c23e01e 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -57,14 +57,14 @@ pub(crate) fn recursively_prove_stark_proof< all_proof: &AllProof, cross_table_lookups: &[CrossTableLookup], inner_config: &StarkConfig, - circuit_config: CircuitConfig, + circuit_config: &CircuitConfig, ) -> Result> where [(); S::COLUMNS]:, [(); C::Hasher::HASH_SIZE]:, C::Hasher: AlgebraicHasher, { - let mut builder = CircuitBuilder::::new(circuit_config); + let mut builder = CircuitBuilder::::new(circuit_config.clone()); let mut pw = PartialWitness::new(); let nums_ctl_zs = all_proof.nums_ctl_zs(); @@ -105,6 +105,75 @@ where data.prove(pw) } +pub(crate) fn recursively_prove_all_proofs< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, +>( + all_stark: &AllStark, + all_proof: &AllProof, + cross_table_lookups: &[CrossTableLookup], + inner_config: &StarkConfig, + circuit_config: CircuitConfig, +) -> Result<[ProofWithPublicInputs; Table::num_tables()]> +where + [(); CpuStark::::COLUMNS]:, + [(); KeccakStark::::COLUMNS]:, + [(); KeccakMemoryStark::::COLUMNS]:, + [(); LogicStark::::COLUMNS]:, + [(); MemoryStark::::COLUMNS]:, + [(); C::Hasher::HASH_SIZE]:, + C::Hasher: AlgebraicHasher, +{ + Ok([ + recursively_prove_stark_proof( + Table::Cpu, + all_stark.cpu_stark, + all_stark, + all_proof, + cross_table_lookups, + inner_config, + &circuit_config, + )?, + recursively_prove_stark_proof( + Table::Cpu, + all_stark.cpu_stark, + all_stark, + all_proof, + cross_table_lookups, + inner_config, + &circuit_config, + )?, + recursively_prove_stark_proof( + Table::Cpu, + all_stark.cpu_stark, + all_stark, + all_proof, + cross_table_lookups, + inner_config, + &circuit_config, + )?, + recursively_prove_stark_proof( + Table::Cpu, + all_stark.cpu_stark, + all_stark, + all_proof, + cross_table_lookups, + inner_config, + &circuit_config, + )?, + recursively_prove_stark_proof( + Table::Cpu, + all_stark.cpu_stark, + all_stark, + all_proof, + cross_table_lookups, + inner_config, + &circuit_config, + )?, + ]) +} + pub fn verify_proof_circuit< F: RichField + Extendable, C: GenericConfig, From da03af2979d6cb0d84811bc09bc39b712eda7855 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 5 Sep 2022 08:38:57 +0200 Subject: [PATCH 04/28] Minor --- evm/src/lib.rs | 1 - evm/src/proof.rs | 1 + evm/src/recursive_verifier.rs | 22 +++++++++++----------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/evm/src/lib.rs b/evm/src/lib.rs index 6f332b59..08dfbc6c 100644 --- a/evm/src/lib.rs +++ b/evm/src/lib.rs @@ -2,7 +2,6 @@ #![allow(clippy::needless_range_loop)] #![allow(clippy::too_many_arguments)] #![allow(clippy::type_complexity)] -#![feature(let_chains)] #![feature(generic_const_exprs)] pub mod all_stark; diff --git a/evm/src/proof.rs b/evm/src/proof.rs index b23e7a37..3c5e9968 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -31,6 +31,7 @@ impl, C: GenericConfig, const D: usize> A pub fn nums_ctl_zs(&self) -> [usize; NUM_TABLES] { std::array::from_fn(|i| self.stark_proofs[i].num_ctl_zs()) } +} pub(crate) struct AllProofChallenges, const D: usize> { pub stark_challenges: [StarkProofChallenges; NUM_TABLES], diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index ecc16a70..508db332 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -15,7 +15,7 @@ use plonky2::plonk::proof::ProofWithPublicInputs; use plonky2::util::reducing::ReducingFactorTarget; use plonky2::with_context; -use crate::all_stark::{AllStark, Table}; +use crate::all_stark::{AllStark, Table, NUM_TABLES}; use crate::config::StarkConfig; use crate::constraint_consumer::RecursiveConstraintConsumer; use crate::cpu::cpu_stark::CpuStark; @@ -42,7 +42,7 @@ pub(crate) struct AllRecursiveProofs< C: GenericConfig, const D: usize, > { - pub recursive_proofs: Vec>, + pub recursive_proofs: [ProofWithPublicInputs; NUM_TABLES], } pub(crate) fn recursively_prove_stark_proof< @@ -115,7 +115,7 @@ pub(crate) fn recursively_prove_all_proofs< cross_table_lookups: &[CrossTableLookup], inner_config: &StarkConfig, circuit_config: CircuitConfig, -) -> Result<[ProofWithPublicInputs; Table::num_tables()]> +) -> Result<[ProofWithPublicInputs; NUM_TABLES]> where [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, @@ -136,8 +136,8 @@ where &circuit_config, )?, recursively_prove_stark_proof( - Table::Cpu, - all_stark.cpu_stark, + Table::Keccak, + all_stark.keccak_stark, all_stark, all_proof, cross_table_lookups, @@ -145,8 +145,8 @@ where &circuit_config, )?, recursively_prove_stark_proof( - Table::Cpu, - all_stark.cpu_stark, + Table::KeccakMemory, + all_stark.keccak_memory_stark, all_stark, all_proof, cross_table_lookups, @@ -154,8 +154,8 @@ where &circuit_config, )?, recursively_prove_stark_proof( - Table::Cpu, - all_stark.cpu_stark, + Table::Logic, + all_stark.logic_stark, all_stark, all_proof, cross_table_lookups, @@ -163,8 +163,8 @@ where &circuit_config, )?, recursively_prove_stark_proof( - Table::Cpu, - all_stark.cpu_stark, + Table::Memory, + all_stark.memory_stark, all_stark, all_proof, cross_table_lookups, From e6490fdd117104b504f457f54c3500782464c17f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 5 Sep 2022 09:17:00 +0200 Subject: [PATCH 05/28] Add verify --- evm/src/all_stark.rs | 56 ++++++------- evm/src/recursive_verifier.rs | 130 ++++++++++++++++-------------- plonky2/src/plonk/circuit_data.rs | 12 +++ 3 files changed, 110 insertions(+), 88 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 2b0fa6b9..e04004cc 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -174,8 +174,6 @@ mod tests { use itertools::Itertools; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::{Field, PrimeField64}; - use plonky2::iop::witness::PartialWitness; - use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2::util::timing::TimingTree; @@ -194,9 +192,7 @@ mod tests { use crate::memory::NUM_CHANNELS; use crate::proof::{AllProof, PublicValues}; use crate::prover::prove_with_traces; - use crate::recursive_verifier::{ - add_virtual_all_proof, set_all_proof_target, verify_proof_circuit, - }; + use crate::recursive_verifier::recursively_prove_all_proof; use crate::stark::Stark; use crate::util::{limb_from_bits_le, trace_rows_to_poly_values}; use crate::verifier::verify_proof; @@ -739,38 +735,44 @@ mod tests { let (all_stark, proof) = get_proof(&config)?; verify_proof(all_stark.clone(), proof.clone(), &config)?; - recursive_proof(all_stark, proof, &config, true) + recursive_proof(all_stark, proof, &config) } fn recursive_proof( inner_all_stark: AllStark, inner_proof: AllProof, inner_config: &StarkConfig, - print_gate_counts: bool, ) -> Result<()> { let circuit_config = CircuitConfig::standard_recursion_config(); - let mut builder = CircuitBuilder::::new(circuit_config); - let mut pw = PartialWitness::new(); - let degree_bits = inner_proof.degree_bits(inner_config); - let nums_ctl_zs = inner_proof.nums_ctl_zs(); - let pt = add_virtual_all_proof( - &mut builder, + let recursive_all_proof = recursively_prove_all_proof( &inner_all_stark, + &inner_proof, inner_config, - °ree_bits, - &nums_ctl_zs, - ); - set_all_proof_target(&mut pw, &pt, &inner_proof, builder.zero()); - - verify_proof_circuit::(&mut builder, inner_all_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) + circuit_config, + )?; + recursive_all_proof.verify() + // let mut builder = CircuitBuilder::::new(circuit_config); + // let mut pw = PartialWitness::new(); + // let degree_bits = inner_proof.degree_bits(inner_config); + // let nums_ctl_zs = inner_proof.nums_ctl_zs(); + // let pt = add_virtual_all_proof( + // &mut builder, + // &inner_all_stark, + // inner_config, + // °ree_bits, + // &nums_ctl_zs, + // ); + // set_all_proof_target(&mut pw, &pt, &inner_proof, builder.zero()); + // + // verify_proof_circuit::(&mut builder, inner_all_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() { diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 508db332..7488b86a 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -8,7 +8,7 @@ use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; use plonky2::iop::witness::{PartialWitness, Witness}; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData}; use plonky2::plonk::config::Hasher; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::plonk::proof::ProofWithPublicInputs; @@ -19,9 +19,7 @@ use crate::all_stark::{AllStark, Table, NUM_TABLES}; use crate::config::StarkConfig; use crate::constraint_consumer::RecursiveConstraintConsumer; use crate::cpu::cpu_stark::CpuStark; -use crate::cross_table_lookup::{ - verify_cross_table_lookups_circuit, CrossTableLookup, CtlCheckVarsTarget, -}; +use crate::cross_table_lookup::{verify_cross_table_lookups_circuit, CtlCheckVarsTarget}; use crate::keccak::keccak_stark::KeccakStark; use crate::keccak_memory::keccak_memory_stark::KeccakMemoryStark; use crate::logic::LogicStark; @@ -37,15 +35,30 @@ use crate::util::{h160_limbs, u256_limbs}; use crate::vanishing_poly::eval_vanishing_poly_circuit; use crate::vars::StarkEvaluationTargets; -pub(crate) struct AllRecursiveProofs< +pub struct AllRecursiveProofs< F: RichField + Extendable, C: GenericConfig, const D: usize, > { - pub recursive_proofs: [ProofWithPublicInputs; NUM_TABLES], + pub recursive_proofs: + [(ProofWithPublicInputs, VerifierCircuitData); NUM_TABLES], } -pub(crate) fn recursively_prove_stark_proof< +impl, C: GenericConfig, const D: usize> + AllRecursiveProofs +{ + pub fn verify(self) -> Result<()> + where + [(); C::Hasher::HASH_SIZE]:, + { + for (proof, verifier_data) in self.recursive_proofs { + verifier_data.verify(proof)?; + } + Ok(()) + } +} + +fn recursively_prove_stark_proof< F: RichField + Extendable, C: GenericConfig, S: Stark, @@ -55,10 +68,9 @@ pub(crate) fn recursively_prove_stark_proof< stark: S, all_stark: &AllStark, all_proof: &AllProof, - cross_table_lookups: &[CrossTableLookup], inner_config: &StarkConfig, circuit_config: &CircuitConfig, -) -> Result> +) -> Result<(ProofWithPublicInputs, VerifierCircuitData)> where [(); S::COLUMNS]:, [(); C::Hasher::HASH_SIZE]:, @@ -87,7 +99,7 @@ where let ctl_vars = CtlCheckVarsTarget::from_proof( table, &all_proof_target.stark_proofs[table as usize], - cross_table_lookups, + &all_stark.cross_table_lookups, &ctl_challenges, num_permutation_zs, ); @@ -102,20 +114,19 @@ where ); let data = builder.build::(); - data.prove(pw) + Ok((data.prove(pw)?, data.verifier_data())) } -pub(crate) fn recursively_prove_all_proofs< +pub fn recursively_prove_all_proof< F: RichField + Extendable, C: GenericConfig, const D: usize, >( all_stark: &AllStark, all_proof: &AllProof, - cross_table_lookups: &[CrossTableLookup], inner_config: &StarkConfig, circuit_config: CircuitConfig, -) -> Result<[ProofWithPublicInputs; NUM_TABLES]> +) -> Result> where [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, @@ -125,53 +136,50 @@ where [(); C::Hasher::HASH_SIZE]:, C::Hasher: AlgebraicHasher, { - Ok([ - recursively_prove_stark_proof( - Table::Cpu, - all_stark.cpu_stark, - all_stark, - all_proof, - cross_table_lookups, - inner_config, - &circuit_config, - )?, - recursively_prove_stark_proof( - Table::Keccak, - all_stark.keccak_stark, - all_stark, - all_proof, - cross_table_lookups, - inner_config, - &circuit_config, - )?, - recursively_prove_stark_proof( - Table::KeccakMemory, - all_stark.keccak_memory_stark, - all_stark, - all_proof, - cross_table_lookups, - inner_config, - &circuit_config, - )?, - recursively_prove_stark_proof( - Table::Logic, - all_stark.logic_stark, - all_stark, - all_proof, - cross_table_lookups, - inner_config, - &circuit_config, - )?, - recursively_prove_stark_proof( - Table::Memory, - all_stark.memory_stark, - all_stark, - all_proof, - cross_table_lookups, - inner_config, - &circuit_config, - )?, - ]) + Ok(AllRecursiveProofs { + recursive_proofs: [ + recursively_prove_stark_proof( + Table::Cpu, + all_stark.cpu_stark, + all_stark, + all_proof, + inner_config, + &circuit_config, + )?, + recursively_prove_stark_proof( + Table::Keccak, + all_stark.keccak_stark, + all_stark, + all_proof, + inner_config, + &circuit_config, + )?, + recursively_prove_stark_proof( + Table::KeccakMemory, + all_stark.keccak_memory_stark, + all_stark, + all_proof, + inner_config, + &circuit_config, + )?, + recursively_prove_stark_proof( + Table::Logic, + all_stark.logic_stark, + all_stark, + all_proof, + inner_config, + &circuit_config, + )?, + recursively_prove_stark_proof( + Table::Memory, + all_stark.memory_stark, + all_stark, + all_proof, + inner_config, + &circuit_config, + )?, + ], + }) } pub fn verify_proof_circuit< diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index fb839978..8e8c13f7 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -139,6 +139,18 @@ impl, C: GenericConfig, const D: usize> { compressed_proof_with_pis.verify(&self.verifier_only, &self.common) } + + pub fn verifier_data(self) -> VerifierCircuitData { + let CircuitData { + verifier_only, + common, + .. + } = self; + VerifierCircuitData { + verifier_only, + common, + } + } } /// Circuit data required by the prover. This may be thought of as a proving key, although it From 35b22974edb717d2954ede6342ab1b54002947a3 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 5 Sep 2022 12:25:30 +0200 Subject: [PATCH 06/28] Recursively verify --- evm/src/all_stark.rs | 34 +++++++++++----------------------- evm/src/recursive_verifier.rs | 24 +++++++++++++++++++++++- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index e04004cc..efc6a3af 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -174,6 +174,8 @@ mod tests { use itertools::Itertools; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::{Field, PrimeField64}; + use plonky2::iop::witness::PartialWitness; + use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::CircuitConfig; use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2::util::timing::TimingTree; @@ -750,29 +752,15 @@ mod tests { inner_config, circuit_config, )?; - recursive_all_proof.verify() - // let mut builder = CircuitBuilder::::new(circuit_config); - // let mut pw = PartialWitness::new(); - // let degree_bits = inner_proof.degree_bits(inner_config); - // let nums_ctl_zs = inner_proof.nums_ctl_zs(); - // let pt = add_virtual_all_proof( - // &mut builder, - // &inner_all_stark, - // inner_config, - // °ree_bits, - // &nums_ctl_zs, - // ); - // set_all_proof_target(&mut pw, &pt, &inner_proof, builder.zero()); - // - // verify_proof_circuit::(&mut builder, inner_all_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) + + let circuit_config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::::new(circuit_config); + let mut pw = PartialWitness::new(); + recursive_all_proof.recursively_verify(&mut builder, &mut pw); + + let data = builder.build::(); + let proof = data.prove(pw)?; + data.verify(proof) } fn init_logger() { diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 7488b86a..02fdc4d6 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -8,7 +8,7 @@ use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; use plonky2::iop::witness::{PartialWitness, Witness}; use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData}; +use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData, VerifierCircuitTarget}; use plonky2::plonk::config::Hasher; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::plonk::proof::ProofWithPublicInputs; @@ -56,6 +56,28 @@ impl, C: GenericConfig, const D: usize> } Ok(()) } + + pub fn recursively_verify(&self, builder: &mut CircuitBuilder, pw: &mut W) + where + W: Witness, + [(); C::Hasher::HASH_SIZE]:, + >::Hasher: AlgebraicHasher, + { + for (proof, verifier_data) in &self.recursive_proofs { + let pt = builder.add_virtual_proof_with_pis(&verifier_data.common); + pw.set_proof_with_pis_target(&pt, &proof); + let inner_data = VerifierCircuitTarget { + constants_sigmas_cap: builder + .add_virtual_cap(verifier_data.common.config.fri_config.cap_height), + }; + pw.set_cap_target( + &inner_data.constants_sigmas_cap, + &verifier_data.verifier_only.constants_sigmas_cap, + ); + builder.verify_proof(pt, &inner_data, &verifier_data.common); + } + // builder.print_gate_counts(0); + } } fn recursively_prove_stark_proof< From a5f4730bd55446615bb76003bba4736aeb66360d Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 5 Sep 2022 15:47:03 +0200 Subject: [PATCH 07/28] Minor --- evm/src/recursive_verifier.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 02fdc4d6..758f7e2b 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -76,7 +76,6 @@ impl, C: GenericConfig, const D: usize> ); builder.verify_proof(pt, &inner_data, &verifier_data.common); } - // builder.print_gate_counts(0); } } From e6708da36fa89b5eca63fe52b8e051d8aa187dcb Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 5 Sep 2022 16:34:29 +0200 Subject: [PATCH 08/28] Comments --- evm/src/all_stark.rs | 6 +++--- evm/src/recursive_verifier.rs | 31 +++++++++++++++++++------------ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index efc6a3af..68b65d41 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -194,7 +194,7 @@ mod tests { use crate::memory::NUM_CHANNELS; use crate::proof::{AllProof, PublicValues}; use crate::prover::prove_with_traces; - use crate::recursive_verifier::recursively_prove_all_proof; + use crate::recursive_verifier::recursively_verify_all_proof; use crate::stark::Stark; use crate::util::{limb_from_bits_le, trace_rows_to_poly_values}; use crate::verifier::verify_proof; @@ -746,7 +746,7 @@ mod tests { inner_config: &StarkConfig, ) -> Result<()> { let circuit_config = CircuitConfig::standard_recursion_config(); - let recursive_all_proof = recursively_prove_all_proof( + let recursive_all_proof = recursively_verify_all_proof( &inner_all_stark, &inner_proof, inner_config, @@ -756,7 +756,7 @@ mod tests { let circuit_config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(circuit_config); let mut pw = PartialWitness::new(); - recursive_all_proof.recursively_verify(&mut builder, &mut pw); + recursive_all_proof.verify_circuit(&mut builder, &mut pw); let data = builder.build::(); let proof = data.prove(pw)?; diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 758f7e2b..328729d9 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -35,7 +35,9 @@ use crate::util::{h160_limbs, u256_limbs}; use crate::vanishing_poly::eval_vanishing_poly_circuit; use crate::vars::StarkEvaluationTargets; -pub struct AllRecursiveProofs< +/// Table-wise recursive proofs of an `AllProof`. +/// Also contains verifier data for each proof. +pub struct RecursiveAllProof< F: RichField + Extendable, C: GenericConfig, const D: usize, @@ -45,8 +47,9 @@ pub struct AllRecursiveProofs< } impl, C: GenericConfig, const D: usize> - AllRecursiveProofs + RecursiveAllProof { + /// Verify every recursive proof. pub fn verify(self) -> Result<()> where [(); C::Hasher::HASH_SIZE]:, @@ -57,7 +60,8 @@ impl, C: GenericConfig, const D: usize> Ok(()) } - pub fn recursively_verify(&self, builder: &mut CircuitBuilder, pw: &mut W) + /// Recursively verify every recursive proof. + pub fn verify_circuit(&self, builder: &mut CircuitBuilder, pw: &mut W) where W: Witness, [(); C::Hasher::HASH_SIZE]:, @@ -79,7 +83,9 @@ impl, C: GenericConfig, const D: usize> } } -fn recursively_prove_stark_proof< +/// Recursively verify a Stark proof. +/// Outputs the recursive proof and the associated verifier data. +fn recursively_verify_stark_proof< F: RichField + Extendable, C: GenericConfig, S: Stark, @@ -138,7 +144,8 @@ where Ok((data.prove(pw)?, data.verifier_data())) } -pub fn recursively_prove_all_proof< +/// Recursively verify every Stark proof in an `AllProof`. +pub fn recursively_verify_all_proof< F: RichField + Extendable, C: GenericConfig, const D: usize, @@ -147,7 +154,7 @@ pub fn recursively_prove_all_proof< all_proof: &AllProof, inner_config: &StarkConfig, circuit_config: CircuitConfig, -) -> Result> +) -> Result> where [(); CpuStark::::COLUMNS]:, [(); KeccakStark::::COLUMNS]:, @@ -157,9 +164,9 @@ where [(); C::Hasher::HASH_SIZE]:, C::Hasher: AlgebraicHasher, { - Ok(AllRecursiveProofs { + Ok(RecursiveAllProof { recursive_proofs: [ - recursively_prove_stark_proof( + recursively_verify_stark_proof( Table::Cpu, all_stark.cpu_stark, all_stark, @@ -167,7 +174,7 @@ where inner_config, &circuit_config, )?, - recursively_prove_stark_proof( + recursively_verify_stark_proof( Table::Keccak, all_stark.keccak_stark, all_stark, @@ -175,7 +182,7 @@ where inner_config, &circuit_config, )?, - recursively_prove_stark_proof( + recursively_verify_stark_proof( Table::KeccakMemory, all_stark.keccak_memory_stark, all_stark, @@ -183,7 +190,7 @@ where inner_config, &circuit_config, )?, - recursively_prove_stark_proof( + recursively_verify_stark_proof( Table::Logic, all_stark.logic_stark, all_stark, @@ -191,7 +198,7 @@ where inner_config, &circuit_config, )?, - recursively_prove_stark_proof( + recursively_verify_stark_proof( Table::Memory, all_stark.memory_stark, all_stark, From a7609045494701a683d4940444e8a0ace6323450 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 5 Sep 2022 16:37:54 +0200 Subject: [PATCH 09/28] Clippy --- evm/src/recursive_verifier.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 328729d9..0878b0e6 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -69,7 +69,7 @@ impl, C: GenericConfig, const D: usize> { for (proof, verifier_data) in &self.recursive_proofs { let pt = builder.add_virtual_proof_with_pis(&verifier_data.common); - pw.set_proof_with_pis_target(&pt, &proof); + pw.set_proof_with_pis_target(&pt, proof); let inner_data = VerifierCircuitTarget { constants_sigmas_cap: builder .add_virtual_cap(verifier_data.common.config.fri_config.cap_height), From 11bdd501c84d0aecb7b993962dcb12ef39e5c913 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 5 Sep 2022 17:00:31 +0200 Subject: [PATCH 10/28] let_chains --- evm/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/evm/src/lib.rs b/evm/src/lib.rs index 08dfbc6c..6f332b59 100644 --- a/evm/src/lib.rs +++ b/evm/src/lib.rs @@ -2,6 +2,7 @@ #![allow(clippy::needless_range_loop)] #![allow(clippy::too_many_arguments)] #![allow(clippy::type_complexity)] +#![feature(let_chains)] #![feature(generic_const_exprs)] pub mod all_stark; From 00c439513aa7fdb63600b9d57f731f8b19f84615 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 6 Sep 2022 16:51:14 +0200 Subject: [PATCH 11/28] Add prover_data method --- plonky2/src/plonk/circuit_builder.rs | 22 ++++------------------ plonky2/src/plonk/circuit_data.rs | 12 ++++++++++++ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index ca68af9c..e4e3e997 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -836,15 +836,8 @@ impl, const D: usize> CircuitBuilder { [(); C::Hasher::HASH_SIZE]:, { // TODO: Can skip parts of this. - let CircuitData { - prover_only, - common, - .. - } = self.build(); - ProverCircuitData { - prover_only, - common, - } + let circuit_data = self.build(); + circuit_data.prover_data() } /// Builds a "verifier circuit", with data needed to verify proofs but not generate them. @@ -853,14 +846,7 @@ impl, const D: usize> CircuitBuilder { [(); C::Hasher::HASH_SIZE]:, { // TODO: Can skip parts of this. - let CircuitData { - verifier_only, - common, - .. - } = self.build(); - VerifierCircuitData { - verifier_only, - common, - } + let circuit_data = self.build(); + circuit_data.verifier_data() } } diff --git a/plonky2/src/plonk/circuit_data.rs b/plonky2/src/plonk/circuit_data.rs index 8e8c13f7..16c899de 100644 --- a/plonky2/src/plonk/circuit_data.rs +++ b/plonky2/src/plonk/circuit_data.rs @@ -151,6 +151,18 @@ impl, C: GenericConfig, const D: usize> common, } } + + pub fn prover_data(self) -> ProverCircuitData { + let CircuitData { + prover_only, + common, + .. + } = self; + ProverCircuitData { + prover_only, + common, + } + } } /// Circuit data required by the prover. This may be thought of as a proving key, although it From 6e6c2daf291c3d20ff2938b8611b2365ad27742b Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 22 Sep 2022 11:01:27 +0200 Subject: [PATCH 12/28] Add challenger state --- evm/src/get_challenges.rs | 39 +++++++- evm/src/proof.rs | 6 ++ evm/src/prover.rs | 2 + evm/src/recursive_verifier.rs | 143 ++++++++++++++++++--------- plonky2/src/iop/challenger.rs | 37 ++++++- plonky2/src/plonk/circuit_builder.rs | 7 ++ plonky2/src/util/serialization.rs | 2 +- 7 files changed, 186 insertions(+), 50 deletions(-) diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index 6545a1af..9a9613f3 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -5,7 +5,7 @@ use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use crate::all_stark::AllStark; +use crate::all_stark::{AllStark, NUM_TABLES}; use crate::config::StarkConfig; use crate::permutation::{ get_grand_product_challenge_set, get_grand_product_challenge_set_target, @@ -46,6 +46,43 @@ impl, C: GenericConfig, const D: usize> A ctl_challenges, } } + pub(crate) fn get_challenger_states( + &self, + all_stark: &AllStark, + config: &StarkConfig, + ) -> AllChallengerState { + let mut challenger = Challenger::::new(); + + for proof in &self.stark_proofs { + challenger.observe_cap(&proof.trace_cap); + } + + // TODO: Observe public values. + + let ctl_challenges = + get_grand_product_challenge_set(&mut challenger, config.num_challenges); + + let num_permutation_zs = all_stark.nums_permutation_zs(config); + let num_permutation_batch_sizes = all_stark.permutation_batch_sizes(); + + challenger.duplexing(); + let mut challenger_states = vec![challenger.state()]; + for i in 0..NUM_TABLES { + self.stark_proofs[i].get_challenges( + &mut challenger, + num_permutation_zs[i] > 0, + num_permutation_batch_sizes[i], + config, + ); + challenger.duplexing(); + challenger_states.push(challenger.state()); + } + + AllChallengerState { + states: challenger_states.try_into().unwrap(), + ctl_challenges, + } + } } impl AllProofTarget { diff --git a/evm/src/proof.rs b/evm/src/proof.rs index 3c5e9968..577fbeb4 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -8,6 +8,7 @@ use plonky2::fri::structure::{ FriOpeningBatch, FriOpeningBatchTarget, FriOpenings, FriOpeningsTarget, }; use plonky2::hash::hash_types::{MerkleCapTarget, RichField}; +use plonky2::hash::hashing::SPONGE_WIDTH; use plonky2::hash::merkle_tree::MerkleCap; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; @@ -38,6 +39,11 @@ pub(crate) struct AllProofChallenges, const D: usiz pub ctl_challenges: GrandProductChallengeSet, } +pub(crate) struct AllChallengerState, const D: usize> { + pub states: [[F; SPONGE_WIDTH]; NUM_TABLES + 1], + pub ctl_challenges: GrandProductChallengeSet, +} + pub struct AllProofTarget { pub stark_proofs: [StarkProofTarget; NUM_TABLES], pub public_values: PublicValuesTarget, diff --git a/evm/src/prover.rs b/evm/src/prover.rs index 31e76a1c..eba0759f 100644 --- a/evm/src/prover.rs +++ b/evm/src/prover.rs @@ -201,6 +201,8 @@ where "FRI total reduction arity is too large.", ); + challenger.duplexing(); + // Permutation arguments. let permutation_challenges = stark.uses_permutation_args().then(|| { get_n_grand_product_challenge_sets( diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 0878b0e6..4f08a053 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -4,6 +4,8 @@ use plonky2::field::extension::Extendable; use plonky2::field::types::Field; use plonky2::fri::witness_util::set_fri_proof_target; use plonky2::hash::hash_types::RichField; +use plonky2::hash::hashing::SPONGE_WIDTH; +use plonky2::iop::challenger::RecursiveChallenger; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; use plonky2::iop::witness::{PartialWitness, Witness}; @@ -19,15 +21,19 @@ use crate::all_stark::{AllStark, Table, NUM_TABLES}; use crate::config::StarkConfig; use crate::constraint_consumer::RecursiveConstraintConsumer; use crate::cpu::cpu_stark::CpuStark; -use crate::cross_table_lookup::{verify_cross_table_lookups_circuit, CtlCheckVarsTarget}; +use crate::cross_table_lookup::{ + verify_cross_table_lookups_circuit, CrossTableLookup, CtlCheckVarsTarget, +}; use crate::keccak::keccak_stark::KeccakStark; use crate::keccak_memory::keccak_memory_stark::KeccakMemoryStark; use crate::logic::LogicStark; use crate::memory::memory_stark::MemoryStark; -use crate::permutation::PermutationCheckDataTarget; +use crate::permutation::{ + GrandProductChallenge, GrandProductChallengeSet, PermutationCheckDataTarget, +}; use crate::proof::{ - AllProof, AllProofChallengesTarget, AllProofTarget, BlockMetadata, BlockMetadataTarget, - PublicValues, PublicValuesTarget, StarkOpeningSetTarget, StarkProof, + AllChallengerState, AllProof, AllProofChallengesTarget, AllProofTarget, BlockMetadata, + BlockMetadataTarget, PublicValues, PublicValuesTarget, StarkOpeningSetTarget, StarkProof, StarkProofChallengesTarget, StarkProofTarget, TrieRoots, TrieRootsTarget, }; use crate::stark::Stark; @@ -93,8 +99,10 @@ fn recursively_verify_stark_proof< >( table: Table, stark: S, - all_stark: &AllStark, - all_proof: &AllProof, + proof: &StarkProof, + cross_table_lookups: &[CrossTableLookup], + ctl_challenges: &GrandProductChallengeSet, + challenger_state_before: [F; SPONGE_WIDTH], inner_config: &StarkConfig, circuit_config: &CircuitConfig, ) -> Result<(ProofWithPublicInputs, VerifierCircuitData)> @@ -106,36 +114,63 @@ where let mut builder = CircuitBuilder::::new(circuit_config.clone()); let mut pw = PartialWitness::new(); - let nums_ctl_zs = all_proof.nums_ctl_zs(); - let degree_bits = all_proof.degree_bits(inner_config); let num_permutation_zs = stark.num_permutation_batches(inner_config); - let all_proof_target = add_virtual_all_proof( + let num_permutation_batch_size = stark.permutation_batch_size(); + let proof_target = add_virtual_stark_proof( &mut builder, - all_stark, + &stark, inner_config, - °ree_bits, - &nums_ctl_zs, + proof.recover_degree_bits(inner_config), + proof.num_ctl_zs(), ); - set_all_proof_target(&mut pw, &all_proof_target, all_proof, builder.zero()); + set_stark_proof_target(&mut pw, &proof_target, proof, builder.zero()); - let AllProofChallengesTarget { - stark_challenges, - ctl_challenges, - } = all_proof_target.get_challenges::(&mut builder, all_stark, inner_config); + let ctl_challenges_target = GrandProductChallengeSet { + challenges: (0..inner_config.num_challenges) + .map(|_| GrandProductChallenge { + beta: builder.add_virtual_public_input(), + gamma: builder.add_virtual_public_input(), + }) + .collect(), + }; + for i in 0..inner_config.num_challenges { + pw.set_target( + ctl_challenges_target.challenges[i].beta, + ctl_challenges.challenges[i].beta, + ); + pw.set_target( + ctl_challenges_target.challenges[i].gamma, + ctl_challenges.challenges[i].gamma, + ); + } let ctl_vars = CtlCheckVarsTarget::from_proof( table, - &all_proof_target.stark_proofs[table as usize], - &all_stark.cross_table_lookups, - &ctl_challenges, + &proof_target, + cross_table_lookups, + &ctl_challenges_target, num_permutation_zs, ); + let challenger_state = std::array::from_fn(|_| builder.add_virtual_public_input()); + pw.set_target_arr(challenger_state, challenger_state_before); + let mut challenger = RecursiveChallenger::::from_state(challenger_state); + let challenges = proof_target.get_challenges::( + &mut builder, + &mut challenger, + num_permutation_zs > 0, + num_permutation_batch_size, + inner_config, + ); + challenger.duplexing(&mut builder); + let challenger_state = challenger.state(); + builder.register_public_inputs(&challenger_state); + verify_stark_proof_with_challenges_circuit::( &mut builder, - stark, - &all_proof_target.stark_proofs[table as usize], - &stark_challenges[table as usize], + &stark, + &proof_target, + &challenges, &ctl_vars, inner_config, ); @@ -164,45 +199,59 @@ where [(); C::Hasher::HASH_SIZE]:, C::Hasher: AlgebraicHasher, { + let AllChallengerState { + states, + ctl_challenges, + } = all_proof.get_challenger_states(all_stark, inner_config); Ok(RecursiveAllProof { recursive_proofs: [ recursively_verify_stark_proof( Table::Cpu, all_stark.cpu_stark, - all_stark, - all_proof, + &all_proof.stark_proofs[Table::Cpu as usize], + &all_stark.cross_table_lookups, + &ctl_challenges, + states[0], inner_config, &circuit_config, )?, recursively_verify_stark_proof( Table::Keccak, all_stark.keccak_stark, - all_stark, - all_proof, + &all_proof.stark_proofs[Table::Keccak as usize], + &all_stark.cross_table_lookups, + &ctl_challenges, + states[1], inner_config, &circuit_config, )?, recursively_verify_stark_proof( Table::KeccakMemory, all_stark.keccak_memory_stark, - all_stark, - all_proof, + &all_proof.stark_proofs[Table::KeccakMemory as usize], + &all_stark.cross_table_lookups, + &ctl_challenges, + states[2], inner_config, &circuit_config, )?, recursively_verify_stark_proof( Table::Logic, all_stark.logic_stark, - all_stark, - all_proof, + &all_proof.stark_proofs[Table::Logic as usize], + &all_stark.cross_table_lookups, + &ctl_challenges, + states[3], inner_config, &circuit_config, )?, recursively_verify_stark_proof( Table::Memory, all_stark.memory_stark, - all_stark, - all_proof, + &all_proof.stark_proofs[Table::Memory as usize], + &all_stark.cross_table_lookups, + &ctl_challenges, + states[4], inner_config, &circuit_config, )?, @@ -255,7 +304,7 @@ pub fn verify_proof_circuit< "verify CPU proof", verify_stark_proof_with_challenges_circuit::( builder, - cpu_stark, + &cpu_stark, &all_proof.stark_proofs[Table::Cpu as usize], &stark_challenges[Table::Cpu as usize], &ctl_vars_per_table[Table::Cpu as usize], @@ -267,7 +316,7 @@ pub fn verify_proof_circuit< "verify Keccak proof", verify_stark_proof_with_challenges_circuit::( builder, - keccak_stark, + &keccak_stark, &all_proof.stark_proofs[Table::Keccak as usize], &stark_challenges[Table::Keccak as usize], &ctl_vars_per_table[Table::Keccak as usize], @@ -279,7 +328,7 @@ pub fn verify_proof_circuit< "verify Keccak memory proof", verify_stark_proof_with_challenges_circuit::( builder, - keccak_memory_stark, + &keccak_memory_stark, &all_proof.stark_proofs[Table::KeccakMemory as usize], &stark_challenges[Table::KeccakMemory as usize], &ctl_vars_per_table[Table::KeccakMemory as usize], @@ -291,7 +340,7 @@ pub fn verify_proof_circuit< "verify logic proof", verify_stark_proof_with_challenges_circuit::( builder, - logic_stark, + &logic_stark, &all_proof.stark_proofs[Table::Logic as usize], &stark_challenges[Table::Logic as usize], &ctl_vars_per_table[Table::Logic as usize], @@ -303,7 +352,7 @@ pub fn verify_proof_circuit< "verify memory proof", verify_stark_proof_with_challenges_circuit::( builder, - memory_stark, + &memory_stark, &all_proof.stark_proofs[Table::Memory as usize], &stark_challenges[Table::Memory as usize], &ctl_vars_per_table[Table::Memory as usize], @@ -332,7 +381,7 @@ fn verify_stark_proof_with_challenges_circuit< const D: usize, >( builder: &mut CircuitBuilder, - stark: S, + stark: &S, proof: &StarkProofTarget, challenges: &StarkProofChallengesTarget, ctl_vars: &[CtlCheckVarsTarget], @@ -388,7 +437,7 @@ fn verify_stark_proof_with_challenges_circuit< "evaluate vanishing polynomial", eval_vanishing_poly_circuit::( builder, - &stark, + stark, inner_config, vars, permutation_data, @@ -462,35 +511,35 @@ pub fn add_virtual_all_proof, const D: usize>( let stark_proofs = [ add_virtual_stark_proof( builder, - all_stark.cpu_stark, + &all_stark.cpu_stark, config, degree_bits[Table::Cpu as usize], nums_ctl_zs[Table::Cpu as usize], ), add_virtual_stark_proof( builder, - all_stark.keccak_stark, + &all_stark.keccak_stark, config, degree_bits[Table::Keccak as usize], nums_ctl_zs[Table::Keccak as usize], ), add_virtual_stark_proof( builder, - all_stark.keccak_memory_stark, + &all_stark.keccak_memory_stark, config, degree_bits[Table::KeccakMemory as usize], nums_ctl_zs[Table::KeccakMemory as usize], ), add_virtual_stark_proof( builder, - all_stark.logic_stark, + &all_stark.logic_stark, config, degree_bits[Table::Logic as usize], nums_ctl_zs[Table::Logic as usize], ), add_virtual_stark_proof( builder, - all_stark.memory_stark, + &all_stark.memory_stark, config, degree_bits[Table::Memory as usize], nums_ctl_zs[Table::Memory as usize], @@ -553,7 +602,7 @@ pub fn add_virtual_block_metadata, const D: usize>( pub fn add_virtual_stark_proof, S: Stark, const D: usize>( builder: &mut CircuitBuilder, - stark: S, + stark: &S, config: &StarkConfig, degree_bits: usize, num_ctl_zs: usize, @@ -580,7 +629,7 @@ pub fn add_virtual_stark_proof, S: Stark, con fn add_stark_opening_set, S: Stark, const D: usize>( builder: &mut CircuitBuilder, - stark: S, + stark: &S, num_ctl_zs: usize, config: &StarkConfig, ) -> StarkOpeningSetTarget { diff --git a/plonky2/src/iop/challenger.rs b/plonky2/src/iop/challenger.rs index 97d21197..4e83b1c6 100644 --- a/plonky2/src/iop/challenger.rs +++ b/plonky2/src/iop/challenger.rs @@ -129,7 +129,7 @@ impl> Challenger { /// Absorb any buffered inputs. After calling this, the input buffer will be empty, and the /// output buffer will be full. - fn duplexing(&mut self) { + pub fn duplexing(&mut self) { assert!(self.input_buffer.len() <= SPONGE_RATE); // Overwrite the first r elements with the inputs. This differs from a standard sponge, @@ -146,6 +146,10 @@ impl> Challenger { self.output_buffer .extend_from_slice(&self.sponge_state[0..SPONGE_RATE]); } + + pub fn state(&self) -> [F; SPONGE_WIDTH] { + self.sponge_state + } } impl> Default for Challenger { @@ -176,6 +180,15 @@ impl, H: AlgebraicHasher, const D: usize> } } + pub fn from_state(sponge_state: [Target; SPONGE_WIDTH]) -> Self { + let output_buffer = sponge_state[0..SPONGE_RATE].to_vec(); + RecursiveChallenger { + sponge_state, + input_buffer: vec![], + output_buffer, + } + } + pub(crate) fn observe_element(&mut self, target: Target) { // Any buffered outputs are now invalid, since they wouldn't reflect this input. self.output_buffer.clear(); @@ -272,6 +285,28 @@ impl, H: AlgebraicHasher, const D: usize> self.input_buffer.clear(); } + + pub fn duplexing(&mut self, builder: &mut CircuitBuilder) { + for input_chunk in self.input_buffer.chunks(SPONGE_RATE) { + // Overwrite the first r elements with the inputs. This differs from a standard sponge, + // where we would xor or add in the inputs. This is a well-known variant, though, + // sometimes called "overwrite mode". + for (i, &input) in input_chunk.iter().enumerate() { + self.sponge_state[i] = input; + } + + // Apply the permutation. + self.sponge_state = builder.permute::(self.sponge_state); + } + + self.output_buffer = self.sponge_state[0..SPONGE_RATE].to_vec(); + + self.input_buffer.clear(); + } + + pub fn state(&self) -> [Target; SPONGE_WIDTH] { + self.sponge_state + } } #[cfg(test)] diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index e4e3e997..7be27c0a 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -208,6 +208,13 @@ impl, const D: usize> CircuitBuilder { b } + /// Add a virtual target and register it as a public input. + pub fn add_virtual_public_input(&mut self) -> Target { + let t = self.add_virtual_target(); + self.register_public_input(t); + t + } + /// Adds a gate to the circuit, and returns its index. pub fn add_gate>(&mut self, gate_type: G, mut constants: Vec) -> usize { self.check_gate_compatibility(&gate_type); diff --git a/plonky2/src/util/serialization.rs b/plonky2/src/util/serialization.rs index da03213c..978134b6 100644 --- a/plonky2/src/util/serialization.rs +++ b/plonky2/src/util/serialization.rs @@ -282,7 +282,7 @@ impl Buffer { arity: usize, compressed: bool, ) -> Result> { - let evals = self.read_field_ext_vec::(arity - if compressed { 1 } else { 0 })?; + let evals = self.read_field_ext_vec::(arity - usize::from(compressed))?; let merkle_proof = self.read_merkle_proof()?; Ok(FriQueryStep { evals, From 2c43da801e9d9012d5a3464e08607b4403c6433f Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 22 Sep 2022 11:17:02 +0200 Subject: [PATCH 13/28] Fix --- evm/src/get_challenges.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index 9a9613f3..8b254ee4 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -36,6 +36,7 @@ impl, C: GenericConfig, const D: usize> A AllProofChallenges { stark_challenges: std::array::from_fn(|i| { + challenger.duplexing(); self.stark_proofs[i].get_challenges( &mut challenger, num_permutation_zs[i] > 0, From e712986a9227e01dd8699cb62d487faf960319ba Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Sep 2022 13:41:14 +0200 Subject: [PATCH 14/28] Challenger state works --- evm/src/all_stark.rs | 13 ++--- evm/src/get_challenges.rs | 1 + evm/src/permutation.rs | 14 ++--- evm/src/recursive_verifier.rs | 98 ++++++++++++++++++++++++++++++++-- plonky2/src/hash/hash_types.rs | 10 ++++ plonky2/src/iop/challenger.rs | 22 ++++---- plonky2/src/plonk/config.rs | 1 + 7 files changed, 133 insertions(+), 26 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 68b65d41..fd9ce01f 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -755,12 +755,13 @@ mod tests { let circuit_config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(circuit_config); - let mut pw = PartialWitness::new(); - recursive_all_proof.verify_circuit(&mut builder, &mut pw); - - let data = builder.build::(); - let proof = data.prove(pw)?; - data.verify(proof) + // let mut pw = PartialWitness::new(); + recursive_all_proof.verify(inner_config) + // recursive_all_proof.verify_circuit(&mut builder, &mut pw); + // + // let data = builder.build::(); + // let proof = data.prove(pw)?; + // data.verify(proof) } fn init_logger() { diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index 8b254ee4..e39e3e23 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -229,6 +229,7 @@ impl StarkProofTarget { challenger.observe_cap(quotient_polys_cap); let stark_zeta = challenger.get_extension_challenge(builder); + dbg!(stark_zeta); challenger.observe_openings(&openings.to_fri_openings(builder.zero())); diff --git a/evm/src/permutation.rs b/evm/src/permutation.rs index 0bb8ab1d..b081c309 100644 --- a/evm/src/permutation.rs +++ b/evm/src/permutation.rs @@ -1,5 +1,7 @@ //! Permutation arguments. +use std::fmt::Debug; + use itertools::Itertools; use maybe_rayon::*; use plonky2::field::batch_util::batch_multiply_inplace; @@ -42,14 +44,14 @@ impl PermutationPair { } /// A single instance of a permutation check protocol. -pub(crate) struct PermutationInstance<'a, T: Copy> { +pub(crate) struct PermutationInstance<'a, T: Copy + Eq + PartialEq + Debug> { pub(crate) pair: &'a PermutationPair, pub(crate) challenge: GrandProductChallenge, } /// Randomness for a single instance of a permutation check protocol. -#[derive(Copy, Clone)] -pub(crate) struct GrandProductChallenge { +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub(crate) struct GrandProductChallenge { /// Randomness used to combine multiple columns into one. pub(crate) beta: T, /// Random offset that's added to the beta-reduced column values. @@ -92,8 +94,8 @@ impl GrandProductChallenge { } /// Like `PermutationChallenge`, but with `num_challenges` copies to boost soundness. -#[derive(Clone)] -pub(crate) struct GrandProductChallengeSet { +#[derive(Clone, Eq, PartialEq, Debug)] +pub(crate) struct GrandProductChallengeSet { pub(crate) challenges: Vec>, } @@ -261,7 +263,7 @@ pub(crate) fn get_n_grand_product_challenge_sets_target< /// Before batching, each permutation pair leads to `num_challenges` permutation arguments, so we /// start with the cartesian product of `permutation_pairs` and `0..num_challenges`. Then we /// chunk these arguments based on our batch size. -pub(crate) fn get_permutation_batches<'a, T: Copy>( +pub(crate) fn get_permutation_batches<'a, T: Copy + Eq + PartialEq + Debug>( permutation_pairs: &'a [PermutationPair], permutation_challenge_sets: &[GrandProductChallengeSet], num_challenges: usize, diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 4f08a053..fca634a7 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -1,16 +1,19 @@ -use anyhow::Result; +use anyhow::{ensure, Result}; use itertools::Itertools; use plonky2::field::extension::Extendable; use plonky2::field::types::Field; use plonky2::fri::witness_util::set_fri_proof_target; -use plonky2::hash::hash_types::RichField; +use plonky2::hash::hash_types::{HashOut, RichField}; use plonky2::hash::hashing::SPONGE_WIDTH; -use plonky2::iop::challenger::RecursiveChallenger; +use plonky2::hash::merkle_tree::MerkleCap; +use plonky2::hash::poseidon::PoseidonHash; +use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; use plonky2::iop::witness::{PartialWitness, Witness}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData, VerifierCircuitTarget}; +use plonky2::plonk::config::GenericHashOut; use plonky2::plonk::config::Hasher; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::plonk::proof::ProofWithPublicInputs; @@ -29,7 +32,8 @@ use crate::keccak_memory::keccak_memory_stark::KeccakMemoryStark; use crate::logic::LogicStark; use crate::memory::memory_stark::MemoryStark; use crate::permutation::{ - GrandProductChallenge, GrandProductChallengeSet, PermutationCheckDataTarget, + get_grand_product_challenge_set, GrandProductChallenge, GrandProductChallengeSet, + PermutationCheckDataTarget, }; use crate::proof::{ AllChallengerState, AllProof, AllProofChallengesTarget, AllProofTarget, BlockMetadata, @@ -52,14 +56,88 @@ pub struct RecursiveAllProof< [(ProofWithPublicInputs, VerifierCircuitData); NUM_TABLES], } +struct PublicInputs, C: GenericConfig, const D: usize> { + trace_cap: MerkleCap, + ctl_zs_last: Vec, + ctl_challenges: GrandProductChallengeSet, + challenger_state_before: [F; SPONGE_WIDTH], + challenger_state_after: [F; SPONGE_WIDTH], +} + +impl, C: GenericConfig, const D: usize> + PublicInputs +{ + fn from_vec(v: &[F], config: &StarkConfig) -> Self { + let mut start = 0; + let trace_cap = MerkleCap( + v[start..4 * (1 << config.fri_config.cap_height)] + .chunks(4) + .map(|chunk| >::Hash::from_vec(chunk)) + .collect(), + ); + start += 4 * (1 << config.fri_config.cap_height); + let ctl_challenges = GrandProductChallengeSet { + challenges: (0..config.num_challenges) + .map(|i| GrandProductChallenge { + beta: v[start + 2 * i], + gamma: v[start + 2 * i + 1], + }) + .collect(), + }; + start += 2 * config.num_challenges; + let challenger_state_before = v[start..start + SPONGE_WIDTH].try_into().unwrap(); + let challenger_state_after = v[start + SPONGE_WIDTH..start + 2 * SPONGE_WIDTH] + .try_into() + .unwrap(); + + start += 2 * SPONGE_WIDTH; + let ctl_zs_last = v[start..].to_vec(); + + Self { + trace_cap, + ctl_zs_last, + ctl_challenges, + challenger_state_before, + challenger_state_after, + } + } +} + impl, C: GenericConfig, const D: usize> RecursiveAllProof { /// Verify every recursive proof. - pub fn verify(self) -> Result<()> + pub fn verify(self, inner_config: &StarkConfig) -> Result<()> where [(); C::Hasher::HASH_SIZE]:, { + let pis: [_; NUM_TABLES] = std::array::from_fn(|i| { + PublicInputs::::from_vec( + &self.recursive_proofs[i].0.public_inputs, + inner_config, + ) + }); + + let mut challenger = Challenger::::new(); + for pi in &pis { + challenger.observe_cap(&pi.trace_cap); + } + let ctl_challenges = + get_grand_product_challenge_set(&mut challenger, inner_config.num_challenges); + for pi in &pis { + ensure!(ctl_challenges == pi.ctl_challenges); + } + challenger.duplexing(); + let state = challenger.state(); + ensure!(state == pis[0].challenger_state_before); + for i in 1..NUM_TABLES { + dbg!(i); + dbg!( + pis[i].challenger_state_before, + pis[i - 1].challenger_state_after + ); + ensure!(pis[i].challenger_state_before == pis[i - 1].challenger_state_after); + } for (proof, verifier_data) in self.recursive_proofs { verifier_data.verify(proof)?; } @@ -124,6 +202,14 @@ where proof.num_ctl_zs(), ); set_stark_proof_target(&mut pw, &proof_target, proof, builder.zero()); + builder.register_public_inputs( + &proof_target + .trace_cap + .0 + .iter() + .flat_map(|h| h.elements) + .collect::>(), + ); let ctl_challenges_target = GrandProductChallengeSet { challenges: (0..inner_config.num_challenges) @@ -166,6 +252,8 @@ where let challenger_state = challenger.state(); builder.register_public_inputs(&challenger_state); + builder.register_public_inputs(&proof_target.openings.ctl_zs_last); + verify_stark_proof_with_challenges_circuit::( &mut builder, &stark, diff --git a/plonky2/src/hash/hash_types.rs b/plonky2/src/hash/hash_types.rs index 14303ad3..955f539a 100644 --- a/plonky2/src/hash/hash_types.rs +++ b/plonky2/src/hash/hash_types.rs @@ -78,6 +78,12 @@ impl GenericHashOut for HashOut { fn to_vec(&self) -> Vec { self.elements.to_vec() } + + fn from_vec(v: &[F]) -> Self { + Self { + elements: v.try_into().unwrap(), + } + } } impl Default for HashOut { @@ -148,6 +154,10 @@ impl GenericHashOut for BytesHash { }) .collect() } + + fn from_vec(_v: &[F]) -> Self { + todo!() + } } impl Serialize for BytesHash { diff --git a/plonky2/src/iop/challenger.rs b/plonky2/src/iop/challenger.rs index 4e83b1c6..1a9e3f13 100644 --- a/plonky2/src/iop/challenger.rs +++ b/plonky2/src/iop/challenger.rs @@ -287,16 +287,20 @@ impl, H: AlgebraicHasher, const D: usize> } pub fn duplexing(&mut self, builder: &mut CircuitBuilder) { - for input_chunk in self.input_buffer.chunks(SPONGE_RATE) { - // Overwrite the first r elements with the inputs. This differs from a standard sponge, - // where we would xor or add in the inputs. This is a well-known variant, though, - // sometimes called "overwrite mode". - for (i, &input) in input_chunk.iter().enumerate() { - self.sponge_state[i] = input; - } - - // Apply the permutation. + if self.input_buffer.is_empty() { self.sponge_state = builder.permute::(self.sponge_state); + } else { + for input_chunk in self.input_buffer.chunks(SPONGE_RATE) { + // Overwrite the first r elements with the inputs. This differs from a standard sponge, + // where we would xor or add in the inputs. This is a well-known variant, though, + // sometimes called "overwrite mode". + for (i, &input) in input_chunk.iter().enumerate() { + self.sponge_state[i] = input; + } + + // Apply the permutation. + self.sponge_state = builder.permute::(self.sponge_state); + } } self.output_buffer = self.sponge_state[0..SPONGE_RATE].to_vec(); diff --git a/plonky2/src/plonk/config.rs b/plonky2/src/plonk/config.rs index f55bad1f..51dacdde 100644 --- a/plonky2/src/plonk/config.rs +++ b/plonky2/src/plonk/config.rs @@ -20,6 +20,7 @@ pub trait GenericHashOut: fn from_bytes(bytes: &[u8]) -> Self; fn to_vec(&self) -> Vec; + fn from_vec(v: &[F]) -> Self; } /// Trait for hash functions. From a63ed60401a5cff094b17cf00d87c2eeeb581143 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Sep 2022 15:50:57 +0200 Subject: [PATCH 15/28] Add CTL verification --- evm/src/cross_table_lookup.rs | 12 +++--------- evm/src/get_challenges.rs | 1 - evm/src/recursive_verifier.rs | 18 ++++++++++++------ evm/src/verifier.rs | 7 +++++-- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 602ff6c5..118b7f09 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -621,18 +621,12 @@ pub(crate) fn verify_cross_table_lookups< const D: usize, >( cross_table_lookups: Vec>, - proofs: &[StarkProof; NUM_TABLES], + ctl_zs_lasts: [Vec; NUM_TABLES], + degrees_bits: [usize; NUM_TABLES], challenges: GrandProductChallengeSet, config: &StarkConfig, ) -> Result<()> { - let degrees_bits = proofs - .iter() - .map(|p| p.recover_degree_bits(config)) - .collect::>(); - let mut ctl_zs_openings = proofs - .iter() - .map(|p| p.openings.ctl_zs_last.iter()) - .collect::>(); + let mut ctl_zs_openings = ctl_zs_lasts.iter().map(|v| v.iter()).collect::>(); for ( i, CrossTableLookup { diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index e39e3e23..8b254ee4 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -229,7 +229,6 @@ impl StarkProofTarget { challenger.observe_cap(quotient_polys_cap); let stark_zeta = challenger.get_extension_challenge(builder); - dbg!(stark_zeta); challenger.observe_openings(&openings.to_fri_openings(builder.zero())); diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index fca634a7..394d4f33 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -25,7 +25,8 @@ use crate::config::StarkConfig; use crate::constraint_consumer::RecursiveConstraintConsumer; use crate::cpu::cpu_stark::CpuStark; use crate::cross_table_lookup::{ - verify_cross_table_lookups_circuit, CrossTableLookup, CtlCheckVarsTarget, + verify_cross_table_lookups, verify_cross_table_lookups_circuit, CrossTableLookup, + CtlCheckVarsTarget, }; use crate::keccak::keccak_stark::KeccakStark; use crate::keccak_memory::keccak_memory_stark::KeccakMemoryStark; @@ -54,6 +55,7 @@ pub struct RecursiveAllProof< > { pub recursive_proofs: [(ProofWithPublicInputs, VerifierCircuitData); NUM_TABLES], + pub cross_table_lookups: Vec>, } struct PublicInputs, C: GenericConfig, const D: usize> { @@ -131,13 +133,16 @@ impl, C: GenericConfig, const D: usize> let state = challenger.state(); ensure!(state == pis[0].challenger_state_before); for i in 1..NUM_TABLES { - dbg!(i); - dbg!( - pis[i].challenger_state_before, - pis[i - 1].challenger_state_after - ); ensure!(pis[i].challenger_state_before == pis[i - 1].challenger_state_after); } + let degrees_bits = std::array::from_fn(|i| self.recursive_proofs[i].1.common.degree_bits); + verify_cross_table_lookups::( + self.cross_table_lookups, + pis.map(|p| p.ctl_zs_last), + degrees_bits, + ctl_challenges, + inner_config, + )?; for (proof, verifier_data) in self.recursive_proofs { verifier_data.verify(proof)?; } @@ -344,6 +349,7 @@ where &circuit_config, )?, ], + cross_table_lookups: all_stark.cross_table_lookups.clone(), }) } diff --git a/evm/src/verifier.rs b/evm/src/verifier.rs index 9b56422d..bcf483e4 100644 --- a/evm/src/verifier.rs +++ b/evm/src/verifier.rs @@ -95,9 +95,12 @@ where config, )?; - verify_cross_table_lookups( + let degrees_bits = + std::array::from_fn(|i| all_proof.stark_proofs[i].recover_degree_bits(config)); + verify_cross_table_lookups::( cross_table_lookups, - &all_proof.stark_proofs, + all_proof.stark_proofs.map(|p| p.openings.ctl_zs_last), + degrees_bits, ctl_challenges, config, ) From 502305146f2513714e08fa6a03312716b5990e22 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Sep 2022 16:25:02 +0200 Subject: [PATCH 16/28] Working --- evm/src/all_stark.rs | 14 +- evm/src/cross_table_lookup.rs | 12 +- evm/src/recursive_verifier.rs | 352 ++++++++++++++++++++-------------- plonky2/src/iop/challenger.rs | 2 +- 4 files changed, 223 insertions(+), 157 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index fd9ce01f..e4f93c62 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -172,6 +172,7 @@ mod tests { use anyhow::Result; use ethereum_types::U256; use itertools::Itertools; + use log::debug; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::{Field, PrimeField64}; use plonky2::iop::witness::PartialWitness; @@ -755,13 +756,12 @@ mod tests { let circuit_config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(circuit_config); - // let mut pw = PartialWitness::new(); - recursive_all_proof.verify(inner_config) - // recursive_all_proof.verify_circuit(&mut builder, &mut pw); - // - // let data = builder.build::(); - // let proof = data.prove(pw)?; - // data.verify(proof) + let mut pw = PartialWitness::new(); + recursive_all_proof.verify_circuit(&mut builder, &mut pw, inner_config); + + let data = builder.build::(); + let proof = data.prove(pw)?; + data.verify(proof) } fn init_logger() { diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 118b7f09..24b8059c 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -673,18 +673,12 @@ pub(crate) fn verify_cross_table_lookups_circuit< >( builder: &mut CircuitBuilder, cross_table_lookups: Vec>, - proofs: &[StarkProofTarget; NUM_TABLES], + ctl_zs_lasts: [Vec; NUM_TABLES], + degrees_bits: [usize; NUM_TABLES], challenges: GrandProductChallengeSet, inner_config: &StarkConfig, ) { - let degrees_bits = proofs - .iter() - .map(|p| p.recover_degree_bits(inner_config)) - .collect::>(); - let mut ctl_zs_openings = proofs - .iter() - .map(|p| p.openings.ctl_zs_last.iter()) - .collect::>(); + let mut ctl_zs_openings = ctl_zs_lasts.iter().map(|v| v.iter()).collect::>(); for ( i, CrossTableLookup { diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 394d4f33..95d8cd80 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -1,3 +1,5 @@ +use std::fmt::Debug; + use anyhow::{ensure, Result}; use itertools::Itertools; use plonky2::field::extension::Extendable; @@ -33,8 +35,8 @@ use crate::keccak_memory::keccak_memory_stark::KeccakMemoryStark; use crate::logic::LogicStark; use crate::memory::memory_stark::MemoryStark; use crate::permutation::{ - get_grand_product_challenge_set, GrandProductChallenge, GrandProductChallengeSet, - PermutationCheckDataTarget, + get_grand_product_challenge_set, get_grand_product_challenge_set_target, GrandProductChallenge, + GrandProductChallengeSet, PermutationCheckDataTarget, }; use crate::proof::{ AllChallengerState, AllProof, AllProofChallengesTarget, AllProofTarget, BlockMetadata, @@ -58,25 +60,21 @@ pub struct RecursiveAllProof< pub cross_table_lookups: Vec>, } -struct PublicInputs, C: GenericConfig, const D: usize> { - trace_cap: MerkleCap, - ctl_zs_last: Vec, - ctl_challenges: GrandProductChallengeSet, - challenger_state_before: [F; SPONGE_WIDTH], - challenger_state_after: [F; SPONGE_WIDTH], +struct PublicInputs { + trace_cap: Vec>, + ctl_zs_last: Vec, + ctl_challenges: GrandProductChallengeSet, + challenger_state_before: [T; SPONGE_WIDTH], + challenger_state_after: [T; SPONGE_WIDTH], } -impl, C: GenericConfig, const D: usize> - PublicInputs -{ - fn from_vec(v: &[F], config: &StarkConfig) -> Self { +impl PublicInputs { + fn from_vec(v: &[T], config: &StarkConfig) -> Self { let mut start = 0; - let trace_cap = MerkleCap( - v[start..4 * (1 << config.fri_config.cap_height)] - .chunks(4) - .map(|chunk| >::Hash::from_vec(chunk)) - .collect(), - ); + let trace_cap = v[start..4 * (1 << config.fri_config.cap_height)] + .chunks(4) + .map(|chunk| chunk.to_vec()) + .collect(); start += 4 * (1 << config.fri_config.cap_height); let ctl_challenges = GrandProductChallengeSet { challenges: (0..config.num_challenges) @@ -114,27 +112,31 @@ impl, C: GenericConfig, const D: usize> [(); C::Hasher::HASH_SIZE]:, { let pis: [_; NUM_TABLES] = std::array::from_fn(|i| { - PublicInputs::::from_vec( - &self.recursive_proofs[i].0.public_inputs, - inner_config, - ) + PublicInputs::from_vec(&self.recursive_proofs[i].0.public_inputs, inner_config) }); let mut challenger = Challenger::::new(); for pi in &pis { - challenger.observe_cap(&pi.trace_cap); + for h in &pi.trace_cap { + challenger.observe_elements(h); + } } let ctl_challenges = get_grand_product_challenge_set(&mut challenger, inner_config.num_challenges); + // Check that the correct CTL challenges are used in every proof. for pi in &pis { ensure!(ctl_challenges == pi.ctl_challenges); } + challenger.duplexing(); let state = challenger.state(); ensure!(state == pis[0].challenger_state_before); + // Check that the challenger state is consistent between proofs. for i in 1..NUM_TABLES { ensure!(pis[i].challenger_state_before == pis[i - 1].challenger_state_after); } + + // Verify the CTL checks. let degrees_bits = std::array::from_fn(|i| self.recursive_proofs[i].1.common.degree_bits); verify_cross_table_lookups::( self.cross_table_lookups, @@ -143,6 +145,8 @@ impl, C: GenericConfig, const D: usize> ctl_challenges, inner_config, )?; + + // Verify the proofs. for (proof, verifier_data) in self.recursive_proofs { verifier_data.verify(proof)?; } @@ -150,13 +154,19 @@ impl, C: GenericConfig, const D: usize> } /// Recursively verify every recursive proof. - pub fn verify_circuit(&self, builder: &mut CircuitBuilder, pw: &mut W) - where + pub fn verify_circuit( + self, + builder: &mut CircuitBuilder, + pw: &mut W, + inner_config: &StarkConfig, + ) where W: Witness, [(); C::Hasher::HASH_SIZE]:, >::Hasher: AlgebraicHasher, { - for (proof, verifier_data) in &self.recursive_proofs { + let proofs_target: [_; NUM_TABLES] = std::array::from_fn(|i| { + let verifier_data = &self.recursive_proofs[i].1; + let proof = &self.recursive_proofs[i].0; let pt = builder.add_virtual_proof_with_pis(&verifier_data.common); pw.set_proof_with_pis_target(&pt, proof); let inner_data = VerifierCircuitTarget { @@ -167,7 +177,69 @@ impl, C: GenericConfig, const D: usize> &inner_data.constants_sigmas_cap, &verifier_data.verifier_only.constants_sigmas_cap, ); - builder.verify_proof(pt, &inner_data, &verifier_data.common); + (pt, inner_data) + }); + + let pis: [_; NUM_TABLES] = std::array::from_fn(|i| { + PublicInputs::from_vec(&proofs_target[i].0.public_inputs, inner_config) + }); + + let mut challenger = RecursiveChallenger::::new(builder); + for pi in &pis { + for h in &pi.trace_cap { + challenger.observe_elements(h); + } + } + let ctl_challenges = get_grand_product_challenge_set_target( + builder, + &mut challenger, + inner_config.num_challenges, + ); + // Check that the correct CTL challenges are used in every proof. + for pi in &pis { + for i in 0..inner_config.num_challenges { + builder.connect( + ctl_challenges.challenges[i].beta, + pi.ctl_challenges.challenges[i].beta, + ); + builder.connect( + ctl_challenges.challenges[i].gamma, + pi.ctl_challenges.challenges[i].gamma, + ); + } + } + + challenger.duplexing(builder); + let state = challenger.state(); + for k in 0..SPONGE_WIDTH { + builder.connect(state[k], pis[0].challenger_state_before[k]); + } + // Check that the challenger state is consistent between proofs. + for i in 1..NUM_TABLES { + for k in 0..SPONGE_WIDTH { + builder.connect( + pis[i].challenger_state_before[k], + pis[i - 1].challenger_state_after[k], + ); + } + } + + // Verify the CTL checks. + let degrees_bits = std::array::from_fn(|i| self.recursive_proofs[i].1.common.degree_bits); + verify_cross_table_lookups_circuit::( + builder, + self.cross_table_lookups, + pis.map(|p| p.ctl_zs_last), + degrees_bits, + ctl_challenges, + inner_config, + ); + for (i, (proof_target, inner_data)) in proofs_target.into_iter().enumerate() { + builder.verify_proof( + proof_target, + &inner_data, + &self.recursive_proofs[i].1.common, + ); } } } @@ -353,119 +425,119 @@ where }) } -pub fn verify_proof_circuit< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, ->( - builder: &mut CircuitBuilder, - all_stark: AllStark, - all_proof: AllProofTarget, - inner_config: &StarkConfig, -) where - [(); CpuStark::::COLUMNS]:, - [(); KeccakStark::::COLUMNS]:, - [(); KeccakMemoryStark::::COLUMNS]:, - [(); LogicStark::::COLUMNS]:, - [(); MemoryStark::::COLUMNS]:, - C::Hasher: AlgebraicHasher, -{ - let AllProofChallengesTarget { - stark_challenges, - ctl_challenges, - } = all_proof.get_challenges::(builder, &all_stark, inner_config); - - let nums_permutation_zs = all_stark.nums_permutation_zs(inner_config); - - let AllStark { - cpu_stark, - keccak_stark, - keccak_memory_stark, - logic_stark, - memory_stark, - cross_table_lookups, - } = all_stark; - - let ctl_vars_per_table = CtlCheckVarsTarget::from_proofs( - &all_proof.stark_proofs, - &cross_table_lookups, - &ctl_challenges, - &nums_permutation_zs, - ); - - with_context!( - builder, - "verify CPU proof", - verify_stark_proof_with_challenges_circuit::( - builder, - &cpu_stark, - &all_proof.stark_proofs[Table::Cpu as usize], - &stark_challenges[Table::Cpu as usize], - &ctl_vars_per_table[Table::Cpu as usize], - inner_config, - ) - ); - with_context!( - builder, - "verify Keccak proof", - verify_stark_proof_with_challenges_circuit::( - builder, - &keccak_stark, - &all_proof.stark_proofs[Table::Keccak as usize], - &stark_challenges[Table::Keccak as usize], - &ctl_vars_per_table[Table::Keccak as usize], - inner_config, - ) - ); - with_context!( - builder, - "verify Keccak memory proof", - verify_stark_proof_with_challenges_circuit::( - builder, - &keccak_memory_stark, - &all_proof.stark_proofs[Table::KeccakMemory as usize], - &stark_challenges[Table::KeccakMemory as usize], - &ctl_vars_per_table[Table::KeccakMemory as usize], - inner_config, - ) - ); - with_context!( - builder, - "verify logic proof", - verify_stark_proof_with_challenges_circuit::( - builder, - &logic_stark, - &all_proof.stark_proofs[Table::Logic as usize], - &stark_challenges[Table::Logic as usize], - &ctl_vars_per_table[Table::Logic as usize], - inner_config, - ) - ); - with_context!( - builder, - "verify memory proof", - verify_stark_proof_with_challenges_circuit::( - builder, - &memory_stark, - &all_proof.stark_proofs[Table::Memory as usize], - &stark_challenges[Table::Memory as usize], - &ctl_vars_per_table[Table::Memory as usize], - inner_config, - ) - ); - - with_context!( - builder, - "verify cross-table lookups", - verify_cross_table_lookups_circuit::( - builder, - cross_table_lookups, - &all_proof.stark_proofs, - ctl_challenges, - inner_config, - ) - ); -} +// pub fn verify_proof_circuit< +// F: RichField + Extendable, +// C: GenericConfig, +// const D: usize, +// >( +// builder: &mut CircuitBuilder, +// all_stark: AllStark, +// all_proof: AllProofTarget, +// inner_config: &StarkConfig, +// ) where +// [(); CpuStark::::COLUMNS]:, +// [(); KeccakStark::::COLUMNS]:, +// [(); KeccakMemoryStark::::COLUMNS]:, +// [(); LogicStark::::COLUMNS]:, +// [(); MemoryStark::::COLUMNS]:, +// C::Hasher: AlgebraicHasher, +// { +// let AllProofChallengesTarget { +// stark_challenges, +// ctl_challenges, +// } = all_proof.get_challenges::(builder, &all_stark, inner_config); +// +// let nums_permutation_zs = all_stark.nums_permutation_zs(inner_config); +// +// let AllStark { +// cpu_stark, +// keccak_stark, +// keccak_memory_stark, +// logic_stark, +// memory_stark, +// cross_table_lookups, +// } = all_stark; +// +// let ctl_vars_per_table = CtlCheckVarsTarget::from_proofs( +// &all_proof.stark_proofs, +// &cross_table_lookups, +// &ctl_challenges, +// &nums_permutation_zs, +// ); +// +// with_context!( +// builder, +// "verify CPU proof", +// verify_stark_proof_with_challenges_circuit::( +// builder, +// &cpu_stark, +// &all_proof.stark_proofs[Table::Cpu as usize], +// &stark_challenges[Table::Cpu as usize], +// &ctl_vars_per_table[Table::Cpu as usize], +// inner_config, +// ) +// ); +// with_context!( +// builder, +// "verify Keccak proof", +// verify_stark_proof_with_challenges_circuit::( +// builder, +// &keccak_stark, +// &all_proof.stark_proofs[Table::Keccak as usize], +// &stark_challenges[Table::Keccak as usize], +// &ctl_vars_per_table[Table::Keccak as usize], +// inner_config, +// ) +// ); +// with_context!( +// builder, +// "verify Keccak memory proof", +// verify_stark_proof_with_challenges_circuit::( +// builder, +// &keccak_memory_stark, +// &all_proof.stark_proofs[Table::KeccakMemory as usize], +// &stark_challenges[Table::KeccakMemory as usize], +// &ctl_vars_per_table[Table::KeccakMemory as usize], +// inner_config, +// ) +// ); +// with_context!( +// builder, +// "verify logic proof", +// verify_stark_proof_with_challenges_circuit::( +// builder, +// &logic_stark, +// &all_proof.stark_proofs[Table::Logic as usize], +// &stark_challenges[Table::Logic as usize], +// &ctl_vars_per_table[Table::Logic as usize], +// inner_config, +// ) +// ); +// with_context!( +// builder, +// "verify memory proof", +// verify_stark_proof_with_challenges_circuit::( +// builder, +// &memory_stark, +// &all_proof.stark_proofs[Table::Memory as usize], +// &stark_challenges[Table::Memory as usize], +// &ctl_vars_per_table[Table::Memory as usize], +// inner_config, +// ) +// ); +// +// with_context!( +// builder, +// "verify cross-table lookups", +// verify_cross_table_lookups_circuit::( +// builder, +// cross_table_lookups, +// &all_proof.stark_proofs, +// ctl_challenges, +// inner_config, +// ) +// ); +// } /// Recursively verifies an inner proof. fn verify_stark_proof_with_challenges_circuit< diff --git a/plonky2/src/iop/challenger.rs b/plonky2/src/iop/challenger.rs index 1a9e3f13..eeb18038 100644 --- a/plonky2/src/iop/challenger.rs +++ b/plonky2/src/iop/challenger.rs @@ -196,7 +196,7 @@ impl, H: AlgebraicHasher, const D: usize> self.input_buffer.push(target); } - pub(crate) fn observe_elements(&mut self, targets: &[Target]) { + pub fn observe_elements(&mut self, targets: &[Target]) { for &target in targets { self.observe_element(target); } From 0053a0211948e91728b9090e2047e3c8bd45bc37 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Sep 2022 16:28:20 +0200 Subject: [PATCH 17/28] Cleaning --- evm/src/all_stark.rs | 1 - evm/src/cross_table_lookup.rs | 49 ------------- evm/src/get_challenges.rs | 41 +---------- evm/src/proof.rs | 5 -- evm/src/recursive_verifier.rs | 125 ++-------------------------------- 5 files changed, 6 insertions(+), 215 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index e4f93c62..7d7b0932 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -172,7 +172,6 @@ mod tests { use anyhow::Result; use ethereum_types::U256; use itertools::Itertools; - use log::debug; use plonky2::field::polynomial::PolynomialValues; use plonky2::field::types::{Field, PrimeField64}; use plonky2::iop::witness::PartialWitness; diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 24b8059c..429a4fce 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -450,55 +450,6 @@ pub struct CtlCheckVarsTarget<'a, F: Field, const D: usize> { } impl<'a, F: Field, const D: usize> CtlCheckVarsTarget<'a, F, D> { - pub(crate) fn from_proofs( - proofs: &[StarkProofTarget; NUM_TABLES], - cross_table_lookups: &'a [CrossTableLookup], - ctl_challenges: &'a GrandProductChallengeSet, - num_permutation_zs: &[usize; NUM_TABLES], - ) -> [Vec; NUM_TABLES] { - let mut ctl_zs = proofs - .iter() - .zip(num_permutation_zs) - .map(|(p, &num_perms)| { - let openings = &p.openings; - let ctl_zs = openings.permutation_ctl_zs.iter().skip(num_perms); - let ctl_zs_next = openings.permutation_ctl_zs_next.iter().skip(num_perms); - ctl_zs.zip(ctl_zs_next) - }) - .collect::>(); - - let mut ctl_vars_per_table = [0; NUM_TABLES].map(|_| vec![]); - for CrossTableLookup { - looking_tables, - looked_table, - .. - } in cross_table_lookups - { - for &challenges in &ctl_challenges.challenges { - for table in looking_tables { - let (looking_z, looking_z_next) = ctl_zs[table.table as usize].next().unwrap(); - ctl_vars_per_table[table.table as usize].push(Self { - local_z: *looking_z, - next_z: *looking_z_next, - challenges, - columns: &table.columns, - filter_column: &table.filter_column, - }); - } - - let (looked_z, looked_z_next) = ctl_zs[looked_table.table as usize].next().unwrap(); - ctl_vars_per_table[looked_table.table as usize].push(Self { - local_z: *looked_z, - next_z: *looked_z_next, - challenges, - columns: &looked_table.columns, - filter_column: &looked_table.filter_column, - }); - } - } - ctl_vars_per_table - } - pub(crate) fn from_proof( table: Table, proof: &StarkProofTarget, diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index 8b254ee4..ac2e7aba 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -8,8 +8,8 @@ use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use crate::all_stark::{AllStark, NUM_TABLES}; use crate::config::StarkConfig; use crate::permutation::{ - get_grand_product_challenge_set, get_grand_product_challenge_set_target, - get_n_grand_product_challenge_sets, get_n_grand_product_challenge_sets_target, + get_grand_product_challenge_set, get_n_grand_product_challenge_sets, + get_n_grand_product_challenge_sets_target, }; use crate::proof::*; @@ -86,43 +86,6 @@ impl, C: GenericConfig, const D: usize> A } } -impl AllProofTarget { - pub(crate) fn get_challenges, C: GenericConfig>( - &self, - builder: &mut CircuitBuilder, - all_stark: &AllStark, - config: &StarkConfig, - ) -> AllProofChallengesTarget - where - C::Hasher: AlgebraicHasher, - { - let mut challenger = RecursiveChallenger::::new(builder); - - for proof in &self.stark_proofs { - challenger.observe_cap(&proof.trace_cap); - } - - let ctl_challenges = - get_grand_product_challenge_set_target(builder, &mut challenger, config.num_challenges); - - let num_permutation_zs = all_stark.nums_permutation_zs(config); - let num_permutation_batch_sizes = all_stark.permutation_batch_sizes(); - - AllProofChallengesTarget { - stark_challenges: std::array::from_fn(|i| { - self.stark_proofs[i].get_challenges::( - builder, - &mut challenger, - num_permutation_zs[i] > 0, - num_permutation_batch_sizes[i], - config, - ) - }), - ctl_challenges, - } - } -} - impl StarkProof where F: RichField + Extendable, diff --git a/evm/src/proof.rs b/evm/src/proof.rs index 577fbeb4..3b2d988b 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -99,11 +99,6 @@ pub struct BlockMetadataTarget { 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. diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 95d8cd80..fd52c218 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -5,17 +5,14 @@ use itertools::Itertools; use plonky2::field::extension::Extendable; use plonky2::field::types::Field; use plonky2::fri::witness_util::set_fri_proof_target; -use plonky2::hash::hash_types::{HashOut, RichField}; +use plonky2::hash::hash_types::RichField; use plonky2::hash::hashing::SPONGE_WIDTH; -use plonky2::hash::merkle_tree::MerkleCap; -use plonky2::hash::poseidon::PoseidonHash; use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; use plonky2::iop::witness::{PartialWitness, Witness}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData, VerifierCircuitTarget}; -use plonky2::plonk::config::GenericHashOut; use plonky2::plonk::config::Hasher; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::plonk::proof::ProofWithPublicInputs; @@ -39,9 +36,9 @@ use crate::permutation::{ GrandProductChallengeSet, PermutationCheckDataTarget, }; use crate::proof::{ - AllChallengerState, AllProof, AllProofChallengesTarget, AllProofTarget, BlockMetadata, - BlockMetadataTarget, PublicValues, PublicValuesTarget, StarkOpeningSetTarget, StarkProof, - StarkProofChallengesTarget, StarkProofTarget, TrieRoots, TrieRootsTarget, + AllChallengerState, AllProof, AllProofTarget, BlockMetadata, BlockMetadataTarget, PublicValues, + PublicValuesTarget, StarkOpeningSetTarget, StarkProof, StarkProofChallengesTarget, + StarkProofTarget, TrieRoots, TrieRootsTarget, }; use crate::stark::Stark; use crate::util::{h160_limbs, u256_limbs}; @@ -425,120 +422,6 @@ where }) } -// pub fn verify_proof_circuit< -// F: RichField + Extendable, -// C: GenericConfig, -// const D: usize, -// >( -// builder: &mut CircuitBuilder, -// all_stark: AllStark, -// all_proof: AllProofTarget, -// inner_config: &StarkConfig, -// ) where -// [(); CpuStark::::COLUMNS]:, -// [(); KeccakStark::::COLUMNS]:, -// [(); KeccakMemoryStark::::COLUMNS]:, -// [(); LogicStark::::COLUMNS]:, -// [(); MemoryStark::::COLUMNS]:, -// C::Hasher: AlgebraicHasher, -// { -// let AllProofChallengesTarget { -// stark_challenges, -// ctl_challenges, -// } = all_proof.get_challenges::(builder, &all_stark, inner_config); -// -// let nums_permutation_zs = all_stark.nums_permutation_zs(inner_config); -// -// let AllStark { -// cpu_stark, -// keccak_stark, -// keccak_memory_stark, -// logic_stark, -// memory_stark, -// cross_table_lookups, -// } = all_stark; -// -// let ctl_vars_per_table = CtlCheckVarsTarget::from_proofs( -// &all_proof.stark_proofs, -// &cross_table_lookups, -// &ctl_challenges, -// &nums_permutation_zs, -// ); -// -// with_context!( -// builder, -// "verify CPU proof", -// verify_stark_proof_with_challenges_circuit::( -// builder, -// &cpu_stark, -// &all_proof.stark_proofs[Table::Cpu as usize], -// &stark_challenges[Table::Cpu as usize], -// &ctl_vars_per_table[Table::Cpu as usize], -// inner_config, -// ) -// ); -// with_context!( -// builder, -// "verify Keccak proof", -// verify_stark_proof_with_challenges_circuit::( -// builder, -// &keccak_stark, -// &all_proof.stark_proofs[Table::Keccak as usize], -// &stark_challenges[Table::Keccak as usize], -// &ctl_vars_per_table[Table::Keccak as usize], -// inner_config, -// ) -// ); -// with_context!( -// builder, -// "verify Keccak memory proof", -// verify_stark_proof_with_challenges_circuit::( -// builder, -// &keccak_memory_stark, -// &all_proof.stark_proofs[Table::KeccakMemory as usize], -// &stark_challenges[Table::KeccakMemory as usize], -// &ctl_vars_per_table[Table::KeccakMemory as usize], -// inner_config, -// ) -// ); -// with_context!( -// builder, -// "verify logic proof", -// verify_stark_proof_with_challenges_circuit::( -// builder, -// &logic_stark, -// &all_proof.stark_proofs[Table::Logic as usize], -// &stark_challenges[Table::Logic as usize], -// &ctl_vars_per_table[Table::Logic as usize], -// inner_config, -// ) -// ); -// with_context!( -// builder, -// "verify memory proof", -// verify_stark_proof_with_challenges_circuit::( -// builder, -// &memory_stark, -// &all_proof.stark_proofs[Table::Memory as usize], -// &stark_challenges[Table::Memory as usize], -// &ctl_vars_per_table[Table::Memory as usize], -// inner_config, -// ) -// ); -// -// with_context!( -// builder, -// "verify cross-table lookups", -// verify_cross_table_lookups_circuit::( -// builder, -// cross_table_lookups, -// &all_proof.stark_proofs, -// ctl_challenges, -// inner_config, -// ) -// ); -// } - /// Recursively verifies an inner proof. fn verify_stark_proof_with_challenges_circuit< F: RichField + Extendable, From 8c96b8d2db84c99917172e4eb500fd5a8f8dbd46 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 23 Sep 2022 16:36:17 +0200 Subject: [PATCH 18/28] Comment --- evm/src/proof.rs | 2 ++ plonky2/src/hash/hash_types.rs | 10 ---------- plonky2/src/plonk/config.rs | 1 - 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/evm/src/proof.rs b/evm/src/proof.rs index 3b2d988b..2b75017a 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -40,6 +40,8 @@ pub(crate) struct AllProofChallenges, const D: usiz } pub(crate) struct AllChallengerState, const D: usize> { + /// Sponge state of the challenger before starting each proof, + /// along with the final state after all proofs are done. This final state isn't strictly needed. pub states: [[F; SPONGE_WIDTH]; NUM_TABLES + 1], pub ctl_challenges: GrandProductChallengeSet, } diff --git a/plonky2/src/hash/hash_types.rs b/plonky2/src/hash/hash_types.rs index 955f539a..14303ad3 100644 --- a/plonky2/src/hash/hash_types.rs +++ b/plonky2/src/hash/hash_types.rs @@ -78,12 +78,6 @@ impl GenericHashOut for HashOut { fn to_vec(&self) -> Vec { self.elements.to_vec() } - - fn from_vec(v: &[F]) -> Self { - Self { - elements: v.try_into().unwrap(), - } - } } impl Default for HashOut { @@ -154,10 +148,6 @@ impl GenericHashOut for BytesHash { }) .collect() } - - fn from_vec(_v: &[F]) -> Self { - todo!() - } } impl Serialize for BytesHash { diff --git a/plonky2/src/plonk/config.rs b/plonky2/src/plonk/config.rs index 51dacdde..f55bad1f 100644 --- a/plonky2/src/plonk/config.rs +++ b/plonky2/src/plonk/config.rs @@ -20,7 +20,6 @@ pub trait GenericHashOut: fn from_bytes(bytes: &[u8]) -> Self; fn to_vec(&self) -> Vec; - fn from_vec(v: &[F]) -> Self; } /// Trait for hash functions. From 6cf6b56aa0fbb6529be1050f5ca4f872189f1e05 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 26 Sep 2022 15:47:35 +0200 Subject: [PATCH 19/28] Method to compute verifier data without proving --- evm/src/all_stark.rs | 14 ++- evm/src/cross_table_lookup.rs | 15 +++ evm/src/recursive_verifier.rs | 200 +++++++++++++++++++++++++++++----- 3 files changed, 201 insertions(+), 28 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 7d7b0932..b160a425 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -194,7 +194,9 @@ mod tests { use crate::memory::NUM_CHANNELS; use crate::proof::{AllProof, PublicValues}; use crate::prover::prove_with_traces; - use crate::recursive_verifier::recursively_verify_all_proof; + use crate::recursive_verifier::{ + all_verifier_data_recursive_stark_proof, recursively_verify_all_proof, + }; use crate::stark::Stark; use crate::util::{limb_from_bits_le, trace_rows_to_poly_values}; use crate::verifier::verify_proof; @@ -750,13 +752,19 @@ mod tests { &inner_all_stark, &inner_proof, inner_config, - circuit_config, + &circuit_config, )?; + let verifier_data = all_verifier_data_recursive_stark_proof( + &inner_all_stark, + inner_proof.degree_bits(inner_config), + inner_config, + &circuit_config, + ); let circuit_config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(circuit_config); let mut pw = PartialWitness::new(); - recursive_all_proof.verify_circuit(&mut builder, &mut pw, inner_config); + recursive_all_proof.verify_circuit(&mut builder, &mut pw, &verifier_data, inner_config); let data = builder.build::(); let proof = data.prove(pw)?; diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 429a4fce..1b42801f 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -191,6 +191,21 @@ impl CrossTableLookup { default, } } + + pub(crate) fn num_ctl_zs(ctls: &[Self], table: Table, num_challenges: usize) -> usize { + let mut ans = 0; + for ctl in ctls { + ans += ctl + .looking_tables + .iter() + .filter_map(|twc| (twc.table == table).then_some(num_challenges)) + .sum::(); + ans += (ctl.looked_table.table == table) + .then_some(num_challenges) + .unwrap_or_default(); + } + ans + } } /// Cross-table lookup data for one table. diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index fd52c218..03d4e4bd 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -52,8 +52,7 @@ pub struct RecursiveAllProof< C: GenericConfig, const D: usize, > { - pub recursive_proofs: - [(ProofWithPublicInputs, VerifierCircuitData); NUM_TABLES], + pub recursive_proofs: [ProofWithPublicInputs; NUM_TABLES], pub cross_table_lookups: Vec>, } @@ -104,12 +103,16 @@ impl, C: GenericConfig, const D: usize> RecursiveAllProof { /// Verify every recursive proof. - pub fn verify(self, inner_config: &StarkConfig) -> Result<()> + pub fn verify( + self, + verifier_data: &[VerifierCircuitData; NUM_TABLES], + inner_config: &StarkConfig, + ) -> Result<()> where [(); C::Hasher::HASH_SIZE]:, { let pis: [_; NUM_TABLES] = std::array::from_fn(|i| { - PublicInputs::from_vec(&self.recursive_proofs[i].0.public_inputs, inner_config) + PublicInputs::from_vec(&self.recursive_proofs[i].public_inputs, inner_config) }); let mut challenger = Challenger::::new(); @@ -134,7 +137,7 @@ impl, C: GenericConfig, const D: usize> } // Verify the CTL checks. - let degrees_bits = std::array::from_fn(|i| self.recursive_proofs[i].1.common.degree_bits); + let degrees_bits = std::array::from_fn(|i| verifier_data[i].common.degree_bits); verify_cross_table_lookups::( self.cross_table_lookups, pis.map(|p| p.ctl_zs_last), @@ -144,7 +147,7 @@ impl, C: GenericConfig, const D: usize> )?; // Verify the proofs. - for (proof, verifier_data) in self.recursive_proofs { + for (proof, verifier_data) in self.recursive_proofs.into_iter().zip(verifier_data) { verifier_data.verify(proof)?; } Ok(()) @@ -155,6 +158,7 @@ impl, C: GenericConfig, const D: usize> self, builder: &mut CircuitBuilder, pw: &mut W, + verifier_data: &[VerifierCircuitData; NUM_TABLES], inner_config: &StarkConfig, ) where W: Witness, @@ -162,8 +166,8 @@ impl, C: GenericConfig, const D: usize> >::Hasher: AlgebraicHasher, { let proofs_target: [_; NUM_TABLES] = std::array::from_fn(|i| { - let verifier_data = &self.recursive_proofs[i].1; - let proof = &self.recursive_proofs[i].0; + let verifier_data = &verifier_data[i]; + let proof = &self.recursive_proofs[i]; let pt = builder.add_virtual_proof_with_pis(&verifier_data.common); pw.set_proof_with_pis_target(&pt, proof); let inner_data = VerifierCircuitTarget { @@ -222,7 +226,7 @@ impl, C: GenericConfig, const D: usize> } // Verify the CTL checks. - let degrees_bits = std::array::from_fn(|i| self.recursive_proofs[i].1.common.degree_bits); + let degrees_bits = std::array::from_fn(|i| verifier_data[i].common.degree_bits); verify_cross_table_lookups_circuit::( builder, self.cross_table_lookups, @@ -232,11 +236,7 @@ impl, C: GenericConfig, const D: usize> inner_config, ); for (i, (proof_target, inner_data)) in proofs_target.into_iter().enumerate() { - builder.verify_proof( - proof_target, - &inner_data, - &self.recursive_proofs[i].1.common, - ); + builder.verify_proof(proof_target, &inner_data, &verifier_data[i].common); } } } @@ -341,6 +341,151 @@ where Ok((data.prove(pw)?, data.verifier_data())) } +/// Returns the verifier data for the recursively Stark circuit. +fn verifier_data_recursive_stark_proof< + F: RichField + Extendable, + C: GenericConfig, + S: Stark, + const D: usize, +>( + table: Table, + stark: S, + degree_bits: usize, + cross_table_lookups: &[CrossTableLookup], + inner_config: &StarkConfig, + circuit_config: &CircuitConfig, +) -> VerifierCircuitData +where + [(); S::COLUMNS]:, + [(); C::Hasher::HASH_SIZE]:, + C::Hasher: AlgebraicHasher, +{ + let mut builder = CircuitBuilder::::new(circuit_config.clone()); + + let num_permutation_zs = stark.num_permutation_batches(inner_config); + let num_permutation_batch_size = stark.permutation_batch_size(); + let num_ctl_zs = + CrossTableLookup::num_ctl_zs(cross_table_lookups, table, inner_config.num_challenges); + let proof_target = + add_virtual_stark_proof(&mut builder, &stark, inner_config, degree_bits, num_ctl_zs); + builder.register_public_inputs( + &proof_target + .trace_cap + .0 + .iter() + .flat_map(|h| h.elements) + .collect::>(), + ); + + let ctl_challenges_target = GrandProductChallengeSet { + challenges: (0..inner_config.num_challenges) + .map(|_| GrandProductChallenge { + beta: builder.add_virtual_public_input(), + gamma: builder.add_virtual_public_input(), + }) + .collect(), + }; + + let ctl_vars = CtlCheckVarsTarget::from_proof( + table, + &proof_target, + cross_table_lookups, + &ctl_challenges_target, + num_permutation_zs, + ); + + let challenger_state = std::array::from_fn(|_| builder.add_virtual_public_input()); + let mut challenger = RecursiveChallenger::::from_state(challenger_state); + let challenges = proof_target.get_challenges::( + &mut builder, + &mut challenger, + num_permutation_zs > 0, + num_permutation_batch_size, + inner_config, + ); + challenger.duplexing(&mut builder); + let challenger_state = challenger.state(); + builder.register_public_inputs(&challenger_state); + + builder.register_public_inputs(&proof_target.openings.ctl_zs_last); + + verify_stark_proof_with_challenges_circuit::( + &mut builder, + &stark, + &proof_target, + &challenges, + &ctl_vars, + inner_config, + ); + + let data = builder.build::(); + data.verifier_data() +} + +/// Recursively verify every Stark proof in an `AllProof`. +pub fn all_verifier_data_recursive_stark_proof< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, +>( + all_stark: &AllStark, + degree_bits: [usize; NUM_TABLES], + inner_config: &StarkConfig, + circuit_config: &CircuitConfig, +) -> [VerifierCircuitData; NUM_TABLES] +where + [(); CpuStark::::COLUMNS]:, + [(); KeccakStark::::COLUMNS]:, + [(); KeccakMemoryStark::::COLUMNS]:, + [(); LogicStark::::COLUMNS]:, + [(); MemoryStark::::COLUMNS]:, + [(); C::Hasher::HASH_SIZE]:, + C::Hasher: AlgebraicHasher, +{ + [ + verifier_data_recursive_stark_proof( + Table::Cpu, + all_stark.cpu_stark, + degree_bits[Table::Cpu as usize], + &all_stark.cross_table_lookups, + inner_config, + circuit_config, + ), + verifier_data_recursive_stark_proof( + Table::Keccak, + all_stark.keccak_stark, + degree_bits[Table::Keccak as usize], + &all_stark.cross_table_lookups, + inner_config, + circuit_config, + ), + verifier_data_recursive_stark_proof( + Table::KeccakMemory, + all_stark.keccak_memory_stark, + degree_bits[Table::KeccakMemory as usize], + &all_stark.cross_table_lookups, + inner_config, + circuit_config, + ), + verifier_data_recursive_stark_proof( + Table::Logic, + all_stark.logic_stark, + degree_bits[Table::Logic as usize], + &all_stark.cross_table_lookups, + inner_config, + circuit_config, + ), + verifier_data_recursive_stark_proof( + Table::Memory, + all_stark.memory_stark, + degree_bits[Table::Memory as usize], + &all_stark.cross_table_lookups, + inner_config, + circuit_config, + ), + ] +} + /// Recursively verify every Stark proof in an `AllProof`. pub fn recursively_verify_all_proof< F: RichField + Extendable, @@ -350,7 +495,7 @@ pub fn recursively_verify_all_proof< all_stark: &AllStark, all_proof: &AllProof, inner_config: &StarkConfig, - circuit_config: CircuitConfig, + circuit_config: &CircuitConfig, ) -> Result> where [(); CpuStark::::COLUMNS]:, @@ -375,8 +520,9 @@ where &ctl_challenges, states[0], inner_config, - &circuit_config, - )?, + circuit_config, + )? + .0, recursively_verify_stark_proof( Table::Keccak, all_stark.keccak_stark, @@ -385,8 +531,9 @@ where &ctl_challenges, states[1], inner_config, - &circuit_config, - )?, + circuit_config, + )? + .0, recursively_verify_stark_proof( Table::KeccakMemory, all_stark.keccak_memory_stark, @@ -395,8 +542,9 @@ where &ctl_challenges, states[2], inner_config, - &circuit_config, - )?, + circuit_config, + )? + .0, recursively_verify_stark_proof( Table::Logic, all_stark.logic_stark, @@ -405,8 +553,9 @@ where &ctl_challenges, states[3], inner_config, - &circuit_config, - )?, + circuit_config, + )? + .0, recursively_verify_stark_proof( Table::Memory, all_stark.memory_stark, @@ -415,8 +564,9 @@ where &ctl_challenges, states[4], inner_config, - &circuit_config, - )?, + circuit_config, + )? + .0, ], cross_table_lookups: all_stark.cross_table_lookups.clone(), }) From 1de3ed823a3e526e95716ff56358339c26257884 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 26 Sep 2022 16:05:15 +0200 Subject: [PATCH 20/28] Update comments --- evm/src/recursive_verifier.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 03d4e4bd..3f079ea4 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -46,7 +46,6 @@ use crate::vanishing_poly::eval_vanishing_poly_circuit; use crate::vars::StarkEvaluationTargets; /// Table-wise recursive proofs of an `AllProof`. -/// Also contains verifier data for each proof. pub struct RecursiveAllProof< F: RichField + Extendable, C: GenericConfig, @@ -341,7 +340,7 @@ where Ok((data.prove(pw)?, data.verifier_data())) } -/// Returns the verifier data for the recursively Stark circuit. +/// Returns the verifier data for the recursive Stark circuit. fn verifier_data_recursive_stark_proof< F: RichField + Extendable, C: GenericConfig, @@ -422,7 +421,7 @@ where data.verifier_data() } -/// Recursively verify every Stark proof in an `AllProof`. +/// Returns the recursive Stark circuit verifier data for every Stark in `AllStark`. pub fn all_verifier_data_recursive_stark_proof< F: RichField + Extendable, C: GenericConfig, From cb620bc55a28ca94649ea89d1111deab6562ebf0 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 29 Sep 2022 16:32:41 +0200 Subject: [PATCH 21/28] Simplify `num_ctl_zs` --- evm/src/cross_table_lookup.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 1b42801f..b5223e50 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -193,18 +193,12 @@ impl CrossTableLookup { } pub(crate) fn num_ctl_zs(ctls: &[Self], table: Table, num_challenges: usize) -> usize { - let mut ans = 0; + let mut num_ctls = 0; for ctl in ctls { - ans += ctl - .looking_tables - .iter() - .filter_map(|twc| (twc.table == table).then_some(num_challenges)) - .sum::(); - ans += (ctl.looked_table.table == table) - .then_some(num_challenges) - .unwrap_or_default(); + let all_tables = std::iter::once(&ctl.looked_table).chain(&ctl.looking_tables); + num_ctls += all_tables.filter(|twc| twc.table == table).count(); } - ans + num_ctls * num_challenges } } From 3579f9e8756fcc75efbce953bc51180b54d8d028 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 3 Oct 2022 10:53:33 +0200 Subject: [PATCH 22/28] state() -> compact() --- evm/src/get_challenges.rs | 8 +++----- evm/src/prover.rs | 2 +- evm/src/recursive_verifier.rs | 12 ++++-------- plonky2/src/iop/challenger.rs | 35 +++++++++-------------------------- 4 files changed, 17 insertions(+), 40 deletions(-) diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index ac2e7aba..9cb07c31 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -36,7 +36,7 @@ impl, C: GenericConfig, const D: usize> A AllProofChallenges { stark_challenges: std::array::from_fn(|i| { - challenger.duplexing(); + challenger.compact(); self.stark_proofs[i].get_challenges( &mut challenger, num_permutation_zs[i] > 0, @@ -66,8 +66,7 @@ impl, C: GenericConfig, const D: usize> A let num_permutation_zs = all_stark.nums_permutation_zs(config); let num_permutation_batch_sizes = all_stark.permutation_batch_sizes(); - challenger.duplexing(); - let mut challenger_states = vec![challenger.state()]; + let mut challenger_states = vec![challenger.compact()]; for i in 0..NUM_TABLES { self.stark_proofs[i].get_challenges( &mut challenger, @@ -75,8 +74,7 @@ impl, C: GenericConfig, const D: usize> A num_permutation_batch_sizes[i], config, ); - challenger.duplexing(); - challenger_states.push(challenger.state()); + challenger_states.push(challenger.compact()); } AllChallengerState { diff --git a/evm/src/prover.rs b/evm/src/prover.rs index eba0759f..3b702c56 100644 --- a/evm/src/prover.rs +++ b/evm/src/prover.rs @@ -201,7 +201,7 @@ where "FRI total reduction arity is too large.", ); - challenger.duplexing(); + challenger.compact(); // Permutation arguments. let permutation_challenges = stark.uses_permutation_args().then(|| { diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 3f079ea4..6a94feb9 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -127,8 +127,7 @@ impl, C: GenericConfig, const D: usize> ensure!(ctl_challenges == pi.ctl_challenges); } - challenger.duplexing(); - let state = challenger.state(); + let state = challenger.compact(); ensure!(state == pis[0].challenger_state_before); // Check that the challenger state is consistent between proofs. for i in 1..NUM_TABLES { @@ -209,8 +208,7 @@ impl, C: GenericConfig, const D: usize> } } - challenger.duplexing(builder); - let state = challenger.state(); + let state = challenger.compact(builder); for k in 0..SPONGE_WIDTH { builder.connect(state[k], pis[0].challenger_state_before[k]); } @@ -321,8 +319,7 @@ where num_permutation_batch_size, inner_config, ); - challenger.duplexing(&mut builder); - let challenger_state = challenger.state(); + let challenger_state = challenger.compact(&mut builder); builder.register_public_inputs(&challenger_state); builder.register_public_inputs(&proof_target.openings.ctl_zs_last); @@ -402,8 +399,7 @@ where num_permutation_batch_size, inner_config, ); - challenger.duplexing(&mut builder); - let challenger_state = challenger.state(); + let challenger_state = challenger.compact(&mut builder); builder.register_public_inputs(&challenger_state); builder.register_public_inputs(&proof_target.openings.ctl_zs_last); diff --git a/plonky2/src/iop/challenger.rs b/plonky2/src/iop/challenger.rs index eeb18038..84bbad1c 100644 --- a/plonky2/src/iop/challenger.rs +++ b/plonky2/src/iop/challenger.rs @@ -147,7 +147,11 @@ impl> Challenger { .extend_from_slice(&self.sponge_state[0..SPONGE_RATE]); } - pub fn state(&self) -> [F; SPONGE_WIDTH] { + pub fn compact(&mut self) -> [F; SPONGE_WIDTH] { + if !self.input_buffer.is_empty() { + self.duplexing(); + } + self.output_buffer.clear(); self.sponge_state } } @@ -181,11 +185,10 @@ impl, H: AlgebraicHasher, const D: usize> } pub fn from_state(sponge_state: [Target; SPONGE_WIDTH]) -> Self { - let output_buffer = sponge_state[0..SPONGE_RATE].to_vec(); RecursiveChallenger { sponge_state, input_buffer: vec![], - output_buffer, + output_buffer: vec![], } } @@ -286,29 +289,9 @@ impl, H: AlgebraicHasher, const D: usize> self.input_buffer.clear(); } - pub fn duplexing(&mut self, builder: &mut CircuitBuilder) { - if self.input_buffer.is_empty() { - self.sponge_state = builder.permute::(self.sponge_state); - } else { - for input_chunk in self.input_buffer.chunks(SPONGE_RATE) { - // Overwrite the first r elements with the inputs. This differs from a standard sponge, - // where we would xor or add in the inputs. This is a well-known variant, though, - // sometimes called "overwrite mode". - for (i, &input) in input_chunk.iter().enumerate() { - self.sponge_state[i] = input; - } - - // Apply the permutation. - self.sponge_state = builder.permute::(self.sponge_state); - } - } - - self.output_buffer = self.sponge_state[0..SPONGE_RATE].to_vec(); - - self.input_buffer.clear(); - } - - pub fn state(&self) -> [Target; SPONGE_WIDTH] { + pub fn compact(&mut self, builder: &mut CircuitBuilder) -> [Target; SPONGE_WIDTH] { + self.absorb_buffered_inputs(builder); + self.output_buffer.clear(); self.sponge_state } } From 668957176a6e5d74e3aabe900f5323e0b1dbbe43 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 3 Oct 2022 11:44:52 +0200 Subject: [PATCH 23/28] PR feedback --- evm/src/all_stark.rs | 10 +++++-- evm/src/cross_table_lookup.rs | 1 + evm/src/generation/mod.rs | 2 +- evm/src/proof.rs | 4 --- evm/src/recursive_verifier.rs | 55 ++++++++++++++++++----------------- plonky2/src/fri/mod.rs | 4 +++ plonky2/src/iop/challenger.rs | 2 +- 7 files changed, 44 insertions(+), 34 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index b160a425..164c60fc 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -221,7 +221,7 @@ mod tests { keccak_memory_stark: &KeccakMemoryStark, config: &StarkConfig, ) -> Vec> { - keccak_memory_stark.generate_trace(vec![], 1 << config.fri_config.cap_height) + keccak_memory_stark.generate_trace(vec![], config.fri_config.num_cap_elements()) } fn make_logic_trace( @@ -764,7 +764,13 @@ mod tests { let circuit_config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(circuit_config); let mut pw = PartialWitness::new(); - recursive_all_proof.verify_circuit(&mut builder, &mut pw, &verifier_data, inner_config); + recursive_all_proof.verify_circuit( + &mut builder, + &mut pw, + &verifier_data, + inner_all_stark.cross_table_lookups, + inner_config, + ); let data = builder.build::(); let proof = data.prove(pw)?; diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index b5223e50..a1fd3ce7 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -509,6 +509,7 @@ impl<'a, F: Field, const D: usize> CtlCheckVarsTarget<'a, F, D> { } } } + assert!(ctl_zs.next().is_none()); ctl_vars } } diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index 5b0b3c8f..f9ec0b3c 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -95,7 +95,7 @@ pub(crate) fn generate_traces, const D: usize>( let keccak_trace = all_stark.keccak_stark.generate_trace(keccak_inputs); let keccak_memory_trace = all_stark .keccak_memory_stark - .generate_trace(keccak_memory_inputs, 1 << config.fri_config.cap_height); + .generate_trace(keccak_memory_inputs, config.fri_config.num_cap_elements()); let logic_trace = all_stark.logic_stark.generate_trace(logic_ops); let memory_trace = all_stark.memory_stark.generate_trace(memory.log); let traces = [ diff --git a/evm/src/proof.rs b/evm/src/proof.rs index 2b75017a..28560a6c 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -28,10 +28,6 @@ impl, C: GenericConfig, const D: usize> A 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].num_ctl_zs()) - } } pub(crate) struct AllProofChallenges, const D: usize> { diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 6a94feb9..ae3bd27f 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -52,7 +52,6 @@ pub struct RecursiveAllProof< const D: usize, > { pub recursive_proofs: [ProofWithPublicInputs; NUM_TABLES], - pub cross_table_lookups: Vec>, } struct PublicInputs { @@ -63,30 +62,32 @@ struct PublicInputs { challenger_state_after: [T; SPONGE_WIDTH], } +/// Similar to the unstable `Iterator::next_chunk`. Could be replaced with that when it's stable. +fn next_chunk(iter: &mut impl Iterator) -> [T; N] { + (0..N) + .flat_map(|_| iter.next()) + .collect_vec() + .try_into() + .expect("Not enough elements") +} + impl PublicInputs { fn from_vec(v: &[T], config: &StarkConfig) -> Self { - let mut start = 0; - let trace_cap = v[start..4 * (1 << config.fri_config.cap_height)] - .chunks(4) - .map(|chunk| chunk.to_vec()) + let mut iter = v.iter().copied(); + let trace_cap = (0..1 << config.fri_config.cap_height) + .map(|_| next_chunk::<_, 4>(&mut iter).to_vec()) .collect(); - start += 4 * (1 << config.fri_config.cap_height); let ctl_challenges = GrandProductChallengeSet { challenges: (0..config.num_challenges) - .map(|i| GrandProductChallenge { - beta: v[start + 2 * i], - gamma: v[start + 2 * i + 1], + .map(|_| GrandProductChallenge { + beta: iter.next().unwrap(), + gamma: iter.next().unwrap(), }) .collect(), }; - start += 2 * config.num_challenges; - let challenger_state_before = v[start..start + SPONGE_WIDTH].try_into().unwrap(); - let challenger_state_after = v[start + SPONGE_WIDTH..start + 2 * SPONGE_WIDTH] - .try_into() - .unwrap(); - - start += 2 * SPONGE_WIDTH; - let ctl_zs_last = v[start..].to_vec(); + let challenger_state_before = next_chunk(&mut iter); + let challenger_state_after = next_chunk(&mut iter); + let ctl_zs_last = iter.collect(); Self { trace_cap, @@ -105,6 +106,7 @@ impl, C: GenericConfig, const D: usize> pub fn verify( self, verifier_data: &[VerifierCircuitData; NUM_TABLES], + cross_table_lookups: Vec>, inner_config: &StarkConfig, ) -> Result<()> where @@ -137,7 +139,7 @@ impl, C: GenericConfig, const D: usize> // Verify the CTL checks. let degrees_bits = std::array::from_fn(|i| verifier_data[i].common.degree_bits); verify_cross_table_lookups::( - self.cross_table_lookups, + cross_table_lookups, pis.map(|p| p.ctl_zs_last), degrees_bits, ctl_challenges, @@ -157,6 +159,7 @@ impl, C: GenericConfig, const D: usize> builder: &mut CircuitBuilder, pw: &mut W, verifier_data: &[VerifierCircuitData; NUM_TABLES], + cross_table_lookups: Vec>, inner_config: &StarkConfig, ) where W: Witness, @@ -226,7 +229,7 @@ impl, C: GenericConfig, const D: usize> let degrees_bits = std::array::from_fn(|i| verifier_data[i].common.degree_bits); verify_cross_table_lookups_circuit::( builder, - self.cross_table_lookups, + cross_table_lookups, pis.map(|p| p.ctl_zs_last), degrees_bits, ctl_challenges, @@ -251,7 +254,7 @@ fn recursively_verify_stark_proof< proof: &StarkProof, cross_table_lookups: &[CrossTableLookup], ctl_challenges: &GrandProductChallengeSet, - challenger_state_before: [F; SPONGE_WIDTH], + challenger_state_before_vals: [F; SPONGE_WIDTH], inner_config: &StarkConfig, circuit_config: &CircuitConfig, ) -> Result<(ProofWithPublicInputs, VerifierCircuitData)> @@ -309,9 +312,10 @@ where num_permutation_zs, ); - let challenger_state = std::array::from_fn(|_| builder.add_virtual_public_input()); - pw.set_target_arr(challenger_state, challenger_state_before); - let mut challenger = RecursiveChallenger::::from_state(challenger_state); + let challenger_state_before = std::array::from_fn(|_| builder.add_virtual_public_input()); + pw.set_target_arr(challenger_state_before, challenger_state_before_vals); + let mut challenger = + RecursiveChallenger::::from_state(challenger_state_before); let challenges = proof_target.get_challenges::( &mut builder, &mut challenger, @@ -319,8 +323,8 @@ where num_permutation_batch_size, inner_config, ); - let challenger_state = challenger.compact(&mut builder); - builder.register_public_inputs(&challenger_state); + let challenger_state_after = challenger.compact(&mut builder); + builder.register_public_inputs(&challenger_state_after); builder.register_public_inputs(&proof_target.openings.ctl_zs_last); @@ -563,7 +567,6 @@ where )? .0, ], - cross_table_lookups: all_stark.cross_table_lookups.clone(), }) } diff --git a/plonky2/src/fri/mod.rs b/plonky2/src/fri/mod.rs index 4ed2ea3b..def33a73 100644 --- a/plonky2/src/fri/mod.rs +++ b/plonky2/src/fri/mod.rs @@ -45,6 +45,10 @@ impl FriConfig { reduction_arity_bits, } } + + pub fn num_cap_elements(&self) -> usize { + 1 << self.cap_height + } } /// FRI parameters, including generated parameters which are specific to an instance size, in diff --git a/plonky2/src/iop/challenger.rs b/plonky2/src/iop/challenger.rs index 84bbad1c..c601ae0f 100644 --- a/plonky2/src/iop/challenger.rs +++ b/plonky2/src/iop/challenger.rs @@ -129,7 +129,7 @@ impl> Challenger { /// Absorb any buffered inputs. After calling this, the input buffer will be empty, and the /// output buffer will be full. - pub fn duplexing(&mut self) { + fn duplexing(&mut self) { assert!(self.input_buffer.len() <= SPONGE_RATE); // Overwrite the first r elements with the inputs. This differs from a standard sponge, From 3be208edf044f9368233fedc786164f2f926ca41 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 3 Oct 2022 11:55:17 +0200 Subject: [PATCH 24/28] Minor --- evm/src/recursive_verifier.rs | 91 ++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index b2f67610..57ae7591 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -19,6 +19,7 @@ use plonky2::plonk::proof::ProofWithPublicInputs; use plonky2::util::reducing::ReducingFactorTarget; use plonky2::with_context; +use crate::all_stark::NUM_TABLES; use crate::config::StarkConfig; use crate::constraint_consumer::RecursiveConstraintConsumer; use crate::cpu::cpu_stark::CpuStark; @@ -242,6 +243,93 @@ impl, C: GenericConfig, const D: usize> builder.verify_proof(proof_target, &inner_data, &verifier_data[i].common); } } + + /// Verifier data to recursively verify every recursive proof. + pub fn verifier_data_verify_circuit( + self, + builder: &mut CircuitBuilder, + pw: &mut W, + verifier_data: &[VerifierCircuitData; NUM_TABLES], + cross_table_lookups: Vec>, + inner_config: &StarkConfig, + ) where + W: Witness, + [(); C::Hasher::HASH_SIZE]:, + >::Hasher: AlgebraicHasher, + { + let proofs_target: [_; NUM_TABLES] = std::array::from_fn(|i| { + let verifier_data = &verifier_data[i]; + let proof = &self.recursive_proofs[i]; + let pt = builder.add_virtual_proof_with_pis(&verifier_data.common); + pw.set_proof_with_pis_target(&pt, proof); + let inner_data = VerifierCircuitTarget { + constants_sigmas_cap: builder + .add_virtual_cap(verifier_data.common.config.fri_config.cap_height), + }; + pw.set_cap_target( + &inner_data.constants_sigmas_cap, + &verifier_data.verifier_only.constants_sigmas_cap, + ); + (pt, inner_data) + }); + + let pis: [_; NUM_TABLES] = std::array::from_fn(|i| { + PublicInputs::from_vec(&proofs_target[i].0.public_inputs, inner_config) + }); + + let mut challenger = RecursiveChallenger::::new(builder); + for pi in &pis { + for h in &pi.trace_cap { + challenger.observe_elements(h); + } + } + let ctl_challenges = get_grand_product_challenge_set_target( + builder, + &mut challenger, + inner_config.num_challenges, + ); + // Check that the correct CTL challenges are used in every proof. + for pi in &pis { + for i in 0..inner_config.num_challenges { + builder.connect( + ctl_challenges.challenges[i].beta, + pi.ctl_challenges.challenges[i].beta, + ); + builder.connect( + ctl_challenges.challenges[i].gamma, + pi.ctl_challenges.challenges[i].gamma, + ); + } + } + + let state = challenger.compact(builder); + for k in 0..SPONGE_WIDTH { + builder.connect(state[k], pis[0].challenger_state_before[k]); + } + // Check that the challenger state is consistent between proofs. + for i in 1..NUM_TABLES { + for k in 0..SPONGE_WIDTH { + builder.connect( + pis[i].challenger_state_before[k], + pis[i - 1].challenger_state_after[k], + ); + } + } + + // Verify the CTL checks. + let degrees_bits = std::array::from_fn(|i| verifier_data[i].common.degree_bits); + verify_cross_table_lookups_circuit::( + builder, + cross_table_lookups, + pis.map(|p| p.ctl_zs_last), + degrees_bits, + ctl_challenges, + inner_config, + ); + for (i, (proof_target, inner_data)) in proofs_target.into_iter().enumerate() { + builder.verify_proof(proof_target, &inner_data, &verifier_data[i].common); + } + } } /// Recursively verify a Stark proof. @@ -420,8 +508,7 @@ where inner_config, ); - let data = builder.build::(); - data.verifier_data() + builder.build_verifier::() } /// Returns the recursive Stark circuit verifier data for every Stark in `AllStark`. From e515f1e1cc5203f88a6c1998135f2c124cbe5fb0 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 4 Oct 2022 09:56:12 +0200 Subject: [PATCH 25/28] Split circuit and witness generation --- evm/src/all_stark.rs | 13 ++++- evm/src/recursive_verifier.rs | 92 ++++++++++++++++++++++++++--------- 2 files changed, 80 insertions(+), 25 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 07f38694..82c19fc2 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -204,7 +204,8 @@ mod tests { use crate::proof::{AllProof, PublicValues}; use crate::prover::prove_with_traces; use crate::recursive_verifier::{ - all_verifier_data_recursive_stark_proof, recursively_verify_all_proof, + add_virtual_recursive_all_proof, all_verifier_data_recursive_stark_proof, + recursively_verify_all_proof, set_recursive_all_proof_target, }; use crate::stark::Stark; use crate::util::{limb_from_bits_le, trace_rows_to_poly_values}; @@ -779,9 +780,17 @@ mod tests { let circuit_config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(circuit_config); let mut pw = PartialWitness::new(); + let recursive_all_proof_target = + add_virtual_recursive_all_proof(&mut builder, &verifier_data); + set_recursive_all_proof_target( + &mut pw, + &recursive_all_proof_target, + &recursive_all_proof, + &verifier_data, + ); recursive_all_proof.verify_circuit( &mut builder, - &mut pw, + recursive_all_proof_target, &verifier_data, inner_all_stark.cross_table_lookups, inner_config, diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 57ae7591..766382e4 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -15,7 +15,7 @@ use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData, VerifierCircuitTarget}; use plonky2::plonk::config::Hasher; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; -use plonky2::plonk::proof::ProofWithPublicInputs; +use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; use plonky2::util::reducing::ReducingFactorTarget; use plonky2::with_context; @@ -58,6 +58,11 @@ pub struct RecursiveAllProof< pub recursive_proofs: [ProofWithPublicInputs; NUM_TABLES], } +pub struct RecursiveAllProofTargetWithData { + pub recursive_proofs: [ProofWithPublicInputsTarget; NUM_TABLES], + pub verifier_data: [VerifierCircuitTarget; NUM_TABLES], +} + struct PublicInputs { trace_cap: Vec>, ctl_zs_last: Vec, @@ -158,36 +163,23 @@ impl, C: GenericConfig, const D: usize> } /// Recursively verify every recursive proof. - pub fn verify_circuit( + pub fn verify_circuit( self, builder: &mut CircuitBuilder, - pw: &mut W, + recursive_all_proof_target: RecursiveAllProofTargetWithData, verifier_data: &[VerifierCircuitData; NUM_TABLES], cross_table_lookups: Vec>, inner_config: &StarkConfig, ) where - W: Witness, [(); C::Hasher::HASH_SIZE]:, >::Hasher: AlgebraicHasher, { - let proofs_target: [_; NUM_TABLES] = std::array::from_fn(|i| { - let verifier_data = &verifier_data[i]; - let proof = &self.recursive_proofs[i]; - let pt = builder.add_virtual_proof_with_pis(&verifier_data.common); - pw.set_proof_with_pis_target(&pt, proof); - let inner_data = VerifierCircuitTarget { - constants_sigmas_cap: builder - .add_virtual_cap(verifier_data.common.config.fri_config.cap_height), - }; - pw.set_cap_target( - &inner_data.constants_sigmas_cap, - &verifier_data.verifier_only.constants_sigmas_cap, - ); - (pt, inner_data) - }); - + let RecursiveAllProofTargetWithData { + recursive_proofs, + verifier_data: verifier_data_target, + } = recursive_all_proof_target; let pis: [_; NUM_TABLES] = std::array::from_fn(|i| { - PublicInputs::from_vec(&proofs_target[i].0.public_inputs, inner_config) + PublicInputs::from_vec(&recursive_proofs[i].public_inputs, inner_config) }); let mut challenger = RecursiveChallenger::::new(builder); @@ -239,8 +231,16 @@ impl, C: GenericConfig, const D: usize> ctl_challenges, inner_config, ); - for (i, (proof_target, inner_data)) in proofs_target.into_iter().enumerate() { - builder.verify_proof(proof_target, &inner_data, &verifier_data[i].common); + for (i, (recursive_proof, verifier_data_target)) in recursive_proofs + .into_iter() + .zip(verifier_data_target) + .enumerate() + { + builder.verify_proof( + recursive_proof, + &verifier_data_target, + &verifier_data[i].common, + ); } } @@ -840,6 +840,31 @@ pub fn add_virtual_all_proof, const D: usize>( } } +pub fn add_virtual_recursive_all_proof< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, +>( + builder: &mut CircuitBuilder, + verifier_data: &[VerifierCircuitData; NUM_TABLES], +) -> RecursiveAllProofTargetWithData { + let recursive_proofs = std::array::from_fn(|i| { + let verifier_data = &verifier_data[i]; + builder.add_virtual_proof_with_pis(&verifier_data.common) + }); + let verifier_data = std::array::from_fn(|i| { + let verifier_data = &verifier_data[i]; + VerifierCircuitTarget { + constants_sigmas_cap: builder + .add_virtual_cap(verifier_data.common.config.fri_config.cap_height), + } + }); + RecursiveAllProofTargetWithData { + recursive_proofs, + verifier_data, + } +} + pub fn add_virtual_public_values, const D: usize>( builder: &mut CircuitBuilder, ) -> PublicValuesTarget { @@ -934,6 +959,27 @@ fn add_stark_opening_set, S: Stark, const D: } } +pub fn set_recursive_all_proof_target, W, const D: usize>( + witness: &mut W, + recursive_all_proof_target: &RecursiveAllProofTargetWithData, + all_proof: &RecursiveAllProof, + verifier_data: &[VerifierCircuitData; NUM_TABLES], +) where + F: RichField + Extendable, + C::Hasher: AlgebraicHasher, + W: Witness, +{ + for i in 0..NUM_TABLES { + witness.set_proof_with_pis_target( + &recursive_all_proof_target.recursive_proofs[i], + &all_proof.recursive_proofs[i], + ); + witness.set_cap_target( + &recursive_all_proof_target.verifier_data[i].constants_sigmas_cap, + &verifier_data[i].verifier_only.constants_sigmas_cap, + ); + } +} pub fn set_all_proof_target, W, const D: usize>( witness: &mut W, all_proof_target: &AllProofTarget, From 0bc3f20479a734af1c25ff8b3757b4dc0433b480 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 6 Oct 2022 16:32:35 +0200 Subject: [PATCH 26/28] PR feedback --- evm/src/all_stark.rs | 5 +- evm/src/recursive_verifier.rs | 94 ++--------------------------------- 2 files changed, 7 insertions(+), 92 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 82c19fc2..177591fd 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -205,7 +205,7 @@ mod tests { use crate::prover::prove_with_traces; use crate::recursive_verifier::{ add_virtual_recursive_all_proof, all_verifier_data_recursive_stark_proof, - recursively_verify_all_proof, set_recursive_all_proof_target, + recursively_verify_all_proof, set_recursive_all_proof_target, RecursiveAllProof, }; use crate::stark::Stark; use crate::util::{limb_from_bits_le, trace_rows_to_poly_values}; @@ -360,6 +360,7 @@ mod tests { let row: &mut cpu::columns::CpuColumnsView = cpu_trace_rows[clock].borrow_mut(); row.clock = F::from_canonical_usize(clock); + dbg!(channel, row.mem_channels.len()); let channel = &mut row.mem_channels[channel]; channel.used = F::ONE; channel.is_read = memory_trace[memory::columns::IS_READ].values[i]; @@ -788,7 +789,7 @@ mod tests { &recursive_all_proof, &verifier_data, ); - recursive_all_proof.verify_circuit( + RecursiveAllProof::verify_circuit( &mut builder, recursive_all_proof_target, &verifier_data, diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 766382e4..1ef493a0 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -164,7 +164,6 @@ impl, C: GenericConfig, const D: usize> /// Recursively verify every recursive proof. pub fn verify_circuit( - self, builder: &mut CircuitBuilder, recursive_all_proof_target: RecursiveAllProofTargetWithData, verifier_data: &[VerifierCircuitData; NUM_TABLES], @@ -243,97 +242,11 @@ impl, C: GenericConfig, const D: usize> ); } } - - /// Verifier data to recursively verify every recursive proof. - pub fn verifier_data_verify_circuit( - self, - builder: &mut CircuitBuilder, - pw: &mut W, - verifier_data: &[VerifierCircuitData; NUM_TABLES], - cross_table_lookups: Vec>, - inner_config: &StarkConfig, - ) where - W: Witness, - [(); C::Hasher::HASH_SIZE]:, - >::Hasher: AlgebraicHasher, - { - let proofs_target: [_; NUM_TABLES] = std::array::from_fn(|i| { - let verifier_data = &verifier_data[i]; - let proof = &self.recursive_proofs[i]; - let pt = builder.add_virtual_proof_with_pis(&verifier_data.common); - pw.set_proof_with_pis_target(&pt, proof); - let inner_data = VerifierCircuitTarget { - constants_sigmas_cap: builder - .add_virtual_cap(verifier_data.common.config.fri_config.cap_height), - }; - pw.set_cap_target( - &inner_data.constants_sigmas_cap, - &verifier_data.verifier_only.constants_sigmas_cap, - ); - (pt, inner_data) - }); - - let pis: [_; NUM_TABLES] = std::array::from_fn(|i| { - PublicInputs::from_vec(&proofs_target[i].0.public_inputs, inner_config) - }); - - let mut challenger = RecursiveChallenger::::new(builder); - for pi in &pis { - for h in &pi.trace_cap { - challenger.observe_elements(h); - } - } - let ctl_challenges = get_grand_product_challenge_set_target( - builder, - &mut challenger, - inner_config.num_challenges, - ); - // Check that the correct CTL challenges are used in every proof. - for pi in &pis { - for i in 0..inner_config.num_challenges { - builder.connect( - ctl_challenges.challenges[i].beta, - pi.ctl_challenges.challenges[i].beta, - ); - builder.connect( - ctl_challenges.challenges[i].gamma, - pi.ctl_challenges.challenges[i].gamma, - ); - } - } - - let state = challenger.compact(builder); - for k in 0..SPONGE_WIDTH { - builder.connect(state[k], pis[0].challenger_state_before[k]); - } - // Check that the challenger state is consistent between proofs. - for i in 1..NUM_TABLES { - for k in 0..SPONGE_WIDTH { - builder.connect( - pis[i].challenger_state_before[k], - pis[i - 1].challenger_state_after[k], - ); - } - } - - // Verify the CTL checks. - let degrees_bits = std::array::from_fn(|i| verifier_data[i].common.degree_bits); - verify_cross_table_lookups_circuit::( - builder, - cross_table_lookups, - pis.map(|p| p.ctl_zs_last), - degrees_bits, - ctl_challenges, - inner_config, - ); - for (i, (proof_target, inner_data)) in proofs_target.into_iter().enumerate() { - builder.verify_proof(proof_target, &inner_data, &verifier_data[i].common); - } - } } /// Recursively verify a Stark proof. /// Outputs the recursive proof and the associated verifier data. +#[cfg(test)] fn recursively_verify_stark_proof< F: RichField + Extendable, C: GenericConfig, @@ -576,6 +489,7 @@ where } /// Recursively verify every Stark proof in an `AllProof`. +#[cfg(test)] pub fn recursively_verify_all_proof< F: RichField + Extendable, C: GenericConfig, @@ -934,12 +848,12 @@ pub fn add_virtual_stark_proof, S: Stark, con trace_cap: builder.add_virtual_cap(cap_height), permutation_ctl_zs_cap: permutation_zs_cap, quotient_polys_cap: builder.add_virtual_cap(cap_height), - openings: add_stark_opening_set::(builder, stark, num_ctl_zs, config), + openings: add_virtual_stark_opening_set::(builder, stark, num_ctl_zs, config), opening_proof: builder.add_virtual_fri_proof(&num_leaves_per_oracle, &fri_params), } } -fn add_stark_opening_set, S: Stark, const D: usize>( +fn add_virtual_stark_opening_set, S: Stark, const D: usize>( builder: &mut CircuitBuilder, stark: &S, num_ctl_zs: usize, From 39fc219324de23c7a08baa7f2cc0c7eecd4c49fb Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 6 Oct 2022 16:40:03 +0200 Subject: [PATCH 27/28] PR feedback --- evm/src/all_stark.rs | 3 +- evm/src/get_challenges.rs | 2 + evm/src/proof.rs | 1 + evm/src/recursive_verifier.rs | 411 ++++++++++++++++++---------------- 4 files changed, 225 insertions(+), 192 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 177591fd..0e2b7736 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -203,9 +203,10 @@ mod tests { use crate::memory::NUM_CHANNELS; use crate::proof::{AllProof, PublicValues}; use crate::prover::prove_with_traces; + use crate::recursive_verifier::tests::recursively_verify_all_proof; use crate::recursive_verifier::{ add_virtual_recursive_all_proof, all_verifier_data_recursive_stark_proof, - recursively_verify_all_proof, set_recursive_all_proof_target, RecursiveAllProof, + set_recursive_all_proof_target, RecursiveAllProof, }; use crate::stark::Stark; use crate::util::{limb_from_bits_le, trace_rows_to_poly_values}; diff --git a/evm/src/get_challenges.rs b/evm/src/get_challenges.rs index 9cb07c31..ede7c466 100644 --- a/evm/src/get_challenges.rs +++ b/evm/src/get_challenges.rs @@ -47,6 +47,8 @@ impl, C: GenericConfig, const D: usize> A ctl_challenges, } } + + #[allow(unused)] // TODO: should be used soon pub(crate) fn get_challenger_states( &self, all_stark: &AllStark, diff --git a/evm/src/proof.rs b/evm/src/proof.rs index e9002c62..4cd03a65 100644 --- a/evm/src/proof.rs +++ b/evm/src/proof.rs @@ -36,6 +36,7 @@ pub(crate) struct AllProofChallenges, const D: usiz pub ctl_challenges: GrandProductChallengeSet, } +#[allow(unused)] // TODO: should be used soon pub(crate) struct AllChallengerState, const D: usize> { /// Sponge state of the challenger before starting each proof, /// along with the final state after all proofs are done. This final state isn't strictly needed. diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index 1ef493a0..e94023a7 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -10,7 +10,7 @@ use plonky2::hash::hashing::SPONGE_WIDTH; use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::iop::target::Target; -use plonky2::iop::witness::{PartialWitness, Witness}; +use plonky2::iop::witness::Witness; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData, VerifierCircuitTarget}; use plonky2::plonk::config::Hasher; @@ -36,9 +36,9 @@ use crate::permutation::{ GrandProductChallengeSet, PermutationCheckDataTarget, }; use crate::proof::{ - AllChallengerState, AllProof, AllProofTarget, BlockMetadata, BlockMetadataTarget, PublicValues, - PublicValuesTarget, StarkOpeningSetTarget, StarkProof, StarkProofChallengesTarget, - StarkProofTarget, TrieRoots, TrieRootsTarget, + AllProof, AllProofTarget, BlockMetadata, BlockMetadataTarget, PublicValues, PublicValuesTarget, + StarkOpeningSetTarget, StarkProof, StarkProofChallengesTarget, StarkProofTarget, TrieRoots, + TrieRootsTarget, }; use crate::stark::Stark; use crate::util::h160_limbs; @@ -244,107 +244,6 @@ impl, C: GenericConfig, const D: usize> } } -/// Recursively verify a Stark proof. -/// Outputs the recursive proof and the associated verifier data. -#[cfg(test)] -fn recursively_verify_stark_proof< - F: RichField + Extendable, - C: GenericConfig, - S: Stark, - const D: usize, ->( - table: Table, - stark: S, - proof: &StarkProof, - cross_table_lookups: &[CrossTableLookup], - ctl_challenges: &GrandProductChallengeSet, - challenger_state_before_vals: [F; SPONGE_WIDTH], - inner_config: &StarkConfig, - circuit_config: &CircuitConfig, -) -> Result<(ProofWithPublicInputs, VerifierCircuitData)> -where - [(); S::COLUMNS]:, - [(); C::Hasher::HASH_SIZE]:, - C::Hasher: AlgebraicHasher, -{ - let mut builder = CircuitBuilder::::new(circuit_config.clone()); - let mut pw = PartialWitness::new(); - - let num_permutation_zs = stark.num_permutation_batches(inner_config); - let num_permutation_batch_size = stark.permutation_batch_size(); - let proof_target = add_virtual_stark_proof( - &mut builder, - &stark, - inner_config, - proof.recover_degree_bits(inner_config), - proof.num_ctl_zs(), - ); - set_stark_proof_target(&mut pw, &proof_target, proof, builder.zero()); - builder.register_public_inputs( - &proof_target - .trace_cap - .0 - .iter() - .flat_map(|h| h.elements) - .collect::>(), - ); - - let ctl_challenges_target = GrandProductChallengeSet { - challenges: (0..inner_config.num_challenges) - .map(|_| GrandProductChallenge { - beta: builder.add_virtual_public_input(), - gamma: builder.add_virtual_public_input(), - }) - .collect(), - }; - for i in 0..inner_config.num_challenges { - pw.set_target( - ctl_challenges_target.challenges[i].beta, - ctl_challenges.challenges[i].beta, - ); - pw.set_target( - ctl_challenges_target.challenges[i].gamma, - ctl_challenges.challenges[i].gamma, - ); - } - - let ctl_vars = CtlCheckVarsTarget::from_proof( - table, - &proof_target, - cross_table_lookups, - &ctl_challenges_target, - num_permutation_zs, - ); - - let challenger_state_before = std::array::from_fn(|_| builder.add_virtual_public_input()); - pw.set_target_arr(challenger_state_before, challenger_state_before_vals); - let mut challenger = - RecursiveChallenger::::from_state(challenger_state_before); - let challenges = proof_target.get_challenges::( - &mut builder, - &mut challenger, - num_permutation_zs > 0, - num_permutation_batch_size, - inner_config, - ); - let challenger_state_after = challenger.compact(&mut builder); - builder.register_public_inputs(&challenger_state_after); - - builder.register_public_inputs(&proof_target.openings.ctl_zs_last); - - verify_stark_proof_with_challenges_circuit::( - &mut builder, - &stark, - &proof_target, - &challenges, - &ctl_vars, - inner_config, - ); - - let data = builder.build::(); - Ok((data.prove(pw)?, data.verifier_data())) -} - /// Returns the verifier data for the recursive Stark circuit. fn verifier_data_recursive_stark_proof< F: RichField + Extendable, @@ -488,92 +387,6 @@ where ] } -/// Recursively verify every Stark proof in an `AllProof`. -#[cfg(test)] -pub fn recursively_verify_all_proof< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, ->( - all_stark: &AllStark, - all_proof: &AllProof, - inner_config: &StarkConfig, - circuit_config: &CircuitConfig, -) -> Result> -where - [(); CpuStark::::COLUMNS]:, - [(); KeccakStark::::COLUMNS]:, - [(); KeccakMemoryStark::::COLUMNS]:, - [(); LogicStark::::COLUMNS]:, - [(); MemoryStark::::COLUMNS]:, - [(); C::Hasher::HASH_SIZE]:, - C::Hasher: AlgebraicHasher, -{ - let AllChallengerState { - states, - ctl_challenges, - } = all_proof.get_challenger_states(all_stark, inner_config); - Ok(RecursiveAllProof { - recursive_proofs: [ - recursively_verify_stark_proof( - Table::Cpu, - all_stark.cpu_stark, - &all_proof.stark_proofs[Table::Cpu as usize], - &all_stark.cross_table_lookups, - &ctl_challenges, - states[0], - inner_config, - circuit_config, - )? - .0, - recursively_verify_stark_proof( - Table::Keccak, - all_stark.keccak_stark, - &all_proof.stark_proofs[Table::Keccak as usize], - &all_stark.cross_table_lookups, - &ctl_challenges, - states[1], - inner_config, - circuit_config, - )? - .0, - recursively_verify_stark_proof( - Table::KeccakMemory, - all_stark.keccak_memory_stark, - &all_proof.stark_proofs[Table::KeccakMemory as usize], - &all_stark.cross_table_lookups, - &ctl_challenges, - states[2], - inner_config, - circuit_config, - )? - .0, - recursively_verify_stark_proof( - Table::Logic, - all_stark.logic_stark, - &all_proof.stark_proofs[Table::Logic as usize], - &all_stark.cross_table_lookups, - &ctl_challenges, - states[3], - inner_config, - circuit_config, - )? - .0, - recursively_verify_stark_proof( - Table::Memory, - all_stark.memory_stark, - &all_proof.stark_proofs[Table::Memory as usize], - &all_stark.cross_table_lookups, - &ctl_challenges, - states[4], - inner_config, - circuit_config, - )? - .0, - ], - }) -} - /// Recursively verifies an inner proof. fn verify_stark_proof_with_challenges_circuit< F: RichField + Extendable, @@ -1028,3 +841,219 @@ pub fn set_block_metadata_target( F::from_canonical_u64(block_metadata.block_base_fee.as_u64()), ); } + +#[cfg(test)] +pub(crate) mod tests { + use anyhow::Result; + use plonky2::field::extension::Extendable; + use plonky2::hash::hash_types::RichField; + use plonky2::hash::hashing::SPONGE_WIDTH; + use plonky2::iop::challenger::RecursiveChallenger; + use plonky2::iop::witness::{PartialWitness, Witness}; + use plonky2::plonk::circuit_builder::CircuitBuilder; + use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData}; + use plonky2::plonk::config::Hasher; + use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; + use plonky2::plonk::proof::ProofWithPublicInputs; + + use crate::all_stark::{AllStark, Table}; + use crate::config::StarkConfig; + use crate::cpu::cpu_stark::CpuStark; + use crate::cross_table_lookup::{CrossTableLookup, CtlCheckVarsTarget}; + use crate::keccak::keccak_stark::KeccakStark; + use crate::keccak_memory::keccak_memory_stark::KeccakMemoryStark; + use crate::logic::LogicStark; + use crate::memory::memory_stark::MemoryStark; + use crate::permutation::{GrandProductChallenge, GrandProductChallengeSet}; + use crate::proof::{AllChallengerState, AllProof, StarkProof}; + use crate::recursive_verifier::{ + add_virtual_stark_proof, set_stark_proof_target, + verify_stark_proof_with_challenges_circuit, RecursiveAllProof, + }; + use crate::stark::Stark; + + /// Recursively verify a Stark proof. + /// Outputs the recursive proof and the associated verifier data. + fn recursively_verify_stark_proof< + F: RichField + Extendable, + C: GenericConfig, + S: Stark, + const D: usize, + >( + table: Table, + stark: S, + proof: &StarkProof, + cross_table_lookups: &[CrossTableLookup], + ctl_challenges: &GrandProductChallengeSet, + challenger_state_before_vals: [F; SPONGE_WIDTH], + inner_config: &StarkConfig, + circuit_config: &CircuitConfig, + ) -> Result<(ProofWithPublicInputs, VerifierCircuitData)> + where + [(); S::COLUMNS]:, + [(); C::Hasher::HASH_SIZE]:, + C::Hasher: AlgebraicHasher, + { + let mut builder = CircuitBuilder::::new(circuit_config.clone()); + let mut pw = PartialWitness::new(); + + let num_permutation_zs = stark.num_permutation_batches(inner_config); + let num_permutation_batch_size = stark.permutation_batch_size(); + let proof_target = add_virtual_stark_proof( + &mut builder, + &stark, + inner_config, + proof.recover_degree_bits(inner_config), + proof.num_ctl_zs(), + ); + set_stark_proof_target(&mut pw, &proof_target, proof, builder.zero()); + builder.register_public_inputs( + &proof_target + .trace_cap + .0 + .iter() + .flat_map(|h| h.elements) + .collect::>(), + ); + + let ctl_challenges_target = GrandProductChallengeSet { + challenges: (0..inner_config.num_challenges) + .map(|_| GrandProductChallenge { + beta: builder.add_virtual_public_input(), + gamma: builder.add_virtual_public_input(), + }) + .collect(), + }; + for i in 0..inner_config.num_challenges { + pw.set_target( + ctl_challenges_target.challenges[i].beta, + ctl_challenges.challenges[i].beta, + ); + pw.set_target( + ctl_challenges_target.challenges[i].gamma, + ctl_challenges.challenges[i].gamma, + ); + } + + let ctl_vars = CtlCheckVarsTarget::from_proof( + table, + &proof_target, + cross_table_lookups, + &ctl_challenges_target, + num_permutation_zs, + ); + + let challenger_state_before = std::array::from_fn(|_| builder.add_virtual_public_input()); + pw.set_target_arr(challenger_state_before, challenger_state_before_vals); + let mut challenger = + RecursiveChallenger::::from_state(challenger_state_before); + let challenges = proof_target.get_challenges::( + &mut builder, + &mut challenger, + num_permutation_zs > 0, + num_permutation_batch_size, + inner_config, + ); + let challenger_state_after = challenger.compact(&mut builder); + builder.register_public_inputs(&challenger_state_after); + + builder.register_public_inputs(&proof_target.openings.ctl_zs_last); + + verify_stark_proof_with_challenges_circuit::( + &mut builder, + &stark, + &proof_target, + &challenges, + &ctl_vars, + inner_config, + ); + + let data = builder.build::(); + Ok((data.prove(pw)?, data.verifier_data())) + } + + /// Recursively verify every Stark proof in an `AllProof`. + pub fn recursively_verify_all_proof< + F: RichField + Extendable, + C: GenericConfig, + const D: usize, + >( + all_stark: &AllStark, + all_proof: &AllProof, + inner_config: &StarkConfig, + circuit_config: &CircuitConfig, + ) -> Result> + where + [(); CpuStark::::COLUMNS]:, + [(); KeccakStark::::COLUMNS]:, + [(); KeccakMemoryStark::::COLUMNS]:, + [(); LogicStark::::COLUMNS]:, + [(); MemoryStark::::COLUMNS]:, + [(); C::Hasher::HASH_SIZE]:, + C::Hasher: AlgebraicHasher, + { + let AllChallengerState { + states, + ctl_challenges, + } = all_proof.get_challenger_states(all_stark, inner_config); + Ok(RecursiveAllProof { + recursive_proofs: [ + recursively_verify_stark_proof( + Table::Cpu, + all_stark.cpu_stark, + &all_proof.stark_proofs[Table::Cpu as usize], + &all_stark.cross_table_lookups, + &ctl_challenges, + states[0], + inner_config, + circuit_config, + )? + .0, + recursively_verify_stark_proof( + Table::Keccak, + all_stark.keccak_stark, + &all_proof.stark_proofs[Table::Keccak as usize], + &all_stark.cross_table_lookups, + &ctl_challenges, + states[1], + inner_config, + circuit_config, + )? + .0, + recursively_verify_stark_proof( + Table::KeccakMemory, + all_stark.keccak_memory_stark, + &all_proof.stark_proofs[Table::KeccakMemory as usize], + &all_stark.cross_table_lookups, + &ctl_challenges, + states[2], + inner_config, + circuit_config, + )? + .0, + recursively_verify_stark_proof( + Table::Logic, + all_stark.logic_stark, + &all_proof.stark_proofs[Table::Logic as usize], + &all_stark.cross_table_lookups, + &ctl_challenges, + states[3], + inner_config, + circuit_config, + )? + .0, + recursively_verify_stark_proof( + Table::Memory, + all_stark.memory_stark, + &all_proof.stark_proofs[Table::Memory as usize], + &all_stark.cross_table_lookups, + &ctl_challenges, + states[4], + inner_config, + circuit_config, + )? + .0, + ], + }) + } +} From 4ff6bbb3de8c7fb64d382db5a6e8714a97bef5b2 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Fri, 7 Oct 2022 09:47:03 +0200 Subject: [PATCH 28/28] Hardcode verifier data in the circuit --- evm/src/all_stark.rs | 24 ++++++++++-------------- evm/src/recursive_verifier.rs | 23 ++++++++++------------- plonky2/src/plonk/circuit_builder.rs | 16 +++++++++++++++- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 0e2b7736..26840c5f 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -185,12 +185,12 @@ mod tests { use plonky2::field::types::{Field, PrimeField64}; use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; - use plonky2::plonk::circuit_data::CircuitConfig; + use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData}; use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use plonky2::util::timing::TimingTree; use rand::{thread_rng, Rng}; - use crate::all_stark::AllStark; + use crate::all_stark::{AllStark, NUM_TABLES}; use crate::config::StarkConfig; use crate::cpu::cpu_stark::CpuStark; use crate::cpu::kernel::aggregator::KERNEL; @@ -773,23 +773,19 @@ mod tests { &circuit_config, )?; - let verifier_data = all_verifier_data_recursive_stark_proof( - &inner_all_stark, - inner_proof.degree_bits(inner_config), - inner_config, - &circuit_config, - ); + let verifier_data: [VerifierCircuitData; NUM_TABLES] = + all_verifier_data_recursive_stark_proof( + &inner_all_stark, + inner_proof.degree_bits(inner_config), + inner_config, + &circuit_config, + ); let circuit_config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(circuit_config); let mut pw = PartialWitness::new(); let recursive_all_proof_target = add_virtual_recursive_all_proof(&mut builder, &verifier_data); - set_recursive_all_proof_target( - &mut pw, - &recursive_all_proof_target, - &recursive_all_proof, - &verifier_data, - ); + set_recursive_all_proof_target(&mut pw, &recursive_all_proof_target, &recursive_all_proof); RecursiveAllProof::verify_circuit( &mut builder, recursive_all_proof_target, diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index e94023a7..a16063c4 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -5,7 +5,7 @@ use itertools::Itertools; use plonky2::field::extension::Extendable; use plonky2::field::types::Field; use plonky2::fri::witness_util::set_fri_proof_target; -use plonky2::hash::hash_types::RichField; +use plonky2::hash::hash_types::{HashOut, RichField}; use plonky2::hash::hashing::SPONGE_WIDTH; use plonky2::iop::challenger::{Challenger, RecursiveChallenger}; use plonky2::iop::ext_target::ExtensionTarget; @@ -567,14 +567,16 @@ pub fn add_virtual_all_proof, const D: usize>( } } -pub fn add_virtual_recursive_all_proof< - F: RichField + Extendable, - C: GenericConfig, - const D: usize, ->( +/// Returns `RecursiveAllProofTargetWithData` where the proofs targets are virtual and the +/// verifier data targets are constants. +pub fn add_virtual_recursive_all_proof, H, C, const D: usize>( builder: &mut CircuitBuilder, verifier_data: &[VerifierCircuitData; NUM_TABLES], -) -> RecursiveAllProofTargetWithData { +) -> RecursiveAllProofTargetWithData +where + H: Hasher>, + C: GenericConfig, +{ let recursive_proofs = std::array::from_fn(|i| { let verifier_data = &verifier_data[i]; builder.add_virtual_proof_with_pis(&verifier_data.common) @@ -583,7 +585,7 @@ pub fn add_virtual_recursive_all_proof< let verifier_data = &verifier_data[i]; VerifierCircuitTarget { constants_sigmas_cap: builder - .add_virtual_cap(verifier_data.common.config.fri_config.cap_height), + .constant_merkle_cap(&verifier_data.verifier_only.constants_sigmas_cap), } }); RecursiveAllProofTargetWithData { @@ -690,7 +692,6 @@ pub fn set_recursive_all_proof_target, W, const D: witness: &mut W, recursive_all_proof_target: &RecursiveAllProofTargetWithData, all_proof: &RecursiveAllProof, - verifier_data: &[VerifierCircuitData; NUM_TABLES], ) where F: RichField + Extendable, C::Hasher: AlgebraicHasher, @@ -701,10 +702,6 @@ pub fn set_recursive_all_proof_target, W, const D: &recursive_all_proof_target.recursive_proofs[i], &all_proof.recursive_proofs[i], ); - witness.set_cap_target( - &recursive_all_proof_target.verifier_data[i].constants_sigmas_cap, - &verifier_data[i].verifier_only.constants_sigmas_cap, - ); } } pub fn set_all_proof_target, W, const D: usize>( diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index 05fe649b..bfa012da 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -23,8 +23,9 @@ use crate::gates::gate::{CurrentSlot, Gate, GateInstance, GateRef}; use crate::gates::noop::NoopGate; use crate::gates::public_input::PublicInputGate; use crate::gates::selectors::selector_polynomials; -use crate::hash::hash_types::{HashOutTarget, MerkleCapTarget, RichField}; +use crate::hash::hash_types::{HashOut, HashOutTarget, MerkleCapTarget, RichField}; use crate::hash::merkle_proofs::MerkleProofTarget; +use crate::hash::merkle_tree::MerkleCap; use crate::iop::ext_target::ExtensionTarget; use crate::iop::generator::{ ConstantGenerator, CopyGenerator, RandomValueGenerator, SimpleGenerator, WitnessGenerator, @@ -368,6 +369,19 @@ impl, const D: usize> CircuitBuilder { } } + pub fn constant_hash(&mut self, h: HashOut) -> HashOutTarget { + HashOutTarget { + elements: h.elements.map(|x| self.constant(x)), + } + } + + pub fn constant_merkle_cap>>( + &mut self, + cap: &MerkleCap, + ) -> MerkleCapTarget { + MerkleCapTarget(cap.0.iter().map(|h| self.constant_hash(*h)).collect()) + } + /// If the given target is a constant (i.e. it was created by the `constant(F)` method), returns /// its constant value. Otherwise, returns `None`. pub fn target_as_constant(&self, target: Target) -> Option {