Formal verification of pure-arithmetic functions from zooko/smalloc, using the Rust → Aeneas → Lean 4 pipeline.
First target in scope: reqali_to_sc — the size-class mapping
function the maintainer identified as the highest-leverage verification
point (one-line function with a history of bugs).
| Function | Upstream location | Theorems |
|---|---|---|
reqali_to_sc(siz, ali) |
smalloc/src/lib.rs |
reqali_to_sc_size_fits, reqali_to_sc_alignment_fits |
Theorems proved:
reqali_to_sc_size_fits. Under safe preconditions on the inputs, the slot size2 ^ reqali_to_sc(siz, ali)is at leastmax(siz, ali, SMALLEST_SLOT_SIZE).reqali_to_sc_alignment_fits. Under safe preconditions, the alignment of the returned slot is at leastali(i.e.alidivides2 ^ result).
Safe preconditions (matching upstream's debug_assert!s):
siz ≥ 1ali ≥ 1aliis a power of twoali < 2³²
smalloc-arith/src/lib.rs (standalone Rust crate)
│
▼ Charon
smalloc_arith.llbc (typed intermediate representation)
│
▼ Aeneas
lean/SmallocArith/{Types,Funs}.lean (pure-functional Lean 4)
lean/SmallocArith/FunsExternal.lean (hand-written model of usize::ilog2)
│
▼ specifications + proofs
lean/SmallocArithVerif/BasicProofs.lean
│
▼ Lean 4 kernel
Machine-checked theorems
smalloc-verify/
├── README.md
├── .gitignore
├── .github/workflows/ci.yml
├── smalloc-arith/ # standalone Rust crate
│ ├── Cargo.toml
│ └── src/lib.rs # reqali_to_sc + supporting consts
├── smalloc_arith.llbc # generated by Charon
└── lean/
├── lakefile.lean
├── lean-toolchain # leanprover/lean4:v4.30.0-rc2 (matches Aeneas)
├── lake-manifest.json # pins dependency revisions
├── SmallocArith.lean
├── SmallocArith/
│ ├── Types.lean # generated by Aeneas
│ ├── Funs.lean # generated by Aeneas
│ ├── FunsExternal_Template.lean # generated by Aeneas (template, not imported)
│ └── FunsExternal.lean # hand-written: model of usize::ilog2
├── SmallocArithVerif.lean
└── SmallocArithVerif/
└── BasicProofs.lean # the proofs
cd smalloc-arith
nix run github:aeneasverif/aeneas#charon -L -- cargo --preset=aeneas
nix run github:aeneasverif/aeneas -L -- -backend lean -split-files *.llbc
# Move the generated Types.lean and Funs.lean into lean/SmallocArith/
# and the .llbc file into the repo root.Aeneas also emits FunsExternal_Template.lean. Do not let it clobber the
hand-written FunsExternal.lean (see "Notes on extraction" below): the
template is regenerated each run, but FunsExternal.lean is maintained by hand.
If a re-extraction introduces a new external function, the template will gain a
new hole — diff it against FunsExternal.lean and port any additions over.
cd lean
lake buildA clean build with no sorry and no unproved axioms is the deliverable.
Two things about the current Aeneas (Lean toolchain v4.30.0-rc2) are worth
recording, since they differ from older walkthroughs:
-
External functions are split into a separate, hand-completed file. Aeneas cannot translate
usize::ilog2(a std intrinsic), so it emits the function as a hole inFunsExternal_Template.lean.Funs.leanimportsSmallocArith.FunsExternal(no_Template), so the build fails until the template is copied toFunsExternal.leanand the hole filled. This file is user-authored and committed. -
ilog2is modelled, not rewritten. Rather than rewriting the Rust withleading_zeros,FunsExternal.leangivesilog2a computable model,ilog2 x = Nat.log 2 x.val(floor-log2), with a@[step]spec lemma. This keeps the Rust source byte-for-byte identical to upstream and replaces the template's opaqueaxiomwith an honest definition, so the proofs rest on no unproved axiom beyond Lean/Mathlib's standardpropext,Classical.choice, andQuot.sound.
Zooko (smalloc maintainer) identified
reqali_to_sc as the highest-leverage verification target. Despite
being one line of code, the function has had multiple bugs historically
— exactly the shape where machine-checked proofs pay off.
This work uses the Aeneas / Charon / Lean 4 stack, building on patterns established in Verified-zkEVM/rust-lean.