mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-02 22:03:07 +00:00
Misc work on witness generation
This commit is contained in:
parent
2d92b4b6b4
commit
afb3e4b1e1
@ -14,17 +14,22 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer
|
||||
use crate::cpu::columns::{CpuColumnsView, NUM_CPU_COLUMNS};
|
||||
use crate::cpu::kernel::aggregator::KERNEL;
|
||||
use crate::cpu::kernel::keccak_util::keccakf_u32s;
|
||||
use crate::generation::state::GenerationState;
|
||||
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::traces::Traces;
|
||||
use crate::witness::util::mem_write_gp_log_and_fill;
|
||||
|
||||
/// We can't process more than `NUM_CHANNELS` bytes per row, since that's all the memory bandwidth
|
||||
/// we have. We also can't process more than 4 bytes (or the number of bytes in a `u32`), since we
|
||||
/// 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>(state: &mut GenerationState<F>) {
|
||||
pub(crate) fn generate_bootstrap_kernel<F: Field>(
|
||||
memory: &mut MemoryState,
|
||||
traces: &mut Traces<F>,
|
||||
) {
|
||||
let mut sponge_state = [0u32; 50];
|
||||
let mut sponge_input_pos: usize = 0;
|
||||
|
||||
@ -35,30 +40,41 @@ pub(crate) fn generate_bootstrap_kernel<F: Field>(state: &mut GenerationState<F>
|
||||
.enumerate()
|
||||
.chunks(BYTES_PER_ROW)
|
||||
{
|
||||
state.current_cpu_row.is_bootstrap_kernel = F::ONE;
|
||||
let mut current_cpu_row = CpuColumnsView::default();
|
||||
current_cpu_row.is_bootstrap_kernel = F::ONE;
|
||||
|
||||
// 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() {
|
||||
state.set_mem_cpu_current(channel, Segment::Code, addr, byte.into());
|
||||
let address = MemoryAddress::new(0, Segment::Code as usize, addr);
|
||||
let write = mem_write_gp_log_and_fill(
|
||||
channel,
|
||||
address,
|
||||
traces,
|
||||
&mut current_cpu_row,
|
||||
byte.into(),
|
||||
);
|
||||
memory.set(address, byte.into());
|
||||
traces.push_memory(write);
|
||||
|
||||
packed_bytes = (packed_bytes << 8) | byte as u32;
|
||||
}
|
||||
|
||||
sponge_state[sponge_input_pos] = packed_bytes;
|
||||
let keccak = state.current_cpu_row.general.keccak_mut();
|
||||
let keccak = current_cpu_row.general.keccak_mut();
|
||||
keccak.input_limbs = sponge_state.map(F::from_canonical_u32);
|
||||
state.commit_cpu_row();
|
||||
|
||||
sponge_input_pos = (sponge_input_pos + 1) % KECCAK_RATE_U32S;
|
||||
// If we just crossed a multiple of KECCAK_RATE_LIMBS, then we've filled the Keccak input
|
||||
// buffer, so it's time to absorb.
|
||||
if sponge_input_pos == 0 {
|
||||
state.current_cpu_row.is_keccak = F::ONE;
|
||||
current_cpu_row.is_keccak = F::ONE;
|
||||
keccakf_u32s(&mut sponge_state);
|
||||
let keccak = state.current_cpu_row.general.keccak_mut();
|
||||
let keccak = current_cpu_row.general.keccak_mut();
|
||||
keccak.output_limbs = sponge_state.map(F::from_canonical_u32);
|
||||
}
|
||||
|
||||
traces.push_cpu(current_cpu_row);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,8 @@ use std::fmt::Debug;
|
||||
use std::mem::{size_of, transmute};
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
use plonky2::field::types::Field;
|
||||
|
||||
use crate::cpu::columns::general::CpuGeneralColumnsView;
|
||||
use crate::cpu::columns::ops::OpsColumnsView;
|
||||
use crate::cpu::membus::NUM_GP_CHANNELS;
|
||||
@ -82,6 +84,12 @@ pub struct CpuColumnsView<T: Copy> {
|
||||
// `u8` is guaranteed to have a `size_of` of 1.
|
||||
pub const NUM_CPU_COLUMNS: usize = size_of::<CpuColumnsView<u8>>();
|
||||
|
||||
impl<F: Field> Default for CpuColumnsView<F> {
|
||||
fn default() -> Self {
|
||||
Self::from([F::ZERO; NUM_CPU_COLUMNS])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> From<[T; NUM_CPU_COLUMNS]> for CpuColumnsView<T> {
|
||||
fn from(value: [T; NUM_CPU_COLUMNS]) -> Self {
|
||||
unsafe { transmute_no_compile_time_size_checks(value) }
|
||||
|
||||
@ -1,50 +1,51 @@
|
||||
use ethereum_types::U256;
|
||||
|
||||
use crate::memory::memory_stark::MemoryOp;
|
||||
use crate::memory::segments::Segment;
|
||||
|
||||
#[allow(unused)] // TODO: Should be used soon.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct MemoryState {
|
||||
/// A log of each memory operation, in the order that it occurred.
|
||||
pub log: Vec<MemoryOp>,
|
||||
|
||||
pub contexts: Vec<MemoryContextState>,
|
||||
}
|
||||
|
||||
impl Default for MemoryState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
log: vec![],
|
||||
// We start with an initial context for the kernel.
|
||||
contexts: vec![MemoryContextState::default()],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub(crate) struct MemoryContextState {
|
||||
/// The content of each memory segment.
|
||||
pub segments: [MemorySegmentState; Segment::COUNT],
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub(crate) struct MemorySegmentState {
|
||||
pub content: Vec<U256>,
|
||||
}
|
||||
|
||||
impl MemorySegmentState {
|
||||
pub(crate) fn get(&self, virtual_addr: usize) -> U256 {
|
||||
self.content
|
||||
.get(virtual_addr)
|
||||
.copied()
|
||||
.unwrap_or(U256::zero())
|
||||
}
|
||||
|
||||
pub(crate) fn set(&mut self, virtual_addr: usize, value: U256) {
|
||||
if virtual_addr >= self.content.len() {
|
||||
self.content.resize(virtual_addr + 1, U256::zero());
|
||||
}
|
||||
self.content[virtual_addr] = value;
|
||||
}
|
||||
}
|
||||
// TODO: Remove?
|
||||
// use ethereum_types::U256;
|
||||
//
|
||||
// use crate::memory::memory_stark::MemoryOp;
|
||||
// use crate::memory::segments::Segment;
|
||||
//
|
||||
// #[allow(unused)] // TODO: Should be used soon.
|
||||
// #[derive(Debug)]
|
||||
// pub(crate) struct MemoryState {
|
||||
// /// A log of each memory operation, in the order that it occurred.
|
||||
// pub log: Vec<MemoryOp>,
|
||||
//
|
||||
// pub contexts: Vec<MemoryContextState>,
|
||||
// }
|
||||
//
|
||||
// impl Default for MemoryState {
|
||||
// fn default() -> Self {
|
||||
// Self {
|
||||
// log: vec![],
|
||||
// // We start with an initial context for the kernel.
|
||||
// contexts: vec![MemoryContextState::default()],
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[derive(Clone, Default, Debug)]
|
||||
// pub(crate) struct MemoryContextState {
|
||||
// /// The content of each memory segment.
|
||||
// pub segments: [MemorySegmentState; Segment::COUNT],
|
||||
// }
|
||||
//
|
||||
// #[derive(Clone, Default, Debug)]
|
||||
// pub(crate) struct MemorySegmentState {
|
||||
// pub content: Vec<U256>,
|
||||
// }
|
||||
//
|
||||
// impl MemorySegmentState {
|
||||
// pub(crate) fn get(&self, virtual_addr: usize) -> U256 {
|
||||
// self.content
|
||||
// .get(virtual_addr)
|
||||
// .copied()
|
||||
// .unwrap_or(U256::zero())
|
||||
// }
|
||||
//
|
||||
// pub(crate) fn set(&mut self, virtual_addr: usize, value: U256) {
|
||||
// if virtual_addr >= self.content.len() {
|
||||
// self.content.resize(virtual_addr + 1, U256::zero());
|
||||
// }
|
||||
// self.content[virtual_addr] = value;
|
||||
// }
|
||||
// }
|
||||
|
||||
@ -4,7 +4,6 @@ use eth_trie_utils::partial_trie::PartialTrie;
|
||||
use ethereum_types::{Address, BigEndianHash, H256};
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::polynomial::PolynomialValues;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::util::timing::TimingTree;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -12,13 +11,15 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::all_stark::{AllStark, NUM_TABLES};
|
||||
use crate::config::StarkConfig;
|
||||
use crate::cpu::bootstrap_kernel::generate_bootstrap_kernel;
|
||||
use crate::cpu::columns::NUM_CPU_COLUMNS;
|
||||
use crate::cpu::kernel::aggregator::KERNEL;
|
||||
use crate::cpu::kernel::constants::global_metadata::GlobalMetadata;
|
||||
use crate::generation::state::GenerationState;
|
||||
use crate::memory::segments::Segment;
|
||||
use crate::memory::NUM_CHANNELS;
|
||||
use crate::proof::{BlockMetadata, PublicValues, TrieRoots};
|
||||
use crate::util::trace_rows_to_poly_values;
|
||||
use crate::witness::memory::{MemoryAddress, MemoryState};
|
||||
use crate::witness::state::RegistersState;
|
||||
use crate::witness::traces::Traces;
|
||||
use crate::witness::transition::transition;
|
||||
|
||||
pub(crate) mod memory;
|
||||
pub(crate) mod mpt;
|
||||
@ -65,25 +66,33 @@ pub(crate) fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
|
||||
config: &StarkConfig,
|
||||
timing: &mut TimingTree,
|
||||
) -> ([Vec<PolynomialValues<F>>; NUM_TABLES], PublicValues) {
|
||||
let mut state = GenerationState::<F>::new(inputs.clone());
|
||||
// let mut state = GenerationState::<F>::new(inputs.clone());
|
||||
|
||||
generate_bootstrap_kernel::<F>(&mut state);
|
||||
let mut memory_state = MemoryState::default();
|
||||
let mut traces = Traces::<F>::default();
|
||||
generate_bootstrap_kernel::<F>(&mut memory_state, &mut traces);
|
||||
|
||||
for txn in &inputs.signed_txns {
|
||||
generate_txn(&mut state, txn);
|
||||
let mut registers_state = RegistersState::default();
|
||||
let halt_pc0 = KERNEL.global_labels["halt_pc0"];
|
||||
let halt_pc1 = KERNEL.global_labels["halt_pc1"];
|
||||
|
||||
loop {
|
||||
// If we've reached the kernel's halt routine, and our trace length is a power of 2, stop.
|
||||
let pc = registers_state.program_counter as usize;
|
||||
let in_halt_loop = pc == halt_pc0 || pc == halt_pc1;
|
||||
if in_halt_loop && traces.cpu.len().is_power_of_two() {
|
||||
break;
|
||||
}
|
||||
|
||||
registers_state = transition(registers_state, &memory_state, &mut traces);
|
||||
}
|
||||
|
||||
// TODO: Pad to a power of two, ending in the `halt` kernel function.
|
||||
|
||||
let cpu_rows = state.cpu_rows.len();
|
||||
let mem_end_timestamp = cpu_rows * NUM_CHANNELS;
|
||||
let mut read_metadata = |field| {
|
||||
state.get_mem(
|
||||
let read_metadata = |field| {
|
||||
memory_state.get(MemoryAddress::new(
|
||||
0,
|
||||
Segment::GlobalMetadata,
|
||||
Segment::GlobalMetadata as usize,
|
||||
field as usize,
|
||||
mem_end_timestamp,
|
||||
)
|
||||
))
|
||||
};
|
||||
|
||||
let trie_roots_before = TrieRoots {
|
||||
@ -101,43 +110,11 @@ pub(crate) fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
|
||||
receipts_root: H256::from_uint(&read_metadata(GlobalMetadata::ReceiptTrieRootDigestAfter)),
|
||||
};
|
||||
|
||||
let GenerationState {
|
||||
cpu_rows,
|
||||
current_cpu_row,
|
||||
memory,
|
||||
keccak_inputs,
|
||||
keccak_memory_inputs,
|
||||
logic_ops,
|
||||
..
|
||||
} = state;
|
||||
assert_eq!(current_cpu_row, [F::ZERO; NUM_CPU_COLUMNS].into());
|
||||
|
||||
let cpu_trace = trace_rows_to_poly_values(cpu_rows);
|
||||
let keccak_trace = all_stark.keccak_stark.generate_trace(keccak_inputs, timing);
|
||||
let keccak_memory_trace = all_stark.keccak_memory_stark.generate_trace(
|
||||
keccak_memory_inputs,
|
||||
config.fri_config.num_cap_elements(),
|
||||
timing,
|
||||
);
|
||||
let logic_trace = all_stark.logic_stark.generate_trace(logic_ops, timing);
|
||||
let memory_trace = all_stark.memory_stark.generate_trace(memory.log, timing);
|
||||
let traces = [
|
||||
cpu_trace,
|
||||
keccak_trace,
|
||||
keccak_memory_trace,
|
||||
logic_trace,
|
||||
memory_trace,
|
||||
];
|
||||
|
||||
let public_values = PublicValues {
|
||||
trie_roots_before,
|
||||
trie_roots_after,
|
||||
block_metadata: inputs.block_metadata,
|
||||
};
|
||||
|
||||
(traces, public_values)
|
||||
}
|
||||
|
||||
fn generate_txn<F: Field>(_state: &mut GenerationState<F>, _signed_txn: &[u8]) {
|
||||
// TODO
|
||||
(traces.to_tables(all_stark, config, timing), public_values)
|
||||
}
|
||||
|
||||
@ -1,35 +1,21 @@
|
||||
use std::mem;
|
||||
|
||||
use ethereum_types::U256;
|
||||
use plonky2::field::types::Field;
|
||||
use tiny_keccak::keccakf;
|
||||
|
||||
use crate::cpu::columns::{CpuColumnsView, NUM_CPU_COLUMNS};
|
||||
use crate::generation::memory::MemoryState;
|
||||
use crate::generation::mpt::all_mpt_prover_inputs_reversed;
|
||||
use crate::generation::rlp::all_rlp_prover_inputs_reversed;
|
||||
use crate::generation::GenerationInputs;
|
||||
use crate::keccak_memory::keccak_memory_stark::KeccakMemoryOp;
|
||||
use crate::memory::memory_stark::MemoryOp;
|
||||
use crate::memory::segments::Segment;
|
||||
use crate::memory::NUM_CHANNELS;
|
||||
use crate::util::u256_limbs;
|
||||
use crate::{keccak, logic};
|
||||
use crate::witness::memory::MemoryState;
|
||||
use crate::witness::state::RegistersState;
|
||||
use crate::witness::traces::Traces;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct GenerationState<F: Field> {
|
||||
#[allow(unused)] // TODO: Should be used soon.
|
||||
pub(crate) inputs: GenerationInputs,
|
||||
pub(crate) next_txn_index: usize,
|
||||
pub(crate) cpu_rows: Vec<[F; NUM_CPU_COLUMNS]>,
|
||||
pub(crate) current_cpu_row: CpuColumnsView<F>,
|
||||
|
||||
pub(crate) current_context: usize,
|
||||
pub(crate) registers: RegistersState,
|
||||
pub(crate) memory: MemoryState,
|
||||
pub(crate) traces: Traces<F>,
|
||||
|
||||
pub(crate) keccak_inputs: Vec<[u64; keccak::keccak_stark::NUM_INPUTS]>,
|
||||
pub(crate) keccak_memory_inputs: Vec<KeccakMemoryOp>,
|
||||
pub(crate) logic_ops: Vec<logic::Operation>,
|
||||
pub(crate) next_txn_index: usize,
|
||||
|
||||
/// Prover inputs containing MPT data, in reverse order so that the next input can be obtained
|
||||
/// via `pop()`.
|
||||
@ -47,206 +33,204 @@ impl<F: Field> GenerationState<F> {
|
||||
|
||||
Self {
|
||||
inputs,
|
||||
next_txn_index: 0,
|
||||
cpu_rows: vec![],
|
||||
current_cpu_row: [F::ZERO; NUM_CPU_COLUMNS].into(),
|
||||
current_context: 0,
|
||||
registers: Default::default(),
|
||||
memory: MemoryState::default(),
|
||||
keccak_inputs: vec![],
|
||||
keccak_memory_inputs: vec![],
|
||||
logic_ops: vec![],
|
||||
traces: Traces::default(),
|
||||
next_txn_index: 0,
|
||||
mpt_prover_inputs,
|
||||
rlp_prover_inputs,
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute logical AND, and record the operation to be added in the logic table later.
|
||||
#[allow(unused)] // TODO: Should be used soon.
|
||||
pub(crate) fn and(&mut self, input0: U256, input1: U256) -> U256 {
|
||||
self.logic_op(logic::Op::And, input0, input1)
|
||||
}
|
||||
// TODO: Remove dead code below.
|
||||
|
||||
/// Compute logical OR, and record the operation to be added in the logic table later.
|
||||
#[allow(unused)] // TODO: Should be used soon.
|
||||
pub(crate) fn or(&mut self, input0: U256, input1: U256) -> U256 {
|
||||
self.logic_op(logic::Op::Or, input0, input1)
|
||||
}
|
||||
// /// Compute logical AND, and record the operation to be added in the logic table later.
|
||||
// #[allow(unused)] // TODO: Should be used soon.
|
||||
// pub(crate) fn and(&mut self, input0: U256, input1: U256) -> U256 {
|
||||
// self.logic_op(logic::Op::And, input0, input1)
|
||||
// }
|
||||
|
||||
/// Compute logical XOR, and record the operation to be added in the logic table later.
|
||||
#[allow(unused)] // TODO: Should be used soon.
|
||||
pub(crate) fn xor(&mut self, input0: U256, input1: U256) -> U256 {
|
||||
self.logic_op(logic::Op::Xor, input0, input1)
|
||||
}
|
||||
// /// Compute logical OR, and record the operation to be added in the logic table later.
|
||||
// #[allow(unused)] // TODO: Should be used soon.
|
||||
// pub(crate) fn or(&mut self, input0: U256, input1: U256) -> U256 {
|
||||
// self.logic_op(logic::Op::Or, input0, input1)
|
||||
// }
|
||||
|
||||
/// Compute logical AND, and record the operation to be added in the logic table later.
|
||||
pub(crate) fn logic_op(&mut self, op: logic::Op, input0: U256, input1: U256) -> U256 {
|
||||
let operation = logic::Operation::new(op, input0, input1);
|
||||
let result = operation.result;
|
||||
self.logic_ops.push(operation);
|
||||
result
|
||||
}
|
||||
// /// Compute logical XOR, and record the operation to be added in the logic table later.
|
||||
// #[allow(unused)] // TODO: Should be used soon.
|
||||
// pub(crate) fn xor(&mut self, input0: U256, input1: U256) -> U256 {
|
||||
// self.logic_op(logic::Op::Xor, input0, input1)
|
||||
// }
|
||||
|
||||
/// Like `get_mem_cpu`, but reads from the current context specifically.
|
||||
#[allow(unused)] // TODO: Should be used soon.
|
||||
pub(crate) fn get_mem_cpu_current(
|
||||
&mut self,
|
||||
channel_index: usize,
|
||||
segment: Segment,
|
||||
virt: usize,
|
||||
) -> U256 {
|
||||
let context = self.current_context;
|
||||
self.get_mem_cpu(channel_index, context, segment, virt)
|
||||
}
|
||||
// /// Compute logical AND, and record the operation to be added in the logic table later.
|
||||
// pub(crate) fn logic_op(&mut self, op: logic::Op, input0: U256, input1: U256) -> U256 {
|
||||
// let operation = logic::Operation::new(op, input0, input1);
|
||||
// let result = operation.result;
|
||||
// self.logic_ops.push(operation);
|
||||
// result
|
||||
// }
|
||||
|
||||
/// Simulates the CPU reading some memory through the given channel. Besides logging the memory
|
||||
/// operation, this also generates the associated registers in the current CPU row.
|
||||
pub(crate) fn get_mem_cpu(
|
||||
&mut self,
|
||||
channel_index: usize,
|
||||
context: usize,
|
||||
segment: Segment,
|
||||
virt: usize,
|
||||
) -> U256 {
|
||||
let timestamp = self.cpu_rows.len() * NUM_CHANNELS + channel_index;
|
||||
let value = self.get_mem(context, segment, virt, timestamp);
|
||||
// /// Like `get_mem_cpu`, but reads from the current context specifically.
|
||||
// #[allow(unused)] // TODO: Should be used soon.
|
||||
// pub(crate) fn get_mem_cpu_current(
|
||||
// &mut self,
|
||||
// channel_index: usize,
|
||||
// segment: Segment,
|
||||
// virt: usize,
|
||||
// ) -> U256 {
|
||||
// let context = self.current_context;
|
||||
// self.get_mem_cpu(channel_index, context, segment, virt)
|
||||
// }
|
||||
|
||||
let channel = &mut self.current_cpu_row.mem_channels[channel_index];
|
||||
channel.used = F::ONE;
|
||||
channel.is_read = F::ONE;
|
||||
channel.addr_context = F::from_canonical_usize(context);
|
||||
channel.addr_segment = F::from_canonical_usize(segment as usize);
|
||||
channel.addr_virtual = F::from_canonical_usize(virt);
|
||||
channel.value = u256_limbs(value);
|
||||
// /// Simulates the CPU reading some memory through the given channel. Besides logging the memory
|
||||
// /// operation, this also generates the associated registers in the current CPU row.
|
||||
// pub(crate) fn get_mem_cpu(
|
||||
// &mut self,
|
||||
// channel_index: usize,
|
||||
// context: usize,
|
||||
// segment: Segment,
|
||||
// virt: usize,
|
||||
// ) -> U256 {
|
||||
// let timestamp = self.cpu_rows.len() * NUM_CHANNELS + channel_index;
|
||||
// let value = self.get_mem(context, segment, virt, timestamp);
|
||||
//
|
||||
// let channel = &mut self.current_cpu_row.mem_channels[channel_index];
|
||||
// channel.used = F::ONE;
|
||||
// channel.is_read = F::ONE;
|
||||
// channel.addr_context = F::from_canonical_usize(context);
|
||||
// channel.addr_segment = F::from_canonical_usize(segment as usize);
|
||||
// channel.addr_virtual = F::from_canonical_usize(virt);
|
||||
// channel.value = u256_limbs(value);
|
||||
//
|
||||
// value
|
||||
// }
|
||||
|
||||
value
|
||||
}
|
||||
// /// Read some memory, and log the operation.
|
||||
// pub(crate) fn get_mem(
|
||||
// &mut self,
|
||||
// context: usize,
|
||||
// segment: Segment,
|
||||
// virt: usize,
|
||||
// timestamp: usize,
|
||||
// ) -> U256 {
|
||||
// let value = self.memory.contexts[context].segments[segment as usize].get(virt);
|
||||
// self.memory.log.push(MemoryOp {
|
||||
// filter: true,
|
||||
// timestamp,
|
||||
// is_read: true,
|
||||
// context,
|
||||
// segment,
|
||||
// virt,
|
||||
// value,
|
||||
// });
|
||||
// value
|
||||
// }
|
||||
|
||||
/// Read some memory, and log the operation.
|
||||
pub(crate) fn get_mem(
|
||||
&mut self,
|
||||
context: usize,
|
||||
segment: Segment,
|
||||
virt: usize,
|
||||
timestamp: usize,
|
||||
) -> U256 {
|
||||
let value = self.memory.contexts[context].segments[segment as usize].get(virt);
|
||||
self.memory.log.push(MemoryOp {
|
||||
filter: true,
|
||||
timestamp,
|
||||
is_read: true,
|
||||
context,
|
||||
segment,
|
||||
virt,
|
||||
value,
|
||||
});
|
||||
value
|
||||
}
|
||||
// /// Write some memory within the current execution context, and log the operation.
|
||||
// pub(crate) fn set_mem_cpu_current(
|
||||
// &mut self,
|
||||
// channel_index: usize,
|
||||
// segment: Segment,
|
||||
// virt: usize,
|
||||
// value: U256,
|
||||
// ) {
|
||||
// let context = self.current_context;
|
||||
// self.set_mem_cpu(channel_index, context, segment, virt, value);
|
||||
// }
|
||||
|
||||
/// Write some memory within the current execution context, and log the operation.
|
||||
pub(crate) fn set_mem_cpu_current(
|
||||
&mut self,
|
||||
channel_index: usize,
|
||||
segment: Segment,
|
||||
virt: usize,
|
||||
value: U256,
|
||||
) {
|
||||
let context = self.current_context;
|
||||
self.set_mem_cpu(channel_index, context, segment, virt, value);
|
||||
}
|
||||
// /// Write some memory, and log the operation.
|
||||
// pub(crate) fn set_mem_cpu(
|
||||
// &mut self,
|
||||
// channel_index: usize,
|
||||
// context: usize,
|
||||
// segment: Segment,
|
||||
// virt: usize,
|
||||
// value: U256,
|
||||
// ) {
|
||||
// let timestamp = self.cpu_rows.len() * NUM_CHANNELS + channel_index;
|
||||
// self.set_mem(context, segment, virt, value, timestamp);
|
||||
//
|
||||
// let channel = &mut self.current_cpu_row.mem_channels[channel_index];
|
||||
// channel.used = F::ONE;
|
||||
// channel.is_read = F::ZERO; // For clarity; should already be 0.
|
||||
// channel.addr_context = F::from_canonical_usize(context);
|
||||
// channel.addr_segment = F::from_canonical_usize(segment as usize);
|
||||
// channel.addr_virtual = F::from_canonical_usize(virt);
|
||||
// channel.value = u256_limbs(value);
|
||||
// }
|
||||
|
||||
/// Write some memory, and log the operation.
|
||||
pub(crate) fn set_mem_cpu(
|
||||
&mut self,
|
||||
channel_index: usize,
|
||||
context: usize,
|
||||
segment: Segment,
|
||||
virt: usize,
|
||||
value: U256,
|
||||
) {
|
||||
let timestamp = self.cpu_rows.len() * NUM_CHANNELS + channel_index;
|
||||
self.set_mem(context, segment, virt, value, timestamp);
|
||||
// /// Write some memory, and log the operation.
|
||||
// pub(crate) fn set_mem(
|
||||
// &mut self,
|
||||
// context: usize,
|
||||
// segment: Segment,
|
||||
// virt: usize,
|
||||
// value: U256,
|
||||
// timestamp: usize,
|
||||
// ) {
|
||||
// self.memory.log.push(MemoryOp {
|
||||
// filter: true,
|
||||
// timestamp,
|
||||
// is_read: false,
|
||||
// context,
|
||||
// segment,
|
||||
// virt,
|
||||
// value,
|
||||
// });
|
||||
// self.memory.contexts[context].segments[segment as usize].set(virt, value)
|
||||
// }
|
||||
|
||||
let channel = &mut self.current_cpu_row.mem_channels[channel_index];
|
||||
channel.used = F::ONE;
|
||||
channel.is_read = F::ZERO; // For clarity; should already be 0.
|
||||
channel.addr_context = F::from_canonical_usize(context);
|
||||
channel.addr_segment = F::from_canonical_usize(segment as usize);
|
||||
channel.addr_virtual = F::from_canonical_usize(virt);
|
||||
channel.value = u256_limbs(value);
|
||||
}
|
||||
// /// Evaluate the Keccak-f permutation in-place on some data in memory, and record the operations
|
||||
// /// for the purpose of witness generation.
|
||||
// #[allow(unused)] // TODO: Should be used soon.
|
||||
// pub(crate) fn keccak_memory(
|
||||
// &mut self,
|
||||
// context: usize,
|
||||
// segment: Segment,
|
||||
// virt: usize,
|
||||
// ) -> [u64; keccak::keccak_stark::NUM_INPUTS] {
|
||||
// let read_timestamp = self.cpu_rows.len() * NUM_CHANNELS;
|
||||
// let _write_timestamp = read_timestamp + 1;
|
||||
// let input = (0..25)
|
||||
// .map(|i| {
|
||||
// let bytes = [0, 1, 2, 3, 4, 5, 6, 7].map(|j| {
|
||||
// let virt = virt + i * 8 + j;
|
||||
// let byte = self.get_mem(context, segment, virt, read_timestamp);
|
||||
// debug_assert!(byte.bits() <= 8);
|
||||
// byte.as_u32() as u8
|
||||
// });
|
||||
// u64::from_le_bytes(bytes)
|
||||
// })
|
||||
// .collect::<Vec<_>>()
|
||||
// .try_into()
|
||||
// .unwrap();
|
||||
// let output = self.keccak(input);
|
||||
// self.keccak_memory_inputs.push(KeccakMemoryOp {
|
||||
// context,
|
||||
// segment,
|
||||
// virt,
|
||||
// read_timestamp,
|
||||
// input,
|
||||
// output,
|
||||
// });
|
||||
// // TODO: Write output to memory.
|
||||
// output
|
||||
// }
|
||||
|
||||
/// Write some memory, and log the operation.
|
||||
pub(crate) fn set_mem(
|
||||
&mut self,
|
||||
context: usize,
|
||||
segment: Segment,
|
||||
virt: usize,
|
||||
value: U256,
|
||||
timestamp: usize,
|
||||
) {
|
||||
self.memory.log.push(MemoryOp {
|
||||
filter: true,
|
||||
timestamp,
|
||||
is_read: false,
|
||||
context,
|
||||
segment,
|
||||
virt,
|
||||
value,
|
||||
});
|
||||
self.memory.contexts[context].segments[segment as usize].set(virt, value)
|
||||
}
|
||||
// /// Evaluate the Keccak-f permutation, and record the operation for the purpose of witness
|
||||
// /// generation.
|
||||
// pub(crate) fn keccak(
|
||||
// &mut self,
|
||||
// mut input: [u64; keccak::keccak_stark::NUM_INPUTS],
|
||||
// ) -> [u64; keccak::keccak_stark::NUM_INPUTS] {
|
||||
// self.keccak_inputs.push(input);
|
||||
// keccakf(&mut input);
|
||||
// input
|
||||
// }
|
||||
|
||||
/// Evaluate the Keccak-f permutation in-place on some data in memory, and record the operations
|
||||
/// for the purpose of witness generation.
|
||||
#[allow(unused)] // TODO: Should be used soon.
|
||||
pub(crate) fn keccak_memory(
|
||||
&mut self,
|
||||
context: usize,
|
||||
segment: Segment,
|
||||
virt: usize,
|
||||
) -> [u64; keccak::keccak_stark::NUM_INPUTS] {
|
||||
let read_timestamp = self.cpu_rows.len() * NUM_CHANNELS;
|
||||
let _write_timestamp = read_timestamp + 1;
|
||||
let input = (0..25)
|
||||
.map(|i| {
|
||||
let bytes = [0, 1, 2, 3, 4, 5, 6, 7].map(|j| {
|
||||
let virt = virt + i * 8 + j;
|
||||
let byte = self.get_mem(context, segment, virt, read_timestamp);
|
||||
debug_assert!(byte.bits() <= 8);
|
||||
byte.as_u32() as u8
|
||||
});
|
||||
u64::from_le_bytes(bytes)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let output = self.keccak(input);
|
||||
self.keccak_memory_inputs.push(KeccakMemoryOp {
|
||||
context,
|
||||
segment,
|
||||
virt,
|
||||
read_timestamp,
|
||||
input,
|
||||
output,
|
||||
});
|
||||
// TODO: Write output to memory.
|
||||
output
|
||||
}
|
||||
|
||||
/// Evaluate the Keccak-f permutation, and record the operation for the purpose of witness
|
||||
/// generation.
|
||||
pub(crate) fn keccak(
|
||||
&mut self,
|
||||
mut input: [u64; keccak::keccak_stark::NUM_INPUTS],
|
||||
) -> [u64; keccak::keccak_stark::NUM_INPUTS] {
|
||||
self.keccak_inputs.push(input);
|
||||
keccakf(&mut input);
|
||||
input
|
||||
}
|
||||
|
||||
pub(crate) fn commit_cpu_row(&mut self) {
|
||||
let mut swapped_row = [F::ZERO; NUM_CPU_COLUMNS].into();
|
||||
mem::swap(&mut self.current_cpu_row, &mut swapped_row);
|
||||
self.cpu_rows.push(swapped_row.into());
|
||||
}
|
||||
// pub(crate) fn commit_cpu_row(&mut self) {
|
||||
// let mut swapped_row = [F::ZERO; NUM_CPU_COLUMNS].into();
|
||||
// mem::swap(&mut self.current_cpu_row, &mut swapped_row);
|
||||
// self.cpu_rows.push(swapped_row.into());
|
||||
// }
|
||||
}
|
||||
|
||||
@ -72,13 +72,23 @@ pub struct LogicStark<F, const D: usize> {
|
||||
pub f: PhantomData<F>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum Op {
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
}
|
||||
|
||||
impl Op {
|
||||
pub(crate) fn result(&self, a: U256, b: U256) -> U256 {
|
||||
match self {
|
||||
Op::And => a & b,
|
||||
Op::Or => a | b,
|
||||
Op::Xor => a ^ b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Operation {
|
||||
operator: Op,
|
||||
@ -89,11 +99,7 @@ pub(crate) struct Operation {
|
||||
|
||||
impl Operation {
|
||||
pub(crate) fn new(operator: Op, input0: U256, input1: U256) -> Self {
|
||||
let result = match operator {
|
||||
Op::And => input0 & input1,
|
||||
Op::Or => input0 | input1,
|
||||
Op::Xor => input0 ^ input1,
|
||||
};
|
||||
let result = operator.result(input0, input1);
|
||||
Operation {
|
||||
operator,
|
||||
input0,
|
||||
@ -101,6 +107,31 @@ impl Operation {
|
||||
result,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_row<F: Field>(&self) -> [F; NUM_COLUMNS] {
|
||||
let Operation {
|
||||
operator,
|
||||
input0,
|
||||
input1,
|
||||
result,
|
||||
} = self;
|
||||
let mut row = [F::ZERO; NUM_COLUMNS];
|
||||
row[match operator {
|
||||
Op::And => columns::IS_AND,
|
||||
Op::Or => columns::IS_OR,
|
||||
Op::Xor => columns::IS_XOR,
|
||||
}] = F::ONE;
|
||||
for i in 0..256 {
|
||||
row[columns::INPUT0.start + i] = F::from_bool(input0.bit(i));
|
||||
row[columns::INPUT1.start + i] = F::from_bool(input1.bit(i));
|
||||
}
|
||||
let result_limbs: &[u64] = result.as_ref();
|
||||
for (i, &limb) in result_limbs.iter().enumerate() {
|
||||
row[columns::RESULT.start + 2 * i] = F::from_canonical_u32(limb as u32);
|
||||
row[columns::RESULT.start + 2 * i + 1] = F::from_canonical_u32((limb >> 32) as u32);
|
||||
}
|
||||
row
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: RichField, const D: usize> LogicStark<F, D> {
|
||||
@ -128,40 +159,20 @@ impl<F: RichField, const D: usize> LogicStark<F, D> {
|
||||
|
||||
let mut rows = Vec::with_capacity(padded_len);
|
||||
for op in operations {
|
||||
rows.push(Self::generate_row(op));
|
||||
rows.push(op.to_row());
|
||||
}
|
||||
|
||||
// Pad to a power of two.
|
||||
for _ in len..padded_len {
|
||||
rows.push([F::ZERO; columns::NUM_COLUMNS]);
|
||||
rows.push([F::ZERO; NUM_COLUMNS]);
|
||||
}
|
||||
|
||||
rows
|
||||
}
|
||||
|
||||
fn generate_row(operation: Operation) -> [F; columns::NUM_COLUMNS] {
|
||||
let mut row = [F::ZERO; columns::NUM_COLUMNS];
|
||||
match operation.operator {
|
||||
Op::And => row[columns::IS_AND] = F::ONE,
|
||||
Op::Or => row[columns::IS_OR] = F::ONE,
|
||||
Op::Xor => row[columns::IS_XOR] = F::ONE,
|
||||
}
|
||||
for (i, col) in columns::INPUT0.enumerate() {
|
||||
row[col] = F::from_bool(operation.input0.bit(i));
|
||||
}
|
||||
for (i, col) in columns::INPUT1.enumerate() {
|
||||
row[col] = F::from_bool(operation.input1.bit(i));
|
||||
}
|
||||
for (i, col) in columns::RESULT.enumerate() {
|
||||
let bit_range = i * PACKED_LIMB_BITS..(i + 1) * PACKED_LIMB_BITS;
|
||||
row[col] = limb_from_bits_le(bit_range.map(|j| F::from_bool(operation.result.bit(j))));
|
||||
}
|
||||
row
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for LogicStark<F, D> {
|
||||
const COLUMNS: usize = columns::NUM_COLUMNS;
|
||||
const COLUMNS: usize = NUM_COLUMNS;
|
||||
|
||||
fn eval_packed_generic<FE, P, const D2: usize>(
|
||||
&self,
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use ethereum_types::U256;
|
||||
use itertools::Itertools;
|
||||
use maybe_rayon::*;
|
||||
use plonky2::field::extension::{Extendable, FieldExtension};
|
||||
@ -20,11 +19,12 @@ use crate::memory::columns::{
|
||||
COUNTER_PERMUTED, FILTER, IS_READ, NUM_COLUMNS, RANGE_CHECK, RANGE_CHECK_PERMUTED,
|
||||
SEGMENT_FIRST_CHANGE, TIMESTAMP, VIRTUAL_FIRST_CHANGE,
|
||||
};
|
||||
use crate::memory::segments::Segment;
|
||||
use crate::memory::VALUE_LIMBS;
|
||||
use crate::permutation::PermutationPair;
|
||||
use crate::stark::Stark;
|
||||
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
||||
use crate::witness::memory::MemoryOpKind::Read;
|
||||
use crate::witness::memory::{MemoryAddress, MemoryOp};
|
||||
|
||||
pub fn ctl_data<F: Field>() -> Vec<Column<F>> {
|
||||
let mut res =
|
||||
@ -43,17 +43,18 @@ pub struct MemoryStark<F, const D: usize> {
|
||||
pub(crate) f: PhantomData<F>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct MemoryOp {
|
||||
/// true if this is an actual memory operation, or false if it's a padding row.
|
||||
pub filter: bool,
|
||||
pub timestamp: usize,
|
||||
pub is_read: bool,
|
||||
pub context: usize,
|
||||
pub segment: Segment,
|
||||
pub virt: usize,
|
||||
pub value: U256,
|
||||
}
|
||||
// TODO: Remove
|
||||
// #[derive(Clone, Debug)]
|
||||
// pub(crate) struct MemoryOp {
|
||||
// /// true if this is an actual memory operation, or false if it's a padding row.
|
||||
// pub filter: bool,
|
||||
// pub timestamp: usize,
|
||||
// pub is_read: bool,
|
||||
// pub context: usize,
|
||||
// pub segment: Segment,
|
||||
// pub virt: usize,
|
||||
// pub value: U256,
|
||||
// }
|
||||
|
||||
impl MemoryOp {
|
||||
/// Generate a row for a given memory operation. Note that this does not generate columns which
|
||||
@ -64,10 +65,15 @@ impl MemoryOp {
|
||||
let mut row = [F::ZERO; NUM_COLUMNS];
|
||||
row[FILTER] = F::from_bool(self.filter);
|
||||
row[TIMESTAMP] = F::from_canonical_usize(self.timestamp);
|
||||
row[IS_READ] = F::from_bool(self.is_read);
|
||||
row[ADDR_CONTEXT] = F::from_canonical_usize(self.context);
|
||||
row[ADDR_SEGMENT] = F::from_canonical_usize(self.segment as usize);
|
||||
row[ADDR_VIRTUAL] = F::from_canonical_usize(self.virt);
|
||||
row[IS_READ] = F::from_bool(self.op == Read);
|
||||
let MemoryAddress {
|
||||
context,
|
||||
segment,
|
||||
virt,
|
||||
} = self.address;
|
||||
row[ADDR_CONTEXT] = F::from_canonical_usize(context);
|
||||
row[ADDR_SEGMENT] = F::from_canonical_usize(segment);
|
||||
row[ADDR_VIRTUAL] = F::from_canonical_usize(virt);
|
||||
for j in 0..VALUE_LIMBS {
|
||||
row[value_limb(j)] = F::from_canonical_u32((self.value >> (j * 32)).low_u32());
|
||||
}
|
||||
@ -80,12 +86,12 @@ fn get_max_range_check(memory_ops: &[MemoryOp]) -> usize {
|
||||
.iter()
|
||||
.tuple_windows()
|
||||
.map(|(curr, next)| {
|
||||
if curr.context != next.context {
|
||||
next.context - curr.context - 1
|
||||
} else if curr.segment != next.segment {
|
||||
next.segment as usize - curr.segment as usize - 1
|
||||
} else if curr.virt != next.virt {
|
||||
next.virt - curr.virt - 1
|
||||
if curr.address.context != next.address.context {
|
||||
next.address.context - curr.address.context - 1
|
||||
} else if curr.address.segment != next.address.segment {
|
||||
next.address.segment as usize - curr.address.segment as usize - 1
|
||||
} else if curr.address.virt != next.address.virt {
|
||||
next.address.virt - curr.address.virt - 1
|
||||
} else {
|
||||
next.timestamp - curr.timestamp - 1
|
||||
}
|
||||
@ -140,7 +146,14 @@ impl<F: RichField + Extendable<D>, const D: usize> MemoryStark<F, D> {
|
||||
/// Generate most of the trace rows. Excludes a few columns like `COUNTER`, which are generated
|
||||
/// later, after transposing to column-major form.
|
||||
fn generate_trace_row_major(&self, mut memory_ops: Vec<MemoryOp>) -> Vec<[F; NUM_COLUMNS]> {
|
||||
memory_ops.sort_by_key(|op| (op.context, op.segment, op.virt, op.timestamp));
|
||||
memory_ops.sort_by_key(|op| {
|
||||
(
|
||||
op.address.context,
|
||||
op.address.segment,
|
||||
op.address.virt,
|
||||
op.timestamp,
|
||||
)
|
||||
});
|
||||
|
||||
Self::pad_memory_ops(&mut memory_ops);
|
||||
|
||||
@ -181,7 +194,7 @@ impl<F: RichField + Extendable<D>, const D: usize> MemoryStark<F, D> {
|
||||
memory_ops.push(MemoryOp {
|
||||
filter: false,
|
||||
timestamp: last_op.timestamp + i + 1,
|
||||
is_read: true,
|
||||
op: Read,
|
||||
..last_op
|
||||
});
|
||||
}
|
||||
|
||||
@ -24,19 +24,37 @@ impl MemoryChannel {
|
||||
}
|
||||
}
|
||||
|
||||
pub type MemoryAddress = (u32, u32, u32);
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct MemoryAddress {
|
||||
pub(crate) context: usize,
|
||||
pub(crate) segment: usize,
|
||||
pub(crate) virt: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
impl MemoryAddress {
|
||||
pub(crate) fn new(context: usize, segment: usize, virt: usize) -> Self {
|
||||
Self {
|
||||
context,
|
||||
segment,
|
||||
virt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum MemoryOpKind {
|
||||
Read,
|
||||
Write(U256),
|
||||
Write,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MemoryOp {
|
||||
pub timestamp: u64,
|
||||
/// true if this is an actual memory operation, or false if it's a padding row.
|
||||
pub filter: bool,
|
||||
pub timestamp: usize,
|
||||
pub address: MemoryAddress,
|
||||
pub op: MemoryOpKind,
|
||||
pub value: U256,
|
||||
}
|
||||
|
||||
impl MemoryOp {
|
||||
@ -45,17 +63,20 @@ impl MemoryOp {
|
||||
clock: usize,
|
||||
address: MemoryAddress,
|
||||
op: MemoryOpKind,
|
||||
value: U256,
|
||||
) -> Self {
|
||||
let timestamp = (clock * NUM_CHANNELS + channel.index()) as u64;
|
||||
let timestamp = clock * NUM_CHANNELS + channel.index();
|
||||
MemoryOp {
|
||||
filter: true,
|
||||
timestamp,
|
||||
address,
|
||||
op,
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct MemoryState {
|
||||
contents: HashMap<MemoryAddress, U256>,
|
||||
}
|
||||
@ -66,7 +87,7 @@ impl MemoryState {
|
||||
|
||||
for (i, &byte) in kernel_code.iter().enumerate() {
|
||||
if byte != 0 {
|
||||
let address = (0, 0, i as u32);
|
||||
let address = MemoryAddress::new(0, 0, i);
|
||||
let val = byte.into();
|
||||
contents.insert(address, val);
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
mod errors;
|
||||
mod memory;
|
||||
pub(crate) mod memory;
|
||||
mod operation;
|
||||
mod state;
|
||||
mod traces;
|
||||
pub(crate) mod state;
|
||||
pub(crate) mod traces;
|
||||
pub mod transition;
|
||||
mod util;
|
||||
pub(crate) mod util;
|
||||
|
||||
@ -8,7 +8,7 @@ use crate::cpu::simple_logic::eq_iszero::generate_pinv_diff;
|
||||
use crate::logic;
|
||||
use crate::memory::segments::Segment;
|
||||
use crate::witness::errors::ProgramError;
|
||||
use crate::witness::memory::MemoryState;
|
||||
use crate::witness::memory::{MemoryAddress, MemoryState};
|
||||
use crate::witness::state::RegistersState;
|
||||
use crate::witness::traces::Traces;
|
||||
use crate::witness::util::{
|
||||
@ -17,7 +17,7 @@ use crate::witness::util::{
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Operation {
|
||||
pub(crate) enum Operation {
|
||||
Dup(u8),
|
||||
Swap(u8),
|
||||
Iszero,
|
||||
@ -25,53 +25,12 @@ pub enum Operation {
|
||||
Syscall(u8),
|
||||
Eq,
|
||||
ExitKernel,
|
||||
BinaryLogic(BinaryLogicOp),
|
||||
BinaryLogic(logic::Op),
|
||||
NotImplemented,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum BinaryLogicOp {
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
}
|
||||
|
||||
impl BinaryLogicOp {
|
||||
pub(self) fn result(&self, a: U256, b: U256) -> U256 {
|
||||
match self {
|
||||
BinaryLogicOp::And => a & b,
|
||||
BinaryLogicOp::Or => a | b,
|
||||
BinaryLogicOp::Xor => a ^ b,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_logic_row<F: Field>(
|
||||
op: BinaryLogicOp,
|
||||
in0: U256,
|
||||
in1: U256,
|
||||
result: U256,
|
||||
) -> [F; logic::columns::NUM_COLUMNS] {
|
||||
let mut row = [F::ZERO; logic::columns::NUM_COLUMNS];
|
||||
row[match op {
|
||||
BinaryLogicOp::And => logic::columns::IS_AND,
|
||||
BinaryLogicOp::Or => logic::columns::IS_OR,
|
||||
BinaryLogicOp::Xor => logic::columns::IS_XOR,
|
||||
}] = F::ONE;
|
||||
for i in 0..256 {
|
||||
row[logic::columns::INPUT0.start + i] = F::from_bool(in0.bit(i));
|
||||
row[logic::columns::INPUT1.start + i] = F::from_bool(in1.bit(i));
|
||||
}
|
||||
let result_limbs: &[u64] = result.as_ref();
|
||||
for (i, &limb) in result_limbs.iter().enumerate() {
|
||||
row[logic::columns::RESULT.start + 2 * i] = F::from_canonical_u32(limb as u32);
|
||||
row[logic::columns::RESULT.start + 2 * i + 1] = F::from_canonical_u32((limb >> 32) as u32);
|
||||
}
|
||||
row
|
||||
}
|
||||
|
||||
pub fn generate_binary_logic_op<F: Field>(
|
||||
op: BinaryLogicOp,
|
||||
pub(crate) fn generate_binary_logic_op<F: Field>(
|
||||
op: logic::Op,
|
||||
mut registers_state: RegistersState,
|
||||
memory_state: &MemoryState,
|
||||
traces: &mut Traces<F>,
|
||||
@ -82,7 +41,7 @@ pub fn generate_binary_logic_op<F: Field>(
|
||||
let result = op.result(in0, in1);
|
||||
let log_out = stack_push_log_and_fill(&mut registers_state, traces, &mut row, result)?;
|
||||
|
||||
traces.push_logic(make_logic_row(op, in0, in1, result));
|
||||
traces.push_logic(logic::Operation::new(op, in0, in1));
|
||||
traces.push_memory(log_in0);
|
||||
traces.push_memory(log_in1);
|
||||
traces.push_memory(log_out);
|
||||
@ -90,7 +49,7 @@ pub fn generate_binary_logic_op<F: Field>(
|
||||
Ok(registers_state)
|
||||
}
|
||||
|
||||
pub fn generate_dup<F: Field>(
|
||||
pub(crate) fn generate_dup<F: Field>(
|
||||
n: u8,
|
||||
mut registers_state: RegistersState,
|
||||
memory_state: &MemoryState,
|
||||
@ -99,11 +58,11 @@ pub fn generate_dup<F: Field>(
|
||||
) -> Result<RegistersState, ProgramError> {
|
||||
let other_addr_lo = registers_state
|
||||
.stack_len
|
||||
.checked_sub(1 + (n as u32))
|
||||
.checked_sub(1 + (n as usize))
|
||||
.ok_or(ProgramError::StackUnderflow)?;
|
||||
let other_addr = (
|
||||
let other_addr = MemoryAddress::new(
|
||||
registers_state.context,
|
||||
Segment::Stack as u32,
|
||||
Segment::Stack as usize,
|
||||
other_addr_lo,
|
||||
);
|
||||
|
||||
@ -117,7 +76,7 @@ pub fn generate_dup<F: Field>(
|
||||
Ok(registers_state)
|
||||
}
|
||||
|
||||
pub fn generate_swap<F: Field>(
|
||||
pub(crate) fn generate_swap<F: Field>(
|
||||
n: u8,
|
||||
mut registers_state: RegistersState,
|
||||
memory_state: &MemoryState,
|
||||
@ -126,11 +85,11 @@ pub fn generate_swap<F: Field>(
|
||||
) -> Result<RegistersState, ProgramError> {
|
||||
let other_addr_lo = registers_state
|
||||
.stack_len
|
||||
.checked_sub(2 + (n as u32))
|
||||
.checked_sub(2 + (n as usize))
|
||||
.ok_or(ProgramError::StackUnderflow)?;
|
||||
let other_addr = (
|
||||
let other_addr = MemoryAddress::new(
|
||||
registers_state.context,
|
||||
Segment::Stack as u32,
|
||||
Segment::Stack as usize,
|
||||
other_addr_lo,
|
||||
);
|
||||
|
||||
@ -150,7 +109,7 @@ pub fn generate_swap<F: Field>(
|
||||
Ok(registers_state)
|
||||
}
|
||||
|
||||
pub fn generate_not<F: Field>(
|
||||
pub(crate) fn generate_not<F: Field>(
|
||||
mut registers_state: RegistersState,
|
||||
memory_state: &MemoryState,
|
||||
traces: &mut Traces<F>,
|
||||
@ -167,7 +126,7 @@ pub fn generate_not<F: Field>(
|
||||
Ok(registers_state)
|
||||
}
|
||||
|
||||
pub fn generate_iszero<F: Field>(
|
||||
pub(crate) fn generate_iszero<F: Field>(
|
||||
mut registers_state: RegistersState,
|
||||
memory_state: &MemoryState,
|
||||
traces: &mut Traces<F>,
|
||||
@ -190,39 +149,39 @@ pub fn generate_iszero<F: Field>(
|
||||
Ok(registers_state)
|
||||
}
|
||||
|
||||
pub fn generate_syscall<F: Field>(
|
||||
pub(crate) fn generate_syscall<F: Field>(
|
||||
opcode: u8,
|
||||
mut registers_state: RegistersState,
|
||||
memory_state: &MemoryState,
|
||||
traces: &mut Traces<F>,
|
||||
mut row: CpuColumnsView<F>,
|
||||
) -> Result<RegistersState, ProgramError> {
|
||||
let handler_jumptable_addr = KERNEL.global_labels["syscall_jumptable"] as u32;
|
||||
let handler_addr_addr = handler_jumptable_addr + (opcode as u32);
|
||||
let handler_jumptable_addr = KERNEL.global_labels["syscall_jumptable"] as usize;
|
||||
let handler_addr_addr = handler_jumptable_addr + (opcode as usize);
|
||||
let (handler_addr0, log_in0) = mem_read_gp_with_log_and_fill(
|
||||
0,
|
||||
(0, Segment::Code as u32, handler_addr_addr),
|
||||
MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr),
|
||||
memory_state,
|
||||
traces,
|
||||
&mut row,
|
||||
);
|
||||
let (handler_addr1, log_in1) = mem_read_gp_with_log_and_fill(
|
||||
1,
|
||||
(0, Segment::Code as u32, handler_addr_addr + 1),
|
||||
MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr + 1),
|
||||
memory_state,
|
||||
traces,
|
||||
&mut row,
|
||||
);
|
||||
let (handler_addr2, log_in2) = mem_read_gp_with_log_and_fill(
|
||||
2,
|
||||
(0, Segment::Code as u32, handler_addr_addr + 2),
|
||||
MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr + 2),
|
||||
memory_state,
|
||||
traces,
|
||||
&mut row,
|
||||
);
|
||||
|
||||
let handler_addr = (handler_addr0 << 16) + (handler_addr1 << 8) + handler_addr2;
|
||||
let new_program_counter = handler_addr.as_u32();
|
||||
let new_program_counter = handler_addr.as_usize();
|
||||
|
||||
let syscall_info = U256::from(registers_state.program_counter)
|
||||
+ (U256::from(u64::from(registers_state.is_kernel)) << 32);
|
||||
@ -240,7 +199,7 @@ pub fn generate_syscall<F: Field>(
|
||||
Ok(registers_state)
|
||||
}
|
||||
|
||||
pub fn generate_eq<F: Field>(
|
||||
pub(crate) fn generate_eq<F: Field>(
|
||||
mut registers_state: RegistersState,
|
||||
memory_state: &MemoryState,
|
||||
traces: &mut Traces<F>,
|
||||
@ -261,7 +220,7 @@ pub fn generate_eq<F: Field>(
|
||||
Ok(registers_state)
|
||||
}
|
||||
|
||||
pub fn generate_exit_kernel<F: Field>(
|
||||
pub(crate) fn generate_exit_kernel<F: Field>(
|
||||
mut registers_state: RegistersState,
|
||||
memory_state: &MemoryState,
|
||||
traces: &mut Traces<F>,
|
||||
@ -270,7 +229,7 @@ pub fn generate_exit_kernel<F: Field>(
|
||||
let [(kexit_info, log_in)] =
|
||||
stack_pop_with_log_and_fill::<1, _>(&mut registers_state, memory_state, traces, &mut row)?;
|
||||
let kexit_info_u64: [u64; 4] = kexit_info.0;
|
||||
let program_counter = kexit_info_u64[0] as u32;
|
||||
let program_counter = kexit_info_u64[0] as usize;
|
||||
let is_kernel_mode_val = (kexit_info_u64[1] >> 32) as u32;
|
||||
assert!(is_kernel_mode_val == 0 || is_kernel_mode_val == 1);
|
||||
let is_kernel_mode = is_kernel_mode_val != 0;
|
||||
|
||||
@ -1,7 +1,20 @@
|
||||
use crate::cpu::kernel::aggregator::KERNEL;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct RegistersState {
|
||||
pub program_counter: u32,
|
||||
pub program_counter: usize,
|
||||
pub is_kernel: bool,
|
||||
pub stack_len: u32,
|
||||
pub context: u32,
|
||||
pub stack_len: usize,
|
||||
pub context: usize,
|
||||
}
|
||||
|
||||
impl Default for RegistersState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
program_counter: KERNEL.global_labels["main"],
|
||||
is_kernel: true,
|
||||
stack_len: 0,
|
||||
context: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,19 @@
|
||||
use crate::arithmetic::columns::NUM_ARITH_COLUMNS;
|
||||
use crate::cpu::columns::CpuColumnsView;
|
||||
use crate::logic;
|
||||
use crate::witness::memory::MemoryOp;
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::polynomial::PolynomialValues;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::util::timing::TimingTree;
|
||||
|
||||
use crate::all_stark::{AllStark, NUM_TABLES};
|
||||
use crate::arithmetic::columns::NUM_ARITH_COLUMNS;
|
||||
use crate::config::StarkConfig;
|
||||
use crate::cpu::columns::CpuColumnsView;
|
||||
use crate::keccak_memory::keccak_memory_stark::KeccakMemoryOp;
|
||||
use crate::keccak_sponge::keccak_sponge_stark::KeccakSpongeOp;
|
||||
use crate::util::trace_rows_to_poly_values;
|
||||
use crate::witness::memory::MemoryOp;
|
||||
use crate::{keccak, logic};
|
||||
|
||||
type LogicRow<T> = [T; logic::columns::NUM_COLUMNS];
|
||||
type ArithmeticRow<T> = [T; NUM_ARITH_COLUMNS];
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@ -14,46 +24,54 @@ pub struct TraceCheckpoint {
|
||||
pub(self) memory_len: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Traces<T: Copy> {
|
||||
cpu: Vec<CpuColumnsView<T>>,
|
||||
logic: Vec<LogicRow<T>>,
|
||||
arithmetic: Vec<ArithmeticRow<T>>,
|
||||
memory: Vec<MemoryOp>,
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Traces<T: Copy> {
|
||||
pub(crate) cpu: Vec<CpuColumnsView<T>>,
|
||||
pub(crate) logic_ops: Vec<logic::Operation>,
|
||||
pub(crate) arithmetic: Vec<ArithmeticRow<T>>,
|
||||
pub(crate) memory_ops: Vec<MemoryOp>,
|
||||
pub(crate) keccak_inputs: Vec<[u64; keccak::keccak_stark::NUM_INPUTS]>,
|
||||
pub(crate) keccak_memory_inputs: Vec<KeccakMemoryOp>,
|
||||
pub(crate) keccak_sponge_ops: Vec<KeccakSpongeOp>,
|
||||
}
|
||||
|
||||
impl<T: Copy> Traces<T> {
|
||||
pub fn new() -> Self {
|
||||
Traces {
|
||||
cpu: vec![],
|
||||
logic: vec![],
|
||||
logic_ops: vec![],
|
||||
arithmetic: vec![],
|
||||
memory: vec![],
|
||||
memory_ops: vec![],
|
||||
keccak_inputs: vec![],
|
||||
keccak_memory_inputs: vec![],
|
||||
keccak_sponge_ops: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checkpoint(&self) -> TraceCheckpoint {
|
||||
TraceCheckpoint {
|
||||
cpu_len: self.cpu.len(),
|
||||
logic_len: self.logic.len(),
|
||||
logic_len: self.logic_ops.len(),
|
||||
arithmetic_len: self.arithmetic.len(),
|
||||
memory_len: self.memory.len(),
|
||||
memory_len: self.memory_ops.len(),
|
||||
// TODO others
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rollback(&mut self, checkpoint: TraceCheckpoint) {
|
||||
self.cpu.truncate(checkpoint.cpu_len);
|
||||
self.logic.truncate(checkpoint.logic_len);
|
||||
self.logic_ops.truncate(checkpoint.logic_len);
|
||||
self.arithmetic.truncate(checkpoint.arithmetic_len);
|
||||
self.memory.truncate(checkpoint.memory_len);
|
||||
self.memory_ops.truncate(checkpoint.memory_len);
|
||||
// TODO others
|
||||
}
|
||||
|
||||
pub fn push_cpu(&mut self, val: CpuColumnsView<T>) {
|
||||
self.cpu.push(val);
|
||||
}
|
||||
|
||||
pub fn push_logic(&mut self, val: LogicRow<T>) {
|
||||
self.logic.push(val);
|
||||
pub fn push_logic(&mut self, val: logic::Operation) {
|
||||
self.logic_ops.push(val);
|
||||
}
|
||||
|
||||
pub fn push_arithmetic(&mut self, val: ArithmeticRow<T>) {
|
||||
@ -61,12 +79,51 @@ impl<T: Copy> Traces<T> {
|
||||
}
|
||||
|
||||
pub fn push_memory(&mut self, val: MemoryOp) {
|
||||
self.memory.push(val);
|
||||
self.memory_ops.push(val);
|
||||
}
|
||||
|
||||
pub fn clock(&self) -> usize {
|
||||
self.cpu.len()
|
||||
}
|
||||
|
||||
pub fn to_tables<const D: usize>(
|
||||
self,
|
||||
all_stark: &AllStark<T, D>,
|
||||
config: &StarkConfig,
|
||||
timing: &mut TimingTree,
|
||||
) -> [Vec<PolynomialValues<T>>; NUM_TABLES]
|
||||
where
|
||||
T: RichField + Extendable<D>,
|
||||
{
|
||||
let Traces {
|
||||
cpu,
|
||||
logic_ops,
|
||||
arithmetic,
|
||||
memory_ops,
|
||||
keccak_inputs,
|
||||
keccak_memory_inputs,
|
||||
keccak_sponge_ops,
|
||||
} = self;
|
||||
|
||||
let cpu_rows = cpu.into_iter().map(|x| x.into()).collect();
|
||||
let cpu_trace = trace_rows_to_poly_values(cpu_rows);
|
||||
let keccak_trace = all_stark.keccak_stark.generate_trace(keccak_inputs, timing);
|
||||
let keccak_memory_trace = all_stark.keccak_memory_stark.generate_trace(
|
||||
keccak_memory_inputs,
|
||||
config.fri_config.num_cap_elements(),
|
||||
timing,
|
||||
);
|
||||
let logic_trace = all_stark.logic_stark.generate_trace(logic_ops, timing);
|
||||
let memory_trace = all_stark.memory_stark.generate_trace(memory_ops, timing);
|
||||
|
||||
[
|
||||
cpu_trace,
|
||||
keccak_trace,
|
||||
keccak_memory_trace,
|
||||
logic_trace,
|
||||
memory_trace,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> Default for Traces<T> {
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
use plonky2::field::types::Field;
|
||||
|
||||
use crate::cpu::columns::{CpuColumnsView, NUM_CPU_COLUMNS};
|
||||
use crate::logic;
|
||||
use crate::memory::segments::Segment;
|
||||
use crate::witness::errors::ProgramError;
|
||||
use crate::witness::memory::MemoryState;
|
||||
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, BinaryLogicOp, Operation,
|
||||
generate_not, 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;
|
||||
|
||||
const KERNEL_CONTEXT: u32 = 0;
|
||||
const KERNEL_CONTEXT: usize = 0;
|
||||
|
||||
fn read_code_memory<F: Field>(
|
||||
registers_state: RegistersState,
|
||||
@ -25,11 +26,11 @@ fn read_code_memory<F: Field>(
|
||||
} else {
|
||||
registers_state.context
|
||||
};
|
||||
row.code_context = F::from_canonical_u32(code_context);
|
||||
row.code_context = F::from_canonical_usize(code_context);
|
||||
|
||||
let address = (
|
||||
let address = MemoryAddress::new(
|
||||
code_context,
|
||||
Segment::Code as u32,
|
||||
Segment::Code as usize,
|
||||
registers_state.program_counter,
|
||||
);
|
||||
let (opcode, mem_log) = mem_read_code_with_log_and_fill(address, memory_state, traces, row);
|
||||
@ -62,9 +63,9 @@ fn decode(registers_state: RegistersState, opcode: u8) -> Result<Operation, Prog
|
||||
(0x13, _) => Ok(Operation::Syscall(opcode)),
|
||||
(0x14, _) => Ok(Operation::Eq),
|
||||
(0x15, _) => Ok(Operation::Iszero),
|
||||
(0x16, _) => Ok(Operation::BinaryLogic(BinaryLogicOp::And)),
|
||||
(0x17, _) => Ok(Operation::BinaryLogic(BinaryLogicOp::Or)),
|
||||
(0x18, _) => Ok(Operation::BinaryLogic(BinaryLogicOp::Xor)),
|
||||
(0x16, _) => Ok(Operation::BinaryLogic(logic::Op::And)),
|
||||
(0x17, _) => Ok(Operation::BinaryLogic(logic::Op::Or)),
|
||||
(0x18, _) => Ok(Operation::BinaryLogic(logic::Op::Xor)),
|
||||
(0x19, _) => Ok(Operation::Not),
|
||||
(0x1a, _) => Ok(Operation::NotImplemented),
|
||||
(0x1b, _) => Ok(Operation::NotImplemented),
|
||||
@ -151,9 +152,9 @@ fn fill_op_flag<F: Field>(op: Operation, row: &mut CpuColumnsView<F>) {
|
||||
Operation::Syscall(_) => &mut flags.syscall,
|
||||
Operation::Eq => &mut flags.eq,
|
||||
Operation::ExitKernel => &mut flags.exit_kernel,
|
||||
Operation::BinaryLogic(BinaryLogicOp::And) => &mut flags.and,
|
||||
Operation::BinaryLogic(BinaryLogicOp::Or) => &mut flags.or,
|
||||
Operation::BinaryLogic(BinaryLogicOp::Xor) => &mut flags.xor,
|
||||
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::NotImplemented => panic!("operation not implemented"),
|
||||
} = F::ONE;
|
||||
}
|
||||
@ -199,6 +200,14 @@ fn try_perform_instruction<F: Field>(
|
||||
|
||||
let opcode = read_code_memory(registers_state, memory_state, traces, &mut row);
|
||||
let op = decode(registers_state, opcode)?;
|
||||
log::trace!(
|
||||
"Executing {}={:?} at {}",
|
||||
opcode,
|
||||
op,
|
||||
registers_state.program_counter
|
||||
);
|
||||
// TODO: Temporarily slowing down so we can view logs easily.
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
fill_op_flag(op, &mut row);
|
||||
|
||||
perform_op(op, registers_state, memory_state, traces, row)
|
||||
@ -212,7 +221,7 @@ fn handle_error<F: Field>(
|
||||
todo!("constraints for exception handling are not implemented");
|
||||
}
|
||||
|
||||
pub fn transition<F: Field>(
|
||||
pub(crate) fn transition<F: Field>(
|
||||
registers_state: RegistersState,
|
||||
memory_state: &MemoryState,
|
||||
traces: &mut Traces<F>,
|
||||
|
||||
@ -23,27 +23,27 @@ fn to_bits_le<F: Field>(n: u8) -> [F; 8] {
|
||||
res
|
||||
}
|
||||
|
||||
pub fn mem_read_with_log<T: Copy>(
|
||||
pub(crate) fn mem_read_with_log<T: Copy>(
|
||||
channel: MemoryChannel,
|
||||
address: MemoryAddress,
|
||||
memory_state: &MemoryState,
|
||||
traces: &Traces<T>,
|
||||
) -> (U256, MemoryOp) {
|
||||
let val = memory_state.get(address);
|
||||
let op = MemoryOp::new(channel, traces.clock(), address, MemoryOpKind::Read);
|
||||
let op = MemoryOp::new(channel, traces.clock(), address, MemoryOpKind::Read, val);
|
||||
(val, op)
|
||||
}
|
||||
|
||||
pub fn mem_write_log<T: Copy>(
|
||||
pub(crate) fn mem_write_log<T: Copy>(
|
||||
channel: MemoryChannel,
|
||||
address: MemoryAddress,
|
||||
traces: &Traces<T>,
|
||||
val: U256,
|
||||
) -> MemoryOp {
|
||||
MemoryOp::new(channel, traces.clock(), address, MemoryOpKind::Write(val))
|
||||
MemoryOp::new(channel, traces.clock(), address, MemoryOpKind::Write, val)
|
||||
}
|
||||
|
||||
pub fn mem_read_code_with_log_and_fill<F: Field>(
|
||||
pub(crate) fn mem_read_code_with_log_and_fill<F: Field>(
|
||||
address: MemoryAddress,
|
||||
memory_state: &MemoryState,
|
||||
traces: &Traces<F>,
|
||||
@ -57,7 +57,7 @@ pub fn mem_read_code_with_log_and_fill<F: Field>(
|
||||
(val_u8, op)
|
||||
}
|
||||
|
||||
pub fn mem_read_gp_with_log_and_fill<F: Field>(
|
||||
pub(crate) fn mem_read_gp_with_log_and_fill<F: Field>(
|
||||
n: usize,
|
||||
address: MemoryAddress,
|
||||
memory_state: &MemoryState,
|
||||
@ -75,9 +75,9 @@ pub fn mem_read_gp_with_log_and_fill<F: Field>(
|
||||
let channel = &mut row.mem_channels[n];
|
||||
channel.used = F::ONE;
|
||||
channel.is_read = F::ONE;
|
||||
channel.addr_context = F::from_canonical_u32(address.0);
|
||||
channel.addr_segment = F::from_canonical_u32(address.1);
|
||||
channel.addr_virtual = F::from_canonical_u32(address.2);
|
||||
channel.addr_context = F::from_canonical_usize(address.context);
|
||||
channel.addr_segment = F::from_canonical_usize(address.segment);
|
||||
channel.addr_virtual = F::from_canonical_usize(address.virt);
|
||||
for (i, limb) in val_limbs.into_iter().enumerate() {
|
||||
channel.value[2 * i] = F::from_canonical_u32(limb as u32);
|
||||
channel.value[2 * i + 1] = F::from_canonical_u32((limb >> 32) as u32);
|
||||
@ -86,7 +86,7 @@ pub fn mem_read_gp_with_log_and_fill<F: Field>(
|
||||
(val, op)
|
||||
}
|
||||
|
||||
pub fn mem_write_gp_log_and_fill<F: Field>(
|
||||
pub(crate) fn mem_write_gp_log_and_fill<F: Field>(
|
||||
n: usize,
|
||||
address: MemoryAddress,
|
||||
traces: &Traces<F>,
|
||||
@ -99,9 +99,9 @@ pub fn mem_write_gp_log_and_fill<F: Field>(
|
||||
let channel = &mut row.mem_channels[n];
|
||||
channel.used = F::ONE;
|
||||
channel.is_read = F::ZERO;
|
||||
channel.addr_context = F::from_canonical_u32(address.0);
|
||||
channel.addr_segment = F::from_canonical_u32(address.1);
|
||||
channel.addr_virtual = F::from_canonical_u32(address.2);
|
||||
channel.addr_context = F::from_canonical_usize(address.context);
|
||||
channel.addr_segment = F::from_canonical_usize(address.segment);
|
||||
channel.addr_virtual = F::from_canonical_usize(address.virt);
|
||||
for (i, limb) in val_limbs.into_iter().enumerate() {
|
||||
channel.value[2 * i] = F::from_canonical_u32(limb as u32);
|
||||
channel.value[2 * i + 1] = F::from_canonical_u32((limb >> 32) as u32);
|
||||
@ -110,7 +110,7 @@ pub fn mem_write_gp_log_and_fill<F: Field>(
|
||||
op
|
||||
}
|
||||
|
||||
pub fn stack_pop_with_log_and_fill<const N: usize, F: Field>(
|
||||
pub(crate) fn stack_pop_with_log_and_fill<const N: usize, F: Field>(
|
||||
registers_state: &mut RegistersState,
|
||||
memory_state: &MemoryState,
|
||||
traces: &Traces<F>,
|
||||
@ -123,10 +123,10 @@ pub fn stack_pop_with_log_and_fill<const N: usize, F: Field>(
|
||||
let result = {
|
||||
let mut i = 0usize;
|
||||
[(); N].map(|_| {
|
||||
let address = (
|
||||
let address = MemoryAddress::new(
|
||||
registers_state.context,
|
||||
Segment::Stack as u32,
|
||||
registers_state.stack_len - 1 - (i as u32),
|
||||
Segment::Stack as usize,
|
||||
registers_state.stack_len - 1 - i,
|
||||
);
|
||||
let res = mem_read_gp_with_log_and_fill(i, address, memory_state, traces, row);
|
||||
i += 1;
|
||||
@ -134,12 +134,12 @@ pub fn stack_pop_with_log_and_fill<const N: usize, F: Field>(
|
||||
})
|
||||
};
|
||||
|
||||
registers_state.stack_len -= N as u32;
|
||||
registers_state.stack_len -= N;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub fn stack_push_log_and_fill<F: Field>(
|
||||
pub(crate) fn stack_push_log_and_fill<F: Field>(
|
||||
registers_state: &mut RegistersState,
|
||||
traces: &Traces<F>,
|
||||
row: &mut CpuColumnsView<F>,
|
||||
@ -149,9 +149,9 @@ pub fn stack_push_log_and_fill<F: Field>(
|
||||
return Err(ProgramError::StackOverflow);
|
||||
}
|
||||
|
||||
let address = (
|
||||
let address = MemoryAddress::new(
|
||||
registers_state.context,
|
||||
Segment::Stack as u32,
|
||||
Segment::Stack as usize,
|
||||
registers_state.stack_len,
|
||||
);
|
||||
let res = mem_write_gp_log_and_fill(NUM_GP_CHANNELS - 1, address, traces, row, val);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use eth_trie_utils::partial_trie::{Nibbles, PartialTrie};
|
||||
use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV};
|
||||
use eth_trie_utils::partial_trie::PartialTrie;
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::plonk::config::PoseidonGoldilocksConfig;
|
||||
use plonky2::util::timing::TimingTree;
|
||||
@ -18,6 +19,8 @@ type C = PoseidonGoldilocksConfig;
|
||||
/// Execute the empty list of transactions, i.e. a no-op.
|
||||
#[test]
|
||||
fn test_empty_txn_list() -> anyhow::Result<()> {
|
||||
init_logger();
|
||||
|
||||
let all_stark = AllStark::<F, D>::default();
|
||||
let config = StarkConfig::standard_fast_config();
|
||||
|
||||
@ -80,3 +83,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> {
|
||||
|
||||
verify_proof(all_stark, proof, &config)
|
||||
}
|
||||
|
||||
fn init_logger() {
|
||||
let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "trace"));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user