1use crate::bytes::hash_bytes_core;
2use crate::constants::SECRET;
3use crate::math::{avalanche, folded_multiply, seed_lane};
4use core::hash::{BuildHasher, Hash, Hasher};
5
6#[derive(Clone)]
7pub struct AxHasher {
8 acc: u64,
9 sponge: u128,
10 sponge_bits: u8,
11}
12
13impl AxHasher {
14 #[inline(always)]
15 pub fn new() -> Self {
16 Self::new_with_seed(0)
17 }
18
19 #[inline(always)]
20 pub fn new_with_seed(seed: u64) -> Self {
21 Self {
22 acc: seed ^ SECRET[0],
23 sponge: 0,
24 sponge_bits: 0,
25 }
26 }
27
28 #[inline(always)]
29 fn flush_sponge(&mut self) {
30 if self.sponge_bits == 0 {
31 return;
32 }
33
34 let lo = self.sponge as u64;
35 let hi = (self.sponge >> 64) as u64;
36 self.acc = folded_multiply(lo ^ self.acc, hi ^ SECRET[1]);
37 self.sponge = 0;
38 self.sponge_bits = 0;
39 }
40
41 #[inline(always)]
42 fn push_num<T: Into<u128>>(&mut self, value: T, bits: u8) {
43 if self.sponge_bits as u16 + bits as u16 > 128 {
44 self.flush_sponge();
45 }
46
47 self.sponge |= value.into() << self.sponge_bits;
48 self.sponge_bits += bits;
49 }
50}
51
52impl Default for AxHasher {
53 #[inline(always)]
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59#[derive(Clone, Copy, Default)]
61pub struct AxBuildHasher {
62 prepared_seed: u64,
63}
64
65impl AxBuildHasher {
66 #[inline(always)]
67 pub const fn new() -> Self {
68 Self {
69 prepared_seed: SECRET[0],
70 }
71 }
72
73 #[inline(always)]
74 pub const fn with_seed(seed: u64) -> Self {
75 Self {
76 prepared_seed: seed ^ SECRET[0],
77 }
78 }
79}
80
81impl BuildHasher for AxBuildHasher {
82 type Hasher = AxHasher;
83
84 #[inline(always)]
85 fn build_hasher(&self) -> Self::Hasher {
86 AxHasher {
87 acc: self.prepared_seed,
88 sponge: 0,
89 sponge_bits: 0,
90 }
91 }
92}
93
94#[inline(always)]
96pub fn axhash(bytes: &[u8]) -> u64 {
97 axhash_seeded(bytes, 0)
98}
99
100#[inline(always)]
102pub fn axhash_seeded(bytes: &[u8], seed: u64) -> u64 {
103 avalanche(hash_bytes_core(bytes, seed_lane(seed, 0)))
104}
105
106#[inline(always)]
108pub fn axhash_of<T: Hash>(data: &T) -> u64 {
109 axhash_of_seeded(data, 0)
110}
111
112#[inline(always)]
113pub fn axhash_of_seeded<T: Hash>(data: &T, seed: u64) -> u64 {
114 let mut hasher = AxHasher::new_with_seed(seed);
115 data.hash(&mut hasher);
116 hasher.finish()
117}
118
119impl Hasher for AxHasher {
120 #[inline(always)]
121 fn finish(&self) -> u64 {
122 if self.sponge_bits == 0 {
123 avalanche(self.acc)
124 } else {
125 let lo = self.sponge as u64;
126 let hi = (self.sponge >> 64) as u64;
127 avalanche(folded_multiply(lo ^ self.acc, hi ^ SECRET[1]))
128 }
129 }
130
131 #[inline(always)]
132 fn write(&mut self, bytes: &[u8]) {
133 self.flush_sponge();
134 self.acc = hash_bytes_core(bytes, self.acc);
135 }
136
137 #[inline(always)]
138 fn write_u8(&mut self, i: u8) {
139 self.push_num(i, 8);
140 }
141
142 #[inline(always)]
143 fn write_u16(&mut self, i: u16) {
144 self.push_num(i, 16);
145 }
146
147 #[inline(always)]
148 fn write_u32(&mut self, i: u32) {
149 self.push_num(i, 32);
150 }
151
152 #[inline(always)]
153 fn write_u64(&mut self, i: u64) {
154 self.push_num(i, 64);
155 }
156
157 #[inline(always)]
158 fn write_u128(&mut self, i: u128) {
159 self.flush_sponge();
160 let lo = i as u64;
161 let hi = (i >> 64) as u64;
162 self.acc = folded_multiply(lo ^ self.acc, hi ^ SECRET[1]);
163 }
164
165 #[inline(always)]
166 fn write_usize(&mut self, i: usize) {
167 #[cfg(target_pointer_width = "32")]
168 self.write_u32(i as u32);
169 #[cfg(target_pointer_width = "64")]
170 self.write_u64(i as u64);
171 }
172
173 #[inline(always)]
174 fn write_i8(&mut self, i: i8) {
175 self.write_u8(i as u8);
176 }
177
178 #[inline(always)]
179 fn write_i16(&mut self, i: i16) {
180 self.write_u16(i as u16);
181 }
182
183 #[inline(always)]
184 fn write_i32(&mut self, i: i32) {
185 self.write_u32(i as u32);
186 }
187
188 #[inline(always)]
189 fn write_i64(&mut self, i: i64) {
190 self.write_u64(i as u64);
191 }
192
193 #[inline(always)]
194 fn write_i128(&mut self, i: i128) {
195 self.write_u128(i as u128);
196 }
197
198 #[inline(always)]
199 fn write_isize(&mut self, i: isize) {
200 self.write_usize(i as usize);
201 }
202}