1
1
use rand:: { rngs:: OsRng , Rng , SeedableRng , TryRngCore } ;
2
2
use rand_xoshiro:: Xoshiro256Plus ;
3
- use std:: cell:: RefCell ;
4
3
5
4
use super :: {
6
5
com_bus_io:: ComBusIO ,
7
6
device_error:: { DeviceError , DeviceResult } ,
8
7
} ;
9
8
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 ) ]
15
10
#[ derive( PartialEq , Eq ) ]
16
11
enum RandomMode {
17
12
Crypto ,
18
- Seeded ,
19
- Standard ,
13
+ Pseudorandom ,
20
14
}
21
15
22
- /// The seedable random generator chip !
16
+ /// The random number generator device !
23
17
pub struct RandomDevice {
24
18
/// Has the random number generator been initialized?
25
19
is_initialized : bool ,
26
20
/// The random generator mode currently being used.
27
21
mode : RandomMode ,
22
+ /// The pseudorandom number generator.
23
+ prng : Xoshiro256Plus ,
24
+ /// The Cryptographically secure RNG generator.
25
+ crng : OsRng ,
28
26
}
29
27
30
28
impl RandomDevice {
31
29
pub fn new ( ) -> Self {
32
30
Self {
33
31
// By default we initialize the random number generator using entropy.
34
32
is_initialized : true ,
35
- mode : RandomMode :: Standard ,
33
+ mode : RandomMode :: Crypto ,
34
+ prng : Xoshiro256Plus :: from_os_rng ( ) ,
35
+ crng : OsRng ,
36
36
}
37
37
}
38
38
}
@@ -44,57 +44,51 @@ impl Default for RandomDevice {
44
44
}
45
45
46
46
impl ComBusIO for RandomDevice {
47
- fn read_u8 ( & self ) -> DeviceResult < u8 > {
47
+ fn read_u8 ( & mut self ) -> DeviceResult < u8 > {
48
48
if !self . is_initialized {
49
49
return DeviceResult :: Err ( DeviceError :: Misconfigured ) ;
50
50
}
51
51
52
52
Ok ( match self . mode {
53
- RandomMode :: Crypto => CRNG . with ( |r| {
53
+ RandomMode :: Crypto => {
54
54
let mut arr: [ u8 ; 1 ] = [ 0 ; 1 ] ;
55
- r . borrow_mut ( )
55
+ self . crng
56
56
. try_fill_bytes ( & mut arr)
57
- . expect ( "failed to get bytes " ) ;
57
+ . expect ( "failed to get u8 " ) ;
58
58
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 > ( ) ,
62
61
} )
63
62
}
64
63
65
- fn read_u32 ( & self ) -> DeviceResult < u32 > {
64
+ fn read_u32 ( & mut self ) -> DeviceResult < u32 > {
66
65
if !self . is_initialized {
67
66
return DeviceResult :: Err ( DeviceError :: Misconfigured ) ;
68
67
}
69
68
70
69
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 > ( ) ,
80
72
} )
81
73
}
82
74
83
- fn read_f32 ( & self ) -> DeviceResult < f32 > {
75
+ fn read_f32 ( & mut self ) -> DeviceResult < f32 > {
84
76
if !self . is_initialized {
85
77
return DeviceResult :: Err ( DeviceError :: Misconfigured ) ;
86
78
}
87
79
88
80
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 > ( ) ,
98
92
} )
99
93
}
100
94
@@ -104,19 +98,15 @@ impl ComBusIO for RandomDevice {
104
98
// The instruction indicating the type of random number generator to be used.
105
99
match value {
106
100
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 ;
110
104
self . is_initialized = true ;
111
105
}
112
106
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 ;
120
110
self . is_initialized = true ;
121
111
}
122
112
_ => {
@@ -130,8 +120,8 @@ impl ComBusIO for RandomDevice {
130
120
fn write_u32 ( & mut self , value : u32 ) -> DeviceResult < ( ) > {
131
121
let mut result = DeviceResult :: Ok ( ( ) ) ;
132
122
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 ) ;
135
125
136
126
// Indicate that the PRNG has been seeded and initialized.
137
127
self . is_initialized = true ;
@@ -149,21 +139,21 @@ impl ComBusIO for RandomDevice {
149
139
150
140
#[ cfg( test) ]
151
141
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 } ;
153
143
154
144
use super :: RandomDevice ;
155
145
156
- /// Test the PRNG to ensure it is non-repeating.
146
+ /// Test the cryptographic RNG to ensure it is non-repeating.
157
147
#[ 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 ( ) ;
161
151
let mut sequence_1 = vec ! [ ] ;
162
152
for _ in 0 ..1000 {
163
153
sequence_1. push ( device. read_u32 ( ) . expect ( "" ) ) ;
164
154
}
165
155
166
- let device = RandomDevice :: default ( ) ;
156
+ let mut device = RandomDevice :: default ( ) ;
167
157
let mut sequence_2 = vec ! [ ] ;
168
158
for _ in 0 ..1000 {
169
159
sequence_2. push ( device. read_u32 ( ) . expect ( "" ) ) ;
@@ -176,7 +166,7 @@ mod tests_random_device {
176
166
#[ test]
177
167
fn test_seeded_prng ( ) {
178
168
let mut device = RandomDevice :: default ( ) ;
179
- _ = device. write_u8 ( 0x1 ) ;
169
+ _ = device. write_u8 ( RandomMode :: Pseudorandom as u8 ) ;
180
170
_ = device. write_u32 ( 0xdeadbeef ) ;
181
171
182
172
let mut sequence_1 = vec ! [ ] ;
@@ -185,7 +175,7 @@ mod tests_random_device {
185
175
}
186
176
187
177
let mut device = RandomDevice :: default ( ) ;
188
- _ = device. write_u8 ( 0x1 ) ;
178
+ _ = device. write_u8 ( RandomMode :: Pseudorandom as u8 ) ;
189
179
_ = device. write_u32 ( 0xdeadbeef ) ;
190
180
191
181
let mut sequence_2 = vec ! [ ] ;
0 commit comments