Skip to content

Commit 980159d

Browse files
committed
Use getrandom for obtaining random state if std is enabled.
(This requires an API change.)
1 parent c5ac439 commit 980159d

File tree

8 files changed

+178
-190
lines changed

8 files changed

+178
-190
lines changed

Cargo.toml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "ahash"
3-
version = "0.4.5"
3+
version = "0.5.0"
44
authors = ["Tom Kaitchuck <[email protected]>"]
55
license = "MIT OR Apache-2.0"
66
description = "A non-cryptographic hash function using AES-NI for high performance"
@@ -19,18 +19,15 @@ bench = true
1919
doc = true
2020

2121
[features]
22-
default = ["compile-time-rng", "std"]
22+
default = ["std"]
2323

2424
# Enabling this will enable `AHashMap` and `AHashSet`
25-
std = []
25+
std = ["getrandom", "lazy_static"]
26+
compile-time-rng = ["const-random"]
2627

27-
# Enables specilization (reuqires nightly)
28+
# Enables specilization (requires nightly)
2829
specialize = []
2930

30-
# Disabling this feature will make the `ABuildHasher::new` use a preset seed
31-
# and disable the `Default` impl for `AHasher`
32-
compile-time-rng = ["const-random"]
33-
3431
[[bench]]
3532
name = "ahash"
3633
path = "tests/bench.rs"
@@ -60,16 +57,18 @@ debug-assertions = false
6057
codegen-units = 1
6158

6259
[dependencies]
60+
lazy_static = { version = "1.4.0", optional = true }
61+
getrandom = { version = "0.2.0", optional = true }
6362
const-random = { version = "0.1.6", optional = true }
6463

6564
[dev-dependencies]
6665
no-panic = "0.1.10"
6766
criterion = {version = "0.3.2"}
68-
seahash = "3.0.5"
67+
seahash = "4.0"
6968
fnv = "1.0.5"
7069
fxhash = "0.2.1"
71-
hex = "0.3.2"
72-
rand = "0.6.5"
70+
hex = "0.4.2"
71+
rand = "0.7.3"
7372

7473
[package.metadata.docs.rs]
7574
rustc-args = ["-C", "target-feature=+aes"]

src/aes_hash.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::operations::*;
33
#[cfg(feature = "specialize")]
44
use crate::HasherExt;
55
use core::hash::Hasher;
6+
use crate::RandomState;
67

78
/// A `Hasher` for hashing an arbitrary stream of bytes.
89
///
@@ -56,14 +57,14 @@ impl AHasher {
5657
}
5758
}
5859

