mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-06 15:53:10 +00:00
Merge branch 'main' of github.com:mir-protocol/plonky2 into ripeMD
This commit is contained in:
commit
4c9e80f298
@ -7,11 +7,15 @@ use std::mem::{size_of, transmute};
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
use crate::cpu::columns::general::CpuGeneralColumnsView;
|
||||
use crate::cpu::columns::ops::OpsColumnsView;
|
||||
use crate::cpu::membus::NUM_GP_CHANNELS;
|
||||
use crate::memory;
|
||||
use crate::util::{indices_arr, transmute_no_compile_time_size_checks};
|
||||
|
||||
mod general;
|
||||
pub(crate) mod ops;
|
||||
|
||||
pub type MemValue<T> = [T; memory::VALUE_LIMBS];
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@ -23,7 +27,7 @@ pub struct MemoryChannelView<T: Copy> {
|
||||
pub addr_context: T,
|
||||
pub addr_segment: T,
|
||||
pub addr_virtual: T,
|
||||
pub value: [T; memory::VALUE_LIMBS],
|
||||
pub value: MemValue<T>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -56,104 +60,9 @@ pub struct CpuColumnsView<T: Copy> {
|
||||
/// If CPU cycle: We're in kernel (privileged) mode.
|
||||
pub is_kernel_mode: T,
|
||||
|
||||
// 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 is_stop: T,
|
||||
pub is_add: T,
|
||||
pub is_mul: T,
|
||||
pub is_sub: T,
|
||||
pub is_div: T,
|
||||
pub is_sdiv: T,
|
||||
pub is_mod: T,
|
||||
pub is_smod: T,
|
||||
pub is_addmod: T,
|
||||
pub is_mulmod: T,
|
||||
pub is_exp: T,
|
||||
pub is_signextend: T,
|
||||
pub is_lt: T,
|
||||
pub is_gt: T,
|
||||
pub is_slt: T,
|
||||
pub is_sgt: T,
|
||||
pub is_eq: T, // Note: This column must be 0 when is_cpu_cycle = 0.
|
||||
pub is_iszero: T, // Note: This column must be 0 when is_cpu_cycle = 0.
|
||||
pub is_and: T,
|
||||
pub is_or: T,
|
||||
pub is_xor: T,
|
||||
pub is_not: T,
|
||||
pub is_byte: T,
|
||||
pub is_shl: T,
|
||||
pub is_shr: T,
|
||||
pub is_sar: T,
|
||||
pub is_keccak256: T,
|
||||
pub is_address: T,
|
||||
pub is_balance: T,
|
||||
pub is_origin: T,
|
||||
pub is_caller: T,
|
||||
pub is_callvalue: T,
|
||||
pub is_calldataload: T,
|
||||
pub is_calldatasize: T,
|
||||
pub is_calldatacopy: T,
|
||||
pub is_codesize: T,
|
||||
pub is_codecopy: T,
|
||||
pub is_gasprice: T,
|
||||
pub is_extcodesize: T,
|
||||
pub is_extcodecopy: T,
|
||||
pub is_returndatasize: T,
|
||||
pub is_returndatacopy: T,
|
||||
pub is_extcodehash: T,
|
||||
pub is_blockhash: T,
|
||||
pub is_coinbase: T,
|
||||
pub is_timestamp: T,
|
||||
pub is_number: T,
|
||||
pub is_difficulty: T,
|
||||
pub is_gaslimit: T,
|
||||
pub is_chainid: T,
|
||||
pub is_selfbalance: T,
|
||||
pub is_basefee: T,
|
||||
pub is_prover_input: T,
|
||||
pub is_pop: T,
|
||||
pub is_mload: T,
|
||||
pub is_mstore: T,
|
||||
pub is_mstore8: T,
|
||||
pub is_sload: T,
|
||||
pub is_sstore: T,
|
||||
pub is_jump: T, // Note: This column must be 0 when is_cpu_cycle = 0.
|
||||
pub is_jumpi: T, // Note: This column must be 0 when is_cpu_cycle = 0.
|
||||
pub is_pc: T,
|
||||
pub is_msize: T,
|
||||
pub is_gas: T,
|
||||
pub is_jumpdest: T,
|
||||
pub is_get_state_root: T,
|
||||
pub is_set_state_root: T,
|
||||
pub is_get_receipt_root: T,
|
||||
pub is_set_receipt_root: T,
|
||||
pub is_push: T,
|
||||
pub is_dup: T,
|
||||
pub is_swap: T,
|
||||
pub is_log0: T,
|
||||
pub is_log1: T,
|
||||
pub is_log2: T,
|
||||
pub is_log3: T,
|
||||
pub is_log4: T,
|
||||
// PANIC does not get a flag; it fails at the decode stage.
|
||||
pub is_create: T,
|
||||
pub is_call: T,
|
||||
pub is_callcode: T,
|
||||
pub is_return: T,
|
||||
pub is_delegatecall: T,
|
||||
pub is_create2: T,
|
||||
pub is_get_context: T,
|
||||
pub is_set_context: T,
|
||||
pub is_consume_gas: T,
|
||||
pub is_exit_kernel: T,
|
||||
pub is_staticcall: T,
|
||||
pub is_mload_general: T,
|
||||
pub is_mstore_general: T,
|
||||
pub is_revert: T,
|
||||
pub is_selfdestruct: T,
|
||||
|
||||
pub is_invalid: T,
|
||||
/// If CPU cycle: flags for EVM instructions (a few cannot be shared; see the comments in
|
||||
/// `OpsColumnsView`).
|
||||
pub op: OpsColumnsView<T>,
|
||||
|
||||
/// If CPU cycle: the opcode, broken up into bits in little-endian order.
|
||||
pub opcode_bits: [T; 8],
|
||||
|
||||
153
evm/src/cpu/columns/ops.rs
Normal file
153
evm/src/cpu/columns/ops.rs
Normal file
@ -0,0 +1,153 @@
|
||||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::mem::{size_of, transmute};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use crate::util::{indices_arr, transmute_no_compile_time_size_checks};
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub struct OpsColumnsView<T> {
|
||||
pub stop: T,
|
||||
pub add: T,
|
||||
pub mul: T,
|
||||
pub sub: T,
|
||||
pub div: T,
|
||||
pub sdiv: T,
|
||||
pub mod_: T,
|
||||
pub smod: T,
|
||||
pub addmod: T,
|
||||
pub mulmod: T,
|
||||
pub exp: T,
|
||||
pub signextend: T,
|
||||
pub lt: T,
|
||||
pub gt: T,
|
||||
pub slt: T,
|
||||
pub sgt: T,
|
||||
pub eq: T, // Note: This column must be 0 when is_cpu_cycle = 0.
|
||||
pub iszero: T, // Note: This column must be 0 when is_cpu_cycle = 0.
|
||||
pub and: T,
|
||||
pub or: T,
|
||||
pub xor: T,
|
||||
pub not: T,
|
||||
pub byte: T,
|
||||
pub shl: T,
|
||||
pub shr: T,
|
||||
pub sar: T,
|
||||
pub keccak256: T,
|
||||
pub address: T,
|
||||
pub balance: T,
|
||||
pub origin: T,
|
||||
pub caller: T,
|
||||
pub callvalue: T,
|
||||
pub calldataload: T,
|
||||
pub calldatasize: T,
|
||||
pub calldatacopy: T,
|
||||
pub codesize: T,
|
||||
pub codecopy: T,
|
||||
pub gasprice: T,
|
||||
pub extcodesize: T,
|
||||
pub extcodecopy: T,
|
||||
pub returndatasize: T,
|
||||
pub returndatacopy: T,
|
||||
pub extcodehash: T,
|
||||
pub blockhash: T,
|
||||
pub coinbase: T,
|
||||
pub timestamp: T,
|
||||
pub number: T,
|
||||
pub difficulty: T,
|
||||
pub gaslimit: T,
|
||||
pub chainid: T,
|
||||
pub selfbalance: T,
|
||||
pub basefee: T,
|
||||
pub prover_input: T,
|
||||
pub pop: T,
|
||||
pub mload: T,
|
||||
pub mstore: T,
|
||||
pub mstore8: T,
|
||||
pub sload: T,
|
||||
pub sstore: T,
|
||||
pub jump: T, // Note: This column must be 0 when is_cpu_cycle = 0.
|
||||
pub jumpi: T, // Note: This column must be 0 when is_cpu_cycle = 0.
|
||||
pub pc: T,
|
||||
pub msize: T,
|
||||
pub gas: T,
|
||||
pub jumpdest: T,
|
||||
pub get_state_root: T,
|
||||
pub set_state_root: T,
|
||||
pub get_receipt_root: T,
|
||||
pub set_receipt_root: T,
|
||||
pub push: T,
|
||||
pub dup: T,
|
||||
pub swap: T,
|
||||
pub log0: T,
|
||||
pub log1: T,
|
||||
pub log2: T,
|
||||
pub log3: T,
|
||||
pub log4: T,
|
||||
// PANIC does not get a flag; it fails at the decode stage.
|
||||
pub create: T,
|
||||
pub call: T,
|
||||
pub callcode: T,
|
||||
pub return_: T,
|
||||
pub delegatecall: T,
|
||||
pub create2: T,
|
||||
pub get_context: T,
|
||||
pub set_context: T,
|
||||
pub consume_gas: T,
|
||||
pub exit_kernel: T,
|
||||
pub staticcall: T,
|
||||
pub mload_general: T,
|
||||
pub mstore_general: T,
|
||||
pub revert: T,
|
||||
pub selfdestruct: T,
|
||||
|
||||
// TODO: this doesn't actually need its own flag. We can just do `1 - sum(all other flags)`.
|
||||
pub invalid: T,
|
||||
}
|
||||
|
||||
// `u8` is guaranteed to have a `size_of` of 1.
|
||||
pub const NUM_OPS_COLUMNS: usize = size_of::<OpsColumnsView<u8>>();
|
||||
|
||||
impl<T> From<[T; NUM_OPS_COLUMNS]> for OpsColumnsView<T> {
|
||||
fn from(value: [T; NUM_OPS_COLUMNS]) -> Self {
|
||||
unsafe { transmute_no_compile_time_size_checks(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<OpsColumnsView<T>> for [T; NUM_OPS_COLUMNS] {
|
||||
fn from(value: OpsColumnsView<T>) -> Self {
|
||||
unsafe { transmute_no_compile_time_size_checks(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Borrow<OpsColumnsView<T>> for [T; NUM_OPS_COLUMNS] {
|
||||
fn borrow(&self) -> &OpsColumnsView<T> {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> BorrowMut<OpsColumnsView<T>> for [T; NUM_OPS_COLUMNS] {
|
||||
fn borrow_mut(&mut self) -> &mut OpsColumnsView<T> {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for OpsColumnsView<T> {
|
||||
type Target = [T; NUM_OPS_COLUMNS];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for OpsColumnsView<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
const fn make_col_map() -> OpsColumnsView<usize> {
|
||||
let indices_arr = indices_arr::<NUM_OPS_COLUMNS>();
|
||||
unsafe { transmute::<[usize; NUM_OPS_COLUMNS], OpsColumnsView<usize>>(indices_arr) }
|
||||
}
|
||||
|
||||
pub const COL_MAP: OpsColumnsView<usize> = make_col_map();
|
||||
@ -10,31 +10,31 @@ use crate::cpu::kernel::aggregator::KERNEL;
|
||||
|
||||
// TODO: This list is incomplete.
|
||||
const NATIVE_INSTRUCTIONS: [usize; 25] = [
|
||||
COL_MAP.is_add,
|
||||
COL_MAP.is_mul,
|
||||
COL_MAP.is_sub,
|
||||
COL_MAP.is_div,
|
||||
COL_MAP.is_sdiv,
|
||||
COL_MAP.is_mod,
|
||||
COL_MAP.is_smod,
|
||||
COL_MAP.is_addmod,
|
||||
COL_MAP.is_mulmod,
|
||||
COL_MAP.is_signextend,
|
||||
COL_MAP.is_lt,
|
||||
COL_MAP.is_gt,
|
||||
COL_MAP.is_slt,
|
||||
COL_MAP.is_sgt,
|
||||
COL_MAP.is_eq,
|
||||
COL_MAP.is_iszero,
|
||||
COL_MAP.is_and,
|
||||
COL_MAP.is_or,
|
||||
COL_MAP.is_xor,
|
||||
COL_MAP.is_not,
|
||||
COL_MAP.is_byte,
|
||||
COL_MAP.is_shl,
|
||||
COL_MAP.is_shr,
|
||||
COL_MAP.is_sar,
|
||||
COL_MAP.is_pop,
|
||||
COL_MAP.op.add,
|
||||
COL_MAP.op.mul,
|
||||
COL_MAP.op.sub,
|
||||
COL_MAP.op.div,
|
||||
COL_MAP.op.sdiv,
|
||||
COL_MAP.op.mod_,
|
||||
COL_MAP.op.smod,
|
||||
COL_MAP.op.addmod,
|
||||
COL_MAP.op.mulmod,
|
||||
COL_MAP.op.signextend,
|
||||
COL_MAP.op.lt,
|
||||
COL_MAP.op.gt,
|
||||
COL_MAP.op.slt,
|
||||
COL_MAP.op.sgt,
|
||||
COL_MAP.op.eq,
|
||||
COL_MAP.op.iszero,
|
||||
COL_MAP.op.and,
|
||||
COL_MAP.op.or,
|
||||
COL_MAP.op.xor,
|
||||
COL_MAP.op.not,
|
||||
COL_MAP.op.byte,
|
||||
COL_MAP.op.shl,
|
||||
COL_MAP.op.shr,
|
||||
COL_MAP.op.sar,
|
||||
COL_MAP.op.pop,
|
||||
];
|
||||
|
||||
fn get_halt_pcs<F: Field>() -> (F, F) {
|
||||
|
||||
@ -11,7 +11,8 @@ use plonky2::hash::hash_types::RichField;
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::cpu::columns::{CpuColumnsView, COL_MAP, NUM_CPU_COLUMNS};
|
||||
use crate::cpu::{
|
||||
bootstrap_kernel, control_flow, decode, jumps, membus, simple_logic, stack_bounds, syscalls,
|
||||
bootstrap_kernel, control_flow, decode, jumps, membus, simple_logic, stack, stack_bounds,
|
||||
syscalls,
|
||||
};
|
||||
use crate::cross_table_lookup::Column;
|
||||
use crate::memory::segments::Segment;
|
||||
@ -50,7 +51,7 @@ pub fn ctl_filter_keccak_memory<F: Field>() -> Column<F> {
|
||||
}
|
||||
|
||||
pub fn ctl_data_logic<F: Field>() -> Vec<Column<F>> {
|
||||
let mut res = Column::singles([COL_MAP.is_and, COL_MAP.is_or, COL_MAP.is_xor]).collect_vec();
|
||||
let mut res = Column::singles([COL_MAP.op.and, COL_MAP.op.or, COL_MAP.op.xor]).collect_vec();
|
||||
res.extend(Column::singles(COL_MAP.mem_channels[0].value));
|
||||
res.extend(Column::singles(COL_MAP.mem_channels[1].value));
|
||||
res.extend(Column::singles(COL_MAP.mem_channels[2].value));
|
||||
@ -58,7 +59,7 @@ pub fn ctl_data_logic<F: Field>() -> Vec<Column<F>> {
|
||||
}
|
||||
|
||||
pub fn ctl_filter_logic<F: Field>() -> Column<F> {
|
||||
Column::sum([COL_MAP.is_and, COL_MAP.is_or, COL_MAP.is_xor])
|
||||
Column::sum([COL_MAP.op.and, COL_MAP.op.or, COL_MAP.op.xor])
|
||||
}
|
||||
|
||||
pub const MEM_CODE_CHANNEL_IDX: usize = 0;
|
||||
@ -149,6 +150,7 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for CpuStark<F, D
|
||||
jumps::eval_packed(local_values, next_values, yield_constr);
|
||||
membus::eval_packed(local_values, yield_constr);
|
||||
simple_logic::eval_packed(local_values, yield_constr);
|
||||
stack::eval_packed(local_values, yield_constr);
|
||||
stack_bounds::eval_packed(local_values, yield_constr);
|
||||
syscalls::eval_packed(local_values, next_values, yield_constr);
|
||||
}
|
||||
@ -167,6 +169,7 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for CpuStark<F, D
|
||||
jumps::eval_ext_circuit(builder, local_values, next_values, yield_constr);
|
||||
membus::eval_ext_circuit(builder, local_values, yield_constr);
|
||||
simple_logic::eval_ext_circuit(builder, local_values, yield_constr);
|
||||
stack::eval_ext_circuit(builder, local_values, yield_constr);
|
||||
stack_bounds::eval_ext_circuit(builder, local_values, yield_constr);
|
||||
syscalls::eval_ext_circuit(builder, local_values, next_values, yield_constr);
|
||||
}
|
||||
|
||||
@ -24,99 +24,99 @@ use crate::cpu::columns::{CpuColumnsView, COL_MAP};
|
||||
/// `is_invalid`. The kernel then verifies that the opcode was _actually_ invalid.
|
||||
const OPCODES: [(u8, usize, bool, usize); 92] = [
|
||||
// (start index of block, number of top bits to check (log2), kernel-only, flag column)
|
||||
(0x00, 0, false, COL_MAP.is_stop),
|
||||
(0x01, 0, false, COL_MAP.is_add),
|
||||
(0x02, 0, false, COL_MAP.is_mul),
|
||||
(0x03, 0, false, COL_MAP.is_sub),
|
||||
(0x04, 0, false, COL_MAP.is_div),
|
||||
(0x05, 0, false, COL_MAP.is_sdiv),
|
||||
(0x06, 0, false, COL_MAP.is_mod),
|
||||
(0x07, 0, false, COL_MAP.is_smod),
|
||||
(0x08, 0, false, COL_MAP.is_addmod),
|
||||
(0x09, 0, false, COL_MAP.is_mulmod),
|
||||
(0x0a, 0, false, COL_MAP.is_exp),
|
||||
(0x0b, 0, false, COL_MAP.is_signextend),
|
||||
(0x10, 0, false, COL_MAP.is_lt),
|
||||
(0x11, 0, false, COL_MAP.is_gt),
|
||||
(0x12, 0, false, COL_MAP.is_slt),
|
||||
(0x13, 0, false, COL_MAP.is_sgt),
|
||||
(0x14, 0, false, COL_MAP.is_eq),
|
||||
(0x15, 0, false, COL_MAP.is_iszero),
|
||||
(0x16, 0, false, COL_MAP.is_and),
|
||||
(0x17, 0, false, COL_MAP.is_or),
|
||||
(0x18, 0, false, COL_MAP.is_xor),
|
||||
(0x19, 0, false, COL_MAP.is_not),
|
||||
(0x1a, 0, false, COL_MAP.is_byte),
|
||||
(0x1b, 0, false, COL_MAP.is_shl),
|
||||
(0x1c, 0, false, COL_MAP.is_shr),
|
||||
(0x1d, 0, false, COL_MAP.is_sar),
|
||||
(0x20, 0, false, COL_MAP.is_keccak256),
|
||||
(0x30, 0, false, COL_MAP.is_address),
|
||||
(0x31, 0, false, COL_MAP.is_balance),
|
||||
(0x32, 0, false, COL_MAP.is_origin),
|
||||
(0x33, 0, false, COL_MAP.is_caller),
|
||||
(0x34, 0, false, COL_MAP.is_callvalue),
|
||||
(0x35, 0, false, COL_MAP.is_calldataload),
|
||||
(0x36, 0, false, COL_MAP.is_calldatasize),
|
||||
(0x37, 0, false, COL_MAP.is_calldatacopy),
|
||||
(0x38, 0, false, COL_MAP.is_codesize),
|
||||
(0x39, 0, false, COL_MAP.is_codecopy),
|
||||
(0x3a, 0, false, COL_MAP.is_gasprice),
|
||||
(0x3b, 0, false, COL_MAP.is_extcodesize),
|
||||
(0x3c, 0, false, COL_MAP.is_extcodecopy),
|
||||
(0x3d, 0, false, COL_MAP.is_returndatasize),
|
||||
(0x3e, 0, false, COL_MAP.is_returndatacopy),
|
||||
(0x3f, 0, false, COL_MAP.is_extcodehash),
|
||||
(0x40, 0, false, COL_MAP.is_blockhash),
|
||||
(0x41, 0, false, COL_MAP.is_coinbase),
|
||||
(0x42, 0, false, COL_MAP.is_timestamp),
|
||||
(0x43, 0, false, COL_MAP.is_number),
|
||||
(0x44, 0, false, COL_MAP.is_difficulty),
|
||||
(0x45, 0, false, COL_MAP.is_gaslimit),
|
||||
(0x46, 0, false, COL_MAP.is_chainid),
|
||||
(0x47, 0, false, COL_MAP.is_selfbalance),
|
||||
(0x48, 0, false, COL_MAP.is_basefee),
|
||||
(0x49, 0, true, COL_MAP.is_prover_input),
|
||||
(0x50, 0, false, COL_MAP.is_pop),
|
||||
(0x51, 0, false, COL_MAP.is_mload),
|
||||
(0x52, 0, false, COL_MAP.is_mstore),
|
||||
(0x53, 0, false, COL_MAP.is_mstore8),
|
||||
(0x54, 0, false, COL_MAP.is_sload),
|
||||
(0x55, 0, false, COL_MAP.is_sstore),
|
||||
(0x56, 0, false, COL_MAP.is_jump),
|
||||
(0x57, 0, false, COL_MAP.is_jumpi),
|
||||
(0x58, 0, false, COL_MAP.is_pc),
|
||||
(0x59, 0, false, COL_MAP.is_msize),
|
||||
(0x5a, 0, false, COL_MAP.is_gas),
|
||||
(0x5b, 0, false, COL_MAP.is_jumpdest),
|
||||
(0x5c, 0, true, COL_MAP.is_get_state_root),
|
||||
(0x5d, 0, true, COL_MAP.is_set_state_root),
|
||||
(0x5e, 0, true, COL_MAP.is_get_receipt_root),
|
||||
(0x5f, 0, true, COL_MAP.is_set_receipt_root),
|
||||
(0x60, 5, false, COL_MAP.is_push), // 0x60-0x7f
|
||||
(0x80, 4, false, COL_MAP.is_dup), // 0x80-0x8f
|
||||
(0x90, 4, false, COL_MAP.is_swap), // 0x90-0x9f
|
||||
(0xa0, 0, false, COL_MAP.is_log0),
|
||||
(0xa1, 0, false, COL_MAP.is_log1),
|
||||
(0xa2, 0, false, COL_MAP.is_log2),
|
||||
(0xa3, 0, false, COL_MAP.is_log3),
|
||||
(0xa4, 0, false, COL_MAP.is_log4),
|
||||
(0x00, 0, false, COL_MAP.op.stop),
|
||||
(0x01, 0, false, COL_MAP.op.add),
|
||||
(0x02, 0, false, COL_MAP.op.mul),
|
||||
(0x03, 0, false, COL_MAP.op.sub),
|
||||
(0x04, 0, false, COL_MAP.op.div),
|
||||
(0x05, 0, false, COL_MAP.op.sdiv),
|
||||
(0x06, 0, false, COL_MAP.op.mod_),
|
||||
(0x07, 0, false, COL_MAP.op.smod),
|
||||
(0x08, 0, false, COL_MAP.op.addmod),
|
||||
(0x09, 0, false, COL_MAP.op.mulmod),
|
||||
(0x0a, 0, false, COL_MAP.op.exp),
|
||||
(0x0b, 0, false, COL_MAP.op.signextend),
|
||||
(0x10, 0, false, COL_MAP.op.lt),
|
||||
(0x11, 0, false, COL_MAP.op.gt),
|
||||
(0x12, 0, false, COL_MAP.op.slt),
|
||||
(0x13, 0, false, COL_MAP.op.sgt),
|
||||
(0x14, 0, false, COL_MAP.op.eq),
|
||||
(0x15, 0, false, COL_MAP.op.iszero),
|
||||
(0x16, 0, false, COL_MAP.op.and),
|
||||
(0x17, 0, false, COL_MAP.op.or),
|
||||
(0x18, 0, false, COL_MAP.op.xor),
|
||||
(0x19, 0, false, COL_MAP.op.not),
|
||||
(0x1a, 0, false, COL_MAP.op.byte),
|
||||
(0x1b, 0, false, COL_MAP.op.shl),
|
||||
(0x1c, 0, false, COL_MAP.op.shr),
|
||||
(0x1d, 0, false, COL_MAP.op.sar),
|
||||
(0x20, 0, false, COL_MAP.op.keccak256),
|
||||
(0x30, 0, false, COL_MAP.op.address),
|
||||
(0x31, 0, false, COL_MAP.op.balance),
|
||||
(0x32, 0, false, COL_MAP.op.origin),
|
||||
(0x33, 0, false, COL_MAP.op.caller),
|
||||
(0x34, 0, false, COL_MAP.op.callvalue),
|
||||
(0x35, 0, false, COL_MAP.op.calldataload),
|
||||
(0x36, 0, false, COL_MAP.op.calldatasize),
|
||||
(0x37, 0, false, COL_MAP.op.calldatacopy),
|
||||
(0x38, 0, false, COL_MAP.op.codesize),
|
||||
(0x39, 0, false, COL_MAP.op.codecopy),
|
||||
(0x3a, 0, false, COL_MAP.op.gasprice),
|
||||
(0x3b, 0, false, COL_MAP.op.extcodesize),
|
||||
(0x3c, 0, false, COL_MAP.op.extcodecopy),
|
||||
(0x3d, 0, false, COL_MAP.op.returndatasize),
|
||||
(0x3e, 0, false, COL_MAP.op.returndatacopy),
|
||||
(0x3f, 0, false, COL_MAP.op.extcodehash),
|
||||
(0x40, 0, false, COL_MAP.op.blockhash),
|
||||
(0x41, 0, false, COL_MAP.op.coinbase),
|
||||
(0x42, 0, false, COL_MAP.op.timestamp),
|
||||
(0x43, 0, false, COL_MAP.op.number),
|
||||
(0x44, 0, false, COL_MAP.op.difficulty),
|
||||
(0x45, 0, false, COL_MAP.op.gaslimit),
|
||||
(0x46, 0, false, COL_MAP.op.chainid),
|
||||
(0x47, 0, false, COL_MAP.op.selfbalance),
|
||||
(0x48, 0, false, COL_MAP.op.basefee),
|
||||
(0x49, 0, true, COL_MAP.op.prover_input),
|
||||
(0x50, 0, false, COL_MAP.op.pop),
|
||||
(0x51, 0, false, COL_MAP.op.mload),
|
||||
(0x52, 0, false, COL_MAP.op.mstore),
|
||||
(0x53, 0, false, COL_MAP.op.mstore8),
|
||||
(0x54, 0, false, COL_MAP.op.sload),
|
||||
(0x55, 0, false, COL_MAP.op.sstore),
|
||||
(0x56, 0, false, COL_MAP.op.jump),
|
||||
(0x57, 0, false, COL_MAP.op.jumpi),
|
||||
(0x58, 0, false, COL_MAP.op.pc),
|
||||
(0x59, 0, false, COL_MAP.op.msize),
|
||||
(0x5a, 0, false, COL_MAP.op.gas),
|
||||
(0x5b, 0, false, COL_MAP.op.jumpdest),
|
||||
(0x5c, 0, true, COL_MAP.op.get_state_root),
|
||||
(0x5d, 0, true, COL_MAP.op.set_state_root),
|
||||
(0x5e, 0, true, COL_MAP.op.get_receipt_root),
|
||||
(0x5f, 0, true, COL_MAP.op.set_receipt_root),
|
||||
(0x60, 5, false, COL_MAP.op.push), // 0x60-0x7f
|
||||
(0x80, 4, false, COL_MAP.op.dup), // 0x80-0x8f
|
||||
(0x90, 4, false, COL_MAP.op.swap), // 0x90-0x9f
|
||||
(0xa0, 0, false, COL_MAP.op.log0),
|
||||
(0xa1, 0, false, COL_MAP.op.log1),
|
||||
(0xa2, 0, false, COL_MAP.op.log2),
|
||||
(0xa3, 0, false, COL_MAP.op.log3),
|
||||
(0xa4, 0, false, COL_MAP.op.log4),
|
||||
// Opcode 0xa5 is PANIC when Kernel. Make the proof unverifiable by giving it no flag to decode to.
|
||||
(0xf0, 0, false, COL_MAP.is_create),
|
||||
(0xf1, 0, false, COL_MAP.is_call),
|
||||
(0xf2, 0, false, COL_MAP.is_callcode),
|
||||
(0xf3, 0, false, COL_MAP.is_return),
|
||||
(0xf4, 0, false, COL_MAP.is_delegatecall),
|
||||
(0xf5, 0, false, COL_MAP.is_create2),
|
||||
(0xf6, 0, true, COL_MAP.is_get_context),
|
||||
(0xf7, 0, true, COL_MAP.is_set_context),
|
||||
(0xf8, 0, true, COL_MAP.is_consume_gas),
|
||||
(0xf9, 0, true, COL_MAP.is_exit_kernel),
|
||||
(0xfa, 0, false, COL_MAP.is_staticcall),
|
||||
(0xfb, 0, true, COL_MAP.is_mload_general),
|
||||
(0xfc, 0, true, COL_MAP.is_mstore_general),
|
||||
(0xfd, 0, false, COL_MAP.is_revert),
|
||||
(0xff, 0, false, COL_MAP.is_selfdestruct),
|
||||
(0xf0, 0, false, COL_MAP.op.create),
|
||||
(0xf1, 0, false, COL_MAP.op.call),
|
||||
(0xf2, 0, false, COL_MAP.op.callcode),
|
||||
(0xf3, 0, false, COL_MAP.op.return_),
|
||||
(0xf4, 0, false, COL_MAP.op.delegatecall),
|
||||
(0xf5, 0, false, COL_MAP.op.create2),
|
||||
(0xf6, 0, true, COL_MAP.op.get_context),
|
||||
(0xf7, 0, true, COL_MAP.op.set_context),
|
||||
(0xf8, 0, true, COL_MAP.op.consume_gas),
|
||||
(0xf9, 0, true, COL_MAP.op.exit_kernel),
|
||||
(0xfa, 0, false, COL_MAP.op.staticcall),
|
||||
(0xfb, 0, true, COL_MAP.op.mload_general),
|
||||
(0xfc, 0, true, COL_MAP.op.mstore_general),
|
||||
(0xfd, 0, false, COL_MAP.op.revert),
|
||||
(0xff, 0, false, COL_MAP.op.selfdestruct),
|
||||
];
|
||||
|
||||
/// Bitfield of invalid opcodes, in little-endian order.
|
||||
@ -150,8 +150,8 @@ pub fn generate<F: RichField>(lv: &mut CpuColumnsView<F>) {
|
||||
let cycle_filter = lv.is_cpu_cycle;
|
||||
if cycle_filter == F::ZERO {
|
||||
// These columns cannot be shared.
|
||||
lv.is_eq = F::ZERO;
|
||||
lv.is_iszero = F::ZERO;
|
||||
lv.op.eq = F::ZERO;
|
||||
lv.op.iszero = F::ZERO;
|
||||
return;
|
||||
}
|
||||
// This assert is not _strictly_ necessary, but I include it as a sanity check.
|
||||
@ -196,7 +196,7 @@ pub fn generate<F: RichField>(lv: &mut CpuColumnsView<F>) {
|
||||
any_flag_set = any_flag_set || flag;
|
||||
}
|
||||
// is_invalid is a catch-all for opcodes we can't decode.
|
||||
lv.is_invalid = F::from_bool(!any_flag_set);
|
||||
lv.op.invalid = F::from_bool(!any_flag_set);
|
||||
}
|
||||
|
||||
/// Break up an opcode (which is 8 bits long) into its eight bits.
|
||||
@ -234,13 +234,13 @@ pub fn eval_packed_generic<P: PackedField>(
|
||||
let flag = lv[flag_col];
|
||||
yield_constr.constraint(cycle_filter * flag * (flag - P::ONES));
|
||||
}
|
||||
yield_constr.constraint(cycle_filter * lv.is_invalid * (lv.is_invalid - P::ONES));
|
||||
yield_constr.constraint(cycle_filter * lv.op.invalid * (lv.op.invalid - P::ONES));
|
||||
// Now check that exactly one is 1.
|
||||
let flag_sum: P = OPCODES
|
||||
.into_iter()
|
||||
.map(|(_, _, _, flag_col)| lv[flag_col])
|
||||
.sum::<P>()
|
||||
+ lv.is_invalid;
|
||||
+ lv.op.invalid;
|
||||
yield_constr.constraint(cycle_filter * (P::ONES - flag_sum));
|
||||
|
||||
// Finally, classify all opcodes, together with the kernel flag, into blocks
|
||||
@ -305,7 +305,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
{
|
||||
let constr = builder.mul_sub_extension(lv.is_invalid, lv.is_invalid, lv.is_invalid);
|
||||
let constr = builder.mul_sub_extension(lv.op.invalid, lv.op.invalid, lv.op.invalid);
|
||||
let constr = builder.mul_extension(cycle_filter, constr);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
@ -316,7 +316,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
let flag = lv[flag_col];
|
||||
constr = builder.sub_extension(constr, flag);
|
||||
}
|
||||
constr = builder.sub_extension(constr, lv.is_invalid);
|
||||
constr = builder.sub_extension(constr, lv.op.invalid);
|
||||
constr = builder.mul_extension(cycle_filter, constr);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
|
||||
@ -23,10 +23,10 @@ pub fn eval_packed_exit_kernel<P: PackedField>(
|
||||
// flag. The top 6 (32-bit) limbs are ignored (this is not part of the spec, but we trust the
|
||||
// kernel to set them to zero).
|
||||
yield_constr.constraint_transition(
|
||||
lv.is_cpu_cycle * lv.is_exit_kernel * (input[0] - nv.program_counter),
|
||||
lv.is_cpu_cycle * lv.op.exit_kernel * (input[0] - nv.program_counter),
|
||||
);
|
||||
yield_constr.constraint_transition(
|
||||
lv.is_cpu_cycle * lv.is_exit_kernel * (input[1] - nv.is_kernel_mode),
|
||||
lv.is_cpu_cycle * lv.op.exit_kernel * (input[1] - nv.is_kernel_mode),
|
||||
);
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ pub fn eval_ext_circuit_exit_kernel<F: RichField + Extendable<D>, const D: usize
|
||||
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
||||
) {
|
||||
let input = lv.mem_channels[0].value;
|
||||
let filter = builder.mul_extension(lv.is_cpu_cycle, lv.is_exit_kernel);
|
||||
let filter = builder.mul_extension(lv.is_cpu_cycle, lv.op.exit_kernel);
|
||||
|
||||
// If we are executing `EXIT_KERNEL` then we simply restore the program counter and kernel mode
|
||||
// flag. The top 6 (32-bit) limbs are ignored (this is not part of the spec, but we trust the
|
||||
@ -60,16 +60,16 @@ pub fn eval_packed_jump_jumpi<P: PackedField>(
|
||||
let jumps_lv = lv.general.jumps();
|
||||
let input0 = lv.mem_channels[0].value;
|
||||
let input1 = lv.mem_channels[1].value;
|
||||
let filter = lv.is_jump + lv.is_jumpi; // `JUMP` or `JUMPI`
|
||||
let filter = lv.op.jump + lv.op.jumpi; // `JUMP` or `JUMPI`
|
||||
|
||||
// If `JUMP`, re-use the `JUMPI` logic, but setting the second input (the predicate) to be 1.
|
||||
// In other words, we implement `JUMP(addr)` as `JUMPI(addr, cond=1)`.
|
||||
yield_constr.constraint(lv.is_jump * (input1[0] - P::ONES));
|
||||
yield_constr.constraint(lv.op.jump * (input1[0] - P::ONES));
|
||||
for &limb in &input1[1..] {
|
||||
// Set all limbs (other than the least-significant limb) to 0.
|
||||
// NB: Technically, they don't have to be 0, as long as the sum
|
||||
// `input1[0] + ... + input1[7]` cannot overflow.
|
||||
yield_constr.constraint(lv.is_jump * limb);
|
||||
yield_constr.constraint(lv.op.jump * limb);
|
||||
}
|
||||
|
||||
// Check `input0_upper_zero`
|
||||
@ -162,19 +162,19 @@ pub fn eval_ext_circuit_jump_jumpi<F: RichField + Extendable<D>, const D: usize>
|
||||
let jumps_lv = lv.general.jumps();
|
||||
let input0 = lv.mem_channels[0].value;
|
||||
let input1 = lv.mem_channels[1].value;
|
||||
let filter = builder.add_extension(lv.is_jump, lv.is_jumpi); // `JUMP` or `JUMPI`
|
||||
let filter = builder.add_extension(lv.op.jump, lv.op.jumpi); // `JUMP` or `JUMPI`
|
||||
|
||||
// If `JUMP`, re-use the `JUMPI` logic, but setting the second input (the predicate) to be 1.
|
||||
// In other words, we implement `JUMP(addr)` as `JUMPI(addr, cond=1)`.
|
||||
{
|
||||
let constr = builder.mul_sub_extension(lv.is_jump, input1[0], lv.is_jump);
|
||||
let constr = builder.mul_sub_extension(lv.op.jump, input1[0], lv.op.jump);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
for &limb in &input1[1..] {
|
||||
// Set all limbs (other than the least-significant limb) to 0.
|
||||
// NB: Technically, they don't have to be 0, as long as the sum
|
||||
// `input1[0] + ... + input1[7]` cannot overflow.
|
||||
let constr = builder.mul_extension(lv.is_jump, limb);
|
||||
let constr = builder.mul_extension(lv.op.jump, limb);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
|
||||
|
||||
@ -7,5 +7,6 @@ mod jumps;
|
||||
pub mod kernel;
|
||||
pub(crate) mod membus;
|
||||
mod simple_logic;
|
||||
mod stack;
|
||||
mod stack_bounds;
|
||||
mod syscalls;
|
||||
|
||||
@ -10,8 +10,8 @@ use crate::cpu::columns::CpuColumnsView;
|
||||
pub fn generate<F: RichField>(lv: &mut CpuColumnsView<F>) {
|
||||
let input0 = lv.mem_channels[0].value;
|
||||
|
||||
let eq_filter = lv.is_eq.to_canonical_u64();
|
||||
let iszero_filter = lv.is_iszero.to_canonical_u64();
|
||||
let eq_filter = lv.op.eq.to_canonical_u64();
|
||||
let iszero_filter = lv.op.iszero.to_canonical_u64();
|
||||
assert!(eq_filter <= 1);
|
||||
assert!(iszero_filter <= 1);
|
||||
assert!(eq_filter + iszero_filter <= 1);
|
||||
@ -62,8 +62,8 @@ pub fn eval_packed<P: PackedField>(
|
||||
let input1 = lv.mem_channels[1].value;
|
||||
let output = lv.mem_channels[2].value;
|
||||
|
||||
let eq_filter = lv.is_eq;
|
||||
let iszero_filter = lv.is_iszero;
|
||||
let eq_filter = lv.op.eq;
|
||||
let iszero_filter = lv.op.iszero;
|
||||
let eq_or_iszero_filter = eq_filter + iszero_filter;
|
||||
|
||||
let equal = output[0];
|
||||
@ -110,8 +110,8 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
let input1 = lv.mem_channels[1].value;
|
||||
let output = lv.mem_channels[2].value;
|
||||
|
||||
let eq_filter = lv.is_eq;
|
||||
let iszero_filter = lv.is_iszero;
|
||||
let eq_filter = lv.op.eq;
|
||||
let iszero_filter = lv.op.iszero;
|
||||
let eq_or_iszero_filter = builder.add_extension(eq_filter, iszero_filter);
|
||||
|
||||
let equal = output[0];
|
||||
|
||||
@ -11,7 +11,7 @@ const LIMB_SIZE: usize = 32;
|
||||
const ALL_1_LIMB: u64 = (1 << LIMB_SIZE) - 1;
|
||||
|
||||
pub fn generate<F: RichField>(lv: &mut CpuColumnsView<F>) {
|
||||
let is_not_filter = lv.is_not.to_canonical_u64();
|
||||
let is_not_filter = lv.op.not.to_canonical_u64();
|
||||
if is_not_filter == 0 {
|
||||
return;
|
||||
}
|
||||
@ -35,7 +35,7 @@ pub fn eval_packed<P: PackedField>(
|
||||
let input = lv.mem_channels[0].value;
|
||||
let output = lv.mem_channels[1].value;
|
||||
let cycle_filter = lv.is_cpu_cycle;
|
||||
let is_not_filter = lv.is_not;
|
||||
let is_not_filter = lv.op.not;
|
||||
let filter = cycle_filter * is_not_filter;
|
||||
for (input_limb, output_limb) in input.into_iter().zip(output) {
|
||||
yield_constr.constraint(
|
||||
@ -52,7 +52,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
let input = lv.mem_channels[0].value;
|
||||
let output = lv.mem_channels[1].value;
|
||||
let cycle_filter = lv.is_cpu_cycle;
|
||||
let is_not_filter = lv.is_not;
|
||||
let is_not_filter = lv.op.not;
|
||||
let filter = builder.mul_extension(cycle_filter, is_not_filter);
|
||||
for (input_limb, output_limb) in input.into_iter().zip(output) {
|
||||
let constr = builder.add_extension(output_limb, input_limb);
|
||||
|
||||
307
evm/src/cpu/stack.rs
Normal file
307
evm/src/cpu/stack.rs
Normal file
@ -0,0 +1,307 @@
|
||||
use itertools::izip;
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::packed::PackedField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::ext_target::ExtensionTarget;
|
||||
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::cpu::columns::ops::OpsColumnsView;
|
||||
use crate::cpu::columns::CpuColumnsView;
|
||||
use crate::cpu::membus::NUM_GP_CHANNELS;
|
||||
use crate::memory::segments::Segment;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct StackBehavior {
|
||||
num_pops: usize,
|
||||
pushes: bool,
|
||||
disable_other_channels: bool,
|
||||
}
|
||||
|
||||
const BASIC_UNARY_OP: Option<StackBehavior> = Some(StackBehavior {
|
||||
num_pops: 1,
|
||||
pushes: true,
|
||||
disable_other_channels: true,
|
||||
});
|
||||
const BASIC_BINARY_OP: Option<StackBehavior> = Some(StackBehavior {
|
||||
num_pops: 2,
|
||||
pushes: true,
|
||||
disable_other_channels: true,
|
||||
});
|
||||
const BASIC_TERNARY_OP: Option<StackBehavior> = Some(StackBehavior {
|
||||
num_pops: 2,
|
||||
pushes: true,
|
||||
disable_other_channels: true,
|
||||
});
|
||||
|
||||
const STACK_BEHAVIORS: OpsColumnsView<Option<StackBehavior>> = OpsColumnsView {
|
||||
stop: None, // TODO
|
||||
add: BASIC_BINARY_OP,
|
||||
mul: BASIC_BINARY_OP,
|
||||
sub: BASIC_BINARY_OP,
|
||||
div: BASIC_BINARY_OP,
|
||||
sdiv: BASIC_BINARY_OP,
|
||||
mod_: BASIC_BINARY_OP,
|
||||
smod: BASIC_BINARY_OP,
|
||||
addmod: BASIC_TERNARY_OP,
|
||||
mulmod: BASIC_TERNARY_OP,
|
||||
exp: None, // TODO
|
||||
signextend: BASIC_BINARY_OP,
|
||||
lt: BASIC_BINARY_OP,
|
||||
gt: BASIC_BINARY_OP,
|
||||
slt: BASIC_BINARY_OP,
|
||||
sgt: BASIC_BINARY_OP,
|
||||
eq: BASIC_BINARY_OP,
|
||||
iszero: BASIC_UNARY_OP,
|
||||
and: BASIC_BINARY_OP,
|
||||
or: BASIC_BINARY_OP,
|
||||
xor: BASIC_BINARY_OP,
|
||||
not: BASIC_TERNARY_OP,
|
||||
byte: BASIC_BINARY_OP,
|
||||
shl: BASIC_BINARY_OP,
|
||||
shr: BASIC_BINARY_OP,
|
||||
sar: BASIC_BINARY_OP,
|
||||
keccak256: None, // TODO
|
||||
address: None, // TODO
|
||||
balance: None, // TODO
|
||||
origin: None, // TODO
|
||||
caller: None, // TODO
|
||||
callvalue: None, // TODO
|
||||
calldataload: None, // TODO
|
||||
calldatasize: None, // TODO
|
||||
calldatacopy: None, // TODO
|
||||
codesize: None, // TODO
|
||||
codecopy: None, // TODO
|
||||
gasprice: None, // TODO
|
||||
extcodesize: None, // TODO
|
||||
extcodecopy: None, // TODO
|
||||
returndatasize: None, // TODO
|
||||
returndatacopy: None, // TODO
|
||||
extcodehash: None, // TODO
|
||||
blockhash: None, // TODO
|
||||
coinbase: None, // TODO
|
||||
timestamp: None, // TODO
|
||||
number: None, // TODO
|
||||
difficulty: None, // TODO
|
||||
gaslimit: None, // TODO
|
||||
chainid: None, // TODO
|
||||
selfbalance: None, // TODO
|
||||
basefee: None, // TODO
|
||||
prover_input: None, // TODO
|
||||
pop: None, // TODO
|
||||
mload: None, // TODO
|
||||
mstore: None, // TODO
|
||||
mstore8: None, // TODO
|
||||
sload: None, // TODO
|
||||
sstore: None, // TODO
|
||||
jump: None, // TODO
|
||||
jumpi: None, // TODO
|
||||
pc: None, // TODO
|
||||
msize: None, // TODO
|
||||
gas: None, // TODO
|
||||
jumpdest: None, // TODO
|
||||
get_state_root: None, // TODO
|
||||
set_state_root: None, // TODO
|
||||
get_receipt_root: None, // TODO
|
||||
set_receipt_root: None, // TODO
|
||||
push: None, // TODO
|
||||
dup: None, // TODO
|
||||
swap: None, // TODO
|
||||
log0: None, // TODO
|
||||
log1: None, // TODO
|
||||
log2: None, // TODO
|
||||
log3: None, // TODO
|
||||
log4: None, // TODO
|
||||
create: None, // TODO
|
||||
call: None, // TODO
|
||||
callcode: None, // TODO
|
||||
return_: None, // TODO
|
||||
delegatecall: None, // TODO
|
||||
create2: None, // TODO
|
||||
get_context: None, // TODO
|
||||
set_context: None, // TODO
|
||||
consume_gas: None, // TODO
|
||||
exit_kernel: None, // TODO
|
||||
staticcall: None, // TODO
|
||||
mload_general: None, // TODO
|
||||
mstore_general: None, // TODO
|
||||
revert: None, // TODO
|
||||
selfdestruct: None, // TODO
|
||||
invalid: None, // TODO
|
||||
};
|
||||
|
||||
fn eval_packed_one<P: PackedField>(
|
||||
lv: &CpuColumnsView<P>,
|
||||
filter: P,
|
||||
stack_behavior: StackBehavior,
|
||||
yield_constr: &mut ConstraintConsumer<P>,
|
||||
) {
|
||||
let num_operands = stack_behavior.num_pops + (stack_behavior.pushes as usize);
|
||||
assert!(num_operands <= NUM_GP_CHANNELS);
|
||||
|
||||
// Pops
|
||||
for i in 0..stack_behavior.num_pops {
|
||||
let channel = lv.mem_channels[i];
|
||||
|
||||
yield_constr.constraint(filter * (channel.used - P::ONES));
|
||||
yield_constr.constraint(filter * (channel.is_read - P::ONES));
|
||||
|
||||
yield_constr.constraint(filter * (channel.addr_context - lv.context));
|
||||
yield_constr.constraint(
|
||||
filter * (channel.addr_segment - P::Scalar::from_canonical_u64(Segment::Stack as u64)),
|
||||
);
|
||||
// E.g. if `stack_len == 1` and `i == 0`, we want `add_virtual == 0`.
|
||||
let addr_virtual = lv.stack_len - P::Scalar::from_canonical_usize(i + 1);
|
||||
yield_constr.constraint(filter * (channel.addr_virtual - addr_virtual));
|
||||
}
|
||||
|
||||
// Pushes
|
||||
if stack_behavior.pushes {
|
||||
let channel = lv.mem_channels[NUM_GP_CHANNELS - 1];
|
||||
|
||||
yield_constr.constraint(filter * (channel.used - P::ONES));
|
||||
yield_constr.constraint(filter * channel.is_read);
|
||||
|
||||
yield_constr.constraint(filter * (channel.addr_context - lv.context));
|
||||
yield_constr.constraint(
|
||||
filter * (channel.addr_segment - P::Scalar::from_canonical_u64(Segment::Stack as u64)),
|
||||
);
|
||||
let addr_virtual = lv.stack_len - P::Scalar::from_canonical_usize(stack_behavior.num_pops);
|
||||
yield_constr.constraint(filter * (channel.addr_virtual - addr_virtual));
|
||||
}
|
||||
|
||||
// Unused channels
|
||||
if stack_behavior.disable_other_channels {
|
||||
for i in stack_behavior.num_pops..NUM_GP_CHANNELS - (stack_behavior.pushes as usize) {
|
||||
let channel = lv.mem_channels[i];
|
||||
yield_constr.constraint(filter * channel.used);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_packed<P: PackedField>(
|
||||
lv: &CpuColumnsView<P>,
|
||||
yield_constr: &mut ConstraintConsumer<P>,
|
||||
) {
|
||||
for (op, stack_behavior) in izip!(lv.op.into_iter(), STACK_BEHAVIORS.into_iter()) {
|
||||
if let Some(stack_behavior) = stack_behavior {
|
||||
let filter = lv.is_cpu_cycle * op;
|
||||
eval_packed_one(lv, filter, stack_behavior, yield_constr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_ext_circuit_one<F: RichField + Extendable<D>, const D: usize>(
|
||||
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
|
||||
lv: &CpuColumnsView<ExtensionTarget<D>>,
|
||||
filter: ExtensionTarget<D>,
|
||||
stack_behavior: StackBehavior,
|
||||
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
||||
) {
|
||||
let num_operands = stack_behavior.num_pops + (stack_behavior.pushes as usize);
|
||||
assert!(num_operands <= NUM_GP_CHANNELS);
|
||||
|
||||
// Pops
|
||||
for i in 0..stack_behavior.num_pops {
|
||||
let channel = lv.mem_channels[i];
|
||||
|
||||
{
|
||||
let constr = builder.mul_sub_extension(filter, channel.used, filter);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
{
|
||||
let constr = builder.mul_sub_extension(filter, channel.is_read, filter);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
|
||||
{
|
||||
let diff = builder.sub_extension(channel.addr_context, lv.context);
|
||||
let constr = builder.mul_extension(filter, diff);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
{
|
||||
let constr = builder.arithmetic_extension(
|
||||
F::ONE,
|
||||
-F::from_canonical_u64(Segment::Stack as u64),
|
||||
filter,
|
||||
channel.addr_segment,
|
||||
filter,
|
||||
);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
{
|
||||
let diff = builder.sub_extension(channel.addr_virtual, lv.stack_len);
|
||||
let constr = builder.arithmetic_extension(
|
||||
F::ONE,
|
||||
F::from_canonical_usize(i + 1),
|
||||
filter,
|
||||
diff,
|
||||
filter,
|
||||
);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
}
|
||||
|
||||
// Pushes
|
||||
if stack_behavior.pushes {
|
||||
let channel = lv.mem_channels[NUM_GP_CHANNELS - 1];
|
||||
|
||||
{
|
||||
let constr = builder.mul_sub_extension(filter, channel.used, filter);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
{
|
||||
let constr = builder.mul_extension(filter, channel.is_read);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
|
||||
{
|
||||
let diff = builder.sub_extension(channel.addr_context, lv.context);
|
||||
let constr = builder.mul_extension(filter, diff);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
{
|
||||
let constr = builder.arithmetic_extension(
|
||||
F::ONE,
|
||||
-F::from_canonical_u64(Segment::Stack as u64),
|
||||
filter,
|
||||
channel.addr_segment,
|
||||
filter,
|
||||
);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
{
|
||||
let diff = builder.sub_extension(channel.addr_virtual, lv.stack_len);
|
||||
let constr = builder.arithmetic_extension(
|
||||
F::ONE,
|
||||
F::from_canonical_usize(stack_behavior.num_pops),
|
||||
filter,
|
||||
diff,
|
||||
filter,
|
||||
);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
}
|
||||
|
||||
// Unused channels
|
||||
if stack_behavior.disable_other_channels {
|
||||
for i in stack_behavior.num_pops..NUM_GP_CHANNELS - (stack_behavior.pushes as usize) {
|
||||
let channel = lv.mem_channels[i];
|
||||
let constr = builder.mul_extension(filter, channel.used);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
|
||||
lv: &CpuColumnsView<ExtensionTarget<D>>,
|
||||
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
||||
) {
|
||||
for (op, stack_behavior) in izip!(lv.op.into_iter(), STACK_BEHAVIORS.into_iter()) {
|
||||
if let Some(stack_behavior) = stack_behavior {
|
||||
let filter = builder.mul_extension(lv.is_cpu_cycle, op);
|
||||
eval_ext_circuit_one(builder, lv, filter, stack_behavior, yield_constr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -26,13 +26,13 @@ const MAX_USER_STACK_SIZE: u64 = 1024;
|
||||
// Other operations that have a minimum stack size (e.g. `MULMOD`, which has three inputs) read
|
||||
// all their inputs from memory. On underflow, the cross-table lookup fails, as -1, ..., -17 are
|
||||
// invalid memory addresses.
|
||||
const DECREMENTING_FLAGS: [usize; 1] = [COL_MAP.is_pop];
|
||||
const DECREMENTING_FLAGS: [usize; 1] = [COL_MAP.op.pop];
|
||||
|
||||
// Operations that increase the stack length by 1, but excluding:
|
||||
// - privileged (kernel-only) operations (superfluous; doesn't affect correctness),
|
||||
// - operations that from userspace to the kernel (required for correctness).
|
||||
// TODO: This list is incomplete.
|
||||
const INCREMENTING_FLAGS: [usize; 2] = [COL_MAP.is_pc, COL_MAP.is_dup];
|
||||
const INCREMENTING_FLAGS: [usize; 2] = [COL_MAP.op.pc, COL_MAP.op.dup];
|
||||
|
||||
/// Calculates `lv.stack_len_bounds_aux`. Note that this must be run after decode.
|
||||
pub fn generate<F: Field>(lv: &mut CpuColumnsView<F>) {
|
||||
|
||||
@ -18,9 +18,9 @@ const NUM_SYSCALLS: usize = 3;
|
||||
fn make_syscall_list() -> [(usize, usize); NUM_SYSCALLS] {
|
||||
let kernel = Lazy::force(&KERNEL);
|
||||
[
|
||||
(COL_MAP.is_stop, "sys_stop"),
|
||||
(COL_MAP.is_exp, "sys_exp"),
|
||||
(COL_MAP.is_invalid, "handle_invalid"),
|
||||
(COL_MAP.op.stop, "sys_stop"),
|
||||
(COL_MAP.op.exp, "sys_exp"),
|
||||
(COL_MAP.op.invalid, "handle_invalid"),
|
||||
]
|
||||
.map(|(col_index, handler_name)| (col_index, kernel.global_labels[handler_name]))
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user