Skip to main content

axhash_core/
hasher.rs

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// AxBuildHasher (Router untuk HashMap)
60#[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// Hash raw bytes non seed eksplisit (default seed = 0)
95#[inline(always)]
96pub fn axhash(bytes: &[u8]) -> u64 {
97    axhash_seeded(bytes, 0)
98}
99
100// Hash raw bytes dengan custom seed
101#[inline(always)]
102pub fn axhash_seeded(bytes: &[u8], seed: u64) -> u64 {
103    avalanche(hash_bytes_core(bytes, seed_lane(seed, 0)))
104}
105
106// Hash non seed eksplisit
107#[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}