use alloc::vec::Vec;
use miden_air::trace::{
CHIPLETS_CLK_COL, 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,
},
eidos_compression::NUM_EIDOS_COMPRESSION_COLS,
};
use miden_core::{field::PrimeCharacteristicRing, mast::OpBatch, program::KernelDescriptor};
use crate::{
Felt, ONE, Word, ZERO,
crypto::merkle::MerklePath,
trace::{ChipletTraceFragment, RowIndex, range::RangeChecker},
};
mod bitwise;
use bitwise::AEAD_STREAM_FRAGMENT_WIDTH;
pub(crate) use bitwise::{AEAD_STREAM_CYCLE_LEN, Bitwise};
const BITWISE_COL_START: usize = 2;
const BITWISE_FRAGMENT_WIDTH: usize = if BITWISE_WIDTH > AEAD_STREAM_FRAGMENT_WIDTH {
BITWISE_WIDTH
} else {
AEAD_STREAM_FRAGMENT_WIDTH
};
const _: () = assert!(BITWISE_COL_START + BITWISE_FRAGMENT_WIDTH == CHIPLETS_CLK_COL);
mod hasher;
pub(crate) use hasher::Hasher;
pub use hasher::{
build_external_eidos_compression_traces, build_ordered_external_eidos_compression_traces,
};
pub(crate) fn build_and8_lookup_trace(and8_counts: &[u64]) -> Vec<Felt> {
hasher::build_and8_lookup_trace(and8_counts)
}
mod memory;
pub(crate) use memory::Memory;
mod ace;
pub use ace::{
Ace, CircuitEvaluation, MAX_EVAL_CIRCUIT_INVOCATIONS, MAX_EVAL_CIRCUIT_WIRES,
MAX_NUM_ACE_WIRES, PTR_OFFSET_ELEM, PTR_OFFSET_WORD,
};
mod kernel_rom;
pub(crate) use kernel_rom::KernelRom;
#[cfg(test)]
mod tests;
pub struct ChipletsTrace {
pub(crate) trace: Vec<Felt>,
}
pub struct EidosCompressionTrace {
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: KernelDescriptor) -> Self {
Self {
hasher: Hasher::default(),
bitwise: Bitwise::default(),
memory: Memory::default(),
ace: Ace::default(),
kernel_rom: KernelRom::new(kernel),
}
}
pub fn trace_len(&self) -> usize {
self.hasher.trace_len()
+ self.bitwise.trace_len()
+ self.memory.trace_len()
+ self.ace.trace_len()
+ self.kernel_rom.trace_len()
+ 1
}
pub fn eidos_compression_trace_len(&self) -> usize {
self.hasher.eidos_compression_trace_len()
}
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(range_checker);
}
pub fn append_eidos_compression_range_checks(
&self,
eidos_compression_height: usize,
range_checker: &mut RangeChecker,
) {
self.hasher
.append_eidos_compression_range_checks(eidos_compression_height, range_checker);
}
pub fn into_traces(
self,
trace_len: usize,
eidos_compression_trace_len: usize,
) -> (ChipletsTrace, EidosCompressionTrace, Vec<u64>) {
assert!(self.trace_len() <= trace_len, "target trace length too small");
assert!(
self.eidos_compression_trace_len() <= eidos_compression_trace_len,
"target Eidos compression trace length too small"
);
let mut trace = Felt::zero_vec(CHIPLETS_WIDTH * trace_len);
let mut eidos_compression_trace =
Felt::zero_vec(NUM_EIDOS_COMPRESSION_COLS * eidos_compression_trace_len);
let and8_counts = self.fill_trace(&mut trace, trace_len, &mut eidos_compression_trace);
(
ChipletsTrace { trace },
EidosCompressionTrace { trace: eidos_compression_trace },
and8_counts,
)
}
fn fill_trace(
self,
trace: &mut [Felt],
trace_len: usize,
eidos_compression_trace: &mut [Felt],
) -> Vec<u64> {
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, ace, kernel_rom } = 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();
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_overheads(hasher_band, W, 1, HASHER_WIDTH, 0, &[]);
let mut bitwise_fragment = ChipletTraceFragment::with_overheads(
bitwise_band,
W,
BITWISE_COL_START,
BITWISE_FRAGMENT_WIDTH,
hasher_len,
&[],
);
let mut memory_fragment = ChipletTraceFragment::with_overheads(
memory_band,
W,
3,
MEMORY_WIDTH,
memory_start,
&[1],
);
let mut ace_fragment = ChipletTraceFragment::with_overheads(
ace_band,
W,
4,
ACE_CHIPLET_NUM_COLS,
ace_start,
&[1, 2],
);
let mut kernel_rom_fragment = ChipletTraceFragment::with_overheads(
kernel_band,
W,
5,
KERNEL_ROM_TRACE_WIDTH,
kernel_rom_start,
&[1, 2, 3],
);
let mut and8_counts = Vec::new();
let mut bitwise_and8_counts = Vec::new();
rayon::scope(|s| {
let and8_counts = &mut and8_counts;
s.spawn(move |_| {
*and8_counts = hasher.fill_trace(&mut hasher_fragment, eidos_compression_trace);
});
let bitwise_and8_counts = &mut bitwise_and8_counts;
s.spawn(move |_| {
*bitwise_and8_counts = bitwise.fill_trace(&mut bitwise_fragment);
});
s.spawn(move |_| {
memory.fill_trace(&mut memory_fragment);
});
s.spawn(move |_| {
ace.fill_trace(&mut ace_fragment);
});
s.spawn(move |_| {
kernel_rom.fill_trace(&mut kernel_rom_fragment);
});
s.spawn(move |_| {
fill_padding_rows(padding_band, padding_start);
});
});
for (count, bitwise_count) in and8_counts.iter_mut().zip(bitwise_and8_counts) {
*count += bitwise_count;
}
and8_counts
}
}
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[1] = ONE;
row[2] = ONE;
row[3] = ONE;
row[4] = ONE;
row[W - 1] = 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
}
}