Home › Security › Crypto primitives
algorithm low

Cryptographic hashes (SHA-2, BLAKE3)

Problem Systems that need a short, trustworthy fingerprint of data (file integrity, content-addressed storage, deduplication, signatures, Merkle trees) must pick a hash that attackers cannot forge collisions for.

Collision-resistant fingerprints of data; SHA-256 for interoperability, BLAKE3 for speed, HMAC/HKDF for keyed uses.

O(n); SHA-256 order of 1-2 GB/s per core with SHA extensions, BLAKE3 order of several GB/s per core and parallel across cores
hashingsha-256blake3hmachkdfintegrity
Overview

A cryptographic hash maps any input to a fixed-size digest where finding collisions or preimages is infeasible, so a 32-byte digest can safely stand in for the data. Keyed uses need a construction on top: HMAC for MACs, HKDF for deriving keys. Ledgers, container registries, source control and government standards all rely on it.

Key facts

Use when

  • Integrity of files, artifacts, content-addressed storage, deduplication.
  • Input to signatures, commitments, Merkle trees.
  • Ledgers: Bitcoin chains block headers with SHA256(SHA256()) (developer docs).
  • Cloud and containers: OCI image descriptors carry sha256: digests (image-spec).
  • Software development: Git picked SHA-256 as the successor to SHA-1 (hash-function-transition).
  • Government: SHA-2 is specified in the US federal standard FIPS 180-4.

Avoid when

Deep dive

How it works

In: message bytes of any length, optionally a key or context string · Out: 32-byte digest (BLAKE3: any length) · State: none (hasher state lives only within one streaming call) · Cost: O(n); order of 1-2 GB/s (SHA-256 with SHA extensions), several GB/s (BLAKE3)

  1. SHA-256 (Merkle-Damgård): pad the message, split into 64-byte blocks, feed each through a 64-round compression function updating a 32-byte state. The final state is the digest, which is why an attacker who knows H(m) can compute H(m || padding || x) without m (length extension).
  2. SHA-512/256, SHA-3, BLAKE2, BLAKE3 don't have length extension.
  3. BLAKE3: split input into 1 KiB chunks, compress each independently (SIMD lanes, threads), combine in a binary tree. Modes: hash, keyed_hash (a MAC, 32-byte key), derive_key (KDF with a context string), and XOF (any output length).
  4. HMAC(K, m) = H((K ⊕ opad) || H((K ⊕ ipad) || m)): a secure MAC for any of these hashes.
  5. HKDF: Extract (HMAC with salt over input key material) then Expand (HMAC chain with an info label) to get independent subkeys.

Code

Rust: sha2 = "0.10", hmac = "0.12", hkdf = "0.12", blake3 = "1".

use hkdf::Hkdf;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256};
use std::io::Read;

type HmacSha256 = Hmac<Sha256>;

/// Streaming file digest; constant memory.
pub fn sha256_file(path: &str) -> std::io::Result<[u8; 32]> {
    let mut f = std::fs::File::open(path)?;
    let mut h = Sha256::new();
    let mut buf = vec![0u8; 1 << 16];
    loop {
        let n = f.read(&mut buf)?;
        if n == 0 { break; }
        h.update(&buf[..n]);
    }
    Ok(h.finalize().into())
}

/// Webhook-style MAC: sign and verify in constant time.
pub fn mac(key: &[u8], msg: &[u8]) -> [u8; 32] {
    let mut m = HmacSha256::new_from_slice(key).expect("any key length works");
    m.update(msg);
    m.finalize().into_bytes().into()
}

pub fn mac_ok(key: &[u8], msg: &[u8], tag: &[u8]) -> bool {
    let mut m = HmacSha256::new_from_slice(key).expect("any key length works");
    m.update(msg);
    m.verify_slice(tag).is_ok() // constant-time compare
}

/// One master secret -> independent keys per purpose.
pub fn subkeys(master: &[u8; 32]) -> ([u8; 32], [u8; 32]) {
    let hk = Hkdf::<Sha256>::new(Some(b"myapp-v1-salt"), master);
    let (mut enc, mut auth) = ([0u8; 32], [0u8; 32]);
    hk.expand(b"encryption", &mut enc).unwrap();
    hk.expand(b"auth-tokens", &mut auth).unwrap();
    (enc, auth)
}

