Archivehashing
What Hash Functions Actually Guarantee
Avalanche, collision resistance, preimage resistance — the three properties that make SHA-256 boring on purpose.
- Published
- Reading time
- 2 min read
A cryptographic hash function does one small thing: it maps a message of any size to a fixed-size digest. Everything useful about it — password storage, commitments, blockchains, content addressing — falls out of three guarantees and one engineering question.
The three guarantees
- Preimage resistance. Given a digest
h, you cannot find an inputmwithhash(m) = h. This is what makes the digest safe to reveal. - Second-preimage resistance. Given a message
m, you cannot find a different messagem'with the same digest. This is what protects commitments: you cannot swap the payload after the fact. - Collision resistance. You cannot find any pair of distinct messages with the same digest. This is what lets a digest stand in for the message when the adversary, not you, constructs both messages.
Note the asymmetry: collisions are always mathematically guaranteed to exist (pigeonhole principle — infinite messages, finite digests) while preimages exist only if the digest belongs to something. The attack surface is what you do with the guarantee.
The avalanche property
Flip a single bit of the input and, on average, half the output bits change, as if by coin flip. This is not in the definition — it is a quality a function must have so that its outputs reveal nothing about their inputs. It is also what makes binary search over "how close is my digest" impossible.
Why SHA-256 is boring on purpose
SHA-256 is overdesigned relative to most applications: 128-bit collision resistance by construction, output 256 bits wide, no exploit beyond a shallow local structure ever found since 2001. Its cost is speed, not slowness — a GPU grinds billions of them per second. That is why nobody chooses it for passwords:
- For passwords you want slow and memory-hungry: Argon2, scrypt, bcrypt.
- For trees and content addressing you want fast and large: SHA-256, BLAKE3.
The interesting engineering question — and the subject of later posts — is what happens when you compose hash functions across many machines: how does a merkle tree prove membership, how does consistent hashing decide which node stores which key, and why do both use the same primitive in very different ways.