use miden_air::{
RowIndex,
trace::{
LOG_PRECOMPILE_LABEL,
chiplets::hasher::DIGEST_RANGE,
log_precompile::{HELPER_CAP_PREV_RANGE, STACK_CAP_NEXT_RANGE},
main_trace::MainTrace,
},
};
use miden_core::{Felt, OPCODE_LOGPRECOMPILE, precompile::PrecompileTranscriptState};
use super::{
FieldElement, build_ace_memory_read_element_request, build_ace_memory_read_word_request,
};
use crate::{
chiplets::aux_trace::build_value,
debug::{BusDebugger, BusMessage},
trace::AuxColumnBuilder,
};
pub struct ChipletsVTableColBuilder {
final_transcript_state: PrecompileTranscriptState,
}
impl ChipletsVTableColBuilder {
pub fn new(final_transcript_state: PrecompileTranscriptState) -> Self {
Self { final_transcript_state }
}
}
impl<E> AuxColumnBuilder<E> for ChipletsVTableColBuilder
where
E: FieldElement<BaseField = Felt>,
{
fn get_requests_at(
&self,
main_trace: &MainTrace,
alphas: &[E],
row: RowIndex,
_debugger: &mut BusDebugger<E>,
) -> E {
let op_code = main_trace.get_op_code(row).as_int() as u8;
let log_pc_request = if op_code == OPCODE_LOGPRECOMPILE {
build_log_precompile_capacity_remove(main_trace, row, alphas, _debugger)
} else {
E::ONE
};
let request_ace = if main_trace.chiplet_ace_is_read_row(row) {
build_ace_memory_read_word_request(main_trace, alphas, row, _debugger)
} else if main_trace.chiplet_ace_is_eval_row(row) {
build_ace_memory_read_element_request(main_trace, alphas, row, _debugger)
} else {
E::ONE
};
chiplets_vtable_remove_sibling(main_trace, alphas, row) * request_ace * log_pc_request
}
fn get_responses_at(
&self,
main_trace: &MainTrace,
alphas: &[E],
row: RowIndex,
_debugger: &mut BusDebugger<E>,
) -> E {
let op_code = main_trace.get_op_code(row).as_int() as u8;
let log_pc_response = if op_code == OPCODE_LOGPRECOMPILE {
build_log_precompile_capacity_insert(main_trace, row, alphas, _debugger)
} else {
E::ONE
};
chiplets_vtable_add_sibling(main_trace, alphas, row) * log_pc_response
}
fn init_requests(
&self,
_main_trace: &MainTrace,
alphas: &[E],
_debugger: &mut BusDebugger<E>,
) -> E {
let message = LogPrecompileMessage { state: self.final_transcript_state };
let value = message.value(alphas);
#[cfg(any(test, feature = "bus-debugger"))]
_debugger.add_request(alloc::boxed::Box::new(message), alphas);
value
}
fn init_responses(
&self,
_main_trace: &MainTrace,
alphas: &[E],
_debugger: &mut BusDebugger<E>,
) -> E {
let message = LogPrecompileMessage {
state: PrecompileTranscriptState::default(),
};
let value = message.value(alphas);
#[cfg(any(test, feature = "bus-debugger"))]
_debugger.add_response(alloc::boxed::Box::new(message), alphas);
value
}
}
fn chiplets_vtable_remove_sibling<E>(main_trace: &MainTrace, alphas: &[E], row: RowIndex) -> E
where
E: FieldElement<BaseField = Felt>,
{
let f_mu: bool = main_trace.f_mu(row);
let f_mua: bool = main_trace.f_mua(row);
if f_mu {
let index = main_trace.chiplet_node_index(row);
let lsb = index.as_int() & 1;
if lsb == 0 {
let sibling = &main_trace.chiplet_hasher_state(row)[DIGEST_RANGE.end..];
alphas[0]
+ alphas[3].mul_base(index)
+ alphas[12].mul_base(sibling[0])
+ alphas[13].mul_base(sibling[1])
+ alphas[14].mul_base(sibling[2])
+ alphas[15].mul_base(sibling[3])
} else {
let sibling = &main_trace.chiplet_hasher_state(row)[DIGEST_RANGE];
alphas[0]
+ alphas[3].mul_base(index)
+ alphas[8].mul_base(sibling[0])
+ alphas[9].mul_base(sibling[1])
+ alphas[10].mul_base(sibling[2])
+ alphas[11].mul_base(sibling[3])
}
} else if f_mua {
let index = main_trace.chiplet_node_index(row);
let lsb = index.as_int() & 1;
if lsb == 0 {
let sibling = &main_trace.chiplet_hasher_state(row + 1)[DIGEST_RANGE.end..];
alphas[0]
+ alphas[3].mul_base(index)
+ alphas[12].mul_base(sibling[0])
+ alphas[13].mul_base(sibling[1])
+ alphas[14].mul_base(sibling[2])
+ alphas[15].mul_base(sibling[3])
} else {
let sibling = &main_trace.chiplet_hasher_state(row + 1)[DIGEST_RANGE];
alphas[0]
+ alphas[3].mul_base(index)
+ alphas[8].mul_base(sibling[0])
+ alphas[9].mul_base(sibling[1])
+ alphas[10].mul_base(sibling[2])
+ alphas[11].mul_base(sibling[3])
}
} else {
E::ONE
}
}
fn chiplets_vtable_add_sibling<E>(main_trace: &MainTrace, alphas: &[E], row: RowIndex) -> E
where
E: FieldElement<BaseField = Felt>,
{
let f_mv: bool = main_trace.f_mv(row);
let f_mva: bool = main_trace.f_mva(row);
if f_mv {
let index = main_trace.chiplet_node_index(row);
let lsb = index.as_int() & 1;
if lsb == 0 {
let sibling = &main_trace.chiplet_hasher_state(row)[DIGEST_RANGE.end..];
alphas[0]
+ alphas[3].mul_base(index)
+ alphas[12].mul_base(sibling[0])
+ alphas[13].mul_base(sibling[1])
+ alphas[14].mul_base(sibling[2])
+ alphas[15].mul_base(sibling[3])
} else {
let sibling = &main_trace.chiplet_hasher_state(row)[DIGEST_RANGE];
alphas[0]
+ alphas[3].mul_base(index)
+ alphas[8].mul_base(sibling[0])
+ alphas[9].mul_base(sibling[1])
+ alphas[10].mul_base(sibling[2])
+ alphas[11].mul_base(sibling[3])
}
} else if f_mva {
let index = main_trace.chiplet_node_index(row);
let lsb = index.as_int() & 1;
if lsb == 0 {
let sibling = &main_trace.chiplet_hasher_state(row + 1)[DIGEST_RANGE.end..];
alphas[0]
+ alphas[3].mul_base(index)
+ alphas[12].mul_base(sibling[0])
+ alphas[13].mul_base(sibling[1])
+ alphas[14].mul_base(sibling[2])
+ alphas[15].mul_base(sibling[3])
} else {
let sibling = &main_trace.chiplet_hasher_state(row + 1)[DIGEST_RANGE];
alphas[0]
+ alphas[3].mul_base(index)
+ alphas[8].mul_base(sibling[0])
+ alphas[9].mul_base(sibling[1])
+ alphas[10].mul_base(sibling[2])
+ alphas[11].mul_base(sibling[3])
}
} else {
E::ONE
}
}
struct LogPrecompileMessage {
state: PrecompileTranscriptState,
}
impl<E> BusMessage<E> for LogPrecompileMessage
where
E: FieldElement<BaseField = Felt>,
{
fn value(&self, alphas: &[E]) -> E {
let state_elements: [Felt; 4] = self.state.into();
alphas[0]
+ alphas[1].mul_base(Felt::from(LOG_PRECOMPILE_LABEL))
+ build_value(&alphas[2..6], state_elements)
}
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: FieldElement<BaseField = Felt>>(
main_trace: &MainTrace,
row: RowIndex,
alphas: &[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(alphas);
#[cfg(any(test, feature = "bus-debugger"))]
_debugger.add_request(alloc::boxed::Box::new(message), alphas);
value
}
fn build_log_precompile_capacity_insert<E: FieldElement<BaseField = Felt>>(
main_trace: &MainTrace,
row: RowIndex,
alphas: &[E],
_debugger: &mut BusDebugger<E>,
) -> E {
let state: PrecompileTranscriptState = [
main_trace.stack_element(STACK_CAP_NEXT_RANGE.end - 1, row + 1),
main_trace.stack_element(STACK_CAP_NEXT_RANGE.end - 2, row + 1),
main_trace.stack_element(STACK_CAP_NEXT_RANGE.end - 3, row + 1),
main_trace.stack_element(STACK_CAP_NEXT_RANGE.end - 4, row + 1),
]
.into();
let message = LogPrecompileMessage { state };
let value = message.value(alphas);
#[cfg(any(test, feature = "bus-debugger"))]
_debugger.add_response(alloc::boxed::Box::new(message), alphas);
value
}