hevm-0.51.2: src/EVM/Keccak.hs
{-# LANGUAGE DataKinds #-}
{- |
Module: EVM.Keccak
Description: Expr passes to determine Keccak assumptions
-}
module EVM.Keccak (keccakAssumptions) where
import Control.Monad.State
import Data.Set (Set)
import Data.Set qualified as Set
import EVM.Traversals
import EVM.Types
data BuilderState = BuilderState
{ keccaks :: Set (Expr EWord) }
deriving (Show)
initState :: BuilderState
initState = BuilderState { keccaks = Set.empty }
go :: forall a. Expr a -> State BuilderState (Expr a)
go = \case
e@(Keccak _) -> do
s <- get
put $ s{keccaks=Set.insert e s.keccaks}
pure e
e -> pure e
findKeccakExpr :: forall a. Expr a -> State BuilderState (Expr a)
findKeccakExpr e = mapExprM go e
findKeccakProp :: Prop -> State BuilderState Prop
findKeccakProp p = mapPropM go p
findKeccakPropsExprs :: [Prop] -> [Expr Buf] -> [Expr Storage]-> State BuilderState ()
findKeccakPropsExprs ps bufs stores = do
mapM_ findKeccakProp ps;
mapM_ findKeccakExpr bufs;
mapM_ findKeccakExpr stores
combine :: [a] -> [(a,a)]
combine lst = combine' lst []
where
combine' [] acc = concat acc
combine' (x:xs) acc =
let xcomb = [ (x, y) | y <- xs] in
combine' xs (xcomb:acc)
minProp :: Expr EWord -> Prop
minProp k@(Keccak _) = PGT k (Lit 50)
minProp _ = internalError "expected keccak expression"
injProp :: (Expr EWord, Expr EWord) -> Prop
injProp (k1@(Keccak b1), k2@(Keccak b2)) =
POr (PEq b1 b2) (PNeg (PEq k1 k2))
injProp _ = internalError "expected keccak expression"
-- Takes a list of props, find all keccak occurences and generates two kinds of assumptions:
-- 1. Minimum output value: That the output of the invocation is greater than
-- 50 (needed to avoid spurious counterexamples due to storage collisions
-- with solidity mappings & value type storage slots)
-- 2. Injectivity: That keccak is an injective function (we avoid quantifiers
-- here by making this claim for each unique pair of keccak invocations
-- discovered in the input expressions)
keccakAssumptions :: [Prop] -> [Expr Buf] -> [Expr Storage] -> [Prop]
keccakAssumptions ps bufs stores = injectivity <> minValue
where
(_, st) = runState (findKeccakPropsExprs ps bufs stores) initState
injectivity = fmap injProp $ combine (Set.toList st.keccaks)
minValue = fmap minProp (Set.toList st.keccaks)