<p><div style="text-align: center">
<img src="static/Aeneas.jpg"
     alt="Iapyx removing arrowhead from Aeneas" title="Iapyx removing arrowhead from Aeneas"
     style=""/>
<figcaption>
Unknown author, <i>Iapyx removing arrowhead from Aeneas</i> [Fresco].
Wall in Pompei, digital image from Michael Lahanis.
<a href="https://commons.wikimedia.org/w/index.php?curid=1357010">Source</a>
</figcaption>
</div></p>

# Aeneas

Aeneas (pronunced [Eh-nee-as]) is a verification toolchain for Rust programs.  It relies on a translation from Rust's MIR
internal language to a pure lambda calculus.  It is intended to be used in combination with
[Charon](https://github.com/AeneasVerif/charon), which compiles Rust programs to an intermediate
representation called LLBC. It currently has backends for [F\*](https://www.fstar-lang.org),
[Coq](https://coq.inria.fr/), [HOL4](https://hol-theorem-prover.org/) and [LEAN](https://leanprover.github.io/).

If you want to contribute or ask questions, we strongly encourage you to join the
[Zulip](https://aeneas-verif.zulipchat.com/). In particular, we welcome external
contributions but ask contributors to engage with us before making deep modifications of
the code or implementing non trivial features, as these require in-depth design
discussions and careful reviews. If you want to contribute a new feature you should either
discuss it on the Zulip or open the corresponding issue on github.

## Project Structure

- `src`: the OCaml sources. Note that we rely on [Dune](https://github.com/ocaml/dune)
  to build the project.
- `backends`: standard libraries for the existing backends (definitions for
   arithmetic operations, for standard collections like vectors, theorems, tactics, etc.)
- `tests`: files generated by applying Aeneas on some of the test files of Charon,
  completed with hand-written files (proof scripts, mostly).

## Installation & Build

You need to install OCaml, together with some packages.

We suggest you to follow those [instructions](https://ocaml.org/docs/install.html),
and install OPAM on the way (same instructions).

We are developing Aeneas by using **OCaml 5**. For instance, if you want to use OCaml 5.3.0:
```
opam switch create 5.3.0
```

You can then install the dependencies with the following command:
```
opam install calendar core_unix domainslib easy_logging menhir \
  ocamlformat.0.27.0 ocamlgraph odoc ppx_deriving ppx_deriving_yojson \
  progress unionFind visitors yojson zarith
```

Moreover, Aeneas uses the [Charon](https://github.com/AeneasVerif/charon) project and library.
For Aeneas to work, `./charon` must contain a clone of the [Charon](https://github.com/AeneasVerif/charon)
repository, at the commit specified in `./charon-pin`.  The easiest way to set this up is to call
`make setup-charon`
(this uses either [rustup](https://rustup.rs/) or [nix](https://nixos.org/download/) to build Charon, depending on which one is installed).
In case of version mismatch, you will be instructed to update Charon.

If you're also developing on Charon, you can instead set up `./charon` to be a symlink to your local version:
`ln -s PATH_TO_CHARON_REPO charon`. In this case, the scripts will not check that your Charon
installation is on a compatible commit. When you pull a new version of Aeneas, you will occasionally
need to update your Charon repository so that Aeneas builds and runs correctly.

Finally, building the project simply requires running `make` in the top
directory.

You can also use `make test` and `make verify` to run the tests, and check
the generated files. As `make test` will run tests which use the Charon tests,
you will need to regenerate the `.llbc` files. To do this, run `make setup-charon` before `make
test`. Alternatively, call `REGEN_LLBC=1 make test-...` to regenerate only the needed files.

## Documentation

If you run `make`, you will generate a documentation accessible from [`doc.html`](./doc.html).

Additionally, a tutorial for using the Aeneas Lean backend is available [here](./tests/lean/Tutorial/); the original Rust file can be found [here](./tests/src/tutorial/src/lib.rs).
It requires a working installation of Lean.

## Usage

You should first generate the serialized `.llbc` file by calling Charon from *inside*
(similarly to cargo) the crate you want to translate. **Important:** you should call
Charon with the following option:
```bash
charon cargo --preset=aeneas
```

The Aeneas binary is in `bin`; you can run: `./bin/aeneas -backend {fstar|coq|lean|hol4} [OPTIONS] LLBC_FILE`,
where `LLBC_FILE` is an .llbc file generated by Charon.

Aeneas provides a lot of flags and options to tweak its behaviour: you can use `--help`
to display a detailed documentation.

> [!IMPORTANT]
> There are additional steps for the Lean backend. Files generated by the Lean backend
> import the `Aeneas` package from Aeneas. To use those files in Lean:
>  1. Create a new Lean package using `lake new`.
>  2. Overwrite the `lean-toolchain` with the one inside `./backends/lean`.
>  3. Add `aeneas` as a dependency in the `lakefile.lean`:
>     ```lean
>     require aeneas from "PATH_TO_AENEAS_REPO/backends/lean"
>     ```
>     or in the `lakefile.toml`:
>     ```toml
>     [[require]]
>     name = "aeneas"
>     path = "PATH_TO_AENEAS_REPO/backends/lean"
>     ```
>     If you don't have Aeneas cloned locally, you can specify the dependency using
>     the GitHub repository. If you opt for this method, consider adding a specific
>     commit hash to ensure that future updates do not break your project.
>     ```toml
>     [[require]]
>     name = "aeneas"
>     git = { url = "https://github.com/AeneasVerif/aeneas", subDir = "backends/lean" }
>     rev = "COMMIT_HASH_HERE"
>     ```

## Targeted Subset And Current Limitations

Aeneas currently functionalizes a subset of safe Rust, and we are in the process
of extending the functional model with reasoning based on separation logic to
support unsafe code and concurrent code.

We currently have the following limitations on the *safe* subset, that we plan to address
one by one:
- **loops**: `return` inside *nested* loops, or `break`/`continue` to *outer* loops
  are not supported yet (e.g., `'a : loop { loop { break 'a; } } `). This is a
  technical limitation, not a fundamental issue, that we plan to address in the
  near future and that we can prioritize depending on our users' needs.

The following limitations will be lifted by the ongoing work on separation logic:
- **unsafe code**
- **concurrency**

Feel free to contact the team or join the Zulip if you need some specific features or if
you're interested in contributing.

## Backend Support

We currently support F\*, Coq, HOL4 and Lean. We would be interested in having an Isabelle
backend. Our most mature backends are Lean and HOL4, for which we have in particular
support for partial functions and extrinsic proofs of termination (see
`./backends/lean/Base/Diverge/Elab.lean` and `./backends/hol4/divDefLib.sig` for instance)
and tactics specialized for monadic programs (see
`./backends/lean/Base/Progress/Progress.lean` and `./backends/hol4/primitivesLib.sml`).

## Adding Models of Rust Definitions to the Lean Backend

When translating a crate which requires external definitions (i.e., definitions
coming from external dependencies such as the Rust standard library), we advise using the
`-split-files` option. With `-split-files`, Aeneas will generate template files listing
the missing definitions for which the user will have to provide hand-written models.
For instance, it can lead to the following structure in Lean:
```
... // Files containing type definitions, etc.
FunsExternal_Template.lean // automatically generated template file
FunsExternal.lean // hand-written file maintained by the user (not overwritten during the translation)
Funs.lean // automatically generated file which imports FunsExternal.lean
```

Rather than adding models to the `TypesExternal.lean`, `FunsExternal.lean`, etc. files it
is possible to port the models to the Aeneas standard library, so that all client projects
can benefit from them. When doing so, it is important to make Aeneas aware of those new
models. This is done by annotating the Lean models with the appropriate attribute
(`rust_type`, `rust_const`, `rust_fun`, `rust_trait` or `rust_trait_impl`) then running the
command `make extract-lean-std`. This command will build the Lean library for Aeneas,
collect those definitions, and regenerate the `src/extract/ExtractBuiltinLean.ml` file,
which provides information about those models.

Note that Aeneas automatically introduces the `rust_type`, etc. attributes when
listing the missing external definitions in the `TypesExternal.lean`, etc. files:
the user just needs to copy/paste those definitions and fill in the holes. Also note that
those attributes have quite a few options to tweak the behavior of the extraction: we
invite the users to read their docstrings for more information.

## Quick start for Nix users

Assuming Nix is installed, with a support for Flakes (`*`):

```console
$ # Run Charon with the exact same version required by Aeneas
$ nix run github:aeneasverif/aeneas#charon -L
$ nix run github:aeneasverif/aeneas -L -- -backend your_preferred_backend your_llbc.file
```

To regenerate the extraction, just run step 2 and step 3 again.

`(*)` : Flakes are not necessary, here is an example of how to do similar steps without it:

```console
$ nix-shell '<aeneas>' -A packages.x86_64-linux.charon --run "charon" -I aeneas=https://github.com/AeneasVerif/aeneas/archive/main.tar.gz
$ nix-shell '<aeneas>' -A packages.x86_64-linux.default --run "aeneas --backend your_preferred_backend your_llbc.file" -I aeneas=https://github.com/AeneasVerif/aeneas/archive/main.tar.gz
```

## Formalization

The translation has been formalized and published at ICFP2022: [Aeneas: Rust
verification by functional
translation](https://dl.acm.org/doi/abs/10.1145/3547647)
([long version](https://arxiv.org/abs/2206.07185)). We also have a proof that
the symbolic execution performed by Aeneas during its translation correctly
implements a borrow checker, and published it at ICFP 2024: [Sound Borrow-Checking for Rust via Symbolic Semantics](https://dl.acm.org/doi/10.1145/3674640) ([long version](https://arxiv.org/abs/2404.02680)).
