diff --git a/evm/src/cpu/columns/ops.rs b/evm/src/cpu/columns/ops.rs index 8b449f40..ecc5e83a 100644 --- a/evm/src/cpu/columns/ops.rs +++ b/evm/src/cpu/columns/ops.rs @@ -22,11 +22,9 @@ pub struct OpsColumnsView { pub submod: T, pub lt: T, pub gt: 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. - // TODO: combine AND/OR, and XOR into one flag - pub and_or: T, - pub xor: 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 logic_op: T, // Combines AND, OR and XOR flags. pub not: T, pub byte: T, // TODO: combine SHL and SHR into one flag diff --git a/evm/src/cpu/control_flow.rs b/evm/src/cpu/control_flow.rs index abbaa7ce..eec2378b 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; 31] = [ +const NATIVE_INSTRUCTIONS: [usize; 30] = [ COL_MAP.op.add, COL_MAP.op.mul, COL_MAP.op.sub, @@ -23,8 +23,7 @@ const NATIVE_INSTRUCTIONS: [usize; 31] = [ COL_MAP.op.gt, COL_MAP.op.eq, COL_MAP.op.iszero, - COL_MAP.op.and_or, - COL_MAP.op.xor, + COL_MAP.op.logic_op, COL_MAP.op.not, COL_MAP.op.shl, COL_MAP.op.shr, diff --git a/evm/src/cpu/cpu_stark.rs b/evm/src/cpu/cpu_stark.rs index d54cf625..19cca992 100644 --- a/evm/src/cpu/cpu_stark.rs +++ b/evm/src/cpu/cpu_stark.rs @@ -89,7 +89,7 @@ pub fn ctl_data_logic() -> Vec> { } pub fn ctl_filter_logic() -> Column { - Column::sum([COL_MAP.op.and_or, COL_MAP.op.xor]) + Column::single(COL_MAP.op.logic_op) } pub fn ctl_arithmetic_base_rows() -> TableWithColumns { diff --git a/evm/src/cpu/decode.rs b/evm/src/cpu/decode.rs index 36a5eca4..e8d595b3 100644 --- a/evm/src/cpu/decode.rs +++ b/evm/src/cpu/decode.rs @@ -22,7 +22,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); 36] = [ +const OPCODES: [(u8, usize, bool, usize); 34] = [ // (start index of block, number of top bits to check (log2), kernel-only, flag column) (0x01, 0, false, COL_MAP.op.add), (0x02, 0, false, COL_MAP.op.mul), @@ -38,8 +38,7 @@ const OPCODES: [(u8, usize, bool, usize); 36] = [ (0x11, 0, false, COL_MAP.op.gt), (0x14, 0, false, COL_MAP.op.eq), (0x15, 0, false, COL_MAP.op.iszero), - (0x16, 1, false, COL_MAP.op.and_or), - (0x18, 0, false, COL_MAP.op.xor), + // AND, OR and XOR flags are handled directly on the logic table side (0x19, 0, false, COL_MAP.op.not), (0x1a, 0, false, COL_MAP.op.byte), (0x1b, 0, false, COL_MAP.op.shl), @@ -143,11 +142,21 @@ pub fn eval_packed_generic( let flag = lv[flag_col]; yield_constr.constraint(cycle_filter * flag * (flag - P::ONES)); } + // Manually check for the logic_op flag combining AND, OR and XOR. + // TODO: This would go away once cycle_filter is replaced by the sum + // of all CPU opcode flags. + let flag = lv.op.logic_op; + yield_constr.constraint(cycle_filter * flag * (flag - P::ONES)); + // Now check that they sum to 0 or 1. + // Include the logic_op flag encompassing AND, OR and XOR opcodes. + // TODO: This would go away once cycle_filter is replaced by the sum + // of all CPU opcode flags. let flag_sum: P = OPCODES .into_iter() .map(|(_, _, _, flag_col)| lv[flag_col]) - .sum::

(); + .sum::

() + + lv.op.logic_op; yield_constr.constraint(cycle_filter * flag_sum * (flag_sum - P::ONES)); // Finally, classify all opcodes, together with the kernel flag, into blocks @@ -211,9 +220,20 @@ pub fn eval_ext_circuit, const D: usize>( let constr = builder.mul_extension(cycle_filter, constr); yield_constr.constraint(builder, constr); } + // Manually check for the logic_op flag combining AND, OR and XOR. + // TODO: This would go away once cycle_filter is replaced by the sum + // of all CPU opcode flags. + let flag = lv.op.logic_op; + let constr = builder.mul_sub_extension(flag, flag, flag); + let constr = builder.mul_extension(cycle_filter, constr); + yield_constr.constraint(builder, constr); + // Now check that they sum to 0 or 1. + // Include the logic_op flag encompassing AND, OR and XOR opcodes. + // TODO: This would go away once cycle_filter is replaced by the sum + // of all CPU opcode flags. { - let mut flag_sum = builder.zero_extension(); + let mut flag_sum = lv.op.logic_op; for (_, _, _, flag_col) in OPCODES { let flag = lv[flag_col]; flag_sum = builder.add_extension(flag_sum, flag); diff --git a/evm/src/cpu/gas.rs b/evm/src/cpu/gas.rs index 6da9cc84..a7235137 100644 --- a/evm/src/cpu/gas.rs +++ b/evm/src/cpu/gas.rs @@ -33,8 +33,7 @@ const SIMPLE_OPCODES: OpsColumnsView> = OpsColumnsView { gt: G_VERYLOW, eq: G_VERYLOW, iszero: G_VERYLOW, - and_or: G_VERYLOW, - xor: G_VERYLOW, + logic_op: G_VERYLOW, not: G_VERYLOW, byte: G_VERYLOW, shl: G_VERYLOW, diff --git a/evm/src/cpu/stack.rs b/evm/src/cpu/stack.rs index f6bd9892..ef290d0a 100644 --- a/evm/src/cpu/stack.rs +++ b/evm/src/cpu/stack.rs @@ -55,8 +55,7 @@ const STACK_BEHAVIORS: OpsColumnsView> = OpsColumnsView { gt: BASIC_BINARY_OP, eq: BASIC_BINARY_OP, iszero: BASIC_UNARY_OP, - and_or: BASIC_BINARY_OP, - xor: BASIC_BINARY_OP, + logic_op: BASIC_BINARY_OP, not: BASIC_UNARY_OP, byte: BASIC_BINARY_OP, shl: Some(StackBehavior { diff --git a/evm/src/logic.rs b/evm/src/logic.rs index 3695503b..3529ed9a 100644 --- a/evm/src/logic.rs +++ b/evm/src/logic.rs @@ -52,6 +52,10 @@ pub(crate) mod columns { } pub fn ctl_data() -> Vec> { + // We scale each filter flag with the associated opcode value. + // If a logic operation is happening on the CPU side, the CTL + // will enforce that the reconstructed opcode value from the + // opcode bits matches. let mut res = vec![Column::linear_combination([ (columns::IS_AND, F::from_canonical_u8(0x16)), (columns::IS_OR, F::from_canonical_u8(0x17)), diff --git a/evm/src/witness/transition.rs b/evm/src/witness/transition.rs index dcac4e71..b8929114 100644 --- a/evm/src/witness/transition.rs +++ b/evm/src/witness/transition.rs @@ -160,10 +160,7 @@ fn fill_op_flag(op: Operation, row: &mut CpuColumnsView) { Operation::Not => &mut flags.not, Operation::Syscall(_, _, _) => &mut flags.syscall, Operation::Eq => &mut flags.eq, - Operation::BinaryLogic(logic::Op::And) | Operation::BinaryLogic(logic::Op::Or) => { - &mut flags.and_or - } - Operation::BinaryLogic(logic::Op::Xor) => &mut flags.xor, + Operation::BinaryLogic(_) => &mut flags.logic_op, Operation::BinaryArithmetic(arithmetic::BinaryOperator::Add) => &mut flags.add, Operation::BinaryArithmetic(arithmetic::BinaryOperator::Mul) => &mut flags.mul, Operation::BinaryArithmetic(arithmetic::BinaryOperator::Sub) => &mut flags.sub,