This repository has been archived on 2025-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
rhaj/rhai_engine/rhaibook/patterns/static-hash.md
2025-04-03 09:18:05 +02:00

3.1 KiB
Raw Blame History

Static Hashing

{{#include ../links.md}}

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.


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

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

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();

`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.


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


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`](https://crates.io/crates/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.