<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://invarians.org/index.php?action=history&amp;feed=atom&amp;title=Lean_theorem_prover%2FSystem%2FProof_export_and_independent_checkers</id>
	<title>Lean theorem prover/System/Proof export and independent checkers - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://invarians.org/index.php?action=history&amp;feed=atom&amp;title=Lean_theorem_prover%2FSystem%2FProof_export_and_independent_checkers"/>
	<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Proof_export_and_independent_checkers&amp;action=history"/>
	<updated>2026-10-21T06:37:25Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Proof_export_and_independent_checkers&amp;diff=6796&amp;oldid=prev</id>
		<title>PMA Publisher: Published from the Principia Machina source</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Proof_export_and_independent_checkers&amp;diff=6796&amp;oldid=prev"/>
		<updated>2026-10-15T19:35:20Z</updated>

		<summary type="html">&lt;p&gt;Published from the Principia Machina source&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw-interface=&quot;&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 19:35, 15 October 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l1&quot;&gt;Line 1:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{DISPLAYTITLE:Proof export and independent checkers}}&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{DISPLAYTITLE:Proof export and independent checkers}}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Plebeian|Lean theorem prover/Explainers/Checking a proof again later}}&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;{{Plebeian|Lean theorem prover/Explainers/Checking a proof again later}}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;{{Lean theorem prover map}}&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;br&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;When a Lean source file is elaborated, the Lean kernel checks every definition and theorem&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;When a Lean source file is elaborated, the Lean kernel checks every definition and theorem&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key pma_cutover_20261020t051351z-soft_:diff:1.41:old-6589:rev-6796:php=table --&gt;
