When the algorithm flips a coin

A hash is a family, not a function

Two thousand and forty-eight keys into two hundred and fifty-six buckets. Under a hash that takes the low bits of the key, all 2,048 land in bucket zero and 255 buckets are empty. Under a multiplier drawn at random, the worst bucket holds 11. The keys are the same keys, and they are the multiples of the table size.

The probe formula nobody checks measured a hash table’s cost as it filled and found the closed form accurate. It also assumed something it did not examine: that the hash spreads the keys roughly uniformly. Every statement about a hash table’s performance rests on that assumption, it is nearly always left implicit, and it is a statement about the keys rather than about the table.

This essay is about what happens when the assumption fails, and about the standard repair — which is not a better hash function, because there is no such thing as a hash function without a bad input. It is a set of hash functions, and one of them chosen at random.

2,048 keys in 256 buckets — the low bits of the keyEach bar is one bucket's load, with keys computed from this hash function. The average load is 8.0 and the worst bucket here holds 2,048. There is only one function in this family, so there is nothing to draw at random and nothing an adversary has to guess. The collision rate over all pairs is 1.00e+0, against 3.91e-3 for a perfectly uniform map.average 8.001,0242,048bucket, 0 to 255keys in the bucketthe low bits · keys built for this hashworst bucket 2,048 against 8.0
Fig. 1 Two thousand and forty-eight keys in two hundred and fifty-six buckets, under a hash that masks off the low eight bits of the key. Every key is in bucket zero; 255 buckets are empty; there are 2,096,128 colliding pairs where a uniform map would give about 8,000. The keys are 256, 512, 768, … — the multiples of the table size, which anyone can write down knowing nothing but how big the table is.

Every fixed hash has a bad input, by counting

The reason is not a defect in any particular hash and it is worth getting right, because it explains why the repair has to be structural.

A hash function maps a universe of UU keys into bb buckets. By the pigeonhole principle some bucket receives at least U/bU/b keys. So for any fixed function there exists a set of U/bU/b keys that all collide — a set that turns the table into a linked list. The set exists for every hash function that has ever been written, including cryptographic ones; the difference between a good hash and a bad one is entirely in how hard the set is to find.

For the low-bits hash it is not hard at all. x & (b - 1) for b=256b = 256 depends on the bottom eight bits of the key and nothing else, so the multiples of 256 all map to zero. Nobody has to search: the colliding set is a closed form in the table size.

For multiply-shift it takes one more step and is still a closed form. The function is h(x)=(axmod232)(32)h(x) = (a x \bmod 2^{32}) \gg (32 - \ell) for an odd multiplier aa, and aa being odd makes it invertible modulo 2322^{32}. So given aa, compute a1a^{-1} — five iterations of Newton’s method, invinv(2ainv)\text{inv} \leftarrow \text{inv}(2 - a \cdot \text{inv}) — and the keys xt=a1tmod232x_t = a^{-1}t \bmod 2^{32} for small tt satisfy axtta x_t \equiv t, which lands them all in bucket zero.

With a=332,584,831a = 332{,}584{,}831 the inverse is 3,605,325,9513{,}605{,}325{,}951 — their product modulo 2322^{32} is exactly 1 — and the colliding keys begin 3,605,325,951 · 2,915,684,606 · 2,226,043,261 · 1,536,401,916 · 846,760,571, each one tt times the inverse for t=1,2,3,t = 1, 2, 3, \ldots

All 2,048 of them land in bucket zero. Not statistically: by construction, every time.

So the multiply-shift family is not stronger than the low-bits hash against an adversary who knows which function is in use. Its entire strength is that the adversary does not know.

What universality guarantees

A family HH of hash functions is universal if, for any two distinct keys xyx \ne y, choosing hh uniformly at random from HH gives

P[h(x)=h(y)]1bP[h(x) = h(y)] \le \frac{1}{b}

That is the whole definition, and three things about it are worth being exact about because it is routinely over-read.

The probability is over the choice of function, not over the keys. No distribution on the input is assumed. The guarantee holds for the worst pair of keys there is — this is an expected-case guarantee, not an average-case one, and it is the same distinction that separates randomised quicksort from first-element quicksort.

It bounds pairwise collisions and nothing more. Universality says nothing directly about the maximum bucket load, the length of the longest probe sequence, or the distribution’s shape. Those follow, but they follow with extra work and weaker constants.

