10
10
11
11
//! Entropy generator, or wrapper around external generators
12
12
13
+ use core:: fmt;
14
+ use std:: rc:: Rc ;
15
+ use std:: sync:: { Once , Mutex , MutexGuard , ONCE_INIT } ;
16
+
13
17
use rand_core:: { RngCore , CryptoRng , Error , ErrorKind , impls} ;
14
18
#[ allow( unused) ]
15
19
use rngs;
@@ -30,6 +34,8 @@ use rngs;
30
34
/// jitter); for better performance it is common to seed a local PRNG from
31
35
/// external entropy then primarily use the local PRNG ([`thread_rng`] is
32
36
/// provided as a convenient, local, automatically-seeded CSPRNG).
37
+ ///
38
+ /// `EntropyRng` instances are explicitly not `Send` or `Sync`.
33
39
///
34
40
/// # Panics
35
41
///
@@ -48,6 +54,7 @@ use rngs;
48
54
#[ derive( Debug ) ]
49
55
pub struct EntropyRng {
50
56
source : Source ,
57
+ _dummy : Rc < ( ) > // enforce !Send
51
58
}
52
59
53
60
#[ derive( Debug ) ]
@@ -65,7 +72,7 @@ impl EntropyRng {
65
72
/// those are done on first use. This is done to make `new` infallible,
66
73
/// and `try_fill_bytes` the only place to report errors.
67
74
pub fn new ( ) -> Self {
68
- EntropyRng { source : Source :: None }
75
+ EntropyRng { source : Source :: None , _dummy : Rc :: new ( ( ) ) }
69
76
}
70
77
}
71
78
@@ -241,8 +248,121 @@ impl EntropySource for Os {
241
248
) ) ) ) ]
242
249
type Os = NoSource ;
243
250
251
+ // TODO: impl !Send. Currently only possible on nightly; instead we use a dummy field in `EntropyRng`.
252
+ #[ derive( Clone ) ]
253
+ struct Custom {
254
+ source : & ' static CustomEntropySource ,
255
+ param : u64 ,
256
+ }
257
+
258
+ impl fmt:: Debug for Custom {
259
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
260
+ write ! ( f, "Custom {{ ... }}" )
261
+ }
262
+ }
263
+
264
+ #[ test]
265
+ fn test_size ( ) {
266
+ use core:: mem:: size_of;
267
+ println ! ( "Size of Custom: {}" , size_of:: <Custom >( ) ) ;
268
+ assert ! ( size_of:: <Custom >( ) <= size_of:: <rngs:: JitterRng >( ) ) ;
269
+ }
270
+
271
+ /// Properties of a custom entropy source.
272
+ pub trait CustomEntropySource {
273
+ /// Name of this source
274
+ fn name ( & self ) -> & ' static str ;
275
+
276
+ /// Is this source available?
277
+ ///
278
+ /// The default implementation returns `true`.
279
+ fn is_available ( & self ) -> bool { true }
280
+
281
+ /// Prepare the entropy source for use.
282
+ ///
283
+ /// This is always called before `fill` on each thread. This may be called
284
+ /// multiple times.
285
+ ///
286
+ /// A `u64` parameter may be returned, which is passed to `fill` when
287
+ /// called, and is considered `!Send` (i.e. is never passed to a different
288
+ /// thread).
289
+ fn init ( & self ) -> Result < u64 , Error > ;
290
+
291
+ /// Fill `dest` with random data from the entropy source.
292
+ ///
293
+ /// The `u64` parameter from `init` is passed.
294
+ fn fill ( & self , param : & mut u64 , dest : & mut [ u8 ] ) -> Result < ( ) , Error > ;
295
+ }
296
+
297
+ struct CustomNoSource ;
298
+ impl CustomEntropySource for CustomNoSource {
299
+ fn name ( & self ) -> & ' static str {
300
+ "no source"
301
+ }
302
+
303
+ fn is_available ( & self ) -> bool { false }
304
+
305
+ fn init ( & self ) -> Result < u64 , Error > {
306
+ unreachable ! ( )
307
+ }
244
308
245
- type Custom = NoSource ;
309
+ fn fill ( & self , _: & mut u64 , _: & mut [ u8 ] ) -> Result < ( ) , Error > {
310
+ unreachable ! ( )
311
+ }
312
+ }
313
+
314
+ // TODO: remove outer Option when `Mutex::new(&...)` is a constant expression
315
+ static mut CUSTOM_SOURCE : Option < Mutex < & CustomEntropySource > > = None ;
316
+ static CUSTOM_SOURCE_ONCE : Once = ONCE_INIT ;
317
+
318
+ fn access_custom_entropy ( ) -> MutexGuard < ' static , & ' static CustomEntropySource > {
319
+ CUSTOM_SOURCE_ONCE . call_once ( || {
320
+ unsafe { CUSTOM_SOURCE = Some ( Mutex :: new ( & CustomNoSource ) ) }
321
+ } ) ;
322
+ let mutex = unsafe { CUSTOM_SOURCE . as_ref ( ) . unwrap ( ) } ;
323
+ mutex. lock ( ) . unwrap ( )
324
+ }
325
+
326
+ fn get_custom_entropy ( ) -> & ' static CustomEntropySource {
327
+ * access_custom_entropy ( )
328
+ }
329
+
330
+ /// Specify a custom entropy source.
331
+ ///
332
+ /// This must be a static reference to an object implementing the
333
+ /// `CustomEntropySource` trait.
334
+ pub fn set_custom_entropy ( source : & ' static CustomEntropySource ) {
335
+ let mut guard = access_custom_entropy ( ) ;
336
+ * guard = source;
337
+ }
338
+
339
+ impl EntropySource for Custom {
340
+ fn name ( ) -> & ' static str {
341
+ get_custom_entropy ( ) . name ( )
342
+ }
343
+
344
+ /// Is this source available?
345
+ ///
346
+ /// The default implementation returns `true`.
347
+ fn is_available ( ) -> bool {
348
+ get_custom_entropy ( ) . is_available ( )
349
+ }
350
+
351
+ /// Create an instance
352
+ fn new ( ) -> Result < Self , Error > where Self : Sized {
353
+ let source = get_custom_entropy ( ) ;
354
+ let param = source. init ( ) ?;
355
+ Ok ( Custom {
356
+ source,
357
+ param,
358
+ } )
359
+ }
360
+
361
+ /// Fill `dest` with random data from the entropy source
362
+ fn fill ( & mut self , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
363
+ self . source . fill ( & mut self . param , dest)
364
+ }
365
+ }
246
366
247
367
248
368
#[ cfg( not( target_arch = "wasm32" ) ) ]
@@ -276,4 +396,21 @@ mod test {
276
396
let n = ( rng. next_u32 ( ) ^ rng. next_u32 ( ) ) . count_ones ( ) ;
277
397
assert ! ( n >= 2 ) ; // p(failure) approx 1e-7
278
398
}
399
+
400
+ #[ test]
401
+ fn test_custom_entropy ( ) {
402
+ struct FakeEntropy ;
403
+ impl CustomEntropySource for FakeEntropy {
404
+ fn name ( & self ) -> & ' static str { "fake entropy" }
405
+ fn init ( & self ) -> Result < u64 , Error > { Ok ( 0 ) }
406
+ fn fill ( & self , _: & mut u64 , dest : & mut [ u8 ] ) -> Result < ( ) , Error > {
407
+ for x in dest { * x = 0 }
408
+ Ok ( ( ) )
409
+ }
410
+ }
411
+ set_custom_entropy ( & FakeEntropy ) ;
412
+ let mut entropy = EntropyRng :: new ( ) ;
413
+ // we can't properly test this because we can't disable `OsRng`
414
+ assert ! ( entropy. next_u64( ) != 1 ) ;
415
+ }
279
416
}
0 commit comments