Skip to main content

rns_embedded_core/
replay.rs

1#[derive(Debug, Clone, Copy, Eq, PartialEq)]
2pub struct ReplayWindow {
3    highest: Option<u64>,
4    seen: u64,
5}
6
7impl ReplayWindow {
8    pub fn new() -> Self {
9        Self { highest: None, seen: 0 }
10    }
11
12    pub fn highest(&self) -> Option<u64> {
13        self.highest
14    }
15
16    pub fn accept(&mut self, sequence: u64) -> bool {
17        match self.highest {
18            None => {
19                self.highest = Some(sequence);
20                self.seen = 1;
21                true
22            }
23            Some(highest) if sequence > highest => {
24                let shift = sequence.saturating_sub(highest);
25                self.seen = if shift >= 64 { 0 } else { self.seen << (shift as u32) };
26                self.highest = Some(sequence);
27                self.seen |= 1;
28                true
29            }
30            Some(highest) => {
31                let delta = highest - sequence;
32                if delta >= 64 {
33                    return false;
34                }
35                let bit = 1_u64 << (delta as u32);
36                if (self.seen & bit) != 0 {
37                    return false;
38                }
39                self.seen |= bit;
40                true
41            }
42        }
43    }
44}
45
46impl Default for ReplayWindow {
47    fn default() -> Self {
48        Self::new()
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::ReplayWindow;
55
56    #[test]
57    fn accepts_forward_and_rejects_duplicates() {
58        let mut window = ReplayWindow::new();
59        assert!(window.accept(10));
60        assert!(window.accept(11));
61        assert!(!window.accept(11));
62        assert!(window.accept(9));
63        assert!(!window.accept(9));
64    }
65
66    #[test]
67    fn rejects_far_old_sequences() {
68        let mut window = ReplayWindow::new();
69        assert!(window.accept(200));
70        assert!(!window.accept(100));
71    }
72}