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. ```admonish abstract.small "Hashing seed" A hashing seed requires four 64-bit numbers (i.e. `u64`). ``` ```admonish tip.small "Tip: Static hashes are consistent and predictable" Under static hashing, the same function signature _always_ generate the same hash value, given the same seed. ``` ```admonish warning.small "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. ```rust // 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(); ``` ```admonish danger.small "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. ```admonish warning.small "Warning" If a hashing seed is also set via `rhai::config::hashing::set_ahash_seed`, this environment variable has no effect. ``` ```sh 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 ----- ~~~admonish question "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`](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. ~~~