use crate::error::Result;
use crate::cast::run_hash_casts;
use crate::state::{enter_post_state, enter_operational_state, enter_error_state};
#[cfg(all(feature = "ml-kem", feature = "fips_140_3"))]
use crate::kat_kyber::run_kyber_decap_kat;
#[cfg(all(feature = "ml-dsa", feature = "fips_140_3"))]
use crate::kat_dilithium::run_dilithium_verify_kat;
#[cfg(all(feature = "ml-kem", feature = "std"))]
use crate::{pct::kyber_pct, KyberKeys};
#[cfg(all(feature = "ml-dsa", feature = "std"))]
use crate::{pct::dilithium_pct, generate_dilithium_keypair};
pub fn run_post() -> Result<()> {
enter_post_state();
let result = run_all_self_tests();
match result {
Ok(()) => {
enter_operational_state();
Ok(())
}
Err(e) => {
enter_error_state();
Err(e)
}
}
}
fn run_all_self_tests() -> Result<()> {
run_hash_casts()?;
#[cfg(all(feature = "ml-kem", feature = "fips_140_3"))]
run_kyber_decap_kat()?;
#[cfg(all(feature = "ml-dsa", feature = "fips_140_3"))]
run_dilithium_verify_kat()?;
#[cfg(all(feature = "ml-kem", feature = "std"))]
{
let kyber_keys = KyberKeys::generate_key_pair();
kyber_pct(&kyber_keys)?;
}
#[cfg(all(feature = "ml-dsa", feature = "std"))]
{
let (dil_pk, dil_sk) = generate_dilithium_keypair();
dilithium_pct(&dil_pk, &dil_sk)?;
}
Ok(())
}
pub fn run_post_or_panic() {
run_post().expect("FIPS 140-3 Pre-Operational Self-Tests failed - cannot continue");
}
#[cfg(test)]
mod tests {
use super::*;
use crate::state::{get_fips_state, FipsState, reset_fips_state};
#[test]
fn test_post_success() {
reset_fips_state();
let result = run_post();
assert!(result.is_ok(), "POST should pass: {:?}", result.err());
assert_eq!(get_fips_state(), FipsState::Operational);
}
#[test]
fn test_post_state_transitions() {
reset_fips_state();
assert_eq!(get_fips_state(), FipsState::Uninitialized);
run_post().expect("POST failed");
assert_eq!(get_fips_state(), FipsState::Operational);
}
#[test]
fn test_post_repeatable() {
for _ in 0..5 {
reset_fips_state();
let result = run_post();
assert!(result.is_ok(), "POST should pass on repeated runs");
}
}
#[cfg(feature = "std")]
#[test]
fn test_post_or_panic_success() {
reset_fips_state();
run_post_or_panic(); assert_eq!(get_fips_state(), FipsState::Operational);
}
}