Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge NOT and POP flags. #1257

Merged
merged 9 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions evm/src/cpu/columns/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ pub struct OpsColumnsView<T: Copy> {
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,
Expand Down
5 changes: 2 additions & 3 deletions evm/src/cpu/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 JUMPS (possible need to jump)
COL_MAP.op.pc,
COL_MAP.op.jumpdest,
Expand Down
29 changes: 25 additions & 4 deletions evm/src/cpu/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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,
];

/// Break up an opcode (which is 8 bits long) into its eight bits.
Expand Down Expand Up @@ -147,6 +147,14 @@ pub fn eval_packed_generic<P: PackedField>(
* (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<F: RichField + Extendable<D>, const D: usize>(
Expand Down Expand Up @@ -249,4 +257,17 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, 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);
}
24 changes: 22 additions & 2 deletions evm/src/cpu/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ const SIMPLE_OPCODES: OpsColumnsView<Option<u32>> = 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
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,
Expand Down Expand Up @@ -105,6 +104,13 @@ fn eval_packed_accumulate<P: PackedField>(
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 * (gas_diff - 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 * (gas_diff - not_pop_cost));
}

fn eval_packed_init<P: PackedField>(
Expand Down Expand Up @@ -233,6 +239,20 @@ fn eval_ext_circuit_accumulate<F: RichField + Extendable<D>, 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<F: RichField + Extendable<D>, const D: usize>(
Expand Down
4 changes: 2 additions & 2 deletions evm/src/cpu/simple_logic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn eval_packed<P: PackedField>(
nv: &CpuColumnsView<P>,
yield_constr: &mut ConstraintConsumer<P>,
) {
not::eval_packed(lv, yield_constr);
not::eval_packed(lv, nv, yield_constr);
eq_iszero::eval_packed(lv, nv, yield_constr);
}

Expand All @@ -24,6 +24,6 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
nv: &CpuColumnsView<ExtensionTarget<D>>,
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
) {
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);
}
20 changes: 18 additions & 2 deletions evm/src/cpu/simple_logic/not.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<P: PackedField>(
lv: &CpuColumnsView<P>,
nv: &CpuColumnsView<P>,
yield_constr: &mut ConstraintConsumer<P>,
) {
// 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<F: RichField + Extendable<D>, const D: usize>(
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
lv: &CpuColumnsView<ExtensionTarget<D>>,
nv: &CpuColumnsView<ExtensionTarget<D>>,
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
) {
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(
Expand All @@ -45,4 +51,14 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, 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,
);
}
Loading