1#![cfg_attr(not(feature = "std"), no_std)]
8#![deny(unused_qualifications)]
10
11#[cfg(feature = "alloc")]
12extern crate alloc;
13
14#[cfg(feature = "alloc")]
15use alloc::{
16 boxed::Box,
17 vec::Vec,
18};
19
20pub use lib_q_core::{
22 Aead,
23 AeadKey,
24 Nonce,
25 Result,
26};
27pub use lib_q_types::{
28 Algorithm,
29 AlgorithmCategory,
30};
31
32mod metadata;
34mod plugin;
35mod registry;
36pub mod security;
37
38pub use metadata::{
40 AeadMetadata,
41 AeadWithMetadata,
42 PerformanceTier,
43};
44pub use plugin::{
45 AeadPlugin,
46 PluginRegistry,
47};
48pub use registry::AeadRegistry;
49pub use security::constant_time;
51pub use security::{
53 SecurityConfig,
54 SecurityContext,
55 get_security_config,
56 set_security_config,
57};
58pub use security::{
59 memory,
60 nonce,
61 side_channel,
62 stack_buffer,
63 timing,
64 validation,
65};
66
67#[cfg(feature = "alloc")]
68mod provider;
69#[cfg(feature = "alloc")]
70pub use provider::LibQAeadProvider;
71
72#[cfg(feature = "wasm")]
73mod wasm;
74
75#[cfg(feature = "duplex-sponge-aead")]
79mod duplex_aead;
80#[cfg(feature = "romulus-m")]
81mod romulus_m;
82#[cfg(feature = "romulus-n")]
83mod romulus_n;
84#[cfg(feature = "saturnin")]
85mod saturnin;
86#[cfg(feature = "shake256")]
87mod shake256;
88#[cfg(feature = "tweak-aead")]
89mod tweak_aead;
90
91#[cfg(feature = "duplex-sponge-aead")]
93pub use duplex_aead::DuplexSpongeAead;
94#[cfg(feature = "romulus-m")]
95pub use romulus_m::RomulusMAead;
96#[cfg(feature = "romulus-n")]
97pub use romulus_n::RomulusNAead;
98#[cfg(feature = "saturnin")]
99pub use saturnin::SaturninAead;
100#[cfg(feature = "shake256")]
101pub use shake256::Shake256Aead;
102#[cfg(feature = "tweak-aead")]
103pub use tweak_aead::TweakAead;
104
105#[cfg(feature = "std")]
112static REGISTRY: once_cell::sync::Lazy<AeadRegistry> = once_cell::sync::Lazy::new(|| {
113 let registry = AeadRegistry::new();
114
115 #[cfg(feature = "saturnin")]
117 let _ = registry.register_algorithm(Algorithm::Saturnin, || {
118 Ok(Box::new(SaturninAead::new()) as Box<dyn AeadWithMetadata>)
119 });
120
121 #[cfg(feature = "shake256")]
122 let _ = registry.register_algorithm(Algorithm::Shake256Aead, || {
123 Ok(Box::new(Shake256Aead::new()) as Box<dyn AeadWithMetadata>)
124 });
125
126 #[cfg(feature = "duplex-sponge-aead")]
127 let _ = registry.register_algorithm(Algorithm::DuplexSpongeAead, || {
128 Ok(Box::new(DuplexSpongeAead::new()) as Box<dyn AeadWithMetadata>)
129 });
130
131 #[cfg(feature = "tweak-aead")]
132 let _ = registry.register_algorithm(Algorithm::TweakAead, || {
133 Ok(Box::new(TweakAead::new()) as Box<dyn AeadWithMetadata>)
134 });
135
136 #[cfg(feature = "romulus-n")]
137 let _ = registry.register_algorithm(Algorithm::RomulusN, || {
138 Ok(Box::new(RomulusNAead::new()) as Box<dyn AeadWithMetadata>)
139 });
140
141 #[cfg(feature = "romulus-m")]
142 let _ = registry.register_algorithm(Algorithm::RomulusM, || {
143 Ok(Box::new(RomulusMAead::new()) as Box<dyn AeadWithMetadata>)
144 });
145
146 registry
147});
148
149#[cfg(not(feature = "std"))]
154static REGISTRY: once_cell::sync::Lazy<AeadRegistry> = once_cell::sync::Lazy::new(|| {
155 let registry = AeadRegistry::new();
156
157 #[cfg(feature = "saturnin")]
159 let _ = registry.register_algorithm(Algorithm::Saturnin, || {
160 Ok(Box::new(SaturninAead::new()) as Box<dyn AeadWithMetadata>)
161 });
162
163 #[cfg(feature = "shake256")]
164 let _ = registry.register_algorithm(Algorithm::Shake256Aead, || {
165 Ok(Box::new(Shake256Aead::new()) as Box<dyn AeadWithMetadata>)
166 });
167
168 #[cfg(feature = "duplex-sponge-aead")]
169 let _ = registry.register_algorithm(Algorithm::DuplexSpongeAead, || {
170 Ok(Box::new(DuplexSpongeAead::new()) as Box<dyn AeadWithMetadata>)
171 });
172
173 #[cfg(feature = "tweak-aead")]
174 let _ = registry.register_algorithm(Algorithm::TweakAead, || {
175 Ok(Box::new(TweakAead::new()) as Box<dyn AeadWithMetadata>)
176 });
177
178 #[cfg(feature = "romulus-n")]
179 let _ = registry.register_algorithm(Algorithm::RomulusN, || {
180 Ok(Box::new(RomulusNAead::new()) as Box<dyn AeadWithMetadata>)
181 });
182
183 #[cfg(feature = "romulus-m")]
184 let _ = registry.register_algorithm(Algorithm::RomulusM, || {
185 Ok(Box::new(RomulusMAead::new()) as Box<dyn AeadWithMetadata>)
186 });
187
188 registry
189});
190
191pub fn registry() -> &'static AeadRegistry {
193 ®ISTRY
194}
195
196pub fn available_algorithms() -> Vec<Algorithm> {
198 registry().available_algorithms()
199}
200
201pub fn create_aead(algorithm: Algorithm) -> Result<Box<dyn AeadWithMetadata>> {
203 if algorithm.category() != AlgorithmCategory::Aead {
205 return Err(lib_q_core::Error::InvalidAlgorithm {
206 algorithm: "Algorithm is not an AEAD algorithm",
207 });
208 }
209
210 registry().create_aead(algorithm)
211}
212
213pub fn is_algorithm_available(algorithm: Algorithm) -> bool {
215 algorithm.category() == AlgorithmCategory::Aead && registry().is_available(algorithm)
216}
217
218pub fn get_algorithm_metadata(algorithm: Algorithm) -> Option<&'static AeadMetadata> {
220 if algorithm.category() != AlgorithmCategory::Aead {
221 return None;
222 }
223 registry().get_metadata(algorithm)
224}
225
226#[cfg(feature = "std")]
228pub fn register_algorithm<F>(_algorithm: Algorithm, _constructor: F) -> Result<()>
229where
230 F: Fn() -> Result<Box<dyn AeadWithMetadata>> + Send + Sync + 'static,
231{
232 Err(lib_q_core::Error::NotImplemented {
235 feature: "Dynamic algorithm registration requires mutable registry".to_string(),
236 })
237}
238
239#[cfg(not(feature = "std"))]
241pub fn register_algorithm<F>(algorithm: Algorithm, constructor: F) -> Result<()>
242where
243 F: Fn() -> Result<Box<dyn AeadWithMetadata>> + Send + Sync + 'static,
244{
245 if algorithm.category() != AlgorithmCategory::Aead {
246 return Err(lib_q_core::Error::InvalidAlgorithm {
247 algorithm: "Algorithm is not an AEAD algorithm",
248 });
249 }
250
251 registry().register_algorithm(algorithm, constructor)
256}
257
258#[cfg(feature = "std")]
260pub fn register_plugin(_plugin: Box<dyn AeadPlugin>) -> Result<()> {
261 Err(lib_q_core::Error::NotImplemented {
264 feature: "Dynamic plugin registration requires mutable registry".to_string(),
265 })
266}
267
268#[cfg(not(feature = "std"))]
270pub fn register_plugin(plugin: Box<dyn AeadPlugin>) -> Result<()> {
271 registry().register_plugin(plugin)
273}
274
275#[cfg(test)]
276mod tests {
277 use super::*;
278
279 #[test]
280 fn test_available_algorithms() {
281 let algorithms = available_algorithms();
282 assert!(!algorithms.is_empty());
283
284 for algorithm in algorithms {
286 assert_eq!(algorithm.category(), AlgorithmCategory::Aead);
287 }
288 }
289
290 #[test]
291 fn test_create_aead() {
292 let algorithms = available_algorithms();
293
294 for algorithm in algorithms {
295 let aead = create_aead(algorithm);
296 assert!(aead.is_ok(), "Failed to create AEAD for {:?}", algorithm);
297 }
298 }
299
300 #[test]
301 fn test_invalid_algorithm() {
302 let result = create_aead(Algorithm::MlKem512);
304 assert!(result.is_err());
305
306 if let Err(lib_q_core::Error::InvalidAlgorithm { algorithm }) = result {
307 assert!(algorithm.contains("not an AEAD algorithm"));
308 } else {
309 panic!("Expected InvalidAlgorithm error");
310 }
311 }
312
313 #[test]
314 fn test_algorithm_availability() {
315 let algorithms = available_algorithms();
316
317 for algorithm in algorithms {
318 assert!(is_algorithm_available(algorithm));
319 }
320
321 assert!(!is_algorithm_available(Algorithm::MlKem512));
323 }
324
325 #[test]
326 fn test_algorithm_metadata() {
327 let algorithms = available_algorithms();
328
329 for algorithm in algorithms {
330 let metadata = get_algorithm_metadata(algorithm);
331 assert!(metadata.is_some(), "No metadata for {:?}", algorithm);
332
333 if let Some(meta) = metadata {
334 assert_eq!(meta.algorithm, algorithm);
335 assert!(meta.key_size > 0);
336 assert!(meta.nonce_size > 0);
337 assert!(meta.tag_size > 0);
338 }
339 }
340 }
341
342 #[test]
343 fn test_security_config_roundtrip() {
344 let orig = get_security_config();
345 set_security_config(orig);
346 assert_eq!(get_security_config(), orig);
347 }
348
349 #[test]
350 fn test_security_context_new() {
351 let _ctx = SecurityContext::new();
352 }
353}