fantastic bugs - the stanford center for blockchain researchblowing bugs” “the certora-prover...
TRANSCRIPT
& how to automatically find themusing reusable invariants
J A N U A R Y 2 0 2 0 2020
Mooly Sagiv
Fantastic Bugs
Keeping your code secure forever
Free demo & user-guide at demo.certora.com
The Certora Team
Shelly GrossmanChief Scientist
Dr. James WilcoxCTO
Dr. Nurit DorHead of Product
Dr. John TomanFormal Verification Expert
Lior OppenheimSecurity Researcher
Marcelo Taube Product Architect
Thomas BernardiSoftware Engineer
Or PistinerSoftware Engineer
Dr. Alexander NutzFormal Verification Expert
Anastasia Fedotov Software
Engineer
And also
Noam RinetzkyNeil ImmermanUMASS
Daniel Jackson MIT
“…Certora's technology is used daily to locate mind blowing bugs”
“The Certora-Prover has already surfaced significant problems missed by expensive and unscalable manual audits."
“Certora’s Prover tool has already uncovered a number of nuanced bugsand also mathematically proved interesting properties of linked lists.”
Top tier customers
Geoff Hayes, CTO Shamiq Islam, Head of Security Marek Olszweski, Founder
Prover (SaaS)
Code Invariants“what we should do”
Yes
No
Product: Continuous Code Verification
Proofs forguaranteedinvariants
Test cases with inputs showing actual invariantviolations
Customer Code“what we do”V1
V2
V3
MOVEFAST AND
BREAK NOTHING
S a: address balances[a]
transfer (from, to, amount) {require (balances[from] ³ amount);balancesFrom := balances[from] - amount;balancesTo := balances[to] + amount;balances[from] := balancesFrom;balances[to] := balancesTo;
}
Code:
balances@start[from] ³ amountbalancesFrom = balances@start[from] – amountbalancesTo = balances@start[to] + amountbalances[from] = balancesFrom balances[to] = balancesTobalances[from] + balances[to] ¹
balances@start[from] + balances@start[to]
Constraints:
Secret Sauce: Constraint Solving
from=“Alice”to=“Alice”amount = 18balances@start[Alice] = 20balances[Alice] = 38
Solution:Invariant:
The Bug
transfer (Alice, Alice, 18) {require (balances[from] ³ 18);balancesFrom := balances[from] - 18;balancesTo := balances[to] + 18;balances[from] := balancesFrom; balances[to] := balancesTo;
}
Balances [Alice] balances[from] balances[to]
20
The Bug
transfer (Alice, Alice, 18) {require (balances[from] ³ 18);balancesFrom := balances[from] - 18;balancesTo := balances[to] + 18;balances[from] := balancesFrom; balances[to] := balancesTo;
}
Balances [Alice] balances[from] balances[to]
20 2
The Bug
transfer (Alice, Alice, 18) {require (balances[from] ³ 18);balancesFrom := balances[from] - 18;balancesTo := balances[to] + 18;balances[from] := balancesFrom; balances[to] := balancesTo;
}
Balances [Alice] balances[from] balances[to]
20 2 38
The Bug
transfer (Alice, Alice, 18) {require (balances[from] ³ 18);balancesFrom := balances[from] - 18;balancesTo := balances[to] + 18;balances[from] := balancesFrom; balances[to] := balancesTo;
}
Balances [Alice] balances[from] balances[to]
2 2 38
The Bug
transfer (Alice, Alice, 18) {require (balances[from] ³ 18);balancesFrom := balances[from] - 18;balancesTo := balances[to] + 18;balances[from] := balancesFrom; balances[to] := balancesTo;
}
Balances [Alice] balances[from] balances[to]
38 2 38
S a: address balances[a]
Invariant:
S a: address balances[a]
from ¹ tobalances@start[from] ³ amountbalancesFrom = balances@start[from] – amountbalancesTo = balances@start[to] + amountbalances[from] = balancesFrom balances[to] = balancesTobalances[from] + balances[to] ¹
balances@start[from] + balances@start[to]
transfer (from, to, amount) {require(from != to);require (balances[from] ³ amount);balancesFrom := balances[from] - amount;balancesTo := balances[to] + amount;balances[from] := balancesFrom;balances[to] := balancesTo;
}
Code:Constraints:
Secret Sauce: Constraint Solving
Invariant:A mathematical proof that the invariant is maintained
Myths and Reality about Formal Verification
Myths: Reality:
FV can only prove absence of bugs Biggest value of FV is finding bugs
Hardest problem is computational Hardest problem is specification
FV has to be done at accurate machine level Abstraction is key to scalability:- Natural vs. bit-vector arithmetic- Memory abstraction- Loop abstraction- Ignore gas
Must consider all objects at once Modularity concept enable scalability
FV is one-time deal FV guarantees code upgrade safety
The Bounded Supply Invariant (ERC20 tokens)
“Nobody should be able to mint unbounded number of tokens”
Shamiq IslamHead of Security,
Minted tokens < predefined amount
MakerDao Test Version
Bid value
new()
Alice’s bid
Bob’s bid
close()
Max UINT
Total supply increases by Bob’s bid and transferred
to Bob
bid() bid()
Initial bid
Time
Total supply value
Auction end time
Charlie’s bid
bid()
MakerDao Test Version
Bidvalue
new() close()
Max UINT
bid()Time
Total supply value
Mallory’s bid
Total supply increases by Mallory’s bid and
transferred to MalloryBecomes Max UINT!
Bid expiry time
Checking the bounded supply invariant
Fixing the Code
function close(uint id) public {require(auctions[id].bid_expiry != 0
&& (auctions[id].bid_expiry < now || auctions[id].end_time < now));
require(auctions[id].prize.safeAdd(auctions[id].prize)+ getTotalSupply() >= getTotalSupply());
mint(auctions[id].winner, auctions[id].prize);delete auctions[id];}
Checking the bounded supply invariant
High Level Smart Contract Invariants
Immunity to reentrancy attack DAO, SpankChain, Constantinople fork
Robustness
Bounded Token Supply
Informal Property: Bugs Found:
Compound V1 Price Oracle
Maker MCD
Proportional token distribution Compound V2, Maker MCD
Any loan can be fully repaid
Sufficient reserves
Compound V2
Several tokens, Maker MCD
Shelly @ Certora Geoff Hayes @ Compound Shamiq Islam @ Coinbase Jared Flatow @ Compound
Correctness rules for Debt (Compound Finance)
function repayBehalfExplicit(address borrower, CEther cEther_) public payable {
uint received = msg.value;uint borrows = cEther_.borrowBalanceStored(borrower);if (received > borrows) {
cEther_.repayBorrowBehalf.value(borrows)(borrower);msg.sender.transfer(received - borrows);
} else {cEther_.repayBorrowBehalf.value(received)(borrower);
}}
Any debt can be paid off: repayAmount ≥ borrowed è newBorrowBalance = 0
Correctness rules for Debt (Compound Finance)
2530
5
6
0
5
10
15
20
25
30
35
40
… 8 9 10 …
Debt
Repay Ξ 40
Time
Refunded Ξ 10Accrued Ξ 6 interest in 9: > 0 outstanding borrow
6
1
Any debt can be paid off: repayAmount ≥ borrowed è newBorrowBalance = 0
Correctness rules for Debt (Compound Finance)
Any debt can be paid off: repayAmount ≥ borrowed è newBorrowBalance = 0
function repayBehalfExplicit(address borrower, CEther cEther_) public payable {
uint received = msg.value;uint borrows = cEther_.borrowBalanceStored(borrower);if (received > borrows) {
cEther_.repayBorrowBehalf.value(borrows)(borrower);msg.sender.transfer(received - borrows);
} else {cEther_.repayBorrowBehalf.value(received)(borrower);
}}
Correctness rules for Debt (Compound Finance)
Any debt can be paid off: repayAmount ≥ borrowed è newBorrowBalance = 0
function repayBehalfExplicit(address borrower, CEther cEther_) public payable {
uint received = msg.value;uint borrows = cEther_.borrowBalanceStored(borrower);if (received > borrows) {
cEther_.repayBorrowBehalf.value(borrows)(borrower);msg.sender.transfer(received - borrows);
} else {cEther_.repayBorrowBehalf.value(received)(borrower);
}}
cEther_.borrowBalanceCurrent(borrower);
Summary
Software specification is the holy grail of computer science
Reusable invariants provide a layer of security used for early bug detection
Community effort
Code is the law è Spec is the law
1
34
2
Thank you! Mooly [email protected]
Twitter@SagivMooly
www.certora.com
+1-617-650-4612
+972-548-303-111
2020