redstone-verifyOverviewLayoutsbalalaika.ai

Certified Minecraft redstone

redstone-verify takes a redstone layout and a Verilog spec. It accepts the layout only if it is proved equal to the spec for every input, the proof is checked by independent programs, and the layout behaves the same on two MCHPRS engines. AI agents or search may propose layouts. The funnel decides.

A 17-input OR bus: the seed lights the lamp when lever i3 is on; the mutant, with one repeater replaced by wire, does not
The bug from the paper's Figure 1. Steady-state model, isometric view. Random tests on the engine miss it; the SAT proof returns the counterexample i3=1.
25benchmark circuits
92layouts checked
44 / 48ACCEPT / REJECT
48 of 48shipped mutants rejected
92layouts with a live viewer
504third-party layouts imported

Browse all 92 layouts. Each has a card with its verdict, and 92 of them open in a viewer where you can flip levers and watch the signal.

Read the paper (PDF) · Source code on GitHub

The funnel

A layout is ACCEPTED only if all eight stages pass. The rejection counts are from the shipped mutants: broken copies of accepted layouts, all of which must be rejected.

1. extract layout to MCHPRS world to graph 2. subset only supported components 3. ports levers and lamps match the spec 4. prove SAT miter: equal for all inputs 48 shipped mutants stop here 5. certify LRAT proof, three checkers 6. lean same claim in Lean 4 7. cosim both MCHPRS engines agree 8. metrics size, critical path, glitches
1. extract
The layout is built as a world and turned into a component graph. Unbuildable layouts are rejected: floating wires, torches without a block, duplicate port names.
2. subset
The graph must use only components with a frozen meaning: levers, wires, torches, repeaters, comparators, lamps, constants. No feedback loops.
3. ports
The spec's ports are 1-bit and match the layout's levers (inputs) and lamps or observed blocks (outputs) by name.
4. prove
The graph is turned into Verilog and compared with the spec by a miter. The solver must show that no input separates them.
5. certify
The same claim is redone from an unoptimised AIGER file with a plain CNF encoder. CaDiCaL writes an LRAT proof; rup_check, lrat-check and the verified cake_lpr must all accept it.
6. lean
An independent route: the spec and the layout become Lean definitions and a Lean theorem says they implement each other.
7. cosim
The layout runs on the MCHPRS engine and on redpiler. Both must equal the model and the spec: every input up to 16 inputs, else structured plus 4,096 random vectors.
8. metrics
Blocks, volume, components, critical path, settle ticks and glitches are recorded.

Benchmark

25 circuits from a NOT gate to a 15-bit adder, a 16-bit comparator and a multiplier. Blocks count every block including levers, lamps and floor. "Best" is the smallest accepted candidate in this table (hand-designed, agent and hill-climb candidates); a later ShinkaEvolve search found a 10-block AND that is not listed here. Time is prove plus certify of the best layout, from one run on an idle AWS server. Mutants: rejected / shipped, and in parentheses how many of the rejected still pass co-simulation. Components, critical path and glitches are seed/best. Click a circuit to see its layouts.

circuitin/outseedbestcomp.crit. rtglitchesprove+cert sCNF vars/cl.LRAT kBmutants (tests pass)
not1/1941/11/10/00.0986/2544-
and22/125163/22/20/00.10248/701111/1 (0)
nand22/12172/21/10/00.10212/5939-
xor22/151313/42/20/00.13798/223137-
xnor22/153324/53/30/00.14825/231239-
imply22/12351/11/10/00.10185/5127-
mux23/143184/53/31/00.12550/153225-
maj33/189294/92/30/00.151010/281648-
half_adder2/296346/72/40/10.15988/275350-
full_adder3/22367114/135/72/80.211932/534295-
dec2to42/4124278/72/30/10.14934/265147-
c175/21624112/73/46/80.171294/360260-
mul24/4504-441370.748845/249505664/4 (0)
add49/5699-60127691.2014697/413278125/5 (0)
add817/91399-12020128582.5329323/8244518245/5 (0)
add1225/132099-18028196584.0243949/12356330855/5 (0)
add1531/162624-22534247565.2554911/15437942755/5 (0)
eq816/1481-37700.769535/266004974/4 (0)
eq1224/1721-55901.1414381/401067794/4 (0)
eq1632/1961-731101.5819227/5361210734/4 (0)
or1717/173561/01/00/00.364091/112372081/1 (0)
or2424/199-1100.465675/155722531/1 (0)
or3232/1131-2200.617502/205733932/2 (0)
and2424/1245-28500.526548/181672833/3 (0)
and3232/1325-37600.688735/242243834/4 (0)

