Hashing and the Birthday Paradox

Naseebullah Ahmadi  Senior Software Engineer, London

A hash space that looks astronomically large can still produce collisions with a surprisingly small number of items, the same math behind the birthday paradox, applied to hashing.

7 min read
#math
In one line

Hash nn items into mm possible values and collisions become likely far sooner than intuition suggests, once nn passes roughly m\sqrt {m}, not mm.

What it says

This formula answers one specific question. If you hash nn items into mm possible slots, uniformly and independently at random, what is the chance that at least two of them land on the same slot?

P(collision)1en22mP(\text{collision}) \approx 1 - e^{-\frac{n^2}{2m}}

(1)  Collision probability for n items over m slots.

It's the same question as the classic birthday paradox: put 23 people in a room (n=23n = 23) against 365 possible birthdays (m=365m = 365). The odds two of them share a birthday are already better than even, even though 23 is nowhere near 365. Hashing falls into the same trap: a hash space that looks astronomically large can still produce collisions with a surprisingly small number of items.

Breaking it down

  • P(collision)P(\text{collision}): the probability that at least two of the nn items land on the same hash value.
  • nn: the number of items being hashed.
  • mm: the size of the hash space, the number of distinct possible output values (for example 2322^{32} for a 32-bit hash).

It is easier to count the ways nothing goes wrong. The chance that all nn items land in distinct slots is a product of shrinking survival terms. The second item must avoid 1 slot, the third must avoid 2, and so on.

P(no collision)=i=0n1(1im)P(\text{no collision}) = \prod_{i=0}^{n-1}\left(1 - \frac{i}{m}\right)

(2)  Exact probability that every item lands in its own slot.

Where it comes from

Take logs of equation (2) and apply ln(1x)x\ln(1 - x) \approx -x for small xx. The sum i=0n1i\sum_{i=0}^{n-1} i collapses to n(n1)/2n2/2n(n-1)/2 \approx n^2/2. That gives the exponential form in equation (1).

Seeing it work

Setting P=1/2P = 1/2 in equation (1) and solving for nn gives n1.1774mn \approx 1.1774\sqrt{m}: even odds arrive at the square root of the output space, not the space itself.

A 32-bit hash has m=232m = 2^{32}, about 4.3 billion possible values, so intuition says you would need billions of items before collisions become a real concern. The formula says otherwise: at n=77,163n = 77{,}163 items, the collision probability is already at 50%.

@itsnas birthday.ts
codebirthday.ts
// Probability of at least one collision when hashing `n` items
// into `m` possible values.
function collisionProbability(n: number, m: number): number {
  return 1 - Math.exp(-(n * n) / (2 * m))
}
 
collisionProbability(77_163, 2 ** 32) // ≈ 0.5006
main
Nas (@itsnas)

A 128-bit hash pushes mm up to 21282^{128}, and the same formula puts the 50% mark at roughly 1.1774×26421.71.1774 \times 2^{64} \approx 21.7 quintillion items. That's why 128-bit hashes are treated as "collision-free" for essentially any practical dataset size.

Common misreadings

  1. 1

    Assuming safety scales with m, not √m

    A hash space of size mm does not buy you mm safe items: it buys you roughly m\sqrt{m}. Doubling the hash width doesn't double the safe item count, it roughly squares it.

  2. 2

    Trusting the formula more than the hash function

    This approximation assumes a perfectly uniform, independent random hash. Real hash functions can fall well short of that: in Daniel Lemire's own experiment, 1,000 items reached a 100% collision rate with a hash function that theory predicted would need over 77,000 items to hit 50%. The formula is a best case, not a guarantee.

  3. 3

    Applying it past n ≈ m

    The en2/2me^{-n^2/2m} approximation holds while nmn \ll m. As nn approaches mm, use the exact product i=0n1(1i/m)\prod_{i=0}^{n-1}(1 - i/m) instead: the exponential approximation stops tracking it closely.