1use crate::util::mix::{rapid_mix, rapid_mum};
2use crate::util::read::{read_u32, read_u64};
3use super::{DEFAULT_RAPID_SECRETS, RapidSecrets};
4
5#[inline]
11pub const fn rapidhash_v2_2(data: &[u8]) -> u64 {
12 rapidhash_v2_inline::<2, true, false, false>(data, &DEFAULT_RAPID_SECRETS)
13}
14
15#[inline]
21pub const fn rapidhash_v2_2_seeded(data: &[u8], secrets: &RapidSecrets) -> u64 {
22 rapidhash_v2_inline::<2, true, false, false>(data, secrets)
23}
24
25#[inline(always)]
42pub const fn rapidhash_v2_inline<const MINOR: u8, const AVALANCHE: bool, const COMPACT: bool, const PROTECTED: bool>(data: &[u8], secrets: &RapidSecrets) -> u64 {
43 rapidhash_core::<MINOR, AVALANCHE, COMPACT, PROTECTED>(secrets.seed, &secrets.secrets, data)
44}
45
46#[inline(always)]
47pub(super) const fn rapidhash_core<const MINOR: u8, const AVALANCHE: bool, const COMPACT: bool, const PROTECTED: bool>(mut seed: u64, secrets: &[u64; 7], data: &[u8]) -> u64 {
48 if MINOR > 2 {
49 panic!("rapidhash_core unsupported minor version. Supported versions are 0, 1, and 2.");
50 }
51
52 let mut a = 0;
53 let mut b = 0;
54 seed ^= data.len() as u64;
55
56 if data.len() <= 16 {
57 if data.len() >= 4 {
58 if data.len() >= 8 {
59 let plast = data.len() - 8;
60 a ^= read_u64(data, 0);
61 b ^= read_u64(data, plast);
62 } else {
63 let plast = data.len() - 4;
64 a ^= read_u32(data, 0) as u64;
65 b ^= read_u32(data, plast) as u64;
66 }
67 } else if !data.is_empty() {
68 if MINOR < 2 {
69 a ^= ((data[0] as u64) << 56) | ((data[data.len() >> 1] as u64) << 32) | data[data.len() - 1] as u64;
70 } else {
71 a ^= ((data[0] as u64) << 56) | data[data.len() - 1] as u64;
72 b ^= data[data.len() >> 1] as u64;
73 }
74 }
75 } else if (MINOR == 0 && data.len() <= 56) || (MINOR > 0 && data.len() <= 64) {
76 return rapidhash_core_17_64::<MINOR, AVALANCHE, PROTECTED>(seed, secrets, data);
78 } else {
79 return rapidhash_core_cold::<AVALANCHE, COMPACT, PROTECTED>(seed, secrets, data);
80 }
81
82 a ^= secrets[1];
83 b ^= seed;
84
85 (a, b) = rapid_mum::<PROTECTED>(a, b);
86
87 if AVALANCHE {
88 rapidhash_finish::<PROTECTED>(a, b, data.len() as u64, secrets)
89 } else {
90 a ^ b
91 }
92}
93
94#[inline] const fn rapidhash_core_17_64<const MINOR: u8, const AVALANCHE: bool, const PROTECTED: bool>(mut seed: u64, secrets: &[u64; 7], data: &[u8]) -> u64 {
96 let mut a = 0;
97 let mut b = 0;
98
99 let slice = data;
100
101 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[0], read_u64(slice, 8) ^ seed);
102 if slice.len() > 32 {
103 seed = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[1], read_u64(slice, 24) ^ seed);
104 if slice.len() > 48 {
105 let index: usize = if MINOR < 2 { 0 } else { 1 };
106 seed = rapid_mix::<PROTECTED>(read_u64(slice, 32) ^ secrets[index], read_u64(slice, 40) ^ seed);
107 }
108 }
109
110 a ^= read_u64(data, data.len() - 16);
111 b ^= read_u64(data, data.len() - 8);
112
113 a ^= secrets[1];
114 b ^= seed;
115
116 (a, b) = rapid_mum::<PROTECTED>(a, b);
117
118 if AVALANCHE {
119 rapidhash_finish::<PROTECTED>(a, b, data.len() as u64, secrets)
120 } else {
121 a ^ b
122 }
123}
124
125#[cold]
129const fn rapidhash_core_cold<const AVALANCHE: bool, const COMPACT: bool, const PROTECTED: bool>(mut seed: u64, secrets: &[u64; 7], data: &[u8]) -> u64 {
130 let mut a = 0;
131 let mut b = 0;
132
133 let mut slice = data;
134
135 let mut see1 = seed;
137 let mut see2 = seed;
138 let mut see3 = seed;
139 let mut see4 = seed;
140 let mut see5 = seed;
141 let mut see6 = seed;
142
143 if !COMPACT {
144 while slice.len() >= 224 {
145 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[0], read_u64(slice, 8) ^ seed);
146 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[1], read_u64(slice, 24) ^ see1);
147 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 32) ^ secrets[2], read_u64(slice, 40) ^ see2);
148 see3 = rapid_mix::<PROTECTED>(read_u64(slice, 48) ^ secrets[3], read_u64(slice, 56) ^ see3);
149 see4 = rapid_mix::<PROTECTED>(read_u64(slice, 64) ^ secrets[4], read_u64(slice, 72) ^ see4);
150 see5 = rapid_mix::<PROTECTED>(read_u64(slice, 80) ^ secrets[5], read_u64(slice, 88) ^ see5);
151 see6 = rapid_mix::<PROTECTED>(read_u64(slice, 96) ^ secrets[6], read_u64(slice, 104) ^ see6);
152
153 seed = rapid_mix::<PROTECTED>(read_u64(slice, 112) ^ secrets[0], read_u64(slice, 120) ^ seed);
154 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 128) ^ secrets[1], read_u64(slice, 136) ^ see1);
155 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 144) ^ secrets[2], read_u64(slice, 152) ^ see2);
156 see3 = rapid_mix::<PROTECTED>(read_u64(slice, 160) ^ secrets[3], read_u64(slice, 168) ^ see3);
157 see4 = rapid_mix::<PROTECTED>(read_u64(slice, 176) ^ secrets[4], read_u64(slice, 184) ^ see4);
158 see5 = rapid_mix::<PROTECTED>(read_u64(slice, 192) ^ secrets[5], read_u64(slice, 200) ^ see5);
159 see6 = rapid_mix::<PROTECTED>(read_u64(slice, 208) ^ secrets[6], read_u64(slice, 216) ^ see6);
160
161 let (_, split) = slice.split_at(224);
162 slice = split;
163 }
164
165 if slice.len() >= 112 {
166 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[0], read_u64(slice, 8) ^ seed);
167 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[1], read_u64(slice, 24) ^ see1);
168 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 32) ^ secrets[2], read_u64(slice, 40) ^ see2);
169 see3 = rapid_mix::<PROTECTED>(read_u64(slice, 48) ^ secrets[3], read_u64(slice, 56) ^ see3);
170 see4 = rapid_mix::<PROTECTED>(read_u64(slice, 64) ^ secrets[4], read_u64(slice, 72) ^ see4);
171 see5 = rapid_mix::<PROTECTED>(read_u64(slice, 80) ^ secrets[5], read_u64(slice, 88) ^ see5);
172 see6 = rapid_mix::<PROTECTED>(read_u64(slice, 96) ^ secrets[6], read_u64(slice, 104) ^ see6);
173 let (_, split) = slice.split_at(112);
174 slice = split;
175 }
176
177 if slice.len() >= 48 {
178 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[0], read_u64(slice, 8) ^ seed);
179 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[1], read_u64(slice, 24) ^ see1);
180 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 32) ^ secrets[2], read_u64(slice, 40) ^ see2);
181 let (_, split) = slice.split_at(48);
182 slice = split;
183
184 if slice.len() >= 48 {
185 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[0], read_u64(slice, 8) ^ seed);
186 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[1], read_u64(slice, 24) ^ see1);
187 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 32) ^ secrets[2], read_u64(slice, 40) ^ see2);
188 let (_, split) = slice.split_at(48);
189 slice = split;
190 }
191 }
192 } else {
193 while slice.len() >= 112 {
194 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[0], read_u64(slice, 8) ^ seed);
195 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[1], read_u64(slice, 24) ^ see1);
196 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 32) ^ secrets[2], read_u64(slice, 40) ^ see2);
197 see3 = rapid_mix::<PROTECTED>(read_u64(slice, 48) ^ secrets[3], read_u64(slice, 56) ^ see3);
198 see4 = rapid_mix::<PROTECTED>(read_u64(slice, 64) ^ secrets[4], read_u64(slice, 72) ^ see4);
199 see5 = rapid_mix::<PROTECTED>(read_u64(slice, 80) ^ secrets[5], read_u64(slice, 88) ^ see5);
200 see6 = rapid_mix::<PROTECTED>(read_u64(slice, 96) ^ secrets[6], read_u64(slice, 104) ^ see6);
201 let (_, split) = slice.split_at(112);
202 slice = split;
203 }
204
205 while slice.len() >= 48 {
206 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[0], read_u64(slice, 8) ^ seed);
207 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[1], read_u64(slice, 24) ^ see1);
208 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 32) ^ secrets[2], read_u64(slice, 40) ^ see2);
209 let (_, split) = slice.split_at(48);
210 slice = split;
211 }
212 }
213
214 see3 ^= see4;
215 see5 ^= see6;
216 seed ^= see1;
217 see3 ^= see2;
218 seed ^= see5;
219 seed ^= see3;
220
221 if slice.len() > 16 {
222 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[2], read_u64(slice, 8) ^ seed);
223 if slice.len() > 32 {
224 seed = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[2], read_u64(slice, 24) ^ seed);
225 }
226 }
227
228 a ^= read_u64(data, data.len() - 16);
229 b ^= read_u64(data, data.len() - 8);
230
231 a ^= secrets[1];
232 b ^= seed;
233
234 (a, b) = rapid_mum::<PROTECTED>(a, b);
235
236 if AVALANCHE {
237 rapidhash_finish::<PROTECTED>(a, b, data.len() as u64, secrets)
238 } else {
239 a ^ b
240 }
241}
242
243#[inline(always)]
244pub(super) const fn rapidhash_finish<const PROTECTED: bool>(a: u64, b: u64, len: u64, secrets: &[u64; 7]) -> u64 {
245 rapid_mix::<PROTECTED>(a ^ 0xaaaaaaaaaaaaaaaa ^ len, b ^ secrets[1])
246}