Series · The Practice
Provably Fair Digital Divination: How Commit–Reveal Cryptography Keeps an Oracle Honest
When you throw three physical coins, the fairness of the cast is self-evident: the coins left your hand, gravity did the rest, and no one — including you — chose the outcome. A digital oracle has a harder problem. However honest its random number generator actually is, you cannot see it. An app could, in principle, serve you gentler hexagrams when you seem anxious, or dramatic ones to keep you engaged, and the result would look exactly like chance.
For most software this would be a quality question. For a contemplative instrument it is foundational. A reading is only worth reflecting on if the symbol genuinely fell to you — if it was not selected for you by anyone's model of what you should hear. This is why the Six Doors instrument does not ask to be trusted. It uses a commit–reveal protocol, borrowed from cryptography, that makes manipulation detectable after every single cast.
The core idea: promise first, act second
A commit–reveal scheme has the structure of a sealed envelope. Before anything happens, one party writes down their contribution, seals it, and hands over the sealed envelope. Only after the other party has acted is the envelope opened. The seal proves the contents were fixed in advance; the delay proves they could not have been chosen in response to what the other party did.
The cryptographic seal is a hash function — here, SHA-256. A hash function turns any input into a fixed-length fingerprint with two properties that matter for us. First, it is one-way: seeing the fingerprint tells you essentially nothing about the input. Second, it is collision-resistant in practice: nobody can produce a second input matching the same fingerprint. Publishing the hash of a secret therefore commits you to that exact secret while revealing nothing about it.
The protocol, step by step
Here is what happens when you cast at Six Doors, in order:
1. The server commits
Before your ritual begins, the server generates a random value called the server seed and sends you its SHA-256 hash — the commit hash. The seed itself stays secret. At this moment the server has locked in its entire contribution to your cast: any later change to the seed would change the hash, and you are holding the hash.
2. You contribute entropy
As you tap to throw each set of coins, the precise timing of your interactions — measured at millisecond resolution, combined with device entropy — is gathered into a client seed. This step matters for two distinct reasons. Ritually, it keeps the cast yours: your hands, your moment, your unrepeatable timing shape the outcome, just as they would with physical coins. Cryptographically, it closes the remaining loophole — because the server cannot predict your timing, it could not have chosen a seed in advance that steers your result, even across many attempts.
3. The result is derived deterministically
The coin values are computed as an HMAC — a keyed hash — of the server seed together with your client seed and the unique cast identifier:
result = HMAC-SHA256(server_seed, client_seed + cast_id)
The output bytes are mapped, by a fixed public rule, onto the eighteen coin faces of a full cast: six throws of three coins, each throw summing to 6, 7, 8, or 9, exactly as in the physical three-coin method. Nothing in this step involves choice. Given the two seeds and the cast ID, the hexagram is fully determined — and neither party alone controlled both seeds.
4. The server reveals
Once your lines are cast, the server discloses the server seed. Now you hold everything: the commit hash from before the cast, the revealed seed, your client seed, and the result.
Verifying a cast yourself
Verification asks two questions, both mechanically checkable:
Did the server keep its promise? Hash the revealed server seed and compare it to the commit hash you were given before casting. If they match, the seed was fixed before you ever touched the screen.
Does the result follow from the seeds? Recompute the HMAC from the revealed server seed, your client seed, and the cast ID, apply the public mapping, and compare with the lines you received.
A verification, written as plain arithmetic-by-hash, looks like this:
given:
commit_hash = 9f2c41...a8 (received before cast)
server_seed = 71e0bd...3c (revealed after cast)
client_seed = 448a19...e5 (from your interaction)
cast_id = c_0192xyz
check 1: SHA256(server_seed) -> 9f2c41...a8 matches
check 2: HMAC-SHA256(server_seed,
client_seed + cast_id) -> mapped lines: 7 8 9 8 8 7
reported lines : 7 8 9 8 8 7 matches
Every cast stores this triple permanently, and the platform's verification page recomputes both checks for you — but the point is that you do not need our page. Any SHA-256 implementation, in any language, on any machine, reaches the same answer. The about page links the full byte-level mapping specification.
Why this matters for digital ritual
There is a quiet philosophical point underneath the engineering. Divination traditions have always been careful about the integrity of the aleatory moment — the yarrow stalks counted in silence, coins cast in view. The randomness is the ritual's guarantee that the symbol arrived from outside your intentions, which is precisely what makes it useful as a mirror: it shows you something you did not choose to see. For the fuller picture of how a cast becomes a reflection — primary hexagram, changing lines, derived hexagram — see our guide to changing lines.
A digital oracle that could be steered, even benevolently, would break that guarantee in the worst way: invisibly. Commit–reveal restores the visible dice. It also, notably, protects the platform from itself — no future product pressure can quietly make readings "more engaging," because every cast is an auditable record and any deviation would surface as a hash mismatch.
None of this makes the oracle wise, and it is not meant to. Cryptography cannot make a hexagram true; no such thing was on offer anyway. What it can do is make the cast clean — provably untouched between your question and your answer — so that whatever you find in the reading, you found by reflecting, not by being managed.
Cast one, then check it
The best way to understand a commit–reveal cast is to run one and then audit it. Ask a real question at the Six Doors casting page, note the commit hash before you throw, and after your reading open the verification panel and watch both checks pass. It takes a minute, and it changes the texture of every digital cast afterward: not trust, but something better — the absence of any need for it.