lorawan_device/rng.rs
1//! RNG based on the `wyrand` pseudorandom number generator.
2//!
3//! This crate uses the random number generator for exactly two things:
4//!
5//! * Generating DevNonces for join requests
6//! * Selecting random channels when transmitting uplinks.
7//!
8//! The good news is that both these operations don't require true
9//! cryptographic randomness. In fact, in both cases, we don't even care about
10//! predictability! A pseudorandom number generator initialized with a seed
11//! generated by a true random number generator is plenty enough:
12//!
13//! * DevNonces must only be unique with a low chance of collision.
14//! The 1.0.4 LoRaWAN spec even explicitly requires the DevNonces to be
15//! a sequence of incrementing integers, which is obviously predictable.
16//! * No one cares if the channel selected for the next uplink is predictable,
17//! as long as the channel selection yields an uniform distribution.
18//!
19//! By providing a PRNG `RngCore` implementation, we enable the crate users the
20//! flexibility of choosing whether they want to provide their own RNG, or just
21//! a seed to instantiate this PRNG to generate the random numbers for them.
22
23use fastrand::Rng;
24use rand_core::RngCore;
25
26#[derive(Clone)]
27/// A pseudorandom number generator utilizing Wyrand algorithm via
28/// the `fastrand` crate.
29pub struct Prng(Rng);
30
31impl Prng {
32 pub(crate) fn new(seed: u64) -> Self {
33 Self(Rng::with_seed(seed))
34 }
35}
36
37impl RngCore for Prng {
38 fn next_u32(&mut self) -> u32 {
39 self.0.u32(..)
40 }
41
42 fn next_u64(&mut self) -> u64 {
43 self.0.u64(..)
44 }
45
46 fn fill_bytes(&mut self, dest: &mut [u8]) {
47 rand_core::impls::fill_bytes_via_next(self, dest)
48 }
49
50 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
51 self.fill_bytes(dest);
52 Ok(())
53 }
54}