---
title: CHARON/AENEAS Rust Verification Pipeline
url: https://www.emergentmind.com/topics/charon-aeneas-pipeline
type: topic
---

# CHARON/AENEAS Rust Verification Pipeline

The CHARON/AENEAS pipeline is an integrated verification and program analysis framework addressing the extraction and verification of Rust code through the coupling of explicit semantic extraction (via CHARON) with higher-order functional translation and proof obligation discharge (via AENEAS). The pipeline is central to recent advances in Rust verification, supporting annotation-free, machine-checked equivalence reasoning for nontrivial transformations, particularly extract-function refactorings within REM2.0 and beyond [2410.18042][2601.19207].

## 1. Architectural Overview

The CHARON/AENEAS pipeline consists of two main stages. CHARON acts at the compiler interface level, intercepting compilation via custom driver hooks and harvesting a fully-resolved intermediate representation (IR) from Rust's Mid-level Intermediate Representation (MIR). AENEAS consumes this IR, converting program fragments into pure, functional definitions in theorem provers such as Coq, F*, Lean, or HOL4.

The canonical workflow is as follows:

1. The user invokes verification via the CHARON CLI:
   ```
   $ charon verify --tool=aeneas /path/to/crate
   ```
2. CHARON wraps cargo by redirecting RUSTC invocations to charon-driver, which employs rustc callbacks to extract IR just before code generation.
3. CHARON constructs two IRs: ULLBC (Unstructured Low-Level Borrow Calculus, a decorated control-flow graph) and LLBC (Low-Level Borrow Calculus, a structured AST).
4. IRs are serialized as JSON (.ullbc/.llbc).
5. AENEAS imports LLBC, applies symbolic execution, functional translation, and proof-condition extraction.
6. The output comprises pure logical definitions and proof obligations, which are discharged by SMT solvers or interactive theorem provers [2410.18042].

In REM2.0, this pipeline is integrated into a VSCode/JSON-RPC-based daemon, supporting rapid extract-function refactoring and optional equivalence verification using minimal "virtual crates" [2601.19207].

## 2. Intermediate Representations

A central contribution is the explicit separation and formalization of program IRs suitable for analysis:

- **Def-IDs and Name Resolution:** CHARON refines rustc's undifferentiated DefId with strongly-typed IDs (FunctionId, StructId, TraitId, etc.) carrying fully qualified, human-readable paths.
- **ULLBC (Unstructured LLBC):** Represents the Rust program as a typified CFG with instructions such as Assign, Drop, Assertion, and control terms (Goto, Switch, Return). All type and trait resolution is performed, yielding monomorphic call targets; constants are reified as ASTs.
- **LLBC (Structured LLBC):** Reconstructs a block-nested, gotoless AST from ULLBC using demand-set analysis, natural loop detection, and control-flow translation. Covers all MIR patterns and preserves original Rust scoping [2410.18042].

Table: CHARON/AENEAS IR Properties

| IR        | Structure   | Key Features                                              |
|-----------|-------------|----------------------------------------------------------|
| ULLBC     | CFG         | Full type/trait resolution, explicit borrows/moves       |
| LLBC      | AST         | No gotos, pure let/if/while/match, scoping as in Rust    |

## 3. Pipeline Stages and Translation Process

The end-to-end translation comprises the following stages [2410.18042][2601.19207]:

1. **Extraction and Repair:** For REM, Rust-Analyzer hoists user-selected code, inferring parameters/types; a "repairer" iteratively fixes lifetimes and signatures until the code type-checks.
2. **Virtual Crate Construction:** Minimal Cargo projects are constructed for both original and refactored versions to isolate input for CHARON.
3. **CHARON (Rust → LLBC):** Converts Rust code post-MIR optimization to ULLBC and LLBC, exposing explicit borrows, lifetime tracking, and normalized trait resolution.
4. **AENEAS (LLBC → Theorem Prover Language):** Interprets LLBC functionally, abstracting stack/heap effects away, handling borrow regions as pure value-passing, and emits pure functional definitions.
5. **Proof Obligation Emission:** AENEAS generates verification conditions (VCs) as SMT2 or proof assistant scripts (e.g., Coq, F*, Lean).

Example: The LLBC for a simple increment function with pre/postconditions will serialize a structured AST, which AENEAS translates to logical definitions and VCs, then emits proof scripts that can be dispatched to Z3, Coq, etc. [2410.18042].

## 4. Verification Methodology

AENEAS employs symbolic execution, region abstraction, and weakest-precondition (WP) generation over LLBC to produce logical VCs:

