1
//! Pseudorandom number utilities for HashX's program generator
2
//!
3
//! HashX uses pseudorandom numbers to make individual decisions in the program
4
//! generation process. The program generator consumes u8 and u32 values that
5
//! use a shared u64 generator, implemented using SipHash1,3.
6
//!
7
//! We use the [`Rng`] trait for this underlying u64 generator,
8
//! allowing substitute random number generators for testing or for special
9
//! purposes that don't require compatibility with HashX proper.
10
//!
11
//! The stateful u8 and u32 layer comes from this module's [`RngBuffer`].
12
//! It's important for the u8 and u32 queues to share a common generator.
13
//! The order of dequeueing u8 items vs u32 items intentionally modifies the
14
//! assignment of particular u64 [`Rng`] values to the two queues.
15

            
16
use std::convert::Infallible;
17

            
18
use crate::siphash::{SipState, siphash13_ctr};
19
use arrayvec::ArrayVec;
20
use rand_core::{Rng, TryRng};
21

            
22
/// Wrap a [`Rng`] implementation for fast `u8` and `u32` output.
23
///
24
/// This maintains small queues for each data type: up to one `u32` and up to
25
/// 7 bytes. The queueing behavior matches conventions required by HashX:
26
/// The underlying `u64` values are always generated lazily, and component
27
/// values are extracted in big endian order.
28
#[derive(Debug)]
29
pub(crate) struct RngBuffer<'a, T: Rng> {
30
    /// Inner [`Rng`] implementation
31
    inner: &'a mut T,
32
    /// Buffer of remaining u8 values from breaking up a u64
33
    u8_vec: ArrayVec<u8, 7>,
34
    /// Up to one buffered u32 value
35
    u32_opt: Option<u32>,
