Factorio is a deterministic simulation, which raises an obvious question: how does it produce random quality rolls? It doesn’t. The game uses taus88, three linear-feedback shift registers XORed together — a generator the developers picked in 2014 because it was the fastest in Boost. A two-year reverse-engineering project starts from that forum post, confirms it against the decompiled binary, and ends with a working prediction rig built entirely out of combinators.
Why it’s breakable:
- Each LFSR step is a linear map over GF(2), so advancing by k steps is just matrix exponentiation — and linearity means observed outputs can be solved back into the internal state.
- Three consecutive observations give a solvable system
A s(t) = [o(t), o(t+1), o(t+2)];Adepends on nothing dynamic, so its inverse is precomputed in Python. - The practical problem is the observation channel, not the algebra. Recycling a repair pack leaks exactly one bit (whether a 50%-chance item appeared), so 44 recycling units wired to decider combinators harvest the 88 bits needed.
- In-game, a GF(2) matrix-vector multiply is just conditional sums; the XOR reduction is free because Factorio adds signals on a wire, so ANDing the pointwise sum with 1 does the job.
- Prediction can’t force the RNG — it can only spend it. Scrap recycling burns 12 calls per craft and gears burn exactly one, letting a skipper consume the bad rolls until the desired one arrives.
- Factorio 2.1 still uses
taus88but rewrote item creation and now consumes RNG on every craft, which breaks the rig while leaving the theory intact.
The most useful lesson is not about Factorio. It’s that a linear PRNG plus any partially observable output equals recoverable state, which is exactly why bare LFSRs are considered cryptographically weak. The exploit here is architectural rather than a bug: nothing is broken, the entropy is simply not there.
The author is also refreshingly honest about what is unverified — the same-tick ordering trick is flaky, and one experimental version drove fish movement off the general RNG, which would have silently desynced everything.