kelvin@cluxnei.dev:~/blog

kelvin@cluxnei:~/blog$ cat entropy.md

2026-09-14 EN ~20 min read ler em português

Where a random number comes from

I built a site that draws things using earthquakes, the position of the Space Station, atmospheric noise and the quantum vacuum. The obvious question is why, given that every computer has a random function built in. The answer involves entropy, chaotic systems, and something that tends to surprise people: your computer's randomness is already physical, you just cannot verify it.

Flow field: thousands of particles following fractal noise, drawn as luminous strands
A flow field generated from atmospheric noise sampled in Dublin. Each particle follows a fractal vector field. The shape comes from the algorithm; which shape, out of the infinitely many possible, came from the world.

In this text

  1. What entropy actually is
  2. Why a computer draws nothing
  3. Where a computer gets real entropy
  4. Chaos: deterministic and unpredictable at once
  5. So why go looking outside
  6. The three classes, and the one that admits it is garnish
  7. What you can do with it

What entropy actually is

The word carries two histories. In thermodynamics, entropy measures how spread out a system's energy is. In information theory, which is the one that matters here, it measures something else: surprise.

Claude Shannon formalised this in 1948. If an event has probability p, the surprise of seeing it happen is log₂(1/p). The entropy of a source is the average surprise across everything it can produce:

H= − ∑i pi ⁢ log2 pi

The unit is the bit. One bit of entropy is exactly the uncertainty of a fair coin.

Two consequences worth keeping.

Entropy is not about the value, it is about the distribution. The number 7 is no more and no less random than 4. What does or does not have entropy is the process that chose.

Bias costs bits. A fair coin gives 1 bit per flip. A coin that lands heads 90% of the time gives only 0.47 bit. It is still unpredictable, just less so, and you need more than twice the flips to extract the same amount of uncertainty.

fair coin        p = 0.50    1.00 bit per flip
biased coin      p = 0.90    0.47 bit per flip
six-sided die    p = 1/6     2.58 bits per roll
full byte        256 values  8.00 bits

Hold on to that idea of "bits per event". It is the ruler that will later separate a source that works from a source that is garnish.

Why a computer draws nothing

A processor is a deterministic machine. Same input, same state, same output, always. That is the most valuable thing it has: it is why software works. And it is exactly why it cannot, on its own, produce a surprise.

What rand() does is something else: it produces a sequence that looks random from an internal state. The name for that is a pseudo-random generator, and the classic form is a linear congruential one:

xn+1 = (a⁢xn +c) modm

Each number is an arithmetic function of the previous one. Knowing the state, you know the whole sequence, forwards and backwards.

Which means the real entropy of a PRNG is the entropy of the seed, and nothing more. If the seed has 32 bits, the entire sequence has 32 bits of surprise, no matter whether you pull a million numbers out of it. The generator does not create uncertainty, it stretches it.

Where common sense is right. Math.random() in the browser and rand() in C are not cryptographically secure, and their own documentation says so. Observe enough outputs and you can reconstruct the internal state and predict the rest. For tic-tac-toe, fine. For drawing anything that matters, no.

Where a computer gets real entropy

Here is the part that usually goes missing from the conversation, and it is the opposite of what many people imagine.

Modern operating systems keep an entropy pool, and what goes into it is not mathematics: it is physics. Jitter in the exact timing between hardware interrupts. Thermal noise in dedicated circuits. CPU instructions like RDRAND, which sample a ring oscillator whose instability is thermal. The interval, in nanoseconds, between two packets arriving at the network card.

That pool feeds a cryptographic generator, and the result is what you get when you call random_bytes(), /dev/urandom or crypto.getRandomValues().

Your computer's "digital" randomness is already real-world randomness. It just comes in through a door you cannot see.

And it is good. In randomly's code, the source representing the system CSPRNG is classified as class A, with this comment:

/** Full-entropy, unpredictable bytes. Safe to stand alone. */
case Cryptographic = 'A';

Safe to stand alone. If the goal were entropy quality alone, the whole project would be unnecessary, and it would be dishonest to pretend otherwise.

Chaos: deterministic and unpredictable at once

Before answering why go looking outside, one piece is missing: understanding why an earthquake or the atmosphere are unpredictable, if both obey perfectly deterministic physical laws.

The answer is deterministic chaos. A chaotic system is governed by exact equations, with no randomness inside at all, and still cannot be predicted in the long run. The reason is sensitivity to initial conditions: two nearly identical configurations separate exponentially.

|δ(t)| ≈ |δ(0)| ⁢ eλ⁢t

An initial difference δ(0) grows exponentially with time. The exponent λ is the Lyapunov exponent: when it is positive, the system is chaotic.

Edward Lorenz stumbled into this in 1961, running a weather model. Restarting a simulation from the middle, he typed the values with three decimal places instead of the six the machine held. The resulting forecast diverged completely from the original. The difference was one part in a thousand.

From that comes the phrase that became a cliché and that almost nobody knows is a technical statement: the butterfly effect is not a poetic metaphor about interconnection, it is a claim about the exponential growth of error in non-linear dissipative systems.

The atmosphere is chaotic. The Earth's crust is chaotic. The geomagnetic field is chaotic. None of them is random in the strict sense, but all of them are impractical to predict, because predicting would require knowing the current state with infinite precision.

