-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
doc(book): architecture of hax #1120
base: main
Are you sure you want to change the base?
Changes from all commits
bb3d431
04d7599
55b17d9
fd4aefa
afff4b3
65c586f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# Architecture | ||
|
||
Hax is a software pipeline designed to transform Rust code into various formal verification backends such as **F\***, **Coq**, **ProVerif**, and **EasyCrypt**. It comprises two main components: | ||
|
||
1. **The Frontend** (written in Rust) | ||
2. **The Engine** (written in OCaml) | ||
|
||
The frontend hooks into the Rust compiler, producing a abstract syntax tree for a given crate. The engine then takes this AST in input, applies various transformation, to reach in the end the language of the backend: F*, Coq... | ||
|
||
## The Frontend (Rust) | ||
|
||
The frontend is responsible for extracting and exporting Rust code's abstract syntax trees (ASTs) in a format suitable for processing by the engine (or by other tools). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You start describing pieces below without putting them into relation. The section up here should tell what's coming and how they are related. The same goes for the top level section. It should also contain what's public things and what are internal things. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added a paragraph just before "The Frontend" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, I don't see a new paragraph here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, messed up with the history, I re-commited, that's commit afff4b3 now |
||
|
||
### [`hax-frontend-exporter` Library](https://hacspec.org/hax/frontend/hax_frontend_exporter/index.html) | ||
|
||
This library mirrors the internal types of the Rust compiler (`rustc`) that constitute the **HIR** (High-Level Intermediate Representation), **THIR** (Typed High-Level Intermediate Representation), and **MIR** (Mid-Level Intermediate Representation) ASTs. It extends them with additional information such as attributes, trait implementations, and removes ID indirections. | ||
|
||
**`SInto` Trait:** The library defines an entry point for translating a given `rustc` value to its mirrored hax version using the [`SInto`](https://hacspec.org/hax/frontend/hax_frontend_exporter/trait.SInto.html) trait (stateful `into`). For a value `x` of type `T` from `rustc`, if `T` is mirrored by hax, then `x.sinto(s)` produces an augmented and simplified "hax-ified" AST for `x`. Here, `s` represents the state holding information about the translation process. | ||
|
||
### `hax-driver` Binary | ||
|
||
`hax-driver` is a custom Rust compiler driver that behaves like `rustc` but performs additional tasks: | ||
|
||
1. **Item Enumeration:** Lists all items in a crate. | ||
2. **AST Transformation:** Applies `sinto` on each item to generate the hax-ified AST. | ||
3. **Output Generation:** Outputs the mirrored items into a `haxmeta` file within the `target` directory. | ||
|
||
### `cargo-hax` Binary | ||
|
||
`cargo-hax` provides a `hax` subcommand for Cargo, accessible via `cargo hax --help`. It serves as the command-line interface for hax, orchestrating both the frontend and the engine. | ||
|
||
**Workflow:** | ||
|
||
1. **Custom Build Execution:** Runs `cargo build`, instructing Cargo to use `hax-driver` instead of `rustc`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This kind of description is great but we should make sure that it doesn't go out of date when changes are done. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, but I don't see how we could enforce that here (since it's a structural description) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a process question. I'll add this to the new processes we are implementing. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Makes sense. So nothing to do in this PR, right? Let's resolve if we agree on this being "future work" (outside of this PR) |
||
2. **Multiple Compiler Invocations:** `cargo build` invokes `hax-driver` multiple times with various options. | ||
3. **Inter-Process Communication:** `hax-driver` communicates with `cargo-hax` via `stderr` using JSON lines. | ||
4. **Metadata Generation:** Produces `haxmeta` files containing the transformed ASTs. | ||
5. **Engine Invocation (Optional):** If requested, runs the engine, passing options and `haxmeta` information via `stdin` serialized as JSON. | ||
6. **Interactive Communication:** Engages in interactive communication with the engine. | ||
7. **User Reporting:** Outputs results and diagnostics to the user. | ||
|
||
## The Engine (OCaml - [documentation](https://hacspec.org/hax/engine/hax-engine/index.html)) | ||
|
||
The engine processes the transformed ASTs and options provided via JSON input from `stdin`. It performs several key functions to convert the hax-ified Rust code into the target backend language. | ||
|
||
### Importing and Simplifying ASTs | ||
|
||
- **AST Importation:** Imports the hax-ified Rust THIR AST. This is module [`Import_thir`](https://hacspec.org/hax/engine/hax-engine/Hax_engine/Import_thir/index.html). | ||
- **Internal AST Conversion:** Converts the imported AST into a simplified and opinionated internal AST designed for ease of transformation and analysis. This is mostly the functor [`Ast.Make`](https://hacspec.org/hax/engine/hax-engine/Hax_engine/Ast/Make/index.html). | ||
|
||
### Internal AST and Features | ||
|
||
The internal AST is defined using a **functor** that takes a list of type-level booleans, referred to as **features**, and produces the AST types accordingly. | ||
|
||
Features are for instances, mutation, loops, unsafe code. The enumeration [`Features.Enumeration`](https://hacspec.org/hax/engine/hax-engine/Hax_engine/Features/Enumeration/index.html) lists all those features. | ||
|
||
**Feature Witnesses:** On relevant AST nodes, feature witnesses are included to enforce constraints at the type level. For example, in the `loop` expression constructor, a witness of type `F.loop` is used, where `F` represents the current feature set. If `F.loop` is an empty type, constructing a `loop` expression is prohibited, ensuring that loops are disallowed in contexts where they are not supported. | ||
|
||
### Transformation Phases | ||
|
||
The engine executes a sequence of **phases**, which are determined based on the target backend. Each phase: | ||
|
||
1. **Input:** Takes a list of items from an AST with specific feature constraints. | ||
2. **Output:** Transforms these items into a new AST type, potentially enabling or disabling features through type-level changes. | ||
|
||
The phases can be found in the [`Phases`](https://hacspec.org/hax/engine/hax-engine/Hax_engine/Phases/index.html) module. | ||
|
||
### Backend Code Generation | ||
|
||
After completing the transformation phases: | ||
|
||
1. **Backend Printer Invocation:** Calls the printer associated with the selected backend to generate the target code. | ||
2. **File Map Creation:** Produces a map from file names to their contents, representing the generated code. | ||
3. **Output Serialization:** Outputs the file map and additional information (e.g., errors) as JSON to `stderr`. | ||
|
||
### Communication Protocol | ||
|
||
The engine communicates asynchronously with the frontend using a protocol defined in [`hax_types::engine_api::protocol`](https://hacspec.org/hax/frontend/hax_types/engine_api/protocol/index.html). This communication includes: | ||
|
||
- **Diagnostic Data:** Sending error messages, warnings, and other diagnostics. | ||
- **Profiling Information:** Providing performance metrics and profiling data. | ||
- **Pretty-Printing Requests:** Requesting formatted versions of Rust source code or diagnostics for better readability. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So far there has always been a distinction between the engine and the backends. Do you intend to drop that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think we should drop that.
For me, the engine contains the backends.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a bigger change than just this document. We are using three parts everywhere so far, including your blog post. And I'm not sure I agree with dropping it. There should be a distinction between transformations and printing. Not doing that just mushes everything into one big module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmh, I see what you mean, but in terms of software architecture, the engine does contain the backends. So, in this architecture document, I think we should not see backends as an artifact outside of the engine. Maybe I can detail that the engine is composed of a library (the phases, the AST),
n
backends, and a binary that wraps everything together?I could also add a small diagram for the whole architecture. That'd make things very clear.
WDYT?