rustc-hash: the fast non-cryptographic hasher rustc uses internally
Custom hash algorithm used by rustc (plus hashmap/set aliases): fast, deterministic, not secure
At a glance
- What is it?
- rustc-hash is the Apache-2.0 or MIT licensed crate that gives Rust code an FxHashMap and FxHashSet backed by a polynomial hash rather than SipHash, because a compiler has no denial-of-service adversary to defend against. It suits internal data structures in a compiler or a build tool, and it is the wrong choice for anything hashing untrusted keys.
- Who is it for?
- rustc-hash fits code that hashes keys it controls, such as internal compiler and build-tool data structures where hash quality matters less than throughput, and it is a good default to reach for when profiling shows SipHash is the bottleneck.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 8 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why the compiler does not use SipHash
The standard library's HashMap uses SipHash by default, and the crate explains the reasoning for departing from that. SipHash provides resistance against denial-of-service attacks, where an attacker supplies many keys that all collide in the same bucket and turn a hash lookup into a linear scan.
Those attacks are not a concern in the compiler, so the crate prefers a quicker, non-cryptographic hash algorithm. That is the whole thesis, and it is more precise than the usual claim that one hash is faster than another. The difference is not in the constants; it is in what the algorithm defends against. SipHash spends cycles on keyed mixing so that an attacker who knows the key cannot predict where the hash goes. A polynomial hash does not, and for a compiler processing its own AST and MIR that work is wasted.
The README then gives the other half of the argument, which is the more interesting half. For rustc they tried many different hashing algorithms, and hashing speed is critical, especially for single integers. Spending more CPU cycles on a higher quality hash does not reduce hash collisions enough to make the compiler faster on real-world benchmarks.
That is a measurable claim about a real workload, and it is the reason to believe the crate rather than assume it. A library that documents the benchmark result it optimised for tells you what to expect.
The repository is not archived, the last push was on 2026-10-15, and the version in the manifest is 2.1.3. The licence is Apache-2.0 OR MIT, and the crate is published on crates.io with documentation on docs.rs.
FxHasher is a name, not a description of the algorithm
The naming is historical and slightly misleading, which is worth sorting out before anyone reads the source expecting Firefox's hash.
The original hash algorithm provided by the crate was one taken from Firefox, hence the hasher it provides is called FxHasher. This name is kept for backwards compatibility, but the underlying hash has since been replaced.
The current design for the hasher is a polynomial hash finished with a single bit rotation, together with a wyhash-inspired compression function for strings and slices. Both parts are credited to Orson Peters.
Two details there matter for performance. The polynomial hash is the classic multiply-accumulate approach, where a value is folded into the accumulator by multiplication and addition, and the final single bit rotation is a cheap way to break up the low bits of the result so that the result distributes well into a table's bucket array. The wyhash-inspired compression handles the other case: hashing a slice of bytes is not a single multiplication, so the input has to be folded into a fixed width first, and wyhash's trick is a multiply and xor pair that mixes input faster than a general-purpose hash while staying cheap.
The practical takeaway is that FxHasher today is not Firefox's hash with a new name, it is a different design that happens to keep the old name so that code written against 1.x still compiles. A reader who expects the Firefox algorithm from the name will misread the performance characteristics.
FxHashMap and FxHashSet are type aliases, nothing more
The public API of the crate is two type aliases. The crate provides FxHashMap and FxHashSet as collections, and they are simply type aliases for their std::collection counterparts using the Fx hasher.
That is worth spelling out, because it explains both the ease of adoption and the limits. The usage example in the README is this short:
use rustc_hash::FxHashMap;
let mut map: FxHashMap<u32, u32> = FxHashMap::default();
map.insert(22, 44);Because it is an alias rather than a new collection type, you get the entire HashMap implementation, including its entry API, its raw entry variants and its ergonomics, and the only thing that changed is which hasher is instantiated. There is no separate type to learn and no separate trait implementations to worry about, and code that takes a std HashMap accepts an FxHashMap unchanged, because they are the same type with a different hasher parameter.
The trade-off of aliases is that you cannot also use a different hasher on the same map, and there is nothing to configure beyond the hasher. For a crate whose entire purpose is a different hasher, that is exactly the right shape. There is also no separate iterator, no entry variant and no attempt to be a better hash map; it is the standard map with a different default.
The consequence for readers is that the performance claim is narrow and checkable. You are not getting a faster data structure, you are getting the same data structure with a cheaper hash function, and the gain shows up in workloads where hashing is a large share of the cost.
The no_std path and the feature flags
The std feature is on by default to enable the collections, and it can be turned off in Cargo.toml:
rustc-hash = { version = "2.1", default-features = false }The reason is structural. The collections in the standard library require std, so without the std feature the type aliases have nothing to alias. What remains is the hasher itself, and that part can run on no_std, which is what makes the crate usable in a kernel, a bootloader, or an embedded target where std is unavailable.
The feature list in the manifest is small and each entry is a distinct capability. default is std, and std is an empty feature flag, so the collections are gated on it. nightly is another empty flag, which in the Rust ecosystem is the conventional way to gate code that needs unstable compiler features. rand is a non-empty one, and it pulls in the rand crate at version 0.9 along with std, which is the way to get a randomly seeded hasher.
That last feature is the one that matters most for a security-minded reader, and it points to the honest limits of the crate. A hasher whose output is deterministic across runs is what a compiler wants, since it makes builds reproducible. The rand feature exists for the case where you want a per-process random seed instead, which defeats the precomputation of collision patterns. That is a mitigation, not a fix, and it is not the same as using a keyed hash function.
The crate requires Rust 1.77 and uses edition 2021, so it is available on any reasonably current toolchain.
The DoS argument, and where it does not apply
The failure mode to understand is hash collision denial of service, and it is worth being precise about the direction of the risk.
With a non-cryptographic hash such as FxHasher, an attacker who can choose the keys of a map can search offline for many keys that all land in the same bucket. The search is cheap because the hash is cheap to compute and the algorithm is public. Once those keys are inserted, every lookup degrades to a linear scan, and a server that authenticated every request against such a map can be made to spend quadratic time on a handful of requests.
SipHash exists precisely to make that search infeasible, because the mixing is keyed with a secret and the attacker cannot predict the bucket without the key. That is the guarantee std gives you by default, and giving it up is exactly the trade this crate asks you to make.
So the rule is simple and worth stating plainly. Use FxHashMap when the keys come from inside your program, and keep std HashMap when the keys come from outside. A map keyed by a user-supplied identifier, a network-supplied header, a path segment or a piece of user input should not use a non-cryptographic hash, no matter how much faster it is. A map keyed by an AST node id, a symbol name, a file path you generated yourself or a compile-time key is a different case entirely.
The rand feature blurs this line, and a reviewer should notice that. A randomly seeded Fx hash makes offline collision search harder because the seed is unknown, but it is not a keyed MAC and it does not give the guarantee SipHash gives. If your threat model requires that guarantee, use a keyed hash.
Where rustc-hash is the wrong choice
The first case is any map keyed by untrusted input, and the previous section is the argument for that. The performance gain does not exist in a real attack scenario, because the attack is what consumes the time.
The second case is when you need a stable hash value across processes or across releases. A deterministic hash is only deterministic within a given build configuration. The rand feature exists precisely because a fixed seed is the default, and a project that stores hashed identifiers on disk, or that compares hashes between two machines, has to think about whether a version change or a feature flag changes the output. The standard library's DefaultHasher is also documented as not guaranteed stable across Rust versions, so the habit of treating any hasher output as a persistent identifier is a mistake regardless of which crate you pick.
The third case is a project that is not performance-bound. FxHashMap is a drop-in, so there is little cost to trying it, but a reviewer looking at a pull request that swaps the hasher deserves to see evidence. The crate's own argument is a benchmark argument, and the honest version of using this crate is to profile, find that hashing is hot, and then try it.
The alternative worth comparing is not a different crate but a different decision, using the standard HashMap and a different data structure. A Vec with a linear scan beats a hash map for small collections, and a sorted Vec with binary search beats both when the key set is static and lookups are rare. Those wins are usually larger than the difference between SipHash and FxHasher, and they come with fewer assumptions. Where hashing really is the bottleneck, the standard library also offers ahash, a randomized hasher that is a compromise between speed and collision resistance, and FxHashMap remains the fastest of the practical options when the keys are trusted.
Editorial conclusion
rustc-hash fits code that hashes keys it controls, such as internal compiler and build-tool data structures where hash quality matters less than throughput, and it is a good default to reach for when profiling shows SipHash is the bottleneck. It is the wrong choice for a map keyed by anything an attacker can supply, because a non-cryptographic hash is exactly the thing that makes collision attacks cheap, and it is the wrong choice when you need a stable hash across processes or releases rather than one the standard library already provides. Before adopting it, confirm you are not replacing a map that holds user-controlled keys, keep the std feature off only if you genuinely need no_std, and measure the change rather than assuming it, since the compiler's own justification was that spending more cycles on hash quality did not make rustc faster on real-world benchmarks.
Frequently asked questions
What is rustc-hash and why does rustc not use SipHash?
It is a speedy, non-cryptographic hashing algorithm used by rustc. The standard library HashMap uses SipHash for resistance against denial-of-service attacks, which the compiler does not need, and the crate notes that spending more CPU cycles on a higher quality hash did not make the compiler faster on real-world benchmarks.
Is FxHasher still the hash from Firefox?
No. The original algorithm was taken from Firefox and the name FxHasher is kept for backwards compatibility, but the underlying hash has since been replaced. The current design is a polynomial hash finished with a single bit rotation, together with a wyhash-inspired compression function for strings and slices.
How do I use FxHashMap in Rust?
Import it and use it like the standard map, since FxHashMap and FxHashSet are type aliases for the std collection counterparts using the Fx hasher. The README example creates a FxHashMap with FxHashMap::default() and inserts into it.
Can I use rustc-hash in a no_std project?
Yes, but only the hasher. The std feature is on by default to enable the collections, and turning it off with rustc-hash = { version = "2.1", default-features = false } in Cargo.toml leaves you with the hasher alone, since the standard library collections need std.
What licence is rustc-hash released under?
The crate is dual licensed under Apache-2.0 OR MIT, with the licence files at the repository root. The version in the manifest is 2.1.3, it requires Rust 1.77, and the last push was on 2026-10-15.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rust-lang-rustc-hash)Was this useful?