A familiar neighbour. The non-linearity that generates chaos is the same one that shows up in the advection term of Navier-Stokes, where velocity transports itself. It is why turbulence and weather unpredictability are close relatives, and it is the subject of the previous post.
Reaction-diffusion pattern: organic mazes in orange tones on a dark background
Reaction-diffusion. Two substances that react and spread at different rates. The rules fit in two equations; the specific pattern that emerges depends entirely on the initial perturbation. It is a chaotic system drawing.

So why go looking outside

If the system CSPRNG is secure, and natural sources are only unpredictable in practice, what is the point?

The point is not quality. It is provenance.

When a site draws a winner and says "it was random", you have no way to check anything. The bytes came from random_bytes(), and that call leaves no trace. There is no way to tell an honest draw from a hand-picked result presented as a draw. The trust is total and blind.

What randomly proposes is trading that for a receipt. Every result comes with the source, the instant, a plain-language account, and a link to the original data on the site of whoever published it.

value      9, 23, 8, 47, 12
source     RANDOM.ORG · class A
account    Atmospheric radio noise, sampled in Dublin moments ago
proof      https://www.random.org/randomness/
instant    2026-09-14T17:31:35+00:00
latency    274 ms

You can go and check. And more importantly, the whole result is reproducible from its own URL: the token carries the generator, the parameters and the source reference, so anyone recomputes exactly the same draw. There is no database behind it; there is nowhere to tamper with a history that does not exist.

The three classes, and the one that admits it is garnish

Now the bits-per-event ruler matters again. Not every real-world source is good for the same thing, and the code sorts the ten into three categories:

A · Cryptographic   Full-entropy, unpredictable bytes. Safe to stand alone.
                     System CSPRNG, ANU (quantum vacuum), RANDOM.ORG

B · Public          High entropy at publication, but globally public afterwards.
                     NIST Beacon, drand, Bitcoin blocks

C · Observational   Low-rate, biased, structured. Flavour, not entropy.
                     USGS seismic, ISS position, space weather

Look at class C. Earthquakes, the ISS and space weather are the prettiest sources in the project, and the comment in the code calls them flavour, not entropy. They produce very few bits per event, they are biased and they have structure. The ISS position is an orbit: you can compute where it will be.

Which is why there is a one-line rule governing the whole system:

mixedWithCsprng: ! $isCsprng

Everything that is not the CSPRNG itself gets mixed with it. The earthquake chooses which of the possible results you receive. The CSPRNG makes sure nobody can predict or reproduce that choice without the token. And every receipt carries a mixed_with_csprng field saying exactly that, rather than selling mysticism.

There is another field worth attention, degraded. While I was preparing this text, one of the examples came back like this:

value      09 15 33 41 56 57
source     Operating System CSPRNG · class A
account    Drawn from the kernel entropy pool on the server
degraded   true

The source I asked for did not answer, and the system fell back to the local CSPRNG. It kept working and announced the fallback in the receipt, instead of serving a result with the pretty narrative of an earthquake that never happened. That is the difference between degrading and lying.

Holding that up with ten third-party services needs a breaker. Three consecutive failures open a source's circuit for sixty seconds, and the next attempt is a probe that either restores or reopens it. The comment in the code sums up the goal better than I would:

Keeps one flaky third party from becoming our outage.

What you can do with it

There are 63 generators across six modules: numbers, words, equations, patterns, images and sound. Everything below is a real result, pulled from the live API while I was writing, each seeded by a different source.

Voronoi diagram in pastel colours
Voronoi. Scatter points and colour each region by its nearest point. Where the points land is the question, and the world answers it.
Truchet tiles forming continuous curves
Truchet tiles. A single tile with two arcs, rotated at random. The continuity of the curves follows from the geometry; the path they take does not.
Layered landscape in colour, from deep purple to yellow
Strata. Layers of noise stacked with a drawn palette. The same generator never returns the same landscape twice.
Three mazes side by side with the solution path highlighted
Mazes, with the solution highlighted. The guarantee that exactly one path exists comes from the algorithm; which path comes from the draw.
Pattern generated by wave function collapse
Wave Function Collapse. The algorithm repeatedly picks the most constrained cell and resolves one possibility. Every one of those choices consumes entropy from the source.
Plant generated by an L-system, branching like a fern
L-Systems. A grammar that rewrites itself, with angles and lengths drawn at random. This is how you draw vegetation without drawing any plant.
Composition of coloured rectangles in the style of Mondrian
Mondrian. Recursive subdivisions of the rectangle, with the palette and the cuts coming from the source.

And beyond images, the same mechanism produces things like these, which I captured along with their receipts:

passphrase   helper-opossum-lion-safehouse-sensitive-washable
             ISS Position · class C · over 40.69° N, 66.82° E

equation     2x² + 4x = 0   →   x = -2  or  x = 0
             USGS · magnitude 2.2 quake, 40 km ESE of Malaga, NM

dice         9, 12, 10, 10, 14, 18
             NOAA · planetary K-index 1.67, geomagnetic field quiet

The summary

Entropy is surprise, measured in bits. A deterministic computer does not manufacture surprise: it stretches the surprise it was given. The surprise it is given already comes from the physical world, through sensors you cannot see. And chaotic systems are unpredictable not because they are random, but because they amplify any uncertainty exponentially.

None of this makes random_bytes() bad. What it lacks is a receipt. That is what I set out to build: not better randomness, but randomness you can check, including the part where it admits to having had help.

randomly lives at randomly.cluxnei.dev, with 63 generators, ten sources and no API keys. Every result is reproducible from its own URL. The source is on GitHub.

kelvin@cluxnei:~/blog$