&lt;/table&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
	<entry>
		<id>https://invarians.org/index.php?title=Lean_theorem_prover/System/Proof_export_and_independent_checkers&amp;diff=6589&amp;oldid=prev</id>
		<title>PMA Publisher: Published from the Principia Machina source</title>
		<link rel="alternate" type="text/html" href="https://invarians.org/index.php?title=Lean_theorem_prover/System/Proof_export_and_independent_checkers&amp;diff=6589&amp;oldid=prev"/>
		<updated>2026-10-14T18:01:10Z</updated>

		<summary type="html">&lt;p&gt;Published from the Principia Machina source&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{DISPLAYTITLE:Proof export and independent checkers}}&lt;br /&gt;
{{Plebeian|Lean theorem prover/Explainers/Checking a proof again later}}&lt;br /&gt;
&lt;br /&gt;
When a Lean source file is elaborated, the Lean kernel checks every definition and theorem&lt;br /&gt;
before it enters Lean&amp;#039;s environment, its table of definitions and theorems. That first check&lt;br /&gt;
happens inside the same program that parsed the file, ran its tactics and executed whatever&lt;br /&gt;
code the file and its imports contain. This page is about checking again: listing the axioms&lt;br /&gt;
a theorem depends on, replaying compiled results through the Lean kernel with&lt;br /&gt;
&amp;lt;code&amp;gt;leanchecker&amp;lt;/code&amp;gt;, exporting proofs to a file, and checking that file with checkers&lt;br /&gt;
written independently of Lean. For each, it says what the check guards against and what it&lt;br /&gt;
does not. The examples were run with Lean 4.34.1.&lt;br /&gt;
&lt;br /&gt;
== What the first check leaves open ==&lt;br /&gt;
&lt;br /&gt;
Lean&amp;#039;s reference manual sets out an escalating series of checks and distinguishes two&lt;br /&gt;
situations. In the &amp;#039;&amp;#039;&amp;#039;honest&amp;#039;&amp;#039;&amp;#039; case the author is trying to produce a valid proof and the&lt;br /&gt;
risks are mistakes and bugs. In the &amp;#039;&amp;#039;&amp;#039;malicious&amp;#039;&amp;#039;&amp;#039; case someone is trying to mislead: by&lt;br /&gt;
exploiting bugs, by code that circumvents the system, or by compromising the machine; the&lt;br /&gt;
manual counts unreviewed proofs generated by AI in this case. It also separates two&lt;br /&gt;
questions: whether a theorem has a valid proof, and what the theorem&amp;#039;s statement&lt;br /&gt;
means.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot;&amp;gt;&amp;quot;Validating a Lean Proof&amp;quot;, a chapter of &amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039; (edition covering Lean 4.34.0), with its sections &amp;quot;The Blue Double Check Marks&amp;quot;, &amp;quot;Printing Axioms&amp;quot;, &amp;quot;Re-Checking Proofs with lean4checker&amp;quot;, &amp;quot;Gold Standard: comparator and external checkers&amp;quot;, &amp;quot;Remaining Issues&amp;quot; and &amp;quot;On Lean.trustCompiler (up to Lean 4.28.0)&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/ValidatingProofs/ lean-lang.org/doc/reference/4.34.0/ValidatingProofs/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The ordinary check, a theorem accepted in the editor or a Lake build of its Lean module&lt;br /&gt;
without errors or warnings, protects against incomplete proofs, an explicit&lt;br /&gt;
&amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; in the theorem itself and honest bugs in tactics and other metaprograms. It assumes that the statement says&lt;br /&gt;
what is intended, that the authors of imported libraries are honest, and that no unsound&lt;br /&gt;
axiom has been declared and used.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; The checks below remove some of these&lt;br /&gt;
assumptions.&lt;br /&gt;
&lt;br /&gt;
== Listing the axioms ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; lists every axiom a theorem depends on, directly or through the&lt;br /&gt;
theorems it uses.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean&amp;quot; style=&amp;quot;background: #f8f9fa; border: 1px solid #c8ccd1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&lt;br /&gt;
theorem two_add_two : 2 + 2 = 4 := rfl&lt;br /&gt;
&lt;br /&gt;
theorem em_or (p : Prop) : p ∨ ¬p := Classical.em p&lt;br /&gt;
&lt;br /&gt;
theorem unfinished : 2 + 2 = 5 := sorry&lt;br /&gt;
&lt;br /&gt;
#print axioms two_add_two&lt;br /&gt;
#print axioms em_or&lt;br /&gt;
#print axioms unfinished&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lean warns &amp;lt;code&amp;gt;declaration uses `sorry`&amp;lt;/code&amp;gt; at the third theorem, and prints:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean-output&amp;quot; style=&amp;quot;background: #ffffff; border: 1px dashed #a2a9b1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&amp;#039;two_add_two&amp;#039; does not depend on any axioms&lt;br /&gt;
&amp;#039;em_or&amp;#039; depends on axioms: [propext, Classical.choice, Quot.sound]&lt;br /&gt;
&amp;#039;unfinished&amp;#039; depends on axioms: [sorryAx]&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;propext&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Classical.choice&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;Quot.sound&amp;lt;/code&amp;gt; are Lean&amp;#039;s&lt;br /&gt;
three standard axioms (see [[Lean theorem prover/Foundations/The three axioms|the three&lt;br /&gt;
axioms]]). &amp;lt;code&amp;gt;sorryAx&amp;lt;/code&amp;gt; marks a gap: a &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; or an incomplete proof&lt;br /&gt;
somewhere in the dependencies, which the editor&amp;#039;s mark next to the theorem does not&lt;br /&gt;
reveal.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The command also exposes proofs that rest on running compiled code. The page on&lt;br /&gt;
[[Lean theorem prover/System/The compiler and runtime|the compiler and runtime]] defines a&lt;br /&gt;
function whose compiled code, supplied through &amp;lt;code&amp;gt;@[implemented_by]&amp;lt;/code&amp;gt;, disagrees&lt;br /&gt;
with its definition. A tactic that trusts compiled code can then prove a falsehood:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean&amp;quot; style=&amp;quot;background: #f8f9fa; border: 1px solid #c8ccd1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&lt;br /&gt;
def alwaysZero (_ : Nat) : Nat := 0&lt;br /&gt;
&lt;br /&gt;
@[implemented_by alwaysZero]&lt;br /&gt;
def ident (n : Nat) : Nat := n&lt;br /&gt;
&lt;br /&gt;
theorem ident_five : ident 5 = 5 := rfl&lt;br /&gt;
&lt;br /&gt;
theorem ident_five_zero : ident 5 = 0 := by decide +native&lt;br /&gt;
&lt;br /&gt;
theorem oops : False := by&lt;br /&gt;
  have h1 := ident_five&lt;br /&gt;
  have h2 := ident_five_zero&lt;br /&gt;
  omega&lt;br /&gt;
