Methodology
Don't trust it. Verify it.
Every claim on this site (the shuffle model, the archive, the zero matches) is meant to be checked, not taken on faith. This page explains exactly how a shuffle gets produced, how it gets recorded, what a “no match” result actually means, and how to confirm any of it yourself.
How a shuffle is produced
Each shuffle is a simulated riffle, run in software using the Gilbert–Shannon–Reeds model, the standard mathematical description of how a human hand actually cuts and interleaves a deck. One pass works like this:
- Cut. The deck splits into two packets. The split size follows a Binomial(52, ½) distribution, computed as the count of heads across 52 fair coin flips, so most cuts land near 26/26, but a cut at 21/31 or 33/19 is entirely normal, exactly as it would be in a real hand.
- Interleave. Cards drop one at a time from whichever packet still has more cards left in it, weighted by how many remain in each. Clumps of two or three cards falling together aren't hardcoded: they emerge naturally from that weighting, the same way they do at a card table.
- Post-cut. 75% of passes end with one more cut, at a uniform position between card 5 and card 47.
One archived shuffle is 7 to 13 of these passes chained together, starting from a freshly sorted deck each time. Only the final deck is recorded.
Every random decision (the coin flips for the cut, the weighted draw at each interleave step, whether to cut again) comes from a cryptographically secure random number generator (the platform's Web Crypto API), never from a language's default pseudo-random generator. That matters: a predictable RNG would undermine the one thing this whole project is trying to prove.
What gets archived
A deck order is stored as 52 bytes: one per card, where a card's value is suit × 13 + rank (hearts = 0, diamonds = 1, clubs = 2, spades = 3; ace = 0 … king = 12). That's the entire encoding rule: no ambiguity, no metadata required to reconstruct the order.
Alongside the deck, the archive stores a 64-bit hash: the first 8 bytes of the SHA-256 digest of those 52 bytes. That hash sits behind a database-level uniqueness constraint, which is what actually performs the match check: inserting a shuffle whose hash already exists is what a match (or a hash collision) looks like at the storage layer. Any conflict there triggers an exact byte-for-byte comparison against every deck sharing that hash before anything is called a match; a 64-bit hash space is large enough that two different decks colliding by chance is itself a roughly 1-in-18.4-quintillion event per pair (1 in 2⁶⁴), and it's checked for explicitly rather than assumed away.
The archive is split into two eras. Era 1 is 12,300,339 shuffles produced by the original engine, recorded April 27, 2025 through September 14, 2025. Era 2 is everything recorded after that, under the same rules: the same 52-byte encoding and the same hash scheme, so era doesn't change how a shuffle is checked or verified. The only difference is where the full deck order physically lives.
Why a fresh deck every time, not one long shuffle
A reasonable worry: if every shuffle starts from a freshly sorted deck instead of continuing to shuffle the previous result, doesn't that risk the underlying random number generator eventually repeating a sequence of decisions, and producing the same deck twice?
No. And the reason is worth spelling out, because it's the crux of why this whole approach is sound. A match doesn't require the RNG's sequence of decisions to repeat. It only requires the final deck order to repeat. There are vastly more possible sequences of random draws through a 7-to-13-pass shuffle than there are possible decks, so enormously many different random paths lead to the exact same destination deck. Whether two shuffles ever collide depends entirely on how close the shuffling process is to producing a uniformly random deck order (the thing Bayer and Diaconis's work quantifies), not on whether the random number generator's internal state ever repeats itself.
Given that, fresh-start shuffling was chosen deliberately: each shuffle is an independent sample rather than a continuation, the archiving process stays stateless (useful for a website where anyone can trigger a shuffle at any time), and it matches what “a shuffle” means at a real card table: you don't inherit the previous player's deck order as your starting point.
The 2026 all-pairs audit
The original engine only ever compared each new shuffle to the one immediately before it. That means, across the roughly 142 days it ran, it never actually checked whether shuffle #40,000 matched shuffle #9,000,000. It simply never asked the question. If two shuffles anywhere in that history had matched, v1 would not have noticed.
In 2026, migrating that history into the v2 archive gave the chance to ask the question properly: every one of the 12,300,339 recorded decks was hashed and checked against every other deck in the set, the first time in the project's history that a genuine all-pairs comparison was run.
The result: all 12,300,339 rows parsed cleanly (zero parse errors: every recorded shuffle was a valid 52-card permutation), and sorting and scanning the full set of 64-bit hashes turned up zero duplicate hash groups. That means zero 64-bit hash collisions and, therefore, zero true matches, across 11 deck sessions spanning April 27, 2025 to September 14, 2025.
The honest history
The original engine ran on a single DigitalOcean droplet, shuffling continuously from April 27, 2025 to September 14, 2025. It stored each shuffle as roughly 1 KB of text plus indexes: full card-by-card order, written out as strings. That works fine at small scale, but it doesn't stay cheap: by the time the project stopped, the table had grown to about 13 GB, and the storage bill kept climbing with no end in sight. The engine was shut down, not because the idea failed, but because the storage model did.
The fix in this version is the 52-byte-plus-hash encoding described above, roughly 50 times more compact than the original text format, and cheap enough that the archive can keep growing indefinitely without repeating v1's mistake. The v1 engine itself is not currently running; the numbers on this site describe its completed, closed history.
How to verify it yourself
Nothing here depends on taking the archive's word for it. The rules are simple enough to re-implement from scratch:
- Encode a deck as 52 bytes using
suit × 13 + rank(hearts 0, diamonds 1, clubs 2, spades 3; ace 0 through king 12). - Hash those 52 bytes with SHA-256 and keep the first 8 bytes, big-endian.
- Era-1 deck orders are packed into batches of 100,000, gzip-compressed, each batch accompanied by a manifest listing its archive-number range and a SHA-256 checksum for both the compressed and raw bytes. Download a batch, verify its checksum, decode it, and recompute the hashes yourself.
- In the rare case two decks legitimately share a base hash, the second is stored under a disambiguated hash (SHA-256 of the deck bytes concatenated with the conflicting archive number, as an 8-byte big-endian integer), so the unique index never has to silently drop a real finding. Any row stored this way is exactly the kind of event this whole project exists to catch, and would be documented as such, not hidden.
For the underlying probability, see 52 factorial and seven shuffles, or start from the math hub.