/// BLAKE3: fastest option when you control both sides.
pub fn blake3_examples(data: &[u8], key: &[u8; 32], master: &[u8]) {
    let digest = blake3::hash(data);                 // 32 B, .to_hex() for display
    let tag = blake3::keyed_hash(key, data);         // MAC
    let k = blake3::derive_key("myapp 2026-10 session keys v1", master); // KDF, context is a fixed string
    let _ = (digest, tag, k);
    // big inputs: blake3::Hasher::new().update_rayon(data).finalize() uses all cores ("rayon" feature)
}

Complexity and constants

  • SHA-256 with SHA-NI (x86) / ARMv8 SHA2: order of 1.5-2 GB/s per core; without, order of 300-500 MB/s, where SHA-512 is faster on 64-bit CPUs.
  • BLAKE3: order of 3-7 GB/s single-threaded with AVX2/AVX-512, scaling near-linearly with cores on large inputs.
  • Small inputs (< 64 B): fixed overhead of hundreds of ns; per-call cost, not throughput, dominates.
  • Digest sizes: 32 B gives 128-bit collision resistance, which is enough. Truncating to 16 B leaves 64-bit collision resistance: fine for non-adversarial dedup keys, not for security.

Efficiency

  • Cost: SHA-256 order of 1.5-2 GB/s per core with SHA extensions, 300-500 MB/s in software; BLAKE3 order of 3-7 GB/s single-threaded, scaling with cores; hundreds of ns fixed cost for tiny inputs. Bound: compute on long inputs, per-call overhead on short ones.
  • Levers:
    • Hardware SHA — order of 3-5x over software (the sha2 crate selects it at runtime) — SHA-256 on x86/ARM with the extensions.
    • Tree hashing — BLAKE3's README says b3sum is an order of magnitude faster than sha256sum on typical desktop hardware (rayon feature) — big inputs, both sides under your control.
    • Clone a keyed HMAC instance — saves the two pad-block compressions per message — many short MACs under one key.
    • 64 KiB or larger read buffers — syscalls stop dominating — streaming files.
  • Naive → standard → state of the art:
    • Naive · software SHA-256, small reads, rebuild HMAC state per message
    • Standard · SHA-256 with hardware backend, streaming, cached keyed state
    • State of the art · multithreaded SIMD BLAKE3; for non-adversarial dedup or hash tables a fast non-cryptographic hash

Implementation notes

  • Hash the exact bytes: define canonical serialization before hashing structured data, and include a domain-separation prefix and length fields when hashing multiple fields (H("v1" || len(a) || a || b)), otherwise ("ab","c") collides with ("a","bc").
  • For MAC checks, compare in constant time (verify_slice, subtle::ConstantTimeEq), never ==.
  • Random tokens (session IDs, API keys) are already uniform: store SHA-256(token) in the DB; no slow KDF needed.
  • Merkle trees: prefix leaves with 0x00 and inner nodes with 0x01 to prevent second-preimage tricks.

Pitfalls

  • SHA-256(secret || message) as an authenticator: length-extendable.
  • Using MD5/SHA-1 "only for integrity" against attackers (chosen-prefix collisions on SHA-1 are practical).
  • Hashing passwords with SHA-256, even salted.
  • Mixing up hex and raw bytes when comparing digests across systems.
  • Assuming a hash hides low-entropy data: SHA-256(phone number) is reversible by enumeration.

Variants and alternatives

SHA-512/256no length extension, fast on 64-bit without SHA-NI.
SHA-3 / SHAKEdifferent design (sponge); use when a standard requires it or as a hedge.
BLAKE2b/2spredecessor of BLAKE3, in libsodium (crypto_generichash) and Argon2.
KangarooTwelvefast Keccak-based tree hash.
xxHash (non-cryptographic) and SipHash (keyed, short-input PRF)hash tables only, SipHash when keys are attacker-controlled.

In production

  • Ledgers: Bitcoin (double SHA-256, docs).
  • Cloud and supply chain: OCI container digests (sha256:, spec), Sigstore, TLS 1.3 (HKDF-SHA256/384).
  • Source control: Git (SHA-1 moving to SHA-256, doc).
  • Networking and storage: WireGuard (BLAKE2s), Bao/iroh (BLAKE3 verified streaming).

