From a63b73a85117230c3908a4fda05c3f374723f1d9 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Fri, 2 Dec 2022 13:56:52 -0800 Subject: [PATCH] Misc fixes --- evm/src/all_stark.rs | 17 +++++++++++++++-- evm/src/cpu/kernel/keccak_util.rs | 16 ++++++++++++++-- evm/src/cross_table_lookup.rs | 7 ++++--- evm/src/generation/mod.rs | 20 ++++++++++---------- evm/src/keccak/keccak_stark.rs | 1 + evm/src/witness/operation.rs | 30 ++++++++++++++++++++++++++++-- evm/src/witness/traces.rs | 18 ++++++++++++++++++ evm/src/witness/transition.rs | 4 ++-- evm/src/witness/util.rs | 22 +++++++++------------- evm/tests/empty_txn_list.rs | 2 +- 10 files changed, 102 insertions(+), 35 deletions(-) diff --git a/evm/src/all_stark.rs b/evm/src/all_stark.rs index 644f73f6..1b3e6151 100644 --- a/evm/src/all_stark.rs +++ b/evm/src/all_stark.rs @@ -8,7 +8,7 @@ use crate::config::StarkConfig; use crate::cpu::cpu_stark; use crate::cpu::cpu_stark::CpuStark; use crate::cpu::membus::NUM_GP_CHANNELS; -use crate::cross_table_lookup::{CrossTableLookup, TableWithColumns}; +use crate::cross_table_lookup::{Column, CrossTableLookup, TableWithColumns}; use crate::keccak::keccak_stark; use crate::keccak::keccak_stark::KeccakStark; use crate::keccak_memory::columns::KECCAK_WIDTH_BYTES; @@ -78,7 +78,20 @@ pub(crate) const NUM_TABLES: usize = Table::Memory as usize + 1; #[allow(unused)] // TODO: Should be used soon. pub(crate) fn all_cross_table_lookups() -> Vec> { - vec![ctl_keccak(), ctl_logic(), ctl_memory(), ctl_keccak_memory()] + let mut ctls = vec![ctl_keccak(), ctl_logic(), ctl_memory(), ctl_keccak_memory()]; + // TODO: Some CTLs temporarily disabled while we get them working. + disable_ctl(&mut ctls[0]); + disable_ctl(&mut ctls[1]); + disable_ctl(&mut ctls[2]); + disable_ctl(&mut ctls[3]); + ctls +} + +fn disable_ctl(ctl: &mut CrossTableLookup) { + for table in &mut ctl.looking_tables { + table.filter_column = Some(Column::zero()); + } + ctl.looked_table.filter_column = Some(Column::zero()); } fn ctl_keccak() -> CrossTableLookup { diff --git a/evm/src/cpu/kernel/keccak_util.rs b/evm/src/cpu/kernel/keccak_util.rs index 01d38cc4..bc6bff7a 100644 --- a/evm/src/cpu/kernel/keccak_util.rs +++ b/evm/src/cpu/kernel/keccak_util.rs @@ -1,6 +1,7 @@ use tiny_keccak::keccakf; -use crate::keccak_sponge::columns::{KECCAK_RATE_BYTES, KECCAK_RATE_U32S}; +use crate::keccak_memory::columns::KECCAK_WIDTH_BYTES; +use crate::keccak_sponge::columns::{KECCAK_RATE_BYTES, KECCAK_RATE_U32S, KECCAK_WIDTH_U32S}; /// A Keccak-f based hash. /// @@ -25,7 +26,7 @@ pub(crate) fn hash_kernel(code: &[u8]) -> [u32; 8] { } /// Like tiny-keccak's `keccakf`, but deals with `u32` limbs instead of `u64` limbs. -pub(crate) fn keccakf_u32s(state_u32s: &mut [u32; 50]) { +pub(crate) fn keccakf_u32s(state_u32s: &mut [u32; KECCAK_WIDTH_U32S]) { let mut state_u64s: [u64; 25] = std::array::from_fn(|i| { let lo = state_u32s[i * 2] as u64; let hi = state_u32s[i * 2 + 1] as u64; @@ -39,6 +40,17 @@ pub(crate) fn keccakf_u32s(state_u32s: &mut [u32; 50]) { }); } +/// Like tiny-keccak's `keccakf`, but deals with bytes instead of `u64` limbs. +pub(crate) fn keccakf_u8s(state_u8s: &mut [u8; KECCAK_WIDTH_BYTES]) { + let mut state_u64s: [u64; 25] = + std::array::from_fn(|i| u64::from_le_bytes(state_u8s[i * 8..][..8].try_into().unwrap())); + keccakf(&mut state_u64s); + *state_u8s = std::array::from_fn(|i| { + let u64_limb = state_u64s[i / 8]; + u64_limb.to_le_bytes()[i % 8] + }); +} + #[cfg(test)] mod tests { use tiny_keccak::keccakf; diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index a1fd3ce7..666d6733 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -145,7 +145,7 @@ impl Column { pub struct TableWithColumns { table: Table, columns: Vec>, - filter_column: Option>, + pub(crate) filter_column: Option>, } impl TableWithColumns { @@ -160,8 +160,8 @@ impl TableWithColumns { #[derive(Clone)] pub struct CrossTableLookup { - looking_tables: Vec>, - looked_table: TableWithColumns, + pub(crate) looking_tables: Vec>, + pub(crate) looked_table: TableWithColumns, /// Default value if filters are not used. default: Option>, } @@ -248,6 +248,7 @@ pub fn cross_table_lookup_data, const D default, } in cross_table_lookups { + log::debug!("Processing CTL for {:?}", looked_table.table); for &challenge in &challenges.challenges { let zs_looking = looking_tables.iter().map(|table| { partial_products( diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index 8c568fb5..2a1c18c9 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -7,6 +7,10 @@ use plonky2::field::polynomial::PolynomialValues; use plonky2::hash::hash_types::RichField; use plonky2::util::timing::TimingTree; use serde::{Deserialize, Serialize}; +use GlobalMetadata::{ + ReceiptTrieRootDigestAfter, ReceiptTrieRootDigestBefore, StateTrieRootDigestAfter, + StateTrieRootDigestBefore, TransactionTrieRootDigestAfter, TransactionTrieRootDigestBefore, +}; use crate::all_stark::{AllStark, NUM_TABLES}; use crate::config::StarkConfig; @@ -90,18 +94,14 @@ pub(crate) fn generate_traces, const D: usize>( }; let trie_roots_before = TrieRoots { - state_root: H256::from_uint(&read_metadata(GlobalMetadata::StateTrieRootDigestBefore)), - transactions_root: H256::from_uint(&read_metadata( - GlobalMetadata::TransactionTrieRootDigestBefore, - )), - receipts_root: H256::from_uint(&read_metadata(GlobalMetadata::ReceiptTrieRootDigestBefore)), + state_root: H256::from_uint(&read_metadata(StateTrieRootDigestBefore)), + transactions_root: H256::from_uint(&read_metadata(TransactionTrieRootDigestBefore)), + receipts_root: H256::from_uint(&read_metadata(ReceiptTrieRootDigestBefore)), }; let trie_roots_after = TrieRoots { - state_root: H256::from_uint(&read_metadata(GlobalMetadata::StateTrieRootDigestAfter)), - transactions_root: H256::from_uint(&read_metadata( - GlobalMetadata::TransactionTrieRootDigestAfter, - )), - receipts_root: H256::from_uint(&read_metadata(GlobalMetadata::ReceiptTrieRootDigestAfter)), + state_root: H256::from_uint(&read_metadata(StateTrieRootDigestAfter)), + transactions_root: H256::from_uint(&read_metadata(TransactionTrieRootDigestAfter)), + receipts_root: H256::from_uint(&read_metadata(ReceiptTrieRootDigestAfter)), }; let public_values = PublicValues { diff --git a/evm/src/keccak/keccak_stark.rs b/evm/src/keccak/keccak_stark.rs index e77769e4..7be421fb 100644 --- a/evm/src/keccak/keccak_stark.rs +++ b/evm/src/keccak/keccak_stark.rs @@ -38,6 +38,7 @@ pub fn ctl_data() -> Vec> { } pub fn ctl_filter() -> Column { + // TODO: Also need to filter out padding rows somehow. Column::single(reg_step(NUM_ROUNDS - 1)) } diff --git a/evm/src/witness/operation.rs b/evm/src/witness/operation.rs index a778d827..6b9ed619 100644 --- a/evm/src/witness/operation.rs +++ b/evm/src/witness/operation.rs @@ -5,9 +5,12 @@ use plonky2::field::types::Field; use crate::cpu::columns::CpuColumnsView; use crate::cpu::kernel::aggregator::KERNEL; +use crate::cpu::kernel::keccak_util::keccakf_u8s; use crate::cpu::membus::NUM_GP_CHANNELS; use crate::cpu::simple_logic::eq_iszero::generate_pinv_diff; use crate::generation::state::GenerationState; +use crate::keccak_memory::columns::KECCAK_WIDTH_BYTES; +use crate::keccak_sponge::columns::KECCAK_RATE_BYTES; use crate::keccak_sponge::keccak_sponge_stark::KeccakSpongeOp; use crate::memory::segments::Segment; use crate::util::u256_saturating_cast_usize; @@ -120,17 +123,39 @@ pub(crate) fn generate_keccak_general( let val = state.memory.get(address); val.as_u32() as u8 }) - .collect(); + .collect_vec(); let hash = keccak(&input); let log_push = stack_push_log_and_fill(state, &mut row, hash.into_uint())?; + let mut input_blocks = input.chunks_exact(KECCAK_RATE_BYTES); + let mut sponge_state = [0u8; KECCAK_WIDTH_BYTES]; + for block in input_blocks.by_ref() { + sponge_state[..KECCAK_RATE_BYTES].copy_from_slice(block); + state.traces.push_keccak_bytes(sponge_state); + keccakf_u8s(&mut sponge_state); + } + + let final_inputs = input_blocks.remainder(); + sponge_state[..final_inputs.len()].copy_from_slice(final_inputs); + // pad10*1 rule + sponge_state[final_inputs.len()..KECCAK_RATE_BYTES].fill(0); + if final_inputs.len() == KECCAK_RATE_BYTES - 1 { + // Both 1s are placed in the same byte. + sponge_state[final_inputs.len()] = 0b10000001; + } else { + sponge_state[final_inputs.len()] = 1; + sponge_state[KECCAK_RATE_BYTES - 1] = 0b10000000; + } + state.traces.push_keccak_bytes(sponge_state); + state.traces.push_keccak_sponge(KeccakSpongeOp { base_address, timestamp: state.traces.clock(), len, input, }); + state.traces.push_memory(log_in0); state.traces.push_memory(log_in1); state.traces.push_memory(log_in2); @@ -332,7 +357,8 @@ pub(crate) fn generate_byte( let [(i, log_in0), (x, log_in1)] = stack_pop_with_log_and_fill::<2, _>(state, &mut row)?; let byte = if i < 32.into() { - x.byte(i.as_usize()) + // byte(i) is the i'th little-endian byte; we want the i'th big-endian byte. + x.byte(31 - i.as_usize()) } else { 0 }; diff --git a/evm/src/witness/traces.rs b/evm/src/witness/traces.rs index bd6016e0..e14b96be 100644 --- a/evm/src/witness/traces.rs +++ b/evm/src/witness/traces.rs @@ -1,3 +1,6 @@ +use std::mem::size_of; + +use itertools::Itertools; use plonky2::field::extension::Extendable; use plonky2::field::polynomial::PolynomialValues; use plonky2::hash::hash_types::RichField; @@ -6,6 +9,7 @@ use plonky2::util::timing::TimingTree; use crate::all_stark::{AllStark, NUM_TABLES}; use crate::config::StarkConfig; use crate::cpu::columns::CpuColumnsView; +use crate::keccak_memory::columns::KECCAK_WIDTH_BYTES; use crate::keccak_memory::keccak_memory_stark::KeccakMemoryOp; use crate::keccak_sponge::keccak_sponge_stark::KeccakSpongeOp; use crate::util::trace_rows_to_poly_values; @@ -82,6 +86,20 @@ impl Traces { self.memory_ops.push(op); } + pub fn push_keccak(&mut self, input: [u64; keccak::keccak_stark::NUM_INPUTS]) { + self.keccak_inputs.push(input); + } + + pub fn push_keccak_bytes(&mut self, input: [u8; KECCAK_WIDTH_BYTES]) { + let chunks = input + .chunks(size_of::()) + .map(|chunk| u64::from_le_bytes(chunk.try_into().unwrap())) + .collect_vec() + .try_into() + .unwrap(); + self.push_keccak(chunks); + } + pub fn push_keccak_sponge(&mut self, op: KeccakSpongeOp) { self.keccak_sponge_ops.push(op); } diff --git a/evm/src/witness/transition.rs b/evm/src/witness/transition.rs index 9716a787..c6573c73 100644 --- a/evm/src/witness/transition.rs +++ b/evm/src/witness/transition.rs @@ -230,14 +230,14 @@ fn try_perform_instruction(state: &mut GenerationState) -> Result<( let op = decode(state.registers, opcode)?; let pc = state.registers.program_counter; - log::trace!("Cycle {}", state.traces.clock()); - log::trace!("Executing {:?} at {}", op, KERNEL.offset_name(pc)); + log::trace!("\nCycle {}", state.traces.clock()); log::trace!( "Stack: {:?}", (0..state.registers.stack_len) .map(|i| stack_peek(state, i).unwrap()) .collect_vec() ); + log::trace!("Executing {:?} at {}", op, KERNEL.offset_name(pc)); fill_op_flag(op, &mut row); perform_op(state, op, row) diff --git a/evm/src/witness/util.rs b/evm/src/witness/util.rs index a22f980d..ea30f9c9 100644 --- a/evm/src/witness/util.rs +++ b/evm/src/witness/util.rs @@ -136,19 +136,15 @@ pub(crate) fn stack_pop_with_log_and_fill( return Err(ProgramError::StackUnderflow); } - let result = { - let mut i = 0usize; - [(); N].map(|_| { - let address = MemoryAddress::new( - state.registers.effective_context(), - Segment::Stack, - state.registers.stack_len - 1 - i, - ); - let res = mem_read_gp_with_log_and_fill(i, address, state, row); - i += 1; - res - }) - }; + let result = std::array::from_fn(|i| { + let address = MemoryAddress::new( + state.registers.effective_context(), + Segment::Stack, + state.registers.stack_len - 1 - i, + ); + let res = mem_read_gp_with_log_and_fill(i, address, state, row); + res + }); state.registers.stack_len -= N; diff --git a/evm/tests/empty_txn_list.rs b/evm/tests/empty_txn_list.rs index 2e4de820..5a5fc696 100644 --- a/evm/tests/empty_txn_list.rs +++ b/evm/tests/empty_txn_list.rs @@ -85,5 +85,5 @@ fn test_empty_txn_list() -> anyhow::Result<()> { } fn init_logger() { - let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "trace")); + let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "debug")); }