Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow generating random value independent of std. #62

Merged
merged 8 commits into from
Nov 21, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ahash"
version = "0.5.8"
version = "0.6.0"
authors = ["Tom Kaitchuck <Tom.Kaitchuck@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "A non-cryptographic hash function using AES-NI for high performance"
Expand All @@ -20,13 +20,16 @@ bench = true
doc = true

[features]
default = ["std"]
default = ["std", "runtime-rng"]

# Enabling this will enable `AHashMap` and `AHashSet`, and runtime key generation.
std = ["getrandom", "lazy_static"]
# Enabling this will enable `AHashMap` and `AHashSet`.
std = []

# This is an alternitive to std which does compile time key generation so that the standard library is not required.
# This implies the produced binary will not be identical. If both this and `std` are disabled constant keys are used.
# This will enable runtime key generation.
runtime-rng = ["getrandom", "lazy_static"]

# This is an alternitive to runtime-rng which does compile time key generation so that gerrandom is not required.
# This implies the produced binary will not be identical. If both this and `runtime-rng` are disabled constant keys are used.
compile-time-rng = ["const-random"]

# Enables specilization (requires nightly)
Expand Down Expand Up @@ -61,7 +64,7 @@ debug-assertions = false
codegen-units = 1

[dependencies]
lazy_static = { version = "1.4.0", optional = true }
lazy_static = { version = "1.4.0", features = ["spin_no_std"], optional = true }
getrandom = { version = "0.2.0", optional = true }
const-random = { version = "0.1.6", optional = true }
serde = { version = "1.0.117", optional = true }
Expand Down
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,17 @@ map.insert(56, 78);

## Flags

The aHash package has three flags:
* `std`: This enables features which require the standard library. (On by default) This includes generating random keys and providing the utility classes `AHashMap` and `AHashSet`.
* `compile-time-rng`: As an alternative to `std` when it is not available, this generates Random numbers for keys at compile time. This allows for DOS resistance even if there is no random number generator available at runtime (assuming the compiled binary is not public).
The aHash package has several flags:
* `std`: This enables features which require the standard library. (On by default) This includes providing the utility classes `AHashMap` and `AHashSet`.
* `runtime-rng`: This generates random keys for each hasher at runtime using the `getrandom` crate. (On by default)
* `compile-time-rng`: As an alternative to `runtime-rng` when random is not available, this generates Random numbers for keys at compile time. This allows for DOS resistance even if there is no random number generator available at runtime (assuming the compiled binary is not public).
Note that this has the effect of making the output of the build non-deterministic.
* `specialize`: This uses the specialization feature to provide optimized algorithms for primitive types. (This requires nightly)

**NOTE:** If neither `std` or `compile-time-rng` aHash will fall back on using the numeric value of memory addresses as a source of randomness.
**NOTE:** If neither `runtime-rng` or `compile-time-rng` aHash will fall back on using the numeric value of memory addresses as a source of randomness.
This is somewhat strong if ALSR is turned on (it is by default) but for some embedded platforms where this is not available,
this will result in weak keys. As a result, it is strongly recommended to use `std` when it is available and `compile-time-rng` when developing for an embedded platform where `std` is not available.
(If both are enabled `std` will take precedence and `compile-time-rng` will have no effect.)
this will result in weak keys. As a result, it is strongly recommended to use `runtime-rng` when `getrandom` is available for the target platform and `compile-time-rng` when developing for an embedded platform where it is not available.
(If both are enabled `runtime-rng` will take precedence and `compile-time-rng` will have no effect.)


## Comparison with other hashers
Expand Down
24 changes: 12 additions & 12 deletions src/random_state.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#[cfg(feature = "std")]
#[cfg(feature = "runtime-rng")]
use crate::convert::Convert;
use crate::{AHasher};
#[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
#[cfg(all(not(feature = "runtime-rng"), feature = "compile-time-rng"))]
use const_random::const_random;
use core::fmt;
use core::hash::BuildHasher;
use core::hash::Hasher;
#[cfg(feature = "std")]
#[cfg(feature = "runtime-rng")]
use lazy_static::*;
use core::sync::atomic::{AtomicUsize, Ordering};

#[cfg(feature = "std")]
#[cfg(feature = "runtime-rng")]
lazy_static! {
static ref SEEDS: [[u64; 4]; 2] = {
let mut result: [u8; 64] = [0; 64];
Expand All @@ -28,7 +28,7 @@ pub(crate) const PI: [u64; 4] = [
0x082e_fa98_ec4e_6c89,
];

#[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
#[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
const PI2: [u64; 4] = [
0x4528_21e6_38d0_1377,
0xbe54_66cf_34e9_0c6c,
Expand All @@ -38,11 +38,11 @@ const PI2: [u64; 4] = [

#[inline]
pub(crate) fn seeds() -> [u64; 4] {
#[cfg(feature = "std")]
#[cfg(feature = "runtime-rng")]
{ SEEDS[1] }
#[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
#[cfg(all(not(feature = "runtime-rng"), feature = "compile-time-rng"))]
{ [const_random!(u64), const_random!(u64), const_random!(u64), const_random!(u64)] }
#[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
#[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
{ PI }
}

Expand Down Expand Up @@ -72,19 +72,19 @@ impl RandomState {
/// Use randomly generated keys
#[inline]
pub fn new() -> RandomState {
#[cfg(feature = "std")]
#[cfg(feature = "runtime-rng")]
{
let seeds = *SEEDS;
RandomState::from_keys(seeds[0], seeds[1])
}
#[cfg(all(not(feature = "std"), feature = "compile-time-rng"))]
#[cfg(all(not(feature = "runtime-rng"), feature = "compile-time-rng"))]
{
RandomState::from_keys(
[const_random!(u64), const_random!(u64), const_random!(u64), const_random!(u64)],
[const_random!(u64), const_random!(u64), const_random!(u64), const_random!(u64)],
)
}
#[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
#[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
{
RandomState::from_keys(PI, PI2)
}
Expand Down Expand Up @@ -113,7 +113,7 @@ impl RandomState {
COUNTER.store(new, Ordering::Relaxed);
hasher.write_usize(new);
}
#[cfg(all(not(feature = "std"), not(feature = "compile-time-rng")))]
#[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
hasher.write_usize(&PI as *const _ as usize);
let mix = |k: u64| {
let mut h = hasher.clone();
Expand Down