It does not say collisions are rare in an absolute sense. 1/b1/b is exactly the collision probability of a perfectly random map, so a universal family is as good as random on pairs and may be much worse on higher-order structure. Multiply-shift is only 2-approximately universal — its bound is 2/b2/b rather than 1/b1/b — which costs a factor of two on collision counts and nothing on the asymptotics.

The consequence that makes it useful: with nn keys in bb buckets, the expected number of colliding pairs is at most (n2)/b\binom{n}{2}/b, so the expected number of other keys sharing a bucket with any fixed key is at most n/bn/b. That is the load factor, and it is the number every hash table analysis wants — now guaranteed for any key set rather than assumed for a nice one.

The measurement

Two thousand and forty-eight keys, two hundred and fifty-six buckets, average load 8:

hash keys worst bucket empty buckets colliding pairs
low bits ordinary 17 0 8,334
low bits multiples of 256 2,048 255 2,096,128
multiply–shift ordinary 16 0 8,059
multiply–shift multiples of 256 11 0 7,512
multiply–shift computed from its own multiplier 2,048 255 2,096,128

Four readings.

On ordinary keys the two hashes are indistinguishable. 17 against 16 in the worst bucket, 8,334 against 8,059 colliding pairs, both against a uniform-map expectation of (20482)/256=8,190\binom{2048}{2}/256 = 8{,}190. Any benchmark on ordinary keys reports these as equally good, which is exactly why the low-bits hash gets written and shipped.

The low-bits hash’s bad input is trivially constructible and ordinary. Multiples of the table size are not exotic data: they are pointers, page-aligned addresses, identifiers allocated in blocks, timestamps at a fixed interval. The failure does not require an attacker.

The family survives that same input. Worst bucket 11 against an average of 8, which is an unremarkable table. The keys that destroyed one function have no special relationship to a randomly chosen member of the family.

And it does not survive an input computed against it. The last row is the same 2,048-in-one-bucket catastrophe, from keys derived from the multiplier by modular inversion. Universality is a statement about a random choice, and once the choice is known there is nothing random left.

2,048 keys in 256 buckets — multiply–shift, a chosen at randomEach bar is one bucket's load, with keys computed from a different member of the family. The average load is 8.0 and the worst bucket here holds 9. The multiplier was drawn at random from the family, so an adversary who does not know it cannot compute a colliding set. The collision rate over all pairs is 3.45e-3, against 3.91e-3 for a perfectly uniform map.average 8.001224bucket, 0 to 255keys in the bucketmultiply–shift · keys built for another memberworst bucket 9 against 8.0
Fig. 2 The third row of the table, drawn. Keys computed to collide under a different member of the family, hashed by this one. The loads are ordinary — worst bucket well within what a uniform map gives — because the keys’ relationship is to a multiplier this function does not use. An adversary who knows the family but not the member has gained nothing.
2,048 keys in 256 buckets — multiply–shift, a chosen at randomEach bar is one bucket's load, with keys computed from this hash function. The average load is 8.0 and the worst bucket here holds 2,048. The multiplier was drawn at random from the family, so an adversary who does not know it cannot compute a colliding set. The collision rate over all pairs is 1.00e+0, against 3.91e-3 for a perfectly uniform map.average 8.001,0242,048bucket, 0 to 255keys in the bucketmultiply–shift · keys built for this hashworst bucket 2,048 against 8.0
Fig. 3 And the last row. The same family, the same table size, keys computed from the multiplier actually in use. Every key in bucket zero. The picture is identical to the low-bits one at the top of the essay, which is the point: a family whose member is known is a fixed function, and a fixed function has a bad input that can be written down.

The two plates above are what the attack looks like. The one below is what everything else looks like, and the pair is the reason the defect survives review: a hash is chosen by measuring it on input somebody had lying around, and on that input the broken function and the sound one are the same function.

