Veri-easy is a lightweight and automated framework that combines multiple testing and proof (TAP) techniques to establish functional equivalence between the verified and original implementations. It automates function collection, harness generation, integrates with Kani model checking, property-based testing (Proptest), and differential fuzzing, and can optionally invoke Alive2 for IR-level validation.
- Functional equivalence checking across multiple components:
identical,kani,pbt,difffuzz,alive2, and more ... - Automatic harness generation for Kani, Proptest, and DiffFuzz with support for preconditions.
- Configurable workflow via
workflow.toml, including component-specific knobs. - Verus precondition/spec translator (in
precond-translator/) to turn Verus specs into executable Rust precondition checkers. - Clear logging with levels:
brief,normal,verbose.
src/main.rs: Entry point; loadsworkflow.toml, parses CLI, orchestrates components.src/config.rs: Workflow and component configs (Kani/PBT/DiffFuzz/Alive2) and CLI schema.src/check.rs: Core checker, source parsing, workflow execution, result aggregation.src/generate.rs: Harness generator backends and helpers for functions/methods and preconditions.src/components/: Implementations of each component (kani.rs,pbt.rs,df.rs,alive2.rs,identical.rs).src/collect/andsrc/defs/: Function/type/path abstractions and collection utilities.precond-translator/: Verus parser and code generator for preconditions and spec functions.hvisor-verified-allocator/: Formal verification of the memory allocator in hvisor.workflow.toml: Configures the component pipeline and per-component settings.
- Rust toolchain and
cargo. - Verus (for verification) Ensure
Verusis installed and usable in the environment. See Verus docs for installation instructions. Verus must be available in$PATHasverus. - Kani (required when using the
kanicomponent). Ensurekaniis installed and usable in the environment.- Use
cargo install --locked kani-verifierto install kani. - Use
cargo kani setupto set up the environment. - See Kani docs for more details.
- Use
- Crate
proptestandproptest-deriveare used via the PBT harness project; The dependencies are included in the generated harness, and handled by Cargo automatically. - Differential fuzzing harness uses AFL (American fuzzy lop) and
afl.rsworkflows. You need to set up the AFL toolchain before running the fuzzing component:- Use
cargo install cargo-aflto install the afl toolchain. - Use
cargo afl config --buildto set up the environment. - Use
cargo afl system-configto configure the system for AFL. - See
cargo-aflfor more details.
- Use
- Alive2 (optional; required when
alive2is enabled): setalive2_pathto youralive-tvbinary inworkflow.toml. See Alive2 repo for installation instructions.
Build and run from the workspace root.
We provide a Makefile that reproduces the results in our FM26 paper:
# Benchmark the allocator implementations.
make bench
# Run Verus on the allocator proof module.
# Please ensure that `verus` is available on your $PATH.
make verify
# Run the full Veri-easy workflow on the original and verified allocator implementations.
# Please ensure that all Veri-easy dependencies are installed and available.
make verieasyGenerally, the workflow can be invoked as follows:
# Build
cargo build
# Run with defaults (uses workflow.toml)
cargo run -- file1.rs file2.rs
# Specify preconditions (Verus file) and strict mode
cargo run -- -p verus_specs.rs -s file1.rs file2.rs
# Adjust log level (brief|normal|verbose)
cargo run -- -l verbose file1.rs file2.rs
# Use a different workflow config
cargo run -- -c path/to/workflow.toml file1.rs file2.rsYou can edit workflow.toml to customize the workflow and per-component settings. For example, you
can increase the Kani timeout to verify more complex functions.
[kani]
timeout_secs = 100
# other settings ...-c, --config <FILE>: workflow TOML (defaultworkflow.toml).-l, --log <LEVEL>:brief,normal, orverbose.-p, --preconditions <FILE>: Verus spec file; translated and appended tofile2.-s, --strict: exit on first error.- Positional:
file1andfile2Rust source files.
Example (defaults present in repo):
For quick demonstration purposes, we use a shorter Kani timeout and fewer test executions than in our full experimental setup. This keeps the Veri-easy workflow lightweight to run on a typical developer machine.
components = ["identical", "kani", "pbt", "difffuzz"]
[kani]
harness_path = "kani_harness"
output_path = "kani.tmp"
timeout_secs = 3 # shorter timeout for quick demo runs
# Reviewers can increase this to 200 seconds to reproduce the full results reported in the paper.
gen_harness = true
keep_harness = true
keep_output = true
use_preconditions = true
loop_unwind = 17 # Reviewers can set this to 33 to match the paper’s experimental configuration (≈1 hour runtime).
[diff_fuzz]
harness_path = "df_harness"
output_path = "df.tmp"
executions = 500000 # fewer executions for faster runs
keep_harness = true
keep_output = true
catch_panic = true
use_preconditions = false
[pbt]
harness_path = "pbt_harness"
output_path = "pbt.tmp"
test_cases = 50000 # reduced number of test cases
keep_harness = true
keep_output = true
use_preconditions = falseNotes:
- Component names accepted:
identical,kani,pbt,difffuzz(diff-fuzz,diff_fuzzalso accepted),alive2. - Missing per-component sections are filled with sensible defaults.
preconditions(CLI) enables argument assumptions in harnesses when supported.- Detailed arguments can be found in
src/config.rs.
- Sources are parsed (
syn), functions and types collected. - (Optional) Preconditions are collected from Verus specs via the precondition translator.
- Functions/methods are matched between the two sources based on name and signature.
- For each component in the workflow, Veri-easy generates harness code and runs the tool:
kani: generates#[kani::proof]harnesses, supportsloop_unwindandArbitraryargs.pbt: generates Proptest tests withprop_assume!for preconditions and mismatch reporting.difffuzz: generates fuzz harness; optionally catches panic and can use preconditions.alive2: invokesalive-tvwith configured path.
- Results are logged; strict mode stops on first fatal error.
- Free functions vs methods are classified automatically.
- Receiver methods require a constructor and optional getter per type.
- Implement constructors named
verieasy_newand gettersverieasy_getinimplblocks to enable method harnessing.
Issues and PRs are welcome. Ensure changes keep harness generation minimal and respect existing component interfaces.