mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-05 23:33: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::columns::{CpuColumnsView, NUM_CPU_COLUMNS};
|
||||||
use crate::cpu::kernel::aggregator::KERNEL;
|
use crate::cpu::kernel::aggregator::KERNEL;
|
||||||
use crate::cpu::kernel::keccak_util::keccakf_u32s;
|
use crate::cpu::kernel::keccak_util::keccakf_u32s;
|
||||||
use crate::generation::state::GenerationState;
|
|
||||||
use crate::keccak_sponge::columns::KECCAK_RATE_U32S;
|
use crate::keccak_sponge::columns::KECCAK_RATE_U32S;
|
||||||
use crate::memory::segments::Segment;
|
use crate::memory::segments::Segment;
|
||||||
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
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 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
|
/// 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.
|
/// want them to fit in a single limb of Keccak input.
|
||||||
const BYTES_PER_ROW: usize = 4;
|
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_state = [0u32; 50];
|
||||||
let mut sponge_input_pos: usize = 0;
|
let mut sponge_input_pos: usize = 0;
|
||||||
|
|
||||||
@ -35,30 +40,41 @@ pub(crate) fn generate_bootstrap_kernel<F: Field>(state: &mut GenerationState<F>
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
.chunks(BYTES_PER_ROW)
|
.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.
|
// Write this chunk to memory, while simultaneously packing its bytes into a u32 word.
|
||||||
let mut packed_bytes: u32 = 0;
|
let mut packed_bytes: u32 = 0;
|
||||||
for (channel, (addr, &byte)) in chunk.enumerate() {
|
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;
|
packed_bytes = (packed_bytes << 8) | byte as u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
sponge_state[sponge_input_pos] = packed_bytes;
|
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);
|
keccak.input_limbs = sponge_state.map(F::from_canonical_u32);
|
||||||
state.commit_cpu_row();
|
|
||||||
|
|
||||||
sponge_input_pos = (sponge_input_pos + 1) % KECCAK_RATE_U32S;
|
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
|
// If we just crossed a multiple of KECCAK_RATE_LIMBS, then we've filled the Keccak input
|
||||||
// buffer, so it's time to absorb.
|
// buffer, so it's time to absorb.
|
||||||
if sponge_input_pos == 0 {
|
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);
|
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);
|
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::mem::{size_of, transmute};
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
use plonky2::field::types::Field;
|
||||||
|
|
||||||
use crate::cpu::columns::general::CpuGeneralColumnsView;
|
use crate::cpu::columns::general::CpuGeneralColumnsView;
|
||||||
use crate::cpu::columns::ops::OpsColumnsView;
|
use crate::cpu::columns::ops::OpsColumnsView;
|
||||||
use crate::cpu::membus::NUM_GP_CHANNELS;
|
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.
|
// `u8` is guaranteed to have a `size_of` of 1.
|
||||||
pub const NUM_CPU_COLUMNS: usize = size_of::<CpuColumnsView<u8>>();
|
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> {
|
impl<T: Copy> From<[T; NUM_CPU_COLUMNS]> for CpuColumnsView<T> {
|
||||||
fn from(value: [T; NUM_CPU_COLUMNS]) -> Self {
|
fn from(value: [T; NUM_CPU_COLUMNS]) -> Self {
|
||||||
unsafe { transmute_no_compile_time_size_checks(value) }
|
unsafe { transmute_no_compile_time_size_checks(value) }
|
||||||
|
|||||||
@ -1,50 +1,51 @@
|
|||||||
use ethereum_types::U256;
|
// TODO: Remove?
|
||||||
|
// use ethereum_types::U256;
|
||||||
use crate::memory::memory_stark::MemoryOp;
|
//
|
||||||
use crate::memory::segments::Segment;
|
// use crate::memory::memory_stark::MemoryOp;
|
||||||
|
// use crate::memory::segments::Segment;
|
||||||
#[allow(unused)] // TODO: Should be used soon.
|
//
|
||||||
#[derive(Debug)]
|
// #[allow(unused)] // TODO: Should be used soon.
|
||||||
pub(crate) struct MemoryState {
|
// #[derive(Debug)]
|
||||||
/// A log of each memory operation, in the order that it occurred.
|
// pub(crate) struct MemoryState {
|
||||||
pub log: Vec<MemoryOp>,
|
// /// A log of each memory operation, in the order that it occurred.
|
||||||
|
// pub log: Vec<MemoryOp>,
|
||||||
pub contexts: Vec<MemoryContextState>,
|
//
|
||||||
}
|
// pub contexts: Vec<MemoryContextState>,
|
||||||
|
// }
|
||||||
impl Default for MemoryState {
|
//
|
||||||
fn default() -> Self {
|
// impl Default for MemoryState {
|
||||||
Self {
|
// fn default() -> Self {
|
||||||
log: vec![],
|
// Self {
|
||||||
// We start with an initial context for the kernel.
|
// log: vec![],
|
||||||
contexts: vec![MemoryContextState::default()],
|
// // We start with an initial context for the kernel.
|
||||||
}
|
// contexts: vec![MemoryContextState::default()],
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
#[derive(Clone, Default, Debug)]
|
//
|
||||||
pub(crate) struct MemoryContextState {
|
// #[derive(Clone, Default, Debug)]
|
||||||
/// The content of each memory segment.
|
// pub(crate) struct MemoryContextState {
|
||||||
pub segments: [MemorySegmentState; Segment::COUNT],
|
// /// The content of each memory segment.
|
||||||
}
|
// pub segments: [MemorySegmentState; Segment::COUNT],
|
||||||
|
// }
|
||||||
#[derive(Clone, Default, Debug)]
|
//
|
||||||
pub(crate) struct MemorySegmentState {
|
// #[derive(Clone, Default, Debug)]
|
||||||
pub content: Vec<U256>,
|
// pub(crate) struct MemorySegmentState {
|
||||||
}
|
// pub content: Vec<U256>,
|
||||||
|
// }
|
||||||
impl MemorySegmentState {
|
//
|
||||||
pub(crate) fn get(&self, virtual_addr: usize) -> U256 {
|
// impl MemorySegmentState {
|
||||||
self.content
|
// pub(crate) fn get(&self, virtual_addr: usize) -> U256 {
|
||||||
.get(virtual_addr)
|
// self.content
|
||||||
.copied()
|
// .get(virtual_addr)
|
||||||
.unwrap_or(U256::zero())
|
// .copied()
|
||||||
}
|
// .unwrap_or(U256::zero())
|
||||||
|
// }
|
||||||
pub(crate) fn set(&mut self, virtual_addr: usize, value: U256) {
|
//
|
||||||
if virtual_addr >= self.content.len() {
|
// pub(crate) fn set(&mut self, virtual_addr: usize, value: U256) {
|
||||||
self.content.resize(virtual_addr + 1, U256::zero());
|
// if virtual_addr >= self.content.len() {
|
||||||
}
|
// self.content.resize(virtual_addr + 1, U256::zero());
|
||||||
self.content[virtual_addr] = value;
|
// }
|
||||||
}
|
// self.content[virtual_addr] = value;
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|||||||
@ -4,7 +4,6 @@ use eth_trie_utils::partial_trie::PartialTrie;
|
|||||||
use ethereum_types::{Address, BigEndianHash, H256};
|
use ethereum_types::{Address, BigEndianHash, H256};
|
||||||
use plonky2::field::extension::Extendable;
|
use plonky2::field::extension::Extendable;
|
||||||
use plonky2::field::polynomial::PolynomialValues;
|
use plonky2::field::polynomial::PolynomialValues;
|
||||||
use plonky2::field::types::Field;
|
|
||||||
use plonky2::hash::hash_types::RichField;
|
use plonky2::hash::hash_types::RichField;
|
||||||
use plonky2::util::timing::TimingTree;
|
use plonky2::util::timing::TimingTree;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@ -12,13 +11,15 @@ use serde::{Deserialize, Serialize};
|
|||||||
use crate::all_stark::{AllStark, NUM_TABLES};
|
use crate::all_stark::{AllStark, NUM_TABLES};
|
||||||
use crate::config::StarkConfig;
|
use crate::config::StarkConfig;
|
||||||
use crate::cpu::bootstrap_kernel::generate_bootstrap_kernel;
|
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::cpu::kernel::constants::global_metadata::GlobalMetadata;
|
||||||
use crate::generation::state::GenerationState;
|
|
||||||
use crate::memory::segments::Segment;
|
use crate::memory::segments::Segment;
|
||||||
use crate::memory::NUM_CHANNELS;
|
|
||||||
use crate::proof::{BlockMetadata, PublicValues, TrieRoots};
|
use crate::proof::{BlockMetadata, PublicValues, TrieRoots};
|
||||||
use crate::util::trace_rows_to_poly_values;
|
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 memory;
|
||||||
pub(crate) mod mpt;
|
pub(crate) mod mpt;
|
||||||
@ -65,25 +66,33 @@ pub(crate) fn generate_traces<F: RichField + Extendable<D>, const D: usize>(
|
|||||||
config: &StarkConfig,
|
config: &StarkConfig,
|
||||||
timing: &mut TimingTree,
|
timing: &mut TimingTree,
|
||||||
) -> ([Vec<PolynomialValues<F>>; NUM_TABLES], PublicValues) {
|
) -> ([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 {
|
let mut registers_state = RegistersState::default();
|
||||||
generate_txn(&mut state, txn);
|
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 read_metadata = |field| {
|
||||||
|
memory_state.get(MemoryAddress::new(
|
||||||
let cpu_rows = state.cpu_rows.len();
|
|
||||||
let mem_end_timestamp = cpu_rows * NUM_CHANNELS;
|
|
||||||
let mut read_metadata = |field| {
|
|
||||||
state.get_mem(
|
|
||||||
0,
|
0,
|
||||||
Segment::GlobalMetadata,
|
Segment::GlobalMetadata as usize,
|
||||||
field as usize,
|
field as usize,
|
||||||
mem_end_timestamp,
|
))
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let trie_roots_before = TrieRoots {
|
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)),
|
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 {
|
let public_values = PublicValues {
|
||||||
trie_roots_before,
|
trie_roots_before,
|
||||||
trie_roots_after,
|
trie_roots_after,
|
||||||
block_metadata: inputs.block_metadata,
|
block_metadata: inputs.block_metadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
(traces, public_values)
|
(traces.to_tables(all_stark, config, timing), public_values)
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_txn<F: Field>(_state: &mut GenerationState<F>, _signed_txn: &[u8]) {
|
|
||||||
// TODO
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,35 +1,21 @@
|
|||||||
use std::mem;
|
|
||||||
|
|
||||||
use ethereum_types::U256;
|
use ethereum_types::U256;
|
||||||
use plonky2::field::types::Field;
|
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::mpt::all_mpt_prover_inputs_reversed;
|
||||||
use crate::generation::rlp::all_rlp_prover_inputs_reversed;
|
use crate::generation::rlp::all_rlp_prover_inputs_reversed;
|
||||||
use crate::generation::GenerationInputs;
|
use crate::generation::GenerationInputs;
|
||||||
use crate::keccak_memory::keccak_memory_stark::KeccakMemoryOp;
|
use crate::witness::memory::MemoryState;
|
||||||
use crate::memory::memory_stark::MemoryOp;
|
use crate::witness::state::RegistersState;
|
||||||
use crate::memory::segments::Segment;
|
use crate::witness::traces::Traces;
|
||||||
use crate::memory::NUM_CHANNELS;
|
|
||||||
use crate::util::u256_limbs;
|
|
||||||
use crate::{keccak, logic};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct GenerationState<F: Field> {
|
pub(crate) struct GenerationState<F: Field> {
|
||||||
#[allow(unused)] // TODO: Should be used soon.
|
|
||||||
pub(crate) inputs: GenerationInputs,
|
pub(crate) inputs: GenerationInputs,
|
||||||
pub(crate) next_txn_index: usize,
|
pub(crate) registers: RegistersState,
|
||||||
pub(crate) cpu_rows: Vec<[F; NUM_CPU_COLUMNS]>,
|
|
||||||
pub(crate) current_cpu_row: CpuColumnsView<F>,
|
|
||||||
|
|
||||||
pub(crate) current_context: usize,
|
|
||||||
pub(crate) memory: MemoryState,
|
pub(crate) memory: MemoryState,
|
||||||
|
pub(crate) traces: Traces<F>,
|
||||||
|
|
||||||
pub(crate) keccak_inputs: Vec<[u64; keccak::keccak_stark::NUM_INPUTS]>,
|
pub(crate) next_txn_index: usize,
|
||||||
pub(crate) keccak_memory_inputs: Vec<KeccakMemoryOp>,
|
|
||||||
pub(crate) logic_ops: Vec<logic::Operation>,
|
|
||||||
|
|
||||||
/// Prover inputs containing MPT data, in reverse order so that the next input can be obtained
|
/// Prover inputs containing MPT data, in reverse order so that the next input can be obtained
|
||||||
/// via `pop()`.
|
/// via `pop()`.
|
||||||
@ -47,206 +33,204 @@ impl<F: Field> GenerationState<F> {
|
|||||||
|
|
||||||
Self {
|
Self {
|
||||||
inputs,
|
inputs,
|
||||||
next_txn_index: 0,
|
registers: Default::default(),
|
||||||
cpu_rows: vec![],
|
|
||||||
current_cpu_row: [F::ZERO; NUM_CPU_COLUMNS].into(),
|
|
||||||
current_context: 0,
|
|
||||||
memory: MemoryState::default(),
|
memory: MemoryState::default(),
|
||||||
keccak_inputs: vec![],
|
traces: Traces::default(),
|
||||||
keccak_memory_inputs: vec![],
|
next_txn_index: 0,
|
||||||
logic_ops: vec![],
|
|
||||||
mpt_prover_inputs,
|
mpt_prover_inputs,
|
||||||
rlp_prover_inputs,
|
rlp_prover_inputs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute logical AND, and record the operation to be added in the logic table later.
|
// TODO: Remove dead code below.
|
||||||
#[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 OR, and record the operation to be added in the logic table later.
|
// /// Compute logical AND, and record the operation to be added in the logic table later.
|
||||||
#[allow(unused)] // TODO: Should be used soon.
|
// #[allow(unused)] // TODO: Should be used soon.
|
||||||
pub(crate) fn or(&mut self, input0: U256, input1: U256) -> U256 {
|
// pub(crate) fn and(&mut self, input0: U256, input1: U256) -> U256 {
|
||||||
self.logic_op(logic::Op::Or, input0, input1)
|
// self.logic_op(logic::Op::And, input0, input1)
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Compute logical XOR, and record the operation to be added in the logic table later.
|
// /// Compute logical OR, and record the operation to be added in the logic table later.
|
||||||
#[allow(unused)] // TODO: Should be used soon.
|
// #[allow(unused)] // TODO: Should be used soon.
|
||||||
pub(crate) fn xor(&mut self, input0: U256, input1: U256) -> U256 {
|
// pub(crate) fn or(&mut self, input0: U256, input1: U256) -> U256 {
|
||||||
self.logic_op(logic::Op::Xor, input0, input1)
|
// self.logic_op(logic::Op::Or, input0, input1)
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// Compute logical AND, and record the operation to be added in the logic table later.
|
// /// Compute logical XOR, 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 {
|
// #[allow(unused)] // TODO: Should be used soon.
|
||||||
let operation = logic::Operation::new(op, input0, input1);
|
// pub(crate) fn xor(&mut self, input0: U256, input1: U256) -> U256 {
|
||||||
let result = operation.result;
|
// self.logic_op(logic::Op::Xor, input0, input1)
|
||||||
self.logic_ops.push(operation);
|
// }
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Like `get_mem_cpu`, but reads from the current context specifically.
|
// /// 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 logic_op(&mut self, op: logic::Op, input0: U256, input1: U256) -> U256 {
|
||||||
pub(crate) fn get_mem_cpu_current(
|
// let operation = logic::Operation::new(op, input0, input1);
|
||||||
&mut self,
|
// let result = operation.result;
|
||||||
channel_index: usize,
|
// self.logic_ops.push(operation);
|
||||||
segment: Segment,
|
// result
|
||||||
virt: usize,
|
// }
|
||||||
) -> U256 {
|
|
||||||
let context = self.current_context;
|
|
||||||
self.get_mem_cpu(channel_index, context, segment, virt)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Simulates the CPU reading some memory through the given channel. Besides logging the memory
|
// /// Like `get_mem_cpu`, but reads from the current context specifically.
|
||||||
/// operation, this also generates the associated registers in the current CPU row.
|
// #[allow(unused)] // TODO: Should be used soon.
|
||||||
pub(crate) fn get_mem_cpu(
|
// pub(crate) fn get_mem_cpu_current(
|
||||||
&mut self,
|
// &mut self,
|
||||||
channel_index: usize,
|
// channel_index: usize,
|
||||||
context: usize,
|
// segment: Segment,
|
||||||
segment: Segment,
|
// virt: usize,
|
||||||
virt: usize,
|
// ) -> U256 {
|
||||||
) -> U256 {
|
// let context = self.current_context;
|
||||||
let timestamp = self.cpu_rows.len() * NUM_CHANNELS + channel_index;
|
// self.get_mem_cpu(channel_index, context, segment, virt)
|
||||||
let value = self.get_mem(context, segment, virt, timestamp);
|
// }
|
||||||
|
|
||||||
let channel = &mut self.current_cpu_row.mem_channels[channel_index];
|
// /// Simulates the CPU reading some memory through the given channel. Besides logging the memory
|
||||||
channel.used = F::ONE;
|
// /// operation, this also generates the associated registers in the current CPU row.
|
||||||
channel.is_read = F::ONE;
|
// pub(crate) fn get_mem_cpu(
|
||||||
channel.addr_context = F::from_canonical_usize(context);
|
// &mut self,
|
||||||
channel.addr_segment = F::from_canonical_usize(segment as usize);
|
// channel_index: usize,
|
||||||
channel.addr_virtual = F::from_canonical_usize(virt);
|
// context: usize,
|
||||||
channel.value = u256_limbs(value);
|
// 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.
|
// /// Write some memory within the current execution context, and log the operation.
|
||||||
pub(crate) fn get_mem(
|
// pub(crate) fn set_mem_cpu_current(
|
||||||
&mut self,
|
// &mut self,
|
||||||
context: usize,
|
// channel_index: usize,
|
||||||
segment: Segment,
|
// segment: Segment,
|
||||||
virt: usize,
|
// virt: usize,
|
||||||
timestamp: usize,
|
// value: U256,
|
||||||
) -> U256 {
|
// ) {
|
||||||
let value = self.memory.contexts[context].segments[segment as usize].get(virt);
|
// let context = self.current_context;
|
||||||
self.memory.log.push(MemoryOp {
|
// self.set_mem_cpu(channel_index, context, segment, virt, value);
|
||||||
filter: true,
|
// }
|
||||||
timestamp,
|
|
||||||
is_read: true,
|
|
||||||
context,
|
|
||||||
segment,
|
|
||||||
virt,
|
|
||||||
value,
|
|
||||||
});
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write some memory within the current execution context, and log the operation.
|
// /// Write some memory, and log the operation.
|
||||||
pub(crate) fn set_mem_cpu_current(
|
// pub(crate) fn set_mem_cpu(
|
||||||
&mut self,
|
// &mut self,
|
||||||
channel_index: usize,
|
// channel_index: usize,
|
||||||
segment: Segment,
|
// context: usize,
|
||||||
virt: usize,
|
// segment: Segment,
|
||||||
value: U256,
|
// virt: usize,
|
||||||
) {
|
// value: U256,
|
||||||
let context = self.current_context;
|
// ) {
|
||||||
self.set_mem_cpu(channel_index, context, segment, virt, value);
|
// 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.
|
// /// Write some memory, and log the operation.
|
||||||
pub(crate) fn set_mem_cpu(
|
// pub(crate) fn set_mem(
|
||||||
&mut self,
|
// &mut self,
|
||||||
channel_index: usize,
|
// context: usize,
|
||||||
context: usize,
|
// segment: Segment,
|
||||||
segment: Segment,
|
// virt: usize,
|
||||||
virt: usize,
|
// value: U256,
|
||||||
value: U256,
|
// timestamp: usize,
|
||||||
) {
|
// ) {
|
||||||
let timestamp = self.cpu_rows.len() * NUM_CHANNELS + channel_index;
|
// self.memory.log.push(MemoryOp {
|
||||||
self.set_mem(context, segment, virt, value, timestamp);
|
// 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];
|
// /// Evaluate the Keccak-f permutation in-place on some data in memory, and record the operations
|
||||||
channel.used = F::ONE;
|
// /// for the purpose of witness generation.
|
||||||
channel.is_read = F::ZERO; // For clarity; should already be 0.
|
// #[allow(unused)] // TODO: Should be used soon.
|
||||||
channel.addr_context = F::from_canonical_usize(context);
|
// pub(crate) fn keccak_memory(
|
||||||
channel.addr_segment = F::from_canonical_usize(segment as usize);
|
// &mut self,
|
||||||
channel.addr_virtual = F::from_canonical_usize(virt);
|
// context: usize,
|
||||||
channel.value = u256_limbs(value);
|
// 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.
|
// /// Evaluate the Keccak-f permutation, and record the operation for the purpose of witness
|
||||||
pub(crate) fn set_mem(
|
// /// generation.
|
||||||
&mut self,
|
// pub(crate) fn keccak(
|
||||||
context: usize,
|
// &mut self,
|
||||||
segment: Segment,
|
// mut input: [u64; keccak::keccak_stark::NUM_INPUTS],
|
||||||
virt: usize,
|
// ) -> [u64; keccak::keccak_stark::NUM_INPUTS] {
|
||||||
value: U256,
|
// self.keccak_inputs.push(input);
|
||||||
timestamp: usize,
|
// keccakf(&mut input);
|
||||||
) {
|
// input
|
||||||
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 in-place on some data in memory, and record the operations
|
// pub(crate) fn commit_cpu_row(&mut self) {
|
||||||
/// for the purpose of witness generation.
|
// let mut swapped_row = [F::ZERO; NUM_CPU_COLUMNS].into();
|
||||||
#[allow(unused)] // TODO: Should be used soon.
|
// mem::swap(&mut self.current_cpu_row, &mut swapped_row);
|
||||||
pub(crate) fn keccak_memory(
|
// self.cpu_rows.push(swapped_row.into());
|
||||||
&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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,13 +72,23 @@ pub struct LogicStark<F, const D: usize> {
|
|||||||
pub f: PhantomData<F>,
|
pub f: PhantomData<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub(crate) enum Op {
|
pub(crate) enum Op {
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
Xor,
|
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)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Operation {
|
pub(crate) struct Operation {
|
||||||
operator: Op,
|
operator: Op,
|
||||||
@ -89,11 +99,7 @@ pub(crate) struct Operation {
|
|||||||
|
|
||||||
impl Operation {
|
impl Operation {
|
||||||
pub(crate) fn new(operator: Op, input0: U256, input1: U256) -> Self {
|
pub(crate) fn new(operator: Op, input0: U256, input1: U256) -> Self {
|
||||||
let result = match operator {
|
let result = operator.result(input0, input1);
|
||||||
Op::And => input0 & input1,
|
|
||||||
Op::Or => input0 | input1,
|
|
||||||
Op::Xor => input0 ^ input1,
|
|
||||||
};
|
|
||||||
Operation {
|
Operation {
|
||||||
operator,
|
operator,
|
||||||
input0,
|
input0,
|
||||||
@ -101,6 +107,31 @@ impl Operation {
|
|||||||
result,
|
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> {
|
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);
|
let mut rows = Vec::with_capacity(padded_len);
|
||||||
for op in operations {
|
for op in operations {
|
||||||
rows.push(Self::generate_row(op));
|
rows.push(op.to_row());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pad to a power of two.
|
// Pad to a power of two.
|
||||||
for _ in len..padded_len {
|
for _ in len..padded_len {
|
||||||
rows.push([F::ZERO; columns::NUM_COLUMNS]);
|
rows.push([F::ZERO; NUM_COLUMNS]);
|
||||||
}
|
}
|
||||||
|
|
||||||
rows
|
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> {
|
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>(
|
fn eval_packed_generic<FE, P, const D2: usize>(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use ethereum_types::U256;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use maybe_rayon::*;
|
use maybe_rayon::*;
|
||||||
use plonky2::field::extension::{Extendable, FieldExtension};
|
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,
|
COUNTER_PERMUTED, FILTER, IS_READ, NUM_COLUMNS, RANGE_CHECK, RANGE_CHECK_PERMUTED,
|
||||||
SEGMENT_FIRST_CHANGE, TIMESTAMP, VIRTUAL_FIRST_CHANGE,
|
SEGMENT_FIRST_CHANGE, TIMESTAMP, VIRTUAL_FIRST_CHANGE,
|
||||||
};
|
};
|
||||||
use crate::memory::segments::Segment;
|
|
||||||
use crate::memory::VALUE_LIMBS;
|
use crate::memory::VALUE_LIMBS;
|
||||||
use crate::permutation::PermutationPair;
|
use crate::permutation::PermutationPair;
|
||||||
use crate::stark::Stark;
|
use crate::stark::Stark;
|
||||||
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
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>> {
|
pub fn ctl_data<F: Field>() -> Vec<Column<F>> {
|
||||||
let mut res =
|
let mut res =
|
||||||
@ -43,17 +43,18 @@ pub struct MemoryStark<F, const D: usize> {
|
|||||||
pub(crate) f: PhantomData<F>,
|
pub(crate) f: PhantomData<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
// TODO: Remove
|
||||||
pub(crate) struct MemoryOp {
|
// #[derive(Clone, Debug)]
|
||||||
/// true if this is an actual memory operation, or false if it's a padding row.
|
// pub(crate) struct MemoryOp {
|
||||||
pub filter: bool,
|
// /// true if this is an actual memory operation, or false if it's a padding row.
|
||||||
pub timestamp: usize,
|
// pub filter: bool,
|
||||||
pub is_read: bool,
|
// pub timestamp: usize,
|
||||||
pub context: usize,
|
// pub is_read: bool,
|
||||||
pub segment: Segment,
|
// pub context: usize,
|
||||||
pub virt: usize,
|
// pub segment: Segment,
|
||||||
pub value: U256,
|
// pub virt: usize,
|
||||||
}
|
// pub value: U256,
|
||||||
|
// }
|
||||||
|
|
||||||
impl MemoryOp {
|
impl MemoryOp {
|
||||||
/// Generate a row for a given memory operation. Note that this does not generate columns which
|
/// 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];
|
let mut row = [F::ZERO; NUM_COLUMNS];
|
||||||
row[FILTER] = F::from_bool(self.filter);
|
row[FILTER] = F::from_bool(self.filter);
|
||||||
row[TIMESTAMP] = F::from_canonical_usize(self.timestamp);
|
row[TIMESTAMP] = F::from_canonical_usize(self.timestamp);
|
||||||
row[IS_READ] = F::from_bool(self.is_read);
|
row[IS_READ] = F::from_bool(self.op == Read);
|
||||||
row[ADDR_CONTEXT] = F::from_canonical_usize(self.context);
|
let MemoryAddress {
|
||||||
row[ADDR_SEGMENT] = F::from_canonical_usize(self.segment as usize);
|
context,
|
||||||
row[ADDR_VIRTUAL] = F::from_canonical_usize(self.virt);
|
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 {
|
for j in 0..VALUE_LIMBS {
|
||||||
row[value_limb(j)] = F::from_canonical_u32((self.value >> (j * 32)).low_u32());
|
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()
|
.iter()
|
||||||
.tuple_windows()
|
.tuple_windows()
|
||||||
.map(|(curr, next)| {
|
.map(|(curr, next)| {
|
||||||
if curr.context != next.context {
|
if curr.address.context != next.address.context {
|
||||||
next.context - curr.context - 1
|
next.address.context - curr.address.context - 1
|
||||||
} else if curr.segment != next.segment {
|
} else if curr.address.segment != next.address.segment {
|
||||||
next.segment as usize - curr.segment as usize - 1
|
next.address.segment as usize - curr.address.segment as usize - 1
|
||||||
} else if curr.virt != next.virt {
|
} else if curr.address.virt != next.address.virt {
|
||||||
next.virt - curr.virt - 1
|
next.address.virt - curr.address.virt - 1
|
||||||
} else {
|
} else {
|
||||||
next.timestamp - curr.timestamp - 1
|
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
|
/// Generate most of the trace rows. Excludes a few columns like `COUNTER`, which are generated
|
||||||
/// later, after transposing to column-major form.
|
/// later, after transposing to column-major form.
|
||||||
fn generate_trace_row_major(&self, mut memory_ops: Vec<MemoryOp>) -> Vec<[F; NUM_COLUMNS]> {
|
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);
|
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 {
|
memory_ops.push(MemoryOp {
|
||||||
filter: false,
|
filter: false,
|
||||||
timestamp: last_op.timestamp + i + 1,
|
timestamp: last_op.timestamp + i + 1,
|
||||||
is_read: true,
|
op: Read,
|
||||||
..last_op
|
..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 {
|
pub enum MemoryOpKind {
|
||||||
Read,
|
Read,
|
||||||
Write(U256),
|
Write,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct MemoryOp {
|
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 address: MemoryAddress,
|
||||||
pub op: MemoryOpKind,
|
pub op: MemoryOpKind,
|
||||||
|
pub value: U256,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryOp {
|
impl MemoryOp {
|
||||||
@ -45,17 +63,20 @@ impl MemoryOp {
|
|||||||
clock: usize,
|
clock: usize,
|
||||||
address: MemoryAddress,
|
address: MemoryAddress,
|
||||||
op: MemoryOpKind,
|
op: MemoryOpKind,
|
||||||
|
value: U256,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let timestamp = (clock * NUM_CHANNELS + channel.index()) as u64;
|
let timestamp = clock * NUM_CHANNELS + channel.index();
|
||||||
MemoryOp {
|
MemoryOp {
|
||||||
|
filter: true,
|
||||||
timestamp,
|
timestamp,
|
||||||
address,
|
address,
|
||||||
op,
|
op,
|
||||||
|
value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default, Debug)]
|
||||||
pub struct MemoryState {
|
pub struct MemoryState {
|
||||||
contents: HashMap<MemoryAddress, U256>,
|
contents: HashMap<MemoryAddress, U256>,
|
||||||
}
|
}
|
||||||
@ -66,7 +87,7 @@ impl MemoryState {
|
|||||||
|
|
||||||
for (i, &byte) in kernel_code.iter().enumerate() {
|
for (i, &byte) in kernel_code.iter().enumerate() {
|
||||||
if byte != 0 {
|
if byte != 0 {
|
||||||
let address = (0, 0, i as u32);
|
let address = MemoryAddress::new(0, 0, i);
|
||||||
let val = byte.into();
|
let val = byte.into();
|
||||||
contents.insert(address, val);
|
contents.insert(address, val);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
mod errors;
|
mod errors;
|
||||||
mod memory;
|
pub(crate) mod memory;
|
||||||
mod operation;
|
mod operation;
|
||||||
mod state;
|
pub(crate) mod state;
|
||||||
mod traces;
|
pub(crate) mod traces;
|
||||||
pub mod transition;
|
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::logic;
|
||||||
use crate::memory::segments::Segment;
|
use crate::memory::segments::Segment;
|
||||||
use crate::witness::errors::ProgramError;
|
use crate::witness::errors::ProgramError;
|
||||||
use crate::witness::memory::MemoryState;
|
use crate::witness::memory::{MemoryAddress, MemoryState};
|
||||||
use crate::witness::state::RegistersState;
|
use crate::witness::state::RegistersState;
|
||||||
use crate::witness::traces::Traces;
|
use crate::witness::traces::Traces;
|
||||||
use crate::witness::util::{
|
use crate::witness::util::{
|
||||||
@ -17,7 +17,7 @@ use crate::witness::util::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub enum Operation {
|
pub(crate) enum Operation {
|
||||||
Dup(u8),
|
Dup(u8),
|
||||||
Swap(u8),
|
Swap(u8),
|
||||||
Iszero,
|
Iszero,
|
||||||
@ -25,53 +25,12 @@ pub enum Operation {
|
|||||||
Syscall(u8),
|
Syscall(u8),
|
||||||
Eq,
|
Eq,
|
||||||
ExitKernel,
|
ExitKernel,
|
||||||
BinaryLogic(BinaryLogicOp),
|
BinaryLogic(logic::Op),
|
||||||
NotImplemented,
|
NotImplemented,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
pub(crate) fn generate_binary_logic_op<F: Field>(
|
||||||
pub enum BinaryLogicOp {
|
op: logic::Op,
|
||||||
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,
|
|
||||||
mut registers_state: RegistersState,
|
mut registers_state: RegistersState,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
traces: &mut Traces<F>,
|
traces: &mut Traces<F>,
|
||||||
@ -82,7 +41,7 @@ pub fn generate_binary_logic_op<F: Field>(
|
|||||||
let result = op.result(in0, in1);
|
let result = op.result(in0, in1);
|
||||||
let log_out = stack_push_log_and_fill(&mut registers_state, traces, &mut row, result)?;
|
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_in0);
|
||||||
traces.push_memory(log_in1);
|
traces.push_memory(log_in1);
|
||||||
traces.push_memory(log_out);
|
traces.push_memory(log_out);
|
||||||
@ -90,7 +49,7 @@ pub fn generate_binary_logic_op<F: Field>(
|
|||||||
Ok(registers_state)
|
Ok(registers_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_dup<F: Field>(
|
pub(crate) fn generate_dup<F: Field>(
|
||||||
n: u8,
|
n: u8,
|
||||||
mut registers_state: RegistersState,
|
mut registers_state: RegistersState,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
@ -99,11 +58,11 @@ pub fn generate_dup<F: Field>(
|
|||||||
) -> Result<RegistersState, ProgramError> {
|
) -> Result<RegistersState, ProgramError> {
|
||||||
let other_addr_lo = registers_state
|
let other_addr_lo = registers_state
|
||||||
.stack_len
|
.stack_len
|
||||||
.checked_sub(1 + (n as u32))
|
.checked_sub(1 + (n as usize))
|
||||||
.ok_or(ProgramError::StackUnderflow)?;
|
.ok_or(ProgramError::StackUnderflow)?;
|
||||||
let other_addr = (
|
let other_addr = MemoryAddress::new(
|
||||||
registers_state.context,
|
registers_state.context,
|
||||||
Segment::Stack as u32,
|
Segment::Stack as usize,
|
||||||
other_addr_lo,
|
other_addr_lo,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -117,7 +76,7 @@ pub fn generate_dup<F: Field>(
|
|||||||
Ok(registers_state)
|
Ok(registers_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_swap<F: Field>(
|
pub(crate) fn generate_swap<F: Field>(
|
||||||
n: u8,
|
n: u8,
|
||||||
mut registers_state: RegistersState,
|
mut registers_state: RegistersState,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
@ -126,11 +85,11 @@ pub fn generate_swap<F: Field>(
|
|||||||
) -> Result<RegistersState, ProgramError> {
|
) -> Result<RegistersState, ProgramError> {
|
||||||
let other_addr_lo = registers_state
|
let other_addr_lo = registers_state
|
||||||
.stack_len
|
.stack_len
|
||||||
.checked_sub(2 + (n as u32))
|
.checked_sub(2 + (n as usize))
|
||||||
.ok_or(ProgramError::StackUnderflow)?;
|
.ok_or(ProgramError::StackUnderflow)?;
|
||||||
let other_addr = (
|
let other_addr = MemoryAddress::new(
|
||||||
registers_state.context,
|
registers_state.context,
|
||||||
Segment::Stack as u32,
|
Segment::Stack as usize,
|
||||||
other_addr_lo,
|
other_addr_lo,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -150,7 +109,7 @@ pub fn generate_swap<F: Field>(
|
|||||||
Ok(registers_state)
|
Ok(registers_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_not<F: Field>(
|
pub(crate) fn generate_not<F: Field>(
|
||||||
mut registers_state: RegistersState,
|
mut registers_state: RegistersState,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
traces: &mut Traces<F>,
|
traces: &mut Traces<F>,
|
||||||
@ -167,7 +126,7 @@ pub fn generate_not<F: Field>(
|
|||||||
Ok(registers_state)
|
Ok(registers_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_iszero<F: Field>(
|
pub(crate) fn generate_iszero<F: Field>(
|
||||||
mut registers_state: RegistersState,
|
mut registers_state: RegistersState,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
traces: &mut Traces<F>,
|
traces: &mut Traces<F>,
|
||||||
@ -190,39 +149,39 @@ pub fn generate_iszero<F: Field>(
|
|||||||
Ok(registers_state)
|
Ok(registers_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_syscall<F: Field>(
|
pub(crate) fn generate_syscall<F: Field>(
|
||||||
opcode: u8,
|
opcode: u8,
|
||||||
mut registers_state: RegistersState,
|
mut registers_state: RegistersState,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
traces: &mut Traces<F>,
|
traces: &mut Traces<F>,
|
||||||
mut row: CpuColumnsView<F>,
|
mut row: CpuColumnsView<F>,
|
||||||
) -> Result<RegistersState, ProgramError> {
|
) -> Result<RegistersState, ProgramError> {
|
||||||
let handler_jumptable_addr = KERNEL.global_labels["syscall_jumptable"] as u32;
|
let handler_jumptable_addr = KERNEL.global_labels["syscall_jumptable"] as usize;
|
||||||
let handler_addr_addr = handler_jumptable_addr + (opcode as u32);
|
let handler_addr_addr = handler_jumptable_addr + (opcode as usize);
|
||||||
let (handler_addr0, log_in0) = mem_read_gp_with_log_and_fill(
|
let (handler_addr0, log_in0) = mem_read_gp_with_log_and_fill(
|
||||||
0,
|
0,
|
||||||
(0, Segment::Code as u32, handler_addr_addr),
|
MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr),
|
||||||
memory_state,
|
memory_state,
|
||||||
traces,
|
traces,
|
||||||
&mut row,
|
&mut row,
|
||||||
);
|
);
|
||||||
let (handler_addr1, log_in1) = mem_read_gp_with_log_and_fill(
|
let (handler_addr1, log_in1) = mem_read_gp_with_log_and_fill(
|
||||||
1,
|
1,
|
||||||
(0, Segment::Code as u32, handler_addr_addr + 1),
|
MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr + 1),
|
||||||
memory_state,
|
memory_state,
|
||||||
traces,
|
traces,
|
||||||
&mut row,
|
&mut row,
|
||||||
);
|
);
|
||||||
let (handler_addr2, log_in2) = mem_read_gp_with_log_and_fill(
|
let (handler_addr2, log_in2) = mem_read_gp_with_log_and_fill(
|
||||||
2,
|
2,
|
||||||
(0, Segment::Code as u32, handler_addr_addr + 2),
|
MemoryAddress::new(0, Segment::Code as usize, handler_addr_addr + 2),
|
||||||
memory_state,
|
memory_state,
|
||||||
traces,
|
traces,
|
||||||
&mut row,
|
&mut row,
|
||||||
);
|
);
|
||||||
|
|
||||||
let handler_addr = (handler_addr0 << 16) + (handler_addr1 << 8) + handler_addr2;
|
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)
|
let syscall_info = U256::from(registers_state.program_counter)
|
||||||
+ (U256::from(u64::from(registers_state.is_kernel)) << 32);
|
+ (U256::from(u64::from(registers_state.is_kernel)) << 32);
|
||||||
@ -240,7 +199,7 @@ pub fn generate_syscall<F: Field>(
|
|||||||
Ok(registers_state)
|
Ok(registers_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_eq<F: Field>(
|
pub(crate) fn generate_eq<F: Field>(
|
||||||
mut registers_state: RegistersState,
|
mut registers_state: RegistersState,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
traces: &mut Traces<F>,
|
traces: &mut Traces<F>,
|
||||||
@ -261,7 +220,7 @@ pub fn generate_eq<F: Field>(
|
|||||||
Ok(registers_state)
|
Ok(registers_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_exit_kernel<F: Field>(
|
pub(crate) fn generate_exit_kernel<F: Field>(
|
||||||
mut registers_state: RegistersState,
|
mut registers_state: RegistersState,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
traces: &mut Traces<F>,
|
traces: &mut Traces<F>,
|
||||||
@ -270,7 +229,7 @@ pub fn generate_exit_kernel<F: Field>(
|
|||||||
let [(kexit_info, log_in)] =
|
let [(kexit_info, log_in)] =
|
||||||
stack_pop_with_log_and_fill::<1, _>(&mut registers_state, memory_state, traces, &mut row)?;
|
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 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;
|
let is_kernel_mode_val = (kexit_info_u64[1] >> 32) as u32;
|
||||||
assert!(is_kernel_mode_val == 0 || is_kernel_mode_val == 1);
|
assert!(is_kernel_mode_val == 0 || is_kernel_mode_val == 1);
|
||||||
let is_kernel_mode = is_kernel_mode_val != 0;
|
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)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
pub struct RegistersState {
|
pub struct RegistersState {
|
||||||
pub program_counter: u32,
|
pub program_counter: usize,
|
||||||
pub is_kernel: bool,
|
pub is_kernel: bool,
|
||||||
pub stack_len: u32,
|
pub stack_len: usize,
|
||||||
pub context: u32,
|
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 plonky2::field::extension::Extendable;
|
||||||
use crate::cpu::columns::CpuColumnsView;
|
use plonky2::field::polynomial::PolynomialValues;
|
||||||
use crate::logic;
|
use plonky2::field::types::Field;
|
||||||
use crate::witness::memory::MemoryOp;
|
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];
|
type ArithmeticRow<T> = [T; NUM_ARITH_COLUMNS];
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@ -14,46 +24,54 @@ pub struct TraceCheckpoint {
|
|||||||
pub(self) memory_len: usize,
|
pub(self) memory_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Traces<T: Copy> {
|
pub(crate) struct Traces<T: Copy> {
|
||||||
cpu: Vec<CpuColumnsView<T>>,
|
pub(crate) cpu: Vec<CpuColumnsView<T>>,
|
||||||
logic: Vec<LogicRow<T>>,
|
pub(crate) logic_ops: Vec<logic::Operation>,
|
||||||
arithmetic: Vec<ArithmeticRow<T>>,
|
pub(crate) arithmetic: Vec<ArithmeticRow<T>>,
|
||||||
memory: Vec<MemoryOp>,
|
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> {
|
impl<T: Copy> Traces<T> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Traces {
|
Traces {
|
||||||
cpu: vec![],
|
cpu: vec![],
|
||||||
logic: vec![],
|
logic_ops: vec![],
|
||||||
arithmetic: vec![],
|
arithmetic: vec![],
|
||||||
memory: vec![],
|
memory_ops: vec![],
|
||||||
|
keccak_inputs: vec![],
|
||||||
|
keccak_memory_inputs: vec![],
|
||||||
|
keccak_sponge_ops: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn checkpoint(&self) -> TraceCheckpoint {
|
pub fn checkpoint(&self) -> TraceCheckpoint {
|
||||||
TraceCheckpoint {
|
TraceCheckpoint {
|
||||||
cpu_len: self.cpu.len(),
|
cpu_len: self.cpu.len(),
|
||||||
logic_len: self.logic.len(),
|
logic_len: self.logic_ops.len(),
|
||||||
arithmetic_len: self.arithmetic.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) {
|
pub fn rollback(&mut self, checkpoint: TraceCheckpoint) {
|
||||||
self.cpu.truncate(checkpoint.cpu_len);
|
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.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>) {
|
pub fn push_cpu(&mut self, val: CpuColumnsView<T>) {
|
||||||
self.cpu.push(val);
|
self.cpu.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_logic(&mut self, val: LogicRow<T>) {
|
pub fn push_logic(&mut self, val: logic::Operation) {
|
||||||
self.logic.push(val);
|
self.logic_ops.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_arithmetic(&mut self, val: ArithmeticRow<T>) {
|
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) {
|
pub fn push_memory(&mut self, val: MemoryOp) {
|
||||||
self.memory.push(val);
|
self.memory_ops.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clock(&self) -> usize {
|
pub fn clock(&self) -> usize {
|
||||||
self.cpu.len()
|
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> {
|
impl<T: Copy> Default for Traces<T> {
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
|
|
||||||
use crate::cpu::columns::{CpuColumnsView, NUM_CPU_COLUMNS};
|
use crate::cpu::columns::{CpuColumnsView, NUM_CPU_COLUMNS};
|
||||||
|
use crate::logic;
|
||||||
use crate::memory::segments::Segment;
|
use crate::memory::segments::Segment;
|
||||||
use crate::witness::errors::ProgramError;
|
use crate::witness::errors::ProgramError;
|
||||||
use crate::witness::memory::MemoryState;
|
use crate::witness::memory::{MemoryAddress, MemoryState};
|
||||||
use crate::witness::operation::{
|
use crate::witness::operation::{
|
||||||
generate_binary_logic_op, generate_dup, generate_eq, generate_exit_kernel, generate_iszero,
|
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::state::RegistersState;
|
||||||
use crate::witness::traces::Traces;
|
use crate::witness::traces::Traces;
|
||||||
use crate::witness::util::mem_read_code_with_log_and_fill;
|
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>(
|
fn read_code_memory<F: Field>(
|
||||||
registers_state: RegistersState,
|
registers_state: RegistersState,
|
||||||
@ -25,11 +26,11 @@ fn read_code_memory<F: Field>(
|
|||||||
} else {
|
} else {
|
||||||
registers_state.context
|
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,
|
code_context,
|
||||||
Segment::Code as u32,
|
Segment::Code as usize,
|
||||||
registers_state.program_counter,
|
registers_state.program_counter,
|
||||||
);
|
);
|
||||||
let (opcode, mem_log) = mem_read_code_with_log_and_fill(address, memory_state, traces, row);
|
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)),
|
(0x13, _) => Ok(Operation::Syscall(opcode)),
|
||||||
(0x14, _) => Ok(Operation::Eq),
|
(0x14, _) => Ok(Operation::Eq),
|
||||||
(0x15, _) => Ok(Operation::Iszero),
|
(0x15, _) => Ok(Operation::Iszero),
|
||||||
(0x16, _) => Ok(Operation::BinaryLogic(BinaryLogicOp::And)),
|
(0x16, _) => Ok(Operation::BinaryLogic(logic::Op::And)),
|
||||||
(0x17, _) => Ok(Operation::BinaryLogic(BinaryLogicOp::Or)),
|
(0x17, _) => Ok(Operation::BinaryLogic(logic::Op::Or)),
|
||||||
(0x18, _) => Ok(Operation::BinaryLogic(BinaryLogicOp::Xor)),
|
(0x18, _) => Ok(Operation::BinaryLogic(logic::Op::Xor)),
|
||||||
(0x19, _) => Ok(Operation::Not),
|
(0x19, _) => Ok(Operation::Not),
|
||||||
(0x1a, _) => Ok(Operation::NotImplemented),
|
(0x1a, _) => Ok(Operation::NotImplemented),
|
||||||
(0x1b, _) => 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::Syscall(_) => &mut flags.syscall,
|
||||||
Operation::Eq => &mut flags.eq,
|
Operation::Eq => &mut flags.eq,
|
||||||
Operation::ExitKernel => &mut flags.exit_kernel,
|
Operation::ExitKernel => &mut flags.exit_kernel,
|
||||||
Operation::BinaryLogic(BinaryLogicOp::And) => &mut flags.and,
|
Operation::BinaryLogic(logic::Op::And) => &mut flags.and,
|
||||||
Operation::BinaryLogic(BinaryLogicOp::Or) => &mut flags.or,
|
Operation::BinaryLogic(logic::Op::Or) => &mut flags.or,
|
||||||
Operation::BinaryLogic(BinaryLogicOp::Xor) => &mut flags.xor,
|
Operation::BinaryLogic(logic::Op::Xor) => &mut flags.xor,
|
||||||
Operation::NotImplemented => panic!("operation not implemented"),
|
Operation::NotImplemented => panic!("operation not implemented"),
|
||||||
} = F::ONE;
|
} = 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 opcode = read_code_memory(registers_state, memory_state, traces, &mut row);
|
||||||
let op = decode(registers_state, opcode)?;
|
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);
|
fill_op_flag(op, &mut row);
|
||||||
|
|
||||||
perform_op(op, registers_state, memory_state, traces, 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");
|
todo!("constraints for exception handling are not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transition<F: Field>(
|
pub(crate) fn transition<F: Field>(
|
||||||
registers_state: RegistersState,
|
registers_state: RegistersState,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
traces: &mut Traces<F>,
|
traces: &mut Traces<F>,
|
||||||
|
|||||||
@ -23,27 +23,27 @@ fn to_bits_le<F: Field>(n: u8) -> [F; 8] {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mem_read_with_log<T: Copy>(
|
pub(crate) fn mem_read_with_log<T: Copy>(
|
||||||
channel: MemoryChannel,
|
channel: MemoryChannel,
|
||||||
address: MemoryAddress,
|
address: MemoryAddress,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
traces: &Traces<T>,
|
traces: &Traces<T>,
|
||||||
) -> (U256, MemoryOp) {
|
) -> (U256, MemoryOp) {
|
||||||
let val = memory_state.get(address);
|
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)
|
(val, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mem_write_log<T: Copy>(
|
pub(crate) fn mem_write_log<T: Copy>(
|
||||||
channel: MemoryChannel,
|
channel: MemoryChannel,
|
||||||
address: MemoryAddress,
|
address: MemoryAddress,
|
||||||
traces: &Traces<T>,
|
traces: &Traces<T>,
|
||||||
val: U256,
|
val: U256,
|
||||||
) -> MemoryOp {
|
) -> 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,
|
address: MemoryAddress,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
traces: &Traces<F>,
|
traces: &Traces<F>,
|
||||||
@ -57,7 +57,7 @@ pub fn mem_read_code_with_log_and_fill<F: Field>(
|
|||||||
(val_u8, op)
|
(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,
|
n: usize,
|
||||||
address: MemoryAddress,
|
address: MemoryAddress,
|
||||||
memory_state: &MemoryState,
|
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];
|
let channel = &mut row.mem_channels[n];
|
||||||
channel.used = F::ONE;
|
channel.used = F::ONE;
|
||||||
channel.is_read = F::ONE;
|
channel.is_read = F::ONE;
|
||||||
channel.addr_context = F::from_canonical_u32(address.0);
|
channel.addr_context = F::from_canonical_usize(address.context);
|
||||||
channel.addr_segment = F::from_canonical_u32(address.1);
|
channel.addr_segment = F::from_canonical_usize(address.segment);
|
||||||
channel.addr_virtual = F::from_canonical_u32(address.2);
|
channel.addr_virtual = F::from_canonical_usize(address.virt);
|
||||||
for (i, limb) in val_limbs.into_iter().enumerate() {
|
for (i, limb) in val_limbs.into_iter().enumerate() {
|
||||||
channel.value[2 * i] = F::from_canonical_u32(limb as u32);
|
channel.value[2 * i] = F::from_canonical_u32(limb as u32);
|
||||||
channel.value[2 * i + 1] = F::from_canonical_u32((limb >> 32) 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)
|
(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,
|
n: usize,
|
||||||
address: MemoryAddress,
|
address: MemoryAddress,
|
||||||
traces: &Traces<F>,
|
traces: &Traces<F>,
|
||||||
@ -99,9 +99,9 @@ pub fn mem_write_gp_log_and_fill<F: Field>(
|
|||||||
let channel = &mut row.mem_channels[n];
|
let channel = &mut row.mem_channels[n];
|
||||||
channel.used = F::ONE;
|
channel.used = F::ONE;
|
||||||
channel.is_read = F::ZERO;
|
channel.is_read = F::ZERO;
|
||||||
channel.addr_context = F::from_canonical_u32(address.0);
|
channel.addr_context = F::from_canonical_usize(address.context);
|
||||||
channel.addr_segment = F::from_canonical_u32(address.1);
|
channel.addr_segment = F::from_canonical_usize(address.segment);
|
||||||
channel.addr_virtual = F::from_canonical_u32(address.2);
|
channel.addr_virtual = F::from_canonical_usize(address.virt);
|
||||||
for (i, limb) in val_limbs.into_iter().enumerate() {
|
for (i, limb) in val_limbs.into_iter().enumerate() {
|
||||||
channel.value[2 * i] = F::from_canonical_u32(limb as u32);
|
channel.value[2 * i] = F::from_canonical_u32(limb as u32);
|
||||||
channel.value[2 * i + 1] = F::from_canonical_u32((limb >> 32) 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
|
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,
|
registers_state: &mut RegistersState,
|
||||||
memory_state: &MemoryState,
|
memory_state: &MemoryState,
|
||||||
traces: &Traces<F>,
|
traces: &Traces<F>,
|
||||||
@ -123,10 +123,10 @@ pub fn stack_pop_with_log_and_fill<const N: usize, F: Field>(
|
|||||||
let result = {
|
let result = {
|
||||||
let mut i = 0usize;
|
let mut i = 0usize;
|
||||||
[(); N].map(|_| {
|
[(); N].map(|_| {
|
||||||
let address = (
|
let address = MemoryAddress::new(
|
||||||
registers_state.context,
|
registers_state.context,
|
||||||
Segment::Stack as u32,
|
Segment::Stack as usize,
|
||||||
registers_state.stack_len - 1 - (i as u32),
|
registers_state.stack_len - 1 - i,
|
||||||
);
|
);
|
||||||
let res = mem_read_gp_with_log_and_fill(i, address, memory_state, traces, row);
|
let res = mem_read_gp_with_log_and_fill(i, address, memory_state, traces, row);
|
||||||
i += 1;
|
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)
|
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,
|
registers_state: &mut RegistersState,
|
||||||
traces: &Traces<F>,
|
traces: &Traces<F>,
|
||||||
row: &mut CpuColumnsView<F>,
|
row: &mut CpuColumnsView<F>,
|
||||||
@ -149,9 +149,9 @@ pub fn stack_push_log_and_fill<F: Field>(
|
|||||||
return Err(ProgramError::StackOverflow);
|
return Err(ProgramError::StackOverflow);
|
||||||
}
|
}
|
||||||
|
|
||||||
let address = (
|
let address = MemoryAddress::new(
|
||||||
registers_state.context,
|
registers_state.context,
|
||||||
Segment::Stack as u32,
|
Segment::Stack as usize,
|
||||||
registers_state.stack_len,
|
registers_state.stack_len,
|
||||||
);
|
);
|
||||||
let res = mem_write_gp_log_and_fill(NUM_GP_CHANNELS - 1, address, traces, row, val);
|
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 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::field::goldilocks_field::GoldilocksField;
|
||||||
use plonky2::plonk::config::PoseidonGoldilocksConfig;
|
use plonky2::plonk::config::PoseidonGoldilocksConfig;
|
||||||
use plonky2::util::timing::TimingTree;
|
use plonky2::util::timing::TimingTree;
|
||||||
@ -18,6 +19,8 @@ type C = PoseidonGoldilocksConfig;
|
|||||||
/// Execute the empty list of transactions, i.e. a no-op.
|
/// Execute the empty list of transactions, i.e. a no-op.
|
||||||
#[test]
|
#[test]
|
||||||
fn test_empty_txn_list() -> anyhow::Result<()> {
|
fn test_empty_txn_list() -> anyhow::Result<()> {
|
||||||
|
init_logger();
|
||||||
|
|
||||||
let all_stark = AllStark::<F, D>::default();
|
let all_stark = AllStark::<F, D>::default();
|
||||||
let config = StarkConfig::standard_fast_config();
|
let config = StarkConfig::standard_fast_config();
|
||||||
|
|
||||||
@ -80,3 +83,7 @@ fn test_empty_txn_list() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
verify_proof(all_stark, proof, &config)
|
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