2,048 keys in 256 buckets — multiply–shift, a chosen at randomEach bar is one bucket's load, with keys with nothing special about them. The average load is 8.0 and the worst bucket here holds 16. The multiplier was drawn at random from the family, so an adversary who does not know it cannot compute a colliding set. The collision rate over all pairs is 3.84e-3, against 3.91e-3 for a perfectly uniform map.average 8.001224bucket, 0 to 255keys in the bucketmultiply–shift · ordinary keysworst bucket 16 against 8.0
Fig. 4 The first and third rows differ by nothing a benchmark would notice. This is the multiply-shift member on keys with no structure: worst bucket 16, no empty buckets, 8,059 colliding pairs against a uniform expectation of 8,190. Put the low-bits hash on the same keys and it measures 17 and 8,334. The two functions are indistinguishable on ordinary input and one of them has a colliding set that fits in a tweet.

The obvious response is to reach for a stronger family, and it is worth measuring because it does not work. Multiply–add–shift draws two parameters rather than one and is universal where multiply–shift is only almost so — a strictly better guarantee, bought for one addition.

2,048 keys in 256 buckets — multiply–add–shift, a and b at randomEach bar is one bucket's load, with keys computed from this hash function. The average load is 8.0 and the worst bucket here holds 2,048. The multiplier was drawn at random from the family, so an adversary who does not know it cannot compute a colliding set. The collision rate over all pairs is 1.00e+0, against 3.91e-3 for a perfectly uniform map.average 8.001,0242,048bucket, 0 to 255keys in the bucketmultiply–add–shift · keys built for this hashworst bucket 2,048 against 8.0
Fig. 5 The stronger family under the same attack: every one of the 2,048 keys in one bucket, and a collision rate of 1.00 against a uniform 3.91 × 10⁻³. Two random parameters instead of one changes nothing at all once the parameters are known, because what the guarantee bounds is the expectation over the draw, and there is no draw left once an adversary has read the values out of the process.

That is the whole content of the word family. The strength of the guarantee is a statement about an average over members, and an average over one member is that member.

What it costs

Universality is unusual among the repairs in this phase in costing almost nothing, which is worth quantifying rather than waving at.

Time. Multiply-shift is one multiplication and one shift. The low-bits hash is one bitwise AND. On any processor built in the last thirty years the multiply is three to five cycles and pipelines, and the difference is invisible next to the cache miss that follows it. Multiply-add-shift adds one addition.

Space. One word per table for the multiplier, or two for multiply-add-shift.

Randomness. Thirty-two bits at table creation, once, and never again. Measured against the other consumers in this phase, that is nothing: a skip list spends two bits per key, so a hash table of a thousand keys spends 32 bits where a skip list of the same size spends 2,000.

The guarantee given up. None, relative to a fixed hash — the fixed hash never had a guarantee, it had an assumption about the keys.

So the comparison against the other randomisations here is stark. A treap pays 32 bits per node and a real space cost to get its guarantee; randomised selection pays a factor of variance; a Bloom filter pays 44% over the floor. Universal hashing pays one multiply and one word. It is the cheapest instance of the pattern in this phase, and it is the one most often left out of real code.

What the maximum load actually does

Universality bounds pairs, and the quantity a program feels is the longest chain. Those are related loosely enough to be worth measuring separately.

For nn keys into nn buckets under a fully random map, the expected maximum load is Θ(logn/loglogn)\Theta(\log n / \log\log n) — a very slowly growing function that is easy to mistake for a constant. Measured, with a multiply-shift member on ordinary keys:

keys = buckets worst bucket lnn/lnlnn\ln n / \ln\ln n empty
256 4 3.24 37.1%
1,024 5 3.58 35.2%
4,096 6 3.93 36.7%

The worst bucket grows by one each time the table quadruples, which is the shape the formula predicts, and it stays small enough over any practical range that treating it as a constant is defensible — provided the constant is understood to be about six rather than about one.

The empty column is the other half of the same picture and it surprises people: about 37% of buckets are empty when a table has as many keys as buckets. That is e1e^{-1}, and it is the reason a hash table at load factor 1 is not “full” in any useful sense. Both numbers come from the same Poisson approximation and both are properties of randomness rather than of the hash.

The three families, and what separates them

The site’s library carries three maps from key to bucket, and the differences between them are small in code and large in what they guarantee.

lowBitsx & (b - 1). Not a family at all: there is exactly one function in it, so there is nothing to choose at random and nothing an adversary has to learn. It is here as the control, and it is the one people write when the table size happens to be a power of two and masking looks like the obvious thing.

