---
title: 'RustyDL: Source-Level Logic for Rust'
url: https://www.emergentmind.com/topics/rustydl
type: topic
---

# RustyDL: Source-Level Logic for Rust

Searching arXiv for the named topic and closely related Rust research to ground the article in current papers.
RustyDL is a program logic for Rust that is designed as a source-level foundation for auto-interactive, human-in-the-loop deductive verification. It reasons about Rust programs directly on the source code level, rather than through translation to an intermediate verification language, and is presented as the core of a prototype Rust instance of the KeY verification system [2602.22075]. Within its current scope, RustyDL targets a substantial subset of safe Rust, including primitive values, arrays, shared and mutable references, loops, and function calls, and develops explicit logical machinery for Rust-specific phenomena such as ownership transfer, borrowing, and mutation through `&mut` references [2602.22075].

## 1. Intellectual setting and verification objective

RustyDL emerges from a line of research that treats Rust’s ownership discipline as a first-class semantic object rather than as a compilation artifact. Earlier source-oriented semantics such as Oxide modeled ownership and borrowing without the details of lifetime analysis and organized Rust as a family of languages of increasing expressive power [1806.02693]. RustyDL moves from source-level semantics to source-level program logic: its purpose is not merely to explain Rust, but to support deductive proofs over Rust source programs in a human-in-the-loop style [2602.22075].

Its central motivation is methodological. Translation-based Rust verifiers typically compile Rust into an intermediate verification language and then rely on VC generation and SMT solving. RustyDL instead treats direct reasoning over Rust source as crucial for highly complex functional verification, because source-level proof states remain legible in terms of Rust constructs such as `if`, loops, borrowing, moves, and array indexing [2602.22075]. This suggests a verification workflow in which failed proofs are debugged at the level of Rust source rather than at the level of an intermediate encoding.

The logic is explicitly restricted to safe Rust. `unsafe` blocks are not modeled as part of the proof system’s current trusted core; rather, they are assumed to be encapsulated and verified separately [2602.22075]. This boundary is consistent with broader verification practice in Rust, where UB-oriented tools and larger library-verification campaigns often treat unsafe code as a specialized target requiring different machinery [2606.17374].

## 2. Dynamic-logic foundation

RustyDL is based on dynamic logic, extending typed first-order logic with modalities that internalize program execution into formulas [2602.22075]. The two central modalities are the box modality for partial correctness and the diamond modality for total correctness:
\[
\dlbox{p}\,\phi
\]
and
\[
\dia{p}\,\phi .
\]

The intended reading is standard. The box modality states that either program fragment \(p\) does not terminate normally, or, if it does terminate normally, the resulting state satisfies \(\phi\). The diamond modality states that \(p\) terminates normally and the resulting state satisfies \(\phi\) [2602.22075]. Hoare-style specifications are represented as implications, for example:
\[
\{\pre\}\ p\ \{\post\}
\quad\equiv\quad
\pre \rightarrow \dlbox{p}\post .
\]

Semantically, RustyDL uses a Kripke structure
\[
\Kstruct = (\States,\rho)
\]
where \(\States\) is a set of first-order structures representing program states, and \(\rho\) maps each legal program fragment \(p\) to a partial function
\[
\rho(p) : \States \rightharpoonup \States
\]
that is defined exactly when \(p\) terminates normally [2602.22075]. This keeps nontermination and abnormal termination inside the modal semantics, while ordinary state changes are handled by updates.

The logic’s sort system is tailored to Rust. It includes \(\Any\) as a top sort, \(\neverTy\) as a bottom sort, base sorts such as \(\bool\), \(\Int\), and \(\unit\), array sorts \(\arrTy{T}{N}\), and distinct sorts for shared and mutable references:
\[
\RefS{A}
\qquad\text{and}\qquad
\RefM{A}.
\]
It also introduces technical sorts such as \(\Field\) and \(\Place\), which are needed to model indexing and mutable-reference targets [2602.22075].

A significant design decision is that integer types are represented as mathematical integers, with Rust-specific range restrictions expressed via predicates such as `inU32`. This makes arithmetic reasoning classical at the logical level while preserving Rust’s debug-style overflow behavior through explicit case splits that either continue normally or yield `panic!()` [2602.22075].

