skrillax_security/
count.rs

1use std::cmp::max;
2
3fn generate_value(mut value: u32) -> u32 {
4    for _ in 0..32 {
5        let mut v = value;
6        v = (v >> 2) ^ value;
7        v = (v >> 2) ^ value;
8        v = (v >> 1) ^ value;
9        v = (v >> 1) ^ value;
10        v = (v >> 1) ^ value;
11        value = (((value >> 1) | (value << 31)) & (!1)) | (v & 1);
12    }
13    value
14}
15
16/// A cryptographic counter for verifying message order.
17///
18/// To verify that messages arrive in the correct order and aren't reused at a later time, you can
19/// use a cryptographic counter. It is essentially a PRNG that always returns a single byte.
20/// Similarly to a PRNG, we need to provide a seed before we can generate values.
21///
22/// ```
23/// # use rand::random;
24/// # use skrillax_security::MessageCounter;
25/// let mut counter = MessageCounter::new(random::<u32>());
26/// let first = counter.next_byte();
27/// let second = counter.next_byte();
28/// assert_ne!(first, second);
29/// ```
30pub struct MessageCounter {
31    seeds: [u8; 3],
32}
33
34impl MessageCounter {
35    /// Creates a new counter with the given seed.
36    pub fn new(seed: u32) -> MessageCounter {
37        let mut1 = generate_value(seed);
38        let mut2 = generate_value(mut1);
39        let mut3 = generate_value(mut2);
40        let mut4 = generate_value(mut3);
41
42        let byte1 = (mut1 as u8) ^ (mut2 as u8);
43        let byte1 = max(byte1, 1);
44
45        let byte2 = (mut3 as u8) ^ (mut4 as u8);
46        let byte2 = max(byte2, 1);
47
48        MessageCounter {
49            seeds: [byte1 ^ byte2, byte1, byte2],
50        }
51    }
52
53    /// Generates the next byte of the counter.
54    ///
55    /// Generates the next byte by advancing the internal state according to the generation
56    /// algorithm.
57    pub fn next_byte(&mut self) -> u8 {
58        let value = (self.seeds[2] as u32 * (!self.seeds[0] as u32 + self.seeds[1] as u32)) as u8;
59        self.seeds[0] = value ^ value >> 4;
60
61        self.seeds[0]
62    }
63}
64
65#[cfg(test)]
66mod test {
67    use super::*;
68
69    #[test]
70    fn test_sniffed() {
71        let mut counter = MessageCounter::new(0x7c);
72        assert_eq!(counter.next_byte(), 0xb7);
73    }
74}