mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-03 14:23:07 +00:00
generate_push and misc other progress
This commit is contained in:
parent
2471f5a391
commit
906a47a1ef
@ -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,
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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]));
|
||||
|
||||
@ -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,
|
||||
))
|
||||
};
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user