# Prusti static verification for Rust programs

> Prusti is a prototype verifier that checks Rust code for integer overflows and panics and can prove user-supplied contracts. It suits developers who need proof-oriented checks, but its specifications and toolchain add complexity.

**prusti/prusti** — A static verifier for Rust, based on the Viper verification infrastructure.

- Repository: https://github.com/prusti/prusti
- Website: https://prusti.github.io/prusti/
- Stars: 1,832 · Forks: 130
- Language: Rust
- License: NOASSERTION
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/prusti-prusti

## Prusti's target: Rust safety beyond ordinary compilation

Prusti addresses a gap between ordinary Rust compilation and mathematical proof. A normal build establishes that a program is well formed and enforces Rust's ownership rules, but Prusti is intended to formally check selected properties and contracts. By default, the verifier checks for integer overflows and panics. It can therefore establish, subject to the supplied specifications, that operations such as `unreachable!()` and `panic!()` cannot execute.

The intended users are Rust developers working on safety-critical code, algorithms, or components whose contracts should be documented and checked mechanically. Prusti is also relevant to formal verification researchers because it is built on Viper infrastructure and described as a prototype verifier. Its guarantees depend on what can be expressed in its annotations and proved by its backend. It is not a general-purpose replacement for testing, fuzzing, code review, or every kind of runtime analysis.

Prusti can go beyond safety checks. Preconditions, postconditions, and loop invariants describe expected behavior of functions and external libraries. That makes it possible to ask for semantic results, such as proving that a returned index has a stated property. Stronger contracts also place a larger proof burden on the developer. The README's binary-search example initially proves the corrected function free of panics and integer overflows, then directs readers to a separate example for proving functional correctness.

## Inside Prusti's Rust-to-Viper verification pipeline

The repository layout shows that Prusti is a multi-crate Rust workspace rather than a single executable. Members include `prusti-interface`, `prusti-rustc-interface`, `prusti-server`, `prusti-smt-solver`, `prusti-viper`, `vir`, and `viper`. The `analysis`, `prusti-contracts`, `prusti-tests`, and `test-crates` directories indicate separate work for analysis, contracts, verification tests, and test inputs.

The documented external behavior is that `prusti-rustc` and `cargo-prusti` operate analogously to `rustc` and `cargo build`. That places Prusti in a compiler-facing position rather than requiring a separate source-language input format. Internally, the README states that Prusti builds upon the Viper verification infrastructure. Repository names also expose an interface between Rust-facing code, a server, an SMT solver component, and Viper support. The README does not document the complete encoding pipeline or solver interchange, so the exact intermediate representations cannot be confirmed from it.

Integer handling is configurable. The README says overflow checking can be disabled with a configuration flag, which then treats integers as unbounded. That option can simplify reasoning in selected proofs, but it changes the property under examination. A passing proof in unbounded mode does not establish that checked-mode arithmetic fits Rust's finite integer types. Contract checking also explains why verification can fail after ordinary compilation has succeeded: Prusti reports when implementation behavior does not satisfy a precondition, postcondition, invariant, or safety obligation.

## Installing Prusti through binaries, source, or the IDE

The documented easiest entry point is the Prusti Assistant extension for VS Code. Its requirements and troubleshooting details are maintained in the extension README, not in the main Prusti README. This route is relevant for users who want verification associated with an editor workflow.

For command-line use, the main README offers precompiled binaries for Ubuntu, Windows, and macOS through a GitHub release. Source builds require `rustup`, followed by the repository's setup and release-build commands. These commands prepare the pinned project environment and compile the verifier, but the README does not state their expected duration or all operating-system prerequisites for a native build.

The source-build commands documented by Prusti are:

```bash
./x.py setup
./x.py build --release
```

The Docker option is explicitly labeled unmaintained. Its `Dockerfile` uses `ubuntu:18.04`, installs system packages and a Java runtime, reads the channel from `rust-toolchain`, and invokes the same setup and release-build commands. Because the README marks that route as unmaintained, it is a reproducibility reference rather than the preferred installation path.

All documented installation routes are intended to provide `prusti-rustc` and `cargo-prusti`. The README does not give a complete platform-neutral command for placing downloaded binaries on `PATH`, nor does it show the exact editor configuration for Prusti Assistant. Those details must come from the selected distribution or extension documentation.

## A first Prusti proof with binary search

Start with a Rust file containing the generic `Function` trait and `bisect` function from the README. The original midpoint expression contains a potential overflow:

```rust
let mid = (low + high) / 2;
```

The README reports that running Prusti against the original line produces a verification error identifying `attempt to add with overflow`. Replace that line with the overflow-safe calculation shown in the project example:

```rust
let mid = low + ((high - low) / 2);
```

Then run Prusti through whichever front end was installed. The README states that `prusti-rustc` corresponds to `rustc` and `cargo-prusti` corresponds to `cargo build`, but it does not provide a complete invocation for the example file. The documented result after the correction is that `bisect` verifies. At this stage, the established claim is limited to the absence of panics and integer overflows in the example.

