1use crate::Checksum;
2
3pub(crate) const PRIME32_1: u64 = 0x9E3779B1;
8pub(crate) const PRIME32_3: u64 = 0xC2B2AE3D;
9
10const PRIME64_1: u64 = 0x9E3779B185EBCA87;
11const PRIME64_2: u64 = 0xC2B2AE3D27D4EB4F;
12const PRIME64_5: u64 = 0x27D4EB2F165667C5;
13
14const STRIPE_LEN: usize = 64;
15const SECRET_CONSUME_RATE: usize = 8;
16pub(crate) const ACC_NB: usize = 8;
17const SECRET_MERGEACCS_START: usize = 11;
18const SECRET_LASTACC_START: usize = 7;
19const MID_SIZE_MAX: usize = 240;
20const SECRET_SIZE_MIN: usize = 136;
21const DEFAULT_SECRET_SIZE: usize = 192;
22const STRIPES_PER_BLOCK: usize = (DEFAULT_SECRET_SIZE - STRIPE_LEN) / SECRET_CONSUME_RATE;
23
24const DEFAULT_SECRET: [u8; 192] = [
26 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xde, 0xd4, 0x6d,
27 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0,
28 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0,
29 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b,
30 0x1b, 0x53, 0x2e, 0xa3, 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac,
31 0xd8, 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, 0x8a, 0x51,
32 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, 0xea, 0xc5, 0xac, 0x83, 0x34,
33 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49,
34 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8,
35 0xd1, 0x7a, 0xd0, 0x31, 0xce, 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b,
36 0x40, 0x7e,
37];
38
39const INITIAL_ACC: [u64; ACC_NB] = [
40 PRIME32_3,
41 PRIME64_1,
42 PRIME64_2,
43 0x165667B19E3779F9, 0x85EBCA77C2B2AE63, 0x85EBCA77, PRIME64_5,
47 PRIME32_1,
48];
49
50#[inline]
54const fn read_64le(data: &[u8], offset: usize) -> u64 {
55 let (_, rest) = data.split_at(offset);
56 let arr = match rest.split_first_chunk::<8>() {
57 Some((arr, _)) => arr,
58 None => panic!("read_64le: out of bounds"),
59 };
60 u64::from_le_bytes(*arr)
61}
62
63#[inline]
64const fn read_32le(data: &[u8], offset: usize) -> u32 {
65 let (_, rest) = data.split_at(offset);
66 let arr = match rest.split_first_chunk::<4>() {
67 Some((arr, _)) => arr,
68 None => panic!("read_32le: out of bounds"),
69 };
70 u32::from_le_bytes(*arr)
71}
72#[inline]
73const fn xorshift64(value: u64, shift: u64) -> u64 {
74 value ^ (value >> shift)
75}
76
77#[inline]
78const fn avalanche(mut h: u64) -> u64 {
79 h = xorshift64(h, 37);
80 h = h.wrapping_mul(0x165667919E3779F9);
81 xorshift64(h, 32)
82}
83
84const fn xxh64_avalanche(mut h: u64) -> u64 {
86 h ^= h >> 33;
87 h = h.wrapping_mul(PRIME64_2);
88 h ^= h >> 29;
89 h = h.wrapping_mul(0x165667B19E3779F9);
90 h ^= h >> 32;
91 h
92}
93
94#[inline]
95const fn strong_avalanche(mut value: u64, len: u64) -> u64 {
96 value ^= value.rotate_left(49) ^ value.rotate_left(24);
97 value = value.wrapping_mul(0x9FB21C651E98DF25);
98 value ^= (value >> 35).wrapping_add(len);
99 value = value.wrapping_mul(0x9FB21C651E98DF25);
100 xorshift64(value, 28)
101}
102
103#[inline]
104const fn mul128_fold64(l: u64, r: u64) -> u64 {
105 let p = (l as u128).wrapping_mul(r as u128);
106 (p as u64) ^ ((p >> 64) as u64)
107}
108
109#[inline]
110const fn mult32_to64(left: u32, right: u32) -> u64 {
111 (left as u64).wrapping_mul(right as u64)
112}
113
114#[inline]
115const fn mix16b(input: &[u8], input_offset: usize, secret: &[u8], secret_offset: usize, seed: u64) -> u64 {
116 let mut input_lo = read_64le(input, input_offset);
117 let mut input_hi = read_64le(input, input_offset + 8);
118
119 input_lo ^= read_64le(secret, secret_offset).wrapping_add(seed);
120 input_hi ^= read_64le(secret, secret_offset + 8).wrapping_sub(seed);
121
122 mul128_fold64(input_lo, input_hi)
123}
124
125#[inline]
126const fn mix_two_accs(acc: &[u64; ACC_NB], offset: usize, secret: &[u8], sec_off: usize) -> u64 {
127 mul128_fold64(
128 acc[offset] ^ read_64le(secret, sec_off),
129 acc[offset + 1] ^ read_64le(secret, sec_off + 8),
130 )
131}
132
133#[inline]
134const fn merge_accs(acc: &[u64; ACC_NB], secret: &[u8], start_offset: usize, mut result: u64) -> u64 {
135 let mut i = 0;
136 while i < 4 {
137 result = result.wrapping_add(mix_two_accs(acc, i * 2, secret, start_offset + i * 16));
138 i += 1;
139 }
140 avalanche(result)
141}
142
143#[inline]
148const fn accumulate_512_scalar(
149 acc: &mut [u64; ACC_NB],
150 input: &[u8],
151 input_off: usize,
152 secret: &[u8],
153 secret_off: usize,
154) {
155 let mut i = 0;
156 while i < ACC_NB {
157 let data_val = read_64le(input, input_off + i * 8);
158 let data_key = data_val ^ read_64le(secret, secret_off + i * 8);
159 acc[i ^ 1] = acc[i ^ 1].wrapping_add(data_val);
160 acc[i] = acc[i].wrapping_add(mult32_to64((data_key & 0xFFFFFFFF) as u32, (data_key >> 32) as u32));
161 i += 1;
162 }
163}
164
165#[inline]
166const fn accumulate_loop_scalar(
167 acc: &mut [u64; ACC_NB],
168 input: &[u8],
169 input_off: usize,
170 secret: &[u8],
171 secret_off: usize,
172 nb_stripes: usize,
173) {
174 let mut i = 0;
175 while i < nb_stripes {
176 accumulate_512_scalar(
177 acc,
178 input,
179 input_off + i * STRIPE_LEN,
180 secret,
181 secret_off + i * SECRET_CONSUME_RATE,
182 );
183 i += 1;
184 }
185}
186
187#[inline]
188const fn scramble_acc_scalar(acc: &mut [u64; ACC_NB], secret: &[u8], secret_off: usize) {
189 let mut i = 0;
190 while i < ACC_NB {
191 let key = read_64le(secret, secret_off + i * 8);
192 let mut val = xorshift64(acc[i], 47);
193 val ^= key;
194 acc[i] = val.wrapping_mul(PRIME32_1);
195 i += 1;
196 }
197}
198
199#[inline]
200const fn hash_long_internal_loop(acc: &mut [u64; ACC_NB], input: &[u8], secret: &[u8]) {
201 let nb_stripes = STRIPES_PER_BLOCK;
202 let block_len = STRIPE_LEN * nb_stripes;
203 let nb_blocks = (input.len() - 1) / block_len;
204
205 let mut i = 0;
206 while i < nb_blocks {
207 accumulate_loop_scalar(acc, input, i * block_len, secret, 0, nb_stripes);
208 scramble_acc_scalar(acc, secret, secret.len() - STRIPE_LEN);
209 i += 1;
210 }
211
212 let nb_stripes = ((input.len() - 1) - (block_len * nb_blocks)) / STRIPE_LEN;
214 accumulate_loop_scalar(acc, input, nb_blocks * block_len, secret, 0, nb_stripes);
215
216 let last_stripe_start = input.len() - STRIPE_LEN;
218 let last_secret_off = secret.len() - STRIPE_LEN - SECRET_LASTACC_START;
219 accumulate_512_scalar(acc, input, last_stripe_start, secret, last_secret_off);
220}
221
222const fn custom_default_secret_scalar(seed: u64) -> [u8; DEFAULT_SECRET_SIZE] {
227 let mut result = [0u8; DEFAULT_SECRET_SIZE];
228 let nb_rounds = DEFAULT_SECRET_SIZE / 16;
229 let mut i = 0;
230 while i < nb_rounds {
231 let lo = read_64le(&DEFAULT_SECRET, i * 16).wrapping_add(seed);
232 let hi = read_64le(&DEFAULT_SECRET, i * 16 + 8).wrapping_sub(seed);
233 let lo_bytes = lo.to_le_bytes();
234 let hi_bytes = hi.to_le_bytes();
235 let mut j = 0;
236 while j < 8 {
237 result[i * 16 + j] = lo_bytes[j];
238 result[i * 16 + 8 + j] = hi_bytes[j];
239 j += 1;
240 }
241 i += 1;
242 }
243 result
244}
245
246#[inline]
253#[allow(unreachable_code)]
254fn accumulate_512(acc: &mut [u64; ACC_NB], input: &[u8], input_off: usize, secret: &[u8], secret_off: usize) {
255 #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
256 {
257 crate::xxh3_wasm_simd128::accumulate_512(acc, input, input_off, secret, secret_off);
258 return;
259 }
260
261 #[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
262 {
263 unsafe { crate::xxh3_neon::accumulate_512(acc, input, input_off, secret, secret_off) };
264 return;
265 }
266
267 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx512f"))]
268 {
269 unsafe { crate::xxh3_avx512::accumulate_512(acc, input, input_off, secret, secret_off) };
270 return;
271 }
272
273 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx2"))]
274 {
275 unsafe { crate::xxh3_avx2::accumulate_512(acc, input, input_off, secret, secret_off) };
276 return;
277 }
278
279 accumulate_512_scalar(acc, input, input_off, secret, secret_off);
280}
281
282#[inline]
283#[allow(unreachable_code)]
284fn accumulate_loop(
285 acc: &mut [u64; ACC_NB],
286 input: &[u8],
287 input_off: usize,
288 secret: &[u8],
289 secret_off: usize,
290 nb_stripes: usize,
291) {
292 let mut idx = 0;
293 while idx < nb_stripes {
294 accumulate_512(
295 acc,
296 input,
297 input_off + idx * STRIPE_LEN,
298 secret,
299 secret_off + idx * SECRET_CONSUME_RATE,
300 );
301 idx += 1;
302 }
303}
304
305#[inline]
306#[allow(unreachable_code)]
307fn scramble_acc(acc: &mut [u64; ACC_NB], secret: &[u8], secret_off: usize) {
308 #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))]
309 {
310 crate::xxh3_wasm_simd128::scramble_acc(acc, secret, secret_off);
311 return;
312 }
313
314 #[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
315 {
316 unsafe { crate::xxh3_neon::scramble_acc(acc, secret, secret_off) };
317 return;
318 }
319
320 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx512f"))]
321 {
322 unsafe { crate::xxh3_avx512::scramble_acc(acc, secret, secret_off) };
323 return;
324 }
325
326 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx2"))]
327 {
328 unsafe { crate::xxh3_avx2::scramble_acc(acc, secret, secret_off) };
329 return;
330 }
331
332 scramble_acc_scalar(acc, secret, secret_off);
333}
334
335#[inline]
336fn custom_default_secret(seed: u64) -> [u8; DEFAULT_SECRET_SIZE] {
337 custom_default_secret_scalar(seed)
338}
339
340const fn xxh3_64_1to3(input: &[u8], seed: u64, secret: &[u8]) -> u64 {
345 let len = input.len();
346 let c1 = input[0] as u32;
347 let c2 = input[len >> 1] as u32;
348 let c3 = input[len - 1] as u32;
349 let combined = (c1 << 16) | (c2 << 24) | (c3) | ((len as u32) << 8);
350 let flip = ((read_32le(secret, 0) ^ read_32le(secret, 4)) as u64).wrapping_add(seed);
351 xxh64_avalanche((combined as u64) ^ flip)
352}
353
354const fn xxh3_64_4to8(input: &[u8], mut seed: u64, secret: &[u8]) -> u64 {
355 seed ^= ((seed as u32).swap_bytes() as u64) << 32;
356 let len = input.len();
357 let input1 = read_32le(input, 0);
358 let input2 = read_32le(input, len - 4);
359 let flip = (read_64le(secret, 8) ^ read_64le(secret, 16)).wrapping_sub(seed);
360 let input64 = (input2 as u64).wrapping_add((input1 as u64) << 32);
361 strong_avalanche(input64 ^ flip, len as u64)
362}
363
364const fn xxh3_64_9to16(input: &[u8], seed: u64, secret: &[u8]) -> u64 {
365 let len = input.len();
366 let flip1 = (read_64le(secret, 24) ^ read_64le(secret, 32)).wrapping_add(seed);
367 let flip2 = (read_64le(secret, 40) ^ read_64le(secret, 48)).wrapping_sub(seed);
368 let input_lo = read_64le(input, 0) ^ flip1;
369 let input_hi = read_64le(input, len - 8) ^ flip2;
370 let acc = (len as u64)
371 .wrapping_add(input_lo.swap_bytes())
372 .wrapping_add(input_hi)
373 .wrapping_add(mul128_fold64(input_lo, input_hi));
374 avalanche(acc)
375}
376
377const fn xxh3_64_0to16(input: &[u8], seed: u64, secret: &[u8]) -> u64 {
378 if input.len() > 8 {
379 xxh3_64_9to16(input, seed, secret)
380 } else if input.len() >= 4 {
381 xxh3_64_4to8(input, seed, secret)
382 } else if !input.is_empty() {
383 xxh3_64_1to3(input, seed, secret)
384 } else {
385 xxh64_avalanche(seed ^ read_64le(secret, 56) ^ read_64le(secret, 64))
386 }
387}
388
389const fn xxh3_64_7to128(input: &[u8], seed: u64, secret: &[u8]) -> u64 {
394 let len = input.len();
395 let mut acc = (len as u64).wrapping_mul(PRIME64_1);
396
397 if len > 32 {
398 if len > 64 {
399 if len > 96 {
400 acc = acc.wrapping_add(mix16b(input, 48, secret, 96, seed));
401 acc = acc.wrapping_add(mix16b(input, len - 64, secret, 112, seed));
402 }
403 acc = acc.wrapping_add(mix16b(input, 32, secret, 64, seed));
404 acc = acc.wrapping_add(mix16b(input, len - 48, secret, 80, seed));
405 }
406 acc = acc.wrapping_add(mix16b(input, 16, secret, 32, seed));
407 acc = acc.wrapping_add(mix16b(input, len - 32, secret, 48, seed));
408 }
409
410 acc = acc.wrapping_add(mix16b(input, 0, secret, 0, seed));
411 acc = acc.wrapping_add(mix16b(input, len - 16, secret, 16, seed));
412
413 avalanche(acc)
414}
415
416const fn xxh3_64_129to240(input: &[u8], seed: u64, secret: &[u8]) -> u64 {
421 let len = input.len();
422 let mut acc = (len as u64).wrapping_mul(PRIME64_1);
423 let nb_rounds = len / 16;
424
425 let mut i = 0;
426 while i < 8 {
427 acc = acc.wrapping_add(mix16b(input, i * 16, secret, i * 16, seed));
428 i += 1;
429 }
430 acc = avalanche(acc);
431
432 i = 8;
433 while i < nb_rounds {
434 acc = acc.wrapping_add(mix16b(input, i * 16, secret, (i - 8) * 16 + 3, seed));
435 i += 1;
436 }
437
438 acc = acc.wrapping_add(mix16b(input, len - 16, secret, SECRET_SIZE_MIN - 17, seed));
439
440 avalanche(acc)
441}
442
443const fn xxh3_64_long_impl(input: &[u8], secret: &[u8]) -> u64 {
448 let mut acc = INITIAL_ACC;
449 hash_long_internal_loop(&mut acc, input, secret);
450 merge_accs(
451 &acc,
452 secret,
453 SECRET_MERGEACCS_START,
454 (input.len() as u64).wrapping_mul(PRIME64_1),
455 )
456}
457
458const fn xxh3_64_long_with_seed(input: &[u8], seed: u64, secret: &[u8]) -> u64 {
459 if seed == 0 {
460 xxh3_64_long_impl(input, secret)
461 } else {
462 xxh3_64_long_impl(input, &custom_default_secret_scalar(seed))
463 }
464}
465
466const fn xxh3_64_one_shot(input: &[u8], seed: u64, secret: &[u8]) -> u64 {
467 if input.len() <= 16 {
468 xxh3_64_0to16(input, seed, secret)
469 } else if input.len() <= 128 {
470 xxh3_64_7to128(input, seed, secret)
471 } else if input.len() <= MID_SIZE_MAX {
472 xxh3_64_129to240(input, seed, secret)
473 } else {
474 xxh3_64_long_with_seed(input, seed, secret)
475 }
476}
477
478#[inline(always)]
483#[allow(clippy::too_many_arguments)]
484const fn mix32_b(
485 lo: &mut u64,
486 hi: &mut u64,
487 input: &[u8],
488 input1_off: usize,
489 input2_off: usize,
490 secret: &[u8],
491 secret_off: usize,
492 seed: u64,
493) {
494 *lo = lo.wrapping_add(mix16b(input, input1_off, secret, secret_off, seed));
495 *lo ^= read_64le(input, input2_off).wrapping_add(read_64le(input, input2_off + 8));
496 *hi = hi.wrapping_add(mix16b(input, input2_off, secret, secret_off + 16, seed));
497 *hi ^= read_64le(input, input1_off).wrapping_add(read_64le(input, input1_off + 8));
498}
499
500const fn xxh3_128_1to3(input: &[u8], seed: u64, secret: &[u8]) -> u128 {
505 let len = input.len();
506 let c1 = input[0] as u32;
507 let c2 = input[len >> 1] as u32;
508 let c3 = input[len - 1] as u32;
509 let combinedl = ((c1) << 16) | (c2 << 24) | (c3) | ((len as u32) << 8);
510 let combinedh = combinedl.swap_bytes().rotate_left(13);
511 let bitflipl = ((read_32le(secret, 0) ^ read_32le(secret, 4)) as u64).wrapping_add(seed);
512 let bitfliph = ((read_32le(secret, 8) ^ read_32le(secret, 12)) as u64).wrapping_sub(seed);
513 let keyed_lo = (combinedl as u64) ^ bitflipl;
514 let keyed_hi = (combinedh as u64) ^ bitfliph;
515 ((xxh64_avalanche(keyed_hi) as u128) << 64) | (xxh64_avalanche(keyed_lo) as u128)
516}
517
518const fn xxh3_128_9to16(input: &[u8], seed: u64, secret: &[u8]) -> u128 {
519 let len = input.len();
520 let bitflipl = (read_64le(secret, 32) ^ read_64le(secret, 40)).wrapping_sub(seed);
521 let bitfliph = (read_64le(secret, 48) ^ read_64le(secret, 56)).wrapping_add(seed);
522 let input_lo = read_64le(input, 0);
523 let mut input_hi = read_64le(input, len - 8);
524
525 let m128_full = (input_lo ^ input_hi ^ bitflipl) as u128 * PRIME64_1 as u128;
526 let mut m128_lo = m128_full as u64;
527 let mut m128_hi = (m128_full >> 64) as u64;
528
529 m128_lo = m128_lo.wrapping_add(((len - 1) as u64) << 54);
530 input_hi ^= bitfliph;
531 m128_hi = m128_hi
532 .wrapping_add(input_hi)
533 .wrapping_add(mult32_to64(input_hi as u32, 0x85EBCA76u32));
534
535 m128_lo ^= m128_hi.swap_bytes();
536
537 let h128_full = (m128_lo as u128).wrapping_mul(PRIME64_2 as u128);
538 let h128_lo = h128_full as u64;
539 let h128_hi = ((h128_full >> 64) as u64).wrapping_add(m128_hi.wrapping_mul(PRIME64_2));
540
541 ((avalanche(h128_hi) as u128) << 64) | (avalanche(h128_lo) as u128)
542}
543
544const fn xxh3_128_4to8_return(input: &[u8], mut seed: u64, secret: &[u8]) -> u128 {
545 seed ^= ((seed as u32).swap_bytes() as u64) << 32;
546 let len = input.len();
547 let input_lo = read_32le(input, 0);
548 let input_hi = read_32le(input, len - 4);
549 let input_64 = (input_lo as u64).wrapping_add((input_hi as u64) << 32);
550 let bitflip = (read_64le(secret, 16) ^ read_64le(secret, 24)).wrapping_add(seed);
551 let keyed = input_64 ^ bitflip;
552 let m128 = (keyed as u128).wrapping_mul(PRIME64_1.wrapping_add((len as u64) << 2) as u128);
553 let mut m128_lo = m128 as u64;
554 let mut m128_hi = (m128 >> 64) as u64;
555 m128_hi = m128_hi.wrapping_add(m128_lo << 1);
556 m128_lo ^= m128_hi >> 3;
557 m128_lo = xorshift64(m128_lo, 35);
558 m128_lo = m128_lo.wrapping_mul(0x9FB21C651E98DF25);
559 m128_lo = xorshift64(m128_lo, 28);
560 m128_hi = avalanche(m128_hi);
561 ((m128_hi as u128) << 64) | (m128_lo as u128)
562}
563
564const fn xxh3_128_0to16(input: &[u8], seed: u64, secret: &[u8]) -> u128 {
565 if input.len() > 8 {
566 xxh3_128_9to16(input, seed, secret)
567 } else if input.len() >= 4 {
568 xxh3_128_4to8_return(input, seed, secret)
569 } else if !input.is_empty() {
570 xxh3_128_1to3(input, seed, secret)
571 } else {
572 let flip_lo = read_64le(secret, 64) ^ read_64le(secret, 72);
573 let flip_hi = read_64le(secret, 80) ^ read_64le(secret, 88);
574 (xxh64_avalanche(seed ^ flip_lo) as u128) | ((xxh64_avalanche(seed ^ flip_hi) as u128) << 64)
575 }
576}
577
578const fn xxh3_128_7to128(input: &[u8], seed: u64, secret: &[u8]) -> u128 {
583 let len = input.len();
584 let mut lo = (len as u64).wrapping_mul(PRIME64_1);
585 let mut hi: u64 = 0;
586
587 if len > 32 {
588 if len > 64 {
589 if len > 96 {
590 mix32_b(&mut lo, &mut hi, input, 48, len - 64, secret, 96, seed);
591 }
592 mix32_b(&mut lo, &mut hi, input, 32, len - 48, secret, 64, seed);
593 }
594 mix32_b(&mut lo, &mut hi, input, 16, len - 32, secret, 32, seed);
595 }
596
597 mix32_b(&mut lo, &mut hi, input, 0, len - 16, secret, 0, seed);
598
599 (avalanche(lo.wrapping_add(hi)) as u128)
600 | ((0u64.wrapping_sub(avalanche(
601 lo.wrapping_mul(PRIME64_1)
602 .wrapping_add(hi.wrapping_mul(0x85EBCA77C2B2AE63))
603 .wrapping_add((len as u64).wrapping_sub(seed).wrapping_mul(PRIME64_2)),
604 )) as u128)
605 << 64)
606}
607
608const fn xxh3_128_129to240(input: &[u8], seed: u64, secret: &[u8]) -> u128 {
609 let len = input.len();
610 let nb_rounds = len / 32;
611 let mut lo = (len as u64).wrapping_mul(PRIME64_1);
612 let mut hi: u64 = 0;
613
614 let mut i = 0;
615 while i < 4 {
616 let offset = 32 * i;
617 mix32_b(&mut lo, &mut hi, input, offset, offset + 16, secret, offset, seed);
618 i += 1;
619 }
620
621 lo = avalanche(lo);
622 hi = avalanche(hi);
623
624 i = 4;
625 while i < nb_rounds {
626 mix32_b(&mut lo, &mut hi, input, 32 * i, 32 * i + 16, secret, 3 + 32 * (i - 4), seed);
627 i += 1;
628 }
629
630 mix32_b(
631 &mut lo,
632 &mut hi,
633 input,
634 len - 16,
635 len - 32,
636 secret,
637 SECRET_SIZE_MIN - 17 - 16,
638 0u64.wrapping_sub(seed),
639 );
640
641 (avalanche(lo.wrapping_add(hi)) as u128)
642 | ((0u64.wrapping_sub(avalanche(
643 lo.wrapping_mul(PRIME64_1)
644 .wrapping_add(hi.wrapping_mul(0x85EBCA77C2B2AE63))
645 .wrapping_add((len as u64).wrapping_sub(seed).wrapping_mul(PRIME64_2)),
646 )) as u128)
647 << 64)
648}
649
650const fn xxh3_128_long_impl(input: &[u8], secret: &[u8]) -> u128 {
655 let mut acc = INITIAL_ACC;
656 hash_long_internal_loop(&mut acc, input, secret);
657
658 let lo = merge_accs(
659 &acc,
660 secret,
661 SECRET_MERGEACCS_START,
662 (input.len() as u64).wrapping_mul(PRIME64_1),
663 );
664 let hi = merge_accs(
665 &acc,
666 secret,
667 secret.len() - ACC_NB * 8 - SECRET_MERGEACCS_START,
668 !(input.len() as u64).wrapping_mul(PRIME64_2),
669 );
670
671 (lo as u128) | ((hi as u128) << 64)
672}
673
674const fn xxh3_128_long_with_seed(input: &[u8], seed: u64, secret: &[u8]) -> u128 {
675 if seed == 0 {
676 xxh3_128_long_impl(input, secret)
677 } else {
678 xxh3_128_long_impl(input, &custom_default_secret_scalar(seed))
679 }
680}
681
682const fn xxh3_128_one_shot(input: &[u8], seed: u64, secret: &[u8]) -> u128 {
683 if input.len() <= 16 {
684 xxh3_128_0to16(input, seed, secret)
685 } else if input.len() <= 128 {
686 xxh3_128_7to128(input, seed, secret)
687 } else if input.len() <= MID_SIZE_MAX {
688 xxh3_128_129to240(input, seed, secret)
689 } else {
690 xxh3_128_long_with_seed(input, seed, secret)
691 }
692}
693
694#[derive(Clone)]
699struct LongState {
700 acc: [u64; ACC_NB],
701 secret: [u8; DEFAULT_SECRET_SIZE],
702 buf: [u8; STRIPE_LEN],
703 buf_len: u8,
704 nb_stripes_acc: usize,
705 total_len: u64,
706}
707
708impl LongState {
709 fn new(secret: &[u8; DEFAULT_SECRET_SIZE]) -> Self {
710 LongState {
711 acc: INITIAL_ACC,
712 secret: *secret,
713 buf: [0u8; STRIPE_LEN],
714 buf_len: 0,
715 nb_stripes_acc: 0,
716 total_len: 0,
717 }
718 }
719
720 fn update(&mut self, mut data: &[u8]) {
721 self.total_len += data.len() as u64;
722
723 if self.buf_len > 0 {
724 let take = (STRIPE_LEN - self.buf_len as usize).min(data.len());
725 self.buf[self.buf_len as usize..self.buf_len as usize + take].copy_from_slice(&data[..take]);
726 self.buf_len += take as u8;
727 data = &data[take..];
728 if self.buf_len as usize == STRIPE_LEN {
729 accumulate_512(
730 &mut self.acc,
731 &self.buf,
732 0,
733 &self.secret,
734 self.nb_stripes_acc * SECRET_CONSUME_RATE,
735 );
736 self.nb_stripes_acc += 1;
737 self.buf_len = 0;
738 }
739 }
740
741 while data.len() > STRIPE_LEN {
744 let nb_stripes = (data.len() - 1) / STRIPE_LEN;
745 let nb = nb_stripes.min(STRIPES_PER_BLOCK - self.nb_stripes_acc);
746 if nb == 0 {
747 break;
748 }
749 accumulate_loop(
750 &mut self.acc,
751 data,
752 0,
753 &self.secret,
754 self.nb_stripes_acc * SECRET_CONSUME_RATE,
755 nb,
756 );
757 self.nb_stripes_acc += nb;
758 if self.nb_stripes_acc >= STRIPES_PER_BLOCK {
759 scramble_acc(&mut self.acc, &self.secret, DEFAULT_SECRET_SIZE - STRIPE_LEN);
760 self.nb_stripes_acc = 0;
761 }
762 data = &data[nb * STRIPE_LEN..];
763 }
764
765 if !data.is_empty() {
766 self.buf[..data.len()].copy_from_slice(data);
767 self.buf_len = data.len() as u8;
768 }
769 }
770
771 fn sum_64b(self) -> u64 {
772 let mut acc = self.acc;
773
774 if self.buf_len > 0 {
775 let mut last_stripe = [0u8; STRIPE_LEN];
776 last_stripe[..self.buf_len as usize].copy_from_slice(&self.buf[..self.buf_len as usize]);
777 let copy_len = (SECRET_LASTACC_START).min(STRIPE_LEN - self.buf_len as usize);
778 let secret_tail_start = DEFAULT_SECRET_SIZE - SECRET_LASTACC_START;
779 last_stripe[STRIPE_LEN - SECRET_LASTACC_START..STRIPE_LEN - SECRET_LASTACC_START + copy_len]
780 .copy_from_slice(&self.secret[secret_tail_start..secret_tail_start + copy_len]);
781 let sec_off = DEFAULT_SECRET_SIZE - STRIPE_LEN - SECRET_LASTACC_START;
782 accumulate_512(&mut acc, &last_stripe, 0, &self.secret, sec_off);
783 }
784
785 merge_accs(
786 &acc,
787 &self.secret,
788 SECRET_MERGEACCS_START,
789 (self.total_len).wrapping_mul(PRIME64_1),
790 )
791 }
792
793 fn sum_128b(self) -> u128 {
794 let mut acc = self.acc;
795
796 if self.buf_len > 0 {
797 let mut last_stripe = [0u8; STRIPE_LEN];
798 last_stripe[..self.buf_len as usize].copy_from_slice(&self.buf[..self.buf_len as usize]);
799 let copy_len = (SECRET_LASTACC_START).min(STRIPE_LEN - self.buf_len as usize);
800 let secret_tail_start = DEFAULT_SECRET_SIZE - SECRET_LASTACC_START;
801 last_stripe[STRIPE_LEN - SECRET_LASTACC_START..STRIPE_LEN - SECRET_LASTACC_START + copy_len]
802 .copy_from_slice(&self.secret[secret_tail_start..secret_tail_start + copy_len]);
803 let sec_off = DEFAULT_SECRET_SIZE - STRIPE_LEN - SECRET_LASTACC_START;
804 accumulate_512(&mut acc, &last_stripe, 0, &self.secret, sec_off);
805 }
806
807 let lo = merge_accs(
808 &acc,
809 &self.secret,
810 SECRET_MERGEACCS_START,
811 (self.total_len).wrapping_mul(PRIME64_1),
812 );
813 let hi = merge_accs(
814 &acc,
815 &self.secret,
816 DEFAULT_SECRET_SIZE - ACC_NB * 8 - SECRET_MERGEACCS_START,
817 !(self.total_len).wrapping_mul(PRIME64_2),
818 );
819
820 (lo as u128) | ((hi as u128) << 64)
821 }
822}
823
824#[derive(Clone)]
841pub struct Xxh3_64 {
842 seed: u64,
843 secret: [u8; DEFAULT_SECRET_SIZE],
844 buf: [u8; MID_SIZE_MAX],
845 buf_len: usize,
846 long: Option<LongState>,
847}
848
849impl Xxh3_64 {
850 #[inline]
852 pub const fn with_seed(seed: u64) -> Self {
853 Xxh3_64 {
854 seed,
855 secret: DEFAULT_SECRET,
856 buf: [0u8; MID_SIZE_MAX],
857 buf_len: 0,
858 long: None,
859 }
860 }
861
862 #[inline]
864 pub const fn with_secret(secret: [u8; DEFAULT_SECRET_SIZE]) -> Self {
865 Xxh3_64 {
866 seed: 0,
867 secret,
868 buf: [0u8; MID_SIZE_MAX],
869 buf_len: 0,
870 long: None,
871 }
872 }
873
874 #[inline]
876 pub const fn with_seed_and_secret(seed: u64, secret: [u8; DEFAULT_SECRET_SIZE]) -> Self {
877 Xxh3_64 {
878 seed,
879 secret,
880 buf: [0u8; MID_SIZE_MAX],
881 buf_len: 0,
882 long: None,
883 }
884 }
885}
886
887impl Checksum for Xxh3_64 {
888 type Output = u64;
889
890 fn new() -> Self {
891 Self::with_seed(0)
892 }
893
894 fn checksum(data: &[u8]) -> Self::Output {
895 if data.len() <= MID_SIZE_MAX {
896 xxh3_64(data)
897 } else {
898 let mut hasher = Self::new();
899 hasher.update(data);
900 hasher.sum()
901 }
902 }
903
904 fn update(&mut self, data: &[u8]) {
905 if let Some(long) = &mut self.long {
906 long.update(data);
907 return;
908 }
909
910 let mut remaining = data;
911
912 if self.buf_len < MID_SIZE_MAX {
913 let take = (MID_SIZE_MAX - self.buf_len).min(remaining.len());
914 self.buf[self.buf_len..self.buf_len + take].copy_from_slice(&remaining[..take]);
915 self.buf_len += take;
916 remaining = &remaining[take..];
917 }
918
919 if self.buf_len >= MID_SIZE_MAX && !remaining.is_empty() {
920 let long_secret = if self.seed == 0 {
921 self.secret
922 } else {
923 custom_default_secret(self.seed)
924 };
925 let mut long = LongState::new(&long_secret);
926 long.update(&self.buf[..self.buf_len]);
927 self.long = Some(long);
928 self.buf_len = 0;
929
930 if !remaining.is_empty() {
931 self.long.as_mut().unwrap().update(remaining);
932 }
933 }
934 }
935
936 fn sum(self) -> Self::Output {
937 if let Some(long) = self.long {
938 return long.sum_64b();
939 }
940 xxh3_64_one_shot(&self.buf[..self.buf_len], self.seed, &self.secret)
941 }
942}
943
944impl core::fmt::Debug for Xxh3_64 {
945 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
946 f.debug_struct("Xxh3_64").finish()
947 }
948}
949
950impl Default for Xxh3_64 {
951 #[inline]
952 fn default() -> Self {
953 Self::with_seed(0)
954 }
955}
956
957#[derive(Clone)]
974pub struct Xxh3_128 {
975 seed: u64,
976 secret: [u8; DEFAULT_SECRET_SIZE],
977 buf: [u8; MID_SIZE_MAX],
978 buf_len: usize,
979 long: Option<LongState>,
980}
981
982impl Xxh3_128 {
983 #[inline]
985 pub const fn with_seed(seed: u64) -> Self {
986 Xxh3_128 {
987 seed,
988 secret: DEFAULT_SECRET,
989 buf: [0u8; MID_SIZE_MAX],
990 buf_len: 0,
991 long: None,
992 }
993 }
994
995 #[inline]
997 pub const fn with_secret(secret: [u8; DEFAULT_SECRET_SIZE]) -> Self {
998 Xxh3_128 {
999 seed: 0,
1000 secret,
1001 buf: [0u8; MID_SIZE_MAX],
1002 buf_len: 0,
1003 long: None,
1004 }
1005 }
1006
1007 #[inline]
1009 pub const fn with_seed_and_secret(seed: u64, secret: [u8; DEFAULT_SECRET_SIZE]) -> Self {
1010 Xxh3_128 {
1011 seed,
1012 secret,
1013 buf: [0u8; MID_SIZE_MAX],
1014 buf_len: 0,
1015 long: None,
1016 }
1017 }
1018}
1019
1020impl Checksum for Xxh3_128 {
1021 type Output = u128;
1022
1023 fn new() -> Self {
1024 Self::with_seed(0)
1025 }
1026
1027 fn checksum(data: &[u8]) -> Self::Output {
1028 if data.len() <= MID_SIZE_MAX {
1029 xxh3_128(data)
1030 } else {
1031 let mut hasher = Self::new();
1032 hasher.update(data);
1033 hasher.sum()
1034 }
1035 }
1036
1037 fn update(&mut self, data: &[u8]) {
1038 if let Some(long) = &mut self.long {
1039 long.update(data);
1040 return;
1041 }
1042
1043 let mut remaining = data;
1044
1045 if self.buf_len < MID_SIZE_MAX {
1046 let take = (MID_SIZE_MAX - self.buf_len).min(remaining.len());
1047 self.buf[self.buf_len..self.buf_len + take].copy_from_slice(&remaining[..take]);
1048 self.buf_len += take;
1049 remaining = &remaining[take..];
1050 }
1051
1052 if self.buf_len >= MID_SIZE_MAX && !remaining.is_empty() {
1053 let long_secret = if self.seed == 0 {
1054 self.secret
1055 } else {
1056 custom_default_secret(self.seed)
1057 };
1058 let mut long = LongState::new(&long_secret);
1059 long.update(&self.buf[..self.buf_len]);
1060 self.long = Some(long);
1061 self.buf_len = 0;
1062
1063 if !remaining.is_empty() {
1064 self.long.as_mut().unwrap().update(remaining);
1065 }
1066 }
1067 }
1068
1069 fn sum(self) -> Self::Output {
1070 if let Some(long) = self.long {
1071 return long.sum_128b();
1072 }
1073 xxh3_128_one_shot(&self.buf[..self.buf_len], self.seed, &self.secret)
1074 }
1075}
1076
1077impl core::fmt::Debug for Xxh3_128 {
1078 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1079 f.debug_struct("Xxh3_128").finish()
1080 }
1081}
1082
1083impl Default for Xxh3_128 {
1084 #[inline]
1085 fn default() -> Self {
1086 Self::with_seed(0)
1087 }
1088}
1089
1090#[inline]
1108pub const fn xxh3_64(data: &[u8]) -> u64 {
1109 xxh3_64_one_shot(data, 0, &DEFAULT_SECRET)
1110}
1111
1112#[inline]
1126pub const fn xxh3_128(data: &[u8]) -> u128 {
1127 xxh3_128_one_shot(data, 0, &DEFAULT_SECRET)
1128}
1129
1130#[cfg(test)]
1135mod tests {
1136 use super::*;
1137 use crate::{Checksum, test_helpers::fill_test_buffer};
1138
1139 const TEST_SEED: u64 = 0x9E3779B185EBCA8D;
1141 const TEST_SEED32: u64 = 0x9E3779B1;
1143
1144 #[test]
1147 fn test_xh3_64_empty() {
1148 assert_eq!(Xxh3_64::checksum(b""), 0x2D06800538D394C2);
1149 }
1150
1151 #[test]
1152 fn test_xh3_64_hello() {
1153 assert_eq!(Xxh3_64::checksum(b"hello"), 0x9555E8555C62DCFD);
1154 }
1155
1156 #[test]
1157 fn test_xh3_64_fox() {
1158 assert_eq!(
1159 Xxh3_64::checksum(b"The quick brown fox jumps over the lazy dog"),
1160 0xCE7D19A5418FB365
1161 );
1162 }
1163
1164 #[test]
1168 fn test_xh3_64_official_vectors() {
1169 let cases: &[(usize, u64, u64)] = &[
1170 (0, 0, 0x2D06800538D394C2),
1171 (0, TEST_SEED, 0xA8A6B918B2F0364A),
1172 (1, 0, 0xC44BDFF4074EECDB),
1173 (1, TEST_SEED, 0x032BE332DD766EF8),
1174 (6, 0, 0x27B56A84CD2D7325),
1175 (6, TEST_SEED, 0x84589C116AB59AB9),
1176 (12, 0, 0xA713DAF0DFBB77E7),
1177 (12, TEST_SEED, 0xE7303E1B2336DE0E),
1178 (24, 0, 0xA3FE70BF9D3510EB),
1179 (24, TEST_SEED, 0x850E80FC35BDD690),
1180 (48, 0, 0x397DA259ECBA1F11),
1181 (48, TEST_SEED, 0xADC2CBAA44ACC616),
1182 (80, 0, 0xBCDEFBBB2C47C90A),
1183 (80, TEST_SEED, 0xC6DD0CB699532E73),
1184 (195, 0, 0xCD94217EE362EC3A),
1185 (195, TEST_SEED, 0xBA68003D370CB3D9),
1186 ];
1187
1188 for &(len, seed, expected) in cases {
1189 let buf = fill_test_buffer(len);
1190 let mut h = Xxh3_64::with_seed(seed);
1191 h.update(&buf);
1192 assert_eq!(h.sum(), expected, "XXH3-64 length {len} seed {seed:#x}");
1193 }
1194 }
1195
1196 #[test]
1198 fn test_xh3_64_byte_at_a_time() {
1199 let cases: &[(usize, u64, u64)] = &[
1200 (0, 0, 0x2D06800538D394C2),
1201 (1, TEST_SEED, 0x032BE332DD766EF8),
1202 (12, 0, 0xA713DAF0DFBB77E7),
1203 (80, TEST_SEED, 0xC6DD0CB699532E73),
1204 ];
1205
1206 for &(len, seed, expected) in cases {
1207 let buf = fill_test_buffer(len);
1208 let mut h = Xxh3_64::with_seed(seed);
1209 for b in &buf {
1210 h.update(&[*b]);
1211 }
1212 assert_eq!(h.sum(), expected, "XXH3-64 byte-at-a-time length {len} seed {seed:#x}");
1213 }
1214 }
1215
1216 #[test]
1218 fn test_xh3_64_boundaries() {
1219 let sizes: &[(usize, u64)] = &[
1220 (0, 0x2D06800538D394C2),
1222 (1, 0xC44BDFF4074EECDB),
1223 (3, 0x54247382A8D6B94D),
1224 (4, 0xE5DC74BC51848A51),
1225 (8, 0x24CCC9ACAA9F65E4),
1226 (16, 0x981B17D36C7498C9),
1227 (17, 0x796F5ACD3A60F862),
1229 (32, 0x9FEADDBDBF57EED3),
1230 (64, 0x9CB48487720EC49D),
1231 (128, 0xFCFF24126754D861),
1232 (129, 0x98F1B0A679A2CA29),
1234 (240, 0x81C3C2B67F568CCF),
1235 ];
1236
1237 for &(len, expected) in sizes {
1238 let buf = fill_test_buffer(len);
1239 let mut h = Xxh3_64::new();
1240 h.update(&buf);
1241 assert_eq!(h.sum(), expected, "XXH3-64 boundary length {len}");
1242 }
1243 }
1244
1245 #[test]
1246 fn test_xh3_64_incremental() {
1247 let mut h = Xxh3_64::new();
1248 h.update(b"The quick brown ");
1249 h.update(b"fox jumps over ");
1250 h.update(b"the lazy dog");
1251 assert_eq!(h.sum(), 0xCE7D19A5418FB365);
1252 }
1253
1254 #[test]
1255 fn test_xh3_64_seeded() {
1256 let mut h = Xxh3_64::with_seed(42);
1257 h.update(b"hello");
1258 assert_eq!(h.sum(), 0xBAFA072F07DB7937);
1259 }
1260
1261 #[test]
1262 fn test_xh3_64_long_incremental() {
1263 let mut h = Xxh3_64::new();
1264 let data = [0x55u8; 512];
1265 h.update(&data[..200]);
1266 h.update(&data[200..400]);
1267 h.update(&data[400..]);
1268 assert_eq!(h.sum(), 0x4C1155EA5825B659);
1269 }
1270
1271 #[test]
1274 fn test_xh3_128_empty() {
1275 assert_eq!(Xxh3_128::checksum(b""), 0x99AA06D3014798D86001C324468D497F);
1276 }
1277
1278 #[test]
1279 fn test_xh3_128_hello() {
1280 assert_eq!(Xxh3_128::checksum(b"hello"), 0xB5E9C1AD071B3E7FC779CFAA5E523818);
1281 }
1282
1283 #[test]
1284 fn test_xh3_128_fox() {
1285 assert_eq!(
1286 Xxh3_128::checksum(b"The quick brown fox jumps over the lazy dog"),
1287 0xDDD650205CA3E7FA24A1CC2E3A8A7651
1288 );
1289 }
1290
1291 #[test]
1294 fn test_xh3_128_official_vectors() {
1295 let cases: &[(usize, u64, u128)] = &[
1296 (0, 0, 0x99AA06D3014798D86001C324468D497F),
1297 (0, TEST_SEED32, 0x92220AE55E14AB505444F7869C671AB0),
1298 (1, 0, 0xA6CD5E9392000F6AC44BDFF4074EECDB),
1299 (1, TEST_SEED32, 0x89B99554BA22467CB53D5557E7F76F8D),
1300 (6, 0, 0x082AFE0B8162D12A3E7039BDDA43CFC6),
1301 (6, TEST_SEED32, 0x5A865B5389ABD2B1269D8F70BE98856E),
1302 (12, 0, 0x6E3EFD8FC7802B18061A192713F69AD9),
1303 (12, TEST_SEED32, 0xD7E09D518A3405D39BE9F9A67F3C7DFB),
1304 (24, 0, 0x0CE966E4678D37611E7044D28B1B901D),
1305 (24, TEST_SEED32, 0x3162026714A6A243D7304C54EBAD40A9),
1306 (48, 0, 0xA002AC4E5478227EF942219AED80F67B),
1307 (48, TEST_SEED32, 0x163ADDE36C0722957BA3C3E453A1934E),
1308 (81, 0, 0x4952F58181AB00425E8BAFB9F95FB803),
1309 (81, TEST_SEED32, 0x2724EC7ADC750FB6703FBB3D7A5F755C),
1310 (222, 0, 0x337E09641B948717F1AEBD597CEC6B3A),
1311 (222, TEST_SEED32, 0x91820016621E97F1AE995BB8AF917A8D),
1312 ];
1313
1314 for &(len, seed, expected) in cases {
1315 let buf = fill_test_buffer(len);
1316 let mut h = Xxh3_128::with_seed(seed);
1317 h.update(&buf);
1318 assert_eq!(h.sum(), expected, "XXH128 length {len} seed {seed:#x}");
1319 }
1320 }
1321
1322 #[test]
1324 fn test_xh3_128_byte_at_a_time() {
1325 let cases: &[(usize, u64, u128)] = &[
1326 (0, 0, 0x99AA06D3014798D86001C324468D497F),
1327 (1, TEST_SEED32, 0x89B99554BA22467CB53D5557E7F76F8D),
1328 (12, 0, 0x6E3EFD8FC7802B18061A192713F69AD9),
1329 ];
1330
1331 for &(len, seed, expected) in cases {
1332 let buf = fill_test_buffer(len);
1333 let mut h = Xxh3_128::with_seed(seed);
1334 for b in &buf {
1335 h.update(&[*b]);
1336 }
1337 assert_eq!(h.sum(), expected, "XXH128 byte-at-a-time length {len} seed {seed:#x}");
1338 }
1339 }
1340
1341 #[test]
1343 fn test_xh3_128_boundaries() {
1344 let sizes: &[(usize, u128)] = &[
1345 (0, 0x99AA06D3014798D86001C324468D497F),
1346 (1, 0xA6CD5E9392000F6AC44BDFF4074EECDB),
1347 (3, 0x20EFC49FF02422EA54247382A8D6B94D),
1348 (4, 0x970D585AC632BF8E2E7D8D6876A39FE9),
1349 (8, 0x47A7F080D82BB45664C69CAB4BB21DC5),
1350 (16, 0xC68C368ECF8A9C05562980258A998629),
1351 (17, 0x955FA78643ED3669ABBC12D11973D7DB),
1352 (32, 0x98FC6458710DC2E8278410A17595E3F9),
1353 (240, 0xAA4202DAA2769DC85C9AAE94C8EBE5A0),
1354 ];
1355
1356 for &(len, expected) in sizes {
1357 let buf = fill_test_buffer(len);
1358 let mut h = Xxh3_128::new();
1359 h.update(&buf);
1360 assert_eq!(h.sum(), expected, "XXH128 boundary length {len}");
1361 }
1362 }
1363
1364 #[test]
1365 fn test_xh3_128_incremental() {
1366 let mut h = Xxh3_128::new();
1367 h.update(b"The quick brown ");
1368 h.update(b"fox jumps over ");
1369 h.update(b"the lazy dog");
1370 assert_eq!(h.sum(), 0xDDD650205CA3E7FA24A1CC2E3A8A7651);
1371 }
1372
1373 #[test]
1374 fn test_xh3_128_long_incremental() {
1375 let mut h = Xxh3_128::new();
1376 let data = [0x55u8; 512];
1377 h.update(&data[..200]);
1378 h.update(&data[200..400]);
1379 h.update(&data[400..]);
1380 assert_eq!(h.sum(), 0x0DD2485B0318DEF24C1155EA5825B659);
1381 }
1382
1383 #[test]
1386 fn test_const_fn_xh3_64() {
1387 assert_eq!(xxh3_64(b""), Xxh3_64::checksum(b""));
1388 assert_eq!(xxh3_64(b"hello"), Xxh3_64::checksum(b"hello"));
1389 assert_eq!(
1390 xxh3_64(b"The quick brown fox jumps over the lazy dog"),
1391 Xxh3_64::checksum(b"The quick brown fox jumps over the lazy dog")
1392 );
1393 let buf = &[0x42u8; 200];
1396 assert_eq!(xxh3_64(buf), Xxh3_64::checksum(buf));
1397 }
1398
1399 #[test]
1402 fn test_const_fn_xh3_128() {
1403 assert_eq!(xxh3_128(b""), Xxh3_128::checksum(b""));
1404 assert_eq!(xxh3_128(b"hello"), Xxh3_128::checksum(b"hello"));
1405 assert_eq!(
1406 xxh3_128(b"The quick brown fox jumps over the lazy dog"),
1407 Xxh3_128::checksum(b"The quick brown fox jumps over the lazy dog")
1408 );
1409 let buf = &[0x42u8; 200];
1410 assert_eq!(xxh3_128(buf), Xxh3_128::checksum(buf));
1411 }
1412}