A trusted core you can audit
The reference verifier, mm0-c, is under 3,000 lines of C.
You don't have to trust the tools that wrote a proof — only the small
program that checks it, and you can read all of it.
A proof language
Metamath Zero is designed so that a reader can see exactly what a theorem claims, and a small, independent verifier can confirm its proof.
-- the language of propositional logic, and its rules
sort wff;
term im (p q: wff): wff; infixr im: $->$ prec 25;
term not (p: wff): wff; prefix not: $~$ prec 41;
axiom ax_1 (a b: wff): $ a -> b -> a $;
axiom ax_2 (a b c: wff): $ (a -> b -> c) -> (a -> b) -> a -> c $;
axiom ax_mp (a b: wff): $ a -> b $ > $ a $ > $ b $;
-- a claim, with no proof attached: this file only states it
theorem id (a: wff): $ a -> a $;
-- the same theorem, now proved -- the term after `=` is the proof
theorem a1i (h: $ b $): $ a -> b $ =
'(ax_1 h);
theorem mpd (h1: $ a -> b $) (h2: $ a -> b -> c $): $ a -> c $ =
'(ax_2 h2 h1);
theorem id: $ a -> a $ =
'(mpd (! ax_1 _ a) ax_1);
-- Metamath C: a program whose type is a theorem about its output
(proc (adder {x : u32} {y : u32}
: {ret : (sn {(cast {x + y}) : u64})})
(sn {(cast {x + y}) : u64}))
A specification states what is true; a proof establishes it; a program can itself be the subject of a theorem — and the same verifier checks all three. Colours carry the ecosystem's meanings: terms, axioms, theorems, hypotheses.
How it works
Everything that produces a proof is untrusted. Only the verifier has to be believed — and it is small enough to read.
The reference verifier, mm0-c, is under 3,000 lines of C.
You don't have to trust the tools that wrote a proof — only the small
program that checks it, and you can read all of it.
MM0 fixes no logic of its own. You supply the axioms — set theory, higher-order logic, type theory, Peano arithmetic — and it checks proofs in the system you defined.
A finished proof is a file, not a session in someone's editor. The untrusted MM1 compiler produces it; the verifier re-checks every step from scratch, knowing nothing about how it was found.
Checking is close to the cost of reading the file. A full library verifies in seconds rather than minutes, so re-checking an entire development is routine rather than a bottleneck.
The project's goal theorem is a verifier for MM0, proved correct in MM0 itself, down to the x86 instructions it runs on — so the trust base terminates in a verified artifact rather than an assumption.
A small trusted kernel matters for what is built on it. MM0 is intended as a common substrate: other proof systems can translate their results into it and have them re-checked, terminating in a verifier that is itself proved correct.
Tools
The verifier is small enough to compile to WebAssembly. Nothing is uploaded; every file is checked in the tab it's opened in.
An in-browser IDE — the real mm0-rs compiled to wasm,
elaborating and reporting errors as you type.
Step a compiled .mmb proof the way the verifier's stack
machine runs it — one command at a time, state shown before each step.
Generated pages for a whole library: every theorem's statement and
proof tree, cross-linked, from mm0-rs doc.
Learn
mm0-rs with the VS Code extension.
Install
# clone and build mm0-rs
git clone https://github.com/digama0/mm0
cd mm0/mm0-rs
cargo build --release
# the "Metamath Zero" VS Code extension
code --install-extension digama0.metamath-zero
# build mm0-c and check a proof
gcc mm0-c/main.c -O2 -o mm0-c
./mm0-c proof.mmb < spec.mm0
Trust
Because the format is small and precisely specified, more than one program can play the role of "the verifier" — so no single implementation has to be believed.
mm0-c C — the referencemm0-rs Rust — compiler + servermm0-hs Haskell — toolchainsecond_opinion Rust — third partytrivial-rs Rust — third partymm0kt Kotlin — third partymm0-zig Zig — third partyThe endpoint: verifier.mm1, a proof that an MM0
verifier is correct — checked by an MM0 verifier.