1#![allow(clippy::must_use_candidate)]
4
5#[cfg(feature = "alloc")]
11use alloc::{
12 boxed::Box,
13 vec,
14};
15#[cfg(feature = "alloc")]
16use core::fmt;
17
18#[cfg(feature = "alloc")]
19use rand_core::{
20 TryCryptoRng,
21 TryRng,
22};
23
24#[cfg(feature = "alloc")]
25use crate::Result;
26#[cfg(feature = "alloc")]
27use crate::traits::{
28 EntropySource,
29 ProviderCapabilities,
30 RngConfig,
31 RngProvider,
32 SecureRng,
33 SecurityLevel,
34};
35#[cfg(feature = "alloc")]
36use crate::validation::EntropyValidator;
37
38#[cfg(feature = "alloc")]
44pub struct LibQRng {
45 entropy_source: Box<dyn EntropySource>,
47 validator: EntropyValidator,
49 security_level: SecurityLevel,
51 deterministic: bool,
53 reseed_counter: u32,
55 bytes_generated: usize,
57 reseed_interval: Option<usize>,
59}
60
61#[cfg(feature = "alloc")]
62impl LibQRng {
63 pub fn new_secure() -> Result<Self> {
83 let entropy_source = crate::entropy::EntropySourceFactory::create_best_available()?;
84 let validator = EntropyValidator::with_settings(
86 64, 8192, 0.3, false, );
91
92 Ok(Self {
93 entropy_source,
94 validator,
95 security_level: SecurityLevel::CryptographicallySecure,
96 deterministic: false,
97 reseed_counter: 0,
98 bytes_generated: 0,
99 reseed_interval: Some(1024 * 1024), })
101 }
102
103 pub fn new_deterministic(seed: [u8; 32]) -> Self {
125 let entropy_source =
126 crate::entropy::EntropySourceFactory::create_deterministic_entropy(seed);
127 let validator = EntropyValidator::with_settings(
129 32, 1024, 0.1, false, );
134
135 Self {
136 entropy_source,
137 validator,
138 security_level: SecurityLevel::Deterministic,
139 deterministic: true,
140 reseed_counter: 0,
141 bytes_generated: 0,
142 reseed_interval: None, }
144 }
145
146 #[cfg(feature = "nist-drbg")]
167 pub fn new_nist_drbg(entropy_input: [u8; 48]) -> Self {
168 let entropy_source =
169 crate::entropy::EntropySourceFactory::create_nist_drbg_entropy(entropy_input);
170 let validator = EntropyValidator::with_settings(
172 256, 4096, 0.9, true, );
177
178 Self {
179 entropy_source,
180 validator,
181 security_level: SecurityLevel::CryptographicallySecure,
182 deterministic: true, reseed_counter: 0,
184 bytes_generated: 0,
185 reseed_interval: Some(1_000_000), }
187 }
188
189 pub fn new_custom<T: EntropySource + 'static>(entropy_source: T) -> Self {
210 let entropy_source = Box::new(entropy_source);
211 let validator = match entropy_source.source_type() {
213 crate::traits::EntropySourceType::Hardware => {
214 EntropyValidator::with_settings(64, 8192, 0.4, false)
215 }
216 crate::traits::EntropySourceType::OperatingSystem => {
217 EntropyValidator::with_settings(64, 8192, 0.3, false)
218 }
219 _ => EntropyValidator::with_settings(64, 8192, 0.3, false),
220 };
221
222 let security_level = match entropy_source.source_type() {
224 crate::traits::EntropySourceType::Hardware => SecurityLevel::Hardware,
225 crate::traits::EntropySourceType::OperatingSystem => {
226 SecurityLevel::CryptographicallySecure
227 }
228 crate::traits::EntropySourceType::Deterministic => SecurityLevel::Deterministic,
229 crate::traits::EntropySourceType::User => SecurityLevel::CryptographicallySecure,
230 };
231
232 let deterministic =
233 entropy_source.source_type() == crate::traits::EntropySourceType::Deterministic;
234
235 Self {
236 entropy_source,
237 validator,
238 security_level,
239 deterministic,
240 reseed_counter: 0,
241 bytes_generated: 0,
242 reseed_interval: if deterministic {
243 None
244 } else {
245 Some(1024 * 1024)
246 },
247 }
248 }
249
250 pub fn with_config(config: &RngConfig) -> Result<Self> {
264 let entropy_source = if let Some(_source) = &config.entropy_source {
265 crate::entropy::EntropySourceFactory::create_best_available()?
268 } else {
269 crate::entropy::EntropySourceFactory::create_best_available()?
270 };
271
272 let validator = match config.security_level {
274 SecurityLevel::Hardware => EntropyValidator::with_settings(64, 8192, 0.4, false),
275 SecurityLevel::CryptographicallySecure => {
276 EntropyValidator::with_settings(64, 8192, 0.3, false)
277 }
278 SecurityLevel::Deterministic => EntropyValidator::with_settings(32, 1024, 0.1, false),
279 SecurityLevel::Software => EntropyValidator::with_settings(64, 8192, 0.3, false),
280 };
281 let deterministic =
282 entropy_source.source_type() == crate::traits::EntropySourceType::Deterministic;
283
284 Ok(Self {
285 entropy_source,
286 validator,
287 security_level: config.security_level,
288 deterministic,
289 reseed_counter: 0,
290 bytes_generated: 0,
291 reseed_interval: config.reseed_interval,
292 })
293 }
294
295 pub fn is_deterministic(&self) -> bool {
297 self.deterministic
298 }
299
300 pub fn security_level(&self) -> SecurityLevel {
302 self.security_level
303 }
304
305 pub fn entropy_source_name(&self) -> &'static str {
307 self.entropy_source.name()
308 }
309
310 pub fn entropy_source_type(&self) -> crate::traits::EntropySourceType {
312 self.entropy_source.source_type()
313 }
314
315 pub fn reseed_counter(&self) -> u32 {
317 self.reseed_counter
318 }
319
320 pub fn bytes_generated(&self) -> usize {
322 self.bytes_generated
323 }
324
325 pub fn is_secure(&self) -> bool {
327 self.security_level == SecurityLevel::CryptographicallySecure
328 }
329
330 pub fn entropy_quality(&self) -> f64 {
332 match self.security_level {
333 SecurityLevel::CryptographicallySecure => 1.0,
334 SecurityLevel::Deterministic => 0.0,
335 SecurityLevel::Hardware => 0.95,
336 SecurityLevel::Software => 0.8,
337 }
338 }
339
340 fn needs_reseed(&self) -> bool {
342 if let Some(interval) = self.reseed_interval {
343 self.bytes_generated >= interval
344 } else {
345 false
346 }
347 }
348
349 fn reseed_if_needed(&mut self) -> Result<()> {
351 if self.needs_reseed() {
352 self.reseed()?;
353 }
354 Ok(())
355 }
356}
357
358#[cfg(feature = "alloc")]
359impl SecureRng for LibQRng {
360 fn fill_bytes_secure(&mut self, dest: &mut [u8]) -> Result<()> {
361 self.reseed_if_needed()?;
363
364 self.entropy_source.get_entropy(dest)?;
366
367 if !self.deterministic {
369 if dest.len() >= 8 {
371 let _ = self.validator.validate_entropy(dest);
372 }
373 }
374
375 self.bytes_generated += dest.len();
377
378 Ok(())
379 }
380
381 fn next_u32_secure(&mut self) -> Result<u32> {
382 let mut bytes = [0u8; 4];
383 self.fill_bytes_secure(&mut bytes)?;
384 Ok(u32::from_le_bytes(bytes))
385 }
386
387 fn next_u64_secure(&mut self) -> Result<u64> {
388 let mut bytes = [0u8; 8];
389 self.fill_bytes_secure(&mut bytes)?;
390 Ok(u64::from_le_bytes(bytes))
391 }
392
393 fn initialize(&mut self, entropy: &[u8]) -> Result<()> {
394 if self.deterministic {
396 let seed: [u8; 32] = entropy.try_into().map_err(|_| {
397 crate::Error::invalid_configuration(
398 "deterministic seed",
399 "exactly 32 bytes",
400 "slice length is not 32",
401 )
402 })?;
403 let new_source =
404 crate::entropy::EntropySourceFactory::create_deterministic_entropy(seed);
405 self.entropy_source = new_source;
406 self.reseed_counter = 0;
407 self.bytes_generated = 0;
408 }
409 Ok(())
412 }
413
414 fn is_secure(&self) -> bool {
415 !self.deterministic
416 }
417
418 fn entropy_quality(&self) -> f64 {
419 self.entropy_source.quality()
420 }
421
422 fn security_level(&self) -> SecurityLevel {
423 self.security_level
424 }
425
426 fn reseed(&mut self) -> Result<()> {
427 if self.deterministic {
428 return Ok(()); }
430
431 self.reseed_counter = self.reseed_counter.wrapping_add(1);
434 self.bytes_generated = 0;
435
436 Ok(())
437 }
438
439 fn state_size(&self) -> usize {
440 64
442 }
443
444 fn reseed_interval(&self) -> Option<usize> {
445 self.reseed_interval
446 }
447}
448
449#[cfg(feature = "alloc")]
450impl TryRng for LibQRng {
451 type Error = core::convert::Infallible;
452
453 fn try_next_u32(&mut self) -> core::result::Result<u32, Self::Error> {
454 match self.next_u32_secure() {
455 Ok(value) => Ok(value),
456 Err(_) => rng_abort(),
457 }
458 }
459
460 fn try_next_u64(&mut self) -> core::result::Result<u64, Self::Error> {
461 match self.next_u64_secure() {
462 Ok(value) => Ok(value),
463 Err(_) => rng_abort(),
464 }
465 }
466
467 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> core::result::Result<(), Self::Error> {
468 match self.fill_bytes_secure(dest) {
469 Ok(()) => Ok(()),
470 Err(_) => rng_abort(),
471 }
472 }
473}
474
475#[cfg(feature = "alloc")]
481#[inline(never)]
482#[allow(clippy::panic)]
483fn rng_abort() -> ! {
484 #[cfg(feature = "std")]
485 std::process::abort();
486 #[cfg(not(feature = "std"))]
487 panic!("CRITICAL SECURITY FAILURE: RNG entropy unavailable");
488}
489
490#[cfg(feature = "alloc")]
491impl TryCryptoRng for LibQRng {}
492
493#[cfg(feature = "alloc")]
494impl LibQRng {
495 pub fn fill<T>(&mut self, dest: &mut [T])
510 where
511 T: Copy + Default,
512 {
513 if dest.is_empty() {
514 return;
515 }
516
517 let size = core::mem::size_of::<T>();
519 let total_bytes = core::mem::size_of_val(dest);
520
521 let mut bytes = vec![0u8; total_bytes];
523
524 let _ = self.fill_bytes_secure(&mut bytes);
526
527 for (i, chunk) in bytes.chunks_exact(size).enumerate() {
529 if i < dest.len() {
530 unsafe {
533 let ptr = dest.as_mut_ptr().add(i).cast::<u8>();
534 core::ptr::copy_nonoverlapping(chunk.as_ptr(), ptr, size);
535 }
536 }
537 }
538 }
539}
540
541#[cfg(feature = "alloc")]
546impl fmt::Display for LibQRng {
547 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
548 write!(
549 f,
550 "LibQRng(security_level: {}, entropy_source: {}, deterministic: {}, reseed_counter: {})",
551 self.security_level,
552 self.entropy_source.name(),
553 self.deterministic,
554 self.reseed_counter
555 )
556 }
557}
558
559pub struct LibQRngProvider;
564
565impl LibQRngProvider {
566 pub fn new() -> Self {
568 Self
569 }
570}
571
572#[cfg(feature = "alloc")]
573impl RngProvider for LibQRngProvider {
574 fn create_rng(&self, config: &RngConfig) -> Result<Box<dyn SecureRng>> {
575 let rng = LibQRng::with_config(config)?;
576 Ok(Box::new(rng))
577 }
578
579 fn name(&self) -> &'static str {
580 "libQ RNG Provider"
581 }
582
583 fn capabilities(&self) -> ProviderCapabilities {
584 ProviderCapabilities {
585 secure: true,
586 deterministic: true,
587 hardware: true,
588 reseeding: true,
589 custom_entropy: true,
590 no_std: true,
591 wasm: true,
592 }
593 }
594
595 fn supports_config(&self, config: &RngConfig) -> bool {
596 let _ = config;
598 true
599 }
600
601 fn priority(&self) -> u32 {
602 100 }
604}
605
606impl Default for LibQRngProvider {
607 fn default() -> Self {
608 Self::new()
609 }
610}
611
612#[cfg(test)]
613mod tests {
614 #[cfg(all(not(feature = "std"), feature = "alloc"))]
615 use alloc::format;
616
617 #[cfg(feature = "alloc")]
618 use rand_core::Rng;
619
620 #[cfg(feature = "alloc")]
621 use super::*;
622
623 #[test]
624 #[cfg(feature = "alloc")]
625 fn test_libq_rng_deterministic_creation() {
626 let mut seed = [0u8; 32];
627 seed[..8].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8]);
628 let rng = LibQRng::new_deterministic(seed);
629 assert!(rng.is_deterministic());
630 assert_eq!(rng.security_level(), SecurityLevel::Deterministic);
631 assert!(!rng.is_secure());
632 }
633
634 #[test]
635 #[cfg(feature = "alloc")]
636 fn test_libq_rng_deterministic_consistency() {
637 let seed = [42u8; 32];
638 let mut rng1 = LibQRng::new_deterministic(seed);
639 let mut rng2 = LibQRng::new_deterministic(seed);
640
641 let mut bytes1 = [0u8; 32];
642 let mut bytes2 = [0u8; 32];
643
644 rng1.fill_bytes(&mut bytes1);
645 rng2.fill_bytes(&mut bytes2);
646
647 assert_eq!(bytes1, bytes2);
648 }
649
650 #[test]
653 #[cfg(feature = "alloc")]
654 fn test_libq_rng_deterministic_seeds_differ_in_final_byte_yield_different_streams() {
655 let seed_a = [0u8; 32];
656 let mut seed_b = [0u8; 32];
657 seed_b[31] = 1;
658
659 let mut rng_a = LibQRng::new_deterministic(seed_a);
660 let mut rng_b = LibQRng::new_deterministic(seed_b);
661
662 let mut out_a = [0u8; 64];
663 let mut out_b = [0u8; 64];
664 rng_a.fill_bytes(&mut out_a);
665 rng_b.fill_bytes(&mut out_b);
666
667 assert_ne!(
668 out_a, out_b,
669 "ChaCha20 streams from different 32-byte keys must diverge immediately"
670 );
671 }
672
673 #[test]
674 #[cfg(feature = "alloc")]
675 fn test_libq_rng_custom_creation() {
676 let entropy_data = vec![1, 2, 3, 4, 5, 6, 7, 8];
677 let entropy_source = crate::entropy::UserEntropySource::new(entropy_data);
678 let rng = LibQRng::new_custom(entropy_source);
679 assert!(!rng.is_deterministic());
680 assert_eq!(rng.security_level(), SecurityLevel::CryptographicallySecure);
681 }
682
683 #[test]
684 #[cfg(feature = "alloc")]
685 fn test_libq_rng_config_creation() {
686 let config = RngConfig::default();
687 let rng = LibQRng::with_config(&config);
688 assert!(rng.is_ok());
689 }
690
691 #[test]
692 #[cfg(feature = "alloc")]
693 fn test_libq_rng_provider_creation() {
694 let provider = LibQRngProvider::new();
695 assert_eq!(provider.name(), "libQ RNG Provider");
696 assert_eq!(provider.priority(), 100);
697 }
698
699 #[test]
700 #[cfg(feature = "alloc")]
701 fn test_libq_rng_provider_capabilities() {
702 let provider = LibQRngProvider::new();
703 let caps = provider.capabilities();
704 assert!(caps.secure);
705 assert!(caps.deterministic);
706 assert!(caps.hardware);
707 assert!(caps.reseeding);
708 assert!(caps.custom_entropy);
709 assert!(caps.no_std);
710 assert!(caps.wasm);
711 }
712
713 #[test]
714 #[cfg(feature = "alloc")]
715 fn test_libq_rng_provider_create_rng() {
716 let provider = LibQRngProvider::new();
717 let config = RngConfig::default();
718 let rng = provider.create_rng(&config);
719 assert!(rng.is_ok());
720 }
721
722 #[test]
723 #[cfg(feature = "alloc")]
724 fn test_libq_rng_reseed_counter() {
725 let mut seed = [0u8; 32];
726 seed[..4].copy_from_slice(&[1, 2, 3, 4]);
727 let rng = LibQRng::new_deterministic(seed);
728 assert_eq!(rng.reseed_counter(), 0);
729 assert_eq!(rng.bytes_generated(), 0);
730 }
731
732 #[test]
733 #[cfg(feature = "alloc")]
734 fn test_libq_rng_entropy_source_info() {
735 let mut seed = [0u8; 32];
736 seed[..4].copy_from_slice(&[1, 2, 3, 4]);
737 let rng = LibQRng::new_deterministic(seed);
738 assert!(!rng.entropy_source_name().is_empty());
739 assert_eq!(
740 rng.entropy_source_type(),
741 crate::traits::EntropySourceType::Deterministic
742 );
743 }
744
745 #[test]
746 #[cfg(feature = "alloc")]
747 fn test_libq_rng_display() {
748 let mut seed = [0u8; 32];
749 seed[..4].copy_from_slice(&[1, 2, 3, 4]);
750 let rng = LibQRng::new_deterministic(seed);
751 let display = format!("{rng}");
752 assert!(display.contains("LibQRng"));
753 assert!(display.contains("Deterministic"));
754 }
755}