moxzi
Docs / Concepts / Byte-identical output

Byte-identical outputalpha

What does "byte-identical to moc" mean, what does it buy you, and how is it verified?

Byte-identical means cmp returns zero: the same source, compiled by two different compilers or in two different places, produces wasm files that agree on every byte. Not "semantically equivalent", not "same size", not "passes the same tests".

The constraint is that this is a claim about pairs, and moxzi makes three different pairs of it. They are proven by different gates and they are not interchangeable.

Three claims, three gates#

ClaimPair being comparedGateCorpus
moxzi output == reference moc outputCompileEnhanced vs moc -no-linkscripts/corpus_run.sh, scripts/byteparity_run.pymoc's own test/run
Two moxzi compiler builds agreeBASELINE compiler.wasm vs CANDIDATE compiler.wasmscripts/compiler_byte_neutral.sh221 programs from test/run-drun
The same compiler agrees across hostsChrome tab vs CLI; on-chain vs localscripts/web_page_compile_gate.sh, scripts/web_mops_gate.shthe compiler itself, plus mops projects

The first is a correctness claim measured against an independent implementation. The second is a neutrality claim: it says a refactor changed nothing observable, and it is far cheaper to run than the first because it never interprets Motoko under moc -r — it just runs two builds and diffs. The third is what makes "one compiler, four places" a measurement rather than an assertion.

What it buys you#

Reproducible builds. The artifact does not depend on which of the four front ends produced it. A customer can run an on-chain build, run the same build locally, and cmp the two files. Every artifact carries a provenance line naming the compiler that made it by SHA-256 (moxzi info prints the loaded compiler and linker hashes), so the comparison is anchored to a specific binary rather than to a version string.

Tamper-evident provenance. This is the point of the on-chain builder. A build whose bytes were produced by a canister anyone can audit, from sources anyone can hash, is evidence no local toolchain can offer — but only because the local build reproduces it exactly. Without byte identity the on-chain artifact would be unverifiable, and an unverifiable artifact from a trusted party is just a trusted party.

A refactor gate that cannot be argued with. Most of the compiler's hard work has been performance work: splitting a function so its wasm frame stops costing every recursion level, packing finished function bodies to bytes at definition time, converting a pass from async* to a pull-driven state machine. Each of those changes message counts, memory profiles and instruction budgets, and none of them may change one byte of output. PAR=6 bash scripts/compiler_byte_neutral.sh answers that in one run.

Transitivity. Behavior comparisons chain the same way. The differential harness established that the native runtime matches a real IC replica across moc's corpus; the browser gate then compares the browser runtime against the native one over 149 programs with zero diverging. Browser == native and native == replica gives browser == replica without ever needing a replica in the browser gate, which is what makes that gate fast enough to run over everything.

How the sweeps actually work#

compiler_byte_neutral.sh copies moc's run-drun corpus, rewrites bare actor to persistent actor exactly as the other harnesses do, filters to programs that declare an actor and do not reference ic:/canister: URLs, then builds each one twice — once with MOXZI_COMPILER=$BASELINE, once with $CANDIDATE — and cmps the results. Outcomes are classified, not summed: SAME, DIFFER, BOTHFAIL (the corpus contains programs the toolchain does not accept, which is not a regression), and ONLYNEW/ONLYOLD (built by one compiler and not the other, which is).

Two safeguards in that script are worth knowing about, because both exist as a result of a gate that once passed while asserting nothing:

web_corpus_gate.sh runs in batches, each its own node process, because past roughly a hundred memory64 modules V8 stops handing out memory and every subsequent program traps identically — a cascade that looks like a systematic failure. Programs the browser cannot host (no management canister; no way to preempt a running call) are named, not counted as agreement.

The known drift#

One difference is open and recorded rather than fixed: the counter byte-parity probe reports exactly one byte differing from the reference, in the name section. It appears in every validation block in PROGRESS.md as "the KNOWN pre-existing 1-byte name-section drift", and the probes assert diffs=1 for that program specifically so it cannot grow silently. The name section carries debug names only; it does not affect execution. It is still a difference, and it is stated here rather than rounded off.

Things you cannot do#

Not possibleWhy
Compare a linked artifact against a -no-link oneLinking embeds the RTS, prunes exports and rewrites sections. Compare like with like, or link both.
Read byte identity as proof of semantic correctnessIt proves two compilers agree, over the programs compared. A shared misunderstanding of the language stays invisible. That is what the differential runtime harness and the corpus are for.
Expect every corpus program to compileBOTHFAIL is a normal outcome. The sweeps measure agreement among programs both compilers accept, and report the rejected count separately.
Run the sweeps in CI todayBoth need the reference corpus checkout and roughly 15 minutes each. They run in a weekly job and always in make alpha-check before a tag (see docs/ci.md).
Diff two artifacts built with different flags--debug, --no-idl and the metadata options change the output legitimately. Byte identity is a claim about identical inputs.

Next#

On this pageThree claims, three gatesWhat it buys youHow the sweeps actually workThe known driftThings you cannot doNext