use alloc::vec;
use core::ops::Deref;
use miden_core::{Felt, field::QuadFelt};
use miden_lifted_air::Statement;
use miden_lifted_stark::{Preprocessed, StarkConfig, lmcs::Lmcs};
use super::prove::ChipletMultiAir;
use crate::{
logup::NUM_PUBLIC_VALUES,
stark_config::{Blake3Config, KeccakConfig, Poseidon2Config, RpoConfig, RpxConfig},
};
pub(super) enum PreprocessedHandle<'a, L>
where
L: Lmcs<F = Felt>,
{
#[cfg_attr(not(feature = "std"), allow(dead_code))]
Cached(&'a Preprocessed<Felt, L>),
#[cfg_attr(feature = "std", allow(dead_code))]
Owned(Preprocessed<Felt, L>),
}
impl<L> Deref for PreprocessedHandle<'_, L>
where
L: Lmcs<F = Felt>,
{
type Target = Preprocessed<Felt, L>;
fn deref(&self) -> &Preprocessed<Felt, L> {
match self {
Self::Cached(p) => p,
Self::Owned(p) => p,
}
}
}
fn scratch_statement() -> Statement<Felt, QuadFelt, ChipletMultiAir> {
Statement::new(ChipletMultiAir::new(), vec![Felt::ZERO; NUM_PUBLIC_VALUES], vec![])
.expect("chiplet statement inputs are valid")
}
fn build<SC>(config: &SC) -> Preprocessed<Felt, SC::Lmcs>
where
SC: StarkConfig<Felt, QuadFelt>,
{
let statement = scratch_statement();
Preprocessed::build(&statement, config)
.expect("chiplet stack always declares BytePairLut preprocessed columns")
}
macro_rules! cached_preprocessed {
($fn_name:ident, $config:ty) => {
pub(super) fn $fn_name(
config: &$config,
) -> PreprocessedHandle<'static, <$config as StarkConfig<Felt, QuadFelt>>::Lmcs> {
#[cfg(feature = "std")]
{
static CACHE: std::sync::OnceLock<
Preprocessed<Felt, <$config as StarkConfig<Felt, QuadFelt>>::Lmcs>,
> = std::sync::OnceLock::new();
PreprocessedHandle::Cached(CACHE.get_or_init(|| build(config)))
}
#[cfg(not(feature = "std"))]
{
PreprocessedHandle::Owned(build(config))
}
}
};
}
cached_preprocessed!(blake3, Blake3Config);
cached_preprocessed!(rpo, RpoConfig);
cached_preprocessed!(rpx, RpxConfig);
cached_preprocessed!(poseidon2, Poseidon2Config);
cached_preprocessed!(keccak, KeccakConfig);