use alloc::vec::Vec;
#[cfg(any(test, feature = "testing"))]
use core::ops::Range;
use miden_air::{
MidenMultiAir, ProverStatement, PublicInputs, StarkConfig, Statement, config, debug,
trace::{MainTrace, decoder::NUM_USER_OP_HELPERS},
};
use miden_core::deferred::DeferredState;
use crate::{
Felt, MIN_STACK_DEPTH, Program, ProgramInfo, StackInputs, StackOutputs, Word, ZERO,
fast::ExecutionOutput, field::QuadFelt, utils::RowMajorMatrix,
};
pub(crate) mod utils;
use utils::ChipletTraceFragment;
pub mod chiplets;
pub(crate) mod execution_tracer;
mod block_stack;
mod parallel;
mod range;
mod stack;
mod trace_state;
#[cfg(test)]
mod tests;
pub use execution_tracer::TraceGenerationContext;
pub use miden_air::trace::RowIndex;
pub use parallel::{CORE_TRACE_WIDTH, build_trace, build_trace_with_max_len};
#[cfg(feature = "std")]
pub(crate) use parallel::{MAX_TRACE_LEN, build_hasher_chiplet, build_trace_with_prebuilt_hasher};
#[cfg(feature = "std")]
pub(crate) use trace_state::ResolvedHasherOp;
pub use utils::{ChipletsLengths, TraceLenSummary};
#[derive(Debug)]
pub struct TraceBuildInputs {
trace_output: TraceBuildOutput,
trace_generation_context: TraceGenerationContext,
program_info: ProgramInfo,
}
impl TraceBuildInputs {
#[cfg(feature = "std")]
pub(crate) fn take_hasher_replay(&mut self) -> trace_state::HasherRequestReplay {
core::mem::take(&mut self.trace_generation_context.hasher_for_chiplet)
}
}
#[derive(Debug)]
pub(crate) struct TraceBuildOutput {
stack_outputs: StackOutputs,
deferred_state: DeferredState,
}
impl TraceBuildOutput {
fn from_execution_output(execution_output: ExecutionOutput) -> Self {
let ExecutionOutput {
stack,
advice: _,
memory: _,
deferred_state,
} = execution_output;
Self { stack_outputs: stack, deferred_state }
}
}
impl TraceBuildInputs {
pub(crate) fn from_execution(
program: &Program,
execution_output: ExecutionOutput,
trace_generation_context: TraceGenerationContext,
) -> Self {
let trace_output = TraceBuildOutput::from_execution_output(execution_output);
let program_info = program.to_info();
Self {
trace_output,
trace_generation_context,
program_info,
}
}
pub fn stack_outputs(&self) -> &StackOutputs {
&self.trace_output.stack_outputs
}
pub fn deferred_state(&self) -> &DeferredState {
&self.trace_output.deferred_state
}
pub fn program_info(&self) -> &ProgramInfo {
&self.program_info
}
#[cfg(any(test, feature = "testing"))]
pub fn trace_generation_context(&self) -> &TraceGenerationContext {
&self.trace_generation_context
}
#[cfg(any(test, feature = "testing"))]
#[cfg_attr(all(feature = "testing", not(test)), expect(dead_code))]
pub(crate) fn trace_generation_context_mut(&mut self) -> &mut TraceGenerationContext {
&mut self.trace_generation_context
}
}
#[derive(Debug)]
pub struct ExecutionTrace {
main_trace: MainTrace,
program_info: ProgramInfo,
stack_outputs: StackOutputs,
deferred_state: DeferredState,
trace_len_summary: TraceLenSummary,
}
impl ExecutionTrace {
pub(crate) fn new_from_parts(
program_info: ProgramInfo,
trace_output: TraceBuildOutput,
main_trace: MainTrace,
trace_len_summary: TraceLenSummary,
) -> Self {
let TraceBuildOutput { stack_outputs, deferred_state } = trace_output;
Self {
main_trace,
program_info,
stack_outputs,
deferred_state,
trace_len_summary,
}
}
pub fn program_info(&self) -> &ProgramInfo {
&self.program_info
}
pub fn program_hash(&self) -> &Word {
self.program_info.program_hash()
}
pub fn stack_outputs(&self) -> &StackOutputs {
&self.stack_outputs
}
pub fn public_inputs(&self) -> PublicInputs {
PublicInputs::new(
self.program_info.clone(),
self.init_stack_state(),
self.stack_outputs,
self.deferred_state.root(),
)
}
pub fn to_public_values(&self) -> Vec<Felt> {
self.public_inputs().to_elements()
}
pub fn main_trace(&self) -> &MainTrace {
&self.main_trace
}
pub fn main_trace_mut(&mut self) -> &mut MainTrace {
&mut self.main_trace
}
pub fn deferred_state(&self) -> &DeferredState {
&self.deferred_state
}
pub fn into_outputs(self) -> StackOutputs {
self.stack_outputs
}
pub fn init_stack_state(&self) -> StackInputs {
let mut result = [ZERO; MIN_STACK_DEPTH];
let row = RowIndex::from(0_u32);
for (i, result) in result.iter_mut().enumerate() {
*result = self.main_trace.stack_element(i, row);
}
result.into()
}
pub fn last_stack_state(&self) -> StackOutputs {
let last_step = RowIndex::from(self.last_step());
let mut result = [ZERO; MIN_STACK_DEPTH];
for (i, result) in result.iter_mut().enumerate() {
*result = self.main_trace.stack_element(i, last_step);
}
result.into()
}
pub fn get_user_op_helpers_at(&self, clk: u32) -> [Felt; NUM_USER_OP_HELPERS] {
let mut result = [ZERO; NUM_USER_OP_HELPERS];
let row = RowIndex::from(clk);
for (i, result) in result.iter_mut().enumerate() {
*result = self.main_trace.helper_register(i, row);
}
result
}
pub fn get_trace_len(&self) -> usize {
self.main_trace.num_rows()
}
pub fn length(&self) -> usize {
self.get_trace_len()
}
pub fn trace_len_summary(&self) -> &TraceLenSummary {
&self.trace_len_summary
}
pub fn check_constraints(&self) {
let public_inputs = self.public_inputs();
let (core_matrix, chiplets_matrix, poseidon2_matrix) = self.main_trace.to_air_matrices();
let (public_values, aux_inputs) = public_inputs.to_air_inputs();
let statement =
Statement::<Felt, QuadFelt, _>::new(MidenMultiAir::new(), public_values, aux_inputs)
.expect("valid statement inputs");
let prover_statement =
ProverStatement::new(statement, vec![core_matrix, chiplets_matrix, poseidon2_matrix])
.expect("valid trace shapes");
let config = config::poseidon2_config(config::pcs_params(), config::RELATION_DIGEST);
debug::check_constraints(&prover_statement, config.challenger());
}
pub fn to_air_matrices(
&self,
) -> (RowMajorMatrix<Felt>, RowMajorMatrix<Felt>, RowMajorMatrix<Felt>) {
self.main_trace.to_air_matrices()
}
pub fn into_air_matrices(
self,
) -> (RowMajorMatrix<Felt>, RowMajorMatrix<Felt>, RowMajorMatrix<Felt>) {
self.main_trace.into_air_matrices()
}
fn last_step(&self) -> usize {
self.main_trace.core_height() - 1
}
#[cfg(any(test, feature = "testing"))]
pub fn get_column_range(&self, range: Range<usize>) -> Vec<Vec<Felt>> {
self.main_trace.get_column_range(range)
}
}