diff --git a/evm_arithmetization/src/generation/mod.rs b/evm_arithmetization/src/generation/mod.rs index 0ff4f1a00..634e47f63 100644 --- a/evm_arithmetization/src/generation/mod.rs +++ b/evm_arithmetization/src/generation/mod.rs @@ -24,7 +24,8 @@ use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::constants::global_metadata::GlobalMetadata; use crate::generation::state::{GenerationState, State}; use crate::generation::trie_extractor::{get_receipt_trie, get_state_trie, get_txn_trie}; -use crate::memory::segments::Segment; +use crate::memory::columns::PREINITIALIZED_SEGMENTS; +use crate::memory::segments::{Segment, PREINITIALIZED_SEGMENTS_INDICES}; use crate::proof::{ BlockHashes, BlockMetadata, ExtraBlockData, MemCap, PublicValues, RegistersData, TrieRoots, }; @@ -380,20 +381,24 @@ fn initialize_kernel_code_and_shift_table(memory: &mut MemoryState) { /// Returns the memory addresses and values that should comprise the state at /// the start of the segment's execution. +/// Ignores zero values in non-preinitialized segments. fn get_all_memory_address_and_values(memory_before: &MemoryState) -> Vec<(MemoryAddress, U256)> { let mut res = vec![]; for (ctx_idx, ctx) in memory_before.contexts.iter().enumerate() { for (segment_idx, segment) in ctx.segments.iter().enumerate() { for (virt, value) in segment.content.iter().enumerate() { if let &Some(val) = value { - res.push(( - MemoryAddress { - context: ctx_idx, - segment: segment_idx, - virt, - }, - val, - )); + // We skip zero values in non-preinitialized segments. + if !val.is_zero() || PREINITIALIZED_SEGMENTS_INDICES.contains(&segment_idx) { + res.push(( + MemoryAddress { + context: ctx_idx, + segment: segment_idx, + virt, + }, + val, + )); + } } } } diff --git a/evm_arithmetization/src/memory/columns.rs b/evm_arithmetization/src/memory/columns.rs index 459554ea4..626952251 100644 --- a/evm_arithmetization/src/memory/columns.rs +++ b/evm_arithmetization/src/memory/columns.rs @@ -67,8 +67,13 @@ pub(crate) const STALE_CONTEXTS_FREQUENCIES: usize = IS_PRUNED + 1; // `ADDR_CONTEXT` + 1 is in `STALE_CONTEXTS`. pub(crate) const IS_STALE: usize = STALE_CONTEXTS_FREQUENCIES + 1; -// Filter for the `MemAfter` CTL. -pub(crate) const MEM_AFTER_FILTER: usize = IS_STALE + 1; +// Flag indicating that a value can potentially be propagated. +// Contains `filter * address_changed * is_not_stale`. +pub(crate) const MAYBE_IN_MEM_AFTER: usize = IS_STALE + 1; + +// Filter for the `MemAfter` CTL. Is equal to `MAYBE_IN_MEM_AFTER` if segment is +// preinitialized or the value is non-zero, is 0 otherwise. +pub(crate) const MEM_AFTER_FILTER: usize = MAYBE_IN_MEM_AFTER + 1; // We use a range check to enforce the ordering. pub(crate) const RANGE_CHECK: usize = MEM_AFTER_FILTER + 1; diff --git a/evm_arithmetization/src/memory/memory_stark.rs b/evm_arithmetization/src/memory/memory_stark.rs index 21f57cb2c..4645599a0 100644 --- a/evm_arithmetization/src/memory/memory_stark.rs +++ b/evm_arithmetization/src/memory/memory_stark.rs @@ -20,15 +20,16 @@ use starky::lookup::{Column, Filter, Lookup}; use starky::stark::Stark; use super::columns::{ - MEM_AFTER_FILTER, PREINITIALIZED_SEGMENTS, PREINITIALIZED_SEGMENTS_AUX, STALE_CONTEXTS, + MAYBE_IN_MEM_AFTER, MEM_AFTER_FILTER, PREINITIALIZED_SEGMENTS, STALE_CONTEXTS, STALE_CONTEXTS_FREQUENCIES, }; -use super::segments::Segment; +use super::segments::{Segment, PREINITIALIZED_SEGMENTS_INDICES}; use crate::all_stark::{EvmStarkFrame, Table}; use crate::memory::columns::{ value_limb, ADDR_CONTEXT, ADDR_SEGMENT, ADDR_VIRTUAL, CONTEXT_FIRST_CHANGE, COUNTER, FILTER, - FREQUENCIES, INITIALIZE_AUX, IS_PRUNED, IS_READ, IS_STALE, NUM_COLUMNS, RANGE_CHECK, - SEGMENT_FIRST_CHANGE, TIMESTAMP, TIMESTAMP_INV, VIRTUAL_FIRST_CHANGE, + FREQUENCIES, INITIALIZE_AUX, IS_PRUNED, IS_READ, IS_STALE, NUM_COLUMNS, + PREINITIALIZED_SEGMENTS_AUX, RANGE_CHECK, SEGMENT_FIRST_CHANGE, TIMESTAMP, TIMESTAMP_INV, + VIRTUAL_FIRST_CHANGE, }; use crate::memory::VALUE_LIMBS; use crate::witness::memory::MemoryOpKind::{self, Read}; @@ -42,7 +43,7 @@ use crate::witness::memory::{MemoryAddress, MemoryOp}; pub(crate) fn ctl_data() -> Vec> { let mut res = Column::singles([IS_READ, ADDR_CONTEXT, ADDR_SEGMENT, ADDR_VIRTUAL]).collect_vec(); - res.extend(Column::singles((0..8).map(value_limb))); + res.extend(Column::singles((0..VALUE_LIMBS).map(value_limb))); res.push(Column::single(TIMESTAMP)); res } @@ -57,7 +58,7 @@ pub(crate) fn ctl_filter() -> Filter { /// - the value in u32 limbs. pub(crate) fn ctl_looking_mem() -> Vec> { let mut res = Column::singles([ADDR_CONTEXT, ADDR_SEGMENT, ADDR_VIRTUAL]).collect_vec(); - res.extend(Column::singles((0..8).map(value_limb))); + res.extend(Column::singles((0..VALUE_LIMBS).map(value_limb))); res } @@ -108,11 +109,7 @@ impl MemoryOp { let mut row = [F::ZERO; NUM_COLUMNS]; row[FILTER] = F::from_bool(self.filter); row[TIMESTAMP] = F::from_canonical_usize(self.timestamp); - if self.timestamp != 0 { - row[TIMESTAMP_INV] = row[TIMESTAMP].inverse(); - } else { - row[TIMESTAMP_INV] = F::ZERO; - } + row[TIMESTAMP_INV] = row[TIMESTAMP].try_inverse().unwrap_or_default(); row[IS_READ] = F::from_bool(self.kind == Read); let MemoryAddress { context, @@ -231,8 +228,8 @@ impl, const D: usize> MemoryStark { /// Generates the `COUNTER`, `RANGE_CHECK` and `FREQUENCIES` columns, given /// a trace in column-major form. - /// Also generates the `STALE_CONTEXTS`, `STALE_CONTEXTS_FREQUENCIES` and - /// `MEM_AFTER_FILTER` columns. + /// Also generates the `STALE_CONTEXTS`, `STALE_CONTEXTS_FREQUENCIES`, + /// `MAYBE_IN_MEM_AFTER` and `MEM_AFTER_FILTER` columns. fn generate_trace_col_major(trace_col_vecs: &mut [Vec]) { let height = trace_col_vecs[0].len(); trace_col_vecs[COUNTER] = (0..height).map(|i| F::from_canonical_usize(i)).collect(); @@ -261,8 +258,19 @@ impl, const D: usize> MemoryStark { || trace_col_vecs[SEGMENT_FIRST_CHANGE][i].is_one() || trace_col_vecs[VIRTUAL_FIRST_CHANGE][i].is_one()) { - // `mem_after_filter = filter * address_changed * (1 - is_stale)` - trace_col_vecs[MEM_AFTER_FILTER][i] = F::ONE; + // `maybe_in_mem_after = filter * address_changed * (1 - is_stale)` + trace_col_vecs[MAYBE_IN_MEM_AFTER][i] = F::ONE; + + let addr_segment = trace_col_vecs[ADDR_SEGMENT][i]; + let is_non_zero_value = + (0..VALUE_LIMBS).any(|limb| trace_col_vecs[value_limb(limb)][i].is_nonzero()); + // We filter out zero values in non-preinitialized segments. + if is_non_zero_value + || PREINITIALIZED_SEGMENTS_INDICES + .contains(&(addr_segment.to_canonical_u64() as usize)) + { + trace_col_vecs[MEM_AFTER_FILTER][i] = F::ONE; + } } } } @@ -472,14 +480,18 @@ impl, const D: usize> Stark for MemoryStark = (0..8).map(|i| local_values[value_limb(i)]).collect(); + let value_limbs: Vec<_> = (0..VALUE_LIMBS) + .map(|i| local_values[value_limb(i)]) + .collect(); let next_timestamp = next_values[TIMESTAMP]; let next_is_read = next_values[IS_READ]; let next_addr_context = next_values[ADDR_CONTEXT]; let next_addr_segment = next_values[ADDR_SEGMENT]; let next_addr_virtual = next_values[ADDR_VIRTUAL]; - let next_values_limbs: Vec<_> = (0..8).map(|i| next_values[value_limb(i)]).collect(); + let next_values_limbs: Vec<_> = (0..VALUE_LIMBS) + .map(|i| next_values[value_limb(i)]) + .collect(); // The filter must be 0 or 1. let filter = local_values[FILTER]; @@ -561,7 +573,7 @@ impl, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark = (0..8).map(|i| local_values[value_limb(i)]).collect(); + let value_limbs: Vec<_> = (0..VALUE_LIMBS) + .map(|i| local_values[value_limb(i)]) + .collect(); let timestamp = local_values[TIMESTAMP]; let next_addr_context = next_values[ADDR_CONTEXT]; let next_addr_segment = next_values[ADDR_SEGMENT]; let next_addr_virtual = next_values[ADDR_VIRTUAL]; - let next_values_limbs: Vec<_> = (0..8).map(|i| next_values[value_limb(i)]).collect(); + let next_values_limbs: Vec<_> = (0..VALUE_LIMBS) + .map(|i| next_values[value_limb(i)]) + .collect(); let next_is_read = next_values[IS_READ]; let next_timestamp = next_values[TIMESTAMP]; @@ -758,7 +787,7 @@ impl, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark Vec> { - assert!( - segment == Segment::AccountsLinkedList - || segment == Segment::StorageLinkedList - || segment == Segment::TrieData - ); + assert!(PREINITIALIZED_SEGMENTS_INDICES.contains(&segment.unscale())); let len = self .preinitialized_segments .get(&segment) @@ -301,6 +297,7 @@ impl MemoryState { segment: Segment, values: MemorySegmentState, ) { + assert!(PREINITIALIZED_SEGMENTS_INDICES.contains(&segment.unscale())); self.preinitialized_segments.insert(segment, values); }