#![cfg_attr(not(feature = "std"), no_std)]
#![deny(unused_qualifications)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::{
boxed::Box,
vec::Vec,
};
pub use lib_q_core::{
Aead,
AeadKey,
Nonce,
Result,
};
pub use lib_q_types::{
Algorithm,
AlgorithmCategory,
};
mod metadata;
mod plugin;
mod registry;
pub mod security;
pub use metadata::{
AeadMetadata,
AeadWithMetadata,
PerformanceTier,
};
pub use plugin::{
AeadPlugin,
PluginRegistry,
};
pub use registry::AeadRegistry;
pub use security::constant_time;
pub use security::{
SecurityConfig,
SecurityContext,
get_security_config,
set_security_config,
};
pub use security::{
memory,
nonce,
side_channel,
stack_buffer,
timing,
validation,
};
#[cfg(feature = "alloc")]
mod provider;
#[cfg(feature = "alloc")]
pub use provider::LibQAeadProvider;
#[cfg(feature = "wasm")]
mod wasm;
#[cfg(feature = "duplex-sponge-aead")]
mod duplex_aead;
#[cfg(feature = "romulus-m")]
mod romulus_m;
#[cfg(feature = "romulus-n")]
mod romulus_n;
#[cfg(feature = "saturnin")]
mod saturnin;
#[cfg(feature = "shake256")]
mod shake256;
#[cfg(feature = "tweak-aead")]
mod tweak_aead;
#[cfg(feature = "duplex-sponge-aead")]
pub use duplex_aead::DuplexSpongeAead;
#[cfg(feature = "romulus-m")]
pub use romulus_m::RomulusMAead;
#[cfg(feature = "romulus-n")]
pub use romulus_n::RomulusNAead;
#[cfg(feature = "saturnin")]
pub use saturnin::SaturninAead;
#[cfg(feature = "shake256")]
pub use shake256::Shake256Aead;
#[cfg(feature = "tweak-aead")]
pub use tweak_aead::TweakAead;
#[cfg(feature = "std")]
static REGISTRY: once_cell::sync::Lazy<AeadRegistry> = once_cell::sync::Lazy::new(|| {
let registry = AeadRegistry::new();
#[cfg(feature = "saturnin")]
let _ = registry.register_algorithm(Algorithm::Saturnin, || {
Ok(Box::new(SaturninAead::new()) as Box<dyn AeadWithMetadata>)
});
#[cfg(feature = "shake256")]
let _ = registry.register_algorithm(Algorithm::Shake256Aead, || {
Ok(Box::new(Shake256Aead::new()) as Box<dyn AeadWithMetadata>)
});
#[cfg(feature = "duplex-sponge-aead")]
let _ = registry.register_algorithm(Algorithm::DuplexSpongeAead, || {
Ok(Box::new(DuplexSpongeAead::new()) as Box<dyn AeadWithMetadata>)
});
#[cfg(feature = "tweak-aead")]
let _ = registry.register_algorithm(Algorithm::TweakAead, || {
Ok(Box::new(TweakAead::new()) as Box<dyn AeadWithMetadata>)
});
#[cfg(feature = "romulus-n")]
let _ = registry.register_algorithm(Algorithm::RomulusN, || {
Ok(Box::new(RomulusNAead::new()) as Box<dyn AeadWithMetadata>)
});
#[cfg(feature = "romulus-m")]
let _ = registry.register_algorithm(Algorithm::RomulusM, || {
Ok(Box::new(RomulusMAead::new()) as Box<dyn AeadWithMetadata>)
});
registry
});
#[cfg(not(feature = "std"))]
static REGISTRY: once_cell::sync::Lazy<AeadRegistry> = once_cell::sync::Lazy::new(|| {
let registry = AeadRegistry::new();
#[cfg(feature = "saturnin")]
let _ = registry.register_algorithm(Algorithm::Saturnin, || {
Ok(Box::new(SaturninAead::new()) as Box<dyn AeadWithMetadata>)
});
#[cfg(feature = "shake256")]
let _ = registry.register_algorithm(Algorithm::Shake256Aead, || {
Ok(Box::new(Shake256Aead::new()) as Box<dyn AeadWithMetadata>)
});
#[cfg(feature = "duplex-sponge-aead")]
let _ = registry.register_algorithm(Algorithm::DuplexSpongeAead, || {
Ok(Box::new(DuplexSpongeAead::new()) as Box<dyn AeadWithMetadata>)
});
#[cfg(feature = "tweak-aead")]
let _ = registry.register_algorithm(Algorithm::TweakAead, || {
Ok(Box::new(TweakAead::new()) as Box<dyn AeadWithMetadata>)
});
#[cfg(feature = "romulus-n")]
let _ = registry.register_algorithm(Algorithm::RomulusN, || {
Ok(Box::new(RomulusNAead::new()) as Box<dyn AeadWithMetadata>)
});
#[cfg(feature = "romulus-m")]
let _ = registry.register_algorithm(Algorithm::RomulusM, || {
Ok(Box::new(RomulusMAead::new()) as Box<dyn AeadWithMetadata>)
});
registry
});
pub fn registry() -> &'static AeadRegistry {
®ISTRY
}
pub fn available_algorithms() -> Vec<Algorithm> {
registry().available_algorithms()
}
pub fn create_aead(algorithm: Algorithm) -> Result<Box<dyn AeadWithMetadata>> {
if algorithm.category() != AlgorithmCategory::Aead {
return Err(lib_q_core::Error::InvalidAlgorithm {
algorithm: "Algorithm is not an AEAD algorithm",
});
}
registry().create_aead(algorithm)
}
pub fn is_algorithm_available(algorithm: Algorithm) -> bool {
algorithm.category() == AlgorithmCategory::Aead && registry().is_available(algorithm)
}
pub fn get_algorithm_metadata(algorithm: Algorithm) -> Option<&'static AeadMetadata> {
if algorithm.category() != AlgorithmCategory::Aead {
return None;
}
registry().get_metadata(algorithm)
}
#[cfg(feature = "std")]
pub fn register_algorithm<F>(_algorithm: Algorithm, _constructor: F) -> Result<()>
where
F: Fn() -> Result<Box<dyn AeadWithMetadata>> + Send + Sync + 'static,
{
Err(lib_q_core::Error::NotImplemented {
feature: "Dynamic algorithm registration requires mutable registry".to_string(),
})
}
#[cfg(not(feature = "std"))]
pub fn register_algorithm<F>(algorithm: Algorithm, constructor: F) -> Result<()>
where
F: Fn() -> Result<Box<dyn AeadWithMetadata>> + Send + Sync + 'static,
{
if algorithm.category() != AlgorithmCategory::Aead {
return Err(lib_q_core::Error::InvalidAlgorithm {
algorithm: "Algorithm is not an AEAD algorithm",
});
}
registry().register_algorithm(algorithm, constructor)
}
#[cfg(feature = "std")]
pub fn register_plugin(_plugin: Box<dyn AeadPlugin>) -> Result<()> {
Err(lib_q_core::Error::NotImplemented {
feature: "Dynamic plugin registration requires mutable registry".to_string(),
})
}
#[cfg(not(feature = "std"))]
pub fn register_plugin(plugin: Box<dyn AeadPlugin>) -> Result<()> {
registry().register_plugin(plugin)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_available_algorithms() {
let algorithms = available_algorithms();
assert!(!algorithms.is_empty());
for algorithm in algorithms {
assert_eq!(algorithm.category(), AlgorithmCategory::Aead);
}
}
#[test]
fn test_create_aead() {
let algorithms = available_algorithms();
for algorithm in algorithms {
let aead = create_aead(algorithm);
assert!(aead.is_ok(), "Failed to create AEAD for {:?}", algorithm);
}
}
#[test]
fn test_invalid_algorithm() {
let result = create_aead(Algorithm::MlKem512);
assert!(result.is_err());
if let Err(lib_q_core::Error::InvalidAlgorithm { algorithm }) = result {
assert!(algorithm.contains("not an AEAD algorithm"));
} else {
panic!("Expected InvalidAlgorithm error");
}
}
#[test]
fn test_algorithm_availability() {
let algorithms = available_algorithms();
for algorithm in algorithms {
assert!(is_algorithm_available(algorithm));
}
assert!(!is_algorithm_available(Algorithm::MlKem512));
}
#[test]
fn test_algorithm_metadata() {
let algorithms = available_algorithms();
for algorithm in algorithms {
let metadata = get_algorithm_metadata(algorithm);
assert!(metadata.is_some(), "No metadata for {:?}", algorithm);
if let Some(meta) = metadata {
assert_eq!(meta.algorithm, algorithm);
assert!(meta.key_size > 0);
assert!(meta.nonce_size > 0);
assert!(meta.tag_size > 0);
}
}
}
#[test]
fn test_security_config_roundtrip() {
let orig = get_security_config();
set_security_config(orig);
assert_eq!(get_security_config(), orig);
}
#[test]
fn test_security_context_new() {
let _ctx = SecurityContext::new();
}
}