## 3. Ownership, moves, and borrowing

RustyDL’s most distinctive contribution lies in its treatment of ownership transfer and references. Rust assignment on non-`Copy` types is modeled as a move, not a copy. Rather than introducing a special uninitialized value, RustyDL handles moves by anonymizing the source variable with a fresh constant of the same type [2602.22075]. The rule has the shape
\[
\pv{x}\upd\pv{y}\parupd\pv{y}\upd c
\]
for fresh \(c\), capturing that `x` receives the old value of `y` while `y` can no longer be reasoned about via its previous value.

Shared borrowing is modeled value-theoretically. Creating
```rust
x = &y;
```
is represented by updating `x` to a shared-reference term:
\[
\rust{x}\upd\refS{\rust{y}} .
\]
Dereferencing a shared reference is then reduced by a simplification rule of the form
\[
\derefS(\refS{t}) \leadsto t .
\]
This reflects the read-only, aliasable status of `&T` in safe Rust [2602.22075].

Mutable references require a different treatment because they denote places that can be written through. RustyDL introduces the sort \(\Place\) together with place constants and constructors such as \(\place{\pv{x}}\) for variables and \(\arrplace{t}{i}\) for mutable array positions [2602.22075]. A mutable reference is then represented by
\[
\refM{pl} : \RefM{A} .
\]
Thus
```rust
x = &mut y;
```
becomes
\[
\rust{x}\upd\refM{\place{\rust{y}}}.
\]

Mutation through a mutable reference is captured by RustyDL’s novel mutating update:
\[
(t_1 \dupd t_2).
\]
Its semantic role is to update the place borrowed by \(t_1\) to the value \(t_2\) [2602.22075]. In particular,
```rust
*y = 3;
```
is modeled by a mutating update, and when `y` is known to be of the form \(\refM{\place{\pv{x}}}\), a rewrite turns
\[
\refM{\place{\rust{a}}}\dupd t
\]
into the ordinary elementary update
\[
\pv{a}\upd t .
\]
This is the key mechanism by which RustyDL internalizes the operational meaning of writing through `&mut` without lowering to an intermediate store model [2602.22075].

This treatment also supports the state dependence of mutable dereferencing. Shared dereferences can collapse immediately to values, but mutable dereferences must reflect the current lender state, because the borrowed place may have changed since the reference was created [2602.22075]. The calculus therefore includes dedicated rewrite rules that propagate ordinary updates into dereferences of mutable references.

## 4. Arrays, arithmetic, and control flow

Arrays are modeled functionally. For each array sort \(\arrTy{S}{n}\), RustyDL provides operations analogous to read and write:
\[
\arrget{S}{n} : \arrTy{S}{n} \times \Field \to S
\]
and
\[
\arrset{S}{n} : \arrTy{S}{n} \times \Field \times S \to \arrTy{S}{n}.
\]
An index term is translated by
\[
\arridx : \Int \to \Field .
\]
This yields the expected functional-array behavior for expressions such as successive indexed writes followed by a read [2602.22075].

Array access rules are explicit about Rust’s bounds checks. Reading
```rust
x = a[i];
```
splits on whether \(i\) is within \([0,n)\): out-of-bounds access leads to `panic!()`, whereas an in-bounds access produces an update
\[
\pv{x}\upd\pv{a}[\pv{i}] .
\]
Writing
```rust
a[i] = se;
```
similarly splits between panic and a functional-array update using `set` [2602.22075]. Mutable borrowing of array elements,
```rust
x = &mut a[i];
```
combines the place-based model of `&mut` with the same bounds discipline, yielding a mutable reference to an array place \(\arrplace{\pv{a}}{\pv{i}}\) [2602.22075].

Arithmetic is handled in debug semantics. For unsigned 32-bit addition, RustyDL uses a rule that branches on
\[
\dlfunc{inU32}(\mathit{se}_1+\mathit{se}_2)
\equiv
0 \le \mathit{se}_1+\mathit{se}_2 \wedge \mathit{se}_1+\mathit{se}_2 \le 2^{32}-1 .
\]
If the bound holds, the assignment proceeds normally; otherwise execution follows the `panic!()` branch [2602.22075]. This makes overflow part of the explicit proof obligation rather than hidden inside machine arithmetic.

