Skip to main content

lib_q_random/
provider.rs

1// Allow clippy warnings in provider code
2// These are legitimate patterns for API design
3#![allow(clippy::must_use_candidate)]
4
5//! RNG provider implementations
6//!
7//! This module provides the main RNG provider implementation and factory
8//! for creating and managing RNG instances with different characteristics.
9
10#[cfg(feature = "alloc")]
11use alloc::boxed::Box;
12#[cfg(feature = "alloc")]
13use core::fmt;
14
15#[cfg(feature = "alloc")]
16use rand_core::{
17    TryCryptoRng,
18    TryRng,
19};
20
21#[cfg(feature = "alloc")]
22use crate::Result;
23#[cfg(feature = "alloc")]
24use crate::traits::{
25    EntropySource,
26    ProviderCapabilities,
27    RngConfig,
28    RngProvider,
29    SecureRng,
30    SecurityLevel,
31};
32#[cfg(feature = "alloc")]
33use crate::validation::EntropyValidator;
34
35/// Main libQ random number generator
36///
37/// This is the primary RNG implementation for the libQ ecosystem, providing
38/// a unified interface for secure random number generation across different
39/// platforms and use cases.
40#[cfg(feature = "alloc")]
41pub struct LibQRng {
42    /// Entropy source for random data
43    entropy_source: Box<dyn EntropySource>,
44    /// Entropy validator for quality assessment
45    validator: EntropyValidator,
46    /// Security level of this RNG
47    security_level: SecurityLevel,
48    /// Whether this RNG is deterministic
49    deterministic: bool,
50    /// Reseed counter for security
51    reseed_counter: u32,
52    /// Bytes generated since last reseed
53    bytes_generated: usize,
54    /// Reseed interval in bytes
55    reseed_interval: Option<usize>,
56}
57
58/// Marker for types [`LibQRng::fill`] may write raw CSPRNG bytes over.
59///
60/// # Contract
61///
62/// Implementing this asserts that **every bit pattern of the type is a valid
63/// value**. `fill` reinterprets the destination slice as bytes and overwrites
64/// it with CSPRNG output, so any type for which some bit pattern is invalid
65/// would be left holding an invalid value — undefined behaviour independent of
66/// whether the value is ever read.
67///
68/// # Why it is sealed, and why it is not `Copy + Default`
69///
70/// `fill`'s bound was `T: Copy + Default` until card `t_1594295d`. That is a
71/// weaker and different property: `bool` is `Copy + Default` and only
72/// `0x00`/`0x01` are valid bit patterns; `char` is `Copy + Default` and must be
73/// a Unicode scalar value. Random bytes satisfy neither. The bound read as
74/// "any simple value type", and the two most obvious simple value types it
75/// admitted were exactly the two it must not.
76///
77/// The trait is sealed so the validity claim cannot be asserted from outside
78/// this crate, where it would not be checkable. It is implemented for the
79/// integer primitives only — the types that genuinely accept every bit
80/// pattern. Notably absent and deliberately so: `bool`, `char`, `f32`/`f64`
81/// (every pattern is a valid float, including signalling `NaNs`, but a random
82/// "float" is almost never what a caller means — ask for integers and convert),
83/// and `NonZero*` (zero is invalid by construction).
84pub trait FillableBytes: private::Sealed + Copy {}
85
86mod private {
87    /// Seals [`super::FillableBytes`] against outside implementations.
88    pub trait Sealed {}
89}
90
91macro_rules! impl_fillable_bytes {
92    ($($t:ty),* $(,)?) => {
93        $(
94            impl private::Sealed for $t {}
95            impl FillableBytes for $t {}
96        )*
97    };
98}
99
100// Every bit pattern of a fixed-width integer is a valid value of that integer.
101impl_fillable_bytes!(
102    u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
103);
104
105#[cfg(feature = "alloc")]
106impl LibQRng {
107    /// Create a new secure RNG using the best available entropy source
108    ///
109    /// This method creates a cryptographically secure RNG using the highest
110    /// quality entropy source available on the current platform.
111    ///
112    /// # Errors
113    ///
114    /// Returns an error if no secure entropy source is available.
115    ///
116    /// # Examples
117    ///
118    /// ```rust
119    /// use lib_q_random::LibQRng;
120    /// use rand_core::Rng;
121    ///
122    /// let mut rng = LibQRng::new_secure().unwrap();
123    /// let mut bytes = [0u8; 32];
124    /// rng.fill_bytes(&mut bytes);
125    /// ```
126    pub fn new_secure() -> Result<Self> {
127        let entropy_source = crate::entropy::EntropySourceFactory::create_best_available()?;
128        // Use relaxed validation settings for real-world entropy sources
129        let validator = EntropyValidator::with_settings(
130            64,    // min_entropy_bits: 64 bits minimum (8 bytes)
131            8192,  // max_entropy_bits: 8KB maximum
132            0.3,   // quality_threshold: More realistic threshold
133            false, // strict_mode: Disabled for real-world usage
134        );
135
136        Ok(Self {
137            entropy_source,
138            validator,
139            security_level: SecurityLevel::CryptographicallySecure,
140            deterministic: false,
141            reseed_counter: 0,
142            bytes_generated: 0,
143            reseed_interval: Some(1024 * 1024), // 1MB reseed interval
144        })
145    }
146
147    /// Create a new deterministic RNG for testing
148    ///
149    /// Initializes a **KT128** (`KangarooTwelve`) XOF byte stream from a **256-bit** seed.
150    /// Suitable for KATs and regression
151    /// tests. **Unpredictability is only as strong as the seed**: this is not a
152    /// substitute for [`Self::new_secure`] in production.
153    ///
154    /// # Arguments
155    ///
156    /// * `seed` - 32-byte seed; must be chosen explicitly for tests
157    ///
158    /// # Examples
159    ///
160    /// ```rust
161    /// use lib_q_random::LibQRng;
162    /// use rand_core::Rng;
163    ///
164    /// let mut rng = LibQRng::new_deterministic([1; 32]);
165    /// let mut bytes = [0u8; 32];
166    /// rng.fill_bytes(&mut bytes);
167    /// ```
168    pub fn new_deterministic(seed: [u8; 32]) -> Self {
169        let entropy_source =
170            crate::entropy::EntropySourceFactory::create_deterministic_entropy(seed);
171        // Deterministic RNGs don't need strict validation since they're not cryptographically secure
172        let validator = EntropyValidator::with_settings(
173            32,    // min_entropy_bits: Lower threshold for deterministic
174            1024,  // max_entropy_bits: Smaller limit
175            0.1,   // quality_threshold: Very low threshold since it's deterministic
176            false, // strict_mode: Disabled
177        );
178
179        Self {
180            entropy_source,
181            validator,
182            security_level: SecurityLevel::Deterministic,
183            deterministic: true,
184            reseed_counter: 0,
185            bytes_generated: 0,
186            reseed_interval: None, // No reseeding for deterministic RNGs
187        }
188    }
189
190    /// Create a deterministic RNG from a `u64` test seed (`SplitMix64` → KT128).
191    pub fn new_deterministic_from_u64(seed: u64) -> Self {
192        let entropy_source =
193            crate::entropy::EntropySourceFactory::create_deterministic_entropy_from_u64(seed);
194        let validator = EntropyValidator::with_settings(32, 1024, 0.1, false);
195
196        Self {
197            entropy_source,
198            validator,
199            security_level: SecurityLevel::Deterministic,
200            deterministic: true,
201            reseed_counter: 0,
202            bytes_generated: 0,
203            reseed_interval: None,
204        }
205    }
206
207    /// Create a deterministic RNG using Saturnin CTR keystream (`deterministic-saturnin` feature).
208    ///
209    /// Requires `alloc`. Uses domain [`crate::kt128_expander::DOMAIN_LIBQ_DET_SATURNIN`] for the CTR nonce.
210    ///
211    /// # Errors
212    ///
213    /// Returns an error if Saturnin keystream generation fails.
214    #[cfg(feature = "deterministic-saturnin")]
215    pub fn new_deterministic_saturnin(seed: [u8; 32]) -> Result<Self> {
216        let entropy_source = alloc::boxed::Box::new(
217            crate::saturnin_det::SaturninDeterministicEntropySource::new(seed)?,
218        );
219        let validator = EntropyValidator::with_settings(32, 1024, 0.1, false);
220        Ok(Self {
221            entropy_source,
222            validator,
223            security_level: SecurityLevel::Deterministic,
224            deterministic: true,
225            reseed_counter: 0,
226            bytes_generated: 0,
227            reseed_interval: None,
228        })
229    }
230
231    /// Create a new RNG with NIST AES256-CTR-DRBG for KAT test compatibility
232    ///
233    /// This method creates an RNG using the NIST AES256-CTR-DRBG algorithm,
234    /// which is required for compatibility with NIST KAT test vectors.
235    ///
236    /// # Arguments
237    ///
238    /// * `entropy_input` - 48-byte entropy input for DRBG initialization
239    ///
240    /// # Examples
241    ///
242    /// ```rust
243    /// use lib_q_random::LibQRng;
244    /// use rand_core::Rng;
245    ///
246    /// let entropy_input = [0u8; 48]; // 48-byte seed
247    /// let mut rng = LibQRng::new_nist_drbg(entropy_input);
248    /// let mut bytes = [0u8; 32];
249    /// rng.fill_bytes(&mut bytes);
250    /// ```
251    #[cfg(feature = "nist-drbg")]
252    pub fn new_nist_drbg(entropy_input: [u8; 48]) -> Self {
253        let entropy_source =
254            crate::entropy::EntropySourceFactory::create_nist_drbg_entropy(entropy_input);
255        // NIST DRBG provides high quality entropy
256        let validator = EntropyValidator::with_settings(
257            256,  // min_entropy_bits: High threshold for NIST DRBG
258            4096, // max_entropy_bits: Higher limit
259            0.9,  // quality_threshold: High threshold for NIST DRBG
260            true, // strict_mode: Enabled for NIST DRBG
261        );
262
263        Self {
264            entropy_source,
265            validator,
266            security_level: SecurityLevel::CryptographicallySecure,
267            deterministic: true, // NIST DRBG is deterministic but cryptographically secure
268            reseed_counter: 0,
269            bytes_generated: 0,
270            reseed_interval: Some(1_000_000), // NIST recommendation
271        }
272    }
273
274    /// Create a new RNG with a custom entropy source
275    ///
276    /// This method allows creating an RNG with a custom entropy source,
277    /// useful for specialized applications or testing.
278    ///
279    /// # Arguments
280    ///
281    /// * `entropy_source` - Custom entropy source implementation
282    ///
283    /// # Examples
284    ///
285    /// ```rust
286    /// use lib_q_random::LibQRng;
287    /// use lib_q_random::entropy::UserEntropySource;
288    /// use rand_core::Rng;
289    ///
290    /// let entropy_data = vec![1, 2, 3, 4, 5, 6, 7, 8];
291    /// let entropy_source = UserEntropySource::new(entropy_data);
292    /// let mut rng = LibQRng::new_custom(entropy_source);
293    /// ```
294    pub fn new_custom<T: EntropySource + 'static>(entropy_source: T) -> Self {
295        let entropy_source = Box::new(entropy_source);
296        // Use appropriate validator settings based on entropy source type
297        let validator = match entropy_source.source_type() {
298            crate::traits::EntropySourceType::Hardware => {
299                EntropyValidator::with_settings(64, 8192, 0.4, false)
300            }
301            crate::traits::EntropySourceType::OperatingSystem => {
302                EntropyValidator::with_settings(64, 8192, 0.3, false)
303            }
304            _ => EntropyValidator::with_settings(64, 8192, 0.3, false),
305        };
306
307        // Determine security level based on entropy source type
308        let security_level = match entropy_source.source_type() {
309            crate::traits::EntropySourceType::Hardware => SecurityLevel::Hardware,
310            crate::traits::EntropySourceType::OperatingSystem => {
311                SecurityLevel::CryptographicallySecure
312            }
313            crate::traits::EntropySourceType::Deterministic |
314            crate::traits::EntropySourceType::User => SecurityLevel::Deterministic,
315        };
316
317        let deterministic = matches!(
318            entropy_source.source_type(),
319            crate::traits::EntropySourceType::Deterministic |
320                crate::traits::EntropySourceType::User
321        );
322
323        Self {
324            entropy_source,
325            validator,
326            security_level,
327            deterministic,
328            reseed_counter: 0,
329            bytes_generated: 0,
330            reseed_interval: if deterministic {
331                None
332            } else {
333                Some(1024 * 1024)
334            },
335        }
336    }
337
338    /// Create a new RNG with custom configuration
339    ///
340    /// This method allows creating an RNG with specific configuration
341    /// parameters for specialized use cases.
342    ///
343    /// # Arguments
344    ///
345    /// * `config` - RNG configuration parameters
346    ///
347    /// # Errors
348    ///
349    /// Returns an error if the configuration is invalid or if the RNG
350    /// cannot be created with the specified parameters.
351    pub fn with_config(config: &RngConfig) -> Result<Self> {
352        let entropy_source = if let Some(_source) = &config.entropy_source {
353            // We can't move out of a reference, so we need to create a new one
354            // This is a limitation of the current design
355            crate::entropy::EntropySourceFactory::create_best_available()?
356        } else {
357            crate::entropy::EntropySourceFactory::create_best_available()?
358        };
359
360        // Use appropriate validator settings based on security level
361        let validator = match config.security_level {
362            SecurityLevel::Hardware => EntropyValidator::with_settings(64, 8192, 0.4, false),
363            SecurityLevel::CryptographicallySecure => {
364                EntropyValidator::with_settings(64, 8192, 0.3, false)
365            }
366            SecurityLevel::Deterministic => EntropyValidator::with_settings(32, 1024, 0.1, false),
367            SecurityLevel::Software => EntropyValidator::with_settings(64, 8192, 0.3, false),
368        };
369        let deterministic =
370            entropy_source.source_type() == crate::traits::EntropySourceType::Deterministic;
371
372        Ok(Self {
373            entropy_source,
374            validator,
375            security_level: config.security_level,
376            deterministic,
377            reseed_counter: 0,
378            bytes_generated: 0,
379            reseed_interval: config.reseed_interval,
380        })
381    }
382
383    /// Check if this RNG is deterministic
384    pub fn is_deterministic(&self) -> bool {
385        self.deterministic
386    }
387
388    /// Get the security level of this RNG
389    pub fn security_level(&self) -> SecurityLevel {
390        self.security_level
391    }
392
393    /// Get the entropy source name
394    pub fn entropy_source_name(&self) -> &'static str {
395        self.entropy_source.name()
396    }
397
398    /// Get the entropy source type
399    pub fn entropy_source_type(&self) -> crate::traits::EntropySourceType {
400        self.entropy_source.source_type()
401    }
402
403    /// Get the reseed counter
404    pub fn reseed_counter(&self) -> u32 {
405        self.reseed_counter
406    }
407
408    /// Get the bytes generated since last reseed
409    pub fn bytes_generated(&self) -> usize {
410        self.bytes_generated
411    }
412
413    /// Check if this RNG is cryptographically secure
414    pub fn is_secure(&self) -> bool {
415        self.security_level == SecurityLevel::CryptographicallySecure
416    }
417
418    /// Get the entropy quality estimate (0.0 to 1.0)
419    pub fn entropy_quality(&self) -> f64 {
420        match self.security_level {
421            SecurityLevel::CryptographicallySecure => 1.0,
422            SecurityLevel::Deterministic => 0.0,
423            SecurityLevel::Hardware => 0.95,
424            SecurityLevel::Software => 0.8,
425        }
426    }
427
428    /// Check if reseeding is needed
429    fn needs_reseed(&self) -> bool {
430        if let Some(interval) = self.reseed_interval {
431            self.bytes_generated >= interval
432        } else {
433            false
434        }
435    }
436
437    /// Perform reseeding if needed
438    fn reseed_if_needed(&mut self) -> Result<()> {
439        if self.needs_reseed() {
440            self.reseed()?;
441        }
442        Ok(())
443    }
444}
445
446#[cfg(feature = "alloc")]
447impl SecureRng for LibQRng {
448    fn fill_bytes_secure(&mut self, dest: &mut [u8]) -> Result<()> {
449        // Check if reseeding is needed
450        self.reseed_if_needed()?;
451
452        // Get entropy from the source
453        self.entropy_source.get_entropy(dest)?;
454
455        // Validate entropy quality if not deterministic.
456        // Skip validation for buffers < 64 bytes: statistical quality tests are
457        // unreliable on small samples and produce false positives that abort the
458        // process.  For larger buffers, validate only the first 64 bytes so we
459        // never exceed the validator's max_entropy_bits / 8 limit (1 KB) even
460        // when the caller requests several kilobytes at once.
461        if !self.deterministic && dest.len() >= 64 {
462            self.validator.validate_entropy(&dest[..64])?;
463        }
464
465        // Update counters
466        self.bytes_generated += dest.len();
467
468        Ok(())
469    }
470
471    fn next_u32_secure(&mut self) -> Result<u32> {
472        let mut bytes = [0u8; 4];
473        self.fill_bytes_secure(&mut bytes)?;
474        Ok(u32::from_le_bytes(bytes))
475    }
476
477    fn next_u64_secure(&mut self) -> Result<u64> {
478        let mut bytes = [0u8; 8];
479        self.fill_bytes_secure(&mut bytes)?;
480        Ok(u64::from_le_bytes(bytes))
481    }
482
483    fn initialize(&mut self, entropy: &[u8]) -> Result<()> {
484        // For deterministic RNGs, we can reinitialize with new seed
485        if self.deterministic {
486            let seed: [u8; 32] = entropy.try_into().map_err(|_| {
487                crate::Error::invalid_configuration(
488                    "deterministic seed",
489                    "exactly 32 bytes",
490                    "slice length is not 32",
491                )
492            })?;
493            let new_source =
494                crate::entropy::EntropySourceFactory::create_deterministic_entropy(seed);
495            self.entropy_source = new_source;
496            self.reseed_counter = 0;
497            self.bytes_generated = 0;
498        }
499        // For secure RNGs, we can't reinitialize with user entropy
500        // as it would compromise security
501        Ok(())
502    }
503
504    fn is_secure(&self) -> bool {
505        !self.deterministic
506    }
507
508    fn entropy_quality(&self) -> f64 {
509        self.entropy_source.quality()
510    }
511
512    fn security_level(&self) -> SecurityLevel {
513        self.security_level
514    }
515
516    fn reseed(&mut self) -> Result<()> {
517        if self.deterministic {
518            return Ok(()); // No reseeding for deterministic RNGs
519        }
520
521        // For secure RNGs, reseeding is handled by the entropy source
522        // We just update our counters
523        self.reseed_counter = self.reseed_counter.wrapping_add(1);
524        self.bytes_generated = 0;
525
526        Ok(())
527    }
528
529    fn state_size(&self) -> usize {
530        // This is an estimate - the actual state size depends on the entropy source
531        64
532    }
533
534    fn reseed_interval(&self) -> Option<usize> {
535        self.reseed_interval
536    }
537}
538
539#[cfg(feature = "alloc")]
540impl TryRng for LibQRng {
541    type Error = core::convert::Infallible;
542
543    fn try_next_u32(&mut self) -> core::result::Result<u32, Self::Error> {
544        match self.next_u32_secure() {
545            Ok(value) => Ok(value),
546            Err(_) => rng_abort(),
547        }
548    }
549
550    fn try_next_u64(&mut self) -> core::result::Result<u64, Self::Error> {
551        match self.next_u64_secure() {
552            Ok(value) => Ok(value),
553            Err(_) => rng_abort(),
554        }
555    }
556
557    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> core::result::Result<(), Self::Error> {
558        match self.fill_bytes_secure(dest) {
559            Ok(()) => Ok(()),
560            Err(_) => rng_abort(),
561        }
562    }
563}
564
565/// Hard stop on unrecoverable entropy failure (avoids `panic!` / `eprintln!` for strict Clippy).
566// `clippy::panic` is denied in non-test builds (see `lib.rs` lint config),
567// but the `no_std` branch of this abort path has no `std::process::abort`
568// alternative, so `panic!` is the only way out. Allow it on the function so
569// the attribute targets an item rather than a macro invocation.
570#[cfg(feature = "alloc")]
571#[inline(never)]
572#[allow(clippy::panic)]
573fn rng_abort() -> ! {
574    #[cfg(feature = "std")]
575    std::process::abort();
576    #[cfg(not(feature = "std"))]
577    panic!("CRITICAL SECURITY FAILURE: RNG entropy unavailable");
578}
579
580#[cfg(feature = "alloc")]
581impl TryCryptoRng for LibQRng {}
582
583#[cfg(feature = "alloc")]
584impl LibQRng {
585    /// Fill a slice with random values of any integer type
586    ///
587    /// This method provides a convenient way to fill slices of different integer types
588    /// with random values, handling the byte conversion internally.
589    ///
590    /// # Which `T` is accepted, and why it is not `Copy + Default`
591    ///
592    /// `T` must implement [`FillableBytes`], a sealed marker for types where
593    /// **every bit pattern is a valid value**. This bound used to be
594    /// `Copy + Default`, which is not the same property and admitted types
595    /// this function cannot legally fill: `bool` (only `0x00`/`0x01` are
596    /// valid) and `char` (must be a Unicode scalar value) both satisfy
597    /// `Copy + Default`, and writing random bytes over one produces an
598    /// invalid value — undefined behaviour before anything even reads it.
599    /// See card `t_1594295d`.
600    ///
601    /// # Guarantee: no unzeroized intermediate buffer
602    ///
603    /// CSPRNG output is written **directly into `dest`**'s backing memory; this
604    /// function never stages the bytes it generates in a temporary heap
605    /// allocation. That matters because `dest` is frequently key material
606    /// (e.g. wrapped in `zeroize::Zeroizing` by the caller) — a temporary
607    /// `Vec<u8>` copy would be dropped without scrubbing and could strand a
608    /// copy of that key material in freed heap memory. Callers do not need to
609    /// take any extra precaution against a hidden intermediate: there isn't
610    /// one.
611    ///
612    /// # Examples
613    ///
614    /// ```rust
615    /// use lib_q_random::LibQRng;
616    ///
617    /// let mut rng = LibQRng::new_secure().unwrap();
618    /// let mut u16_array = [0u16; 10];
619    /// rng.fill(&mut u16_array);
620    /// ```
621    ///
622    /// `bool` is rejected at compile time. It is `Copy + Default`, so the old
623    /// bound accepted it, and a random byte that is neither `0x00` nor `0x01`
624    /// is an invalid `bool` — UB. This doctest is the regression pin for that:
625    /// it fails the build if the bound is ever loosened back.
626    ///
627    /// ```compile_fail
628    /// use lib_q_random::LibQRng;
629    ///
630    /// let mut rng = LibQRng::new_secure().unwrap();
631    /// let mut flags = [false; 8];
632    /// rng.fill(&mut flags);
633    /// ```
634    ///
635    /// `char` likewise — most 4-byte patterns are not Unicode scalar values.
636    ///
637    /// ```compile_fail
638    /// use lib_q_random::LibQRng;
639    ///
640    /// let mut rng = LibQRng::new_secure().unwrap();
641    /// let mut chars = [''; 4];
642    /// rng.fill(&mut chars);
643    /// ```
644    pub fn fill<T>(&mut self, dest: &mut [T])
645    where
646        T: FillableBytes,
647    {
648        if dest.is_empty() {
649            return;
650        }
651
652        // Calculate the number of bytes needed
653        let size = core::mem::size_of::<T>();
654        if size == 0 {
655            return;
656        }
657        let total_bytes = core::mem::size_of_val(dest);
658
659        // SAFETY: `dest` is a valid, exclusively-borrowed `&mut [T]` of
660        // `dest.len()` elements, so it denotes exactly `total_bytes` bytes of
661        // valid, properly aligned, writable memory for the lifetime of this
662        // borrow. Reinterpreting it as `&mut [u8]` is sound because `u8` has
663        // no alignment requirement (any `T` alignment satisfies it) and every
664        // byte in the region is being written by `fill_bytes_secure` before
665        // it is read as part of `T` again, so we never observe uninitialized
666        // padding as a `T`-typed value through this reference. Writing
667        // straight into `dest` this way (rather than through a temporary
668        // `Vec<u8>`) is what gives `fill` the no-intermediate-buffer
669        // guarantee documented above.
670        let bytes =
671            unsafe { core::slice::from_raw_parts_mut(dest.as_mut_ptr().cast::<u8>(), total_bytes) };
672
673        // Entropy failure must never yield predictable output; abort like the
674        // infallible `RngCore` path instead of leaving `dest` with whatever
675        // bytes were written so far.
676        if self.fill_bytes_secure(bytes).is_err() {
677            rng_abort();
678        }
679    }
680}
681
682// LibQRng implements rand_core::Rng and TryCryptoRng, so CryptoRng and Rng
683// are provided by rand_core blanket impls. The signature crate uses rand_core
684// and will see these implementations when using the same rand_core version.
685
686#[cfg(feature = "alloc")]
687impl fmt::Display for LibQRng {
688    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
689        write!(
690            f,
691            "LibQRng(security_level: {}, entropy_source: {}, deterministic: {}, reseed_counter: {})",
692            self.security_level,
693            self.entropy_source.name(),
694            self.deterministic,
695            self.reseed_counter
696        )
697    }
698}
699
700/// RNG provider factory
701///
702/// This factory provides convenient methods for creating RNG instances
703/// with different characteristics and configurations.
704pub struct LibQRngProvider;
705
706impl LibQRngProvider {
707    /// Create a new RNG provider
708    pub fn new() -> Self {
709        Self
710    }
711}
712
713#[cfg(feature = "alloc")]
714impl RngProvider for LibQRngProvider {
715    fn create_rng(&self, config: &RngConfig) -> Result<Box<dyn SecureRng>> {
716        let rng = LibQRng::with_config(config)?;
717        Ok(Box::new(rng))
718    }
719
720    fn name(&self) -> &'static str {
721        "libQ RNG Provider"
722    }
723
724    fn capabilities(&self) -> ProviderCapabilities {
725        ProviderCapabilities {
726            secure: true,
727            deterministic: true,
728            hardware: true,
729            reseeding: true,
730            custom_entropy: true,
731            no_std: true,
732            wasm: true,
733        }
734    }
735
736    fn supports_config(&self, config: &RngConfig) -> bool {
737        // We support all configurations
738        let _ = config;
739        true
740    }
741
742    fn priority(&self) -> u32 {
743        100 // High priority as the main provider
744    }
745}
746
747impl Default for LibQRngProvider {
748    fn default() -> Self {
749        Self::new()
750    }
751}
752
753#[cfg(test)]
754mod tests {
755    #[cfg(all(not(feature = "std"), feature = "alloc"))]
756    use alloc::format;
757
758    #[cfg(feature = "alloc")]
759    use rand_core::Rng;
760
761    #[cfg(feature = "alloc")]
762    use super::*;
763
764    #[test]
765    #[cfg(feature = "alloc")]
766    fn test_libq_rng_deterministic_creation() {
767        let mut seed = [0u8; 32];
768        seed[..8].copy_from_slice(&[1, 2, 3, 4, 5, 6, 7, 8]);
769        let rng = LibQRng::new_deterministic(seed);
770        assert!(rng.is_deterministic());
771        assert_eq!(rng.security_level(), SecurityLevel::Deterministic);
772        assert!(!rng.is_secure());
773    }
774
775    #[test]
776    #[cfg(feature = "alloc")]
777    fn test_libq_rng_deterministic_consistency() {
778        let seed = [42u8; 32];
779        let mut rng1 = LibQRng::new_deterministic(seed);
780        let mut rng2 = LibQRng::new_deterministic(seed);
781
782        let mut bytes1 = [0u8; 32];
783        let mut bytes2 = [0u8; 32];
784
785        rng1.fill_bytes(&mut bytes1);
786        rng2.fill_bytes(&mut bytes2);
787
788        assert_eq!(bytes1, bytes2);
789    }
790
791    #[test]
792    #[cfg(feature = "alloc")]
793    fn test_libq_rng_deterministic_golden_zero_seed() {
794        use crate::kt128_expander::Kt128Expander;
795
796        let expected = crate::kt128_expander::KT128_DET_GOLDEN_ZERO_SEED_64;
797        let mut rng = LibQRng::new_deterministic([0u8; 32]);
798        let mut out = [0u8; 64];
799        rng.fill_bytes(&mut out);
800        let mut direct = Kt128Expander::from_det_seed_32([0u8; 32]);
801        let mut expected_direct = [0u8; 64];
802        direct.fill_bytes(&mut expected_direct);
803        assert_eq!(out, expected);
804        assert_eq!(out, expected_direct);
805    }
806
807    /// Regression: deterministic RNG must use the full 256-bit seed (KT128), not a
808    /// collapsed 64-bit state where distant seed bytes could be ignored.
809    #[test]
810    #[cfg(feature = "alloc")]
811    fn test_libq_rng_deterministic_seeds_differ_in_final_byte_yield_different_streams() {
812        let seed_a = [0u8; 32];
813        let mut seed_b = [0u8; 32];
814        seed_b[31] = 1;
815
816        let mut rng_a = LibQRng::new_deterministic(seed_a);
817        let mut rng_b = LibQRng::new_deterministic(seed_b);
818
819        let mut out_a = [0u8; 64];
820        let mut out_b = [0u8; 64];
821        rng_a.fill_bytes(&mut out_a);
822        rng_b.fill_bytes(&mut out_b);
823
824        assert_ne!(
825            out_a, out_b,
826            "KT128 streams from different 32-byte keys must diverge immediately"
827        );
828    }
829
830    #[test]
831    #[cfg(feature = "alloc")]
832    fn test_libq_rng_custom_creation() {
833        let entropy_data = vec![1, 2, 3, 4, 5, 6, 7, 8];
834        let entropy_source = crate::entropy::UserEntropySource::new(entropy_data);
835        let rng = LibQRng::new_custom(entropy_source);
836        assert!(rng.is_deterministic());
837        assert_eq!(rng.security_level(), SecurityLevel::Deterministic);
838    }
839
840    #[test]
841    #[cfg(feature = "alloc")]
842    fn test_libq_rng_config_creation() {
843        let config = RngConfig::default();
844        let rng = LibQRng::with_config(&config);
845        assert!(rng.is_ok());
846    }
847
848    #[test]
849    #[cfg(feature = "alloc")]
850    fn test_libq_rng_provider_creation() {
851        let provider = LibQRngProvider::new();
852        assert_eq!(provider.name(), "libQ RNG Provider");
853        assert_eq!(provider.priority(), 100);
854    }
855
856    #[test]
857    #[cfg(feature = "alloc")]
858    fn test_libq_rng_provider_capabilities() {
859        let provider = LibQRngProvider::new();
860        let caps = provider.capabilities();
861        assert!(caps.secure);
862        assert!(caps.deterministic);
863        assert!(caps.hardware);
864        assert!(caps.reseeding);
865        assert!(caps.custom_entropy);
866        assert!(caps.no_std);
867        assert!(caps.wasm);
868    }
869
870    #[test]
871    #[cfg(feature = "alloc")]
872    fn test_libq_rng_provider_create_rng() {
873        let provider = LibQRngProvider::new();
874        let config = RngConfig::default();
875        let rng = provider.create_rng(&config);
876        assert!(rng.is_ok());
877    }
878
879    #[test]
880    #[cfg(feature = "alloc")]
881    fn test_libq_rng_reseed_counter() {
882        let mut seed = [0u8; 32];
883        seed[..4].copy_from_slice(&[1, 2, 3, 4]);
884        let rng = LibQRng::new_deterministic(seed);
885        assert_eq!(rng.reseed_counter(), 0);
886        assert_eq!(rng.bytes_generated(), 0);
887    }
888
889    #[test]
890    #[cfg(feature = "alloc")]
891    fn test_libq_rng_entropy_source_info() {
892        let mut seed = [0u8; 32];
893        seed[..4].copy_from_slice(&[1, 2, 3, 4]);
894        let rng = LibQRng::new_deterministic(seed);
895        assert!(!rng.entropy_source_name().is_empty());
896        assert_eq!(
897            rng.entropy_source_type(),
898            crate::traits::EntropySourceType::Deterministic
899        );
900    }
901
902    #[test]
903    #[cfg(feature = "alloc")]
904    fn test_libq_rng_display() {
905        let mut seed = [0u8; 32];
906        seed[..4].copy_from_slice(&[1, 2, 3, 4]);
907        let rng = LibQRng::new_deterministic(seed);
908        let display = format!("{rng}");
909        assert!(display.contains("LibQRng"));
910        assert!(display.contains("Deterministic"));
911    }
912}