netstack3_base/
rng.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Base types and traits for generating random numbers in netstack.
//!
//! NOTE:
//! - Code in netstack3 is required to only obtain random values through an
//!   [`RngContext`]. This allows a deterministic RNG to be provided when useful
//!   (for example, in tests).
//! - The CSPRNG requirement exists so that random values produced within the
//!   network stack are not predictable by outside observers. This helps prevent
//!   certain kinds of fingerprinting and denial of service attacks.

use rand::{CryptoRng, RngCore};

/// A context that provides a random number generator (RNG).
pub trait RngContext {
    // NB: If the CSPRNG requirement becomes a performance problem,
    // introduce a second, non-cryptographically secure, RNG.

    /// The random number generator (RNG) provided by this `RngContext`.
    ///
    /// The provided RNG must be cryptographically secure, and users may rely on
    /// that property for their correctness and security.
    type Rng<'a>: RngCore + CryptoRng
    where
        Self: 'a;

    /// Gets the random number generator (RNG).
    fn rng(&mut self) -> Self::Rng<'_>;
}

#[cfg(any(test, feature = "testutils"))]
pub(crate) mod testutil {
    use alloc::sync::Arc;

    use rand::{CryptoRng, Rng as _, RngCore, SeedableRng};
    use rand_xorshift::XorShiftRng;

    use crate::sync::Mutex;
    use crate::RngContext;

    /// A wrapper which implements `RngCore` and `CryptoRng` for any `RngCore`.
    ///
    /// This is used to satisfy [`RngContext`]'s requirement that the
    /// associated `Rng` type implements `CryptoRng`.
    ///
    /// # Security
    ///
    /// This is obviously insecure. Don't use it except in testing!
    #[derive(Clone, Debug)]
    pub struct FakeCryptoRng<R = XorShiftRng>(Arc<Mutex<R>>);

    impl Default for FakeCryptoRng<XorShiftRng> {
        fn default() -> FakeCryptoRng<XorShiftRng> {
            FakeCryptoRng::new_xorshift(12957992561116578403)
        }
    }

    impl FakeCryptoRng<XorShiftRng> {
        /// Creates a new [`FakeCryptoRng<XorShiftRng>`] from a seed.
        pub fn new_xorshift(seed: u128) -> FakeCryptoRng<XorShiftRng> {
            Self(Arc::new(Mutex::new(new_rng(seed))))
        }

        /// Returns a deep clone of this RNG, copying the current RNG state.
        pub fn deep_clone(&self) -> Self {
            Self(Arc::new(Mutex::new(self.0.lock().clone())))
        }

        /// Creates `iterations` fake RNGs.
        ///
        /// `with_fake_rngs` will create `iterations` different
        /// [`FakeCryptoRng`]s and call the function `f` for each one of them.
        ///
        /// This function can be used for tests that weed out weirdness that can
        /// happen with certain random number sequences.
        pub fn with_fake_rngs<F: Fn(Self)>(iterations: u128, f: F) {
            for seed in 0..iterations {
                f(FakeCryptoRng::new_xorshift(seed))
            }
        }
    }

    impl<R: RngCore> RngCore for FakeCryptoRng<R> {
        fn next_u32(&mut self) -> u32 {
            self.0.lock().next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.0.lock().next_u64()
        }
        fn fill_bytes(&mut self, dest: &mut [u8]) {
            self.0.lock().fill_bytes(dest)
        }
        fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
            self.0.lock().try_fill_bytes(dest)
        }
    }

    impl<R: RngCore> CryptoRng for FakeCryptoRng<R> {}

    impl<R: SeedableRng> SeedableRng for FakeCryptoRng<R> {
        type Seed = R::Seed;

        fn from_seed(seed: Self::Seed) -> Self {
            Self(Arc::new(Mutex::new(R::from_seed(seed))))
        }
    }

    impl<R: RngCore> RngContext for FakeCryptoRng<R> {
        type Rng<'a>
            = &'a mut Self
        where
            Self: 'a;

        fn rng(&mut self) -> Self::Rng<'_> {
            self
        }
    }

    /// Create a new deterministic RNG from a seed.
    pub fn new_rng(mut seed: u128) -> XorShiftRng {
        if seed == 0 {
            // XorShiftRng can't take 0 seeds
            seed = 1;
        }
        XorShiftRng::from_seed(seed.to_ne_bytes())
    }

    /// Invokes a function multiple times with different RNG seeds.
    pub fn run_with_many_seeds<F: FnMut(u128)>(mut f: F) {
        // Arbitrary seed.
        let mut rng = new_rng(0x0fe50fae6c37593d71944697f1245847);
        for _ in 0..64 {
            f(rng.gen());
        }
    }
}