From bc05666f9e194d2d91b09ee2f2e8d4319a732717 Mon Sep 17 00:00:00 2001 From: Linda Guiga Date: Tue, 26 Sep 2023 17:30:00 -0400 Subject: [PATCH 1/5] Merge NOT and POP flags --- evm/src/cpu/columns/ops.rs | 5 ++--- evm/src/cpu/control_flow.rs | 5 ++--- evm/src/cpu/decode.rs | 34 +++++++++++++++++++++++++++++---- evm/src/cpu/gas.rs | 24 +++++++++++++++++++++-- evm/src/cpu/simple_logic/mod.rs | 4 ++-- evm/src/cpu/simple_logic/not.rs | 20 +++++++++++++++++-- evm/src/cpu/stack.rs | 28 +++++++++++++++++++-------- evm/src/witness/transition.rs | 3 +-- 8 files changed, 97 insertions(+), 26 deletions(-) diff --git a/evm/src/cpu/columns/ops.rs b/evm/src/cpu/columns/ops.rs index d4d753f7cf..ca6348959f 100644 --- a/evm/src/cpu/columns/ops.rs +++ b/evm/src/cpu/columns/ops.rs @@ -12,11 +12,10 @@ pub struct OpsColumnsView { pub fp254_op: T, // Combines ADD_FP254, MUL_FP254 and SUB_FP254 flags. pub eq_iszero: T, // Combines EQ and ISZERO flags. pub logic_op: T, // Combines AND, OR and XOR flags. - pub not: T, - pub shift: T, // Combines SHL and SHR flags. + pub not_pop: T, // Combines NOT and POP flags. + pub shift: T, // Combines SHL and SHR flags. pub keccak_general: T, pub prover_input: T, - pub pop: T, pub jumps: T, // Combines JUMP and JUMPI flags. pub pc: T, pub jumpdest: T, diff --git a/evm/src/cpu/control_flow.rs b/evm/src/cpu/control_flow.rs index 9c17367aa2..7e04594b3c 100644 --- a/evm/src/cpu/control_flow.rs +++ b/evm/src/cpu/control_flow.rs @@ -8,17 +8,16 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer use crate::cpu::columns::{CpuColumnsView, COL_MAP}; use crate::cpu::kernel::aggregator::KERNEL; -const NATIVE_INSTRUCTIONS: [usize; 17] = [ +const NATIVE_INSTRUCTIONS: [usize; 16] = [ COL_MAP.op.binary_op, COL_MAP.op.ternary_op, COL_MAP.op.fp254_op, COL_MAP.op.eq_iszero, COL_MAP.op.logic_op, - COL_MAP.op.not, + COL_MAP.op.not_pop, COL_MAP.op.shift, COL_MAP.op.keccak_general, COL_MAP.op.prover_input, - COL_MAP.op.pop, // not JUMP (need to jump) // not JUMPI (possible need to jump) COL_MAP.op.pc, diff --git a/evm/src/cpu/decode.rs b/evm/src/cpu/decode.rs index c1c43a0bb1..a449bd7def 100644 --- a/evm/src/cpu/decode.rs +++ b/evm/src/cpu/decode.rs @@ -23,18 +23,17 @@ 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); 16] = [ +const OPCODES: [(u8, usize, bool, usize); 14] = [ // (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. // FP254 operation flags are handled partly manually here, and partly through the Arithmetic table CTL. (0x14, 1, false, COL_MAP.op.eq_iszero), // AND, OR and XOR flags are handled partly manually here, and partly through the Logic table CTL. - (0x19, 0, false, COL_MAP.op.not), + // NOT and POP are handled manually here. // SHL and SHR flags are handled partly manually here, and partly through the Logic table CTL. (0x21, 0, true, COL_MAP.op.keccak_general), (0x49, 0, true, COL_MAP.op.prover_input), - (0x50, 0, false, COL_MAP.op.pop), (0x56, 1, false, COL_MAP.op.jumps), // 0x56-0x57 (0x58, 0, false, COL_MAP.op.pc), (0x5b, 0, false, COL_MAP.op.jumpdest), @@ -52,13 +51,14 @@ const OPCODES: [(u8, usize, bool, usize); 16] = [ /// 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; 6] = [ +const COMBINED_OPCODES: [usize; 7] = [ COL_MAP.op.logic_op, COL_MAP.op.fp254_op, COL_MAP.op.binary_op, COL_MAP.op.ternary_op, COL_MAP.op.shift, COL_MAP.op.m_op_general, + COL_MAP.op.not_pop, ]; pub fn generate(lv: &mut CpuColumnsView) { @@ -104,6 +104,11 @@ pub fn generate(lv: &mut CpuColumnsView) { if opcode == 0xfb || opcode == 0xfc { lv.op.m_op_general = F::from_bool(kernel); } + + // NOT and POP are not kernel-only instructions. + if opcode == 0x50 || opcode == 0x19 { + lv.op.not_pop = F::ONE; + } } /// Break up an opcode (which is 8 bits long) into its eight bits. @@ -192,6 +197,14 @@ pub fn eval_packed_generic( * (opcode - P::Scalar::from_canonical_usize(0xfc_usize)) * lv.op.m_op_general; yield_constr.constraint(m_op_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. + let not_pop_op = (opcode - P::Scalar::from_canonical_usize(0x19_usize)) + * (opcode - P::Scalar::from_canonical_usize(0x50_usize)) + * lv.op.not_pop; + yield_constr.constraint(not_pop_op); } pub fn eval_ext_circuit, const D: usize>( @@ -294,4 +307,17 @@ pub fn eval_ext_circuit, const D: usize>( m_op_constr = builder.mul_extension(m_op_constr, lv.op.m_op_general); yield_constr.constraint(builder, m_op_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. + let not_opcode = builder.constant_extension(F::Extension::from_canonical_usize(0x19_usize)); + let pop_opcode = builder.constant_extension(F::Extension::from_canonical_usize(0x50_usize)); + + let not_constr = builder.sub_extension(opcode, not_opcode); + let pop_constr = builder.sub_extension(opcode, pop_opcode); + + let mut not_pop_constr = builder.mul_extension(not_constr, pop_constr); + not_pop_constr = builder.mul_extension(lv.op.not_pop, not_pop_constr); + yield_constr.constraint(builder, not_pop_constr); } diff --git a/evm/src/cpu/gas.rs b/evm/src/cpu/gas.rs index 51f375c056..c72c824f06 100644 --- a/evm/src/cpu/gas.rs +++ b/evm/src/cpu/gas.rs @@ -24,11 +24,10 @@ const SIMPLE_OPCODES: OpsColumnsView> = OpsColumnsView { fp254_op: KERNEL_ONLY_INSTR, eq_iszero: G_VERYLOW, logic_op: G_VERYLOW, - not: G_VERYLOW, + not_pop: None, // This is handled manually below //G_VERYLOW pop: g_base, shift: G_VERYLOW, keccak_general: KERNEL_ONLY_INSTR, prover_input: KERNEL_ONLY_INSTR, - pop: G_BASE, jumps: None, // Combined flag handled separately. pc: G_BASE, jumpdest: G_JUMPDEST, @@ -99,6 +98,13 @@ fn eval_packed_accumulate( let ternary_op_cost = P::Scalar::from_canonical_u32(G_MID.unwrap()) - lv.opcode_bits[1] * P::Scalar::from_canonical_u32(G_MID.unwrap()); yield_constr.constraint_transition(lv.op.ternary_op * (nv.gas - lv.gas - ternary_op_cost)); + + // For NOT and POP. + // NOT is differentiated from POP by its first bit set to 1. + let not_pop_cost = (P::ONES - lv.opcode_bits[0]) + * P::Scalar::from_canonical_u32(G_BASE.unwrap()) + + lv.opcode_bits[0] * P::Scalar::from_canonical_u32(G_VERYLOW.unwrap()); + yield_constr.constraint_transition(lv.op.not_pop * (nv.gas - lv.gas - not_pop_cost)); } fn eval_packed_init( @@ -223,6 +229,20 @@ fn eval_ext_circuit_accumulate, const D: usize>( let gas_diff = builder.sub_extension(nv_lv_diff, ternary_op_cost); let constr = builder.mul_extension(filter, gas_diff); yield_constr.constraint_transition(builder, constr); + + // For NOT and POP. + // NOT is differentiated from POP by its first bit set to 1. + let filter = lv.op.not_pop; + let one = builder.one_extension(); + let mut not_pop_cost = + builder.mul_const_extension(F::from_canonical_u32(G_VERYLOW.unwrap()), lv.opcode_bits[0]); + let mut pop_cost = builder.sub_extension(one, lv.opcode_bits[0]); + pop_cost = builder.mul_const_extension(F::from_canonical_u32(G_BASE.unwrap()), pop_cost); + not_pop_cost = builder.add_extension(not_pop_cost, pop_cost); + + let not_pop_gas_diff = builder.sub_extension(nv_lv_diff, not_pop_cost); + let not_pop_constr = builder.mul_extension(filter, not_pop_gas_diff); + yield_constr.constraint_transition(builder, not_pop_constr); } fn eval_ext_circuit_init, const D: usize>( diff --git a/evm/src/cpu/simple_logic/mod.rs b/evm/src/cpu/simple_logic/mod.rs index 9b4e60b016..cfedfa51c7 100644 --- a/evm/src/cpu/simple_logic/mod.rs +++ b/evm/src/cpu/simple_logic/mod.rs @@ -14,7 +14,7 @@ pub fn eval_packed( nv: &CpuColumnsView

, yield_constr: &mut ConstraintConsumer

, ) { - not::eval_packed(lv, yield_constr); + not::eval_packed(lv, nv, yield_constr); eq_iszero::eval_packed(lv, nv, yield_constr); } @@ -24,6 +24,6 @@ pub fn eval_ext_circuit, const D: usize>( nv: &CpuColumnsView>, yield_constr: &mut RecursiveConstraintConsumer, ) { - not::eval_ext_circuit(builder, lv, yield_constr); + not::eval_ext_circuit(builder, lv, nv, yield_constr); eq_iszero::eval_ext_circuit(builder, lv, nv, yield_constr); } diff --git a/evm/src/cpu/simple_logic/not.rs b/evm/src/cpu/simple_logic/not.rs index 0bfaa0b71a..a45548638c 100644 --- a/evm/src/cpu/simple_logic/not.rs +++ b/evm/src/cpu/simple_logic/not.rs @@ -7,33 +7,39 @@ use plonky2::iop::ext_target::ExtensionTarget; use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer}; use crate::cpu::columns::CpuColumnsView; use crate::cpu::membus::NUM_GP_CHANNELS; +use crate::cpu::stack; const LIMB_SIZE: usize = 32; const ALL_1_LIMB: u64 = (1 << LIMB_SIZE) - 1; pub fn eval_packed( lv: &CpuColumnsView

, + nv: &CpuColumnsView

, yield_constr: &mut ConstraintConsumer

, ) { // This is simple: just do output = 0xffffffff - input. let input = lv.mem_channels[0].value; let output = lv.mem_channels[NUM_GP_CHANNELS - 1].value; - let filter = lv.op.not; + let filter = lv.op.not_pop * lv.opcode_bits[0]; for (input_limb, output_limb) in input.into_iter().zip(output) { yield_constr.constraint( filter * (output_limb + input_limb - P::Scalar::from_canonical_u64(ALL_1_LIMB)), ); } + + // Stack constraints. + stack::eval_packed_one(lv, nv, filter, stack::BASIC_UNARY_OP.unwrap(), yield_constr); } pub fn eval_ext_circuit, const D: usize>( builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder, lv: &CpuColumnsView>, + nv: &CpuColumnsView>, yield_constr: &mut RecursiveConstraintConsumer, ) { let input = lv.mem_channels[0].value; let output = lv.mem_channels[NUM_GP_CHANNELS - 1].value; - let filter = lv.op.not; + let filter = builder.mul_extension(lv.op.not_pop, lv.opcode_bits[0]); for (input_limb, output_limb) in input.into_iter().zip(output) { let constr = builder.add_extension(output_limb, input_limb); let constr = builder.arithmetic_extension( @@ -45,4 +51,14 @@ pub fn eval_ext_circuit, const D: usize>( ); yield_constr.constraint(builder, constr); } + + // Stack constraints. + stack::eval_ext_circuit_one( + builder, + lv, + nv, + filter, + stack::BASIC_UNARY_OP.unwrap(), + yield_constr, + ); } diff --git a/evm/src/cpu/stack.rs b/evm/src/cpu/stack.rs index 28abf077cb..ae930f78ff 100644 --- a/evm/src/cpu/stack.rs +++ b/evm/src/cpu/stack.rs @@ -18,7 +18,7 @@ pub(crate) struct StackBehavior { disable_other_channels: bool, } -const BASIC_UNARY_OP: Option = Some(StackBehavior { +pub(crate) const BASIC_UNARY_OP: Option = Some(StackBehavior { num_pops: 1, pushes: true, disable_other_channels: true, @@ -33,6 +33,13 @@ const BASIC_TERNARY_OP: Option = Some(StackBehavior { pushes: true, disable_other_channels: true, }); + +const POP_OP: Option = Some(StackBehavior { + num_pops: 1, + pushes: false, + disable_other_channels: true, +}); + pub(crate) const JUMP_OP: Option = Some(StackBehavior { num_pops: 1, pushes: false, @@ -67,7 +74,7 @@ const STACK_BEHAVIORS: OpsColumnsView> = OpsColumnsView { fp254_op: BASIC_BINARY_OP, eq_iszero: None, // EQ is binary, IS_ZERO is unary. logic_op: BASIC_BINARY_OP, - not: BASIC_UNARY_OP, + not_pop: None, shift: Some(StackBehavior { num_pops: 2, pushes: true, @@ -79,12 +86,7 @@ const STACK_BEHAVIORS: OpsColumnsView> = OpsColumnsView { disable_other_channels: true, }), prover_input: None, // TODO - pop: Some(StackBehavior { - num_pops: 1, - pushes: false, - disable_other_channels: true, - }), - jumps: None, // Depends on whether it's a JUMP or a JUMPI. + jumps: None, // Depends on whether it's a JUMP or a JUMPI. pc: Some(StackBehavior { num_pops: 0, pushes: true, @@ -200,6 +202,10 @@ pub fn eval_packed( eval_packed_one(lv, nv, op, stack_behavior, yield_constr); } } + + // Stack constraints for POP. + let filter = lv.op.not_pop * (P::ONES - lv.opcode_bits[0]); + eval_packed_one(lv, nv, filter, POP_OP.unwrap(), yield_constr); } pub(crate) fn eval_ext_circuit_one, const D: usize>( @@ -326,4 +332,10 @@ pub fn eval_ext_circuit, const D: usize>( eval_ext_circuit_one(builder, lv, nv, op, stack_behavior, yield_constr); } } + + // Stack constraints for POP. + let one = builder.one_extension(); + let mut filter = builder.sub_extension(one, lv.opcode_bits[0]); + filter = builder.mul_extension(filter, lv.op.not_pop); + eval_ext_circuit_one(builder, lv, nv, filter, POP_OP.unwrap(), yield_constr); } diff --git a/evm/src/witness/transition.rs b/evm/src/witness/transition.rs index 1418beba8d..effef5a024 100644 --- a/evm/src/witness/transition.rs +++ b/evm/src/witness/transition.rs @@ -159,7 +159,7 @@ fn fill_op_flag(op: Operation, row: &mut CpuColumnsView) { Operation::Dup(_) => &mut flags.dup, Operation::Swap(_) => &mut flags.swap, Operation::Iszero | Operation::Eq => &mut flags.eq_iszero, - Operation::Not => &mut flags.not, + Operation::Not | Operation::Pop => &mut flags.not_pop, Operation::Syscall(_, _, _) => &mut flags.syscall, Operation::BinaryLogic(_) => &mut flags.logic_op, Operation::BinaryArithmetic(arithmetic::BinaryOperator::AddFp254) @@ -171,7 +171,6 @@ fn fill_op_flag(op: Operation, row: &mut CpuColumnsView) { Operation::TernaryArithmetic(_) => &mut flags.ternary_op, Operation::KeccakGeneral => &mut flags.keccak_general, Operation::ProverInput => &mut flags.prover_input, - Operation::Pop => &mut flags.pop, Operation::Jump | Operation::Jumpi => &mut flags.jumps, Operation::Pc => &mut flags.pc, Operation::Jumpdest => &mut flags.jumpdest, From 58fe166ede24a9fc9d666ba028f37bab09e4cf18 Mon Sep 17 00:00:00 2001 From: Linda Guiga Date: Thu, 12 Oct 2023 17:49:02 -0400 Subject: [PATCH 2/5] Add comments --- evm/src/cpu/stack.rs | 6 ++++++ evm/src/witness/operation.rs | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/evm/src/cpu/stack.rs b/evm/src/cpu/stack.rs index 21fab69d0f..6eada35698 100644 --- a/evm/src/cpu/stack.rs +++ b/evm/src/cpu/stack.rs @@ -293,6 +293,9 @@ pub fn eval_packed( } // Stack constraints for POP. + // The only constraints POP has are stack constraints. + // Since POP and NOT are combined into one flag and they have + // different stack behaviors, POP needs special stack constraints. // Constrain `stack_inv_aux`. let len_diff = lv.stack_len - P::Scalar::ONES; yield_constr.constraint( @@ -555,6 +558,9 @@ pub fn eval_ext_circuit, const D: usize>( } // Stack constraints for POP. + // The only constraints POP has are stack constraints. + // Since POP and NOT are combined into one flag and they have + // different stack behaviors, POP needs special stack constraints. // Constrain `stack_inv_aux`. { let len_diff = builder.add_const_extension(lv.stack_len, F::NEG_ONE); diff --git a/evm/src/witness/operation.rs b/evm/src/witness/operation.rs index 2294a6d1bf..fe44825d54 100644 --- a/evm/src/witness/operation.rs +++ b/evm/src/witness/operation.rs @@ -542,7 +542,8 @@ pub(crate) fn generate_not( let result = !x; push_no_write(state, &mut row, result, Some(NUM_GP_CHANNELS - 1)); - // This is necessary for the stack constraints for POP. + // This is necessary for the stack constraints for POP, + // since the two flags are combined. let diff = row.stack_len - F::from_canonical_usize(1); if let Some(inv) = diff.try_inverse() { row.general.stack_mut().stack_inv = inv; From 14beb58dff1ea8c20ee41c9f805e497f5a2c35d7 Mon Sep 17 00:00:00 2001 From: Linda Guiga Date: Thu, 12 Oct 2023 19:20:03 -0400 Subject: [PATCH 3/5] Disable remaining memory channels for POP --- evm/src/cpu/stack.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/evm/src/cpu/stack.rs b/evm/src/cpu/stack.rs index 6eada35698..c7d76f87e0 100644 --- a/evm/src/cpu/stack.rs +++ b/evm/src/cpu/stack.rs @@ -325,6 +325,11 @@ pub fn eval_packed( lv.op.not_pop * (lv.general.stack().stack_inv_aux - P::ONES) * top_read_channel.used, ); yield_constr.constraint(lv.op.not_pop * lv.opcode_bits[0] * top_read_channel.used); + + // Disable remaining memory channels. + for &channel in &lv.mem_channels[1..] { + yield_constr.constraint(lv.op.not_pop * (lv.opcode_bits[0] - P::ONES) * channel.used); + } } pub(crate) fn eval_ext_circuit_one, const D: usize>( @@ -625,4 +630,11 @@ pub fn eval_ext_circuit, const D: usize>( let constr = builder.mul_extension(mul, top_read_channel.used); yield_constr.constraint(builder, constr); } + + // Disable remaining memory channels. + let filter = builder.mul_sub_extension(lv.op.not_pop, lv.opcode_bits[0], lv.op.not_pop); + for &channel in &lv.mem_channels[1..] { + let constr = builder.mul_extension(filter, channel.used); + yield_constr.constraint(builder, constr); + } } From 9d1543e76d1aa4fc6b96527b414f31887b74771a Mon Sep 17 00:00:00 2001 From: Linda Guiga Date: Fri, 27 Oct 2023 09:50:37 -0400 Subject: [PATCH 4/5] Apply comments --- evm/src/cpu/gas.rs | 2 +- evm/src/cpu/stack.rs | 24 +++++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/evm/src/cpu/gas.rs b/evm/src/cpu/gas.rs index 0600fdf5a9..1fa1b49ee9 100644 --- a/evm/src/cpu/gas.rs +++ b/evm/src/cpu/gas.rs @@ -24,7 +24,7 @@ const SIMPLE_OPCODES: OpsColumnsView> = OpsColumnsView { fp254_op: KERNEL_ONLY_INSTR, eq_iszero: G_VERYLOW, logic_op: G_VERYLOW, - not_pop: None, // This is handled manually below //G_VERYLOW pop: g_base, + not_pop: None, // This is handled manually below shift: G_VERYLOW, keccak_general: KERNEL_ONLY_INSTR, prover_input: KERNEL_ONLY_INSTR, diff --git a/evm/src/cpu/stack.rs b/evm/src/cpu/stack.rs index 93327abfac..5ae816e5b5 100644 --- a/evm/src/cpu/stack.rs +++ b/evm/src/cpu/stack.rs @@ -306,7 +306,7 @@ pub fn eval_packed( let top_read_channel = nv.mem_channels[0]; let is_top_read = lv.general.stack().stack_inv_aux * (P::ONES - lv.opcode_bits[0]); - // Constrain `stack_inv_aux_2`. It contains `stack_inv_aux * opcode_bits[0]`. + // Constrain `stack_inv_aux_2`. It contains `stack_inv_aux * (1 - opcode_bits[0])`. yield_constr.constraint(lv.op.not_pop * (lv.general.stack().stack_inv_aux_2 - is_top_read)); let new_filter = lv.op.not_pop * lv.general.stack().stack_inv_aux_2; yield_constr.constraint_transition(new_filter * (top_read_channel.used - P::ONES)); @@ -320,15 +320,20 @@ pub fn eval_packed( let addr_virtual = nv.stack_len - P::ONES; yield_constr.constraint_transition(new_filter * (top_read_channel.addr_virtual - addr_virtual)); // If stack_len == 1 or NOT, disable the channel. + // If NOT or (len==1 and POP), then `stack_inv_aux_2` = 0. yield_constr.constraint( - lv.op.not_pop * (lv.general.stack().stack_inv_aux - P::ONES) * top_read_channel.used, + lv.op.not_pop * (lv.general.stack().stack_inv_aux_2 - P::ONES) * top_read_channel.used, ); - yield_constr.constraint(lv.op.not_pop * lv.opcode_bits[0] * top_read_channel.used); // Disable remaining memory channels. for &channel in &lv.mem_channels[1..] { yield_constr.constraint(lv.op.not_pop * (lv.opcode_bits[0] - P::ONES) * channel.used); } + + // Constrain the new stack length for POP. + yield_constr.constraint_transition( + lv.op.not_pop * (lv.opcode_bits[0] - P::ONES) * (nv.stack_len - lv.stack_len + P::ONES), + ); } pub(crate) fn eval_ext_circuit_one, const D: usize>( @@ -618,17 +623,12 @@ pub fn eval_ext_circuit, const D: usize>( { let diff = builder.mul_sub_extension( lv.op.not_pop, - lv.general.stack().stack_inv_aux, + lv.general.stack().stack_inv_aux_2, lv.op.not_pop, ); let constr = builder.mul_extension(diff, top_read_channel.used); yield_constr.constraint(builder, constr); } - { - let mul = builder.mul_extension(lv.op.not_pop, lv.opcode_bits[0]); - let constr = builder.mul_extension(mul, top_read_channel.used); - yield_constr.constraint(builder, constr); - } // Disable remaining memory channels. let filter = builder.mul_sub_extension(lv.op.not_pop, lv.opcode_bits[0], lv.op.not_pop); @@ -636,4 +636,10 @@ pub fn eval_ext_circuit, const D: usize>( let constr = builder.mul_extension(filter, channel.used); yield_constr.constraint(builder, constr); } + + // Constrain the new stack length for POP. + let diff = builder.sub_extension(nv.stack_len, lv.stack_len); + let mut constr = builder.add_const_extension(diff, F::ONES); + constr = builder.mul_extension(filter, constr); + yield_constr.constraint_transition(builder, constr); } From 9d0183297f2f56ffe81d68d1f94d7a0ec3d193f9 Mon Sep 17 00:00:00 2001 From: Linda Guiga Date: Fri, 27 Oct 2023 18:03:28 -0400 Subject: [PATCH 5/5] Fix stack --- evm/src/cpu/stack.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/evm/src/cpu/stack.rs b/evm/src/cpu/stack.rs index 8186e00f71..dbeeedcb2e 100644 --- a/evm/src/cpu/stack.rs +++ b/evm/src/cpu/stack.rs @@ -23,7 +23,6 @@ pub(crate) struct StackBehavior { pub(crate) const BASIC_UNARY_OP: Option = Some(StackBehavior { num_pops: 1, pushes: true, - new_top_stack_channel: Some(NUM_GP_CHANNELS - 1), disable_other_channels: true, }); const BASIC_BINARY_OP: Option = Some(StackBehavior {