From 7ba0652c01dd54c25a7b909c21bf8c83c19582f2 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 23 Jun 2022 14:00:44 -0700 Subject: [PATCH] all_stark --- evm/src/cpu/columns.rs | 47 +++++++++--- evm/src/lib.rs | 1 + evm/src/memory/memory_stark.rs | 130 ++++++++++++--------------------- evm/src/memory/registers.rs | 14 ++-- 4 files changed, 93 insertions(+), 99 deletions(-) diff --git a/evm/src/cpu/columns.rs b/evm/src/cpu/columns.rs index 44264c52..16c13de6 100644 --- a/evm/src/cpu/columns.rs +++ b/evm/src/cpu/columns.rs @@ -13,12 +13,6 @@ pub const IS_CPU_CYCLE: usize = IS_BOOTSTRAP_CONTRACT + 1; /// If CPU cycle: The opcode being decoded, in {0, ..., 255}. pub const OPCODE: usize = IS_CPU_CYCLE + 1; -<<<<<<< HEAD -/// If CPU cycle: flags for EVM instructions. PUSHn, DUPn, and SWAPn only get one flag each. Invalid -/// opcodes are split between a number of flags for practical reasons. Exactly one of these flags -/// must be 1. -pub const IS_STOP: usize = OPCODE + 1; -======= pub const KECCAK_DUMMY: usize = OPCODE + 1; pub const MEMORY_DUMMY: usize = KECCAK_DUMMY + 1; @@ -26,7 +20,6 @@ pub const MEMORY_DUMMY: usize = KECCAK_DUMMY + 1; // opcodes are split between a number of flags for practical reasons. Exactly one of these flags // must be 1. pub const IS_STOP: usize = MEMORY_DUMMY + 1; ->>>>>>> ade7e5e0 (updated all_stark framework to include memory stark (doesn't pass yet)) pub const IS_ADD: usize = IS_STOP + 1; pub const IS_MUL: usize = IS_ADD + 1; pub const IS_SUB: usize = IS_MUL + 1; @@ -154,7 +147,7 @@ pub const OPCODE_BITS: [usize; 8] = [ pub const IS_KECCAK: usize = OPCODE_BITS[OPCODE_BITS.len() - 1] + 1; pub const START_KECCAK_INPUT: usize = IS_KECCAK + 1; -#[allow(dead_code)] // TODO: Remove when used +// TODO: Remove when used pub const KECCAK_INPUT_LIMBS: Range = START_KECCAK_INPUT..START_KECCAK_INPUT + 50; pub const START_KECCAK_OUTPUT: usize = KECCAK_INPUT_LIMBS.end; @@ -169,4 +162,40 @@ pub const LOGIC_OUTPUT: Range = LOGIC_INPUT1.end..LOGIC_INPUT1.end + 16; pub const SIMPLE_LOGIC_DIFF: usize = LOGIC_OUTPUT.end; pub const SIMPLE_LOGIC_DIFF_INV: usize = SIMPLE_LOGIC_DIFF + 1; -pub const NUM_CPU_COLUMNS: usize = SIMPLE_LOGIC_DIFF_INV + 1; +const NUM_MEMORY_OPS: usize = 4; +const NUM_MEMORY_VALUE_LIMBS: usize = 8; + +pub(crate) const MEMORY_TIMESTAMP: usize = SIMPLE_LOGIC_DIFF_INV + 1; + +const USES_MEMOP_START: usize = MEMORY_TIMESTAMP + 1; +pub const fn uses_memop(op: usize) -> usize { + debug_assert!(op < NUM_MEMORY_OPS); + USES_MEMOP_START + op +} + +const MEMOP_ISREAD_START: usize = USES_MEMOP_START + NUM_MEMORY_OPS; +pub const fn memop_is_read(op: usize) -> usize { + MEMOP_ISREAD_START + op +} + +const MEMOP_ADDR_CONTEXT_START: usize = MEMOP_ISREAD_START + NUM_MEMORY_OPS; +pub const fn memop_addr_context(op: usize) -> usize { + MEMOP_ADDR_CONTEXT_START + op +} + +const MEMOP_ADDR_SEGMENT_START: usize = MEMOP_ADDR_CONTEXT_START + NUM_MEMORY_OPS; +pub const fn memop_addr_segment(op: usize) -> usize { + MEMOP_ADDR_SEGMENT_START + op +} + +const MEMOP_ADDR_VIRTUAL_START: usize = MEMOP_ADDR_SEGMENT_START + NUM_MEMORY_OPS; +pub const fn memop_addr_virtual(op: usize) -> usize { + MEMOP_ADDR_VIRTUAL_START + op +} + +const MEMOP_ADDR_VALUE_START: usize = MEMOP_ADDR_VIRTUAL_START + NUM_MEMORY_OPS; +pub const fn memop_value(op: usize, limb: usize) -> usize { + MEMOP_ADDR_VALUE_START + op * NUM_MEMORY_VALUE_LIMBS + limb +} + +pub const NUM_CPU_COLUMNS: usize = MEMOP_ADDR_VALUE_START + NUM_MEMORY_OPS * NUM_MEMORY_VALUE_LIMBS; diff --git a/evm/src/lib.rs b/evm/src/lib.rs index 422fae29..f60ea23c 100644 --- a/evm/src/lib.rs +++ b/evm/src/lib.rs @@ -3,6 +3,7 @@ #![allow(clippy::too_many_arguments)] #![allow(clippy::type_complexity)] #![feature(generic_const_exprs)] +#![allow(dead_code)] pub mod all_stark; pub mod config; diff --git a/evm/src/memory/memory_stark.rs b/evm/src/memory/memory_stark.rs index a6590db1..a675bcfd 100644 --- a/evm/src/memory/memory_stark.rs +++ b/evm/src/memory/memory_stark.rs @@ -47,7 +47,7 @@ pub struct MemoryStark { pub(crate) f: PhantomData, } -pub fn generate_random_memory_ops(num_ops: usize) -> Vec<(F, F, F, [F; 8], F, F)> { +pub fn generate_random_memory_ops(num_ops: usize) -> Vec<(F, F, F, F, F, [F; 8])> { let mut memory_ops = Vec::new(); let mut rng = thread_rng(); @@ -82,31 +82,31 @@ pub fn generate_random_memory_ops(num_ops: usize) -> Vec<(F, F, F, let timestamp = F::from_canonical_usize(cur_timestamp); cur_timestamp += 1; - memory_ops.push((context, segment, virt, vals, is_read_F, timestamp)) + memory_ops.push((timestamp, is_read_F, context, segment, virt, vals)) } memory_ops } pub fn sort_memory_ops( + timestamp: &[F], + is_read: &[F], context: &[F], segment: &[F], virtuals: &[F], values: &Vec<[F; 8]>, - is_read: &[F], - timestamp: &[F], -) -> (Vec, Vec, Vec, Vec<[F; 8]>, Vec, Vec) { - let mut ops: Vec<(F, F, F, [F; 8], F, F)> = izip!( +) -> (Vec, Vec, Vec, Vec, Vec, Vec<[F; 8]>) { + let mut ops: Vec<(F, F, F, F, F, [F; 8])> = izip!( + timestamp.iter().cloned(), + is_read.iter().cloned(), context.iter().cloned(), segment.iter().cloned(), virtuals.iter().cloned(), values.iter().cloned(), - is_read.iter().cloned(), - timestamp.iter().cloned() ) .collect(); - ops.sort_by_key(|&(c, s, v, _, _, t)| { + ops.sort_by_key(|&(t, _, c, s, v, _)| { ( c.to_noncanonical_u64(), s.to_noncanonical_u64(), @@ -173,7 +173,7 @@ pub fn generate_range_check_value( let mut range_check = Vec::new(); for idx in 0..num_ops - 1 { - let this_timestamp_first_change = F::ONE + let this_address_unchanged = F::ONE - context_first_change[idx] - segment_first_change[idx] - virtual_first_change[idx]; @@ -182,7 +182,7 @@ pub fn generate_range_check_value( context_first_change[idx] * (context[idx + 1] - context[idx] - F::ONE) + segment_first_change[idx] * (segment[idx + 1] - segment[idx] - F::ONE) + virtual_first_change[idx] * (virtuals[idx + 1] - virtuals[idx] - F::ONE) - + this_timestamp_first_change * (timestamp[idx + 1] - timestamp[idx] - F::ONE), + + this_address_unchanged * (timestamp[idx + 1] - timestamp[idx] - F::ONE), ); } @@ -194,7 +194,7 @@ pub fn generate_range_check_value( impl, const D: usize> MemoryStark { pub(crate) fn generate_trace_rows( &self, - memory_ops: Vec<(F, F, F, [F; 8], F, F)>, + memory_ops: Vec<(F, F, F, F, F, [F; 8])>, ) -> Vec<[F; NUM_REGISTERS]> { let num_ops = memory_ops.len(); @@ -202,15 +202,15 @@ impl, const D: usize> MemoryStark { .try_into() .unwrap(); for i in 0..num_ops { - let (context, segment, virt, values, is_read, timestamp) = memory_ops[i]; + let (timestamp, is_read, context, segment, virt, values) = memory_ops[i]; + trace_cols[MEMORY_TIMESTAMP][i] = timestamp; + trace_cols[MEMORY_IS_READ][i] = is_read; trace_cols[MEMORY_ADDR_CONTEXT][i] = context; trace_cols[MEMORY_ADDR_SEGMENT][i] = segment; trace_cols[MEMORY_ADDR_VIRTUAL][i] = virt; for j in 0..8 { trace_cols[memory_value_limb(j)][i] = values[j]; } - trace_cols[MEMORY_IS_READ][i] = is_read; - trace_cols[MEMORY_TIMESTAMP][i] = timestamp; } self.generate_memory(&mut trace_cols); @@ -227,6 +227,8 @@ impl, const D: usize> MemoryStark { fn generate_memory(&self, trace_cols: &mut [Vec]) { let num_trace_rows = trace_cols[0].len(); + let timestamp = &trace_cols[MEMORY_TIMESTAMP]; + let is_read = &trace_cols[MEMORY_IS_READ]; let context = &trace_cols[MEMORY_ADDR_CONTEXT]; let segment = &trace_cols[MEMORY_ADDR_SEGMENT]; let virtuals = &trace_cols[MEMORY_ADDR_VIRTUAL]; @@ -241,17 +243,15 @@ impl, const D: usize> MemoryStark { arr }) .collect(); - let is_read = &trace_cols[MEMORY_IS_READ]; - let timestamp = &trace_cols[MEMORY_TIMESTAMP]; let ( + sorted_timestamp, + sorted_is_read, sorted_context, sorted_segment, sorted_virtual, sorted_values, - sorted_is_read, - sorted_timestamp, - ) = sort_memory_ops(context, segment, virtuals, &values, is_read, timestamp); + ) = sort_memory_ops(timestamp, is_read, context, segment, virtuals, &values); let (context_first_change, segment_first_change, virtual_first_change) = generate_first_change_flags(&sorted_context, &sorted_segment, &sorted_virtual); @@ -266,6 +266,8 @@ impl, const D: usize> MemoryStark { &virtual_first_change, ); + trace_cols[SORTED_MEMORY_TIMESTAMP] = sorted_timestamp; + trace_cols[SORTED_MEMORY_IS_READ] = sorted_is_read; trace_cols[SORTED_MEMORY_ADDR_CONTEXT] = sorted_context; trace_cols[SORTED_MEMORY_ADDR_SEGMENT] = sorted_segment; trace_cols[SORTED_MEMORY_ADDR_VIRTUAL] = sorted_virtual; @@ -274,8 +276,6 @@ impl, const D: usize> MemoryStark { trace_cols[sorted_memory_value_limb(j)][i] = sorted_values[i][j]; } } - trace_cols[SORTED_MEMORY_IS_READ] = sorted_is_read; - trace_cols[SORTED_MEMORY_TIMESTAMP] = sorted_timestamp; trace_cols[MEMORY_CONTEXT_FIRST_CHANGE] = context_first_change; trace_cols[MEMORY_SEGMENT_FIRST_CHANGE] = segment_first_change; @@ -294,7 +294,7 @@ impl, const D: usize> MemoryStark { pub fn generate_trace( &self, - memory_ops: Vec<(F, F, F, [F; 8], F, F)>, + memory_ops: Vec<(F, F, F, F, F, [F; 8])>, ) -> Vec> { let mut timing = TimingTree::new("generate trace", log::Level::Debug); @@ -330,27 +330,27 @@ impl, const D: usize> Stark for MemoryStark = (0..8) .map(|i| vars.local_values[sorted_memory_value_limb(i)]) .collect(); - let timestamp = vars.local_values[SORTED_MEMORY_TIMESTAMP]; + let next_timestamp = vars.next_values[SORTED_MEMORY_TIMESTAMP]; + let next_is_read = vars.next_values[SORTED_MEMORY_IS_READ]; let next_addr_context = vars.next_values[SORTED_MEMORY_ADDR_CONTEXT]; let next_addr_segment = vars.next_values[SORTED_MEMORY_ADDR_SEGMENT]; let next_addr_virtual = vars.next_values[SORTED_MEMORY_ADDR_VIRTUAL]; let next_values: Vec<_> = (0..8) .map(|i| vars.next_values[sorted_memory_value_limb(i)]) .collect(); - let next_is_read = vars.next_values[SORTED_MEMORY_IS_READ]; - let next_timestamp = vars.next_values[SORTED_MEMORY_TIMESTAMP]; let context_first_change = vars.local_values[MEMORY_CONTEXT_FIRST_CHANGE]; let segment_first_change = vars.local_values[MEMORY_SEGMENT_FIRST_CHANGE]; let virtual_first_change = vars.local_values[MEMORY_VIRTUAL_FIRST_CHANGE]; - let timestamp_first_change = + let address_unchanged = one - context_first_change - segment_first_change - virtual_first_change; let range_check = vars.local_values[MEMORY_RANGE_CHECK]; @@ -358,13 +358,13 @@ impl, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark, const D: usize> Stark for MemoryStark(stark) } - - #[test] - fn test_memory_stark() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - type S = MemoryStark; - - let stark = S { - f: Default::default(), - }; - - const MAX_CONTEXT: usize = 256; - const MAX_SEGMENT: usize = 8; - const MAX_VIRTUAL: usize = 1 << 12; - - let num_ops = 20; - let memory_ops = generate_random_memory_ops(num_ops); - - let rows = stark.generate_trace_rows(memory_ops); - - Ok(()) - } } diff --git a/evm/src/memory/registers.rs b/evm/src/memory/registers.rs index 885fda19..25b3cb5a 100644 --- a/evm/src/memory/registers.rs +++ b/evm/src/memory/registers.rs @@ -1,6 +1,8 @@ //! Memory unit. -pub(crate) const MEMORY_ADDR_CONTEXT: usize = 0; +pub(crate) const MEMORY_TIMESTAMP: usize = 0; +pub(crate) const MEMORY_IS_READ: usize = MEMORY_TIMESTAMP + 1; +pub(crate) const MEMORY_ADDR_CONTEXT: usize = MEMORY_IS_READ + 1; pub(crate) const MEMORY_ADDR_SEGMENT: usize = MEMORY_ADDR_CONTEXT + 1; pub(crate) const MEMORY_ADDR_VIRTUAL: usize = MEMORY_ADDR_SEGMENT + 1; pub(crate) const MEMORY_VALUE_START: usize = MEMORY_ADDR_VIRTUAL + 1; @@ -9,10 +11,9 @@ pub const fn memory_value_limb(i: usize) -> usize { MEMORY_VALUE_START + i } -pub(crate) const MEMORY_IS_READ: usize = MEMORY_VALUE_START + 8; -pub(crate) const MEMORY_TIMESTAMP: usize = MEMORY_IS_READ + 1; - -pub(crate) const SORTED_MEMORY_ADDR_CONTEXT: usize = MEMORY_TIMESTAMP + 1; +pub(crate) const SORTED_MEMORY_TIMESTAMP: usize = MEMORY_VALUE_START + 8; +pub(crate) const SORTED_MEMORY_IS_READ: usize = SORTED_MEMORY_TIMESTAMP + 1; +pub(crate) const SORTED_MEMORY_ADDR_CONTEXT: usize = SORTED_MEMORY_IS_READ + 1; pub(crate) const SORTED_MEMORY_ADDR_SEGMENT: usize = SORTED_MEMORY_ADDR_CONTEXT + 1; pub(crate) const SORTED_MEMORY_ADDR_VIRTUAL: usize = SORTED_MEMORY_ADDR_SEGMENT + 1; pub(crate) const SORTED_MEMORY_VALUE_START: usize = SORTED_MEMORY_ADDR_VIRTUAL + 1; @@ -21,9 +22,6 @@ pub const fn sorted_memory_value_limb(i: usize) -> usize { SORTED_MEMORY_VALUE_START + i } -pub(crate) const SORTED_MEMORY_IS_READ: usize = SORTED_MEMORY_VALUE_START + 8; -pub(crate) const SORTED_MEMORY_TIMESTAMP: usize = SORTED_MEMORY_IS_READ + 1; - pub(crate) const MEMORY_CONTEXT_FIRST_CHANGE: usize = SORTED_MEMORY_TIMESTAMP + 1; pub(crate) const MEMORY_SEGMENT_FIRST_CHANGE: usize = MEMORY_CONTEXT_FIRST_CHANGE + 1; pub(crate) const MEMORY_VIRTUAL_FIRST_CHANGE: usize = MEMORY_SEGMENT_FIRST_CHANGE + 1;