pub mod atomic_write;
pub mod audit;
pub mod convenience;
pub mod crypto_types;
pub mod error;
pub mod key_format;
pub mod logging;
pub mod selector;
pub mod serialization;
pub mod types;
pub mod zero_trust;
pub mod win_acl;
pub(crate) use win_acl::set_local_admin_dacl;
use std::sync::atomic::{AtomicBool, Ordering};
pub use crate::types::config::{
CoreConfig, EncryptionConfig, ProofComplexity, SignatureConfig, UseCaseConfig, ZeroTrustConfig,
};
pub use audit::{
AuditConfig, AuditEvent, AuditEventBuilder, AuditEventType, AuditOutcome, AuditStorage,
FileAuditStorage,
};
pub use error::{CoreError, Result};
pub use crate::types::key_lifecycle::{
CustodianRole, KeyCustodian, KeyLifecycleRecord, KeyLifecycleState, KeyStateMachine,
StateTransition,
};
pub use crate::types::traits::{
ContinuousVerifiable, DataCharacteristics, HardwareCapabilities, HardwareInfo, HardwareType,
PatternType, ProofOfPossession, SchemeSelector, VerificationStatus, ZeroTrustAuthenticable,
};
pub use selector::{
CLASSICAL_AES_GCM,
CLASSICAL_ED25519,
CryptoPolicyEngine,
DEFAULT_ENCRYPTION_SCHEME,
DEFAULT_PQ_ENCRYPTION_SCHEME,
DEFAULT_PQ_SIGNATURE_SCHEME,
DEFAULT_SIGNATURE_SCHEME,
HYBRID_ENCRYPTION_512,
HYBRID_ENCRYPTION_768,
HYBRID_ENCRYPTION_1024,
HYBRID_SIGNATURE_44,
HYBRID_SIGNATURE_65,
HYBRID_SIGNATURE_87,
PQ_ENCRYPTION_512,
PQ_ENCRYPTION_768,
PQ_ENCRYPTION_1024,
PQ_SIGNATURE_44,
PQ_SIGNATURE_65,
PQ_SIGNATURE_87,
PerformanceMetrics,
};
pub use types::{
AlgorithmSelection, ComplianceMode, CryptoConfig, CryptoContext, CryptoMode, CryptoPayload,
CryptoScheme, DecryptKey, EncryptKey, EncryptedData, EncryptedMetadata, EncryptedOutput,
EncryptionScheme, HashOutput, HybridComponents, KeyPair, PerformancePreference, PrivateKey,
PublicKey, SecretBytes, SecretVec, SecurityLevel, SignedData, SignedMetadata, SymmetricKey,
UseCase, fips_available,
};
pub use zero_trust::{
Challenge, ContinuousSession, ProofOfPossessionData, SecurityMode, TrustLevel, VerifiedSession,
ZeroKnowledgeProof, ZeroTrustAuth, ZeroTrustSession,
};
pub use convenience::{
SigningKeypair, decrypt, encrypt, generate_signing_keypair, sign_with_key, verify,
verify_with_anchor,
};
pub use convenience::{generate_hybrid_keypair, generate_hybrid_keypair_with_level};
pub use convenience::{
generate_hybrid_signing_keypair, generate_hybrid_signing_keypair_with_config, sign_hybrid,
sign_hybrid_with_config, verify_hybrid_signature, verify_hybrid_signature_with_config,
};
pub use convenience::{
generate_fn_dsa_keypair, generate_fn_dsa_keypair_with_config,
generate_fn_dsa_keypair_with_level, generate_keypair, generate_keypair_with_config,
generate_ml_dsa_keypair, generate_ml_dsa_keypair_with_config, generate_ml_kem_keypair,
generate_ml_kem_keypair_with_config, generate_slh_dsa_keypair,
generate_slh_dsa_keypair_with_config,
};
pub use convenience::{
derive_key, derive_key_with_config, derive_key_with_info, hash_data, hmac, hmac_check,
hmac_check_with_config, hmac_with_config,
};
pub use convenience::{
ECDSA_P384_SIGNATURE_LEN,
decrypt_aes_gcm,
decrypt_aes_gcm_with_aad,
decrypt_aes_gcm_with_config,
decrypt_pq_ml_kem,
decrypt_pq_ml_kem_with_config,
encrypt_aes_gcm,
encrypt_aes_gcm_with_aad,
encrypt_aes_gcm_with_config,
encrypt_pq_ml_kem,
encrypt_pq_ml_kem_with_config,
generate_ecdsa_p384_keypair,
sign_ecdsa_p384,
sign_ed25519,
sign_ed25519_with_config,
sign_pq_fn_dsa,
sign_pq_fn_dsa_with_config,
sign_pq_ml_dsa,
sign_pq_ml_dsa_with_config,
sign_pq_slh_dsa,
sign_pq_slh_dsa_with_config,
verify_ecdsa_p384,
verify_ecdsa_p384_prehash,
verify_ecdsa_p384_prehash_der,
verify_ed25519,
verify_ed25519_with_config,
verify_pq_fn_dsa,
verify_pq_fn_dsa_with_config,
verify_pq_ml_dsa,
verify_pq_ml_dsa_with_config,
verify_pq_slh_dsa,
verify_pq_slh_dsa_with_config,
};
pub use convenience::{
decrypt_aes_gcm_unverified,
decrypt_aes_gcm_with_aad_unverified,
decrypt_aes_gcm_with_config_unverified,
decrypt_pq_ml_kem_unverified,
decrypt_pq_ml_kem_with_config_unverified,
derive_key_unverified,
derive_key_with_config_unverified,
derive_key_with_info_unverified,
encrypt_aes_gcm_unverified,
encrypt_aes_gcm_with_aad_unverified,
encrypt_aes_gcm_with_config_unverified,
encrypt_pq_ml_kem_unverified,
encrypt_pq_ml_kem_with_config_unverified,
generate_hybrid_signing_keypair_unverified,
hmac_check_unverified,
hmac_check_with_config_unverified,
hmac_unverified,
hmac_with_config_unverified,
sign_ed25519_unverified,
sign_ed25519_with_config_unverified,
sign_hybrid_unverified,
sign_pq_fn_dsa_unverified,
sign_pq_fn_dsa_with_config_unverified,
sign_pq_ml_dsa_unverified,
sign_pq_ml_dsa_with_config_unverified,
sign_pq_slh_dsa_unverified,
sign_pq_slh_dsa_with_config_unverified,
verify_ed25519_unverified,
verify_ed25519_with_config_unverified,
verify_hybrid_signature_unverified,
verify_pq_fn_dsa_unverified,
verify_pq_fn_dsa_with_config_unverified,
verify_pq_ml_dsa_unverified,
verify_pq_ml_dsa_with_config_unverified,
verify_pq_slh_dsa_unverified,
verify_pq_slh_dsa_with_config_unverified,
};
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
static SELF_TESTS_PASSED: AtomicBool = AtomicBool::new(false);
pub fn init() -> Result<()> {
let config = CoreConfig::default();
config.validate()?;
run_power_up_self_tests()?;
Ok(())
}
pub fn init_with_config(config: &CoreConfig) -> Result<()> {
config.validate()?;
run_power_up_self_tests()?;
Ok(())
}
#[must_use]
pub fn self_tests_passed() -> bool {
SELF_TESTS_PASSED.load(Ordering::SeqCst)
}
fn run_power_up_self_tests() -> Result<()> {
let hash = crate::primitives::hash::sha3::sha3_256(b"abc");
let expected_sha3 = [
0x3a, 0x98, 0x5d, 0xa7, 0x4f, 0xe2, 0x25, 0xb2, 0x04, 0x5c, 0x17, 0x2d, 0x6b, 0xd3, 0x90,
0xbd, 0x85, 0x5f, 0x08, 0x6e, 0x3e, 0x9d, 0x52, 0x5b, 0x46, 0xbf, 0xe2, 0x45, 0x11, 0x43,
0x15, 0x32,
];
if !bool::from(subtle::ConstantTimeEq::ct_eq(hash.as_slice(), expected_sha3.as_slice())) {
return Err(CoreError::SelfTestFailed {
component: "SHA-3".to_string(),
status: "KAT failed".to_string(),
});
}
use crate::primitives::aead::AeadCipher;
use crate::primitives::aead::aes_gcm::AesGcm256;
struct AesGcm256Kat {
name: &'static str,
key: &'static [u8; 32],
nonce: &'static [u8; 12],
plaintext: &'static [u8],
expected_ct: &'static [u8],
expected_tag: &'static [u8; 16],
}
const AES_GCM_KAT_VECTORS: &[AesGcm256Kat] = &[
AesGcm256Kat {
name: "Count=0",
key: &[
0xb5, 0x2c, 0x50, 0x5a, 0x37, 0xd7, 0x8e, 0xda, 0x5d, 0xd3, 0x4f, 0x20, 0xc2, 0x25,
0x40, 0xea, 0x1b, 0x58, 0x96, 0x3c, 0xf8, 0xe5, 0xbf, 0x8f, 0xfa, 0x85, 0xf9, 0xf2,
0x49, 0x25, 0x05, 0xb4,
],
nonce: &[0x51, 0x6c, 0x33, 0x92, 0x9d, 0xf5, 0xa3, 0x28, 0x4f, 0xf4, 0x63, 0xd7],
plaintext: &[],
expected_ct: &[],
expected_tag: &[
0xbd, 0xc1, 0xac, 0x88, 0x4d, 0x33, 0x24, 0x57, 0xa1, 0xd2, 0x66, 0x4f, 0x16, 0x8c,
0x76, 0xf0,
],
},
AesGcm256Kat {
name: "Count=12",
key: &[
0x31, 0xbd, 0xad, 0xd9, 0x66, 0x98, 0xc2, 0x04, 0xaa, 0x9c, 0xe1, 0x44, 0x8e, 0xa9,
0x4a, 0xe1, 0xfb, 0x4a, 0x9a, 0x0b, 0x3c, 0x9d, 0x77, 0x3b, 0x51, 0xbb, 0x18, 0x22,
0x66, 0x6b, 0x8f, 0x22,
],
nonce: &[0x0d, 0x18, 0xe0, 0x6c, 0x7c, 0x72, 0x5a, 0xc9, 0xe3, 0x62, 0xe1, 0xce],
plaintext: &[
0x2d, 0xb5, 0x16, 0x8e, 0x93, 0x25, 0x56, 0xf8, 0x08, 0x9a, 0x06, 0x22, 0x98, 0x1d,
0x01, 0x7d,
],
expected_ct: &[
0xfa, 0x43, 0x62, 0x18, 0x96, 0x61, 0xd1, 0x63, 0xfc, 0xd6, 0xa5, 0x6d, 0x8b, 0xf0,
0x40, 0x5a,
],
expected_tag: &[
0xd6, 0x36, 0xac, 0x1b, 0xbe, 0xdd, 0x5c, 0xc3, 0xee, 0x72, 0x7d, 0xc2, 0xab, 0x4a,
0x94, 0x89,
],
},
];
for kat in AES_GCM_KAT_VECTORS {
let cipher = AesGcm256::new(kat.key).map_err(|e| CoreError::SelfTestFailed {
component: "AES-GCM".to_string(),
status: format!("{} key creation failed: {e}", kat.name),
})?;
let (ct, tag) = cipher.encrypt(kat.nonce, kat.plaintext, None).map_err(|e| {
CoreError::SelfTestFailed {
component: "AES-GCM".to_string(),
status: format!("{} encryption failed: {e}", kat.name),
}
})?;
if !bool::from(subtle::ConstantTimeEq::ct_eq(&ct[..], kat.expected_ct)) {
return Err(CoreError::SelfTestFailed {
component: "AES-GCM".to_string(),
status: format!(
"{} ciphertext mismatch (AES round-function or CTR-mode bug)",
kat.name
),
});
}
if !bool::from(subtle::ConstantTimeEq::ct_eq(&tag[..], &kat.expected_tag[..])) {
return Err(CoreError::SelfTestFailed {
component: "AES-GCM".to_string(),
status: format!("{} tag mismatch", kat.name),
});
}
let decrypted = cipher
.decrypt(kat.nonce, kat.expected_ct, kat.expected_tag, None)
.map_err(|e| CoreError::SelfTestFailed {
component: "AES-GCM".to_string(),
status: format!("{} decryption failed: {e}", kat.name),
})?;
if !bool::from(subtle::ConstantTimeEq::ct_eq(decrypted.as_slice(), kat.plaintext)) {
return Err(CoreError::SelfTestFailed {
component: "AES-GCM".to_string(),
status: format!("{} decrypted plaintext mismatch", kat.name),
});
}
}
use crate::primitives::ec::ed25519::{Ed25519KeyPair, Ed25519Signature};
use crate::primitives::ec::traits::{EcKeyPair, EcSignature};
const TEST_MESSAGE: &[u8] = b"latticearc-power-on-self-test-message-v1";
let keypair = Ed25519KeyPair::generate().map_err(|e| CoreError::SelfTestFailed {
component: "Ed25519 Keypair".to_string(),
status: format!("keygen failed: {e}"),
})?;
let signature = keypair.sign(TEST_MESSAGE).map_err(|e| CoreError::SelfTestFailed {
component: "Ed25519 Sign/Verify".to_string(),
status: format!("Ed25519 sign failed at startup: {e}"),
})?;
let public_key_bytes = keypair.public_key_bytes();
Ed25519Signature::verify(&public_key_bytes, TEST_MESSAGE, &signature).map_err(|e| {
CoreError::SelfTestFailed {
component: "Ed25519 Sign/Verify".to_string(),
status: format!("valid signature was rejected at startup: {e}"),
}
})?;
let mut tampered = TEST_MESSAGE.to_vec();
if let Some(b) = tampered.get_mut(0) {
*b ^= 0xFF;
}
if Ed25519Signature::verify(&public_key_bytes, &tampered, &signature).is_ok() {
return Err(CoreError::SelfTestFailed {
component: "Ed25519 Sign/Verify".to_string(),
status: "tampered message was incorrectly accepted at startup".to_string(),
});
}
SELF_TESTS_PASSED.store(true, Ordering::SeqCst);
Ok(())
}
#[cfg(test)]
#[expect(
clippy::panic,
clippy::unwrap_used,
clippy::expect_used,
clippy::indexing_slicing,
clippy::redundant_clone,
clippy::useless_vec,
clippy::clone_on_copy,
unused_qualifications,
reason = "test/bench scaffolding: lints suppressed for this module"
)]
mod tests;
#[cfg(test)]
pub(crate) mod test_helpers;