Control flow is treated proof-theoretically. An `if` expression is handled by branching the sequent into the `true` and `false` cases. For simple guards, RustyDL uses a direct split on
\[
\mathit{se}\keyeq\keybooltrue
\qquad\text{and}\qquad
\mathit{se}\keyeq\keyboolfalse .
\]
For complex guards, it first normalizes by introducing a temporary variable holding the guard expression, then splits over that variable [2602.22075]. This keeps symbolic execution close to Rust source structure and avoids premature expansion of complex conditions.

## 5. Proof calculus and prototype realization

RustyDL is presented as a sequent calculus for source-level Rust verification [2602.22075]. The calculus combines symbolic execution rules for Rust statements and expressions with logical reasoning in typed first-order dynamic logic. Because proofs are represented explicitly as sequents and proof trees, the system is intended for auto-interactive use rather than purely push-button discharge.

The prototype realization is a Rust instance of KeY, described as “Rusty KeY” [2602.22075]. This is a proof-of-concept rather than a finished verifier, but it demonstrates the intended architecture: Rust programs are taken at a normalized source representation close to HIR, and proof steps operate directly over Rust constructs. A human verifier can therefore inspect intermediate states that still refer to Rust-level variables, references, arrays, and control-flow structure.

This source-level strategy sharply distinguishes RustyDL from other major Rust verifiers. Tools such as Prusti, Creusot, Aeneas, and Verus are characterized as translation-based: they compile Rust into an intermediate verification language and then rely on VC generation and SMT automation [2602.22075]. RustyDL instead prioritizes explicit inference steps and source fidelity. A plausible implication is that it is particularly suited to the verification of proofs whose difficulty lies less in discovering loop invariants mechanically than in guiding a large, semantically rich argument over source structure.

The same orientation also clarifies its present limitations. The current logic covers a rich subset of safe Rust, but not `unsafe`, explicit lifetimes, traits, unions, smart pointers, macros, or async constructs [2602.22075]. Those omissions are not incidental; they mark precisely the frontier between a source-level proof system already capable of nontrivial functional reasoning and a fuller logic for the whole language.

## 6. Position within Rust verification research

RustyDL belongs to a broader Rust verification landscape that includes source-level semantics, bounded model checking, refinement types, separation logic, fuzzing, and runtime enforcement. Within that landscape, its closest conceptual predecessor is Oxide, which models ownership and borrowing without the details of lifetime analysis and structures Rust as an expressive tower of languages [1806.02693]. RustyDL can be read as a move from such semantic distillation toward proof-calculus engineering at the source level.

A different strand of work targets library-scale automated verification. A recent campaign on the Rust standard library integrates Kani, ESBMC, Flux, and VeriFast into continuous integration for `core`, `alloc`, and `std`, focusing primarily on absence of UB and selected functional invariants [2606.17374]. RustyDL addresses a different point in the design space: source-level, human-guided deductive verification of functional properties, rather than repository-scale automated checking over an intermediate representation [2602.22075].

Other research addresses problems RustyDL does not yet target. deepSURF detects memory-safety vulnerabilities in unsafe Rust libraries by combining static analysis with LLM-augmented fuzzing harnesses [2506.15648]. CapsLock proposes runtime enforcement of ownership, borrowing, and AXM in mixed Rust, FFI, and inline assembly via hardware capabilities and revoke-on-use semantics [2507.03344]. Static deadlock detection for Rust programs uses MIR-based pointer analysis and lock graphs to identify double lock, conflict lock, and condition-variable deadlocks [2401.01114]. These efforts are complementary rather than competitive: they concern unsafe code, mixed-language execution, or concurrency bugs, whereas RustyDL currently concentrates on safe Rust and deductive functional reasoning [2602.22075].

Taken together, this context makes RustyDL significant as a distinct verification paradigm for Rust. It is neither an IR-based VC generator nor a runtime monitor nor a fuzzing framework. It is a source-level program logic whose central thesis is that Rust verification, especially in human-in-the-loop settings, benefits from keeping ownership, borrowing, moves, mutation, and control flow visible all the way through the proof calculus [2602.22075].

Source: https://www.emergentmind.com/topics/rustydl