ant_quic/crypto/pqc/
config.rs1use std::fmt;
8
9#[derive(Debug, Clone, PartialEq)]
11pub struct PqcConfig {
12 pub mode: PqcMode,
14 pub ml_kem_enabled: bool,
16 pub ml_dsa_enabled: bool,
18 pub hybrid_preference: HybridPreference,
20 pub memory_pool_size: usize,
22 pub handshake_timeout_multiplier: f32,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum PqcMode {
29 ClassicalOnly,
31 Hybrid,
33 PqcOnly,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum HybridPreference {
40 PreferClassical,
42 Balanced,
44 PreferPqc,
46}
47
48#[derive(Debug, Clone, PartialEq)]
50pub enum ConfigError {
51 NoPqcAlgorithmsEnabled,
53 InvalidMemoryPoolSize(usize),
55 InvalidTimeoutMultiplier(f32),
57 ConflictingOptions(String),
59}
60
61impl fmt::Display for ConfigError {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 match self {
64 ConfigError::NoPqcAlgorithmsEnabled => {
65 write!(
66 f,
67 "PqcOnly mode requires at least one PQC algorithm enabled"
68 )
69 }
70 ConfigError::InvalidMemoryPoolSize(size) => {
71 write!(
72 f,
73 "Invalid memory pool size {}: must be between 1 and 1000",
74 size
75 )
76 }
77 ConfigError::InvalidTimeoutMultiplier(mult) => {
78 write!(
79 f,
80 "Invalid timeout multiplier {}: must be between 1.0 and 10.0",
81 mult
82 )
83 }
84 ConfigError::ConflictingOptions(msg) => {
85 write!(f, "Conflicting configuration options: {}", msg)
86 }
87 }
88 }
89}
90
91impl std::error::Error for ConfigError {}
92
93impl Default for PqcConfig {
94 fn default() -> Self {
95 Self {
96 mode: PqcMode::Hybrid,
97 ml_kem_enabled: true,
98 ml_dsa_enabled: true,
99 hybrid_preference: HybridPreference::PreferPqc, memory_pool_size: 10,
101 handshake_timeout_multiplier: 2.0,
102 }
103 }
104}
105
106impl PqcConfig {
107 pub fn new() -> Self {
109 Self::default()
110 }
111
112 pub fn builder() -> PqcConfigBuilder {
114 PqcConfigBuilder::new()
115 }
116
117 pub fn validate(&self) -> Result<(), ConfigError> {
119 if self.mode == PqcMode::PqcOnly && !self.ml_kem_enabled && !self.ml_dsa_enabled {
121 return Err(ConfigError::NoPqcAlgorithmsEnabled);
122 }
123
124 if self.memory_pool_size == 0 || self.memory_pool_size > 1000 {
126 return Err(ConfigError::InvalidMemoryPoolSize(self.memory_pool_size));
127 }
128
129 if self.handshake_timeout_multiplier < 1.0 || self.handshake_timeout_multiplier > 10.0 {
131 return Err(ConfigError::InvalidTimeoutMultiplier(
132 self.handshake_timeout_multiplier,
133 ));
134 }
135
136 Ok(())
137 }
138}
139
140#[derive(Debug, Clone)]
142pub struct PqcConfigBuilder {
143 mode: PqcMode,
144 ml_kem_enabled: bool,
145 ml_dsa_enabled: bool,
146 hybrid_preference: HybridPreference,
147 memory_pool_size: usize,
148 handshake_timeout_multiplier: f32,
149}
150
151impl Default for PqcConfigBuilder {
152 fn default() -> Self {
153 Self::new()
154 }
155}
156
157impl PqcConfigBuilder {
158 pub fn new() -> Self {
160 let default = PqcConfig::default();
161 Self {
162 mode: default.mode,
163 ml_kem_enabled: default.ml_kem_enabled,
164 ml_dsa_enabled: default.ml_dsa_enabled,
165 hybrid_preference: default.hybrid_preference,
166 memory_pool_size: default.memory_pool_size,
167 handshake_timeout_multiplier: default.handshake_timeout_multiplier,
168 }
169 }
170
171 pub fn mode(mut self, mode: PqcMode) -> Self {
173 self.mode = mode;
174 self
175 }
176
177 pub fn ml_kem(mut self, enabled: bool) -> Self {
179 self.ml_kem_enabled = enabled;
180 self
181 }
182
183 pub fn ml_dsa(mut self, enabled: bool) -> Self {
185 self.ml_dsa_enabled = enabled;
186 self
187 }
188
189 pub fn hybrid_preference(mut self, preference: HybridPreference) -> Self {
191 self.hybrid_preference = preference;
192 self
193 }
194
195 pub fn memory_pool_size(mut self, size: usize) -> Self {
197 self.memory_pool_size = size;
198 self
199 }
200
201 pub fn handshake_timeout_multiplier(mut self, multiplier: f32) -> Self {
203 self.handshake_timeout_multiplier = multiplier;
204 self
205 }
206
207 pub fn build(self) -> Result<PqcConfig, ConfigError> {
209 let config = PqcConfig {
210 mode: self.mode,
211 ml_kem_enabled: self.ml_kem_enabled,
212 ml_dsa_enabled: self.ml_dsa_enabled,
213 hybrid_preference: self.hybrid_preference,
214 memory_pool_size: self.memory_pool_size,
215 handshake_timeout_multiplier: self.handshake_timeout_multiplier,
216 };
217
218 config.validate()?;
219 Ok(config)
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 #[test]
228 fn test_default_config() {
229 let config = PqcConfig::default();
230 assert_eq!(config.mode, PqcMode::Hybrid);
231 assert!(config.ml_kem_enabled);
232 assert!(config.ml_dsa_enabled);
233 assert_eq!(config.hybrid_preference, HybridPreference::PreferPqc);
234 assert_eq!(config.memory_pool_size, 10);
235 assert_eq!(config.handshake_timeout_multiplier, 2.0);
236 assert!(config.validate().is_ok());
237 }
238
239 #[test]
240 fn test_builder_basic() {
241 let config = PqcConfig::builder()
242 .mode(PqcMode::PqcOnly)
243 .ml_kem(true)
244 .ml_dsa(true)
245 .build()
246 .unwrap();
247
248 assert_eq!(config.mode, PqcMode::PqcOnly);
249 assert!(config.ml_kem_enabled);
250 assert!(config.ml_dsa_enabled);
251 }
252
253 #[test]
254 fn test_pqc_only_requires_algorithms() {
255 let result = PqcConfig::builder()
257 .mode(PqcMode::PqcOnly)
258 .ml_kem(false)
259 .ml_dsa(false)
260 .build();
261
262 assert!(matches!(result, Err(ConfigError::NoPqcAlgorithmsEnabled)));
263
264 let config = PqcConfig::builder()
266 .mode(PqcMode::PqcOnly)
267 .ml_kem(true)
268 .ml_dsa(false)
269 .build()
270 .unwrap();
271
272 assert!(config.ml_kem_enabled);
273 assert!(!config.ml_dsa_enabled);
274 }
275
276 #[test]
277 fn test_memory_pool_validation() {
278 let result = PqcConfig::builder().memory_pool_size(0).build();
280
281 assert!(matches!(result, Err(ConfigError::InvalidMemoryPoolSize(0))));
282
283 let result = PqcConfig::builder().memory_pool_size(1001).build();
285
286 assert!(matches!(
287 result,
288 Err(ConfigError::InvalidMemoryPoolSize(1001))
289 ));
290
291 let config = PqcConfig::builder().memory_pool_size(100).build().unwrap();
293
294 assert_eq!(config.memory_pool_size, 100);
295 }
296
297 #[test]
298 fn test_timeout_multiplier_validation() {
299 let result = PqcConfig::builder()
301 .handshake_timeout_multiplier(0.5)
302 .build();
303
304 assert!(matches!(
305 result,
306 Err(ConfigError::InvalidTimeoutMultiplier(_))
307 ));
308
309 let result = PqcConfig::builder()
311 .handshake_timeout_multiplier(11.0)
312 .build();
313
314 assert!(matches!(
315 result,
316 Err(ConfigError::InvalidTimeoutMultiplier(_))
317 ));
318
319 let config = PqcConfig::builder()
321 .handshake_timeout_multiplier(3.0)
322 .build()
323 .unwrap();
324
325 assert_eq!(config.handshake_timeout_multiplier, 3.0);
326 }
327
328 #[test]
329 fn test_classical_only_mode() {
330 let config = PqcConfig::builder()
331 .mode(PqcMode::ClassicalOnly)
332 .ml_kem(false)
333 .ml_dsa(false)
334 .build()
335 .unwrap();
336
337 assert_eq!(config.mode, PqcMode::ClassicalOnly);
338 assert!(!config.ml_kem_enabled);
339 assert!(!config.ml_dsa_enabled);
340 }
341
342 #[test]
343 fn test_hybrid_preferences() {
344 let config = PqcConfig::builder()
345 .mode(PqcMode::Hybrid)
346 .hybrid_preference(HybridPreference::PreferPqc)
347 .build()
348 .unwrap();
349
350 assert_eq!(config.hybrid_preference, HybridPreference::PreferPqc);
351 }
352}