SMT Verification
SMT verification is the enforcement engine for Ora’s specs and refinements.
It turns requires, ensures, invariant, and refinement guards into proof
obligations and eliminates runtime checks when proofs succeed.
Implemented today
- Z3 verification pass runs after Ora MLIR emission.
requires,ensures, andinvariantclauses are encoded and checked.- Counterexamples are surfaced when constraints fail.
- SMT-only assumptions are preserved when refinements cannot be inferred.
Syntax (Defny-style)
Ora’s specification syntax follows a Defny-style layout: clauses attach to functions or loops, and verification-only statements live in blocks.
pub fn transfer(to: address, amount: u256) -> bool
requires amount > 0
requires balances[std.msg.sender()] >= amount
ensures balances[to] == old(balances[to]) + amount
{
// ...
}
When SMT proves these clauses, the compiler removes the corresponding runtime guards. If SMT cannot prove them, the checks remain in bytecode.
Example: if requires amount > 0 is not implied by refinements or control
flow, the compiler emits a runtime guard such as:
if (amount < 1) {
// runtime error / abort
}
Where to put the code
- Function clauses:
requires,ensures - Loop clauses:
invariant(placed on the loop header) - Block statements:
assert,assume,havoc - Quantifiers:
forall,existsinside clauses or ghost code
while (i < n)
invariant(i <= n)
{
// ...
}
assume(x >= 0);
assert(x >= 0);
havoc balance;
Quantifiers
pub fn check_all(balances: map[address, u256]) -> bool
requires forall addr: address where addr != std.constants.ZERO_ADDRESS
=> balances[addr] >= 0
{
return true;
}
Where it lives in the compiler
- Pass orchestration:
src/z3/verification.zig - Encoding:
src/z3/encoder.zig - Solver interaction:
src/z3/solver.zig
Proof flow
Implementation details
- Pass runs in
src/z3/verification.zigafter Ora MLIR emission. - Encoding is defined in
src/z3/encoder.zigfor Ora ops and types. - Solver integration and models live in
src/z3/solver.zig.
Research direction
- Make refinement guards first-class SMT obligations by default.
- Provide a consistent “prove or keep runtime” policy.
- Expand SMT-driven pruning of unreachable branches.
Evidence
docs/compiler/onboarding/09-z3-smt.md(Z3 integration details)docs/compiler/formal-verification.md(FV surface and pipeline)src/z3/encoder.zig(MLIR-to-SMT encoding entry point)
References
docs/compiler/onboarding/09-z3-smt.mddocs/compiler/formal-verification.mddocs/compiler/refinement-types-strategy.md