From 906a47a1ef9ba50759a2ab002e35dfd9c6c9a49a Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Wed, 30 Nov 2022 17:45:31 -0800 Subject: [PATCH] generate_push and misc other progress --- evm/src/arithmetic/mod.rs | 2 +- evm/src/cpu/bootstrap_kernel.rs | 10 ++-- evm/src/cpu/mod.rs | 2 +- evm/src/cpu/stack_bounds.rs | 8 ++-- evm/src/generation/mod.rs | 6 +-- evm/src/witness/memory.rs | 8 ++-- evm/src/witness/operation.rs | 83 +++++++++++++++++++++++++++------ evm/src/witness/state.rs | 10 ++++ evm/src/witness/traces.rs | 2 - evm/src/witness/transition.rs | 27 +++++++---- evm/src/witness/util.rs | 7 +-- 11 files changed, 117 insertions(+), 48 deletions(-) diff --git a/evm/src/arithmetic/mod.rs b/evm/src/arithmetic/mod.rs index ad00aa28..e74cac34 100644 --- a/evm/src/arithmetic/mod.rs +++ b/evm/src/arithmetic/mod.rs @@ -12,6 +12,7 @@ pub(crate) mod columns; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum BinaryOperator { + Add, Mul, Sub, Div, @@ -25,7 +26,6 @@ pub(crate) enum BinaryOperator { #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) enum TernaryOperator { AddMod, - SubMod, MulMod, } diff --git a/evm/src/cpu/bootstrap_kernel.rs b/evm/src/cpu/bootstrap_kernel.rs index 5372d075..b2c83ab1 100644 --- a/evm/src/cpu/bootstrap_kernel.rs +++ b/evm/src/cpu/bootstrap_kernel.rs @@ -17,7 +17,7 @@ use crate::cpu::kernel::keccak_util::keccakf_u32s; use crate::keccak_sponge::columns::KECCAK_RATE_U32S; use crate::memory::segments::Segment; use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars}; -use crate::witness::memory::{MemoryAddress, MemoryState}; +use crate::witness::memory::MemoryAddress; use crate::witness::traces::Traces; use crate::witness::util::mem_write_gp_log_and_fill; @@ -26,10 +26,7 @@ use crate::witness::util::mem_write_gp_log_and_fill; /// want them to fit in a single limb of Keccak input. const BYTES_PER_ROW: usize = 4; -pub(crate) fn generate_bootstrap_kernel( - memory: &mut MemoryState, - traces: &mut Traces, -) { +pub(crate) fn generate_bootstrap_kernel(traces: &mut Traces) { let mut sponge_state = [0u32; 50]; let mut sponge_input_pos: usize = 0; @@ -46,7 +43,7 @@ pub(crate) fn generate_bootstrap_kernel( // Write this chunk to memory, while simultaneously packing its bytes into a u32 word. let mut packed_bytes: u32 = 0; for (channel, (addr, &byte)) in chunk.enumerate() { - let address = MemoryAddress::new(0, Segment::Code as usize, addr); + let address = MemoryAddress::new(0, Segment::Code, addr); let write = mem_write_gp_log_and_fill( channel, address, @@ -54,7 +51,6 @@ pub(crate) fn generate_bootstrap_kernel( &mut current_cpu_row, byte.into(), ); - memory.set(address, byte.into()); traces.push_memory(write); packed_bytes = (packed_bytes << 8) | byte as u32; diff --git a/evm/src/cpu/mod.rs b/evm/src/cpu/mod.rs index bc338e2a..3a2df351 100644 --- a/evm/src/cpu/mod.rs +++ b/evm/src/cpu/mod.rs @@ -11,5 +11,5 @@ mod modfp254; mod shift; pub(crate) mod simple_logic; mod stack; -mod stack_bounds; +pub(crate) mod stack_bounds; mod syscalls; diff --git a/evm/src/cpu/stack_bounds.rs b/evm/src/cpu/stack_bounds.rs index b19997f2..627411ea 100644 --- a/evm/src/cpu/stack_bounds.rs +++ b/evm/src/cpu/stack_bounds.rs @@ -19,7 +19,7 @@ use plonky2::iop::ext_target::ExtensionTarget; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cpu::columns::{CpuColumnsView, COL_MAP}; -pub const MAX_USER_STACK_SIZE: u64 = 1024; +pub const MAX_USER_STACK_SIZE: usize = 1024; // Below only includes the operations that pop the top of the stack **without reading the value from // memory**, i.e. `POP`. @@ -45,7 +45,7 @@ pub fn generate(lv: &mut CpuColumnsView) { let check_overflow: F = INCREMENTING_FLAGS.map(|i| lv[i]).into_iter().sum(); let no_check = F::ONE - (check_underflow + check_overflow); - let disallowed_len = check_overflow * F::from_canonical_u64(MAX_USER_STACK_SIZE) - no_check; + let disallowed_len = check_overflow * F::from_canonical_usize(MAX_USER_STACK_SIZE) - no_check; let diff = lv.stack_len - disallowed_len; let user_mode = F::ONE - lv.is_kernel_mode; @@ -84,7 +84,7 @@ pub fn eval_packed( // 0 if `check_underflow`, `MAX_USER_STACK_SIZE` if `check_overflow`, and -1 if `no_check`. let disallowed_len = - check_overflow * P::Scalar::from_canonical_u64(MAX_USER_STACK_SIZE) - no_check; + check_overflow * P::Scalar::from_canonical_usize(MAX_USER_STACK_SIZE) - no_check; // This `lhs` must equal some `rhs`. If `rhs` is nonzero, then this shows that `lv.stack_len` is // not `disallowed_len`. let lhs = (lv.stack_len - disallowed_len) * lv.stack_len_bounds_aux; @@ -108,7 +108,7 @@ pub fn eval_ext_circuit, const D: usize>( ) { let one = builder.one_extension(); let max_stack_size = - builder.constant_extension(F::from_canonical_u64(MAX_USER_STACK_SIZE).into()); + builder.constant_extension(F::from_canonical_usize(MAX_USER_STACK_SIZE).into()); // `check_underflow`, `check_overflow`, and `no_check` are mutually exclusive. let check_underflow = builder.add_many_extension(DECREMENTING_FLAGS.map(|i| lv[i])); diff --git a/evm/src/generation/mod.rs b/evm/src/generation/mod.rs index c14436e3..855169e5 100644 --- a/evm/src/generation/mod.rs +++ b/evm/src/generation/mod.rs @@ -67,9 +67,9 @@ pub(crate) fn generate_traces, const D: usize>( ) -> ([Vec>; NUM_TABLES], PublicValues) { // let mut state = GenerationState::::new(inputs.clone()); - let mut memory_state = MemoryState::default(); + let mut memory_state = MemoryState::new(&KERNEL.code); let mut traces = Traces::::default(); - generate_bootstrap_kernel::(&mut memory_state, &mut traces); + generate_bootstrap_kernel::(&mut traces); let mut registers_state = RegistersState::default(); let halt_pc0 = KERNEL.global_labels["halt_pc0"]; @@ -89,7 +89,7 @@ pub(crate) fn generate_traces, const D: usize>( let read_metadata = |field| { memory_state.get(MemoryAddress::new( 0, - Segment::GlobalMetadata as usize, + Segment::GlobalMetadata, field as usize, )) }; diff --git a/evm/src/witness/memory.rs b/evm/src/witness/memory.rs index 2baea733..8294fd96 100644 --- a/evm/src/witness/memory.rs +++ b/evm/src/witness/memory.rs @@ -12,6 +12,8 @@ pub enum MemoryChannel { use MemoryChannel::{Code, GeneralPurpose}; +use crate::memory::segments::Segment; + impl MemoryChannel { pub fn index(&self) -> usize { match *self { @@ -32,10 +34,10 @@ pub struct MemoryAddress { } impl MemoryAddress { - pub(crate) fn new(context: usize, segment: usize, virt: usize) -> Self { + pub(crate) fn new(context: usize, segment: Segment, virt: usize) -> Self { Self { context, - segment, + segment: segment as usize, virt, } } @@ -87,7 +89,7 @@ impl MemoryState { for (i, &byte) in kernel_code.iter().enumerate() { if byte != 0 { - let address = MemoryAddress::new(0, 0, i); + let address = MemoryAddress::new(0, Segment::Code, i); let val = byte.into(); contents.insert(address, val); } diff --git a/evm/src/witness/operation.rs b/evm/src/witness/operation.rs index 8863eb79..71152b09 100644 --- a/evm/src/witness/operation.rs +++ b/evm/src/witness/operation.rs @@ -1,4 +1,5 @@ use ethereum_types::U256; +use itertools::Itertools; use plonky2::field::types::Field; use crate::cpu::columns::CpuColumnsView; @@ -11,8 +12,8 @@ use crate::witness::memory::{MemoryAddress, MemoryState}; use crate::witness::state::RegistersState; use crate::witness::traces::Traces; use crate::witness::util::{ - mem_read_gp_with_log_and_fill, mem_write_gp_log_and_fill, stack_pop_with_log_and_fill, - stack_push_log_and_fill, + mem_read_code_with_log_and_fill, mem_read_gp_with_log_and_fill, mem_write_gp_log_and_fill, + stack_pop_with_log_and_fill, stack_push_log_and_fill, }; use crate::{arithmetic, logic}; @@ -52,6 +53,66 @@ pub(crate) fn generate_binary_logic_op( Ok(registers_state) } +pub(crate) fn generate_push( + n: u8, + mut registers_state: RegistersState, + memory_state: &MemoryState, + traces: &mut Traces, + mut row: CpuColumnsView, +) -> Result { + let context = registers_state.effective_context(); + let num_bytes = n as usize + 1; + let initial_offset = registers_state.program_counter + 1; + let offsets = initial_offset..initial_offset + num_bytes; + let mut addrs = offsets.map(|offset| MemoryAddress::new(context, Segment::Code, offset)); + + // First read val without going through `mem_read_with_log` type methods, so we can pass it + // to stack_push_log_and_fill. + let bytes = (0..num_bytes) + .map(|i| { + memory_state + .get(MemoryAddress::new( + context, + Segment::Code, + initial_offset + i, + )) + .as_u32() as u8 + }) + .collect_vec(); + + let val = U256::from_big_endian(&bytes); + let write = stack_push_log_and_fill(&mut registers_state, traces, &mut row, val)?; + + // In the first cycle, we read up to NUM_GP_CHANNELS - 1 bytes, leaving the last GP channel + // to push the result. + for (i, addr) in (&mut addrs).take(NUM_GP_CHANNELS - 1).enumerate() { + let (_, read) = mem_read_gp_with_log_and_fill(i, addr, memory_state, traces, &mut row); + traces.push_memory(read); + } + traces.push_memory(write); + traces.push_cpu(row); + + // In any subsequent cycles, we read up to 1 + NUM_GP_CHANNELS bytes. + for mut addrs_chunk in &addrs.chunks(1 + NUM_GP_CHANNELS) { + let mut row = CpuColumnsView::default(); + // TODO: Set other row fields, like push=1? + + let first_addr = addrs_chunk.next().unwrap(); + let (_, first_read) = + mem_read_code_with_log_and_fill(first_addr, memory_state, traces, &mut row); + traces.push_memory(first_read); + + for (i, addr) in addrs_chunk.enumerate() { + let (_, read) = mem_read_gp_with_log_and_fill(i, addr, memory_state, traces, &mut row); + traces.push_memory(read); + } + + traces.push_cpu(row); + } + + Ok(registers_state) +} + pub(crate) fn generate_dup( n: u8, mut registers_state: RegistersState, @@ -63,11 +124,7 @@ pub(crate) fn generate_dup( .stack_len .checked_sub(1 + (n as usize)) .ok_or(ProgramError::StackUnderflow)?; - let other_addr = MemoryAddress::new( - registers_state.context, - Segment::Stack as usize, - other_addr_lo, - ); + let other_addr = MemoryAddress::new(registers_state.context, Segment::Stack, other_addr_lo); let (val, log_in) = mem_read_gp_with_log_and_fill(0, other_addr, memory_state, traces, &mut row); @@ -90,11 +147,7 @@ pub(crate) fn generate_swap( .stack_len .checked_sub(2 + (n as usize)) .ok_or(ProgramError::StackUnderflow)?; - let other_addr = MemoryAddress::new( - registers_state.context, - Segment::Stack as usize, - other_addr_lo, - ); + let other_addr = MemoryAddress::new(registers_state.context, Segment::Stack, other_addr_lo); let [(in0, log_in0)] = stack_pop_with_log_and_fill::<1, _>(&mut registers_state, memory_state, traces, &mut row)?; @@ -163,21 +216,21 @@ pub(crate) fn generate_syscall( let handler_addr_addr = handler_jumptable_addr + (opcode as usize); let (handler_addr0, log_in0) = mem_read_gp_with_log_and_fill( 0, - MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr), + MemoryAddress::new(0, Segment::Code, handler_addr_addr), memory_state, traces, &mut row, ); let (handler_addr1, log_in1) = mem_read_gp_with_log_and_fill( 1, - MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr + 1), + MemoryAddress::new(0, Segment::Code, handler_addr_addr + 1), memory_state, traces, &mut row, ); let (handler_addr2, log_in2) = mem_read_gp_with_log_and_fill( 2, - MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr + 2), + MemoryAddress::new(0, Segment::Code, handler_addr_addr + 2), memory_state, traces, &mut row, diff --git a/evm/src/witness/state.rs b/evm/src/witness/state.rs index 6f6843ce..bcadf63e 100644 --- a/evm/src/witness/state.rs +++ b/evm/src/witness/state.rs @@ -8,6 +8,16 @@ pub struct RegistersState { pub context: usize, } +impl RegistersState { + pub(crate) fn effective_context(&self) -> usize { + if self.is_kernel { + 0 + } else { + self.context + } + } +} + impl Default for RegistersState { fn default() -> Self { Self { diff --git a/evm/src/witness/traces.rs b/evm/src/witness/traces.rs index a220a2ea..f0c96e6b 100644 --- a/evm/src/witness/traces.rs +++ b/evm/src/witness/traces.rs @@ -13,8 +13,6 @@ use crate::util::trace_rows_to_poly_values; use crate::witness::memory::MemoryOp; use crate::{arithmetic, keccak, logic}; -type ArithmeticRow = [T; NUM_ARITH_COLUMNS]; - #[derive(Clone, Copy, Debug)] pub struct TraceCheckpoint { pub(self) cpu_len: usize, diff --git a/evm/src/witness/transition.rs b/evm/src/witness/transition.rs index de6a8863..ac6ce23d 100644 --- a/evm/src/witness/transition.rs +++ b/evm/src/witness/transition.rs @@ -1,17 +1,17 @@ use plonky2::field::types::Field; -use crate::cpu::columns::{CpuColumnsView, NUM_CPU_COLUMNS}; -use crate::logic; +use crate::cpu::columns::CpuColumnsView; use crate::memory::segments::Segment; use crate::witness::errors::ProgramError; use crate::witness::memory::{MemoryAddress, MemoryState}; use crate::witness::operation::{ generate_binary_logic_op, generate_dup, generate_eq, generate_exit_kernel, generate_iszero, - generate_not, generate_swap, generate_syscall, Operation, + generate_not, generate_push, generate_swap, generate_syscall, Operation, }; use crate::witness::state::RegistersState; use crate::witness::traces::Traces; use crate::witness::util::mem_read_code_with_log_and_fill; +use crate::{arithmetic, logic}; const KERNEL_CONTEXT: usize = 0; @@ -28,11 +28,7 @@ fn read_code_memory( }; row.code_context = F::from_canonical_usize(code_context); - let address = MemoryAddress::new( - code_context, - Segment::Code as usize, - registers_state.program_counter, - ); + let address = MemoryAddress::new(code_context, Segment::Code, registers_state.program_counter); let (opcode, mem_log) = mem_read_code_with_log_and_fill(address, memory_state, traces, row); traces.push_memory(mem_log); @@ -156,6 +152,17 @@ fn fill_op_flag(op: Operation, row: &mut CpuColumnsView) { Operation::BinaryLogic(logic::Op::And) => &mut flags.and, Operation::BinaryLogic(logic::Op::Or) => &mut flags.or, Operation::BinaryLogic(logic::Op::Xor) => &mut flags.xor, + Operation::BinaryArithmetic(arithmetic::BinaryOperator::Add) => &mut flags.add, + Operation::BinaryArithmetic(arithmetic::BinaryOperator::Mul) => &mut flags.mul, + Operation::BinaryArithmetic(arithmetic::BinaryOperator::Sub) => &mut flags.sub, + Operation::BinaryArithmetic(arithmetic::BinaryOperator::Div) => &mut flags.div, + Operation::BinaryArithmetic(arithmetic::BinaryOperator::Mod) => &mut flags.mod_, + Operation::BinaryArithmetic(arithmetic::BinaryOperator::Lt) => &mut flags.lt, + Operation::BinaryArithmetic(arithmetic::BinaryOperator::Gt) => &mut flags.gt, + Operation::BinaryArithmetic(arithmetic::BinaryOperator::Shl) => &mut flags.shl, + Operation::BinaryArithmetic(arithmetic::BinaryOperator::Shr) => &mut flags.shr, + Operation::TernaryArithmetic(arithmetic::TernaryOperator::AddMod) => &mut flags.addmod, + Operation::TernaryArithmetic(arithmetic::TernaryOperator::MulMod) => &mut flags.mulmod, _ => panic!("operation not implemented: {:?}", op), } = F::ONE; } @@ -168,6 +175,7 @@ fn perform_op( row: CpuColumnsView, ) -> Result { let mut new_registers_state = match op { + Operation::Push(n) => generate_push(n, registers_state, memory_state, traces, row)?, Operation::Dup(n) => generate_dup(n, registers_state, memory_state, traces, row)?, Operation::Swap(n) => generate_swap(n, registers_state, memory_state, traces, row)?, Operation::Iszero => generate_iszero(registers_state, memory_state, traces, row)?, @@ -185,6 +193,7 @@ fn perform_op( new_registers_state.program_counter += match op { Operation::Syscall(_) | Operation::ExitKernel => 0, + Operation::Push(n) => n as usize + 2, _ => 1, }; @@ -196,7 +205,7 @@ fn try_perform_instruction( memory_state: &MemoryState, traces: &mut Traces, ) -> Result { - let mut row: CpuColumnsView = [F::ZERO; NUM_CPU_COLUMNS].into(); + let mut row: CpuColumnsView = CpuColumnsView::default(); row.is_cpu_cycle = F::ONE; let opcode = read_code_memory(registers_state, memory_state, traces, &mut row); diff --git a/evm/src/witness/util.rs b/evm/src/witness/util.rs index c7f8777e..d6c06473 100644 --- a/evm/src/witness/util.rs +++ b/evm/src/witness/util.rs @@ -3,6 +3,7 @@ use plonky2::field::types::Field; use crate::cpu::columns::CpuColumnsView; use crate::cpu::membus::NUM_GP_CHANNELS; +use crate::cpu::stack_bounds::MAX_USER_STACK_SIZE; use crate::memory::segments::Segment; use crate::witness::errors::ProgramError; use crate::witness::memory::{MemoryAddress, MemoryChannel, MemoryOp, MemoryOpKind, MemoryState}; @@ -125,7 +126,7 @@ pub(crate) fn stack_pop_with_log_and_fill( [(); N].map(|_| { let address = MemoryAddress::new( registers_state.context, - Segment::Stack as usize, + Segment::Stack, registers_state.stack_len - 1 - i, ); let res = mem_read_gp_with_log_and_fill(i, address, memory_state, traces, row); @@ -145,13 +146,13 @@ pub(crate) fn stack_push_log_and_fill( row: &mut CpuColumnsView, val: U256, ) -> Result { - if !registers_state.is_kernel && registers_state.stack_len >= 1024 { + if !registers_state.is_kernel && registers_state.stack_len >= MAX_USER_STACK_SIZE { return Err(ProgramError::StackOverflow); } let address = MemoryAddress::new( registers_state.context, - Segment::Stack as usize, + Segment::Stack, registers_state.stack_len, ); let res = mem_write_gp_log_and_fill(NUM_GP_CHANNELS - 1, address, traces, row, val);