Viewer

The viewer covers layouts up to 1,000 blocks. It has an isometric and a plan view with a layer slider. Clicking a lever flips its input.

Two kinds of simulation, both labelled in the viewer. Steady state is our own model, a JavaScript port of the frozen graph semantics (graph2v.py). It shows where the signal ends up. It is not vanilla Minecraft and has no timing. Tick playback replays a recorded run of the MCHPRS engine, one redstone tick per step, for layouts with at most 6 inputs. It has no torch burnout. Before a layout gets a viewer, the JavaScript evaluator must agree with both engines on every checked vector and with the engine's block states, block by block (results/site_check.json).

Additional experiments

Multipliers: proof search and proof checking

A separate three-seed campaign extends certificate measurements: at 22 inputs, median CaDiCaL time is 1825 s against a*b, versus 10.4 s against the layout's array architecture. Checker time scales approximately with LRAT size (empirical log-log slopes 0.86–1.00), while proof search and size grow sharply across architectures. Bit-parallel enumeration is faster throughout the measured 10–22-input cross-architecture range, but yields no checked proof. These are certificate-route results, not full-gate ACCEPTs; timings use a shared host.

Weak carry chains: faults missed by generic tests

A separate carry-skip adder experiment exposes faults missed by the tests. At widths 12–14, 20 of 45 faulty layouts pass the gate's co-simulation and both generic structured suites. The proof refutes all 45, with counterexamples confirmed on the engine; all 6 fault-free controls receive full ACCEPT. ABC also finds every fault, as do a fault-specific structured suite and 106 random model vectors. At widths 15–24, 107 random model vectors miss 3 of 24 faults; above 15 bits the engine's 32-input limit prevents replay and full ACCEPT.

Independent encoding and mutation checks

A separately written Rust encoder agrees on 62 accepted and 116 refuted miters, with all 62 independent UNSAT certificates checked by cake_lpr. Translator mutation tests exercise 314 single-site and 10 paired faults, with no observed false ACCEPT: 227 are detected (20 only by differential regressions outside the gate), 68 change no layout of the test pool, and 29 are noticed by nothing. A separate wire/timing generator produces 748 mutants, including 510 proof refutations and 224 steady-state equivalences; co-simulation misses 4 refuted wide-layout mutants.

Third-party compilers

We imported layouts from three public redstone compilers and ran them through the same funnel. 504 layouts were imported and 470 were accepted. 99 came from a compiler run and 65 of those were accepted. The rest are the compilers' own shipped example files. Every rejection has a located cause.

