use alloc::vec::Vec;
use miden_core::{WORD_SIZE, field::PrimeCharacteristicRing};
use super::messages::{BlockHashMsg, KernelRomMsg, LogPrecompileMsg};
use crate::{PV_PROGRAM_HASH, PV_TRANSCRIPT_STATE, lookup::BoundaryBuilder};
pub const NUM_LOGUP_COMMITTED_FINALS: usize = 2;
pub(crate) fn emit_core_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],
];
boundary.add(
"block_hash_seed",
BlockHashMsg::Child {
parent: B::F::ZERO,
child_hash: program_hash,
},
);
boundary.add("log_precompile_initial", LogPrecompileMsg { state: [B::F::ZERO; 4] });
boundary.remove("log_precompile_final", LogPrecompileMsg { state: final_state });
}
pub(crate) fn emit_chiplets_boundary<B: BoundaryBuilder>(boundary: &mut B) {
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();
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 crate::{
ChipletsAir, Felt, MidenAir, NUM_PUBLIC_VALUES,
constraints::{
columns::{NUM_CHIPLETS_COLS, NUM_CORE_COLS},
lookup::{
BusId, MIDEN_MAX_MESSAGE_WIDTH, chiplet_air::CHIPLET_COLUMN_SHAPE,
main_air::MAIN_COLUMN_SHAPE,
},
},
lookup::{
Challenges,
debug::{ValidateLayout, ValidateLookupAir, check_trace_balance},
},
trace::AUX_TRACE_RAND_CHALLENGES,
};
#[test]
fn block_hash_seed_matches_root_end_removal() {
use crate::{
constraints::lookup::messages::BlockHashMsg,
lookup::{Challenges, LookupMessage},
};
let challenges = Challenges::<QuadFelt>::new(
QuadFelt::from_u32(7),
QuadFelt::from_u32(11),
MIDEN_MAX_MESSAGE_WIDTH,
BusId::COUNT,
);
let program_hash: [Felt; 4] = [
Felt::from_u32(101),
Felt::from_u32(102),
Felt::from_u32(103),
Felt::from_u32(104),
];
let seed = BlockHashMsg::Child {
parent: Felt::ZERO,
child_hash: program_hash,
};
let root_end = BlockHashMsg::End {
parent: Felt::ZERO,
child_hash: program_hash,
is_first_child: Felt::ZERO,
is_loop_body: Felt::ZERO,
};
assert_eq!(
<BlockHashMsg<Felt> as LookupMessage<Felt, QuadFelt>>::encode(&seed, &challenges),
<BlockHashMsg<Felt> as LookupMessage<Felt, QuadFelt>>::encode(&root_end, &challenges),
"boundary `Child` seed and root-END `End` removal must encode to equal denominators"
);
}
#[test]
fn core_air_lookup_validates() {
let layout = ValidateLayout {
trace_width: NUM_CORE_COLS,
num_public_values: NUM_PUBLIC_VALUES,
num_periodic_columns: 0,
permutation_width: MAIN_COLUMN_SHAPE.len(),
num_permutation_challenges: AUX_TRACE_RAND_CHALLENGES,
num_permutation_values: 1,
};
ValidateLookupAir::validate(&MidenAir::CORE, layout)
.unwrap_or_else(|err| panic!("CoreAir LookupAir validation failed: {err}"));
}
#[test]
fn chiplets_air_lookup_validates() {
let num_periodic = ChipletsAir.periodic_columns().len();
let layout = ValidateLayout {
trace_width: NUM_CHIPLETS_COLS,
num_public_values: NUM_PUBLIC_VALUES,
num_periodic_columns: num_periodic,
permutation_width: CHIPLET_COLUMN_SHAPE.len(),
num_permutation_challenges: AUX_TRACE_RAND_CHALLENGES,
num_permutation_values: 1,
};
ValidateLookupAir::validate(&MidenAir::CHIPLETS, layout)
.unwrap_or_else(|err| panic!("ChipletsAir LookupAir validation failed: {err}"));
}
#[test]
fn trace_balance_runs_on_zero_trace() {
const NUM_ROWS: usize = 4;
let data = vec![Felt::ZERO; NUM_CORE_COLS * NUM_ROWS];
let main_trace = RowMajorMatrix::new(data, NUM_CORE_COLS);
let periodic: Vec<Vec<Felt>> = Vec::new();
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(
&MidenAir::CORE,
&main_trace,
&periodic,
&publics,
&[],
&challenges,
);
}
}