Division Safety
Division and modulo operations in contracts require explicit non-zero guards.
The Problem
Division by zero is undefined. When division appears in method contracts (requires, ensures, assertions lowered as contract obligations, or invariants), the verifier must prove the divisor is never zero. Without proof, the Viper translation rejects the program before SMT verification.
// REJECTED - divisor y could be zero
public func divide(x : Nat, y : Nat) : async Nat
ensures result == x / y;
{ x / y }
Error message:
division/modulo by possibly zero denominator in contract; add requires d != 0 or d > 0
Basic Non-Zero Guards
Add a requires clause to guarantee the divisor is non-zero:
// Basic division with non-zero guard
persistent actor {
public func divide(a : Int, b : Int) : async Int
entry_requires b != 0;
requires b != 0;
ensures result == a / b;
{
a / b
};
// Alternative: use positive guard
public func dividePositive(a : Int, b : Int) : async Int
entry_requires b > 0;
requires b > 0;
ensures result == a / b;
{
a / b
};
}
The verifier recognizes these guard patterns:
| Pattern | Meaning |
|---|---|
d != 0 | d is not zero |
d > 0 | d is positive (implies non-zero) |
d < 0 | d is negative (implies non-zero) |
d >= 1 | d is at least 1 (implies non-zero for Nat) |
Guard Placement
When using division in preconditions, place the non-zero guard before the division. Current verification collects logical preconditions before checking contract divisions, so requires order is not semantically significant to the proof. entry_requires clauses are executable runtime checks, though, so guard order matters there: do not evaluate a / b before checking b != 0.
- Correct
- Late Guard
// Correct: guard appears before division
persistent actor {
public func divideWithCheck(a : Nat, b : Nat) : async Nat
entry_requires b != 0;
entry_requires a / b > 0;
requires b != 0;
requires a / b > 0;
ensures result == a / b;
{
a / b
};
}
// Discouraged: the guard appears after division.
// Logical requires are accepted because verification collects all preconditions,
// but entry_requires is executable and should check b != 0 before a / b.
persistent actor {
public func divideWithCheck(a : Nat, b : Nat) : async Nat
entry_requires a / b > 0;
entry_requires b != 0;
requires a / b > 0;
requires b != 0;
ensures result == a / b;
{
a / b
};
}
Best practice: place non-zero guards in separate requires clauses before any division.
For exported actor methods, mirror caller-provided non-zero assumptions with
entry_requires so external calls are checked at the runtime boundary, and put the executable entry_requires guard before any entry_requires expression that divides.
Modulo Operations
Modulo (%) follows the same rules as division. Both require non-zero guards:
// Division and modulo together
persistent actor {
public func divMod(a : Nat, b : Nat) : async (Nat, Nat)
entry_requires b != 0;
requires b != 0;
ensures result.0 == a / b;
ensures result.1 == a % b;
ensures a == result.0 * b + result.1;
{
(a / b, a % b)
};
// Modulo bounds
public func modBound(a : Nat, b : Nat) : async Nat
entry_requires b != 0;
requires b != 0;
ensures result == a % b;
ensures result < b;
{
a % b
};
}
Nested and Computed Divisors
When the divisor is a computed expression, you must guard the entire expression:
// Nested and computed divisors
persistent actor {
// Computed divisor: guard the expression
public func divBySum(a : Nat, b : Nat, c : Nat) : async Nat
entry_requires b + c != 0;
requires b + c != 0;
ensures result == a / (b + c);
{
a / (b + c)
};
// Nested division: guard each level
public func divNested(a : Nat, b : Nat, c : Nat) : async Nat
entry_requires b != 0;
entry_requires c != 0;
entry_requires b / c != 0;
requires b != 0;
requires c != 0;
requires b / c != 0;
ensures result == a / (b / c);
{
a / (b / c)
};
}
For nested divisions like a / (b / c), guard each divisor separately, then guard the computed result.
Runtime Protection
Use runtime:assert for defense-in-depth. This both proves and enforces at runtime:
// Defense-in-depth with runtime:assert
persistent actor {
public func safeDivide(a : Int, b : Int) : async Int
entry_requires b != 0;
requires b != 0;
ensures result == a / b;
{
runtime:assert b != 0;
a / b
};
}
The requires clause is for callers. The runtime:assert provides a safety net if the precondition is violated.
Division in Pure Functions
Pure functions can perform division but cannot use assert, runtime:assert, or trap. Use requires clauses only:
// Pure function with division
module {
// Pure helper for division
public pure func half(n : Nat) : Nat
requires n >= 2;
ensures result == n / 2;
{
n / 2
};
// Use in contracts
public pure func isEven(n : Nat) : Bool {
n % 2 == 0
};
}
Division in Loop Invariants
Division in loop invariants requires guards that hold throughout the loop:
// Division in loop invariant
persistent actor {
public func sumDivided(n : Nat, d : Nat) : async Nat
entry_requires d != 0;
requires d != 0;
ensures result == n / d;
{
var i : Nat = 0;
var acc : Nat = 0;
while (i < n) {
loop:invariant i <= n;
loop:invariant d != 0;
loop:invariant acc == i / d or i < d;
i += 1;
if (i % d == 0) {
acc += 1;
};
};
n / d
};
}
The invariant d != 0 is trivially preserved since d is not modified.
Literal Divisors
Non-zero literal divisors are always allowed without guards:
public func percent(x : Nat) : async Nat
ensures result == x / 100;
{ x / 100 }
The verifier recognizes that 100 is non-zero.
Common Mistakes
Missing Guard
// REJECTED
public func bad(a : Nat, b : Nat) : async Nat
ensures result == a / b;
{ a / b }
Fix: add entry_requires b != 0; requires b != 0; for exported actor methods, or just requires b != 0; for private/module helpers.
Guard Hidden After Division
// Logical requires are accepted today, but this is unsafe entry_requires order.
public func bad(a : Nat, b : Nat) : async Nat
entry_requires a / b > 0;
entry_requires b != 0;
requires a / b > 0;
requires b != 0;
{ a / b }
Fix: move entry_requires b != 0 and requires b != 0 before the division.
Unguarded Computed Divisor
// REJECTED - (b - c) could be zero
public func bad(a : Nat, b : Nat, c : Nat) : async Nat
entry_requires b >= c;
requires b >= c;
ensures result == a / (b - c);
{ a / (b - c) }
Fix: add entry_requires (b - c) != 0; requires (b - c) != 0; or use the stronger b > c, which implies b - c > 0 for Nat.
Summary
- Division and modulo in contracts require explicit non-zero guards
- Use
requires d != 0orrequires d > 0for any divisor used in contracts - Put executable
entry_requiresguards before any entry guard that divides - Computed divisors need explicit guards on the full expression
- Literal non-zero divisors are automatically allowed
- Pure functions must use
requiresclauses, not assertions - Use
runtime:assertfor defense-in-depth protection
Related Topics
- Bounds proofs for arithmetic range obligations
- Logical
requiresfor caller obligations - Runtime assertions for executable safety checks
- Entry requires for public actor runtime guards