Skip to content
hashkey.bond

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

  1. Preimage resistance. Given a digest h, you cannot find an input m with hash(m) = h. This is what makes the digest safe to reveal.
  2. Second-preimage resistance. Given a message m, you cannot find a different message m' with the same digest. This is what protects commitments: you cannot swap the payload after the fact.
  3. 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.