diff --git a/evm/src/cpu/bootstrap_kernel.rs b/evm/src/cpu/bootstrap_kernel.rs index bb0e2be9..af307a28 100644 --- a/evm/src/cpu/bootstrap_kernel.rs +++ b/evm/src/cpu/bootstrap_kernel.rs @@ -17,7 +17,6 @@ use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::keccak_util::keccakf_u32s; use crate::cpu::public_inputs::NUM_PUBLIC_INPUTS; use crate::generation::state::GenerationState; -use crate::memory; use crate::memory::segments::Segment; use crate::memory::NUM_CHANNELS; use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; @@ -50,11 +49,8 @@ pub(crate) fn generate_bootstrap_kernel(state: &mut GenerationState // Write this chunk to memory, while simultaneously packing its bytes into a u32 word. let mut packed_bytes: u32 = 0; for (addr, byte) in chunk { - let mut value = [F::ZERO; memory::VALUE_LIMBS]; - value[0] = F::from_canonical_u8(byte); - let channel = addr % NUM_CHANNELS; - state.set_mem_current(channel, Segment::Code, addr, value); + state.set_mem_current(channel, Segment::Code, addr, byte.into()); packed_bytes = (packed_bytes << 8) | byte as u32; } diff --git a/evm/src/generation/memory.rs b/evm/src/generation/memory.rs index 2ef46d15..0b80756a 100644 --- a/evm/src/generation/memory.rs +++ b/evm/src/generation/memory.rs @@ -1,19 +1,18 @@ -use plonky2::field::types::Field; +use ethereum_types::U256; use crate::memory::memory_stark::MemoryOp; use crate::memory::segments::Segment; -use crate::memory::VALUE_LIMBS; #[allow(unused)] // TODO: Should be used soon. #[derive(Debug)] -pub(crate) struct MemoryState { +pub(crate) struct MemoryState { /// A log of each memory operation, in the order that it occurred. - pub log: Vec>, + pub log: Vec, - pub contexts: Vec>, + pub contexts: Vec, } -impl Default for MemoryState { +impl Default for MemoryState { fn default() -> Self { Self { log: vec![], @@ -24,28 +23,27 @@ impl Default for MemoryState { } #[derive(Default, Debug)] -pub(crate) struct MemoryContextState { +pub(crate) struct MemoryContextState { /// The content of each memory segment. - pub segments: [MemorySegmentState; Segment::COUNT], + pub segments: [MemorySegmentState; Segment::COUNT], } #[derive(Default, Debug)] -pub(crate) struct MemorySegmentState { - pub content: Vec<[F; VALUE_LIMBS]>, +pub(crate) struct MemorySegmentState { + pub content: Vec, } -impl MemorySegmentState { - pub(super) fn get(&self, virtual_addr: usize) -> [F; VALUE_LIMBS] { +impl MemorySegmentState { + pub(super) fn get(&self, virtual_addr: usize) -> U256 { self.content .get(virtual_addr) .copied() - .unwrap_or([F::ZERO; VALUE_LIMBS]) + .unwrap_or(U256::zero()) } - pub(super) fn set(&mut self, virtual_addr: usize, value: [F; VALUE_LIMBS]) { + pub(super) fn set(&mut self, virtual_addr: usize, value: U256) { if virtual_addr + 1 > self.content.len() { - self.content - .resize(virtual_addr + 1, [F::ZERO; VALUE_LIMBS]); + self.content.resize(virtual_addr + 1, U256::zero()); } self.content[virtual_addr] = value; } diff --git a/evm/src/generation/state.rs b/evm/src/generation/state.rs index c5a6bbc4..46ccc4e3 100644 --- a/evm/src/generation/state.rs +++ b/evm/src/generation/state.rs @@ -15,7 +15,7 @@ pub(crate) struct GenerationState { pub(crate) current_cpu_row: CpuColumnsView, pub(crate) current_context: usize, - pub(crate) memory: MemoryState, + pub(crate) memory: MemoryState, pub(crate) keccak_inputs: Vec<[u64; keccak::keccak_stark::NUM_INPUTS]>, pub(crate) logic_ops: Vec, @@ -55,7 +55,7 @@ impl GenerationState { channel_index: usize, segment: Segment, virt: usize, - ) -> [F; crate::memory::VALUE_LIMBS] { + ) -> U256 { let timestamp = self.cpu_rows.len(); let context = self.current_context; let value = self.memory.contexts[context].segments[segment as usize].get(virt); @@ -77,7 +77,7 @@ impl GenerationState { channel_index: usize, segment: Segment, virt: usize, - value: [F; crate::memory::VALUE_LIMBS], + value: U256, ) { let timestamp = self.cpu_rows.len(); let context = self.current_context; diff --git a/evm/src/memory/columns.rs b/evm/src/memory/columns.rs index 5f6c3911..7229a834 100644 --- a/evm/src/memory/columns.rs +++ b/evm/src/memory/columns.rs @@ -9,7 +9,8 @@ pub(crate) const ADDR_CONTEXT: usize = IS_READ + 1; pub(crate) const ADDR_SEGMENT: usize = ADDR_CONTEXT + 1; pub(crate) const ADDR_VIRTUAL: usize = ADDR_SEGMENT + 1; -// Eight limbs to hold up to a 256-bit value. +// Eight 32-bit limbs hold a total of 256 bits. +// If a value represents an integer, it is little-endian encoded. const VALUE_START: usize = ADDR_VIRTUAL + 1; pub(crate) const fn value_limb(i: usize) -> usize { debug_assert!(i < VALUE_LIMBS); diff --git a/evm/src/memory/memory_stark.rs b/evm/src/memory/memory_stark.rs index 843dfc2f..82e10869 100644 --- a/evm/src/memory/memory_stark.rs +++ b/evm/src/memory/memory_stark.rs @@ -1,5 +1,6 @@ use std::marker::PhantomData; +use ethereum_types::U256; use itertools::Itertools; use plonky2::field::extension::{Extendable, FieldExtension}; use plonky2::field::packed::PackedField; @@ -45,7 +46,7 @@ pub struct MemoryStark { } #[derive(Clone, Debug)] -pub(crate) struct MemoryOp { +pub(crate) struct MemoryOp { /// The channel this operation came from, or `None` if it's a dummy operation for padding. pub channel_index: Option, pub timestamp: usize, @@ -53,15 +54,15 @@ pub(crate) struct MemoryOp { pub context: usize, pub segment: Segment, pub virt: usize, - pub value: [F; 8], + pub value: U256, } -impl MemoryOp { +impl MemoryOp { /// Generate a row for a given memory operation. Note that this does not generate columns which /// depend on the next operation, such as `CONTEXT_FIRST_CHANGE`; those are generated later. /// It also does not generate columns such as `COUNTER`, which are generated later, after the /// trace has been transposed into column-major form. - fn to_row(&self) -> [F; NUM_COLUMNS] { + fn to_row(&self) -> [F; NUM_COLUMNS] { let mut row = [F::ZERO; NUM_COLUMNS]; if let Some(channel) = self.channel_index { row[is_channel(channel)] = F::ONE; @@ -72,13 +73,13 @@ impl MemoryOp { row[ADDR_SEGMENT] = F::from_canonical_usize(self.segment as usize); row[ADDR_VIRTUAL] = F::from_canonical_usize(self.virt); for j in 0..VALUE_LIMBS { - row[value_limb(j)] = self.value[j]; + row[value_limb(j)] = F::from_canonical_u32((self.value >> (j * 32)).low_u32()); } row } } -fn get_max_range_check(memory_ops: &[MemoryOp]) -> usize { +fn get_max_range_check(memory_ops: &[MemoryOp]) -> usize { memory_ops .iter() .tuple_windows() @@ -142,7 +143,7 @@ pub fn generate_first_change_flags_and_rc(trace_rows: &mut [[F; NU impl, const D: usize> MemoryStark { /// Generate most of the trace rows. Excludes a few columns like `COUNTER`, which are generated /// later, after transposing to column-major form. - fn generate_trace_row_major(&self, mut memory_ops: Vec>) -> Vec<[F; NUM_COLUMNS]> { + fn generate_trace_row_major(&self, mut memory_ops: Vec) -> Vec<[F; NUM_COLUMNS]> { memory_ops.sort_by_key(|op| (op.context, op.segment, op.virt, op.timestamp)); Self::pad_memory_ops(&mut memory_ops); @@ -167,7 +168,7 @@ impl, const D: usize> MemoryStark { trace_col_vecs[COUNTER_PERMUTED] = permuted_table; } - fn pad_memory_ops(memory_ops: &mut Vec>) { + fn pad_memory_ops(memory_ops: &mut Vec) { let num_ops = memory_ops.len(); let max_range_check = get_max_range_check(memory_ops); let num_ops_padded = num_ops.max(max_range_check + 1).next_power_of_two(); @@ -190,7 +191,7 @@ impl, const D: usize> MemoryStark { } } - pub(crate) fn generate_trace(&self, memory_ops: Vec>) -> Vec> { + pub(crate) fn generate_trace(&self, memory_ops: Vec) -> Vec> { let mut timing = TimingTree::new("generate trace", log::Level::Debug); // Generate most of the trace in row-major form. @@ -463,7 +464,7 @@ pub(crate) mod tests { use std::collections::{HashMap, HashSet}; use anyhow::Result; - use plonky2::hash::hash_types::RichField; + use ethereum_types::U256; use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; use rand::prelude::SliceRandom; use rand::Rng; @@ -473,13 +474,10 @@ pub(crate) mod tests { use crate::memory::NUM_CHANNELS; use crate::stark_testing::{test_stark_circuit_constraints, test_stark_low_degree}; - pub(crate) fn generate_random_memory_ops( - num_ops: usize, - rng: &mut R, - ) -> Vec> { + pub(crate) fn generate_random_memory_ops(num_ops: usize, rng: &mut R) -> Vec { let mut memory_ops = Vec::new(); - let mut current_memory_values: HashMap<(usize, Segment, usize), [F; 8]> = HashMap::new(); + let mut current_memory_values: HashMap<(usize, Segment, usize), U256> = HashMap::new(); let num_cycles = num_ops / 2; for clock in 0..num_cycles { let mut used_indices = HashSet::new(); @@ -520,12 +518,11 @@ pub(crate) mod tests { virt = rng.gen_range(0..20); } - let val: [u32; 8] = rng.gen(); - let vals: [F; 8] = val.map(F::from_canonical_u32); + let val = U256(rng.gen()); - new_writes_this_cycle.insert((context, segment, virt), vals); + new_writes_this_cycle.insert((context, segment, virt), val); - (context, segment, virt, vals) + (context, segment, virt, val) }; let timestamp = clock * NUM_CHANNELS + channel_index;