use alloc::vec::Vec;
use miden_core::{WORD_SIZE, field::PrimeCharacteristicRing};
use super::{
chiplet_air::CHIPLET_COLUMN_SHAPE,
main_air::MAIN_COLUMN_SHAPE,
messages::{BlockHashMsg, KernelRomMsg, LogCapacityMsg},
};
use crate::{PV_PROGRAM_HASH, PV_TRANSCRIPT_STATE, lookup::BoundaryBuilder};
pub(crate) const MIDEN_COLUMN_SHAPE: [usize; 7] = [
MAIN_COLUMN_SHAPE[0],
MAIN_COLUMN_SHAPE[1],
MAIN_COLUMN_SHAPE[2],
MAIN_COLUMN_SHAPE[3],
CHIPLET_COLUMN_SHAPE[0],
CHIPLET_COLUMN_SHAPE[1],
CHIPLET_COLUMN_SHAPE[2],
];
pub const NUM_LOGUP_COMMITTED_FINALS: usize = 2;
pub(crate) fn emit_miden_boundary<B: BoundaryBuilder>(boundary: &mut B) {
let pv = boundary.public_values();
let program_hash: [B::F; 4] = [
pv[PV_PROGRAM_HASH],
pv[PV_PROGRAM_HASH + 1],
pv[PV_PROGRAM_HASH + 2],
pv[PV_PROGRAM_HASH + 3],
];
let final_state: [B::F; 4] = [
pv[PV_TRANSCRIPT_STATE],
pv[PV_TRANSCRIPT_STATE + 1],
pv[PV_TRANSCRIPT_STATE + 2],
pv[PV_TRANSCRIPT_STATE + 3],
];
let kernel_digests: Vec<[B::F; 4]> = boundary
.var_len_public_inputs()
.first()
.map(|felts| felts.chunks_exact(WORD_SIZE).map(|d| [d[0], d[1], d[2], d[3]]).collect())
.unwrap_or_default();
boundary.add(
"block_hash_seed",
BlockHashMsg::Child {
parent: B::F::ZERO,
child_hash: program_hash,
},
);
boundary.add("log_precompile_initial", LogCapacityMsg { capacity: [B::F::ZERO; 4] });
boundary.remove("log_precompile_final", LogCapacityMsg { capacity: final_state });
for digest in kernel_digests {
boundary.add("kernel_rom_init", KernelRomMsg::init(digest));
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
extern crate std;
use std::{vec, vec::Vec};
use miden_core::{
field::{PrimeCharacteristicRing, QuadFelt},
utils::RowMajorMatrix,
};
use miden_crypto::stark::air::LiftedAir;
use super::NUM_LOGUP_COMMITTED_FINALS;
use crate::{
Felt, NUM_PUBLIC_VALUES, ProcessorAir,
constraints::lookup::{BusId, MIDEN_MAX_MESSAGE_WIDTH},
lookup::{
Challenges,
debug::{ValidateLayout, ValidateLookupAir, check_trace_balance},
},
trace::{AUX_TRACE_RAND_CHALLENGES, AUX_TRACE_WIDTH, TRACE_WIDTH},
};
fn num_periodic() -> usize {
LiftedAir::<Felt, QuadFelt>::periodic_columns(&ProcessorAir).len()
}
fn validate_layout() -> ValidateLayout {
ValidateLayout {
trace_width: TRACE_WIDTH,
num_public_values: NUM_PUBLIC_VALUES,
num_periodic_columns: num_periodic(),
permutation_width: AUX_TRACE_WIDTH,
num_permutation_challenges: AUX_TRACE_RAND_CHALLENGES,
num_permutation_values: NUM_LOGUP_COMMITTED_FINALS,
}
}
#[test]
fn processor_air_lookup_validates() {
ValidateLookupAir::validate(&ProcessorAir, validate_layout())
.unwrap_or_else(|err| panic!("ProcessorAir LookupAir validation failed: {err}"));
}
#[test]
fn trace_balance_runs_on_zero_trace() {
const NUM_ROWS: usize = 4;
let data = vec![Felt::ZERO; TRACE_WIDTH * NUM_ROWS];
let main_trace = RowMajorMatrix::new(data, TRACE_WIDTH);
let periodic: Vec<Vec<Felt>> =
(0..num_periodic()).map(|_| vec![Felt::ZERO; NUM_ROWS]).collect();
let publics: Vec<Felt> = vec![Felt::ZERO; NUM_PUBLIC_VALUES];
let challenges = Challenges::<QuadFelt>::new(
QuadFelt::ONE,
QuadFelt::ONE,
MIDEN_MAX_MESSAGE_WIDTH,
BusId::COUNT,
);
let _ =
check_trace_balance(&ProcessorAir, &main_trace, &periodic, &publics, &[], &challenges);
}
}