There is a global lottery that publishes an unriggable random number every three seconds. This is how you turn that into a price chart that behaves like a market — and why one stubborn rule about rounding turns out to be holding the whole idea up.
If you have ever traded a synthetic index — the ones brokers offer that go up and down like a stock but are not attached to anything — you have trusted somebody. The broker generates the price. The broker sets the odds. The broker takes the other side of your bet. You cannot check any of it, and the three roles sit in the same building.
That is not necessarily fraud. It is just unverifiable, which in practice is the same thing from where you are sitting.
Croom separates those roles completely, and the way it does it is the interesting part.
There is a thing called drand, run by a group of independent organisations — universities, companies, research labs — who between them publish a random number every three seconds. No single member can control the output. They have been doing it continuously for years, and every number they have ever published is still retrievable by anyone, for free, forever.
It is unpredictable before it is published and permanent afterwards. Those two properties are the entire foundation.
A Croom price is unguessable before the draw and reproducible by anyone after it. That is the resolution to what sounds like a contradiction: how can something be both unpredictable and verifiable?
A Room is a recipe. It takes the lottery numbers and turns them into a price path. The recipe is fixed when the Room is created and can never change — not by its creator, not by us, not by anyone — because the Room's name is a fingerprint of its recipe. Change a single parameter and you have made a different Room, not edited an existing one.
So the question becomes: what is a good recipe? And that is where it stops being a blockchain problem and starts being an arithmetic one.
Open a browser console and type 0.1 + 0.2. You will get
0.30000000000000004.
That is not a bug. One tenth has no exact representation in binary, in the same way one third has no exact representation in decimal. The error is tiny. It is also dependent on the order you did the operations in, and it can differ between machines.
For us, tiny is fatal. Two people recomputing the same chart have to agree on
every digit, or the claim collapses. So there are no decimals anywhere in
Croom. A price is a whole number of hundred-quintillionths — every value is multiplied by
1018 and stored as an integer. One pound is stored as
1000000000000000000.
Integer arithmetic is exact and identical everywhere. Problem solved, except for one thing.
Multiplying two of those scaled numbers overshoots, so you have to divide back down — and that division almost never comes out even. Something must be thrown away, and the rule is: delete the leftover, whichever side of zero you are on.
7 / 2 = 3 -7 / 2 = -3
Note that -7 / 2 is -3, not -4. That is
toward zero, not downward. It makes no difference whatsoever to positive
numbers, which is precisely what makes it dangerous: a test suite that only uses rising
prices passes either way.
Python, as it happens, rounds the other direction. So a tool written in Python to generate the expected answers would disagree with the contract on every negative intermediate value — and only on negative ones. It would look correct for weeks.
The lottery gives you numbers that are uniformly random: every value equally likely. Real prices do not move like that. Small moves are common, big moves are rare, enormous moves are very rare. That shape is the bell curve.
So we need to bend a flat draw into a bell-shaped one, and the trick for doing it is lovely.
Write down the function that answers what is the probability a bell-curve draw comes out below x? It climbs from 0 to 1:
| x | probability of landing below |
|---|---|
| −2 | 0.023 |
| −1 | 0.159 |
| 0 | 0.500 |
| +1 | 0.841 |
| +2 | 0.977 |
Now run it backwards. Feed it a flat random number between 0 and 1 and ask
which x would have produced that probability. Do this with flat draws, and the
answers come out bell-curve distributed.
The reason is almost a tautology: a value lands below x exactly when the flat
draw lands below the probability of landing below x — which happens with
exactly that probability. Draws near one half map to small moves; the rare draws near the
edges map to the extremes. The flatness gets stretched at the ends and squashed in the
middle, and out comes a bell.
There is no tidy formula for running it backwards, so we use a published approximation from 1988 with forty-eight constants in it. They are data, not settings. One mistyped digit leaves the middle of the distribution looking perfectly sensible and corrupts only the extremes — which is exactly where a price chart spends its interesting moments.
Volatility is quoted per year. Our prices move every three seconds. How much should a price move in three seconds if it moves 75% in a year?
The tempting answer is to divide by the number of three-second intervals in a year. That is wrong, and the reason is worth a moment.
Flip a coin a hundred times, scoring +1 for heads and −1 for tails. How far from zero do you typically end up? Not a hundred — the ups and downs cancel. Not one either. The answer is about ten, which is the square root of a hundred.
That is the general rule: when you add up independent random moves, their squared sizes add, not their sizes. So the typical total grows like the square root of the number of steps — and to go from a year to three seconds you divide by the square root of the number of steps, not the number itself.
There are 10,512,000 three-second rounds in a year. The square root of that is about 3,242. So 75% a year works out at roughly 0.0231% per round.
Here is the part that surprised me most.
Prices move multiplicatively — a 1% move matters the same at £2 and at £10,000. The clean way to handle multiplication is to work with logarithms, because logarithms turn multiplying into adding. So instead of multiplying the price by a random factor, we add a random amount to the price's logarithm and convert back.
Now: the random shock is symmetric. As likely to be +0.5 as −0.5. Surely that is fair?
It is not, and school algebra shows why. Adding +s to the logarithm multiplies
the price by some factor u. Adding −s multiplies it by
1/u. So a symmetric move in logarithm-land is a multiply by u or
by 1/u, each equally likely. The average multiplier is:
(u + 1/u) / 2
Try u = 1.1: (1.1 + 0.909) / 2 = 1.00454. Bigger than one. Try
u = 1.5: (1.5 + 0.667) / 2 = 1.083. Bigger again.
It is always bigger than one, and you can prove it in one line. Since any real number squared is at least zero:
(√u − 1/√u)² ≥ 0
u − 2 + 1/u ≥ 0
u + 1/u ≥ 2
(u + 1/u)/2 ≥ 1
with equality only when u = 1.
So a price driven by a perfectly symmetric shock drifts upward forever, for free. That is not a market, it is a money printer, and anybody betting "up" would win in the long run without taking a view on anything.
The fix is to subtract exactly enough to cancel it. The amount turns out to be half the variance. In our numbers that correction is about 0.0000000268 against a typical move of 0.0059% — utterly negligible per tick, and over ten million ticks a year it is the difference between a fair market and a rigged one.
Notice how little of this has involved a blockchain. The prices are computed from public data by a published recipe. Anyone can do it. We do it in your browser, and the page counts its own network requests to prove it is not quietly fetching the answer from us.
So what is the chain for? Two things.
Proving the lottery numbers are real. Anyone can claim a random number came from drand. The chain checks the cryptographic signature and records that the round exists.
Settling disagreements about money. If you and I have a bet on where the price went, we need something neutral that can decide. The chain holds a short fingerprint of a batch of prices, posted by somebody who put up a deposit saying it is correct. If it is wrong, anyone who notices can prove it and take that deposit.
We have done exactly that, on purpose, in public. Somebody posted a batch where one price was wrong by one unit — the eighteenth decimal place, the smallest lie the system can express. Somebody else, who was told nothing, recomputed the batch from the public lottery, found the value that did not follow, and proved it. The deposit changed hands. The transactions are there to look at.
That is why the rounding rule matters so much. The contract does not ask whether a claimed price is close to the right one. It asks whether it is equal. If two honest implementations could disagree by one unit in the last place, a liar could always claim to be an honest implementation that rounded differently — and there would be no way to settle anything.
Exactness is not tidiness here. It is the whole security model.
If you want the same material with the formulas written out, there is a longer technical breakdown in the repository, and every number quoted here is asserted by a test so that this page cannot drift away from the code.