-
The documentation states “Cryptographic security. […] OsRng […] The other random number generators provided by this module are not suitable for such purposes”. However, at least the chacha-based RNG should be suitable, and anyway a cryptographically safe non-OsRng RNG definitely needs to be provided, since reading from /dev/urandom is likely too slow due to kernel overhead.
-
The RNG returned by thread_rng() should be guaranteed to be cryptographically secure, since that’s the safe default. An unsafe_thread_rng() could also be provided that is faster but cryptographically insecure. This mimics the Rust policy on hash table where the default is secure (note that misusing an insecure RNG is catastrophic, while misusing an insecure hash table merely leads to denial of service).
-
Maybe there should be a global_rng() / GlobalRng that would be the same as thread_rng() / ThreadRng except global and thus using an Arc<Mutex<<…>> instead of an Rc<RefCell<…>>. This could then be used to initialize the per-thread RNGs without requiring reading /dev/urandom. When the reseeding threshold is reached on a thread_rng, the global rng also needs to be reseeding before using it to reseed the thread rng, to preserve current behavior.
-
Speaking of the reseeding threshold, it is unnecessary if the RNG algorithm is assumed to be cryptographically strong and the seed kept secret, and if that algorithm is broken or if something can inspect the seed, it’s not clear if reseeding would do any good as the attack could often just be repeated, and 32KB of predictable random data is often going to be enough to catastrophically compromise the system. Could still keep it for extra safety, but should perhaps at least set the threshold based on benchmarking to a value that causes minimal overhead (which might already be the case, not sure).
-
There seems to be an inconsistency with the Rand implementations for f32 and f64: for all other types, rand picks from an uniform distribution over all possible values, but for f32 and f64, it instead (abstractly) picks from the uniform distribution on [0, 1) and then rounds to the nearest float. I think it might make sense to either remove the implementations of Rand for f32 and f64 or make them generate an u32/u64 and bitcast, and move the current Rand for f32/f64 implementation to HalfOpen01<f32/f64>.
-
Is the Rand trait needed at all? Could it be removed in favor of using Deserialize and a serde deserializer that just generates random data, thus greatly simplifying the Rand crate and getting random generation for free for any deserializable type? Looking at serde it seems this might be possible, but not completely sure.
-
How about an AES-based RNG? Many CPUs have hardware AES acceleration, so it might be faster than anything else on those, while obviously being cryptographically secure (with proper constant time implementation).
-
Maybe there should be some support for virtio-rng when running in a VM without a kernel, but that might be out of scope since it’s a non-standard environment. However, allowing external crates to replace or implement OsRng might be a good idea for this reason.
-
RNGs, especially cryptographically secure ones, should be designed, if possible, so that retrieving the seed doesn’t allow to determine past random numbers, but only future ones, and whether this is the case should be explicitly documented for the RNG
1 Like