Skip to content

Commit b0e7e9f

Browse files
msoosethblishko
andauthored
Add 2 more Expr simplifications related to negative numbers, enable NOT concretization (#1017)
* Add 2 more Expr simplifications related to negative numbers * Update src/EVM/Expr.hs Co-authored-by: blishko <blishko@argot.org> * Update test/EVM/Expr/ExprTests.hs Co-authored-by: blishko <blishko@argot.org> * Update test/EVM/Expr/ExprTests.hs Co-authored-by: blishko <blishko@argot.org> * Update test/EVM/Expr/ExprTests.hs Co-authored-by: blishko <blishko@argot.org> * Oops, not concretization was missing Testing * Cleaner, thanks to @blishko --------- Co-authored-by: blishko <blishko@argot.org>
1 parent 7d18999 commit b0e7e9f

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
controlled via `merge-max-budget`
1717

1818
## Changed
19+
- Simplifier now rewrites `Mul(-1, x)` and `~x + 1` to `Sub(0, x)`
1920
- `AbiFunction` and `AbiBytes` parser is now more strict
2021
- We now check length of AbiArrayDynamic and don't crash in case it's too large
2122
- SMT queries now run in separate processes, which allows us to better manage

src/EVM/Expr.hs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,6 +1212,9 @@ simplifyNoLitToKeccak e = untilFixpoint (mapExpr go) e
12121212
| b == c = a
12131213
| otherwise = sub (add a b) c
12141214

1215+
-- Negation: ~x + 1 = 0 - x (two's complement)
1216+
go (Add (Lit 1) (Not b)) = Sub (Lit 0) b
1217+
12151218
-- add / sub identities
12161219
go (Add a b)
12171220
| b == (Lit 0) = a
@@ -1223,8 +1226,14 @@ simplifyNoLitToKeccak e = untilFixpoint (mapExpr go) e
12231226
| otherwise = sub a b
12241227

12251228
-- XOR normalization
1229+
go (Xor (Lit a) b) | a == maxLit = EVM.Expr.not b
12261230
go (Xor a b) = EVM.Expr.xor a b
12271231

1232+
-- Not simplification
1233+
go (EVM.Types.Not (EVM.Types.Not a)) = a
1234+
go (Not a) = EVM.Expr.not a
1235+
1236+
-- EqByte
12281237
go (EqByte a b) = eqByte a b
12291238

12301239
-- SHL / SHR / SAR
@@ -1257,8 +1266,6 @@ simplifyNoLitToKeccak e = untilFixpoint (mapExpr go) e
12571266
| b == (Lit 0) = a
12581267
| otherwise = EVM.Expr.or a b
12591268

1260-
-- Double NOT is a no-op, since it's a bitwise inversion
1261-
go (EVM.Types.Not (EVM.Types.Not a)) = a
12621269

12631270
-- Some trivial min / max eliminations
12641271
go (Max a b) = EVM.Expr.max a b
@@ -1271,6 +1278,7 @@ simplifyNoLitToKeccak e = untilFixpoint (mapExpr go) e
12711278
go (Mul a b) = case (a, b) of
12721279
(Lit 0, _) -> Lit 0
12731280
(Lit 1, _) -> b
1281+
(Lit v, _) | v == maxLit -> Sub (Lit 0) b
12741282
_ -> mul a b
12751283

12761284
-- Some trivial (s)div eliminations

test/EVM/Expr/ExprTests.hs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,21 @@ basicSimplificationTests = testGroup "Basic simplification tests"
279279
a = successPath [PEq (Add (Lit 1) (Lit 2)) (Sub (Lit 4) (Lit 1))]
280280
b = Expr.simplify a
281281
assertEqual "Must simplify down" (successPath []) b
282+
, testCase "simp-mul-neg1" $ do
283+
let simp = Expr.simplify $ Mul (Lit Expr.maxLit) (Var "x")
284+
assertEqual "mul by -1 is negation" (Sub (Lit 0) (Var "x")) simp
285+
, testCase "simp-not-plus1" $ do
286+
let simp = Expr.simplify $ Add (Lit 1) (Not (Var "x"))
287+
assertEqual "~x + 1 is negation" (Sub (Lit 0) (Var "x")) simp
288+
, testCase "simp-xor-maxlit-plus1" $ do
289+
let simp = Expr.simplify $ Add (Lit 1) (Xor (Lit Expr.maxLit) (Var "x"))
290+
assertEqual "xor(maxLit, x) + 1 is negation" (Sub (Lit 0) (Var "x")) simp
291+
, testCase "simp-double-not" $ do
292+
let simp = Expr.simplify $ Not (Not (Var "a"))
293+
assertEqual "Not should be concretized" (Var "a") simp
294+
, testCase "simp-not-concrete" $ do
295+
let simp = Expr.simplify $ Not (Lit 0x55)
296+
assertEqual "Not should be concretized" (Lit 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaa) simp
282297
]
283298

284299
propSimplificationTests :: TestTree
@@ -847,4 +862,4 @@ isSatOrUnknown :: SMTResult -> Bool
847862
isSatOrUnknown res = isSat res || isUnknown res
848863

849864
isUnsatOrUnknown :: SMTResult -> Bool
850-
isUnsatOrUnknown res = isQed res || isUnknown res
865+
isUnsatOrUnknown res = isQed res || isUnknown res

0 commit comments

Comments
 (0)