From 6332900d86b4372ca1bba702ba80d92fe205868a Mon Sep 17 00:00:00 2001 From: Linda Guiga <101227802+LindaGuiga@users.noreply.github.com> Date: Mon, 30 Oct 2023 15:43:06 -0400 Subject: [PATCH] Combine PUSH0 and PC flags. (#1256) --- evm/src/cpu/columns/ops.rs | 6 ++---- evm/src/cpu/control_flow.rs | 5 ++--- evm/src/cpu/decode.rs | 26 ++++++++++++++++++++++---- evm/src/cpu/gas.rs | 3 +-- evm/src/cpu/pc.rs | 8 ++++++-- evm/src/cpu/push0.rs | 6 ++++-- evm/src/cpu/stack.rs | 7 +------ evm/src/witness/transition.rs | 6 ++---- 8 files changed, 40 insertions(+), 27 deletions(-) diff --git a/evm/src/cpu/columns/ops.rs b/evm/src/cpu/columns/ops.rs index c9039526..3ea33689 100644 --- a/evm/src/cpu/columns/ops.rs +++ b/evm/src/cpu/columns/ops.rs @@ -28,12 +28,8 @@ pub struct OpsColumnsView { pub prover_input: T, /// Combines JUMP and JUMPI flags. pub jumps: T, - /// Flag for PC. - pub pc: T, /// Flag for JUMPDEST. pub jumpdest: T, - /// Flag for PUSH0. - pub push0: T, /// Flag for PUSH. pub push: T, /// Combines DUP and SWAP flags. @@ -48,6 +44,8 @@ pub struct OpsColumnsView { pub exit_kernel: T, /// Combines MSTORE_GENERAL and MLOAD_GENERAL flags. pub m_op_general: T, + /// Combines PC and PUSH0 + pub pc_push0: T, /// Flag for syscalls. pub syscall: T, diff --git a/evm/src/cpu/control_flow.rs b/evm/src/cpu/control_flow.rs index d050aa16..b87a6f62 100644 --- a/evm/src/cpu/control_flow.rs +++ b/evm/src/cpu/control_flow.rs @@ -8,7 +8,7 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer use crate::cpu::columns::{CpuColumnsView, COL_MAP}; use crate::cpu::kernel::aggregator::KERNEL; -const NATIVE_INSTRUCTIONS: [usize; 15] = [ +const NATIVE_INSTRUCTIONS: [usize; 14] = [ COL_MAP.op.binary_op, COL_MAP.op.ternary_op, COL_MAP.op.fp254_op, @@ -19,9 +19,8 @@ const NATIVE_INSTRUCTIONS: [usize; 15] = [ COL_MAP.op.keccak_general, COL_MAP.op.prover_input, // not JUMPS (possible need to jump) - COL_MAP.op.pc, + COL_MAP.op.pc_push0, COL_MAP.op.jumpdest, - COL_MAP.op.push0, // not PUSH (need to increment by more than 1) COL_MAP.op.dup_swap, COL_MAP.op.context_op, diff --git a/evm/src/cpu/decode.rs b/evm/src/cpu/decode.rs index 9a0df4fd..bafa4ec9 100644 --- a/evm/src/cpu/decode.rs +++ b/evm/src/cpu/decode.rs @@ -23,7 +23,7 @@ use crate::cpu::columns::{CpuColumnsView, COL_MAP}; /// behavior. /// Note: invalid opcodes are not represented here. _Any_ opcode is permitted to decode to /// `is_invalid`. The kernel then verifies that the opcode was _actually_ invalid. -const OPCODES: [(u8, usize, bool, usize); 13] = [ +const OPCODES: [(u8, usize, bool, usize); 11] = [ // (start index of block, number of top bits to check (log2), kernel-only, flag column) // ADD, MUL, SUB, DIV, MOD, LT, GT and BYTE flags are handled partly manually here, and partly through the Arithmetic table CTL. // ADDMOD, MULMOD and SUBMOD flags are handled partly manually here, and partly through the Arithmetic table CTL. @@ -35,9 +35,7 @@ const OPCODES: [(u8, usize, bool, usize); 13] = [ (0x21, 0, true, COL_MAP.op.keccak_general), (0x49, 0, true, COL_MAP.op.prover_input), (0x56, 1, false, COL_MAP.op.jumps), // 0x56-0x57 - (0x58, 0, false, COL_MAP.op.pc), (0x5b, 0, false, COL_MAP.op.jumpdest), - (0x5f, 0, false, COL_MAP.op.push0), (0x60, 5, false, COL_MAP.op.push), // 0x60-0x7f (0x80, 5, false, COL_MAP.op.dup_swap), // 0x80-0x9f (0xee, 0, true, COL_MAP.op.mstore_32bytes), @@ -50,7 +48,7 @@ const OPCODES: [(u8, usize, bool, usize); 13] = [ /// List of combined opcodes requiring a special handling. /// Each index in the list corresponds to an arbitrary combination /// of opcodes defined in evm/src/cpu/columns/ops.rs. -const COMBINED_OPCODES: [usize; 7] = [ +const COMBINED_OPCODES: [usize; 8] = [ COL_MAP.op.logic_op, COL_MAP.op.fp254_op, COL_MAP.op.binary_op, @@ -58,6 +56,7 @@ const COMBINED_OPCODES: [usize; 7] = [ COL_MAP.op.shift, COL_MAP.op.m_op_general, COL_MAP.op.not_pop, + COL_MAP.op.pc_push0, ]; /// Break up an opcode (which is 8 bits long) into its eight bits. @@ -148,6 +147,14 @@ pub fn eval_packed_generic( * lv.op.m_op_general; yield_constr.constraint(m_op_constr); + // Manually check lv.op.pc_push0. + // Both PC and PUSH0 can be called outside of the kernel mode: + // there is no need to constrain them in that regard. + let pc_push0_constr = (opcode - P::Scalar::from_canonical_usize(0x58_usize)) + * (opcode - P::Scalar::from_canonical_usize(0x5f_usize)) + * lv.op.pc_push0; + yield_constr.constraint(pc_push0_constr); + // Manually check lv.op.not_pop. // Both NOT and POP can be called outside of the kernel mode: // there is no need to constrain them in that regard. @@ -260,6 +267,17 @@ pub fn eval_ext_circuit, const D: usize>( yield_constr.constraint(builder, m_op_constr); + // Manually check lv.op.pc_push0. + // Both PC and PUSH0 can be called outside of the kernel mode: + // there is no need to constrain them in that regard. + let pc_opcode = builder.constant_extension(F::Extension::from_canonical_usize(0x58_usize)); + let push0_opcode = builder.constant_extension(F::Extension::from_canonical_usize(0x5f_usize)); + let pc_constr = builder.sub_extension(opcode, pc_opcode); + let push0_constr = builder.sub_extension(opcode, push0_opcode); + let mut pc_push0_constr = builder.mul_extension(pc_constr, push0_constr); + pc_push0_constr = builder.mul_extension(pc_push0_constr, lv.op.pc_push0); + yield_constr.constraint(builder, pc_push0_constr); + // Manually check lv.op.not_pop. // Both NOT and POP can be called outside of the kernel mode: // there is no need to constrain them in that regard. diff --git a/evm/src/cpu/gas.rs b/evm/src/cpu/gas.rs index f7ba330d..6abcc786 100644 --- a/evm/src/cpu/gas.rs +++ b/evm/src/cpu/gas.rs @@ -29,9 +29,8 @@ const SIMPLE_OPCODES: OpsColumnsView> = OpsColumnsView { keccak_general: KERNEL_ONLY_INSTR, prover_input: KERNEL_ONLY_INSTR, jumps: None, // Combined flag handled separately. - pc: G_BASE, + pc_push0: G_BASE, jumpdest: G_JUMPDEST, - push0: G_BASE, push: G_VERYLOW, dup_swap: G_VERYLOW, context_op: KERNEL_ONLY_INSTR, diff --git a/evm/src/cpu/pc.rs b/evm/src/cpu/pc.rs index 6641aea0..16915a53 100644 --- a/evm/src/cpu/pc.rs +++ b/evm/src/cpu/pc.rs @@ -12,7 +12,8 @@ pub fn eval_packed( nv: &CpuColumnsView

, yield_constr: &mut ConstraintConsumer

, ) { - let filter = lv.op.pc; + // `PUSH0`'s opcode is odd, while `PC`'s opcode is even. + let filter = lv.op.pc_push0 * (P::ONES - lv.opcode_bits[0]); let new_stack_top = nv.mem_channels[0].value; yield_constr.constraint(filter * (new_stack_top[0] - lv.program_counter)); for &limb in &new_stack_top[1..] { @@ -28,7 +29,10 @@ pub fn eval_ext_circuit, const D: usize>( nv: &CpuColumnsView>, yield_constr: &mut RecursiveConstraintConsumer, ) { - let filter = lv.op.pc; + // `PUSH0`'s opcode is odd, while `PC`'s opcode is even. + let one = builder.one_extension(); + let mut filter = builder.sub_extension(one, lv.opcode_bits[0]); + filter = builder.mul_extension(lv.op.pc_push0, filter); let new_stack_top = nv.mem_channels[0].value; { let diff = builder.sub_extension(new_stack_top[0], lv.program_counter); diff --git a/evm/src/cpu/push0.rs b/evm/src/cpu/push0.rs index c8c58fef..e48e77f3 100644 --- a/evm/src/cpu/push0.rs +++ b/evm/src/cpu/push0.rs @@ -12,7 +12,8 @@ pub fn eval_packed( nv: &CpuColumnsView

, yield_constr: &mut ConstraintConsumer

, ) { - let filter = lv.op.push0; + // `PUSH0`'s opcode is odd, while `PC`'s opcode is even. + let filter = lv.op.pc_push0 * lv.opcode_bits[0]; for limb in nv.mem_channels[0].value { yield_constr.constraint(filter * limb); } @@ -26,7 +27,8 @@ pub fn eval_ext_circuit, const D: usize>( nv: &CpuColumnsView>, yield_constr: &mut RecursiveConstraintConsumer, ) { - let filter = lv.op.push0; + // `PUSH0`'s opcode is odd, while `PC`'s opcode is even. + let filter = builder.mul_extension(lv.op.pc_push0, lv.opcode_bits[0]); for limb in nv.mem_channels[0].value { let constr = builder.mul_extension(filter, limb); yield_constr.constraint(builder, constr); diff --git a/evm/src/cpu/stack.rs b/evm/src/cpu/stack.rs index 7057d20f..f24504f4 100644 --- a/evm/src/cpu/stack.rs +++ b/evm/src/cpu/stack.rs @@ -85,7 +85,7 @@ pub(crate) const STACK_BEHAVIORS: OpsColumnsView> = OpsCol }), prover_input: None, // TODO jumps: None, // Depends on whether it's a JUMP or a JUMPI. - pc: Some(StackBehavior { + pc_push0: Some(StackBehavior { num_pops: 0, pushes: true, disable_other_channels: true, @@ -95,11 +95,6 @@ pub(crate) const STACK_BEHAVIORS: OpsColumnsView> = OpsCol pushes: false, disable_other_channels: true, }), - push0: Some(StackBehavior { - num_pops: 0, - pushes: true, - disable_other_channels: true, - }), push: None, // TODO dup_swap: None, context_op: None, diff --git a/evm/src/witness/transition.rs b/evm/src/witness/transition.rs index cc2a7672..ac95ffae 100644 --- a/evm/src/witness/transition.rs +++ b/evm/src/witness/transition.rs @@ -160,7 +160,6 @@ fn decode(registers: RegistersState, opcode: u8) -> Result(op: Operation, row: &mut CpuColumnsView) { let flags = &mut row.op; *match op { - Operation::Push(0) => &mut flags.push0, Operation::Push(1..) => &mut flags.push, Operation::Dup(_) | Operation::Swap(_) => &mut flags.dup_swap, Operation::Iszero | Operation::Eq => &mut flags.eq_iszero, @@ -177,7 +176,7 @@ fn fill_op_flag(op: Operation, row: &mut CpuColumnsView) { Operation::KeccakGeneral => &mut flags.keccak_general, Operation::ProverInput => &mut flags.prover_input, Operation::Jump | Operation::Jumpi => &mut flags.jumps, - Operation::Pc => &mut flags.pc, + Operation::Pc | Operation::Push(0) => &mut flags.pc_push0, Operation::Jumpdest => &mut flags.jumpdest, Operation::GetContext | Operation::SetContext => &mut flags.context_op, Operation::Mload32Bytes => &mut flags.mload_32bytes, @@ -190,7 +189,7 @@ fn fill_op_flag(op: Operation, row: &mut CpuColumnsView) { // Equal to the number of pops if an operation pops without pushing, and `None` otherwise. fn get_op_special_length(op: Operation) -> Option { let behavior_opt = match op { - Operation::Push(0) => STACK_BEHAVIORS.push0, + Operation::Push(0) | Operation::Pc => STACK_BEHAVIORS.pc_push0, Operation::Push(1..) => STACK_BEHAVIORS.push, Operation::Dup(_) | Operation::Swap(_) => STACK_BEHAVIORS.dup_swap, Operation::Iszero => IS_ZERO_STACK_BEHAVIOR, @@ -211,7 +210,6 @@ fn get_op_special_length(op: Operation) -> Option { Operation::ProverInput => STACK_BEHAVIORS.prover_input, Operation::Jump => JUMP_OP, Operation::Jumpi => JUMPI_OP, - Operation::Pc => STACK_BEHAVIORS.pc, Operation::Jumpdest => STACK_BEHAVIORS.jumpdest, Operation::GetContext | Operation::SetContext => None, Operation::Mload32Bytes => STACK_BEHAVIORS.mload_32bytes,