&lt;br /&gt;
#print axioms oops&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Everything is accepted, and the last line prints&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean-output&amp;quot; style=&amp;quot;background: #ffffff; border: 1px dashed #a2a9b1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&amp;#039;oops&amp;#039; depends on axioms: [propext, Quot.sound, ident_five_zero._native.decide.ax_1_1]&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;decide +native&amp;lt;/code&amp;gt; evaluated the claim with compiled code and admitted the result&lt;br /&gt;
as a new axiom. Since Lean 4.29.0 each such computation has its own axiom, named after the&lt;br /&gt;
theorem that made it; before that, all of them appeared as one axiom,&lt;br /&gt;
&amp;lt;code&amp;gt;Lean.trustCompiler&amp;lt;/code&amp;gt;.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; Any axiom other than the standard three&lt;br /&gt;
means that the proof depends on something the Lean kernel did not check.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; reads Lean&amp;#039;s environment as it stands. It cannot detect a theorem&lt;br /&gt;
that entered that table without being checked at all.&lt;br /&gt;
&lt;br /&gt;
== Replaying through the Lean kernel: leanchecker ==&lt;br /&gt;
&lt;br /&gt;
Lean&amp;#039;s environment is held in memory while a file is processed and saved, Lean module by&lt;br /&gt;
Lean module, in &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; files. Code run during elaboration has the access it&lt;br /&gt;
needs to add a constant to that table without passing it to the Lean kernel, and Lean has&lt;br /&gt;
a debugging option, &amp;lt;code&amp;gt;debug.skipKernelTC&amp;lt;/code&amp;gt;, that skips the check.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; The&lt;br /&gt;
following file uses it together with the false tactic from [[Lean theorem prover/System/Metaprogramming in Lean|metaprogramming in&lt;br /&gt;
Lean]], which the Lean kernel would reject.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean&amp;quot; style=&amp;quot;background: #f8f9fa; border: 1px solid #c8ccd1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;&lt;br /&gt;
import Lean&lt;br /&gt;
open Lean Elab Tactic&lt;br /&gt;
&lt;br /&gt;
elab &amp;quot;cheat&amp;quot; : tactic =&amp;gt; do&lt;br /&gt;
  let goal ← getMainGoal&lt;br /&gt;
  goal.assign (mkConst ``True.intro)&lt;br /&gt;
  replaceMainGoal []&lt;br /&gt;
