1use crate::util::mix::{rapid_mix, rapid_mum};
2use crate::util::read::{read_u32_combined, read_u64};
3use super::{DEFAULT_RAPID_SECRETS, RapidSecrets};
4
5#[inline]
7pub const fn rapidhash_v1(data: &[u8]) -> u64 {
8 rapidhash_v1_inline::<true, false, false, false>(data, &DEFAULT_RAPID_SECRETS)
9}
10
11#[inline]
13pub const fn rapidhash_v1_seeded(data: &[u8], secrets: &RapidSecrets) -> u64 {
14 rapidhash_v1_inline::<true, false, false, false>(data, secrets)
15}
16
17#[inline(always)]
32pub const fn rapidhash_v1_inline<const AVALANCHE: bool, const COMPACT: bool, const PROTECTED: bool, const V1_BUG: bool>(data: &[u8], secrets: &RapidSecrets) -> u64 {
33 rapidhash_core::<AVALANCHE, COMPACT, PROTECTED, V1_BUG>(secrets.seed, &secrets.secrets, data)
34}
35
36#[inline(always)]
37pub(super) const fn rapidhash_core<const AVALANCHE: bool, const COMPACT: bool, const PROTECTED: bool, const V1_BUG: bool>(mut seed: u64, secrets: &[u64; 3], data: &[u8]) -> u64 {
38 let mut a = 0;
39 let mut b = 0;
40
41 seed ^= data.len() as u64;
42
43 if data.len() <= 16 {
44 if data.len() >= 8 {
50 let plast = data.len() - 4;
52 let delta = 4;
53 a ^= read_u32_combined(data, 0, plast);
54 b ^= read_u32_combined(data, delta, plast - delta);
55 } else if data.len() >= 4 {
56 let plast = data.len() - 4;
57 let delta = 0;
58 a ^= read_u32_combined(data, 0, plast);
59 b ^= read_u32_combined(data, delta, plast - delta);
60 } else if !data.is_empty() {
61 let len = data.len();
63 a ^= ((data[0] as u64) << 56) | ((data[len >> 1] as u64) << 32) | data[len - 1] as u64;
64 }
66 } else {
67 let mut slice = data;
68
69 if slice.len() > 48 || V1_BUG {
74 let mut see1 = seed;
76 let mut see2 = seed;
77
78 if !COMPACT {
79 while slice.len() >= 96 {
80 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[0], read_u64(slice, 8) ^ seed);
81 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[1], read_u64(slice, 24) ^ see1);
82 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 32) ^ secrets[2], read_u64(slice, 40) ^ see2);
83 seed = rapid_mix::<PROTECTED>(read_u64(slice, 48) ^ secrets[0], read_u64(slice, 56) ^ seed);
84 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 64) ^ secrets[1], read_u64(slice, 72) ^ see1);
85 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 80) ^ secrets[2], read_u64(slice, 88) ^ see2);
86 let (_, split) = slice.split_at(96);
87 slice = split;
88 }
89 if slice.len() >= 48 {
90 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[0], read_u64(slice, 8) ^ seed);
91 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[1], read_u64(slice, 24) ^ see1);
92 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 32) ^ secrets[2], read_u64(slice, 40) ^ see2);
93 let (_, split) = slice.split_at(48);
94 slice = split;
95 }
96 } else {
97 while slice.len() >= 48 {
98 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[0], read_u64(slice, 8) ^ seed);
99 see1 = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[1], read_u64(slice, 24) ^ see1);
100 see2 = rapid_mix::<PROTECTED>(read_u64(slice, 32) ^ secrets[2], read_u64(slice, 40) ^ see2);
101 let (_, split) = slice.split_at(48);
102 slice = split;
103 }
104 }
105 seed ^= see1 ^ see2;
106 }
107
108 if slice.len() > 16 {
109 seed = rapid_mix::<PROTECTED>(read_u64(slice, 0) ^ secrets[2], read_u64(slice, 8) ^ seed ^ secrets[1]);
110 if slice.len() > 32 {
111 seed = rapid_mix::<PROTECTED>(read_u64(slice, 16) ^ secrets[2], read_u64(slice, 24) ^ seed);
112 }
113 }
114
115 a ^= read_u64(data, data.len() - 16);
116 b ^= read_u64(data, data.len() - 8);
117 }
118
119 a ^= secrets[1];
120 b ^= seed;
121
122 let (a2, b2) = rapid_mum::<PROTECTED>(a, b);
123 a = a2;
124 b = b2;
125
126 if AVALANCHE {
127 rapidhash_finish::<PROTECTED>(a, b, data.len() as u64, secrets)
128 } else {
129 a ^ b
130 }
131}
132
133#[inline(always)]
134pub(super) const fn rapidhash_finish<const PROTECTED: bool>(a: u64, b: u64, len: u64, secrets: &[u64; 3]) -> u64 {
135 rapid_mix::<PROTECTED>(a ^ secrets[0] ^ len, b ^ secrets[1])
136}