Functional correctness is a separate obligation. The README sends readers to `prusti-tests/tests/verify_overflow/pass/overflow/bisect.rs` for a version that proves the result can satisfy `f(x) == target`. That distinction matters: replacing the midpoint calculation fixes the reported arithmetic issue, but it does not turn an implementation into a proof of its intended search result. A real project would need suitable preconditions and invariants, especially because the example delegates evaluation to a caller-supplied `Function` implementation.

## Contracts, assumptions, and verification limits

Prusti is the wrong tool when the objective is simply to find behavioral bugs through execution. The documented example rejects a possible overflow, but the project is not described as a fuzzing system or a replacement for runtime tests. A developer seeking broad input discovery, performance profiling, or production incident detection should choose a tool built for that activity.

Prusti cannot establish properties for which no specification or supporting fact has been supplied. Preconditions, postconditions, and loop invariants are inputs to the proof process, not automatically discovered descriptions of the code. An incomplete or inaccurate contract can leave more work to the verifier or result in a verification error that exposes an incorrect assumption. The README does not document a general fallback that turns an unproved specification into a confirmed property, so acceptance should be tied to the exact contract and configuration used.

The prototype label is significant. The README concentrates on research usage, examples, development guides, and nightly releases rather than a conventional stability and compatibility promise. Overflow checking can also be disabled. Teams must therefore record whether a passing result used checked or unbounded integers. Treating those results as interchangeable would misstate what was verified.

Prusti may also be unsuitable where the surrounding codebase is mostly unannotated. The README does not quantify how many external crates can be modeled or how difficult unsupported language features are. It states that functions and external libraries can be specified with annotations. Compatibility and proof coverage must therefore be established against representative source files, not inferred from Rust compatibility alone.

## Prusti compared with compiler checks and property testing

The clearest alternative is an ordinary Rust toolchain augmented by runtime-oriented testing. `rustc` and `cargo build` establish ordinary compilation correctness, while a property-testing library can exercise a function over generated inputs. Prusti follows a different approach: it checks symbolic safety properties and explicit contracts through formal verification infrastructure.

These approaches answer different questions. Compilation asks whether Rust's language rules permit the program. Property testing looks for concrete input-dependent counterexamples. Prusti asks whether the program can satisfy stated properties under the semantics used by the verifier. Prusti can establish that panics and overflows are unreachable for a proved function, but the developer may need to construct contracts and invariants that make the proof possible. Runtime tools may cover implementations and inputs that are awkward to model but cannot turn observations of many inputs into a proof for all inputs.

A multi-tool workflow may fit better than forced substitution. Prusti can handle selected mathematical or safety obligations, while tests exercise behavior that is not formalized. The README does not provide Prusti performance figures, benchmark results, or evidence about how much human effort is needed for a particular codebase.

## Prusti maintenance, releases, and licensing cost

The repository is not archived, and its last push was on 2026-10-06. The listed releases are nightly builds from March 2024, including `v-2024-03-26-1504`, `v-2024-03-06-1207`, and `v-2024-03-01-2003`. This indicates recent repository activity, but the listed release history centers on dated nightly artifacts. The README continues to call Prusti a prototype, so repository activity should not be treated as a guarantee of stable release support.

Upgrading may require rebuilding against the `rust-toolchain`, running `./x.py setup`, and rebuilding with `./x.py build --release`. The workspace contains interface, server, solver, Viper, contracts, tests, and generated-code crates, so adoption can involve more than installing one small command-line binary. The README does not document a compatibility matrix for stable Rust releases, a migration guide for changing annotation syntax, or a service-level support policy.

License classification also needs care. Repository metadata identifies the license as a custom license GitHub cannot classify. The README links a `LICENSE` file and says the Mozilla Public License Version 2.0 applies to code authored by the project. That does not establish the terms for every dependency or bundled component. A team should inspect the repository `LICENSE` and relevant dependency terms before redistribution. This is a licensing boundary, not legal advice.

## Conclusion

Prusti is appropriate for developers who can write contracts and accept its prototype status, especially when overflow and panic proofs matter more than a conventional build workflow. It is a poor default for ordinary Rust projects without specifications or for teams that need a small, low-maintenance toolchain. Before adoption, verify that the documented rust-toolchain builds in the target environment, review the LICENSE for each relevant component, and run a representative contract-bearing program with the selected prusti-rustc or cargo-prusti distribution.

## FAQ

### How do I install Prusti for Rust verification?

The README lists three routes: the Prusti Assistant VS Code extension, precompiled binaries for Ubuntu, Windows, or macOS, and a source build through `./x.py setup` followed by `./x.py build --release`. It also lists a Docker build but marks it as unmaintained.

### What does Prusti check by default?

By default, Prusti checks for integer overflows and panics, including whether expressions such as `panic!()` and `unreachable!()` are unreachable. It can also check preconditions, postconditions, and loop invariants.

### Which command-line programs does Prusti provide?

The documented programs are `prusti-rustc` and `cargo-prusti`. They are intended to be used analogously to `rustc` and `cargo build`, respectively.

## Sources

- [Issues](https://github.com/prusti/prusti/issues)
- [Project website](https://prusti.github.io/prusti/)
- [prusti/prusti on GitHub](https://github.com/prusti/prusti)
- [README](https://github.com/prusti/prusti/blob/main/README.md)
- [Releases](https://github.com/prusti/prusti/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/prusti-prusti