&lt;br /&gt;
set_option debug.skipKernelTC true in&lt;br /&gt;
theorem bad : False := by cheat&lt;br /&gt;
&lt;br /&gt;
#print axioms bad&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As the library &amp;lt;code&amp;gt;Hack&amp;lt;/code&amp;gt; of a small Lake package, it compiles without error, and the&lt;br /&gt;
axiom check reports nothing amiss:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean-output&amp;quot; style=&amp;quot;background: #ffffff; border: 1px dashed #a2a9b1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;ℹ [2/3] Built Hack (868ms)&lt;br /&gt;
info: Hack.lean:12:0: &amp;#039;bad&amp;#039; does not depend on any axioms&lt;br /&gt;
Build completed successfully (3 jobs).&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The reference manual names &amp;lt;code&amp;gt;debug.skipKernelTC&amp;lt;/code&amp;gt; as an example of code whose only&lt;br /&gt;
purpose is to circumvent the system.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; The second check exists for this&lt;br /&gt;
case. &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;leanchecker&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039;, which is part of the Lean 4.34.1 toolchain, reads the&lt;br /&gt;
&amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; files and replays every definition and theorem in them through the Lean&lt;br /&gt;
kernel.&amp;lt;ref name=&amp;quot;rm-bt&amp;quot;&amp;gt;&amp;quot;Build Tools and Distribution&amp;quot;, a chapter of &amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039; (edition covering Lean 4.34.0). [https://lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/ lean-lang.org/doc/reference/4.34.0/Build-Tools-and-Distribution/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
Since Lean 4.28.0 the program is the external checker &amp;lt;code&amp;gt;lean4checker&amp;lt;/code&amp;gt;, shipped with&lt;br /&gt;
every toolchain;&amp;lt;ref name=&amp;quot;rn428&amp;quot;&amp;gt;&amp;quot;Lean 4.28.0&amp;quot;, in &amp;quot;Release Notes&amp;quot;, &amp;#039;&amp;#039;The Lean Language Reference&amp;#039;&amp;#039; (edition covering Lean 4.34.0), section &amp;quot;External Checker&amp;quot;. [https://lean-lang.org/doc/reference/4.34.0/releases/v4.28.0/ lean-lang.org/doc/reference/4.34.0/releases/v4.28.0/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
the reference manual&amp;#039;s chapter on validating proofs still calls it by that&lt;br /&gt;
name.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; Run as &amp;lt;code&amp;gt;lake env leanchecker --fresh&lt;br /&gt;
Hack&amp;lt;/code&amp;gt;, it reports:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre class=&amp;quot;lean-output&amp;quot; style=&amp;quot;background: #ffffff; border: 1px dashed #a2a9b1; padding: 0.6em; margin: 0.3em 0; font-size: 0.85em; line-height: 1.35; overflow-x: auto; white-space: pre;&amp;quot;&amp;gt;uncaught exception: while replaying declaration &amp;#039;bad&amp;#039;:&lt;br /&gt;
(kernel) declaration type mismatch, &amp;#039;bad&amp;#039; has type&lt;br /&gt;
  True&lt;br /&gt;
but it is expected to have type&lt;br /&gt;
  False&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
and exits with a failure. With &amp;lt;code&amp;gt;--fresh&amp;lt;/code&amp;gt; it replays the named Lean module and&lt;br /&gt;
everything it imports into an empty table; without it, it replays only the Lean module&amp;#039;s own&lt;br /&gt;
constants on top of its imports.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;l4l&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
According to the reference manual, this check protects against bugs in Lean&amp;#039;s handling of&lt;br /&gt;
the Lean kernel&amp;#039;s state, for instance in parallel processing or imports, and against&lt;br /&gt;
metaprograms that deliberately bypass that state. It trusts that the &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt;&lt;br /&gt;
files are well formed, and a crafted file could defeat it. It also runs after the code under&lt;br /&gt;
test has been compiled, and such code, the manual warns, can perform arbitrary actions when&lt;br /&gt;
run; a determined attacker can compromise the machine before any check takes&lt;br /&gt;
place.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; And it uses the same Lean kernel, so it cannot find a bug in the&lt;br /&gt;
Lean kernel itself.&lt;br /&gt;
&lt;br /&gt;
== Exporting proofs ==&lt;br /&gt;
&lt;br /&gt;
The next step separates the proof from the program that produced it. &amp;#039;&amp;#039;&amp;#039;lean4export&amp;#039;&amp;#039;&amp;#039; writes&lt;br /&gt;
the constants of a Lean module and everything it depends on to a file in an NDJSON format,&lt;br /&gt;
one JSON record per line.&amp;lt;ref name=&amp;quot;res-export&amp;quot;&amp;gt;&amp;quot;lean4export&amp;quot;, Reservoir, the index of Lake packages: &amp;quot;A simple declaration exporter for Lean 4 using the Lean 4 NDJSON export format&amp;quot;. [https://reservoir.lean-lang.org/@leanprover/lean4export reservoir.lean-lang.org/@leanprover/lean4export]&amp;lt;/ref&amp;gt;&lt;br /&gt;
The file contains terms of the type theory and nothing else: no tactics, no notation, no&lt;br /&gt;
elaborator. A checker that reads it needs to implement only the type theory: universes,&lt;br /&gt;
dependent function types, inductive types and their recursors, quotients and definitional&lt;br /&gt;
equality. It need not trust what the file says about derived data. A test in the&lt;br /&gt;
Lean Kernel Arena makes the point that a checker &amp;quot;must not blindly trust the recursors it is&lt;br /&gt;
handed&amp;quot;, and should either check them or derive them anew from the inductive type&lt;br /&gt;
itself.&amp;lt;ref name=&amp;quot;arena-tut&amp;quot;&amp;gt;&amp;quot;Tutorial&amp;quot; test suite, Lean Kernel Arena. [https://arena.lean-lang.org/tutorial/ arena.lean-lang.org/tutorial/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Independent checkers ==&lt;br /&gt;
&lt;br /&gt;
Three programs illustrate the range.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;nanoda&amp;#039;&amp;#039;&amp;#039; is a checker for Lean exports written in Rust, developed independently of&lt;br /&gt;
Lean.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt;&amp;lt;ref name=&amp;quot;arena-nanoda&amp;quot;&amp;gt;&amp;quot;nanoda&amp;quot;, checker page, Lean Kernel Arena. [https://arena.lean-lang.org/checker/nanoda/ arena.lean-lang.org/checker/nanoda/]&amp;lt;/ref&amp;gt;&lt;br /&gt;
A bug would have to occur in both nanoda and the Lean kernel, written separately in&lt;br /&gt;
different languages, to let a false theorem through both.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Lean4Lean&amp;#039;&amp;#039;&amp;#039;, by Mario Carneiro, is a type checker for Lean 4 written in Lean. It reads&lt;br /&gt;
compiled &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; files, offers the same interface as lean4checker, and can check&lt;br /&gt;
the whole of Mathlib, running 20 to 50 per cent slower than the Lean kernel, which is&lt;br /&gt;
written in C++. Because it is written in a language with proofs, parts of it can be, and have&lt;br /&gt;
been, proved correct against a formalisation of Lean&amp;#039;s type theory; that work found a&lt;br /&gt;
soundness bug in the Lean kernel, which has since been fixed.&amp;lt;ref name=&amp;quot;l4l&amp;quot;&amp;gt;Mario Carneiro, &amp;quot;Lean4Lean: Verifying a Typechecker for Lean, in Lean&amp;quot;, in &amp;#039;&amp;#039;31st International Conference on Types for Proofs and Programs (TYPES 2025)&amp;#039;&amp;#039;, Leibniz International Proceedings in Informatics 384, Schloss Dagstuhl, 2026, 2:1–2:23. doi:[https://doi.org/10.4230/LIPIcs.TYPES.2025.2 10.4230/LIPIcs.TYPES.2025.2]; full version [https://arxiv.org/abs/2403.14064 arXiv:2403.14064].&amp;lt;/ref&amp;gt;&lt;br /&gt;
Its description in the Lean Kernel Arena notes the limit of the approach: it follows the C++&lt;br /&gt;
implementation closely, and so &amp;quot;likely shares some implementation bugs with it&amp;quot;.&amp;lt;ref name=&amp;quot;arena-l4l&amp;quot;&amp;gt;&amp;quot;lean4lean&amp;quot;, checker page, Lean Kernel Arena. [https://arena.lean-lang.org/checker/lean4lean arena.lean-lang.org/checker/lean4lean]&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;comparator&amp;#039;&amp;#039;&amp;#039; is the reference manual&amp;#039;s &amp;quot;gold standard&amp;quot; for high-risk settings; the manual&lt;br /&gt;
names proof marketplaces, competitions with high rewards, and unaligned AI. The theorem&lt;br /&gt;
statement is written first, in a trusted setting, as a challenge file. comparator compiles&lt;br /&gt;
the proposed proof inside a sandbox, exports it, and, outside the sandbox, validates the export, replays it with the Lean kernel,&lt;br /&gt;
nanoda or both, and checks that the proved statements are exactly those in the challenge&lt;br /&gt;
file.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;#039;&amp;#039;&amp;#039;Lean Kernel Arena&amp;#039;&amp;#039;&amp;#039; tests such checkers side by side. It runs each on the same&lt;br /&gt;
exported tests, some of which a correct checker must accept and some of which it must&lt;br /&gt;
reject, and publishes the results; the Lean kernel of version 4.34.1 is among the checkers&lt;br /&gt;
listed.&amp;lt;ref name=&amp;quot;arena&amp;quot;&amp;gt;Lean Kernel Arena: &amp;quot;presents, tests and benchmarks proof checkers for the Lean Theorem Prover&amp;quot;. [https://arena.lean-lang.org arena.lean-lang.org]&amp;lt;/ref&amp;gt;&amp;lt;ref name=&amp;quot;arena-tut&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What each check guards against ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Check !! Reads !! Guards against !! Does not guard against&lt;br /&gt;
|-&lt;br /&gt;
| Editor or Lake build || source files || incomplete proofs, &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; in the theorem, honest bugs in tactics || gaps in dependencies, extra axioms, bypassed checks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;#print axioms&amp;lt;/code&amp;gt; || Lean&amp;#039;s environment in memory || &amp;lt;code&amp;gt;sorry&amp;lt;/code&amp;gt; anywhere in the dependencies, custom axioms, native computation || constants that were never checked&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;leanchecker&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; files || constants added without the Lean kernel&amp;#039;s check, bugs in handling the Lean kernel&amp;#039;s state || crafted &amp;lt;code&amp;gt;.olean&amp;lt;/code&amp;gt; files, a compromised machine, bugs in the Lean kernel&lt;br /&gt;
|-&lt;br /&gt;
| comparator with an external checker || an export, outside a sandbox || malicious proofs, a bug present in one checker but not all || a bug shared by every checker, an unsound logic, a wrong statement&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Sources: the reference manual&amp;#039;s chapter on validating proofs,&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; and the&lt;br /&gt;
demonstrations above.&lt;br /&gt;
&lt;br /&gt;
== Why check outside the tool that made the proof ==&lt;br /&gt;
&lt;br /&gt;
The Lean kernel is small, but it is a program, and programs have bugs. Lean 4&amp;#039;s kernel was&lt;br /&gt;
extended for performance, with fast arithmetic on natural numbers, nested inductive types and&lt;br /&gt;
primitive projections among other things, and Carneiro reports that some soundness bugs&lt;br /&gt;
entered in the process.&amp;lt;ref name=&amp;quot;l4l&amp;quot; /&amp;gt; A second implementation does not make a bug&lt;br /&gt;
impossible. It makes a bug matter only if every implementation has it.&lt;br /&gt;
&lt;br /&gt;
There is a second reason. Elaboration runs code, much of it written by users, with the full&lt;br /&gt;
rights of a program. A check that runs in the same process, on the same machine, after that&lt;br /&gt;
code, inherits whatever that code did. A check that reads an exported file elsewhere depends&lt;br /&gt;
only on the file and on the checker.&lt;br /&gt;
&lt;br /&gt;
The checks do not answer the other question, whether the statement means what it is taken to&lt;br /&gt;
mean. The reference manual lists among the assumptions that remain even at its gold&lt;br /&gt;
standard: the soundness of Lean&amp;#039;s logic, the correctness of the tools and the sandbox, the&lt;br /&gt;
absence of a bug shared by all checkers, and a statement free of human error, with custom&lt;br /&gt;
notation and type classes named as places to look.&amp;lt;ref name=&amp;quot;rm-vp&amp;quot; /&amp;gt; That question is&lt;br /&gt;
taken up in [[Lean theorem prover/Explainers/Stating the right thing|stating the right thing]].&lt;br /&gt;
&lt;br /&gt;
== Next ==&lt;br /&gt;
&lt;br /&gt;
[[Lean theorem prover/System/Monads and do-notation|Monads and do-notation]] returns to Lean&lt;br /&gt;
as a programming language.&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>PMA Publisher</name></author>
	</entry>
</feed>