generate_keccak_general, generate_byte

This commit is contained in:
Daniel Lubarov 2022-12-01 12:06:29 -08:00
parent 25205f319a
commit d3aa33975a
10 changed files with 118 additions and 45 deletions

View File

@ -62,6 +62,18 @@ impl Kernel {
padded_code.resize(padded_len, 0);
padded_code
}
/// Get a string representation of the current offset for debugging purposes.
pub(crate) fn offset_name(&self, offset: usize) -> String {
self.offset_label(offset)
.unwrap_or_else(|| offset.to_string())
}
pub(crate) fn offset_label(&self, offset: usize) -> Option<String> {
self.global_labels
.iter()
.find_map(|(k, v)| (*v == offset).then(|| k.clone()))
}
}
#[derive(Eq, PartialEq, Hash, Clone, Debug)]

View File

@ -355,18 +355,12 @@ impl<'a> Interpreter<'a> {
Ok(())
}
/// Get a string representation of the current offset for debugging purposes.
fn offset_name(&self) -> String {
self.offset_label()
.unwrap_or_else(|| self.offset.to_string())
KERNEL.offset_name(self.offset)
}
fn offset_label(&self) -> Option<String> {
// TODO: Not sure we should use KERNEL? Interpreter is more general in other places.
KERNEL
.global_labels
.iter()
.find_map(|(k, v)| (*v == self.offset).then(|| k.clone()))
KERNEL.offset_label(self.offset)
}
fn run_stop(&mut self) {

View File

@ -12,10 +12,10 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer
use crate::cross_table_lookup::Column;
use crate::keccak::keccak_stark::NUM_INPUTS;
use crate::keccak_memory::columns::*;
use crate::memory::segments::Segment;
use crate::stark::Stark;
use crate::util::trace_rows_to_poly_values;
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
use crate::witness::memory::MemoryAddress;
pub(crate) fn ctl_looked_data<F: Field>() -> Vec<Column<F>> {
Column::singles([COL_CONTEXT, COL_SEGMENT, COL_VIRTUAL, COL_READ_TIMESTAMP]).collect()
@ -67,10 +67,8 @@ pub(crate) fn ctl_filter<F: Field>() -> Column<F> {
/// Information about a Keccak memory operation needed for witness generation.
#[derive(Debug)]
pub(crate) struct KeccakMemoryOp {
// The address at which we will read inputs and write outputs.
pub(crate) context: usize,
pub(crate) segment: Segment,
pub(crate) virt: usize,
/// The base address at which we will read inputs and write outputs.
pub(crate) address: MemoryAddress,
/// The timestamp at which inputs should be read from memory.
/// Outputs will be written at the following timestamp.
@ -131,9 +129,9 @@ impl<F: RichField + Extendable<D>, const D: usize> KeccakMemoryStark<F, D> {
fn generate_row_for_op(&self, op: KeccakMemoryOp) -> [F; NUM_COLUMNS] {
let mut row = [F::ZERO; NUM_COLUMNS];
row[COL_IS_REAL] = F::ONE;
row[COL_CONTEXT] = F::from_canonical_usize(op.context);
row[COL_SEGMENT] = F::from_canonical_usize(op.segment as usize);
row[COL_VIRTUAL] = F::from_canonical_usize(op.virt);
row[COL_CONTEXT] = F::from_canonical_usize(op.address.context);
row[COL_SEGMENT] = F::from_canonical_usize(op.address.segment as usize);
row[COL_VIRTUAL] = F::from_canonical_usize(op.address.virt);
row[COL_READ_TIMESTAMP] = F::from_canonical_usize(op.read_timestamp);
for i in 0..25 {
let input_u64 = op.input[i];

View File

@ -21,7 +21,7 @@ pub(crate) struct KeccakSpongeColumnsView<T: Copy> {
/// in the block will be padding bytes; 0 otherwise.
pub is_final_block: T,
// The address at which we will read the input block.
// The base address at which we will read the input block.
pub context: T,
pub segment: T,
pub virt: T,

View File

@ -18,10 +18,10 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer
use crate::cpu::kernel::keccak_util::keccakf_u32s;
use crate::cross_table_lookup::Column;
use crate::keccak_sponge::columns::*;
use crate::memory::segments::Segment;
use crate::stark::Stark;
use crate::util::trace_rows_to_poly_values;
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
use crate::witness::memory::MemoryAddress;
#[allow(unused)] // TODO: Should be used soon.
pub(crate) fn ctl_looked_data<F: Field>() -> Vec<Column<F>> {
@ -144,10 +144,8 @@ pub(crate) fn ctl_looking_memory_filter<F: Field>(i: usize) -> Column<F> {
/// Information about a Keccak sponge operation needed for witness generation.
#[derive(Debug)]
pub(crate) struct KeccakSpongeOp {
// The address at which inputs are read.
pub(crate) context: usize,
pub(crate) segment: Segment,
pub(crate) virt: usize,
/// The base address at which inputs are read.
pub(crate) base_address: MemoryAddress,
/// The timestamp at which inputs are read.
pub(crate) timestamp: usize,
@ -295,9 +293,9 @@ impl<F: RichField + Extendable<D>, const D: usize> KeccakSpongeStark<F, D> {
already_absorbed_bytes: usize,
mut sponge_state: [u32; KECCAK_WIDTH_U32S],
) {
row.context = F::from_canonical_usize(op.context);
row.segment = F::from_canonical_usize(op.segment as usize);
row.virt = F::from_canonical_usize(op.virt);
row.context = F::from_canonical_usize(op.base_address.context);
row.segment = F::from_canonical_usize(op.base_address.segment as usize);
row.virt = F::from_canonical_usize(op.base_address.virt);
row.timestamp = F::from_canonical_usize(op.timestamp);
row.len = F::from_canonical_usize(op.len);
row.already_absorbed_bytes = F::from_canonical_usize(already_absorbed_bytes);

View File

@ -1,4 +1,5 @@
#[allow(dead_code)]
#[derive(Debug)]
pub enum ProgramError {
OutOfGas,
InvalidOpcode,

View File

@ -13,6 +13,7 @@ pub enum MemoryChannel {
use MemoryChannel::{Code, GeneralPurpose};
use crate::memory::segments::Segment;
use crate::util::u256_saturating_cast_usize;
impl MemoryChannel {
pub fn index(&self) -> usize {
@ -41,6 +42,14 @@ impl MemoryAddress {
virt,
}
}
pub(crate) fn new_u256s(context: U256, segment: U256, virt: U256) -> Self {
Self {
context: u256_saturating_cast_usize(context),
segment: u256_saturating_cast_usize(segment),
virt: u256_saturating_cast_usize(virt),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]

View File

@ -7,6 +7,7 @@ use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::membus::NUM_GP_CHANNELS;
use crate::cpu::simple_logic::eq_iszero::generate_pinv_diff;
use crate::generation::state::GenerationState;
use crate::keccak_sponge::keccak_sponge_stark::KeccakSpongeOp;
use crate::memory::segments::Segment;
use crate::util::u256_saturating_cast_usize;
use crate::witness::errors::ProgramError;
@ -100,6 +101,40 @@ pub(crate) fn generate_ternary_arithmetic_op<F: Field>(
Ok(())
}
pub(crate) fn generate_keccak_general<F: Field>(
state: &mut GenerationState<F>,
mut row: CpuColumnsView<F>,
) -> Result<(), ProgramError> {
let [(context, log_in0), (segment, log_in1), (base_virt, log_in2), (len, log_in3)] =
stack_pop_with_log_and_fill::<4, _>(state, &mut row)?;
let len = len.as_usize();
let mut base_address = MemoryAddress::new_u256s(context, segment, base_virt);
let input = (0..len)
.map(|i| {
let address = MemoryAddress {
virt: base_address.virt.saturating_add(i),
..base_address
};
let val = state.memory.get(address);
val.as_u32() as u8
})
.collect();
state.traces.push_keccak_sponge(KeccakSpongeOp {
base_address,
timestamp: state.traces.clock(),
len,
input,
});
state.traces.push_memory(log_in0);
state.traces.push_memory(log_in1);
state.traces.push_memory(log_in2);
state.traces.push_memory(log_in3);
state.traces.push_cpu(row);
Ok(())
}
pub(crate) fn generate_prover_input<F: Field>(
state: &mut GenerationState<F>,
mut row: CpuColumnsView<F>,
@ -285,6 +320,26 @@ pub(crate) fn generate_not<F: Field>(
Ok(())
}
pub(crate) fn generate_byte<F: Field>(
state: &mut GenerationState<F>,
mut row: CpuColumnsView<F>,
) -> Result<(), ProgramError> {
let [(i, log_in0), (x, log_in1)] = stack_pop_with_log_and_fill::<2, _>(state, &mut row)?;
let byte = if i < 32.into() {
x.byte(i.as_usize())
} else {
0
};
let log_out = stack_push_log_and_fill(state, &mut row, byte.into())?;
state.traces.push_memory(log_in0);
state.traces.push_memory(log_in1);
state.traces.push_memory(log_out);
state.traces.push_cpu(row);
Ok(())
}
pub(crate) fn generate_iszero<F: Field>(
state: &mut GenerationState<F>,
mut row: CpuColumnsView<F>,
@ -395,17 +450,9 @@ pub(crate) fn generate_mload_general<F: Field>(
let [(context, log_in0), (segment, log_in1), (virt, log_in2)] =
stack_pop_with_log_and_fill::<3, _>(state, &mut row)?;
// If virt won't fit in a usize, don't try to convert it, just return 0.
let val = if virt > usize::MAX.into() {
U256::zero()
} else {
state.memory.get(MemoryAddress {
context: context.as_usize(),
segment: segment.as_usize(),
virt: virt.as_usize(),
})
};
let val = state
.memory
.get(MemoryAddress::new_u256s(context, segment, virt));
let log_out = stack_push_log_and_fill(state, &mut row, val)?;
state.traces.push_memory(log_in0);

View File

@ -78,8 +78,12 @@ impl<T: Copy> Traces<T> {
self.arithmetic.push(op);
}
pub fn push_memory(&mut self, val: MemoryOp) {
self.memory_ops.push(val);
pub fn push_memory(&mut self, op: MemoryOp) {
self.memory_ops.push(op);
}
pub fn push_keccak_sponge(&mut self, op: KeccakSpongeOp) {
self.keccak_sponge_ops.push(op);
}
pub fn clock(&self) -> usize {

View File

@ -1,13 +1,15 @@
use itertools::Itertools;
use plonky2::field::types::Field;
use crate::cpu::columns::CpuColumnsView;
use crate::cpu::kernel::aggregator::KERNEL;
use crate::generation::state::GenerationState;
use crate::memory::segments::Segment;
use crate::witness::errors::ProgramError;
use crate::witness::memory::MemoryAddress;
use crate::witness::operation::*;
use crate::witness::state::RegistersState;
use crate::witness::util::mem_read_code_with_log_and_fill;
use crate::witness::util::{mem_read_code_with_log_and_fill, stack_peek};
use crate::{arithmetic, logic};
fn read_code_memory<F: Field>(state: &mut GenerationState<F>, row: &mut CpuColumnsView<F>) -> u8 {
@ -186,7 +188,7 @@ fn perform_op<F: Field>(
Operation::Swap(n) => generate_swap(n, state, row)?,
Operation::Iszero => generate_iszero(state, row)?,
Operation::Not => generate_not(state, row)?,
Operation::Byte => todo!(),
Operation::Byte => generate_byte(state, row)?,
Operation::Syscall(opcode) => generate_syscall(opcode, state, row)?,
Operation::Eq => generate_eq(state, row)?,
Operation::BinaryLogic(binary_logic_op) => {
@ -194,7 +196,7 @@ fn perform_op<F: Field>(
}
Operation::BinaryArithmetic(op) => generate_binary_arithmetic_op(op, state, row)?,
Operation::TernaryArithmetic(op) => generate_ternary_arithmetic_op(op, state, row)?,
Operation::KeccakGeneral => todo!(),
Operation::KeccakGeneral => generate_keccak_general(state, row)?,
Operation::ProverInput => generate_prover_input(state, row)?,
Operation::Pop => generate_pop(state, row)?,
Operation::Jump => generate_jump(state, row)?,
@ -226,7 +228,15 @@ fn try_perform_instruction<F: Field>(state: &mut GenerationState<F>) -> Result<(
let opcode = read_code_memory(state, &mut row);
let op = decode(state.registers, opcode)?;
log::trace!("Executing {:?} at {}", op, state.registers.program_counter);
let pc = state.registers.program_counter;
log::trace!("Executing {:?} at {}", op, KERNEL.offset_name(pc));
log::trace!(
"Stack: {:?}",
(0..state.registers.stack_len)
.map(|i| stack_peek(state, i).unwrap())
.collect_vec()
);
fill_op_flag(op, &mut row);
perform_op(state, op, row)
@ -246,11 +256,11 @@ pub(crate) fn transition<F: Field>(state: &mut GenerationState<F>) {
.memory
.apply_ops(state.traces.mem_ops_since(checkpoint.traces));
}
Err(_) => {
state.rollback(checkpoint);
Err(e) => {
if state.registers.is_kernel {
panic!("exception in kernel mode");
panic!("exception in kernel mode: {:?}", e);
}
state.rollback(checkpoint);
handle_error(state)
}
}