Rust verification: choosing the right adversary
Tests show a program works on the inputs you tried. Verification tools
attack the program with adversaries chosen by failure mode: UB,
unexpected inputs, schedule chaos, logic gaps, exhaustive state, or
unbounded reasoning. Pick the smallest adversary that fits the property
at risk.
Working stance
- Name the failure mode before naming the tool.
- Each tool is additive: Miri does not replace proptest, Kani does not
replace Verus.
- Run cheap adversaries on every change; reserve expensive sweeps for
code where they pay back.
- The effort is not finished until a deliberate mutation of the
production code is caught by it.
Selection by failure mode
| Failure mode |
First reach |
Undefined behaviour in unsafe (aliasing, init, UB) |
Miri + sanitizers |
| Input gaps in pure functions |
proptest |
| "My tests pass but my logic is wrong" |
cargo-mutants |
| Async cancellation, ordering, partial-failure |
turmoil |
| Atomic / lock-free memory ordering on a single core |
loom |
| Mutex / channel scheduling on a single core |
shuttle |
| Structural invariant over a bounded state space |
kani |
| Algebraic property over an unbounded domain |
verus |
See references/tool-selection.md for a
longer walkthrough with one paragraph per tool.
Layering rule
Climb only when the layer below is clean; bugs found higher up are much
harder to diagnose.
- Unit tests anchor concrete expectations.
- Miri and sanitizers catch UB on the inputs tests already exercise.
proptest widens inputs; cargo-mutants checks the tests can fail.
loom, shuttle, and turmoil shake the schedule.
kani proves bounded structural invariants.
verus proves unbounded algebraic properties.
Deterministic chaos
loom, shuttle, turmoil, and kani require the system under test
to be deterministic given its inputs. Hidden non-determinism (clocks,
RNG, thread IDs, env reads) breaks reproduction. See
references/deterministic-chaos.md
for the fences chaos tools require.
Red flags
- "We already test this" and a one-line mutation does not break the test.
- An
unsafe block has a safety comment but never runs under Miri.
- A
proptest regression file is checked in but never minimised or
promoted to a unit test.
- A Kani harness or Verus proof references symbols that no longer match
production — the mirror is decaying.
- Concurrency tests pass locally and flake in CI;
loom, shuttle, or
turmoil have not been tried.
Routing into deep dives
- Strategy design, shrinking discipline, regression files, the
filtering trap, and state-machine tests:
proptest.
- Kani harness shape, unwind discipline, contracts, stubbing:
kani.
- Verus modes, triggers, sequence proofs,
assert by:
verus.
Proptest is a regular Cargo dev-dependency; kani and verus
install via
rust-prover-tools.
The selection rules above stay authoritative for picking between
them.
References
Source: leynos/rust-skill — distributed by TomeVault.
1---2name: rust-verification3description: Select and combine Rust verification tools — Miri, sanitizers, property testing, mutation testing, deterministic concurrency exploration (loom, shuttle, turmoil), bounded model checking (Kani), and deductive proofs (Verus). Use when choosing the smallest tool that gives the required guarantee for a given failure mode. Use when this capability is needed.4---56# Rust verification: choosing the right adversary78Tests show a program works on the inputs you tried. Verification tools9attack the program with adversaries chosen by failure mode: UB,10unexpected inputs, schedule chaos, logic gaps, exhaustive state, or11unbounded reasoning. Pick the smallest adversary that fits the property12at risk.1314## Working stance1516- Name the failure mode before naming the tool.17- Each tool is additive: Miri does not replace proptest, Kani does not18 replace Verus.19- Run cheap adversaries on every change; reserve expensive sweeps for20 code where they pay back.21- The effort is not finished until a deliberate mutation of the22 production code is caught by it.2324## Selection by failure mode2526| Failure mode | First reach |27| ----------------------------------------------------- | ------------------ |28| Undefined behaviour in `unsafe` (aliasing, init, UB) | Miri + sanitizers |29| Input gaps in pure functions | `proptest` |30| "My tests pass but my logic is wrong" | `cargo-mutants` |31| Async cancellation, ordering, partial-failure | `turmoil` |32| Atomic / lock-free memory ordering on a single core | `loom` |33| Mutex / channel scheduling on a single core | `shuttle` |34| Structural invariant over a bounded state space | `kani` |35| Algebraic property over an unbounded domain | `verus` |3637See [`references/tool-selection.md`](references/tool-selection.md) for a38longer walkthrough with one paragraph per tool.3940## Layering rule4142Climb only when the layer below is clean; bugs found higher up are much43harder to diagnose.44451. Unit tests anchor concrete expectations.462. Miri and sanitizers catch UB on the inputs tests already exercise.473. `proptest` widens inputs; `cargo-mutants` checks the tests can fail.484. `loom`, `shuttle`, and `turmoil` shake the schedule.495. `kani` proves bounded structural invariants.506. `verus` proves unbounded algebraic properties.5152## Deterministic chaos5354`loom`, `shuttle`, `turmoil`, and `kani` require the system under test55to be deterministic given its inputs. Hidden non-determinism (clocks,56RNG, thread IDs, env reads) breaks reproduction. See57[`references/deterministic-chaos.md`](references/deterministic-chaos.md)58for the fences chaos tools require.5960## Red flags6162- "We already test this" and a one-line mutation does not break the test.63- An `unsafe` block has a safety comment but never runs under Miri.64- A `proptest` regression file is checked in but never minimised or65 promoted to a unit test.66- A Kani harness or Verus proof references symbols that no longer match67 production — the mirror is decaying.68- Concurrency tests pass locally and flake in CI; `loom`, `shuttle`, or69 `turmoil` have not been tried.7071## Routing into deep dives7273- Strategy design, shrinking discipline, regression files, the74 filtering trap, and state-machine tests:75 [`proptest`](../proptest/SKILL.md).76- Kani harness shape, unwind discipline, contracts, stubbing:77 [`kani`](../kani/SKILL.md).78- Verus modes, triggers, sequence proofs, `assert by`:79 [`verus`](../verus/SKILL.md).8081Proptest is a regular Cargo dev-dependency; `kani` and `verus`82install via83[`rust-prover-tools`](https://github.com/leynos/rust-prover-tools).84The selection rules above stay authoritative for picking between85them.8687## References8889- [`references/tool-selection.md`](references/tool-selection.md) — per-tool90 "use when" rationale.91- [`references/deterministic-chaos.md`](references/deterministic-chaos.md)92 — determinism fences for chaos tools.93- Deep dives: [`../proptest/SKILL.md`](../proptest/SKILL.md),94 [`../kani/SKILL.md`](../kani/SKILL.md),95 [`../verus/SKILL.md`](../verus/SKILL.md).9697---98> Source: [leynos/rust-skill](https://github.com/leynos/rust-skill) — distributed by [TomeVault](https://tomevault.io).99<!-- tomevault:4.0:skill_md:2026-06-16 -->