36
}
37

            
38
impl<'a, T: Rng> RngBuffer<'a, T> {
39
    /// Construct a new empty buffer around a [`Rng`] implementation.
40
    ///
41
    /// No actual random numbers will be generated until the first call to
42
    /// [`Self::next_u8`] or [`Self::next_u32`].
43
    #[inline(always)]
44
10084
    pub(crate) fn new(rng: &'a mut T) -> Self {
45
10084
        Self {
46
10084
            inner: rng,
47
10084
            u8_vec: Default::default(),
48
10084
            u32_opt: None,
49
10084
        }
50
10084
    }
51

            
52
    /// Request 32 bits from the buffered random number generator.
53
    ///
54
    /// If we have buffered data stored, returns that. If not,
55
    /// requests 64 bits from the [`Rng`] and saves half for later.
56
    #[inline(always)]
57
10416246
    pub(crate) fn next_u32(&mut self) -> u32 {
58
10416246
        let previous = self.u32_opt;
59
10416246
        match previous {
60
5205638
            Some(value) => {
61
5205638
                self.u32_opt = None;
62
5205638
                value
63
            }
64
            None => {
65
5210608
                let value = self.inner.next_u64();
66
5210608
                self.u32_opt = Some(value as u32);
67
5210608
                (value >> 32) as u32
68
            }
69
        }
70
10416246
    }
71

            
72
    /// Request 8 bits from the buffered random number generator.
73
    ///
74
    /// If we have buffered data stored, returns that. If not,
75
    /// requests 64 bits from the [`Rng`] and saves 7 bytes for later.
76
    #[inline(always)]
77
4259896
    pub(crate) fn next_u8(&mut self) -> u8 {
78
4259896
        let value = self.u8_vec.pop();
79
4259896
        match value {
80
3722349
            Some(value) => value,
81
            None => {
82
                // Little endian (reversed) order here,
83
                // because we dequeue items from the end of the Vec.
84
537547
                let bytes = self.inner.next_u64().to_le_bytes();
85
537547
                let (last, saved) = bytes.split_last().expect("u64 has nonzero length");
86
537547
                self.u8_vec
87
537547
                    .try_extend_from_slice(saved)
88
537547
                    .expect("slice length correct");
89
537547
                *last
90
            }
91
        }
92
4259896
    }
93
}
94

            
95
/// HashX-style random number generator built on SipHash1,3
96
///
97
/// This is an implementation of [`Rng`] using SipHash1,3 as
98
/// the 64-bit PRNG layer needed by HashX's program generator.
99
#[derive(Debug, Clone)]
100
pub struct SipRand {
101
    /// SipHash state vector used as input to SipHash1,3 in counter mode
102
    key: SipState,
103
    /// Next unused counter value
104
    counter: u64,
105
}
106

            
107
impl SipRand {
108
    /// Build a new SipHash random number generator.
109
    ///
110
    /// The internal SipHash1,3 generator is initialized to a supplied
111
    /// internal state, and the counter is reset to zero.
112
    #[inline(always)]
113
10084
    pub fn new(key: SipState) -> Self {
114
10084
        Self::new_with_counter(key, 0)
115
10084
    }
116

            
117
    /// Build a new [`SipRand`] with a specific initial counter value.
118
    #[inline(always)]
119
10084
    pub fn new_with_counter(key: SipState, counter: u64) -> Self {
120
10084
        Self { key, counter }
121
10084
    }
122
}
123

            
124
impl TryRng for SipRand {
125
    type Error = Infallible;
126

            
127
    /// Generate a full 64-bit random result using SipHash1,3.
128
5675786
    fn try_next_u64(&mut self) -> Result<u64, Infallible> {
129
5675786
        let value = siphash13_ctr(self.key, self.counter);
130
5675786
        self.counter += 1;
131
5675786
        Ok(value)
132
5675786
    }
133

            
134
    /// Return a 32-bit value by discarding the upper half of a 64-bit result.
135
    fn try_next_u32(&mut self) -> Result<u32, Infallible> {
136
        Ok(self.next_u64() as u32)
137
    }
138

            
139
    /// Fill `dest` with random data.
140
    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Infallible> {
141
        rand_core::utils::fill_bytes_via_next_word(dest, || Ok::<u64, Infallible>(self.next_u64()))
142
    }
143
}
144

            
145
#[cfg(test)]
146
mod test {
147
    use super::{RngBuffer, SipRand, SipState};
148

            
149
    #[test]
150
    fn rng_vectors() {
151
        // Check against pseudorandom number streams seen during tor unit tests
152

            
153
        let (key0, _key1) = SipState::pair_from_seed(b"abc");
154
        let mut rng_inner = SipRand::new(key0);
155
        let mut rng = RngBuffer::new(&mut rng_inner);
156

            
157
        #[derive(Debug, PartialEq)]
158
        enum Value {
159
            U32(u32),
160
            U8(u8),
161
        }
162

            
163
        let expected = vec![
164
            Value::U32(0xf695edd0),
165
            Value::U32(0x2205449d),
166
            Value::U32(0x51c1ac51),
167
            Value::U32(0xcd19a7d1),
168
            Value::U8(0xad),
169
            Value::U32(0x79793a52),
170
            Value::U32(0xd965083d),
171
            Value::U8(0xf4),
172
            Value::U32(0x915e9969),
173
            Value::U32(0x7563b6e2),
174
            Value::U32(0x4e5a9d8b),
175
            Value::U32(0xef2bb9ce),
176
            Value::U8(0xcb),
177
            Value::U32(0xa4beee16),
178
            Value::U32(0x78fa6e6f),
179
            Value::U8(0x30),
180
            Value::U32(0xc321cb9f),
181
            Value::U32(0xbbf29635),
182
            Value::U32(0x919450f4),
183
            Value::U32(0xf3d8f358),
184
            Value::U8(0x3b),
185
            Value::U32(0x818a72e9),
186
            Value::U32(0x58225fcf),
187
            Value::U8(0x98),
188
            Value::U32(0x3fcb5059),
189
            Value::U32(0xaf5bcb70),
190
            Value::U8(0x14),
191
            Value::U32(0xd41e0326),
192
            Value::U32(0xe79aebc6),
193
            Value::U32(0xa348672c),
194
            Value::U8(0xcf),
195
            Value::U32(0x5d51b520),
196
            Value::U32(0x73afc36f),
197
            Value::U32(0x31348711),
198
            Value::U32(0xca25b040),
199
            Value::U32(0x3700c37b),
200
            Value::U8(0x62),
201
            Value::U32(0xf0d1d6a6),
202
            Value::U32(0xc1edebf3),
203
            Value::U8(0x9d),
204
            Value::U32(0x9bb1f33f),
205
            Value::U32(0xf1309c95),
206
            Value::U32(0x0797718a),
207
            Value::U32(0xa3bbcf7e),
208
            Value::U8(0x80),
209
            Value::U8(0x28),
210
            Value::U8(0xe9),
211
            Value::U8(0x2e),
212
            Value::U32(0xf5506289),
213
            Value::U32(0x97b46d7c),
214
            Value::U8(0x64),
215
            Value::U32(0xc99fe4ad),
216
            Value::U32(0x6e756189),
217
            Value::U8(0x54),
218
            Value::U8(0xf7),
219
            Value::U8(0x0f),
220
            Value::U8(0x7d),
221
            Value::U32(0x38c983eb),
222
        ];
223

            
224
        let mut actual = Vec::new();
225
        for item in &expected {
226
            match item {
227
                Value::U8(_) => actual.push(Value::U8(rng.next_u8())),
228
                Value::U32(_) => actual.push(Value::U32(rng.next_u32())),
229
            }
230
        }
231

            
232
        assert_eq!(expected, actual);
233
    }
234
}