Skip to main content

lib_q_random/
traits.rs

1// Allow clippy warnings in trait definitions
2// These are legitimate patterns for API design
3#![allow(clippy::struct_excessive_bools, clippy::doc_markdown)]
4
5//! Core traits for lib-q-random
6//!
7//! This module defines the fundamental traits that form the interface
8//! for random number generation in the libQ ecosystem.
9
10#[cfg(feature = "alloc")]
11use alloc::{
12    boxed::Box,
13    collections::BTreeMap,
14    string::String,
15};
16use core::fmt;
17
18use rand_core::{
19    CryptoRng,
20    Rng,
21};
22
23use crate::Result;
24
25/// Enhanced random number generator trait for cryptographic applications
26///
27/// This trait extends the standard `Rng` and `CryptoRng` traits with
28/// additional functionality required for secure cryptographic operations.
29pub trait SecureRng: Rng + CryptoRng + Send + Sync {
30    /// Fill the buffer with cryptographically secure random bytes
31    ///
32    /// This method provides the same functionality as `Rng::fill_bytes`
33    /// but with additional security guarantees and error handling.
34    ///
35    /// # Arguments
36    ///
37    /// * `dest` - Buffer to fill with random bytes
38    ///
39    /// # Errors
40    ///
41    /// Returns an error if the random number generation fails or if
42    /// the generated bytes don't meet security requirements.
43    fn fill_bytes_secure(&mut self, dest: &mut [u8]) -> Result<()> {
44        self.fill_bytes(dest);
45        Ok(())
46    }
47
48    /// Generate a random u32 with security validation
49    ///
50    /// # Errors
51    ///
52    /// Returns an error if the random number generation fails.
53    fn next_u32_secure(&mut self) -> Result<u32> {
54        Ok(self.next_u32())
55    }
56
57    /// Generate a random u64 with security validation
58    ///
59    /// # Errors
60    ///
61    /// Returns an error if the random number generation fails.
62    fn next_u64_secure(&mut self) -> Result<u64> {
63        Ok(self.next_u64())
64    }
65
66    /// Initialize the RNG with entropy (if supported)
67    ///
68    /// # Arguments
69    ///
70    /// * `entropy` - Entropy data to initialize the RNG
71    ///
72    /// # Errors
73    ///
74    /// Returns an error if the entropy is invalid or initialization fails.
75    fn initialize(&mut self, entropy: &[u8]) -> Result<()> {
76        // Default implementation does nothing
77        let _ = entropy;
78        Ok(())
79    }
80
81    /// Check if the RNG is cryptographically secure
82    ///
83    /// Returns `true` if the RNG provides cryptographically secure randomness,
84    /// `false` otherwise (e.g., for deterministic RNGs used in testing).
85    fn is_secure(&self) -> bool {
86        true
87    }
88
89    /// Get the entropy quality estimate (0.0 to 1.0)
90    ///
91    /// Returns an estimate of the entropy quality, where 1.0 represents
92    /// perfect entropy and 0.0 represents no entropy.
93    fn entropy_quality(&self) -> f64 {
94        1.0
95    }
96
97    /// Get the RNG's security level
98    ///
99    /// Returns a description of the RNG's security characteristics.
100    fn security_level(&self) -> SecurityLevel {
101        if self.is_secure() {
102            SecurityLevel::CryptographicallySecure
103        } else {
104            SecurityLevel::Deterministic
105        }
106    }
107
108    /// Reseed the RNG with fresh entropy
109    ///
110    /// This method allows the RNG to be reseeded with fresh entropy,
111    /// which is important for long-running applications.
112    ///
113    /// # Errors
114    ///
115    /// Returns an error if reseeding fails or is not supported.
116    fn reseed(&mut self) -> Result<()> {
117        // Default implementation does nothing
118        Ok(())
119    }
120
121    /// Get the RNG's internal state size
122    ///
123    /// Returns the size of the RNG's internal state in bytes.
124    fn state_size(&self) -> usize {
125        0
126    }
127
128    /// Get the RNG's reseed interval
129    ///
130    /// Returns the recommended number of bytes to generate before reseeding,
131    /// or `None` if reseeding is not required.
132    fn reseed_interval(&self) -> Option<usize> {
133        None
134    }
135}
136
137/// Entropy source trait for providing random data
138///
139/// This trait defines the interface for entropy sources that can provide
140/// random data to RNG implementations.
141pub trait EntropySource: Send + Sync {
142    /// Get entropy from the source
143    ///
144    /// # Arguments
145    ///
146    /// * `dest` - Buffer to fill with entropy data
147    ///
148    /// # Errors
149    ///
150    /// Returns an error if entropy cannot be obtained from the source.
151    fn get_entropy(&mut self, dest: &mut [u8]) -> Result<()>;
152
153    /// Check if the entropy source is available
154    ///
155    /// Returns `true` if the entropy source is available and can provide
156    /// entropy, `false` otherwise.
157    fn is_available(&self) -> bool {
158        true
159    }
160
161    /// Get the entropy source's quality estimate (0.0 to 1.0)
162    ///
163    /// Returns an estimate of the entropy source's quality, where 1.0
164    /// represents perfect entropy and 0.0 represents no entropy.
165    fn quality(&self) -> f64 {
166        1.0
167    }
168
169    /// Get the entropy source's name
170    ///
171    /// Returns a human-readable name for the entropy source.
172    fn name(&self) -> &'static str {
173        "Unknown"
174    }
175
176    /// Get the entropy source's type
177    ///
178    /// Returns the type of entropy source.
179    fn source_type(&self) -> EntropySourceType {
180        EntropySourceType::User // Default to User for custom implementations
181    }
182
183    /// Get the maximum entropy that can be obtained in one call
184    ///
185    /// Returns the maximum number of bytes that can be obtained in a single
186    /// call to `get_entropy`, or `None` if there's no limit.
187    fn max_entropy_per_call(&self) -> Option<usize> {
188        None
189    }
190
191    /// Check if the entropy source requires initialization
192    ///
193    /// Returns `true` if the entropy source requires initialization before use.
194    fn requires_initialization(&self) -> bool {
195        false
196    }
197
198    /// Initialize the entropy source
199    ///
200    /// # Arguments
201    ///
202    /// * `config` - Configuration parameters for initialization
203    ///
204    /// # Errors
205    ///
206    /// Returns an error if initialization fails.
207    fn initialize(&mut self, config: &EntropyConfig) -> Result<()> {
208        let _ = config;
209        Ok(())
210    }
211}
212
213/// RNG provider trait for creating and managing RNG instances
214///
215/// This trait defines the interface for RNG providers that can create
216/// and manage RNG instances with different characteristics.
217pub trait RngProvider: Send + Sync {
218    /// Create a new RNG instance
219    ///
220    /// # Arguments
221    ///
222    /// * `config` - Configuration for the RNG
223    ///
224    /// # Errors
225    ///
226    /// Returns an error if the RNG cannot be created.
227    #[cfg(feature = "alloc")]
228    fn create_rng(&self, config: &RngConfig) -> Result<Box<dyn SecureRng>>;
229
230    /// Get the provider's name
231    ///
232    /// Returns a human-readable name for the provider.
233    fn name(&self) -> &'static str;
234
235    /// Get the provider's capabilities
236    ///
237    /// Returns the capabilities of the provider.
238    fn capabilities(&self) -> ProviderCapabilities;
239
240    /// Check if the provider supports a specific configuration
241    ///
242    /// # Arguments
243    ///
244    /// * `config` - Configuration to check
245    ///
246    /// Returns `true` if the provider supports the configuration.
247    fn supports_config(&self, config: &RngConfig) -> bool {
248        let _ = config;
249        true
250    }
251
252    /// Get the provider's priority
253    ///
254    /// Returns a priority value for the provider, where higher values
255    /// indicate higher priority.
256    fn priority(&self) -> u32 {
257        0
258    }
259}
260
261/// Security level enumeration
262#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
263pub enum SecurityLevel {
264    /// Deterministic (not cryptographically secure)
265    Deterministic,
266    /// Cryptographically secure
267    CryptographicallySecure,
268    /// Hardware-based security
269    Hardware,
270    /// Software-based security
271    Software,
272}
273
274impl fmt::Display for SecurityLevel {
275    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276        match self {
277            Self::Deterministic => write!(f, "Deterministic"),
278            Self::CryptographicallySecure => write!(f, "Cryptographically Secure"),
279            Self::Hardware => write!(f, "Hardware"),
280            Self::Software => write!(f, "Software"),
281        }
282    }
283}
284
285/// Entropy source type enumeration
286#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
287pub enum EntropySourceType {
288    /// Operating system entropy source
289    OperatingSystem,
290    /// Hardware random number generator
291    Hardware,
292    /// User-provided entropy
293    User,
294    /// Deterministic source (for testing)
295    Deterministic,
296}
297
298impl fmt::Display for EntropySourceType {
299    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300        match self {
301            Self::OperatingSystem => write!(f, "Operating System"),
302            Self::Hardware => write!(f, "Hardware"),
303            Self::User => write!(f, "User"),
304            Self::Deterministic => write!(f, "Deterministic"),
305        }
306    }
307}
308
309/// RNG configuration structure
310pub struct RngConfig {
311    /// Security level required
312    pub security_level: SecurityLevel,
313    /// Entropy source to use
314    #[cfg(feature = "alloc")]
315    pub entropy_source: Option<Box<dyn EntropySource>>,
316    /// Reseed interval in bytes
317    pub reseed_interval: Option<usize>,
318    /// Additional configuration parameters
319    #[cfg(feature = "alloc")]
320    pub parameters: BTreeMap<String, String>,
321}
322
323impl Default for RngConfig {
324    fn default() -> Self {
325        Self {
326            security_level: SecurityLevel::CryptographicallySecure,
327            #[cfg(feature = "alloc")]
328            entropy_source: None,
329            reseed_interval: None,
330            #[cfg(feature = "alloc")]
331            parameters: BTreeMap::new(),
332        }
333    }
334}
335
336/// Entropy configuration structure
337#[derive(Debug, Clone)]
338pub struct EntropyConfig {
339    /// Minimum entropy quality required
340    pub min_quality: f64,
341    /// Maximum entropy per call
342    pub max_per_call: Option<usize>,
343    /// Additional configuration parameters
344    #[cfg(feature = "alloc")]
345    pub parameters: BTreeMap<String, String>,
346}
347
348impl Default for EntropyConfig {
349    fn default() -> Self {
350        Self {
351            min_quality: 0.8,
352            max_per_call: None,
353            #[cfg(feature = "alloc")]
354            parameters: BTreeMap::new(),
355        }
356    }
357}
358
359/// Provider capabilities structure
360#[derive(Debug, Clone, Copy, PartialEq, Eq)]
361pub struct ProviderCapabilities {
362    /// Can provide cryptographically secure randomness
363    pub secure: bool,
364    /// Can provide deterministic randomness
365    pub deterministic: bool,
366    /// Supports hardware entropy sources
367    pub hardware: bool,
368    /// Supports reseeding
369    pub reseeding: bool,
370    /// Supports custom entropy sources
371    pub custom_entropy: bool,
372    /// Supports no_std environments
373    pub no_std: bool,
374    /// Supports WASM environments
375    pub wasm: bool,
376}
377
378impl Default for ProviderCapabilities {
379    fn default() -> Self {
380        Self {
381            secure: true,
382            deterministic: false,
383            hardware: false,
384            reseeding: false,
385            custom_entropy: false,
386            no_std: true,
387            wasm: false,
388        }
389    }
390}
391
392#[cfg(test)]
393mod tests {
394    #[cfg(all(not(feature = "std"), feature = "alloc"))]
395    use alloc::format;
396
397    use super::*;
398
399    #[test]
400    fn test_security_level_ordering() {
401        assert!(SecurityLevel::CryptographicallySecure > SecurityLevel::Deterministic);
402        assert!(SecurityLevel::Hardware > SecurityLevel::CryptographicallySecure);
403    }
404
405    #[test]
406    #[cfg(any(feature = "std", feature = "alloc"))]
407    fn test_entropy_source_type_display() {
408        assert_eq!(
409            format!("{}", EntropySourceType::OperatingSystem),
410            "Operating System"
411        );
412        assert_eq!(format!("{}", EntropySourceType::Hardware), "Hardware");
413    }
414
415    #[test]
416    fn test_rng_config_default() {
417        let config = RngConfig::default();
418        assert_eq!(
419            config.security_level,
420            SecurityLevel::CryptographicallySecure
421        );
422        assert!(config.reseed_interval.is_none());
423    }
424
425    #[test]
426    fn test_entropy_config_default() {
427        let config = EntropyConfig::default();
428        #[allow(clippy::float_cmp)]
429        {
430            assert_eq!(config.min_quality, 0.8);
431        }
432        assert!(config.max_per_call.is_none());
433    }
434
435    #[test]
436    fn test_provider_capabilities_default() {
437        let caps = ProviderCapabilities::default();
438        assert!(caps.secure);
439        assert!(!caps.deterministic);
440        assert!(!caps.hardware);
441        assert!(!caps.reseeding);
442        assert!(!caps.custom_entropy);
443        assert!(caps.no_std);
444        assert!(!caps.wasm);
445    }
446}