1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), no_std)]
3#![forbid(unsafe_code)]
4
5extern crate alloc;
6
7use alloc::vec::Vec;
8use core::hash::Hasher;
9
10#[derive(Clone, Debug)]
45pub struct PolymurHash {
46 k: u64,
47 k2: u64,
48 k7: u64,
49 s: u64,
50}
51
52impl PolymurHash {
53 pub fn new(seed: u128) -> Self {
67 let k_seed = seed as u64;
68 let s_seed = (seed >> 64) as u64;
69 Self::from_u64x2_seed(k_seed, s_seed)
70 }
71
72 pub fn from_u64_seed(seed: u64) -> Self {
88 let k_seed = Self::mix(seed.wrapping_add(POLYMUR_ARBITRARY3));
89 let s_seed = Self::mix(seed.wrapping_add(POLYMUR_ARBITRARY4));
90 Self::from_u64x2_seed(k_seed, s_seed)
91 }
92
93 pub fn from_u64x2_seed(mut k_seed: u64, s_seed: u64) -> Self {
110 let s = s_seed ^ POLYMUR_ARBITRARY1;
111 let mut pow37 = [0u64; 64];
112 pow37[0] = 37;
113 pow37[32] = 559096694736811184;
114 for i in 0..31 {
115 pow37[i + 1] = extrared611(red611(mul128(pow37[i], pow37[i])));
116 pow37[i + 33] = extrared611(red611(mul128(pow37[i + 32], pow37[i + 32])));
117 }
118
119 'retry: loop {
120 k_seed = k_seed.wrapping_add(POLYMUR_ARBITRARY2);
121 let mut e = (k_seed >> 3) | 1;
122 const PRIMES: [u64; 11] = [3, 5, 7, 11, 13, 31, 41, 61, 151, 331, 1321];
123 for &p in PRIMES.iter() {
124 if (e % p) == 0 {
125 continue 'retry;
126 }
127 }
128 let (mut ka, mut kb): (u64, u64) = (1, 1);
129 let mut i: usize = 0;
130 while e > 0 {
131 if (e & 1) != 0 {
132 ka = extrared611(red611(mul128(ka, pow37[i])));
133 }
134 if (e & 2) != 0 {
135 kb = extrared611(red611(mul128(kb, pow37[i + 1])));
136 }
137 e >>= 2;
138 i += 2;
139 }
140 let k = extrared611(extrared611(red611(mul128(ka, kb))));
141 let k2 = extrared611(red611(mul128(k, k)));
142 let k3 = red611(mul128(k, k2));
143 let k4 = red611(mul128(k2, k2));
144 let k7 = extrared611(red611(mul128(k3, k4)));
145 if k7 < (1_u64 << 60) - (1_u64 << 56) {
146 return Self { k, k2, k7, s };
147 }
148 }
149 }
150
151 pub fn hash_with_tweak(&self, buf: impl AsRef<[u8]>, tweak: u64) -> u64 {
174 let h = self.poly1611(buf, tweak);
175 Self::mix(h).wrapping_add(self.s)
176 }
177
178 pub fn hash(&self, buf: impl AsRef<[u8]>) -> u64 {
197 let h = self.poly1611(buf, 0);
198 Self::mix(h).wrapping_add(self.s)
199 }
200
201 fn poly1611(&self, buf: impl AsRef<[u8]>, tweak: u64) -> u64 {
202 let mut buf = buf.as_ref();
203 let mut m = [0u64; 7];
204 let mut poly_acc = tweak;
205 if buf.len() <= 7 {
206 m[0] = le_u64_0_8(buf);
207 return poly_acc.wrapping_add(red611(mul128(
208 self.k.wrapping_add(m[0]),
209 self.k2.wrapping_add(buf.len() as u64),
210 )));
211 }
212
213 let k3 = red611(mul128(self.k, self.k2));
214 let k4 = red611(mul128(self.k2, self.k2));
215 if buf.len() >= 50 {
216 let k5 = extrared611(red611(mul128(self.k, k4)));
217 let k6 = extrared611(red611(mul128(self.k2, k4)));
218 let k3 = extrared611(k3);
219 let k4 = extrared611(k4);
220 let mut h: u64 = 0;
221 loop {
222 for i in 0..7 {
223 let mut tmp = [0u8; 8];
224 tmp.copy_from_slice(&buf[7 * i..][..8]);
225 m[i] = u64::from_le_bytes(tmp) & 0x00ffffffffffffff;
226 }
227 let t0 = mul128(self.k + m[0], k6 + m[1]);
228 let t1 = mul128(self.k2 + m[2], k5 + m[3]);
229 let t2 = mul128(k3 + m[4], k4 + m[5]);
230 let t3 = mul128(h + m[6], self.k7);
231 let s = t0.wrapping_add(t1).wrapping_add(t2).wrapping_add(t3);
232 h = red611(s);
233 buf = &buf[49..];
234 if buf.len() < 50 {
235 break;
236 }
237 }
238 let k14 = red611(mul128(self.k7, self.k7));
239 let hk14 = red611(mul128(extrared611(h), k14));
240 poly_acc += extrared611(hk14);
241 }
242
243 if buf.len() >= 8 {
244 let mut tmp = [0u8; 8];
245 tmp.copy_from_slice(&buf[..8]);
246 m[0] = u64::from_le_bytes(tmp) & 0x00ffffffffffffff;
247 tmp.copy_from_slice(&buf[(buf.len() - 7) / 2..][0..8]);
248 m[1] = u64::from_le_bytes(tmp) & 0x00ffffffffffffff;
249 tmp.copy_from_slice(&buf[buf.len() - 8..][0..8]);
250 m[2] = u64::from_le_bytes(tmp) >> 8;
251 let t0 = mul128(self.k2 + m[0], self.k7.wrapping_add(m[1]));
252 let t1 = mul128(self.k + m[2], k3.wrapping_add(buf.len() as _));
253 if buf.len() <= 21 {
254 return poly_acc + red611(t0.wrapping_add(t1));
255 }
256 tmp.copy_from_slice(&buf[7..][0..8]);
257 m[3] = u64::from_le_bytes(tmp) & 0x00ffffffffffffff;
258 tmp.copy_from_slice(&buf[14..][0..8]);
259 m[4] = u64::from_le_bytes(tmp) & 0x00ffffffffffffff;
260 tmp.copy_from_slice(&buf[buf.len() - 21..][0..8]);
261 m[5] = u64::from_le_bytes(tmp) & 0x00ffffffffffffff;
262 tmp.copy_from_slice(&buf[buf.len() - 14..][0..8]);
263 m[6] = u64::from_le_bytes(tmp) & 0x00ffffffffffffff;
264 let t0r = red611(t0);
265 let t2 = mul128(self.k2 + m[3], self.k7 + m[4]);
266 let t3 = mul128(t0r + m[5], k4 + m[6]);
267 let s = t1.wrapping_add(t2).wrapping_add(t3);
268 return poly_acc.wrapping_add(red611(s));
269 }
270
271 m[0] = le_u64_0_8(buf);
272 poly_acc.wrapping_add(red611(mul128(
273 self.k.wrapping_add(m[0]),
274 self.k2.wrapping_add(buf.len() as _),
275 )))
276 }
277
278 #[inline(always)]
279 fn mix(mut x: u64) -> u64 {
280 x ^= x >> 32;
281 x = x.wrapping_mul(0xe9846af9b1a615d);
282 x ^= x >> 32;
283 x = x.wrapping_mul(0xe9846af9b1a615d);
284 x ^= x >> 28;
285 x
286 }
287}
288
289const POLYMUR_P611: u64 = 0x1fffffffffffffff;
290const POLYMUR_ARBITRARY1: u64 = 0x6a09e667f3bcc908;
291const POLYMUR_ARBITRARY2: u64 = 0xbb67ae8584caa73b;
292const POLYMUR_ARBITRARY3: u64 = 0x3c6ef372fe94f82b;
293const POLYMUR_ARBITRARY4: u64 = 0xa54ff53a5f1d36f1;
294
295#[derive(Clone, Debug)]
316pub struct PolymurHasher {
317 hasher: PolymurHash,
318 buffer: Vec<u8>,
319}
320
321impl Default for PolymurHasher {
322 fn default() -> Self {
323 Self {
324 hasher: PolymurHash::new(0),
325 buffer: Vec::new(),
326 }
327 }
328}
329
330impl PolymurHasher {
331 pub fn with_seed(seed: u128) -> Self {
333 Self {
334 hasher: PolymurHash::new(seed),
335 buffer: Vec::new(),
336 }
337 }
338}
339
340impl Hasher for PolymurHasher {
341 fn finish(&self) -> u64 {
342 self.hasher.hash(&self.buffer)
343 }
344
345 fn write(&mut self, bytes: &[u8]) {
346 self.buffer.extend_from_slice(bytes);
347 }
348
349 fn write_u8(&mut self, i: u8) {
350 self.buffer.push(i);
351 }
352
353 fn write_u16(&mut self, i: u16) {
354 self.buffer.extend_from_slice(&i.to_le_bytes());
355 }
356
357 fn write_u32(&mut self, i: u32) {
358 self.buffer.extend_from_slice(&i.to_le_bytes());
359 }
360
361 fn write_u64(&mut self, i: u64) {
362 self.buffer.extend_from_slice(&i.to_le_bytes());
363 }
364
365 fn write_u128(&mut self, i: u128) {
366 self.buffer.extend_from_slice(&i.to_le_bytes());
367 }
368
369 fn write_usize(&mut self, i: usize) {
370 self.buffer.extend_from_slice(&i.to_le_bytes());
371 }
372
373 fn write_i8(&mut self, i: i8) {
374 self.write_u8(i as u8);
375 }
376
377 fn write_i16(&mut self, i: i16) {
378 self.write_u16(i as u16);
379 }
380
381 fn write_i32(&mut self, i: i32) {
382 self.write_u32(i as u32);
383 }
384
385 fn write_i64(&mut self, i: i64) {
386 self.write_u64(i as u64);
387 }
388
389 fn write_i128(&mut self, i: i128) {
390 self.write_u128(i as u128);
391 }
392
393 fn write_isize(&mut self, i: isize) {
394 self.write_usize(i as usize);
395 }
396}
397
398#[inline(always)]
399fn mul128(a: u64, b: u64) -> u128 {
400 (a as u128) * (b as u128)
401}
402
403#[inline(always)]
404fn red611(x: u128) -> u64 {
405 ((x as u64) & POLYMUR_P611) + ((x >> 61) as u64)
406}
407
408#[inline(always)]
409fn extrared611(x: u64) -> u64 {
410 (x & POLYMUR_P611) + (x >> 61)
411}
412
413#[inline(always)]
414fn le_u64_0_8(buf: &[u8]) -> u64 {
415 let len = buf.len();
416 if len < 4 {
417 if len == 0 {
418 return 0;
419 }
420 let mut v = buf[0] as u64;
421 v |= (buf[len / 2] as u64) << (8 * (len / 2));
422 v |= (buf[len - 1] as u64) << (8 * (len - 1));
423 return v;
424 }
425
426 let mut tmp = [0u8; 4];
427 tmp.copy_from_slice(&buf[0..4]);
428 let lo = u32::from_le_bytes(tmp) as u64;
429 tmp.copy_from_slice(&buf[len - 4..][..4]);
430 let hi = u32::from_le_bytes(tmp) as u64;
431
432 lo | (hi << (8 * (len - 4)))
433}
434
435#[cfg(test)]
436mod tests {
437 use super::*;
438
439 #[test]
440 fn test_edge_cases() {
441 let hasher = PolymurHash::new(0);
442
443 assert_eq!(hasher.hash(b""), hasher.hash([]));
445
446 assert_ne!(hasher.hash(b"a"), hasher.hash(b"b"));
448
449 let hasher2 = PolymurHash::new(0xDEADBEEFCAFEBABE);
451 assert_ne!(hasher.hash(b"test"), hasher2.hash(b"test"));
452
453 let data = b"test data";
455 assert_ne!(
456 hasher.hash_with_tweak(data, 0),
457 hasher.hash_with_tweak(data, 1)
458 );
459 assert_eq!(hasher.hash(data), hasher.hash_with_tweak(data, 0));
460 }
461
462 #[test]
463 fn test_different_lengths() {
464 let hasher = PolymurHash::new(42);
465
466 let lengths = [
468 0, 1, 2, 3, 4, 5, 6, 7, 8, 15, 16, 31, 32, 48, 49, 50, 63, 64, 127, 128, 255, 256,
469 1023, 1024,
470 ];
471
472 for &len in &lengths {
473 let data = vec![0xABu8; len];
474 let hash = hasher.hash(&data);
475
476 if len > 0 {
478 let mut modified = data.clone();
479 modified[len / 2] = 0xCD;
480 assert_ne!(
481 hash,
482 hasher.hash(&modified),
483 "Hash collision at length {}",
484 len
485 );
486 }
487 }
488 }
489
490 #[test]
491 fn test_seed_variants() {
492 let data = b"test data for seed variants";
493
494 let seed_high = 0x123456789ABCDEF0_u64;
496 let seed_low = 0x0123456789ABCDEF0_u64;
497 let seed_128 = ((seed_high as u128) << 64) | (seed_low as u128);
498 let h1 = PolymurHash::new(seed_128);
499 let h2 = PolymurHash::from_u64x2_seed(seed_low, seed_high);
500
501 assert_eq!(h1.hash(data), h2.hash(data));
503
504 let h3 = PolymurHash::from_u64_seed(0x123456789ABCDEF0);
506 assert_ne!(h1.hash(data), h3.hash(data));
507 }
508
509 #[test]
510 fn test_hasher_trait() {
511 use core::hash::{Hash, Hasher as _};
512
513 let mut hasher1 = PolymurHasher::default();
514 let mut hasher2 = PolymurHasher::default();
515
516 "Hello, world!".hash(&mut hasher1);
518 "Hello, world!".hash(&mut hasher2);
519
520 assert_eq!(hasher1.finish(), hasher2.finish());
521
522 let mut hasher3 = PolymurHasher::default();
524 let mut hasher4 = PolymurHasher::default();
525
526 42u32.hash(&mut hasher3);
527 hasher4.write_u32(42);
528
529 assert_eq!(hasher3.finish(), hasher4.finish());
530 }
531
532 #[test]
533 fn test_hashmap_integration() {
534 use core::hash::BuildHasherDefault;
535 use std::collections::HashMap;
536
537 type PolymurHashMap<K, V> = HashMap<K, V, BuildHasherDefault<PolymurHasher>>;
538
539 let mut map: PolymurHashMap<String, i32> = PolymurHashMap::default();
540
541 map.insert("foo".to_string(), 42);
542 map.insert("bar".to_string(), 123);
543 map.insert("baz".to_string(), 456);
544
545 assert_eq!(map.get("foo"), Some(&42));
546 assert_eq!(map.get("bar"), Some(&123));
547 assert_eq!(map.get("baz"), Some(&456));
548 assert_eq!(map.get("qux"), None);
549 }
550
551 #[test]
552 fn test() {
553 let mut t = 0;
554
555 for i in 0..1000 {
556 let hasher = PolymurHash::new(i as u128 * 0x419a02900419a02900419a02900419);
557 let mut size = 1;
558 loop {
559 let mut m = vec![0u8; size];
560 m.iter_mut().for_each(|x| *x = i as u8);
561 let res = hasher.hash(&m);
562 t += res as u128;
563 debug_assert!(t != 0);
564 if size >= 65536 {
565 break;
566 }
567 size *= 2;
568 }
569
570 let hasher = PolymurHash::from_u64_seed(i * 0x419a02900419a0);
571 let mut size = 1;
572 loop {
573 let mut m = vec![0u8; size];
574 m.iter_mut().for_each(|x| *x = i as u8);
575 let res = hasher.hash(&m);
576 t += res as u128;
577 debug_assert!(t != 0);
578 if size >= 65536 {
579 break;
580 }
581 size *= 3;
582 }
583 }
584
585 assert_eq!(t, 0x38e01175b44e95e6e0f6);
586 }
587
588 #[test]
589 fn test_vectors() {
590 const POLYMUR_TEST_STRINGS: [&str;100] = [
593 "",
594 "i",
595 "es",
596 "vca",
597 "bdxa",
598 "bbbmc",
599 "vn5719",
600 "lpvif62",
601 "1fcjgark",
602 "1jlz2nr6w",
603 "g4q6ebxvod",
604 "ehiybujo2n1",
605 "6u2990ulzi7m",
606 "c3xcb4ew8v678",
607 "bhcaqrm221pea1",
608 "oyl3iqxqr85eeve",
609 "b41kacwmnim8rup5",
610 "563ug64z3zdtlj438",
611 "3spvl57qfg4udw2l3s",
612 "297r1bqesqdhb3jd50g",
613 "kbc5btot9x1fqslddmha",
614 "r0vxw6kk8tc6pk0oxnr6m",
615 "wkgmmma9icgky3bnj5bjir",
616 "5eslfmq1w3i7wvd89ls7nvf",
617 "40ytv0ye8cq49no6ys1pdrot",
618 "p3mbto6bl36g3cx9sstyiugsd",
619 "m0ylpn0wh5krbebs0j5trzgveb",
620 "qsy8gpheo76vb8g0ivaojk1zgk4",
621 "dwqf8tpad4k3x69sah7pstrg8zxx",
622 "ls3zrsjf1o3cr5sjy7dzp98198i3y",
623 "xvhvx3wbzer9b7kr4jqg2ok9e3mv5d",
624 "yapzlwab361wvh0xf1rydn5ynqx8cz0",
625 "nj56v1p9dc7qdmcn2wksfg5kic1uegm2",
626 "hlebeoafjqtqxfwd9ge94z3ofk88c4a5x",
627 "6li8qyu0n8nwoggm4hqzqdamem5barzjyw",
628 "wj7sp7dhpfapsd8w2nzn8s7xtnro9g45x7t",
629 "ahio6so1x30oziw54ux5iojjdfvkwpw2v14d",
630 "wm6yacnl6k3kj3c6i1jeajuwmquv9yujms0wq",
631 "kzs6xfhmc4ifmstnekcze4y1l83ddvxust2r0o",
632 "ckamexupx7cmsuza9nssw6n45e7go4s3osr1903",
633 "nob5bj9tok346dg62jbfjfrhg5l6itsno2hkhfru",
634 "vgo0ko42n5jvrvnv3ddpwg8h7gkqoxbllv2fdy0no",
635 "dgs47djqzq3czo0i0v1u3d3x72vtvi3w2tsf9shx6k",
636 "8vjrw7jz90kf969txb5qrh0u5332zf5epsp8aes4aqh",
637 "3ni9vtqiq6vnxipfa2wag8vfwq2nyce1kgq5nj3razx9",
638 "u29xjkod6rtu5j5tlwkydt9khih6o2do84q6ukwlr00xf",
639 "yxxubvyxuusw827qctqr6tmm69rij5ex2zk1etps8qh61e",
640 "p7lh4mvadnp6uw0vt7bnzcbv1wjswuuc6gjmu684yznx8lp",
641 "8c27lotvnab6ra8pq9aon0w30ydyulesinew3akqrhhmm39e",
642 "ttipbm97gpk7tiog1doncalwgpb7alk16dapga2ekzjt59pv6",
643 "mbbtplseab2mgtgh8uwlhbmdrwxae3tc2mtf98bwuhmz4bfjnf",
644 "shnjeydnj8awrkz3rd69wqqd9srie4eo6gc6ylhz2ouv4t4qbar",
645 "lckl12agnpr6q5053h9v38lyk71emkvwdzrv0ic3a4a4pn3w3o4x",
646 "7927wqjo5jiecfk0bbtt6065j5jl7x0vv1mcxxxl0j1oatrom44zp",
647 "bajk3ff026vx0u7o5d7ry7w7n07sqdy4urv4psr79jp13e0mxsks1r",
648 "en6j5o90gmgj7ssbz6jv3kzdsbzczu518c3zmezkp02rtvo1s88n9pu",
649 "58fkwyf44tjnrytgplb5qfbvlwtav3zutxowoor2mklkr2up4nzpefos",
650 "cep02qfl6swv1j3mwy5kprm4p8drszchufrkyr5ejbtzgu5cti6fqab5c",
651 "lr5q0p1dljga8h4vruy1doa79hntwbdyolnh1fbe3phfk7f5rgs4815foj",
652 "hmnjq6h1sslivjzmbxbpqba29f6kvbea6n6c4sanm40nzmrxt8hm61ooq3e",
653 "ae43xxu1mqrbynmctit7m4wf02o0kf2vvw1l3y51n4cu5v5ba4dia67wf0bo",
654 "qz9ye2ur849obmm23d5tnfc3xdaeajil0gm2pz8z9psedj50h5hcwbcn8n2lo",
655 "w3xar1pzaff7fhyw6cshdgechm2pj1ebwrbkdct5xfbmxskr3937dodvky62i8",
656 "ypy5k197quc9ypqoj9kle2eky307jnnd7tu52hqhn6mo7jj1fvmi42kkgq40iy6",
657 "k1bp6qwiul8fnd6rfe42ge6gskk0jkr9fjgmuujey3kn8ie88h9qguw2gboo7i80",
658 "begb64jkzfujx7ch3ain1iixidnbhcbcglcuf7nys8eansnkewtiye9xv7s2ksuev",
659 "vf5d8vdjtwp5vo1ocb274nkl6h8vg97m4v5htfwv02tj9u68vdnteeim6q0zllxflj",
660 "dcg9osulcdw9sqaue4cfz6k990vpstoxmvwbxzhzichkhdujy36v556u7oxug51gdup",
661 "1rtgdtibcaos4ebzrbl1fkjahtbel6fyqipuu8lxfrwnggjr8wgoscfxp46wv9wjk315",
662 "r27qj342zj4anpkqpr9yqo7udnldwiqqpq667zzjgw33yia3wt2p6t221onq4pvfaywbj",
663 "2yzxskad06pt9zvjmiobfz12a3q6wqgpj4450rpxj0jvjk3cx39qo6cbpukxqsy6idqd40",
664 "813zultj26k3gn6gibolpuozgaxu8exfatf4iqqugelcf6k8dnzvsjb9s25g3gyess2uscc",
665 "i4p0jkxf3ajc02x330y3tg8l521fzootabn53ovru20ph3n17hfygaz1axs61jxipz6jac5z",
666 "5bk748kkvww7toeyeueukk2qyin2o5ohnvj7l1cqs9zgy92n6ujxg6sxdjw81hfd29nzrb4kh",
667 "uvhy62avo1wqms1rrtefth84xhnv1a59aez6r4xq0pla74036o3vznihxexwydnfjojmk6ipl6",
668 "0t0dlfopg27cqv1xp4qfgwdlivvgqz204hkh5ianbb4abgk0yjolcwhhitrcksha5s6otmps0hd",
669 "vrbhcwrmn5xbq8f518ntvmaeg89n7nh1uxebfsmd7smoog3k2w12zv0px32pf4b78er5f3pgy7b9",
670 "x5bmnefocbtxm8avt22ekuy5hcdyxh86is5fnns9ycfm7o25x9frwv9kfv2ohyd3txlc8zlg5rjjx",
671 "ttfrgnfvvj552vjymrqqd1yjlyff7vkffprnvu3co4vuah8y0s56tziih3yowm64ja810gb1sgk0um",
672 "a66t43i9vrr3cmg5qf52akuk8bxl4rm3i86rm7h5brjou9k2egrzy3h19hh8kqr2queyvrwb673qikj",
673 "mfuwhbvd88n21obpmwx273mmeqiz98qfmb04z0ute54kc1d9bbdyfbx2sc4em6t4pfektm05qs7bgc9z",
674 "x8wbm0kjpyua8wpgsejgxc06geitm1c0bxihvcwnxnif63dj7cygzk7led0z49ol6zf2xwcmf99n4osip",
675 "fvba43myr0ozab882crozdz0zx4lfl2h7xe2phfqte97g58fake2fzi87mpftz9qdmt45gm79xl43k1hji",
676 "wnr0pz08rm3j65b7pl116l59pxy6prnydf9xod1qdi3hp3lod2vuzy1v7gt2g72sejaomn5u53daxjrr9xk",
677 "bwo7nfqda6w56voyvg1nr7vkq61zi7gy0aggn6pic3gup7uy18zzsc7y5yz3ptvp5cd53i95dj521k4n6n7t",
678 "mromebynw459uydhhgcgrate6hnst5srng9knfjc02vtg1vywok3rdbw935pf1qwghnh0nibyb60l9elkmajg",
679 "59dcjawsd4kjjcceco3hphizua88l0qtrfd000iam3rnb4tmy6kzf5bhkc9ud1hsg3dd53tlsxarcl0n59081h",
680 "odgdgfkwcpz0zjcwsz9is5h4nhebzht7fqa1b4g8e2snb6bn5hu3ixyd2pk1ey5g3eab0m3aoknfi9ctkpxz07j",
681 "0ljqm7r10ns2pjo8x69oi0zuqss9y7301yd6rmex8djwrbqmvh2mbwscgj9pmrgul5ao0tvpefpe5a9cac5xbdwb",
682 "b449ak3ihp8tdrbteffru5vboeh1z63c55at3qz70p13d2fim50q8i06zjyb53i4gqzunx6rsl07jxjd9g77me1ww",
683 "oqzf6c40snvrjz4v0f4h8p0ozjfy1y4xihxwaz16vbxf3qsa805xodw8z5xq3hb7dag8fnxtlsc62150kk253i3buj",
684 "2eicp9a5aq2uycq55y7rsixlg3pfk7gyin65fghf03kks18dixbckxmbv5xnhyrir7qm8maz4rk2bi3zs9chidlhehf",
685 "7k1wyjs6fxss4e0ywqfurgop6f7y7e97f3mr5hnb0hlhqkqbqvi1e1z3qfyxc3te75r67fc4h9li06rl9zadg3v9zmz6",
686 "k3e403zdtia8i0gpodm00yaujr1w474bh3985o3csbfjp3dll4t98i5lesloo6rqjec2aycb3ttx1t6lg0cl9hrjkgheb",
687 "2fv8zdl1ljmpjbvaan0nt99tra48yjmc5pv91n1c5l8qp5pv77zwsx75ouay7bmgy2tjc1aazyu5zj7oimesavv9n2h7ky",
688 "ghxs7uejpzpbxjsdmc2w9fabrg4j4pwwbn0wjxux2luk1k0ciror4gcvww18e610u2wpczuwrcphy2xr1129vweqhhgitge",
689 "vk7wfi9hhi0j9n2grs8rxgq68kw54dbdviuxnvtwgz77h0qkbzqw7pgm7zgn21cxlxnyzigeyz2rzrj3awloq86tqe60e070",
690 "d1aot9216s547uk1rg651iscb1bjpgth5j4f6arx1902npcykk8niz3ffpbed47idgzvt4u59fyi5e0e2afpjb5gjk4rysn8j",
691 "2jef2xl4o9yub0z6jnxu8gm87g9iv9zdtu9yolvxtensjrtgplnmnuhz43nsxztk8s936k6eruckkiwc5hnch4qdzft093986x",
692 "oo70ed77jci4bgodhnyf37axrx4f8gf8qs94f4l9xi9h0jkdl2ozoi2p7q7qu1945l21dzj6rhvqearzrmblfo3ljjldj0m9fue",
693];
694
695 const POLYMUR_REFERENCE_VALUES: [u64; 100] = [
696 0x1a6ef9f9d6c576fb,
697 0xd16d059771c65e13,
698 0x5ee4e0c09f562f87,
699 0x535b5311db007b0b,
700 0xd17124f14bd16b5d,
701 0xe84c87105c5b5cad,
702 0xb16ce684b89df9c0,
703 0x656525cace200667,
704 0x92b460794885d16d,
705 0xe6cc0fd9725b46b9,
706 0xc875ade1929bc93d,
707 0x68a2686ced37268a,
708 0x1d1809fd7e7e14ef,
709 0x699b8f31fc40c137,
710 0xd10dca2605654d2d,
711 0xd6bc75cb729f18d7,
712 0xfe0c617e7cb1bffe,
713 0xf5f14c731c1b9a22,
714 0x7a0382228d248631,
715 0x6c3a5f49d8a48bc0,
716 0x3606ebe637bb4ebc,
717 0xeb4854d75431ad1d,
718 0xfa8ff1a34793ebb0,
719 0x7e46ad8e2338cc38,
720 0xf8ff088ada3154b4,
721 0x706669bf0925914f,
722 0x70fc5fbcd3485ace,
723 0x96fd279baed2f2ab,
724 0x6403a64c68d7bf68,
725 0x3f8f532e1df472e5,
726 0xbfc49c083515596f,
727 0xd678a4b338fbf03b,
728 0x127142a2f38b70a1,
729 0x8a1a56fbb85b71f6,
730 0x961d22b14e6f1932,
731 0xa166b0326c942c30,
732 0x0f3d837dddb86ae2,
733 0x0f8164504b4ea8b1,
734 0xe4f6475d5a739af4,
735 0xbf535ad625c0d51f,
736 0x47f10a5a13be50ad,
737 0x3dc5ce9c148969b3,
738 0x8dc071fb4df8e144,
739 0x9d0a83586cbed3b8,
740 0xc4379e22f2809b99,
741 0x42010c7dd7657650,
742 0xcc31a6fbcdab8be8,
743 0x7bad06c38400138a,
744 0x0178b41584eb483d,
745 0x78afc38d52514efc,
746 0x65a57c4e59288dc7,
747 0x86e7cc3e273e4e47,
748 0xeb99661fb41a6bd2,
749 0xea0979aa6cd70feb,
750 0xa64a347c0b8e007b,
751 0x3692969270fe8fa4,
752 0x17640c6052e26555,
753 0xdf9e0fd276291357,
754 0x64cca6ebf4580720,
755 0xf82b33f6399c3f49,
756 0xbe3ccb7526561379,
757 0x8c796fce8509c043,
758 0x9849fded8c92ce51,
759 0xa0e744d838dbc4ef,
760 0x8e4602d33a961a65,
761 0xda381d6727886a7e,
762 0xa503a344fc066833,
763 0xbf8ff5bc36d5dc7b,
764 0x795ae9ed95bca7e9,
765 0x19c80807dc900762,
766 0xea7d27083e6ca641,
767 0xeba7e4a637fe4fb5,
768 0x34ac9bde50ce9087,
769 0xe290dd0393f2586a,
770 0xbd7074e9843d9dca,
771 0x66c17140a05887e6,
772 0x4ad7b3e525e37f94,
773 0xde0d009c18880dd6,
774 0x1516bbb1caca46d3,
775 0xe9c907ec28f89499,
776 0xd677b655085e1e14,
777 0xac5f949b08f29553,
778 0xd353b06cb49b5503,
779 0x9c25eb30ffa8cc78,
780 0x6cf18c91658e0285,
781 0x99264d2b2cc86a77,
782 0x8b438cd1bb8fb65d,
783 0xdfd56cf20b217732,
784 0x71f4e35bf761bacf,
785 0x87d7c01f2b11659c,
786 0x95de608c3ad2653c,
787 0x51b50e6996b8de93,
788 0xd21e837b2121e8c9,
789 0x73d07c7cb3fa0ba7,
790 0x8113fab03cab6df3,
791 0x57cdddea972cc490,
792 0xc3df94778f1eec30,
793 0x7509771e4127701e,
794 0x28240c74c56f8f7c,
795 0x194fa4f68aab8e27,
796 ];
797
798 let hasher = PolymurHash::from_u64_seed(0xfedbca9876543210);
799 let tweak = 0xabcdef0123456789;
800 for (i, s) in POLYMUR_TEST_STRINGS.iter().enumerate() {
801 let hash = hasher.hash_with_tweak(s.as_bytes(), tweak);
802 assert_eq!(
803 POLYMUR_REFERENCE_VALUES[i], hash,
804 "i={}; expected={:x}; got={:x}",
805 i, POLYMUR_REFERENCE_VALUES[i], hash
806 );
807 }
808 }
809}