generate_push and misc other progress

This commit is contained in:
Daniel Lubarov 2022-11-30 17:45:31 -08:00
parent 2471f5a391
commit 906a47a1ef
11 changed files with 117 additions and 48 deletions

View File

@ -12,6 +12,7 @@ pub(crate) mod columns;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum BinaryOperator {
Add,
Mul,
Sub,
Div,
@ -25,7 +26,6 @@ pub(crate) enum BinaryOperator {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum TernaryOperator {
AddMod,
SubMod,
MulMod,
}

View File

@ -17,7 +17,7 @@ use crate::cpu::kernel::keccak_util::keccakf_u32s;
use crate::keccak_sponge::columns::KECCAK_RATE_U32S;
use crate::memory::segments::Segment;
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
use crate::witness::memory::{MemoryAddress, MemoryState};
use crate::witness::memory::MemoryAddress;
use crate::witness::traces::Traces;
use crate::witness::util::mem_write_gp_log_and_fill;
@ -26,10 +26,7 @@ use crate::witness::util::mem_write_gp_log_and_fill;
/// want them to fit in a single limb of Keccak input.
const BYTES_PER_ROW: usize = 4;
pub(crate) fn generate_bootstrap_kernel<F: Field>(
memory: &mut MemoryState,
traces: &mut Traces<F>,
) {
pub(crate) fn generate_bootstrap_kernel<F: Field>(traces: &mut Traces<F>) {
let mut sponge_state = [0u32; 50];
let mut sponge_input_pos: usize = 0;
@ -46,7 +43,7 @@ pub(crate) fn generate_bootstrap_kernel<F: Field>(
// Write this chunk to memory, while simultaneously packing its bytes into a u32 word.
let mut packed_bytes: u32 = 0;
for (channel, (addr, &byte)) in chunk.enumerate() {
let address = MemoryAddress::new(0, Segment::Code as usize, addr);
let address = MemoryAddress::new(0, Segment::Code, addr);
let write = mem_write_gp_log_and_fill(
channel,
address,
@ -54,7 +51,6 @@ pub(crate) fn generate_bootstrap_kernel<F: Field>(
&mut current_cpu_row,
byte.into(),
);
memory.set(address, byte.into());
traces.push_memory(write);
packed_bytes = (packed_bytes << 8) | byte as u32;

View File

@ -11,5 +11,5 @@ mod modfp254;
mod shift;
pub(crate) mod simple_logic;
mod stack;
mod stack_bounds;
pub(crate) mod stack_bounds;
mod syscalls;

View File

@ -19,7 +19,7 @@ use plonky2::iop::ext_target::ExtensionTarget;
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
use crate::cpu::columns::{CpuColumnsView, COL_MAP};
pub const MAX_USER_STACK_SIZE: u64 = 1024;
pub const MAX_USER_STACK_SIZE: usize = 1024;
// Below only includes the operations that pop the top of the stack **without reading the value from
// memory**, i.e. `POP`.
@ -45,7 +45,7 @@ pub fn generate<F: Field>(lv: &mut CpuColumnsView<F>) {
let check_overflow: F = INCREMENTING_FLAGS.map(|i| lv[i]).into_iter().sum();
let no_check = F::ONE - (check_underflow + check_overflow);
let disallowed_len = check_overflow * F::from_canonical_u64(MAX_USER_STACK_SIZE) - no_check;
let disallowed_len = check_overflow * F::from_canonical_usize(MAX_USER_STACK_SIZE) - no_check;
let diff = lv.stack_len - disallowed_len;
let user_mode = F::ONE - lv.is_kernel_mode;
@ -84,7 +84,7 @@ pub fn eval_packed<P: PackedField>(
// 0 if `check_underflow`, `MAX_USER_STACK_SIZE` if `check_overflow`, and -1 if `no_check`.
let disallowed_len =
check_overflow * P::Scalar::from_canonical_u64(MAX_USER_STACK_SIZE) - no_check;
check_overflow * P::Scalar::from_canonical_usize(MAX_USER_STACK_SIZE) - no_check;
// This `lhs` must equal some `rhs`. If `rhs` is nonzero, then this shows that `lv.stack_len` is
// not `disallowed_len`.
let lhs = (lv.stack_len - disallowed_len) * lv.stack_len_bounds_aux;
@ -108,7 +108,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
) {
let one = builder.one_extension();
let max_stack_size =
builder.constant_extension(F::from_canonical_u64(MAX_USER_STACK_SIZE).into());
builder.constant_extension(F::from_canonical_usize(MAX_USER_STACK_SIZE).into());
// `check_underflow`, `check_overflow`, and `no_check` are mutually exclusive.
let check_underflow = builder.add_many_extension(DECREMENTING_FLAGS.map(|i| lv[i]));

View File

@ -67,9 +67,9 @@ pub(crate) fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
) -> ([Vec<PolynomialValues<F>>; NUM_TABLES], PublicValues) {
// let mut state = GenerationState::<F>::new(inputs.clone());
let mut memory_state = MemoryState::default();
let mut memory_state = MemoryState::new(&KERNEL.code);
let mut traces = Traces::<F>::default();
generate_bootstrap_kernel::<F>(&mut memory_state, &mut traces);
generate_bootstrap_kernel::<F>(&mut traces);
let mut registers_state = RegistersState::default();
let halt_pc0 = KERNEL.global_labels["halt_pc0"];
@ -89,7 +89,7 @@ pub(crate) fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
let read_metadata = |field| {
memory_state.get(MemoryAddress::new(
0,
Segment::GlobalMetadata as usize,
Segment::GlobalMetadata,
field as usize,
))
};

View File

@ -12,6 +12,8 @@ pub enum MemoryChannel {
use MemoryChannel::{Code, GeneralPurpose};
use crate::memory::segments::Segment;
impl MemoryChannel {
pub fn index(&self) -> usize {
match *self {
@ -32,10 +34,10 @@ pub struct MemoryAddress {
}
impl MemoryAddress {
pub(crate) fn new(context: usize, segment: usize, virt: usize) -> Self {
pub(crate) fn new(context: usize, segment: Segment, virt: usize) -> Self {
Self {
context,
segment,
segment: segment as usize,
virt,
}
}
@ -87,7 +89,7 @@ impl MemoryState {
for (i, &byte) in kernel_code.iter().enumerate() {
if byte != 0 {
let address = MemoryAddress::new(0, 0, i);
let address = MemoryAddress::new(0, Segment::Code, i);
let val = byte.into();
contents.insert(address, val);
}

View File

@ -1,4 +1,5 @@
use ethereum_types::U256;
use itertools::Itertools;
use plonky2::field::types::Field;
use crate::cpu::columns::CpuColumnsView;
@ -11,8 +12,8 @@ use crate::witness::memory::{MemoryAddress, MemoryState};
use crate::witness::state::RegistersState;
use crate::witness::traces::Traces;
use crate::witness::util::{
mem_read_gp_with_log_and_fill, mem_write_gp_log_and_fill, stack_pop_with_log_and_fill,
stack_push_log_and_fill,
mem_read_code_with_log_and_fill, mem_read_gp_with_log_and_fill, mem_write_gp_log_and_fill,
stack_pop_with_log_and_fill, stack_push_log_and_fill,
};
use crate::{arithmetic, logic};
@ -52,6 +53,66 @@ pub(crate) fn generate_binary_logic_op<F: Field>(
Ok(registers_state)
}
pub(crate) fn generate_push<F: Field>(
n: u8,
mut registers_state: RegistersState,
memory_state: &MemoryState,
traces: &mut Traces<F>,
mut row: CpuColumnsView<F>,
) -> Result<RegistersState, ProgramError> {
let context = registers_state.effective_context();
let num_bytes = n as usize + 1;
let initial_offset = registers_state.program_counter + 1;
let offsets = initial_offset..initial_offset + num_bytes;
let mut addrs = offsets.map(|offset| MemoryAddress::new(context, Segment::Code, offset));
// First read val without going through `mem_read_with_log` type methods, so we can pass it
// to stack_push_log_and_fill.
let bytes = (0..num_bytes)
.map(|i| {
memory_state
.get(MemoryAddress::new(
context,
Segment::Code,
initial_offset + i,
))
.as_u32() as u8
})
.collect_vec();
let val = U256::from_big_endian(&bytes);
let write = stack_push_log_and_fill(&mut registers_state, traces, &mut row, val)?;
// In the first cycle, we read up to NUM_GP_CHANNELS - 1 bytes, leaving the last GP channel
// to push the result.
for (i, addr) in (&mut addrs).take(NUM_GP_CHANNELS - 1).enumerate() {
let (_, read) = mem_read_gp_with_log_and_fill(i, addr, memory_state, traces, &mut row);
traces.push_memory(read);
}
traces.push_memory(write);
traces.push_cpu(row);
// In any subsequent cycles, we read up to 1 + NUM_GP_CHANNELS bytes.
for mut addrs_chunk in &addrs.chunks(1 + NUM_GP_CHANNELS) {
let mut row = CpuColumnsView::default();
// TODO: Set other row fields, like push=1?
let first_addr = addrs_chunk.next().unwrap();
let (_, first_read) =
mem_read_code_with_log_and_fill(first_addr, memory_state, traces, &mut row);
traces.push_memory(first_read);
for (i, addr) in addrs_chunk.enumerate() {
let (_, read) = mem_read_gp_with_log_and_fill(i, addr, memory_state, traces, &mut row);
traces.push_memory(read);
}
traces.push_cpu(row);
}
Ok(registers_state)
}
pub(crate) fn generate_dup<F: Field>(
n: u8,
mut registers_state: RegistersState,
@ -63,11 +124,7 @@ pub(crate) fn generate_dup<F: Field>(
.stack_len
.checked_sub(1 + (n as usize))
.ok_or(ProgramError::StackUnderflow)?;
let other_addr = MemoryAddress::new(
registers_state.context,
Segment::Stack as usize,
other_addr_lo,
);
let other_addr = MemoryAddress::new(registers_state.context, Segment::Stack, other_addr_lo);
let (val, log_in) =
mem_read_gp_with_log_and_fill(0, other_addr, memory_state, traces, &mut row);
@ -90,11 +147,7 @@ pub(crate) fn generate_swap<F: Field>(
.stack_len
.checked_sub(2 + (n as usize))
.ok_or(ProgramError::StackUnderflow)?;
let other_addr = MemoryAddress::new(
registers_state.context,
Segment::Stack as usize,
other_addr_lo,
);
let other_addr = MemoryAddress::new(registers_state.context, Segment::Stack, other_addr_lo);
let [(in0, log_in0)] =
stack_pop_with_log_and_fill::<1, _>(&mut registers_state, memory_state, traces, &mut row)?;
@ -163,21 +216,21 @@ pub(crate) fn generate_syscall<F: Field>(
let handler_addr_addr = handler_jumptable_addr + (opcode as usize);
let (handler_addr0, log_in0) = mem_read_gp_with_log_and_fill(
0,
MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr),
MemoryAddress::new(0, Segment::Code, handler_addr_addr),
memory_state,
traces,
&mut row,
);
let (handler_addr1, log_in1) = mem_read_gp_with_log_and_fill(
1,
MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr + 1),
MemoryAddress::new(0, Segment::Code, handler_addr_addr + 1),
memory_state,
traces,
&mut row,
);
let (handler_addr2, log_in2) = mem_read_gp_with_log_and_fill(
2,
MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr + 2),
MemoryAddress::new(0, Segment::Code, handler_addr_addr + 2),
memory_state,
traces,
&mut row,

View File

@ -8,6 +8,16 @@ pub struct RegistersState {
pub context: usize,
}
impl RegistersState {
pub(crate) fn effective_context(&self) -> usize {
if self.is_kernel {
0
} else {
self.context
}
}
}
impl Default for RegistersState {
fn default() -> Self {
Self {

View File

@ -13,8 +13,6 @@ use crate::util::trace_rows_to_poly_values;
use crate::witness::memory::MemoryOp;
use crate::{arithmetic, keccak, logic};
type ArithmeticRow<T> = [T; NUM_ARITH_COLUMNS];
#[derive(Clone, Copy, Debug)]
pub struct TraceCheckpoint {
pub(self) cpu_len: usize,

View File

@ -1,17 +1,17 @@
use plonky2::field::types::Field;
use crate::cpu::columns::{CpuColumnsView, NUM_CPU_COLUMNS};
use crate::logic;
use crate::cpu::columns::CpuColumnsView;
use crate::memory::segments::Segment;
use crate::witness::errors::ProgramError;
use crate::witness::memory::{MemoryAddress, MemoryState};
use crate::witness::operation::{
generate_binary_logic_op, generate_dup, generate_eq, generate_exit_kernel, generate_iszero,
generate_not, generate_swap, generate_syscall, Operation,
generate_not, generate_push, generate_swap, generate_syscall, Operation,
};
use crate::witness::state::RegistersState;
use crate::witness::traces::Traces;
use crate::witness::util::mem_read_code_with_log_and_fill;
use crate::{arithmetic, logic};
const KERNEL_CONTEXT: usize = 0;
@ -28,11 +28,7 @@ fn read_code_memory<F: Field>(
};
row.code_context = F::from_canonical_usize(code_context);
let address = MemoryAddress::new(
code_context,
Segment::Code as usize,
registers_state.program_counter,
);
let address = MemoryAddress::new(code_context, Segment::Code, registers_state.program_counter);
let (opcode, mem_log) = mem_read_code_with_log_and_fill(address, memory_state, traces, row);
traces.push_memory(mem_log);
@ -156,6 +152,17 @@ fn fill_op_flag<F: Field>(op: Operation, row: &mut CpuColumnsView<F>) {
Operation::BinaryLogic(logic::Op::And) => &mut flags.and,
Operation::BinaryLogic(logic::Op::Or) => &mut flags.or,
Operation::BinaryLogic(logic::Op::Xor) => &mut flags.xor,
Operation::BinaryArithmetic(arithmetic::BinaryOperator::Add) => &mut flags.add,
Operation::BinaryArithmetic(arithmetic::BinaryOperator::Mul) => &mut flags.mul,
Operation::BinaryArithmetic(arithmetic::BinaryOperator::Sub) => &mut flags.sub,
Operation::BinaryArithmetic(arithmetic::BinaryOperator::Div) => &mut flags.div,
Operation::BinaryArithmetic(arithmetic::BinaryOperator::Mod) => &mut flags.mod_,
Operation::BinaryArithmetic(arithmetic::BinaryOperator::Lt) => &mut flags.lt,
Operation::BinaryArithmetic(arithmetic::BinaryOperator::Gt) => &mut flags.gt,
Operation::BinaryArithmetic(arithmetic::BinaryOperator::Shl) => &mut flags.shl,
Operation::BinaryArithmetic(arithmetic::BinaryOperator::Shr) => &mut flags.shr,
Operation::TernaryArithmetic(arithmetic::TernaryOperator::AddMod) => &mut flags.addmod,
Operation::TernaryArithmetic(arithmetic::TernaryOperator::MulMod) => &mut flags.mulmod,
_ => panic!("operation not implemented: {:?}", op),
} = F::ONE;
}
@ -168,6 +175,7 @@ fn perform_op<F: Field>(
row: CpuColumnsView<F>,
) -> Result<RegistersState, ProgramError> {
let mut new_registers_state = match op {
Operation::Push(n) => generate_push(n, registers_state, memory_state, traces, row)?,
Operation::Dup(n) => generate_dup(n, registers_state, memory_state, traces, row)?,
Operation::Swap(n) => generate_swap(n, registers_state, memory_state, traces, row)?,
Operation::Iszero => generate_iszero(registers_state, memory_state, traces, row)?,
@ -185,6 +193,7 @@ fn perform_op<F: Field>(
new_registers_state.program_counter += match op {
Operation::Syscall(_) | Operation::ExitKernel => 0,
Operation::Push(n) => n as usize + 2,
_ => 1,
};
@ -196,7 +205,7 @@ fn try_perform_instruction<F: Field>(
memory_state: &MemoryState,
traces: &mut Traces<F>,
) -> Result<RegistersState, ProgramError> {
let mut row: CpuColumnsView<F> = [F::ZERO; NUM_CPU_COLUMNS].into();
let mut row: CpuColumnsView<F> = CpuColumnsView::default();
row.is_cpu_cycle = F::ONE;
let opcode = read_code_memory(registers_state, memory_state, traces, &mut row);

View File

@ -3,6 +3,7 @@ use plonky2::field::types::Field;
use crate::cpu::columns::CpuColumnsView;
use crate::cpu::membus::NUM_GP_CHANNELS;
use crate::cpu::stack_bounds::MAX_USER_STACK_SIZE;
use crate::memory::segments::Segment;
use crate::witness::errors::ProgramError;
use crate::witness::memory::{MemoryAddress, MemoryChannel, MemoryOp, MemoryOpKind, MemoryState};
@ -125,7 +126,7 @@ pub(crate) fn stack_pop_with_log_and_fill<const N: usize, F: Field>(
[(); N].map(|_| {
let address = MemoryAddress::new(
registers_state.context,
Segment::Stack as usize,
Segment::Stack,
registers_state.stack_len - 1 - i,
);
let res = mem_read_gp_with_log_and_fill(i, address, memory_state, traces, row);
@ -145,13 +146,13 @@ pub(crate) fn stack_push_log_and_fill<F: Field>(
row: &mut CpuColumnsView<F>,
val: U256,
) -> Result<MemoryOp, ProgramError> {
if !registers_state.is_kernel && registers_state.stack_len >= 1024 {
if !registers_state.is_kernel && registers_state.stack_len >= MAX_USER_STACK_SIZE {
return Err(ProgramError::StackOverflow);
}
let address = MemoryAddress::new(
registers_state.context,
Segment::Stack as usize,
Segment::Stack,
registers_state.stack_len,
);
let res = mem_write_gp_log_and_fill(NUM_GP_CHANNELS - 1, address, traces, row, val);