]>
git.proxmox.com Git - rustc.git/blob - vendor/ahash-0.7.6/src/aes_hash.rs
2 #[cfg(feature = "specialize")]
3 use crate::fallback_hash
::MULTIPLE
;
4 use crate::operations
::*;
5 use crate::RandomState
;
6 use core
::hash
::Hasher
;
7 use crate::random_state
::PI
;
9 /// A `Hasher` for hashing an arbitrary stream of bytes.
11 /// Instances of [`AHasher`] represent state that is updated while hashing data.
13 /// Each method updates the internal state based on the new data provided. Once
14 /// all of the data has been provided, the resulting hash can be obtained by calling
17 /// [Clone] is also provided in case you wish to calculate hashes for two different items that
18 /// start with the same data.
20 #[derive(Debug, Clone)]
28 /// Creates a new hasher keyed to the provided keys.
30 /// Normally hashers are created via `AHasher::default()` for fixed keys or `RandomState::new()` for randomly
31 /// generated keys and `RandomState::with_seeds(a,b)` for seeds that are set and can be reused. All of these work at
32 /// map creation time (and hence don't have any overhead on a per-item bais).
34 /// This method directly creates the hasher instance and performs no transformation on the provided seeds. This may
35 /// be useful where a HashBuilder is not desired, such as for testing purposes.
40 /// use std::hash::Hasher;
41 /// use ahash::AHasher;
43 /// let mut hasher = AHasher::new_with_keys(1234, 5678);
45 /// hasher.write_u32(1989);
46 /// hasher.write_u8(11);
47 /// hasher.write_u8(9);
48 /// hasher.write(b"Huh?");
50 /// println!("Hash is {:x}!", hasher.finish());
53 pub fn new_with_keys(key1
: u128
, key2
: u128
) -> Self {
54 let pi
: [u128
; 2] = PI
.convert();
55 let key1
= key1 ^ pi
[0];
56 let key2
= key2 ^ pi
[1];
64 #[allow(unused)] // False positive
65 pub(crate) fn test_with_keys(key1
: u128
, key2
: u128
) -> Self {
75 pub(crate) fn from_random_state(rand_state
: &RandomState
) -> Self {
76 let key1
= [rand_state
.k0
, rand_state
.k1
].convert();
77 let key2
= [rand_state
.k2
, rand_state
.k3
].convert();
86 fn add_in_length(&mut self, length
: u64) {
87 //This will be scrambled by the next AES round.
88 let mut enc
: [u64; 2] = self.enc
.convert();
89 enc
[0] = enc
[0].wrapping_add(length
);
90 self.enc
= enc
.convert();
94 fn hash_in(&mut self, new_value
: u128
) {
95 self.enc
= aesenc(self.enc
, new_value
);
96 self.sum
= shuffle_and_add(self.sum
, new_value
);
100 fn hash_in_2(&mut self, v1
: u128
, v2
: u128
) {
101 self.enc
= aesenc(self.enc
, v1
);
102 self.sum
= shuffle_and_add(self.sum
, v1
);
103 self.enc
= aesenc(self.enc
, v2
);
104 self.sum
= shuffle_and_add(self.sum
, v2
);
108 #[cfg(feature = "specialize")]
109 fn short_finish(&self) -> u64 {
110 let combined
= aesdec(self.sum
, self.enc
);
111 let result
: [u64; 2] = aesenc(combined
, combined
).convert();
116 /// Provides [Hasher] methods to hash all of the primitive types.
118 /// [Hasher]: core::hash::Hasher
119 impl Hasher
for AHasher
{
121 fn write_u8(&mut self, i
: u8) {
122 self.write_u64(i
as u64);
126 fn write_u16(&mut self, i
: u16) {
127 self.write_u64(i
as u64);
131 fn write_u32(&mut self, i
: u32) {
132 self.write_u64(i
as u64);
136 fn write_u128(&mut self, i
: u128
) {
141 #[cfg(any(target_pointer_width = "64", target_pointer_width = "32", target_pointer_width = "16"))]
142 fn write_usize(&mut self, i
: usize) {
143 self.write_u64(i
as u64);
147 #[cfg(target_pointer_width = "128")]
148 fn write_usize(&mut self, i
: usize) {
149 self.write_u128(i
as u128
);
153 fn write_u64(&mut self, i
: u64) {
154 self.write_u128(i
as u128
);
158 #[allow(clippy::collapsible_if)]
159 fn write(&mut self, input
: &[u8]) {
160 let mut data
= input
;
161 let length
= data
.len();
162 self.add_in_length(length
as u64);
163 //A 'binary search' on sizes reduces the number of comparisons.
165 let value
= read_small(data
);
166 self.hash_in(value
.convert());
170 let tail
= data
.read_last_u128x4();
171 let mut current
: [u128
; 4] = [self.key
; 4];
172 current
[0] = aesenc(current
[0], tail
[0]);
173 current
[1] = aesenc(current
[1], tail
[1]);
174 current
[2] = aesenc(current
[2], tail
[2]);
175 current
[3] = aesenc(current
[3], tail
[3]);
176 let mut sum
: [u128
; 2] = [self.key
, self.key
];
177 sum
[0] = add_by_64s(sum
[0].convert(), tail
[0].convert()).convert();
178 sum
[1] = add_by_64s(sum
[1].convert(), tail
[1].convert()).convert();
179 sum
[0] = shuffle_and_add(sum
[0], tail
[2]);
180 sum
[1] = shuffle_and_add(sum
[1], tail
[3]);
181 while data
.len() > 64 {
182 let (blocks
, rest
) = data
.read_u128x4();
183 current
[0] = aesenc(current
[0], blocks
[0]);
184 current
[1] = aesenc(current
[1], blocks
[1]);
185 current
[2] = aesenc(current
[2], blocks
[2]);
186 current
[3] = aesenc(current
[3], blocks
[3]);
187 sum
[0] = shuffle_and_add(sum
[0], blocks
[0]);
188 sum
[1] = shuffle_and_add(sum
[1], blocks
[1]);
189 sum
[0] = shuffle_and_add(sum
[0], blocks
[2]);
190 sum
[1] = shuffle_and_add(sum
[1], blocks
[3]);
193 self.hash_in_2(aesenc(current
[0], current
[1]), aesenc(current
[2], current
[3]));
194 self.hash_in(add_by_64s(sum
[0].convert(), sum
[1].convert()).convert());
197 let (head
, _
) = data
.read_u128x2();
198 let tail
= data
.read_last_u128x2();
199 self.hash_in_2(head
[0], head
[1]);
200 self.hash_in_2(tail
[0], tail
[1]);
205 self.hash_in_2(data
.read_u128().0, data
.read_last_u128());
208 let value
: [u64; 2] = [data
.read_u64().0, data
.read_last_u64()];
209 self.hash_in(value
.convert());
215 fn finish(&self) -> u64 {
216 let combined
= aesdec(self.sum
, self.enc
);
217 let result
: [u64; 2] = aesenc(aesenc(combined
, self.key
), combined
).convert();
222 #[cfg(feature = "specialize")]
223 pub(crate) struct AHasherU64
{
224 pub(crate) buffer
: u64,
228 /// A specialized hasher for only primitives under 64 bits.
229 #[cfg(feature = "specialize")]
230 impl Hasher
for AHasherU64
{
232 fn finish(&self) -> u64 {
233 let rot
= (self.pad
& 63) as u32;
234 self.buffer
.rotate_left(rot
)
238 fn write(&mut self, _bytes
: &[u8]) {
239 unreachable
!("Specialized hasher was called with a different type of object")
243 fn write_u8(&mut self, i
: u8) {
244 self.write_u64(i
as u64);
248 fn write_u16(&mut self, i
: u16) {
249 self.write_u64(i
as u64);
253 fn write_u32(&mut self, i
: u32) {
254 self.write_u64(i
as u64);
258 fn write_u64(&mut self, i
: u64) {
259 self.buffer
= folded_multiply(i ^
self.buffer
, MULTIPLE
);
263 fn write_u128(&mut self, _i
: u128
) {
264 unreachable
!("Specialized hasher was called with a different type of object")
268 fn write_usize(&mut self, _i
: usize) {
269 unreachable
!("Specialized hasher was called with a different type of object")
273 #[cfg(feature = "specialize")]
274 pub(crate) struct AHasherFixed(pub AHasher
);
276 /// A specialized hasher for fixed size primitives larger than 64 bits.
277 #[cfg(feature = "specialize")]
278 impl Hasher
for AHasherFixed
{
280 fn finish(&self) -> u64 {
281 self.0.short_finish()
285 fn write(&mut self, bytes
: &[u8]) {
290 fn write_u8(&mut self, i
: u8) {
291 self.write_u64(i
as u64);
295 fn write_u16(&mut self, i
: u16) {
296 self.write_u64(i
as u64);
300 fn write_u32(&mut self, i
: u32) {
301 self.write_u64(i
as u64);
305 fn write_u64(&mut self, i
: u64) {
310 fn write_u128(&mut self, i
: u128
) {
311 self.0.write_u128(i
);
315 fn write_usize(&mut self, i
: usize) {
316 self.0.write_usize(i
);
320 #[cfg(feature = "specialize")]
321 pub(crate) struct AHasherStr(pub AHasher
);
323 /// A specialized hasher for strings
324 /// Note that the other types don't panic because the hash impl for String tacks on an unneeded call. (As does vec)
325 #[cfg(feature = "specialize")]
326 impl Hasher
for AHasherStr
{
328 fn finish(&self) -> u64 {
329 let result
: [u64; 2] = self.0.enc
.convert();
334 fn write(&mut self, bytes
: &[u8]) {
337 self.0.enc
= aesdec(self.0.sum
, self.0.enc
);
338 self.0.enc
= aesenc(aesenc(self.0.enc
, self.0.key
), self.0.enc
);
340 self.0.add_in_length(bytes
.len() as u64);
341 let value
= read_small(bytes
).convert();
342 self.0.sum
= shuffle_and_add(self.0.sum
, value
);
343 self.0.enc
= aesdec(self.0.sum
, self.0.enc
);
344 self.0.enc
= aesenc(aesenc(self.0.enc
, self.0.key
), self.0.enc
);
349 fn write_u8(&mut self, _i
: u8) {}
352 fn write_u16(&mut self, _i
: u16) {}
355 fn write_u32(&mut self, _i
: u32) {}
358 fn write_u64(&mut self, _i
: u64) {}
361 fn write_u128(&mut self, _i
: u128
) {}
364 fn write_usize(&mut self, _i
: usize) {}
370 use crate::convert
::Convert
;
371 use crate::operations
::aesenc
;
372 use crate::RandomState
;
373 use std
::hash
::{BuildHasher, Hasher}
;
376 let mut hasher
= RandomState
::with_seeds(1, 2, 3, 4).build_hasher();
378 let h1
= hasher
.finish();
379 hasher
.write(&[1, 0, 0, 0, 0, 0, 0, 0]);
380 let h2
= hasher
.finish();
384 #[cfg(feature = "compile-time-rng")]
387 use std
::collections
::HashMap
;
388 use std
::hash
::BuildHasherDefault
;
390 let mut map
= HashMap
::<u32, u64, BuildHasherDefault
<AHasher
>>::default();
394 #[cfg(feature = "compile-time-rng")]
397 let hasher_a
= AHasher
::default();
398 let a_enc
: [u64; 2] = hasher_a
.enc
.convert();
399 let a_sum
: [u64; 2] = hasher_a
.sum
.convert();
400 assert_ne
!(0, a_enc
[0]);
401 assert_ne
!(0, a_enc
[1]);
402 assert_ne
!(0, a_sum
[0]);
403 assert_ne
!(0, a_sum
[1]);
404 assert_ne
!(a_enc
[0], a_enc
[1]);
405 assert_ne
!(a_sum
[0], a_sum
[1]);
406 assert_ne
!(a_enc
[0], a_sum
[0]);
407 assert_ne
!(a_enc
[1], a_sum
[1]);
408 let hasher_b
= AHasher
::default();
409 let b_enc
: [u64; 2] = hasher_b
.enc
.convert();
410 let b_sum
: [u64; 2] = hasher_b
.sum
.convert();
411 assert_eq
!(a_enc
[0], b_enc
[0]);
412 assert_eq
!(a_enc
[1], b_enc
[1]);
413 assert_eq
!(a_sum
[0], b_sum
[0]);
414 assert_eq
!(a_sum
[1], b_sum
[1]);
419 let mut result
: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
420 let value
: [u64; 2] = [1 << 32, 0xFEDCBA9876543210];
421 result
= aesenc(value
.convert(), result
.convert()).convert();
422 result
= aesenc(result
.convert(), result
.convert()).convert();
423 let mut result2
: [u64; 2] = [0x6c62272e07bb0142, 0x62b821756295c58d];
424 let value2
: [u64; 2] = [1, 0xFEDCBA9876543210];
425 result2
= aesenc(value2
.convert(), result2
.convert()).convert();
426 result2
= aesenc(result2
.convert(), result
.convert()).convert();
427 let result
: [u8; 16] = result
.convert();
428 let result2
: [u8; 16] = result2
.convert();
429 assert_ne
!(hex
::encode(result
), hex
::encode(result2
));
433 fn test_conversion() {
434 let input
: &[u8] = "dddddddd".as_bytes();
435 let bytes
: u64 = as_array
!(input
, 8).convert();
436 assert_eq
!(bytes
, 0x6464646464646464);