Static Hashing

To counter DOS attacks, the hasher used by Rhai, ahash, automatically generates a different seed for hashing during each compilation and execution run.

This means that hash values generated by the hasher will not be stable – they change during each compile, and during each run.

For certain niche scenarios, however, dynamic hashes are undesirable.

So, when static hashing is employed, all hashing uses a fixed, predictable seed all the time.

Hashing seed

A hashing seed requires four 64-bit numbers (i.e. u64).

Tip: Static hashes are consistent and predictable

Under static hashing, the same function signature always generate the same hash value, given the same seed.

Warning: Safety considerations

A fixed hashing seed enlarges the attack surface of Rhai to malicious intent (e.g. DOS attacks).

Set at Run-Time

Call the static function rhai::config::hashing::set_ahash_seed with four u64 numbers that make up the hashing seed.

The seed specified is always used to initialize the hasher.

// Set specific hashing seed - do this BEFORE anything else!
rhai::config::hashing::set_ahash_seed(Some([123, 456, 789, 42]))?;

// ... from now on, all hashing will be predictable
let engine = Engine::new();

Warning: Only call once

rhai::config::hashing::set_ahash_seed can only ever be called once, and must be called BEFORE performing any operation on Rhai (e.g. creating an Engine).

Calling it a second time simply returns an error.

Set at Compile Time

The hashing seed can also be provided, at compile time, via the environment variable RHAI_AHASH_SEED, with four u64 numbers that must be specified in Rust array literal format.

Warning

If a hashing seed is also set via rhai::config::hashing::set_ahash_seed, this environment variable has no effect.

RHAI_AHASH_SEED="[123, 456, 789, 42]" cargo build ...

The seed specified in RHAI_AHASH_SEED is always used to initialize the hasher.

If the environment variable is missing, or it contains all zeros (i.e. [0, 0, 0, 0]), then static hashing is disabled.

TL;DR

Why can’t we tell ahash to use a static (fixed) seed?

For static hashing seed, ahash requires:

  • default-features = false
  • runtime-rng feature is not set (default on)
  • compile-time-rng feature is not set

The bane of additive Cargo features

However, ahash is also extremely popular, used by many many other crates, most notably hashbrown.

Chances are that there are dependency crates that in turn depend on ahash with default features. Since cargo features are additive, it is almost certain that ahash will use a runtime-generated seed for large projects.

Hence, there exists a need to tell ahash to use a fixed seed, even when its feature flags say otherwise.