Getting Started

Our artifact is provided as a VirtualBox VM, which can be launched using a standard installation of VirtualBox (tested with VirtualBox 6.1 on Mac and Ubuntu).

Using the VM

On most Linux distributions, VirtualBox is available as a package through standard tools apt-get, yum, etc..

On Mac, it is available through Homebrew. Recent versions of Apple computers (with Apple M1) introduce restrictions around Kernel Extensions (which VirtualBox uses), and may at present an error with code -1908. The extension must be allowed in the "Security & Privacy" pane of the settings.

Upon launching the VM you may be asked to log in, in which case, the username and password are:

username: vagrant
password: vagrant

Without the VM

If you have a non-x86 computer, you may need to compile our artifact from sources. Among the provided files is a tar containing all the code needed to build and verify our proofs and benchmarks. At the bottom of this document is a section titled "Building from Sources" with detailed instructions.

The rest of this document will assume that you are using the provided VM image.

Structure of the artifact

On the desktop is a folder the_artifact, inside of which are further directories:

  • The lambda_rust directory contains the Coq development for our mechanization.
  • The rhb_specs directory contains the code for all Creusot benchmarks of the RustHornBelt paper.
  • The creusot directory contains the code for Creusot, the tool used to generate proof obligations for rhb_specs. (This directory is not a contribution of the paper but is provided for reproducibility reasons.)