toolcircuitblocks (ours)verdictLRAT
REDA d8f3af0not / and2 / nand2 / imply212 / 54 / 54 / 44 (4 / 16 / 7 / 5)ACCEPT 10–60 KB
REDAmux2, half_adder, maj3, full_adder, dec2to4, c17174, 208, 792, 1,636, 648, 1,086 (18, 34, 29, 71, 27, 41)ACCEPT 0.1–0.7 MB
REDAmul2, mul3, eq8, eq121,880, 12,426, 13,806, 28,954ACCEPT (eq8 exhaustive, 65,536 vectors)up to 56 MB
REDAeq1651,436REJECT at Lean: simp step limit exceeded (SAT, LRAT and co-simulation pass); ACCEPT with --lean-long (Lean 851 s)56 MB
REDAor24, or32, and24, and32, add48,250–23,516; add4 16,872 (699)ACCEPT up to 18 MB
REDAadd8, add12, add1552,016, 93,086, 147,868 (1,399–2,624)REJECT at Lean (simp step limit exceeded); also not settled within 200 ticks on redpiler. With --max-ticks 600 and --lean-long: add8 ACCEPT (Lean 790 s); add12 and add15 REJECT, bv_decide does not finish (add12: compile error after 2,505 s with a 7200 s budget; add15: timeout after 7200 s)59–167 MB
REDAxor2, xnor2, or17193*, 193*, 1,761*REJECT unbuildable (F3)–
Redstone-Compiler cc99773, final worldnot / imply23 (4) / 21 (5)ACCEPT 2.5 / 19.5 KB
Redstone-Compiler, final worldand2 / nand232* / 31*REJECT oscillates (F1)–
Redstone-Compiler, all 64 candidatesand2 / nand2 / imply2 / not–6, 11, 11, 16 of 16 ACCEPT–
Redstone-Compilerxor2, xnor2, half_adder, mux2, maj3, dec2to4, c17, full_adder, mul2, add4, eq8, or17–no layout from the tool (F5)–
Redstone-Compiler, its own shipped files (405)half adder, xor-generated, full-adder, 3-input XOR, and-gate, 400 sampled tiles36 (34), 25 (31), 59 (71), 70, 17, tiles 19–70all ACCEPT–
rtl2mc cbe416dand2, xor2, half_adder, full_adder, mux22,224–17,044*REJECT outside the subset (redstone_block)–

Findings in the compilers' output

Reproducers have been reported to Redstone-Compiler, REDA and MCHPRS. The separate certificate-checker finding is reported to drat-trim.

F1. Redstone-Compiler: input ports that feed back into the logic

In its exported and2 the torch that computes NOT a powers a block that touches a's own input wire. That is a one-torch ring oscillator. Source inspection suggests that candidate testing with levers, followed by export with wire at the ports, explains the discrepancy; we have not instrumented that execution path. With levers at the port cells the same world is accepted with a certificate.

We placed the raw layouts in vanilla Minecraft 1.21.1. The ring runs with period 4 for eight pulses, then the torch burns out and the ring stays dead. So vanilla does not oscillate forever, but the world is still not a working gate: nand2 gives the wrong output at a=0, b=1, and and2 matches its table only after the burnout. The tool's own simulator calls and2 wrong at a=0, b=1 (y=1, spec 0).

Redstone-Compiler and2, exactly as exported, in vanilla Minecraft 1.21.1. The input ports feed back into the logic.
Redstone-Compiler and2, exactly as exported, in vanilla Minecraft 1.21.1. The input ports feed back into the logic.
Control: the same world with levers placed at the port cells. This variant matches the spec.
Control: the same world with levers placed at the port cells. This variant matches the spec.

F3. REDA: redstone dust with nothing to stand on

REDA places dust on top of dust (xor2, xnor2) or on a repeater (or17). Its own simulator calls these layouts correct. Vanilla removes that dust when the layout is placed. The outputs then equal the dust-removed engine variant on every probed vector and differ from the spec exactly where the proof says: xor2 gives y=1 and xnor2 gives y=0 at a=b=0, and or17 gives y=0 with only i15 or only i16 on. For or17 all 4,096 random co-simulation vectors pass. Only the proof finds the bug.

REDA xor2 as placed in vanilla Minecraft 1.21.1. Vanilla removes the dust that has nothing to stand on.
REDA xor2 as placed in vanilla Minecraft 1.21.1. Vanilla removes the dust that has nothing to stand on.
Diagnostic: the same layout with the unsupported dust removed by hand. The outputs are the same.
Diagnostic: the same layout with the unsupported dust removed by hand. The outputs are the same.

Also found: Redstone-Compiler's interface.json lacks the placement offset and the outputs (F2). rtl2mc uses a redstone block that is outside our subset (F4). Redstone-Compiler cannot compile most of the benchmark (F5).

What this does not show