Implementations

namelangrepoinstallverdictlicencehealthas_ofnotes
blake3RustBLAKE3-team/BLAKE3cargo add blake3————official; SSE2 to AVX-512, NEON, runtime detection, rayon threads; b3sum CLI
sha2RustRustCrypto/hashescargo add sha2————SHA-256/512, runtime SHA-NI and AArch64 backends; SHA-3 and BLAKE2 in sibling crates
hmac, hkdfRustRustCrypto/MACs, RustCrypto/KDFscargo add hmac hkdf————generic over any digest hash; constant-time verify_slice
aws-lc-rsRustaws/aws-lc-rscargo add aws-lc-rs————SHA-2, HMAC, HKDF over AWS-LC; FIPS option via aws-lc-fips-sys
ringRustbriansmith/ringcargo add ring————SHA-2, HMAC, HKDF; C/asm largely from BoringSSL

Sources

  • NIST, FIPS 180-4: Secure Hash Standard, 2015. spec; FIPS 202: SHA-3 Standard, 2015. spec
  • O'Connor, Aumasson, Neves, Wilcox-O'Hearn, BLAKE3: one function, fast everywhere, 2020. paper · code
  • Krawczyk, Bellare, Canetti, RFC 2104: HMAC, 1997. RFC; Krawczyk, Eronen, RFC 5869: HKDF, 2010. RFC
  • Stevens et al., The first collision for full SHA-1, CRYPTO 2017. paper · site

Used by

code signing · plannedSigning binaries/apps with certificate chains, entitlements, timestamping and notarization
Content-addressed storageBuild caches, backups, package registries and version control store huge numbers of files, many identical; they need deduplication and proof that what they read back is what was written.
dnssec · plannedDNSSEC signing (RRSIG, DNSKEY, NSEC/NSEC3) and chain-of-trust validation
hardware root of trust · plannedSecure elements/TPM/TEE holding device keys, attestation and monotonic counters
hermetic execution · plannedRun actions with only declared inputs in a sandbox and fixed environment
Idempotency keysAnyone calling a service over an unreliable network must retry when a reply is lost, yet repeating an action such as a charge, a booking or a server launch must not perform it twice.
image based provisioning · plannedStream and verify disk images onto machines, then first-boot configuration
kademlia dht · plannedXOR-metric DHT with k-buckets and iterative parallel lookups
measured boot · plannedEach boot stage hashes the next into TPM PCRs (extend) and logs events for later attestation
memory integrity scanning · plannedScanning process memory and loaded modules for patches, injected code and hooks
model registry · plannedVersioned model artifacts with metadata, stages, lineage and immutable content hashes
nakamoto consensus · plannedProof-of-work longest-chain consensus: difficulty adjustment, orphan handling, confirmations
OAuth 2 and OpenID ConnectTeams adding "Sign in with Google/Microsoft/Okta", enterprise SSO, or letting third parties call their API for users must choose a safe login and delegated-access flow. This guide answers which flow to use and what goes wrong.Password hashing (Argon2id)A service that stores user passwords must make a leaked database expensive to crack, since attackers can test billions of guesses per second on GPUs against ordinary hashes.
pdf digital signatures · plannedCMS/PAdES signatures embedded in PDFs with byte ranges and long-term validation
peer to peer swarming · plannedBitTorrent-style piece exchange: rarest-first, choking, tit-for-tat, hash-verified pieces
rsync delta algorithm · plannedRsync rolling checksum + strong hash to send only changed blocks
schema migration versioning · plannedVersioned forward migrations for local and server databases; expand-contract changes
selective disclosure credentials · plannedVerifiable credentials revealing only chosen attributes (SD-JWT, BBS+ signatures)
signed attestations · plannedDSSE/in-toto signed provenance statements about artifacts
Signed update metadata (TUF)Publishers who ship files to many clients through repositories and mirrors they do not fully trust need each client to install only the file meant for it, the newest one, even after a key is stolen.Software supply chain securityTeams shipping software with third-party dependencies and a deploying CI system must decide how to control what code enters the build and prove what comes out, against malicious packages and compromised build tooling.TLS 1.3Any network service must keep traffic between clients, or between internal services, private, tamper-proof and authenticated to the right server, without hand-building a secure channel.

Systems (65):

Alternatives and related