hash32

32-bit FNV-1a and MurmurHash3 hashers for no_std and embedded Rust targets.

Library
Cargo
v1.0.0
14stars
MIT OR Apache-2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
31/100Needs Attention
Development Activity12
Maintenance20
Community20
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
70/100Good
Architecture75
Code Quality78
Innovation55
Learning Curve70

hash32 provides 32-bit implementations of two well-known non-cryptographic hashing algorithms — FNV-1a and MurmurHash3 — built specifically for platforms where 64-bit arithmetic is expensive or unavailable, such as 32-bit microcontrollers like ARM Cortex-M. Standard library hashers assume a 64-bit finish() result, which on small embedded targets forces the compiler to emit software-emulated 64-bit operations even when the underlying data never needs more than 32 bits of hash space.

The crate defines its own hash32::Hasher trait, a strict subtree of core::hash::Hasher that both extends it and enforces (by construction) that implementers only ever perform 32-bit operations while accumulating a hash. Because it extends core::hash::Hasher, both FnvHasher and Murmur3Hasher work anywhere a type implementing core::hash::Hash is expected — including #[derive(Hash)] structs — with no additional glue code required.

The crate is #![no_std], has zero dependencies, and ships two hasher choices with a clear tradeoff documented up front: FnvHasher is faster and smaller in code size, while Murmur3Hasher offers better collision resistance. Both are explicitly non-cryptographic and unsuitable for security-sensitive or adversarial-input use cases.

What You Get

  • FnvHasher - a 32-bit FNV-1a implementation, the faster and smaller of the two hashers.
  • Murmur3Hasher - a 32-bit MurmurHash3 implementation with stronger collision resistance than FNV-1a.
  • A hash32::Hasher trait - extends core::hash::Hasher with finish32(), guaranteeing the hasher performs only 32-bit operations.
  • Zero-dependency, #![no_std] crate - compiles for bare-metal and embedded targets with no allocator or OS assumptions.
  • Compatibility with #[derive(Hash)] - works with any type implementing core::hash::Hash, including structs, tuples, and generics.

Common Use Cases

  • Hashing keys in embedded hash maps - libraries like heapless use hash32 hashers to back fixed-capacity hash maps on microcontrollers.
  • Fast checksums on 32-bit MCUs - computing lightweight, non-cryptographic checksums on ARM Cortex-M and similar targets without triggering 64-bit intrinsics.
  • Deduplication in resource-constrained firmware - hashing sensor readings, message IDs, or config keys where a std::collections::HashMap isn’t available.
  • Generic code over hash algorithms - writing functions generic over H: hash32::Hasher to guarantee 32-bit-only behavior at the type level.

Under The Hood

Architecture The crate is organized as a thin trait plus two independent, self-contained hasher modules. lib.rs defines the hash32::Hasher trait — a supertrait bound of core::hash::Hasher adding finish32() -> u32 — and re-exports FnvHasher (from fnv.rs) and Murmur3Hasher (from murmur3.rs). Neither hasher module depends on the other; each independently implements both core::hash::Hasher::write/finish and the crate’s own Hasher::finish32, so callers can use either interchangeably wherever a 64-bit core::hash::Hasher is expected, with finish() simply zero-extending the 32-bit result. There is no shared mutable state, no allocation, and no runtime configuration — the entire public surface is two structs and one trait.

Tech Stack Pure Rust, edition 2021, MSRV 1.56, with zero runtime dependencies (the crate previously depended on byteorder but that was removed in the 1.0 release in favor of u32::from_le_bytes). It is #![no_std], so it has no reliance on an allocator, OS, or standard library facilities beyond core. Cargo.toml declares only dev-time tooling implicitly via CI (rustfmt, clippy). The GitHub Actions pipeline cross-compiles and tests against both x86_64-unknown-linux-gnu and i686-unknown-linux-musl targets, runs cargo fmt --check and cargo clippy --all --all-targets -- --deny warnings, and separately builds docs with cargo +nightly rustdoc --all-features under -D warnings to match how docs.rs renders the crate.

Code Quality Testing is table-driven: tests/fnv.rs and tests/murmur3.rs each check known-good hash values against public-domain test vectors (28 FNV-1a vectors, 10+ MurmurHash3 vectors including edge cases like 1-3 trailing bytes). The Murmur3Hasher internals use unsafe for a hand-rolled byte buffer (MaybeUninit-backed) to avoid memcpy overhead on 0-3 byte tail copies; each unsafe block carries an inline safety-invariant comment explaining why the access is sound, and the CHANGELOG records at least one prior fix to undefined behavior in that path, showing active scrutiny of the unsafe code. #![warn(missing_docs, clippy::use_self, ...)] is set crate-wide and enforced as a hard error in CI via --deny warnings. Naming and structure are minimal and consistent; there’s no dedicated benchmark suite.

What Makes It Unique The crate’s core idea — a Hasher trait that is a strict, compiler-enforced subtree of core::hash::Hasher guaranteeing only 32-bit operations — is a narrow but genuinely useful abstraction for embedded Rust: it lets generic code declare “I need a hash that never touches 64-bit arithmetic” as a trait bound rather than as a convention or comment. It isn’t inventing new hash algorithms; FNV-1a and MurmurHash3 are well-established. Its value is as foundational, dependency-free plumbing that other embedded-focused crates (notably heapless) build hash maps on top of.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search