use alloc::vec::Vec;
use miden_air::trace::{
CHIPLETS_WIDTH,
chiplets::{
KERNEL_ROM_TRACE_WIDTH,
ace::ACE_CHIPLET_NUM_COLS,
bitwise::TRACE_WIDTH as BITWISE_WIDTH,
hasher::{HasherState, TRACE_WIDTH as HASHER_WIDTH},
memory::TRACE_WIDTH as MEMORY_WIDTH,
},
};
use miden_core::{mast::OpBatch, program::Kernel};
use crate::{
Felt, ONE, Word, ZERO,
crypto::merkle::MerklePath,
trace::{
ChipletTraceFragment, RowIndex,
range::RangeChecker,
utils::{CHIP_CLK_COL, DATA_COL_START, S_00_COL},
},
};
mod bitwise;
use bitwise::Bitwise;
mod hasher;
use hasher::Hasher;
mod memory;
use memory::Memory;
mod ace;
pub use ace::{Ace, CircuitEvaluation, MAX_NUM_ACE_WIRES, PTR_OFFSET_ELEM, PTR_OFFSET_WORD};
mod kernel_rom;
use kernel_rom::KernelRom;
#[cfg(test)]
mod tests;
pub struct ChipletsTrace {
pub(crate) trace: Vec<Felt>,
}
#[derive(Debug)]
pub struct Chiplets {
pub hasher: Hasher,
pub bitwise: Bitwise,
pub memory: Memory,
pub ace: Ace,
pub kernel_rom: KernelRom,
}
impl Chiplets {
pub fn new(kernel: Kernel) -> Self {
Self {
hasher: Hasher::default(),
bitwise: Bitwise::default(),
memory: Memory::default(),
kernel_rom: KernelRom::new(kernel),
ace: Ace::default(),
}
}
pub fn trace_len(&self) -> usize {
self.hasher.trace_len()
+ self.bitwise.trace_len()
+ self.memory.trace_len()
+ self.kernel_rom.trace_len()
+ self.ace.trace_len()
+ 1
}
pub fn bitwise_start(&self) -> RowIndex {
self.hasher.trace_len().into()
}
pub fn memory_start(&self) -> RowIndex {
self.bitwise_start() + self.bitwise.trace_len()
}
pub fn ace_start(&self) -> RowIndex {
self.memory_start() + self.memory.trace_len()
}
pub fn kernel_rom_start(&self) -> RowIndex {
self.ace_start() + self.ace.trace_len()
}
pub fn padding_start(&self) -> RowIndex {
self.kernel_rom_start() + self.kernel_rom.trace_len()
}
pub fn append_range_checks(&self, range_checker: &mut RangeChecker) {
self.memory.append_range_checks(self.memory_start(), range_checker);
}
pub fn into_trace(self, trace_len: usize) -> ChipletsTrace {
assert!(self.trace_len() <= trace_len, "target trace length too small");
let mut trace = vec![Felt::ZERO; CHIPLETS_WIDTH * trace_len];
self.fill_trace(&mut trace, trace_len);
ChipletsTrace { trace }
}
fn fill_trace(self, trace: &mut [Felt], trace_len: usize) {
const W: usize = CHIPLETS_WIDTH;
debug_assert_eq!(trace.len(), W * trace_len);
let memory_start: usize = self.memory_start().into();
let ace_start: usize = self.ace_start().into();
let kernel_rom_start: usize = self.kernel_rom_start().into();
let padding_start: usize = self.padding_start().into();
let Chiplets { hasher, bitwise, memory, kernel_rom, ace } = self;
let hasher_len = hasher.trace_len();
let bitwise_len = bitwise.trace_len();
let memory_len = memory.trace_len();
let ace_len = ace.trace_len();
let kernel_rom_len = kernel_rom.trace_len();
const _: () = assert!(DATA_COL_START + HASHER_WIDTH - 1 == CHIPLETS_WIDTH);
let (hasher_band, rest) = trace.split_at_mut(hasher_len * W);
let (bitwise_band, rest) = rest.split_at_mut(bitwise_len * W);
let (memory_band, rest) = rest.split_at_mut(memory_len * W);
let (ace_band, rest) = rest.split_at_mut(ace_len * W);
let (kernel_band, padding_band) = rest.split_at_mut(kernel_rom_len * W);
let mut hasher_fragment =
ChipletTraceFragment::with_scattered_last(hasher_band, W, 3, HASHER_WIDTH, 0, S_00_COL);
let mut bitwise_fragment = ChipletTraceFragment::with_overheads(
bitwise_band,
W,
4,
BITWISE_WIDTH,
hasher_len,
&[],
);
let mut memory_fragment = ChipletTraceFragment::with_overheads(
memory_band,
W,
5,
MEMORY_WIDTH,
memory_start,
&[3],
);
let mut ace_fragment = ChipletTraceFragment::with_overheads(
ace_band,
W,
6,
ACE_CHIPLET_NUM_COLS,
ace_start,
&[3, 4],
);
let mut kernel_rom_fragment = ChipletTraceFragment::with_overheads(
kernel_band,
W,
7,
KERNEL_ROM_TRACE_WIDTH,
kernel_rom_start,
&[3, 4, 5],
);
rayon::scope(|s| {
s.spawn(move |_| {
hasher.fill_trace(&mut hasher_fragment);
});
s.spawn(move |_| {
bitwise.fill_trace(&mut bitwise_fragment);
});
s.spawn(move |_| {
memory.fill_trace(&mut memory_fragment);
});
s.spawn(move |_| {
kernel_rom.fill_trace(&mut kernel_rom_fragment);
});
s.spawn(move |_| {
ace.fill_trace(&mut ace_fragment);
});
s.spawn(move |_| {
fill_padding_rows(padding_band, padding_start);
});
});
}
}
fn fill_padding_rows(band: &mut [Felt], row_offset: usize) {
const W: usize = CHIPLETS_WIDTH;
let (rows, _) = band.as_chunks_mut::<W>();
for (i, row) in rows.iter_mut().enumerate() {
row[DATA_COL_START] = ONE;
row[DATA_COL_START + 1] = ONE;
row[DATA_COL_START + 2] = ONE;
row[DATA_COL_START + 3] = ONE;
row[CHIP_CLK_COL] = Felt::from_u32((row_offset + i + 1) as u32);
}
}
#[derive(Debug, Copy, Clone)]
pub struct MerkleRootUpdate {
address: Felt,
old_root: Word,
new_root: Word,
}
impl MerkleRootUpdate {
pub fn get_address(&self) -> Felt {
self.address
}
pub fn get_old_root(&self) -> Word {
self.old_root
}
pub fn get_new_root(&self) -> Word {
self.new_root
}
}