quantacore/
random.rs

1//! Quantum Random Number Generation (QRNG).
2//!
3//! This module provides access to the hardware quantum random number generator.
4
5use crate::device::Device;
6use crate::error::{check_error, Result};
7use crate::ffi;
8
9/// Entropy pool status.
10#[derive(Debug, Clone)]
11pub struct EntropyStatus {
12    /// Current entropy level (0-100%)
13    pub level: u32,
14    /// Whether the entropy source is healthy
15    pub is_healthy: bool,
16    /// Total bytes generated
17    pub total_generated: u64,
18    /// Current generation rate (bytes/second)
19    pub generation_rate: f64,
20}
21
22impl EntropyStatus {
23    pub(crate) fn from_ffi(status: &ffi::quac_entropy_status_t) -> Self {
24        Self {
25            level: status.level,
26            is_healthy: status.is_healthy != 0,
27            total_generated: status.total_generated,
28            generation_rate: status.generation_rate,
29        }
30    }
31}
32
33/// Random number generator subsystem.
34///
35/// Provides access to the hardware Quantum Random Number Generator (QRNG)
36/// for generating cryptographically secure random data.
37///
38/// # Example
39///
40/// ```no_run
41/// use quantacore::{initialize, open_first_device};
42///
43/// initialize().unwrap();
44/// let device = open_first_device().unwrap();
45/// let random = device.random();
46///
47/// // Generate random bytes
48/// let bytes = random.bytes(32).unwrap();
49/// println!("Random: {}", hex::encode(&bytes));
50///
51/// // Generate random integer
52/// let value = random.next_u64().unwrap();
53///
54/// // Generate random float in [0, 1)
55/// let f = random.next_f64().unwrap();
56///
57/// // Check entropy status
58/// let status = random.get_entropy_status().unwrap();
59/// println!("Entropy level: {}%", status.level);
60/// ```
61#[derive(Clone)]
62pub struct Random {
63    device: Device,
64}
65
66impl Random {
67    /// Create a new random subsystem handle.
68    pub(crate) fn new(device: Device) -> Self {
69        Self { device }
70    }
71
72    /// Get the current entropy status.
73    pub fn get_entropy_status(&self) -> Result<EntropyStatus> {
74        let mut status = ffi::quac_entropy_status_t::default();
75        let result = unsafe { ffi::quac_get_entropy_status(self.device.handle(), &mut status) };
76        check_error(result)?;
77        Ok(EntropyStatus::from_ffi(&status))
78    }
79
80    /// Generate random bytes.
81    ///
82    /// # Arguments
83    ///
84    /// * `length` - Number of bytes to generate
85    ///
86    /// # Returns
87    ///
88    /// A vector of random bytes.
89    pub fn bytes(&self, length: usize) -> Result<Vec<u8>> {
90        let mut buffer = vec![0u8; length];
91        self.fill(&mut buffer)?;
92        Ok(buffer)
93    }
94
95    /// Fill a buffer with random bytes.
96    ///
97    /// # Arguments
98    ///
99    /// * `buffer` - The buffer to fill
100    pub fn fill(&self, buffer: &mut [u8]) -> Result<()> {
101        let result = unsafe {
102            ffi::quac_random_bytes(self.device.handle(), buffer.as_mut_ptr(), buffer.len())
103        };
104        check_error(result)
105    }
106
107    /// Generate a random u8.
108    pub fn next_u8(&self) -> Result<u8> {
109        let mut buf = [0u8; 1];
110        self.fill(&mut buf)?;
111        Ok(buf[0])
112    }
113
114    /// Generate a random u16.
115    pub fn next_u16(&self) -> Result<u16> {
116        let mut buf = [0u8; 2];
117        self.fill(&mut buf)?;
118        Ok(u16::from_le_bytes(buf))
119    }
120
121    /// Generate a random u32.
122    pub fn next_u32(&self) -> Result<u32> {
123        let mut buf = [0u8; 4];
124        self.fill(&mut buf)?;
125        Ok(u32::from_le_bytes(buf))
126    }
127
128    /// Generate a random u64.
129    pub fn next_u64(&self) -> Result<u64> {
130        let mut buf = [0u8; 8];
131        self.fill(&mut buf)?;
132        Ok(u64::from_le_bytes(buf))
133    }
134
135    /// Generate a random i32.
136    pub fn next_i32(&self) -> Result<i32> {
137        let mut buf = [0u8; 4];
138        self.fill(&mut buf)?;
139        Ok(i32::from_le_bytes(buf))
140    }
141
142    /// Generate a random i64.
143    pub fn next_i64(&self) -> Result<i64> {
144        let mut buf = [0u8; 8];
145        self.fill(&mut buf)?;
146        Ok(i64::from_le_bytes(buf))
147    }
148
149    /// Generate a random u32 in range [0, bound).
150    ///
151    /// Uses rejection sampling to ensure uniform distribution.
152    pub fn next_u32_bound(&self, bound: u32) -> Result<u32> {
153        if bound == 0 {
154            return Ok(0);
155        }
156        if bound.is_power_of_two() {
157            return Ok(self.next_u32()? & (bound - 1));
158        }
159
160        let threshold = bound.wrapping_neg() % bound;
161        loop {
162            let r = self.next_u32()?;
163            if r >= threshold {
164                return Ok(r % bound);
165            }
166        }
167    }
168
169    /// Generate a random u64 in range [0, bound).
170    pub fn next_u64_bound(&self, bound: u64) -> Result<u64> {
171        if bound == 0 {
172            return Ok(0);
173        }
174        if bound.is_power_of_two() {
175            return Ok(self.next_u64()? & (bound - 1));
176        }
177
178        let threshold = bound.wrapping_neg() % bound;
179        loop {
180            let r = self.next_u64()?;
181            if r >= threshold {
182                return Ok(r % bound);
183            }
184        }
185    }
186
187    /// Generate a random integer in range [min, max].
188    pub fn randint(&self, min: i64, max: i64) -> Result<i64> {
189        if min > max {
190            return Ok(min);
191        }
192        let range = (max - min) as u64 + 1;
193        let r = self.next_u64_bound(range)?;
194        Ok(min + r as i64)
195    }
196
197    /// Generate a random f32 in range [0.0, 1.0).
198    pub fn next_f32(&self) -> Result<f32> {
199        // Use 24 bits for f32 mantissa
200        let r = self.next_u32()? >> 8;
201        Ok(r as f32 / (1u32 << 24) as f32)
202    }
203
204    /// Generate a random f64 in range [0.0, 1.0).
205    pub fn next_f64(&self) -> Result<f64> {
206        // Use 53 bits for f64 mantissa
207        let r = self.next_u64()? >> 11;
208        Ok(r as f64 / (1u64 << 53) as f64)
209    }
210
211    /// Generate a random f64 in range [min, max).
212    pub fn uniform(&self, min: f64, max: f64) -> Result<f64> {
213        let r = self.next_f64()?;
214        Ok(min + (max - min) * r)
215    }
216
217    /// Generate a random boolean.
218    pub fn next_bool(&self) -> Result<bool> {
219        Ok((self.next_u8()? & 1) != 0)
220    }
221
222    /// Generate a random boolean with given probability of being true.
223    pub fn next_bool_with_probability(&self, p: f64) -> Result<bool> {
224        Ok(self.next_f64()? < p)
225    }
226
227    /// Generate a UUID v4 string.
228    ///
229    /// Returns a string in the format `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`
230    /// where x is any hexadecimal digit and y is one of 8, 9, a, or b.
231    pub fn uuid(&self) -> Result<String> {
232        let mut bytes = [0u8; 16];
233        self.fill(&mut bytes)?;
234
235        // Set version to 4
236        bytes[6] = (bytes[6] & 0x0f) | 0x40;
237        // Set variant to 10xx
238        bytes[8] = (bytes[8] & 0x3f) | 0x80;
239
240        Ok(format!(
241            "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
242            bytes[0], bytes[1], bytes[2], bytes[3],
243            bytes[4], bytes[5],
244            bytes[6], bytes[7],
245            bytes[8], bytes[9],
246            bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]
247        ))
248    }
249
250    /// Select a random element from a slice.
251    pub fn choice<'a, T>(&self, items: &'a [T]) -> Result<Option<&'a T>> {
252        if items.is_empty() {
253            return Ok(None);
254        }
255        let idx = self.next_u64_bound(items.len() as u64)? as usize;
256        Ok(Some(&items[idx]))
257    }
258
259    /// Sample n unique elements from a slice without replacement.
260    pub fn sample<T: Clone>(&self, items: &[T], n: usize) -> Result<Vec<T>> {
261        if n >= items.len() {
262            return Ok(items.to_vec());
263        }
264
265        let mut pool: Vec<usize> = (0..items.len()).collect();
266        let mut result = Vec::with_capacity(n);
267
268        for _ in 0..n {
269            let idx = self.next_u64_bound(pool.len() as u64)? as usize;
270            result.push(items[pool[idx]].clone());
271            pool.swap_remove(idx);
272        }
273
274        Ok(result)
275    }
276
277    /// Shuffle a slice in place using Fisher-Yates algorithm.
278    pub fn shuffle<T>(&self, items: &mut [T]) -> Result<()> {
279        for i in (1..items.len()).rev() {
280            let j = self.next_u64_bound((i + 1) as u64)? as usize;
281            items.swap(i, j);
282        }
283        Ok(())
284    }
285
286    /// Return a shuffled copy of a slice.
287    pub fn shuffled<T: Clone>(&self, items: &[T]) -> Result<Vec<T>> {
288        let mut result = items.to_vec();
289        self.shuffle(&mut result)?;
290        Ok(result)
291    }
292}
293
294impl std::fmt::Debug for Random {
295    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
296        f.debug_struct("Random").finish()
297    }
298}
299
300#[cfg(test)]
301mod tests {
302    use super::*;
303
304    #[test]
305    fn test_entropy_status() {
306        let status = EntropyStatus {
307            level: 80,
308            is_healthy: true,
309            total_generated: 1000000,
310            generation_rate: 1000.0,
311        };
312        assert!(status.is_healthy);
313        assert_eq!(status.level, 80);
314    }
315}