use super::{
hasher::HasherLookup, BTreeMap, BitwiseLookup, Felt, FieldElement, LookupTableRow,
MemoryLookup, Vec,
};
use crate::Matrix;
mod aux_trace;
pub use aux_trace::AuxTraceBuilder;
#[derive(Default)]
pub struct ChipletsBus {
lookup_hints: BTreeMap<u32, ChipletsLookup>,
request_rows: Vec<ChipletsLookupRow>,
response_rows: Vec<ChipletsLookupRow>,
queued_requests: Vec<HasherLookup>,
}
impl ChipletsBus {
fn request_lookup(&mut self, request_cycle: u32) {
let request_idx = self.request_rows.len();
self.lookup_hints
.entry(request_cycle)
.and_modify(|lookup| {
if let ChipletsLookup::Response(response_idx) = *lookup {
*lookup = ChipletsLookup::RequestAndResponse((request_idx, response_idx));
}
})
.or_insert_with(|| ChipletsLookup::Request(request_idx));
}
fn provide_lookup(&mut self, response_cycle: u32) {
let response_idx = self.response_rows.len();
self.lookup_hints
.entry(response_cycle)
.and_modify(|lookup| {
if let ChipletsLookup::Request(request_idx) = *lookup {
*lookup = ChipletsLookup::RequestAndResponse((request_idx, response_idx));
}
})
.or_insert_with(|| ChipletsLookup::Response(response_idx));
}
pub fn request_hasher_operation(&mut self, lookups: &[HasherLookup], cycle: u32) {
debug_assert!(
lookups.len() == 2 || lookups.len() == 4,
"incorrect number of lookup rows for hasher operation request"
);
self.request_lookup(cycle);
self.request_rows
.push(ChipletsLookupRow::HasherMulti(lookups.to_vec()));
}
pub fn request_hasher_lookup(&mut self, lookup: HasherLookup, cycle: u32) {
self.request_lookup(cycle);
self.request_rows.push(ChipletsLookupRow::Hasher(lookup));
}
pub fn enqueue_hasher_request(&mut self, lookup: HasherLookup) {
self.queued_requests.push(lookup);
}
pub fn send_queued_hasher_request(&mut self, cycle: u32) {
let lookup = self.queued_requests.pop();
debug_assert!(lookup.is_some(), "no queued requests");
if let Some(lookup) = lookup {
self.request_hasher_lookup(lookup, cycle);
}
}
pub fn provide_hasher_lookup(&mut self, lookup: HasherLookup, response_cycle: u32) {
self.provide_lookup(response_cycle);
self.response_rows.push(ChipletsLookupRow::Hasher(lookup));
}
pub fn provide_hasher_lookups(&mut self, lookups: &[HasherLookup]) {
for lookup in lookups.iter() {
self.provide_hasher_lookup(*lookup, lookup.cycle());
}
}
pub fn request_bitwise_operation(&mut self, lookup: BitwiseLookup, cycle: u32) {
self.request_lookup(cycle);
self.request_rows.push(ChipletsLookupRow::Bitwise(lookup));
}
pub fn provide_bitwise_operation(&mut self, lookup: BitwiseLookup, response_cycle: u32) {
self.provide_lookup(response_cycle);
self.response_rows.push(ChipletsLookupRow::Bitwise(lookup));
}
pub fn request_memory_operation(&mut self, lookups: &[MemoryLookup], cycle: u32) {
self.request_lookup(cycle);
let request = match lookups.len() {
1 => ChipletsLookupRow::Memory(lookups[0]),
2 => ChipletsLookupRow::MemoryMulti([lookups[0], lookups[1]]),
_ => panic!("invalid number of requested memory operations"),
};
self.request_rows.push(request);
}
pub fn provide_memory_operation(&mut self, lookup: MemoryLookup, response_cycle: u32) {
self.provide_lookup(response_cycle);
self.response_rows.push(ChipletsLookupRow::Memory(lookup));
}
pub fn into_aux_builder(self) -> AuxTraceBuilder {
let lookup_hints = self.lookup_hints.into_iter().collect();
AuxTraceBuilder {
lookup_hints,
request_rows: self.request_rows,
response_rows: self.response_rows,
}
}
#[cfg(test)]
pub(super) fn get_lookup_hint(&self, cycle: u32) -> Option<&ChipletsLookup> {
self.lookup_hints.get(&cycle)
}
#[cfg(test)]
pub(super) fn get_response_row(&self, i: usize) -> ChipletsLookupRow {
self.response_rows[i].clone()
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(super) enum ChipletsLookup {
Request(usize),
Response(usize),
RequestAndResponse((usize, usize)),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(super) enum ChipletsLookupRow {
Hasher(HasherLookup),
HasherMulti(Vec<HasherLookup>),
Bitwise(BitwiseLookup),
Memory(MemoryLookup),
MemoryMulti([MemoryLookup; 2]),
}
impl LookupTableRow for ChipletsLookupRow {
fn to_value<E: FieldElement<BaseField = Felt>>(
&self,
main_trace: &Matrix<Felt>,
alphas: &[E],
) -> E {
match self {
ChipletsLookupRow::HasherMulti(lookups) => lookups
.iter()
.fold(E::ONE, |acc, row| acc * row.to_value(main_trace, alphas)),
ChipletsLookupRow::Hasher(row) => row.to_value(main_trace, alphas),
ChipletsLookupRow::Bitwise(row) => row.to_value(main_trace, alphas),
ChipletsLookupRow::Memory(row) => row.to_value(main_trace, alphas),
ChipletsLookupRow::MemoryMulti(lookups) => lookups
.iter()
.fold(E::ONE, |acc, row| acc * row.to_value(main_trace, alphas)),
}
}
}