-
Notifications
You must be signed in to change notification settings - Fork 4
Description
Overview
Enable proving sum properties ("total supply = sum of all balances") by adding finite address set abstraction.
Status: Design clear, well-understood problem
Effort: 1-2 weeks
Difficulty: Medium (requires modeling changes)
Priority: Low (polish, not blocking core verification)
Impact: Completes Ledger contract verification to 100%
Current State
Property Coverage: 70% (203/292)
- ✅ All testable properties are covered!
- ❌ 7 sum properties cannot be proven
The 7 Blocked Properties:
mint_sum_equation- Minting increases total by amountburn_sum_equation- Burning decreases total by amounttransfer_sum_preservation- Transfers preserve totaltotalSupply_equals_sum- Total supply equals sum of all balancesmint_increases_supply- Minting increases total supplyburn_decreases_supply- Burning decreases total supplytransfer_preserves_supply- Transfers don't change total supply
The Problem
Current model: Addresses are unbounded (Nat, representing uint160)
structure State where
balances : Nat → Nat -- Address → Balance (unbounded)
totalSupply : NatIssue: Cannot sum over infinite domain
- Cannot express "sum of all balances"
- Properties like
totalSupply = Σ balancesare unprovable
Proposed Solution
Add Finite Address Set Abstraction
-- Finite set of addresses with bound
structure FiniteAddressSet where
addresses : Finset Address
maxSize : addresses.card ≤ 2^160 -- Bound by uint160 max
-- State with tracked addresses
structure StateWithAddresses where
balances : Nat → Nat
totalSupply : Nat
knownAddresses : FiniteAddressSet
-- Invariant: only knownAddresses have non-zero balances
balances_finite : ∀ addr ∉ knownAddresses.addresses, balances addr = 0Prove Sum Properties
-- Helper: sum balances over finite set
def sum_balances (addrs : Finset Address) (balances : Address → Nat) : Nat :=
addrs.sum (fun addr => balances addr)
-- Main invariant
theorem totalSupply_equals_sum (s : StateWithAddresses) :
s.totalSupply = sum_balances s.knownAddresses.addresses s.balances := by
-- Proof by induction on operations (mint, burn, transfer)
sorry
-- Now we can prove the 7 properties!
theorem mint_preserves_supply_sum (s : StateWithAddresses) (to : Address) (amount : Nat) :
let s' := mint s to amount
sum_balances s'.knownAddresses.addresses s'.balances =
sum_balances s.knownAddresses.addresses s.balances + amount := by
sorryImplementation Plan
Phase 1: Modeling (Week 1)
Files to modify:
DumbContracts/Core.lean- Add FiniteAddressSet- Contract state definitions - Add knownAddresses tracking
Changes:
- Define FiniteAddressSet structure
- Add to contract states
- Update operations to maintain knownAddresses
- Prove finiteness invariant
Phase 2: Sum Properties (Week 2)
Files to modify:
DumbContracts/Specs/Ledger.lean- Add sum property definitionsDumbContracts/Specs/Ledger/Proofs.lean- Prove the 7 properties
Proofs:
totalSupply_equals_sum- Base invariantmint_preserves_supply_sum- Minting adds to bothburn_preserves_supply_sum- Burning subtracts from bothtransfer_preserves_supply_sum- Transfer doesn't change sum- Derive the other 4 from these
Acceptance Criteria
- FiniteAddressSet structure defined
- Contract states track knownAddresses
- All operations maintain knownAddresses invariant
- 7 sum properties proven (no sorries)
- Property coverage increases to ~72%+ (206/292)
- Ledger contract at 100% completeness
- CI passes (all tests)
Impact
Before: 70% property coverage, 7 sum properties unprovable
After: ~72% property coverage, Ledger contract 100% verified
- ✅ All invariants provable
- ✅ Complete verification of supply properties
- ✅ Stronger correctness guarantees
Alternative Approaches
Option B: Bounded Address Space
Use Fin (2^160) instead of Nat for addresses.
Pros: More accurate model
Cons: More complex, may require extensive refactoring
Option C: Ghost State
Add specification-only activeAddresses that tracks non-zero balances.
Pros: Minimal changes to existing code
Cons: Less explicit, harder to reason about
Recommendation: Option A (FiniteAddressSet) - clear, explicit, maintainable
References
- Current properties:
DumbContracts/Specs/Ledger.lean - Property extraction:
docs/ROADMAP.md- Property Extraction section - Finset docs: https://leanprover-community.github.io/mathlib4_docs/Mathlib/Data/Finset/Basic.html
Questions?
This is a well-understood problem with a clear solution. The main work is updating the model and proving the properties - no research needed!