Skip to content

Commit a3e94c2

Browse files
committed
Rework how the random number generating device operates internally, it is now more sane and less complicated overall.
1 parent 6b340df commit a3e94c2

File tree

3 files changed

+53
-63
lines changed

3 files changed

+53
-63
lines changed

redox-core/src/com_bus/com_bus_io.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ use super::device_error::DeviceResult;
22

33
pub trait ComBusIO {
44
/// Read a u8 value from the device.
5-
fn read_u8(&self) -> DeviceResult<u8>;
5+
fn read_u8(&mut self) -> DeviceResult<u8>;
66
/// Read a u32 value from the device.
7-
fn read_u32(&self) -> DeviceResult<u32>;
7+
fn read_u32(&mut self) -> DeviceResult<u32>;
88
/// Read a uf32 value from the device.
9-
fn read_f32(&self) -> DeviceResult<f32>;
9+
fn read_f32(&mut self) -> DeviceResult<f32>;
1010

1111
/// Write a u8 value to the device.
1212
fn write_u8(&mut self, value: u8) -> DeviceResult<()>;

redox-core/src/com_bus/random_device.rs

+47-57
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,38 @@
11
use rand::{rngs::OsRng, Rng, SeedableRng, TryRngCore};
22
use rand_xoshiro::Xoshiro256Plus;
3-
use std::cell::RefCell;
43

54
use super::{
65
com_bus_io::ComBusIO,
76
device_error::{DeviceError, DeviceResult},
87
};
98

10-
thread_local! {
11-
static PRNG: RefCell<Xoshiro256Plus> = RefCell::new(Xoshiro256Plus::from_os_rng());
12-
static CRNG: RefCell<OsRng> = const { RefCell::new(OsRng) };
13-
}
14-
9+
#[repr(u8)]
1510
#[derive(PartialEq, Eq)]
1611
enum RandomMode {
1712
Crypto,
18-
Seeded,
19-
Standard,
13+
Pseudorandom,
2014
}
2115

22-
/// The seedable random generator chip!
16+
/// The random number generator device!
2317
pub struct RandomDevice {
2418
/// Has the random number generator been initialized?
2519
is_initialized: bool,
2620
/// The random generator mode currently being used.
2721
mode: RandomMode,
22+
/// The pseudorandom number generator.
23+
prng: Xoshiro256Plus,
24+
/// The Cryptographically secure RNG generator.
25+
crng: OsRng,
2826
}
2927

3028
impl RandomDevice {
3129
pub fn new() -> Self {
3230
Self {
3331
// By default we initialize the random number generator using entropy.
3432
is_initialized: true,
35-
mode: RandomMode::Standard,
33+
mode: RandomMode::Crypto,
34+
prng: Xoshiro256Plus::from_os_rng(),
35+
crng: OsRng,
3636
}
3737
}
3838
}
@@ -44,57 +44,51 @@ impl Default for RandomDevice {
4444
}
4545

4646
impl ComBusIO for RandomDevice {
47-
fn read_u8(&self) -> DeviceResult<u8> {
47+
fn read_u8(&mut self) -> DeviceResult<u8> {
4848
if !self.is_initialized {
4949
return DeviceResult::Err(DeviceError::Misconfigured);
5050
}
5151

5252
Ok(match self.mode {
53-
RandomMode::Crypto => CRNG.with(|r| {
53+
RandomMode::Crypto => {
5454
let mut arr: [u8; 1] = [0; 1];
55-
r.borrow_mut()
55+
self.crng
5656
.try_fill_bytes(&mut arr)
57-
.expect("failed to get bytes");
57+
.expect("failed to get u8");
5858
arr[0]
59-
}),
60-
RandomMode::Seeded => PRNG.with(|r| r.borrow_mut().random::<u8>()),
61-
RandomMode::Standard => rand::rng().random::<u8>(),
59+
}
60+
RandomMode::Pseudorandom => self.prng.random::<u8>(),
6261
})
6362
}
6463

65-
fn read_u32(&self) -> DeviceResult<u32> {
64+
fn read_u32(&mut self) -> DeviceResult<u32> {
6665
if !self.is_initialized {
6766
return DeviceResult::Err(DeviceError::Misconfigured);
6867
}
6968

7069
Ok(match self.mode {
71-
RandomMode::Crypto => CRNG.with(|r| {
72-
let mut arr: [u8; 4] = [0; 4];
73-
r.borrow_mut()
74-
.try_fill_bytes(&mut arr)
75-
.expect("failed to get bytes");
76-
u32::from_ne_bytes(arr)
77-
}),
78-
RandomMode::Seeded => PRNG.with(|r| r.borrow_mut().random::<u32>()),
79-
RandomMode::Standard => rand::rng().random::<u32>(),
70+
RandomMode::Crypto => self.crng.try_next_u32().expect("failed to get u32"),
71+
RandomMode::Pseudorandom => self.prng.random::<u32>(),
8072
})
8173
}
8274

83-
fn read_f32(&self) -> DeviceResult<f32> {
75+
fn read_f32(&mut self) -> DeviceResult<f32> {
8476
if !self.is_initialized {
8577
return DeviceResult::Err(DeviceError::Misconfigured);
8678
}
8779

8880
Ok(match self.mode {
89-
RandomMode::Crypto => CRNG.with(|r| {
90-
let mut arr: [u8; 4] = [0; 4];
91-
r.borrow_mut()
92-
.try_fill_bytes(&mut arr)
93-
.expect("failed to get bytes");
94-
f32::from_ne_bytes(arr)
95-
}),
96-
RandomMode::Seeded => PRNG.with(|r| r.borrow_mut().random::<f32>()),
97-
RandomMode::Standard => rand::rng().random::<f32>(),
81+
RandomMode::Crypto => {
82+
// We want to weed out any potential infinities or NaN's,
83+
// and we'll iterate until we find one.
84+
let mut value = f32::INFINITY;
85+
while !value.is_finite() {
86+
let v = self.crng.try_next_u32().expect("failed to get u32");
87+
value = f32::from_bits(v);
88+
}
89+
value
90+
}
91+
RandomMode::Pseudorandom => self.prng.random::<f32>(),
9892
})
9993
}
10094

@@ -104,19 +98,15 @@ impl ComBusIO for RandomDevice {
10498
// The instruction indicating the type of random number generator to be used.
10599
match value {
106100
0 => {
107-
// Standard mode - a PRNG derived from entropy.
108-
PRNG.with(|r| *r.borrow_mut() = Xoshiro256Plus::from_os_rng());
109-
self.mode = RandomMode::Standard;
101+
// Cryptographic random mode - a cryptographically secure random number generator.
102+
// This is the default.
103+
self.mode = RandomMode::Crypto;
110104
self.is_initialized = true;
111105
}
112106
1 => {
113-
// Seeded random mode - the seed must be set via sending a u32 command after this one.
114-
self.mode = RandomMode::Seeded;
115-
self.is_initialized = false;
116-
}
117-
2 => {
118-
// Cryptographic random mode - a cryptographically secure random number generator.
119-
self.mode = RandomMode::Crypto;
107+
// Standard mode - a PRNG derived from entropy.
108+
self.prng = Xoshiro256Plus::from_os_rng();
109+
self.mode = RandomMode::Pseudorandom;
120110
self.is_initialized = true;
121111
}
122112
_ => {
@@ -130,8 +120,8 @@ impl ComBusIO for RandomDevice {
130120
fn write_u32(&mut self, value: u32) -> DeviceResult<()> {
131121
let mut result = DeviceResult::Ok(());
132122

133-
if self.mode == RandomMode::Seeded {
134-
PRNG.with(|r| *r.borrow_mut() = Xoshiro256Plus::seed_from_u64(value as u64));
123+
if self.mode == RandomMode::Pseudorandom {
124+
self.prng = Xoshiro256Plus::seed_from_u64(value as u64);
135125

136126
// Indicate that the PRNG has been seeded and initialized.
137127
self.is_initialized = true;
@@ -149,21 +139,21 @@ impl ComBusIO for RandomDevice {
149139

150140
#[cfg(test)]
151141
mod tests_random_device {
152-
use crate::com_bus::com_bus_io::ComBusIO;
142+
use crate::com_bus::{com_bus_io::ComBusIO, random_device::RandomMode};
153143

154144
use super::RandomDevice;
155145

156-
/// Test the PRNG to ensure it is non-repeating.
146+
/// Test the cryptographic RNG to ensure it is non-repeating.
157147
#[test]
158-
fn test_prng() {
159-
// By default, the generator should use an entropy-seeded PRNG.
160-
let device = RandomDevice::default();
148+
fn test_crng() {
149+
// By default, the generator should use an entropy-seeded RNG.
150+
let mut device = RandomDevice::default();
161151
let mut sequence_1 = vec![];
162152
for _ in 0..1000 {
163153
sequence_1.push(device.read_u32().expect(""));
164154
}
165155

166-
let device = RandomDevice::default();
156+
let mut device = RandomDevice::default();
167157
let mut sequence_2 = vec![];
168158
for _ in 0..1000 {
169159
sequence_2.push(device.read_u32().expect(""));
@@ -176,7 +166,7 @@ mod tests_random_device {
176166
#[test]
177167
fn test_seeded_prng() {
178168
let mut device = RandomDevice::default();
179-
_ = device.write_u8(0x1);
169+
_ = device.write_u8(RandomMode::Pseudorandom as u8);
180170
_ = device.write_u32(0xdeadbeef);
181171

182172
let mut sequence_1 = vec![];
@@ -185,7 +175,7 @@ mod tests_random_device {
185175
}
186176

187177
let mut device = RandomDevice::default();
188-
_ = device.write_u8(0x1);
178+
_ = device.write_u8(RandomMode::Pseudorandom as u8);
189179
_ = device.write_u32(0xdeadbeef);
190180

191181
let mut sequence_2 = vec![];

redox-core/src/com_bus/test_debug_device.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,23 @@ impl Default for TestDebugDevice {
2727
}
2828

2929
impl ComBusIO for TestDebugDevice {
30-
fn read_u8(&self) -> DeviceResult<u8> {
30+
fn read_u8(&mut self) -> DeviceResult<u8> {
3131
if self.should_fail[0] {
3232
return DeviceResult::Err(DeviceError::OperationNotSupported);
3333
}
3434

3535
Ok(u8::MAX)
3636
}
3737

38-
fn read_u32(&self) -> DeviceResult<u32> {
38+
fn read_u32(&mut self) -> DeviceResult<u32> {
3939
if self.should_fail[1] {
4040
return DeviceResult::Err(DeviceError::OperationNotSupported);
4141
}
4242

4343
Ok(u32::MAX)
4444
}
4545

46-
fn read_f32(&self) -> DeviceResult<f32> {
46+
fn read_f32(&mut self) -> DeviceResult<f32> {
4747
if self.should_fail[2] {
4848
return DeviceResult::Err(DeviceError::OperationNotSupported);
4949
}

0 commit comments

Comments
 (0)