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 = "rocca-s")]
81mod rocca_s;
82#[cfg(feature = "romulus-m")]
83mod romulus_m;
84#[cfg(feature = "romulus-n")]
85mod romulus_n;
86#[cfg(feature = "saturnin")]
87mod saturnin;
88#[cfg(feature = "shake256")]
89mod shake256;
90#[cfg(feature = "tweak-aead")]
91mod tweak_aead;
92
93#[cfg(feature = "duplex-sponge-aead")]
95pub use duplex_aead::DuplexSpongeAead;
96#[cfg(feature = "rocca-s")]
97pub use rocca_s::RoccaSAead;
98#[cfg(feature = "romulus-m")]
99pub use romulus_m::RomulusMAead;
100#[cfg(feature = "romulus-n")]
101pub use romulus_n::RomulusNAead;
102#[cfg(feature = "saturnin")]
103pub use saturnin::SaturninAead;
104#[cfg(feature = "shake256")]
105pub use shake256::Shake256Aead;
106#[cfg(feature = "tweak-aead")]
107pub use tweak_aead::TweakAead;
108
109#[cfg(feature = "std")]
116static REGISTRY: once_cell::sync::Lazy<AeadRegistry> = once_cell::sync::Lazy::new(|| {
117 let registry = AeadRegistry::new();
118
119 #[cfg(feature = "saturnin")]
121 let _ = registry.register_algorithm(Algorithm::Saturnin, || {
122 Ok(Box::new(SaturninAead::new()) as Box<dyn AeadWithMetadata>)
123 });
124
125 #[cfg(feature = "shake256")]
126 let _ = registry.register_algorithm(Algorithm::Shake256Aead, || {
127 Ok(Box::new(Shake256Aead::new()) as Box<dyn AeadWithMetadata>)
128 });
129
130 #[cfg(feature = "duplex-sponge-aead")]
131 let _ = registry.register_algorithm(Algorithm::DuplexSpongeAead, || {
132 Ok(Box::new(DuplexSpongeAead::new()) as Box<dyn AeadWithMetadata>)
133 });
134
135 #[cfg(feature = "tweak-aead")]
136 let _ = registry.register_algorithm(Algorithm::TweakAead, || {
137 Ok(Box::new(TweakAead::new()) as Box<dyn AeadWithMetadata>)
138 });
139
140 #[cfg(feature = "romulus-n")]
141 let _ = registry.register_algorithm(Algorithm::RomulusN, || {
142 Ok(Box::new(RomulusNAead::new()) as Box<dyn AeadWithMetadata>)
143 });
144
145 #[cfg(feature = "romulus-m")]
146 let _ = registry.register_algorithm(Algorithm::RomulusM, || {
147 Ok(Box::new(RomulusMAead::new()) as Box<dyn AeadWithMetadata>)
148 });
149
150 #[cfg(feature = "rocca-s")]
151 let _ = registry.register_algorithm(Algorithm::RoccaS, || {
152 Ok(Box::new(RoccaSAead::new()) as Box<dyn AeadWithMetadata>)
153 });
154
155 registry
156});
157
158#[cfg(not(feature = "std"))]
163static REGISTRY: once_cell::sync::Lazy<AeadRegistry> = once_cell::sync::Lazy::new(|| {
164 let registry = AeadRegistry::new();
165
166 #[cfg(feature = "saturnin")]
168 let _ = registry.register_algorithm(Algorithm::Saturnin, || {
169 Ok(Box::new(SaturninAead::new()) as Box<dyn AeadWithMetadata>)
170 });
171
172 #[cfg(feature = "shake256")]
173 let _ = registry.register_algorithm(Algorithm::Shake256Aead, || {
174 Ok(Box::new(Shake256Aead::new()) as Box<dyn AeadWithMetadata>)
175 });
176
177 #[cfg(feature = "duplex-sponge-aead")]
178 let _ = registry.register_algorithm(Algorithm::DuplexSpongeAead, || {
179 Ok(Box::new(DuplexSpongeAead::new()) as Box<dyn AeadWithMetadata>)
180 });
181
182 #[cfg(feature = "tweak-aead")]
183 let _ = registry.register_algorithm(Algorithm::TweakAead, || {
184 Ok(Box::new(TweakAead::new()) as Box<dyn AeadWithMetadata>)
185 });
186
187 #[cfg(feature = "romulus-n")]
188 let _ = registry.register_algorithm(Algorithm::RomulusN, || {
189 Ok(Box::new(RomulusNAead::new()) as Box<dyn AeadWithMetadata>)
190 });
191
192 #[cfg(feature = "romulus-m")]
193 let _ = registry.register_algorithm(Algorithm::RomulusM, || {
194 Ok(Box::new(RomulusMAead::new()) as Box<dyn AeadWithMetadata>)
195 });
196
197 #[cfg(feature = "rocca-s")]
198 let _ = registry.register_algorithm(Algorithm::RoccaS, || {
199 Ok(Box::new(RoccaSAead::new()) as Box<dyn AeadWithMetadata>)
200 });
201
202 registry
203});
204
205pub fn registry() -> &'static AeadRegistry {
207 ®ISTRY
208}
209
210pub fn available_algorithms() -> Vec<Algorithm> {
212 registry().available_algorithms()
213}
214
215pub fn create_aead(algorithm: Algorithm) -> Result<Box<dyn AeadWithMetadata>> {
217 if algorithm.category() != AlgorithmCategory::Aead {
219 return Err(lib_q_core::Error::InvalidAlgorithm {
220 algorithm: "Algorithm is not an AEAD algorithm",
221 });
222 }
223
224 registry().create_aead(algorithm)
225}
226
227pub fn is_algorithm_available(algorithm: Algorithm) -> bool {
229 algorithm.category() == AlgorithmCategory::Aead && registry().is_available(algorithm)
230}
231
232pub fn get_algorithm_metadata(algorithm: Algorithm) -> Option<&'static AeadMetadata> {
234 if algorithm.category() != AlgorithmCategory::Aead {
235 return None;
236 }
237 registry().get_metadata(algorithm)
238}
239
240#[cfg(feature = "std")]
242pub fn register_algorithm<F>(_algorithm: Algorithm, _constructor: F) -> Result<()>
243where
244 F: Fn() -> Result<Box<dyn AeadWithMetadata>> + Send + Sync + 'static,
245{
246 Err(lib_q_core::Error::NotImplemented {
249 feature: "Dynamic algorithm registration requires mutable registry".to_string(),
250 })
251}
252
253#[cfg(not(feature = "std"))]
255pub fn register_algorithm<F>(algorithm: Algorithm, constructor: F) -> Result<()>
256where
257 F: Fn() -> Result<Box<dyn AeadWithMetadata>> + Send + Sync + 'static,
258{
259 if algorithm.category() != AlgorithmCategory::Aead {
260 return Err(lib_q_core::Error::InvalidAlgorithm {
261 algorithm: "Algorithm is not an AEAD algorithm",
262 });
263 }
264
265 registry().register_algorithm(algorithm, constructor)
270}
271
272#[cfg(feature = "std")]
274pub fn register_plugin(_plugin: Box<dyn AeadPlugin>) -> Result<()> {
275 Err(lib_q_core::Error::NotImplemented {
278 feature: "Dynamic plugin registration requires mutable registry".to_string(),
279 })
280}
281
282#[cfg(not(feature = "std"))]
284pub fn register_plugin(plugin: Box<dyn AeadPlugin>) -> Result<()> {
285 registry().register_plugin(plugin)
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292
293 #[test]
294 fn test_available_algorithms() {
295 let algorithms = available_algorithms();
296 assert!(!algorithms.is_empty());
297
298 for algorithm in algorithms {
300 assert_eq!(algorithm.category(), AlgorithmCategory::Aead);
301 }
302 }
303
304 #[test]
305 fn test_create_aead() {
306 let algorithms = available_algorithms();
307
308 for algorithm in algorithms {
309 let aead = create_aead(algorithm);
310 assert!(aead.is_ok(), "Failed to create AEAD for {:?}", algorithm);
311 }
312 }
313
314 #[test]
315 fn test_invalid_algorithm() {
316 let result = create_aead(Algorithm::MlKem512);
318 assert!(result.is_err());
319
320 if let Err(lib_q_core::Error::InvalidAlgorithm { algorithm }) = result {
321 assert!(algorithm.contains("not an AEAD algorithm"));
322 } else {
323 panic!("Expected InvalidAlgorithm error");
324 }
325 }
326
327 #[test]
328 fn test_algorithm_availability() {
329 let algorithms = available_algorithms();
330
331 for algorithm in algorithms {
332 assert!(is_algorithm_available(algorithm));
333 }
334
335 assert!(!is_algorithm_available(Algorithm::MlKem512));
337 }
338
339 #[test]
340 fn test_algorithm_metadata() {
341 let algorithms = available_algorithms();
342
343 for algorithm in algorithms {
344 let metadata = get_algorithm_metadata(algorithm);
345 assert!(metadata.is_some(), "No metadata for {:?}", algorithm);
346
347 if let Some(meta) = metadata {
348 assert_eq!(meta.algorithm, algorithm);
349 assert!(meta.key_size > 0);
350 assert!(meta.nonce_size > 0);
351 assert!(meta.tag_size > 0);
352 }
353 }
354 }
355
356 #[test]
357 fn test_security_config_roundtrip() {
358 let orig = get_security_config();
359 set_security_config(orig);
360 assert_eq!(get_security_config(), orig);
361 }
362
363 #[test]
364 fn test_security_context_new() {
365 let _ctx = SecurityContext::new();
366 }
367}