multiplyShift(axmod232)(32)(a x \bmod 2^{32}) \gg (32-\ell) for random odd aa. Dietzfelbinger’s family. Two instructions, 2-approximately universal, and the one a fast hash table actually uses. Its weakness is structural rather than statistical: because the map is linear in xx, the difference h(x)h(y)h(x) - h(y) depends only on xyx - y, so keys in arithmetic progression land in buckets in arithmetic progression. That is invisible in a collision count and is exactly what made the Bloom filter measurements go wrong on consecutive keys.

multiplyAddShift((ax+b)mod232)(32)((a x + b) \bmod 2^{32}) \gg (32-\ell) for random odd aa and random bb. One extra addition buys strong universality: the pair (h(x),h(y))(h(x), h(y)) is close to uniform over all pairs of buckets, not merely unlikely to be equal. Analyses that need pairwise independence — most load-balancing arguments, and the Bloom filter’s assumption that its kk probes behave independently — want this one.

The progression is worth reading as a general shape. Each step costs one instruction and buys one more property, and the property bought is always about higher-order structure in the input rather than about the average case. None of the three differs measurably on keys with no structure, which is why the choice between them cannot be made by benchmarking.

What to do about it

The practical guidance is short and it is mostly about when.

Choose the member at run time, not at compile time. A family whose multiplier is a named constant in the source is a fixed function. This is the single most common way the repair is applied and undone in the same breath, and it is what the next essay is about.

Choose it per table, not per program. One multiplier used by every hash table in a process means one colliding set breaks all of them. Per-table selection costs one word.

Use a family with the properties the analysis needs, not just any randomisation. Multiply-shift is universal and gives collision bounds. It is not strongly universal — the pairs (h(x),h(y))(h(x), h(y)) are not uniform over all pairs of buckets — and analyses that need pairwise independence, such as some load-balancing arguments, want multiply-add-shift or tabulation hashing instead. The difference costs one addition.

Do not confuse a good avalanche with a family. A hash with excellent mixing — one where flipping one input bit changes half the output bits — is still one function, and still has its U/bU/b colliding keys. Avalanche makes them harder to find by hand and does nothing about someone who inverts the function or searches for collisions offline. The two properties are orthogonal, and “the hash has good avalanche” is not an answer to “what happens when the keys are chosen against it”.

And know that none of this is a cryptographic guarantee. An adversary who can observe timing can learn about the multiplier without being told it: a slow response reveals a collision, and enough collisions constrain aa. Universality defends against an adversary who chooses keys in advance, not against one who probes adaptively and watches the clock. If that is the threat, the answer is a keyed cryptographic hash — SipHash exists for exactly this — and it costs several times more per key.

Probes per insertion against load factor, table of 8,192The line is Knuth's closed form for linear probing, integrated over the fill; the points are a table actually filled and counted. They agree to within 2.3% everywhere. At a load factor of 0.5 an insertion averages 1.49 probes; at 0.9 it averages 5.39. The formula that matters for insertion is the unsuccessful-search one, ½(1 + 1/(1−α)²), and using the successful-search form instead is an error that hides at low load and is glaring at high load.1234560.000.250.500.75formulameasuredload factor αprobes per insertion8,192 slots, mean of 8 fills, seeds stated in lib/structures.jstwo routes agree to 2.3%
Fig. 6 And the reason all of this matters to a hash table’s cost rather than only to its worst bucket. The expected probe count under linear probing has a closed form in the load factor and the measurement tracks it to within 5% up to 90% full — provided the keys spread. Every point on this curve assumes what this essay’s first figure destroys, and when the assumption fails the curve is not slightly wrong, it is describing a different structure.
4,096 accesses, five ordersEvery row performs exactly 4,096 array accesses — the same count an operation-counting analysis would assign them all — and the modelled miss counts differ by a factor of 8. Reading backwards is as cheap as reading forwards, because a cache line is a line whichever end you enter it from. Stepping by 8 elements touches a new line every time and is as expensive as random. Model: fully associative · 32 lines × 8 elements · LRU.cache missesstraight through512100% sequentialbackwards5120% sequentialevery 8th element4,0960% sequentialevery 97th element4,0960% sequentialuniformly random3,8460% sequentialfully associative · 32 lines × 8 elements · LRU8× between best and worst order
Fig. 7 The second reason bucket loads matter, which the collision count does not show. Five access orders performing exactly 4,096 array accesses each, with modelled miss counts differing by a factor of 8. A hash table with a long chain is not merely doing more comparisons; it is chasing pointers through memory the allocator scattered, and the two counts diverge in the direction that makes the failure worse than the pair count suggests.

