
Cryptographic code is the foundation of computer security — it protects operating systems, cloud services, and communication protocols. Because of this:
Testing checks that code usually works correctly. But:
| Testing | Formal Verification |
|---|---|
| Checks specific inputs | Checks all possible inputs |
| Can miss edge cases | Proves correctness mathematically |
| Finds bugs after the fact | Provides guarantees upfront |
Key Insight: Testing asks "did it work for these cases?" Formal verification asks "can we prove it works for every valid case?"
Formal verification uses machine-checked mathematical proofs to guarantee that code behaves exactly as specified.
Think of it like this:
Standard Algorithm (what it SHOULD do)
↕ ← Proof that these match
Actual Code (what it DOES do)
The Microsoft SymCrypt project combines two complementary tools:
Rust — the programming language
Lean — the formal proof framework
Analogy: Rust is like building a bridge with safety rails (prevents falling off). Lean proofs are like engineering calculations proving the bridge holds the required weight.
Before you can prove code is correct, you need a precise mathematical description of what "correct" means.
For cryptography, this comes from public standards:
The Lean specification is written to mirror the standard as closely as possible:
NIST Standard describes: Lean Specification mirrors:
- A loop over 256 coefficients → Same loop structure
- Array updates with zeta → Same mathematical operations
- Nested loop structure → Same nesting
Example: The NTT (Number-Theoretic Transform) from ML-KEM is an in-place transformation over 256 coefficients. The Lean version uses the same loop nest, same zeta selection, and same coefficient updates as the NIST standard — making line-by-line review straightforward.
You now have:
You need to bridge these two worlds.
Aeneas is a toolchain that translates Rust code into a pure Lean model:
Rust Code (mutable, imperative)
↓ Aeneas translation
Lean Model (pure, functional)
↓ Proof
Lean Specification (from standard)
Rust uses mutable state. Lean works with pure functions. Aeneas handles this translation:
| Rust (imperative) | Lean (functional) |
|---|---|
fn ntt(&mut [u16; 256]) | ntt : Array U16 256 → Result (Array U16 256) |
| Updates array in-place | Explicitly takes array in, returns new array |
| Mutable borrow | Value transformation |
| May panic | Wrapped in Result type |
Rust's ownership and borrowing discipline means:
Once translated, a theorem is attached stating:
"For every input satisfying the preconditions (e.g., valid polynomial representation), the Rust model returns the same result as the formal specification."
Software Engineers → Write idiomatic, performant Rust (unchanged)
Verification Engineers → Work on Lean models and proofs
The proof burden does not force developers to write unnatural code.
Production cryptography must run on many platforms:
A verification approach that only works on a simple reference implementation is not enough.
The toolchain:
Rust code with cfg attributes
↓
Compile for x86-64 + Compile for aarch64
↓ ↓
Lean model (x86) + Lean model (ARM)
↓
Merged Lean model
(dynamic dispatch)
↓
Single correctness proof
Low-level hardware instructions (SIMD, etc.) that can't be directly translated are handled by:
Key Point: Verification does not require giving up performance optimization. The methodology is designed to handle the full complexity of production code.
A proof sitting in a repository that only specialists can read doesn't scale in an engineering organization.
Verification results are surfaced through automatically generated dashboards that show:
| Dashboard Element | What It Tells Developers |
|---|---|
| ✅ "Verified" badge | This function has a machine-checked proof |
| Preconditions | What inputs the proof covers |
| Postconditions | What the proof guarantees about outputs |
| Covered functions | Which parts of the code are verified |
| Trusted models | What assumptions were made |
| Links to Rust/Lean | Navigate directly to source and proof |
Rust code changes
↓
Lean models regenerated automatically
↓
Proofs replayed
↓
Proof breaks? → Signal: either update proof OR investigate discrepancy
Proof passes? → Dashboard shows green ✅
This turns formal verification from a one-time research artifact into part of the continuous engineering workflow.
Even with good tooling, writing formal proofs is specialist work that previously required months of effort per algorithm.
Agents are used in two places:
Agents can handle:
Agent proposes proof script
↓
Lean kernel independently verifies it
↓
Accepted ONLY if:
1. Lean validates the proof
2. Final theorem states the desired guarantee
3. No unreviewed assumptions introduced
Critical Point: Agents operate on the proof side only — they never modify the production Rust code. The correctness of the proof is verified by Lean's trusted kernel, not by trusting the agent.
| Before Agents | After Agents |
|---|---|
| Write every proof by hand | Design specifications |
| Months per algorithm | Curate automation libraries |
| Specialist bottleneck | Review theorem statements |
| Steer agents to complete proofs |
NIST Standard / RFC
↓
[Human + Agent] Write Lean Specification
↓ (tested against official vectors)
Formal Lean Specification
↑ ↑
| |
[Aeneas] Translate [Proof + Agent]
Rust → Lean model Connect spec to model
↑
Production Rust Code
(written by engineers, unchanged)
↓
[Multi-target compilation]
x86-64 + aarch64 + intrinsics
↓
[Dashboard] Show results to developers
↓
✅ Machine-checked guarantee:
"This Rust code correctly implements
the standard, for all valid inputs,
on all supported platforms"
| Concept | Core Idea |
|---|---|
| Why verify? | Testing finds bugs; proofs guarantee correctness for all inputs |
| Two-layer assurance | Rust = memory safety; Lean = functional correctness |
| Lean specifications | Mirror the standard closely; executable and auditable |
| Aeneas | Translates Rust's mutable code into pure Lean models for reasoning |
| Multi-architecture | Compile multiple times, merge models, verify all paths |
| Dashboards | Make proofs visible and actionable for developers |
| AI agents | Scale proof writing while Lean's kernel independently validates results |
The Big Promise: Cryptographic code that is fast, portable, maintainable, and developer-owned — while carrying machine-checked evidence that it correctly implements the standards it's meant to realize.