59-
#[cfg(test)]
60-
pub(crate) fn test_with_keys(key1: u64, key2: u64) -> AHasher {
61-
use crate::random_state::scramble_keys;
62-
let (k1, k2, k3, k4) = scramble_keys(key1, key2);
63-
AHasher {
64-
enc: [k1, k2].convert(),
65-
sum: [k3, k4].convert(),
66-
key: add_by_64s([k1, k2], [k3, k4]).convert(),
60+
#[inline]
61+
pub(crate) fn from_random_state(rand_state: &RandomState) -> Self {
62+
let key1 = [rand_state.k0, rand_state.k1].convert();
63+
let key2 = [rand_state.k2, rand_state.k3].convert();
64+
Self {
65+
enc: key1,
66+
sum: key2,
67+
key: key1 ^ key2,
6768
}
6869
}
6970

@@ -108,7 +109,9 @@ impl HasherExt for AHasher {
108109
}
109110
}
110111

111-
/// Provides methods to hash all of the primitive types.
112+
/// Provides [Hasher] methods to hash all of the primitive types.
113+
///
114+
/// [Hasher]: core::hash::Hasher
112115
impl Hasher for AHasher {
113116
#[inline]
114117
fn write_u8(&mut self, i: u8) {
@@ -228,7 +231,7 @@ mod tests {
228231
use std::hash::{BuildHasher, Hasher};
229232
#[test]
230233
fn test_sanity() {
231-
let mut hasher = RandomState::with_seeds(192837465, 1234567890).build_hasher();
234+
let mut hasher = RandomState::with_seeds(1, 2, 3,4).build_hasher();
232235
hasher.write_u64(0);
233236
let h1 = hasher.finish();
234237
hasher.write(&[1, 0, 0, 0, 0, 0, 0, 0]);

src/convert.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ convert!(u128, [u64; 2]);
4747
convert!(u128, [u32; 4]);
4848
convert!(u128, [u16; 8]);
4949
convert!(u128, [u8; 16]);
50+
convert!([u64; 8], [u32; 16]);
51+
convert!([u64; 8], [u16; 32]);
52+
convert!([u64; 8], [u8; 64]);
53+
convert!([u64; 4], [u32; 8]);
54+
convert!([u64; 4], [u16; 16]);
55+
convert!([u64; 4], [u8; 32]);
5056
convert!([u64; 2], [u32; 4]);
5157
convert!([u64; 2], [u16; 8]);
5258
convert!([u64; 2], [u8; 16]);

src/fallback_hash.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ use crate::operations::folded_multiply;
33
#[cfg(feature = "specialize")]
44
use crate::HasherExt;
55
use core::hash::Hasher;
6+
use crate::RandomState;
7+
use crate::random_state::PI;
68

79
///This constant come from Kunth's prng (Empirically it works better than those from splitmix32).
8-
const MULTIPLE: u64 = crate::random_state::MULTIPLE;
10+
const MULTIPLE: u64 = 6364136223846793005;
911
const ROT: u32 = 23; //17
1012

1113
/// A `Hasher` for hashing an arbitrary stream of bytes.
@@ -31,22 +33,23 @@ impl AHasher {
3133
#[inline]
3234
#[allow(dead_code)] // Is not called if non-fallback hash is used.
3335
pub fn new_with_keys(key1: u128, key2: u128) -> AHasher {
36+
let pi: [u128; 2] = PI.convert();
37+
let key1: [u64; 2] = (key1 ^ pi[0]).convert();
38+
let key2: [u64; 2] = (key2 ^ pi[1]).convert();
3439
AHasher {
35-
buffer: key1 as u64,
36-
pad: key2 as u64,
37-
extra_keys: (key1 ^ key2).convert(),
40+
buffer: key1[0],
41+
pad: key1[1],
42+
extra_keys: key2,
3843
}
3944
}
40-
41-
#[cfg(test)]
45+
46+
#[inline]
4247
#[allow(dead_code)] // Is not called if non-fallback hash is used.
43-
pub(crate) fn test_with_keys(key1: u64, key2: u64) -> AHasher {
44-
use crate::random_state::scramble_keys;
45-
let (k1, k2, k3, k4) = scramble_keys(key1, key2);
48+
pub(crate) fn from_random_state(rand_state: &RandomState) -> AHasher {
4649
AHasher {
47-
buffer: k1,
48-
pad: k2,
49-
extra_keys: [k3, k4],
50+
buffer: rand_state.k0,
51+
pad: rand_state.k1,
52+
extra_keys: [rand_state.k2, rand_state.k3],
5053
}
5154
}
5255

@@ -117,7 +120,9 @@ impl HasherExt for AHasher {
117120
}
118121
}
119122

120-
/// Provides methods to hash all of the primitive types.
123+
/// Provides [Hasher] methods to hash all of the primitive types.
124+
///
125+
/// [Hasher]: core::hash::Hasher
121126
impl Hasher for AHasher {
122127
#[inline]
123128
fn write_u8(&mut self, i: u8) {
@@ -141,9 +146,7 @@ impl Hasher for AHasher {
141146

142147
#[inline]
143148
fn write_u128(&mut self, i: u128) {
144-
let data: [u64; 2] = i.convert();
145-
self.update(data[0]);
146-
self.update(data[1]);
149+
self.large_update(i);
147150
}
148151

149152
#[inline]

src/hash_quality_test.rs

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ fn test_no_full_collisions<T: Hasher>(gen_hash: impl Fn() -> T) {
9393
assert_eq!(2396744, map.len());
9494
}
9595

96-
fn test_keys_change_output<T: HasherExt>(constructor: impl Fn(u64, u64) -> T) {
96+
fn test_keys_change_output<T: HasherExt>(constructor: impl Fn(u128, u128) -> T) {
9797
let mut a = constructor(1, 1);
9898
let mut b = constructor(1, 2);
9999
let mut c = constructor(2, 1);
@@ -110,7 +110,7 @@ fn test_keys_change_output<T: HasherExt>(constructor: impl Fn(u64, u64) -> T) {
110110
assert_sufficiently_different(c.finish(), d.finish(), 1);
111111
}
112112

113-
fn test_input_affect_every_byte<T: HasherExt>(constructor: impl Fn(u64, u64) -> T) {
113+
fn test_input_affect_every_byte<T: HasherExt>(constructor: impl Fn(u128, u128) -> T) {
114114
let base = 0.get_hash(constructor(0, 0));
115115
for shift in 0..16 {
116116
let mut alternitives = vec![];
@@ -124,13 +124,13 @@ fn test_input_affect_every_byte<T: HasherExt>(constructor: impl Fn(u64, u64) ->
124124
}
125125

126126
///Ensures that for every bit in the output there is some value for each byte in the key that flips it.
127-
fn test_keys_affect_every_byte<H: Hash, T: HasherExt>(item: H, constructor: impl Fn(u64, u64) -> T) {
127+
fn test_keys_affect_every_byte<H: Hash, T: HasherExt>(item: H, constructor: impl Fn(u128, u128) -> T) {
128128
let base = item.get_hash(constructor(0, 0));
129-
for shift in 0..8 {
129+
for shift in 0..16 {
130130
let mut alternitives1 = vec![];
131131
let mut alternitives2 = vec![];
132132
for v in 0..256 {
133-
let input = (v as u64) << (shift * 8);
133+
let input = (v as u128) << (shift * 8);
134134
let hasher1 = constructor(input, 0);
135135
let hasher2 = constructor(0, input);
136136
let h1 = item.get_hash(hasher1);
@@ -151,16 +151,16 @@ fn assert_each_byte_differs(base: u64, alternitives: Vec<u64>) {
151151
assert_eq!(core::u64::MAX, changed_bits, "Bits changed: {:x}", changed_bits);
152152
}
153153

154-
fn test_finish_is_consistent<T: Hasher>(constructor: impl Fn(u64, u64) -> T) {
154+
fn test_finish_is_consistent<T: Hasher>(constructor: impl Fn(u128, u128) -> T) {
155155
let mut hasher = constructor(1, 2);
156156
"Foo".hash(&mut hasher);
157157
let a = hasher.finish();
158158
let b = hasher.finish();
159159
assert_eq!(a, b);
160160
}
161161

162-
fn test_single_key_bit_flip<T: Hasher>(constructor: impl Fn(u64, u64) -> T) {
163-
for bit in 0..64 {
162+
fn test_single_key_bit_flip<T: Hasher>(constructor: impl Fn(u128, u128) -> T) {
163+
for bit in 0..128 {
164164
let mut a = constructor(0, 0);
165165
let mut b = constructor(0, 1 << bit);
166166
let mut c = constructor(1 << bit, 0);
@@ -320,57 +320,58 @@ mod fallback_tests {
320320

321321
#[test]
322322
fn fallback_single_bit_flip() {
323-
test_single_bit_flip(|| AHasher::test_with_keys(0, 0))
323+
test_single_bit_flip(|| AHasher::new_with_keys(0, 0))
324324
}
325325

326326
#[test]
327327
fn fallback_single_key_bit_flip() {
328-
test_single_key_bit_flip(AHasher::test_with_keys)
328+
test_single_key_bit_flip(AHasher::new_with_keys)
329329
}
330330

331331
#[test]
332332
fn fallback_all_bytes_matter() {
333-
test_all_bytes_matter(|| AHasher::test_with_keys(0, 0));
333+
test_all_bytes_matter(|| AHasher::new_with_keys(0, 0));
334334
}
335335

336336
#[test]
337337
fn fallback_test_no_pair_collisions() {
338-
test_no_pair_collisions(|| AHasher::test_with_keys(0, 0));
338+
test_no_pair_collisions(|| AHasher::new_with_keys(0, 0));
339339
}
340340

341341
#[test]
342342
fn fallback_test_no_full_collisions() {
343-
test_no_full_collisions(|| AHasher::test_with_keys(12345, 67890));
343+
test_no_full_collisions(|| AHasher::new_with_keys(12345, 67890));
344344
}
345345

346346
#[test]
347347
fn fallback_keys_change_output() {
348-
test_keys_change_output(AHasher::test_with_keys);
348+
test_keys_change_output(AHasher::new_with_keys);
349349
}
350350

351351
#[test]
352352
fn fallback_input_affect_every_byte() {
353-
test_input_affect_every_byte(AHasher::test_with_keys);
353+
test_input_affect_every_byte(AHasher::new_with_keys);
354354
}
355355

356356
#[test]
357357
fn fallback_keys_affect_every_byte() {
358-
test_keys_affect_every_byte(0, AHasher::test_with_keys);
359-
test_keys_affect_every_byte("", AHasher::test_with_keys);
360-
test_keys_affect_every_byte((0, 0), AHasher::test_with_keys);
358+
//For fallback second key is not used in every hash.
359+
test_keys_affect_every_byte(0, |a, b| AHasher::new_with_keys(a ^ b, a));
360+
test_keys_affect_every_byte("", |a, b| AHasher::new_with_keys(a ^ b, a));
361+
test_keys_affect_every_byte((0, 0), |a, b| AHasher::new_with_keys(a ^ b, a));
361362
}
362363

363364
#[test]
364365
fn fallback_finish_is_consistant() {
365-
test_finish_is_consistent(AHasher::test_with_keys)
366+
test_finish_is_consistent(AHasher::new_with_keys)
366367
}
367368

368369
#[test]
369370
fn fallback_padding_doesnot_collide() {
370-
test_padding_doesnot_collide(|| AHasher::test_with_keys(0, 0));
371-
test_padding_doesnot_collide(|| AHasher::test_with_keys(0, 1));
372-
test_padding_doesnot_collide(|| AHasher::test_with_keys(1, 0));
373-
test_padding_doesnot_collide(|| AHasher::test_with_keys(1, 1));
371+
test_padding_doesnot_collide(|| AHasher::new_with_keys(0, 0));
372+
test_padding_doesnot_collide(|| AHasher::new_with_keys(0, 1));
373+
test_padding_doesnot_collide(|| AHasher::new_with_keys(1, 0));
374+
test_padding_doesnot_collide(|| AHasher::new_with_keys(1, 1));
374375
}
375376
}
376377

@@ -382,8 +383,8 @@ mod aes_tests {
382383
use crate::hash_quality_test::*;
383384
use std::hash::{Hash, Hasher};
384385

385-
const BAD_KEY: u64 = 0x5252_5252_5252_5252; //This encrypts to 0.
386-
const BAD_KEY2: u64 = 0x6363_6363_6363_6363; //This decrypts to 0.
386+
const BAD_KEY: u128 = 0x5252_5252_5252_5252_5252_5252_5252_5252; //This encrypts to 0.
387+
const BAD_KEY2: u128 = 0x6363_6363_6363_6363_6363_6363_6363_6363; //This decrypts to 0.
387388

388389
#[test]
389390
fn test_single_bit_in_byte() {
@@ -396,56 +397,56 @@ mod aes_tests {
396397

397398
#[test]
398399
fn aes_single_bit_flip() {
399-
test_single_bit_flip(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY));
400-
test_single_bit_flip(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2));
400+
test_single_bit_flip(|| AHasher::new_with_keys(BAD_KEY, BAD_KEY));
401+
test_single_bit_flip(|| AHasher::new_with_keys(BAD_KEY2, BAD_KEY2));
401402
}
402403

403404
#[test]
404405
fn aes_single_key_bit_flip() {
405-
test_single_key_bit_flip(|k1, k2| AHasher::test_with_keys(k1, k2))
406+
test_single_key_bit_flip(AHasher::new_with_keys)
406407
}
407408

408409
#[test]
409410
fn aes_all_bytes_matter() {
410-
test_all_bytes_matter(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY));
411-
test_all_bytes_matter(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2));
411+
test_all_bytes_matter(|| AHasher::new_with_keys(BAD_KEY, BAD_KEY));
412+
test_all_bytes_matter(|| AHasher::new_with_keys(BAD_KEY2, BAD_KEY2));
412413
}
413414

414415
#[test]
415416
fn aes_test_no_pair_collisions() {
416-
test_no_pair_collisions(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY));
417-
test_no_pair_collisions(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2));
417+
test_no_pair_collisions(|| AHasher::new_with_keys(BAD_KEY, BAD_KEY));
418+
test_no_pair_collisions(|| AHasher::new_with_keys(BAD_KEY2, BAD_KEY2));
418419
}
419420

420421
#[test]
421422
fn ase_test_no_full_collisions() {
422-
test_no_full_collisions(|| AHasher::test_with_keys(12345, 67890));
423+
test_no_full_collisions(|| AHasher::new_with_keys(12345, 67890));
423424
}
424425

425426
#[test]
426427
fn aes_keys_change_output() {
427-
test_keys_change_output(AHasher::test_with_keys);
428+
test_keys_change_output(AHasher::new_with_keys);
428429
}
429430

430431
#[test]
431432
fn aes_input_affect_every_byte() {
432-
test_input_affect_every_byte(AHasher::test_with_keys);
433+
test_input_affect_every_byte(AHasher::new_with_keys);
433434
}
434435

435436
#[test]
436437
fn aes_keys_affect_every_byte() {
437-
test_keys_affect_every_byte(0, AHasher::test_with_keys);
438-
test_keys_affect_every_byte("", AHasher::test_with_keys);
439-
test_keys_affect_every_byte((0, 0), AHasher::test_with_keys);
438+
test_keys_affect_every_byte(0, AHasher::new_with_keys);
439+
test_keys_affect_every_byte("", AHasher::new_with_keys);
440+
test_keys_affect_every_byte((0, 0), AHasher::new_with_keys);
440441
}
441442
#[test]
442443
fn aes_finish_is_consistant() {
443-
test_finish_is_consistent(AHasher::test_with_keys)
444+
test_finish_is_consistent(AHasher::new_with_keys)
444445
}
445446

446447
#[test]
447448
fn aes_padding_doesnot_collide() {
448-
test_padding_doesnot_collide(|| AHasher::test_with_keys(BAD_KEY, BAD_KEY));
449-
test_padding_doesnot_collide(|| AHasher::test_with_keys(BAD_KEY2, BAD_KEY2));
449+
test_padding_doesnot_collide(|| AHasher::new_with_keys(BAD_KEY, BAD_KEY));
450+
test_padding_doesnot_collide(|| AHasher::new_with_keys(BAD_KEY2, BAD_KEY2));
450451
}
451452
}

0 commit comments

Comments
 (0)