From 662c8db3bd8b5935d9e3f3a159de079adc819085 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Sat, 21 Sep 2024 09:13:48 -0700 Subject: [PATCH 01/29] refactoring --- .../src/fixed_recursive_verifier.rs | 95 +++------ evm_arithmetization/src/prover.rs | 181 +++--------------- evm_arithmetization/src/verifier.rs | 103 +++------- 3 files changed, 79 insertions(+), 300 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 7f3842826..cb3cec8a8 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -697,77 +697,30 @@ where // Sanity check on the provided config assert_eq!(DEFAULT_CAP_LEN, 1 << stark_config.fri_config.cap_height); - let arithmetic = RecursiveCircuitsForTable::new( - Table::Arithmetic, - &all_stark.arithmetic_stark, - degree_bits_ranges[*Table::Arithmetic].clone(), - &all_stark.cross_table_lookups, - stark_config, - ); - let byte_packing = RecursiveCircuitsForTable::new( - Table::BytePacking, - &all_stark.byte_packing_stark, - degree_bits_ranges[*Table::BytePacking].clone(), - &all_stark.cross_table_lookups, - stark_config, - ); - let cpu = RecursiveCircuitsForTable::new( - Table::Cpu, - &all_stark.cpu_stark, - degree_bits_ranges[*Table::Cpu].clone(), - &all_stark.cross_table_lookups, - stark_config, - ); - let keccak = RecursiveCircuitsForTable::new( - Table::Keccak, - &all_stark.keccak_stark, - degree_bits_ranges[*Table::Keccak].clone(), - &all_stark.cross_table_lookups, - stark_config, - ); - let keccak_sponge = RecursiveCircuitsForTable::new( - Table::KeccakSponge, - &all_stark.keccak_sponge_stark, - degree_bits_ranges[*Table::KeccakSponge].clone(), - &all_stark.cross_table_lookups, - stark_config, - ); - let logic = RecursiveCircuitsForTable::new( - Table::Logic, - &all_stark.logic_stark, - degree_bits_ranges[*Table::Logic].clone(), - &all_stark.cross_table_lookups, - stark_config, - ); - let memory = RecursiveCircuitsForTable::new( - Table::Memory, - &all_stark.memory_stark, - degree_bits_ranges[*Table::Memory].clone(), - &all_stark.cross_table_lookups, - stark_config, - ); - let mem_before = RecursiveCircuitsForTable::new( - Table::MemBefore, - &all_stark.mem_before_stark, - degree_bits_ranges[*Table::MemBefore].clone(), - &all_stark.cross_table_lookups, - stark_config, - ); - let mem_after = RecursiveCircuitsForTable::new( - Table::MemAfter, - &all_stark.mem_after_stark, - degree_bits_ranges[*Table::MemAfter].clone(), - &all_stark.cross_table_lookups, - stark_config, - ); + macro_rules! create_recursive_circuit { + ($table_enum:expr, $stark_field:ident) => { + RecursiveCircuitsForTable::new( + $table_enum, + &all_stark.$stark_field, + degree_bits_ranges[*$table_enum].clone(), + &all_stark.cross_table_lookups, + stark_config, + ) + }; + } + + let arithmetic = create_recursive_circuit!(Table::Arithmetic, arithmetic_stark); + let byte_packing = create_recursive_circuit!(Table::BytePacking, byte_packing_stark); + let cpu = create_recursive_circuit!(Table::Cpu, cpu_stark); + let keccak = create_recursive_circuit!(Table::Keccak, keccak_stark); + let keccak_sponge = create_recursive_circuit!(Table::KeccakSponge, keccak_sponge_stark); + let logic = create_recursive_circuit!(Table::Logic, logic_stark); + let memory = create_recursive_circuit!(Table::Memory, memory_stark); + let mem_before = create_recursive_circuit!(Table::MemBefore, mem_before_stark); + let mem_after = create_recursive_circuit!(Table::MemAfter, mem_after_stark); + #[cfg(feature = "cdk_erigon")] - let poseidon = RecursiveCircuitsForTable::new( - Table::Poseidon, - &all_stark.poseidon_stark, - degree_bits_ranges[*Table::Poseidon].clone(), - &all_stark.cross_table_lookups, - stark_config, - ); + let poseidon = create_recursive_circuit!(Table::Poseidon, poseidon_stark); let by_table = [ arithmetic, @@ -782,6 +735,7 @@ where #[cfg(feature = "cdk_erigon")] poseidon, ]; + let root = Self::create_segment_circuit(&by_table, stark_config); let segment_aggregation = Self::create_segment_aggregation_circuit(&root); let txn_aggregation = @@ -789,6 +743,7 @@ where let block = Self::create_block_circuit(&txn_aggregation); let block_wrapper = Self::create_block_wrapper_circuit(&block); let two_to_one_block = Self::create_two_to_one_block_circuit(&block_wrapper); + Self { root, segment_aggregation, diff --git a/evm_arithmetization/src/prover.rs b/evm_arithmetization/src/prover.rs index 0cd825e87..079fe3469 100644 --- a/evm_arithmetization/src/prover.rs +++ b/evm_arithmetization/src/prover.rs @@ -239,157 +239,38 @@ where F: RichField + Extendable, C: GenericConfig, { - let (arithmetic_proof, _) = timed!( - timing, - "prove Arithmetic STARK", - prove_single_table( - &all_stark.arithmetic_stark, - config, - &trace_poly_values[*Table::Arithmetic], - &trace_commitments[*Table::Arithmetic], - &ctl_data_per_table[*Table::Arithmetic], - ctl_challenges, - challenger, - timing, - abort_signal.clone(), - )? - ); - let (byte_packing_proof, _) = timed!( - timing, - "prove byte packing STARK", - prove_single_table( - &all_stark.byte_packing_stark, - config, - &trace_poly_values[*Table::BytePacking], - &trace_commitments[*Table::BytePacking], - &ctl_data_per_table[*Table::BytePacking], - ctl_challenges, - challenger, - timing, - abort_signal.clone(), - )? - ); - let (cpu_proof, _) = timed!( - timing, - "prove CPU STARK", - prove_single_table( - &all_stark.cpu_stark, - config, - &trace_poly_values[*Table::Cpu], - &trace_commitments[*Table::Cpu], - &ctl_data_per_table[*Table::Cpu], - ctl_challenges, - challenger, - timing, - abort_signal.clone(), - )? - ); - let (keccak_proof, _) = timed!( - timing, - "prove Keccak STARK", - prove_single_table( - &all_stark.keccak_stark, - config, - &trace_poly_values[*Table::Keccak], - &trace_commitments[*Table::Keccak], - &ctl_data_per_table[*Table::Keccak], - ctl_challenges, - challenger, - timing, - abort_signal.clone(), - )? - ); - let (keccak_sponge_proof, _) = timed!( - timing, - "prove Keccak sponge STARK", - prove_single_table( - &all_stark.keccak_sponge_stark, - config, - &trace_poly_values[*Table::KeccakSponge], - &trace_commitments[*Table::KeccakSponge], - &ctl_data_per_table[*Table::KeccakSponge], - ctl_challenges, - challenger, - timing, - abort_signal.clone(), - )? - ); - let (logic_proof, _) = timed!( - timing, - "prove logic STARK", - prove_single_table( - &all_stark.logic_stark, - config, - &trace_poly_values[*Table::Logic], - &trace_commitments[*Table::Logic], - &ctl_data_per_table[*Table::Logic], - ctl_challenges, - challenger, - timing, - abort_signal.clone(), - )? - ); - let (memory_proof, _) = timed!( - timing, - "prove memory STARK", - prove_single_table( - &all_stark.memory_stark, - config, - &trace_poly_values[*Table::Memory], - &trace_commitments[*Table::Memory], - &ctl_data_per_table[*Table::Memory], - ctl_challenges, - challenger, - timing, - abort_signal.clone(), - )? - ); - let (mem_before_proof, mem_before_cap) = timed!( - timing, - "prove mem_before STARK", - prove_single_table( - &all_stark.mem_before_stark, - config, - &trace_poly_values[*Table::MemBefore], - &trace_commitments[*Table::MemBefore], - &ctl_data_per_table[*Table::MemBefore], - ctl_challenges, - challenger, - timing, - abort_signal.clone(), - )? - ); - let (mem_after_proof, mem_after_cap) = timed!( - timing, - "prove mem_after STARK", - prove_single_table( - &all_stark.mem_after_stark, - config, - &trace_poly_values[*Table::MemAfter], - &trace_commitments[*Table::MemAfter], - &ctl_data_per_table[*Table::MemAfter], - ctl_challenges, - challenger, - timing, - abort_signal.clone(), - )? - ); + macro_rules! prove_table { + ($stark:ident, $table:expr) => { + timed!( + timing, + &format!("prove {} STARK", stringify!($stark)), + prove_single_table( + &all_stark.$stark, + config, + &trace_poly_values[*$table], + &trace_commitments[*$table], + &ctl_data_per_table[*$table], + ctl_challenges, + challenger, + timing, + abort_signal.clone(), + )? + ) + }; + } + + let (arithmetic_proof, _) = prove_table!(arithmetic_stark, Table::Arithmetic); + let (byte_packing_proof, _) = prove_table!(byte_packing_stark, Table::BytePacking); + let (cpu_proof, _) = prove_table!(cpu_stark, Table::Cpu); + let (keccak_proof, _) = prove_table!(keccak_stark, Table::Keccak); + let (keccak_sponge_proof, _) = prove_table!(keccak_sponge_stark, Table::KeccakSponge); + let (logic_proof, _) = prove_table!(logic_stark, Table::Logic); + let (memory_proof, _) = prove_table!(memory_stark, Table::Memory); + let (mem_before_proof, mem_before_cap) = prove_table!(mem_before_stark, Table::MemBefore); + let (mem_after_proof, mem_after_cap) = prove_table!(mem_after_stark, Table::MemAfter); + #[cfg(feature = "cdk_erigon")] - let (poseidon_proof, _) = timed!( - timing, - "prove poseidon STARK", - prove_single_table( - &all_stark.poseidon_stark, - config, - &trace_poly_values[*Table::Poseidon], - &trace_commitments[*Table::Poseidon], - &ctl_data_per_table[*Table::Poseidon], - ctl_challenges, - challenger, - timing, - abort_signal, - )? - ); + let (poseidon_proof, _) = prove_table!(poseidon_stark, Table::Poseidon); Ok(( [ diff --git a/evm_arithmetization/src/verifier.rs b/evm_arithmetization/src/verifier.rs index 9ee5750f8..caa01859e 100644 --- a/evm_arithmetization/src/verifier.rs +++ b/evm_arithmetization/src/verifier.rs @@ -156,88 +156,31 @@ fn verify_proof, C: GenericConfig, const let stark_proofs = &all_proof.multi_proof.stark_proofs; - verify_stark_proof_with_challenges( - arithmetic_stark, - &stark_proofs[*Table::Arithmetic].proof, - &stark_challenges[*Table::Arithmetic], - Some(&ctl_vars_per_table[*Table::Arithmetic]), - &[], - config, - )?; + macro_rules! verify_table { + ($stark:ident, $table:expr) => { + verify_stark_proof_with_challenges( + $stark, + &stark_proofs[*$table].proof, + &stark_challenges[*$table], + Some(&ctl_vars_per_table[*$table]), + &[], + config, + )?; + }; + } + + verify_table!(arithmetic_stark, Table::Arithmetic); + verify_table!(byte_packing_stark, Table::BytePacking); + verify_table!(cpu_stark, Table::Cpu); + verify_table!(keccak_stark, Table::Keccak); + verify_table!(keccak_sponge_stark, Table::KeccakSponge); + verify_table!(logic_stark, Table::Logic); + verify_table!(memory_stark, Table::Memory); + verify_table!(mem_before_stark, Table::MemBefore); + verify_table!(mem_after_stark, Table::MemAfter); - verify_stark_proof_with_challenges( - byte_packing_stark, - &stark_proofs[*Table::BytePacking].proof, - &stark_challenges[*Table::BytePacking], - Some(&ctl_vars_per_table[*Table::BytePacking]), - &[], - config, - )?; - verify_stark_proof_with_challenges( - cpu_stark, - &stark_proofs[*Table::Cpu].proof, - &stark_challenges[*Table::Cpu], - Some(&ctl_vars_per_table[*Table::Cpu]), - &[], - config, - )?; - verify_stark_proof_with_challenges( - keccak_stark, - &stark_proofs[*Table::Keccak].proof, - &stark_challenges[*Table::Keccak], - Some(&ctl_vars_per_table[*Table::Keccak]), - &[], - config, - )?; - verify_stark_proof_with_challenges( - keccak_sponge_stark, - &stark_proofs[*Table::KeccakSponge].proof, - &stark_challenges[*Table::KeccakSponge], - Some(&ctl_vars_per_table[*Table::KeccakSponge]), - &[], - config, - )?; - verify_stark_proof_with_challenges( - logic_stark, - &stark_proofs[*Table::Logic].proof, - &stark_challenges[*Table::Logic], - Some(&ctl_vars_per_table[*Table::Logic]), - &[], - config, - )?; - verify_stark_proof_with_challenges( - memory_stark, - &stark_proofs[*Table::Memory].proof, - &stark_challenges[*Table::Memory], - Some(&ctl_vars_per_table[*Table::Memory]), - &[], - config, - )?; - verify_stark_proof_with_challenges( - mem_before_stark, - &stark_proofs[*Table::MemBefore].proof, - &stark_challenges[*Table::MemBefore], - Some(&ctl_vars_per_table[*Table::MemBefore]), - &[], - config, - )?; - verify_stark_proof_with_challenges( - mem_after_stark, - &stark_proofs[*Table::MemAfter].proof, - &stark_challenges[*Table::MemAfter], - Some(&ctl_vars_per_table[*Table::MemAfter]), - &[], - config, - )?; #[cfg(feature = "cdk_erigon")] - verify_stark_proof_with_challenges( - poseidon_stark, - &stark_proofs[*Table::Poseidon].proof, - &stark_challenges[*Table::Poseidon], - Some(&ctl_vars_per_table[*Table::Poseidon]), - &[], - config, - )?; + verify_table!(poseidon_stark, Table::Poseidon); let public_values = all_proof.public_values; From d82b1a88d3a6824e4b84525fdc4d866553b4e8dc Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Sat, 21 Sep 2024 09:39:48 -0700 Subject: [PATCH 02/29] fix clippy --- evm_arithmetization/src/arithmetic/arithmetic_stark.rs | 3 ++- evm_arithmetization/src/byte_packing/byte_packing_stark.rs | 3 ++- evm_arithmetization/src/cpu/cpu_stark.rs | 3 ++- evm_arithmetization/src/keccak/keccak_stark.rs | 3 ++- evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs | 3 ++- evm_arithmetization/src/logic.rs | 3 ++- evm_arithmetization/src/memory/memory_stark.rs | 3 ++- .../src/memory_continuation/memory_continuation_stark.rs | 3 ++- evm_arithmetization/src/poseidon/poseidon_stark.rs | 3 ++- 9 files changed, 18 insertions(+), 9 deletions(-) diff --git a/evm_arithmetization/src/arithmetic/arithmetic_stark.rs b/evm_arithmetization/src/arithmetic/arithmetic_stark.rs index d0712a3bc..2b7eb2507 100644 --- a/evm_arithmetization/src/arithmetic/arithmetic_stark.rs +++ b/evm_arithmetization/src/arithmetic/arithmetic_stark.rs @@ -191,7 +191,8 @@ impl ArithmeticStark { } impl, const D: usize> Stark for ArithmeticStark { - type EvaluationFrame = EvmStarkFrame + type EvaluationFrame + = EvmStarkFrame where FE: FieldExtension, P: PackedField; diff --git a/evm_arithmetization/src/byte_packing/byte_packing_stark.rs b/evm_arithmetization/src/byte_packing/byte_packing_stark.rs index 018c23e14..af62a5079 100644 --- a/evm_arithmetization/src/byte_packing/byte_packing_stark.rs +++ b/evm_arithmetization/src/byte_packing/byte_packing_stark.rs @@ -285,7 +285,8 @@ impl, const D: usize> BytePackingStark { } impl, const D: usize> Stark for BytePackingStark { - type EvaluationFrame = EvmStarkFrame + type EvaluationFrame + = EvmStarkFrame where FE: FieldExtension, P: PackedField; diff --git a/evm_arithmetization/src/cpu/cpu_stark.rs b/evm_arithmetization/src/cpu/cpu_stark.rs index 386f89519..a0dd45e1e 100644 --- a/evm_arithmetization/src/cpu/cpu_stark.rs +++ b/evm_arithmetization/src/cpu/cpu_stark.rs @@ -581,7 +581,8 @@ pub(crate) struct CpuStark { } impl, const D: usize> Stark for CpuStark { - type EvaluationFrame = EvmStarkFrame + type EvaluationFrame + = EvmStarkFrame where FE: FieldExtension, P: PackedField; diff --git a/evm_arithmetization/src/keccak/keccak_stark.rs b/evm_arithmetization/src/keccak/keccak_stark.rs index 5f505cf06..0a086d03d 100644 --- a/evm_arithmetization/src/keccak/keccak_stark.rs +++ b/evm_arithmetization/src/keccak/keccak_stark.rs @@ -255,7 +255,8 @@ impl, const D: usize> KeccakStark { } impl, const D: usize> Stark for KeccakStark { - type EvaluationFrame = EvmStarkFrame + type EvaluationFrame + = EvmStarkFrame where FE: FieldExtension, P: PackedField; diff --git a/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs b/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs index b517117a3..26cc76431 100644 --- a/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs +++ b/evm_arithmetization/src/keccak_sponge/keccak_sponge_stark.rs @@ -534,7 +534,8 @@ impl, const D: usize> KeccakSpongeStark { } impl, const D: usize> Stark for KeccakSpongeStark { - type EvaluationFrame = EvmStarkFrame + type EvaluationFrame + = EvmStarkFrame where FE: FieldExtension, P: PackedField; diff --git a/evm_arithmetization/src/logic.rs b/evm_arithmetization/src/logic.rs index eae7c972b..0ba378b52 100644 --- a/evm_arithmetization/src/logic.rs +++ b/evm_arithmetization/src/logic.rs @@ -237,7 +237,8 @@ impl LogicStark { } impl, const D: usize> Stark for LogicStark { - type EvaluationFrame = EvmStarkFrame + type EvaluationFrame + = EvmStarkFrame where FE: FieldExtension, P: PackedField; diff --git a/evm_arithmetization/src/memory/memory_stark.rs b/evm_arithmetization/src/memory/memory_stark.rs index e58a85a26..357e72095 100644 --- a/evm_arithmetization/src/memory/memory_stark.rs +++ b/evm_arithmetization/src/memory/memory_stark.rs @@ -463,7 +463,8 @@ impl, const D: usize> MemoryStark { } impl, const D: usize> Stark for MemoryStark { - type EvaluationFrame = EvmStarkFrame + type EvaluationFrame + = EvmStarkFrame where FE: FieldExtension, P: PackedField; diff --git a/evm_arithmetization/src/memory_continuation/memory_continuation_stark.rs b/evm_arithmetization/src/memory_continuation/memory_continuation_stark.rs index 72c869b61..107c8dd5d 100644 --- a/evm_arithmetization/src/memory_continuation/memory_continuation_stark.rs +++ b/evm_arithmetization/src/memory_continuation/memory_continuation_stark.rs @@ -99,7 +99,8 @@ impl, const D: usize> MemoryContinuationStark } impl, const D: usize> Stark for MemoryContinuationStark { - type EvaluationFrame = EvmStarkFrame + type EvaluationFrame + = EvmStarkFrame where FE: FieldExtension, P: PackedField; diff --git a/evm_arithmetization/src/poseidon/poseidon_stark.rs b/evm_arithmetization/src/poseidon/poseidon_stark.rs index 0aacbaa50..ff4b5aed7 100644 --- a/evm_arithmetization/src/poseidon/poseidon_stark.rs +++ b/evm_arithmetization/src/poseidon/poseidon_stark.rs @@ -427,7 +427,8 @@ impl, const D: usize> PoseidonStark { } impl, const D: usize> Stark for PoseidonStark { - type EvaluationFrame = EvmStarkFrame + type EvaluationFrame + = EvmStarkFrame where FE: FieldExtension, P: PackedField; From 449887052f52b9ff58fa628757caf745603c075d Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Sat, 21 Sep 2024 10:00:17 -0700 Subject: [PATCH 03/29] fix clippy --- evm_arithmetization/src/poseidon/poseidon_stark.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evm_arithmetization/src/poseidon/poseidon_stark.rs b/evm_arithmetization/src/poseidon/poseidon_stark.rs index ff4b5aed7..ae6f485fb 100644 --- a/evm_arithmetization/src/poseidon/poseidon_stark.rs +++ b/evm_arithmetization/src/poseidon/poseidon_stark.rs @@ -429,9 +429,9 @@ impl, const D: usize> PoseidonStark { impl, const D: usize> Stark for PoseidonStark { type EvaluationFrame = EvmStarkFrame - where - FE: FieldExtension, - P: PackedField; + where + FE: FieldExtension, + P: PackedField; type EvaluationFrameTarget = EvmStarkFrame, ExtensionTarget, NUM_COLUMNS>; From b14417fa8df83786c8354f3dbdf93767ed7fd77d Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Sun, 22 Sep 2024 14:36:52 -0700 Subject: [PATCH 04/29] wip --- .../src/fixed_recursive_verifier.rs | 40 +++++++++ evm_arithmetization/src/testing_utils.rs | 84 ++++++++++++++++++- 2 files changed, 122 insertions(+), 2 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index cb3cec8a8..17b504b5c 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -36,6 +36,7 @@ use starky::proof::StarkProofWithMetadata; use starky::stark::Stark; use crate::all_stark::{all_cross_table_lookups, AllStark, Table, NUM_TABLES}; +use crate::all_stark::Table::Keccak; use crate::cpu::kernel::aggregator::KERNEL; use crate::generation::segments::{GenerationSegmentData, SegmentDataIterator, SegmentError}; use crate::generation::{GenerationInputs, TrimmedGenerationInputs}; @@ -1816,6 +1817,8 @@ where timing, abort_signal.clone(), )?; + dbg!(&all_proof.multi_proof.stark_proofs[*Table::Keccak].proof.trace_cap); + dbg!(&all_proof.multi_proof.stark_proofs[*Table::KeccakSponge].proof.trace_cap); let mut root_inputs = PartialWitness::new(); for table in 0..NUM_TABLES { @@ -2944,3 +2947,40 @@ where circuit.verifier_only.circuit_digest.elements.len() + (1 << circuit.common.config.fri_config.cap_height) * NUM_HASH_OUT_ELTS } + +#[cfg(test)] +mod tests { + use plonky2::field::goldilocks_field::GoldilocksField; + use plonky2::plonk::config::PoseidonGoldilocksConfig; + + use super::*; + use crate::testing_utils::{dummy_payload, init_logger}; + + type F = GoldilocksField; + const D: usize = 2; + type C = PoseidonGoldilocksConfig; + + #[test] + #[ignore] + fn test_root_proof_generation() -> anyhow::Result<()> { + init_logger(); + + let all_stark = AllStark::::default(); + let config = StarkConfig::standard_fast_config(); + + let all_circuits = AllRecursiveCircuits::::new( + &all_stark, + &[16..17, 8..9, 9..10, 4..9, 8..9, 4..7, 17..18, 17..18, 7..18], + &config, + ); + let dummy = dummy_payload(100, true)?; + + let timing = &mut TimingTree::new(&format!("Blockproof"), log::Level::Info); + let dummy_proof = + all_circuits.prove_all_segments(&all_stark, &config, dummy, 9, timing, None)?; + all_circuits.verify_root(dummy_proof[0].proof_with_pis.clone())?; + timing.print(); + + Ok(()) + } +} diff --git a/evm_arithmetization/src/testing_utils.rs b/evm_arithmetization/src/testing_utils.rs index 7018e06be..528cae9ed 100644 --- a/evm_arithmetization/src/testing_utils.rs +++ b/evm_arithmetization/src/testing_utils.rs @@ -1,18 +1,22 @@ //! A set of utility functions and constants to be used by `evm_arithmetization` //! unit and integration tests. +use anyhow::Result; use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; -use ethereum_types::{BigEndianHash, H256, U256}; +use ethereum_types::{Address, BigEndianHash, H256, U256}; use hex_literal::hex; use keccak_hash::keccak; use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, Node, PartialTrie}, }; +use plonky2::field::goldilocks_field::GoldilocksField; pub use crate::cpu::kernel::cancun_constants::*; pub use crate::cpu::kernel::constants::global_exit_root::*; -use crate::{generation::mpt::AccountRlp, proof::BlockMetadata, util::h2u}; +use crate::generation::TrieInputs; +use crate::proof::TrieRoots; +use crate::{generation::mpt::AccountRlp, proof::BlockMetadata, util::h2u, GenerationInputs}; pub const EMPTY_NODE_HASH: H256 = H256(hex!( "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" @@ -161,3 +165,79 @@ pub fn scalable_contract_from_storage(storage_trie: &HashedPartialTrie) -> Accou ..Default::default() } } + +/// Get `GenerationInputs` for a dummy payload, where the block has the given +/// timestamp. +pub fn dummy_payload( + timestamp: u64, + is_first_payload: bool, +) -> Result> { + let beneficiary = hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + + let block_metadata = BlockMetadata { + block_beneficiary: Address::from(beneficiary), + block_timestamp: timestamp.into(), + block_number: 1.into(), + block_difficulty: 0x020000.into(), + block_random: H256::from_uint(&0x020000.into()), + block_gaslimit: 0xff112233u32.into(), + block_chain_id: 1.into(), + block_base_fee: 0xa.into(), + ..Default::default() + }; + + let (mut state_trie_before, mut storage_tries) = preinitialized_state_and_storage_tries()?; + let checkpoint_state_trie_root = state_trie_before.hash(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); + + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + )?; + let updated_beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + + if !is_first_payload { + // This isn't the first dummy payload being processed. We need to update the + // initial state trie to account for the update on the beacon roots contract. + state_trie_before.insert( + beacon_roots_account_nibbles(), + rlp::encode(&updated_beacon_roots_account).to_vec(), + )?; + storage_tries[0].1 = beacon_roots_account_storage; + } + + let tries_before = TrieInputs { + state_trie: state_trie_before, + storage_tries, + ..Default::default() + }; + + let expected_state_trie_after: HashedPartialTrie = { + let mut state_trie_after = HashedPartialTrie::from(crate::Node::Empty); + state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&updated_beacon_roots_account).to_vec(), + )?; + + state_trie_after + }; + + let trie_roots_after = TrieRoots { + state_root: expected_state_trie_after.hash(), + transactions_root: tries_before.transactions_trie.hash(), + receipts_root: tries_before.receipts_trie.hash(), + }; + + let inputs = GenerationInputs { + tries: tries_before.clone(), + burn_addr: None, + trie_roots_after, + checkpoint_state_trie_root, + block_metadata, + ..Default::default() + }; + + Ok(inputs) +} From eabcf5e51395e8b0d788ca6bed9bb0c3523c5788 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Sun, 22 Sep 2024 15:58:50 -0700 Subject: [PATCH 05/29] wip --- evm_arithmetization/src/all_stark.rs | 4 ++ .../src/fixed_recursive_verifier.rs | 39 +++++++++++++++---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/evm_arithmetization/src/all_stark.rs b/evm_arithmetization/src/all_stark.rs index f37021897..d899d9e50 100644 --- a/evm_arithmetization/src/all_stark.rs +++ b/evm_arithmetization/src/all_stark.rs @@ -126,6 +126,10 @@ pub const NUM_TABLES: usize = if cfg!(feature = "cdk_erigon") { Table::MemAfter as usize + 1 }; +/// Indices of Keccak Tables +pub const KECCAK_TABLES_INDICES: [usize; 2] = + [Table::Keccak as usize, Table::KeccakSponge as usize]; + impl Table { /// Returns all STARK table indices. pub(crate) const fn all() -> [Self; NUM_TABLES] { diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 17b504b5c..927712b52 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -35,8 +35,10 @@ use starky::lookup::{get_grand_product_challenge_set_target, GrandProductChallen use starky::proof::StarkProofWithMetadata; use starky::stark::Stark; -use crate::all_stark::{all_cross_table_lookups, AllStark, Table, NUM_TABLES}; use crate::all_stark::Table::Keccak; +use crate::all_stark::{ + all_cross_table_lookups, AllStark, Table, KECCAK_TABLES_INDICES, NUM_TABLES, +}; use crate::cpu::kernel::aggregator::KERNEL; use crate::generation::segments::{GenerationSegmentData, SegmentDataIterator, SegmentError}; use crate::generation::{GenerationInputs, TrimmedGenerationInputs}; @@ -129,6 +131,8 @@ where /// for EVM root proofs; the circuit has them just to match the /// structure of aggregation proofs. cyclic_vk: VerifierCircuitTarget, + /// We can skip verifying Keccak tables when they are not in use. + enable_keccak_tables: BoolTarget, } impl RootCircuitData @@ -785,6 +789,7 @@ where let mut builder = CircuitBuilder::new(CircuitConfig::standard_recursion_config()); + let enable_keccak_tables = builder.add_virtual_bool_target_safe(); let public_values = add_virtual_public_values_public_input(&mut builder); let recursive_proofs = @@ -884,11 +889,20 @@ where let inner_verifier_data = builder.random_access_verifier_data(index_verifier_data[i], possible_vks); - builder.verify_proof::( - &recursive_proofs[i], - &inner_verifier_data, - inner_common_data[i], - ); + if KECCAK_TABLES_INDICES.contains(&i) { + builder.conditionally_verify_proof_or_dummy::( + enable_keccak_tables, + &recursive_proofs[i], + &inner_verifier_data, + inner_common_data[i], + )?; + } else { + builder.verify_proof::( + &recursive_proofs[i], + &inner_verifier_data, + inner_common_data[i], + ); + } } let merkle_before = @@ -919,6 +933,7 @@ where index_verifier_data, public_values, cyclic_vk, + enable_keccak_tables, } } @@ -1817,8 +1832,16 @@ where timing, abort_signal.clone(), )?; - dbg!(&all_proof.multi_proof.stark_proofs[*Table::Keccak].proof.trace_cap); - dbg!(&all_proof.multi_proof.stark_proofs[*Table::KeccakSponge].proof.trace_cap); + dbg!( + &all_proof.multi_proof.stark_proofs[*Table::Keccak] + .proof + .trace_cap + ); + dbg!( + &all_proof.multi_proof.stark_proofs[*Table::KeccakSponge] + .proof + .trace_cap + ); let mut root_inputs = PartialWitness::new(); for table in 0..NUM_TABLES { From 2b2e737ac9217608ac0a5376bf9e411140cb0dcb Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 23 Sep 2024 09:27:55 -0700 Subject: [PATCH 06/29] wip --- .../src/fixed_recursive_verifier.rs | 78 ++++++++++++++----- 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 927712b52..8c3851d36 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use anyhow::anyhow; use hashbrown::HashMap; use itertools::{zip_eq, Itertools}; +use log::info; use mpt_trie::partial_trie::{HashedPartialTrie, Node, PartialTrie}; use plonky2::field::extension::Extendable; use plonky2::fri::FriParams; @@ -131,8 +132,8 @@ where /// for EVM root proofs; the circuit has them just to match the /// structure of aggregation proofs. cyclic_vk: VerifierCircuitTarget, - /// We can skip verifying Keccak tables when they are not in use. - enable_keccak_tables: BoolTarget, + // We can skip verifying Keccak tables when they are not in use. + // enable_keccak_tables: BoolTarget, } impl RootCircuitData @@ -790,6 +791,7 @@ where let mut builder = CircuitBuilder::new(CircuitConfig::standard_recursion_config()); let enable_keccak_tables = builder.add_virtual_bool_target_safe(); + let disable_keccak_tables = builder.not(enable_keccak_tables); let public_values = add_virtual_public_values_public_input(&mut builder); let recursive_proofs = @@ -860,6 +862,14 @@ where }) .collect_vec(); + // When Keccak Tables are disabled, Keccak Tables' ctl_zs_first should be 0s. + for &tbl in KECCAK_TABLES_INDICES.iter() { + for &t in pis[tbl].ctl_zs_first.iter() { + let keccak_ctl_check = builder.mul(disable_keccak_tables.target, t); + builder.assert_zero(keccak_ctl_check); + } + } + // Verify the CTL checks. verify_cross_table_lookups_circuit::( &mut builder, @@ -889,20 +899,20 @@ where let inner_verifier_data = builder.random_access_verifier_data(index_verifier_data[i], possible_vks); - if KECCAK_TABLES_INDICES.contains(&i) { - builder.conditionally_verify_proof_or_dummy::( - enable_keccak_tables, - &recursive_proofs[i], - &inner_verifier_data, - inner_common_data[i], - )?; - } else { - builder.verify_proof::( - &recursive_proofs[i], - &inner_verifier_data, - inner_common_data[i], - ); - } + // if KECCAK_TABLES_INDICES.contains(&i) { + // builder.conditionally_verify_proof_or_dummy::( + // enable_keccak_tables, + // &recursive_proofs[i], + // &inner_verifier_data, + // inner_common_data[i], + // )?; + // } else { + builder.verify_proof::( + &recursive_proofs[i], + &inner_verifier_data, + inner_common_data[i], + ); + // } } let merkle_before = @@ -933,7 +943,7 @@ where index_verifier_data, public_values, cyclic_vk, - enable_keccak_tables, + // enable_keccak_tables, } } @@ -1832,16 +1842,46 @@ where timing, abort_signal.clone(), )?; - dbg!( + info!( + "Debugging trace_cap.0[0]: {:?}", &all_proof.multi_proof.stark_proofs[*Table::Keccak] .proof .trace_cap + .0[0] + ); + + info!( + "Debugging openings.ctl_zs_first: {:?}", + &all_proof.multi_proof.stark_proofs[*Table::Keccak] + .proof + .openings + .ctl_zs_first ); - dbg!( + + info!( + "Debugging trace_cap.0[0] for KeccakSponge: {:?}", &all_proof.multi_proof.stark_proofs[*Table::KeccakSponge] .proof .trace_cap + .0[0] + ); + + info!( + "Debugging openings.ctl_zs_first for KeccakSponge: {:?}", + &all_proof.multi_proof.stark_proofs[*Table::KeccakSponge] + .proof + .openings + .ctl_zs_first ); + + info!( + "Debugging openings.ctl_zs_first for Logic: {:?}", + &all_proof.multi_proof.stark_proofs[*Table::Logic] + .proof + .openings + .ctl_zs_first + ); + let mut root_inputs = PartialWitness::new(); for table in 0..NUM_TABLES { From f63363b6ac07fd8d4c875223ce3997d6835e3264 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 23 Sep 2024 09:31:48 -0700 Subject: [PATCH 07/29] cleanup --- evm_arithmetization/src/all_stark.rs | 4 -- .../src/fixed_recursive_verifier.rs | 68 +------------------ 2 files changed, 1 insertion(+), 71 deletions(-) diff --git a/evm_arithmetization/src/all_stark.rs b/evm_arithmetization/src/all_stark.rs index d899d9e50..f37021897 100644 --- a/evm_arithmetization/src/all_stark.rs +++ b/evm_arithmetization/src/all_stark.rs @@ -126,10 +126,6 @@ pub const NUM_TABLES: usize = if cfg!(feature = "cdk_erigon") { Table::MemAfter as usize + 1 }; -/// Indices of Keccak Tables -pub const KECCAK_TABLES_INDICES: [usize; 2] = - [Table::Keccak as usize, Table::KeccakSponge as usize]; - impl Table { /// Returns all STARK table indices. pub(crate) const fn all() -> [Self; NUM_TABLES] { diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 8c3851d36..436a46bd2 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -7,7 +7,6 @@ use std::sync::Arc; use anyhow::anyhow; use hashbrown::HashMap; use itertools::{zip_eq, Itertools}; -use log::info; use mpt_trie::partial_trie::{HashedPartialTrie, Node, PartialTrie}; use plonky2::field::extension::Extendable; use plonky2::fri::FriParams; @@ -36,10 +35,7 @@ use starky::lookup::{get_grand_product_challenge_set_target, GrandProductChallen use starky::proof::StarkProofWithMetadata; use starky::stark::Stark; -use crate::all_stark::Table::Keccak; -use crate::all_stark::{ - all_cross_table_lookups, AllStark, Table, KECCAK_TABLES_INDICES, NUM_TABLES, -}; +use crate::all_stark::{all_cross_table_lookups, AllStark, Table, NUM_TABLES}; use crate::cpu::kernel::aggregator::KERNEL; use crate::generation::segments::{GenerationSegmentData, SegmentDataIterator, SegmentError}; use crate::generation::{GenerationInputs, TrimmedGenerationInputs}; @@ -132,8 +128,6 @@ where /// for EVM root proofs; the circuit has them just to match the /// structure of aggregation proofs. cyclic_vk: VerifierCircuitTarget, - // We can skip verifying Keccak tables when they are not in use. - // enable_keccak_tables: BoolTarget, } impl RootCircuitData @@ -790,8 +784,6 @@ where let mut builder = CircuitBuilder::new(CircuitConfig::standard_recursion_config()); - let enable_keccak_tables = builder.add_virtual_bool_target_safe(); - let disable_keccak_tables = builder.not(enable_keccak_tables); let public_values = add_virtual_public_values_public_input(&mut builder); let recursive_proofs = @@ -862,14 +854,6 @@ where }) .collect_vec(); - // When Keccak Tables are disabled, Keccak Tables' ctl_zs_first should be 0s. - for &tbl in KECCAK_TABLES_INDICES.iter() { - for &t in pis[tbl].ctl_zs_first.iter() { - let keccak_ctl_check = builder.mul(disable_keccak_tables.target, t); - builder.assert_zero(keccak_ctl_check); - } - } - // Verify the CTL checks. verify_cross_table_lookups_circuit::( &mut builder, @@ -899,20 +883,11 @@ where let inner_verifier_data = builder.random_access_verifier_data(index_verifier_data[i], possible_vks); - // if KECCAK_TABLES_INDICES.contains(&i) { - // builder.conditionally_verify_proof_or_dummy::( - // enable_keccak_tables, - // &recursive_proofs[i], - // &inner_verifier_data, - // inner_common_data[i], - // )?; - // } else { builder.verify_proof::( &recursive_proofs[i], &inner_verifier_data, inner_common_data[i], ); - // } } let merkle_before = @@ -943,7 +918,6 @@ where index_verifier_data, public_values, cyclic_vk, - // enable_keccak_tables, } } @@ -1842,46 +1816,6 @@ where timing, abort_signal.clone(), )?; - info!( - "Debugging trace_cap.0[0]: {:?}", - &all_proof.multi_proof.stark_proofs[*Table::Keccak] - .proof - .trace_cap - .0[0] - ); - - info!( - "Debugging openings.ctl_zs_first: {:?}", - &all_proof.multi_proof.stark_proofs[*Table::Keccak] - .proof - .openings - .ctl_zs_first - ); - - info!( - "Debugging trace_cap.0[0] for KeccakSponge: {:?}", - &all_proof.multi_proof.stark_proofs[*Table::KeccakSponge] - .proof - .trace_cap - .0[0] - ); - - info!( - "Debugging openings.ctl_zs_first for KeccakSponge: {:?}", - &all_proof.multi_proof.stark_proofs[*Table::KeccakSponge] - .proof - .openings - .ctl_zs_first - ); - - info!( - "Debugging openings.ctl_zs_first for Logic: {:?}", - &all_proof.multi_proof.stark_proofs[*Table::Logic] - .proof - .openings - .ctl_zs_first - ); - let mut root_inputs = PartialWitness::new(); for table in 0..NUM_TABLES { From cc9d41be6d29aad230a21e8e930d7a1821f757ec Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 23 Sep 2024 10:01:03 -0700 Subject: [PATCH 08/29] prove one segment --- .../src/fixed_recursive_verifier.rs | 74 ++++++++++++++++--- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 436a46bd2..8d6dd8e05 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -2949,6 +2949,7 @@ where mod tests { use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::plonk::config::PoseidonGoldilocksConfig; + use plonky2::timed; use super::*; use crate::testing_utils::{dummy_payload, init_logger}; @@ -2958,24 +2959,75 @@ mod tests { type C = PoseidonGoldilocksConfig; #[test] - #[ignore] - fn test_root_proof_generation() -> anyhow::Result<()> { + fn test_root_proof_generation_without_keccak() -> anyhow::Result<()> { + let timing = &mut TimingTree::new(&format!("segment proof"), log::Level::Info); init_logger(); let all_stark = AllStark::::default(); let config = StarkConfig::standard_fast_config(); - let all_circuits = AllRecursiveCircuits::::new( - &all_stark, - &[16..17, 8..9, 9..10, 4..9, 8..9, 4..7, 17..18, 17..18, 7..18], - &config, + let all_circuits = timed!( + timing, + log::Level::Info, + "create all circuits.", + AllRecursiveCircuits::::new( + &all_stark, + &[ + 16..17, + 8..9, + 9..10, + 4..5, + 8..9, + 4..5, + 17..18, + 17..18, + 17..18 + ], + &config, + ) + ); + let dummy = timed!( + timing, + log::Level::Info, + "generate dummy payload.", + dummy_payload(100, true)? ); - let dummy = dummy_payload(100, true)?; - let timing = &mut TimingTree::new(&format!("Blockproof"), log::Level::Info); - let dummy_proof = - all_circuits.prove_all_segments(&all_stark, &config, dummy, 9, timing, None)?; - all_circuits.verify_root(dummy_proof[0].proof_with_pis.clone())?; + let max_cpu_len_log = 9; + let segment_iterator = SegmentDataIterator::::new(&dummy, Some(max_cpu_len_log)); + + let mut dummy_proof = vec![]; + + let proof_without_keccak_index = 3; + for (i, segment_run) in segment_iterator.enumerate() { + if i < proof_without_keccak_index { + continue; + } + let (_, mut next_data) = + segment_run.map_err(|e: SegmentError| anyhow::format_err!(e))?; + let proof = timed!( + timing, + log::Level::Info, + "prove the segment.", + all_circuits.prove_segment( + &all_stark, + &config, + dummy.trim(), + &mut next_data, + timing, + None, + )? + ); + dummy_proof.push(proof); + break; + } + + timed!( + timing, + log::Level::Info, + "verify segment proofs.", + all_circuits.verify_root(dummy_proof[0].proof_with_pis.clone())? + ); timing.print(); Ok(()) From fe88819ad9d1c59e94d1b1440d93304071e4d5ec Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 23 Sep 2024 10:06:08 -0700 Subject: [PATCH 09/29] polish the code --- .../src/fixed_recursive_verifier.rs | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 8d6dd8e05..7ee352c91 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -2959,8 +2959,8 @@ mod tests { type C = PoseidonGoldilocksConfig; #[test] - fn test_root_proof_generation_without_keccak() -> anyhow::Result<()> { - let timing = &mut TimingTree::new(&format!("segment proof"), log::Level::Info); + fn test_segment_proof_generation_without_keccak() -> anyhow::Result<()> { + let timing = &mut TimingTree::new("Segment Proof Generation", log::Level::Info); init_logger(); let all_stark = AllStark::::default(); @@ -2969,7 +2969,7 @@ mod tests { let all_circuits = timed!( timing, log::Level::Info, - "create all circuits.", + "Create all recursive circuits", AllRecursiveCircuits::::new( &all_stark, &[ @@ -2986,48 +2986,56 @@ mod tests { &config, ) ); - let dummy = timed!( + + // Generate a dummy payload for testing + let dummy_payload = timed!( timing, log::Level::Info, - "generate dummy payload.", + "Generate dummy payload", dummy_payload(100, true)? ); let max_cpu_len_log = 9; - let segment_iterator = SegmentDataIterator::::new(&dummy, Some(max_cpu_len_log)); + let segment_iterator = SegmentDataIterator::::new(&dummy_payload, Some(max_cpu_len_log)); - let mut dummy_proof = vec![]; + let mut proofs_without_keccak = vec![]; - let proof_without_keccak_index = 3; + let skip_proofs_before_index = 3; for (i, segment_run) in segment_iterator.enumerate() { - if i < proof_without_keccak_index { + if i < skip_proofs_before_index { continue; } - let (_, mut next_data) = + + // Process and prove segment + let (_, mut segment_data) = segment_run.map_err(|e: SegmentError| anyhow::format_err!(e))?; - let proof = timed!( + let segment_proof = timed!( timing, log::Level::Info, - "prove the segment.", + "Prove segment", all_circuits.prove_segment( &all_stark, &config, - dummy.trim(), - &mut next_data, + dummy_payload.trim(), + &mut segment_data, timing, None, )? ); - dummy_proof.push(proof); - break; + + proofs_without_keccak.push(segment_proof); + break; // Process only one proof } + // Verify the generated segment proof timed!( timing, log::Level::Info, - "verify segment proofs.", - all_circuits.verify_root(dummy_proof[0].proof_with_pis.clone())? + "Verify segment proof", + all_circuits.verify_root(proofs_without_keccak[0].proof_with_pis.clone())? ); + + // Print timing details timing.print(); Ok(()) From 7ff2fb11ab58eb462d98fdd62359f1287e313669 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 23 Sep 2024 10:14:11 -0700 Subject: [PATCH 10/29] cleanup --- evm_arithmetization/tests/two_to_one_block.rs | 90 +------------------ 1 file changed, 3 insertions(+), 87 deletions(-) diff --git a/evm_arithmetization/tests/two_to_one_block.rs b/evm_arithmetization/tests/two_to_one_block.rs index a70c43c8c..9750f1dc7 100644 --- a/evm_arithmetization/tests/two_to_one_block.rs +++ b/evm_arithmetization/tests/two_to_one_block.rs @@ -1,22 +1,12 @@ #![cfg(feature = "eth_mainnet")] -use ethereum_types::{Address, BigEndianHash, H256}; use evm_arithmetization::fixed_recursive_verifier::{ extract_block_final_public_values, extract_two_to_one_block_hash, }; -use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; -use evm_arithmetization::proof::{ - BlockMetadata, FinalPublicValues, PublicValues, TrieRoots, EMPTY_CONSOLIDATED_BLOCKHASH, -}; -use evm_arithmetization::testing_utils::{ - beacon_roots_account_nibbles, beacon_roots_contract_from_storage, init_logger, - preinitialized_state_and_storage_tries, update_beacon_roots_account_storage, -}; -use evm_arithmetization::{AllRecursiveCircuits, AllStark, Node, StarkConfig}; -use hex_literal::hex; -use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; +use evm_arithmetization::proof::{FinalPublicValues, PublicValues}; +use evm_arithmetization::testing_utils::{dummy_payload, init_logger}; +use evm_arithmetization::{AllRecursiveCircuits, AllStark, StarkConfig}; use plonky2::field::goldilocks_field::GoldilocksField; -use plonky2::field::types::Field; use plonky2::hash::poseidon::PoseidonHash; use plonky2::plonk::config::{Hasher, PoseidonGoldilocksConfig}; use plonky2::plonk::proof::ProofWithPublicInputs; @@ -26,80 +16,6 @@ type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; -/// Get `GenerationInputs` for a dummy payload, where the block has the given -/// timestamp. -fn dummy_payload(timestamp: u64, is_first_payload: bool) -> anyhow::Result> { - let beneficiary = hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); - - let block_metadata = BlockMetadata { - block_beneficiary: Address::from(beneficiary), - block_timestamp: timestamp.into(), - block_number: 1.into(), - block_difficulty: 0x020000.into(), - block_random: H256::from_uint(&0x020000.into()), - block_gaslimit: 0xff112233u32.into(), - block_chain_id: 1.into(), - block_base_fee: 0xa.into(), - ..Default::default() - }; - - let (mut state_trie_before, mut storage_tries) = preinitialized_state_and_storage_tries()?; - let checkpoint_state_trie_root = state_trie_before.hash(); - let mut beacon_roots_account_storage = storage_tries[0].1.clone(); - - update_beacon_roots_account_storage( - &mut beacon_roots_account_storage, - block_metadata.block_timestamp, - block_metadata.parent_beacon_block_root, - )?; - let updated_beacon_roots_account = - beacon_roots_contract_from_storage(&beacon_roots_account_storage); - - if !is_first_payload { - // This isn't the first dummy payload being processed. We need to update the - // initial state trie to account for the update on the beacon roots contract. - state_trie_before.insert( - beacon_roots_account_nibbles(), - rlp::encode(&updated_beacon_roots_account).to_vec(), - )?; - storage_tries[0].1 = beacon_roots_account_storage; - } - - let tries_before = TrieInputs { - state_trie: state_trie_before, - storage_tries, - ..Default::default() - }; - - let expected_state_trie_after: HashedPartialTrie = { - let mut state_trie_after = HashedPartialTrie::from(Node::Empty); - state_trie_after.insert( - beacon_roots_account_nibbles(), - rlp::encode(&updated_beacon_roots_account).to_vec(), - )?; - - state_trie_after - }; - - let trie_roots_after = TrieRoots { - state_root: expected_state_trie_after.hash(), - transactions_root: tries_before.transactions_trie.hash(), - receipts_root: tries_before.receipts_trie.hash(), - }; - - let inputs = GenerationInputs { - tries: tries_before.clone(), - burn_addr: None, - trie_roots_after, - checkpoint_state_trie_root, - checkpoint_consolidated_hash: EMPTY_CONSOLIDATED_BLOCKHASH.map(F::from_canonical_u64), - block_metadata, - ..Default::default() - }; - - Ok(inputs) -} - fn get_test_block_proof( timestamp: u64, all_circuits: &AllRecursiveCircuits, From 6ce3cbe374fb6c6d4644d756f7495ef037cc5f07 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 23 Sep 2024 10:29:20 -0700 Subject: [PATCH 11/29] Revert "cleanup" This reverts commit f63363b6ac07fd8d4c875223ce3997d6835e3264. --- evm_arithmetization/src/all_stark.rs | 4 ++ .../src/fixed_recursive_verifier.rs | 68 ++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/evm_arithmetization/src/all_stark.rs b/evm_arithmetization/src/all_stark.rs index f37021897..d899d9e50 100644 --- a/evm_arithmetization/src/all_stark.rs +++ b/evm_arithmetization/src/all_stark.rs @@ -126,6 +126,10 @@ pub const NUM_TABLES: usize = if cfg!(feature = "cdk_erigon") { Table::MemAfter as usize + 1 }; +/// Indices of Keccak Tables +pub const KECCAK_TABLES_INDICES: [usize; 2] = + [Table::Keccak as usize, Table::KeccakSponge as usize]; + impl Table { /// Returns all STARK table indices. pub(crate) const fn all() -> [Self; NUM_TABLES] { diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 7ee352c91..c09051ec9 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use anyhow::anyhow; use hashbrown::HashMap; use itertools::{zip_eq, Itertools}; +use log::info; use mpt_trie::partial_trie::{HashedPartialTrie, Node, PartialTrie}; use plonky2::field::extension::Extendable; use plonky2::fri::FriParams; @@ -35,7 +36,10 @@ use starky::lookup::{get_grand_product_challenge_set_target, GrandProductChallen use starky::proof::StarkProofWithMetadata; use starky::stark::Stark; -use crate::all_stark::{all_cross_table_lookups, AllStark, Table, NUM_TABLES}; +use crate::all_stark::Table::Keccak; +use crate::all_stark::{ + all_cross_table_lookups, AllStark, Table, KECCAK_TABLES_INDICES, NUM_TABLES, +}; use crate::cpu::kernel::aggregator::KERNEL; use crate::generation::segments::{GenerationSegmentData, SegmentDataIterator, SegmentError}; use crate::generation::{GenerationInputs, TrimmedGenerationInputs}; @@ -128,6 +132,8 @@ where /// for EVM root proofs; the circuit has them just to match the /// structure of aggregation proofs. cyclic_vk: VerifierCircuitTarget, + // We can skip verifying Keccak tables when they are not in use. + // enable_keccak_tables: BoolTarget, } impl RootCircuitData @@ -784,6 +790,8 @@ where let mut builder = CircuitBuilder::new(CircuitConfig::standard_recursion_config()); + let enable_keccak_tables = builder.add_virtual_bool_target_safe(); + let disable_keccak_tables = builder.not(enable_keccak_tables); let public_values = add_virtual_public_values_public_input(&mut builder); let recursive_proofs = @@ -854,6 +862,14 @@ where }) .collect_vec(); + // When Keccak Tables are disabled, Keccak Tables' ctl_zs_first should be 0s. + for &tbl in KECCAK_TABLES_INDICES.iter() { + for &t in pis[tbl].ctl_zs_first.iter() { + let keccak_ctl_check = builder.mul(disable_keccak_tables.target, t); + builder.assert_zero(keccak_ctl_check); + } + } + // Verify the CTL checks. verify_cross_table_lookups_circuit::( &mut builder, @@ -883,11 +899,20 @@ where let inner_verifier_data = builder.random_access_verifier_data(index_verifier_data[i], possible_vks); + // if KECCAK_TABLES_INDICES.contains(&i) { + // builder.conditionally_verify_proof_or_dummy::( + // enable_keccak_tables, + // &recursive_proofs[i], + // &inner_verifier_data, + // inner_common_data[i], + // )?; + // } else { builder.verify_proof::( &recursive_proofs[i], &inner_verifier_data, inner_common_data[i], ); + // } } let merkle_before = @@ -918,6 +943,7 @@ where index_verifier_data, public_values, cyclic_vk, + // enable_keccak_tables, } } @@ -1816,6 +1842,46 @@ where timing, abort_signal.clone(), )?; + info!( + "Debugging trace_cap.0[0]: {:?}", + &all_proof.multi_proof.stark_proofs[*Table::Keccak] + .proof + .trace_cap + .0[0] + ); + + info!( + "Debugging openings.ctl_zs_first: {:?}", + &all_proof.multi_proof.stark_proofs[*Table::Keccak] + .proof + .openings + .ctl_zs_first + ); + + info!( + "Debugging trace_cap.0[0] for KeccakSponge: {:?}", + &all_proof.multi_proof.stark_proofs[*Table::KeccakSponge] + .proof + .trace_cap + .0[0] + ); + + info!( + "Debugging openings.ctl_zs_first for KeccakSponge: {:?}", + &all_proof.multi_proof.stark_proofs[*Table::KeccakSponge] + .proof + .openings + .ctl_zs_first + ); + + info!( + "Debugging openings.ctl_zs_first for Logic: {:?}", + &all_proof.multi_proof.stark_proofs[*Table::Logic] + .proof + .openings + .ctl_zs_first + ); + let mut root_inputs = PartialWitness::new(); for table in 0..NUM_TABLES { From 8c940b04414cde430ef4c7a2e6d41c017289878a Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 23 Sep 2024 10:47:49 -0700 Subject: [PATCH 12/29] add [ignore] --- evm_arithmetization/src/fixed_recursive_verifier.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 7ee352c91..80f7f1b66 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -2959,6 +2959,7 @@ mod tests { type C = PoseidonGoldilocksConfig; #[test] + #[ignore] fn test_segment_proof_generation_without_keccak() -> anyhow::Result<()> { let timing = &mut TimingTree::new("Segment Proof Generation", log::Level::Info); init_logger(); From d6af500d3c1e485bf8c33e64d5ab5e3971f7ae5f Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 23 Sep 2024 11:12:18 -0700 Subject: [PATCH 13/29] add challenger state check --- .../src/fixed_recursive_verifier.rs | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index c09051ec9..befb03bb8 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -132,8 +132,8 @@ where /// for EVM root proofs; the circuit has them just to match the /// structure of aggregation proofs. cyclic_vk: VerifierCircuitTarget, - // We can skip verifying Keccak tables when they are not in use. - // enable_keccak_tables: BoolTarget, + /// We can skip verifying Keccak tables when they are not in use. + enable_keccak_tables: BoolTarget, } impl RootCircuitData @@ -844,6 +844,19 @@ where ) { builder.connect(before, after); } + if KECCAK_TABLES_INDICES.contains(&i) { + for (&before, &after) in zip_eq( + pis[i].challenger_state_before.as_ref(), + pis[i].challenger_state_after.as_ref(), + ) { + // Ensure that the challenger state remains consistent before and after Keccak + // tables. + let state_difference = builder.sub(before, after); + let keccak_consistency_check = + builder.mul(disable_keccak_tables.target, state_difference); + builder.assert_zero(keccak_consistency_check); + } + } } // Extra sums to add to the looked last value. @@ -899,20 +912,20 @@ where let inner_verifier_data = builder.random_access_verifier_data(index_verifier_data[i], possible_vks); - // if KECCAK_TABLES_INDICES.contains(&i) { - // builder.conditionally_verify_proof_or_dummy::( - // enable_keccak_tables, - // &recursive_proofs[i], - // &inner_verifier_data, - // inner_common_data[i], - // )?; - // } else { - builder.verify_proof::( - &recursive_proofs[i], - &inner_verifier_data, - inner_common_data[i], - ); - // } + if KECCAK_TABLES_INDICES.contains(&i) { + builder.conditionally_verify_proof_or_dummy::( + enable_keccak_tables, + &recursive_proofs[i], + &inner_verifier_data, + inner_common_data[i], + )?; + } else { + builder.verify_proof::( + &recursive_proofs[i], + &inner_verifier_data, + inner_common_data[i], + ); + } } let merkle_before = @@ -943,7 +956,7 @@ where index_verifier_data, public_values, cyclic_vk, - // enable_keccak_tables, + enable_keccak_tables, } } From f5deedbd1e75d64ad0572664bc44f7a8b28cd81e Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 23 Sep 2024 15:52:57 -0700 Subject: [PATCH 14/29] add more checks --- .../src/fixed_recursive_verifier.rs | 99 ++++++++++++------- evm_arithmetization/src/recursive_verifier.rs | 4 + 2 files changed, 68 insertions(+), 35 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index befb03bb8..0dc837407 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -36,7 +36,6 @@ use starky::lookup::{get_grand_product_challenge_set_target, GrandProductChallen use starky::proof::StarkProofWithMetadata; use starky::stark::Stark; -use crate::all_stark::Table::Keccak; use crate::all_stark::{ all_cross_table_lookups, AllStark, Table, KECCAK_TABLES_INDICES, NUM_TABLES, }; @@ -156,6 +155,7 @@ where } self.public_values.to_buffer(buffer)?; buffer.write_target_verifier_circuit(&self.cyclic_vk)?; + buffer.write_target_bool(self.enable_keccak_tables)?; Ok(()) } @@ -175,6 +175,7 @@ where } let public_values = PublicValuesTarget::from_buffer(buffer)?; let cyclic_vk = buffer.read_target_verifier_circuit()?; + let enable_keccak_tables = buffer.read_target_bool()?; Ok(Self { circuit, @@ -182,6 +183,7 @@ where index_verifier_data: index_verifier_data.try_into().unwrap(), public_values, cyclic_vk, + enable_keccak_tables, }) } } @@ -811,6 +813,15 @@ where } } + for i in KECCAK_TABLES_INDICES { + for h in &pis[i].trace_cap { + for t in h { + let trace_cap_check = builder.mul(disable_keccak_tables.target, *t); + builder.assert_zero(trace_cap_check); + } + } + } + observe_public_values_target::(&mut challenger, &public_values); let ctl_challenges = get_grand_product_challenge_set_target( @@ -819,16 +830,35 @@ where stark_config.num_challenges, ); // Check that the correct CTL challenges are used in every proof. - for pi in &pis { - for i in 0..stark_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, - ); + for (i, pi) in pis.iter().enumerate() { + if KECCAK_TABLES_INDICES.contains(&i) { + // Ensures that the correct CTL challenges are used in Keccak tables when + // `enable_keccak_tables` is true. + for i in 0..stark_config.num_challenges { + let beta_diff = builder.sub( + ctl_challenges.challenges[i].beta, + pi.ctl_challenges.challenges[i].beta, + ); + let gamma_diff = builder.sub( + ctl_challenges.challenges[i].gamma, + pi.ctl_challenges.challenges[i].gamma, + ); + let beta_check = builder.mul(enable_keccak_tables.target, beta_diff); + let gamma_check = builder.mul(enable_keccak_tables.target, gamma_diff); + builder.assert_zero(beta_check); + builder.assert_zero(gamma_check); + } + } else { + for i in 0..stark_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, + ); + } } } @@ -845,16 +875,16 @@ where builder.connect(before, after); } if KECCAK_TABLES_INDICES.contains(&i) { + // Ensure that the challenger state remains consistent before and after Keccak + // tables. for (&before, &after) in zip_eq( pis[i].challenger_state_before.as_ref(), pis[i].challenger_state_after.as_ref(), ) { - // Ensure that the challenger state remains consistent before and after Keccak - // tables. let state_difference = builder.sub(before, after); - let keccak_consistency_check = + let challenger_state_check = builder.mul(disable_keccak_tables.target, state_difference); - builder.assert_zero(keccak_consistency_check); + builder.assert_zero(challenger_state_check); } } } @@ -878,8 +908,8 @@ where // When Keccak Tables are disabled, Keccak Tables' ctl_zs_first should be 0s. for &tbl in KECCAK_TABLES_INDICES.iter() { for &t in pis[tbl].ctl_zs_first.iter() { - let keccak_ctl_check = builder.mul(disable_keccak_tables.target, t); - builder.assert_zero(keccak_ctl_check); + let ctl_check = builder.mul(disable_keccak_tables.target, t); + builder.assert_zero(ctl_check); } } @@ -913,12 +943,14 @@ where builder.random_access_verifier_data(index_verifier_data[i], possible_vks); if KECCAK_TABLES_INDICES.contains(&i) { - builder.conditionally_verify_proof_or_dummy::( - enable_keccak_tables, - &recursive_proofs[i], - &inner_verifier_data, - inner_common_data[i], - )?; + builder + .conditionally_verify_proof_or_dummy::( + enable_keccak_tables, + &recursive_proofs[i], + &inner_verifier_data, + inner_common_data[i], + ) + .expect("Unable conditionally verify Keccak proofs in the root circuit"); } else { builder.verify_proof::( &recursive_proofs[i], @@ -1940,6 +1972,9 @@ where anyhow::Error::msg("Invalid conversion when setting public values targets.") })?; + // TODO(sdeng): Set to false when this segment contains no Keccak operations. + root_inputs.set_bool_target(self.root.enable_keccak_tables, true); + let root_proof = self.root.circuit.prove(root_inputs)?; Ok(ProverOutputData { @@ -2080,6 +2115,9 @@ where anyhow::Error::msg("Invalid conversion when setting public values targets.") })?; + // TODO(sdeng): Set to false when this segment contains no Keccak operations. + root_inputs.set_bool_target(self.root.enable_keccak_tables, true); + let root_proof = self.root.circuit.prove(root_inputs)?; Ok((root_proof, all_proof.public_values)) @@ -3038,6 +3076,7 @@ mod tests { type C = PoseidonGoldilocksConfig; #[test] + #[ignore] fn test_segment_proof_generation_without_keccak() -> anyhow::Result<()> { let timing = &mut TimingTree::new("Segment Proof Generation", log::Level::Info); init_logger(); @@ -3051,17 +3090,7 @@ mod tests { "Create all recursive circuits", AllRecursiveCircuits::::new( &all_stark, - &[ - 16..17, - 8..9, - 9..10, - 4..5, - 8..9, - 4..5, - 17..18, - 17..18, - 17..18 - ], + &[16..17, 8..9, 9..10, 4..9, 8..9, 4..7, 17..18, 17..18, 7..18], &config, ) ); @@ -3103,7 +3132,7 @@ mod tests { ); proofs_without_keccak.push(segment_proof); - break; // Process only one proof + // break; // Process only one proof } // Verify the generated segment proof diff --git a/evm_arithmetization/src/recursive_verifier.rs b/evm_arithmetization/src/recursive_verifier.rs index 417bf468d..14ed5957e 100644 --- a/evm_arithmetization/src/recursive_verifier.rs +++ b/evm_arithmetization/src/recursive_verifier.rs @@ -4,6 +4,7 @@ use core::fmt::Debug; use anyhow::Result; use ethereum_types::{BigEndianHash, U256}; use plonky2::field::extension::Extendable; +use plonky2::gates::constant::ConstantGate; use plonky2::gates::exponentiation::ExponentiationGate; use plonky2::gates::gate::GateRef; use plonky2::gates::noop::NoopGate; @@ -326,6 +327,9 @@ pub(crate) fn add_common_recursion_gates, const D: builder.add_gate_to_gate_set(GateRef::new(ExponentiationGate::new_from_config( &builder.config, ))); + builder.add_gate_to_gate_set(GateRef::new(ConstantGate::new( + builder.config.num_constants, + ))); } /// Recursive version of `get_memory_extra_looking_sum`. From e39894ad6dfc2f2217fb8b9f5550c2ab77ad22d9 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 23 Sep 2024 16:06:33 -0700 Subject: [PATCH 15/29] cleanup --- .../src/fixed_recursive_verifier.rs | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 0dc837407..4beda37b6 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -831,32 +831,30 @@ where ); // Check that the correct CTL challenges are used in every proof. for (i, pi) in pis.iter().enumerate() { - if KECCAK_TABLES_INDICES.contains(&i) { - // Ensures that the correct CTL challenges are used in Keccak tables when - // `enable_keccak_tables` is true. - for i in 0..stark_config.num_challenges { + for j in 0..stark_config.num_challenges { + if KECCAK_TABLES_INDICES.contains(&i) { + // Ensures that the correct CTL challenges are used in Keccak tables when + // `enable_keccak_tables` is true. let beta_diff = builder.sub( - ctl_challenges.challenges[i].beta, - pi.ctl_challenges.challenges[i].beta, + ctl_challenges.challenges[j].beta, + pi.ctl_challenges.challenges[j].beta, ); let gamma_diff = builder.sub( - ctl_challenges.challenges[i].gamma, - pi.ctl_challenges.challenges[i].gamma, + ctl_challenges.challenges[j].gamma, + pi.ctl_challenges.challenges[j].gamma, ); let beta_check = builder.mul(enable_keccak_tables.target, beta_diff); let gamma_check = builder.mul(enable_keccak_tables.target, gamma_diff); builder.assert_zero(beta_check); builder.assert_zero(gamma_check); - } - } else { - for i in 0..stark_config.num_challenges { + } else { builder.connect( - ctl_challenges.challenges[i].beta, - pi.ctl_challenges.challenges[i].beta, + ctl_challenges.challenges[j].beta, + pi.ctl_challenges.challenges[j].beta, ); builder.connect( - ctl_challenges.challenges[i].gamma, - pi.ctl_challenges.challenges[i].gamma, + ctl_challenges.challenges[j].gamma, + pi.ctl_challenges.challenges[j].gamma, ); } } @@ -906,8 +904,8 @@ where .collect_vec(); // When Keccak Tables are disabled, Keccak Tables' ctl_zs_first should be 0s. - for &tbl in KECCAK_TABLES_INDICES.iter() { - for &t in pis[tbl].ctl_zs_first.iter() { + for &i in KECCAK_TABLES_INDICES.iter() { + for &t in pis[i].ctl_zs_first.iter() { let ctl_check = builder.mul(disable_keccak_tables.target, t); builder.assert_zero(ctl_check); } @@ -3132,7 +3130,7 @@ mod tests { ); proofs_without_keccak.push(segment_proof); - // break; // Process only one proof + break; // Process only one proof } // Verify the generated segment proof From 36ace10e5ceeef9a8937c5167b47b083cca5420c Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Tue, 24 Sep 2024 20:38:24 -0700 Subject: [PATCH 16/29] fix --- .../src/fixed_recursive_verifier.rs | 103 ++++++------------ 1 file changed, 32 insertions(+), 71 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 4beda37b6..8056f9ab3 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -7,7 +7,6 @@ use std::sync::Arc; use anyhow::anyhow; use hashbrown::HashMap; use itertools::{zip_eq, Itertools}; -use log::info; use mpt_trie::partial_trie::{HashedPartialTrie, Node, PartialTrie}; use plonky2::field::extension::Extendable; use plonky2::fri::FriParams; @@ -132,7 +131,7 @@ where /// structure of aggregation proofs. cyclic_vk: VerifierCircuitTarget, /// We can skip verifying Keccak tables when they are not in use. - enable_keccak_tables: BoolTarget, + use_keccak_tables: BoolTarget, } impl RootCircuitData @@ -155,7 +154,7 @@ where } self.public_values.to_buffer(buffer)?; buffer.write_target_verifier_circuit(&self.cyclic_vk)?; - buffer.write_target_bool(self.enable_keccak_tables)?; + buffer.write_target_bool(self.use_keccak_tables)?; Ok(()) } @@ -175,7 +174,7 @@ where } let public_values = PublicValuesTarget::from_buffer(buffer)?; let cyclic_vk = buffer.read_target_verifier_circuit()?; - let enable_keccak_tables = buffer.read_target_bool()?; + let use_keccak_tables = buffer.read_target_bool()?; Ok(Self { circuit, @@ -183,7 +182,7 @@ where index_verifier_data: index_verifier_data.try_into().unwrap(), public_values, cyclic_vk, - enable_keccak_tables, + use_keccak_tables, }) } } @@ -792,8 +791,8 @@ where let mut builder = CircuitBuilder::new(CircuitConfig::standard_recursion_config()); - let enable_keccak_tables = builder.add_virtual_bool_target_safe(); - let disable_keccak_tables = builder.not(enable_keccak_tables); + let use_keccak_tables = builder.add_virtual_bool_target_safe(); + let skip_keccak_tables = builder.not(use_keccak_tables); let public_values = add_virtual_public_values_public_input(&mut builder); let recursive_proofs = @@ -816,7 +815,7 @@ where for i in KECCAK_TABLES_INDICES { for h in &pis[i].trace_cap { for t in h { - let trace_cap_check = builder.mul(disable_keccak_tables.target, *t); + let trace_cap_check = builder.mul(skip_keccak_tables.target, *t); builder.assert_zero(trace_cap_check); } } @@ -843,8 +842,8 @@ where ctl_challenges.challenges[j].gamma, pi.ctl_challenges.challenges[j].gamma, ); - let beta_check = builder.mul(enable_keccak_tables.target, beta_diff); - let gamma_check = builder.mul(enable_keccak_tables.target, gamma_diff); + let beta_check = builder.mul(use_keccak_tables.target, beta_diff); + let gamma_check = builder.mul(use_keccak_tables.target, gamma_diff); builder.assert_zero(beta_check); builder.assert_zero(gamma_check); } else { @@ -865,24 +864,25 @@ where builder.connect(before, s); } // Check that the challenger state is consistent between proofs. + let mut prev_state = pis[0].challenger_state_after.as_ref().to_vec(); + let state_len = prev_state.len(); for i in 1..NUM_TABLES { - for (&before, &after) in zip_eq( - pis[i].challenger_state_before.as_ref(), - pis[i - 1].challenger_state_after.as_ref(), - ) { - builder.connect(before, after); - } - if KECCAK_TABLES_INDICES.contains(&i) { - // Ensure that the challenger state remains consistent before and after Keccak - // tables. - for (&before, &after) in zip_eq( - pis[i].challenger_state_before.as_ref(), - pis[i].challenger_state_after.as_ref(), - ) { - let state_difference = builder.sub(before, after); - let challenger_state_check = - builder.mul(disable_keccak_tables.target, state_difference); - builder.assert_zero(challenger_state_check); + let current_state_before = pis[i].challenger_state_before.as_ref(); + let current_state_after = pis[i].challenger_state_after.as_ref(); + for j in 0..state_len { + if KECCAK_TABLES_INDICES.contains(&i) { + // Ensure that the challenger state: + // 1) prev == current_before, when using keccak + let diff = builder.sub(prev_state[j], current_state_before[j]); + let check = builder.mul(use_keccak_tables.target, diff); + builder.assert_zero(check); + // 2) prev <- current_after, when using keccak + // 3) prev <- prev, when skipping using keccak + prev_state[j] = + builder.select(use_keccak_tables, current_state_after[j], prev_state[j]); + } else { + builder.connect(prev_state[j], current_state_before[j]); + prev_state[j] = current_state_after[j]; } } } @@ -906,7 +906,7 @@ where // When Keccak Tables are disabled, Keccak Tables' ctl_zs_first should be 0s. for &i in KECCAK_TABLES_INDICES.iter() { for &t in pis[i].ctl_zs_first.iter() { - let ctl_check = builder.mul(disable_keccak_tables.target, t); + let ctl_check = builder.mul(skip_keccak_tables.target, t); builder.assert_zero(ctl_check); } } @@ -943,7 +943,7 @@ where if KECCAK_TABLES_INDICES.contains(&i) { builder .conditionally_verify_proof_or_dummy::( - enable_keccak_tables, + use_keccak_tables, &recursive_proofs[i], &inner_verifier_data, inner_common_data[i], @@ -986,7 +986,7 @@ where index_verifier_data, public_values, cyclic_vk, - enable_keccak_tables, + use_keccak_tables, } } @@ -1885,45 +1885,6 @@ where timing, abort_signal.clone(), )?; - info!( - "Debugging trace_cap.0[0]: {:?}", - &all_proof.multi_proof.stark_proofs[*Table::Keccak] - .proof - .trace_cap - .0[0] - ); - - info!( - "Debugging openings.ctl_zs_first: {:?}", - &all_proof.multi_proof.stark_proofs[*Table::Keccak] - .proof - .openings - .ctl_zs_first - ); - - info!( - "Debugging trace_cap.0[0] for KeccakSponge: {:?}", - &all_proof.multi_proof.stark_proofs[*Table::KeccakSponge] - .proof - .trace_cap - .0[0] - ); - - info!( - "Debugging openings.ctl_zs_first for KeccakSponge: {:?}", - &all_proof.multi_proof.stark_proofs[*Table::KeccakSponge] - .proof - .openings - .ctl_zs_first - ); - - info!( - "Debugging openings.ctl_zs_first for Logic: {:?}", - &all_proof.multi_proof.stark_proofs[*Table::Logic] - .proof - .openings - .ctl_zs_first - ); let mut root_inputs = PartialWitness::new(); @@ -1971,7 +1932,7 @@ where })?; // TODO(sdeng): Set to false when this segment contains no Keccak operations. - root_inputs.set_bool_target(self.root.enable_keccak_tables, true); + root_inputs.set_bool_target(self.root.use_keccak_tables, true); let root_proof = self.root.circuit.prove(root_inputs)?; @@ -2114,7 +2075,7 @@ where })?; // TODO(sdeng): Set to false when this segment contains no Keccak operations. - root_inputs.set_bool_target(self.root.enable_keccak_tables, true); + root_inputs.set_bool_target(self.root.use_keccak_tables, true); let root_proof = self.root.circuit.prove(root_inputs)?; From 7a3fe087d3752aa3c5f1c55d22178a7e507ebcfe Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Wed, 25 Sep 2024 10:14:27 -0700 Subject: [PATCH 17/29] polish the comments --- evm_arithmetization/src/fixed_recursive_verifier.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 8056f9ab3..a13386569 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -812,6 +812,7 @@ where } } + // Ensures that the trace cap is set to 0 when skipping Keccak tables. for i in KECCAK_TABLES_INDICES { for h in &pis[i].trace_cap { for t in h { @@ -871,13 +872,13 @@ where let current_state_after = pis[i].challenger_state_after.as_ref(); for j in 0..state_len { if KECCAK_TABLES_INDICES.contains(&i) { - // Ensure that the challenger state: - // 1) prev == current_before, when using keccak + // Ensure the challenger state: + // 1) prev == current_before when using Keccak let diff = builder.sub(prev_state[j], current_state_before[j]); let check = builder.mul(use_keccak_tables.target, diff); builder.assert_zero(check); - // 2) prev <- current_after, when using keccak - // 3) prev <- prev, when skipping using keccak + // 2) Update prev <- current_after when using Keccak + // 3) Keep prev <- prev when skipping Keccak prev_state[j] = builder.select(use_keccak_tables, current_state_after[j], prev_state[j]); } else { @@ -903,7 +904,8 @@ where }) .collect_vec(); - // When Keccak Tables are disabled, Keccak Tables' ctl_zs_first should be 0s. + // Ensure that when Keccak tables are skipped, the Keccak tables' ctl_zs_first + // are all zeros. for &i in KECCAK_TABLES_INDICES.iter() { for &t in pis[i].ctl_zs_first.iter() { let ctl_check = builder.mul(skip_keccak_tables.target, t); From 38009861d130e5fd6b8f88d8cafa2a73634a3c92 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Wed, 25 Sep 2024 11:15:47 -0700 Subject: [PATCH 18/29] update tests --- .../src/fixed_recursive_verifier.rs | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 80f7f1b66..781635b6c 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -2973,17 +2973,7 @@ mod tests { "Create all recursive circuits", AllRecursiveCircuits::::new( &all_stark, - &[ - 16..17, - 8..9, - 9..10, - 4..5, - 8..9, - 4..5, - 17..18, - 17..18, - 17..18 - ], + &[16..17, 8..9, 9..10, 4..9, 8..9, 4..7, 17..18, 17..18, 7..18], &config, ) ); @@ -3001,12 +2991,7 @@ mod tests { let mut proofs_without_keccak = vec![]; - let skip_proofs_before_index = 3; - for (i, segment_run) in segment_iterator.enumerate() { - if i < skip_proofs_before_index { - continue; - } - + for segment_run in segment_iterator { // Process and prove segment let (_, mut segment_data) = segment_run.map_err(|e: SegmentError| anyhow::format_err!(e))?; @@ -3025,7 +3010,6 @@ mod tests { ); proofs_without_keccak.push(segment_proof); - break; // Process only one proof } // Verify the generated segment proof From 91dbeaa3ea4da6fbda43541645aba4e263b71d3b Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Wed, 25 Sep 2024 11:25:18 -0700 Subject: [PATCH 19/29] fix ci --- evm_arithmetization/src/testing_utils.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/evm_arithmetization/src/testing_utils.rs b/evm_arithmetization/src/testing_utils.rs index 528cae9ed..41b2a05fd 100644 --- a/evm_arithmetization/src/testing_utils.rs +++ b/evm_arithmetization/src/testing_utils.rs @@ -10,8 +10,7 @@ use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, Node, PartialTrie}, }; -use plonky2::field::goldilocks_field::GoldilocksField; - +use plonky2::hash::hash_types::RichField; pub use crate::cpu::kernel::cancun_constants::*; pub use crate::cpu::kernel::constants::global_exit_root::*; use crate::generation::TrieInputs; @@ -168,10 +167,10 @@ pub fn scalable_contract_from_storage(storage_trie: &HashedPartialTrie) -> Accou /// Get `GenerationInputs` for a dummy payload, where the block has the given /// timestamp. -pub fn dummy_payload( +pub fn dummy_payload( timestamp: u64, is_first_payload: bool, -) -> Result> { +) -> Result> { let beneficiary = hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); let block_metadata = BlockMetadata { From bb790807d04bfe8c3f41d23926cd8890e8c9d918 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Wed, 25 Sep 2024 11:26:52 -0700 Subject: [PATCH 20/29] fix ci --- evm_arithmetization/src/testing_utils.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/evm_arithmetization/src/testing_utils.rs b/evm_arithmetization/src/testing_utils.rs index 41b2a05fd..18f1f1186 100644 --- a/evm_arithmetization/src/testing_utils.rs +++ b/evm_arithmetization/src/testing_utils.rs @@ -11,6 +11,7 @@ use mpt_trie::{ partial_trie::{HashedPartialTrie, Node, PartialTrie}, }; use plonky2::hash::hash_types::RichField; + pub use crate::cpu::kernel::cancun_constants::*; pub use crate::cpu::kernel::constants::global_exit_root::*; use crate::generation::TrieInputs; From fd55d1a4cf42803664391253a77f855279f6e38a Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Wed, 25 Sep 2024 11:41:28 -0700 Subject: [PATCH 21/29] fix ci --- evm_arithmetization/src/fixed_recursive_verifier.rs | 3 +-- evm_arithmetization/src/testing_utils.rs | 6 +----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 6a20bef48..41ab5498f 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -2992,8 +2992,7 @@ mod tests { for segment_run in segment_iterator { // Process and prove segment - let (_, mut segment_data) = - segment_run.map_err(|e: SegmentError| anyhow::format_err!(e))?; + let (_, mut segment_data) = segment_run?; let segment_proof = timed!( timing, log::Level::Info, diff --git a/evm_arithmetization/src/testing_utils.rs b/evm_arithmetization/src/testing_utils.rs index 18f1f1186..383c4aa10 100644 --- a/evm_arithmetization/src/testing_utils.rs +++ b/evm_arithmetization/src/testing_utils.rs @@ -10,7 +10,6 @@ use mpt_trie::{ nibbles::Nibbles, partial_trie::{HashedPartialTrie, Node, PartialTrie}, }; -use plonky2::hash::hash_types::RichField; pub use crate::cpu::kernel::cancun_constants::*; pub use crate::cpu::kernel::constants::global_exit_root::*; @@ -168,10 +167,7 @@ pub fn scalable_contract_from_storage(storage_trie: &HashedPartialTrie) -> Accou /// Get `GenerationInputs` for a dummy payload, where the block has the given /// timestamp. -pub fn dummy_payload( - timestamp: u64, - is_first_payload: bool, -) -> Result> { +pub fn dummy_payload(timestamp: u64, is_first_payload: bool) -> Result { let beneficiary = hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); let block_metadata = BlockMetadata { From 4de4c64f0cec61564c679bfda212242caabea82c Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Thu, 26 Sep 2024 15:39:47 -0700 Subject: [PATCH 22/29] empty payload and no keccak op check --- evm_arithmetization/src/arithmetic/mod.rs | 5 +- .../src/cpu/kernel/interpreter.rs | 14 ++- .../src/fixed_recursive_verifier.rs | 56 +++++----- .../src/generation/segments.rs | 11 ++ evm_arithmetization/src/logic.rs | 3 +- evm_arithmetization/src/testing_utils.rs | 70 ++++-------- evm_arithmetization/src/witness/operation.rs | 3 +- evm_arithmetization/tests/two_to_one_block.rs | 102 +++++++++++++++--- 8 files changed, 163 insertions(+), 101 deletions(-) diff --git a/evm_arithmetization/src/arithmetic/mod.rs b/evm_arithmetization/src/arithmetic/mod.rs index 0ca1bbe7a..ab65def9b 100644 --- a/evm_arithmetization/src/arithmetic/mod.rs +++ b/evm_arithmetization/src/arithmetic/mod.rs @@ -1,5 +1,6 @@ use ethereum_types::U256; use plonky2::field::types::PrimeField64; +use serde::{Deserialize, Serialize}; use self::columns::{ INPUT_REGISTER_0, INPUT_REGISTER_1, INPUT_REGISTER_2, OPCODE_COL, OUTPUT_REGISTER, @@ -24,7 +25,7 @@ pub(crate) mod columns; /// /// `Shl` and `Shr` are handled differently, by leveraging `Mul` and `Div` /// respectively. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub(crate) enum BinaryOperator { Add, Mul, @@ -114,7 +115,7 @@ impl BinaryOperator { /// An enum representing different ternary operations. #[allow(clippy::enum_variant_names)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub(crate) enum TernaryOperator { AddMod, MulMod, diff --git a/evm_arithmetization/src/cpu/kernel/interpreter.rs b/evm_arithmetization/src/cpu/kernel/interpreter.rs index b831a921a..6c3cc73e0 100644 --- a/evm_arithmetization/src/cpu/kernel/interpreter.rs +++ b/evm_arithmetization/src/cpu/kernel/interpreter.rs @@ -54,8 +54,7 @@ pub(crate) struct Interpreter { /// halt_context pub(crate) halt_context: Option, /// Counts the number of appearances of each opcode. For debugging purposes. - #[allow(unused)] - pub(crate) opcode_count: [usize; 0x100], + pub(crate) opcode_count: HashMap, jumpdest_table: HashMap>, /// `true` if the we are currently carrying out a jumpdest analysis. pub(crate) is_jumpdest_analysis: bool, @@ -178,7 +177,7 @@ impl Interpreter { // while the label `halt` is the halting label in the kernel. halt_offsets: vec![DEFAULT_HALT_OFFSET, KERNEL.global_labels["halt_final"]], halt_context: None, - opcode_count: [0; 256], + opcode_count: HashMap::new(), jumpdest_table: HashMap::new(), is_jumpdest_analysis: false, clock: 0, @@ -209,7 +208,7 @@ impl Interpreter { generation_state: state.soft_clone(), halt_offsets: vec![halt_offset], halt_context: Some(halt_context), - opcode_count: [0; 256], + opcode_count: HashMap::new(), jumpdest_table: HashMap::new(), is_jumpdest_analysis: true, clock: 0, @@ -428,6 +427,10 @@ impl Interpreter { self.max_cpu_len_log } + pub(crate) fn reset_opcode_counts(&mut self) { + self.opcode_count = HashMap::new(); + } + pub(crate) fn code(&self) -> &MemorySegmentState { // The context is 0 if we are in kernel mode. &self.generation_state.memory.contexts[(1 - self.is_kernel() as usize) * self.context()] @@ -661,6 +664,9 @@ impl State for Interpreter { let op = decode(registers, opcode)?; + // Increment the opcode count + *self.opcode_count.entry(op).or_insert(0) += 1; + fill_op_flag(op, &mut row); self.fill_stack_fields(&mut row)?; diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 41ab5498f..825ab4091 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -2951,7 +2951,8 @@ mod tests { use plonky2::timed; use super::*; - use crate::testing_utils::{dummy_payload, init_logger}; + use crate::testing_utils::{empty_payload, init_logger}; + use crate::witness::operation::Operation; type F = GoldilocksField; const D: usize = 2; @@ -2966,56 +2967,47 @@ mod tests { let all_stark = AllStark::::default(); let config = StarkConfig::standard_fast_config(); + // Generate a dummy payload for testing + let payload = empty_payload()?; + let max_cpu_len_log = Some(7); + let mut segment_iterator = SegmentDataIterator::::new(&payload, max_cpu_len_log); + let (_, mut segment_data) = segment_iterator.next().unwrap()?; + + let opcode_counts = &segment_data.opcode_counts; + assert!(!opcode_counts.contains_key(&Operation::KeccakGeneral)); + + // Process and prove segment let all_circuits = timed!( timing, log::Level::Info, "Create all recursive circuits", AllRecursiveCircuits::::new( &all_stark, - &[16..17, 8..9, 9..10, 4..9, 8..9, 4..7, 17..18, 17..18, 7..18], + &[16..17, 8..9, 7..8, 4..9, 8..9, 4..7, 17..18, 17..18, 17..18], &config, ) ); - // Generate a dummy payload for testing - let dummy_payload = timed!( + let segment_proof = timed!( timing, log::Level::Info, - "Generate dummy payload", - dummy_payload(100, true)? - ); - - let max_cpu_len_log = 9; - let segment_iterator = SegmentDataIterator::::new(&dummy_payload, Some(max_cpu_len_log)); - - let mut proofs_without_keccak = vec![]; - - for segment_run in segment_iterator { - // Process and prove segment - let (_, mut segment_data) = segment_run?; - let segment_proof = timed!( + "Prove segment", + all_circuits.prove_segment( + &all_stark, + &config, + payload.trim(), + &mut segment_data, timing, - log::Level::Info, - "Prove segment", - all_circuits.prove_segment( - &all_stark, - &config, - dummy_payload.trim(), - &mut segment_data, - timing, - None, - )? - ); - - proofs_without_keccak.push(segment_proof); - } + None, + )? + ); // Verify the generated segment proof timed!( timing, log::Level::Info, "Verify segment proof", - all_circuits.verify_root(proofs_without_keccak[0].proof_with_pis.clone())? + all_circuits.verify_root(segment_proof.proof_with_pis.clone())? ); // Print timing details diff --git a/evm_arithmetization/src/generation/segments.rs b/evm_arithmetization/src/generation/segments.rs index b3a129137..8203aafdb 100644 --- a/evm_arithmetization/src/generation/segments.rs +++ b/evm_arithmetization/src/generation/segments.rs @@ -1,6 +1,8 @@ //! Module defining the logic around proof segmentation into chunks, //! which allows what is commonly known as zk-continuations. +use std::collections::HashMap; + use anyhow::Result; use plonky2::hash::hash_types::RichField; use serde::{Deserialize, Serialize}; @@ -11,6 +13,7 @@ use crate::cpu::kernel::interpreter::{set_registers_and_run, ExtraSegmentData, I use crate::generation::state::State; use crate::generation::{collect_debug_tries, debug_inputs, ErrorWithTries, GenerationInputs}; use crate::witness::memory::MemoryState; +use crate::witness::operation::Operation; use crate::witness::state::RegistersState; /// Structure holding the data needed to initialize a segment. @@ -29,6 +32,8 @@ pub struct GenerationSegmentData { pub(crate) extra_data: ExtraSegmentData, /// Log of the maximal cpu length. pub(crate) max_cpu_len_log: Option, + /// Counts the number of appearances of each opcode. For debugging purposes. + pub(crate) opcode_counts: HashMap, } impl GenerationSegmentData { @@ -77,6 +82,7 @@ fn build_segment_data( accounts: interpreter.generation_state.accounts_pointers.clone(), storage: interpreter.generation_state.storage_pointers.clone(), }, + opcode_counts: interpreter.opcode_count.clone(), } } @@ -133,6 +139,9 @@ impl SegmentDataIterator { let segment_index = segment_data.segment_index; + // Reset opcode counts before executing the segment + self.interpreter.reset_opcode_counts(); + // Run the interpreter to get `registers_after` and the partial data for the // next segment. let execution_result = @@ -147,6 +156,8 @@ impl SegmentDataIterator { )); segment_data.registers_after = updated_registers; + segment_data.opcode_counts = self.interpreter.opcode_count.clone(); + Ok(Some(Box::new((segment_data, partial_segment_data)))) } else { let inputs = &self.interpreter.get_generation_state().inputs; diff --git a/evm_arithmetization/src/logic.rs b/evm_arithmetization/src/logic.rs index 0ba378b52..7d68e463e 100644 --- a/evm_arithmetization/src/logic.rs +++ b/evm_arithmetization/src/logic.rs @@ -11,6 +11,7 @@ use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::timed; use plonky2::util::timing::TimingTree; +use serde::{Deserialize, Serialize}; use starky::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use starky::evaluation_frame::StarkEvaluationFrame; use starky::lookup::{Column, Filter}; @@ -118,7 +119,7 @@ pub(crate) struct LogicStark { } /// Logic operations. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub(crate) enum Op { And, Or, diff --git a/evm_arithmetization/src/testing_utils.rs b/evm_arithmetization/src/testing_utils.rs index 383c4aa10..5f1b1b041 100644 --- a/evm_arithmetization/src/testing_utils.rs +++ b/evm_arithmetization/src/testing_utils.rs @@ -165,70 +165,46 @@ pub fn scalable_contract_from_storage(storage_trie: &HashedPartialTrie) -> Accou } } -/// Get `GenerationInputs` for a dummy payload, where the block has the given -/// timestamp. -pub fn dummy_payload(timestamp: u64, is_first_payload: bool) -> Result { - let beneficiary = hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); - +pub fn empty_payload() -> Result { + // Set up default block metadata let block_metadata = BlockMetadata { - block_beneficiary: Address::from(beneficiary), - block_timestamp: timestamp.into(), - block_number: 1.into(), - block_difficulty: 0x020000.into(), - block_random: H256::from_uint(&0x020000.into()), - block_gaslimit: 0xff112233u32.into(), - block_chain_id: 1.into(), - block_base_fee: 0xa.into(), + block_beneficiary: Address::zero(), + block_timestamp: U256::zero(), + block_number: U256::one(), + block_difficulty: U256::zero(), + block_random: H256::zero(), + block_gaslimit: U256::zero(), + block_chain_id: U256::one(), + block_base_fee: U256::zero(), ..Default::default() }; - let (mut state_trie_before, mut storage_tries) = preinitialized_state_and_storage_tries()?; + // Initialize an empty state trie and storage tries + let state_trie_before = HashedPartialTrie::from(crate::Node::Empty); + let storage_tries = Vec::new(); let checkpoint_state_trie_root = state_trie_before.hash(); - let mut beacon_roots_account_storage = storage_tries[0].1.clone(); - - update_beacon_roots_account_storage( - &mut beacon_roots_account_storage, - block_metadata.block_timestamp, - block_metadata.parent_beacon_block_root, - )?; - let updated_beacon_roots_account = - beacon_roots_contract_from_storage(&beacon_roots_account_storage); - - if !is_first_payload { - // This isn't the first dummy payload being processed. We need to update the - // initial state trie to account for the update on the beacon roots contract. - state_trie_before.insert( - beacon_roots_account_nibbles(), - rlp::encode(&updated_beacon_roots_account).to_vec(), - )?; - storage_tries[0].1 = beacon_roots_account_storage; - } + // Prepare the tries without any transactions or receipts let tries_before = TrieInputs { - state_trie: state_trie_before, - storage_tries, - ..Default::default() + state_trie: state_trie_before.clone(), + storage_tries: storage_tries.clone(), + transactions_trie: HashedPartialTrie::from(crate::Node::Empty), + receipts_trie: HashedPartialTrie::from(crate::Node::Empty), }; - let expected_state_trie_after: HashedPartialTrie = { - let mut state_trie_after = HashedPartialTrie::from(crate::Node::Empty); - state_trie_after.insert( - beacon_roots_account_nibbles(), - rlp::encode(&updated_beacon_roots_account).to_vec(), - )?; - - state_trie_after - }; + // The expected state trie after execution remains the same as before + let expected_state_trie_after = state_trie_before; + // Compute the trie roots after execution let trie_roots_after = TrieRoots { state_root: expected_state_trie_after.hash(), transactions_root: tries_before.transactions_trie.hash(), receipts_root: tries_before.receipts_trie.hash(), }; + // Construct the GenerationInputs without any transactions or state changes let inputs = GenerationInputs { - tries: tries_before.clone(), - burn_addr: None, + tries: tries_before, trie_roots_after, checkpoint_state_trie_root, block_metadata, diff --git a/evm_arithmetization/src/witness/operation.rs b/evm_arithmetization/src/witness/operation.rs index 55f3d3c18..c8e2a5376 100644 --- a/evm_arithmetization/src/witness/operation.rs +++ b/evm_arithmetization/src/witness/operation.rs @@ -2,6 +2,7 @@ use ethereum_types::{BigEndianHash, U256}; use itertools::Itertools; use keccak_hash::keccak; use plonky2::hash::hash_types::RichField; +use serde::{Deserialize, Serialize}; use super::state::KERNEL_CONTEXT; use super::transition::Transition; @@ -29,7 +30,7 @@ use crate::witness::util::{ }; use crate::{arithmetic, logic}; -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub(crate) enum Operation { Iszero, Not, diff --git a/evm_arithmetization/tests/two_to_one_block.rs b/evm_arithmetization/tests/two_to_one_block.rs index 55489187d..db4363ae6 100644 --- a/evm_arithmetization/tests/two_to_one_block.rs +++ b/evm_arithmetization/tests/two_to_one_block.rs @@ -1,12 +1,22 @@ #![cfg(feature = "eth_mainnet")] +use ethereum_types::{Address, BigEndianHash, H256}; use evm_arithmetization::fixed_recursive_verifier::{ extract_block_final_public_values, extract_two_to_one_block_hash, }; -use evm_arithmetization::proof::{FinalPublicValues, PublicValues}; -use evm_arithmetization::testing_utils::{dummy_payload, init_logger}; -use evm_arithmetization::{AllRecursiveCircuits, AllStark, StarkConfig}; +use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; +use evm_arithmetization::proof::{ + BlockMetadata, FinalPublicValues, PublicValues, TrieRoots, EMPTY_CONSOLIDATED_BLOCKHASH, +}; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, init_logger, + preinitialized_state_and_storage_tries, update_beacon_roots_account_storage, +}; +use evm_arithmetization::{AllRecursiveCircuits, AllStark, Node, StarkConfig}; +use hex_literal::hex; +use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; use plonky2::hash::poseidon::PoseidonHash; use plonky2::plonk::config::{Hasher, PoseidonGoldilocksConfig}; use plonky2::plonk::proof::ProofWithPublicInputs; @@ -16,6 +26,80 @@ type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; +/// Get `GenerationInputs` for a dummy payload, where the block has the given +/// timestamp. +fn dummy_payload(timestamp: u64, is_first_payload: bool) -> anyhow::Result> { + let beneficiary = hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + + let block_metadata = BlockMetadata { + block_beneficiary: Address::from(beneficiary), + block_timestamp: timestamp.into(), + block_number: 1.into(), + block_difficulty: 0x020000.into(), + block_random: H256::from_uint(&0x020000.into()), + block_gaslimit: 0xff112233u32.into(), + block_chain_id: 1.into(), + block_base_fee: 0xa.into(), + ..Default::default() + }; + + let (mut state_trie_before, mut storage_tries) = preinitialized_state_and_storage_tries()?; + let checkpoint_state_trie_root = state_trie_before.hash(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); + + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + )?; + let updated_beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + + if !is_first_payload { + // This isn't the first dummy payload being processed. We need to update the + // initial state trie to account for the update on the beacon roots contract. + state_trie_before.insert( + beacon_roots_account_nibbles(), + rlp::encode(&updated_beacon_roots_account).to_vec(), + )?; + storage_tries[0].1 = beacon_roots_account_storage; + } + + let tries_before = TrieInputs { + state_trie: state_trie_before, + storage_tries, + ..Default::default() + }; + + let expected_state_trie_after: HashedPartialTrie = { + let mut state_trie_after = HashedPartialTrie::from(Node::Empty); + state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&updated_beacon_roots_account).to_vec(), + )?; + + state_trie_after + }; + + let trie_roots_after = TrieRoots { + state_root: expected_state_trie_after.hash(), + transactions_root: tries_before.transactions_trie.hash(), + receipts_root: tries_before.receipts_trie.hash(), + }; + + let inputs = GenerationInputs { + tries: tries_before.clone(), + burn_addr: None, + trie_roots_after, + checkpoint_state_trie_root, + checkpoint_consolidated_hash: EMPTY_CONSOLIDATED_BLOCKHASH.map(F::from_canonical_u64), + block_metadata, + ..Default::default() + }; + + Ok(inputs) +} + fn get_test_block_proof( timestamp: u64, all_circuits: &AllRecursiveCircuits, @@ -90,17 +174,7 @@ fn test_two_to_one_block_aggregation() -> anyhow::Result<()> { let all_circuits = AllRecursiveCircuits::new( &all_stark, - &[ - 16..17, - 8..9, - 12..13, - 9..10, - 8..9, - 6..7, - 17..18, - 17..18, - 7..8, - ], + &[16..17, 8..9, 12..13, 8..9, 8..9, 6..7, 17..18, 17..18, 7..8], &config, ); From e34c59a62a544601caa48bd28c8857ab47750c6d Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Thu, 26 Sep 2024 16:05:17 -0700 Subject: [PATCH 23/29] refactor --- evm_arithmetization/src/fixed_recursive_verifier.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 825ab4091..d3dd1f286 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -2961,7 +2961,6 @@ mod tests { #[test] #[ignore] fn test_segment_proof_generation_without_keccak() -> anyhow::Result<()> { - let timing = &mut TimingTree::new("Segment Proof Generation", log::Level::Info); init_logger(); let all_stark = AllStark::::default(); @@ -2976,6 +2975,10 @@ mod tests { let opcode_counts = &segment_data.opcode_counts; assert!(!opcode_counts.contains_key(&Operation::KeccakGeneral)); + let timing = &mut TimingTree::new( + "Segment Proof Generation Without Keccak Test", + log::Level::Info, + ); // Process and prove segment let all_circuits = timed!( timing, From be887e6f3a5c6d133cee46878476ca0f159e7887 Mon Sep 17 00:00:00 2001 From: Sai <135601871+sai-deng@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:02:31 -0700 Subject: [PATCH 24/29] Update evm_arithmetization/src/fixed_recursive_verifier.rs Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> --- evm_arithmetization/src/fixed_recursive_verifier.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 8e15901d7..2c0b70574 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -835,18 +835,16 @@ where if KECCAK_TABLES_INDICES.contains(&i) { // Ensures that the correct CTL challenges are used in Keccak tables when // `enable_keccak_tables` is true. - let beta_diff = builder.sub( + builder.conditional_assert_eq( + use_keccak_tables.target, ctl_challenges.challenges[j].beta, pi.ctl_challenges.challenges[j].beta, ); - let gamma_diff = builder.sub( + builder.conditional_assert_eq( + use_keccak_tables.target, ctl_challenges.challenges[j].gamma, pi.ctl_challenges.challenges[j].gamma, ); - let beta_check = builder.mul(use_keccak_tables.target, beta_diff); - let gamma_check = builder.mul(use_keccak_tables.target, gamma_diff); - builder.assert_zero(beta_check); - builder.assert_zero(gamma_check); } else { builder.connect( ctl_challenges.challenges[j].beta, From d2ca0cc97a5431fc323296b0aab6ed7d63a7e1c2 Mon Sep 17 00:00:00 2001 From: Sai <135601871+sai-deng@users.noreply.github.com> Date: Mon, 30 Sep 2024 11:03:21 -0700 Subject: [PATCH 25/29] Update evm_arithmetization/src/fixed_recursive_verifier.rs Co-authored-by: Robin Salen <30937548+Nashtare@users.noreply.github.com> --- evm_arithmetization/src/fixed_recursive_verifier.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 2c0b70574..60c2eae42 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -872,9 +872,7 @@ where if KECCAK_TABLES_INDICES.contains(&i) { // Ensure the challenger state: // 1) prev == current_before when using Keccak - let diff = builder.sub(prev_state[j], current_state_before[j]); - let check = builder.mul(use_keccak_tables.target, diff); - builder.assert_zero(check); + builder. conditional_assert_eq(use_keccak_tables.target, prev_state[j], current_state_before[j]); // 2) Update prev <- current_after when using Keccak // 3) Keep prev <- prev when skipping Keccak prev_state[j] = From ce88ef8450c6e4b3263c0c73f9f13600da3e1bb4 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Thu, 26 Sep 2024 15:39:47 -0700 Subject: [PATCH 26/29] empty payload and no keccak op check --- evm_arithmetization/src/arithmetic/mod.rs | 5 +- .../src/cpu/kernel/interpreter.rs | 14 ++- .../src/fixed_recursive_verifier.rs | 56 +++++----- .../src/generation/segments.rs | 11 ++ evm_arithmetization/src/logic.rs | 3 +- evm_arithmetization/src/testing_utils.rs | 70 ++++-------- evm_arithmetization/src/witness/operation.rs | 3 +- evm_arithmetization/tests/two_to_one_block.rs | 102 +++++++++++++++--- 8 files changed, 163 insertions(+), 101 deletions(-) diff --git a/evm_arithmetization/src/arithmetic/mod.rs b/evm_arithmetization/src/arithmetic/mod.rs index 0ca1bbe7a..ab65def9b 100644 --- a/evm_arithmetization/src/arithmetic/mod.rs +++ b/evm_arithmetization/src/arithmetic/mod.rs @@ -1,5 +1,6 @@ use ethereum_types::U256; use plonky2::field::types::PrimeField64; +use serde::{Deserialize, Serialize}; use self::columns::{ INPUT_REGISTER_0, INPUT_REGISTER_1, INPUT_REGISTER_2, OPCODE_COL, OUTPUT_REGISTER, @@ -24,7 +25,7 @@ pub(crate) mod columns; /// /// `Shl` and `Shr` are handled differently, by leveraging `Mul` and `Div` /// respectively. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub(crate) enum BinaryOperator { Add, Mul, @@ -114,7 +115,7 @@ impl BinaryOperator { /// An enum representing different ternary operations. #[allow(clippy::enum_variant_names)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub(crate) enum TernaryOperator { AddMod, MulMod, diff --git a/evm_arithmetization/src/cpu/kernel/interpreter.rs b/evm_arithmetization/src/cpu/kernel/interpreter.rs index b831a921a..6c3cc73e0 100644 --- a/evm_arithmetization/src/cpu/kernel/interpreter.rs +++ b/evm_arithmetization/src/cpu/kernel/interpreter.rs @@ -54,8 +54,7 @@ pub(crate) struct Interpreter { /// halt_context pub(crate) halt_context: Option, /// Counts the number of appearances of each opcode. For debugging purposes. - #[allow(unused)] - pub(crate) opcode_count: [usize; 0x100], + pub(crate) opcode_count: HashMap, jumpdest_table: HashMap>, /// `true` if the we are currently carrying out a jumpdest analysis. pub(crate) is_jumpdest_analysis: bool, @@ -178,7 +177,7 @@ impl Interpreter { // while the label `halt` is the halting label in the kernel. halt_offsets: vec![DEFAULT_HALT_OFFSET, KERNEL.global_labels["halt_final"]], halt_context: None, - opcode_count: [0; 256], + opcode_count: HashMap::new(), jumpdest_table: HashMap::new(), is_jumpdest_analysis: false, clock: 0, @@ -209,7 +208,7 @@ impl Interpreter { generation_state: state.soft_clone(), halt_offsets: vec![halt_offset], halt_context: Some(halt_context), - opcode_count: [0; 256], + opcode_count: HashMap::new(), jumpdest_table: HashMap::new(), is_jumpdest_analysis: true, clock: 0, @@ -428,6 +427,10 @@ impl Interpreter { self.max_cpu_len_log } + pub(crate) fn reset_opcode_counts(&mut self) { + self.opcode_count = HashMap::new(); + } + pub(crate) fn code(&self) -> &MemorySegmentState { // The context is 0 if we are in kernel mode. &self.generation_state.memory.contexts[(1 - self.is_kernel() as usize) * self.context()] @@ -661,6 +664,9 @@ impl State for Interpreter { let op = decode(registers, opcode)?; + // Increment the opcode count + *self.opcode_count.entry(op).or_insert(0) += 1; + fill_op_flag(op, &mut row); self.fill_stack_fields(&mut row)?; diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 60c2eae42..92853a9c0 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -3025,7 +3025,8 @@ mod tests { use plonky2::timed; use super::*; - use crate::testing_utils::{dummy_payload, init_logger}; + use crate::testing_utils::{empty_payload, init_logger}; + use crate::witness::operation::Operation; type F = GoldilocksField; const D: usize = 2; @@ -3040,56 +3041,47 @@ mod tests { let all_stark = AllStark::::default(); let config = StarkConfig::standard_fast_config(); + // Generate a dummy payload for testing + let payload = empty_payload()?; + let max_cpu_len_log = Some(7); + let mut segment_iterator = SegmentDataIterator::::new(&payload, max_cpu_len_log); + let (_, mut segment_data) = segment_iterator.next().unwrap()?; + + let opcode_counts = &segment_data.opcode_counts; + assert!(!opcode_counts.contains_key(&Operation::KeccakGeneral)); + + // Process and prove segment let all_circuits = timed!( timing, log::Level::Info, "Create all recursive circuits", AllRecursiveCircuits::::new( &all_stark, - &[16..17, 8..9, 9..10, 4..9, 8..9, 4..7, 17..18, 17..18, 7..18], + &[16..17, 8..9, 7..8, 4..9, 8..9, 4..7, 17..18, 17..18, 17..18], &config, ) ); - // Generate a dummy payload for testing - let dummy_payload = timed!( + let segment_proof = timed!( timing, log::Level::Info, - "Generate dummy payload", - dummy_payload(100, true)? - ); - - let max_cpu_len_log = 9; - let segment_iterator = SegmentDataIterator::::new(&dummy_payload, Some(max_cpu_len_log)); - - let mut proofs_without_keccak = vec![]; - - for segment_run in segment_iterator { - // Process and prove segment - let (_, mut segment_data) = segment_run?; - let segment_proof = timed!( + "Prove segment", + all_circuits.prove_segment( + &all_stark, + &config, + payload.trim(), + &mut segment_data, timing, - log::Level::Info, - "Prove segment", - all_circuits.prove_segment( - &all_stark, - &config, - dummy_payload.trim(), - &mut segment_data, - timing, - None, - )? - ); - - proofs_without_keccak.push(segment_proof); - } + None, + )? + ); // Verify the generated segment proof timed!( timing, log::Level::Info, "Verify segment proof", - all_circuits.verify_root(proofs_without_keccak[0].proof_with_pis.clone())? + all_circuits.verify_root(segment_proof.proof_with_pis.clone())? ); // Print timing details diff --git a/evm_arithmetization/src/generation/segments.rs b/evm_arithmetization/src/generation/segments.rs index b3a129137..8203aafdb 100644 --- a/evm_arithmetization/src/generation/segments.rs +++ b/evm_arithmetization/src/generation/segments.rs @@ -1,6 +1,8 @@ //! Module defining the logic around proof segmentation into chunks, //! which allows what is commonly known as zk-continuations. +use std::collections::HashMap; + use anyhow::Result; use plonky2::hash::hash_types::RichField; use serde::{Deserialize, Serialize}; @@ -11,6 +13,7 @@ use crate::cpu::kernel::interpreter::{set_registers_and_run, ExtraSegmentData, I use crate::generation::state::State; use crate::generation::{collect_debug_tries, debug_inputs, ErrorWithTries, GenerationInputs}; use crate::witness::memory::MemoryState; +use crate::witness::operation::Operation; use crate::witness::state::RegistersState; /// Structure holding the data needed to initialize a segment. @@ -29,6 +32,8 @@ pub struct GenerationSegmentData { pub(crate) extra_data: ExtraSegmentData, /// Log of the maximal cpu length. pub(crate) max_cpu_len_log: Option, + /// Counts the number of appearances of each opcode. For debugging purposes. + pub(crate) opcode_counts: HashMap, } impl GenerationSegmentData { @@ -77,6 +82,7 @@ fn build_segment_data( accounts: interpreter.generation_state.accounts_pointers.clone(), storage: interpreter.generation_state.storage_pointers.clone(), }, + opcode_counts: interpreter.opcode_count.clone(), } } @@ -133,6 +139,9 @@ impl SegmentDataIterator { let segment_index = segment_data.segment_index; + // Reset opcode counts before executing the segment + self.interpreter.reset_opcode_counts(); + // Run the interpreter to get `registers_after` and the partial data for the // next segment. let execution_result = @@ -147,6 +156,8 @@ impl SegmentDataIterator { )); segment_data.registers_after = updated_registers; + segment_data.opcode_counts = self.interpreter.opcode_count.clone(); + Ok(Some(Box::new((segment_data, partial_segment_data)))) } else { let inputs = &self.interpreter.get_generation_state().inputs; diff --git a/evm_arithmetization/src/logic.rs b/evm_arithmetization/src/logic.rs index 0ba378b52..7d68e463e 100644 --- a/evm_arithmetization/src/logic.rs +++ b/evm_arithmetization/src/logic.rs @@ -11,6 +11,7 @@ use plonky2::hash::hash_types::RichField; use plonky2::iop::ext_target::ExtensionTarget; use plonky2::timed; use plonky2::util::timing::TimingTree; +use serde::{Deserialize, Serialize}; use starky::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use starky::evaluation_frame::StarkEvaluationFrame; use starky::lookup::{Column, Filter}; @@ -118,7 +119,7 @@ pub(crate) struct LogicStark { } /// Logic operations. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub(crate) enum Op { And, Or, diff --git a/evm_arithmetization/src/testing_utils.rs b/evm_arithmetization/src/testing_utils.rs index 383c4aa10..5f1b1b041 100644 --- a/evm_arithmetization/src/testing_utils.rs +++ b/evm_arithmetization/src/testing_utils.rs @@ -165,70 +165,46 @@ pub fn scalable_contract_from_storage(storage_trie: &HashedPartialTrie) -> Accou } } -/// Get `GenerationInputs` for a dummy payload, where the block has the given -/// timestamp. -pub fn dummy_payload(timestamp: u64, is_first_payload: bool) -> Result { - let beneficiary = hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); - +pub fn empty_payload() -> Result { + // Set up default block metadata let block_metadata = BlockMetadata { - block_beneficiary: Address::from(beneficiary), - block_timestamp: timestamp.into(), - block_number: 1.into(), - block_difficulty: 0x020000.into(), - block_random: H256::from_uint(&0x020000.into()), - block_gaslimit: 0xff112233u32.into(), - block_chain_id: 1.into(), - block_base_fee: 0xa.into(), + block_beneficiary: Address::zero(), + block_timestamp: U256::zero(), + block_number: U256::one(), + block_difficulty: U256::zero(), + block_random: H256::zero(), + block_gaslimit: U256::zero(), + block_chain_id: U256::one(), + block_base_fee: U256::zero(), ..Default::default() }; - let (mut state_trie_before, mut storage_tries) = preinitialized_state_and_storage_tries()?; + // Initialize an empty state trie and storage tries + let state_trie_before = HashedPartialTrie::from(crate::Node::Empty); + let storage_tries = Vec::new(); let checkpoint_state_trie_root = state_trie_before.hash(); - let mut beacon_roots_account_storage = storage_tries[0].1.clone(); - - update_beacon_roots_account_storage( - &mut beacon_roots_account_storage, - block_metadata.block_timestamp, - block_metadata.parent_beacon_block_root, - )?; - let updated_beacon_roots_account = - beacon_roots_contract_from_storage(&beacon_roots_account_storage); - - if !is_first_payload { - // This isn't the first dummy payload being processed. We need to update the - // initial state trie to account for the update on the beacon roots contract. - state_trie_before.insert( - beacon_roots_account_nibbles(), - rlp::encode(&updated_beacon_roots_account).to_vec(), - )?; - storage_tries[0].1 = beacon_roots_account_storage; - } + // Prepare the tries without any transactions or receipts let tries_before = TrieInputs { - state_trie: state_trie_before, - storage_tries, - ..Default::default() + state_trie: state_trie_before.clone(), + storage_tries: storage_tries.clone(), + transactions_trie: HashedPartialTrie::from(crate::Node::Empty), + receipts_trie: HashedPartialTrie::from(crate::Node::Empty), }; - let expected_state_trie_after: HashedPartialTrie = { - let mut state_trie_after = HashedPartialTrie::from(crate::Node::Empty); - state_trie_after.insert( - beacon_roots_account_nibbles(), - rlp::encode(&updated_beacon_roots_account).to_vec(), - )?; - - state_trie_after - }; + // The expected state trie after execution remains the same as before + let expected_state_trie_after = state_trie_before; + // Compute the trie roots after execution let trie_roots_after = TrieRoots { state_root: expected_state_trie_after.hash(), transactions_root: tries_before.transactions_trie.hash(), receipts_root: tries_before.receipts_trie.hash(), }; + // Construct the GenerationInputs without any transactions or state changes let inputs = GenerationInputs { - tries: tries_before.clone(), - burn_addr: None, + tries: tries_before, trie_roots_after, checkpoint_state_trie_root, block_metadata, diff --git a/evm_arithmetization/src/witness/operation.rs b/evm_arithmetization/src/witness/operation.rs index 55f3d3c18..c8e2a5376 100644 --- a/evm_arithmetization/src/witness/operation.rs +++ b/evm_arithmetization/src/witness/operation.rs @@ -2,6 +2,7 @@ use ethereum_types::{BigEndianHash, U256}; use itertools::Itertools; use keccak_hash::keccak; use plonky2::hash::hash_types::RichField; +use serde::{Deserialize, Serialize}; use super::state::KERNEL_CONTEXT; use super::transition::Transition; @@ -29,7 +30,7 @@ use crate::witness::util::{ }; use crate::{arithmetic, logic}; -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub(crate) enum Operation { Iszero, Not, diff --git a/evm_arithmetization/tests/two_to_one_block.rs b/evm_arithmetization/tests/two_to_one_block.rs index 55489187d..db4363ae6 100644 --- a/evm_arithmetization/tests/two_to_one_block.rs +++ b/evm_arithmetization/tests/two_to_one_block.rs @@ -1,12 +1,22 @@ #![cfg(feature = "eth_mainnet")] +use ethereum_types::{Address, BigEndianHash, H256}; use evm_arithmetization::fixed_recursive_verifier::{ extract_block_final_public_values, extract_two_to_one_block_hash, }; -use evm_arithmetization::proof::{FinalPublicValues, PublicValues}; -use evm_arithmetization::testing_utils::{dummy_payload, init_logger}; -use evm_arithmetization::{AllRecursiveCircuits, AllStark, StarkConfig}; +use evm_arithmetization::generation::{GenerationInputs, TrieInputs}; +use evm_arithmetization::proof::{ + BlockMetadata, FinalPublicValues, PublicValues, TrieRoots, EMPTY_CONSOLIDATED_BLOCKHASH, +}; +use evm_arithmetization::testing_utils::{ + beacon_roots_account_nibbles, beacon_roots_contract_from_storage, init_logger, + preinitialized_state_and_storage_tries, update_beacon_roots_account_storage, +}; +use evm_arithmetization::{AllRecursiveCircuits, AllStark, Node, StarkConfig}; +use hex_literal::hex; +use mpt_trie::partial_trie::{HashedPartialTrie, PartialTrie}; use plonky2::field::goldilocks_field::GoldilocksField; +use plonky2::field::types::Field; use plonky2::hash::poseidon::PoseidonHash; use plonky2::plonk::config::{Hasher, PoseidonGoldilocksConfig}; use plonky2::plonk::proof::ProofWithPublicInputs; @@ -16,6 +26,80 @@ type F = GoldilocksField; const D: usize = 2; type C = PoseidonGoldilocksConfig; +/// Get `GenerationInputs` for a dummy payload, where the block has the given +/// timestamp. +fn dummy_payload(timestamp: u64, is_first_payload: bool) -> anyhow::Result> { + let beneficiary = hex!("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + + let block_metadata = BlockMetadata { + block_beneficiary: Address::from(beneficiary), + block_timestamp: timestamp.into(), + block_number: 1.into(), + block_difficulty: 0x020000.into(), + block_random: H256::from_uint(&0x020000.into()), + block_gaslimit: 0xff112233u32.into(), + block_chain_id: 1.into(), + block_base_fee: 0xa.into(), + ..Default::default() + }; + + let (mut state_trie_before, mut storage_tries) = preinitialized_state_and_storage_tries()?; + let checkpoint_state_trie_root = state_trie_before.hash(); + let mut beacon_roots_account_storage = storage_tries[0].1.clone(); + + update_beacon_roots_account_storage( + &mut beacon_roots_account_storage, + block_metadata.block_timestamp, + block_metadata.parent_beacon_block_root, + )?; + let updated_beacon_roots_account = + beacon_roots_contract_from_storage(&beacon_roots_account_storage); + + if !is_first_payload { + // This isn't the first dummy payload being processed. We need to update the + // initial state trie to account for the update on the beacon roots contract. + state_trie_before.insert( + beacon_roots_account_nibbles(), + rlp::encode(&updated_beacon_roots_account).to_vec(), + )?; + storage_tries[0].1 = beacon_roots_account_storage; + } + + let tries_before = TrieInputs { + state_trie: state_trie_before, + storage_tries, + ..Default::default() + }; + + let expected_state_trie_after: HashedPartialTrie = { + let mut state_trie_after = HashedPartialTrie::from(Node::Empty); + state_trie_after.insert( + beacon_roots_account_nibbles(), + rlp::encode(&updated_beacon_roots_account).to_vec(), + )?; + + state_trie_after + }; + + let trie_roots_after = TrieRoots { + state_root: expected_state_trie_after.hash(), + transactions_root: tries_before.transactions_trie.hash(), + receipts_root: tries_before.receipts_trie.hash(), + }; + + let inputs = GenerationInputs { + tries: tries_before.clone(), + burn_addr: None, + trie_roots_after, + checkpoint_state_trie_root, + checkpoint_consolidated_hash: EMPTY_CONSOLIDATED_BLOCKHASH.map(F::from_canonical_u64), + block_metadata, + ..Default::default() + }; + + Ok(inputs) +} + fn get_test_block_proof( timestamp: u64, all_circuits: &AllRecursiveCircuits, @@ -90,17 +174,7 @@ fn test_two_to_one_block_aggregation() -> anyhow::Result<()> { let all_circuits = AllRecursiveCircuits::new( &all_stark, - &[ - 16..17, - 8..9, - 12..13, - 9..10, - 8..9, - 6..7, - 17..18, - 17..18, - 7..8, - ], + &[16..17, 8..9, 12..13, 8..9, 8..9, 6..7, 17..18, 17..18, 7..8], &config, ); From a23eaf03c25fe4f2d14369b8a9f219e83e37ee51 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Mon, 30 Sep 2024 11:52:04 -0700 Subject: [PATCH 27/29] fmt --- evm_arithmetization/src/fixed_recursive_verifier.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 92853a9c0..9c3b9f42f 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -872,7 +872,11 @@ where if KECCAK_TABLES_INDICES.contains(&i) { // Ensure the challenger state: // 1) prev == current_before when using Keccak - builder. conditional_assert_eq(use_keccak_tables.target, prev_state[j], current_state_before[j]); + builder.conditional_assert_eq( + use_keccak_tables.target, + prev_state[j], + current_state_before[j], + ); // 2) Update prev <- current_after when using Keccak // 3) Keep prev <- prev when skipping Keccak prev_state[j] = From c822a70394130124451849c8f44606c71969b7b5 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Tue, 1 Oct 2024 15:29:10 -0700 Subject: [PATCH 28/29] fix test --- evm_arithmetization/src/fixed_recursive_verifier.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index 89813d530..adab855c9 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -3064,7 +3064,7 @@ mod tests { timing, log::Level::Info, "Verify segment proof", - all_circuits.verify_root(segment_proof.proof_with_pis.clone())? + all_circuits.verify_root(segment_proof.proof_with_pvs.intern.clone())? ); // Print timing details From 447cfb93cdf3dbdbc8a7de170c97c2b50fa2f455 Mon Sep 17 00:00:00 2001 From: Sai Deng Date: Tue, 1 Oct 2024 15:40:17 -0700 Subject: [PATCH 29/29] fix ci error with "cdk_erigon" --- evm_arithmetization/src/fixed_recursive_verifier.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/evm_arithmetization/src/fixed_recursive_verifier.rs b/evm_arithmetization/src/fixed_recursive_verifier.rs index adab855c9..4432011d6 100644 --- a/evm_arithmetization/src/fixed_recursive_verifier.rs +++ b/evm_arithmetization/src/fixed_recursive_verifier.rs @@ -2999,6 +2999,7 @@ where } #[cfg(test)] +#[cfg(not(feature = "cdk_erigon"))] mod tests { use plonky2::field::goldilocks_field::GoldilocksField; use plonky2::plonk::config::PoseidonGoldilocksConfig;