- For each function, logical variables are introduced for all relevant program entities (parameters, locals, borrow regions).
- The system maintains a symbolic state $\sigma=(V, B)$, mapping variables to immutable values and tracking live borrows with invariants.
- Each kind of statement (let, if, match, call) generates explicit WP formulas on paths; function calls are abstracted via pre/postregion contracts.
- Proof obligations emerge as universally quantifed formulas, over input variables and regions, to be checked externally.

Classic WP rules in LaTeX:

\[
\inference[\textsc{WP-Let}]
  {Q[x \mapsto e]\ =\ Q'}
  {\mathit{wp}(\texttt{let }x=e;\,S, Q) = \mathit{wp}(S,\,Q')}
\]

\[
\inference[\textsc{WP-If}]
  {\mathit{wp}(S_t, Q)\;=\;R_t \quad \mathit{wp}(S_f, Q)\;=\;R_f}
  {\mathit{wp}(\texttt{if }c\ S_t\ \texttt{else}\ S_f,\,Q) =
    (c\Rightarrow R_t) \land (\neg c\Rightarrow R_f)}
\]

Equivalence proofs require extraction of both original and refactored definitions, translation to Coq, and generation of the lemma:

\[
\texttt{Theorem extract\_equiv : }
  \forall x{:}\tau.\; f_{\mathrm{orig}}^{\mathrm{coq}}(x)=f_{\mathrm{refact}}^{\mathrm{coq}}(x)
\]

In most purely functional cases, Coq's `reflexivity` suffices; unsound or non-equivalent transformations result in proof failure at this stage [2601.19207].

## 5. Applications: Verification and Refactoring

A primary application domain is machine-checked equivalence verification for extract-function refactorings. REM2.0 leverages the pipeline to provide interactive, annotation-free proof of behaviour preservation after automated code transformations.

The process sequence is as follows [2601.19207]:

1. Code extraction and refactoring in the editor.
2. Automatic fixing of type and lifetime signatures until type checking succeeds.
3. Generation of minimal proof artifacts (virtual crates).
4. CHARON/AENEAS translation to Coq.
5. Automated proof obligation discharge, surfacing results to the user for accept/rollback.

This has enabled fast (generally sub-2s for small examples, ~4s for more substantial cases) equivalence checking for a substantial Rust subset (safe, sequential code with trait bounds but without closures, dynamic dispatch, or `unsafe`). Deliberately incorrect refactorings correctly yield failed proof obligations, ensuring no false positives.

Other applications demonstrated include Rust verification frameworks, taint checkers, and cross-language translation tools that harness the intermediate LLBC/ULLBC representations [2410.18042].

## 6. APIs, Extensibility, and Engineering

The pipeline's extensibility arises from explicit, stable IRs, open APIs, and customizable cleanup/analysis passes [2410.18042]:

- **APIs** expose Rust data structures for IR manipulation (e.g., `pub struct ULLBCFunction`, `Instr`, `Expr`, etc.).
- **Extensibility hooks** permit the registration of custom passes (`charon::PassManager::add_pass`), as well as pattern-matching for trait instances.
- **Language bindings:** LLBC/ULLBC can be parsed and manipulated from Rust, OCaml, and other host languages.

Workflow scripts and pseudocode are provided for typical usage patterns: parsing LLBC, symbolic execution over statement lists, VC accumulation, and downstream emission of backend-prover scripts.

## 7. Empirical Results and Limitations

Empirical evaluation demonstrates the pipeline's practicality and reliability:

- End-to-end verification over nontrivial Rust crates (20KLOC): ~80s for CHARON extraction, 2–5s for AENEAS/VC generation, <50ms per function for SMT discharge (batch), ~90s for full translation of a 200-function crate [2410.18042].
- REM2.0 benchmarks: For 20 verification cases (10 trivial, 10 real-world), all trivial and 90% real-world cases proved equivalence under 10s wall-clock time. No false positives were observed; explicit support and rejection for non-supported constructs prevent unsound proofs [2601.19207].
- The supported Rust subset intentionally omits interior mutability, closures, concurrency, unsafe code, and advanced generics (e.g., nested for<’a> patterns). Ongoing work aims to lift these restrictions.

A plausible implication is that further expansion of CHARON/AENEAS to richer fragments of Rust may incrementally generalize automated verification for the language, driven by the stability and invertibility of the intermediate representations.

---

**References:**  
- "Charon: An Analysis Framework for Rust" [2410.18042]  
- "Refactoring and Equivalence in Rust: Expanding the REM Toolchain with a Novel Approach to Automated Equivalence Proofs" [2601.19207]

Source: https://www.emergentmind.com/topics/charon-aeneas-pipeline