Combine get_context and set_context into one flag

This commit is contained in:
Linda Guiga 2023-07-19 10:17:28 +01:00
parent f6f9fa3197
commit c3cb227896
No known key found for this signature in database
9 changed files with 96 additions and 34 deletions

View File

@ -40,9 +40,7 @@ pub struct OpsColumnsView<T: Copy> {
pub push: T,
pub dup: T,
pub swap: T,
// TODO: combine GET_CONTEXT and SET_CONTEXT into one flag
pub get_context: T,
pub set_context: T,
pub context_op: T,
pub exit_kernel: T,
// TODO: combine MLOAD_GENERAL and MSTORE_GENERAL into one flag
pub mload_general: T,

View File

@ -15,12 +15,31 @@ fn eval_packed_get<P: PackedField>(
lv: &CpuColumnsView<P>,
yield_constr: &mut ConstraintConsumer<P>,
) {
let filter = lv.op.get_context;
// If the opcode is GET_CONTEXT, then lv.opcode_bits[0] = 0
let filter = lv.op.context_op * (P::ONES - lv.opcode_bits[0]);
let push_channel = lv.mem_channels[NUM_GP_CHANNELS - 1];
yield_constr.constraint(filter * (push_channel.value[0] - lv.context));
for &limb in &push_channel.value[1..] {
yield_constr.constraint(filter * limb);
}
// Stack constraints
let channel = lv.mem_channels[NUM_GP_CHANNELS - 1];
yield_constr.constraint(filter * (channel.used - P::ONES));
yield_constr.constraint(filter * channel.is_read);
yield_constr.constraint(filter * (channel.addr_context - lv.context));
yield_constr.constraint(
filter * (channel.addr_segment - P::Scalar::from_canonical_u64(Segment::Stack as u64)),
);
let addr_virtual = lv.stack_len;
yield_constr.constraint(filter * (channel.addr_virtual - addr_virtual));
// Unused channels
for i in 0..NUM_GP_CHANNELS - 1 {
let channel = lv.mem_channels[i];
yield_constr.constraint(filter * channel.used);
}
}
fn eval_ext_circuit_get<F: RichField + Extendable<D>, const D: usize>(
@ -28,7 +47,11 @@ fn eval_ext_circuit_get<F: RichField + Extendable<D>, const D: usize>(
lv: &CpuColumnsView<ExtensionTarget<D>>,
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
) {
let filter = lv.op.get_context;
let mut filter = lv.op.context_op;
let one = builder.one_extension();
let minus = builder.sub_extension(one, lv.opcode_bits[0]);
filter = builder.mul_extension(filter, minus);
let push_channel = lv.mem_channels[NUM_GP_CHANNELS - 1];
{
let diff = builder.sub_extension(push_channel.value[0], lv.context);
@ -39,6 +62,45 @@ fn eval_ext_circuit_get<F: RichField + Extendable<D>, const D: usize>(
let constr = builder.mul_extension(filter, limb);
yield_constr.constraint(builder, constr);
}
// Stack constraints
let channel = lv.mem_channels[NUM_GP_CHANNELS - 1];
{
let constr = builder.mul_sub_extension(filter, channel.used, filter);
yield_constr.constraint(builder, constr);
}
{
let constr = builder.mul_extension(filter, channel.is_read);
yield_constr.constraint(builder, constr);
}
{
let diff = builder.sub_extension(channel.addr_context, lv.context);
let constr = builder.mul_extension(filter, diff);
yield_constr.constraint(builder, constr);
}
{
let constr = builder.arithmetic_extension(
F::ONE,
-F::from_canonical_u64(Segment::Stack as u64),
filter,
channel.addr_segment,
filter,
);
yield_constr.constraint(builder, constr);
}
{
let diff = builder.sub_extension(channel.addr_virtual, lv.stack_len);
let constr = builder.arithmetic_extension(F::ONE, F::ZERO, filter, diff, filter);
yield_constr.constraint(builder, constr);
}
for i in 0..NUM_GP_CHANNELS - 1 {
let channel = lv.mem_channels[i];
let constr = builder.mul_extension(filter, channel.used);
yield_constr.constraint(builder, constr);
}
}
fn eval_packed_set<P: PackedField>(
@ -46,7 +108,7 @@ fn eval_packed_set<P: PackedField>(
nv: &CpuColumnsView<P>,
yield_constr: &mut ConstraintConsumer<P>,
) {
let filter = lv.op.set_context;
let filter = lv.op.context_op * lv.opcode_bits[0];
let pop_channel = lv.mem_channels[0];
let write_old_sp_channel = lv.mem_channels[1];
let read_new_sp_channel = lv.mem_channels[2];
@ -94,7 +156,8 @@ fn eval_ext_circuit_set<F: RichField + Extendable<D>, const D: usize>(
nv: &CpuColumnsView<ExtensionTarget<D>>,
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
) {
let filter = lv.op.set_context;
let mut filter = lv.op.context_op;
filter = builder.mul_extension(filter, lv.opcode_bits[0]);
let pop_channel = lv.mem_channels[0];
let write_old_sp_channel = lv.mem_channels[1];
let read_new_sp_channel = lv.mem_channels[2];

View File

@ -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; 29] = [
const NATIVE_INSTRUCTIONS: [usize; 28] = [
COL_MAP.op.add,
COL_MAP.op.mul,
COL_MAP.op.sub,
@ -37,8 +37,7 @@ const NATIVE_INSTRUCTIONS: [usize; 29] = [
// not PUSH (need to increment by more than 1)
COL_MAP.op.dup,
COL_MAP.op.swap,
COL_MAP.op.get_context,
COL_MAP.op.set_context,
COL_MAP.op.context_op,
// not EXIT_KERNEL (performs a jump)
COL_MAP.op.mload_general,
COL_MAP.op.mstore_general,

View File

@ -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); 32] = [
const OPCODES: [(u8, usize, bool, usize); 31] = [
// (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),
@ -49,11 +49,10 @@ const OPCODES: [(u8, usize, bool, usize); 32] = [
(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, 4, false, COL_MAP.op.dup), // 0x80-0x8f
(0x90, 4, false, COL_MAP.op.swap), // 0x90-0x9f
(0xf6, 0, true, COL_MAP.op.get_context),
(0xf7, 0, true, COL_MAP.op.set_context),
(0x60, 5, false, COL_MAP.op.push), // 0x60-0x7f
(0x80, 4, false, COL_MAP.op.dup), // 0x80-0x8f
(0x90, 4, false, COL_MAP.op.swap), // 0x90-0x9f
(0xf6, 1, true, COL_MAP.op.context_op), // 0xf6-0xf7
(0xf9, 0, true, COL_MAP.op.exit_kernel),
(0xfb, 0, true, COL_MAP.op.mload_general),
(0xfc, 0, true, COL_MAP.op.mstore_general),

View File

@ -48,8 +48,7 @@ const SIMPLE_OPCODES: OpsColumnsView<Option<u32>> = OpsColumnsView {
push: G_VERYLOW,
dup: G_VERYLOW,
swap: G_VERYLOW,
get_context: KERNEL_ONLY_INSTR,
set_context: KERNEL_ONLY_INSTR,
context_op: KERNEL_ONLY_INSTR,
exit_kernel: None,
mload_general: KERNEL_ONLY_INSTR,
mstore_general: KERNEL_ONLY_INSTR,

View File

@ -107,12 +107,7 @@ const STACK_BEHAVIORS: OpsColumnsView<Option<StackBehavior>> = OpsColumnsView {
push: None, // TODO
dup: None,
swap: None,
get_context: Some(StackBehavior {
num_pops: 0,
pushes: true,
disable_other_channels: true,
}),
set_context: None, // SET_CONTEXT is special since it involves the old and the new stack.
context_op: None, // SET_CONTEXT is special since it involves the old and the new stack.
exit_kernel: Some(StackBehavior {
num_pops: 1,
pushes: false,

View File

@ -42,8 +42,7 @@ pub(crate) fn gas_to_charge(op: Operation) -> u64 {
Push(1..) => G_VERYLOW,
Dup(_) => G_VERYLOW,
Swap(_) => G_VERYLOW,
GetContext => KERNEL_ONLY_INSTR,
SetContext => KERNEL_ONLY_INSTR,
ContextOp(_) => KERNEL_ONLY_INSTR,
ExitKernel => KERNEL_ONLY_INSTR,
MloadGeneral => KERNEL_ONLY_INSTR,
MstoreGeneral => KERNEL_ONLY_INSTR,

View File

@ -45,8 +45,7 @@ pub(crate) enum Operation {
Push(u8),
Dup(u8),
Swap(u8),
GetContext,
SetContext,
ContextOp(bool),
ExitKernel,
MloadGeneral,
MstoreGeneral,
@ -293,6 +292,19 @@ pub(crate) fn generate_jumpdest<F: Field>(
Ok(())
}
pub(crate) fn generate_context_op<F: Field>(
is_set: bool,
state: &mut GenerationState<F>,
row: CpuColumnsView<F>,
) -> Result<(), ProgramError> {
// SET_CONTEXT uses mem_channels[0..=2]
if is_set {
generate_set_context(state, row)
} else {
generate_get_context(state, row)
}
}
pub(crate) fn generate_get_context<F: Field>(
state: &mut GenerationState<F>,
mut row: CpuColumnsView<F>,

View File

@ -134,8 +134,8 @@ fn decode(registers: RegistersState, opcode: u8) -> Result<Operation, ProgramErr
(0xf3, _) => Ok(Operation::Syscall(opcode, 2, false)), // RETURN
(0xf4, _) => Ok(Operation::Syscall(opcode, 6, false)), // DELEGATECALL
(0xf5, _) => Ok(Operation::Syscall(opcode, 4, false)), // CREATE2
(0xf6, true) => Ok(Operation::GetContext),
(0xf7, true) => Ok(Operation::SetContext),
(0xf6, true) => Ok(Operation::ContextOp(false)), // GET_CONTEXT
(0xf7, true) => Ok(Operation::ContextOp(true)), // SET_CONTEXT
(0xf9, true) => Ok(Operation::ExitKernel),
(0xfa, _) => Ok(Operation::Syscall(opcode, 6, false)), // STATICCALL
(0xfb, true) => Ok(Operation::MloadGeneral),
@ -182,8 +182,7 @@ fn fill_op_flag<F: Field>(op: Operation, row: &mut CpuColumnsView<F>) {
Operation::Jump | Operation::Jumpi => &mut flags.jumps,
Operation::Pc => &mut flags.pc,
Operation::Jumpdest => &mut flags.jumpdest,
Operation::GetContext => &mut flags.get_context,
Operation::SetContext => &mut flags.set_context,
Operation::ContextOp(_) => &mut flags.context_op,
Operation::ExitKernel => &mut flags.exit_kernel,
Operation::MloadGeneral => &mut flags.mload_general,
Operation::MstoreGeneral => &mut flags.mstore_general,
@ -219,8 +218,7 @@ fn perform_op<F: Field>(
Operation::Jumpi => generate_jumpi(state, row)?,
Operation::Pc => generate_pc(state, row)?,
Operation::Jumpdest => generate_jumpdest(state, row)?,
Operation::GetContext => generate_get_context(state, row)?,
Operation::SetContext => generate_set_context(state, row)?,
Operation::ContextOp(is_set) => generate_context_op(is_set, state, row)?,
Operation::ExitKernel => generate_exit_kernel(state, row)?,
Operation::MloadGeneral => generate_mload_general(state, row)?,
Operation::MstoreGeneral => generate_mstore_general(state, row)?,