mwhash 0.1.1

A simple, fast, non-cryptographic hash function for Rust
Documentation
  • Coverage
  • 6.25%
    1 out of 16 items documented1 out of 16 items with examples
  • Size
  • Source code size: 32.36 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 202.35 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 2s Average build duration of successful builds.
  • all releases: 1s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • meow-land/mwhash
    4 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • horizonwiki

mwhash

A fast, non-cryptographic u32 hash. no_std, zero dependencies, zero allocations.

Useful for: integrity checks on packets, checksums, fast buffer comparison, hash tables, embedded projects. Not suitable for cryptography.


Performance

Benchmark results (seed = 0x12345678) are shown below:

----------------------------------------------------------------------------------------------------
64 KB      | size:     64.00 KB  | iters:  20000 | total: 339.070ms | per call:   16.953µs | throughput:   3.87 GB/s
1 MB       | size:   1024.00 KB  | iters:   2000 | total: 549.020ms | per call:  274.509µs | throughput:   3.82 GB/s
1 GB       | size: 1048576.00 KB | iters:      3 | total: 979.626ms | per call:  326.542ms | throughput:   3.29 GB/s
----------------------------------------------------------------------------------------------------
  • 64 KB: L1/L2 cache.
  • 1 MB: L3 cache.
  • 1 GB: main memory.

Environment:* Tested on AMD64 architecture (Processor: [Intel Core Ultra 5 125h], RAM: [16 GB lpddr5x 6000MT/s]). Source code: examples/benchmark.rs


Installation

[dependencies]
mwhash = "0.1.0"

Examples

One-shot hashing

Use this when all your data is already in memory.

use mwhash::mwhash;

let hash = mwhash(b"hello mwhash");
println!("Result: {:08x}", hash);

assert_ne!(hash, 0);

Incremental hashing

Use this when data arrives in chunks — e.g. from a file or a network stream. No need to keep the whole buffer in memory.

use mwhash::{Hasher, mwhash};

let mut h = Hasher::new();
h.update(b"hello");
h.update(b" rust");

let hash = h.finish();
println!("Incremental hash: {:08x}", hash);

assert_eq!(hash, mwhash(b"hello rust"));

Hashing with a numeric seed

The same input produces a different hash in a different "domain" — useful for salting data or separating hash spaces.

use mwhash::{mwhash, Hasher};

let mut h = Hasher::with_seed(0x12345678);
h.update(b"codeberg better than github");
let h1 = h.finish();

println!("Seeded hash: {:08x}", h1);
assert_ne!(h1, mwhash(b"codeberg better than github"));

Hashing with a string seed

More convenient than picking magic numbers by hand — the string itself is hashed into a numeric seed.

use mwhash::{mwhash, Hasher};

let mut h = Hasher::with_string_seed("My-SID-is-definitely-unique");
h.update(b"100% essential data");
let hash = h.finish();

println!("String-seeded hash: {:08x}", hash);

assert_ne!(hash, 0);
assert_ne!(hash, mwhash(b"100% essential data"));

One-shot hashing with a seed

The fastest way to get a seeded hash when you don't need to process data in chunks.

use mwhash::mwhash_seeded;

let data = b"test";
let seed = 0xDEAD_BEEF;

let hash = mwhash_seeded(data, seed);
println!("Hash: {:08x}", hash);

assert_ne!(hash, mwhash::mwhash(data));

Concatenation without allocation

The order of updates doesn't matter — the result matches the hash of the combined data.

use mwhash::{mwhash, mwhash_concat};

let part1 = b"foo";
let part2 = b"bar";

let combined_hash = mwhash_concat(part1, part2);
let full_hash = mwhash(b"foobar");

println!("Hash: {:08x}", combined_hash);
assert_eq!(combined_hash, full_hash);

Reusing the Hasher

reset() returns the hasher to its initial state without new allocations — useful when processing many independent messages.

use mwhash::{mwhash_seeded, Hasher};

let custom_seed = 0x12345678;
let mut h = Hasher::with_seed(custom_seed);

h.update(b"data1");
let hash1 = h.finish();
println!("Hash 1: {:08x}", hash1);

h.reset();
h.update(b"data2");
let hash2 = h.finish();
println!("Hash 2: {:08x}", hash2);

assert_eq!(hash2, mwhash_seeded(b"data2", custom_seed));
assert_ne!(hash1, hash2);

After reset(), a hasher with a custom seed behaves exactly as it did right after creation with that same seed:

use mwhash::Hasher;

let custom_seed = 0x12345678;
let mut h = Hasher::with_seed(custom_seed);

h.update(b"some data");
println!("Hash: {:08x}", h.finish());

h.reset();

assert_eq!(h.finish(), mwhash::mwhash_seeded(b"", custom_seed));

h.update(b"new data");
println!("New hash after reset: {:08x}", h.finish());

no_std

The library is fully no_std, with no alloc. It runs on any target, including bare metal.


License

Apache License 2.0. View License