SHA-256, HMAC-DRBG, and Fisher-Yates: The Cryptography Behind a Tarot Shuffle
What does a tarot app have in common with Bitcoin, TLS, and nuclear launch codes? More than you might expect. The cryptographic primitives that secure trillions of dollars in financial transactions, protect classified military communications, and validate every block on the Bitcoin blockchain are the same ones that shuffle your tarot deck in Entropic Tarot. This is not marketing language. It is a literal description of the software pipeline.
Most tarot apps call Math.random(), pick some cards, and call it a day. Entropic Tarot runs your shuffle through a four-stage cryptographic pipeline that would satisfy a security auditor at a tier-one bank. Here is exactly how it works, stage by stage, and why each step matters.
Stage 1: Harvesting Raw Entropy
Every cryptographic system begins with a source of unpredictability. In Entropic Tarot, that source is you -- or more precisely, the physical world around you as measured by your device's sensors.
The app collects raw data from three independent sources: electromagnetic noise from your microphone circuit, thermal noise from your camera sensor, and microsecond-precision timing jitter from your touch interactions. Each source captures a different flavor of physical unpredictability. Combined, they produce a rich stream of raw entropy -- genuinely random data rooted in quantum-level physical processes that no algorithm can predict or reproduce.
But raw entropy is messy. Microphone samples might cluster around certain voltage levels. Camera pixels might have consistent biases. Touch timing might carry patterns from human motor rhythms. The raw data is unpredictable, but it is not uniform. To turn it into something cryptographically useful, we need Stage 2.
Stage 2: SHA-256 -- Compressing Chaos into Perfect Randomness
A cryptographic hash function is a mathematical operation that takes an input of any size and produces a fixed-size output. Think of it as a one-way compressor: you can feed in a single byte or an entire novel, and you always get back exactly 256 bits. But unlike ordinary compression, a hash function is designed to be irreversible. Given the output, there is no way -- not even in principle -- to reconstruct the input.
SHA-256 (Secure Hash Algorithm, 256-bit) is the specific hash function used in Entropic Tarot. It was designed by the National Security Agency and published by NIST in 2001. It secures every Bitcoin transaction ever made, authenticates every HTTPS connection your browser opens, and anchors the digital signature on your passport. After twenty-five years of sustained cryptanalytic attack by the best mathematicians on Earth, no one has found a collision -- two different inputs that produce the same output.
SHA-256 has a property called the avalanche effect: change a single bit of the input and, on average, half the bits of the output flip. The result is that even highly structured, biased input produces output that is statistically indistinguishable from perfect randomness.
Conceptual flow:
Raw entropy input (variable length, potentially biased):
microphone_noise + camera_noise + touch_timing
[3,847 bytes of raw sensor data]
|
v
SHA-256()
|
v
Output (fixed 256 bits, uniformly distributed):
a7 3f 91 0b e4 22 d8 ... [32 bytes, every bit equally likely to be 0 or 1]
This is the crucial transformation. No matter how biased or structured the raw sensor data might be, SHA-256 whitens it into a seed that is, for all practical and theoretical purposes, perfectly random. The same function that ensures no one can counterfeit a Bitcoin ensures that no one can predict your tarot shuffle.
SHA-256 is a one-way function: given the output, reconstructing the input would require more energy than exists in the observable universe. Your shuffle seed is irreversible by the laws of thermodynamics.
Stage 3: HMAC-DRBG -- Stretching a Seed into a Stream
We now have a 256-bit seed of excellent quality. But a tarot shuffle needs more than one random number. To shuffle a 78-card deck using the Fisher-Yates algorithm, we need 77 independent random values -- one for each swap operation. We could hash the entropy 77 separate times, but that would require 77 independent pools of raw sensor data, which is impractical. Instead, we need a way to deterministically expand a single high-quality seed into a long sequence of random numbers without introducing patterns.
This is precisely the problem that a Deterministic Random Bit Generator (DRBG) solves. Entropic Tarot uses HMAC-DRBG, specified in NIST Special Publication 800-90A -- the same standard mandated for cryptographic applications in U.S. federal systems, banking infrastructure, and hardware security modules.
The word "deterministic" might sound alarming in this context, but it is actually the point. Given the same seed, an HMAC-DRBG will always produce the same sequence of outputs. This is a feature, not a bug -- it means the shuffle is reproducible from the seed, which makes it auditable. The unpredictability comes entirely from the seed, which is rooted in physical entropy. The DRBG's job is to stretch that unpredictability without degrading it.
How HMAC-DRBG works
HMAC-DRBG maintains an internal state consisting of two values: a key (K) and a value (V), both 256 bits. The lifecycle has three phases:
- Instantiate -- The seed material (our SHA-256 output) initializes
KandVthrough a series of HMAC operations. HMAC (Hash-based Message Authentication Code) is itself built on SHA-256, adding another layer of cryptographic mixing. - Generate -- Each time we need random bytes, the DRBG computes
V = HMAC(K, V), outputsV, then updates bothKandVto advance the internal state. Each output is cryptographically independent of the previous one -- knowing any number of prior outputs gives an attacker zero information about the next. - Reseed -- If additional entropy becomes available (more sensor data), it can be mixed into the state, further strengthening the generator. This is optional but adds defense in depth.
The security guarantee is strong: an attacker who observes any number of HMAC-DRBG outputs cannot predict the next output without knowing the internal state, and recovering the internal state from outputs alone is computationally infeasible. This is the same guarantee that protects the session keys in your online banking connection.
HMAC-DRBG is not an approximation of randomness. It is a NIST-certified method for expanding a truly random seed into an arbitrarily long sequence that no known or theoretical attack can distinguish from true randomness.
Stage 4: Fisher-Yates -- The Only Correct Shuffle
We now have a cryptographic random number generator producing high-quality random values on demand. The final step is to use those values to actually arrange the 78 tarot cards into a random order. This is where the Fisher-Yates shuffle (also known as the Knuth shuffle) comes in -- and the choice of algorithm here is not arbitrary. Fisher-Yates is the only shuffle algorithm that is mathematically guaranteed to produce a uniform distribution over all possible permutations.
The algorithm
Fisher-Yates works by iterating through the deck from the last card to the second, and at each position, swapping that card with a randomly chosen card from the remaining unshuffled portion (including itself):
fisher_yates_shuffle(deck):
n = length(deck)
for i from (n - 1) down to 1:
j = random_integer(0, i) // inclusive on both ends
swap(deck[i], deck[j])
return deck
Walk through it with a small example. Suppose you have five cards: [A, B, C, D, E].
- i = 4: Pick random j from 0..4. Say j = 2. Swap positions 4 and 2. Deck:
[A, B, E, D, C] - i = 3: Pick random j from 0..3. Say j = 0. Swap positions 3 and 0. Deck:
[D, B, E, A, C] - i = 2: Pick random j from 0..2. Say j = 2. Swap positions 2 and 2 (no change). Deck:
[D, B, E, A, C] - i = 1: Pick random j from 0..1. Say j = 0. Swap positions 1 and 0. Deck:
[B, D, E, A, C]
Each card ends up in each position with exactly equal probability. This is provable: the algorithm makes exactly n - 1 swaps, and the number of possible execution paths is n * (n-1) * (n-2) * ... * 1 = n!, which is exactly the number of possible permutations. Every permutation corresponds to exactly one path through the algorithm.
Why naive shuffles fail
A common alternative that seems correct -- sorting the array with a random comparator -- actually produces biased results. When you tell a sorting algorithm to compare two elements and randomly return "less than" or "greater than," the final ordering depends on the sort algorithm's internal decisions, which do not map uniformly onto permutations. Some orderings become significantly more likely than others. For a 78-card deck, certain arrangements might be two or three times more probable than others. The bias is invisible to casual observation but mathematically demonstrable.
Fisher-Yates has no such bias. It is optimal in time complexity (O(n)), optimal in space complexity (O(1) additional space), and mathematically perfect in distribution. There is no reason to use anything else, and Entropic Tarot does not.
Rejection Sampling: Eliminating Modulo Bias
There is one more subtlety that most implementations get wrong, and Entropic Tarot gets right: modulo bias.
When the Fisher-Yates algorithm needs a random integer between 0 and i (inclusive), it must convert raw random bytes into a number in that range. The naive approach is to take a random byte (value 0-255) and compute byte % (i + 1). But this introduces a subtle bias whenever 256 is not evenly divisible by (i + 1).
Consider needing a random number from 0 to 77 (for the first swap of a 78-card deck). There are 256 possible byte values, and 256 / 78 = 3 remainder 22. This means values 0-21 each map to from four byte values, while values 22-77 each map from only three. The first 22 positions are approximately 33% more likely than the remaining 56. Over a single shuffle this is slight, but across thousands of readings, it is a measurable, systematic bias.
Rejection sampling eliminates this entirely. Instead of accepting every random byte, the algorithm computes the largest multiple of 78 that fits within 256 (which is 234), and discards any byte value of 234 or higher. Only values in the range 0-233 are accepted, and since 234 divides evenly into 78 groups of 3, every outcome is exactly equally likely. Discarded values are simply replaced by drawing another random byte from the HMAC-DRBG.
unbiased_random(max, drbg):
range = max + 1
limit = 256 - (256 % range) // largest usable value
loop:
byte = drbg.generate(1) // one random byte
if byte < limit:
return byte % range
// else: discard and try again
The expected number of rejections is small (always less than one extra draw on average), so performance is not affected. But the mathematical guarantee is absolute: every value in the target range is exactly equally probable.
The Result: 78 Factorial
Put it all together. Physical entropy feeds into SHA-256, which produces a perfectly uniform seed. That seed initializes an HMAC-DRBG, which generates a cryptographic stream of random values. Those values drive a Fisher-Yates shuffle with rejection sampling to eliminate modulo bias.
The outcome space is 78! (78 factorial) -- the total number of possible orderings of a 78-card tarot deck. That number is:
78! = 1.89 x 10^115 -- a number with 116 digits. For comparison, the estimated number of atoms in the observable universe is approximately 10^80. The number of possible deck orderings exceeds the number of atoms by a factor of ten trillion trillion trillion.
Every single one of those orderings is equally probable. Not approximately equal. Not "close enough for practical purposes." Exactly equal, to the limits of the cryptographic guarantees provided by SHA-256 and HMAC-DRBG -- guarantees that the entire global financial system depends on daily.
Verification: Trust, but Audit
One of the most important properties of this pipeline is that it is reproducible. Because every stage after the initial entropy harvest is deterministic, anyone who knows the seed can independently verify the shuffle. Given the same 256-bit seed, running it through the same HMAC-DRBG and Fisher-Yates implementation will always produce the same deck ordering.
This means the shuffle is auditable. The code is open-source. The algorithms are public standards with decades of peer-reviewed analysis. There is no hidden server-side manipulation, no weighting of certain cards, no thumb on the scale. The shuffle is exactly what the math says it is, and anyone with the technical inclination can prove it.
This is a property that no physical card shuffle can offer. When you shuffle a physical deck, you trust the process because you can see and feel it. When Entropic Tarot shuffles digitally, you can trust the process because you can mathematically verify it.
A physical shuffle is trusted because it is tangible. A cryptographic shuffle is trusted because it is provable. Entropic Tarot offers both: physical entropy as the source, mathematical proof as the guarantee.
The Honest Shuffle
There are simpler ways to build a tarot app. You could call Math.random(), shuffle an array, and ship it in an afternoon. Most apps do exactly that, and for many users, it is sufficient.
But Entropic Tarot was built on the premise that if you are going to shuffle cards digitally, you should do it correctly -- with the same rigor applied to systems where the stakes are measured in billions of dollars and national security. Not because a tarot reading has those stakes, but because the mathematics of fairness does not have a "good enough" threshold. A shuffle is either uniform or it is not. A random number generator is either cryptographically secure or it is not.
SHA-256. HMAC-DRBG. Fisher-Yates. Rejection sampling. Four components, each backed by decades of mathematical proof and real-world deployment at the highest levels of security. Together, they produce the most mathematically honest card shuffle ever implemented in a consumer application.
Your cards are not chosen by an algorithm pretending to be random. They are chosen by the physical universe, filtered through cryptography that guards the world's secrets, arranged by the only shuffle algorithm that mathematics certifies as perfect.