Crush: Extensible Proof Automation for Lean
Summary (Overview)
- Crush is an extensible SMT-backed proof automation framework for the Lean proof assistant that bridges the gap between Lean's higher-order, polymorphic logic and first-order SMT solvers.
- The framework employs defunctionalization to encode higher-order functions (including lambdas, partial applications, and function-valued arguments) into first-order SMT logic, with a mechanized soundness proof in Lean itself.
- Crush provides extensible translation interfaces (head-indexed and type-indexed rewrite rules) allowing users to customize how Lean types, functions, and operators are encoded to SMT without modifying the core translator.
- It supports two proof reconstruction paths: unsat core-guided search using native Lean tactics, and full replay of solver inference steps (Alethe format) via extensible rewrite rules.
- In evaluation across 754 verification conditions from four benchmark suites (Curated, Cashmere, Velvet, PLean), crush discharges 709 VCs (94.0%) when trusting the solver and 693 (91.9%) with kernel-checked proofs, outperforming all baselines including auto (82.5%), grind (85.0%), lean-smt, and Duper.
Introduction and Theoretical Foundation
Background and Motivation
The paper addresses the integration of automated theorem provers (ATPs) with proof assistants (PAs). While PAs like Lean, Rocq, Isabelle/HOL, and Agda provide rich type systems supporting higher-order and polymorphic constructs, ATPs like Z3, CVC5, and E-Prover offer powerful automation but support less expressive (typically first-order) logics.
The two main challenges in this integration are:
- Translation (ITP → ATP): Translating expressive proof obligations (with polymorphism, higher-order functions, user-defined abstractions) into the solver's first-order logic.
- Proof Reconstruction (ATP → ITP): Reconstructing kernel-checkable proofs from solver certificates (unsat cores or proof scripts).
Limitations of Existing Approaches
The paper highlights key gaps in existing tools for Lean:
- lean-auto: Supports polymorphism but lacks higher-order function support, custom encodings, and proof reconstruction.
- LeanHammer: Supports higher-order functions but lacks extensible encodings and replay.
- lean-smt: Supports extensible encodings and replay but not higher-order functions.
- grind and aesop: Native Lean tactics with good proof production but limited to internal decision procedures.
Table 1 (from paper): Qualitative comparison of goal translation and proof reconstruction.
| ITP | Tool | Poly. | HO | Ext. encoding | Core-guided | Replay |
|---|---|---|---|---|---|---|
| Isabelle/HOL | smt | ✓ | ✓ | ✓ | × | ✓ |
| Rocq | SMTCoq | × | × | ✓ | × | ✓ |
| Rocq | CoqHammer | ✓ | ✓ | × | ✓ | × |
| Lean | lean-auto | ✓ | × | × | × | × |
| Lean | LeanHammer | ✓ | ✓ | × | ✓ | × |
| Lean | lean-smt | ✓ | × | ✓ | × | ✓ |
| Lean | crush | ✓ | ✓ | ✓ | ✓ | ✓ |
Methodology
3. Extensible Lean-to-SMT Translation
Crush provides two mechanisms for translating Lean terms into SMT:
3.1 Definition Unfolding
The @[crush_unfold] attribute exposes defining equations of functions to the SMT query. For example:
@[crush_unfold]
def clamp (x lo hi : Int) : Int :=
if x < lo then lo
else if hi < x then hi else x
theorem clamp_bounds (x lo hi : Int) (h : lo ≤ hi) :
lo ≤ clamp x lo hi ∧ clamp x lo hi ≤ hi := by
crush
3.2 Head- and Type-Indexed Term Translation
Let denote the SMT term produced from a Lean expression , and denote the SMT sort used to represent a Lean type .
-
Head-indexed translation: Rewrite rules matching the head symbol of an application. E.g., for the NAND function:
-
Type-indexed translation: Rewrites grouped by type, e.g., handling both
Bool.notandBool.xorunder aBooltype pattern.
3.3 Coordinating Sort and Term Translation
Users can define rewrite rules over type applications to encode custom Lean types. For example, TotalMap κ ν can be encoded as SMT Array sort, with get → select and set → store. Crush performs light-weight sort checking on emitted queries to catch incompatible sort/term translations.
4. Higher-Order Translation via Defunctionalization
4.1 Defunctionalization
For a nondependent function type (where is not a function type), crush introduces:
- An uninterpreted sort for function values.
- An application symbol with signature:
Lambdas and captured variables: For each lambda , a fresh uninterpreted symbol is introduced, with axiom:
where are captured variables.
Partial application: η-expansion transforms partial applications into closures. Function equality: Extensionality axioms are emitted when comparing function values. Guarded subtypes (e.g., Nat within Int) are represented with guards like .
4.2 Soundness of Defunctionalization
The paper formalizes higher-order (HO) and first-order (FO) languages with denotational semantics (Fig. 8), then proves:
Theorem 1 (Soundness): For every finite collection of closed higher-order formulas, if is unsatisfiable, then is unsatisfiable.
Key definitions include:
- Defunctionalization where are closure equations and are extensionality axioms.
- First-order encoding:
The proof uses a canonical model extension interpreting Fn sorts as function spaces:
5. Proof Reconstruction
Crush supports two reconstruction approaches:
5.1 Core-Guided Reconstruction
- Maps unsat core assertions back to Lean hypotheses
- Searches for proofs using native Lean tactics (e.g.,
omega,grind) - Extensible via
@[crush_reconstruct]theorem hints
5.2 Extensible Solver Inference Replay
- Replays Alethe proof scripts from SMT solvers
register_crush_replay term: maps SMT operators to Lean terms (type-checked by kernel)register_crush_replay rule: translates solver inference steps to Lean proofs
Example: handling bv-not-idemp rule using BitVec.not_not lemma:
Empirical Validation / Results
6. Evaluation Setup
- 754 VCs across four suites: Curated (20), Cashmere (38), Velvet (504), PLean (192)
- Baselines: lean-auto (auto), Duper, lean-smt, Grind
- Hardware: Apple M1 Pro, 32 GB RAM
- Solver: CVC5 1.3.4
- Limits: 5s per solver call, 1M Lean heartbeats per tactic
6.1 Verification Coverage
| Method | VCs Discharged | Percentage |
|---|---|---|
| crush (trusted) | 709 | 94.0% |
| crush (kernel-checked) | 693 | 91.9% |
| grind | 641 | 85.0% |
| auto | 622 | 82.5% |
| lean-smt | 431 | 57.2% |
| Duper | 413 | 54.8% |
Crush achieves the highest overall coverage even with kernel-checked proofs required. Runtime curves show a tradeoff: grind is faster on many VCs but crush achieves higher overall coverage.
6.2 Pairwise Comparison
Table 2 (from paper): Head-to-head comparison with crush using proof reconstruction.
| Benchmark | Baseline | crush only | Baseline only | Both |
|---|---|---|---|---|
| Curated (20) | auto | 2 | 0 | 17 |
| Curated | Duper | 8 | 1 | 11 |
| Curated | lean-smt | 7 | 0 | 12 |
| Curated | grind | 3 | 0 | 16 |
| Cashmere (38) | auto | 20 | 0 | 18 |
| Cashmere | Duper | 17 | 0 | 21 |
| Cashmere | lean-smt | 21 | 0 | 17 |
| Cashmere | grind | 19 | 0 | 19 |
| Velvet (504) | auto | 70 | 13 | 402 |
| Velvet | Duper | 184 | 3 | 288 |
| Velvet | lean-smt | 180 | 10 | 292 |
| Velvet | grind | 37 | 9 | 435 |
| PLean (192) | auto | 2 | 10 | 162 |
| PLean | Duper | 75 | 0 | 89 |
| PLean | lean-smt | 65 | 1 | 99 |
| PLean | grind | 2 | 0 | 162 |
Crush discharges more VCs in all pairs except against auto on PLean (2 vs. 10).
6.3 Proof Reconstruction Analysis
Table 3 (from paper): Proof reconstruction failures among 503 VCs discharged by SMT.
| Method | Failure mode | VCs |
|---|---|---|
| Alethe replay alone | Certificate generation | 431 |
| Term decoding | 1 | |
| Total | 432/503 | |
| Combined | Certificate generation + core-guided failure | 11 |
| Lean heartbeat limit | 2 | |
| Tactic failure during replay | 3 | |
| Total | 16/503 |
Key finding: Adding core-guided reconstruction enables crush to close many more VCs (693 vs. 241 with Alethe replay alone, vs. 431 for lean-smt). The main limitation is that CVC5 cannot generate Alethe proofs for all theories (particularly arrays).
Table 4 (from paper): Implementation size of built-in Alethe replay extensions.
| Category | Handlers | Handler LoC | Lemma LoC | Total |
|---|---|---|---|---|
| Assumption normalization | 2 | 16 | 34 | 50 |
| Logic and equality | 10 | 47 | 10 | 57 |
| Quantifiers | 1 | 3 | 22 | 25 |
| Arithmetic | 17 | 68 | 311 | 379 |
| Bitvectors | 13 | 72 | 337 | 409 |
| Strings | 12 | 50 | 83 | 133 |
| Total | 55 | 256 | 797 | 1,053 |
Theoretical and Practical Implications
Theoretical Contributions
-
Mechanized soundness proof: Unlike tools like CoqHammer that have informal soundness arguments with known approximation issues, crush formally proves the soundness of its defunctionalization pass in Lean itself, providing strong correctness guarantees.
-
First-class treatment of higher-order functions: The defunctionalization approach with explicit application symbols, closure axioms, and extensionality provides a principled bridge between higher-order and first-order logic.
-
Extensible architecture: The pattern-based translation and replay interfaces separate the core pipeline from user extensions, allowing customization without compromising the core's soundness.
Practical Implications
-
Improved verification coverage: Crush discharges 94.0% of VCs (91.9% with proofs), significantly outperforming native tactics (grind: 85.0%) and existing SMT integrations (lean-smt: 57.2%, Duper: 54.8%).
-
Kernel-level trust: All reconstructed proofs are independently checked by the Lean kernel, maintaining the highest level of trustworthiness.
-
Low implementation overhead for extensions: The replay library required only 1,053 LoC for 55 handlers covering six theory categories, demonstrating the practicality of the extension interface.
-
Flexible integration: Crush works both as a standalone tactic and as a backend for third-party automation systems like Loom.
Conclusion
Main Takeaways
Crush successfully addresses the two main challenges of ATP-PA integration:
- Translation: Supports higher-order, polymorphic Lean constructs via defunctionalization with a mechanized soundness proof.
- Proof reconstruction: Combines unsat core-guided search with extensible Alethe proof replay for kernel-checked proofs.
The framework outperforms all baselines across diverse benchmark suites covering verification, distributed protocols, and general mathematics, achieving high coverage even when kernel-checked proofs are required.
Future Work
The authors identify several directions for future research:
- Dependent function types: Extending the supported fragment beyond nondependent higher-order constructs.
- Broader soundness formalization: Extending beyond defunctionalization to the full Lean-to-SMT-LIB translation.
- Additional proof integrations: Integrating tactics like Duper, supporting CPC certificates, and synthesizing non-emptiness proofs for choice expressions in solver certificates.
- Better SAT feedback: Distinguishing true vs. spurious counter-examples when the solver reports SAT.
Data Availability
The implementation, mechanized proofs, benchmark data, and reproduction scripts are publicly available at: https://github.com/AD1024/lean-crush/tree/tacas-ae
Related papers
- An upper bound of 61 for the Ramsey number $R(3,3,3,3)$
The paper proves every 4-coloring of K61 contains a monochromatic triangle, improving the Ramsey number R(3,3,3,3) upper bound from 62 to 61 via SAT solving and Lean verification.
- Iris in Lean
Iris-Lean fully reimplements Iris in Lean, outperforming Iris-Rocq in automation speed, and enabling probabilistic program verification via Mathlib integration.
- The set of primes is supernatural: a Lean formalization of the statement of the conjecture
This paper presents a complete Lean 4 formalization of "The Set of Primes is Supernatural," proving all 89 experimental table rows and all theorems except the central conjecture, which remains deliberately open.