mx3/
hasher.rs

1use core::fmt::{Debug, Formatter};
2use core::hash::Hasher;
3
4/// Hasher for computing a hash digest of a stream of bytes.
5///
6/// This hasher is *not* cryptographically secure.
7///
8/// Due the to the reference design not specifying unbounded streams,
9/// the output is not guaranteed to be deterministic between versions of this
10/// crate.
11///
12/// If you are simply hashing a slice,
13/// consider using the shorter [`crate::v3::hash()`] function instead.
14///
15/// If you need a stable stream hasher, check the source code of
16/// this hasher for inspiration to design your own streaming hash function.
17#[derive(Clone)]
18pub struct Mx3Hasher {
19    seed: u64,
20    state: u64,
21    buf: [u8; 1024],
22    buf_filled: usize,
23}
24
25impl Mx3Hasher {
26    /// Construct a hasher with the given seed for a stream of bytes.
27    ///
28    /// This constructor is not compatible with the reference design due to
29    /// the length of the stream being unknown.
30    pub fn new(seed: u64) -> Self {
31        Self {
32            seed,
33            state: crate::v3::mix(seed),
34            buf: [0u8; 1024],
35            buf_filled: 0,
36        }
37    }
38}
39
40impl Hasher for Mx3Hasher {
41    fn write(&mut self, bytes: &[u8]) {
42        let mut remain = bytes;
43
44        while !remain.is_empty() {
45            let amount = bytes.len().min(self.buf.len() - self.buf_filled);
46            let (left, right) = bytes.split_at(amount);
47
48            self.buf[self.buf_filled..self.buf_filled + amount].copy_from_slice(left);
49            self.buf_filled += amount;
50
51            debug_assert!(self.buf_filled <= self.buf.len());
52
53            if self.buf_filled == self.buf.len() {
54                self.state ^= crate::v3::hash(&self.buf, self.seed);
55                self.buf_filled = 0;
56            }
57
58            remain = right;
59        }
60    }
61
62    fn finish(&self) -> u64 {
63        let mut output = self.state;
64
65        if self.buf_filled > 0 {
66            output ^= crate::v3::hash(&self.buf[0..self.buf_filled], self.seed);
67        }
68
69        output
70    }
71}
72
73impl Debug for Mx3Hasher {
74    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
75        write!(f, "Mx3Hasher {{...}}")
76    }
77}
78
79impl Default for Mx3Hasher {
80    fn default() -> Self {
81        Self::new(1)
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88
89    #[test]
90    fn test_mx3hasher() {
91        let input = b"abcdefghijklmnopqrstuvwxyz";
92        let mut hasher = Mx3Hasher::new(123456789);
93
94        for _ in 0..100 {
95            hasher.write(input);
96        }
97
98        assert_eq!(hasher.finish(), 8878623092709932526);
99    }
100
101    #[test]
102    fn test_mx3hasher_empty() {
103        let input = b"";
104        let mut hasher = Mx3Hasher::new(123456789);
105        hasher.write(input);
106        assert_eq!(hasher.finish(), 0x95bd1de6327dae0a);
107    }
108
109    #[test]
110    fn test_debug() {
111        let hasher = Mx3Hasher::default();
112        format_args!("{:?}", hasher);
113    }
114
115    #[test]
116    fn test_clone() {
117        let mut hasher = Mx3Hasher::default();
118        hasher.write(b"abc");
119
120        let hasher2 = hasher.clone();
121
122        assert_eq!(hasher.finish(), hasher2.finish());
123    }
124}