mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-03 06:13:07 +00:00
Merge push and prover_input flags (#1417)
* Merge PUSH and PROVER_INPUT flags * Apply comment
This commit is contained in:
parent
51ff8c5b51
commit
bc1a3c4851
@ -24,12 +24,10 @@ pub(crate) struct OpsColumnsView<T: Copy> {
|
||||
pub shift: T,
|
||||
/// Combines JUMPDEST and KECCAK_GENERAL flags.
|
||||
pub jumpdest_keccak_general: T,
|
||||
/// Flag for PROVER_INPUT.
|
||||
pub prover_input: T,
|
||||
/// Combines JUMP and JUMPI flags.
|
||||
pub jumps: T,
|
||||
/// Flag for PUSH.
|
||||
pub push: T,
|
||||
/// Combines PUSH and PROVER_INPUT flags.
|
||||
pub push_prover_input: T,
|
||||
/// Combines DUP and SWAP flags.
|
||||
pub dup_swap: T,
|
||||
/// Combines GET_CONTEXT and SET_CONTEXT flags.
|
||||
|
||||
@ -24,10 +24,9 @@ const KEEPS_CONTEXT: OpsColumnsView<bool> = OpsColumnsView {
|
||||
not_pop: true,
|
||||
shift: true,
|
||||
jumpdest_keccak_general: true,
|
||||
prover_input: true,
|
||||
push_prover_input: true,
|
||||
jumps: true,
|
||||
pc_push0: true,
|
||||
push: true,
|
||||
dup_swap: true,
|
||||
context_op: false,
|
||||
m_op_32bytes: true,
|
||||
|
||||
@ -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; 13] = [
|
||||
const NATIVE_INSTRUCTIONS: [usize; 12] = [
|
||||
COL_MAP.op.binary_op,
|
||||
COL_MAP.op.ternary_op,
|
||||
COL_MAP.op.fp254_op,
|
||||
@ -17,7 +17,7 @@ const NATIVE_INSTRUCTIONS: [usize; 13] = [
|
||||
COL_MAP.op.not_pop,
|
||||
COL_MAP.op.shift,
|
||||
COL_MAP.op.jumpdest_keccak_general,
|
||||
COL_MAP.op.prover_input,
|
||||
// Not PROVER_INPUT: it is dealt with manually below.
|
||||
// not JUMPS (possible need to jump)
|
||||
COL_MAP.op.pc_push0,
|
||||
// not PUSH (need to increment by more than 1)
|
||||
@ -70,6 +70,13 @@ pub(crate) fn eval_packed_generic<P: PackedField>(
|
||||
yield_constr
|
||||
.constraint_transition(is_native_instruction * (lv.is_kernel_mode - nv.is_kernel_mode));
|
||||
|
||||
// Apply the same checks as before, for PROVER_INPUT.
|
||||
let is_prover_input: P = lv.op.push_prover_input * (lv.opcode_bits[5] - P::ONES);
|
||||
yield_constr.constraint_transition(
|
||||
is_prover_input * (lv.program_counter - nv.program_counter + P::ONES),
|
||||
);
|
||||
yield_constr.constraint_transition(is_prover_input * (lv.is_kernel_mode - nv.is_kernel_mode));
|
||||
|
||||
// If a non-CPU cycle row is followed by a CPU cycle row, then:
|
||||
// - the `program_counter` of the CPU cycle row is `main` (the entry point of our kernel),
|
||||
// - execution is in kernel mode, and
|
||||
@ -117,6 +124,17 @@ pub(crate) fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
let kernel_diff = builder.sub_extension(lv.is_kernel_mode, nv.is_kernel_mode);
|
||||
let kernel_constr = builder.mul_extension(filter, kernel_diff);
|
||||
yield_constr.constraint_transition(builder, kernel_constr);
|
||||
|
||||
// Same constraints as before, for PROVER_INPUT.
|
||||
let is_prover_input = builder.mul_sub_extension(
|
||||
lv.op.push_prover_input,
|
||||
lv.opcode_bits[5],
|
||||
lv.op.push_prover_input,
|
||||
);
|
||||
let pc_constr = builder.mul_add_extension(is_prover_input, pc_diff, is_prover_input);
|
||||
yield_constr.constraint_transition(builder, pc_constr);
|
||||
let kernel_constr = builder.mul_extension(is_prover_input, kernel_diff);
|
||||
yield_constr.constraint_transition(builder, kernel_constr);
|
||||
}
|
||||
|
||||
// If a non-CPU cycle row is followed by a CPU cycle row, then:
|
||||
|
||||
@ -103,18 +103,24 @@ pub(crate) fn ctl_arithmetic_base_rows<F: Field>() -> TableWithColumns<F> {
|
||||
// (also `ops` is used as the operation filter). The list of
|
||||
// operations includes binary operations which will simply ignore
|
||||
// the third input.
|
||||
let col_bit = Column::linear_combination_with_constant(
|
||||
vec![(COL_MAP.opcode_bits[5], F::NEG_ONE)],
|
||||
F::ONE,
|
||||
);
|
||||
TableWithColumns::new(
|
||||
Table::Cpu,
|
||||
columns,
|
||||
Some(Filter::new_simple(Column::sum([
|
||||
COL_MAP.op.binary_op,
|
||||
COL_MAP.op.fp254_op,
|
||||
COL_MAP.op.ternary_op,
|
||||
COL_MAP.op.shift,
|
||||
COL_MAP.op.prover_input,
|
||||
COL_MAP.op.syscall,
|
||||
COL_MAP.op.exception,
|
||||
]))),
|
||||
Some(Filter::new(
|
||||
vec![(Column::single(COL_MAP.op.push_prover_input), col_bit)],
|
||||
vec![Column::sum([
|
||||
COL_MAP.op.binary_op,
|
||||
COL_MAP.op.fp254_op,
|
||||
COL_MAP.op.ternary_op,
|
||||
COL_MAP.op.shift,
|
||||
COL_MAP.op.syscall,
|
||||
COL_MAP.op.exception,
|
||||
])],
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
@ -201,7 +207,11 @@ pub(crate) fn ctl_data_byte_packing_push<F: Field>() -> Vec<Column<F>> {
|
||||
|
||||
/// CTL filter for the `PUSH` operation.
|
||||
pub(crate) fn ctl_filter_byte_packing_push<F: Field>() -> Filter<F> {
|
||||
Filter::new_simple(Column::single(COL_MAP.op.push))
|
||||
let bit_col = Column::single(COL_MAP.opcode_bits[5]);
|
||||
Filter::new(
|
||||
vec![(Column::single(COL_MAP.op.push_prover_input), bit_col)],
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
|
||||
/// Index of the memory channel storing code.
|
||||
|
||||
@ -3,6 +3,7 @@ use plonky2::field::packed::PackedField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::ext_target::ExtensionTarget;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::cpu::columns::{CpuColumnsView, COL_MAP};
|
||||
@ -23,7 +24,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); 7] = [
|
||||
const OPCODES: [(u8, usize, bool, usize); 5] = [
|
||||
// (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.
|
||||
@ -33,9 +34,7 @@ const OPCODES: [(u8, usize, bool, usize); 7] = [
|
||||
// NOT and POP are handled manually here.
|
||||
// SHL and SHR flags are handled partly manually here, and partly through the Logic table CTL.
|
||||
// JUMPDEST and KECCAK_GENERAL are handled manually here.
|
||||
(0x49, 0, true, COL_MAP.op.prover_input),
|
||||
(0x56, 1, false, COL_MAP.op.jumps), // 0x56-0x57
|
||||
(0x60, 5, false, COL_MAP.op.push), // 0x60-0x7f
|
||||
(0x80, 5, false, COL_MAP.op.dup_swap), // 0x80-0x9f
|
||||
(0xf6, 1, true, COL_MAP.op.context_op), //0xf6-0xf7
|
||||
(0xf9, 0, true, COL_MAP.op.exit_kernel),
|
||||
@ -45,7 +44,7 @@ const OPCODES: [(u8, usize, bool, usize); 7] = [
|
||||
/// 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; 10] = [
|
||||
const COMBINED_OPCODES: [usize; 11] = [
|
||||
COL_MAP.op.logic_op,
|
||||
COL_MAP.op.fp254_op,
|
||||
COL_MAP.op.binary_op,
|
||||
@ -56,6 +55,7 @@ const COMBINED_OPCODES: [usize; 10] = [
|
||||
COL_MAP.op.not_pop,
|
||||
COL_MAP.op.pc_push0,
|
||||
COL_MAP.op.m_op_32bytes,
|
||||
COL_MAP.op.push_prover_input,
|
||||
];
|
||||
|
||||
/// Break up an opcode (which is 8 bits long) into its eight bits.
|
||||
@ -192,6 +192,16 @@ pub(crate) fn eval_packed_generic<P: PackedField>(
|
||||
* (opcode - P::Scalar::from_canonical_usize(0xf8_usize))
|
||||
* lv.op.m_op_32bytes;
|
||||
yield_constr.constraint(op_32bytes);
|
||||
|
||||
// Manually check PUSH and PROVER_INPUT.
|
||||
// PROVER_INPUT is a kernel-only instruction, but not PUSH.
|
||||
let push_prover_input_constr = (opcode - P::Scalar::from_canonical_usize(0x49_usize))
|
||||
* (opcode_high_three - P::Scalar::from_canonical_usize(0x60_usize))
|
||||
* lv.op.push_prover_input;
|
||||
yield_constr.constraint(push_prover_input_constr);
|
||||
let prover_input_constr =
|
||||
lv.op.push_prover_input * (lv.opcode_bits[5] - P::ONES) * (P::ONES - kernel_mode);
|
||||
yield_constr.constraint(prover_input_constr);
|
||||
}
|
||||
|
||||
fn opcode_high_bits_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
@ -373,4 +383,24 @@ pub(crate) fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
let constr = builder.mul_extension(mstore_32bytes_constr, mload_32bytes_constr);
|
||||
let constr = builder.mul_extension(constr, lv.op.m_op_32bytes);
|
||||
yield_constr.constraint(builder, constr);
|
||||
|
||||
// Manually check PUSH and PROVER_INPUT.
|
||||
// PROVER_INPUT is a kernel-only instruction, but not PUSH.
|
||||
let prover_input_opcode =
|
||||
builder.constant_extension(F::Extension::from_canonical_usize(0x49usize));
|
||||
let push_opcodes = builder.constant_extension(F::Extension::from_canonical_usize(0x60usize));
|
||||
|
||||
let push_constr = builder.sub_extension(opcode_high_three, push_opcodes);
|
||||
let prover_input_constr = builder.sub_extension(opcode, prover_input_opcode);
|
||||
|
||||
let push_prover_input_constr =
|
||||
builder.mul_many_extension([lv.op.push_prover_input, prover_input_constr, push_constr]);
|
||||
yield_constr.constraint(builder, push_prover_input_constr);
|
||||
let prover_input_filter = builder.mul_sub_extension(
|
||||
lv.op.push_prover_input,
|
||||
lv.opcode_bits[5],
|
||||
lv.op.push_prover_input,
|
||||
);
|
||||
let constr = builder.mul_extension(prover_input_filter, is_not_kernel_mode);
|
||||
yield_constr.constraint(builder, constr);
|
||||
}
|
||||
|
||||
@ -27,10 +27,9 @@ const SIMPLE_OPCODES: OpsColumnsView<Option<u32>> = OpsColumnsView {
|
||||
not_pop: None, // This is handled manually below
|
||||
shift: G_VERYLOW,
|
||||
jumpdest_keccak_general: None, // This is handled manually below.
|
||||
prover_input: KERNEL_ONLY_INSTR,
|
||||
jumps: None, // Combined flag handled separately.
|
||||
push_prover_input: None, // This is handled manually below.
|
||||
jumps: None, // Combined flag handled separately.
|
||||
pc_push0: G_BASE,
|
||||
push: G_VERYLOW,
|
||||
dup_swap: G_VERYLOW,
|
||||
context_op: KERNEL_ONLY_INSTR,
|
||||
m_op_32bytes: KERNEL_ONLY_INSTR,
|
||||
@ -112,6 +111,14 @@ fn eval_packed_accumulate<P: PackedField>(
|
||||
yield_constr.constraint_transition(
|
||||
lv.op.jumpdest_keccak_general * (gas_diff - jumpdest_keccak_general_gas_cost),
|
||||
);
|
||||
|
||||
// For PROVER_INPUT and PUSH operations.
|
||||
// PUSH operations are differentiated from PROVER_INPUT by their 6th bit set to 1.
|
||||
let push_prover_input_gas_cost = lv.opcode_bits[5]
|
||||
* P::Scalar::from_canonical_u32(G_VERYLOW.unwrap())
|
||||
+ (P::ONES - lv.opcode_bits[5]) * P::Scalar::from_canonical_u32(KERNEL_ONLY_INSTR.unwrap());
|
||||
yield_constr
|
||||
.constraint_transition(lv.op.push_prover_input * (gas_diff - push_prover_input_gas_cost));
|
||||
}
|
||||
|
||||
fn eval_packed_init<P: PackedField>(
|
||||
@ -270,6 +277,21 @@ fn eval_ext_circuit_accumulate<F: RichField + Extendable<D>, const D: usize>(
|
||||
let constr = builder.mul_extension(filter, gas_diff);
|
||||
|
||||
yield_constr.constraint_transition(builder, constr);
|
||||
|
||||
// For PROVER_INPUT and PUSH operations.
|
||||
// PUSH operations are differentiated from PROVER_INPUT by their 6th bit set to 1.
|
||||
let push_prover_input_gas_cost = builder.arithmetic_extension(
|
||||
F::from_canonical_u32(G_VERYLOW.unwrap())
|
||||
- F::from_canonical_u32(KERNEL_ONLY_INSTR.unwrap()),
|
||||
F::from_canonical_u32(KERNEL_ONLY_INSTR.unwrap()),
|
||||
lv.opcode_bits[5],
|
||||
one,
|
||||
one,
|
||||
);
|
||||
let gas_diff = builder.sub_extension(nv_lv_diff, push_prover_input_gas_cost);
|
||||
let constr = builder.mul_extension(lv.op.push_prover_input, gas_diff);
|
||||
|
||||
yield_constr.constraint_transition(builder, constr);
|
||||
}
|
||||
|
||||
fn eval_ext_circuit_init<F: RichField + Extendable<D>, const D: usize>(
|
||||
|
||||
@ -28,10 +28,9 @@ pub(crate) const MIGHT_OVERFLOW: OpsColumnsView<bool> = OpsColumnsView {
|
||||
not_pop: false,
|
||||
shift: false,
|
||||
jumpdest_keccak_general: false,
|
||||
prover_input: false,
|
||||
push_prover_input: true, // PROVER_INPUT doesn't require the check, but PUSH does.
|
||||
jumps: false,
|
||||
pc_push0: true,
|
||||
push: true,
|
||||
dup_swap: true,
|
||||
context_op: false,
|
||||
m_op_32bytes: false,
|
||||
@ -119,7 +118,7 @@ pub(crate) const STACK_BEHAVIORS: OpsColumnsView<Option<StackBehavior>> = OpsCol
|
||||
disable_other_channels: false,
|
||||
}),
|
||||
jumpdest_keccak_general: None,
|
||||
prover_input: Some(StackBehavior {
|
||||
push_prover_input: Some(StackBehavior {
|
||||
num_pops: 0,
|
||||
pushes: true,
|
||||
disable_other_channels: true,
|
||||
@ -130,11 +129,6 @@ pub(crate) const STACK_BEHAVIORS: OpsColumnsView<Option<StackBehavior>> = OpsCol
|
||||
pushes: true,
|
||||
disable_other_channels: true,
|
||||
}),
|
||||
push: Some(StackBehavior {
|
||||
num_pops: 0,
|
||||
pushes: true,
|
||||
disable_other_channels: true,
|
||||
}),
|
||||
dup_swap: None,
|
||||
context_op: None,
|
||||
m_op_32bytes: Some(StackBehavior {
|
||||
|
||||
@ -161,7 +161,6 @@ pub(crate) fn decode(registers: RegistersState, opcode: u8) -> Result<Operation,
|
||||
fn fill_op_flag<F: Field>(op: Operation, row: &mut CpuColumnsView<F>) {
|
||||
let flags = &mut row.op;
|
||||
*match op {
|
||||
Operation::Push(1..) => &mut flags.push,
|
||||
Operation::Dup(_) | Operation::Swap(_) => &mut flags.dup_swap,
|
||||
Operation::Iszero | Operation::Eq => &mut flags.eq_iszero,
|
||||
Operation::Not | Operation::Pop => &mut flags.not_pop,
|
||||
@ -175,7 +174,7 @@ fn fill_op_flag<F: Field>(op: Operation, row: &mut CpuColumnsView<F>) {
|
||||
Operation::BinaryArithmetic(_) => &mut flags.binary_op,
|
||||
Operation::TernaryArithmetic(_) => &mut flags.ternary_op,
|
||||
Operation::KeccakGeneral | Operation::Jumpdest => &mut flags.jumpdest_keccak_general,
|
||||
Operation::ProverInput => &mut flags.prover_input,
|
||||
Operation::ProverInput | Operation::Push(1..) => &mut flags.push_prover_input,
|
||||
Operation::Jump | Operation::Jumpi => &mut flags.jumps,
|
||||
Operation::Pc | Operation::Push(0) => &mut flags.pc_push0,
|
||||
Operation::GetContext | Operation::SetContext => &mut flags.context_op,
|
||||
@ -189,7 +188,7 @@ fn fill_op_flag<F: Field>(op: Operation, row: &mut CpuColumnsView<F>) {
|
||||
const fn get_op_special_length(op: Operation) -> Option<usize> {
|
||||
let behavior_opt = match op {
|
||||
Operation::Push(0) | Operation::Pc => STACK_BEHAVIORS.pc_push0,
|
||||
Operation::Push(1..) => STACK_BEHAVIORS.push,
|
||||
Operation::Push(1..) | Operation::ProverInput => STACK_BEHAVIORS.push_prover_input,
|
||||
Operation::Dup(_) | Operation::Swap(_) => STACK_BEHAVIORS.dup_swap,
|
||||
Operation::Iszero => IS_ZERO_STACK_BEHAVIOR,
|
||||
Operation::Not | Operation::Pop => STACK_BEHAVIORS.not_pop,
|
||||
@ -206,7 +205,6 @@ const fn get_op_special_length(op: Operation) -> Option<usize> {
|
||||
Operation::BinaryArithmetic(_) => STACK_BEHAVIORS.binary_op,
|
||||
Operation::TernaryArithmetic(_) => STACK_BEHAVIORS.ternary_op,
|
||||
Operation::KeccakGeneral | Operation::Jumpdest => STACK_BEHAVIORS.jumpdest_keccak_general,
|
||||
Operation::ProverInput => STACK_BEHAVIORS.prover_input,
|
||||
Operation::Jump => JUMP_OP,
|
||||
Operation::Jumpi => JUMPI_OP,
|
||||
Operation::GetContext | Operation::SetContext => None,
|
||||
@ -229,7 +227,7 @@ const fn get_op_special_length(op: Operation) -> Option<usize> {
|
||||
// Kernel-only pushing instructions aren't considered; they can't overflow.
|
||||
const fn might_overflow_op(op: Operation) -> bool {
|
||||
match op {
|
||||
Operation::Push(1..) => MIGHT_OVERFLOW.push,
|
||||
Operation::Push(1..) | Operation::ProverInput => MIGHT_OVERFLOW.push_prover_input,
|
||||
Operation::Dup(_) | Operation::Swap(_) => MIGHT_OVERFLOW.dup_swap,
|
||||
Operation::Iszero | Operation::Eq => MIGHT_OVERFLOW.eq_iszero,
|
||||
Operation::Not | Operation::Pop => MIGHT_OVERFLOW.not_pop,
|
||||
@ -245,7 +243,6 @@ const fn might_overflow_op(op: Operation) -> bool {
|
||||
Operation::BinaryArithmetic(_) => MIGHT_OVERFLOW.binary_op,
|
||||
Operation::TernaryArithmetic(_) => MIGHT_OVERFLOW.ternary_op,
|
||||
Operation::KeccakGeneral | Operation::Jumpdest => MIGHT_OVERFLOW.jumpdest_keccak_general,
|
||||
Operation::ProverInput => MIGHT_OVERFLOW.prover_input,
|
||||
Operation::Jump | Operation::Jumpi => MIGHT_OVERFLOW.jumps,
|
||||
Operation::Pc | Operation::Push(0) => MIGHT_OVERFLOW.pc_push0,
|
||||
Operation::GetContext | Operation::SetContext => MIGHT_OVERFLOW.context_op,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user