use miden_air::trace::{
Challenges, LOG_PRECOMPILE_LABEL, MainTrace, RowIndex,
chiplets::hasher::DIGEST_LEN,
log_precompile::{HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE},
};
use miden_core::{
Felt, field::ExtensionField, operations::opcodes, precompile::PrecompileTranscriptState,
};
use super::{build_ace_memory_read_element_request, build_ace_memory_read_word_request};
use crate::{
debug::{BusDebugger, BusMessage},
trace::AuxColumnBuilder,
};
pub struct ChipletsVTableColBuilder;
impl<E> AuxColumnBuilder<E> for ChipletsVTableColBuilder
where
E: ExtensionField<Felt>,
{
fn get_requests_at(
&self,
main_trace: &MainTrace,
challenges: &Challenges<E>,
row: RowIndex,
_debugger: &mut BusDebugger<E>,
) -> E {
let op_code = main_trace.get_op_code(row).as_canonical_u64() as u8;
let log_pc_request = if op_code == opcodes::LOGPRECOMPILE {
build_log_precompile_capacity_remove(main_trace, row, challenges, _debugger)
} else {
E::ONE
};
let request_ace = if main_trace.chiplet_ace_is_read_row(row) {
build_ace_memory_read_word_request(main_trace, challenges, row, _debugger)
} else if main_trace.chiplet_ace_is_eval_row(row) {
build_ace_memory_read_element_request(main_trace, challenges, row, _debugger)
} else {
E::ONE
};
chiplets_vtable_remove_sibling(main_trace, challenges, row) * request_ace * log_pc_request
}
fn get_responses_at(
&self,
main_trace: &MainTrace,
challenges: &Challenges<E>,
row: RowIndex,
_debugger: &mut BusDebugger<E>,
) -> E {
let op_code = main_trace.get_op_code(row).as_canonical_u64() as u8;
let log_pc_response = if op_code == opcodes::LOGPRECOMPILE {
build_log_precompile_capacity_insert(main_trace, row, challenges, _debugger)
} else {
E::ONE
};
chiplets_vtable_add_sibling(main_trace, challenges, row) * log_pc_response
}
#[cfg(any(test, feature = "bus-debugger"))]
fn enforce_bus_balance(&self) -> bool {
false
}
}
const RATE0_RANGE: core::ops::Range<usize> = 0..DIGEST_LEN;
const RATE1_RANGE: core::ops::Range<usize> = DIGEST_LEN..(2 * DIGEST_LEN);
const SIBLING_RATE1_LAYOUT: [usize; 5] = [2, 7, 8, 9, 10];
const SIBLING_RATE0_LAYOUT: [usize; 5] = [2, 3, 4, 5, 6];
#[inline(always)]
fn encode_sibling_from_trace<E: ExtensionField<Felt>>(
main_trace: &MainTrace,
challenges: &Challenges<E>,
row: RowIndex,
state_row: RowIndex,
) -> E {
let index = main_trace.chiplet_node_index(row);
let lsb = index.as_canonical_u64() & 1;
let (layout, sibling) = if lsb == 0 {
(SIBLING_RATE1_LAYOUT, &main_trace.chiplet_hasher_state(state_row)[RATE1_RANGE])
} else {
(SIBLING_RATE0_LAYOUT, &main_trace.chiplet_hasher_state(state_row)[RATE0_RANGE])
};
challenges.encode_sparse(layout, [index, sibling[0], sibling[1], sibling[2], sibling[3]])
}
fn chiplets_vtable_remove_sibling<E: ExtensionField<Felt>>(
main_trace: &MainTrace,
challenges: &Challenges<E>,
row: RowIndex,
) -> E {
if main_trace.f_mu(row) {
encode_sibling_from_trace(main_trace, challenges, row, row)
} else if main_trace.f_mua(row) {
encode_sibling_from_trace(main_trace, challenges, row, row + 1)
} else {
E::ONE
}
}
fn chiplets_vtable_add_sibling<E: ExtensionField<Felt>>(
main_trace: &MainTrace,
challenges: &Challenges<E>,
row: RowIndex,
) -> E {
if main_trace.f_mv(row) {
encode_sibling_from_trace(main_trace, challenges, row, row)
} else if main_trace.f_mva(row) {
encode_sibling_from_trace(main_trace, challenges, row, row + 1)
} else {
E::ONE
}
}
struct LogPrecompileMessage {
state: PrecompileTranscriptState,
}
impl<E> BusMessage<E> for LogPrecompileMessage
where
E: ExtensionField<Felt>,
{
fn value(&self, challenges: &Challenges<E>) -> E {
let state_elements: [Felt; 4] = self.state.into();
challenges.encode([
Felt::from_u8(LOG_PRECOMPILE_LABEL),
state_elements[0],
state_elements[1],
state_elements[2],
state_elements[3],
])
}
fn source(&self) -> &str {
"log_precompile"
}
}
impl core::fmt::Display for LogPrecompileMessage {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{{ state: {:?} }}", self.state)
}
}
fn build_log_precompile_capacity_remove<E: ExtensionField<Felt>>(
main_trace: &MainTrace,
row: RowIndex,
challenges: &Challenges<E>,
_debugger: &mut BusDebugger<E>,
) -> E {
let state = PrecompileTranscriptState::from([
main_trace.helper_register(HELPER_CAP_PREV_RANGE.start, row),
main_trace.helper_register(HELPER_CAP_PREV_RANGE.start + 1, row),
main_trace.helper_register(HELPER_CAP_PREV_RANGE.start + 2, row),
main_trace.helper_register(HELPER_CAP_PREV_RANGE.start + 3, row),
]);
let message = LogPrecompileMessage { state };
let value = message.value(challenges);
#[cfg(any(test, feature = "bus-debugger"))]
_debugger.add_request(alloc::boxed::Box::new(message), challenges);
value
}
fn build_log_precompile_capacity_insert<E: ExtensionField<Felt>>(
main_trace: &MainTrace,
row: RowIndex,
challenges: &Challenges<E>,
_debugger: &mut BusDebugger<E>,
) -> E {
let state: PrecompileTranscriptState = [
main_trace.stack_element(STACK_CAP_NEXT_RANGE.start, row + 1),
main_trace.stack_element(STACK_CAP_NEXT_RANGE.start + 1, row + 1),
main_trace.stack_element(STACK_CAP_NEXT_RANGE.start + 2, row + 1),
main_trace.stack_element(STACK_CAP_NEXT_RANGE.start + 3, row + 1),
]
.into();
let message = LogPrecompileMessage { state };
let value = message.value(challenges);
#[cfg(any(test, feature = "bus-debugger"))]
_debugger.add_response(alloc::boxed::Box::new(message), challenges);
value
}