A fourth family, and why it is the modern answer

The three families above are a progression in instructions bought and properties gained, and there is a fourth that leaves the progression rather than extending it.

Tabulation hashing. Split the key into cc bytes. Keep cc tables of 256 random 32-bit words, filled at construction. The hash is the exclusive-or of the cc table entries indexed by the key’s bytes — four lookups and three exclusive-ors for a 32-bit key, and no multiplication anywhere.

It is 3-independent, which is one degree more than multiply-add-shift, and its real advantage is not the degree. Properties are provable about it that are not provable about the multiplicative families: bounds on the maximum bucket load, on the behaviour of linear probing, and on Bloom-filter false-positive rates all hold for tabulation hashing and are open or false for multiply-shift. The reason is structural — the multiplicative families are linear in the key, so arithmetic progressions in the input become arithmetic progressions in the output, which is the weakness the third family’s description names and which no amount of extra degree removes.

The costs are a kilobyte of tables per hash and a memory access per byte of key rather than a register operation. On a modern processor the tables are in cache after the first few keys and the whole thing is competitive with a multiply; on a memory-constrained device a kilobyte is not free.

Naming it here rather than measuring it is deliberate: it is a different construction, its advantages are theorems rather than measurements, and quoting somebody else’s numbers beside the ones on this page would be mixing two kinds of statement. What can be said from the sections above is that the choice between families cannot be made by benchmarking on ordinary keys — all four are indistinguishable there — so it has to be made from what is provable, and tabulation is where the provable statements are.

What the load factor is chosen against

The two numbers at the end of the maximum-load section — a worst bucket of about six and 37% of buckets empty at a load factor of one — invite a question the essay has not answered: why do real tables resize at 0.75 rather than at 1?

Not because of the maximum load. Under chaining the longest chain grows like logn/loglogn\log n / \log\log n whatever the load factor is, so 0.75 buys almost nothing there.

It is chosen against the probe formula, and that formula is about open addressing rather than chaining. The expected probes for an unsuccessful linear-probing search is about 12(1+1/(1α)2)\tfrac12\bigl(1 + 1/(1-\alpha)^2\bigr), which is 8.5 at α=0.75\alpha = 0.75, 50.5 at α=0.9\alpha = 0.9 and unbounded as α1\alpha \to 1. Three quarters is where that curve is still gentle and just before it turns vertical, and it is the number every implementation inherited.

So a chained hash table resizing at 0.75 is using a threshold derived for a structure it is not, which is a harmless inheritance and an instructive one. The number is right for the wrong reason, nobody re-derives it, and a chained table could comfortably run at a load factor of two — its chains would average two and its longest would still be about six.

That also explains a detail of the essay’s own measurements. Every table here is at a load factor of eight, which no open-addressed table could survive and which a chained one handles without comment, and the reason the plates look unremarkable is that the quantity being stressed is not the one 0.75 was chosen to protect.

The pattern, one level up

This is the third instance in this phase of one shape, and it is worth stating in the general form because it is a design technique rather than three facts.

An algorithm makes a choice — a pivot, a root, a bucket — and if the input can predict the choice, the input can construct the worst case. Randomising the choice does not make the worst case impossible; it makes it independent of the input, and it moves the guarantee from “true of most data” to “true of all data, most of the time”.

The hashing instance is the cleanest of the three because the adversary’s work is a closed form rather than an argument. Given the function, the colliding keys are a1ta^{-1}t for t=1,2,3,t = 1, 2, 3, \ldots — no search, no heuristic, five multiplications to get the inverse and one per key after that. That is what “the input can predict the choice” looks like when it is written down completely, and it is why the defence has to be that the choice is genuinely unknown rather than merely complicated.

What this makes readable

Essays that name this one as a prerequisite.

Named alongside this one

Essays reaching for the same objects. Nobody chose these; they are what the concept index makes visible.

What links here

The 8 essays that link to this one and share the most of its objects, of 15 that link here.

The objects this essay names

Each one links to every other essay that touches it.

Adversarial inputBloom filterBucket loadClosed formGuaranteeHash familyHash functionHash tableLoad factorMultiply shiftUniversal hashing