lib_q_core/security/
constants.rs1use lib_q_types::{
7 cbkem,
8 fndsa,
9 hqc,
10 mldsa,
11 mlkem,
12 slhdsa,
13};
14
15use crate::api::Algorithm;
16use crate::error::Result;
17
18#[cfg(feature = "alloc")]
23#[derive(Clone)]
24pub struct SecurityConstants {
25 max_aead_message_size: usize,
31 max_hash_message_size: usize,
36 standard_nonce_size: usize,
38 min_randomness_size: usize,
40}
41
42#[cfg(feature = "alloc")]
43impl SecurityConstants {
44 pub fn new() -> Self {
50 Self {
51 max_aead_message_size: 1024 * 1024, max_hash_message_size: usize::MAX,
53 standard_nonce_size: 16, min_randomness_size: 32, }
56 }
57}
58
59#[cfg(feature = "alloc")]
60impl Default for SecurityConstants {
61 fn default() -> Self {
62 Self::new()
63 }
64}
65
66impl SecurityConstants {
67 pub fn max_aead_message_size(&self) -> usize {
69 self.max_aead_message_size
70 }
71
72 pub fn max_hash_message_size(&self) -> usize {
74 self.max_hash_message_size
75 }
76
77 pub fn standard_nonce_size(&self) -> usize {
83 self.standard_nonce_size
84 }
85
86 pub fn min_randomness_size(&self) -> usize {
92 self.min_randomness_size
93 }
94
95 pub fn get_expected_key_size(&self, algorithm: Algorithm, is_secret: bool) -> Result<usize> {
107 let expected_size = match algorithm {
108 Algorithm::MlKem512 => {
110 if is_secret {
111 mlkem::MLKEM512_SECRET_KEY_BYTES
112 } else {
113 mlkem::MLKEM512_PUBLIC_KEY_BYTES
114 }
115 }
116 Algorithm::MlKem768 => {
117 if is_secret {
118 mlkem::MLKEM768_SECRET_KEY_BYTES
119 } else {
120 mlkem::MLKEM768_PUBLIC_KEY_BYTES
121 }
122 }
123 Algorithm::MlKem1024 => {
124 if is_secret {
125 mlkem::MLKEM1024_SECRET_KEY_BYTES
126 } else {
127 mlkem::MLKEM1024_PUBLIC_KEY_BYTES
128 }
129 }
130 Algorithm::CbKem348864 => {
132 if is_secret {
133 cbkem::CBKEM348864_SECRET_KEY_BYTES
134 } else {
135 cbkem::CBKEM348864_PUBLIC_KEY_BYTES
136 }
137 }
138 Algorithm::CbKem460896 => {
139 if is_secret {
140 cbkem::CBKEM460896_SECRET_KEY_BYTES
141 } else {
142 cbkem::CBKEM460896_PUBLIC_KEY_BYTES
143 }
144 }
145 Algorithm::CbKem6688128 => {
146 if is_secret {
147 cbkem::CBKEM6688128_SECRET_KEY_BYTES
148 } else {
149 cbkem::CBKEM6688128_PUBLIC_KEY_BYTES
150 }
151 }
152 Algorithm::CbKem6960119 => {
153 if is_secret {
154 cbkem::CBKEM6960119_SECRET_KEY_BYTES
155 } else {
156 cbkem::CBKEM6960119_PUBLIC_KEY_BYTES
157 }
158 }
159 Algorithm::CbKem8192128 => {
160 if is_secret {
161 cbkem::CBKEM8192128_SECRET_KEY_BYTES
162 } else {
163 cbkem::CBKEM8192128_PUBLIC_KEY_BYTES
164 }
165 }
166
167 Algorithm::Hqc128 => {
169 if is_secret {
170 hqc::HQC128_SECRET_KEY_BYTES
171 } else {
172 hqc::HQC128_PUBLIC_KEY_BYTES
173 }
174 }
175 Algorithm::Hqc192 => {
176 if is_secret {
177 hqc::HQC192_SECRET_KEY_BYTES
178 } else {
179 hqc::HQC192_PUBLIC_KEY_BYTES
180 }
181 }
182 Algorithm::Hqc256 => {
183 if is_secret {
184 hqc::HQC256_SECRET_KEY_BYTES
185 } else {
186 hqc::HQC256_PUBLIC_KEY_BYTES
187 }
188 }
189
190 Algorithm::MlDsa44 => {
192 if is_secret {
193 mldsa::MLDSA44_SECRET_KEY_BYTES
194 } else {
195 mldsa::MLDSA44_PUBLIC_KEY_BYTES
196 }
197 }
198 Algorithm::MlDsa65 => {
199 if is_secret {
200 mldsa::MLDSA65_SECRET_KEY_BYTES
201 } else {
202 mldsa::MLDSA65_PUBLIC_KEY_BYTES
203 }
204 }
205 Algorithm::MlDsa87 => {
206 if is_secret {
207 mldsa::MLDSA87_SECRET_KEY_BYTES
208 } else {
209 mldsa::MLDSA87_PUBLIC_KEY_BYTES
210 }
211 }
212 Algorithm::FnDsa | Algorithm::FnDsa512 => {
218 if is_secret {
219 fndsa::FNDSA512_SECRET_KEY_BYTES
220 } else {
221 fndsa::FNDSA512_PUBLIC_KEY_BYTES
222 }
223 }
224 Algorithm::FnDsa1024 => {
225 if is_secret {
226 fndsa::FNDSA1024_SECRET_KEY_BYTES
227 } else {
228 fndsa::FNDSA1024_PUBLIC_KEY_BYTES
229 }
230 }
231
232 Algorithm::SlhDsaSha256128fRobust | Algorithm::SlhDsaShake256128fRobust => {
234 if is_secret {
235 slhdsa::SLHDSA_128F_SECRET_KEY_BYTES
236 } else {
237 slhdsa::SLHDSA_128F_PUBLIC_KEY_BYTES
238 }
239 }
240 Algorithm::SlhDsaSha256192fRobust | Algorithm::SlhDsaShake256192fRobust => {
241 if is_secret {
242 slhdsa::SLHDSA_192F_SECRET_KEY_BYTES
243 } else {
244 slhdsa::SLHDSA_192F_PUBLIC_KEY_BYTES
245 }
246 }
247 Algorithm::SlhDsaSha256256fRobust | Algorithm::SlhDsaShake256256fRobust => {
248 if is_secret {
249 slhdsa::SLHDSA_256F_SECRET_KEY_BYTES
250 } else {
251 slhdsa::SLHDSA_256F_PUBLIC_KEY_BYTES
252 }
253 }
254
255 _ => {
257 return Err(crate::error::Error::InvalidAlgorithm {
258 algorithm: "Algorithm does not use keys",
259 });
260 }
261 };
262
263 Ok(expected_size)
264 }
265
266 pub fn get_expected_ciphertext_size(&self, algorithm: Algorithm) -> Result<usize> {
277 let expected_size = match algorithm {
278 Algorithm::MlKem512 => mlkem::MLKEM512_CIPHERTEXT_BYTES,
279 Algorithm::MlKem768 => mlkem::MLKEM768_CIPHERTEXT_BYTES,
280 Algorithm::MlKem1024 => mlkem::MLKEM1024_CIPHERTEXT_BYTES,
281
282 Algorithm::CbKem348864 => cbkem::CBKEM348864_CIPHERTEXT_BYTES,
284 Algorithm::CbKem460896 => cbkem::CBKEM460896_CIPHERTEXT_BYTES,
285 Algorithm::CbKem6688128 => cbkem::CBKEM6688128_CIPHERTEXT_BYTES,
286 Algorithm::CbKem6960119 => cbkem::CBKEM6960119_CIPHERTEXT_BYTES,
287 Algorithm::CbKem8192128 => cbkem::CBKEM8192128_CIPHERTEXT_BYTES,
288
289 Algorithm::Hqc128 => hqc::HQC128_CIPHERTEXT_BYTES,
290 Algorithm::Hqc192 => hqc::HQC192_CIPHERTEXT_BYTES,
291 Algorithm::Hqc256 => hqc::HQC256_CIPHERTEXT_BYTES,
292
293 _ => {
294 return Err(crate::error::Error::InvalidAlgorithm {
295 algorithm: "Algorithm does not produce ciphertext",
296 });
297 }
298 };
299
300 Ok(expected_size)
301 }
302
303 pub fn get_expected_signature_size(&self, algorithm: Algorithm) -> Result<usize> {
314 let expected_size = match algorithm {
315 Algorithm::MlDsa44 => mldsa::MLDSA44_SIGNATURE_BYTES,
316 Algorithm::MlDsa65 => mldsa::MLDSA65_SIGNATURE_BYTES,
317 Algorithm::MlDsa87 => mldsa::MLDSA87_SIGNATURE_BYTES,
318 Algorithm::FnDsa | Algorithm::FnDsa512 => fndsa::FNDSA512_SIGNATURE_BYTES,
319 Algorithm::FnDsa1024 => fndsa::FNDSA1024_SIGNATURE_BYTES,
320
321 Algorithm::SlhDsaSha256128fRobust | Algorithm::SlhDsaShake256128fRobust => {
323 slhdsa::SLHDSA_128F_SIGNATURE_BYTES
324 }
325 Algorithm::SlhDsaSha256192fRobust | Algorithm::SlhDsaShake256192fRobust => {
326 slhdsa::SLHDSA_192F_SIGNATURE_BYTES
327 }
328 Algorithm::SlhDsaSha256256fRobust | Algorithm::SlhDsaShake256256fRobust => {
329 slhdsa::SLHDSA_256F_SIGNATURE_BYTES
330 }
331
332 _ => {
333 return Err(crate::error::Error::InvalidAlgorithm {
334 algorithm: "Algorithm does not produce signatures",
335 });
336 }
337 };
338
339 Ok(expected_size)
340 }
341
342 pub fn set_max_aead_message_size(&mut self, max_size: usize) {
344 self.max_aead_message_size = max_size;
345 }
346
347 pub fn set_max_hash_message_size(&mut self, max_size: usize) {
349 self.max_hash_message_size = max_size;
350 }
351
352 pub fn set_standard_nonce_size(&mut self, nonce_size: usize) {
358 self.standard_nonce_size = nonce_size;
359 }
360
361 pub fn set_min_randomness_size(&mut self, min_size: usize) {
367 self.min_randomness_size = min_size;
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use lib_q_types::hqc;
374
375 use super::*;
376
377 #[test]
378 fn test_security_constants_creation() {
379 let constants = SecurityConstants::new();
380 assert_eq!(constants.max_aead_message_size(), 1024 * 1024);
381 assert_eq!(constants.max_hash_message_size(), usize::MAX);
382 assert_eq!(constants.standard_nonce_size(), 16);
383 assert_eq!(constants.min_randomness_size(), 32);
384 }
385
386 #[test]
387 fn test_get_expected_key_size() {
388 let constants = SecurityConstants::new();
389
390 let public_size = constants
392 .get_expected_key_size(Algorithm::MlKem512, false)
393 .unwrap();
394 assert_eq!(public_size, 800);
395
396 let secret_size = constants
397 .get_expected_key_size(Algorithm::MlKem512, true)
398 .unwrap();
399 assert_eq!(secret_size, 1632);
400
401 let public_size = constants
403 .get_expected_key_size(Algorithm::MlDsa65, false)
404 .unwrap();
405 assert_eq!(public_size, 1952);
406
407 let secret_size = constants
408 .get_expected_key_size(Algorithm::MlDsa65, true)
409 .unwrap();
410 assert_eq!(secret_size, 4032);
411
412 assert_eq!(
413 constants
414 .get_expected_key_size(Algorithm::Hqc128, false)
415 .unwrap(),
416 hqc::HQC128_PUBLIC_KEY_BYTES
417 );
418 assert_eq!(
419 constants
420 .get_expected_key_size(Algorithm::Hqc128, true)
421 .unwrap(),
422 hqc::HQC128_SECRET_KEY_BYTES
423 );
424
425 let result = constants.get_expected_key_size(Algorithm::Sha3_256, false);
427 assert!(result.is_err(), "Hash algorithms should not have keys");
428 }
429
430 #[test]
431 fn test_get_expected_ciphertext_size() {
432 let constants = SecurityConstants::new();
433
434 assert_eq!(
436 constants
437 .get_expected_ciphertext_size(Algorithm::MlKem512)
438 .unwrap(),
439 768
440 );
441 assert_eq!(
442 constants
443 .get_expected_ciphertext_size(Algorithm::MlKem768)
444 .unwrap(),
445 1088
446 );
447 assert_eq!(
448 constants
449 .get_expected_ciphertext_size(Algorithm::MlKem1024)
450 .unwrap(),
451 1568
452 );
453
454 assert_eq!(
455 constants
456 .get_expected_ciphertext_size(Algorithm::Hqc128)
457 .unwrap(),
458 hqc::HQC128_CIPHERTEXT_BYTES
459 );
460 assert_eq!(
461 constants
462 .get_expected_ciphertext_size(Algorithm::Hqc192)
463 .unwrap(),
464 hqc::HQC192_CIPHERTEXT_BYTES
465 );
466 assert_eq!(
467 constants
468 .get_expected_ciphertext_size(Algorithm::Hqc256)
469 .unwrap(),
470 hqc::HQC256_CIPHERTEXT_BYTES
471 );
472
473 let result = constants.get_expected_ciphertext_size(Algorithm::Sha3_256);
475 assert!(
476 result.is_err(),
477 "Non-KEM algorithms should not produce ciphertext"
478 );
479 }
480
481 #[test]
482 fn test_get_expected_signature_size() {
483 let constants = SecurityConstants::new();
484
485 assert_eq!(
487 constants
488 .get_expected_signature_size(Algorithm::MlDsa44)
489 .unwrap(),
490 2420
491 );
492 assert_eq!(
493 constants
494 .get_expected_signature_size(Algorithm::MlDsa65)
495 .unwrap(),
496 3309
497 );
498 assert_eq!(
499 constants
500 .get_expected_signature_size(Algorithm::MlDsa87)
501 .unwrap(),
502 4627
503 );
504
505 assert_eq!(
507 constants
508 .get_expected_signature_size(Algorithm::FnDsa)
509 .unwrap(),
510 666
511 );
512 assert_eq!(
513 constants
514 .get_expected_signature_size(Algorithm::FnDsa512)
515 .unwrap(),
516 666
517 );
518 assert_eq!(
519 constants
520 .get_expected_signature_size(Algorithm::FnDsa1024)
521 .unwrap(),
522 1280
523 );
524
525 let result = constants.get_expected_signature_size(Algorithm::Sha3_256);
527 assert!(
528 result.is_err(),
529 "Non-signature algorithms should not produce signatures"
530 );
531 }
532
533 #[test]
534 fn test_set_constants() {
535 let mut constants = SecurityConstants::new();
536
537 constants.set_max_aead_message_size(2048 * 1024);
538 assert_eq!(constants.max_aead_message_size(), 2048 * 1024);
539
540 constants.set_max_hash_message_size(4096);
541 assert_eq!(constants.max_hash_message_size(), 4096);
542
543 constants.set_standard_nonce_size(32);
545 assert_eq!(constants.standard_nonce_size(), 32);
546
547 constants.set_min_randomness_size(64);
549 assert_eq!(constants.min_randomness_size(), 64);
550 }
551}