⚠️ This crate is NOT for password storage. Hashing passwords requires a memory-hard / iteration-hard KDF (Argon2id, scrypt, bcrypt, PBKDF2). For that, use
hsh::api::hash— not the primitives here.
Contents
Install · When to use · Quick Start · Algorithm matrix · Streaming vs one-shot · Constant-time compare · Test vectors · Examples · License
Install
[]
= "0.0.9"
MSRV 1.75 stable.
Feature flags
| Feature | Status | Pulls in | Notes |
|---|---|---|---|
default |
— | sha2 sha3 blake3 |
The sensible defaults |
sha2 |
✅ | sha2 0.10 |
SHA-256, SHA-384, SHA-512 (FIPS 180-4) |
sha3 |
✅ | sha3 0.10 |
SHA3-256, SHA3-384, SHA3-512 (FIPS 202) |
blake3 |
✅ | blake3 1.5 |
BLAKE3-256 |
k12 |
🚧 reserved | (future) k12 |
KangarooTwelve / TurboSHAKE128/256 (RFC 9861, Oct 2025) |
ascon |
🚧 reserved | (future) ascon-hash |
Ascon-Hash256 / Ascon-XOF128 (NIST SP 800-232 Aug 2025) |
Disable a default feature to shrink the dependency surface:
= { = "0.0.9", = false, = ["sha2"] }
When to use
✅ Yes, use hsh-digest for:
- Content addressing (Git-style, IPFS-style content hashes).
- Building blocks for higher-level protocols (Merkle trees, commitment schemes).
- Pre-processing input for an HMAC or signature scheme.
- PHC string parsing for non-
hshhashes.
❌ No, don't use hsh-digest for:
- Password storage. Use
hsh::api::hash— it picks a memory-hard KDF and applies constant-time verification. - HMAC / KDF / signatures / KEMs. Use the RustCrypto siblings (
hmac,hkdf,digest,signatures/*).
ADR-0005 documents the scope boundary: doc/adr/0005-general-hashing-scope.md.
Quick Start
One-shot
use ;
let digest = hash.unwrap;
assert_eq!;
Streaming
use ;
let mut hasher = new.unwrap;
hasher.update;
hasher.update;
let digest = hasher.finalize;
assert_eq!;
Algorithm matrix
| Variant | Output | Spec | Cargo feature |
|---|---|---|---|
Algorithm::Sha256 |
32 B | FIPS 180-4 | sha2 |
Algorithm::Sha384 |
48 B | FIPS 180-4 | sha2 |
Algorithm::Sha512 |
64 B | FIPS 180-4 | sha2 |
Algorithm::Sha3_256 |
32 B | FIPS 202 | sha3 |
Algorithm::Sha3_384 |
48 B | FIPS 202 | sha3 |
Algorithm::Sha3_512 |
64 B | FIPS 202 | sha3 |
Algorithm::Blake3 |
32 B | BLAKE3 spec (Aumasson et al., 2020) | blake3 |
All variants implement constant-output-length digests. For variable-length output (SHAKE / TurboSHAKE), see the k12 follow-up feature.
Algorithm::id() returns the standard identifier ("sha256", "sha3-256", "blake3", etc.) for use in PHC strings or protocol headers.
Streaming vs one-shot
Both are equivalent — choose based on whether the input is already in memory:
use ;
let oneshot = hash.unwrap;
let mut streaming = new.unwrap;
streaming.update;
let streamed = streaming.finalize;
assert_eq!;
The streaming API exposes Update semantics for incremental hashing (file-content addressing, network-stream MACing, etc.).
Constant-time compare
use constant_time_eq;
let a = b"sha256-tag-32-bytes...";
let b = b"sha256-tag-32-bytes...";
assert!;
Wraps [subtle::ConstantTimeEq] so comparing two digest tags doesn't leak the prefix-match length via timing. Use this whenever you compare a computed digest against an expected one (MAC verification, content-hash equality checks).
Test vectors
The crate ships KAT tests (crates/hsh-digest/tests/kat.rs) against:
- SHA-2 — NIST CAVP byte-test vectors (
SHAVS). - SHA-3 — NIST CAVP byte-test vectors (
SHA3VS). - BLAKE3 — project test vectors at
blake3-team/BLAKE3/test_vectors.
Run with:
Examples
See crates/hsh-digest/examples/ for runnable demos:
oneshot.rs— minimal hash + hex print.streaming.rs— incremental hashing of a large input.content_addressing.rs— Git-style content-hash workflow.
Run with cargo run -p hsh-digest --example oneshot.
Documentation
| Doc | What's in it |
|---|---|
adr/0005-general-hashing-scope.md |
Scope decision: re-export only, no KDF / MAC / signature drift |
License
Dual-licensed under Apache 2.0 or MIT, at your option.