metrohash/
metrohash128.rs

1use crate::utils::*;
2use std::hash::Hasher;
3use std::mem::MaybeUninit;
4use std::num::Wrapping;
5
6const K0: Wrapping<u64> = Wrapping(0xC83A91E1);
7const K1: Wrapping<u64> = Wrapping(0x8648DBDB);
8const K2: Wrapping<u64> = Wrapping(0x7BDEC03B);
9const K3: Wrapping<u64> = Wrapping(0x2F5870A5);
10
11pub struct MetroHash128 {
12    v: [Wrapping<u64>; 4],
13    b: [MaybeUninit<u64>; 4],
14    bytes: usize,
15}
16
17impl Default for MetroHash128 {
18    #[inline]
19    fn default() -> Self {
20        Self::new()
21    }
22}
23
24impl MetroHash128 {
25    #[inline]
26    pub fn new() -> MetroHash128 {
27        Self::with_seed(0)
28    }
29
30    #[inline]
31    pub fn with_seed(seed: u64) -> MetroHash128 {
32        let seed = Wrapping(seed);
33        MetroHash128 {
34            b: [MaybeUninit::uninit(); 4],
35            v: [
36                (seed - K0) * K3,
37                (seed + K1) * K2,
38                (seed + K0) * K2,
39                (seed - K1) * K3,
40            ],
41            bytes: 0,
42        }
43    }
44
45    #[inline]
46    pub fn finish128(&self) -> (u64, u64) {
47        unsafe {
48            // copy internal state
49            let mut v = self.v;
50
51            // finalize bulk loop, if used
52            if self.bytes >= 32 {
53                v[2] ^= rotate_right(((v[0] + v[3]) * K0) + v[1], 21) * K1;
54                v[3] ^= rotate_right(((v[1] + v[2]) * K1) + v[0], 21) * K0;
55                v[0] = v[0] ^ (rotate_right(((v[0] + v[2]) * K0) + v[3], 21) * K1);
56                v[1] = v[1] ^ (rotate_right(((v[1] + v[3]) * K1) + v[2], 21) * K0);
57            }
58
59            // process any self.bytes remaining in the input buffer
60            let mut ptr = self.b.as_ptr().cast::<u8>();
61            let end = ptr.add(self.bytes % 32);
62
63            if end.offset_from(ptr) >= 16 {
64                v[0] += read_u64(ptr) * K2;
65                ptr = ptr.add(8);
66                v[0] = rotate_right(v[0], 33) * K3;
67                v[1] += read_u64(ptr) * K2;
68                ptr = ptr.add(8);
69                v[1] = rotate_right(v[1], 33) * K3;
70                v[0] = v[0] ^ (rotate_right((v[0] * K2) + v[1], 45) * K1);
71                v[1] = v[1] ^ (rotate_right((v[1] * K3) + v[0], 45) * K0);
72            }
73
74            if end.offset_from(ptr) >= 8 {
75                v[0] += read_u64(ptr) * K2;
76                ptr = ptr.add(8);
77                v[0] = rotate_right(v[0], 33) * K3;
78                v[0] = v[0] ^ (rotate_right((v[0] * K2) + v[1], 27) * K1);
79            }
80
81            if end.offset_from(ptr) >= 4 {
82                v[1] += read_u32(ptr) * K2;
83                ptr = ptr.add(4);
84                v[1] = rotate_right(v[1], 33) * K3;
85                v[1] = v[1] ^ (rotate_right((v[1] * K3) + v[0], 46) * K0);
86            }
87
88            if end.offset_from(ptr) >= 2 {
89                v[0] += read_u16(ptr) * K2;
90                ptr = ptr.add(2);
91                v[0] = rotate_right(v[0], 33) * K3;
92                v[0] = v[0] ^ (rotate_right((v[0] * K2) + v[1], 22) * K1);
93            }
94
95            if end.offset_from(ptr) >= 1 {
96                v[1] += read_u8(ptr) * K2;
97                v[1] = rotate_right(v[1], 33) * K3;
98                v[1] = v[1] ^ (rotate_right((v[1] * K3) + v[0], 58) * K0);
99            }
100
101            v[0] = v[0] + (rotate_right((v[0] * K0) + v[1], 13));
102            v[1] = v[1] + (rotate_right((v[1] * K1) + v[0], 37));
103            v[0] = v[0] + (rotate_right((v[0] * K2) + v[1], 13));
104            v[1] = v[1] + (rotate_right((v[1] * K3) + v[0], 37));
105
106            (v[0].0, v[1].0)
107        }
108    }
109}
110
111impl Hasher for MetroHash128 {
112    #[inline]
113    fn write(&mut self, bytes: &[u8]) {
114        unsafe {
115            let mut ptr = bytes.as_ptr();
116            let end = ptr.add(bytes.len());
117            // input buffer may be partially filled
118            if self.bytes % 32 != 0 {
119                let mut fill = 32 - (self.bytes % 32);
120                if fill > bytes.len() {
121                    fill = bytes.len();
122                }
123
124                copy_32(
125                    ptr,
126                    self.b[0].as_mut_ptr().cast::<u8>().add(self.bytes % 32),
127                    fill,
128                );
129
130                ptr = ptr.add(fill);
131                self.bytes += fill;
132
133                // input buffer is still partially filled
134                if self.bytes % 32 != 0 {
135                    return;
136                }
137
138                // process full input buffer
139                self.v[0] += read_u64(&self.b[0] as *const _) * K0;
140                self.v[0] = rotate_right(self.v[0], 29) + self.v[2];
141                self.v[1] += read_u64(&self.b[1] as *const _) * K1;
142                self.v[1] = rotate_right(self.v[1], 29) + self.v[3];
143                self.v[2] += read_u64(&self.b[2] as *const _) * K2;
144                self.v[2] = rotate_right(self.v[2], 29) + self.v[0];
145                self.v[3] += read_u64(&self.b[3] as *const _) * K3;
146                self.v[3] = rotate_right(self.v[3], 29) + self.v[1];
147            }
148
149            // bulk update
150            self.bytes += end.offset_from(ptr) as usize;
151            while end.offset_from(ptr) >= 32 {
152                // process directly from the source, bypassing the input buffer
153                // these reads may be unaligned
154                self.v[0] += read_u64_unaligned(ptr) * K0;
155                ptr = ptr.add(8);
156                self.v[0] = rotate_right(self.v[0], 29) + self.v[2];
157                self.v[1] += read_u64_unaligned(ptr) * K1;
158                ptr = ptr.add(8);
159                self.v[1] = rotate_right(self.v[1], 29) + self.v[3];
160                self.v[2] += read_u64_unaligned(ptr) * K2;
161                ptr = ptr.add(8);
162                self.v[2] = rotate_right(self.v[2], 29) + self.v[0];
163                self.v[3] += read_u64_unaligned(ptr) * K3;
164                ptr = ptr.add(8);
165                self.v[3] = rotate_right(self.v[3], 29) + self.v[1];
166            }
167
168            // store remaining self.bytes in input buffer
169            if ptr < end {
170                copy_32(
171                    ptr,
172                    self.b.as_mut_ptr().cast::<u8>(),
173                    end.offset_from(ptr) as usize,
174                );
175            }
176        }
177    }
178
179    #[inline]
180    fn finish(&self) -> u64 {
181        self.finish128().0
182    }
183}