Also, the artifact contains the walkthroughs for Coq ( and for Creusot (

Navigating the Coq mechanization

The lambda_rust directory contains the Coq development for our mechanization. in lambda_rust has more information on it.

Provided in the VM is an installation of CoqIDE, which can be used to browse the Coq proof files (*.v). A shortcut is provided on the desktop to launch it.

The Coq walkthrough (in the_artifact) explains in detail how to verify integer addition, model Vec, verify Vec::new, and verify mem::swap (featuring mutable borrows). In particular, it focuses on the things you need to know in extending our Coq mechanization.

Navigating the Creusot benchmarks

The rhb_specs directory contains the code for all Creusot benchmarks of the RustHornBelt paper. These benchmarks are meant to demonstrate that specifications obtained from RustHornBelt are well adapted to usage with automated verifiers. A README file is provided with more information on the structure of the benchmarks.

The Creusot walkthrough (in the_artifact) explains verification of all_zero, featuring update through mutable borrows.

Our benchmarks are verified using the deductive verification tool Creusot. Creusot is based on the same prophetic model of mutable borrows as our formalization, making it well adapted as a benchmarking platform for our specifications. Creusot takes as input a Rust crate and outputs a single mlcfg file, containing the translation of the crate into the functional language WhyML. The benchmarks can then be verified using automated provers in Why3.

The compiled benchmarks are provided in the file ~/Desktop/rhb-specs/proofs.mlcfg, and the proof session in the accompanying folder ~/Desktop/rhb-specs/proofs.

The source of the benchmarks is provided in the src directory. We recommend src/ as a simple example to begin with.

The proofs can be browsed by launching the Why3IDE shortcut on the desktop.

Why3 primer

The left-hand pane contains the proof tree and can be expanded by clicking on the arrow next to each entry or by selecting an entry and hitting the '+' mark.

When an entry is selected, the right-hand pane will highlight relevant bits of the code. To view the actual proof context, select the Task tab in the right-hand pane.

A tutorial for Why3 can be found here:


By expanding the RhbSpecs_IncVec_IncVec node fully, we reveal a list of subentries, selecting one of the [integer overflow] entries and opening the Tasks tab should show something similar to:

goal inc_vec'vc : in_bounds5 (uint32'int ( * r_12) +' 5)

Step-by-Step Instructions

There are two key facets to verify within our artifact: the Coq proof of RustHornBelt showing that we proved our claims in section 3 and our benchmarks showing our specifications are adapted to automatic verification.

Our proposed method of evaluation would be:

  1. To verify our Coq proof by rebuilding it and checking it for assumptions (showing no sub-proofs are undone), along with verifying the presence and statement of key lemmas and theorems.
  2. To verify our benchmarks by rebuilding and reproving them, inspecting the specifications for correspondence to the Coq work, and inspecting the benchmarks to correctness.

Verifying our Coq mechanization

We make these specific claims regarding our Coq development:

  • Our Coq proof is complete and axiom-free.
  • Our Coq proof proves the central claims of our paper.
  • Our Coq formalization enables modeling Rust types and verifying Rust methods with a safe API using these types and with an implementation possibly depending on unsafe features.

We do not make the following claims:

  • As stated in our paper, we do not provide an automatic framework for reasoning about correctness within Coq.
  • Our proof development contains several FIXME statements inherited from RustBelt, limitations which we did not lift from prior work.

Rebuilding the proofs

To rebuild all the Coq proofs from scratch:

  1. Open a terminal
  2. Enter the ~/Desktop/lambda-rust directory
  3. Run eval $(opam env)
  4. Run make clean
  5. Run make

Location of key rules

The following table contains the location of every rule mentioned in our paper in the Coq development. The filenames are spread across theories/typing/examples, theories/typing, theories/typing/lib (and its subfolders), and theories/prophecy.

Proof Rule File Lemma
Adequacy soundness.v type_soundness
MUTBOR derived_rules.v ty_uniq_bor
MUTREF-WRITE derived_rules.v ty_uniq_ref_write
MUTREF-BYE derived_rules.v ty_uniq_ref_bye
ENDLFT programs.v type_endlft
PROPH-INTRO prophecy.v proph_intro
PROPH-FRACT prophecy.v proph_tok_fractional
PROPH-IMPL prophecy.v proph_obs_impl
PROPH-MERGE prophecy.v proph_obs_and
PROPH-TRUE prophecy.v proph_obs_true
PROPH-RESOLVE prophecy.v proph_resolve
PROPH-SAT prophecy.v proph_obs_sat
Mutable Borrows
MUT-AGREE uniq_cmra.v uniq_agree
MUT-UPDATE uniq_cmra.v uniq_update
MUT-INTRO uniq_cmra.v uniq_intro
MUT-RESOLVE uniq_cmra.v uniq_resolve
push vec_pushpop.v vec_push_type
pop vec_pushpop.v vec_pop_type
index_mut vec_index.v vec_index_uniq_type
iter_mut vec_slice.v vec_as_uniq_slice_type
next iter.v iter_uniq_next_type
inc_vec inc_vec.v inc_vec_type
new cell.v cell_new_type
get cell.v cell_get_type
set cell.v cell_set_type
inc_cell inc_cell.v inc_cell_type
new mutex.v mutex_new_type
get_mut mutex.v mutex_get_uniq
swap swap.v swap_type

Verifying our benchmarks

We make these specific claims regarding our benchmarks:

  • Our automatic benchmarks faithfully use specifications proven in Coq
  • Our benchmarks prove our examples automatically.

The non-claims:

  • The VM will not reproduce the performance of the benchmarks provided in the paper. We estimate approximately a 5x slowdown compared to our original measurements.
  • We do not claim the source of Creusot as a contribution of our work.

Our benchmarks are designed to provide evidence that the specifications derived from RustHornBelt are adapted to automatic verification. For this reason, we verify several examples using the semi-automatic tool Creusot, which internally is based on the RustHornBelt model. Creusot translates Rust code to "MLCFG", a functional language structured like a control-flow graph (CFG), which can then be fed into the tool Why3 and verified using off-the-shelf provers.

In the benchmarks we axiomatize specifications proved in Coq, and then verify example code using them. These axiomatizations can be found in the directory src/prelude of rhb-specs. The actual examples are found at the top level of src/. Their correspondence to the paper is detailed in the table below.

Rebuilding the benchmarks

To reproduce the proofs from scratch:

  1. Open a terminal
  2. Enter ~/Desktop/rhb-specs
  3. Execute make clean followed by make proofs. The resulting file should be approximately 3-4 thousand lines long.
  4. Use the Why3IDE shortcut to open the generated output in a fresh proof session.
  5. In the Why3 IDE, select the top entry in the left-hand pane and press 3 to run the 'Auto Level 3' strategy.

Verifying our specifications correspond to the Coq mechanization

The specifications used during automatic verification can be found in the files located in src/prelude/.

The following table shows the correspondence between the automatic and Coq specs.

Type Automatic Spec Coq Spec
Vec typing/lib/vec/\*.v
Mutex typing/lib/mutex/\*.v
Spawn typing/lib/spawn.v
Cell typing/lib/cell.v
IterMut typing/lib/slice/iter.v
Box typing/examples/unbox.v
Fn typing/function.v

Correspondence of examples to paper

The example benchmarks provided in the paper correspond to the code in the following files, within the src directory of rhb-specs.

Paper Name Rust File RHB Specs used
List-Reversal mem::swap
All-Zero Vec::len, Vec::index_mut
Go-IterMut Vec::iter_mut, IterMut::next
Even-Cell Cell::get, Cell::set
Fib-Memo-Cell Vec::index, Cell::get, Cell::set
Even-Mutex thread::spawn, JoinHandle::join, Mutex::lock, Mutex::new, (Box::leak)
Knights-Tour Vec::push, Vec::index, Vec::index_mut, Vec::len

"Paper Name": the name given to the function in the paper. "Rust File": the Rust file containing the benchmark equivalent. "RHB Specs": which functions are used with RustHornBelt proven specifications.

Building from Sources

For those who either cannot or prefer not to use the virtual machine, we also provide instructions on how to build and verify our proofs and benchmarks.

Within the provided archive, there are three folders:

  • lambda-rust containing our Coq development
  • creusot containing the Rust sources to Creusot
  • rhb-specs containing the benchmarks for our paper

Building the Coq proofs

  1. Install gmp using your system package manager.
  2. Install opam using your system package manager.
  3. Initialize opam by running opam init.
  4. Create a local 'opam switch' inside the lambda-rust directory by running opam switch create . and eval $(opam env). This will avoid polluting your global ocaml environment.
  5. Add the following opam repositories to fetch dependencies:
    opam repo add coq-released
    opam repo add iris-dev
  6. Run make build-dep to install the latest dependencies
  7. Run make -j to build the Coq proofs.
  8. Explore the proofs using the editor of your choice, referring to previous sections for areas of interest.

Building the benchmarks

  1. Install rustup, using the instructions at
  2. Enter the creusot directory, and execute cargo install --path creusot
  3. Enter the rhb-specs directory and execute make clean followed by make proofs.

If you wish to modify the benchmarks, we recommend repeating steps 4 and 5 to refresh the output. Additionally, you may browse the test suite of Creusot (found at creusot/creusot/tests/should_succeed) for further examples.

Loading the benchmarks

The benchmarks can be evaluated using why3, and its ide.

  1. Install opam using your system package manager.
  2. Initialize opam by running opam init.
  3. Create a local 'opam switch' inside the rhb-specs directory by running opam switch create . and eval $(opam env).
  4. Pin why3: opam pin add why3
  5. Install why3 by running opam install ocamlgraph why3 why3-ide.
  6. Install z3 and cvc4 as backends to why3 using your system package manager or installer of choice.
  7. Configure why3 by running why3 config detect. It should provide an output stating which provers have been detected and configured.
  8. Open the proofs.mlcfg created in the previous subsection with the following command:
    why3 ide -Lpath/to/creusot/prelude proofs.mlcfg
  9. Run the proofs by selecting the 'theory' node in the left-hand pane and pressing '3'.