cryptol 2.9.1 → 2.10.0
raw patch · 91 files changed
+10784/−6930 lines, 91 filesdep +MemoTriedep +ghc-primdep +integer-gmpdep ~sbvPVP ok
version bump matches the API change (PVP)
Dependencies added: MemoTrie, ghc-prim, integer-gmp, stm
Dependency ranges changed: sbv
API changes (from Hackage documentation)
- Cryptol.Eval.Arch: maxBigIntWidth :: Integer
- Cryptol.Eval.Backend: SRational :: SInteger sym -> SInteger sym -> SRational sym
- Cryptol.Eval.Backend: [sDenom] :: SRational sym -> SInteger sym
- Cryptol.Eval.Backend: [sNum] :: SRational sym -> SInteger sym
- Cryptol.Eval.Backend: assertSideCondition :: Backend sym => sym -> SBit sym -> EvalError -> SEval sym ()
- Cryptol.Eval.Backend: bitAnd :: Backend sym => sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: bitAsLit :: Backend sym => sym -> SBit sym -> Maybe Bool
- Cryptol.Eval.Backend: bitComplement :: Backend sym => sym -> SBit sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: bitEq :: Backend sym => sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: bitLit :: Backend sym => sym -> Bool -> SBit sym
- Cryptol.Eval.Backend: bitOr :: Backend sym => sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: bitXor :: Backend sym => sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: class MonadIO (SEval sym) => Backend sym where {
- Cryptol.Eval.Backend: cryNoPrimError :: Backend sym => sym -> Name -> SEval sym a
- Cryptol.Eval.Backend: cryUserError :: Backend sym => sym -> String -> SEval sym a
- Cryptol.Eval.Backend: data SRational sym
- Cryptol.Eval.Backend: extractWord :: Backend sym => sym -> Integer -> Integer -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: fpDiv :: Backend sym => FPArith2 sym
- Cryptol.Eval.Backend: fpEq :: Backend sym => sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: fpFromInteger :: Backend sym => sym -> Integer -> Integer -> SWord sym -> SInteger sym -> SEval sym (SFloat sym)
- Cryptol.Eval.Backend: fpGreaterThan :: Backend sym => sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: fpLessThan :: Backend sym => sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: fpLit :: Backend sym => sym -> Integer -> Integer -> Rational -> SEval sym (SFloat sym)
- Cryptol.Eval.Backend: fpMinus :: Backend sym => FPArith2 sym
- Cryptol.Eval.Backend: fpMult :: Backend sym => FPArith2 sym
- Cryptol.Eval.Backend: fpNeg :: Backend sym => sym -> SFloat sym -> SEval sym (SFloat sym)
- Cryptol.Eval.Backend: fpPlus :: Backend sym => FPArith2 sym
- Cryptol.Eval.Backend: fpToInteger :: Backend sym => sym -> String -> SWord sym -> SFloat sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: intDiv :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: intEq :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: intGreaterThan :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: intLessThan :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: intMinus :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: intMod :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: intMult :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: intNegate :: Backend sym => sym -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: intPlus :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: intToRational :: Backend sym => sym -> SInteger sym -> SEval sym (SRational sym)
- Cryptol.Eval.Backend: intToZn :: Backend sym => sym -> Integer -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: integerAsLit :: Backend sym => sym -> SInteger sym -> Maybe Integer
- Cryptol.Eval.Backend: integerLit :: Backend sym => sym -> Integer -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: invalidIndex :: Backend sym => sym -> Integer -> SEval sym a
- Cryptol.Eval.Backend: isReady :: Backend sym => sym -> SEval sym a -> Bool
- Cryptol.Eval.Backend: iteBit :: Backend sym => sym -> SBit sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: iteInteger :: Backend sym => sym -> SBit sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: iteRational :: Backend sym => sym -> SBit sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
- Cryptol.Eval.Backend: iteWord :: Backend sym => sym -> SBit sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: joinWord :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: mergeEval :: Backend sym => sym -> (SBit sym -> a -> a -> SEval sym a) -> SBit sym -> SEval sym a -> SEval sym a -> SEval sym a
- Cryptol.Eval.Backend: packWord :: Backend sym => sym -> [SBit sym] -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: ppBit :: Backend sym => sym -> SBit sym -> Doc
- Cryptol.Eval.Backend: ppFloat :: Backend sym => sym -> PPOpts -> SFloat sym -> Doc
- Cryptol.Eval.Backend: ppInteger :: Backend sym => sym -> PPOpts -> SInteger sym -> Doc
- Cryptol.Eval.Backend: ppRational :: Backend sym => sym -> PPOpts -> SRational sym -> Doc
- Cryptol.Eval.Backend: ppWord :: Backend sym => sym -> PPOpts -> SWord sym -> Doc
- Cryptol.Eval.Backend: raiseError :: Backend sym => sym -> EvalError -> SEval sym a
- Cryptol.Eval.Backend: ratio :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SRational sym)
- Cryptol.Eval.Backend: rationalAdd :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
- Cryptol.Eval.Backend: rationalCeiling :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: rationalDivide :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
- Cryptol.Eval.Backend: rationalEq :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: rationalFloor :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: rationalGreaterThan :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: rationalLessThan :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: rationalMul :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
- Cryptol.Eval.Backend: rationalNegate :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)
- Cryptol.Eval.Backend: rationalRecip :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)
- Cryptol.Eval.Backend: rationalRoundAway :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: rationalRoundToEven :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: rationalSub :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
- Cryptol.Eval.Backend: rationalTrunc :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: sDeclareHole :: Backend sym => sym -> String -> SEval sym (SEval sym a, SEval sym a -> SEval sym ())
- Cryptol.Eval.Backend: sDelay :: Backend sym => sym -> Maybe String -> SEval sym a -> SEval sym (SEval sym a)
- Cryptol.Eval.Backend: sDelayFill :: Backend sym => sym -> SEval sym a -> SEval sym a -> SEval sym (SEval sym a)
- Cryptol.Eval.Backend: sSpark :: Backend sym => sym -> SEval sym a -> SEval sym (SEval sym a)
- Cryptol.Eval.Backend: splitWord :: Backend sym => sym -> Integer -> Integer -> SWord sym -> SEval sym (SWord sym, SWord sym)
- Cryptol.Eval.Backend: type FPArith2 sym = sym -> SWord sym -> SFloat sym -> SFloat sym -> SEval sym (SFloat sym)
- Cryptol.Eval.Backend: type family SEval sym :: Type -> Type;
- Cryptol.Eval.Backend: unpackWord :: Backend sym => sym -> SWord sym -> SEval sym [SBit sym]
- Cryptol.Eval.Backend: wordAnd :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordAsChar :: Backend sym => sym -> SWord sym -> Maybe Char
- Cryptol.Eval.Backend: wordAsLit :: Backend sym => sym -> SWord sym -> Maybe (Integer, Integer)
- Cryptol.Eval.Backend: wordBit :: Backend sym => sym -> SWord sym -> Integer -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: wordComplement :: Backend sym => sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordDiv :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordEq :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: wordFromInt :: Backend sym => sym -> Integer -> SInteger sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordGreaterThan :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: wordLen :: Backend sym => sym -> SWord sym -> Integer
- Cryptol.Eval.Backend: wordLessThan :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: wordLg2 :: Backend sym => sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordLit :: Backend sym => sym -> Integer -> Integer -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordMinus :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordMod :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordMult :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordNegate :: Backend sym => sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordOr :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordPlus :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordSignedDiv :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordSignedLessThan :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: wordSignedMod :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordToInt :: Backend sym => sym -> SWord sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: wordUpdate :: Backend sym => sym -> SWord sym -> Integer -> SBit sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: wordXor :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
- Cryptol.Eval.Backend: znEq :: Backend sym => sym -> Integer -> SInteger sym -> SInteger sym -> SEval sym (SBit sym)
- Cryptol.Eval.Backend: znMinus :: Backend sym => sym -> Integer -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: znMult :: Backend sym => sym -> Integer -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: znNegate :: Backend sym => sym -> Integer -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: znPlus :: Backend sym => sym -> Integer -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: znToInt :: Backend sym => sym -> Integer -> SInteger sym -> SEval sym (SInteger sym)
- Cryptol.Eval.Backend: }
- Cryptol.Eval.Concrete: evalPrim :: PrimIdent -> Maybe Value
- Cryptol.Eval.Concrete.Float: floatPrims :: Concrete -> Map PrimIdent Value
- Cryptol.Eval.Concrete.FloatHelpers: BF :: Integer -> Integer -> BigFloat -> BF
- Cryptol.Eval.Concrete.FloatHelpers: [bfExpWidth] :: BF -> Integer
- Cryptol.Eval.Concrete.FloatHelpers: [bfPrecWidth] :: BF -> Integer
- Cryptol.Eval.Concrete.FloatHelpers: [bfValue] :: BF -> BigFloat
- Cryptol.Eval.Concrete.FloatHelpers: data BF
- Cryptol.Eval.Concrete.FloatHelpers: floatFromBits :: Integer -> Integer -> Integer -> BF
- Cryptol.Eval.Concrete.FloatHelpers: floatFromBits' :: Integer -> Integer -> Integer -> BigFloat
- Cryptol.Eval.Concrete.FloatHelpers: floatFromRational :: Integer -> Integer -> RoundMode -> Rational -> BF
- Cryptol.Eval.Concrete.FloatHelpers: floatToBits :: Integer -> Integer -> BigFloat -> Integer
- Cryptol.Eval.Concrete.FloatHelpers: floatToInteger :: String -> RoundMode -> BF -> Either EvalError Integer
- Cryptol.Eval.Concrete.FloatHelpers: floatToRational :: String -> BF -> Either EvalError Rational
- Cryptol.Eval.Concrete.FloatHelpers: fpCheckStatus :: (BigFloat, Status) -> BigFloat
- Cryptol.Eval.Concrete.FloatHelpers: fpLit :: Integer -> Integer -> Rational -> BF
- Cryptol.Eval.Concrete.FloatHelpers: fpOpts :: Integer -> Integer -> RoundMode -> BFOpts
- Cryptol.Eval.Concrete.FloatHelpers: fpPP :: PPOpts -> BF -> Doc
- Cryptol.Eval.Concrete.FloatHelpers: fpRound :: Integer -> Either EvalError RoundMode
- Cryptol.Eval.Concrete.Value: BV :: !Integer -> !Integer -> BV
- Cryptol.Eval.Concrete.Value: Concrete :: Concrete
- Cryptol.Eval.Concrete.Value: binBV :: Applicative m => (Integer -> Integer -> Integer) -> BV -> BV -> m BV
- Cryptol.Eval.Concrete.Value: bvVal :: BV -> Integer
- Cryptol.Eval.Concrete.Value: data BV
- Cryptol.Eval.Concrete.Value: data Concrete
- Cryptol.Eval.Concrete.Value: fpBinArith :: (BFOpts -> BigFloat -> BigFloat -> (BigFloat, Status)) -> Concrete -> SWord Concrete -> SFloat Concrete -> SFloat Concrete -> SEval Concrete (SFloat Concrete)
- Cryptol.Eval.Concrete.Value: fpRoundMode :: Concrete -> SWord Concrete -> SEval Concrete RoundMode
- Cryptol.Eval.Concrete.Value: instance Cryptol.Eval.Backend.Backend Cryptol.Eval.Concrete.Value.Concrete
- Cryptol.Eval.Concrete.Value: instance GHC.Show.Show Cryptol.Eval.Concrete.Value.BV
- Cryptol.Eval.Concrete.Value: instance GHC.Show.Show Cryptol.Eval.Concrete.Value.Concrete
- Cryptol.Eval.Concrete.Value: integerToChar :: Integer -> Char
- Cryptol.Eval.Concrete.Value: lg2 :: Integer -> Integer
- Cryptol.Eval.Concrete.Value: liftBinIntMod :: Monad m => (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer -> m Integer
- Cryptol.Eval.Concrete.Value: mask :: Integer -> Integer -> Integer
- Cryptol.Eval.Concrete.Value: mkBv :: Integer -> Integer -> BV
- Cryptol.Eval.Concrete.Value: ppBV :: PPOpts -> BV -> Doc
- Cryptol.Eval.Concrete.Value: signedBV :: BV -> Integer
- Cryptol.Eval.Concrete.Value: signedValue :: Integer -> Integer -> Integer
- Cryptol.Eval.Concrete.Value: type Value = GenValue Concrete
- Cryptol.Eval.Concrete.Value: unaryBV :: (Integer -> Integer) -> BV -> BV
- Cryptol.Eval.Monad: AutoExponent :: PPFloatExp
- Cryptol.Eval.Monad: BadRoundingMode :: Integer -> EvalError
- Cryptol.Eval.Monad: BadValue :: String -> EvalError
- Cryptol.Eval.Monad: DivideByZero :: EvalError
- Cryptol.Eval.Monad: EvalOpts :: Logger -> PPOpts -> EvalOpts
- Cryptol.Eval.Monad: FloatFixed :: Int -> PPFloatExp -> PPFloatFormat
- Cryptol.Eval.Monad: FloatFrac :: Int -> PPFloatFormat
- Cryptol.Eval.Monad: FloatFree :: PPFloatExp -> PPFloatFormat
- Cryptol.Eval.Monad: ForceExponent :: PPFloatExp
- Cryptol.Eval.Monad: InvalidIndex :: Maybe Integer -> EvalError
- Cryptol.Eval.Monad: LogNegative :: EvalError
- Cryptol.Eval.Monad: LoopError :: String -> EvalError
- Cryptol.Eval.Monad: NegativeExponent :: EvalError
- Cryptol.Eval.Monad: NoPrim :: Name -> EvalError
- Cryptol.Eval.Monad: PPOpts :: Bool -> Int -> Int -> Int -> PPFloatFormat -> PPOpts
- Cryptol.Eval.Monad: Ready :: !a -> Eval a
- Cryptol.Eval.Monad: Thunk :: !EvalOpts -> IO a -> Eval a
- Cryptol.Eval.Monad: TypeCannotBeDemoted :: Type -> EvalError
- Cryptol.Eval.Monad: UnsupportedSymbolicOp :: String -> Unsupported
- Cryptol.Eval.Monad: UserError :: String -> EvalError
- Cryptol.Eval.Monad: WordTooWide :: Integer -> EvalError
- Cryptol.Eval.Monad: [evalLogger] :: EvalOpts -> Logger
- Cryptol.Eval.Monad: [evalPPOpts] :: EvalOpts -> PPOpts
- Cryptol.Eval.Monad: [useAscii] :: PPOpts -> Bool
- Cryptol.Eval.Monad: [useBase] :: PPOpts -> Int
- Cryptol.Eval.Monad: [useFPBase] :: PPOpts -> Int
- Cryptol.Eval.Monad: [useFPFormat] :: PPOpts -> PPFloatFormat
- Cryptol.Eval.Monad: [useInfLength] :: PPOpts -> Int
- Cryptol.Eval.Monad: blackhole :: String -> Eval (Eval a, Eval a -> Eval ())
- Cryptol.Eval.Monad: data Eval a
- Cryptol.Eval.Monad: data EvalError
- Cryptol.Eval.Monad: data EvalOpts
- Cryptol.Eval.Monad: data PPFloatExp
- Cryptol.Eval.Monad: data PPFloatFormat
- Cryptol.Eval.Monad: data PPOpts
- Cryptol.Eval.Monad: data Unsupported
- Cryptol.Eval.Monad: defaultPPOpts :: PPOpts
- Cryptol.Eval.Monad: delayFill :: Eval a -> Eval a -> Eval (Eval a)
- Cryptol.Eval.Monad: evalPanic :: HasCallStack => String -> [String] -> a
- Cryptol.Eval.Monad: evalSpark :: Eval a -> Eval (Eval a)
- Cryptol.Eval.Monad: getEvalOpts :: Eval EvalOpts
- Cryptol.Eval.Monad: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Cryptol.Eval.Monad.Eval a)
- Cryptol.Eval.Monad: instance Control.Monad.Fail.MonadFail Cryptol.Eval.Monad.Eval
- Cryptol.Eval.Monad: instance Control.Monad.Fix.MonadFix Cryptol.Eval.Monad.Eval
- Cryptol.Eval.Monad: instance Control.Monad.IO.Class.MonadIO Cryptol.Eval.Monad.Eval
- Cryptol.Eval.Monad: instance Cryptol.Utils.PP.PP Cryptol.Eval.Monad.EvalError
- Cryptol.Eval.Monad: instance Cryptol.Utils.PP.PP Cryptol.Eval.Monad.Unsupported
- Cryptol.Eval.Monad: instance GHC.Base.Applicative Cryptol.Eval.Monad.Eval
- Cryptol.Eval.Monad: instance GHC.Base.Functor Cryptol.Eval.Monad.Eval
- Cryptol.Eval.Monad: instance GHC.Base.Monad Cryptol.Eval.Monad.Eval
- Cryptol.Eval.Monad: instance GHC.Exception.Type.Exception Cryptol.Eval.Monad.EvalError
- Cryptol.Eval.Monad: instance GHC.Exception.Type.Exception Cryptol.Eval.Monad.Unsupported
- Cryptol.Eval.Monad: instance GHC.Show.Show Cryptol.Eval.Monad.EvalError
- Cryptol.Eval.Monad: instance GHC.Show.Show Cryptol.Eval.Monad.Unsupported
- Cryptol.Eval.Monad: io :: IO a -> Eval a
- Cryptol.Eval.Monad: ready :: a -> Eval a
- Cryptol.Eval.Monad: runEval :: EvalOpts -> Eval a -> IO a
- Cryptol.Eval.Monad: typeCannotBeDemoted :: Type -> a
- Cryptol.Eval.Monad: wordTooWide :: Integer -> a
- Cryptol.Eval.SBV: SBV :: SBV
- Cryptol.Eval.SBV: SBVError :: !EvalError -> SBVResult a
- Cryptol.Eval.SBV: SBVEval :: Eval (SBVResult a) -> SBVEval a
- Cryptol.Eval.SBV: SBVResult :: !SVal -> !a -> SBVResult a
- Cryptol.Eval.SBV: [sbvEval] :: SBVEval a -> Eval (SBVResult a)
- Cryptol.Eval.SBV: data SBV
- Cryptol.Eval.SBV: data SBVResult a
- Cryptol.Eval.SBV: evalPrim :: PrimIdent -> Maybe Value
- Cryptol.Eval.SBV: existsBV_ :: Int -> Symbolic (SWord SBV)
- Cryptol.Eval.SBV: existsSBool_ :: Symbolic (SBit SBV)
- Cryptol.Eval.SBV: existsSInteger_ :: Symbolic (SBit SBV)
- Cryptol.Eval.SBV: forallBV_ :: Int -> Symbolic (SWord SBV)
- Cryptol.Eval.SBV: forallSBool_ :: Symbolic (SBit SBV)
- Cryptol.Eval.SBV: forallSInteger_ :: Symbolic (SBit SBV)
- Cryptol.Eval.SBV: instance Control.Monad.IO.Class.MonadIO Cryptol.Eval.SBV.SBVEval
- Cryptol.Eval.SBV: instance Cryptol.Eval.Backend.Backend Cryptol.Eval.SBV.SBV
- Cryptol.Eval.SBV: instance GHC.Base.Applicative Cryptol.Eval.SBV.SBVEval
- Cryptol.Eval.SBV: instance GHC.Base.Applicative Cryptol.Eval.SBV.SBVResult
- Cryptol.Eval.SBV: instance GHC.Base.Functor Cryptol.Eval.SBV.SBVEval
- Cryptol.Eval.SBV: instance GHC.Base.Functor Cryptol.Eval.SBV.SBVResult
- Cryptol.Eval.SBV: instance GHC.Base.Monad Cryptol.Eval.SBV.SBVEval
- Cryptol.Eval.SBV: instance GHC.Base.Monad Cryptol.Eval.SBV.SBVResult
- Cryptol.Eval.SBV: newtype SBVEval a
- Cryptol.Eval.SBV: type Value = GenValue SBV
- Cryptol.Eval.Value: instance Cryptol.Eval.Backend.Backend sym => GHC.Show.Show (Cryptol.Eval.Value.GenValue sym)
- Cryptol.Eval.What4: W4Defs :: !Pred sym -> !a -> W4Defs sym a
- Cryptol.Eval.What4: W4Error :: !EvalError -> W4Result sym a
- Cryptol.Eval.What4: W4Result :: !Pred sym -> !a -> W4Result sym a
- Cryptol.Eval.What4: What4 :: sym -> What4 sym
- Cryptol.Eval.What4: [w4Defs] :: W4Defs sym a -> !Pred sym
- Cryptol.Eval.What4: [w4Result] :: W4Defs sym a -> !a
- Cryptol.Eval.What4: data W4Defs sym a
- Cryptol.Eval.What4: data W4Eval sym a
- Cryptol.Eval.What4: data W4Result sym a
- Cryptol.Eval.What4: data What4 sym
- Cryptol.Eval.What4: evalPrim :: IsSymExprBuilder sym => sym -> PrimIdent -> Maybe (Value sym)
- Cryptol.Eval.What4: w4Eval :: W4Eval sym a -> sym -> Eval (W4Defs sym (W4Result sym a))
- Cryptol.Eval.What4.Float: floatPrims :: IsSymExprBuilder sym => What4 sym -> Map PrimIdent (Value sym)
- Cryptol.Eval.What4.SFloat: FPTypeError :: Some BaseTypeRepr -> Some BaseTypeRepr -> FPTypeError
- Cryptol.Eval.What4.SFloat: UnsupportedFloat :: String -> Integer -> UnsupportedFloat
- Cryptol.Eval.What4.SFloat: [SFloat] :: IsExpr (SymExpr sym) => SymFloat sym fpp -> SFloat sym
- Cryptol.Eval.What4.SFloat: [exponentBits, precisionBits] :: UnsupportedFloat -> Integer
- Cryptol.Eval.What4.SFloat: [fpActual] :: FPTypeError -> Some BaseTypeRepr
- Cryptol.Eval.What4.SFloat: [fpExpected] :: FPTypeError -> Some BaseTypeRepr
- Cryptol.Eval.What4.SFloat: [fpWho] :: UnsupportedFloat -> String
- Cryptol.Eval.What4.SFloat: data FPTypeError
- Cryptol.Eval.What4.SFloat: data SFloat sym
- Cryptol.Eval.What4.SFloat: data UnsupportedFloat
- Cryptol.Eval.What4.SFloat: fpAdd :: IsExprBuilder sym => SFloatBinArith sym
- Cryptol.Eval.What4.SFloat: fpDiv :: IsExprBuilder sym => SFloatBinArith sym
- Cryptol.Eval.What4.SFloat: fpEq :: IsExprBuilder sym => SFloatRel sym
- Cryptol.Eval.What4.SFloat: fpEqIEEE :: IsExprBuilder sym => SFloatRel sym
- Cryptol.Eval.What4.SFloat: fpFresh :: IsSymExprBuilder sym => sym -> Integer -> Integer -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: fpFromBinary :: IsExprBuilder sym => sym -> Integer -> Integer -> SWord sym -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: fpFromInteger :: IsExprBuilder sym => sym -> Integer -> Integer -> RoundingMode -> SymInteger sym -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: fpFromRational :: IsExprBuilder sym => sym -> Integer -> Integer -> RoundingMode -> SymInteger sym -> SymInteger sym -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: fpFromRationalLit :: IsExprBuilder sym => sym -> Integer -> Integer -> Rational -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: fpFromReal :: IsExprBuilder sym => sym -> Integer -> Integer -> RoundingMode -> SymReal sym -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: fpGtIEEE :: IsExprBuilder sym => SFloatRel sym
- Cryptol.Eval.What4.SFloat: fpIsInf :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)
- Cryptol.Eval.What4.SFloat: fpIsNaN :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)
- Cryptol.Eval.What4.SFloat: fpLtIEEE :: IsExprBuilder sym => SFloatRel sym
- Cryptol.Eval.What4.SFloat: fpMul :: IsExprBuilder sym => SFloatBinArith sym
- Cryptol.Eval.What4.SFloat: fpNaN :: IsExprBuilder sym => sym -> Integer -> Integer -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: fpNeg :: IsExprBuilder sym => sym -> SFloat sym -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: fpPosInf :: IsExprBuilder sym => sym -> Integer -> Integer -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: fpReprOf :: IsExpr (SymExpr sym) => sym -> SymFloat sym fpp -> FloatPrecisionRepr fpp
- Cryptol.Eval.What4.SFloat: fpRound :: IsExprBuilder sym => sym -> RoundingMode -> SFloat sym -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: fpSize :: SFloat sym -> (Integer, Integer)
- Cryptol.Eval.What4.SFloat: fpSub :: IsExprBuilder sym => SFloatBinArith sym
- Cryptol.Eval.What4.SFloat: fpToBinary :: IsExprBuilder sym => sym -> SFloat sym -> IO (SWord sym)
- Cryptol.Eval.What4.SFloat: fpToRational :: IsSymExprBuilder sym => sym -> SFloat sym -> IO (Pred sym, SymInteger sym, SymInteger sym)
- Cryptol.Eval.What4.SFloat: fpToReal :: IsExprBuilder sym => sym -> SFloat sym -> IO (SymReal sym)
- Cryptol.Eval.What4.SFloat: instance GHC.Exception.Type.Exception Cryptol.Eval.What4.SFloat.FPTypeError
- Cryptol.Eval.What4.SFloat: instance GHC.Exception.Type.Exception Cryptol.Eval.What4.SFloat.UnsupportedFloat
- Cryptol.Eval.What4.SFloat: instance GHC.Show.Show Cryptol.Eval.What4.SFloat.FPTypeError
- Cryptol.Eval.What4.SFloat: instance GHC.Show.Show Cryptol.Eval.What4.SFloat.UnsupportedFloat
- Cryptol.Eval.What4.SFloat: type SFloatBinArith sym = sym -> RoundingMode -> SFloat sym -> SFloat sym -> IO (SFloat sym)
- Cryptol.Eval.What4.SFloat: type SFloatRel sym = sym -> SFloat sym -> SFloat sym -> IO (Pred sym)
- Cryptol.Eval.What4.Value: W4Conn :: (sym -> Eval (W4Defs sym a)) -> W4Conn sym a
- Cryptol.Eval.What4.Value: W4Defs :: !Pred sym -> !a -> W4Defs sym a
- Cryptol.Eval.What4.Value: W4Error :: !EvalError -> W4Result sym a
- Cryptol.Eval.What4.Value: W4Eval :: W4Conn sym (W4Result sym a) -> W4Eval sym a
- Cryptol.Eval.What4.Value: W4Result :: !Pred sym -> !a -> W4Result sym a
- Cryptol.Eval.What4.Value: What4 :: sym -> What4 sym
- Cryptol.Eval.What4.Value: [evalConn] :: W4Conn sym a -> sym -> Eval (W4Defs sym a)
- Cryptol.Eval.What4.Value: [evalPartial] :: W4Eval sym a -> W4Conn sym (W4Result sym a)
- Cryptol.Eval.What4.Value: [w4Defs] :: W4Defs sym a -> !Pred sym
- Cryptol.Eval.What4.Value: [w4Result] :: W4Defs sym a -> !a
- Cryptol.Eval.What4.Value: addDef :: Pred sym -> W4Conn sym ()
- Cryptol.Eval.What4.Value: addDefEqn :: IsExprBuilder sym => Pred sym -> W4Eval sym ()
- Cryptol.Eval.What4.Value: addSafety :: IsExprBuilder sym => Pred sym -> W4Eval sym ()
- Cryptol.Eval.What4.Value: assertBVDivisor :: IsExprBuilder sym => sym -> SWord sym -> W4Eval sym ()
- Cryptol.Eval.What4.Value: assertIntDivisor :: IsExprBuilder sym => sym -> SymInteger sym -> W4Eval sym ()
- Cryptol.Eval.What4.Value: data W4Defs sym a
- Cryptol.Eval.What4.Value: data W4Result sym a
- Cryptol.Eval.What4.Value: data What4 sym
- Cryptol.Eval.What4.Value: doEval :: IsExprBuilder sym => Eval a -> W4Conn sym a
- Cryptol.Eval.What4.Value: evalError :: IsExprBuilder sym => EvalError -> W4Eval sym a
- Cryptol.Eval.What4.Value: evalPanic :: String -> [String] -> a
- Cryptol.Eval.What4.Value: fpBinArith :: IsExprBuilder sym => SFloatBinArith sym -> What4 sym -> SWord (What4 sym) -> SFloat (What4 sym) -> SFloat (What4 sym) -> SEval (What4 sym) (SFloat (What4 sym))
- Cryptol.Eval.What4.Value: fpCvtFromRational :: (IsExprBuilder sy, sym ~ What4 sy) => sym -> Integer -> Integer -> SWord sym -> SRational sym -> SEval sym (SFloat sym)
- Cryptol.Eval.What4.Value: fpCvtToInteger :: (IsExprBuilder sy, sym ~ What4 sy) => sym -> String -> SWord sym -> SFloat sym -> SEval sym (SInteger sym)
- Cryptol.Eval.What4.Value: fpCvtToRational :: (IsSymExprBuilder sy, sym ~ What4 sy) => sym -> SFloat sym -> SEval sym (SRational sym)
- Cryptol.Eval.What4.Value: fpRoundingMode :: IsExprBuilder sym => What4 sym -> SWord (What4 sym) -> SEval (What4 sym) RoundingMode
- Cryptol.Eval.What4.Value: getSym :: IsExprBuilder sym => W4Conn sym sym
- Cryptol.Eval.What4.Value: indexBack_bits :: IsExprBuilder sym => sym -> Nat' -> TValue -> SeqMap (What4 sym) -> TValue -> [SBit (What4 sym)] -> SEval (What4 sym) (Value sym)
- Cryptol.Eval.What4.Value: indexBack_int :: IsExprBuilder sym => sym -> Nat' -> TValue -> SeqMap (What4 sym) -> TValue -> SInteger (What4 sym) -> SEval (What4 sym) (Value sym)
- Cryptol.Eval.What4.Value: indexBack_word :: IsExprBuilder sym => sym -> Nat' -> TValue -> SeqMap (What4 sym) -> TValue -> SWord (What4 sym) -> SEval (What4 sym) (Value sym)
- Cryptol.Eval.What4.Value: indexFront_bits :: forall sym. IsExprBuilder sym => sym -> Nat' -> TValue -> SeqMap (What4 sym) -> TValue -> [SBit (What4 sym)] -> SEval (What4 sym) (Value sym)
- Cryptol.Eval.What4.Value: indexFront_int :: IsExprBuilder sym => sym -> Nat' -> TValue -> SeqMap (What4 sym) -> TValue -> SInteger (What4 sym) -> SEval (What4 sym) (Value sym)
- Cryptol.Eval.What4.Value: indexFront_word :: IsExprBuilder sym => sym -> Nat' -> TValue -> SeqMap (What4 sym) -> TValue -> SWord (What4 sym) -> SEval (What4 sym) (Value sym)
- Cryptol.Eval.What4.Value: instance What4.Interface.IsExprBuilder sym => Control.Monad.IO.Class.MonadIO (Cryptol.Eval.What4.Value.W4Conn sym)
- Cryptol.Eval.What4.Value: instance What4.Interface.IsExprBuilder sym => Control.Monad.IO.Class.MonadIO (Cryptol.Eval.What4.Value.W4Eval sym)
- Cryptol.Eval.What4.Value: instance What4.Interface.IsExprBuilder sym => Cryptol.Eval.Backend.Backend (Cryptol.Eval.What4.Value.What4 sym)
- Cryptol.Eval.What4.Value: instance What4.Interface.IsExprBuilder sym => GHC.Base.Applicative (Cryptol.Eval.What4.Value.W4Conn sym)
- Cryptol.Eval.What4.Value: instance What4.Interface.IsExprBuilder sym => GHC.Base.Applicative (Cryptol.Eval.What4.Value.W4Eval sym)
- Cryptol.Eval.What4.Value: instance What4.Interface.IsExprBuilder sym => GHC.Base.Functor (Cryptol.Eval.What4.Value.W4Conn sym)
- Cryptol.Eval.What4.Value: instance What4.Interface.IsExprBuilder sym => GHC.Base.Functor (Cryptol.Eval.What4.Value.W4Eval sym)
- Cryptol.Eval.What4.Value: instance What4.Interface.IsExprBuilder sym => GHC.Base.Monad (Cryptol.Eval.What4.Value.W4Conn sym)
- Cryptol.Eval.What4.Value: instance What4.Interface.IsExprBuilder sym => GHC.Base.Monad (Cryptol.Eval.What4.Value.W4Eval sym)
- Cryptol.Eval.What4.Value: lazyIte :: (IsExpr p, Monad m) => (p BaseBoolType -> a -> a -> m a) -> p BaseBoolType -> m a -> m a -> m a
- Cryptol.Eval.What4.Value: newtype W4Conn sym a
- Cryptol.Eval.What4.Value: newtype W4Eval sym a
- Cryptol.Eval.What4.Value: sLg2 :: IsExprBuilder sym => sym -> SWord sym -> SEval (What4 sym) (SWord sym)
- Cryptol.Eval.What4.Value: sModAdd :: IsExprBuilder sym => sym -> Integer -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
- Cryptol.Eval.What4.Value: sModMult :: IsExprBuilder sym => sym -> Integer -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
- Cryptol.Eval.What4.Value: sModNegate :: IsExprBuilder sym => sym -> Integer -> SymInteger sym -> IO (SymInteger sym)
- Cryptol.Eval.What4.Value: sModSub :: IsExprBuilder sym => sym -> Integer -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
- Cryptol.Eval.What4.Value: sshrV :: IsExprBuilder sym => sym -> Value sym
- Cryptol.Eval.What4.Value: total :: IsExprBuilder sym => W4Conn sym a -> W4Eval sym a
- Cryptol.Eval.What4.Value: type Value sym = GenValue (What4 sym)
- Cryptol.Eval.What4.Value: updateBackSym :: IsExprBuilder sym => sym -> Nat' -> TValue -> SeqMap (What4 sym) -> Either (SInteger (What4 sym)) (WordValue (What4 sym)) -> SEval (What4 sym) (Value sym) -> SEval (What4 sym) (SeqMap (What4 sym))
- Cryptol.Eval.What4.Value: updateBackSym_word :: IsExprBuilder sym => sym -> Nat' -> TValue -> WordValue (What4 sym) -> Either (SInteger (What4 sym)) (WordValue (What4 sym)) -> SEval (What4 sym) (GenValue (What4 sym)) -> SEval (What4 sym) (WordValue (What4 sym))
- Cryptol.Eval.What4.Value: updateFrontSym :: IsExprBuilder sym => sym -> Nat' -> TValue -> SeqMap (What4 sym) -> Either (SInteger (What4 sym)) (WordValue (What4 sym)) -> SEval (What4 sym) (Value sym) -> SEval (What4 sym) (SeqMap (What4 sym))
- Cryptol.Eval.What4.Value: updateFrontSym_word :: IsExprBuilder sym => sym -> Nat' -> TValue -> WordValue (What4 sym) -> Either (SInteger (What4 sym)) (WordValue (What4 sym)) -> SEval (What4 sym) (GenValue (What4 sym)) -> SEval (What4 sym) (WordValue (What4 sym))
- Cryptol.Eval.What4.Value: w4And :: IsExprBuilder sym => Pred sym -> Pred sym -> W4Conn sym (Pred sym)
- Cryptol.Eval.What4.Value: w4Eval :: W4Eval sym a -> sym -> Eval (W4Defs sym (W4Result sym a))
- Cryptol.Eval.What4.Value: w4ITE :: IsExprBuilder sym => Pred sym -> Pred sym -> Pred sym -> W4Conn sym (Pred sym)
- Cryptol.Eval.What4.Value: w4Not :: IsExprBuilder sym => Pred sym -> W4Conn sym (Pred sym)
- Cryptol.Eval.What4.Value: w4Thunk :: Eval (W4Defs sym (W4Result sym a)) -> W4Eval sym a
- Cryptol.Eval.What4.Value: w4bvAshr :: IsExprBuilder sym => sym -> SWord sym -> SWord sym -> W4Eval sym (SWord sym)
- Cryptol.Eval.What4.Value: w4bvLshr :: IsExprBuilder sym => sym -> SWord sym -> SWord sym -> W4Eval sym (SWord sym)
- Cryptol.Eval.What4.Value: w4bvRol :: IsExprBuilder sym => sym -> SWord sym -> SWord sym -> W4Eval sym (SWord sym)
- Cryptol.Eval.What4.Value: w4bvRor :: IsExprBuilder sym => sym -> SWord sym -> SWord sym -> W4Eval sym (SWord sym)
- Cryptol.Eval.What4.Value: w4bvShl :: IsExprBuilder sym => sym -> SWord sym -> SWord sym -> W4Eval sym (SWord sym)
- Cryptol.Eval.What4.Value: wordValueEqualsInteger :: forall sym. IsExprBuilder sym => sym -> WordValue (What4 sym) -> Integer -> W4Eval sym (Pred sym)
- Cryptol.REPL.Monad: disableLet :: REPL ()
- Cryptol.REPL.Monad: enableLet :: REPL ()
- Cryptol.REPL.Monad: getLetEnabled :: REPL Bool
- Cryptol.Testing.Random: TestSpec :: (Integer -> s -> m (TestResult, s)) -> String -> Integer -> Maybe Integer -> (Integer -> Integer -> m ()) -> m () -> (TestResult -> m ()) -> m () -> TestSpec m s
- Cryptol.Testing.Random: [testClrProgress] :: TestSpec m s -> m ()
- Cryptol.Testing.Random: [testFn] :: TestSpec m s -> Integer -> s -> m (TestResult, s)
- Cryptol.Testing.Random: [testPossible] :: TestSpec m s -> Maybe Integer
- Cryptol.Testing.Random: [testProp] :: TestSpec m s -> String
- Cryptol.Testing.Random: [testRptFailure] :: TestSpec m s -> TestResult -> m ()
- Cryptol.Testing.Random: [testRptProgress] :: TestSpec m s -> Integer -> Integer -> m ()
- Cryptol.Testing.Random: [testRptSuccess] :: TestSpec m s -> m ()
- Cryptol.Testing.Random: [testTotal] :: TestSpec m s -> Integer
- Cryptol.Testing.Random: data TestSpec m s
- Cryptol.Testing.Random: evalTest :: EvalOpts -> Value -> [Value] -> IO TestResult
- Cryptol.Testing.Random: randomBit :: (Backend sym, RandomGen g) => sym -> Gen g sym
- Cryptol.Testing.Random: randomFloat :: (Backend sym, RandomGen g) => sym -> Integer -> Integer -> Gen g sym
- Cryptol.Testing.Random: randomIntMod :: (Backend sym, RandomGen g) => sym -> Integer -> Gen g sym
- Cryptol.Testing.Random: randomInteger :: (Backend sym, RandomGen g) => sym -> Gen g sym
- Cryptol.Testing.Random: randomRational :: (Backend sym, RandomGen g) => sym -> Gen g sym
- Cryptol.Testing.Random: randomRecord :: (Backend sym, RandomGen g) => RecordMap Ident (Gen g sym) -> Gen g sym
- Cryptol.Testing.Random: randomSequence :: (Backend sym, RandomGen g) => Integer -> Gen g sym -> Gen g sym
- Cryptol.Testing.Random: randomSize :: RandomGen g => Int -> Int -> g -> (Int, g)
- Cryptol.Testing.Random: randomStream :: (Backend sym, RandomGen g) => Gen g sym -> Gen g sym
- Cryptol.Testing.Random: randomTuple :: (Backend sym, RandomGen g) => [Gen g sym] -> Gen g sym
- Cryptol.Testing.Random: randomV :: Backend sym => sym -> TValue -> Integer -> SEval sym (GenValue sym)
- Cryptol.Testing.Random: randomWord :: (Backend sym, RandomGen g) => sym -> Integer -> Gen g sym
- Cryptol.Testing.Random: returnOneTest :: RandomGen g => EvalOpts -> Value -> [Gen g Concrete] -> Integer -> g -> IO ([Value], Value, g)
- Cryptol.Testing.Random: runOneTest :: RandomGen g => EvalOpts -> Value -> [Gen g Concrete] -> Integer -> g -> IO (TestResult, g)
- Cryptol.Testing.Random: runTests :: Monad m => TestSpec m s -> s -> m TestReport
- Cryptol.Testing.Random: testableTypeGenerators :: RandomGen g => Type -> Maybe [Gen g Concrete]
- Cryptol.Testing.Random: typeSize :: Type -> Maybe Integer
- Cryptol.Testing.Random: typeValues :: Type -> [Value]
- Cryptol.TypeCheck: ErrorMsg :: Doc -> Error
- Cryptol.TypeCheck.AST: TCErrorMessage :: !String -> TCErrorMessage
- Cryptol.TypeCheck.AST: [tcErrorMessage] :: TCErrorMessage -> !String
- Cryptol.TypeCheck.AST: data TCErrorMessage
- Cryptol.TypeCheck.Error: ErrorMsg :: Doc -> Error
- Cryptol.TypeCheck.Solver.SMT: instance Cryptol.TypeCheck.Solver.SMT.Mk Cryptol.TypeCheck.TCon.TCErrorMessage
- Cryptol.TypeCheck.Subst: instance (GHC.Base.Functor m, Cryptol.TypeCheck.Subst.TVars a) => Cryptol.TypeCheck.Subst.TVars (Cryptol.TypeCheck.TypeMap.List m a)
- Cryptol.TypeCheck.TCon: TCErrorMessage :: !String -> TCErrorMessage
- Cryptol.TypeCheck.TCon: [tcErrorMessage] :: TCErrorMessage -> !String
- Cryptol.TypeCheck.TCon: data TCErrorMessage
- Cryptol.TypeCheck.TCon: instance Control.DeepSeq.NFData Cryptol.TypeCheck.TCon.TCErrorMessage
- Cryptol.TypeCheck.TCon: instance Cryptol.Utils.PP.PP Cryptol.TypeCheck.TCon.TCErrorMessage
- Cryptol.TypeCheck.TCon: instance GHC.Classes.Eq Cryptol.TypeCheck.TCon.TCErrorMessage
- Cryptol.TypeCheck.TCon: instance GHC.Classes.Ord Cryptol.TypeCheck.TCon.TCErrorMessage
- Cryptol.TypeCheck.TCon: instance GHC.Generics.Generic Cryptol.TypeCheck.TCon.TCErrorMessage
- Cryptol.TypeCheck.TCon: instance GHC.Show.Show Cryptol.TypeCheck.TCon.TCErrorMessage
- Cryptol.TypeCheck.Type: data TVarSource
- Cryptol.TypeCheck.Type: instance Control.DeepSeq.NFData Cryptol.TypeCheck.Type.TVarSource
- Cryptol.TypeCheck.Type: instance Cryptol.Utils.PP.PP Cryptol.TypeCheck.Type.TVarSource
- Cryptol.TypeCheck.Type: instance GHC.Generics.Generic Cryptol.TypeCheck.Type.TVarSource
- Cryptol.TypeCheck.Type: instance GHC.Show.Show Cryptol.TypeCheck.Type.TVarSource
- Cryptol.Utils.Patterns: instance (f Data.Type.Equality.~ Cryptol.Utils.Patterns.Pat a a1', a1 Data.Type.Equality.~ Cryptol.Utils.Patterns.Pat a1' r1) => Cryptol.Utils.Patterns.Matches a (f, a1) r1
- Cryptol.Utils.Patterns: instance (op Data.Type.Equality.~ Cryptol.Utils.Patterns.Pat a (a1', a2'), a1 Data.Type.Equality.~ Cryptol.Utils.Patterns.Pat a1' r1, a2 Data.Type.Equality.~ Cryptol.Utils.Patterns.Pat a2' r2) => Cryptol.Utils.Patterns.Matches a (op, a1, a2) (r1, r2)
- Cryptol.Utils.Patterns: instance (op Data.Type.Equality.~ Cryptol.Utils.Patterns.Pat a (a1', a2', a3'), a1 Data.Type.Equality.~ Cryptol.Utils.Patterns.Pat a1' r1, a2 Data.Type.Equality.~ Cryptol.Utils.Patterns.Pat a2' r2, a3 Data.Type.Equality.~ Cryptol.Utils.Patterns.Pat a3' r3) => Cryptol.Utils.Patterns.Matches a (op, a1, a2, a3) (r1, r2, r3)
+ Cryptol.AES: aesFinalRound :: State -> State
+ Cryptol.AES: aesInvFinalRound :: State -> State
+ Cryptol.AES: aesInvRound :: State -> State
+ Cryptol.AES: aesRound :: State -> State
+ Cryptol.AES: invMixColumns :: State -> State
+ Cryptol.AES: keyExpansionWords :: Integer -> Key -> [Word32]
+ Cryptol.AES: type Key = [Word32]
+ Cryptol.AES: type State = [Word32]
+ Cryptol.Backend: SRational :: SInteger sym -> SInteger sym -> SRational sym
+ Cryptol.Backend: [sDenom] :: SRational sym -> SInteger sym
+ Cryptol.Backend: [sNum] :: SRational sym -> SInteger sym
+ Cryptol.Backend: assertSideCondition :: Backend sym => sym -> SBit sym -> EvalError -> SEval sym ()
+ Cryptol.Backend: bitAnd :: Backend sym => sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
+ Cryptol.Backend: bitAsLit :: Backend sym => sym -> SBit sym -> Maybe Bool
+ Cryptol.Backend: bitComplement :: Backend sym => sym -> SBit sym -> SEval sym (SBit sym)
+ Cryptol.Backend: bitEq :: Backend sym => sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
+ Cryptol.Backend: bitLit :: Backend sym => sym -> Bool -> SBit sym
+ Cryptol.Backend: bitOr :: Backend sym => sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
+ Cryptol.Backend: bitXor :: Backend sym => sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
+ Cryptol.Backend: class MonadIO (SEval sym) => Backend sym where {
+ Cryptol.Backend: cryNoPrimError :: Backend sym => sym -> Name -> SEval sym a
+ Cryptol.Backend: cryUserError :: Backend sym => sym -> String -> SEval sym a
+ Cryptol.Backend: data SRational sym
+ Cryptol.Backend: extractWord :: Backend sym => sym -> Integer -> Integer -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: fpDiv :: Backend sym => FPArith2 sym
+ Cryptol.Backend: fpEq :: Backend sym => sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Backend: fpExactLit :: Backend sym => sym -> BF -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpFromInteger :: Backend sym => sym -> Integer -> Integer -> SWord sym -> SInteger sym -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpGreaterThan :: Backend sym => sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Backend: fpLessThan :: Backend sym => sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Backend: fpLit :: Backend sym => sym -> Integer -> Integer -> Rational -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpLogicalEq :: Backend sym => sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Backend: fpMinus :: Backend sym => FPArith2 sym
+ Cryptol.Backend: fpMult :: Backend sym => FPArith2 sym
+ Cryptol.Backend: fpNeg :: Backend sym => sym -> SFloat sym -> SEval sym (SFloat sym)
+ Cryptol.Backend: fpPlus :: Backend sym => FPArith2 sym
+ Cryptol.Backend: fpToInteger :: Backend sym => sym -> String -> SWord sym -> SFloat sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: intDiv :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: intEq :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SBit sym)
+ Cryptol.Backend: intGreaterThan :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SBit sym)
+ Cryptol.Backend: intLessThan :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SBit sym)
+ Cryptol.Backend: intMinus :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: intMod :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: intMult :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: intNegate :: Backend sym => sym -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: intPlus :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: intToRational :: Backend sym => sym -> SInteger sym -> SEval sym (SRational sym)
+ Cryptol.Backend: intToZn :: Backend sym => sym -> Integer -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: integerAsLit :: Backend sym => sym -> SInteger sym -> Maybe Integer
+ Cryptol.Backend: integerLit :: Backend sym => sym -> Integer -> SEval sym (SInteger sym)
+ Cryptol.Backend: invalidIndex :: Backend sym => sym -> Integer -> SEval sym a
+ Cryptol.Backend: isReady :: Backend sym => sym -> SEval sym a -> Bool
+ Cryptol.Backend: iteBit :: Backend sym => sym -> SBit sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)
+ Cryptol.Backend: iteInteger :: Backend sym => sym -> SBit sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: iteRational :: Backend sym => sym -> SBit sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
+ Cryptol.Backend: iteWord :: Backend sym => sym -> SBit sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: joinWord :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: mergeEval :: Backend sym => sym -> (SBit sym -> a -> a -> SEval sym a) -> SBit sym -> SEval sym a -> SEval sym a -> SEval sym a
+ Cryptol.Backend: packWord :: Backend sym => sym -> [SBit sym] -> SEval sym (SWord sym)
+ Cryptol.Backend: ppBit :: Backend sym => sym -> SBit sym -> Doc
+ Cryptol.Backend: ppFloat :: Backend sym => sym -> PPOpts -> SFloat sym -> Doc
+ Cryptol.Backend: ppInteger :: Backend sym => sym -> PPOpts -> SInteger sym -> Doc
+ Cryptol.Backend: ppRational :: Backend sym => sym -> PPOpts -> SRational sym -> Doc
+ Cryptol.Backend: ppWord :: Backend sym => sym -> PPOpts -> SWord sym -> Doc
+ Cryptol.Backend: raiseError :: Backend sym => sym -> EvalError -> SEval sym a
+ Cryptol.Backend: ratio :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SRational sym)
+ Cryptol.Backend: rationalAdd :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
+ Cryptol.Backend: rationalCeiling :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: rationalDivide :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
+ Cryptol.Backend: rationalEq :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)
+ Cryptol.Backend: rationalFloor :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: rationalGreaterThan :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)
+ Cryptol.Backend: rationalLessThan :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)
+ Cryptol.Backend: rationalMul :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
+ Cryptol.Backend: rationalNegate :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)
+ Cryptol.Backend: rationalRecip :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)
+ Cryptol.Backend: rationalRoundAway :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: rationalRoundToEven :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: rationalSub :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)
+ Cryptol.Backend: rationalTrunc :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: sDeclareHole :: Backend sym => sym -> String -> SEval sym (SEval sym a, SEval sym a -> SEval sym ())
+ Cryptol.Backend: sDelay :: Backend sym => sym -> Maybe String -> SEval sym a -> SEval sym (SEval sym a)
+ Cryptol.Backend: sDelayFill :: Backend sym => sym -> SEval sym a -> SEval sym a -> SEval sym (SEval sym a)
+ Cryptol.Backend: sSpark :: Backend sym => sym -> SEval sym a -> SEval sym (SEval sym a)
+ Cryptol.Backend: splitWord :: Backend sym => sym -> Integer -> Integer -> SWord sym -> SEval sym (SWord sym, SWord sym)
+ Cryptol.Backend: type FPArith2 sym = sym -> SWord sym -> SFloat sym -> SFloat sym -> SEval sym (SFloat sym)
+ Cryptol.Backend: type family SEval sym :: Type -> Type;
+ Cryptol.Backend: unpackWord :: Backend sym => sym -> SWord sym -> SEval sym [SBit sym]
+ Cryptol.Backend: wordAnd :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordAsChar :: Backend sym => sym -> SWord sym -> Maybe Char
+ Cryptol.Backend: wordAsLit :: Backend sym => sym -> SWord sym -> Maybe (Integer, Integer)
+ Cryptol.Backend: wordBit :: Backend sym => sym -> SWord sym -> Integer -> SEval sym (SBit sym)
+ Cryptol.Backend: wordComplement :: Backend sym => sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordDiv :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordEq :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SBit sym)
+ Cryptol.Backend: wordFromInt :: Backend sym => sym -> Integer -> SInteger sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordGreaterThan :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SBit sym)
+ Cryptol.Backend: wordLen :: Backend sym => sym -> SWord sym -> Integer
+ Cryptol.Backend: wordLessThan :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SBit sym)
+ Cryptol.Backend: wordLg2 :: Backend sym => sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordLit :: Backend sym => sym -> Integer -> Integer -> SEval sym (SWord sym)
+ Cryptol.Backend: wordMinus :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordMod :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordMult :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordNegate :: Backend sym => sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordOr :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordPlus :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordSignedDiv :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordSignedLessThan :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SBit sym)
+ Cryptol.Backend: wordSignedMod :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordToInt :: Backend sym => sym -> SWord sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: wordUpdate :: Backend sym => sym -> SWord sym -> Integer -> SBit sym -> SEval sym (SWord sym)
+ Cryptol.Backend: wordXor :: Backend sym => sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)
+ Cryptol.Backend: znEq :: Backend sym => sym -> Integer -> SInteger sym -> SInteger sym -> SEval sym (SBit sym)
+ Cryptol.Backend: znMinus :: Backend sym => sym -> Integer -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: znMult :: Backend sym => sym -> Integer -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: znNegate :: Backend sym => sym -> Integer -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: znPlus :: Backend sym => sym -> Integer -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: znRecip :: Backend sym => sym -> Integer -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: znToInt :: Backend sym => sym -> Integer -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Backend: }
+ Cryptol.Backend.Arch: maxBigIntWidth :: Integer
+ Cryptol.Backend.Concrete: BV :: !Integer -> !Integer -> BV
+ Cryptol.Backend.Concrete: Concrete :: Concrete
+ Cryptol.Backend.Concrete: binBV :: Applicative m => (Integer -> Integer -> Integer) -> BV -> BV -> m BV
+ Cryptol.Backend.Concrete: bvVal :: BV -> Integer
+ Cryptol.Backend.Concrete: data BV
+ Cryptol.Backend.Concrete: data Concrete
+ Cryptol.Backend.Concrete: fpBinArith :: (BFOpts -> BigFloat -> BigFloat -> (BigFloat, Status)) -> Concrete -> SWord Concrete -> SFloat Concrete -> SFloat Concrete -> SEval Concrete (SFloat Concrete)
+ Cryptol.Backend.Concrete: fpRoundMode :: Concrete -> SWord Concrete -> SEval Concrete RoundMode
+ Cryptol.Backend.Concrete: instance Cryptol.Backend.Backend Cryptol.Backend.Concrete.Concrete
+ Cryptol.Backend.Concrete: instance GHC.Show.Show Cryptol.Backend.Concrete.BV
+ Cryptol.Backend.Concrete: instance GHC.Show.Show Cryptol.Backend.Concrete.Concrete
+ Cryptol.Backend.Concrete: integerToChar :: Integer -> Char
+ Cryptol.Backend.Concrete: lg2 :: Integer -> Integer
+ Cryptol.Backend.Concrete: liftBinIntMod :: Monad m => (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer -> m Integer
+ Cryptol.Backend.Concrete: mask :: Integer -> Integer -> Integer
+ Cryptol.Backend.Concrete: mkBv :: Integer -> Integer -> BV
+ Cryptol.Backend.Concrete: ppBV :: PPOpts -> BV -> Doc
+ Cryptol.Backend.Concrete: signedBV :: BV -> Integer
+ Cryptol.Backend.Concrete: signedValue :: Integer -> Integer -> Integer
+ Cryptol.Backend.Concrete: unaryBV :: (Integer -> Integer) -> BV -> BV
+ Cryptol.Backend.FloatHelpers: BF :: Integer -> Integer -> BigFloat -> BF
+ Cryptol.Backend.FloatHelpers: [bfExpWidth] :: BF -> Integer
+ Cryptol.Backend.FloatHelpers: [bfPrecWidth] :: BF -> Integer
+ Cryptol.Backend.FloatHelpers: [bfValue] :: BF -> BigFloat
+ Cryptol.Backend.FloatHelpers: data BF
+ Cryptol.Backend.FloatHelpers: floatFromBits :: Integer -> Integer -> Integer -> BF
+ Cryptol.Backend.FloatHelpers: floatFromBits' :: Integer -> Integer -> Integer -> BigFloat
+ Cryptol.Backend.FloatHelpers: floatFromRational :: Integer -> Integer -> RoundMode -> Rational -> BF
+ Cryptol.Backend.FloatHelpers: floatToBits :: Integer -> Integer -> BigFloat -> Integer
+ Cryptol.Backend.FloatHelpers: floatToInteger :: String -> RoundMode -> BF -> Either EvalError Integer
+ Cryptol.Backend.FloatHelpers: floatToRational :: String -> BF -> Either EvalError Rational
+ Cryptol.Backend.FloatHelpers: fpCheckStatus :: (BigFloat, Status) -> BigFloat
+ Cryptol.Backend.FloatHelpers: fpLit :: Integer -> Integer -> Rational -> BF
+ Cryptol.Backend.FloatHelpers: fpOpts :: Integer -> Integer -> RoundMode -> BFOpts
+ Cryptol.Backend.FloatHelpers: fpPP :: PPOpts -> BF -> Doc
+ Cryptol.Backend.FloatHelpers: fpRound :: Integer -> Either EvalError RoundMode
+ Cryptol.Backend.Monad: AutoExponent :: PPFloatExp
+ Cryptol.Backend.Monad: BadRoundingMode :: Integer -> EvalError
+ Cryptol.Backend.Monad: BadValue :: String -> EvalError
+ Cryptol.Backend.Monad: DivideByZero :: EvalError
+ Cryptol.Backend.Monad: Eval :: !IO a -> Eval a
+ Cryptol.Backend.Monad: EvalOpts :: Logger -> PPOpts -> EvalOpts
+ Cryptol.Backend.Monad: FloatFixed :: Int -> PPFloatExp -> PPFloatFormat
+ Cryptol.Backend.Monad: FloatFrac :: Int -> PPFloatFormat
+ Cryptol.Backend.Monad: FloatFree :: PPFloatExp -> PPFloatFormat
+ Cryptol.Backend.Monad: ForceExponent :: PPFloatExp
+ Cryptol.Backend.Monad: InvalidIndex :: Maybe Integer -> EvalError
+ Cryptol.Backend.Monad: LogNegative :: EvalError
+ Cryptol.Backend.Monad: LoopError :: String -> EvalError
+ Cryptol.Backend.Monad: NegativeExponent :: EvalError
+ Cryptol.Backend.Monad: NoPrim :: Name -> EvalError
+ Cryptol.Backend.Monad: PPOpts :: Bool -> Int -> Int -> Int -> PPFloatFormat -> PPOpts
+ Cryptol.Backend.Monad: Ready :: !a -> Eval a
+ Cryptol.Backend.Monad: Thunk :: !TVar (ThunkState a) -> Eval a
+ Cryptol.Backend.Monad: TypeCannotBeDemoted :: Type -> EvalError
+ Cryptol.Backend.Monad: UnsupportedSymbolicOp :: String -> Unsupported
+ Cryptol.Backend.Monad: UserError :: String -> EvalError
+ Cryptol.Backend.Monad: WordTooWide :: Integer -> EvalError
+ Cryptol.Backend.Monad: [evalLogger] :: EvalOpts -> Logger
+ Cryptol.Backend.Monad: [evalPPOpts] :: EvalOpts -> PPOpts
+ Cryptol.Backend.Monad: [useAscii] :: PPOpts -> Bool
+ Cryptol.Backend.Monad: [useBase] :: PPOpts -> Int
+ Cryptol.Backend.Monad: [useFPBase] :: PPOpts -> Int
+ Cryptol.Backend.Monad: [useFPFormat] :: PPOpts -> PPFloatFormat
+ Cryptol.Backend.Monad: [useInfLength] :: PPOpts -> Int
+ Cryptol.Backend.Monad: asciiMode :: PPOpts -> Integer -> Bool
+ Cryptol.Backend.Monad: blackhole :: String -> Eval (Eval a, Eval a -> Eval ())
+ Cryptol.Backend.Monad: data Eval a
+ Cryptol.Backend.Monad: data EvalError
+ Cryptol.Backend.Monad: data EvalOpts
+ Cryptol.Backend.Monad: data PPFloatExp
+ Cryptol.Backend.Monad: data PPFloatFormat
+ Cryptol.Backend.Monad: data PPOpts
+ Cryptol.Backend.Monad: data Unsupported
+ Cryptol.Backend.Monad: defaultPPOpts :: PPOpts
+ Cryptol.Backend.Monad: delayFill :: Eval a -> Eval a -> Eval (Eval a)
+ Cryptol.Backend.Monad: evalPanic :: HasCallStack => String -> [String] -> a
+ Cryptol.Backend.Monad: evalSpark :: Eval a -> Eval (Eval a)
+ Cryptol.Backend.Monad: instance Control.Monad.Fail.MonadFail Cryptol.Backend.Monad.Eval
+ Cryptol.Backend.Monad: instance Control.Monad.Fix.MonadFix Cryptol.Backend.Monad.Eval
+ Cryptol.Backend.Monad: instance Control.Monad.IO.Class.MonadIO Cryptol.Backend.Monad.Eval
+ Cryptol.Backend.Monad: instance Cryptol.Utils.PP.PP Cryptol.Backend.Monad.EvalError
+ Cryptol.Backend.Monad: instance Cryptol.Utils.PP.PP Cryptol.Backend.Monad.Unsupported
+ Cryptol.Backend.Monad: instance GHC.Base.Applicative Cryptol.Backend.Monad.Eval
+ Cryptol.Backend.Monad: instance GHC.Base.Functor Cryptol.Backend.Monad.Eval
+ Cryptol.Backend.Monad: instance GHC.Base.Monad Cryptol.Backend.Monad.Eval
+ Cryptol.Backend.Monad: instance GHC.Exception.Type.Exception Cryptol.Backend.Monad.EvalError
+ Cryptol.Backend.Monad: instance GHC.Exception.Type.Exception Cryptol.Backend.Monad.Unsupported
+ Cryptol.Backend.Monad: instance GHC.Show.Show Cryptol.Backend.Monad.EvalError
+ Cryptol.Backend.Monad: instance GHC.Show.Show Cryptol.Backend.Monad.Unsupported
+ Cryptol.Backend.Monad: io :: IO a -> Eval a
+ Cryptol.Backend.Monad: maybeReady :: Eval a -> Eval (Maybe a)
+ Cryptol.Backend.Monad: ready :: a -> Eval a
+ Cryptol.Backend.Monad: runEval :: Eval a -> IO a
+ Cryptol.Backend.Monad: typeCannotBeDemoted :: Type -> a
+ Cryptol.Backend.Monad: wordTooWide :: Integer -> a
+ Cryptol.Backend.SBV: SBV :: MVar State -> MVar SVal -> SBV
+ Cryptol.Backend.SBV: SBVError :: !EvalError -> SBVResult a
+ Cryptol.Backend.SBV: SBVEval :: Eval (SBVResult a) -> SBVEval a
+ Cryptol.Backend.SBV: SBVResult :: !SVal -> !a -> SBVResult a
+ Cryptol.Backend.SBV: [sbvDefRelations] :: SBV -> MVar SVal
+ Cryptol.Backend.SBV: [sbvEval] :: SBVEval a -> Eval (SBVResult a)
+ Cryptol.Backend.SBV: [sbvStateVar] :: SBV -> MVar State
+ Cryptol.Backend.SBV: addDefEqn :: SBV -> SVal -> IO ()
+ Cryptol.Backend.SBV: ashr :: SVal -> SVal -> SVal
+ Cryptol.Backend.SBV: data SBV
+ Cryptol.Backend.SBV: data SBVResult a
+ Cryptol.Backend.SBV: evalPanic :: String -> [String] -> a
+ Cryptol.Backend.SBV: freshBV_ :: SBV -> Int -> IO (SWord SBV)
+ Cryptol.Backend.SBV: freshSBool_ :: SBV -> IO (SBit SBV)
+ Cryptol.Backend.SBV: freshSInteger_ :: SBV -> IO (SInteger SBV)
+ Cryptol.Backend.SBV: instance Control.Monad.IO.Class.MonadIO Cryptol.Backend.SBV.SBVEval
+ Cryptol.Backend.SBV: instance Cryptol.Backend.Backend Cryptol.Backend.SBV.SBV
+ Cryptol.Backend.SBV: instance GHC.Base.Applicative Cryptol.Backend.SBV.SBVEval
+ Cryptol.Backend.SBV: instance GHC.Base.Applicative Cryptol.Backend.SBV.SBVResult
+ Cryptol.Backend.SBV: instance GHC.Base.Functor Cryptol.Backend.SBV.SBVEval
+ Cryptol.Backend.SBV: instance GHC.Base.Functor Cryptol.Backend.SBV.SBVResult
+ Cryptol.Backend.SBV: instance GHC.Base.Monad Cryptol.Backend.SBV.SBVEval
+ Cryptol.Backend.SBV: instance GHC.Base.Monad Cryptol.Backend.SBV.SBVResult
+ Cryptol.Backend.SBV: literalSWord :: Int -> Integer -> SWord SBV
+ Cryptol.Backend.SBV: lshr :: SVal -> SVal -> SVal
+ Cryptol.Backend.SBV: newtype SBVEval a
+ Cryptol.Backend.SBV: shl :: SVal -> SVal -> SVal
+ Cryptol.Backend.SBV: svFromInteger :: Integer -> SInteger SBV -> SWord SBV
+ Cryptol.Backend.SBV: svToInteger :: SWord SBV -> SInteger SBV
+ Cryptol.Backend.What4: SomeSymFn :: SymFn sym args ret -> SomeSymFn sym
+ Cryptol.Backend.What4: W4Conn :: (sym -> Eval a) -> W4Conn sym a
+ Cryptol.Backend.What4: W4Error :: !EvalError -> W4Result sym a
+ Cryptol.Backend.What4: W4Eval :: W4Conn sym (W4Result sym a) -> W4Eval sym a
+ Cryptol.Backend.What4: W4Result :: !Pred sym -> !a -> W4Result sym a
+ Cryptol.Backend.What4: What4 :: sym -> MVar (Pred sym) -> MVar (What4FunCache sym) -> MVar (Set Text) -> What4 sym
+ Cryptol.Backend.What4: [evalConn] :: W4Conn sym a -> sym -> Eval a
+ Cryptol.Backend.What4: [evalPartial] :: W4Eval sym a -> W4Conn sym (W4Result sym a)
+ Cryptol.Backend.What4: [w4] :: What4 sym -> sym
+ Cryptol.Backend.What4: [w4defs] :: What4 sym -> MVar (Pred sym)
+ Cryptol.Backend.What4: [w4funs] :: What4 sym -> MVar (What4FunCache sym)
+ Cryptol.Backend.What4: [w4uninterpWarns] :: What4 sym -> MVar (Set Text)
+ Cryptol.Backend.What4: addDefEqn :: IsSymExprBuilder sym => What4 sym -> Pred sym -> W4Eval sym ()
+ Cryptol.Backend.What4: addSafety :: IsSymExprBuilder sym => Pred sym -> W4Eval sym ()
+ Cryptol.Backend.What4: assertBVDivisor :: IsSymExprBuilder sym => What4 sym -> SWord sym -> W4Eval sym ()
+ Cryptol.Backend.What4: assertIntDivisor :: IsSymExprBuilder sym => What4 sym -> SymInteger sym -> W4Eval sym ()
+ Cryptol.Backend.What4: data SomeSymFn sym
+ Cryptol.Backend.What4: data W4Result sym a
+ Cryptol.Backend.What4: data What4 sym
+ Cryptol.Backend.What4: doEval :: IsSymExprBuilder sym => Eval a -> W4Conn sym a
+ Cryptol.Backend.What4: evalError :: IsSymExprBuilder sym => EvalError -> W4Eval sym a
+ Cryptol.Backend.What4: evalPanic :: String -> [String] -> a
+ Cryptol.Backend.What4: fpBinArith :: IsSymExprBuilder sym => SFloatBinArith sym -> What4 sym -> SWord (What4 sym) -> SFloat (What4 sym) -> SFloat (What4 sym) -> SEval (What4 sym) (SFloat (What4 sym))
+ Cryptol.Backend.What4: fpCvtFromRational :: (IsSymExprBuilder sy, sym ~ What4 sy) => sym -> Integer -> Integer -> SWord sym -> SRational sym -> SEval sym (SFloat sym)
+ Cryptol.Backend.What4: fpCvtToInteger :: (IsSymExprBuilder sy, sym ~ What4 sy) => sym -> String -> SWord sym -> SFloat sym -> SEval sym (SInteger sym)
+ Cryptol.Backend.What4: fpCvtToRational :: (IsSymExprBuilder sy, sym ~ What4 sy) => sym -> SFloat sym -> SEval sym (SRational sym)
+ Cryptol.Backend.What4: fpRoundingMode :: IsSymExprBuilder sym => What4 sym -> SWord (What4 sym) -> SEval (What4 sym) RoundingMode
+ Cryptol.Backend.What4: getSym :: W4Conn sym sym
+ Cryptol.Backend.What4: instance What4.Interface.IsSymExprBuilder sym => Control.Monad.IO.Class.MonadIO (Cryptol.Backend.What4.W4Conn sym)
+ Cryptol.Backend.What4: instance What4.Interface.IsSymExprBuilder sym => Control.Monad.IO.Class.MonadIO (Cryptol.Backend.What4.W4Eval sym)
+ Cryptol.Backend.What4: instance What4.Interface.IsSymExprBuilder sym => Cryptol.Backend.Backend (Cryptol.Backend.What4.What4 sym)
+ Cryptol.Backend.What4: instance What4.Interface.IsSymExprBuilder sym => GHC.Base.Applicative (Cryptol.Backend.What4.W4Conn sym)
+ Cryptol.Backend.What4: instance What4.Interface.IsSymExprBuilder sym => GHC.Base.Applicative (Cryptol.Backend.What4.W4Eval sym)
+ Cryptol.Backend.What4: instance What4.Interface.IsSymExprBuilder sym => GHC.Base.Functor (Cryptol.Backend.What4.W4Conn sym)
+ Cryptol.Backend.What4: instance What4.Interface.IsSymExprBuilder sym => GHC.Base.Functor (Cryptol.Backend.What4.W4Eval sym)
+ Cryptol.Backend.What4: instance What4.Interface.IsSymExprBuilder sym => GHC.Base.Monad (Cryptol.Backend.What4.W4Conn sym)
+ Cryptol.Backend.What4: instance What4.Interface.IsSymExprBuilder sym => GHC.Base.Monad (Cryptol.Backend.What4.W4Eval sym)
+ Cryptol.Backend.What4: lazyIte :: (IsExpr p, Monad m) => (p BaseBoolType -> a -> a -> m a) -> p BaseBoolType -> m a -> m a -> m a
+ Cryptol.Backend.What4: newtype W4Conn sym a
+ Cryptol.Backend.What4: newtype W4Eval sym a
+ Cryptol.Backend.What4: sLg2 :: IsSymExprBuilder sym => sym -> SWord sym -> SEval (What4 sym) (SWord sym)
+ Cryptol.Backend.What4: sModAdd :: IsSymExprBuilder sym => sym -> Integer -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
+ Cryptol.Backend.What4: sModMult :: IsSymExprBuilder sym => sym -> Integer -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
+ Cryptol.Backend.What4: sModNegate :: IsSymExprBuilder sym => sym -> Integer -> SymInteger sym -> IO (SymInteger sym)
+ Cryptol.Backend.What4: sModRecip :: IsSymExprBuilder sym => What4 sym -> Integer -> SymInteger sym -> W4Eval sym (SymInteger sym)
+ Cryptol.Backend.What4: sModSub :: IsSymExprBuilder sym => sym -> Integer -> SymInteger sym -> SymInteger sym -> IO (SymInteger sym)
+ Cryptol.Backend.What4: total :: IsSymExprBuilder sym => W4Conn sym a -> W4Eval sym a
+ Cryptol.Backend.What4: type What4FunCache sym = Map Text (SomeSymFn sym)
+ Cryptol.Backend.What4: w4And :: IsSymExprBuilder sym => Pred sym -> Pred sym -> W4Conn sym (Pred sym)
+ Cryptol.Backend.What4: w4Eval :: W4Eval sym a -> sym -> Eval (W4Result sym a)
+ Cryptol.Backend.What4: w4ITE :: IsSymExprBuilder sym => Pred sym -> Pred sym -> Pred sym -> W4Conn sym (Pred sym)
+ Cryptol.Backend.What4: w4Not :: IsSymExprBuilder sym => Pred sym -> W4Conn sym (Pred sym)
+ Cryptol.Backend.What4: w4Thunk :: Eval (W4Result sym a) -> W4Eval sym a
+ Cryptol.Backend.What4: w4bvAshr :: IsSymExprBuilder sym => sym -> SWord sym -> SWord sym -> W4Eval sym (SWord sym)
+ Cryptol.Backend.What4: w4bvLshr :: IsSymExprBuilder sym => sym -> SWord sym -> SWord sym -> W4Eval sym (SWord sym)
+ Cryptol.Backend.What4: w4bvRol :: IsSymExprBuilder sym => sym -> SWord sym -> SWord sym -> W4Eval sym (SWord sym)
+ Cryptol.Backend.What4: w4bvRor :: IsSymExprBuilder sym => sym -> SWord sym -> SWord sym -> W4Eval sym (SWord sym)
+ Cryptol.Backend.What4: w4bvShl :: IsSymExprBuilder sym => sym -> SWord sym -> SWord sym -> W4Eval sym (SWord sym)
+ Cryptol.Backend.What4.SFloat: FPTypeError :: Some BaseTypeRepr -> Some BaseTypeRepr -> FPTypeError
+ Cryptol.Backend.What4.SFloat: UnsupportedFloat :: String -> Integer -> UnsupportedFloat
+ Cryptol.Backend.What4.SFloat: [SFloat] :: IsExpr (SymExpr sym) => SymFloat sym fpp -> SFloat sym
+ Cryptol.Backend.What4.SFloat: [exponentBits, precisionBits] :: UnsupportedFloat -> Integer
+ Cryptol.Backend.What4.SFloat: [fpActual] :: FPTypeError -> Some BaseTypeRepr
+ Cryptol.Backend.What4.SFloat: [fpExpected] :: FPTypeError -> Some BaseTypeRepr
+ Cryptol.Backend.What4.SFloat: [fpWho] :: UnsupportedFloat -> String
+ Cryptol.Backend.What4.SFloat: data FPTypeError
+ Cryptol.Backend.What4.SFloat: data SFloat sym
+ Cryptol.Backend.What4.SFloat: data UnsupportedFloat
+ Cryptol.Backend.What4.SFloat: fpAdd :: IsExprBuilder sym => SFloatBinArith sym
+ Cryptol.Backend.What4.SFloat: fpDiv :: IsExprBuilder sym => SFloatBinArith sym
+ Cryptol.Backend.What4.SFloat: fpEq :: IsExprBuilder sym => SFloatRel sym
+ Cryptol.Backend.What4.SFloat: fpEqIEEE :: IsExprBuilder sym => SFloatRel sym
+ Cryptol.Backend.What4.SFloat: fpFresh :: IsSymExprBuilder sym => sym -> Integer -> Integer -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: fpFromBinary :: IsExprBuilder sym => sym -> Integer -> Integer -> SWord sym -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: fpFromInteger :: IsExprBuilder sym => sym -> Integer -> Integer -> RoundingMode -> SymInteger sym -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: fpFromRational :: IsExprBuilder sym => sym -> Integer -> Integer -> RoundingMode -> SymInteger sym -> SymInteger sym -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: fpFromRationalLit :: IsExprBuilder sym => sym -> Integer -> Integer -> Rational -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: fpFromReal :: IsExprBuilder sym => sym -> Integer -> Integer -> RoundingMode -> SymReal sym -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: fpGtIEEE :: IsExprBuilder sym => SFloatRel sym
+ Cryptol.Backend.What4.SFloat: fpIsInf :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)
+ Cryptol.Backend.What4.SFloat: fpIsNaN :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)
+ Cryptol.Backend.What4.SFloat: fpLtIEEE :: IsExprBuilder sym => SFloatRel sym
+ Cryptol.Backend.What4.SFloat: fpMul :: IsExprBuilder sym => SFloatBinArith sym
+ Cryptol.Backend.What4.SFloat: fpNaN :: IsExprBuilder sym => sym -> Integer -> Integer -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: fpNeg :: IsExprBuilder sym => sym -> SFloat sym -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: fpPosInf :: IsExprBuilder sym => sym -> Integer -> Integer -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: fpRepr :: Integer -> Integer -> Maybe (Some FloatPrecisionRepr)
+ Cryptol.Backend.What4.SFloat: fpReprOf :: IsExpr (SymExpr sym) => sym -> SymFloat sym fpp -> FloatPrecisionRepr fpp
+ Cryptol.Backend.What4.SFloat: fpRound :: IsExprBuilder sym => sym -> RoundingMode -> SFloat sym -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: fpSize :: SFloat sym -> (Integer, Integer)
+ Cryptol.Backend.What4.SFloat: fpSub :: IsExprBuilder sym => SFloatBinArith sym
+ Cryptol.Backend.What4.SFloat: fpToBinary :: IsExprBuilder sym => sym -> SFloat sym -> IO (SWord sym)
+ Cryptol.Backend.What4.SFloat: fpToRational :: IsSymExprBuilder sym => sym -> SFloat sym -> IO (Pred sym, SymInteger sym, SymInteger sym)
+ Cryptol.Backend.What4.SFloat: fpToReal :: IsExprBuilder sym => sym -> SFloat sym -> IO (SymReal sym)
+ Cryptol.Backend.What4.SFloat: instance GHC.Exception.Type.Exception Cryptol.Backend.What4.SFloat.FPTypeError
+ Cryptol.Backend.What4.SFloat: instance GHC.Exception.Type.Exception Cryptol.Backend.What4.SFloat.UnsupportedFloat
+ Cryptol.Backend.What4.SFloat: instance GHC.Show.Show Cryptol.Backend.What4.SFloat.FPTypeError
+ Cryptol.Backend.What4.SFloat: instance GHC.Show.Show Cryptol.Backend.What4.SFloat.UnsupportedFloat
+ Cryptol.Backend.What4.SFloat: type SFloatBinArith sym = sym -> RoundingMode -> SFloat sym -> SFloat sym -> IO (SFloat sym)
+ Cryptol.Backend.What4.SFloat: type SFloatRel sym = sym -> SFloat sym -> SFloat sym -> IO (Pred sym)
+ Cryptol.Eval.Concrete: primTable :: EvalOpts -> Map PrimIdent Value
+ Cryptol.Eval.Concrete: type Value = GenValue Concrete
+ Cryptol.Eval.Generic: foldl'V :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: foldlV :: Backend sym => sym -> GenValue sym
+ Cryptol.Eval.Generic: randomV :: Backend sym => sym -> TValue -> Integer -> SEval sym (GenValue sym)
+ Cryptol.Eval.Reference: Err :: EvalError -> E a
+ Cryptol.Eval.Reference: Value :: !a -> E a
+ Cryptol.Eval.Reference: data E a
+ Cryptol.Eval.Reference: instance GHC.Base.Applicative Cryptol.Eval.Reference.E
+ Cryptol.Eval.Reference: instance GHC.Base.Functor Cryptol.Eval.Reference.E
+ Cryptol.Eval.Reference: instance GHC.Base.Monad Cryptol.Eval.Reference.E
+ Cryptol.Eval.Reference: ppEValue :: PPOpts -> E Value -> Doc
+ Cryptol.Eval.SBV: primTable :: SBV -> Map PrimIdent Value
+ Cryptol.Eval.Value: fpExactLit :: Backend sym => sym -> BF -> SEval sym (SFloat sym)
+ Cryptol.Eval.Value: fpLogicalEq :: Backend sym => sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)
+ Cryptol.Eval.Value: instance Cryptol.Backend.Backend sym => GHC.Show.Show (Cryptol.Eval.Value.GenValue sym)
+ Cryptol.Eval.Value: znRecip :: Backend sym => sym -> Integer -> SInteger sym -> SEval sym (SInteger sym)
+ Cryptol.Eval.What4: floatPrims :: IsSymExprBuilder sym => What4 sym -> Map PrimIdent (Value sym)
+ Cryptol.Eval.What4: primTable :: IsSymExprBuilder sym => What4 sym -> Map PrimIdent (Value sym)
+ Cryptol.F2: pdiv :: Int -> Integer -> Integer -> Integer
+ Cryptol.F2: pmod :: Int -> Integer -> Integer -> Integer
+ Cryptol.F2: pmult :: Int -> Integer -> Integer -> Integer
+ Cryptol.Parser.AST: EmptyInput :: ReplInput name
+ Cryptol.Parser.Lexer: MalformedLiteral :: TokenErr
+ Cryptol.Parser.Lexer: MalformedSelector :: TokenErr
+ Cryptol.Parser.Lexer: Selector :: !SelectorType -> TokenT
+ Cryptol.PrimeEC: ProjectivePoint :: !BigNat -> !BigNat -> !BigNat -> ProjectivePoint
+ Cryptol.PrimeEC: [px] :: ProjectivePoint -> !BigNat
+ Cryptol.PrimeEC: [py] :: ProjectivePoint -> !BigNat
+ Cryptol.PrimeEC: [pz] :: ProjectivePoint -> !BigNat
+ Cryptol.PrimeEC: bigNatToInteger :: BigNat -> Integer
+ Cryptol.PrimeEC: data PrimeModulus
+ Cryptol.PrimeEC: data ProjectivePoint
+ Cryptol.PrimeEC: ec_add_nonzero :: PrimeModulus -> ProjectivePoint -> ProjectivePoint -> ProjectivePoint
+ Cryptol.PrimeEC: ec_double :: PrimeModulus -> ProjectivePoint -> ProjectivePoint
+ Cryptol.PrimeEC: ec_mult :: PrimeModulus -> Integer -> ProjectivePoint -> ProjectivePoint
+ Cryptol.PrimeEC: ec_twin_mult :: PrimeModulus -> Integer -> ProjectivePoint -> Integer -> ProjectivePoint -> ProjectivePoint
+ Cryptol.PrimeEC: integerToBigNat :: Integer -> BigNat
+ Cryptol.PrimeEC: primeModulus :: Integer -> PrimeModulus
+ Cryptol.SHA: SHA256Block :: !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> SHA256Block
+ Cryptol.SHA: SHA256S :: !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> !Word32 -> SHA256State
+ Cryptol.SHA: SHA512Block :: !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> SHA512Block
+ Cryptol.SHA: SHA512S :: !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> !Word64 -> SHA512State
+ Cryptol.SHA: calc_k :: Word64 -> Word64 -> Word64 -> Word64
+ Cryptol.SHA: data SHA256Block
+ Cryptol.SHA: data SHA256State
+ Cryptol.SHA: data SHA512Block
+ Cryptol.SHA: data SHA512State
+ Cryptol.SHA: fromBigEndianSBS :: (Integral a, Bits a) => ByteString -> a
+ Cryptol.SHA: initialSHA224State :: SHA256State
+ Cryptol.SHA: initialSHA256State :: SHA256State
+ Cryptol.SHA: initialSHA384State :: SHA512State
+ Cryptol.SHA: initialSHA512State :: SHA512State
+ Cryptol.SHA: padSHA1 :: ByteString -> ByteString
+ Cryptol.SHA: padSHA1Chunks :: Int -> [ByteString]
+ Cryptol.SHA: padSHA512 :: ByteString -> ByteString
+ Cryptol.SHA: padSHA512Chunks :: Int -> [ByteString]
+ Cryptol.SHA: processSHA256Block :: SHA256State -> SHA256Block -> SHA256State
+ Cryptol.SHA: processSHA512Block :: SHA512State -> SHA512Block -> SHA512State
+ Cryptol.SHA: toBigEndianSBS :: (Integral a, Bits a) => Int -> a -> ByteString
+ Cryptol.Symbolic: FreshVarFns :: IO (SBit sym) -> (Integer -> IO (SWord sym)) -> (Maybe Integer -> Maybe Integer -> IO (SInteger sym)) -> (Integer -> Integer -> IO (SFloat sym)) -> FreshVarFns sym
+ Cryptol.Symbolic: VarBit :: SBit sym -> VarShape sym
+ Cryptol.Symbolic: VarFinSeq :: Integer -> [VarShape sym] -> VarShape sym
+ Cryptol.Symbolic: VarFloat :: SFloat sym -> VarShape sym
+ Cryptol.Symbolic: VarInteger :: SInteger sym -> VarShape sym
+ Cryptol.Symbolic: VarRational :: SInteger sym -> SInteger sym -> VarShape sym
+ Cryptol.Symbolic: VarRecord :: RecordMap Ident (VarShape sym) -> VarShape sym
+ Cryptol.Symbolic: VarTuple :: [VarShape sym] -> VarShape sym
+ Cryptol.Symbolic: VarWord :: SWord sym -> VarShape sym
+ Cryptol.Symbolic: [freshBitVar] :: FreshVarFns sym -> IO (SBit sym)
+ Cryptol.Symbolic: [freshFloatVar] :: FreshVarFns sym -> Integer -> Integer -> IO (SFloat sym)
+ Cryptol.Symbolic: [freshIntegerVar] :: FreshVarFns sym -> Maybe Integer -> Maybe Integer -> IO (SInteger sym)
+ Cryptol.Symbolic: [freshWordVar] :: FreshVarFns sym -> Integer -> IO (SWord sym)
+ Cryptol.Symbolic: computeModel :: PrimMap -> [FinType] -> [VarShape Concrete] -> [(Type, Expr, Value)]
+ Cryptol.Symbolic: data FreshVarFns sym
+ Cryptol.Symbolic: data VarShape sym
+ Cryptol.Symbolic: freshVar :: Backend sym => FreshVarFns sym -> FinType -> IO (VarShape sym)
+ Cryptol.Symbolic: modelPred :: Backend sym => sym -> [VarShape sym] -> [VarShape Concrete] -> SEval sym (SBit sym)
+ Cryptol.Symbolic: varModelPred :: Backend sym => sym -> (VarShape sym, VarShape Concrete) -> SEval sym (SBit sym)
+ Cryptol.Symbolic: varShapeToValue :: Backend sym => sym -> VarShape sym -> GenValue sym
+ Cryptol.Symbolic: varToExpr :: PrimMap -> FinType -> VarShape Concrete -> Expr
+ Cryptol.Testing.Random: exhaustiveTests :: MonadIO m => (Integer -> m ()) -> Value -> [[Value]] -> m (TestResult, Integer)
+ Cryptol.Testing.Random: randomTests :: (MonadIO m, RandomGen g) => (Integer -> m ()) -> Integer -> Value -> [Gen g Concrete] -> g -> m (TestResult, Integer)
+ Cryptol.TypeCheck: MissingModTParam :: Located Ident -> Error
+ Cryptol.TypeCheck: MissingModVParam :: Located Ident -> Error
+ Cryptol.TypeCheck: TypeShadowing :: String -> Name -> String -> Error
+ Cryptol.TypeCheck: UndefinedExistVar :: Name -> Error
+ Cryptol.TypeCheck: UnsolvableGoals :: [Goal] -> Error
+ Cryptol.TypeCheck: WithNames :: a -> NameMap -> WithNames a
+ Cryptol.TypeCheck: data WithNames a
+ Cryptol.TypeCheck: ppNamedError :: NameMap -> (Range, Error) -> Doc
+ Cryptol.TypeCheck: ppNamedWarning :: NameMap -> (Range, Warning) -> Doc
+ Cryptol.TypeCheck: type NameMap = IntMap String
+ Cryptol.TypeCheck.Error: MissingModTParam :: Located Ident -> Error
+ Cryptol.TypeCheck.Error: MissingModVParam :: Located Ident -> Error
+ Cryptol.TypeCheck.Error: TypeShadowing :: String -> Name -> String -> Error
+ Cryptol.TypeCheck.Error: UndefinedExistVar :: Name -> Error
+ Cryptol.TypeCheck.Error: UnsolvableGoals :: [Goal] -> Error
+ Cryptol.TypeCheck.Error: computeFreeVarNames :: [(Range, Warning)] -> [(Range, Error)] -> NameMap
+ Cryptol.TypeCheck.Error: errorImportance :: Error -> Int
+ Cryptol.TypeCheck.Error: explainUnsolvable :: NameMap -> [Goal] -> Doc
+ Cryptol.TypeCheck.InferTypes: selSrc :: Selector -> TypeSource
+ Cryptol.TypeCheck.Solver.Numeric: cryIsPrime :: Ctxt -> Type -> Solved
+ Cryptol.TypeCheck.Solver.Numeric: primeTable :: Integer :->: Bool
+ Cryptol.TypeCheck.Subst: (!$) :: (a -> b) -> a -> b
+ Cryptol.TypeCheck.Subst: (.$) :: (a -> b) -> a -> b
+ Cryptol.TypeCheck.Subst: fmap' :: Traversable t => (a -> b) -> t a -> t b
+ Cryptol.TypeCheck.Subst: infixl 0 .$
+ Cryptol.TypeCheck.Subst: instance (Data.Traversable.Traversable m, Cryptol.TypeCheck.Subst.TVars a) => Cryptol.TypeCheck.Subst.TVars (Cryptol.TypeCheck.TypeMap.List m a)
+ Cryptol.TypeCheck.Subst: instance Data.Foldable.Foldable Cryptol.TypeCheck.Subst.Done
+ Cryptol.TypeCheck.Subst: instance Data.Traversable.Traversable Cryptol.TypeCheck.Subst.Done
+ Cryptol.TypeCheck.Subst: instance GHC.Base.Applicative Cryptol.TypeCheck.Subst.Done
+ Cryptol.TypeCheck.Subst: instance GHC.Base.Functor Cryptol.TypeCheck.Subst.Done
+ Cryptol.TypeCheck.TCon: PPrime :: PC
+ Cryptol.TypeCheck.Type: ArgDescr :: Maybe Name -> Maybe Int -> ArgDescr
+ Cryptol.TypeCheck.Type: FunApp :: TypeSource
+ Cryptol.TypeCheck.Type: GeneratorOfListComp :: TypeSource
+ Cryptol.TypeCheck.Type: TypeFromUserAnnotation :: TypeSource
+ Cryptol.TypeCheck.Type: TypeOfIfCondExpr :: TypeSource
+ Cryptol.TypeCheck.Type: WithSource :: Type -> TypeSource -> TypeWithSource
+ Cryptol.TypeCheck.Type: [argDescrFun] :: ArgDescr -> Maybe Name
+ Cryptol.TypeCheck.Type: [argDescrNumber] :: ArgDescr -> Maybe Int
+ Cryptol.TypeCheck.Type: [twsSource] :: TypeWithSource -> TypeSource
+ Cryptol.TypeCheck.Type: [twsType] :: TypeWithSource -> Type
+ Cryptol.TypeCheck.Type: data ArgDescr
+ Cryptol.TypeCheck.Type: data TypeSource
+ Cryptol.TypeCheck.Type: data TypeWithSource
+ Cryptol.TypeCheck.Type: instance Control.DeepSeq.NFData Cryptol.TypeCheck.Type.ArgDescr
+ Cryptol.TypeCheck.Type: instance Control.DeepSeq.NFData Cryptol.TypeCheck.Type.TypeSource
+ Cryptol.TypeCheck.Type: instance Cryptol.Utils.PP.PP Cryptol.TypeCheck.Type.ArgDescr
+ Cryptol.TypeCheck.Type: instance Cryptol.Utils.PP.PP Cryptol.TypeCheck.Type.TypeSource
+ Cryptol.TypeCheck.Type: instance GHC.Generics.Generic Cryptol.TypeCheck.Type.ArgDescr
+ Cryptol.TypeCheck.Type: instance GHC.Generics.Generic Cryptol.TypeCheck.Type.TypeSource
+ Cryptol.TypeCheck.Type: instance GHC.Show.Show Cryptol.TypeCheck.Type.ArgDescr
+ Cryptol.TypeCheck.Type: instance GHC.Show.Show Cryptol.TypeCheck.Type.TypeSource
+ Cryptol.TypeCheck.Type: noArgDescr :: ArgDescr
+ Cryptol.TypeCheck.Type: pIsPrime :: Prop -> Maybe Type
+ Cryptol.TypeCheck.Type: pPrime :: Type -> Prop
+ Cryptol.TypeCheck.Type: tHasErrors :: Type -> Bool
+ Cryptol.TypeCheck.Type: tvUnique :: TVar -> Int
+ Cryptol.TypeCheck.TypeMap: instance Data.Foldable.Foldable Cryptol.TypeCheck.TypeMap.TypeMap
+ Cryptol.TypeCheck.TypeMap: instance Data.Foldable.Foldable m => Data.Foldable.Foldable (Cryptol.TypeCheck.TypeMap.List m)
+ Cryptol.TypeCheck.TypeMap: instance Data.Traversable.Traversable Cryptol.TypeCheck.TypeMap.TypeMap
+ Cryptol.TypeCheck.TypeMap: instance Data.Traversable.Traversable m => Data.Traversable.Traversable (Cryptol.TypeCheck.TypeMap.List m)
+ Cryptol.Utils.Ident: preludeReferenceName :: ModName
+ Cryptol.Utils.Ident: primeECName :: ModName
+ Cryptol.Utils.Ident: primeECPrim :: Text -> PrimIdent
+ Cryptol.Utils.Ident: suiteBName :: ModName
+ Cryptol.Utils.Ident: suiteBPrim :: Text -> PrimIdent
+ Cryptol.Utils.Patterns: instance (f GHC.Types.~ Cryptol.Utils.Patterns.Pat a a1', a1 GHC.Types.~ Cryptol.Utils.Patterns.Pat a1' r1) => Cryptol.Utils.Patterns.Matches a (f, a1) r1
+ Cryptol.Utils.Patterns: instance (op GHC.Types.~ Cryptol.Utils.Patterns.Pat a (a1', a2'), a1 GHC.Types.~ Cryptol.Utils.Patterns.Pat a1' r1, a2 GHC.Types.~ Cryptol.Utils.Patterns.Pat a2' r2) => Cryptol.Utils.Patterns.Matches a (op, a1, a2) (r1, r2)
+ Cryptol.Utils.Patterns: instance (op GHC.Types.~ Cryptol.Utils.Patterns.Pat a (a1', a2', a3'), a1 GHC.Types.~ Cryptol.Utils.Patterns.Pat a1' r1, a2 GHC.Types.~ Cryptol.Utils.Patterns.Pat a2' r2, a3 GHC.Types.~ Cryptol.Utils.Patterns.Pat a3' r3) => Cryptol.Utils.Patterns.Matches a (op, a1, a2, a3) (r1, r2, r3)
- Cryptol.Eval: evalSetSel :: forall sym. EvalPrims sym => sym -> GenValue sym -> Selector -> SEval sym (GenValue sym) -> SEval sym (GenValue sym)
+ Cryptol.Eval: evalSetSel :: forall sym. EvalPrims sym => sym -> TValue -> GenValue sym -> Selector -> SEval sym (GenValue sym) -> SEval sym (GenValue sym)
- Cryptol.Eval: runEval :: EvalOpts -> Eval a -> IO a
+ Cryptol.Eval: runEval :: Eval a -> IO a
- Cryptol.Eval.Env: EvalEnv :: !Map Name (SEval sym (GenValue sym)) -> !TypeEnv -> GenEvalEnv sym
+ Cryptol.Eval.Env: EvalEnv :: !IntMap (SEval sym (GenValue sym)) -> !TypeEnv -> GenEvalEnv sym
- Cryptol.Eval.Env: [envVars] :: GenEvalEnv sym -> !Map Name (SEval sym (GenValue sym))
+ Cryptol.Eval.Env: [envVars] :: GenEvalEnv sym -> !IntMap (SEval sym (GenValue sym))
- Cryptol.Eval.Reference: VBit :: Either EvalError Bool -> Value
+ Cryptol.Eval.Reference: VBit :: !Bool -> Value
- Cryptol.Eval.Reference: VFloat :: Either EvalError BF -> Value
+ Cryptol.Eval.Reference: VFloat :: !BF -> Value
- Cryptol.Eval.Reference: VFun :: (Value -> Value) -> Value
+ Cryptol.Eval.Reference: VFun :: (E Value -> E Value) -> Value
- Cryptol.Eval.Reference: VInteger :: Either EvalError Integer -> Value
+ Cryptol.Eval.Reference: VInteger :: !Integer -> Value
- Cryptol.Eval.Reference: VList :: Nat' -> [Value] -> Value
+ Cryptol.Eval.Reference: VList :: Nat' -> [E Value] -> Value
- Cryptol.Eval.Reference: VNumPoly :: (Nat' -> Value) -> Value
+ Cryptol.Eval.Reference: VNumPoly :: (Nat' -> E Value) -> Value
- Cryptol.Eval.Reference: VPoly :: (TValue -> Value) -> Value
+ Cryptol.Eval.Reference: VPoly :: (TValue -> E Value) -> Value
- Cryptol.Eval.Reference: VRational :: Either EvalError Rational -> Value
+ Cryptol.Eval.Reference: VRational :: !Rational -> Value
- Cryptol.Eval.Reference: VRecord :: [(Ident, Value)] -> Value
+ Cryptol.Eval.Reference: VRecord :: [(Ident, E Value)] -> Value
- Cryptol.Eval.Reference: VTuple :: [Value] -> Value
+ Cryptol.Eval.Reference: VTuple :: [E Value] -> Value
- Cryptol.Eval.Reference: evalExpr :: Env -> Expr -> Value
+ Cryptol.Eval.Reference: evalExpr :: Env -> Expr -> E Value
- Cryptol.Eval.Reference: evaluate :: Expr -> ModuleCmd Value
+ Cryptol.Eval.Reference: evaluate :: Expr -> ModuleCmd (E Value)
- Cryptol.Eval.Type: evalNumType :: HasCallStack => TypeEnv -> Type -> Nat'
+ Cryptol.Eval.Type: evalNumType :: TypeEnv -> Type -> Nat'
- Cryptol.Eval.Type: evalTF :: HasCallStack => TFun -> [Nat'] -> Nat'
+ Cryptol.Eval.Type: evalTF :: TFun -> [Nat'] -> Nat'
- Cryptol.Eval.Type: evalType :: HasCallStack => TypeEnv -> Type -> Either Nat' TValue
+ Cryptol.Eval.Type: evalType :: TypeEnv -> Type -> Either Nat' TValue
- Cryptol.Eval.Type: evalValType :: HasCallStack => TypeEnv -> Type -> TValue
+ Cryptol.Eval.Type: evalValType :: TypeEnv -> Type -> TValue
- Cryptol.Eval.Type: type TypeEnv = Map TVar (Either Nat' TValue)
+ Cryptol.Eval.Type: type TypeEnv = IntMap (Either Nat' TValue)
- Cryptol.ModuleSystem: IfaceDecl :: !Name -> Schema -> [Pragma] -> Bool -> Maybe Fixity -> Maybe String -> IfaceDecl
+ Cryptol.ModuleSystem: IfaceDecl :: !Name -> Schema -> [Pragma] -> Bool -> Maybe Fixity -> Maybe Text -> IfaceDecl
- Cryptol.ModuleSystem: TypeCheckWarnings :: [(Range, Warning)] -> ModuleWarning
+ Cryptol.ModuleSystem: TypeCheckWarnings :: NameMap -> [(Range, Warning)] -> ModuleWarning
- Cryptol.ModuleSystem: TypeCheckingFailed :: ImportSource -> [(Range, Error)] -> ModuleError
+ Cryptol.ModuleSystem: TypeCheckingFailed :: ImportSource -> NameMap -> [(Range, Error)] -> ModuleError
- Cryptol.ModuleSystem: [ifDeclDoc] :: IfaceDecl -> Maybe String
+ Cryptol.ModuleSystem: [ifDeclDoc] :: IfaceDecl -> Maybe Text
- Cryptol.ModuleSystem.Base: doLoadModule :: ImportSource -> ModulePath -> Fingerprint -> Module PName -> ModuleM Module
+ Cryptol.ModuleSystem.Base: doLoadModule :: Bool -> ImportSource -> ModulePath -> Fingerprint -> Module PName -> ModuleM Module
- Cryptol.ModuleSystem.Base: loadModuleFrom :: ImportSource -> ModuleM (ModulePath, Module)
+ Cryptol.ModuleSystem.Base: loadModuleFrom :: Bool -> ImportSource -> ModuleM (ModulePath, Module)
- Cryptol.ModuleSystem.Interface: IfaceDecl :: !Name -> Schema -> [Pragma] -> Bool -> Maybe Fixity -> Maybe String -> IfaceDecl
+ Cryptol.ModuleSystem.Interface: IfaceDecl :: !Name -> Schema -> [Pragma] -> Bool -> Maybe Fixity -> Maybe Text -> IfaceDecl
- Cryptol.ModuleSystem.Interface: [ifDeclDoc] :: IfaceDecl -> Maybe String
+ Cryptol.ModuleSystem.Interface: [ifDeclDoc] :: IfaceDecl -> Maybe Text
- Cryptol.ModuleSystem.Monad: TypeCheckWarnings :: [(Range, Warning)] -> ModuleWarning
+ Cryptol.ModuleSystem.Monad: TypeCheckWarnings :: NameMap -> [(Range, Warning)] -> ModuleWarning
- Cryptol.ModuleSystem.Monad: TypeCheckingFailed :: ImportSource -> [(Range, Error)] -> ModuleError
+ Cryptol.ModuleSystem.Monad: TypeCheckingFailed :: ImportSource -> NameMap -> [(Range, Error)] -> ModuleError
- Cryptol.ModuleSystem.Monad: typeCheckWarnings :: [(Range, Warning)] -> ModuleM ()
+ Cryptol.ModuleSystem.Monad: typeCheckWarnings :: NameMap -> [(Range, Warning)] -> ModuleM ()
- Cryptol.ModuleSystem.Monad: typeCheckingFailed :: [(Range, Error)] -> ModuleM a
+ Cryptol.ModuleSystem.Monad: typeCheckingFailed :: NameMap -> [(Range, Error)] -> ModuleM a
- Cryptol.Parser.AST: BinFrac :: FracInfo
+ Cryptol.Parser.AST: BinFrac :: Text -> FracInfo
- Cryptol.Parser.AST: BinLit :: Int -> NumInfo
+ Cryptol.Parser.AST: BinLit :: Text -> Int -> NumInfo
- Cryptol.Parser.AST: Bind :: Located name -> [Pattern name] -> Located (BindDef name) -> Maybe (Schema name) -> Bool -> Maybe Fixity -> [Pragma] -> Bool -> Maybe String -> Bind name
+ Cryptol.Parser.AST: Bind :: Located name -> [Pattern name] -> Located (BindDef name) -> Maybe (Schema name) -> Bool -> Maybe Fixity -> [Pragma] -> Bool -> Maybe Text -> Bind name
- Cryptol.Parser.AST: DecFrac :: FracInfo
+ Cryptol.Parser.AST: DecFrac :: Text -> FracInfo
- Cryptol.Parser.AST: DecLit :: NumInfo
+ Cryptol.Parser.AST: DecLit :: Text -> NumInfo
- Cryptol.Parser.AST: HexFrac :: FracInfo
+ Cryptol.Parser.AST: HexFrac :: Text -> FracInfo
- Cryptol.Parser.AST: HexLit :: Int -> NumInfo
+ Cryptol.Parser.AST: HexLit :: Text -> Int -> NumInfo
- Cryptol.Parser.AST: OctFrac :: FracInfo
+ Cryptol.Parser.AST: OctFrac :: Text -> FracInfo
- Cryptol.Parser.AST: OctLit :: Int -> NumInfo
+ Cryptol.Parser.AST: OctLit :: Text -> Int -> NumInfo
- Cryptol.Parser.AST: ParameterFun :: Located name -> Schema name -> Maybe String -> Maybe Fixity -> ParameterFun name
+ Cryptol.Parser.AST: ParameterFun :: Located name -> Schema name -> Maybe Text -> Maybe Fixity -> ParameterFun name
- Cryptol.Parser.AST: ParameterType :: Located name -> Kind -> Maybe String -> Maybe Fixity -> !Int -> ParameterType name
+ Cryptol.Parser.AST: ParameterType :: Located name -> Kind -> Maybe Text -> Maybe Fixity -> !Int -> ParameterType name
- Cryptol.Parser.AST: TopLevel :: ExportType -> Maybe (Located String) -> a -> TopLevel a
+ Cryptol.Parser.AST: TopLevel :: ExportType -> Maybe (Located Text) -> a -> TopLevel a
- Cryptol.Parser.AST: [bDoc] :: Bind name -> Maybe String
+ Cryptol.Parser.AST: [bDoc] :: Bind name -> Maybe Text
- Cryptol.Parser.AST: [pfDoc] :: ParameterFun name -> Maybe String
+ Cryptol.Parser.AST: [pfDoc] :: ParameterFun name -> Maybe Text
- Cryptol.Parser.AST: [ptDoc] :: ParameterType name -> Maybe String
+ Cryptol.Parser.AST: [ptDoc] :: ParameterType name -> Maybe Text
- Cryptol.Parser.AST: [tlDoc] :: TopLevel a -> Maybe (Located String)
+ Cryptol.Parser.AST: [tlDoc] :: TopLevel a -> Maybe (Located Text)
- Cryptol.Symbolic.What4: satProve :: W4ProverConfig -> Bool -> ProverCommand -> ModuleCmd (Maybe String, ProverResult)
+ Cryptol.Symbolic.What4: satProve :: W4ProverConfig -> Bool -> Bool -> ProverCommand -> ModuleCmd (Maybe String, ProverResult)
- Cryptol.Symbolic.What4: satProveOffline :: W4ProverConfig -> Bool -> ProverCommand -> ((Handle -> IO ()) -> IO ()) -> ModuleCmd (Maybe String)
+ Cryptol.Symbolic.What4: satProveOffline :: W4ProverConfig -> Bool -> Bool -> ProverCommand -> ((Handle -> IO ()) -> IO ()) -> ModuleCmd (Maybe String)
- Cryptol.Testing.Random: dumpableType :: forall g. RandomGen g => Type -> Maybe [Gen g Concrete]
+ Cryptol.Testing.Random: dumpableType :: forall g. RandomGen g => TValue -> Maybe [Gen g Concrete]
- Cryptol.Testing.Random: randomValue :: (Backend sym, RandomGen g) => sym -> Type -> Maybe (Gen g sym)
+ Cryptol.Testing.Random: randomValue :: (Backend sym, RandomGen g) => sym -> TValue -> Maybe (Gen g sym)
- Cryptol.Testing.Random: returnTests :: RandomGen g => g -> EvalOpts -> [Gen g Concrete] -> Value -> Int -> IO [([Value], Value)]
+ Cryptol.Testing.Random: returnTests :: RandomGen g => g -> [Gen g Concrete] -> Value -> Int -> IO [([Value], Value)]
- Cryptol.Testing.Random: testableType :: Type -> Maybe (Maybe Integer, [Type], [[Value]])
+ Cryptol.Testing.Random: testableType :: RandomGen g => TValue -> Maybe (Maybe Integer, [TValue], [[Value]], [Gen g Concrete])
- Cryptol.TypeCheck: DefaultingTo :: TVarInfo -> Type -> Warning
+ Cryptol.TypeCheck: DefaultingTo :: !TVarInfo -> Type -> Warning
- Cryptol.TypeCheck: InferFailed :: [(Range, Warning)] -> [(Range, Error)] -> InferOutput a
+ Cryptol.TypeCheck: InferFailed :: NameMap -> [(Range, Warning)] -> [(Range, Error)] -> InferOutput a
- Cryptol.TypeCheck: InferOK :: [(Range, Warning)] -> NameSeeds -> Supply -> a -> InferOutput a
+ Cryptol.TypeCheck: InferOK :: NameMap -> [(Range, Warning)] -> NameSeeds -> Supply -> a -> InferOutput a
- Cryptol.TypeCheck: KindMismatch :: Kind -> Kind -> Error
+ Cryptol.TypeCheck: KindMismatch :: Maybe TypeSource -> Kind -> Kind -> Error
- Cryptol.TypeCheck: NotForAll :: TVar -> Type -> Error
+ Cryptol.TypeCheck: NotForAll :: TypeSource -> TVar -> Type -> Error
- Cryptol.TypeCheck: RecursiveType :: Type -> Type -> Error
+ Cryptol.TypeCheck: RecursiveType :: TypeSource -> Type -> Type -> Error
- Cryptol.TypeCheck: TypeMismatch :: Type -> Type -> Error
+ Cryptol.TypeCheck: TypeMismatch :: TypeSource -> Type -> Type -> Error
- Cryptol.TypeCheck: TypeVariableEscaped :: Type -> [TParam] -> Error
+ Cryptol.TypeCheck: TypeVariableEscaped :: TypeSource -> Type -> [TParam] -> Error
- Cryptol.TypeCheck: UnsolvedGoals :: Maybe TCErrorMessage -> [Goal] -> Error
+ Cryptol.TypeCheck: UnsolvedGoals :: [Goal] -> Error
- Cryptol.TypeCheck.AST: Decl :: !Name -> Schema -> DeclDef -> [Pragma] -> !Bool -> Maybe Fixity -> Maybe String -> Decl
+ Cryptol.TypeCheck.AST: Decl :: !Name -> Schema -> DeclDef -> [Pragma] -> !Bool -> Maybe Fixity -> Maybe Text -> Decl
- Cryptol.TypeCheck.AST: ESet :: Expr -> Selector -> Expr -> Expr
+ Cryptol.TypeCheck.AST: ESet :: Type -> Expr -> Selector -> Expr -> Expr
- Cryptol.TypeCheck.AST: ModTParam :: Name -> Kind -> !Int -> Maybe String -> ModTParam
+ Cryptol.TypeCheck.AST: ModTParam :: Name -> Kind -> !Int -> Maybe Text -> ModTParam
- Cryptol.TypeCheck.AST: ModVParam :: Name -> Schema -> Maybe String -> Maybe Fixity -> ModVParam
+ Cryptol.TypeCheck.AST: ModVParam :: Name -> Schema -> Maybe Text -> Maybe Fixity -> ModVParam
- Cryptol.TypeCheck.AST: [dDoc] :: Decl -> Maybe String
+ Cryptol.TypeCheck.AST: [dDoc] :: Decl -> Maybe Text
- Cryptol.TypeCheck.AST: [mtpDoc] :: ModTParam -> Maybe String
+ Cryptol.TypeCheck.AST: [mtpDoc] :: ModTParam -> Maybe Text
- Cryptol.TypeCheck.AST: [mvpDoc] :: ModVParam -> Maybe String
+ Cryptol.TypeCheck.AST: [mvpDoc] :: ModVParam -> Maybe Text
- Cryptol.TypeCheck.Default: flitDefaultCandidates :: Goals -> Map TVar ((TVar, Type), Warning)
+ Cryptol.TypeCheck.Default: flitDefaultCandidates :: Goals -> Map TVar (Maybe ((TVar, Type), Warning))
- Cryptol.TypeCheck.Depends: AT :: ParameterType Name -> Maybe String -> TyDecl
+ Cryptol.TypeCheck.Depends: AT :: ParameterType Name -> Maybe Text -> TyDecl
- Cryptol.TypeCheck.Depends: NT :: Newtype Name -> Maybe String -> TyDecl
+ Cryptol.TypeCheck.Depends: NT :: Newtype Name -> Maybe Text -> TyDecl
- Cryptol.TypeCheck.Depends: PS :: PropSyn Name -> Maybe String -> TyDecl
+ Cryptol.TypeCheck.Depends: PS :: PropSyn Name -> Maybe Text -> TyDecl
- Cryptol.TypeCheck.Depends: PT :: PrimType Name -> Maybe String -> TyDecl
+ Cryptol.TypeCheck.Depends: PT :: PrimType Name -> Maybe Text -> TyDecl
- Cryptol.TypeCheck.Depends: TS :: TySyn Name -> Maybe String -> TyDecl
+ Cryptol.TypeCheck.Depends: TS :: TySyn Name -> Maybe Text -> TyDecl
- Cryptol.TypeCheck.Depends: setDocString :: Maybe String -> TyDecl -> TyDecl
+ Cryptol.TypeCheck.Depends: setDocString :: Maybe Text -> TyDecl -> TyDecl
- Cryptol.TypeCheck.Error: DefaultingTo :: TVarInfo -> Type -> Warning
+ Cryptol.TypeCheck.Error: DefaultingTo :: !TVarInfo -> Type -> Warning
- Cryptol.TypeCheck.Error: KindMismatch :: Kind -> Kind -> Error
+ Cryptol.TypeCheck.Error: KindMismatch :: Maybe TypeSource -> Kind -> Kind -> Error
- Cryptol.TypeCheck.Error: NotForAll :: TVar -> Type -> Error
+ Cryptol.TypeCheck.Error: NotForAll :: TypeSource -> TVar -> Type -> Error
- Cryptol.TypeCheck.Error: RecursiveType :: Type -> Type -> Error
+ Cryptol.TypeCheck.Error: RecursiveType :: TypeSource -> Type -> Type -> Error
- Cryptol.TypeCheck.Error: TypeMismatch :: Type -> Type -> Error
+ Cryptol.TypeCheck.Error: TypeMismatch :: TypeSource -> Type -> Type -> Error
- Cryptol.TypeCheck.Error: TypeVariableEscaped :: Type -> [TParam] -> Error
+ Cryptol.TypeCheck.Error: TypeVariableEscaped :: TypeSource -> Type -> [TParam] -> Error
- Cryptol.TypeCheck.Error: UnsolvedGoals :: Maybe TCErrorMessage -> [Goal] -> Error
+ Cryptol.TypeCheck.Error: UnsolvedGoals :: [Goal] -> Error
- Cryptol.TypeCheck.Error: subsumes :: Error -> Error -> Bool
+ Cryptol.TypeCheck.Error: subsumes :: (Range, Error) -> (Range, Error) -> Bool
- Cryptol.TypeCheck.Infer: checkE :: Expr Name -> Type -> InferM Expr
+ Cryptol.TypeCheck.Infer: checkE :: Expr Name -> TypeWithSource -> InferM Expr
- Cryptol.TypeCheck.InferTypes: CtPattern :: Doc -> ConstraintSource
+ Cryptol.TypeCheck.InferTypes: CtPattern :: TypeSource -> ConstraintSource
- Cryptol.TypeCheck.Kind: checkNewtype :: Newtype Name -> Maybe String -> InferM Newtype
+ Cryptol.TypeCheck.Kind: checkNewtype :: Newtype Name -> Maybe Text -> InferM Newtype
- Cryptol.TypeCheck.Kind: checkParameterType :: ParameterType Name -> Maybe String -> InferM ModTParam
+ Cryptol.TypeCheck.Kind: checkParameterType :: ParameterType Name -> Maybe Text -> InferM ModTParam
- Cryptol.TypeCheck.Kind: checkPrimType :: PrimType Name -> Maybe String -> InferM AbstractType
+ Cryptol.TypeCheck.Kind: checkPrimType :: PrimType Name -> Maybe Text -> InferM AbstractType
- Cryptol.TypeCheck.Kind: checkPropSyn :: PropSyn Name -> Maybe String -> InferM TySyn
+ Cryptol.TypeCheck.Kind: checkPropSyn :: PropSyn Name -> Maybe Text -> InferM TySyn
- Cryptol.TypeCheck.Kind: checkTySyn :: TySyn Name -> Maybe String -> InferM TySyn
+ Cryptol.TypeCheck.Kind: checkTySyn :: TySyn Name -> Maybe Text -> InferM TySyn
- Cryptol.TypeCheck.Monad: InferFailed :: [(Range, Warning)] -> [(Range, Error)] -> InferOutput a
+ Cryptol.TypeCheck.Monad: InferFailed :: NameMap -> [(Range, Warning)] -> [(Range, Error)] -> InferOutput a
- Cryptol.TypeCheck.Monad: InferOK :: [(Range, Warning)] -> NameSeeds -> Supply -> a -> InferOutput a
+ Cryptol.TypeCheck.Monad: InferOK :: NameMap -> [(Range, Warning)] -> NameSeeds -> Supply -> a -> InferOutput a
- Cryptol.TypeCheck.Monad: kNewType :: TVarSource -> Kind -> KindM Type
+ Cryptol.TypeCheck.Monad: kNewType :: TypeSource -> Kind -> KindM Type
- Cryptol.TypeCheck.Monad: newTVar :: TVarSource -> Kind -> InferM TVar
+ Cryptol.TypeCheck.Monad: newTVar :: TypeSource -> Kind -> InferM TVar
- Cryptol.TypeCheck.Monad: newTVar' :: TVarSource -> Set TParam -> Kind -> InferM TVar
+ Cryptol.TypeCheck.Monad: newTVar' :: TypeSource -> Set TParam -> Kind -> InferM TVar
- Cryptol.TypeCheck.Monad: newType :: TVarSource -> Kind -> InferM Type
+ Cryptol.TypeCheck.Monad: newType :: TypeSource -> Kind -> InferM Type
- Cryptol.TypeCheck.Monad: unify :: Type -> Type -> InferM [Prop]
+ Cryptol.TypeCheck.Monad: unify :: TypeWithSource -> Type -> InferM [Prop]
- Cryptol.TypeCheck.Solver.Types: Unsolvable :: TCErrorMessage -> Solved
+ Cryptol.TypeCheck.Solver.Types: Unsolvable :: Solved
- Cryptol.TypeCheck.TCon: TError :: Kind -> TCErrorMessage -> TCon
+ Cryptol.TypeCheck.TCon: TError :: Kind -> TCon
- Cryptol.TypeCheck.Type: AbstractType :: Name -> Kind -> ([TParam], [Prop]) -> Maybe Fixity -> Maybe String -> AbstractType
+ Cryptol.TypeCheck.Type: AbstractType :: Name -> Kind -> ([TParam], [Prop]) -> Maybe Fixity -> Maybe Text -> AbstractType
- Cryptol.TypeCheck.Type: DefinitionOf :: Name -> TVarSource
+ Cryptol.TypeCheck.Type: DefinitionOf :: Name -> TypeSource
- Cryptol.TypeCheck.Type: LenOfCompGen :: TVarSource
+ Cryptol.TypeCheck.Type: LenOfCompGen :: TypeSource
- Cryptol.TypeCheck.Type: LenOfSeq :: TVarSource
+ Cryptol.TypeCheck.Type: LenOfSeq :: TypeSource
- Cryptol.TypeCheck.Type: Newtype :: Name -> [TParam] -> [Prop] -> [(Ident, Type)] -> Maybe String -> Newtype
+ Cryptol.TypeCheck.Type: Newtype :: Name -> [TParam] -> [Prop] -> [(Ident, Type)] -> Maybe Text -> Newtype
- Cryptol.TypeCheck.Type: TVFromModParam :: Name -> TVarSource
+ Cryptol.TypeCheck.Type: TVFromModParam :: Name -> TypeSource
- Cryptol.TypeCheck.Type: TVFromSignature :: Name -> TVarSource
+ Cryptol.TypeCheck.Type: TVFromSignature :: Name -> TypeSource
- Cryptol.TypeCheck.Type: TVarInfo :: Range -> TVarSource -> TVarInfo
+ Cryptol.TypeCheck.Type: TVarInfo :: !Range -> !TypeSource -> TVarInfo
- Cryptol.TypeCheck.Type: TySyn :: Name -> [TParam] -> [Prop] -> Type -> !Maybe String -> TySyn
+ Cryptol.TypeCheck.Type: TySyn :: Name -> [TParam] -> [Prop] -> Type -> !Maybe Text -> TySyn
- Cryptol.TypeCheck.Type: TypeErrorPlaceHolder :: TVarSource
+ Cryptol.TypeCheck.Type: TypeErrorPlaceHolder :: TypeSource
- Cryptol.TypeCheck.Type: TypeOfArg :: Maybe Int -> TVarSource
+ Cryptol.TypeCheck.Type: TypeOfArg :: ArgDescr -> TypeSource
- Cryptol.TypeCheck.Type: TypeOfRecordField :: Ident -> TVarSource
+ Cryptol.TypeCheck.Type: TypeOfRecordField :: Ident -> TypeSource
- Cryptol.TypeCheck.Type: TypeOfRes :: TVarSource
+ Cryptol.TypeCheck.Type: TypeOfRes :: TypeSource
- Cryptol.TypeCheck.Type: TypeOfSeqElement :: TVarSource
+ Cryptol.TypeCheck.Type: TypeOfSeqElement :: TypeSource
- Cryptol.TypeCheck.Type: TypeOfTupleField :: Int -> TVarSource
+ Cryptol.TypeCheck.Type: TypeOfTupleField :: Int -> TypeSource
- Cryptol.TypeCheck.Type: TypeParamInstNamed :: Name -> Ident -> TVarSource
+ Cryptol.TypeCheck.Type: TypeParamInstNamed :: Name -> Ident -> TypeSource
- Cryptol.TypeCheck.Type: TypeParamInstPos :: Name -> Int -> TVarSource
+ Cryptol.TypeCheck.Type: TypeParamInstPos :: Name -> Int -> TypeSource
- Cryptol.TypeCheck.Type: TypeWildCard :: TVarSource
+ Cryptol.TypeCheck.Type: TypeWildCard :: TypeSource
- Cryptol.TypeCheck.Type: [atDoc] :: AbstractType -> Maybe String
+ Cryptol.TypeCheck.Type: [atDoc] :: AbstractType -> Maybe Text
- Cryptol.TypeCheck.Type: [ntDoc] :: Newtype -> Maybe String
+ Cryptol.TypeCheck.Type: [ntDoc] :: Newtype -> Maybe Text
- Cryptol.TypeCheck.Type: [tsDoc] :: TySyn -> !Maybe String
+ Cryptol.TypeCheck.Type: [tsDoc] :: TySyn -> !Maybe Text
- Cryptol.TypeCheck.Type: [tvarDesc] :: TVarInfo -> TVarSource
+ Cryptol.TypeCheck.Type: [tvarDesc] :: TVarInfo -> !TypeSource
- Cryptol.TypeCheck.Type: [tvarSource] :: TVarInfo -> Range
+ Cryptol.TypeCheck.Type: [tvarSource] :: TVarInfo -> !Range
- Cryptol.TypeCheck.Type: pickTVarName :: Kind -> TVarSource -> Int -> Doc
+ Cryptol.TypeCheck.Type: pickTVarName :: Kind -> TypeSource -> Int -> Doc
- Cryptol.TypeCheck.Type: tError :: Type -> String -> Type
+ Cryptol.TypeCheck.Type: tError :: Type -> Type
- Cryptol.TypeCheck.Type: tIsError :: Type -> Maybe (TCErrorMessage, Type)
+ Cryptol.TypeCheck.Type: tIsError :: Type -> Maybe Type
- Cryptol.TypeCheck.Type: tvSourceName :: TVarSource -> Maybe Name
+ Cryptol.TypeCheck.Type: tvSourceName :: TypeSource -> Maybe Name
- Cryptol.TypeCheck.TypePat: anError :: Kind -> Pat Type TCErrorMessage
+ Cryptol.TypeCheck.TypePat: anError :: Kind -> Pat Type ()
Files
- CHANGES.md +58/−0
- cryptol.cabal +29/−56
- lib/Cryptol.cry +72/−46
- lib/Cryptol/Reference.cry +46/−0
- lib/PrimeEC.cry +162/−0
- lib/SuiteB.cry +236/−0
- src/Cryptol/AES.hs +493/−0
- src/Cryptol/Backend.hs +714/−0
- src/Cryptol/Backend/Arch.hs +30/−0
- src/Cryptol/Backend/Concrete.hs +398/−0
- src/Cryptol/Backend/FloatHelpers.hs +248/−0
- src/Cryptol/Backend/Monad.hs +394/−0
- src/Cryptol/Backend/SBV.hs +457/−0
- src/Cryptol/Backend/What4.hs +666/−0
- src/Cryptol/Backend/What4/SFloat.hs +362/−0
- src/Cryptol/Eval.hs +30/−28
- src/Cryptol/Eval/Arch.hs +0/−30
- src/Cryptol/Eval/Backend.hs +0/−705
- src/Cryptol/Eval/Concrete.hs +338/−18
- src/Cryptol/Eval/Concrete/Float.hs +0/−69
- src/Cryptol/Eval/Concrete/FloatHelpers.hs +0/−252
- src/Cryptol/Eval/Concrete/Value.hs +0/−390
- src/Cryptol/Eval/Env.hs +17/−15
- src/Cryptol/Eval/Generic.hs +94/−7
- src/Cryptol/Eval/Monad.hs +0/−272
- src/Cryptol/Eval/Reference.lhs +1689/−1644
- src/Cryptol/Eval/SBV.hs +87/−449
- src/Cryptol/Eval/Type.hs +10/−11
- src/Cryptol/Eval/Value.hs +9/−11
- src/Cryptol/Eval/What4.hs +863/−24
- src/Cryptol/Eval/What4/Float.hs +0/−68
- src/Cryptol/Eval/What4/SFloat.hs +0/−361
- src/Cryptol/Eval/What4/Value.hs +0/−975
- src/Cryptol/F2.hs +48/−0
- src/Cryptol/IR/FreeVars.hs +1/−1
- src/Cryptol/ModuleSystem.hs +1/−1
- src/Cryptol/ModuleSystem/Base.hs +31/−24
- src/Cryptol/ModuleSystem/InstantiateModule.hs +3/−1
- src/Cryptol/ModuleSystem/Interface.hs +2/−1
- src/Cryptol/ModuleSystem/Monad.hs +14/−14
- src/Cryptol/ModuleSystem/Name.hs +1/−1
- src/Cryptol/Parser.y +28/−27
- src/Cryptol/Parser/AST.hs +25/−23
- src/Cryptol/Parser/Lexer.x +8/−25
- src/Cryptol/Parser/LexerUtils.hs +123/−42
- src/Cryptol/Parser/NoPat.hs +4/−3
- src/Cryptol/Parser/ParserUtils.hs +59/−37
- src/Cryptol/Prelude.hs +12/−0
- src/Cryptol/PrimeEC.hs +574/−0
- src/Cryptol/REPL/Command.hs +134/−113
- src/Cryptol/REPL/Monad.hs +3/−18
- src/Cryptol/SHA.hs +564/−0
- src/Cryptol/Symbolic.hs +211/−1
- src/Cryptol/Symbolic/SBV.hs +97/−127
- src/Cryptol/Symbolic/What4.hs +150/−216
- src/Cryptol/Testing/Random.hs +166/−218
- src/Cryptol/Transform/AddModParams.hs +1/−1
- src/Cryptol/Transform/MonoValues.hs +1/−1
- src/Cryptol/Transform/Specialize.hs +1/−1
- src/Cryptol/TypeCheck.hs +17/−4
- src/Cryptol/TypeCheck/AST.hs +8/−8
- src/Cryptol/TypeCheck/CheckModuleInstance.hs +13/−11
- src/Cryptol/TypeCheck/Default.hs +29/−26
- src/Cryptol/TypeCheck/Depends.hs +7/−6
- src/Cryptol/TypeCheck/Error.hs +293/−75
- src/Cryptol/TypeCheck/Infer.hs +111/−96
- src/Cryptol/TypeCheck/InferTypes.hs +11/−2
- src/Cryptol/TypeCheck/Instantiate.hs +5/−3
- src/Cryptol/TypeCheck/Kind.hs +8/−7
- src/Cryptol/TypeCheck/Monad.hs +39/−37
- src/Cryptol/TypeCheck/Parseable.hs +1/−1
- src/Cryptol/TypeCheck/Sanity.hs +8/−7
- src/Cryptol/TypeCheck/SimpType.hs +16/−13
- src/Cryptol/TypeCheck/SimpleSolver.hs +6/−3
- src/Cryptol/TypeCheck/Solve.hs +74/−28
- src/Cryptol/TypeCheck/Solver/Class.hs +57/−119
- src/Cryptol/TypeCheck/Solver/Numeric.hs +47/−34
- src/Cryptol/TypeCheck/Solver/Numeric/Fin.hs +1/−2
- src/Cryptol/TypeCheck/Solver/SMT.hs +0/−3
- src/Cryptol/TypeCheck/Solver/Selector.hs +5/−4
- src/Cryptol/TypeCheck/Solver/Types.hs +5/−2
- src/Cryptol/TypeCheck/Subst.hs +76/−36
- src/Cryptol/TypeCheck/TCon.hs +8/−11
- src/Cryptol/TypeCheck/Type.hs +139/−54
- src/Cryptol/TypeCheck/TypeMap.hs +4/−2
- src/Cryptol/TypeCheck/TypeOf.hs +1/−1
- src/Cryptol/TypeCheck/TypePat.hs +3/−3
- src/Cryptol/Utils/Ident.hs +21/−2
- src/Cryptol/Utils/Misc.hs +4/−3
- src/GitRev.hs +1/−0
- utils/CryHtml.hs +2/−0
CHANGES.md view
@@ -1,3 +1,61 @@+# 2.10.0++## Language changes++* Cryptol now supports primality checking at the type level. The+ type-level predicate `prime` is true when its parameter passes the+ Miller-Rabin probabilistic primality test implemented in the GMP+ library.++* The `Z p` type is now a `Field` when `p` is prime, allowing additional+ operations on `Z p` values.++* The literals `0` and `1` can now be used at type `Bit`, as+ alternatives for `False` and `True`, respectively.++## New features++* The interpreter now includes a number of primitive functions that+ allow faster execution of a number of common cryptographic functions,+ including the core operations of AES and SHA-2, operations on GF(2)+ polynomials (the existing `pmod`, `pdiv`, and `pmult` functions), and+ some operations on prime field elliptic curves. These functions are+ useful for implementing higher-level algorithms, such as many+ post-quantum schemes, with more acceptable performance than possible+ when running a top-to-bottom Cryptol implementation in the+ interpreter.++ For a full list of the new primitives, see the new Cryptol+ [`SuiteB`](https://github.com/GaloisInc/cryptol/blob/master/lib/SuiteB.cry)+ and+ [`PrimeEC`](https://github.com/GaloisInc/cryptol/blob/master/lib/PrimeEC.cry)+ modules.++* The REPL now allows lines containing only comments, making it easier+ to copy and paste examples.++* The interpreter has generally improved performance overall.++* Several error messages are more comprehensible and less verbose.++* Cryptol releases and nightly builds now include an RPC server+ alongside the REPL. This provides an alternative interface to the same+ interpreter and proof engine available from the REPL, but is+ better-suited to programmatic use. Details on the protocol used by the+ server are available+ [here](https://github.com/GaloisInc/argo/blob/master/docs/Protocol.rst).+ A Python client for this protocol is available+ [here](https://github.com/GaloisInc/argo/tree/master/python).++* Windows builds are now distributed as both `.tar.gz` and `.msi` files.++## Bug Fixes++* Closed issues #98, #485, #713, #744, #746, #787, #796, #803, #818,+ #826, #838, #856, #873, #875, #876, #877, #879, #880, #881, #883,+ #886, #887, #888, #892, #894, #901, #910, #913, #924, #926, #931,+ #933, #937, #939, #946, #948, #953, #956, #958, and #969.+ # 2.9.1 ## Language changes
cryptol.cabal view
@@ -1,8 +1,9 @@+Cabal-version: 2.4 Name: cryptol-Version: 2.9.1+Version: 2.10.0 Synopsis: Cryptol: The Language of Cryptography Description: Cryptol is a domain-specific language for specifying cryptographic algorithms. A Cryptol implementation of an algorithm resembles its mathematical specification more closely than an implementation in a general purpose language. For more, see <http://www.cryptol.net/>.-License: BSD3+License: BSD-3-Clause License-file: LICENSE Author: Galois, Inc. Maintainer: cryptol@galois.com@@ -11,11 +12,10 @@ Copyright: 2013-2020 Galois Inc. Category: Language Build-type: Simple-Cabal-version: 1.18 extra-source-files: bench/data/*.cry CHANGES.md -data-files: *.cry *.z3+data-files: **/*.cry **/*.z3 data-dir: lib source-repository head@@ -25,8 +25,9 @@ source-repository this type: git location: https://github.com/GaloisInc/cryptol.git- tag: 2.9.1+ tag: 2.10.0 + flag static default: False description: Create a statically-linked binary@@ -35,11 +36,6 @@ default: True description: Don't use the Cabal-provided data directory for looking up Cryptol libraries. This is useful when the data directory can't be known ahead of time, like for a relocatable distribution. --- Note: the Cryptol server needs to be updated to some new APIs.---flag server--- default: False--- description: Build with the ZeroMQ/JSON cryptol-server executable- library Default-language: Haskell2010@@ -56,17 +52,21 @@ exceptions, filepath >= 1.3, gitrev >= 1.0,+ ghc-prim, GraphSCC >= 1.0.4, heredoc >= 0.2,+ integer-gmp >= 1.0 && < 1.1, libBF >= 0.5.1,+ MemoTrie >= 0.6 && < 0.7, monad-control >= 1.0, monadLib >= 3.7.2, parameterized-utils >= 2.0.2, pretty >= 1.1, process >= 1.2, random >= 1.0.1,- sbv >= 8.6,+ sbv >= 8.6 && < 8.8, simple-smt >= 0.7.1,+ stm >= 2.4, strict, text >= 1.1, tf-random >= 0.5,@@ -76,7 +76,7 @@ panic >= 0.3, what4 >= 1.0 && < 1.1 - Build-tools: alex, happy+ Build-tool-depends: alex:alex, happy:happy hs-source-dirs: src Exposed-modules: Cryptol.Parser,@@ -157,25 +157,30 @@ Cryptol.IR.FreeVars, + Cryptol.Backend,+ Cryptol.Backend.Arch,+ Cryptol.Backend.Concrete,+ Cryptol.Backend.FloatHelpers,+ Cryptol.Backend.Monad,+ Cryptol.Backend.SBV,+ Cryptol.Backend.What4,+ Cryptol.Backend.What4.SFloat,+ Cryptol.Eval,- Cryptol.Eval.Arch,- Cryptol.Eval.Backend, Cryptol.Eval.Concrete,- Cryptol.Eval.Concrete.Float,- Cryptol.Eval.Concrete.FloatHelpers,- Cryptol.Eval.Concrete.Value, Cryptol.Eval.Env, Cryptol.Eval.Generic,- Cryptol.Eval.Monad, Cryptol.Eval.Reference, Cryptol.Eval.SBV, Cryptol.Eval.Type, Cryptol.Eval.Value, Cryptol.Eval.What4,- Cryptol.Eval.What4.Value,- Cryptol.Eval.What4.Float,- Cryptol.Eval.What4.SFloat, + Cryptol.AES,+ Cryptol.F2,+ Cryptol.SHA,+ Cryptol.PrimeEC,+ Cryptol.Testing.Random, Cryptol.Symbolic,@@ -196,8 +201,6 @@ if impl(ghc >= 8.0.1) ghc-options: -Wno-redundant-constraints - ghc-prof-options: -O2 -fprof-auto-top- if flag(relocatable) cpp-options: -DRELOCATABLE @@ -206,10 +209,13 @@ Haskell2010 Main-is: Main.hs hs-source-dirs: cryptol+ Autogen-modules: Paths_cryptol+ Other-modules: OptParser, REPL.Haskeline, REPL.Logo, Paths_cryptol+ build-depends: ansi-terminal , base , base-compat@@ -225,8 +231,6 @@ if impl(ghc >= 8.0.1) ghc-options: -Wno-redundant-constraints - ghc-prof-options: -O2 -fprof-auto-top- if os(linux) && flag(static) ld-options: -static -pthread @@ -237,37 +241,6 @@ hs-source-dirs: utils build-depends: base, text, cryptol, blaze-html GHC-options: -Wall---- Note: the Cryptol server needs to be updated to some new APIs.---executable cryptol-server--- main-is: Main.hs--- hs-source-dirs: cryptol-server--- other-modules: Cryptol.Aeson--- default-language: Haskell2010--- default-extensions: OverloadedStrings--- GHC-options: -Wall -threaded -rtsopts "-with-rtsopts=-N1 -A64m"--- if impl(ghc >= 8.0.1)--- ghc-options: -Wno-redundant-constraints--- if os(linux) && flag(static)--- ld-options: -static -pthread--- if flag(server)--- build-depends: aeson >= 0.10--- , aeson-pretty >= 0.7--- , base--- , base-compat--- , bytestring >= 0.10--- , containers--- , cryptol--- , filepath--- , monad-control--- , optparse-applicative >= 0.12--- , text--- , transformers--- , unix--- , unordered-containers >= 0.2--- , zeromq4-haskell >= 0.6--- else--- buildable: False benchmark cryptol-bench type: exitcode-stdio-1.0
lib/Cryptol.cry view
@@ -44,6 +44,9 @@ * of the equivalance class. In other words, 'fromZ' computes * the (unique) integer value 'i' where '0 <= i < n' and * 'i' is in the given equivalance class.+ *+ * If the modulus 'n' is prime, 'Z n' also+ * supports computing inverses and forms a field. */ primitive type {n : #} (fin n, n >= 1) => Z n : * @@ -80,6 +83,9 @@ /** Assert that a numeric type is a proper natural number (not 'inf'). */ primitive type fin : # -> Prop +/** Assert that a numeric type is a prime number. */+primitive type prime : # -> Prop+ /** Add numeric types. */ primitive type (+) : # -> # -> # @@ -111,7 +117,8 @@ primitive type width : # -> # /**- * Define the base 2 logarithm function in terms of width+ * The ceiling of the base-2 logarithm of a numeric type.+ * We define 'lg2 n = width (n - 1)' for nonzero n, and 'lg2 0 = 0'. */ type lg2 n = width (max n 1 - 1) @@ -656,10 +663,8 @@ primitive (>>$) : {n, ix} (fin n, n >= 1, Integral ix) => [n] -> ix -> [n] /**- * Log base two.- *- * For words, computes the ceiling of log, base 2, of a number.- * We set 'lg2 0 = 0'+ * The ceiling of the base-2 logarithm of an unsigned bitvector.+ * We set 'lg2 0 = 0'. */ primitive lg2 : {n} (fin n) => [n] -> [n] @@ -883,60 +888,56 @@ /** * Performs multiplication of polynomials over GF(2). */-pmult : {u, v} (fin u, fin v) => [1 + u] -> [1 + v] -> [1 + u + v]-pmult x y = last zs- where- zs = [0] # [ (z << 1) ^ (if yi then 0 # x else 0) | yi <- y | z <- zs ]+primitive pmult : {u, v} (fin u, fin v) => [1 + u] -> [1 + v] -> [1 + u + v] /** * Performs division of polynomials over GF(2). */-pdiv : {u, v} (fin u, fin v) => [u] -> [v] -> [u]-pdiv x y = [ z ! degree | z <- zs ]- where- degree : [width v]- degree = last (ds : [1 + v]_)- where ds = [0/0] # [if yi then i else d | yi <- reverse y | i <- [0..v] | d <- ds ]-- reduce : [v] -> [v]- reduce u = if u ! degree then u ^ y else u-- zs : [u][v]- zs = [ tail (reduce z # [xi]) | z <- [0] # zs | xi <- x ]+primitive pdiv : {u, v} (fin u, fin v) => [u] -> [v] -> [u] /** * Performs modulus of polynomials over GF(2). */-pmod : {u, v} (fin u, fin v) => [u] -> [1 + v] -> [v]-pmod x y = if y == 0 then 0/0 else last zs- where- degree : [width v]- degree = last (ds : [2 + v]_)- where ds = [0/0] # [if yi then i else d | yi <- reverse y | i <- [0..v] | d <- ds ]-- reduce : [1 + v] -> [1 + v]- reduce u = if u ! degree then u ^ y else u-- powers : [inf][1 + v]- powers = [reduce 1] # [ reduce (p << 1) | p <- powers ]-- zs = [0] # [ z ^ (if xi then tail p else 0) | xi <- reverse x | p <- powers | z <- zs ]-+primitive pmod : {u, v} (fin u, fin v) => [u] -> [1 + v] -> [v] // Experimental primitives ------------------------------------------------------------ /** * Parallel map. The given function is applied to each element in the * given finite seqeuence, and the results are computed in parallel.+ * The values in the resulting sequence are reduced to normal form,+ * as is done with the deepseq operation. *+ * The Eq constraint restricts this operation to types+ * where reduction to normal form makes sense.+ * * This function is experimental. */-primitive parmap : {a, b, n} (fin n) => (a -> b) -> [n]a -> [n]b+primitive parmap : {a, b, n} (Eq b, fin n) => (a -> b) -> [n]a -> [n]b // Utility operations ----------------------------------------------------------------- /**+ * A strictness-increasing operation. The first operand+ * is reduced to normal form before evaluating the second+ * argument.+ *+ * The Eq constraint restricts this operation to types+ * where reduction to normal form makes sense.+ */+primitive deepseq : {a, b} Eq a => a -> b -> b++/**+ * Reduce to normal form.+ *+ * The Eq constraint restricts this operation to types+ * where reduction to normal form makes sense.+ */+rnf : {a} Eq a => a -> a+rnf x = deepseq x x++/** * Raise a run-time error with the given message. * This function can be called at any type. */@@ -1009,13 +1010,13 @@ * Conjunction after applying a predicate to all elements. */ all : {n, a} (fin n) => (a -> Bit) -> [n]a -> Bit-all f xs = and (map f xs)+all f xs = foldl' (/\) True (map f xs) /** * Disjunction after applying a predicate to all elements. */ any : {n, a} (fin n) => (a -> Bit) -> [n]a -> Bit-any f xs = or (map f xs)+any f xs = foldl' (\/) False (map f xs) /** * Map a function over a sequence.@@ -1028,24 +1029,49 @@ * * foldl (+) 0 [1,2,3] = ((0 + 1) + 2) + 3 */-foldl : {n, a, b} (fin n) => (a -> b -> a) -> a -> [n]b -> a-foldl f acc xs = ys ! 0- where ys = [acc] # [f a x | a <- ys | x <- xs]+primitive foldl : {n, a, b} (fin n) => (a -> b -> a) -> a -> [n]b -> a /**+ * Functional left fold, with strict evaluation of the accumulator value.+ * The accumulator is reduced to normal form at each step. The Eq constraint+ * restricts the accumulator to types where reduction to normal form makes sense.+ *+ * foldl' (+) 0 [1,2,3] = ((0 + 1) + 2) + 3+ */+primitive foldl' : {n, a, b} (fin n, Eq a) => (a -> b -> a) -> a -> [n]b -> a++/** * Functional right fold. * * foldr (-) 0 [1,2,3] = 0 - (1 - (2 - 3)) */ foldr : {n, a, b} (fin n) => (a -> b -> b) -> b -> [n]a -> b-foldr f acc xs = ys ! 0- where ys = [acc] # [f x a | a <- ys | x <- reverse xs]+foldr f acc xs = foldl g acc (reverse xs)+ where g b a = f a b /**+ * Functional right fold, with strict evaluation of the accumulator value.+ * The accumulator is reduced to weak head normal form at each step.+ *+ * foldr' (-) 0 [1,2,3] = 0 - (1 - (2 - 3))+ */+foldr' : {n, a, b} (fin n, Eq b) => (a -> b -> b) -> b -> [n]a -> b+foldr' f acc xs = foldl' g acc (reverse xs)+ where g b a = f a b++/** * Compute the sum of the values in the sequence. */-sum : {n, a} (fin n, Ring a) => [n]a -> a-sum xs = foldl (+) (fromInteger 0) xs+sum : {n, a} (fin n, Eq a, Ring a) => [n]a -> a+sum xs = foldl' (+) (fromInteger 0) xs+++/**+ * Compute the product of the values in the sequence.+ */+product : {n, a} (fin n, Eq a, Ring a) => [n]a -> a+product xs = foldl' (*) (fromInteger 1) xs+ /** * Scan left is like a foldl that also emits the intermediate values.
+ lib/Cryptol/Reference.cry view
@@ -0,0 +1,46 @@+module Cryptol::Reference where++/**+ * Performs multiplication of polynomials over GF(2).+ * Reference implementation.+ */+pmult : {u, v} (fin u, fin v) => [1 + u] -> [1 + v] -> [1 + u + v]+pmult x y = last zs+ where+ zs = [0] # [ (z << 1) ^ (if yi then 0 # x else 0) | yi <- y | z <- zs ]++/**+ * Performs division of polynomials over GF(2).+ * Reference implementation.+ */+pdiv : {u, v} (fin u, fin v) => [u] -> [v] -> [u]+pdiv x y = [ z ! degree | z <- zs ]+ where+ degree : [width v]+ degree = last (ds : [1 + v]_)+ where ds = [0/0] # [if yi then i else d | yi <- reverse y | i <- [0..v] | d <- ds ]++ reduce : [v] -> [v]+ reduce u = if u ! degree then u ^ y else u++ zs : [u][v]+ zs = [ tail (reduce z # [xi]) | z <- [0] # zs | xi <- x ]++/**+ * Performs modulus of polynomials over GF(2).+ * Reference implementation.+ */+pmod : {u, v} (fin u, fin v) => [u] -> [1 + v] -> [v]+pmod x y = if y == 0 then 0/0 else last zs+ where+ degree : [width v]+ degree = last (ds : [2 + v]_)+ where ds = [0/0] # [if yi then i else d | yi <- reverse y | i <- [0..v] | d <- ds ]++ reduce : [1 + v] -> [1 + v]+ reduce u = if u ! degree then u ^ y else u++ powers : [inf][1 + v]+ powers = [reduce 1] # [ reduce (p << 1) | p <- powers ]++ zs = [0] # [ z ^ (if xi then tail p else 0) | xi <- reverse x | p <- powers | z <- zs ]
+ lib/PrimeEC.cry view
@@ -0,0 +1,162 @@+module PrimeEC where++/**+ * The type of points of an elliptic curve in affine coordinates.+ * The coefficients are taken from the prime field 'Z p' with 'p > 3'.+ * This is intended to represent all the "normal" points+ * on the curve, which satisfy 'x^^3 == y^^2 - 3x + b', + * for some curve parameter 'b'. This type cannot represent+ * the special projective "point at infinity".+ */+type AffinePoint p =+ { x : Z p+ , y : Z p+ }++/**+ * The type of points of an elliptic curve in (homogeneous)+ * projective coordinates. The coefficients are taken from the+ * prime field 'Z p' with 'p > 3'. These points should be understood as+ * representatives of equivalence classes of points, where two representatives+ * 'S' and 'T' are equivalent iff one is a scalar multiple of the other. That+ * is, 'S' and 'T' are equivalent iff there exists some 'k' where+ * 'S.x == k*T.x /\ S.y == k*T.y /\ S.z == k*T.z'. Finally, the+ * vector with all coordinates equal to 0 is excluded and does not+ * represent any point.+ *+ * Note that all the affine points are easily embedded into projective+ * coordinates by simply setting the `z` coordinate to 1, and the "point at+ * infinity" is represented by any point with 'z == 0'. Further, for any+ * projective point with 'z != 0', we can compute the corresponding affine+ * point by simply multiplying the x and y coordinates by the inverse of z.+ */+type ProjectivePoint p =+ { x : Z p+ , y : Z p+ , z : Z p+ }++/**+ * 'ec_is_point_affine b S' checks that the supposed affine elliptic curve+ * point 'S' in fact lies on the curve defined by the curve parameter 'b'. Here,+ * and throughout this module, we assume the curve parameter 'a' is equal to+ * '-3'. Precisely, this function checks the following condition:+ *+ * S.y^^2 == S.x^^3 - 3*S.x + b+ */+ec_is_point_affine : {p} (prime p, p > 3) => Z p -> AffinePoint p -> Bit+ec_is_point_affine b S = S.y^^2 == S.x^^3 - (3*S.x) + b+++/**+ * 'ec_is_nonsingular' checks that the given curve parameter 'b' gives rise to+ * a non-singular elliptic curve, appropriate for use in ECC.+ *+ * Precisely, this checks that '4*a^^3 + 27*b^^2 != 0 mod p'. Here, and+ * throughout this module, we assume 'a = -3'.+ */+ec_is_nonsingular : {p} (prime p, p > 3) => Z p -> Bit+ec_is_nonsingular b = (fromInteger 4) * a^^3 + (fromInteger 27) * b^^2 != 0+ where a = -3 : Z p++/**+ * Returns true if the given point is the identity "point at infinity."+ * This is true whenever the 'z' coordinate is 0, but one of the 'x' or+ * 'y' coordinates is nonzero.+ */+ec_is_identity : {p} (prime p, p > 3) => ProjectivePoint p -> Bit+ec_is_identity S = S.z == 0 /\ ~(S.x == 0 /\ S.y == 0)++/**+ * Test two projective points for equality, up to the equivalence relation+ * on projective points.+ */+ec_equal : {p} (prime p, p > 3) => ProjectivePoint p -> ProjectivePoint p -> Bit+ec_equal S T =+ (S.z == 0 /\ T.z == 0) \/+ (S.z != 0 /\ T.z != 0 /\ ec_affinify S == ec_affinify T)++/**+ * Compute a projective representative for the given affine point.+ */+ec_projectify : {p} (prime p, p > 3) => AffinePoint p -> ProjectivePoint p+ec_projectify R = { x = R.x, y = R.y, z = 1 }++/**+ * Compute the affine point corresponding to the given projective point.+ * This results in an error if the 'z' component of the given point is 0,+ * in which case there is no corresponding affine point.+ */+ec_affinify : {p} (prime p, p > 3) => ProjectivePoint p -> AffinePoint p+ec_affinify S =+ if S.z == 0 then error "Cannot affinify the point at infinity" else R+ where+ R = {x = lambda^^2 * S.x, y = lambda^^3 * S.y }+ lambda = recip S.z++/**+ * Coerce an integer modulo 'p' to a bitvector. This will reduce the value+ * modulo '2^^a' if necessary.+ */+ZtoBV : {p, a} (fin p, p >= 1, fin a) => Z p -> [a]+ZtoBV x = fromInteger (fromZ x)++/**+ * Coerce a bitvector value to an integer modulo 'p'. This will+ * reduce the value modulo 'p' if necessary.+ */+BVtoZ : {p, a} (fin p, p >= 1, fin a) => [a] -> Z p+BVtoZ x = fromInteger (toInteger x)++/**+ * Given a projective point 'S', compute '2S = S+S'.+ */+primitive ec_double : {p} (prime p, p > 3) =>+ ProjectivePoint p -> ProjectivePoint p++/**+ * Given two projective points 'S' and 'T' where neither is the identity,+ * compute 'S+T'. If the points are not known to be distinct from the point+ * at infinity, use 'ec_add' instead.+ */+primitive ec_add_nonzero : {p} (prime p, p > 3) =>+ ProjectivePoint p -> ProjectivePoint p -> ProjectivePoint p++/**+ * Given a projective point 'S', compute its negation, '-S'+ */+ec_negate : {p} (prime p, p > 3) => ProjectivePoint p -> ProjectivePoint p+ec_negate S = { x = S.x, y = -S.y, z = S.z }++/**+ * Given two projective points 'S' and 'T' compute 'S+T'.+ */+ec_add : {p} (prime p, p > 3) =>+ ProjectivePoint p -> ProjectivePoint p -> ProjectivePoint p+ec_add S T =+ if S.z == 0 then T+ | T.z == 0 then S+ else R+ where R = ec_add_nonzero S T++/**+ * Given two projective points 'S' and 'T' compute 'S-T'.+ */+ec_sub : {p} (prime p, p > 3) =>+ ProjectivePoint p -> ProjectivePoint p -> ProjectivePoint p+ec_sub S T = ec_add S U+ where U = { x = T.x, y = -T.y, z = T.z }++/**+ * Given a scalar value 'k' and a projective point 'S', compute the+ * scalar multiplication 'kS'.+ */+primitive ec_mult : {p} (prime p, p > 3) =>+ Z p -> ProjectivePoint p -> ProjectivePoint p++/**+ * Given a scalar value 'j' and a projective point 'S', and another scalar+ * value 'k' and point 'T', compute the "twin" scalar multiplication 'jS + kT'.+ */+primitive ec_twin_mult : {p} (prime p, p > 3) =>+ Z p -> ProjectivePoint p -> Z p -> ProjectivePoint p -> ProjectivePoint p
+ lib/SuiteB.cry view
@@ -0,0 +1,236 @@+module SuiteB where++/***** AES ******/++/**+ * Key schedule parameter setting for AES-128+ */+type AES128 = 4++/**+ * Key schedule parameter setting for AES-192+ */+type AES192 = 6++/**+ * Key schedule parameter setting for AES-256+ */+type AES256 = 8++/**+ * Element of an AES key schedule for use in a particular round+ */+type AESRoundKey = [4][32]++/**+ * Expanded encryption key schedule for AES+ */+type AESEncryptKeySchedule k =+ { aesEncInitialKey : AESRoundKey+ , aesEncRoundKeys : [k+5]AESRoundKey+ , aesEncFinalKey : AESRoundKey+ }++/**+ * Expanded decryption key schedule for AES+ */+type AESDecryptKeySchedule k =+ { aesDecInitialKey : AESRoundKey+ , aesDecRoundKeys : [k+5]AESRoundKey+ , aesDecFinalKey : AESRoundKey+ }++/**+ * Encryption key expansion for AES-128.+ * See FIPS 197, section 5.2.+ */+aes128EncryptSchedule : [128] -> AESEncryptKeySchedule AES128+aes128EncryptSchedule = aesExpandEncryptSchedule++/**+ * Decryption key expansion for AES-128, for use in the "equivalent inverse cypher".+ * See FIPS 197, sections 5.2 and 5.3.5.+ */+aes128DecryptSchedule : [128] -> AESDecryptKeySchedule AES128+aes128DecryptSchedule = aesExpandDecryptSchedule++/**+ * Encryption and decryption key schedules for AES-128.+ * If you will need both schedules, it is slightly more efficient+ * to call this function than to compute the two schedules separately.+ * See FIPS 197, sections 5.2 and 5.3.5.+ */+aes128Schedules : [128] -> (AESEncryptKeySchedule AES128, AESDecryptKeySchedule AES128)+aes128Schedules = aesExpandSchedules++/**+ * Encryption key expansion for AES-192.+ * See FIPS 197, section 5.2.+ */+aes192EncryptSchedule : [192] -> AESEncryptKeySchedule AES192+aes192EncryptSchedule = aesExpandEncryptSchedule++/**+ * Decryption key expansion for AES-192, for use in the "equivalent inverse cypher".+ * See FIPS 197, sections 5.2 and 5.3.5.+ */+aes192DecryptSchedule : [192] -> AESDecryptKeySchedule AES192+aes192DecryptSchedule = aesExpandDecryptSchedule++/**+ * Encryption and decryption key schedules for AES-192.+ * If you will need both schedules, it is slightly more efficient+ * to call this function than to compute the two schedules separately.+ * See FIPS 197, sections 5.2 and 5.3.5.+ */+aes192Schedules : [192] -> (AESEncryptKeySchedule AES192, AESDecryptKeySchedule AES192)+aes192Schedules = aesExpandSchedules+++/**+ * Encryption key expansion for AES-256.+ * See FIPS 197, section 5.2+ */+aes256EncryptSchedule : [256] -> AESEncryptKeySchedule AES256+aes256EncryptSchedule = aesExpandEncryptSchedule++/**+ * Decryption key expansion for AES-256, for use in the "equivalent inverse cypher".+ * See FIPS 197, sections 5.2 and 5.3.5.+ */+aes256DecryptSchedule : [256] -> AESDecryptKeySchedule AES256+aes256DecryptSchedule = aesExpandDecryptSchedule++/**+ * Encryption and decryption key schedules for AES-256.+ * If you will need both schedules, it is slightly more efficient+ * to call this function than to compute the two schedules separately.+ * See FIPS 197, sections 5.2 and 5.3.5.+ */+aes256Schedules : [256] -> (AESEncryptKeySchedule AES256, AESDecryptKeySchedule AES256)+aes256Schedules = aesExpandSchedules++/**+ * AES block encryption algorithm.+ * See FIPS 197, section 5.1.+ */+aesEncryptBlock : {k} (fin k) => AESEncryptKeySchedule k -> [128] -> [128]+aesEncryptBlock schedule plaintext = rnf (join final)+ where+ final = (AESEncFinalRound (rds!0)) ^ schedule.aesEncFinalKey++ rds = [ schedule.aesEncInitialKey ^ split plaintext ] #+ [ AESEncRound r ^ rdk+ | rdk <- schedule.aesEncRoundKeys+ | r <- rds+ ]++/**+ * AES block decryption algorithm, via the "equivalent inverse cypher".+ * See FIPS 197, section 5.3.5.+ */+aesDecryptBlock : {k} (fin k) => AESDecryptKeySchedule k -> [128] -> [128]+aesDecryptBlock schedule cyphertext = rnf (join final)+ where+ final = (AESDecFinalRound (rds!0)) ^ schedule.aesDecFinalKey++ rds = [ split cyphertext ^ schedule.aesDecInitialKey ] #+ [ AESDecRound r ^ rdk+ | rdk <- schedule.aesDecRoundKeys+ | r <- rds+ ]++private+ aesExpandEncryptSchedule : {k} (fin k, k >= 4, 8 >= k) => [k * 32] -> AESEncryptKeySchedule k+ aesExpandEncryptSchedule key = rnf+ { aesEncInitialKey = ks @ 0+ , aesEncRoundKeys = ks @@ [ 1 .. k+5 ]+ , aesEncFinalKey = ks @ `(k+6)+ }+ where+ ks : [k+7]AESRoundKey+ ks = groupBy`{4} (AESKeyExpand`{k} (split key))++ aesEncToDecSchedule : {k} (fin k) => AESEncryptKeySchedule k -> AESDecryptKeySchedule k+ aesEncToDecSchedule enc = rnf+ { aesDecInitialKey = enc.aesEncFinalKey+ , aesDecRoundKeys = map AESInvMixColumns (reverse (enc.aesEncRoundKeys))+ , aesDecFinalKey = enc.aesEncInitialKey+ }++ aesExpandDecryptSchedule : {k} (fin k, k >= 4, 8 >= k) => [k * 32] -> AESDecryptKeySchedule k+ aesExpandDecryptSchedule key = aesEncToDecSchedule (aesExpandEncryptSchedule key)++ aesExpandSchedules : {k} (fin k, k >= 4, 8 >= k) => [k * 32] -> (AESEncryptKeySchedule k, AESDecryptKeySchedule k)+ aesExpandSchedules key = (encS, aesEncToDecSchedule encS)+ where encS = aesExpandEncryptSchedule key++ primitive AESEncRound : [4][32] -> [4][32]+ primitive AESEncFinalRound : [4][32] -> [4][32]+ primitive AESDecRound : [4][32] -> [4][32]+ primitive AESDecFinalRound : [4][32] -> [4][32]+ primitive AESInvMixColumns : [4][32] -> [4][32]+ primitive AESKeyExpand : {k} (fin k, k >= 4, 8 >= k) => [k][32] -> [4*(k+7)][32]+++/***** SHA2 *****/++/**+ * The SHA-224 secure hash algorithm. See FIPS 180-4, section 6.3.+ */+sha224 : {L} (fin L) => [L] -> [224]+sha224 msg = join (processSHA2_224 (sha2blocks`{32} msg))++/**+ * The SHA-256 secure hash algorithm. See FIPS 180-4, section 6.2.2.+ */+sha256 : {L} (fin L) => [L] -> [256]+sha256 msg = join (processSHA2_256 (sha2blocks`{32} msg))++/**+ * The SHA-384 secure hash algorithm. See FIPS 180-4, section 6.5.+ */+sha384 : {L} (fin L) => [L] -> [384]+sha384 msg = join (processSHA2_384 (sha2blocks`{64} msg))++/**+ * The SHA-512 secure hash algorithm. See FIPS 180-4, section 6.4.+ */+sha512 : {L} (fin L) => [L] -> [512]+sha512 msg = join (processSHA2_512 (sha2blocks`{64} msg))++private+ type sha2_block_size w = 16 * w+ type sha2_num_blocks w L = (L+1+2*w) /^ sha2_block_size w+ type sha2_padded_size w L = sha2_num_blocks w L * sha2_block_size w++ sha2pad : {w, L} (fin w, fin L, w >= 1) => [L] -> [sha2_padded_size w L]+ sha2pad M = M # 0b1 # zero # ((fromInteger `L) : [2*w])++ sha2blocks : {w, L} (fin w, fin L, w >= 1) =>+ [L] -> [sha2_num_blocks w L][16][w]+ sha2blocks msg = [ split x | x <- split (sha2pad`{w} msg) ]++ /**+ * Apply the SHA224 hash algorithm to a sequence of SHA256-size blocks,+ * which are assumed to already be correctly padded.+ */+ primitive processSHA2_224 : {n} (fin n) => [n][16][32] -> [7][32]++ /**+ * Apply the SHA256 hash algorithm to a sequence of SHA256-size blocks,+ * which are assumed to already be correctly padded.+ */+ primitive processSHA2_256 : {n} (fin n) => [n][16][32] -> [8][32]++ /**+ * Apply the SHA384 hash algorithm to a sequence of SHA512-size blocks,+ * which are assumed to already be correctly padded.+ */+ primitive processSHA2_384 : {n} (fin n) => [n][16][64] -> [6][64]++ /**+ * Apply the SHA512 hash algorithm to a sequence of SHA512-size blocks,+ * which are assumed to already be correctly padded.+ */+ primitive processSHA2_512 : {n} (fin n) => [n][16][64] -> [8][64]
+ src/Cryptol/AES.hs view
@@ -0,0 +1,493 @@+-----------------------------------------------------------------------------+-- |+-- Module : Cryptol.AES+-- Copyright : (c) Levent Erkok+-- License : BSD3+-- Maintainer: erkokl@gmail.com+-- Stability : experimental+--+-- A TBox-based implementation of AES primitives, based on+-- the AES example code from SBV. Here we've stripped out+-- everything except the basic primitives needed, which+-- essentially boil down to table table lookups in most cases.+-----------------------------------------------------------------------------+{-# LANGUAGE ParallelListComp #-}+module Cryptol.AES+ ( State+ , Key+ , keyExpansionWords+ , invMixColumns+ , aesRound+ , aesFinalRound+ , aesInvRound+ , aesInvFinalRound+ ) where++import Data.Bits+import Data.List (transpose, genericDrop, genericTake)+import Data.Word (Word8, Word32)++-- | An element of the Galois Field 2^8, which are essentially polynomials with+-- maximum degree 7. They are conveniently represented as values between 0 and 255.+type GF28 = Word8++-----------------------------------------------------------------------------+-- ** Types and basic operations+-----------------------------------------------------------------------------+-- | AES state. The state consists of four 32-bit words, each of which is in turn treated+-- as four GF28's, i.e., 4 bytes. The T-Box implementation keeps the four-bytes together+-- for efficient representation.+type State = [Word32]++-- | The key, which can be 128, 192, or 256 bits. Represented as a sequence of 32-bit words.+type Key = [Word32]++-- | Rotating a state row by a fixed amount to the right.+rotR :: [GF28] -> Int -> [GF28]+rotR [a, b, c, d] 1 = [d, a, b, c]+rotR [a, b, c, d] 2 = [c, d, a, b]+rotR [a, b, c, d] 3 = [b, c, d, a]+rotR xs i = error $ "rotR: Unexpected input: " ++ show (xs, i)+++toBytes :: Word32 -> [Word8]+toBytes w = [b0,b1,b2,b3]+ where+ b0 = fromIntegral (w `shiftR` 24)+ b1 = fromIntegral (w `shiftR` 16)+ b2 = fromIntegral (w `shiftR` 8)+ b3 = fromIntegral w++fromBytes :: [Word8] -> Word32+fromBytes [b0,b1,b2,b3] = w+ where+ w = ((fromIntegral b0) `shiftL` 24) .|.+ ((fromIntegral b1) `shiftL` 16) .|.+ ((fromIntegral b2) `shiftL` 8) .|.+ (fromIntegral b3)+fromBytes bs = error ("Unexpected list length in fromBytes: " ++ show (length bs))+++-----------------------------------------------------------------------------+-- ** GF28 multiplication tables+-----------------------------------------------------------------------------++-- GF(2^8) multiplication by 0x0e+mETable :: [GF28]+mETable =+ [0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c,+ 0x62, 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6,+ 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb,+ 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9,+ 0x93, 0x9d, 0x8f, 0x81, 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f,+ 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3,+ 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5,+ 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67,+ 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, 0x76, 0x78, 0x6a,+ 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30,+ 0x22, 0x2c, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6,+ 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53,+ 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15,+ 0x1b, 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf,+ 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2,+ 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0,+ 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16,+ 0x18, 0x32, 0x3c, 0x2e, 0x20, 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda,+ 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, 0x0c,+ 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e,+ 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13,+ 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, 0xd7, 0xd9,+ 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f,+ 0x91, 0x83, 0x8d]++-- GF(2^8) multiplication by 0x0b+mBTable :: [GF28]+mBTable =+ [0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e,+ 0x45, 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97,+ 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b,+ 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e,+ 0x0f, 0x04, 0x19, 0x12, 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1,+ 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd,+ 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82,+ 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77,+ 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, 0x8d, 0x86, 0x9b,+ 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2,+ 0xef, 0xe4, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65,+ 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea,+ 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95,+ 0x9e, 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14,+ 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0,+ 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5,+ 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72,+ 0x79, 0x48, 0x43, 0x5e, 0x55, 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26,+ 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, 0xb1,+ 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4,+ 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40,+ 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, 0xca, 0xc1,+ 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe,+ 0xb5, 0xa8, 0xa3]+++-- GF(2^8) multiplication by 0x0d+mDTable :: [GF28]+mDTable =+ [0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72,+ 0x7f, 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9,+ 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb,+ 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4,+ 0xe7, 0xea, 0xfd, 0xf0, 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45,+ 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60,+ 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31,+ 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e,+ 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, 0xd6, 0xdb, 0xcc,+ 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87,+ 0x90, 0x9d, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e,+ 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd,+ 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c,+ 0x91, 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f,+ 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55,+ 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a,+ 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3,+ 0xce, 0xed, 0xe0, 0xf7, 0xfa, 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e,+ 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, 0x67,+ 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18,+ 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22,+ 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, 0xdc, 0xd1,+ 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80,+ 0x8d, 0x9a, 0x97]++-- GF(2^8) multiplication by 0x09+m9Table :: [GF28]+m9Table =+ [0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a,+ 0x53, 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd,+ 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b,+ 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68,+ 0x57, 0x5e, 0x45, 0x4c, 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d,+ 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f,+ 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a,+ 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9,+ 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, 0x4d, 0x44, 0x5f,+ 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28,+ 0x33, 0x3a, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95,+ 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7,+ 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92,+ 0x9b, 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d,+ 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3,+ 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0,+ 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d,+ 0x14, 0x2b, 0x22, 0x39, 0x30, 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7,+ 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, 0x0a,+ 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59,+ 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97,+ 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, 0x31, 0x38,+ 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d,+ 0x54, 0x4f, 0x46]+++-- GF(2^8) multiplication by 0x02+m2Table :: [GF28]+m2Table =+ [0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14,+ 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a,+ 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40,+ 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56,+ 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c,+ 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82,+ 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98,+ 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae,+ 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 0xc0, 0xc2, 0xc4,+ 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda,+ 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0,+ 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d,+ 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07,+ 0x05, 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29,+ 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53,+ 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,+ 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f,+ 0x6d, 0x63, 0x61, 0x67, 0x65, 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91,+ 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, 0xbb,+ 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad,+ 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7,+ 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, 0xfb, 0xf9,+ 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3,+ 0xe1, 0xe7, 0xe5]++-- GF(2^8) multiplication by 0x03+m3Table :: [GF28]+m3Table =+ [0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e,+ 0x1d, 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f,+ 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60,+ 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d,+ 0x74, 0x77, 0x72, 0x71, 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a,+ 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3,+ 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4,+ 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9,+ 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, 0xa0, 0xa3, 0xa6,+ 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7,+ 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88,+ 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e,+ 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89,+ 0x8a, 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0,+ 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7,+ 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,+ 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5,+ 0xd6, 0xdf, 0xdc, 0xd9, 0xda, 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54,+ 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, 0x6b,+ 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76,+ 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31,+ 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, 0x0b, 0x08,+ 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f,+ 0x1c, 0x19, 0x1a]+++-- table-lookup versions of gf28Mult with the constants used in invMixColumns+-- and TBox construction++m2 :: GF28 -> GF28+m2 i = m2Table !! fromIntegral i++m3 :: GF28 -> GF28+m3 i = m3Table !! fromIntegral i++mE :: GF28 -> GF28+mE i = mETable !! fromIntegral i++mB :: GF28 -> GF28+mB i = mBTable !! fromIntegral i++mD :: GF28 -> GF28+mD i = mDTable !! fromIntegral i++m9 :: GF28 -> GF28+m9 i = m9Table !! fromIntegral i++-----------------------------------------------------------------------------+-- ** The key schedule+-----------------------------------------------------------------------------++-- | The @InvMixColumns@ transformation, as described in Section 5.3.3 of the standard. Note+-- that this transformation is only used explicitly during key-expansion in the T-Box implementation+-- of AES.+invMixColumns :: State -> State+invMixColumns state = map fromBytes $ transpose $ mmult (map toBytes state)+ where dot f = foldr1 xor . zipWith ($) f+ mmult :: [[Word8]] -> [[Word8]]+ mmult n = [map (dot r) n | r <- [ [mE, mB, mD, m9]+ , [m9, mE, mB, mD]+ , [mD, m9, mE, mB]+ , [mB, mD, m9, mE]+ ]]++keyExpansionWords :: Integer -> Key -> [Word32]+keyExpansionWords nk key = genericTake (4*(nk+7)) keys+ where keys :: [Word32]+ keys = key ++ [nextWord i prev old | i <- [nk ..] | prev <- genericDrop (nk-1) keys | old <- keys]++ nextWord :: Integer -> Word32 -> Word32 -> Word32+ nextWord i prev old+ | i `mod` nk == 0 = old `xor` subWordRcon (prev `rotateL` 8) (roundConstants !! fromInteger (i `div` nk))+ | i `mod` nk == 4 && nk > 6 = old `xor` subWordRcon prev 0+ | True = old `xor` prev++ subWordRcon :: Word32 -> GF28 -> Word32+ subWordRcon w rc = fromBytes [a `xor` rc, b, c, d]+ where [a, b, c, d] = map sbox $ toBytes w+++-- | Definition of round-constants, as specified in Section 5.2 of the AES standard.+-- We only need up to the 11th value for AES-128, and fewer than that for AES-192+-- and AES-256.+roundConstants :: [GF28]+roundConstants = [0,1,2,4,8,16,32,64,128,27,54]++-----------------------------------------------------------------------------+-- ** The S-box transformation+-----------------------------------------------------------------------------++sboxTable :: [GF28]+sboxTable =+ [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67,+ 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59,+ 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7,+ 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1,+ 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05,+ 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83,+ 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29,+ 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa,+ 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c,+ 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc,+ 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,+ 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19,+ 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee,+ 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49,+ 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4,+ 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6,+ 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70,+ 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9,+ 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e,+ 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1,+ 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0,+ 0x54, 0xbb, 0x16]++-- | The AES sbox transformation+sbox :: GF28 -> GF28+sbox i = sboxTable !! fromIntegral i++-----------------------------------------------------------------------------+-- ** The inverse S-box transformation+-----------------------------------------------------------------------------++unSBoxTable :: [GF28]+unSBoxTable =+ [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3,+ 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f,+ 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54,+ 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b,+ 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24,+ 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8,+ 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d,+ 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,+ 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab,+ 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3,+ 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1,+ 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41,+ 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6,+ 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9,+ 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d,+ 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0,+ 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07,+ 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60,+ 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f,+ 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5,+ 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b,+ 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55,+ 0x21, 0x0c, 0x7d]++-- | The inverse s-box transformation.+unSBox :: GF28 -> GF28+unSBox i = unSBoxTable !! fromIntegral i+++-----------------------------------------------------------------------------+-- ** Tables for T-Box encryption+-----------------------------------------------------------------------------++-- | T-box table generation function for encryption+t0Func :: GF28 -> [GF28]+t0Func a = [ m2 s, s, s, m3 s]+ where s = sbox a++-- | First look-up table used in encryption+t0 :: GF28 -> Word32+t0 i = t0Table !! fromIntegral i++t0Table :: [Word32]+t0Table = [fromBytes (t0Func a) | a <- [0..255]]++-- | Second look-up table used in encryption+t1 :: GF28 -> Word32+t1 i = t1Table !! fromIntegral i++t1Table :: [Word32]+t1Table = [fromBytes (t0Func a `rotR` 1) | a <- [0..255]]++-- | Third look-up table used in encryption+t2 :: GF28 -> Word32+t2 i = t2Table !! fromIntegral i++t2Table :: [Word32]+t2Table = [fromBytes (t0Func a `rotR` 2) | a <- [0..255]]++-- | Fourth look-up table used in encryption+t3 :: GF28 -> Word32+t3 i = t3Table !! fromIntegral i++t3Table :: [Word32]+t3Table = [fromBytes (t0Func a `rotR` 3) | a <- [0..255]]++-----------------------------------------------------------------------------+-- ** Tables for T-Box decryption+-----------------------------------------------------------------------------++-- | T-box table generating function for decryption+u0Func :: GF28 -> [GF28]+u0Func a = [ mE s, m9 s, mD s, mB s ]+ where s = unSBox a++-- | First look-up table used in decryption+u0 :: GF28 -> Word32+u0 i = u0Table !! fromIntegral i++u0Table :: [Word32]+u0Table = [fromBytes (u0Func a) | a <- [0..255]]++-- | Second look-up table used in decryption+u1 :: GF28 -> Word32+u1 i = u1Table !! fromIntegral i++u1Table :: [Word32]+u1Table = [fromBytes (u0Func a `rotR` 1) | a <- [0..255]]++-- | Third look-up table used in decryption+u2 :: GF28 -> Word32+u2 i = u2Table !! fromIntegral i++u2Table :: [Word32]+u2Table = [fromBytes (u0Func a `rotR` 2) | a <- [0..255]]++-- | Fourth look-up table used in decryption+u3 :: GF28 -> Word32+u3 i = u3Table !! fromIntegral i++u3Table :: [Word32]+u3Table = [fromBytes (u0Func a `rotR` 3) | a <- [0..255]]++-----------------------------------------------------------------------------+-- ** AES rounds+-----------------------------------------------------------------------------++aesRound :: State -> State+aesRound s = d+ where d = map f [0..3]+ a = map toBytes s+ f j = e0 `xor` e1 `xor` e2 `xor` e3+ where e0 = t0 (a !! ((j+0) `mod` 4) !! 0)+ e1 = t1 (a !! ((j+1) `mod` 4) !! 1)+ e2 = t2 (a !! ((j+2) `mod` 4) !! 2)+ e3 = t3 (a !! ((j+3) `mod` 4) !! 3)++aesFinalRound :: State -> State+aesFinalRound s = d+ where d = map f [0..3]+ a = map toBytes s+ f j = fromBytes [ sbox (a !! ((j+0) `mod` 4) !! 0)+ , sbox (a !! ((j+1) `mod` 4) !! 1)+ , sbox (a !! ((j+2) `mod` 4) !! 2)+ , sbox (a !! ((j+3) `mod` 4) !! 3)+ ]++aesInvRound :: State -> State+aesInvRound s = d+ where d = map f [0..3]+ a = map toBytes s+ f j = e0 `xor` e1 `xor` e2 `xor` e3+ where e0 = u0 (a !! ((j+0) `mod` 4) !! 0)+ e1 = u1 (a !! ((j+3) `mod` 4) !! 1)+ e2 = u2 (a !! ((j+2) `mod` 4) !! 2)+ e3 = u3 (a !! ((j+1) `mod` 4) !! 3)++aesInvFinalRound :: State -> State+aesInvFinalRound s = d+ where d = map f [0..3]+ a = map toBytes s+ f j = fromBytes [ unSBox (a !! ((j+0) `mod` 4) !! 0)+ , unSBox (a !! ((j+3) `mod` 4) !! 1)+ , unSBox (a !! ((j+2) `mod` 4) !! 2)+ , unSBox (a !! ((j+1) `mod` 4) !! 3)+ ]
+ src/Cryptol/Backend.hs view
@@ -0,0 +1,714 @@+{-# Language FlexibleContexts #-}+{-# Language TypeFamilies #-}+module Cryptol.Backend+ ( Backend(..)+ , sDelay+ , invalidIndex+ , cryUserError+ , cryNoPrimError+ , FPArith2++ -- * Rationals+ , SRational(..)+ , intToRational+ , ratio+ , rationalAdd+ , rationalSub+ , rationalNegate+ , rationalMul+ , rationalRecip+ , rationalDivide+ , rationalFloor+ , rationalCeiling+ , rationalTrunc+ , rationalRoundAway+ , rationalRoundToEven+ , rationalEq+ , rationalLessThan+ , rationalGreaterThan+ , iteRational+ , ppRational+ ) where++import Control.Monad.IO.Class+import Data.Kind (Type)+import Data.Ratio ( (%), numerator, denominator )++import Cryptol.Backend.FloatHelpers (BF)+import Cryptol.Backend.Monad ( PPOpts(..), EvalError(..) )+import Cryptol.TypeCheck.AST(Name)+import Cryptol.Utils.PP+++invalidIndex :: Backend sym => sym -> Integer -> SEval sym a+invalidIndex sym = raiseError sym . InvalidIndex . Just++cryUserError :: Backend sym => sym -> String -> SEval sym a+cryUserError sym = raiseError sym . UserError++cryNoPrimError :: Backend sym => sym -> Name -> SEval sym a+cryNoPrimError sym = raiseError sym . NoPrim+++{-# INLINE sDelay #-}+-- | Delay the given evaluation computation, returning a thunk+-- which will run the computation when forced. Raise a loop+-- error if the resulting thunk is forced during its own evaluation.+sDelay :: Backend sym => sym -> Maybe String -> SEval sym a -> SEval sym (SEval sym a)+sDelay sym msg m =+ let msg' = maybe "" ("while evaluating "++) msg+ retry = raiseError sym (LoopError msg')+ in sDelayFill sym m retry+++-- | Representation of rational numbers.+-- Invariant: denominator is not 0+data SRational sym =+ SRational+ { sNum :: SInteger sym+ , sDenom :: SInteger sym+ }++intToRational :: Backend sym => sym -> SInteger sym -> SEval sym (SRational sym)+intToRational sym x = SRational x <$> (integerLit sym 1)++ratio :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SRational sym)+ratio sym n d =+ do pz <- bitComplement sym =<< intEq sym d =<< integerLit sym 0+ assertSideCondition sym pz DivideByZero+ pure (SRational n d)++rationalRecip :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)+rationalRecip sym (SRational a b) = ratio sym b a++rationalDivide :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)+rationalDivide sym x y = rationalMul sym x =<< rationalRecip sym y++rationalFloor :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)+ -- NB, relies on integer division being round-to-negative-inf division+rationalFloor sym (SRational n d) = intDiv sym n d++rationalCeiling :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)+rationalCeiling sym r = intNegate sym =<< rationalFloor sym =<< rationalNegate sym r++rationalTrunc :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)+rationalTrunc sym r =+ do p <- rationalLessThan sym r =<< intToRational sym =<< integerLit sym 0+ cr <- rationalCeiling sym r+ fr <- rationalFloor sym r+ iteInteger sym p cr fr++rationalRoundAway :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)+rationalRoundAway sym r =+ do p <- rationalLessThan sym r =<< intToRational sym =<< integerLit sym 0+ half <- SRational <$> integerLit sym 1 <*> integerLit sym 2+ cr <- rationalCeiling sym =<< rationalSub sym r half+ fr <- rationalFloor sym =<< rationalAdd sym r half+ iteInteger sym p cr fr++rationalRoundToEven :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)+rationalRoundToEven sym r =+ do lo <- rationalFloor sym r+ hi <- intPlus sym lo =<< integerLit sym 1+ -- NB: `diff` will be nonnegative because `lo <= r`+ diff <- rationalSub sym r =<< intToRational sym lo+ half <- SRational <$> integerLit sym 1 <*> integerLit sym 2++ ite (rationalLessThan sym diff half) (pure lo) $+ ite (rationalGreaterThan sym diff half) (pure hi) $+ ite (isEven lo) (pure lo) (pure hi)++ where+ isEven x =+ do parity <- intMod sym x =<< integerLit sym 2+ intEq sym parity =<< integerLit sym 0++ ite x t e =+ do x' <- x+ case bitAsLit sym x' of+ Just True -> t+ Just False -> e+ Nothing ->+ do t' <- t+ e' <- e+ iteInteger sym x' t' e'+++rationalAdd :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)+rationalAdd sym (SRational a b) (SRational c d) =+ do ad <- intMult sym a d+ bc <- intMult sym b c+ bd <- intMult sym b d+ ad_bc <- intPlus sym ad bc+ pure (SRational ad_bc bd)++rationalSub :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)+rationalSub sym (SRational a b) (SRational c d) =+ do ad <- intMult sym a d+ bc <- intMult sym b c+ bd <- intMult sym b d+ ad_bc <- intMinus sym ad bc+ pure (SRational ad_bc bd)++rationalNegate :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)+rationalNegate sym (SRational a b) =+ do aneg <- intNegate sym a+ pure (SRational aneg b)++rationalMul :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)+rationalMul sym (SRational a b) (SRational c d) =+ do ac <- intMult sym a c+ bd <- intMult sym b d+ pure (SRational ac bd)++rationalEq :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)+rationalEq sym (SRational a b) (SRational c d) =+ do ad <- intMult sym a d+ bc <- intMult sym b c+ intEq sym ad bc++normalizeSign :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)+normalizeSign sym (SRational a b) =+ do p <- intLessThan sym b =<< integerLit sym 0+ case bitAsLit sym p of+ Just False -> pure (SRational a b)+ Just True ->+ do aneg <- intNegate sym a+ bneg <- intNegate sym b+ pure (SRational aneg bneg)+ Nothing ->+ do aneg <- intNegate sym a+ bneg <- intNegate sym b+ a' <- iteInteger sym p aneg a+ b' <- iteInteger sym p bneg b+ pure (SRational a' b')++rationalLessThan:: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)+rationalLessThan sym x y =+ do SRational a b <- normalizeSign sym x+ SRational c d <- normalizeSign sym y+ ad <- intMult sym a d+ bc <- intMult sym b c+ intLessThan sym ad bc++rationalGreaterThan:: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)+rationalGreaterThan sym = flip (rationalLessThan sym)++iteRational :: Backend sym => sym -> SBit sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)+iteRational sym p (SRational a b) (SRational c d) =+ SRational <$> iteInteger sym p a c <*> iteInteger sym p b d++ppRational :: Backend sym => sym -> PPOpts -> SRational sym -> Doc+ppRational sym opts (SRational n d)+ | Just ni <- integerAsLit sym n+ , Just di <- integerAsLit sym d+ = let q = ni % di in+ text "(ratio" <+> integer (numerator q) <+> (integer (denominator q) <> text ")")++ | otherwise+ = text "(ratio" <+> ppInteger sym opts n <+> (ppInteger sym opts d <> text ")")++-- | This type class defines a collection of operations on bits, words and integers that+-- are necessary to define generic evaluator primitives that operate on both concrete+-- and symbolic values uniformly.+class MonadIO (SEval sym) => Backend sym where+ type SBit sym :: Type+ type SWord sym :: Type+ type SInteger sym :: Type+ type SFloat sym :: Type+ type SEval sym :: Type -> Type++ -- ==== Evaluation monad operations ====++ -- | Check if an operation is "ready", which means its+ -- evaluation will be trivial.+ isReady :: sym -> SEval sym a -> Bool++ -- | Produce a thunk value which can be filled with its associated computation+ -- after the fact. A preallocated thunk is returned, along with an operation to+ -- fill the thunk with the associated computation.+ -- This is used to implement recursive declaration groups.+ sDeclareHole :: sym -> String -> SEval sym (SEval sym a, SEval sym a -> SEval sym ())++ -- | Delay the given evaluation computation, returning a thunk+ -- which will run the computation when forced. Run the 'retry'+ -- computation instead if the resulting thunk is forced during+ -- its own evaluation.+ sDelayFill :: sym -> SEval sym a -> SEval sym a -> SEval sym (SEval sym a)++ -- | Begin evaluating the given computation eagerly in a separate thread+ -- and return a thunk which will await the completion of the given computation+ -- when forced.+ sSpark :: sym -> SEval sym a -> SEval sym (SEval sym a)++ -- | Merge the two given computations according to the predicate.+ mergeEval ::+ sym ->+ (SBit sym -> a -> a -> SEval sym a) {- ^ A merge operation on values -} ->+ SBit sym {- ^ The condition -} ->+ SEval sym a {- ^ The "then" computation -} ->+ SEval sym a {- ^ The "else" computation -} ->+ SEval sym a++ -- | Assert that a condition must hold, and indicate what sort of+ -- error is indicated if the condition fails.+ assertSideCondition :: sym -> SBit sym -> EvalError -> SEval sym ()++ -- | Indiciate that an error condition exists+ raiseError :: sym -> EvalError -> SEval sym a+++ -- ==== Pretty printing ====+ -- | Pretty-print an individual bit+ ppBit :: sym -> SBit sym -> Doc++ -- | Pretty-print a word value+ ppWord :: sym -> PPOpts -> SWord sym -> Doc++ -- | Pretty-print an integer value+ ppInteger :: sym -> PPOpts -> SInteger sym -> Doc++ -- | Pretty-print a floating-point value+ ppFloat :: sym -> PPOpts -> SFloat sym -> Doc+++ -- ==== Identifying literal values ====++ -- | Determine if this symbolic bit is a boolean literal+ bitAsLit :: sym -> SBit sym -> Maybe Bool++ -- | The number of bits in a word value.+ wordLen :: sym -> SWord sym -> Integer++ -- | Determine if this symbolic word is a literal.+ -- If so, return the bit width and value.+ wordAsLit :: sym -> SWord sym -> Maybe (Integer, Integer)++ -- | Attempt to render a word value as an ASCII character. Return 'Nothing'+ -- if the character value is unknown (e.g., for symbolic values).+ wordAsChar :: sym -> SWord sym -> Maybe Char++ -- | Determine if this symbolic integer is a literal+ integerAsLit :: sym -> SInteger sym -> Maybe Integer++ -- ==== Creating literal values ====++ -- | Construct a literal bit value from a boolean.+ bitLit :: sym -> Bool -> SBit sym++ -- | Construct a literal word value given a bit width and a value.+ wordLit ::+ sym ->+ Integer {- ^ Width -} ->+ Integer {- ^ Value -} ->+ SEval sym (SWord sym)++ -- | Construct a literal integer value from the given integer.+ integerLit ::+ sym ->+ Integer {- ^ Value -} ->+ SEval sym (SInteger sym)++ -- | Construct a floating point value from the given rational.+ fpLit ::+ sym ->+ Integer {- ^ exponent bits -} ->+ Integer {- ^ precision bits -} ->+ Rational {- ^ The rational -} ->+ SEval sym (SFloat sym)++ -- | Construct a floating point value from the given bit-precise+ -- floating-point representation.+ fpExactLit :: sym -> BF -> SEval sym (SFloat sym)++ -- ==== If/then/else operations ====+ iteBit :: sym -> SBit sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)+ iteWord :: sym -> SBit sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)+ iteInteger :: sym -> SBit sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)++ -- ==== Bit operations ====+ bitEq :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)+ bitOr :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)+ bitAnd :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)+ bitXor :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)+ bitComplement :: sym -> SBit sym -> SEval sym (SBit sym)+++ -- ==== Word operations ====++ -- | Extract the numbered bit from the word.+ --+ -- NOTE: this assumes that the sequence of bits is big-endian and finite, so the+ -- bit numbered 0 is the most significant bit.+ wordBit ::+ sym ->+ SWord sym ->+ Integer {- ^ Bit position to extract -} ->+ SEval sym (SBit sym)++ -- | Update the numbered bit in the word.+ --+ -- NOTE: this assumes that the sequence of bits is big-endian and finite, so the+ -- bit numbered 0 is the most significant bit.+ wordUpdate ::+ sym ->+ SWord sym ->+ Integer {- ^ Bit position to update -} ->+ SBit sym ->+ SEval sym (SWord sym)++ -- | Construct a word value from a finite sequence of bits.+ -- NOTE: this assumes that the sequence of bits is big-endian and finite, so the+ -- first element of the list will be the most significant bit.+ packWord ::+ sym ->+ [SBit sym] ->+ SEval sym (SWord sym)++ -- | Deconstruct a packed word value in to a finite sequence of bits.+ -- NOTE: this produces a list of bits that represent a big-endian word, so+ -- the most significant bit is the first element of the list.+ unpackWord ::+ sym ->+ SWord sym ->+ SEval sym [SBit sym]++ -- | Construct a packed word of the specified width from an integer value.+ wordFromInt ::+ sym ->+ Integer {- ^ bit-width -} ->+ SInteger sym ->+ SEval sym (SWord sym)++ -- | Concatenate the two given word values.+ -- NOTE: the first argument represents the more-significant bits+ joinWord ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | Take the most-significant bits, and return+ -- those bits and the remainder. The first element+ -- of the pair is the most significant bits.+ -- The two integer sizes must sum to the length of the given word value.+ splitWord ::+ sym ->+ Integer {- ^ left width -} ->+ Integer {- ^ right width -} ->+ SWord sym ->+ SEval sym (SWord sym, SWord sym)++ -- | Extract a subsequence of bits from a packed word value.+ -- The first integer argument is the number of bits in the+ -- resulting word. The second integer argument is the+ -- number of less-significant digits to discard. Stated another+ -- way, the operation @extractWord n i w@ is equivalent to+ -- first shifting @w@ right by @i@ bits, and then truncating to+ -- @n@ bits.+ extractWord ::+ sym ->+ Integer {- ^ Number of bits to take -} ->+ Integer {- ^ starting bit -} ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | Bitwise OR+ wordOr ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | Bitwise AND+ wordAnd ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | Bitwise XOR+ wordXor ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | Bitwise complement+ wordComplement ::+ sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | 2's complement addition of packed words. The arguments must have+ -- equal bit width, and the result is of the same width. Overflow is silently+ -- discarded.+ wordPlus ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | 2's complement subtraction of packed words. The arguments must have+ -- equal bit width, and the result is of the same width. Overflow is silently+ -- discarded.+ wordMinus ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | 2's complement multiplication of packed words. The arguments must have+ -- equal bit width, and the result is of the same width. The high bits of the+ -- multiplication are silently discarded.+ wordMult ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | 2's complement unsigned division of packed words. The arguments must have+ -- equal bit width, and the result is of the same width. It is illegal to+ -- call with a second argument concretely equal to 0.+ wordDiv ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | 2's complement unsigned modulus of packed words. The arguments must have+ -- equal bit width, and the result is of the same width. It is illegal to+ -- call with a second argument concretely equal to 0.+ wordMod ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | 2's complement signed division of packed words. The arguments must have+ -- equal bit width, and the result is of the same width. It is illegal to+ -- call with a second argument concretely equal to 0.+ wordSignedDiv ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | 2's complement signed modulus of packed words. The arguments must have+ -- equal bit width, and the result is of the same width. It is illegal to+ -- call with a second argument concretely equal to 0.+ wordSignedMod ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | 2's complement negation of bitvectors+ wordNegate ::+ sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | Compute rounded-up log-2 of the input+ wordLg2 ::+ sym ->+ SWord sym ->+ SEval sym (SWord sym)++ -- | Test if two words are equal. Arguments must have the same width.+ wordEq ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SBit sym)++ -- | Signed less-than comparison on words. Arguments must have the same width.+ wordSignedLessThan ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SBit sym)++ -- | Unsigned less-than comparison on words. Arguments must have the same width.+ wordLessThan ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SBit sym)++ -- | Unsigned greater-than comparison on words. Arguments must have the same width.+ wordGreaterThan ::+ sym ->+ SWord sym ->+ SWord sym ->+ SEval sym (SBit sym)++ -- | Construct an integer value from the given packed word.+ wordToInt ::+ sym ->+ SWord sym ->+ SEval sym (SInteger sym)++ -- ==== Integer operations ====++ -- | Addition of unbounded integers.+ intPlus ::+ sym ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Negation of unbounded integers+ intNegate ::+ sym ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Subtraction of unbounded integers.+ intMinus ::+ sym ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Multiplication of unbounded integers.+ intMult ::+ sym ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Integer division, rounding down. It is illegal to+ -- call with a second argument concretely equal to 0.+ -- Same semantics as Haskell's @div@ operation.+ intDiv ::+ sym ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Integer modulus, with division rounding down. It is illegal to+ -- call with a second argument concretely equal to 0.+ -- Same semantics as Haskell's @mod@ operation.+ intMod ::+ sym ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Equality comparison on integers+ intEq ::+ sym ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SBit sym)++ -- | Less-than comparison on integers+ intLessThan ::+ sym ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SBit sym)++ -- | Greater-than comparison on integers+ intGreaterThan ::+ sym ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SBit sym)+++ -- ==== Operations on Z_n ====++ -- | Turn an integer into a value in Z_n+ intToZn ::+ sym ->+ Integer {- ^ modulus -} ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Transform a Z_n value into an integer, ensuring the value is properly+ -- reduced modulo n+ znToInt ::+ sym ->+ Integer {- ^ modulus -} ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Addition of integers modulo n, for a concrete positive integer n.+ znPlus ::+ sym ->+ Integer {- ^ modulus -} ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Additive inverse of integers modulo n+ znNegate ::+ sym ->+ Integer {- ^ modulus -} ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Subtraction of integers modulo n, for a concrete positive integer n.+ znMinus ::+ sym ->+ Integer {- ^ modulus -} ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Multiplication of integers modulo n, for a concrete positive integer n.+ znMult ::+ sym ->+ Integer {- ^ modulus -} ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- | Equality test of integers modulo n+ znEq ::+ sym ->+ Integer {- ^ modulus -} ->+ SInteger sym ->+ SInteger sym ->+ SEval sym (SBit sym)++ -- | Multiplicitive inverse in (Z n).+ -- PRECONDITION: the modulus is a prime+ znRecip ::+ sym ->+ Integer {- ^ modulus -} ->+ SInteger sym ->+ SEval sym (SInteger sym)++ -- == Float Operations ==+ fpEq :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)+ fpLessThan :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)+ fpGreaterThan :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)++ fpLogicalEq :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)++ fpPlus, fpMinus, fpMult, fpDiv :: FPArith2 sym+ fpNeg :: sym -> SFloat sym -> SEval sym (SFloat sym)++ fpToInteger ::+ sym ->+ String {- ^ Name of the function for error reporting -} ->+ SWord sym {-^ Rounding mode -} ->+ SFloat sym -> SEval sym (SInteger sym)++ fpFromInteger ::+ sym ->+ Integer {- exp width -} ->+ Integer {- prec width -} ->+ SWord sym {- ^ rounding mode -} ->+ SInteger sym {- ^ the integeer to use -} ->+ SEval sym (SFloat sym)++type FPArith2 sym =+ sym ->+ SWord sym ->+ SFloat sym ->+ SFloat sym ->+ SEval sym (SFloat sym)
+ src/Cryptol/Backend/Arch.hs view
@@ -0,0 +1,30 @@+-- |+-- Module : Cryptol.Eval.Arch+-- Copyright : (c) 2014-2016 Galois, Inc.+-- License : BSD3+-- Maintainer : cryptol@galois.com+-- Stability : provisional+-- Portability : portable+--+-- Architecture-specific parts of the concrete evaluator go here.+{-# LANGUAGE CPP #-}+module Cryptol.Backend.Arch where++-- | This is the widest word we can have before gmp will fail to+-- allocate and bring down the whole program. According to+-- <https://gmplib.org/list-archives/gmp-bugs/2009-July/001538.html>+-- the sizes are 2^32-1 for 32-bit, and 2^37 for 64-bit, however+-- experiments show that it's somewhere under 2^37 at least on 64-bit+-- Mac OS X.+maxBigIntWidth :: Integer+#if i386_HOST_ARCH+maxBigIntWidth = 2^(32 :: Integer) - 0x1+#elif x86_64_HOST_ARCH+maxBigIntWidth = 2^(37 :: Integer) - 0x100+#else+-- Because GHC doesn't seem to define a CPP macro that will portably+-- tell us the bit width we're compiling for, fall back on a safe choice+-- for other architectures. If we care about large words on another+-- architecture, we can add a special case for it.+maxBigIntWidth = 2^(32 :: Integer) - 0x1+#endif
+ src/Cryptol/Backend/Concrete.hs view
@@ -0,0 +1,398 @@+-- |+-- Module : Cryptol.Backend.Concrete+-- Copyright : (c) 2013-2020 Galois, Inc.+-- License : BSD3+-- Maintainer : cryptol@galois.com+-- Stability : provisional+-- Portability : portable++{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-}+module Cryptol.Backend.Concrete+ ( BV(..)+ , binBV+ , unaryBV+ , bvVal+ , ppBV+ , mkBv+ , mask+ , signedBV+ , signedValue+ , integerToChar+ , lg2+ , Concrete(..)+ , liftBinIntMod+ , fpBinArith+ , fpRoundMode+ ) where++import qualified Control.Exception as X+import Data.Bits+import Numeric (showIntAtBase)+import qualified LibBF as FP+import qualified GHC.Integer.GMP.Internals as Integer++import qualified Cryptol.Backend.Arch as Arch+import qualified Cryptol.Backend.FloatHelpers as FP+import Cryptol.Backend+import Cryptol.Backend.Monad+import Cryptol.TypeCheck.Solver.InfNat (genLog)+import Cryptol.Utils.Panic (panic)+import Cryptol.Utils.PP++data Concrete = Concrete deriving Show++-- | Concrete bitvector values: width, value+-- Invariant: The value must be within the range 0 .. 2^width-1+data BV = BV !Integer !Integer++instance Show BV where+ show = show . bvVal++-- | Apply an integer function to the values of bitvectors.+-- This function assumes both bitvectors are the same width.+binBV :: Applicative m => (Integer -> Integer -> Integer) -> BV -> BV -> m BV+binBV f (BV w x) (BV _ y) = pure $! mkBv w (f x y)+{-# INLINE binBV #-}++-- | Apply an integer function to the values of a bitvector.+-- This function assumes the function will not require masking.+unaryBV :: (Integer -> Integer) -> BV -> BV+unaryBV f (BV w x) = mkBv w $! f x+{-# INLINE unaryBV #-}++bvVal :: BV -> Integer+bvVal (BV _w x) = x+{-# INLINE bvVal #-}++-- | Smart constructor for 'BV's that checks for the width limit+mkBv :: Integer -> Integer -> BV+mkBv w i = BV w (mask w i)++signedBV :: BV -> Integer+signedBV (BV i x) = signedValue i x++signedValue :: Integer -> Integer -> Integer+signedValue i x = if testBit x (fromInteger (i-1)) then x - (bit (fromInteger i)) else x++integerToChar :: Integer -> Char+integerToChar = toEnum . fromInteger++lg2 :: Integer -> Integer+lg2 i = case genLog i 2 of+ Just (i',isExact) | isExact -> i'+ | otherwise -> i' + 1+ Nothing -> 0+++ppBV :: PPOpts -> BV -> Doc+ppBV opts (BV width i)+ | base > 36 = integer i -- not sure how to rule this out+ | asciiMode opts width = text (show (toEnum (fromInteger i) :: Char))+ | otherwise = prefix <.> text value+ where+ base = useBase opts++ padding bitsPerDigit = text (replicate padLen '0')+ where+ padLen | m > 0 = d + 1+ | otherwise = d++ (d,m) = (fromInteger width - (length value * bitsPerDigit))+ `divMod` bitsPerDigit++ prefix = case base of+ 2 -> text "0b" <.> padding 1+ 8 -> text "0o" <.> padding 3+ 10 -> empty+ 16 -> text "0x" <.> padding 4+ _ -> text "0" <.> char '<' <.> int base <.> char '>'++ value = showIntAtBase (toInteger base) (digits !!) i ""+ digits = "0123456789abcdefghijklmnopqrstuvwxyz"++-- Concrete Big-endian Words ------------------------------------------------------------++mask ::+ Integer {- ^ Bit-width -} ->+ Integer {- ^ Value -} ->+ Integer {- ^ Masked result -}+mask w i | w >= Arch.maxBigIntWidth = wordTooWide w+ | otherwise = i .&. (bit (fromInteger w) - 1)++instance Backend Concrete where+ type SBit Concrete = Bool+ type SWord Concrete = BV+ type SInteger Concrete = Integer+ type SFloat Concrete = FP.BF+ type SEval Concrete = Eval++ raiseError _ err = io (X.throwIO err)++ assertSideCondition _ True _ = return ()+ assertSideCondition _ False err = io (X.throwIO err)++ wordLen _ (BV w _) = w+ wordAsChar _ (BV _ x) = Just $! integerToChar x++ wordBit _ (BV w x) idx = pure $! testBit x (fromInteger (w - 1 - idx))++ wordUpdate _ (BV w x) idx True = pure $! BV w (setBit x (fromInteger (w - 1 - idx)))+ wordUpdate _ (BV w x) idx False = pure $! BV w (clearBit x (fromInteger (w - 1 - idx)))++ isReady _ (Ready _) = True+ isReady _ _ = False++ mergeEval _sym f c mx my =+ do x <- mx+ y <- my+ f c x y++ sDeclareHole _ = blackhole+ sDelayFill _ = delayFill+ sSpark _ = evalSpark++ ppBit _ b | b = text "True"+ | otherwise = text "False"++ ppWord _ = ppBV++ ppInteger _ _opts i = integer i++ ppFloat _ = FP.fpPP++ bitLit _ b = b+ bitAsLit _ b = Just b++ bitEq _ x y = pure $! x == y+ bitOr _ x y = pure $! x .|. y+ bitAnd _ x y = pure $! x .&. y+ bitXor _ x y = pure $! x `xor` y+ bitComplement _ x = pure $! complement x++ iteBit _ b x y = pure $! if b then x else y+ iteWord _ b x y = pure $! if b then x else y+ iteInteger _ b x y = pure $! if b then x else y++ wordLit _ w i = pure $! mkBv w i+ wordAsLit _ (BV w i) = Just (w,i)+ integerLit _ i = pure i+ integerAsLit _ = Just++ wordToInt _ (BV _ x) = pure x+ wordFromInt _ w x = pure $! mkBv w x++ packWord _ bits = pure $! BV (toInteger w) a+ where+ w = case length bits of+ len | toInteger len >= Arch.maxBigIntWidth -> wordTooWide (toInteger len)+ | otherwise -> len+ a = foldl setb 0 (zip [w - 1, w - 2 .. 0] bits)+ setb acc (n,b) | b = setBit acc n+ | otherwise = acc++ unpackWord _ (BV w a) = pure [ testBit a n | n <- [w' - 1, w' - 2 .. 0] ]+ where+ w' = fromInteger w++ joinWord _ (BV i x) (BV j y) =+ pure $! BV (i + j) (shiftL x (fromInteger j) + y)++ splitWord _ leftW rightW (BV _ x) =+ pure ( BV leftW (x `shiftR` (fromInteger rightW)), mkBv rightW x )++ extractWord _ n i (BV _ x) = pure $! mkBv n (x `shiftR` (fromInteger i))++ wordEq _ (BV i x) (BV j y)+ | i == j = pure $! x == y+ | otherwise = panic "Attempt to compare words of different sizes: wordEq" [show i, show j]++ wordSignedLessThan _ (BV i x) (BV j y)+ | i == j = pure $! signedValue i x < signedValue i y+ | otherwise = panic "Attempt to compare words of different sizes: wordSignedLessThan" [show i, show j]++ wordLessThan _ (BV i x) (BV j y)+ | i == j = pure $! x < y+ | otherwise = panic "Attempt to compare words of different sizes: wordLessThan" [show i, show j]++ wordGreaterThan _ (BV i x) (BV j y)+ | i == j = pure $! x > y+ | otherwise = panic "Attempt to compare words of different sizes: wordGreaterThan" [show i, show j]++ wordAnd _ (BV i x) (BV j y)+ | i == j = pure $! mkBv i (x .&. y)+ | otherwise = panic "Attempt to AND words of different sizes: wordPlus" [show i, show j]++ wordOr _ (BV i x) (BV j y)+ | i == j = pure $! mkBv i (x .|. y)+ | otherwise = panic "Attempt to OR words of different sizes: wordPlus" [show i, show j]++ wordXor _ (BV i x) (BV j y)+ | i == j = pure $! mkBv i (x `xor` y)+ | otherwise = panic "Attempt to XOR words of different sizes: wordPlus" [show i, show j]++ wordComplement _ (BV i x) = pure $! mkBv i (complement x)++ wordPlus _ (BV i x) (BV j y)+ | i == j = pure $! mkBv i (x+y)+ | otherwise = panic "Attempt to add words of different sizes: wordPlus" [show i, show j]++ wordNegate _ (BV i x) = pure $! mkBv i (negate x)++ wordMinus _ (BV i x) (BV j y)+ | i == j = pure $! mkBv i (x-y)+ | otherwise = panic "Attempt to subtract words of different sizes: wordMinus" [show i, show j]++ wordMult _ (BV i x) (BV j y)+ | i == j = pure $! mkBv i (x*y)+ | otherwise = panic "Attempt to multiply words of different sizes: wordMult" [show i, show j]++ wordDiv sym (BV i x) (BV j y)+ | i == 0 && j == 0 = pure $! mkBv 0 0+ | i == j =+ do assertSideCondition sym (y /= 0) DivideByZero+ pure $! mkBv i (x `div` y)+ | otherwise = panic "Attempt to divide words of different sizes: wordDiv" [show i, show j]++ wordMod sym (BV i x) (BV j y)+ | i == 0 && j == 0 = pure $! mkBv 0 0+ | i == j =+ do assertSideCondition sym (y /= 0) DivideByZero+ pure $! mkBv i (x `mod` y)+ | otherwise = panic "Attempt to mod words of different sizes: wordMod" [show i, show j]++ wordSignedDiv sym (BV i x) (BV j y)+ | i == 0 && j == 0 = pure $! mkBv 0 0+ | i == j =+ do assertSideCondition sym (y /= 0) DivideByZero+ let sx = signedValue i x+ sy = signedValue i y+ pure $! mkBv i (sx `quot` sy)+ | otherwise = panic "Attempt to divide words of different sizes: wordSignedDiv" [show i, show j]++ wordSignedMod sym (BV i x) (BV j y)+ | i == 0 && j == 0 = pure $! mkBv 0 0+ | i == j =+ do assertSideCondition sym (y /= 0) DivideByZero+ let sx = signedValue i x+ sy = signedValue i y+ pure $! mkBv i (sx `rem` sy)+ | otherwise = panic "Attempt to mod words of different sizes: wordSignedMod" [show i, show j]++ wordLg2 _ (BV i x) = pure $! mkBv i (lg2 x)++ intEq _ x y = pure $! x == y+ intLessThan _ x y = pure $! x < y+ intGreaterThan _ x y = pure $! x > y++ intPlus _ x y = pure $! x + y+ intMinus _ x y = pure $! x - y+ intNegate _ x = pure $! negate x+ intMult _ x y = pure $! x * y+ intDiv sym x y =+ do assertSideCondition sym (y /= 0) DivideByZero+ pure $! x `div` y+ intMod sym x y =+ do assertSideCondition sym (y /= 0) DivideByZero+ pure $! x `mod` y++ intToZn _ 0 _ = evalPanic "intToZn" ["0 modulus not allowed"]+ intToZn _ m x = pure $! x `mod` m++ -- NB: requires we maintain the invariant that+ -- Z_n is in reduced form+ znToInt _ _m x = pure x+ znEq _ _m x y = pure $! x == y++ -- NB: under the precondition that `m` is prime,+ -- the only values for which no inverse exists are+ -- congruent to 0 modulo m.+ znRecip sym m x+ | r == 0 = raiseError sym DivideByZero+ | otherwise = pure r+ where+ r = Integer.recipModInteger x m++ znPlus _ = liftBinIntMod (+)+ znMinus _ = liftBinIntMod (-)+ znMult _ = liftBinIntMod (*)+ znNegate _ 0 _ = evalPanic "znNegate" ["0 modulus not allowed"]+ znNegate _ m x = pure $! (negate x) `mod` m++ ------------------------------------------------------------------------+ -- Floating Point+ fpLit _sym e p rat = pure (FP.fpLit e p rat)+ fpExactLit _sym bf = pure bf+ fpEq _sym x y = pure (FP.bfValue x == FP.bfValue y)+ fpLogicalEq _sym x y = pure (FP.bfCompare (FP.bfValue x) (FP.bfValue y) == EQ)+ fpLessThan _sym x y = pure (FP.bfValue x < FP.bfValue y)+ fpGreaterThan _sym x y = pure (FP.bfValue x > FP.bfValue y)+ fpPlus = fpBinArith FP.bfAdd+ fpMinus = fpBinArith FP.bfSub+ fpMult = fpBinArith FP.bfMul+ fpDiv = fpBinArith FP.bfDiv+ fpNeg _ x = pure x { FP.bfValue = FP.bfNeg (FP.bfValue x) }+ fpFromInteger sym e p r x =+ do opts <- FP.fpOpts e p <$> fpRoundMode sym r+ pure FP.BF { FP.bfExpWidth = e+ , FP.bfPrecWidth = p+ , FP.bfValue = FP.fpCheckStatus $+ FP.bfRoundInt opts (FP.bfFromInteger x)+ }+ fpToInteger = fpCvtToInteger+++{-# INLINE liftBinIntMod #-}+liftBinIntMod :: Monad m =>+ (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer -> m Integer+liftBinIntMod op m x y+ | m == 0 = evalPanic "znArithmetic" ["0 modulus not allowed"]+ | otherwise = pure $ (op x y) `mod` m++++{-# INLINE fpBinArith #-}+fpBinArith ::+ (FP.BFOpts -> FP.BigFloat -> FP.BigFloat -> (FP.BigFloat, FP.Status)) ->+ Concrete ->+ SWord Concrete {- ^ Rouding mode -} ->+ SFloat Concrete ->+ SFloat Concrete ->+ SEval Concrete (SFloat Concrete)+fpBinArith fun = \sym r x y ->+ do opts <- FP.fpOpts (FP.bfExpWidth x) (FP.bfPrecWidth x)+ <$> fpRoundMode sym r+ pure x { FP.bfValue = FP.fpCheckStatus+ (fun opts (FP.bfValue x) (FP.bfValue y)) }++fpCvtToInteger ::+ Concrete ->+ String ->+ SWord Concrete {- ^ Rounding mode -} ->+ SFloat Concrete ->+ SEval Concrete (SInteger Concrete)+fpCvtToInteger sym fun rnd flt =+ do mode <- fpRoundMode sym rnd+ case FP.floatToInteger fun mode flt of+ Right i -> pure i+ Left err -> raiseError sym err++fpRoundMode :: Concrete -> SWord Concrete -> SEval Concrete FP.RoundMode+fpRoundMode sym w =+ case FP.fpRound (bvVal w) of+ Left err -> raiseError sym err+ Right a -> pure a+++++
+ src/Cryptol/Backend/FloatHelpers.hs view
@@ -0,0 +1,248 @@+{-# Language BlockArguments, OverloadedStrings #-}+{-# Language BangPatterns #-}+module Cryptol.Backend.FloatHelpers where++import Data.Ratio(numerator,denominator)+import Data.Int(Int64)+import Data.Bits(testBit,setBit,shiftL,shiftR,(.&.),(.|.))+import LibBF++import Cryptol.Utils.PP+import Cryptol.Utils.Panic(panic)+import Cryptol.Backend.Monad( EvalError(..)+ , PPOpts(..), PPFloatFormat(..), PPFloatExp(..)+ )+++data BF = BF+ { bfExpWidth :: Integer+ , bfPrecWidth :: Integer+ , bfValue :: BigFloat+ }+++-- | Make LibBF options for the given precision and rounding mode.+fpOpts :: Integer -> Integer -> RoundMode -> BFOpts+fpOpts e p r =+ case ok of+ Just opts -> opts+ Nothing -> panic "floatOpts" [ "Invalid Float size"+ , "exponent: " ++ show e+ , "precision: " ++ show p+ ]+ where+ ok = do eb <- rng expBits expBitsMin expBitsMax e+ pb <- rng precBits precBitsMin precBitsMax p+ pure (eb <> pb <> allowSubnormal <> rnd r)++ rng f a b x = if toInteger a <= x && x <= toInteger b+ then Just (f (fromInteger x))+ else Nothing++++-- | Mapping from the rounding modes defined in the `Float.cry` to+-- the rounding modes of `LibBF`.+fpRound :: Integer -> Either EvalError RoundMode+fpRound n =+ case n of+ 0 -> Right NearEven+ 1 -> Right NearAway+ 2 -> Right ToPosInf+ 3 -> Right ToNegInf+ 4 -> Right ToZero+ _ -> Left (BadRoundingMode n)++-- | Check that we didn't get an unexpected status.+fpCheckStatus :: (BigFloat,Status) -> BigFloat+fpCheckStatus (r,s) =+ case s of+ MemError -> panic "checkStatus" [ "libBF: Memory error" ]+ _ -> r+++-- | Pretty print a float+fpPP :: PPOpts -> BF -> Doc+fpPP opts bf =+ case bfSign num of+ Nothing -> "fpNaN"+ Just s+ | bfIsFinite num -> text hacStr+ | otherwise ->+ case s of+ Pos -> "fpPosInf"+ Neg -> "fpNegInf"+ where+ num = bfValue bf+ precW = bfPrecWidth bf++ base = useFPBase opts++ withExp :: PPFloatExp -> ShowFmt -> ShowFmt+ withExp e f = case e of+ AutoExponent -> f+ ForceExponent -> f <> forceExp++ str = bfToString base fmt num+ fmt = addPrefix <> showRnd NearEven <>+ case useFPFormat opts of+ FloatFree e -> withExp e $ showFreeMin+ $ Just $ fromInteger precW+ FloatFixed n e -> withExp e $ showFixed $ fromIntegral n+ FloatFrac n -> showFrac $ fromIntegral n++ -- non-base 10 literals are not overloaded so we add an explicit+ -- .0 if one is not present. + hacStr+ | base == 10 || elem '.' str = str+ | otherwise = case break (== 'p') str of+ (xs,ys) -> xs ++ ".0" ++ ys+++-- | Make a literal+fpLit ::+ Integer {- ^ Exponent width -} ->+ Integer {- ^ Precision width -} ->+ Rational ->+ BF+fpLit e p rat = floatFromRational e p NearEven rat++-- | Make a floating point number from a rational, using the given rounding mode+floatFromRational :: Integer -> Integer -> RoundMode -> Rational -> BF+floatFromRational e p r rat =+ BF { bfExpWidth = e+ , bfPrecWidth = p+ , bfValue = fpCheckStatus+ if den == 1 then bfRoundFloat opts num+ else bfDiv opts num (bfFromInteger den)+ }+ where+ opts = fpOpts e p r++ num = bfFromInteger (numerator rat)+ den = denominator rat+++-- | Convert a floating point number to a rational, if possible.+floatToRational :: String -> BF -> Either EvalError Rational+floatToRational fun bf =+ case bfToRep (bfValue bf) of+ BFNaN -> Left (BadValue fun)+ BFRep s num ->+ case num of+ Inf -> Left (BadValue fun)+ Zero -> Right 0+ Num i ev -> Right case s of+ Pos -> ab+ Neg -> negate ab+ where ab = fromInteger i * (2 ^^ ev)+++-- | Convert a floating point number to an integer, if possible.+floatToInteger :: String -> RoundMode -> BF -> Either EvalError Integer+floatToInteger fun r fp =+ do rat <- floatToRational fun fp+ pure case r of+ NearEven -> round rat+ NearAway -> if rat > 0 then ceiling rat else floor rat+ ToPosInf -> ceiling rat+ ToNegInf -> floor rat+ ToZero -> truncate rat+ _ -> panic "fpCvtToInteger"+ ["Unexpected rounding mode", show r]+++++floatFromBits :: + Integer {- ^ Exponent width -} ->+ Integer {- ^ Precision widht -} ->+ Integer {- ^ Raw bits -} ->+ BF+floatFromBits e p bv = BF { bfValue = floatFromBits' e p bv+ , bfExpWidth = e, bfPrecWidth = p }++++-- | Make a float using "raw" bits.+floatFromBits' ::+ Integer {- ^ Exponent width -} ->+ Integer {- ^ Precision widht -} ->+ Integer {- ^ Raw bits -} ->+ BigFloat++floatFromBits' e p bits+ | expoBiased == 0 && mant == 0 = -- zero+ if isNeg then bfNegZero else bfPosZero++ | expoBiased == eMask && mant == 0 = -- infinity+ if isNeg then bfNegInf else bfPosInf++ | expoBiased == eMask = bfNaN -- NaN++ | expoBiased == 0 = -- Subnormal+ case bfMul2Exp opts (bfFromInteger mant) (expoVal + 1) of+ (num,Ok) -> if isNeg then bfNeg num else num+ (_,s) -> panic "floatFromBits" [ "Unexpected status: " ++ show s ]++ | otherwise = -- Normal+ case bfMul2Exp opts (bfFromInteger mantVal) expoVal of+ (num,Ok) -> if isNeg then bfNeg num else num+ (_,s) -> panic "floatFromBits" [ "Unexpected status: " ++ show s ]++ where+ opts = expBits e' <> precBits (p' + 1) <> allowSubnormal++ e' = fromInteger e :: Int+ p' = fromInteger p - 1 :: Int+ eMask = (1 `shiftL` e') - 1 :: Int64+ pMask = (1 `shiftL` p') - 1 :: Integer++ isNeg = testBit bits (e' + p')++ mant = pMask .&. bits :: Integer+ mantVal = mant `setBit` p' :: Integer+ -- accounts for the implicit 1 bit++ expoBiased = eMask .&. fromInteger (bits `shiftR` p') :: Int64+ bias = eMask `shiftR` 1 :: Int64+ expoVal = expoBiased - bias - fromIntegral p' :: Int64+++-- | Turn a float into raw bits.+-- @NaN@ is represented as a positive "quiet" @NaN@+-- (most significant bit in the significand is set, the rest of it is 0)+floatToBits :: Integer -> Integer -> BigFloat -> Integer+floatToBits e p bf = (isNeg `shiftL` (e' + p'))+ .|. (expBiased `shiftL` p')+ .|. (mant `shiftL` 0)+ where+ e' = fromInteger e :: Int+ p' = fromInteger p - 1 :: Int++ eMask = (1 `shiftL` e') - 1 :: Integer+ pMask = (1 `shiftL` p') - 1 :: Integer++ (isNeg, expBiased, mant) =+ case bfToRep bf of+ BFNaN -> (0, eMask, 1 `shiftL` (p' - 1))+ BFRep s num -> (sign, be, ma)+ where+ sign = case s of+ Neg -> 1+ Pos -> 0++ (be,ma) =+ case num of+ Zero -> (0,0)+ Num i ev+ | ex == 0 -> (0, i `shiftL` (p' - m -1))+ | otherwise -> (ex, (i `shiftL` (p' - m)) .&. pMask)+ where+ m = msb 0 i - 1+ bias = eMask `shiftR` 1+ ex = toInteger ev + bias + toInteger m++ Inf -> (eMask,0)++ msb !n j = if j == 0 then n else msb (n+1) (j `shiftR` 1)
+ src/Cryptol/Backend/Monad.hs view
@@ -0,0 +1,394 @@+-- |+-- Module : Cryptol.Eval.Monad+-- Copyright : (c) 2013-2016 Galois, Inc.+-- License : BSD3+-- Maintainer : cryptol@galois.com+-- Stability : provisional+-- Portability : portable++{-# LANGUAGE Safe #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}++module Cryptol.Backend.Monad+( -- * Evaluation monad+ Eval(..)+, runEval+, EvalOpts(..)+, PPOpts(..)+, asciiMode+, PPFloatFormat(..)+, PPFloatExp(..)+, defaultPPOpts+, io+, delayFill+, ready+, blackhole+, evalSpark+, maybeReady+ -- * Error reporting+, Unsupported(..)+, EvalError(..)+, evalPanic+, wordTooWide+, typeCannotBeDemoted+) where++import Control.Concurrent+import Control.Concurrent.STM++import Control.Monad+import qualified Control.Monad.Fail as Fail+import Control.Monad.Fix+import Control.Monad.IO.Class+import Data.Typeable (Typeable)+import qualified Control.Exception as X+++import Cryptol.Utils.Panic+import Cryptol.Utils.PP+import Cryptol.Utils.Logger(Logger)+import Cryptol.TypeCheck.AST(Type,Name)++-- | A computation that returns an already-evaluated value.+ready :: a -> Eval a+ready a = Ready a++-- | How to pretty print things when evaluating+data PPOpts = PPOpts+ { useAscii :: Bool+ , useBase :: Int+ , useInfLength :: Int+ , useFPBase :: Int+ , useFPFormat :: PPFloatFormat+ }++asciiMode :: PPOpts -> Integer -> Bool+asciiMode opts width = useAscii opts && (width == 7 || width == 8)++data PPFloatFormat =+ FloatFixed Int PPFloatExp -- ^ Use this many significant digis+ | FloatFrac Int -- ^ Show this many digits after floating point+ | FloatFree PPFloatExp -- ^ Use the correct number of digits++data PPFloatExp = ForceExponent -- ^ Always show an exponent+ | AutoExponent -- ^ Only show exponent when needed+++defaultPPOpts :: PPOpts+defaultPPOpts = PPOpts { useAscii = False, useBase = 10, useInfLength = 5+ , useFPBase = 16+ , useFPFormat = FloatFree AutoExponent+ }+++-- | Some options for evalutaion+data EvalOpts = EvalOpts+ { evalLogger :: Logger -- ^ Where to print stuff (e.g., for @trace@)+ , evalPPOpts :: PPOpts -- ^ How to pretty print things.+ }++-- | The monad for Cryptol evaluation.+-- A computation is either "ready", which means it represents+-- only trivial computation, or is an "eval" action which must+-- be computed to get the answer, or it is a "thunk", which+-- represents a delayed, shared computation.+data Eval a+ = Ready !a+ | Eval !(IO a)+ | Thunk !(TVar (ThunkState a))++-- | This datastructure tracks the lifecycle of a thunk.+--+-- Thunks are used for basically three use cases. First,+-- we use thunks to preserve sharing. Basically every+-- cryptol expression that is bound to a name, and is not+-- already obviously a value (and in a few other places as+-- well) will get turned into a thunk in order to avoid+-- recomputations. These thunks will start in the `Unforced`+-- state, and have a backup computation that just raises+-- the `LoopError` exception.+--+-- Secondly, thunks are used to cut cycles when evaluating+-- recursive definition groups. Every named clause in a+-- recursive definition is thunked so that the value can appear+-- in its definition. Such thunks start in the `Void` state,+-- as they must exist before we have a definition to assign them.+-- Forcing a thunk in the `Void` state is a programmer error (panic).+-- Once the body of a definition is ready, we replace the+-- thunk with the relevant computation, going to the `Unforced` state.+--+-- In the third case, we are using thunks to provide an optimistic+-- shortcut for evaluation. In these cases we first try to run a+-- computation that is stricter than the semantics actually allows.+-- If it succeeds, all is well an we continue. However, if it tight+-- loops, we fall back on a lazier (and generally more expensive)+-- version, which is the "backup" computation referred to above.+data ThunkState a+ = Void !String+ -- ^ This thunk has not yet been initialized+ | Unforced !(IO a) !(IO a)+ -- ^ This thunk has not yet been forced. We keep track of the "main"+ -- computation to run and a "backup" computation to run if we+ -- detect a tight loop when evaluating the first one.+ | UnderEvaluation !ThreadId !(IO a)+ -- ^ This thunk is currently being evaluated by the thread with the given+ -- thread ID. We track the "backup" computation to run if we detect+ -- a tight loop evaluating this thunk. If the thunk is being evaluated+ -- by some other thread, the current thread will await its completion.+ | ForcedErr !EvalError+ -- ^ This thunk has been forced, and its evaluation results in an exception+ | Forced !a+ -- ^ This thunk has been forced to the given value+++-- | Test if a value is "ready", which means that+-- it requires no computation to return.+maybeReady :: Eval a -> Eval (Maybe a)+maybeReady (Ready a) = pure (Just a)+maybeReady (Thunk tv) = Eval $+ readTVarIO tv >>= \case+ Forced a -> pure (Just a)+ _ -> pure Nothing+maybeReady (Eval _) = pure Nothing+++{-# INLINE delayFill #-}++-- | Delay the given evaluation computation, returning a thunk+-- which will run the computation when forced. Run the 'retry'+-- computation instead if the resulting thunk is forced during+-- its own evaluation.+delayFill ::+ Eval a {- ^ Computation to delay -} ->+ Eval a {- ^ Backup computation to run if a tight loop is detected -} ->+ Eval (Eval a)+delayFill e@(Ready _) _ = return e+delayFill e@(Thunk _) _ = return e+delayFill (Eval x) backup = Eval (Thunk <$> newTVarIO (Unforced x (runEval backup)))++-- | Begin executing the given operation in a separate thread,+-- returning a thunk which will await the completion of+-- the computation when forced.+evalSpark ::+ Eval a ->+ Eval (Eval a)++-- Ready computations need no additional evaluation.+evalSpark e@(Ready _) = return e++-- A thunked computation might already have+-- been forced. If so, return the result. Otherwise,+-- fork a thread to force this computation and return+-- the thunk.+evalSpark (Thunk tv) = Eval $+ readTVarIO tv >>= \case+ Forced x -> return (Ready x)+ ForcedErr ex -> return (Eval (X.throwIO ex))+ _ ->+ do _ <- forkIO (sparkThunk tv)+ return (Thunk tv)++-- If the computation is nontrivial but not already a thunk,+-- create a thunk and fork a thread to force it.+evalSpark (Eval x) = Eval $+ do tv <- newTVarIO (Unforced x (X.throwIO (LoopError "")))+ _ <- forkIO (sparkThunk tv)+ return (Thunk tv)+++-- | To the work of forcing a thunk. This is the worker computation+-- that is foked off via @evalSpark@.+sparkThunk :: TVar (ThunkState a) -> IO ()+sparkThunk tv =+ do tid <- myThreadId+ -- Try to claim the thunk. If it is still in the @Void@ state, wait+ -- until it is in some other state. If it is @Unforced@ claim the thunk.+ -- Otherwise, it is already evaluated or under evaluation by another thread,+ -- and we have no work to do.+ st <- atomically $+ do st <- readTVar tv+ case st of+ Void _ -> retry+ Unforced _ backup -> writeTVar tv (UnderEvaluation tid backup)+ _ -> return ()+ return st+ -- If we successfully claimed the thunk to work on, run the computation and+ -- update the thunk state with the result.+ case st of+ Unforced work _ ->+ X.try work >>= \case+ Left err -> atomically (writeTVar tv (ForcedErr err))+ Right a -> atomically (writeTVar tv (Forced a))+ _ -> return ()+++-- | Produce a thunk value which can be filled with its associated computation+-- after the fact. A preallocated thunk is returned, along with an operation to+-- fill the thunk with the associated computation.+-- This is used to implement recursive declaration groups.+blackhole ::+ String {- ^ A name to associate with this thunk. -} ->+ Eval (Eval a, Eval a -> Eval ())+blackhole msg = Eval $+ do tv <- newTVarIO (Void msg)+ let set (Ready x) = io $ atomically (writeTVar tv (Forced x))+ set m = io $ atomically (writeTVar tv (Unforced (runEval m) (X.throwIO (LoopError msg))))+ return (Thunk tv, set)++-- | Force a thunk to get the result.+unDelay :: TVar (ThunkState a) -> IO a+unDelay tv =+ -- First, check if the thunk is in an evaluated state,+ -- and return the value if so.+ readTVarIO tv >>= \case+ Forced x -> pure x+ ForcedErr e -> X.throwIO e+ _ ->+ -- Otherwise, try to claim the thunk to work on.+ do tid <- myThreadId+ res <- atomically $ do+ res <- readTVar tv+ case res of+ -- In this case, we claim the thunk. Update the state to indicate+ -- that we are working on it.+ Unforced _ backup -> writeTVar tv (UnderEvaluation tid backup)++ -- In this case, the thunk is already being evaluated. If it is+ -- under evaluation by this thread, we have to run the backup computation,+ -- and "consume" it by updating the backup computation to one that throws+ -- a loop error. If some other thread is evaluating, reset the+ -- transaction to await completion of the thunk.+ UnderEvaluation t _+ | tid == t -> writeTVar tv (UnderEvaluation tid (X.throwIO (LoopError "")))+ | otherwise -> retry -- wait, if some other thread is evaualting+ _ -> return ()++ -- Return the original thunk state so we can decide what work to do+ -- after the transaction completes.+ return res++ -- helper for actually doing the work+ let doWork work =+ X.try work >>= \case+ Left ex -> do atomically (writeTVar tv (ForcedErr ex))+ X.throwIO ex+ Right a -> do atomically (writeTVar tv (Forced a))+ return a++ -- Now, examine the thunk state and decide what to do.+ case res of+ Void msg -> evalPanic "unDelay" ["Thunk forced before it was initialized", msg]+ Forced x -> pure x+ ForcedErr e -> X.throwIO e+ UnderEvaluation _ backup -> doWork backup -- this thread was already evaluating this thunk+ Unforced work _ -> doWork work++-- | Execute the given evaluation action.+runEval :: Eval a -> IO a+runEval (Ready a) = return a+runEval (Eval x) = x+runEval (Thunk tv) = unDelay tv++{-# INLINE evalBind #-}+evalBind :: Eval a -> (a -> Eval b) -> Eval b+evalBind (Ready a) f = f a+evalBind (Eval x) f = Eval (x >>= runEval . f)+evalBind (Thunk x) f = Eval (unDelay x >>= runEval . f)++instance Functor Eval where+ fmap f (Ready x) = Ready (f x)+ fmap f (Eval m) = Eval (f <$> m)+ fmap f (Thunk tv) = Eval (f <$> unDelay tv)+ {-# INLINE fmap #-}++instance Applicative Eval where+ pure = return+ (<*>) = ap+ {-# INLINE pure #-}+ {-# INLINE (<*>) #-}++instance Monad Eval where+ return = Ready+ (>>=) = evalBind+ {-# INLINE return #-}+ {-# INLINE (>>=) #-}++instance Fail.MonadFail Eval where+ fail x = Eval (fail x)++instance MonadIO Eval where+ liftIO = io++instance MonadFix Eval where+ mfix f = Eval $ mfix (\x -> runEval (f x))++-- | Lift an 'IO' computation into the 'Eval' monad.+io :: IO a -> Eval a+io m = Eval m+{-# INLINE io #-}+++-- Errors ----------------------------------------------------------------------++-- | Panic from an @Eval@ context.+evalPanic :: HasCallStack => String -> [String] -> a+evalPanic cxt = panic ("[Eval] " ++ cxt)+++-- | Data type describing errors that can occur during evaluation.+data EvalError+ = InvalidIndex (Maybe Integer) -- ^ Out-of-bounds index+ | TypeCannotBeDemoted Type -- ^ Non-numeric type passed to @number@ function+ | DivideByZero -- ^ Division or modulus by 0+ | NegativeExponent -- ^ Exponentiation by negative integer+ | LogNegative -- ^ Logarithm of a negative integer+ | WordTooWide Integer -- ^ Bitvector too large+ | UserError String -- ^ Call to the Cryptol @error@ primitive+ | LoopError String -- ^ Detectable nontermination+ | NoPrim Name -- ^ Primitive with no implementation+ | BadRoundingMode Integer -- ^ Invalid rounding mode+ | BadValue String -- ^ Value outside the domain of a partial function.+ deriving (Typeable,Show)++instance PP EvalError where+ ppPrec _ e = case e of+ InvalidIndex (Just i) -> text "invalid sequence index:" <+> integer i+ InvalidIndex Nothing -> text "invalid sequence index"+ TypeCannotBeDemoted t -> text "type cannot be demoted:" <+> pp t+ DivideByZero -> text "division by 0"+ NegativeExponent -> text "negative exponent"+ LogNegative -> text "logarithm of negative"+ WordTooWide w ->+ text "word too wide for memory:" <+> integer w <+> text "bits"+ UserError x -> text "Run-time error:" <+> text x+ LoopError x -> text "<<loop>>" <+> text x+ BadRoundingMode r -> "invalid rounding mode" <+> integer r+ BadValue x -> "invalid input for" <+> backticks (text x)+ NoPrim x -> text "unimplemented primitive:" <+> pp x++instance X.Exception EvalError+++data Unsupported+ = UnsupportedSymbolicOp String -- ^ Operation cannot be supported in the symbolic simulator+ deriving (Typeable,Show)++instance PP Unsupported where+ ppPrec _ e = case e of+ UnsupportedSymbolicOp nm -> text "operation can not be supported on symbolic values:" <+> text nm++instance X.Exception Unsupported+++-- | For things like @`(inf)@ or @`(0-1)@.+typeCannotBeDemoted :: Type -> a+typeCannotBeDemoted t = X.throw (TypeCannotBeDemoted t)++-- | For when we know that a word is too wide and will exceed gmp's+-- limits (though words approaching this size will probably cause the+-- system to crash anyway due to lack of memory).+wordTooWide :: Integer -> a+wordTooWide w = X.throw (WordTooWide w)
+ src/Cryptol/Backend/SBV.hs view
@@ -0,0 +1,457 @@+-- |+-- Module : Cryptol.Backend.SBV+-- Copyright : (c) 2013-2016 Galois, Inc.+-- License : BSD3+-- Maintainer : cryptol@galois.com+-- Stability : provisional+-- Portability : portable++{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE ViewPatterns #-}+module Cryptol.Backend.SBV+ ( SBV(..), SBVEval(..), SBVResult(..)+ , literalSWord+ , freshSBool_+ , freshBV_+ , freshSInteger_+ , addDefEqn+ , ashr+ , lshr+ , shl+ , evalPanic+ , svFromInteger+ , svToInteger+ ) where++import qualified Control.Exception as X+import Control.Concurrent.MVar+import Control.Monad.IO.Class (MonadIO(..))+import Data.Bits (bit, complement)+import Data.List (foldl')++import qualified GHC.Integer.GMP.Internals as Integer++import Data.SBV.Dynamic as SBV+import qualified Data.SBV.Internals as SBV++import Cryptol.Backend+import Cryptol.Backend.Concrete ( integerToChar, ppBV, BV(..) )+import Cryptol.Backend.Monad+ ( Eval(..), blackhole, delayFill, evalSpark+ , EvalError(..), Unsupported(..)+ )++import Cryptol.Utils.Panic (panic)+import Cryptol.Utils.PP++data SBV =+ SBV+ { sbvStateVar :: MVar (SBV.State)+ , sbvDefRelations :: MVar SVal+ }++-- Utility operations -------------------------------------------------------------++fromBitsLE :: [SBit SBV] -> SWord SBV+fromBitsLE bs = foldl' f (literalSWord 0 0) bs+ where f w b = svJoin (svToWord1 b) w++packSBV :: [SBit SBV] -> SWord SBV+packSBV bs = fromBitsLE (reverse bs)++unpackSBV :: SWord SBV -> [SBit SBV]+unpackSBV x = [ svTestBit x i | i <- reverse [0 .. intSizeOf x - 1] ]++literalSWord :: Int -> Integer -> SWord SBV+literalSWord w i = svInteger (KBounded False w) i++freshBV_ :: SBV -> Int -> IO (SWord SBV)+freshBV_ (SBV stateVar _) w =+ withMVar stateVar (svMkSymVar Nothing (KBounded False w) Nothing)++freshSBool_ :: SBV -> IO (SBit SBV)+freshSBool_ (SBV stateVar _) =+ withMVar stateVar (svMkSymVar Nothing KBool Nothing)++freshSInteger_ :: SBV -> IO (SInteger SBV)+freshSInteger_ (SBV stateVar _) =+ withMVar stateVar (svMkSymVar Nothing KUnbounded Nothing)+++-- SBV Evaluation monad -------------------------------------------------------++data SBVResult a+ = SBVError !EvalError+ | SBVResult !SVal !a -- safety predicate and result++instance Functor SBVResult where+ fmap _ (SBVError err) = SBVError err+ fmap f (SBVResult p x) = SBVResult p (f x)++instance Applicative SBVResult where+ pure = SBVResult svTrue+ SBVError err <*> _ = SBVError err+ _ <*> SBVError err = SBVError err+ SBVResult p1 f <*> SBVResult p2 x = SBVResult (svAnd p1 p2) (f x)++instance Monad SBVResult where+ return = pure+ SBVError err >>= _ = SBVError err+ SBVResult px x >>= m =+ case m x of+ SBVError err -> SBVError err+ SBVResult pm z -> SBVResult (svAnd px pm) z++newtype SBVEval a = SBVEval{ sbvEval :: Eval (SBVResult a) }+ deriving (Functor)++instance Applicative SBVEval where+ pure = SBVEval . pure . pure+ f <*> x = SBVEval $+ do f' <- sbvEval f+ x' <- sbvEval x+ pure (f' <*> x')++instance Monad SBVEval where+ return = pure+ x >>= f = SBVEval $+ sbvEval x >>= \case+ SBVError err -> pure (SBVError err)+ SBVResult px x' ->+ sbvEval (f x') >>= \case+ SBVError err -> pure (SBVError err)+ SBVResult pz z -> pure (SBVResult (svAnd px pz) z)++instance MonadIO SBVEval where+ liftIO m = SBVEval $ fmap pure (liftIO m)+++addDefEqn :: SBV -> SVal -> IO ()+addDefEqn (SBV _ relsVar) b = modifyMVar_ relsVar (pure . svAnd b)++-- Symbolic Big-endian Words -------------------------------------------------------++instance Backend SBV where+ type SBit SBV = SVal+ type SWord SBV = SVal+ type SInteger SBV = SVal+ type SFloat SBV = () -- XXX: not implemented+ type SEval SBV = SBVEval++ raiseError _ err = SBVEval (pure (SBVError err))++ assertSideCondition _ cond err+ | Just False <- svAsBool cond = SBVEval (pure (SBVError err))+ | otherwise = SBVEval (pure (SBVResult cond ()))++ isReady _ (SBVEval (Ready _)) = True+ isReady _ _ = False++ sDelayFill _ m retry = SBVEval $+ do m' <- delayFill (sbvEval m) (sbvEval retry)+ pure (pure (SBVEval m'))++ sSpark _ m = SBVEval $+ do m' <- evalSpark (sbvEval m)+ pure (pure (SBVEval m'))++ sDeclareHole _ msg = SBVEval $+ do (hole, fill) <- blackhole msg+ pure (pure (SBVEval hole, \m -> SBVEval (fmap pure $ fill (sbvEval m))))++ mergeEval _sym f c mx my = SBVEval $+ do rx <- sbvEval mx+ ry <- sbvEval my+ case (rx, ry) of+ (SBVError err, SBVError _) ->+ pure $ SBVError err -- arbitrarily choose left error to report+ (SBVError _, SBVResult p y) ->+ pure $ SBVResult (svAnd (svNot c) p) y+ (SBVResult p x, SBVError _) ->+ pure $ SBVResult (svAnd c p) x+ (SBVResult px x, SBVResult py y) ->+ do zr <- sbvEval (f c x y)+ case zr of+ SBVError err -> pure $ SBVError err+ SBVResult pz z ->+ pure $ SBVResult (svAnd (svIte c px py) pz) z++ wordLen _ v = toInteger (intSizeOf v)+ wordAsChar _ v = integerToChar <$> svAsInteger v++ ppBit _ v+ | Just b <- svAsBool v = text $! if b then "True" else "False"+ | otherwise = text "?"+ ppWord sym opts v+ | Just x <- svAsInteger v = ppBV opts (BV (wordLen sym v) x)+ | otherwise = text "[?]"+ ppInteger _ _opts v+ | Just x <- svAsInteger v = integer x+ | otherwise = text "[?]"++ iteBit _ b x y = pure $! svSymbolicMerge KBool True b x y+ iteWord _ b x y = pure $! svSymbolicMerge (kindOf x) True b x y+ iteInteger _ b x y = pure $! svSymbolicMerge KUnbounded True b x y++ bitAsLit _ b = svAsBool b+ wordAsLit _ w =+ case svAsInteger w of+ Just x -> Just (toInteger (intSizeOf w), x)+ Nothing -> Nothing+ integerAsLit _ v = svAsInteger v++ bitLit _ b = svBool b+ wordLit _ n x = pure $! literalSWord (fromInteger n) x+ integerLit _ x = pure $! svInteger KUnbounded x++ bitEq _ x y = pure $! svEqual x y+ bitOr _ x y = pure $! svOr x y+ bitAnd _ x y = pure $! svAnd x y+ bitXor _ x y = pure $! svXOr x y+ bitComplement _ x = pure $! svNot x++ wordBit _ x idx = pure $! svTestBit x (intSizeOf x - 1 - fromInteger idx)++ wordUpdate _ x idx b = pure $! svSymbolicMerge (kindOf x) False b wtrue wfalse+ where+ i' = intSizeOf x - 1 - fromInteger idx+ wtrue = x `svOr` svInteger (kindOf x) (bit i' :: Integer)+ wfalse = x `svAnd` svInteger (kindOf x) (complement (bit i' :: Integer))++ packWord _ bs = pure $! packSBV bs+ unpackWord _ x = pure $! unpackSBV x++ wordEq _ x y = pure $! svEqual x y+ wordLessThan _ x y = pure $! svLessThan x y+ wordGreaterThan _ x y = pure $! svGreaterThan x y++ wordSignedLessThan _ x y = pure $! svLessThan sx sy+ where sx = svSign x+ sy = svSign y++ joinWord _ x y = pure $! svJoin x y++ splitWord _ _leftW rightW w = pure+ ( svExtract (intSizeOf w - 1) (fromInteger rightW) w+ , svExtract (fromInteger rightW - 1) 0 w+ )++ extractWord _ len start w =+ pure $! svExtract (fromInteger start + fromInteger len - 1) (fromInteger start) w++ wordAnd _ a b = pure $! svAnd a b+ wordOr _ a b = pure $! svOr a b+ wordXor _ a b = pure $! svXOr a b+ wordComplement _ a = pure $! svNot a++ wordPlus _ a b = pure $! svPlus a b+ wordMinus _ a b = pure $! svMinus a b+ wordMult _ a b = pure $! svTimes a b+ wordNegate _ a = pure $! svUNeg a++ wordDiv sym a b =+ do let z = literalSWord (intSizeOf b) 0+ assertSideCondition sym (svNot (svEqual b z)) DivideByZero+ pure $! svQuot a b++ wordMod sym a b =+ do let z = literalSWord (intSizeOf b) 0+ assertSideCondition sym (svNot (svEqual b z)) DivideByZero+ pure $! svRem a b++ wordSignedDiv sym a b =+ do let z = literalSWord (intSizeOf b) 0+ assertSideCondition sym (svNot (svEqual b z)) DivideByZero+ pure $! signedQuot a b++ wordSignedMod sym a b =+ do let z = literalSWord (intSizeOf b) 0+ assertSideCondition sym (svNot (svEqual b z)) DivideByZero+ pure $! signedRem a b++ wordLg2 _ a = sLg2 a++ wordToInt _ x = pure $! svToInteger x+ wordFromInt _ w i = pure $! svFromInteger w i++ intEq _ a b = pure $! svEqual a b+ intLessThan _ a b = pure $! svLessThan a b+ intGreaterThan _ a b = pure $! svGreaterThan a b++ intPlus _ a b = pure $! svPlus a b+ intMinus _ a b = pure $! svMinus a b+ intMult _ a b = pure $! svTimes a b+ intNegate _ a = pure $! SBV.svUNeg a++ intDiv sym a b =+ do let z = svInteger KUnbounded 0+ assertSideCondition sym (svNot (svEqual b z)) DivideByZero+ let p = svLessThan z b+ pure $! svSymbolicMerge KUnbounded True p (svQuot a b) (svQuot (svUNeg a) (svUNeg b))+ intMod sym a b =+ do let z = svInteger KUnbounded 0+ assertSideCondition sym (svNot (svEqual b z)) DivideByZero+ let p = svLessThan z b+ pure $! svSymbolicMerge KUnbounded True p (svRem a b) (svUNeg (svRem (svUNeg a) (svUNeg b)))++ -- NB, we don't do reduction here+ intToZn _ _m a = pure a++ znToInt _ 0 _ = evalPanic "znToInt" ["0 modulus not allowed"]+ znToInt _ m a =+ do let m' = svInteger KUnbounded m+ pure $! svRem a m'++ znEq _ 0 _ _ = evalPanic "znEq" ["0 modulus not allowed"]+ znEq sym m a b = svDivisible sym m (SBV.svMinus a b)++ znPlus sym m a b = sModAdd sym m a b+ znMinus sym m a b = sModSub sym m a b+ znMult sym m a b = sModMult sym m a b+ znNegate sym m a = sModNegate sym m a+ znRecip = sModRecip++ ppFloat _ _ _ = text "[?]"+ fpExactLit _ _ = unsupported "fpExactLit"+ fpLit _ _ _ _ = unsupported "fpLit"+ fpLogicalEq _ _ _ = unsupported "fpLogicalEq"+ fpEq _ _ _ = unsupported "fpEq"+ fpLessThan _ _ _ = unsupported "fpLessThan"+ fpGreaterThan _ _ _ = unsupported "fpGreaterThan"+ fpPlus _ _ _ _ = unsupported "fpPlus"+ fpMinus _ _ _ _ = unsupported "fpMinus"+ fpMult _ _ _ _ = unsupported "fpMult"+ fpDiv _ _ _ _ = unsupported "fpDiv"+ fpNeg _ _ = unsupported "fpNeg"+ fpFromInteger _ _ _ _ _ = unsupported "fpFromInteger"+ fpToInteger _ _ _ _ = unsupported "fpToInteger"++unsupported :: String -> SEval SBV a+unsupported x = liftIO (X.throw (UnsupportedSymbolicOp x))+++svToInteger :: SWord SBV -> SInteger SBV+svToInteger w =+ case svAsInteger w of+ Nothing -> svFromIntegral KUnbounded w+ Just x -> svInteger KUnbounded x++svFromInteger :: Integer -> SInteger SBV -> SWord SBV+svFromInteger 0 _ = literalSWord 0 0+svFromInteger n i =+ case svAsInteger i of+ Nothing -> svFromIntegral (KBounded False (fromInteger n)) i+ Just x -> literalSWord (fromInteger n) x++-- Errors ----------------------------------------------------------------------++evalPanic :: String -> [String] -> a+evalPanic cxt = panic ("[SBV] " ++ cxt)+++sModAdd :: SBV -> Integer -> SInteger SBV -> SInteger SBV -> SEval SBV (SInteger SBV)+sModAdd _ 0 _ _ = evalPanic "sModAdd" ["0 modulus not allowed"]+sModAdd sym modulus x y =+ case (SBV.svAsInteger x, SBV.svAsInteger y) of+ (Just i, Just j) -> integerLit sym ((i + j) `mod` modulus)+ _ -> pure $ SBV.svPlus x y++sModSub :: SBV -> Integer -> SInteger SBV -> SInteger SBV -> SEval SBV (SInteger SBV)+sModSub _ 0 _ _ = evalPanic "sModSub" ["0 modulus not allowed"]+sModSub sym modulus x y =+ case (SBV.svAsInteger x, SBV.svAsInteger y) of+ (Just i, Just j) -> integerLit sym ((i - j) `mod` modulus)+ _ -> pure $ SBV.svMinus x y++sModNegate :: SBV -> Integer -> SInteger SBV -> SEval SBV (SInteger SBV)+sModNegate _ 0 _ = evalPanic "sModNegate" ["0 modulus not allowed"]+sModNegate sym modulus x =+ case SBV.svAsInteger x of+ Just i -> integerLit sym ((negate i) `mod` modulus)+ _ -> pure $ SBV.svUNeg x++sModMult :: SBV -> Integer -> SInteger SBV -> SInteger SBV -> SEval SBV (SInteger SBV)+sModMult _ 0 _ _ = evalPanic "sModMult" ["0 modulus not allowed"]+sModMult sym modulus x y =+ case (SBV.svAsInteger x, SBV.svAsInteger y) of+ (Just i, Just j) -> integerLit sym ((i * j) `mod` modulus)+ _ -> pure $ SBV.svTimes x y++-- Create a fresh constant and assert that it is the+-- multiplicitive inverse of x; return the constant.+-- Such an inverse must exist under the precondition+-- that the modulus is prime and the input is nonzero.+sModRecip ::+ SBV ->+ Integer {- ^ modulus: must be prime -} ->+ SInteger SBV ->+ SEval SBV (SInteger SBV)+sModRecip _sym 0 _ = panic "sModRecip" ["0 modulus not allowed"]+sModRecip sym m x+ -- If the input is concrete, evaluate the answer+ | Just xi <- svAsInteger x+ = let r = Integer.recipModInteger xi m+ in if r == 0 then raiseError sym DivideByZero else integerLit sym r++ -- If the input is symbolic, create a new symbolic constant+ -- and assert that it is the desired multiplicitive inverse.+ -- Such an inverse will exist under the precondition that+ -- the modulus is prime, and as long as the input is nonzero.+ | otherwise+ = do divZero <- svDivisible sym m x+ assertSideCondition sym (svNot divZero) DivideByZero++ z <- liftIO (freshSInteger_ sym)+ let xz = svTimes x z+ rel <- znEq sym m xz (svInteger KUnbounded 1)+ let range = svAnd (svLessThan (svInteger KUnbounded 0) z)+ (svLessThan z (svInteger KUnbounded m))+ liftIO (addDefEqn sym (svAnd range (svOr divZero rel)))++ return z++-- | Ceiling (log_2 x)+sLg2 :: SWord SBV -> SEval SBV (SWord SBV)+sLg2 x = pure $ go 0+ where+ lit n = literalSWord (SBV.intSizeOf x) n+ go i | i < SBV.intSizeOf x = SBV.svIte (SBV.svLessEq x (lit (2^i))) (lit (toInteger i)) (go (i + 1))+ | otherwise = lit (toInteger i)++svDivisible :: SBV -> Integer -> SInteger SBV -> SEval SBV (SBit SBV)+svDivisible sym m x =+ do m' <- integerLit sym m+ z <- integerLit sym 0+ pure $ SBV.svEqual (SBV.svRem x m') z++signedQuot :: SWord SBV -> SWord SBV -> SWord SBV+signedQuot x y = SBV.svUnsign (SBV.svQuot (SBV.svSign x) (SBV.svSign y))++signedRem :: SWord SBV -> SWord SBV -> SWord SBV+signedRem x y = SBV.svUnsign (SBV.svRem (SBV.svSign x) (SBV.svSign y))++ashr :: SVal -> SVal -> SVal+ashr x idx =+ case SBV.svAsInteger idx of+ Just i -> SBV.svUnsign (SBV.svShr (SBV.svSign x) (fromInteger i))+ Nothing -> SBV.svUnsign (SBV.svShiftRight (SBV.svSign x) idx)++lshr :: SVal -> SVal -> SVal+lshr x idx =+ case SBV.svAsInteger idx of+ Just i -> SBV.svShr x (fromInteger i)+ Nothing -> SBV.svShiftRight x idx++shl :: SVal -> SVal -> SVal+shl x idx =+ case SBV.svAsInteger idx of+ Just i -> SBV.svShl x (fromInteger i)+ Nothing -> SBV.svShiftLeft x idx
+ src/Cryptol/Backend/What4.hs view
@@ -0,0 +1,666 @@+-- |+-- Module : Cryptol.Backend.What4+-- Copyright : (c) 2020 Galois, Inc.+-- License : BSD3+-- Maintainer : cryptol@galois.com++{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-}+module Cryptol.Backend.What4 where+++import qualified Control.Exception as X+import Control.Concurrent.MVar+import Control.Monad (foldM,ap,liftM)+import Control.Monad.IO.Class+import Data.Bits (bit)+import qualified Data.BitVector.Sized as BV+import Data.List+import Data.Map (Map)+import Data.Set (Set)+import Data.Text (Text)+import Data.Parameterized.NatRepr+import Data.Parameterized.Some++import qualified GHC.Integer.GMP.Internals as Integer++import qualified What4.Interface as W4+import qualified What4.SWord as SW++import qualified Cryptol.Backend.What4.SFloat as FP++import Cryptol.Backend+import Cryptol.Backend.Concrete( BV(..), ppBV )+import Cryptol.Backend.FloatHelpers+import Cryptol.Backend.Monad+ ( Eval(..), EvalError(..), Unsupported(..)+ , delayFill, blackhole, evalSpark+ )+import Cryptol.Utils.Panic+import Cryptol.Utils.PP+++data What4 sym =+ What4+ { w4 :: sym+ , w4defs :: MVar (W4.Pred sym)+ , w4funs :: MVar (What4FunCache sym)+ , w4uninterpWarns :: MVar (Set Text)+ }++type What4FunCache sym = Map Text (SomeSymFn sym)++data SomeSymFn sym =+ forall args ret. SomeSymFn (W4.SymFn sym args ret)++{- | This is the monad used for symbolic evaluation. It adds to+aspects to 'Eval'---'WConn' keeps track of the backend and collects+definitional predicates, and 'W4Eval` adds support for partially+defined values -}+newtype W4Eval sym a = W4Eval { evalPartial :: W4Conn sym (W4Result sym a) }++{- | This layer has the symbolic back-end, and can keep track of definitional+predicates used when working with uninterpreted constants defined+via a property. -}+newtype W4Conn sym a = W4Conn { evalConn :: sym -> Eval a }++-- | The symbolic value we computed.+data W4Result sym a+ = W4Error !EvalError+ -- ^ A malformed value++ | W4Result !(W4.Pred sym) !a+ -- ^ safety predicate and result: the result only makes sense when+ -- the predicate holds.+++--------------------------------------------------------------------------------+-- Moving between the layers++w4Eval :: W4Eval sym a -> sym -> Eval (W4Result sym a)+w4Eval (W4Eval (W4Conn m)) = m++w4Thunk :: Eval (W4Result sym a) -> W4Eval sym a+w4Thunk m = W4Eval (W4Conn \_ -> m)++-- | A value with no context.+doEval :: W4.IsSymExprBuilder sym => Eval a -> W4Conn sym a+doEval m = W4Conn \_sym -> m++-- | A total value.+total :: W4.IsSymExprBuilder sym => W4Conn sym a -> W4Eval sym a+total m = W4Eval+ do sym <- getSym+ W4Result (W4.backendPred sym True) <$> m++--------------------------------------------------------------------------------+-- Operations in WConn++instance W4.IsSymExprBuilder sym => Functor (W4Conn sym) where+ fmap = liftM++instance W4.IsSymExprBuilder sym => Applicative (W4Conn sym) where+ pure = doEval . pure+ (<*>) = ap++instance W4.IsSymExprBuilder sym => Monad (W4Conn sym) where+ m1 >>= f = W4Conn \sym ->+ do res1 <- evalConn m1 sym+ evalConn (f res1) sym++instance W4.IsSymExprBuilder sym => MonadIO (W4Conn sym) where+ liftIO = doEval . liftIO++-- | Access the symbolic back-end+getSym :: W4Conn sym sym+getSym = W4Conn \sym -> pure sym++-- | Record a definition.+--addDef :: W4.Pred sym -> W4Conn sym ()+--addDef p = W4Conn \_ -> pure W4Defs { w4Defs = p, w4Result = () }++-- | Compute conjunction.+w4And :: W4.IsSymExprBuilder sym =>+ W4.Pred sym -> W4.Pred sym -> W4Conn sym (W4.Pred sym)+w4And p q =+ do sym <- getSym+ liftIO (W4.andPred sym p q)++-- | Compute negation.+w4Not :: W4.IsSymExprBuilder sym => W4.Pred sym -> W4Conn sym (W4.Pred sym)+w4Not p =+ do sym <- getSym+ liftIO (W4.notPred sym p)++-- | Compute if-then-else.+w4ITE :: W4.IsSymExprBuilder sym =>+ W4.Pred sym -> W4.Pred sym -> W4.Pred sym -> W4Conn sym (W4.Pred sym)+w4ITE ifP ifThen ifElse =+ do sym <- getSym+ liftIO (W4.itePred sym ifP ifThen ifElse)++++--------------------------------------------------------------------------------+-- Operations in W4Eval++instance W4.IsSymExprBuilder sym => Functor (W4Eval sym) where+ fmap = liftM++instance W4.IsSymExprBuilder sym => Applicative (W4Eval sym) where+ pure = total . pure+ (<*>) = ap++instance W4.IsSymExprBuilder sym => Monad (W4Eval sym) where+ m1 >>= f = W4Eval+ do res1 <- evalPartial m1+ case res1 of+ W4Error err -> pure (W4Error err)+ W4Result px x' ->+ do res2 <- evalPartial (f x')+ case res2 of+ W4Result py y ->+ do pz <- w4And px py+ pure (W4Result pz y)+ W4Error _ -> pure res2++instance W4.IsSymExprBuilder sym => MonadIO (W4Eval sym) where+ liftIO = total . liftIO+++-- | Add a definitional equation.+-- This will always be asserted when we make queries to the solver.+addDefEqn :: W4.IsSymExprBuilder sym => What4 sym -> W4.Pred sym -> W4Eval sym ()+addDefEqn sym p =+ liftIO (modifyMVar_ (w4defs sym) (W4.andPred (w4 sym) p))++-- | Add s safety condition.+addSafety :: W4.IsSymExprBuilder sym => W4.Pred sym -> W4Eval sym ()+addSafety p = W4Eval (pure (W4Result p ()))++-- | A fully undefined symbolic value+evalError :: W4.IsSymExprBuilder sym => EvalError -> W4Eval sym a+evalError err = W4Eval (pure (W4Error err))++--------------------------------------------------------------------------------+++assertBVDivisor :: W4.IsSymExprBuilder sym => What4 sym -> SW.SWord sym -> W4Eval sym ()+assertBVDivisor sym x =+ do p <- liftIO (SW.bvIsNonzero (w4 sym) x)+ assertSideCondition sym p DivideByZero++assertIntDivisor ::+ W4.IsSymExprBuilder sym => What4 sym -> W4.SymInteger sym -> W4Eval sym ()+assertIntDivisor sym x =+ do p <- liftIO (W4.notPred (w4 sym) =<< W4.intEq (w4 sym) x =<< W4.intLit (w4 sym) 0)+ assertSideCondition sym p DivideByZero++instance W4.IsSymExprBuilder sym => Backend (What4 sym) where+ type SBit (What4 sym) = W4.Pred sym+ type SWord (What4 sym) = SW.SWord sym+ type SInteger (What4 sym) = W4.SymInteger sym+ type SFloat (What4 sym) = FP.SFloat sym+ type SEval (What4 sym) = W4Eval sym++ raiseError _ = evalError++ assertSideCondition _ cond err+ | Just False <- W4.asConstantPred cond = evalError err+ | otherwise = addSafety cond++ isReady sym m =+ case w4Eval m (w4 sym) of+ Ready _ -> True+ _ -> False++ sDelayFill _ m retry =+ total+ do sym <- getSym+ doEval (w4Thunk <$> delayFill (w4Eval m sym) (w4Eval retry sym))++ sSpark _ m =+ total+ do sym <- getSym+ doEval (w4Thunk <$> evalSpark (w4Eval m sym))+++ sDeclareHole _ msg =+ total+ do (hole, fill) <- doEval (blackhole msg)+ pure ( w4Thunk hole+ , \m -> total+ do sym <- getSym+ doEval (fill (w4Eval m sym))+ )++ mergeEval _sym f c mx my = W4Eval+ do rx <- evalPartial mx+ ry <- evalPartial my+ case (rx, ry) of++ (W4Error err, W4Error _) ->+ pure (W4Error err) -- arbitrarily choose left error to report++ (W4Error _, W4Result p y) ->+ do p' <- w4And p =<< w4Not c+ pure (W4Result p' y)++ (W4Result p x, W4Error _) ->+ do p' <- w4And p c+ pure (W4Result p' x)++ (W4Result px x, W4Result py y) ->+ do zr <- evalPartial (f c x y)+ case zr of+ W4Error err -> pure $ W4Error err+ W4Result pz z ->+ do p' <- w4And pz =<< w4ITE c px py+ pure (W4Result p' z)++ wordAsChar _ bv+ | SW.bvWidth bv == 8 = toEnum . fromInteger <$> SW.bvAsUnsignedInteger bv+ | otherwise = Nothing++ wordLen _ bv = SW.bvWidth bv++ bitLit sym b = W4.backendPred (w4 sym) b+ bitAsLit _ v = W4.asConstantPred v++ wordLit sym intw i+ | Just (Some w) <- someNat intw+ = case isPosNat w of+ Nothing -> pure $ SW.ZBV+ Just LeqProof -> SW.DBV <$> liftIO (W4.bvLit (w4 sym) w (BV.mkBV w i))+ | otherwise = panic "what4: wordLit" ["invalid bit width:", show intw ]++ wordAsLit _ v+ | Just x <- SW.bvAsUnsignedInteger v = Just (SW.bvWidth v, x)+ | otherwise = Nothing++ integerLit sym i = liftIO (W4.intLit (w4 sym) i)++ integerAsLit _ v = W4.asInteger v++ ppBit _ v+ | Just b <- W4.asConstantPred v = text $! if b then "True" else "False"+ | otherwise = text "?"++ ppWord _ opts v+ | Just x <- SW.bvAsUnsignedInteger v+ = ppBV opts (BV (SW.bvWidth v) x)++ | otherwise = text "[?]"++ ppInteger _ _opts v+ | Just x <- W4.asInteger v = integer x+ | otherwise = text "[?]"++ ppFloat _ _opts _ = text "[?]"++ iteBit sym c x y = liftIO (W4.itePred (w4 sym) c x y)+ iteWord sym c x y = liftIO (SW.bvIte (w4 sym) c x y)+ iteInteger sym c x y = liftIO (W4.intIte (w4 sym) c x y)++ bitEq sym x y = liftIO (W4.eqPred (w4 sym) x y)+ bitAnd sym x y = liftIO (W4.andPred (w4 sym) x y)+ bitOr sym x y = liftIO (W4.orPred (w4 sym) x y)+ bitXor sym x y = liftIO (W4.xorPred (w4 sym) x y)+ bitComplement sym x = liftIO (W4.notPred (w4 sym) x)++ wordBit sym bv idx = liftIO (SW.bvAtBE (w4 sym) bv idx)+ wordUpdate sym bv idx b = liftIO (SW.bvSetBE (w4 sym) bv idx b)++ packWord sym bs =+ do z <- wordLit sym (genericLength bs) 0+ let f w (idx,b) = wordUpdate sym w idx b+ foldM f z (zip [0..] bs)++ unpackWord sym bv = liftIO $+ mapM (SW.bvAtBE (w4 sym) bv) [0 .. SW.bvWidth bv-1]++ joinWord sym x y = liftIO $ SW.bvJoin (w4 sym) x y++ splitWord _sym 0 _ bv = pure (SW.ZBV, bv)+ splitWord _sym _ 0 bv = pure (bv, SW.ZBV)+ splitWord sym lw rw bv = liftIO $+ do l <- SW.bvSliceBE (w4 sym) 0 lw bv+ r <- SW.bvSliceBE (w4 sym) lw rw bv+ return (l, r)++ extractWord sym bits idx bv =+ liftIO $ SW.bvSliceLE (w4 sym) idx bits bv++ wordEq sym x y = liftIO (SW.bvEq (w4 sym) x y)+ wordLessThan sym x y = liftIO (SW.bvult (w4 sym) x y)+ wordGreaterThan sym x y = liftIO (SW.bvugt (w4 sym) x y)+ wordSignedLessThan sym x y = liftIO (SW.bvslt (w4 sym) x y)++ wordOr sym x y = liftIO (SW.bvOr (w4 sym) x y)+ wordAnd sym x y = liftIO (SW.bvAnd (w4 sym) x y)+ wordXor sym x y = liftIO (SW.bvXor (w4 sym) x y)+ wordComplement sym x = liftIO (SW.bvNot (w4 sym) x)++ wordPlus sym x y = liftIO (SW.bvAdd (w4 sym) x y)+ wordMinus sym x y = liftIO (SW.bvSub (w4 sym) x y)+ wordMult sym x y = liftIO (SW.bvMul (w4 sym) x y)+ wordNegate sym x = liftIO (SW.bvNeg (w4 sym) x)+ wordLg2 sym x = sLg2 (w4 sym) x+ + wordDiv sym x y =+ do assertBVDivisor sym y+ liftIO (SW.bvUDiv (w4 sym) x y)+ wordMod sym x y =+ do assertBVDivisor sym y+ liftIO (SW.bvURem (w4 sym) x y)+ wordSignedDiv sym x y =+ do assertBVDivisor sym y+ liftIO (SW.bvSDiv (w4 sym) x y)+ wordSignedMod sym x y =+ do assertBVDivisor sym y+ liftIO (SW.bvSRem (w4 sym) x y)++ wordToInt sym x = liftIO (SW.bvToInteger (w4 sym) x)+ wordFromInt sym width i = liftIO (SW.integerToBV (w4 sym) i width)++ intPlus sym x y = liftIO $ W4.intAdd (w4 sym) x y+ intMinus sym x y = liftIO $ W4.intSub (w4 sym) x y+ intMult sym x y = liftIO $ W4.intMul (w4 sym) x y+ intNegate sym x = liftIO $ W4.intNeg (w4 sym) x++ -- NB: What4's division operation provides SMTLib's euclidean division,+ -- which doesn't match the round-to-neg-infinity semantics of Cryptol,+ -- so we have to do some work to get the desired semantics.+ intDiv sym x y =+ do assertIntDivisor sym y+ liftIO $ do+ neg <- liftIO (W4.intLt (w4 sym) y =<< W4.intLit (w4 sym) 0)+ case W4.asConstantPred neg of+ Just False -> W4.intDiv (w4 sym) x y+ Just True ->+ do xneg <- W4.intNeg (w4 sym) x+ yneg <- W4.intNeg (w4 sym) y+ W4.intDiv (w4 sym) xneg yneg+ Nothing ->+ do xneg <- W4.intNeg (w4 sym) x+ yneg <- W4.intNeg (w4 sym) y+ zneg <- W4.intDiv (w4 sym) xneg yneg+ z <- W4.intDiv (w4 sym) x y+ W4.intIte (w4 sym) neg zneg z++ -- NB: What4's division operation provides SMTLib's euclidean division,+ -- which doesn't match the round-to-neg-infinity semantics of Cryptol,+ -- so we have to do some work to get the desired semantics.+ intMod sym x y =+ do assertIntDivisor sym y+ liftIO $ do+ neg <- liftIO (W4.intLt (w4 sym) y =<< W4.intLit (w4 sym) 0)+ case W4.asConstantPred neg of+ Just False -> W4.intMod (w4 sym) x y+ Just True ->+ do xneg <- W4.intNeg (w4 sym) x+ yneg <- W4.intNeg (w4 sym) y+ W4.intNeg (w4 sym) =<< W4.intMod (w4 sym) xneg yneg+ Nothing ->+ do xneg <- W4.intNeg (w4 sym) x+ yneg <- W4.intNeg (w4 sym) y+ z <- W4.intMod (w4 sym) x y+ zneg <- W4.intNeg (w4 sym) =<< W4.intMod (w4 sym) xneg yneg+ W4.intIte (w4 sym) neg zneg z++ intEq sym x y = liftIO $ W4.intEq (w4 sym) x y+ intLessThan sym x y = liftIO $ W4.intLt (w4 sym) x y+ intGreaterThan sym x y = liftIO $ W4.intLt (w4 sym) y x++ -- NB, we don't do reduction here on symbolic values+ intToZn sym m x+ | Just xi <- W4.asInteger x+ = liftIO $ W4.intLit (w4 sym) (xi `mod` m)++ | otherwise+ = pure x++ znToInt _ 0 _ = evalPanic "znToInt" ["0 modulus not allowed"]+ znToInt sym m x = liftIO (W4.intMod (w4 sym) x =<< W4.intLit (w4 sym) m)++ znEq _ 0 _ _ = evalPanic "znEq" ["0 modulus not allowed"]+ znEq sym m x y = liftIO $+ do diff <- W4.intSub (w4 sym) x y+ W4.intDivisible (w4 sym) diff (fromInteger m)++ znPlus sym m x y = liftIO $ sModAdd (w4 sym) m x y+ znMinus sym m x y = liftIO $ sModSub (w4 sym) m x y+ znMult sym m x y = liftIO $ sModMult (w4 sym) m x y+ znNegate sym m x = liftIO $ sModNegate (w4 sym) m x+ znRecip = sModRecip++ --------------------------------------------------------------++ fpLit sym e p r = liftIO $ FP.fpFromRationalLit (w4 sym) e p r++ fpExactLit sym BF{ bfExpWidth = e, bfPrecWidth = p, bfValue = bf } =+ liftIO (FP.fpFromBinary (w4 sym) e p =<< SW.bvLit (w4 sym) (e+p) (floatToBits e p bf))++ fpEq sym x y = liftIO $ FP.fpEqIEEE (w4 sym) x y+ fpLessThan sym x y = liftIO $ FP.fpLtIEEE (w4 sym) x y+ fpGreaterThan sym x y = liftIO $ FP.fpGtIEEE (w4 sym) x y+ fpLogicalEq sym x y = liftIO $ FP.fpEq (w4 sym) x y++ fpPlus = fpBinArith FP.fpAdd+ fpMinus = fpBinArith FP.fpSub+ fpMult = fpBinArith FP.fpMul+ fpDiv = fpBinArith FP.fpDiv++ fpNeg sym x = liftIO $ FP.fpNeg (w4 sym) x++ fpFromInteger sym e p r x =+ do rm <- fpRoundingMode sym r+ liftIO $ FP.fpFromInteger (w4 sym) e p rm x++ fpToInteger = fpCvtToInteger++sModAdd :: W4.IsSymExprBuilder sym =>+ sym -> Integer -> W4.SymInteger sym -> W4.SymInteger sym -> IO (W4.SymInteger sym)+sModAdd _sym 0 _ _ = evalPanic "sModAdd" ["0 modulus not allowed"]+sModAdd sym m x y+ | Just xi <- W4.asInteger x+ , Just yi <- W4.asInteger y+ = W4.intLit sym ((xi+yi) `mod` m)++ | otherwise+ = W4.intAdd sym x y++sModSub :: W4.IsSymExprBuilder sym =>+ sym -> Integer -> W4.SymInteger sym -> W4.SymInteger sym -> IO (W4.SymInteger sym)+sModSub _sym 0 _ _ = evalPanic "sModSub" ["0 modulus not allowed"]+sModSub sym m x y+ | Just xi <- W4.asInteger x+ , Just yi <- W4.asInteger y+ = W4.intLit sym ((xi-yi) `mod` m)++ | otherwise+ = W4.intSub sym x y+++sModMult :: W4.IsSymExprBuilder sym =>+ sym -> Integer -> W4.SymInteger sym -> W4.SymInteger sym -> IO (W4.SymInteger sym)+sModMult _sym 0 _ _ = evalPanic "sModMult" ["0 modulus not allowed"]+sModMult sym m x y+ | Just xi <- W4.asInteger x+ , Just yi <- W4.asInteger y+ = W4.intLit sym ((xi*yi) `mod` m)++ | otherwise+ = W4.intMul sym x y++sModNegate :: W4.IsSymExprBuilder sym =>+ sym -> Integer -> W4.SymInteger sym -> IO (W4.SymInteger sym)+sModNegate _sym 0 _ = evalPanic "sModMult" ["0 modulus not allowed"]+sModNegate sym m x+ | Just xi <- W4.asInteger x+ = W4.intLit sym ((negate xi) `mod` m)++ | otherwise+ = W4.intNeg sym x+++-- | Try successive powers of 2 to find the first that dominates the input.+-- We could perhaps reduce to using CLZ instead...+sLg2 :: W4.IsSymExprBuilder sym => sym -> SW.SWord sym -> SEval (What4 sym) (SW.SWord sym)+sLg2 sym x = liftIO $ go 0+ where+ w = SW.bvWidth x+ lit n = SW.bvLit sym w (toInteger n)++ go i | toInteger i < w =+ do p <- SW.bvule sym x =<< lit (bit i)+ lazyIte (SW.bvIte sym) p (lit i) (go (i+1))++ -- base case, should only happen when i = w+ go i = lit i++++-- Errors ----------------------------------------------------------------------++evalPanic :: String -> [String] -> a+evalPanic cxt = panic ("[What4] " ++ cxt)++lazyIte ::+ (W4.IsExpr p, Monad m) =>+ (p W4.BaseBoolType -> a -> a -> m a) ->+ p W4.BaseBoolType ->+ m a ->+ m a ->+ m a+lazyIte f c mx my+ | Just b <- W4.asConstantPred c = if b then mx else my+ | otherwise =+ do x <- mx+ y <- my+ f c x y++w4bvShl :: W4.IsSymExprBuilder sym => sym -> SW.SWord sym -> SW.SWord sym -> W4Eval sym (SW.SWord sym)+w4bvShl sym x y = liftIO $ SW.bvShl sym x y++w4bvLshr :: W4.IsSymExprBuilder sym => sym -> SW.SWord sym -> SW.SWord sym -> W4Eval sym (SW.SWord sym)+w4bvLshr sym x y = liftIO $ SW.bvLshr sym x y++w4bvAshr :: W4.IsSymExprBuilder sym => sym -> SW.SWord sym -> SW.SWord sym -> W4Eval sym (SW.SWord sym)+w4bvAshr sym x y = liftIO $ SW.bvAshr sym x y++w4bvRol :: W4.IsSymExprBuilder sym => sym -> SW.SWord sym -> SW.SWord sym -> W4Eval sym (SW.SWord sym)+w4bvRol sym x y = liftIO $ SW.bvRol sym x y++w4bvRor :: W4.IsSymExprBuilder sym => sym -> SW.SWord sym -> SW.SWord sym -> W4Eval sym (SW.SWord sym)+w4bvRor sym x y = liftIO $ SW.bvRor sym x y++++fpRoundingMode ::+ W4.IsSymExprBuilder sym =>+ What4 sym -> SWord (What4 sym) -> SEval (What4 sym) W4.RoundingMode+fpRoundingMode sym v =+ case wordAsLit sym v of+ Just (_w,i) ->+ case i of+ 0 -> pure W4.RNE+ 1 -> pure W4.RNA+ 2 -> pure W4.RTP+ 3 -> pure W4.RTN+ 4 -> pure W4.RTZ+ x -> raiseError sym (BadRoundingMode x)+ _ -> liftIO $ X.throwIO $ UnsupportedSymbolicOp "rounding mode"++fpBinArith ::+ W4.IsSymExprBuilder sym =>+ FP.SFloatBinArith sym ->+ What4 sym ->+ SWord (What4 sym) ->+ SFloat (What4 sym) ->+ SFloat (What4 sym) ->+ SEval (What4 sym) (SFloat (What4 sym))+fpBinArith fun = \sym r x y ->+ do m <- fpRoundingMode sym r+ liftIO (fun (w4 sym) m x y)+++fpCvtToInteger ::+ (W4.IsSymExprBuilder sy, sym ~ What4 sy) =>+ sym -> String -> SWord sym -> SFloat sym -> SEval sym (SInteger sym)+fpCvtToInteger sym fun r x =+ do grd <- liftIO+ do bad1 <- FP.fpIsInf (w4 sym) x+ bad2 <- FP.fpIsNaN (w4 sym) x+ W4.notPred (w4 sym) =<< W4.orPred (w4 sym) bad1 bad2+ assertSideCondition sym grd (BadValue fun)+ rnd <- fpRoundingMode sym r+ liftIO+ do y <- FP.fpToReal (w4 sym) x+ case rnd of+ W4.RNE -> W4.realRoundEven (w4 sym) y+ W4.RNA -> W4.realRound (w4 sym) y+ W4.RTP -> W4.realCeil (w4 sym) y+ W4.RTN -> W4.realFloor (w4 sym) y+ W4.RTZ -> W4.realTrunc (w4 sym) y+++fpCvtToRational ::+ (W4.IsSymExprBuilder sy, sym ~ What4 sy) =>+ sym -> SFloat sym -> SEval sym (SRational sym)+fpCvtToRational sym fp =+ do grd <- liftIO+ do bad1 <- FP.fpIsInf (w4 sym) fp+ bad2 <- FP.fpIsNaN (w4 sym) fp+ W4.notPred (w4 sym) =<< W4.orPred (w4 sym) bad1 bad2+ assertSideCondition sym grd (BadValue "fpToRational")+ (rel,x,y) <- liftIO (FP.fpToRational (w4 sym) fp)+ addDefEqn sym =<< liftIO (W4.impliesPred (w4 sym) grd rel)+ ratio sym x y++fpCvtFromRational ::+ (W4.IsSymExprBuilder sy, sym ~ What4 sy) =>+ sym -> Integer -> Integer -> SWord sym ->+ SRational sym -> SEval sym (SFloat sym)+fpCvtFromRational sym e p r rat =+ do rnd <- fpRoundingMode sym r+ liftIO (FP.fpFromRational (w4 sym) e p rnd (sNum rat) (sDenom rat))++-- Create a fresh constant and assert that it is the+-- multiplicitive inverse of x; return the constant.+-- Such an inverse must exist under the precondition+-- that the modulus is prime and the input is nonzero.+sModRecip ::+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Integer ->+ W4.SymInteger sym ->+ W4Eval sym (W4.SymInteger sym)+sModRecip _sym 0 _ = panic "sModRecip" ["0 modulus not allowed"]+sModRecip sym m x+ -- If the input is concrete, evaluate the answer+ | Just xi <- W4.asInteger x+ = let r = Integer.recipModInteger xi m+ in if r == 0 then raiseError sym DivideByZero else integerLit sym r++ -- If the input is symbolic, create a new symbolic constant+ -- and assert that it is the desired multiplicitive inverse.+ -- Such an inverse will exist under the precondition that+ -- the modulus is prime, and as long as the input is nonzero.+ | otherwise+ = do divZero <- liftIO (W4.intDivisible (w4 sym) x (fromInteger m))+ ok <- liftIO (W4.notPred (w4 sym) divZero)+ assertSideCondition sym ok DivideByZero++ z <- liftIO (W4.freshBoundedInt (w4 sym) W4.emptySymbol (Just 1) (Just (m-1)))+ xz <- liftIO (W4.intMul (w4 sym) x z)+ rel <- znEq sym m xz =<< liftIO (W4.intLit (w4 sym) 1)+ addDefEqn sym =<< liftIO (W4.orPred (w4 sym) divZero rel)++ return z
+ src/Cryptol/Backend/What4/SFloat.hs view
@@ -0,0 +1,362 @@+{-# Language DataKinds #-}+{-# Language FlexibleContexts #-}+{-# Language GADTs #-}+{-# Language RankNTypes #-}+{-# Language TypeApplications #-}+{-# Language TypeOperators #-}+-- | Working with floats of dynamic sizes.+-- This should probably be moved to What4 one day.+module Cryptol.Backend.What4.SFloat+ ( -- * Interface+ SFloat(..)+ , fpReprOf+ , fpSize+ , fpRepr++ -- * Constants+ , fpFresh+ , fpNaN+ , fpPosInf+ , fpFromRationalLit++ -- * Interchange formats+ , fpFromBinary+ , fpToBinary++ -- * Relations+ , SFloatRel+ , fpEq+ , fpEqIEEE+ , fpLtIEEE+ , fpGtIEEE++ -- * Arithmetic+ , SFloatBinArith+ , fpNeg+ , fpAdd+ , fpSub+ , fpMul+ , fpDiv++ -- * Conversions+ , fpRound+ , fpToReal+ , fpFromReal+ , fpFromRational+ , fpToRational+ , fpFromInteger++ -- * Queries+ , fpIsInf, fpIsNaN++ -- * Exceptions+ , UnsupportedFloat(..)+ , FPTypeError(..)+ ) where++import Control.Exception++import Data.Parameterized.Some+import Data.Parameterized.NatRepr++import What4.BaseTypes+import What4.Panic(panic)+import What4.SWord+import What4.Interface++-- | Symbolic floating point numbers.+data SFloat sym where+ SFloat :: IsExpr (SymExpr sym) => SymFloat sym fpp -> SFloat sym++++--------------------------------------------------------------------------------++-- | This exception is thrown if the operations try to create a+-- floating point value we do not support+data UnsupportedFloat =+ UnsupportedFloat { fpWho :: String, exponentBits, precisionBits :: Integer }+ deriving Show+++-- | Throw 'UnsupportedFloat' exception+unsupported ::+ String {- ^ Label -} ->+ Integer {- ^ Exponent width -} ->+ Integer {- ^ Precision width -} ->+ IO a+unsupported l e p =+ throwIO UnsupportedFloat { fpWho = l+ , exponentBits = e+ , precisionBits = p }++instance Exception UnsupportedFloat++-- | This exceptoin is throws if the types don't match.+data FPTypeError =+ FPTypeError { fpExpected :: Some BaseTypeRepr+ , fpActual :: Some BaseTypeRepr+ }+ deriving Show++instance Exception FPTypeError++fpTypeMismatch :: BaseTypeRepr t1 -> BaseTypeRepr t2 -> IO a+fpTypeMismatch expect actual =+ throwIO FPTypeError { fpExpected = Some expect+ , fpActual = Some actual+ }+fpTypeError :: FloatPrecisionRepr t1 -> FloatPrecisionRepr t2 -> IO a+fpTypeError t1 t2 =+ fpTypeMismatch (BaseFloatRepr t1) (BaseFloatRepr t2)+++--------------------------------------------------------------------------------+-- | Construct the 'FloatPrecisionRepr' with the given parameters.+fpRepr ::+ Integer {- ^ Exponent width -} ->+ Integer {- ^ Precision width -} ->+ Maybe (Some FloatPrecisionRepr)+fpRepr iE iP =+ do Some e <- someNat iE+ LeqProof <- testLeq (knownNat @2) e+ Some p <- someNat iP+ LeqProof <- testLeq (knownNat @2) p+ pure (Some (FloatingPointPrecisionRepr e p))++fpReprOf ::+ IsExpr (SymExpr sym) => sym -> SymFloat sym fpp -> FloatPrecisionRepr fpp+fpReprOf _ e =+ case exprType e of+ BaseFloatRepr r -> r++fpSize :: SFloat sym -> (Integer,Integer)+fpSize (SFloat f) =+ case exprType f of+ BaseFloatRepr (FloatingPointPrecisionRepr e p) -> (intValue e, intValue p)+++--------------------------------------------------------------------------------+-- Constants++-- | A fresh variable of the given type.+fpFresh ::+ IsSymExprBuilder sym =>+ sym ->+ Integer ->+ Integer ->+ IO (SFloat sym)+fpFresh sym e p+ | Just (Some fpp) <- fpRepr e p =+ SFloat <$> freshConstant sym emptySymbol (BaseFloatRepr fpp)+ | otherwise = unsupported "fpFresh" e p++-- | Not a number+fpNaN ::+ IsExprBuilder sym =>+ sym ->+ Integer {- ^ Exponent width -} ->+ Integer {- ^ Precision width -} ->+ IO (SFloat sym)+fpNaN sym e p+ | Just (Some fpp) <- fpRepr e p = SFloat <$> floatNaN sym fpp+ | otherwise = unsupported "fpNaN" e p+++-- | Positive infinity+fpPosInf ::+ IsExprBuilder sym =>+ sym ->+ Integer {- ^ Exponent width -} ->+ Integer {- ^ Precision width -} ->+ IO (SFloat sym)+fpPosInf sym e p+ | Just (Some fpp) <- fpRepr e p = SFloat <$> floatPInf sym fpp+ | otherwise = unsupported "fpPosInf" e p++-- | A floating point number corresponding to the given rations.+fpFromRationalLit ::+ IsExprBuilder sym =>+ sym ->+ Integer {- ^ Exponent width -} ->+ Integer {- ^ Precision width -} ->+ Rational ->+ IO (SFloat sym)+fpFromRationalLit sym e p r+ | Just (Some fpp) <- fpRepr e p = SFloat <$> floatLit sym fpp r+ | otherwise = unsupported "fpFromRational" e p+++-- | Make a floating point number with the given bit representation.+fpFromBinary ::+ IsExprBuilder sym =>+ sym ->+ Integer {- ^ Exponent width -} ->+ Integer {- ^ Precision width -} ->+ SWord sym ->+ IO (SFloat sym)+fpFromBinary sym e p swe+ | DBV sw <- swe+ , Just (Some fpp) <- fpRepr e p+ , FloatingPointPrecisionRepr ew pw <- fpp+ , let expectW = addNat ew pw+ , actual@(BaseBVRepr actualW) <- exprType sw =+ case testEquality expectW actualW of+ Just Refl -> SFloat <$> floatFromBinary sym fpp sw+ Nothing -- we want to report type correct type errors! :-)+ | Just LeqProof <- testLeq (knownNat @1) expectW ->+ fpTypeMismatch (BaseBVRepr expectW) actual+ | otherwise -> panic "fpFromBits" [ "1 >= 2" ]+ | otherwise = unsupported "fpFromBits" e p++fpToBinary :: IsExprBuilder sym => sym -> SFloat sym -> IO (SWord sym)+fpToBinary sym (SFloat f)+ | FloatingPointPrecisionRepr e p <- fpReprOf sym f+ , Just LeqProof <- testLeq (knownNat @1) (addNat e p)+ = DBV <$> floatToBinary sym f+ | otherwise = panic "fpToBinary" [ "we messed up the types" ]+++--------------------------------------------------------------------------------+-- Arithmetic++fpNeg :: IsExprBuilder sym => sym -> SFloat sym -> IO (SFloat sym)+fpNeg sym (SFloat fl) = SFloat <$> floatNeg sym fl++fpBinArith ::+ IsExprBuilder sym =>+ (forall t.+ sym ->+ RoundingMode ->+ SymFloat sym t ->+ SymFloat sym t ->+ IO (SymFloat sym t)+ ) ->+ sym -> RoundingMode -> SFloat sym -> SFloat sym -> IO (SFloat sym)+fpBinArith fun sym r (SFloat x) (SFloat y) =+ let t1 = sym `fpReprOf` x+ t2 = sym `fpReprOf` y+ in+ case testEquality t1 t2 of+ Just Refl -> SFloat <$> fun sym r x y+ _ -> fpTypeError t1 t2++type SFloatBinArith sym =+ sym -> RoundingMode -> SFloat sym -> SFloat sym -> IO (SFloat sym)++fpAdd :: IsExprBuilder sym => SFloatBinArith sym+fpAdd = fpBinArith floatAdd++fpSub :: IsExprBuilder sym => SFloatBinArith sym+fpSub = fpBinArith floatSub++fpMul :: IsExprBuilder sym => SFloatBinArith sym+fpMul = fpBinArith floatMul++fpDiv :: IsExprBuilder sym => SFloatBinArith sym+fpDiv = fpBinArith floatDiv+++++--------------------------------------------------------------------------------++fpRel ::+ IsExprBuilder sym =>+ (forall t.+ sym ->+ SymFloat sym t ->+ SymFloat sym t ->+ IO (Pred sym)+ ) ->+ sym -> SFloat sym -> SFloat sym -> IO (Pred sym)+fpRel fun sym (SFloat x) (SFloat y) =+ let t1 = sym `fpReprOf` x+ t2 = sym `fpReprOf` y+ in+ case testEquality t1 t2 of+ Just Refl -> fun sym x y+ _ -> fpTypeError t1 t2+++++type SFloatRel sym =+ sym -> SFloat sym -> SFloat sym -> IO (Pred sym)++fpEq :: IsExprBuilder sym => SFloatRel sym+fpEq = fpRel floatEq++fpEqIEEE :: IsExprBuilder sym => SFloatRel sym+fpEqIEEE = fpRel floatFpEq++fpLtIEEE :: IsExprBuilder sym => SFloatRel sym+fpLtIEEE = fpRel floatLt++fpGtIEEE :: IsExprBuilder sym => SFloatRel sym+fpGtIEEE = fpRel floatGt+++--------------------------------------------------------------------------------+fpRound ::+ IsExprBuilder sym => sym -> RoundingMode -> SFloat sym -> IO (SFloat sym)+fpRound sym r (SFloat x) = SFloat <$> floatRound sym r x++-- | This is undefined on "special" values (NaN,infinity)+fpToReal :: IsExprBuilder sym => sym -> SFloat sym -> IO (SymReal sym)+fpToReal sym (SFloat x) = floatToReal sym x++fpFromReal ::+ IsExprBuilder sym =>+ sym -> Integer -> Integer -> RoundingMode -> SymReal sym -> IO (SFloat sym)+fpFromReal sym e p r x+ | Just (Some repr) <- fpRepr e p = SFloat <$> realToFloat sym repr r x+ | otherwise = unsupported "fpFromReal" e p+++fpFromInteger ::+ IsExprBuilder sym =>+ sym -> Integer -> Integer -> RoundingMode -> SymInteger sym -> IO (SFloat sym)+fpFromInteger sym e p r x = fpFromReal sym e p r =<< integerToReal sym x+++fpFromRational ::+ IsExprBuilder sym =>+ sym -> Integer -> Integer -> RoundingMode ->+ SymInteger sym -> SymInteger sym -> IO (SFloat sym)+fpFromRational sym e p r x y =+ do num <- integerToReal sym x+ den <- integerToReal sym y+ res <- realDiv sym num den+ fpFromReal sym e p r res++{- | Returns a predicate and two integers, @x@ and @y@.+If the the predicate holds, then @x / y@ is a rational representing+the floating point number. Assumes the FP number is not one of the+special ones that has no real representation. -}+fpToRational ::+ IsSymExprBuilder sym =>+ sym ->+ SFloat sym ->+ IO (Pred sym, SymInteger sym, SymInteger sym)+fpToRational sym fp =+ do r <- fpToReal sym fp+ x <- freshConstant sym emptySymbol BaseIntegerRepr+ y <- freshConstant sym emptySymbol BaseIntegerRepr+ num <- integerToReal sym x+ den <- integerToReal sym y+ res <- realDiv sym num den+ same <- realEq sym r res+ pure (same, x, y)++++--------------------------------------------------------------------------------+fpIsInf :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)+fpIsInf sym (SFloat x) = floatIsInf sym x++fpIsNaN :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)+fpIsNaN sym (SFloat x) = floatIsNaN sym x+++
src/Cryptol/Eval.hs view
@@ -13,7 +13,6 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ParallelListComp #-} {-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE Safe #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE ViewPatterns #-} @@ -35,11 +34,11 @@ , forceValue ) where -import Cryptol.Eval.Backend-import Cryptol.Eval.Concrete( Concrete(..) )+import Cryptol.Backend+import Cryptol.Backend.Concrete( Concrete(..) )+import Cryptol.Backend.Monad import Cryptol.Eval.Generic ( iteValue ) import Cryptol.Eval.Env-import Cryptol.Eval.Monad import Cryptol.Eval.Type import Cryptol.Eval.Value import Cryptol.ModuleSystem.Name@@ -54,6 +53,7 @@ import Control.Monad import Data.List import Data.Maybe+import qualified Data.IntMap.Strict as IntMap import qualified Data.Map.Strict as Map import Data.Semigroup @@ -63,10 +63,9 @@ type EvalEnv = GenEvalEnv Concrete type EvalPrims sym =- ( Backend sym, ?evalPrim :: PrimIdent -> Maybe (GenValue sym) )+ ( Backend sym, ?evalPrim :: PrimIdent -> Maybe (Either Expr (GenValue sym)) ) -type ConcPrims =- ?evalPrim :: PrimIdent -> Maybe (GenValue Concrete)+type ConcPrims = ?evalPrim :: PrimIdent -> Maybe (Either Expr (GenValue Concrete)) -- Expression Evaluation ------------------------------------------------------- @@ -138,9 +137,10 @@ e' <- eval e evalSel sym e' sel - ESet e sel v -> {-# SCC "evalExpr->ESet" #-}+ ESet ty e sel v -> {-# SCC "evalExpr->ESet" #-} do e' <- eval e- evalSetSel sym e' sel (eval v)+ let tyv = evalValType (envTypes env) ty+ evalSetSel sym tyv e' sel (eval v) EIf c t f -> {-# SCC "evalExpr->EIf" #-} do b <- fromVBit <$> eval c@@ -157,7 +157,7 @@ Nothing -> do envdoc <- ppEnv sym defaultPPOpts env panic "[Eval] evalExpr"- ["var `" ++ show (pp n) ++ "` is not defined"+ ["var `" ++ show (pp n) ++ "` (" ++ show (nameUnique n) ++ ") is not defined" , show envdoc ] @@ -274,7 +274,7 @@ -- declare a "hole" for each declaration -- and extend the evaluation environment holes <- mapM (declHole sym) ds- let holeEnv = Map.fromList $ [ (nm,h) | (nm,_,h,_) <- holes ]+ let holeEnv = IntMap.fromList $ [ (nameUnique nm, h) | (nm,_,h,_) <- holes ] let env' = env `mappend` emptyEnv{ envVars = holeEnv } -- evaluate the declaration bodies, building a new evaluation environment@@ -326,7 +326,7 @@ -- | 'Value' types are non-polymorphic types recursive constructed from -- bits, finite sequences, tuples and records. Types of this form can--- be implemented rather more efficently than general types because we can+-- be implemented rather more efficiently than general types because we can -- rely on the 'delayFill' operation to build a thunk that falls back on performing -- eta-expansion rather than doing it eagerly. isValueType :: GenEvalEnv sym -> Schema -> Bool@@ -525,8 +525,9 @@ case dDefinition d of DPrim -> case ?evalPrim =<< asPrim (dName d) of- Just v -> pure (bindVarDirect (dName d) v env)- Nothing -> bindVar sym (dName d) (cryNoPrimError sym (dName d)) env+ Just (Right v) -> pure (bindVarDirect (dName d) v env)+ Just (Left ex) -> bindVar sym (dName d) (evalExpr sym renv ex) env+ Nothing -> bindVar sym (dName d) (cryNoPrimError sym (dName d)) env DExpr e -> bindVar sym (dName d) (evalExpr sym renv e) env @@ -584,14 +585,15 @@ , show vdoc ] {-# SPECIALIZE evalSetSel :: ConcPrims =>- Concrete ->+ Concrete -> TValue -> GenValue Concrete -> Selector -> SEval Concrete (GenValue Concrete) -> SEval Concrete (GenValue Concrete) #-} evalSetSel :: forall sym. EvalPrims sym => sym ->+ TValue -> GenValue sym -> Selector -> SEval sym (GenValue sym) -> SEval sym (GenValue sym)-evalSetSel sym e sel v =+evalSetSel sym _tyv e sel v = case sel of TupleSel n _ -> setTuple n RecordSel n _ -> setRecord n@@ -641,25 +643,25 @@ -- name is bound to a list of values, one for each element in the list -- comprehension. data ListEnv sym = ListEnv- { leVars :: !(Map.Map Name (Integer -> SEval sym (GenValue sym)))+ { leVars :: !(IntMap.IntMap (Integer -> SEval sym (GenValue sym))) -- ^ Bindings whose values vary by position- , leStatic :: !(Map.Map Name (SEval sym (GenValue sym)))+ , leStatic :: !(IntMap.IntMap (SEval sym (GenValue sym))) -- ^ Bindings whose values are constant , leTypes :: !TypeEnv } instance Semigroup (ListEnv sym) where l <> r = ListEnv- { leVars = Map.union (leVars l) (leVars r)- , leStatic = Map.union (leStatic l) (leStatic r)- , leTypes = Map.union (leTypes l) (leTypes r)+ { leVars = IntMap.union (leVars l) (leVars r)+ , leStatic = IntMap.union (leStatic l) (leStatic r)+ , leTypes = IntMap.union (leTypes l) (leTypes r) } instance Monoid (ListEnv sym) where mempty = ListEnv- { leVars = Map.empty- , leStatic = Map.empty- , leTypes = Map.empty+ { leVars = IntMap.empty+ , leStatic = IntMap.empty+ , leTypes = IntMap.empty } mappend l r = l <> r@@ -679,7 +681,7 @@ evalListEnv :: ListEnv sym -> Integer -> GenEvalEnv sym evalListEnv (ListEnv vm st tm) i = let v = fmap ($i) vm- in EvalEnv{ envVars = Map.union v st+ in EvalEnv{ envVars = IntMap.union v st , envTypes = tm } {-# INLINE evalListEnv #-}@@ -690,7 +692,7 @@ (Integer -> SEval sym (GenValue sym)) -> ListEnv sym -> ListEnv sym-bindVarList n vs lenv = lenv { leVars = Map.insert n vs (leVars lenv) }+bindVarList n vs lenv = lenv { leVars = IntMap.insert (nameUnique n) vs (leVars lenv) } {-# INLINE bindVarList #-} -- List Comprehensions ---------------------------------------------------------@@ -776,8 +778,8 @@ -- `leVars` elements of the comprehension environment into `leStatic` elements -- by selecting out the 0th element. Inf -> do- let allvars = Map.union (fmap ($0) (leVars lenv)) (leStatic lenv)- let lenv' = lenv { leVars = Map.empty+ let allvars = IntMap.union (fmap ($0) (leVars lenv)) (leStatic lenv)+ let lenv' = lenv { leVars = IntMap.empty , leStatic = allvars } let env = EvalEnv allvars (leTypes lenv)
− src/Cryptol/Eval/Arch.hs
@@ -1,30 +0,0 @@--- |--- Module : Cryptol.Eval.Arch--- Copyright : (c) 2014-2016 Galois, Inc.--- License : BSD3--- Maintainer : cryptol@galois.com--- Stability : provisional--- Portability : portable------ Architecture-specific parts of the concrete evaluator go here.-{-# LANGUAGE CPP #-}-module Cryptol.Eval.Arch where---- | This is the widest word we can have before gmp will fail to--- allocate and bring down the whole program. According to--- <https://gmplib.org/list-archives/gmp-bugs/2009-July/001538.html>--- the sizes are 2^32-1 for 32-bit, and 2^37 for 64-bit, however--- experiments show that it's somewhere under 2^37 at least on 64-bit--- Mac OS X.-maxBigIntWidth :: Integer-#if i386_HOST_ARCH-maxBigIntWidth = 2^(32 :: Integer) - 0x1-#elif x86_64_HOST_ARCH-maxBigIntWidth = 2^(37 :: Integer) - 0x100-#else--- Because GHC doesn't seem to define a CPP macro that will portably--- tell us the bit width we're compiling for, fall back on a safe choice--- for other architectures. If we care about large words on another--- architecture, we can add a special case for it.-maxBigIntWidth = 2^(32 :: Integer) - 0x1-#endif
− src/Cryptol/Eval/Backend.hs
@@ -1,705 +0,0 @@-{-# Language FlexibleContexts #-}-{-# Language TypeFamilies #-}-module Cryptol.Eval.Backend- ( Backend(..)- , sDelay- , invalidIndex- , cryUserError- , cryNoPrimError- , FPArith2-- -- * Rationals- , SRational(..)- , intToRational- , ratio- , rationalAdd- , rationalSub- , rationalNegate- , rationalMul- , rationalRecip- , rationalDivide- , rationalFloor- , rationalCeiling- , rationalTrunc- , rationalRoundAway- , rationalRoundToEven- , rationalEq- , rationalLessThan- , rationalGreaterThan- , iteRational- , ppRational- ) where--import Control.Monad.IO.Class-import Data.Kind (Type)-import Data.Ratio ( (%), numerator, denominator )--import Cryptol.Eval.Monad-import Cryptol.TypeCheck.AST(Name)-import Cryptol.Utils.PP---invalidIndex :: Backend sym => sym -> Integer -> SEval sym a-invalidIndex sym = raiseError sym . InvalidIndex . Just--cryUserError :: Backend sym => sym -> String -> SEval sym a-cryUserError sym = raiseError sym . UserError--cryNoPrimError :: Backend sym => sym -> Name -> SEval sym a-cryNoPrimError sym = raiseError sym . NoPrim---{-# INLINE sDelay #-}--- | Delay the given evaluation computation, returning a thunk--- which will run the computation when forced. Raise a loop--- error if the resulting thunk is forced during its own evaluation.-sDelay :: Backend sym => sym -> Maybe String -> SEval sym a -> SEval sym (SEval sym a)-sDelay sym msg m =- let msg' = maybe "" ("while evaluating "++) msg- retry = raiseError sym (LoopError msg')- in sDelayFill sym m retry----- | Representation of rational numbers.--- Invariant: denominator is not 0-data SRational sym =- SRational- { sNum :: SInteger sym- , sDenom :: SInteger sym- }--intToRational :: Backend sym => sym -> SInteger sym -> SEval sym (SRational sym)-intToRational sym x = SRational x <$> (integerLit sym 1)--ratio :: Backend sym => sym -> SInteger sym -> SInteger sym -> SEval sym (SRational sym)-ratio sym n d =- do pz <- bitComplement sym =<< intEq sym d =<< integerLit sym 0- assertSideCondition sym pz DivideByZero- pure (SRational n d)--rationalRecip :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)-rationalRecip sym (SRational a b) = ratio sym b a--rationalDivide :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)-rationalDivide sym x y = rationalMul sym x =<< rationalRecip sym y--rationalFloor :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)- -- NB, relies on integer division being round-to-negative-inf division-rationalFloor sym (SRational n d) = intDiv sym n d--rationalCeiling :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)-rationalCeiling sym r = intNegate sym =<< rationalFloor sym =<< rationalNegate sym r--rationalTrunc :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)-rationalTrunc sym r =- do p <- rationalLessThan sym r =<< intToRational sym =<< integerLit sym 0- cr <- rationalCeiling sym r- fr <- rationalFloor sym r- iteInteger sym p cr fr--rationalRoundAway :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)-rationalRoundAway sym r =- do p <- rationalLessThan sym r =<< intToRational sym =<< integerLit sym 0- half <- SRational <$> integerLit sym 1 <*> integerLit sym 2- cr <- rationalCeiling sym =<< rationalSub sym r half- fr <- rationalFloor sym =<< rationalAdd sym r half- iteInteger sym p cr fr--rationalRoundToEven :: Backend sym => sym -> SRational sym -> SEval sym (SInteger sym)-rationalRoundToEven sym r =- do lo <- rationalFloor sym r- hi <- intPlus sym lo =<< integerLit sym 1- -- NB: `diff` will be nonnegative because `lo <= r`- diff <- rationalSub sym r =<< intToRational sym lo- half <- SRational <$> integerLit sym 1 <*> integerLit sym 2-- ite (rationalLessThan sym diff half) (pure lo) $- ite (rationalGreaterThan sym diff half) (pure hi) $- ite (isEven lo) (pure lo) (pure hi)-- where- isEven x =- do parity <- intMod sym x =<< integerLit sym 2- intEq sym parity =<< integerLit sym 0-- ite x t e =- do x' <- x- case bitAsLit sym x' of- Just True -> t- Just False -> e- Nothing ->- do t' <- t- e' <- e- iteInteger sym x' t' e'---rationalAdd :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)-rationalAdd sym (SRational a b) (SRational c d) =- do ad <- intMult sym a d- bc <- intMult sym b c- bd <- intMult sym b d- ad_bc <- intPlus sym ad bc- pure (SRational ad_bc bd)--rationalSub :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)-rationalSub sym (SRational a b) (SRational c d) =- do ad <- intMult sym a d- bc <- intMult sym b c- bd <- intMult sym b d- ad_bc <- intMinus sym ad bc- pure (SRational ad_bc bd)--rationalNegate :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)-rationalNegate sym (SRational a b) =- do aneg <- intNegate sym a- pure (SRational aneg b)--rationalMul :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)-rationalMul sym (SRational a b) (SRational c d) =- do ac <- intMult sym a c- bd <- intMult sym b d- pure (SRational ac bd)--rationalEq :: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)-rationalEq sym (SRational a b) (SRational c d) =- do ad <- intMult sym a d- bc <- intMult sym b c- intEq sym ad bc--normalizeSign :: Backend sym => sym -> SRational sym -> SEval sym (SRational sym)-normalizeSign sym (SRational a b) =- do p <- intLessThan sym b =<< integerLit sym 0- case bitAsLit sym p of- Just False -> pure (SRational a b)- Just True ->- do aneg <- intNegate sym a- bneg <- intNegate sym b- pure (SRational aneg bneg)- Nothing ->- do aneg <- intNegate sym a- bneg <- intNegate sym b- a' <- iteInteger sym p aneg a- b' <- iteInteger sym p bneg b- pure (SRational a' b')--rationalLessThan:: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)-rationalLessThan sym x y =- do SRational a b <- normalizeSign sym x- SRational c d <- normalizeSign sym y- ad <- intMult sym a d- bc <- intMult sym b c- intLessThan sym ad bc--rationalGreaterThan:: Backend sym => sym -> SRational sym -> SRational sym -> SEval sym (SBit sym)-rationalGreaterThan sym = flip (rationalLessThan sym)--iteRational :: Backend sym => sym -> SBit sym -> SRational sym -> SRational sym -> SEval sym (SRational sym)-iteRational sym p (SRational a b) (SRational c d) =- SRational <$> iteInteger sym p a c <*> iteInteger sym p b d--ppRational :: Backend sym => sym -> PPOpts -> SRational sym -> Doc-ppRational sym opts (SRational n d)- | Just ni <- integerAsLit sym n- , Just di <- integerAsLit sym d- = let q = ni % di in- text "(ratio" <+> integer (numerator q) <+> (integer (denominator q) <> text ")")-- | otherwise- = text "(ratio" <+> ppInteger sym opts n <+> (ppInteger sym opts d <> text ")")---- | This type class defines a collection of operations on bits, words and integers that--- are necessary to define generic evaluator primitives that operate on both concrete--- and symbolic values uniformly.-class MonadIO (SEval sym) => Backend sym where- type SBit sym :: Type- type SWord sym :: Type- type SInteger sym :: Type- type SFloat sym :: Type- type SEval sym :: Type -> Type-- -- ==== Evaluation monad operations ====-- -- | Check if an operation is "ready", which means its- -- evaluation will be trivial.- isReady :: sym -> SEval sym a -> Bool-- -- | Produce a thunk value which can be filled with its associated computation- -- after the fact. A preallocated thunk is returned, along with an operation to- -- fill the thunk with the associated computation.- -- This is used to implement recursive declaration groups.- sDeclareHole :: sym -> String -> SEval sym (SEval sym a, SEval sym a -> SEval sym ())-- -- | Delay the given evaluation computation, returning a thunk- -- which will run the computation when forced. Run the 'retry'- -- computation instead if the resulting thunk is forced during- -- its own evaluation.- sDelayFill :: sym -> SEval sym a -> SEval sym a -> SEval sym (SEval sym a)-- -- | Begin evaluating the given computation eagerly in a separate thread- -- and return a thunk which will await the completion of the given computation- -- when forced.- sSpark :: sym -> SEval sym a -> SEval sym (SEval sym a)-- -- | Merge the two given computations according to the predicate.- mergeEval ::- sym ->- (SBit sym -> a -> a -> SEval sym a) {- ^ A merge operation on values -} ->- SBit sym {- ^ The condition -} ->- SEval sym a {- ^ The "then" computation -} ->- SEval sym a {- ^ The "else" computation -} ->- SEval sym a-- -- | Assert that a condition must hold, and indicate what sort of- -- error is indicated if the condition fails.- assertSideCondition :: sym -> SBit sym -> EvalError -> SEval sym ()-- -- | Indiciate that an error condition exists- raiseError :: sym -> EvalError -> SEval sym a--- -- ==== Pretty printing ====- -- | Pretty-print an individual bit- ppBit :: sym -> SBit sym -> Doc-- -- | Pretty-print a word value- ppWord :: sym -> PPOpts -> SWord sym -> Doc-- -- | Pretty-print an integer value- ppInteger :: sym -> PPOpts -> SInteger sym -> Doc-- -- | Pretty-print a floating-point value- ppFloat :: sym -> PPOpts -> SFloat sym -> Doc--- -- ==== Identifying literal values ====-- -- | Determine if this symbolic bit is a boolean literal- bitAsLit :: sym -> SBit sym -> Maybe Bool-- -- | The number of bits in a word value.- wordLen :: sym -> SWord sym -> Integer-- -- | Determine if this symbolic word is a literal.- -- If so, return the bit width and value.- wordAsLit :: sym -> SWord sym -> Maybe (Integer, Integer)-- -- | Attempt to render a word value as an ASCII character. Return 'Nothing'- -- if the character value is unknown (e.g., for symbolic values).- wordAsChar :: sym -> SWord sym -> Maybe Char-- -- | Determine if this symbolic integer is a literal- integerAsLit :: sym -> SInteger sym -> Maybe Integer-- -- ==== Creating literal values ====-- -- | Construct a literal bit value from a boolean.- bitLit :: sym -> Bool -> SBit sym-- -- | Construct a literal word value given a bit width and a value.- wordLit ::- sym ->- Integer {- ^ Width -} ->- Integer {- ^ Value -} ->- SEval sym (SWord sym)-- -- | Construct a literal integer value from the given integer.- integerLit ::- sym ->- Integer {- ^ Value -} ->- SEval sym (SInteger sym)-- -- | Construct a floating point value from the given rational.- fpLit ::- sym ->- Integer {- ^ exponent bits -} ->- Integer {- ^ precision bits -} ->- Rational {- ^ The rational -} ->- SEval sym (SFloat sym)-- -- ==== If/then/else operations ====- iteBit :: sym -> SBit sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)- iteWord :: sym -> SBit sym -> SWord sym -> SWord sym -> SEval sym (SWord sym)- iteInteger :: sym -> SBit sym -> SInteger sym -> SInteger sym -> SEval sym (SInteger sym)--- -- ==== Bit operations ====- bitEq :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)- bitOr :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)- bitAnd :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)- bitXor :: sym -> SBit sym -> SBit sym -> SEval sym (SBit sym)- bitComplement :: sym -> SBit sym -> SEval sym (SBit sym)--- -- ==== Word operations ====-- -- | Extract the numbered bit from the word.- --- -- NOTE: this assumes that the sequence of bits is big-endian and finite, so the- -- bit numbered 0 is the most significant bit.- wordBit ::- sym ->- SWord sym ->- Integer {- ^ Bit position to extract -} ->- SEval sym (SBit sym)-- -- | Update the numbered bit in the word.- --- -- NOTE: this assumes that the sequence of bits is big-endian and finite, so the- -- bit numbered 0 is the most significant bit.- wordUpdate ::- sym ->- SWord sym ->- Integer {- ^ Bit position to update -} ->- SBit sym ->- SEval sym (SWord sym)-- -- | Construct a word value from a finite sequence of bits.- -- NOTE: this assumes that the sequence of bits is big-endian and finite, so the- -- first element of the list will be the most significant bit.- packWord ::- sym ->- [SBit sym] ->- SEval sym (SWord sym)-- -- | Deconstruct a packed word value in to a finite sequence of bits.- -- NOTE: this produces a list of bits that represent a big-endian word, so- -- the most significant bit is the first element of the list.- unpackWord ::- sym ->- SWord sym ->- SEval sym [SBit sym]-- -- | Construct a packed word of the specified width from an integer value.- wordFromInt ::- sym ->- Integer {- ^ bit-width -} ->- SInteger sym ->- SEval sym (SWord sym)-- -- | Concatenate the two given word values.- -- NOTE: the first argument represents the more-significant bits- joinWord ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | Take the most-significant bits, and return- -- those bits and the remainder. The first element- -- of the pair is the most significant bits.- -- The two integer sizes must sum to the length of the given word value.- splitWord ::- sym ->- Integer {- ^ left width -} ->- Integer {- ^ right width -} ->- SWord sym ->- SEval sym (SWord sym, SWord sym)-- -- | Extract a subsequence of bits from a packed word value.- -- The first integer argument is the number of bits in the- -- resulting word. The second integer argument is the- -- number of less-significant digits to discard. Stated another- -- way, the operation @extractWord n i w@ is equivalent to- -- first shifting @w@ right by @i@ bits, and then truncating to- -- @n@ bits.- extractWord ::- sym ->- Integer {- ^ Number of bits to take -} ->- Integer {- ^ starting bit -} ->- SWord sym ->- SEval sym (SWord sym)-- -- | Bitwise OR- wordOr ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | Bitwise AND- wordAnd ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | Bitwise XOR- wordXor ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | Bitwise complement- wordComplement ::- sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | 2's complement addition of packed words. The arguments must have- -- equal bit width, and the result is of the same width. Overflow is silently- -- discarded.- wordPlus ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | 2's complement subtraction of packed words. The arguments must have- -- equal bit width, and the result is of the same width. Overflow is silently- -- discarded.- wordMinus ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | 2's complement multiplication of packed words. The arguments must have- -- equal bit width, and the result is of the same width. The high bits of the- -- multiplication are silently discarded.- wordMult ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | 2's complement unsigned division of packed words. The arguments must have- -- equal bit width, and the result is of the same width. It is illegal to- -- call with a second argument concretely equal to 0.- wordDiv ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | 2's complement unsigned modulus of packed words. The arguments must have- -- equal bit width, and the result is of the same width. It is illegal to- -- call with a second argument concretely equal to 0.- wordMod ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | 2's complement signed division of packed words. The arguments must have- -- equal bit width, and the result is of the same width. It is illegal to- -- call with a second argument concretely equal to 0.- wordSignedDiv ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | 2's complement signed modulus of packed words. The arguments must have- -- equal bit width, and the result is of the same width. It is illegal to- -- call with a second argument concretely equal to 0.- wordSignedMod ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | 2's complement negation of bitvectors- wordNegate ::- sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | Compute rounded-up log-2 of the input- wordLg2 ::- sym ->- SWord sym ->- SEval sym (SWord sym)-- -- | Test if two words are equal. Arguments must have the same width.- wordEq ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SBit sym)-- -- | Signed less-than comparison on words. Arguments must have the same width.- wordSignedLessThan ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SBit sym)-- -- | Unsigned less-than comparison on words. Arguments must have the same width.- wordLessThan ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SBit sym)-- -- | Unsigned greater-than comparison on words. Arguments must have the same width.- wordGreaterThan ::- sym ->- SWord sym ->- SWord sym ->- SEval sym (SBit sym)-- -- | Construct an integer value from the given packed word.- wordToInt ::- sym ->- SWord sym ->- SEval sym (SInteger sym)-- -- ==== Integer operations ====-- -- | Addition of unbounded integers.- intPlus ::- sym ->- SInteger sym ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Negation of unbounded integers- intNegate ::- sym ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Subtraction of unbounded integers.- intMinus ::- sym ->- SInteger sym ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Multiplication of unbounded integers.- intMult ::- sym ->- SInteger sym ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Integer division, rounding down. It is illegal to- -- call with a second argument concretely equal to 0.- -- Same semantics as Haskell's @div@ operation.- intDiv ::- sym ->- SInteger sym ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Integer modulus, with division rounding down. It is illegal to- -- call with a second argument concretely equal to 0.- -- Same semantics as Haskell's @mod@ operation.- intMod ::- sym ->- SInteger sym ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Equality comparison on integers- intEq ::- sym ->- SInteger sym ->- SInteger sym ->- SEval sym (SBit sym)-- -- | Less-than comparison on integers- intLessThan ::- sym ->- SInteger sym ->- SInteger sym ->- SEval sym (SBit sym)-- -- | Greater-than comparison on integers- intGreaterThan ::- sym ->- SInteger sym ->- SInteger sym ->- SEval sym (SBit sym)--- -- ==== Operations on Z_n ====-- -- | Turn an integer into a value in Z_n- intToZn ::- sym ->- Integer {- ^ modulus -} ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Transform a Z_n value into an integer, ensuring the value is properly- -- reduced modulo n- znToInt ::- sym ->- Integer {- ^ modulus -} ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Addition of integers modulo n, for a concrete positive integer n.- znPlus ::- sym ->- Integer {- ^ modulus -} ->- SInteger sym ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Additive inverse of integers modulo n- znNegate ::- sym ->- Integer {- ^ modulus -} ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Subtraction of integers modulo n, for a concrete positive integer n.- znMinus ::- sym ->- Integer {- ^ modulus -} ->- SInteger sym ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Multiplication of integers modulo n, for a concrete positive integer n.- znMult ::- sym ->- Integer {- ^ modulus -} ->- SInteger sym ->- SInteger sym ->- SEval sym (SInteger sym)-- -- | Equality test of integers modulo n- znEq ::- sym ->- Integer {- ^ modulus -} ->- SInteger sym ->- SInteger sym ->- SEval sym (SBit sym)-- -- == Float Operations ==- fpEq :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)- fpLessThan :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)- fpGreaterThan :: sym -> SFloat sym -> SFloat sym -> SEval sym (SBit sym)-- fpPlus, fpMinus, fpMult, fpDiv :: FPArith2 sym- fpNeg :: sym -> SFloat sym -> SEval sym (SFloat sym)-- fpToInteger ::- sym ->- String {- ^ Name of the function for error reporting -} ->- SWord sym {-^ Rounding mode -} ->- SFloat sym -> SEval sym (SInteger sym)-- fpFromInteger ::- sym ->- Integer {- exp width -} ->- Integer {- prec width -} ->- SWord sym {- ^ rounding mode -} ->- SInteger sym {- ^ the integeer to use -} ->- SEval sym (SFloat sym)--type FPArith2 sym =- sym ->- SWord sym ->- SFloat sym ->- SFloat sym ->- SEval sym (SFloat sym)-----
src/Cryptol/Eval/Concrete.hs view
@@ -7,49 +7,57 @@ -- Portability : portable {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BlockArguments #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE Safe #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE ViewPatterns #-} module Cryptol.Eval.Concrete- ( module Cryptol.Eval.Concrete.Value- , evalPrim+ ( module Cryptol.Backend.Concrete+ , Value+ , primTable , toExpr ) where -import Control.Monad (join, guard, zipWithM)+import Control.Monad (join, guard, zipWithM, foldM) import Data.Bits (Bits(..))-import Data.Ratio(numerator,denominator)+import Data.Ratio((%),numerator,denominator)+import Data.Word(Word32, Word64) import MonadLib( ChoiceT, findOne, lift ) import qualified LibBF as FP+import qualified Cryptol.F2 as F2 import qualified Data.Map.Strict as Map+import Data.Map(Map) import Cryptol.TypeCheck.Solver.InfNat (Nat'(..))-import Cryptol.Eval.Backend-import Cryptol.Eval.Concrete.Float(floatPrims)-import Cryptol.Eval.Concrete.FloatHelpers(bfValue)-import Cryptol.Eval.Concrete.Value++import Cryptol.Backend+import Cryptol.Backend.Concrete+import Cryptol.Backend.FloatHelpers+import Cryptol.Backend.Monad+ import Cryptol.Eval.Generic hiding (logicShift)-import Cryptol.Eval.Monad import Cryptol.Eval.Type import Cryptol.Eval.Value+import qualified Cryptol.SHA as SHA+import qualified Cryptol.AES as AES+import qualified Cryptol.PrimeEC as PrimeEC import Cryptol.ModuleSystem.Name-import Cryptol.Testing.Random (randomV) import Cryptol.TypeCheck.AST as AST import Cryptol.Utils.Panic (panic)-import Cryptol.Utils.Ident (PrimIdent,prelPrim,floatPrim)+import Cryptol.Utils.Ident (PrimIdent,prelPrim,floatPrim,suiteBPrim,primeECPrim) import Cryptol.Utils.PP import Cryptol.Utils.Logger(logPrint) import Cryptol.Utils.RecordMap +type Value = GenValue Concrete -- Value to Expression conversion ---------------------------------------------- @@ -131,12 +139,12 @@ -- Primitives ------------------------------------------------------------------ -evalPrim :: PrimIdent -> Maybe Value-evalPrim prim = Map.lookup prim primTable--primTable :: Map.Map PrimIdent Value-primTable = let sym = Concrete in+primTable :: EvalOpts -> Map PrimIdent Value+primTable eOpts = let sym = Concrete in Map.union (floatPrims sym) $+ Map.union suiteBPrims $+ Map.union primeECPrims $+ Map.fromList $ map (\(n, v) -> (prelPrim n, v)) [ -- Literals@@ -301,6 +309,20 @@ updatePrim sym updateBack_word updateBack) -- Misc+ , ("foldl" , {-# SCC "Prelude::foldl" #-}+ foldlV sym)++ , ("foldl'" , {-# SCC "Prelude::foldl'" #-}+ foldl'V sym)++ , ("deepseq" , {-# SCC "Prelude::deepseq" #-}+ tlam $ \_a ->+ tlam $ \_b ->+ lam $ \x -> pure $+ lam $ \y ->+ do _ <- forceValue =<< x+ y)+ , ("parmap" , {-# SCC "Prelude::parmap" #-} parmapV sym) @@ -324,15 +346,261 @@ lam $ \x -> return $ lam $ \y -> do msg <- valueToString sym =<< s- EvalOpts { evalPPOpts, evalLogger } <- getEvalOpts+ let EvalOpts { evalPPOpts, evalLogger } = eOpts doc <- ppValue sym evalPPOpts =<< x yv <- y io $ logPrint evalLogger $ if null msg then doc else text msg <+> doc return yv)++ , ("pmult",+ ilam $ \u ->+ ilam $ \v ->+ wlam Concrete $ \(BV _ x) -> return $+ wlam Concrete $ \(BV _ y) ->+ let z = if u <= v then+ F2.pmult (fromInteger (u+1)) x y+ else+ F2.pmult (fromInteger (v+1)) y x+ in return . VWord (1+u+v) . pure . WordVal . mkBv (1+u+v) $! z)++ , ("pmod",+ ilam $ \_u ->+ ilam $ \v ->+ wlam Concrete $ \(BV w x) -> return $+ wlam Concrete $ \(BV _ m) ->+ do assertSideCondition sym (m /= 0) DivideByZero+ return . VWord v . pure . WordVal . mkBv v $! F2.pmod (fromInteger w) x m)++ , ("pdiv",+ ilam $ \_u ->+ ilam $ \_v ->+ wlam Concrete $ \(BV w x) -> return $+ wlam Concrete $ \(BV _ m) ->+ do assertSideCondition sym (m /= 0) DivideByZero+ return . VWord w . pure . WordVal . mkBv w $! F2.pdiv (fromInteger w) x m) ] +primeECPrims :: Map.Map PrimIdent Value+primeECPrims = Map.fromList $ map (\(n,v) -> (primeECPrim n, v))+ [ ("ec_double", {-# SCC "PrimeEC::ec_double" #-}+ ilam $ \p ->+ lam $ \s ->+ do s' <- toProjectivePoint =<< s+ let r = PrimeEC.ec_double (PrimeEC.primeModulus p) s'+ fromProjectivePoint $! r)++ , ("ec_add_nonzero", {-# SCC "PrimeEC::ec_add_nonzero" #-}+ ilam $ \p ->+ lam $ \s -> pure $+ lam $ \t ->+ do s' <- toProjectivePoint =<< s+ t' <- toProjectivePoint =<< t+ let r = PrimeEC.ec_add_nonzero (PrimeEC.primeModulus p) s' t'+ fromProjectivePoint $! r)++ , ("ec_mult", {-# SCC "PrimeEC::ec_mult" #-}+ ilam $ \p ->+ lam $ \d -> pure $+ lam $ \s ->+ do d' <- fromVInteger <$> d+ s' <- toProjectivePoint =<< s+ let r = PrimeEC.ec_mult (PrimeEC.primeModulus p) d' s'+ fromProjectivePoint $! r)++ , ("ec_twin_mult", {-# SCC "PrimeEC::ec_twin_mult" #-}+ ilam $ \p ->+ lam $ \d0 -> pure $+ lam $ \s -> pure $+ lam $ \d1 -> pure $+ lam $ \t ->+ do d0' <- fromVInteger <$> d0+ s' <- toProjectivePoint =<< s+ d1' <- fromVInteger <$> d1+ t' <- toProjectivePoint =<< t+ let r = PrimeEC.ec_twin_mult (PrimeEC.primeModulus p) d0' s' d1' t'+ fromProjectivePoint $! r)+ ]++toProjectivePoint :: Value -> Eval PrimeEC.ProjectivePoint+toProjectivePoint v = PrimeEC.ProjectivePoint <$> f "x" <*> f "y" <*> f "z"+ where+ f nm = PrimeEC.integerToBigNat . fromVInteger <$> lookupRecord nm v++fromProjectivePoint :: PrimeEC.ProjectivePoint -> Eval Value+fromProjectivePoint (PrimeEC.ProjectivePoint x y z) =+ pure . VRecord . recordFromFields $ [("x", f x), ("y", f y), ("z", f z)]+ where+ f i = pure (VInteger (PrimeEC.bigNatToInteger i))++++suiteBPrims :: Map.Map PrimIdent Value+suiteBPrims = Map.fromList $ map (\(n, v) -> (suiteBPrim n, v))+ [ ("processSHA2_224", {-# SCC "SuiteB::processSHA2_224" #-}+ ilam $ \n ->+ lam $ \xs ->+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ (SHA.SHA256S w0 w1 w2 w3 w4 w5 w6 _) <-+ foldM (\st blk -> seq st (SHA.processSHA256Block st <$> (toSHA256Block =<< blk)))+ SHA.initialSHA224State blks+ let f :: Word32 -> Eval Value+ f = pure . VWord 32 . pure . WordVal . BV 32 . toInteger+ zs = finiteSeqMap Concrete (map f [w0,w1,w2,w3,w4,w5,w6])+ seq zs (pure (VSeq 7 zs)))++ , ("processSHA2_256", {-# SCC "SuiteB::processSHA2_256" #-}+ ilam $ \n ->+ lam $ \xs ->+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ (SHA.SHA256S w0 w1 w2 w3 w4 w5 w6 w7) <-+ foldM (\st blk -> seq st (SHA.processSHA256Block st <$> (toSHA256Block =<< blk)))+ SHA.initialSHA256State blks+ let f :: Word32 -> Eval Value+ f = pure . VWord 32 . pure . WordVal . BV 32 . toInteger+ zs = finiteSeqMap Concrete (map f [w0,w1,w2,w3,w4,w5,w6,w7])+ seq zs (pure (VSeq 8 zs)))++ , ("processSHA2_384", {-# SCC "SuiteB::processSHA2_384" #-}+ ilam $ \n ->+ lam $ \xs ->+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ (SHA.SHA512S w0 w1 w2 w3 w4 w5 _ _) <-+ foldM (\st blk -> seq st (SHA.processSHA512Block st <$> (toSHA512Block =<< blk)))+ SHA.initialSHA384State blks+ let f :: Word64 -> Eval Value+ f = pure . VWord 64 . pure . WordVal . BV 64 . toInteger+ zs = finiteSeqMap Concrete (map f [w0,w1,w2,w3,w4,w5])+ seq zs (pure (VSeq 6 zs)))++ , ("processSHA2_512", {-# SCC "SuiteB::processSHA2_512" #-}+ ilam $ \n ->+ lam $ \xs ->+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ (SHA.SHA512S w0 w1 w2 w3 w4 w5 w6 w7) <-+ foldM (\st blk -> seq st (SHA.processSHA512Block st <$> (toSHA512Block =<< blk)))+ SHA.initialSHA512State blks+ let f :: Word64 -> Eval Value+ f = pure . VWord 64 . pure . WordVal . BV 64 . toInteger+ zs = finiteSeqMap Concrete (map f [w0,w1,w2,w3,w4,w5,w6,w7])+ seq zs (pure (VSeq 8 zs)))++ , ("AESKeyExpand", {-# SCC "SuiteB::AESKeyExpand" #-}+ ilam $ \k ->+ lam $ \seed ->+ do ss <- fromVSeq <$> seed+ let toWord :: Integer -> Eval Word32+ toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESInfKeyExpand" =<< lookupSeqMap ss i)+ let fromWord :: Word32 -> Eval Value+ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger+ kws <- mapM toWord [0 .. k-1]+ let ws = AES.keyExpansionWords k kws+ let len = 4*(k+7)+ pure (VSeq len (finiteSeqMap Concrete (map fromWord ws))))++ , ("AESInvMixColumns", {-# SCC "SuiteB::AESInvMixColumns" #-}+ lam $ \st ->+ do ss <- fromVSeq <$> st+ let toWord :: Integer -> Eval Word32+ toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESInvMixColumns" =<< lookupSeqMap ss i)+ let fromWord :: Word32 -> Eval Value+ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger+ ws <- mapM toWord [0,1,2,3]+ let ws' = AES.invMixColumns ws+ pure . VSeq 4 . finiteSeqMap Concrete . map fromWord $ ws')++ , ("AESEncRound", {-# SCC "SuiteB::AESEncRound" #-}+ lam $ \st ->+ do ss <- fromVSeq <$> st+ let toWord :: Integer -> Eval Word32+ toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESEncRound" =<< lookupSeqMap ss i)+ let fromWord :: Word32 -> Eval Value+ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger+ ws <- mapM toWord [0,1,2,3]+ let ws' = AES.aesRound ws+ pure . VSeq 4 . finiteSeqMap Concrete . map fromWord $ ws')++ , ("AESEncFinalRound", {-# SCC "SuiteB::AESEncFinalRound" #-}+ lam $ \st ->+ do ss <- fromVSeq <$> st+ let toWord :: Integer -> Eval Word32+ toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESEncFinalRound" =<< lookupSeqMap ss i)+ let fromWord :: Word32 -> Eval Value+ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger+ ws <- mapM toWord [0,1,2,3]+ let ws' = AES.aesFinalRound ws+ pure . VSeq 4 . finiteSeqMap Concrete . map fromWord $ ws')++ , ("AESDecRound", {-# SCC "SuiteB::AESDecRound" #-}+ lam $ \st ->+ do ss <- fromVSeq <$> st+ let toWord :: Integer -> Eval Word32+ toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESDecRound" =<< lookupSeqMap ss i)+ let fromWord :: Word32 -> Eval Value+ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger+ ws <- mapM toWord [0,1,2,3]+ let ws' = AES.aesInvRound ws+ pure . VSeq 4 . finiteSeqMap Concrete . map fromWord $ ws')++ , ("AESDecFinalRound", {-# SCC "SuiteB::AESDecFinalRound" #-}+ lam $ \st ->+ do ss <- fromVSeq <$> st+ let toWord :: Integer -> Eval Word32+ toWord i = fromInteger. bvVal <$> (fromVWord Concrete "AESDecFinalRound" =<< lookupSeqMap ss i)+ let fromWord :: Word32 -> Eval Value+ fromWord = pure . VWord 32 . pure . WordVal . BV 32 . toInteger+ ws <- mapM toWord [0,1,2,3]+ let ws' = AES.aesInvFinalRound ws+ pure . VSeq 4 . finiteSeqMap Concrete . map fromWord $ ws')+ ]+++toSHA256Block :: Value -> Eval SHA.SHA256Block+toSHA256Block blk =+ do let ws = fromVSeq blk+ let toWord i = fromInteger . bvVal <$> (fromVWord Concrete "toSHA256Block" =<< lookupSeqMap ws i)+ SHA.SHA256Block <$>+ (toWord 0) <*>+ (toWord 1) <*>+ (toWord 2) <*>+ (toWord 3) <*>+ (toWord 4) <*>+ (toWord 5) <*>+ (toWord 6) <*>+ (toWord 7) <*>+ (toWord 8) <*>+ (toWord 9) <*>+ (toWord 10) <*>+ (toWord 11) <*>+ (toWord 12) <*>+ (toWord 13) <*>+ (toWord 14) <*>+ (toWord 15)+++toSHA512Block :: Value -> Eval SHA.SHA512Block+toSHA512Block blk =+ do let ws = fromVSeq blk+ let toWord i = fromInteger . bvVal <$> (fromVWord Concrete "toSHA512Block" =<< lookupSeqMap ws i)+ SHA.SHA512Block <$>+ (toWord 0) <*>+ (toWord 1) <*>+ (toWord 2) <*>+ (toWord 3) <*>+ (toWord 4) <*>+ (toWord 5) <*>+ (toWord 6) <*>+ (toWord 7) <*>+ (toWord 8) <*>+ (toWord 9) <*>+ (toWord 10) <*>+ (toWord 11) <*>+ (toWord 12) <*>+ (toWord 13) <*>+ (toWord 14) <*>+ (toWord 15)+ -------------------------------------------------------------------------------- sshrV :: Value@@ -527,3 +795,55 @@ updateBack_word (Nat n) _eltTy bs (Right w) val = do idx <- bvVal <$> asWordVal Concrete w updateWordValue Concrete bs (n - idx - 1) (fromVBit <$> val)+++floatPrims :: Concrete -> Map PrimIdent Value+floatPrims sym = Map.fromList [ (floatPrim i,v) | (i,v) <- nonInfixTable ]+ where+ (~>) = (,)+ nonInfixTable =+ [ "fpNaN" ~> ilam \e -> ilam \p ->+ VFloat BF { bfValue = FP.bfNaN+ , bfExpWidth = e, bfPrecWidth = p }++ , "fpPosInf" ~> ilam \e -> ilam \p ->+ VFloat BF { bfValue = FP.bfPosInf+ , bfExpWidth = e, bfPrecWidth = p }++ , "fpFromBits" ~> ilam \e -> ilam \p -> wlam sym \bv ->+ pure $ VFloat $ floatFromBits e p $ bvVal bv++ , "fpToBits" ~> ilam \e -> ilam \p -> flam \x ->+ pure $ word sym (e + p)+ $ floatToBits e p+ $ bfValue x+ , "=.=" ~> ilam \_ -> ilam \_ -> flam \x -> pure $ flam \y ->+ pure $ VBit+ $ bitLit sym+ $ FP.bfCompare (bfValue x) (bfValue y) == EQ++ , "fpIsFinite" ~> ilam \_ -> ilam \_ -> flam \x ->+ pure $ VBit $ bitLit sym $ FP.bfIsFinite $ bfValue x++ -- From Backend class+ , "fpAdd" ~> fpBinArithV sym fpPlus+ , "fpSub" ~> fpBinArithV sym fpMinus+ , "fpMul" ~> fpBinArithV sym fpMult+ , "fpDiv" ~> fpBinArithV sym fpDiv++ , "fpFromRational" ~>+ ilam \e -> ilam \p -> wlam sym \r -> pure $ lam \x ->+ do rat <- fromVRational <$> x+ VFloat <$> do mode <- fpRoundMode sym r+ pure $ floatFromRational e p mode+ $ sNum rat % sDenom rat+ , "fpToRational" ~>+ ilam \_e -> ilam \_p -> flam \fp ->+ case floatToRational "fpToRational" fp of+ Left err -> raiseError sym err+ Right r -> pure $+ VRational+ SRational { sNum = numerator r, sDenom = denominator r }+ ]++
− src/Cryptol/Eval/Concrete/Float.hs
@@ -1,69 +0,0 @@-{-# Language BlockArguments #-}-{-# Language OverloadedStrings #-}--- | Concrete evaluations for floating point primitives.-module Cryptol.Eval.Concrete.Float where--import Data.Map(Map)-import Data.Ratio((%),numerator,denominator)-import qualified Data.Map as Map-import LibBF--import Cryptol.Utils.Ident(PrimIdent, floatPrim)-import Cryptol.Eval.Value-import Cryptol.Eval.Generic-import Cryptol.Eval.Concrete.Value-import Cryptol.Eval.Backend(SRational(..))-import Cryptol.Eval.Concrete.FloatHelpers----floatPrims :: Concrete -> Map PrimIdent Value-floatPrims sym = Map.fromList [ (floatPrim i,v) | (i,v) <- nonInfixTable ]- where- (~>) = (,)- nonInfixTable =- [ "fpNaN" ~> ilam \e -> ilam \p ->- VFloat BF { bfValue = bfNaN- , bfExpWidth = e, bfPrecWidth = p }-- , "fpPosInf" ~> ilam \e -> ilam \p ->- VFloat BF { bfValue = bfPosInf- , bfExpWidth = e, bfPrecWidth = p }-- , "fpFromBits" ~> ilam \e -> ilam \p -> wlam sym \bv ->- pure $ VFloat $ floatFromBits e p $ bvVal bv-- , "fpToBits" ~> ilam \e -> ilam \p -> flam \x ->- pure $ word sym (e + p)- $ floatToBits e p- $ bfValue x- , "=.=" ~> ilam \_ -> ilam \_ -> flam \x -> pure $ flam \y ->- pure $ VBit- $ bitLit sym- $ bfCompare (bfValue x) (bfValue y) == EQ-- , "fpIsFinite" ~> ilam \_ -> ilam \_ -> flam \x ->- pure $ VBit $ bitLit sym $ bfIsFinite $ bfValue x-- -- From Backend class- , "fpAdd" ~> fpBinArithV sym fpPlus- , "fpSub" ~> fpBinArithV sym fpMinus- , "fpMul" ~> fpBinArithV sym fpMult- , "fpDiv" ~> fpBinArithV sym fpDiv-- , "fpFromRational" ~>- ilam \e -> ilam \p -> wlam sym \r -> pure $ lam \x ->- do rat <- fromVRational <$> x- VFloat <$> do mode <- fpRoundMode sym r- pure $ floatFromRational e p mode- $ sNum rat % sDenom rat- , "fpToRational" ~>- ilam \_e -> ilam \_p -> flam \fp ->- case floatToRational "fpToRational" fp of- Left err -> raiseError sym err- Right r -> pure $- VRational- SRational { sNum = numerator r, sDenom = denominator r }- ]--
− src/Cryptol/Eval/Concrete/FloatHelpers.hs
@@ -1,252 +0,0 @@-{-# Language BlockArguments, OverloadedStrings #-}-{-# Language BangPatterns #-}-module Cryptol.Eval.Concrete.FloatHelpers where--import Data.Ratio(numerator,denominator)-import Data.Int(Int64)-import Data.Bits(testBit,setBit,shiftL,shiftR,(.&.),(.|.))-import LibBF--import Cryptol.Utils.PP-import Cryptol.Utils.Panic(panic)-import Cryptol.Eval.Monad( EvalError(..)- , PPOpts(..), PPFloatFormat(..), PPFloatExp(..)- )---data BF = BF- { bfExpWidth :: Integer- , bfPrecWidth :: Integer- , bfValue :: BigFloat- }----- | Make LibBF options for the given precision and rounding mode.-fpOpts :: Integer -> Integer -> RoundMode -> BFOpts-fpOpts e p r =- case ok of- Just opts -> opts- Nothing -> panic "floatOpts" [ "Invalid Float size"- , "exponent: " ++ show e- , "precision: " ++ show p- ]- where- ok = do eb <- rng expBits expBitsMin expBitsMax e- pb <- rng precBits precBitsMin precBitsMax p- pure (eb <> pb <> allowSubnormal <> rnd r)-- rng f a b x = if toInteger a <= x && x <= toInteger b- then Just (f (fromInteger x))- else Nothing------ | Mapping from the rounding modes defined in the `Float.cry` to--- the rounding modes of `LibBF`.-fpRound :: Integer -> Either EvalError RoundMode-fpRound n =- case n of- 0 -> Right NearEven- 1 -> Right NearAway- 2 -> Right ToPosInf- 3 -> Right ToNegInf- 4 -> Right ToZero- _ -> Left (BadRoundingMode n)---- | Check that we didn't get an unexpected status.-fpCheckStatus :: (BigFloat,Status) -> BigFloat-fpCheckStatus (r,s) =- case s of- MemError -> panic "checkStatus" [ "libBF: Memory error" ]- _ -> r----- | Pretty print a float-fpPP :: PPOpts -> BF -> Doc-fpPP opts bf =- case bfSign num of- Nothing -> "fpNaN"- Just s- | bfIsFinite num -> text hacStr- | otherwise ->- case s of- Pos -> "fpPosInf"- Neg -> "fpNegInf"- where- num = bfValue bf- precW = bfPrecWidth bf-- base = useFPBase opts-- withExp :: PPFloatExp -> ShowFmt -> ShowFmt- withExp e f = case e of- AutoExponent -> f- ForceExponent -> f <> forceExp-- str = bfToString base fmt num- fmt = addPrefix <> showRnd NearEven <>- case useFPFormat opts of- FloatFree e -> withExp e $ showFreeMin- $ Just $ fromInteger precW- FloatFixed n e -> withExp e $ showFixed $ fromIntegral n- FloatFrac n -> showFrac $ fromIntegral n-- -- non-base 10 literals are not overloaded so we add an explicit- -- .0 if one is not present. - hacStr- | base == 10 || elem '.' str = str- | otherwise = case break (== 'p') str of- (xs,ys) -> xs ++ ".0" ++ ys----- | Make a literal-fpLit ::- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- Rational ->- BF-fpLit e p rat = floatFromRational e p NearEven rat---- | Make a floating point number from a rational, using the given rounding mode-floatFromRational :: Integer -> Integer -> RoundMode -> Rational -> BF-floatFromRational e p r rat =- BF { bfExpWidth = e- , bfPrecWidth = p- , bfValue = fpCheckStatus- if den == 1 then bfRoundFloat opts num- else bfDiv opts num (bfFromInteger den)- }- where- opts = fpOpts e p r-- num = bfFromInteger (numerator rat)- den = denominator rat----- | Convert a floating point number to a rational, if possible.-floatToRational :: String -> BF -> Either EvalError Rational-floatToRational fun bf =- case bfToRep (bfValue bf) of- BFNaN -> Left (BadValue fun)- BFRep s num ->- case num of- Inf -> Left (BadValue fun)- Zero -> Right 0- Num i ev -> Right case s of- Pos -> ab- Neg -> negate ab- where ab = fromInteger i * (2 ^^ ev)----- | Convert a floating point number to an integer, if possible.-floatToInteger :: String -> RoundMode -> BF -> Either EvalError Integer-floatToInteger fun r fp =- do rat <- floatToRational fun fp- pure case r of- NearEven -> round rat- NearAway -> if rat > 0 then ceiling rat else floor rat- ToPosInf -> ceiling rat- ToNegInf -> floor rat- ToZero -> truncate rat- _ -> panic "fpCvtToInteger"- ["Unexpected rounding mode", show r]-----floatFromBits :: - Integer {- ^ Exponent width -} ->- Integer {- ^ Precision widht -} ->- Integer {- ^ Raw bits -} ->- BF-floatFromBits e p bv = BF { bfValue = floatFromBits' e p bv- , bfExpWidth = e, bfPrecWidth = p }------ | Make a float using "raw" bits.-floatFromBits' ::- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision widht -} ->- Integer {- ^ Raw bits -} ->- BigFloat--floatFromBits' e p bits- | expoBiased == 0 && mant == 0 = -- zero- if isNeg then bfNegZero else bfPosZero-- | expoBiased == eMask && mant == 0 = -- infinity- if isNeg then bfNegInf else bfPosInf-- | expoBiased == eMask = bfNaN -- NaN-- | expoBiased == 0 = -- Subnormal- case bfMul2Exp opts (bfFromInteger mant) (expoVal + 1) of- (num,Ok) -> if isNeg then bfNeg num else num- (_,s) -> panic "floatFromBits" [ "Unexpected status: " ++ show s ]-- | otherwise = -- Normal- case bfMul2Exp opts (bfFromInteger mantVal) expoVal of- (num,Ok) -> if isNeg then bfNeg num else num- (_,s) -> panic "floatFromBits" [ "Unexpected status: " ++ show s ]-- where- opts = expBits e' <> precBits (p' + 1) <> allowSubnormal-- e' = fromInteger e :: Int- p' = fromInteger p - 1 :: Int- eMask = (1 `shiftL` e') - 1 :: Int64- pMask = (1 `shiftL` p') - 1 :: Integer-- isNeg = testBit bits (e' + p')-- mant = pMask .&. bits :: Integer- mantVal = mant `setBit` p' :: Integer- -- accounts for the implicit 1 bit-- expoBiased = eMask .&. fromInteger (bits `shiftR` p') :: Int64- bias = eMask `shiftR` 1 :: Int64- expoVal = expoBiased - bias - fromIntegral p' :: Int64----- | Turn a float into raw bits.--- @NaN@ is represented as a positive "quiet" @NaN@--- (most significant bit in the significand is set, the rest of it is 0)-floatToBits :: Integer -> Integer -> BigFloat -> Integer-floatToBits e p bf = (isNeg `shiftL` (e' + p'))- .|. (expBiased `shiftL` p')- .|. (mant `shiftL` 0)- where- e' = fromInteger e :: Int- p' = fromInteger p - 1 :: Int-- eMask = (1 `shiftL` e') - 1 :: Integer- pMask = (1 `shiftL` p') - 1 :: Integer-- (isNeg, expBiased, mant) =- case bfToRep bf of- BFNaN -> (0, eMask, 1 `shiftL` (p' - 1))- BFRep s num -> (sign, be, ma)- where- sign = case s of- Neg -> 1- Pos -> 0-- (be,ma) =- case num of- Zero -> (0,0)- Num i ev- | ex == 0 -> (0, i `shiftL` (p' - m -1))- | otherwise -> (ex, (i `shiftL` (p' - m)) .&. pMask)- where- m = msb 0 i - 1- bias = eMask `shiftR` 1- ex = toInteger ev + bias + toInteger m-- Inf -> (eMask,0)-- msb !n j = if j == 0 then n else msb (n+1) (j `shiftR` 1)----
− src/Cryptol/Eval/Concrete/Value.hs
@@ -1,390 +0,0 @@--- |fpToInteger r e p f--- Module : Cryptol.Eval.Concrete.Value--- Copyright : (c) 2013-2020 Galois, Inc.--- License : BSD3--- Maintainer : cryptol@galois.com--- Stability : provisional--- Portability : portable--{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE BlockArguments #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE PatternGuards #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE Safe #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ViewPatterns #-}-module Cryptol.Eval.Concrete.Value- ( BV(..)- , binBV- , unaryBV- , bvVal- , ppBV- , mkBv- , mask- , signedBV- , signedValue- , integerToChar- , lg2- , Value- , Concrete(..)- , liftBinIntMod- , fpBinArith- , fpRoundMode- ) where--import qualified Control.Exception as X-import Data.Bits-import Numeric (showIntAtBase)-import qualified LibBF as FP--import qualified Cryptol.Eval.Arch as Arch-import qualified Cryptol.Eval.Concrete.FloatHelpers as FP-import Cryptol.Eval.Monad-import Cryptol.Eval.Value-import Cryptol.TypeCheck.Solver.InfNat (genLog)-import Cryptol.Utils.Panic (panic)-import Cryptol.Utils.PP--data Concrete = Concrete deriving Show--type Value = GenValue Concrete---- | Concrete bitvector values: width, value--- Invariant: The value must be within the range 0 .. 2^width-1-data BV = BV !Integer !Integer--instance Show BV where- show = show . bvVal---- | Apply an integer function to the values of bitvectors.--- This function assumes both bitvectors are the same width.-binBV :: Applicative m => (Integer -> Integer -> Integer) -> BV -> BV -> m BV-binBV f (BV w x) (BV _ y) = pure $! mkBv w (f x y)-{-# INLINE binBV #-}---- | Apply an integer function to the values of a bitvector.--- This function assumes the function will not require masking.-unaryBV :: (Integer -> Integer) -> BV -> BV-unaryBV f (BV w x) = mkBv w $! f x-{-# INLINE unaryBV #-}--bvVal :: BV -> Integer-bvVal (BV _w x) = x-{-# INLINE bvVal #-}---- | Smart constructor for 'BV's that checks for the width limit-mkBv :: Integer -> Integer -> BV-mkBv w i = BV w (mask w i)--signedBV :: BV -> Integer-signedBV (BV i x) = signedValue i x--signedValue :: Integer -> Integer -> Integer-signedValue i x = if testBit x (fromInteger (i-1)) then x - (bit (fromInteger i)) else x--integerToChar :: Integer -> Char-integerToChar = toEnum . fromInteger--lg2 :: Integer -> Integer-lg2 i = case genLog i 2 of- Just (i',isExact) | isExact -> i'- | otherwise -> i' + 1- Nothing -> 0---ppBV :: PPOpts -> BV -> Doc-ppBV opts (BV width i)- | base > 36 = integer i -- not sure how to rule this out- | asciiMode opts width = text (show (toEnum (fromInteger i) :: Char))- | otherwise = prefix <.> text value- where- base = useBase opts-- padding bitsPerDigit = text (replicate padLen '0')- where- padLen | m > 0 = d + 1- | otherwise = d-- (d,m) = (fromInteger width - (length value * bitsPerDigit))- `divMod` bitsPerDigit-- prefix = case base of- 2 -> text "0b" <.> padding 1- 8 -> text "0o" <.> padding 3- 10 -> empty- 16 -> text "0x" <.> padding 4- _ -> text "0" <.> char '<' <.> int base <.> char '>'-- value = showIntAtBase (toInteger base) (digits !!) i ""- digits = "0123456789abcdefghijklmnopqrstuvwxyz"---- Concrete Big-endian Words --------------------------------------------------------------mask ::- Integer {- ^ Bit-width -} ->- Integer {- ^ Value -} ->- Integer {- ^ Masked result -}-mask w i | w >= Arch.maxBigIntWidth = wordTooWide w- | otherwise = i .&. (bit (fromInteger w) - 1)--instance Backend Concrete where- type SBit Concrete = Bool- type SWord Concrete = BV- type SInteger Concrete = Integer- type SFloat Concrete = FP.BF- type SEval Concrete = Eval-- raiseError _ err = io (X.throwIO err)-- assertSideCondition _ True _ = return ()- assertSideCondition _ False err = io (X.throwIO err)-- wordLen _ (BV w _) = w- wordAsChar _ (BV _ x) = Just $! integerToChar x-- wordBit _ (BV w x) idx = pure $! testBit x (fromInteger (w - 1 - idx))-- wordUpdate _ (BV w x) idx True = pure $! BV w (setBit x (fromInteger (w - 1 - idx)))- wordUpdate _ (BV w x) idx False = pure $! BV w (clearBit x (fromInteger (w - 1 - idx)))-- isReady _ (Ready _) = True- isReady _ _ = False-- mergeEval _sym f c mx my =- do x <- mx- y <- my- f c x y-- sDeclareHole _ = blackhole- sDelayFill _ = delayFill- sSpark _ = evalSpark-- ppBit _ b | b = text "True"- | otherwise = text "False"-- ppWord _ = ppBV-- ppInteger _ _opts i = integer i-- ppFloat _ = FP.fpPP-- bitLit _ b = b- bitAsLit _ b = Just b-- bitEq _ x y = pure $! x == y- bitOr _ x y = pure $! x .|. y- bitAnd _ x y = pure $! x .&. y- bitXor _ x y = pure $! x `xor` y- bitComplement _ x = pure $! complement x-- iteBit _ b x y = pure $! if b then x else y- iteWord _ b x y = pure $! if b then x else y- iteInteger _ b x y = pure $! if b then x else y-- wordLit _ w i = pure $! mkBv w i- wordAsLit _ (BV w i) = Just (w,i)- integerLit _ i = pure i- integerAsLit _ = Just-- wordToInt _ (BV _ x) = pure x- wordFromInt _ w x = pure $! mkBv w x-- packWord _ bits = pure $! BV (toInteger w) a- where- w = case length bits of- len | toInteger len >= Arch.maxBigIntWidth -> wordTooWide (toInteger len)- | otherwise -> len- a = foldl setb 0 (zip [w - 1, w - 2 .. 0] bits)- setb acc (n,b) | b = setBit acc n- | otherwise = acc-- unpackWord _ (BV w a) = pure [ testBit a n | n <- [w' - 1, w' - 2 .. 0] ]- where- w' = fromInteger w-- joinWord _ (BV i x) (BV j y) =- pure $! BV (i + j) (shiftL x (fromInteger j) + y)-- splitWord _ leftW rightW (BV _ x) =- pure ( BV leftW (x `shiftR` (fromInteger rightW)), mkBv rightW x )-- extractWord _ n i (BV _ x) = pure $! mkBv n (x `shiftR` (fromInteger i))-- wordEq _ (BV i x) (BV j y)- | i == j = pure $! x == y- | otherwise = panic "Attempt to compare words of different sizes: wordEq" [show i, show j]-- wordSignedLessThan _ (BV i x) (BV j y)- | i == j = pure $! signedValue i x < signedValue i y- | otherwise = panic "Attempt to compare words of different sizes: wordSignedLessThan" [show i, show j]-- wordLessThan _ (BV i x) (BV j y)- | i == j = pure $! x < y- | otherwise = panic "Attempt to compare words of different sizes: wordLessThan" [show i, show j]-- wordGreaterThan _ (BV i x) (BV j y)- | i == j = pure $! x > y- | otherwise = panic "Attempt to compare words of different sizes: wordGreaterThan" [show i, show j]-- wordAnd _ (BV i x) (BV j y)- | i == j = pure $! mkBv i (x .&. y)- | otherwise = panic "Attempt to AND words of different sizes: wordPlus" [show i, show j]-- wordOr _ (BV i x) (BV j y)- | i == j = pure $! mkBv i (x .|. y)- | otherwise = panic "Attempt to OR words of different sizes: wordPlus" [show i, show j]-- wordXor _ (BV i x) (BV j y)- | i == j = pure $! mkBv i (x `xor` y)- | otherwise = panic "Attempt to XOR words of different sizes: wordPlus" [show i, show j]-- wordComplement _ (BV i x) = pure $! mkBv i (complement x)-- wordPlus _ (BV i x) (BV j y)- | i == j = pure $! mkBv i (x+y)- | otherwise = panic "Attempt to add words of different sizes: wordPlus" [show i, show j]-- wordNegate _ (BV i x) = pure $! mkBv i (negate x)-- wordMinus _ (BV i x) (BV j y)- | i == j = pure $! mkBv i (x-y)- | otherwise = panic "Attempt to subtract words of different sizes: wordMinus" [show i, show j]-- wordMult _ (BV i x) (BV j y)- | i == j = pure $! mkBv i (x*y)- | otherwise = panic "Attempt to multiply words of different sizes: wordMult" [show i, show j]-- wordDiv sym (BV i x) (BV j y)- | i == 0 && j == 0 = pure $! mkBv 0 0- | i == j =- do assertSideCondition sym (y /= 0) DivideByZero- pure $! mkBv i (x `div` y)- | otherwise = panic "Attempt to divide words of different sizes: wordDiv" [show i, show j]-- wordMod sym (BV i x) (BV j y)- | i == 0 && j == 0 = pure $! mkBv 0 0- | i == j =- do assertSideCondition sym (y /= 0) DivideByZero- pure $! mkBv i (x `mod` y)- | otherwise = panic "Attempt to mod words of different sizes: wordMod" [show i, show j]-- wordSignedDiv sym (BV i x) (BV j y)- | i == 0 && j == 0 = pure $! mkBv 0 0- | i == j =- do assertSideCondition sym (y /= 0) DivideByZero- let sx = signedValue i x- sy = signedValue i y- pure $! mkBv i (sx `quot` sy)- | otherwise = panic "Attempt to divide words of different sizes: wordSignedDiv" [show i, show j]-- wordSignedMod sym (BV i x) (BV j y)- | i == 0 && j == 0 = pure $! mkBv 0 0- | i == j =- do assertSideCondition sym (y /= 0) DivideByZero- let sx = signedValue i x- sy = signedValue i y- pure $! mkBv i (sx `rem` sy)- | otherwise = panic "Attempt to mod words of different sizes: wordSignedMod" [show i, show j]-- wordLg2 _ (BV i x) = pure $! mkBv i (lg2 x)-- intEq _ x y = pure $! x == y- intLessThan _ x y = pure $! x < y- intGreaterThan _ x y = pure $! x > y-- intPlus _ x y = pure $! x + y- intMinus _ x y = pure $! x - y- intNegate _ x = pure $! negate x- intMult _ x y = pure $! x * y- intDiv sym x y =- do assertSideCondition sym (y /= 0) DivideByZero- pure $! x `div` y- intMod sym x y =- do assertSideCondition sym (y /= 0) DivideByZero- pure $! x `mod` y-- intToZn _ 0 _ = evalPanic "intToZn" ["0 modulus not allowed"]- intToZn _ m x = pure $! x `mod` m-- -- NB: requires we maintain the invariant that- -- Z_n is in reduced form- znToInt _ _m x = pure x- znEq _ _m x y = pure $! x == y-- znPlus _ = liftBinIntMod (+)- znMinus _ = liftBinIntMod (-)- znMult _ = liftBinIntMod (*)- znNegate _ 0 _ = evalPanic "znNegate" ["0 modulus not allowed"]- znNegate _ m x = pure $! (negate x) `mod` m-- ------------------------------------------------------------------------- -- Floating Point- fpLit _sym e p rat = pure (FP.fpLit e p rat)- fpEq _sym x y = pure (FP.bfValue x == FP.bfValue y)- fpLessThan _sym x y = pure (FP.bfValue x < FP.bfValue y)- fpGreaterThan _sym x y = pure (FP.bfValue x > FP.bfValue y)- fpPlus = fpBinArith FP.bfAdd- fpMinus = fpBinArith FP.bfSub- fpMult = fpBinArith FP.bfMul- fpDiv = fpBinArith FP.bfDiv- fpNeg _ x = pure x { FP.bfValue = FP.bfNeg (FP.bfValue x) }- fpFromInteger sym e p r x =- do opts <- FP.fpOpts e p <$> fpRoundMode sym r- pure FP.BF { FP.bfExpWidth = e- , FP.bfPrecWidth = p- , FP.bfValue = FP.fpCheckStatus $- FP.bfRoundInt opts (FP.bfFromInteger x)- }- fpToInteger = fpCvtToInteger---{-# INLINE liftBinIntMod #-}-liftBinIntMod :: Monad m =>- (Integer -> Integer -> Integer) -> Integer -> Integer -> Integer -> m Integer-liftBinIntMod op m x y- | m == 0 = evalPanic "znArithmetic" ["0 modulus not allowed"]- | otherwise = pure $ (op x y) `mod` m----{-# INLINE fpBinArith #-}-fpBinArith ::- (FP.BFOpts -> FP.BigFloat -> FP.BigFloat -> (FP.BigFloat, FP.Status)) ->- Concrete ->- SWord Concrete {- ^ Rouding mode -} ->- SFloat Concrete ->- SFloat Concrete ->- SEval Concrete (SFloat Concrete)-fpBinArith fun = \sym r x y ->- do opts <- FP.fpOpts (FP.bfExpWidth x) (FP.bfPrecWidth x)- <$> fpRoundMode sym r- pure x { FP.bfValue = FP.fpCheckStatus- (fun opts (FP.bfValue x) (FP.bfValue y)) }--fpCvtToInteger ::- Concrete ->- String ->- SWord Concrete {- ^ Rounding mode -} ->- SFloat Concrete ->- SEval Concrete (SInteger Concrete)-fpCvtToInteger sym fun rnd flt =- do mode <- fpRoundMode sym rnd- case FP.floatToInteger fun mode flt of- Right i -> pure i- Left err -> raiseError sym err--fpRoundMode :: Concrete -> SWord Concrete -> SEval Concrete FP.RoundMode-fpRoundMode sym w =- case FP.fpRound (bvVal w) of- Left err -> raiseError sym err- Right a -> pure a-----
src/Cryptol/Eval/Env.hs view
@@ -14,8 +14,10 @@ {-# LANGUAGE DeriveGeneric #-} module Cryptol.Eval.Env where -import Cryptol.Eval.Backend-import Cryptol.Eval.Monad( PPOpts )+import Cryptol.Backend++import Cryptol.Backend.Monad( PPOpts )+ import Cryptol.Eval.Type import Cryptol.Eval.Value import Cryptol.ModuleSystem.Name@@ -24,7 +26,7 @@ import Cryptol.Utils.PP -import qualified Data.Map.Strict as Map+import qualified Data.IntMap.Strict as IntMap import Data.Semigroup import GHC.Generics (Generic)@@ -35,29 +37,29 @@ -- Evaluation Environment ------------------------------------------------------ data GenEvalEnv sym = EvalEnv- { envVars :: !(Map.Map Name (SEval sym (GenValue sym)))+ { envVars :: !(IntMap.IntMap (SEval sym (GenValue sym))) , envTypes :: !TypeEnv } deriving Generic instance Semigroup (GenEvalEnv sym) where l <> r = EvalEnv- { envVars = Map.union (envVars l) (envVars r)- , envTypes = Map.union (envTypes l) (envTypes r)+ { envVars = IntMap.union (envVars l) (envVars r)+ , envTypes = IntMap.union (envTypes l) (envTypes r) } instance Monoid (GenEvalEnv sym) where mempty = EvalEnv- { envVars = Map.empty- , envTypes = Map.empty+ { envVars = IntMap.empty+ , envTypes = IntMap.empty } mappend l r = l <> r ppEnv :: Backend sym => sym -> PPOpts -> GenEvalEnv sym -> SEval sym Doc-ppEnv sym opts env = brackets . fsep <$> mapM bind (Map.toList (envVars env))+ppEnv sym opts env = brackets . fsep <$> mapM bind (IntMap.toList (envVars env)) where bind (k,v) = do vdoc <- ppValue sym opts =<< v- return (pp k <+> text "->" <+> vdoc)+ return (int k <+> text "->" <+> vdoc) -- | Evaluation environment with no bindings emptyEnv :: GenEvalEnv sym@@ -74,7 +76,7 @@ bindVar sym n val env = do let nm = show $ ppLocName n val' <- sDelay sym (Just nm) val- return $ env{ envVars = Map.insert n val' (envVars env) }+ return $ env{ envVars = IntMap.insert (nameUnique n) val' (envVars env) } -- | Bind a variable to a value in the evaluation environment, without -- creating a thunk.@@ -85,20 +87,20 @@ GenEvalEnv sym -> GenEvalEnv sym bindVarDirect n val env = do- env{ envVars = Map.insert n (pure val) (envVars env) }+ env{ envVars = IntMap.insert (nameUnique n) (pure val) (envVars env) } -- | Lookup a variable in the environment. {-# INLINE lookupVar #-} lookupVar :: Name -> GenEvalEnv sym -> Maybe (SEval sym (GenValue sym))-lookupVar n env = Map.lookup n (envVars env)+lookupVar n env = IntMap.lookup (nameUnique n) (envVars env) -- | Bind a type variable of kind *. {-# INLINE bindType #-} bindType :: TVar -> Either Nat' TValue -> GenEvalEnv sym -> GenEvalEnv sym-bindType p ty env = env { envTypes = Map.insert p ty (envTypes env) }+bindType p ty env = env { envTypes = IntMap.insert (tvUnique p) ty (envTypes env) } -- | Lookup a type variable. {-# INLINE lookupType #-} lookupType :: TVar -> GenEvalEnv sym -> Maybe (Either Nat' TValue)-lookupType p env = Map.lookup p (envTypes env)+lookupType p env = IntMap.lookup (tvUnique p) (envTypes env)
src/Cryptol/Eval/Generic.hs view
@@ -8,7 +8,7 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE BlockArguments #-}-{-# LANGUAGE Safe #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TupleSections #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-}@@ -24,16 +24,20 @@ import qualified Control.Exception as X import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad (join, unless)+import System.Random.TF.Gen (seedTFGen) -import Data.Bits (testBit)+import Data.Bits (testBit, (.&.), shiftR)+ import Data.Maybe (fromMaybe) import Data.Ratio ((%)) import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.Solver.InfNat (Nat'(..),nMul,widthInteger)-import Cryptol.Eval.Backend-import Cryptol.Eval.Concrete.Value (Concrete(..))-import Cryptol.Eval.Monad+import Cryptol.Backend+import Cryptol.Backend.Concrete (Concrete(..))+import Cryptol.Backend.Monad ( Eval, evalPanic, EvalError(..), Unsupported(..) )+import Cryptol.Testing.Random( randomValue )+ import Cryptol.Eval.Type import Cryptol.Eval.Value import Cryptol.Utils.Panic (panic)@@ -48,6 +52,7 @@ mkLit :: Backend sym => sym -> TValue -> Integer -> SEval sym (GenValue sym) mkLit sym ty i = case ty of+ TVBit -> pure $ VBit (bitLit sym (i > 0)) TVInteger -> VInteger <$> integerLit sym i TVIntMod m | m == 0 -> evalPanic "mkLit" ["0 modulus not allowed"]@@ -544,7 +549,7 @@ r <- fpRndMode sym xv <- fromVFloat <$> x VFloat <$> fpDiv sym r one xv-+ TVIntMod m -> VInteger <$> (znRecip sym m . fromVInteger =<< x) _ -> evalPanic "recip" [show a ++ "is not a Field"] {-# SPECIALIZE fieldDivideV :: Concrete -> GenValue Concrete #-}@@ -563,6 +568,12 @@ yv <- fromVFloat <$> y r <- fpRndMode sym VFloat <$> fpDiv sym r xv yv+ TVIntMod m ->+ do x' <- fromVInteger <$> x+ y' <- fromVInteger <$> y+ yinv <- znRecip sym m y'+ VInteger <$> znMult sym m x' yinv+ _ -> evalPanic "recip" [show a ++ "is not a Field"] --------------------------------------------------------------@@ -1909,6 +1920,77 @@ iteValue sym c (lookupSeqMap x i) (lookupSeqMap y i) ++foldlV :: Backend sym => sym -> GenValue sym+foldlV sym =+ ilam $ \_n ->+ tlam $ \_a ->+ tlam $ \_b ->+ lam $ \f -> pure $+ lam $ \z -> pure $+ lam $ \v ->+ v >>= \case+ VSeq n m -> go0 f z (enumerateSeqMap n m)+ VWord _n wv -> go0 f z . map (pure . VBit) =<< (enumerateWordValue sym =<< wv)+ _ -> panic "Cryptol.Eval.Generic.foldlV" ["Expected finite sequence"]+ where+ go0 _f a [] = a+ go0 f a bs =+ do f' <- fromVFun <$> f+ go1 f' a bs++ go1 _f a [] = a+ go1 f a (b:bs) =+ do f' <- fromVFun <$> (f a)+ go1 f (f' b) bs++foldl'V :: Backend sym => sym -> GenValue sym+foldl'V sym =+ ilam $ \_n ->+ tlam $ \_a ->+ tlam $ \_b ->+ lam $ \f -> pure $+ lam $ \z -> pure $+ lam $ \v ->+ v >>= \case+ VSeq n m -> go0 f z (enumerateSeqMap n m)+ VWord _n wv -> go0 f z . map (pure . VBit) =<< (enumerateWordValue sym =<< wv)+ _ -> panic "Cryptol.Eval.Generic.foldlV" ["Expected finite sequence"]+ where+ go0 _f a [] = a+ go0 f a bs =+ do f' <- fromVFun <$> f+ a' <- sDelay sym Nothing a+ forceValue =<< a'+ go1 f' a' bs++ go1 _f a [] = a+ go1 f a (b:bs) =+ do f' <- fromVFun <$> (f a)+ a' <- sDelay sym Nothing (f' b)+ forceValue =<< a'+ go1 f a' bs+++-- Random Values ---------------------------------------------------------------++{-# SPECIALIZE randomV ::+ Concrete -> TValue -> Integer -> SEval Concrete (GenValue Concrete)+ #-}+-- | Produce a random value with the given seed. If we do not support+-- making values of the given type, return zero of that type.+-- TODO: do better than returning zero+randomV :: Backend sym => sym -> TValue -> Integer -> SEval sym (GenValue sym)+randomV sym ty seed =+ case randomValue sym ty of+ Nothing -> zeroV sym ty+ Just gen ->+ -- unpack the seed into four Word64s+ let mask64 = 0xFFFFFFFFFFFFFFFF+ unpack s = fromInteger (s .&. mask64) : unpack (s `shiftR` 64)+ [a, b, c, d] = take 4 (unpack seed)+ in fst $ gen 100 $ seedTFGen (a, b, c, d)+ -------------------------------------------------------------------------------- -- Experimental parallel primitives @@ -1940,7 +2022,12 @@ SeqMap sym -> SEval sym (SeqMap sym) sparkParMap sym f n m =- finiteSeqMap sym <$> mapM (sSpark sym . f) (enumerateSeqMap n m)+ finiteSeqMap sym <$> mapM (sSpark sym . g) (enumerateSeqMap n m)+ where+ g x =+ do z <- sDelay sym Nothing (f x)+ forceValue =<< z+ z -------------------------------------------------------------------------------- -- Floating Point Operations
− src/Cryptol/Eval/Monad.hs
@@ -1,272 +0,0 @@--- |--- Module : Cryptol.Eval.Monad--- Copyright : (c) 2013-2016 Galois, Inc.--- License : BSD3--- Maintainer : cryptol@galois.com--- Stability : provisional--- Portability : portable--{-# LANGUAGE Safe #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE OverloadedStrings #-}--module Cryptol.Eval.Monad-( -- * Evaluation monad- Eval(..)-, runEval-, EvalOpts(..)-, getEvalOpts-, PPOpts(..)-, PPFloatFormat(..)-, PPFloatExp(..)-, defaultPPOpts-, io-, delayFill-, ready-, blackhole-, evalSpark- -- * Error reporting-, Unsupported(..)-, EvalError(..)-, evalPanic-, wordTooWide-, typeCannotBeDemoted-) where--import Control.Concurrent.Async-import Control.DeepSeq-import Control.Monad-import qualified Control.Monad.Fail as Fail-import Control.Monad.Fix-import Control.Monad.IO.Class-import Data.IORef-import Data.Typeable (Typeable)-import qualified Control.Exception as X---import Cryptol.Utils.Panic-import Cryptol.Utils.PP-import Cryptol.Utils.Logger(Logger)-import Cryptol.TypeCheck.AST(Type,Name)---- | A computation that returns an already-evaluated value.-ready :: a -> Eval a-ready a = Ready a---- | How to pretty print things when evaluating-data PPOpts = PPOpts- { useAscii :: Bool- , useBase :: Int- , useInfLength :: Int- , useFPBase :: Int- , useFPFormat :: PPFloatFormat- }--data PPFloatFormat =- FloatFixed Int PPFloatExp -- ^ Use this many significant digis- | FloatFrac Int -- ^ Show this many digits after floating point- | FloatFree PPFloatExp -- ^ Use the correct number of digits--data PPFloatExp = ForceExponent -- ^ Always show an exponent- | AutoExponent -- ^ Only show exponent when needed---defaultPPOpts :: PPOpts-defaultPPOpts = PPOpts { useAscii = False, useBase = 10, useInfLength = 5- , useFPBase = 16- , useFPFormat = FloatFree AutoExponent- }----- | Some options for evalutaion-data EvalOpts = EvalOpts- { evalLogger :: Logger -- ^ Where to print stuff (e.g., for @trace@)- , evalPPOpts :: PPOpts -- ^ How to pretty print things.- }----- | The monad for Cryptol evaluation.-data Eval a- = Ready !a- | Thunk !(EvalOpts -> IO a)--data ThunkState a- = Unforced -- ^ This thunk has not yet been forced- | BlackHole -- ^ This thunk is currently being evaluated- | Forced !(Either EvalError a)- -- ^ This thunk has previously been forced,- -- and has the given value, or evaluation resulted in an error.----- | Access the evaluation options.-getEvalOpts :: Eval EvalOpts-getEvalOpts = Thunk pure---{-# INLINE delayFill #-}---- | Delay the given evaluation computation, returning a thunk--- which will run the computation when forced. Run the 'retry'--- computation instead if the resulting thunk is forced during--- its own evaluation.-delayFill ::- Eval a {- ^ Computation to delay -} ->- Eval a {- ^ Backup computation to run if a tight loop is detected -} ->- Eval (Eval a)-delayFill (Ready x) _ = Ready (Ready x)-delayFill (Thunk x) retry = Thunk $ \opts -> do- r <- newIORef Unforced- return $ unDelay retry r (x opts)----- | Begin executing the given operation in a separate thread,--- returning a thunk which will await the completion of--- the computation when forced.-evalSpark ::- Eval a ->- Eval (Eval a)-evalSpark (Ready x) = Ready (Ready x)-evalSpark (Thunk x) = Thunk $ \opts ->- do a <- async (x opts)- return (Thunk $ \_ -> wait a)----- | Produce a thunk value which can be filled with its associated computation--- after the fact. A preallocated thunk is returned, along with an operation to--- fill the thunk with the associated computation.--- This is used to implement recursive declaration groups.-blackhole ::- String {- ^ A name to associate with this thunk. -} ->- Eval (Eval a, Eval a -> Eval ())-blackhole msg = do- r <- io $ newIORef (fail msg)- let get = join (io $ readIORef r)- let set = io . writeIORef r- return (get, set)--unDelay :: Eval a -> IORef (ThunkState a) -> IO a -> Eval a-unDelay retry r x = do- rval <- io $ readIORef r- case rval of- Forced val -> io (toVal val)- BlackHole ->- retry- Unforced -> io $ do- writeIORef r BlackHole- val <- X.try x- writeIORef r (Forced val)- toVal val-- where- toVal mbV = case mbV of- Right a -> pure a- Left e -> X.throwIO e---- | Execute the given evaluation action.-runEval :: EvalOpts -> Eval a -> IO a-runEval _ (Ready a) = return a-runEval opts (Thunk x) = x opts--{-# INLINE evalBind #-}-evalBind :: Eval a -> (a -> Eval b) -> Eval b-evalBind (Ready a) f = f a-evalBind (Thunk x) f = Thunk $ \opts -> x opts >>= runEval opts . f--instance Functor Eval where- fmap f (Ready x) = Ready (f x)- fmap f (Thunk m) = Thunk $ \opts -> f <$> m opts- {-# INLINE fmap #-}--instance Applicative Eval where- pure = return- (<*>) = ap- {-# INLINE pure #-}- {-# INLINE (<*>) #-}--instance Monad Eval where- return = Ready- (>>=) = evalBind- {-# INLINE return #-}- {-# INLINE (>>=) #-}--instance Fail.MonadFail Eval where- fail x = Thunk (\_ -> fail x)--instance MonadIO Eval where- liftIO = io--instance NFData a => NFData (Eval a) where- rnf (Ready a) = rnf a- rnf (Thunk _) = ()--instance MonadFix Eval where- mfix f = Thunk $ \opts -> mfix (\x -> runEval opts (f x))---- | Lift an 'IO' computation into the 'Eval' monad.-io :: IO a -> Eval a-io m = Thunk (\_ -> m)-{-# INLINE io #-}----- Errors -------------------------------------------------------------------------- | Panic from an @Eval@ context.-evalPanic :: HasCallStack => String -> [String] -> a-evalPanic cxt = panic ("[Eval] " ++ cxt)----- | Data type describing errors that can occur during evaluation.-data EvalError- = InvalidIndex (Maybe Integer) -- ^ Out-of-bounds index- | TypeCannotBeDemoted Type -- ^ Non-numeric type passed to @number@ function- | DivideByZero -- ^ Division or modulus by 0- | NegativeExponent -- ^ Exponentiation by negative integer- | LogNegative -- ^ Logarithm of a negative integer- | WordTooWide Integer -- ^ Bitvector too large- | UserError String -- ^ Call to the Cryptol @error@ primitive- | LoopError String -- ^ Detectable nontermination- | NoPrim Name -- ^ Primitive with no implementation- | BadRoundingMode Integer -- ^ Invalid rounding mode- | BadValue String -- ^ Value outside the domain of a partial function.- deriving (Typeable,Show)--instance PP EvalError where- ppPrec _ e = case e of- InvalidIndex (Just i) -> text "invalid sequence index:" <+> integer i- InvalidIndex Nothing -> text "invalid sequence index"- TypeCannotBeDemoted t -> text "type cannot be demoted:" <+> pp t- DivideByZero -> text "division by 0"- NegativeExponent -> text "negative exponent"- LogNegative -> text "logarithm of negative"- WordTooWide w ->- text "word too wide for memory:" <+> integer w <+> text "bits"- UserError x -> text "Run-time error:" <+> text x- LoopError x -> text "<<loop>>" <+> text x- BadRoundingMode r -> "invalid rounding mode" <+> integer r- BadValue x -> "invalid input for" <+> backticks (text x)- NoPrim x -> text "unimplemented primitive:" <+> pp x--instance X.Exception EvalError---data Unsupported- = UnsupportedSymbolicOp String -- ^ Operation cannot be supported in the symbolic simulator- deriving (Typeable,Show)--instance PP Unsupported where- ppPrec _ e = case e of- UnsupportedSymbolicOp nm -> text "operation can not be supported on symbolic values:" <+> text nm--instance X.Exception Unsupported----- | For things like @`(inf)@ or @`(0-1)@.-typeCannotBeDemoted :: Type -> a-typeCannotBeDemoted t = X.throw (TypeCannotBeDemoted t)---- | For when we know that a word is too wide and will exceed gmp's--- limits (though words approaching this size will probably cause the--- system to crash anyway due to lack of memory).-wordTooWide :: Integer -> a-wordTooWide w = X.throw (WordTooWide w)
src/Cryptol/Eval/Reference.lhs view
@@ -1,1650 +1,1695 @@ > -- | > -- Module : Cryptol.Eval.Reference > -- Description : The reference implementation of the Cryptol evaluation semantics.-> -- Copyright : (c) 2013-2016 Galois, Inc.-> -- License : BSD3-> -- Maintainer : cryptol@galois.com-> -- Stability : provisional-> -- Portability : portable->-> {-# LANGUAGE PatternGuards #-}-> {-# LANGUAGE BlockArguments #-}->-> module Cryptol.Eval.Reference-> ( Value(..)-> , evaluate-> , evalExpr-> , evalDeclGroup-> , ppValue-> ) where->-> import Control.Applicative (liftA2)-> import Data.Bits-> import Data.Ratio((%))-> import Data.List-> (genericDrop, genericIndex, genericLength, genericReplicate, genericSplitAt,-> genericTake, sortBy)-> import Data.Ord (comparing)-> import Data.Map (Map)-> import qualified Data.Map as Map-> import qualified Data.Text as T (pack)-> import LibBF (BigFloat)-> import qualified LibBF as FP->-> import Cryptol.ModuleSystem.Name (asPrim)-> import Cryptol.TypeCheck.Solver.InfNat (Nat'(..), nAdd, nMin, nMul)-> import Cryptol.TypeCheck.AST-> import Cryptol.Eval.Monad (EvalError(..), PPOpts(..))-> import Cryptol.Eval.Type (TValue(..), isTBit, evalValType, evalNumType, tvSeq)-> import Cryptol.Eval.Concrete (mkBv, ppBV, lg2)-> import Cryptol.Eval.Concrete.FloatHelpers (BF(..))-> import qualified Cryptol.Eval.Concrete.FloatHelpers as FP-> import Cryptol.Utils.Ident (Ident,PrimIdent, prelPrim, floatPrim)-> import Cryptol.Utils.Panic (panic)-> import Cryptol.Utils.PP-> import Cryptol.Utils.RecordMap->-> import qualified Cryptol.ModuleSystem as M-> import qualified Cryptol.ModuleSystem.Env as M (loadedModules)--Overview-========--This file describes the semantics of the explicitly-typed Cryptol-language (i.e., terms after type checking). Issues related to type-inference, type functions, and type constraints are beyond the scope-of this document.--Cryptol Types----------------Cryptol types come in two kinds: numeric types (kind `#`) and value-types (kind `*`). While value types are inhabited by well-typed-Cryptol expressions, numeric types are only used as parameters to-other types; they have no inhabitants. In this implementation we-represent numeric types as values of the Haskell type `Nat'` of-natural numbers with infinity; value types are represented as values-of type `TValue`.--The value types of Cryptol, along with their Haskell representations,-are as follows:--| Cryptol type | Description | `TValue` representation |-|:------------------|:------------------|:----------------------------|-| `Bit` | booleans | `TVBit` |-| `Integer` | integers | `TVInteger` |-| `Z n` | integers modulo n | `TVIntMod n` |-| `Rational` | rationals | `TVRational` |-| `Float e p` | floating point | `TVFloat` |-| `Array` | arrays | `TVArray` |-| `[n]a` | finite lists | `TVSeq n a` |-| `[inf]a` | infinite lists | `TVStream a` |-| `(a, b, c)` | tuples | `TVTuple [a,b,c]` |-| `{x:a, y:b, z:c}` | records | `TVRec [(x,a),(y,b),(z,c)]` |-| `a -> b` | functions | `TVFun a b` |--We model each Cryptol value type `t` as a complete partial order (cpo)-*M*(`t`). To each Cryptol expression `e : t` we assign a meaning-*M*(`e`) in *M*(`t`); in particular, recursive Cryptol programs of-type `t` are modeled as least fixed points in *M*(`t`). In other words,-this is a domain-theoretic denotational semantics.--Evaluating a Cryptol expression of base type (one of: `Bit`, `Integer`,-`Z n`, or `Rational`) may result in:--- a defined value (e.g., `True` or `False`)--- a run-time error, or--- non-termination.--Accordingly, *M*(`Bit`) is a flat cpo with values for `True`,-`False`, run-time errors of type `EvalError`, and $\bot$; we-represent it with the Haskell type `Either EvalError Bool`.--Similarly, *M*(`Integer`) is a flat cpo with values for integers,-run-time errors, and $\bot$; we represent it with the Haskell type-`Either EvalError Integer`.--The cpos for lists, tuples, and records are cartesian products. The-cpo ordering is pointwise, and the bottom element $\bot$ is the-list/tuple/record whose elements are all $\bot$. Trivial types `[0]t`,-`()` and `{}` denote single-element cpos where the unique value-`[]`/`()`/`{}` *is* the bottom element $\bot$. *M*(`a -> b`) is the-continuous function space *M*(`a`) $\to$ *M*(`b`).--Type schemas of the form `{a1 ... an} (p1 ... pk) => t` classify-polymorphic values in Cryptol. These are represented with the Haskell-type `Schema`. The meaning of a schema is cpo whose elements are-functions: For each valid instantiation `t1 ... tn` of the type-parameters `a1 ... an` that satisfies the constraints `p1 ... pk`, the-function returns a value in *M*(`t[t1/a1 ... tn/an]`).--Values---------The Haskell code in this module defines the semantics of typed Cryptol-terms by providing an evaluator to an appropriate `Value` type.--> -- | Value type for the reference evaluator.-> data Value-> = VBit (Either EvalError Bool) -- ^ @ Bit @ booleans-> | VInteger (Either EvalError Integer) -- ^ @ Integer @ or @Z n@ integers-> | VRational (Either EvalError Rational) -- ^ @ Rational @ rationals-> | VFloat (Either EvalError BF) -- ^ Floating point numbers-> | VList Nat' [Value] -- ^ @ [n]a @ finite or infinite lists-> | VTuple [Value] -- ^ @ ( .. ) @ tuples-> | VRecord [(Ident, Value)] -- ^ @ { .. } @ records-> | VFun (Value -> Value) -- ^ functions-> | VPoly (TValue -> Value) -- ^ polymorphic values (kind *)-> | VNumPoly (Nat' -> Value) -- ^ polymorphic values (kind #)--Invariant: Undefinedness and run-time exceptions are only allowed-inside the argument of a `VBit`, `VInteger` or `VRational` constructor.-All other `Value` and list constructors should evaluate without error. For-example, a non-terminating computation at type `(Bit,Bit)` must be-represented as `VTuple [VBit undefined, VBit undefined]`, and not-simply as `undefined`. Similarly, an expression like `1/0:[2]` that-raises a run-time error must be encoded as `VList (Nat 2) [VBit (Left-e), VBit (Left e)]` where `e = DivideByZero`.--Copy Functions-----------------Functions `copyBySchema` and `copyByTValue` make a copy of the given-value, building the spine based only on the type without forcing the-value argument. This ensures that undefinedness appears inside `VBit`-and `VInteger` values only, and never on any constructors of the-`Value` type. In turn, this gives the appropriate semantics to-recursive definitions: The bottom value for a compound type is equal-to a value of the same type where every individual bit is bottom.--For each Cryptol type `t`, the cpo *M*(`t`) can be represented as a-subset of values of type `Value` that satisfy the datatype invariant.-This subset consists precisely of the output range of `copyByTValue-t`. Similarly, the range of output values of `copyBySchema` yields the-cpo that represents any given schema.--> copyBySchema :: Env -> Schema -> Value -> Value-> copyBySchema env0 (Forall params _props ty) = go params env0-> where-> go :: [TParam] -> Env -> Value -> Value-> go [] env v = copyByTValue (evalValType (envTypes env) ty) v-> go (p : ps) env v =-> case v of-> VPoly f -> VPoly $ \t -> go ps (bindType (tpVar p) (Right t) env) (f t)-> VNumPoly f -> VNumPoly $ \n -> go ps (bindType (tpVar p) (Left n) env) (f n)-> _ -> evalPanic "copyBySchema" ["Expected polymorphic value"]->-> copyByTValue :: TValue -> Value -> Value-> copyByTValue = go-> where-> go :: TValue -> Value -> Value-> go ty val =-> case ty of-> TVBit -> VBit (fromVBit val)-> TVInteger -> VInteger (fromVInteger val)-> TVIntMod _ -> VInteger (fromVInteger val)-> TVRational -> VRational (fromVRational val)-> TVFloat _ _ -> VFloat (fromVFloat' val)-> TVArray{} -> evalPanic "copyByTValue" ["Unsupported Array type"]-> TVSeq w ety -> VList (Nat w) (map (go ety) (copyList w (fromVList val)))-> TVStream ety -> VList Inf (map (go ety) (copyStream (fromVList val)))-> TVTuple etys -> VTuple (zipWith go etys (copyList (genericLength etys) (fromVTuple val)))-> TVRec fields -> VRecord [ (f, go fty (lookupRecord f val)) | (f, fty) <- canonicalFields fields ]-> TVFun _ bty -> VFun (\v -> go bty (fromVFun val v))-> TVAbstract {} -> val->-> copyStream :: [a] -> [a]-> copyStream xs = head xs : copyStream (tail xs)->-> copyList :: Integer -> [a] -> [a]-> copyList 0 _ = []-> copyList n xs = head xs : copyList (n - 1) (tail xs)--Operations on Values-----------------------> -- | Destructor for @VBit@.-> fromVBit :: Value -> Either EvalError Bool-> fromVBit (VBit b) = b-> fromVBit _ = evalPanic "fromVBit" ["Expected a bit"]->-> -- | Destructor for @VInteger@.-> fromVInteger :: Value -> Either EvalError Integer-> fromVInteger (VInteger i) = i-> fromVInteger _ = evalPanic "fromVInteger" ["Expected an integer"]->-> -- | Destructor for @VRational@.-> fromVRational :: Value -> Either EvalError Rational-> fromVRational (VRational i) = i-> fromVRational _ = evalPanic "fromVRational" ["Expected a rational"]->-> fromVFloat :: Value -> Either EvalError BigFloat-> fromVFloat = fmap bfValue . fromVFloat'--> fromVFloat' :: Value -> Either EvalError BF-> fromVFloat' v =-> case v of-> VFloat f -> f-> _ -> evalPanic "fromVFloat" [ "Expected a floating point value." ]----->-> -- | Destructor for @VList@.-> fromVList :: Value -> [Value]-> fromVList (VList _ vs) = vs-> fromVList _ = evalPanic "fromVList" ["Expected a list"]->-> -- | Destructor for @VTuple@.-> fromVTuple :: Value -> [Value]-> fromVTuple (VTuple vs) = vs-> fromVTuple _ = evalPanic "fromVTuple" ["Expected a tuple"]->-> -- | Destructor for @VRecord@.-> fromVRecord :: Value -> [(Ident, Value)]-> fromVRecord (VRecord fs) = fs-> fromVRecord _ = evalPanic "fromVRecord" ["Expected a record"]->-> -- | Destructor for @VFun@.-> fromVFun :: Value -> (Value -> Value)-> fromVFun (VFun f) = f-> fromVFun _ = evalPanic "fromVFun" ["Expected a function"]->-> -- | Destructor for @VPoly@.-> fromVPoly :: Value -> (TValue -> Value)-> fromVPoly (VPoly f) = f-> fromVPoly _ = evalPanic "fromVPoly" ["Expected a polymorphic value"]->-> -- | Destructor for @VNumPoly@.-> fromVNumPoly :: Value -> (Nat' -> Value)-> fromVNumPoly (VNumPoly f) = f-> fromVNumPoly _ = evalPanic "fromVNumPoly" ["Expected a polymorphic value"]->-> -- | Look up a field in a record.-> lookupRecord :: Ident -> Value -> Value-> lookupRecord f v =-> case lookup f (fromVRecord v) of-> Just val -> val-> Nothing -> evalPanic "lookupRecord" ["Malformed record"]->-> -- | Polymorphic function values that expect a finite numeric type.-> vFinPoly :: (Integer -> Value) -> Value-> vFinPoly f = VNumPoly g-> where-> g (Nat n) = f n-> g Inf = evalPanic "vFinPoly" ["Expected finite numeric type"]---Environments---------------An evaluation environment keeps track of the values of term variables-and type variables that are in scope at any point.--> data Env = Env-> { envVars :: !(Map Name Value)-> , envTypes :: !(Map TVar (Either Nat' TValue))-> }->-> instance Semigroup Env where-> l <> r = Env-> { envVars = Map.union (envVars l) (envVars r)-> , envTypes = Map.union (envTypes l) (envTypes r)-> }->-> instance Monoid Env where-> mempty = Env-> { envVars = Map.empty-> , envTypes = Map.empty-> }-> mappend l r = l <> r->-> -- | Bind a variable in the evaluation environment.-> bindVar :: (Name, Value) -> Env -> Env-> bindVar (n, val) env = env { envVars = Map.insert n val (envVars env) }->-> -- | Bind a type variable of kind # or *.-> bindType :: TVar -> Either Nat' TValue -> Env -> Env-> bindType p ty env = env { envTypes = Map.insert p ty (envTypes env) }---Evaluation-==========--The meaning *M*(`expr`) of a Cryptol expression `expr` is defined by-recursion over its structure. For an expression that contains free-variables, the meaning also depends on the environment `env`, which-assigns values to those variables.--> evalExpr :: Env -- ^ Evaluation environment-> -> Expr -- ^ Expression to evaluate-> -> Value-> evalExpr env expr =-> case expr of->-> EList es _ty -> VList (Nat (genericLength es)) [ evalExpr env e | e <- es ]-> ETuple es -> VTuple [ evalExpr env e | e <- es ]-> ERec fields -> VRecord [ (f, evalExpr env e) | (f, e) <- canonicalFields fields ]-> ESel e sel -> evalSel (evalExpr env e) sel-> ESet e sel v -> evalSet (evalExpr env e) sel (evalExpr env v)->-> EIf c t f ->-> condValue (fromVBit (evalExpr env c)) (evalExpr env t) (evalExpr env f)->-> EComp _n _ty e branches ->-> evalComp env e branches->-> EVar n ->-> case Map.lookup n (envVars env) of-> Just val -> val-> Nothing -> evalPanic "evalExpr" ["var `" ++ show (pp n) ++ "` is not defined" ]->-> ETAbs tv b ->-> case tpKind tv of-> KType -> VPoly $ \ty -> evalExpr (bindType (tpVar tv) (Right ty) env) b-> KNum -> VNumPoly $ \n -> evalExpr (bindType (tpVar tv) (Left n) env) b-> k -> evalPanic "evalExpr" ["Invalid kind on type abstraction", show k]->-> ETApp e ty ->-> case evalExpr env e of-> VPoly f -> f $! (evalValType (envTypes env) ty)-> VNumPoly f -> f $! (evalNumType (envTypes env) ty)-> _ -> evalPanic "evalExpr" ["Expected a polymorphic value"]->-> EApp e1 e2 -> fromVFun (evalExpr env e1) (evalExpr env e2)-> EAbs n _ty b -> VFun (\v -> evalExpr (bindVar (n, v) env) b)-> EProofAbs _ e -> evalExpr env e-> EProofApp e -> evalExpr env e-> EWhere e dgs -> evalExpr (foldl evalDeclGroup env dgs) e---Selectors------------Apply the the given selector form to the given value.--> evalSel :: Value -> Selector -> Value-> evalSel val sel =-> case sel of-> TupleSel n _ -> tupleSel n val-> RecordSel n _ -> recordSel n val-> ListSel n _ -> listSel n val-> where-> tupleSel n v =-> case v of-> VTuple vs -> vs !! n-> _ -> evalPanic "evalSel"-> ["Unexpected value in tuple selection."]-> recordSel n v =-> case v of-> VRecord _ -> lookupRecord n v-> _ -> evalPanic "evalSel"-> ["Unexpected value in record selection."]-> listSel n v =-> case v of-> VList _ vs -> vs !! n-> _ -> evalPanic "evalSel"-> ["Unexpected value in list selection."]---Update the given value using the given selector and new value.--> evalSet :: Value -> Selector -> Value -> Value-> evalSet val sel fval =-> case sel of-> TupleSel n _ -> updTupleAt n-> RecordSel n _ -> updRecAt n-> ListSel n _ -> updSeqAt n-> where-> updTupleAt n =-> case val of-> VTuple vs | (as,_:bs) <- splitAt n vs ->-> VTuple (as ++ fval : bs)-> _ -> bad "Invalid tuple upldate."->-> updRecAt n =-> case val of-> VRecord vs | (as, (i,_) : bs) <- break ((n==) . fst) vs ->-> VRecord (as ++ (i,fval) : bs)-> _ -> bad "Invalid record update."->-> updSeqAt n =-> case val of-> VList i vs | (as, _ : bs) <- splitAt n vs ->-> VList i (as ++ fval : bs)-> _ -> bad "Invalid sequence update."->-> bad msg = evalPanic "evalSet" [msg]----Conditionals---------------We evaluate conditionals on larger types by pushing the conditionals-down to the individual bits.--> condValue :: Either EvalError Bool -> Value -> Value -> Value-> condValue c l r =-> case l of-> VBit b -> VBit (condBit c b (fromVBit r))-> VInteger i -> VInteger (condBit c i (fromVInteger r))-> VRational x -> VRational (condBit c x (fromVRational r))-> VFloat x -> VFloat (condBit c x (fromVFloat' r))-> VList n vs -> VList n (zipWith (condValue c) vs (fromVList r))-> VTuple vs -> VTuple (zipWith (condValue c) vs (fromVTuple r))-> VRecord fs -> VRecord [ (f, condValue c v (lookupRecord f r)) | (f, v) <- fs ]-> VFun f -> VFun (\v -> condValue c (f v) (fromVFun r v))-> VPoly f -> VPoly (\t -> condValue c (f t) (fromVPoly r t))-> VNumPoly f -> VNumPoly (\n -> condValue c (f n) (fromVNumPoly r n))--Conditionals are explicitly lazy: Run-time errors in an untaken branch-are ignored.--> condBit :: Either e Bool -> Either e a -> Either e a -> Either e a-> condBit (Left e) _ _ = Left e-> condBit (Right b) x y = if b then x else y---List Comprehensions----------------------Cryptol list comprehensions consist of one or more parallel branches;-each branch has one or more matches that bind values to variables.--The result of evaluating a match in an initial environment is a list-of extended environments. Each new environment binds the same single-variable to a different element of the match's list.--> evalMatch :: Env -> Match -> [Env]-> evalMatch env m =-> case m of-> Let d ->-> [ bindVar (evalDecl env d) env ]-> From n _l _ty expr ->-> [ bindVar (n, v) env | v <- fromVList (evalExpr env expr) ]--> lenMatch :: Env -> Match -> Nat'-> lenMatch env m =-> case m of-> Let _ -> Nat 1-> From _ len _ _ -> evalNumType (envTypes env) len--The result of of evaluating a branch in an initial environment is a-list of extended environments, each of which extends the initial-environment with the same set of new variables. The length of the list-is equal to the product of the lengths of the lists in the matches.--> evalBranch :: Env -> [Match] -> [Env]-> evalBranch env [] = [env]-> evalBranch env (match : matches) =-> [ env'' | env' <- evalMatch env match-> , env'' <- evalBranch env' matches ]--> lenBranch :: Env -> [Match] -> Nat'-> lenBranch _env [] = Nat 1-> lenBranch env (match : matches) =-> nMul (lenMatch env match) (lenBranch env matches)--The head expression of the comprehension can refer to any variable-bound in any of the parallel branches. So to evaluate the-comprehension, we zip and merge together the lists of extended-environments from each branch. The head expression is then evaluated-separately in each merged environment. The length of the resulting-list is equal to the minimum length over all parallel branches.--> evalComp :: Env -- ^ Starting evaluation environment-> -> Expr -- ^ Head expression of the comprehension-> -> [[Match]] -- ^ List of parallel comprehension branches-> -> Value-> evalComp env expr branches = VList len [ evalExpr e expr | e <- envs ]-> where-> -- Generate a new environment for each iteration of each-> -- parallel branch.-> benvs :: [[Env]]-> benvs = map (evalBranch env) branches->-> -- Zip together the lists of environments from each branch,-> -- producing a list of merged environments. Longer branches get-> -- truncated to the length of the shortest branch.-> envs :: [Env]-> envs = foldr1 (zipWith mappend) benvs->-> len :: Nat'-> len = foldr1 nMin (map (lenBranch env) branches)---Declarations---------------Function `evalDeclGroup` extends the given evaluation environment with-the result of evaluating the given declaration group. In the case of a-recursive declaration group, we tie the recursive knot by evaluating-each declaration in the extended environment `env'` that includes all-the new bindings.--> evalDeclGroup :: Env -> DeclGroup -> Env-> evalDeclGroup env dg = do-> case dg of-> NonRecursive d ->-> bindVar (evalDecl env d) env-> Recursive ds ->-> let env' = foldr bindVar env bindings-> bindings = map (evalDeclRecursive env') ds-> in env'--To evaluate a declaration in a non-recursive context, we need only-evaluate the expression on the right-hand side or look up the-appropriate primitive.--> evalDecl :: Env -> Decl -> (Name, Value)-> evalDecl env d =-> case dDefinition d of-> DPrim -> (dName d, evalPrim (dName d))-> DExpr e -> (dName d, evalExpr env e)--To evaluate a declaration in a recursive context, we must perform a-type-directed copy to build the spine of the value. This ensures that-the definedness invariant for type `Value` will be maintained.--> evalDeclRecursive :: Env -> Decl -> (Name, Value)-> evalDeclRecursive env d =-> case dDefinition d of-> DPrim -> (dName d, evalPrim (dName d))-> DExpr e -> (dName d, copyBySchema env (dSignature d) (evalExpr env e))---Primitives-==========--To evaluate a primitive, we look up its implementation by name in a table.--> evalPrim :: Name -> Value-> evalPrim n-> | Just i <- asPrim n, Just v <- Map.lookup i primTable = v-> | otherwise = evalPanic "evalPrim" ["Unimplemented primitive", show n]--Cryptol primitives fall into several groups, mostly delenieated-by corresponding typeclasses--* Literals: `True`, `False`, `number`, `ratio`--* Zero: zero--* Logic: `&&`, `||`, `^`, `complement`--* Ring: `+`, `-`, `*`, `negate`, `fromInteger`--* Integral: `/`, `%`, `^^`, `toInteger`--* Bitvector: `/$` `%$`, `lg2`, `<=$`--* Comparison: `<`, `>`, `<=`, `>=`, `==`, `!=`--* Sequences: `#`, `join`, `split`, `splitAt`, `reverse`, `transpose`--* Shifting: `<<`, `>>`, `<<<`, `>>>`--* Indexing: `@`, `@@`, `!`, `!!`, `update`, `updateEnd`--* Enumerations: `fromTo`, `fromThenTo`, `infFrom`, `infFromThen`--* Polynomials: `pmult`, `pdiv`, `pmod`--* Miscellaneous: `error`, `random`, `trace`--> primTable :: Map PrimIdent Value-> primTable = Map.unions-> [ cryptolPrimTable-> , floatPrimTable-> ]--> cryptolPrimTable :: Map PrimIdent Value-> cryptolPrimTable = Map.fromList $ map (\(n, v) -> (prelPrim (T.pack n), v))->-> -- Literals-> [ ("True" , VBit (Right True))-> , ("False" , VBit (Right False))-> , ("number" , vFinPoly $ \val ->-> VPoly $ \a ->-> literal val a)-> , ("fraction" , vFinPoly \top ->-> vFinPoly \bot ->-> vFinPoly \rnd ->-> VPoly \a -> fraction top bot rnd a)-> -- Zero-> , ("zero" , VPoly zero)->-> -- Logic (bitwise)-> , ("&&" , binary (logicBinary (&&)))-> , ("||" , binary (logicBinary (||)))-> , ("^" , binary (logicBinary (/=)))-> , ("complement" , unary (logicUnary not))->-> -- Ring-> , ("+" , binary (ringBinary-> (\x y -> Right (x + y))-> (\x y -> Right (x + y))-> (fpBin FP.bfAdd fpImplicitRound)-> ))-> , ("-" , binary (ringBinary-> (\x y -> Right (x - y))-> (\x y -> Right (x - y))-> (fpBin FP.bfSub fpImplicitRound)-> ))-> , ("*" , binary ringMul)-> , ("negate" , unary (ringUnary (\x -> Right (- x))-> (\x -> Right (- x))-> (\_ _ x -> Right (FP.bfNeg x))))-> , ("fromInteger", VPoly $ \a ->-> VFun $ \x ->-> ringNullary (fromVInteger x)-> (fromInteger <$> fromVInteger x)-> (\e p -> fpFromInteger e p <$> fromVInteger x)-> a)->-> -- Integral-> , ("toInteger" , VPoly $ \a ->-> VFun $ \x ->-> VInteger $ cryToInteger a x)-> , ("/" , binary (integralBinary divWrap))-> , ("%" , binary (integralBinary modWrap))-> , ("^^" , VPoly $ \aty ->-> VPoly $ \ety ->-> VFun $ \a ->-> VFun $ \e ->-> ringExp aty a (cryToInteger ety e))->-> -- Field-> , ("/." , binary (fieldBinary ratDiv-> (fpBin FP.bfDiv fpImplicitRound)-> ))--> , ("recip" , unary (fieldUnary ratRecip fpRecip))->-> -- Round-> , ("floor" , unary (roundUnary floor-> (FP.floatToInteger "floor" FP.ToNegInf)-> ))-> , ("ceiling" , unary (roundUnary ceiling-> (FP.floatToInteger "ceiling" FP.ToPosInf)-> ))-> , ("trunc" , unary (roundUnary truncate-> (FP.floatToInteger "trunc" FP.ToZero)-> ))-> , ("roundAway", unary (roundUnary roundAwayRat-> (FP.floatToInteger "roundAway" FP.Away)-> ))-> , ("roundToEven", unary (roundUnary round-> (FP.floatToInteger "roundToEven" FP.NearEven)-> ))->-> -- Comparison-> , ("<" , binary (cmpOrder (\o -> o == LT)))-> , (">" , binary (cmpOrder (\o -> o == GT)))-> , ("<=" , binary (cmpOrder (\o -> o /= GT)))-> , (">=" , binary (cmpOrder (\o -> o /= LT)))-> , ("==" , binary (cmpOrder (\o -> o == EQ)))-> , ("!=" , binary (cmpOrder (\o -> o /= EQ)))-> , ("<$" , binary signedLessThan)->-> -- Bitvector-> , ("/$" , vFinPoly $ \n ->-> VFun $ \l ->-> VFun $ \r ->-> vWord n $ appOp2 divWrap (fromSignedVWord l) (fromSignedVWord r))-> , ("%$" , vFinPoly $ \n ->-> VFun $ \l ->-> VFun $ \r ->-> vWord n $ appOp2 modWrap (fromSignedVWord l) (fromSignedVWord r))-> , (">>$" , signedShiftRV)-> , ("lg2" , vFinPoly $ \n ->-> VFun $ \v ->-> vWord n $ appOp1 lg2Wrap (fromVWord v))-> -- Rational-> , ("ratio" , VFun $ \l ->-> VFun $ \r ->-> VRational (appOp2 ratioOp (fromVInteger l) (fromVInteger r)))->-> -- Z n-> , ("fromZ" , vFinPoly $ \n ->-> VFun $ \x ->-> VInteger (flip mod n <$> fromVInteger x))->-> -- Sequences-> , ("#" , VNumPoly $ \front ->-> VNumPoly $ \back ->-> VPoly $ \_elty ->-> VFun $ \l ->-> VFun $ \r ->-> VList (nAdd front back) (fromVList l ++ fromVList r))->-> , ("join" , VNumPoly $ \parts ->-> VNumPoly $ \each ->-> VPoly $ \_a ->-> VFun $ \xss ->-> case each of-> -- special case when the inner sequences are of length 0-> Nat 0 -> VList (Nat 0) []-> _ -> VList (nMul parts each)-> (concat (map fromVList (fromVList xss))))->-> , ("split" , VNumPoly $ \parts ->-> vFinPoly $ \each ->-> VPoly $ \_a ->-> VFun $ \val ->-> VList parts (splitV parts each (fromVList val)))->-> , ("splitAt" , vFinPoly $ \front ->-> VNumPoly $ \back ->-> VPoly $ \_a ->-> VFun $ \v ->-> let (xs, ys) = genericSplitAt front (fromVList v)-> in VTuple [VList (Nat front) xs, VList back ys])->-> , ("reverse" , VNumPoly $ \n ->-> VPoly $ \_a ->-> VFun $ \v ->-> VList n (reverse (fromVList v)))->-> , ("transpose" , VNumPoly $ \rows ->-> VNumPoly $ \cols ->-> VPoly $ \_a ->-> VFun $ \v ->-> VList cols-> (map (VList rows) (transposeV cols (map fromVList (fromVList v)))))->-> -- Shifting:-> , ("<<" , shiftV shiftLV)-> , (">>" , shiftV shiftRV)-> , ("<<<" , rotateV rotateLV)-> , (">>>" , rotateV rotateRV)->-> -- Indexing:-> , ("@" , indexPrimOne indexFront)-> , ("!" , indexPrimOne indexBack)-> , ("update" , updatePrim updateFront)-> , ("updateEnd" , updatePrim updateBack)->-> -- Enumerations-> , ("fromTo" , vFinPoly $ \first ->-> vFinPoly $ \lst ->-> VPoly $ \ty ->-> let f i = literal i ty-> in VList (Nat (1 + lst - first)) (map f [first .. lst]))->-> , ("fromThenTo" , vFinPoly $ \first ->-> vFinPoly $ \next ->-> vFinPoly $ \_lst ->-> VPoly $ \ty ->-> vFinPoly $ \len ->-> let f i = literal i ty-> in VList (Nat len) (map f (genericTake len [first, next ..])))->-> , ("infFrom" , VPoly $ \ty ->-> VFun $ \first ->-> case cryToInteger ty first of-> Left e -> cryError e (TVStream ty)-> Right x -> VList Inf (map f [0 ..])-> where f i = literal (x + i) ty)->-> , ("infFromThen", VPoly $ \ty ->-> VFun $ \first ->-> VFun $ \next ->-> case cryToInteger ty first of-> Left e -> cryError e (TVStream ty)-> Right x ->-> case cryToInteger ty next of-> Left e -> cryError e (TVStream ty)-> Right y -> VList Inf (map f [0 ..])-> where f i = literal (x + diff * i) ty-> diff = y - x)->-> -- Miscellaneous:-> , ("parmap" , VPoly $ \_a ->-> VPoly $ \_b ->-> VNumPoly $ \n ->-> VFun $ \f ->-> VFun $ \xs ->-> -- Note: the reference implementation simply-> -- executes parmap sequentially-> let xs' = map (fromVFun f) (fromVList xs) in-> VList n xs')->-> , ("error" , VPoly $ \a ->-> VNumPoly $ \_ ->-> VFun $ \_s -> cryError (UserError "error") a)-> -- TODO: obtain error string from argument s->-> , ("random" , VPoly $ \a ->-> VFun $ \_seed -> cryError (UserError "random: unimplemented") a)->-> , ("trace" , VNumPoly $ \_n ->-> VPoly $ \_a ->-> VPoly $ \_b ->-> VFun $ \_s ->-> VFun $ \_x ->-> VFun $ \y -> y)-> ]->-->-> unary :: (TValue -> Value -> Value) -> Value-> unary f = VPoly $ \ty -> VFun $ \x -> f ty x->-> binary :: (TValue -> Value -> Value -> Value) -> Value-> binary f = VPoly $ \ty -> VFun $ \x -> VFun $ \y -> f ty x y->-> appOp1 :: (a -> Either EvalError b) -> Either EvalError a -> Either EvalError b-> appOp1 _f (Left e) = Left e-> appOp1 f (Right x) = f x->-> appOp2 :: (a -> b -> Either EvalError c) -> Either EvalError a -> Either EvalError b -> Either EvalError c-> appOp2 _f (Left e) _y = Left e-> appOp2 _f _x (Left e) = Left e-> appOp2 f (Right x) (Right y) = f x y--Word operations------------------Many Cryptol primitives take numeric arguments in the form of-bitvectors. For such operations, any output bit that depends on the-numeric value is strict in *all* bits of the numeric argument. This is-implemented in function `fromVWord`, which converts a value from a-big-endian binary format to an integer. The result is an evaluation-error if any of the input bits contain an evaluation error.--> fromVWord :: Value -> Either EvalError Integer-> fromVWord v = fmap bitsToInteger (mapM fromVBit (fromVList v))->-> -- | Convert a list of booleans in big-endian format to an integer.-> bitsToInteger :: [Bool] -> Integer-> bitsToInteger bs = foldl f 0 bs-> where f x b = if b then 2 * x + 1 else 2 * x--> fromSignedVWord :: Value -> Either EvalError Integer-> fromSignedVWord v = fmap signedBitsToInteger (mapM fromVBit (fromVList v))->-> -- | Convert a list of booleans in signed big-endian format to an integer.-> signedBitsToInteger :: [Bool] -> Integer-> signedBitsToInteger [] = evalPanic "signedBitsToInteger" ["Bitvector has zero length"]-> signedBitsToInteger (b0 : bs) = foldl f (if b0 then -1 else 0) bs-> where f x b = if b then 2 * x + 1 else 2 * x--Function `vWord` converts an integer back to the big-endian bitvector-representation. If an integer-producing function raises a run-time-exception, then the output bitvector will contain the exception in all-bit positions.--> vWord :: Integer -> Either EvalError Integer -> Value-> vWord w e = VList (Nat w) [ VBit (fmap (test i) e) | i <- [w-1, w-2 .. 0] ]-> where test i x = testBit x (fromInteger i)---Errors---------The domain semantics indicate that errors can only exist at the base-types. This function constructs an error representation at any type-where the given error is "pushed down" into the leaf types.--> cryError :: EvalError -> TValue -> Value-> cryError e TVBit = VBit (Left e)-> cryError e TVInteger = VInteger (Left e)-> cryError e TVIntMod{} = VInteger (Left e)-> cryError e TVRational = VRational (Left e)-> cryError e TVFloat{} = VFloat (Left e)-> cryError _ TVArray{} = evalPanic "error" ["Array type not supported in `error`"]-> cryError e (TVSeq n ety) = VList (Nat n) (genericReplicate n (cryError e ety))-> cryError e (TVStream ety) = VList Inf (repeat (cryError e ety))-> cryError e (TVTuple tys) = VTuple (map (cryError e) tys)-> cryError e (TVRec fields) = VRecord [ (f, cryError e fty) | (f, fty) <- canonicalFields fields ]-> cryError e (TVFun _ bty) = VFun (\_ -> cryError e bty)-> cryError _ (TVAbstract{}) = evalPanic "error" ["Abstract type encountered in `error`"]---Zero-------The `Zero` class has a single method `zero` which computes-a zero value for all the built-in types for Cryptol.-For bits, bitvectors and the base numeric types, this-returns the obvious 0 representation. For sequences, records,-and tuples, the zero method operates pointwise the underlying types.-For functions, `zero` returns the constant function that returns-`zero` in the codomain.--> zero :: TValue -> Value-> zero TVBit = VBit (Right False)-> zero TVInteger = VInteger (Right 0)-> zero TVIntMod{} = VInteger (Right 0)-> zero TVRational = VRational (Right 0)-> zero (TVFloat e p) = VFloat (Right (fpToBF e p FP.bfPosZero))-> zero TVArray{} = evalPanic "zero" ["Array type not in `Zero`"]-> zero (TVSeq n ety) = VList (Nat n) (genericReplicate n (zero ety))-> zero (TVStream ety) = VList Inf (repeat (zero ety))-> zero (TVTuple tys) = VTuple (map zero tys)-> zero (TVRec fields) = VRecord [ (f, zero fty) | (f, fty) <- canonicalFields fields ]-> zero (TVFun _ bty) = VFun (\_ -> zero bty)-> zero (TVAbstract{}) = evalPanic "zero" ["Abstract type not in `Zero`"]---Literals-----------Given a literal integer, construct a value of a type that can represent that literal.--> literal :: Integer -> TValue -> Value-> literal i = go-> where-> go TVInteger = VInteger (Right i)-> go TVRational = VRational (Right (fromInteger i))-> go (TVIntMod n)-> | i < n = VInteger (Right i)-> | otherwise = evalPanic "literal" ["Literal out of range for type Z " ++ show n]-> go (TVSeq w a)-> | isTBit a = vWord w (Right i)-> go ty = evalPanic "literal" [show ty ++ " cannot represent literals"]---Given a fraction, construct a value of a type that can represent that literal.-The rounding flag determines the behavior if the literal cannot be represented-exactly: 0 means report and error, other numbers round to the nearest-representable value.--> fraction :: Integer -> Integer -> Integer -> TValue -> Value-> fraction top btm _rnd ty =-> case ty of-> TVRational -> VRational (Right (top % btm))-> TVFloat e p -> VFloat $ Right $ fpToBF e p $ FP.fpCheckStatus val-> where val = FP.bfDiv opts (FP.bfFromInteger top) (FP.bfFromInteger btm)-> opts = FP.fpOpts e p fpImplicitRound-> _ -> evalPanic "fraction" [show ty ++ " cannot represent " ++-> show top ++ "/" ++ show btm]---Logic--------Bitwise logic primitives are defined by recursion over the type-structure. On type `Bit`, we use `fmap` and `liftA2` to make these-operations strict in all arguments. For example, `True || error "foo"`-does not evaluate to `True`, but yields a run-time exception. On other-types, run-time exceptions on input bits only affect the output bits-at the same positions.--> logicUnary :: (Bool -> Bool) -> TValue -> Value -> Value-> logicUnary op = go-> where-> go :: TValue -> Value -> Value-> go ty val =-> case ty of-> TVBit -> VBit (fmap op (fromVBit val))-> TVSeq w ety -> VList (Nat w) (map (go ety) (fromVList val))-> TVStream ety -> VList Inf (map (go ety) (fromVList val))-> TVTuple etys -> VTuple (zipWith go etys (fromVTuple val))-> TVRec fields -> VRecord [ (f, go fty (lookupRecord f val)) | (f, fty) <- canonicalFields fields ]-> TVFun _ bty -> VFun (\v -> go bty (fromVFun val v))-> TVInteger -> evalPanic "logicUnary" ["Integer not in class Logic"]-> TVIntMod _ -> evalPanic "logicUnary" ["Z not in class Logic"]-> TVArray{} -> evalPanic "logicUnary" ["Array not in class Logic"]-> TVRational -> evalPanic "logicUnary" ["Rational not in class Logic"]-> TVFloat{} -> evalPanic "logicUnary" ["Float not in class Logic"]-> TVAbstract{} -> evalPanic "logicUnary" ["Abstract type not in `Logic`"]--> logicBinary :: (Bool -> Bool -> Bool) -> TValue -> Value -> Value -> Value-> logicBinary op = go-> where-> go :: TValue -> Value -> Value -> Value-> go ty l r =-> case ty of-> TVBit -> VBit (liftA2 op (fromVBit l) (fromVBit r))-> TVSeq w ety -> VList (Nat w) (zipWith (go ety) (fromVList l) (fromVList r))-> TVStream ety -> VList Inf (zipWith (go ety) (fromVList l) (fromVList r))-> TVTuple etys -> VTuple (zipWith3 go etys (fromVTuple l) (fromVTuple r))-> TVRec fields -> VRecord [ (f, go fty (lookupRecord f l) (lookupRecord f r))-> | (f, fty) <- canonicalFields fields ]-> TVFun _ bty -> VFun (\v -> go bty (fromVFun l v) (fromVFun r v))-> TVInteger -> evalPanic "logicBinary" ["Integer not in class Logic"]-> TVIntMod _ -> evalPanic "logicBinary" ["Z not in class Logic"]-> TVArray{} -> evalPanic "logicBinary" ["Array not in class Logic"]-> TVRational -> evalPanic "logicBinary" ["Rational not in class Logic"]-> TVFloat{} -> evalPanic "logicBinary" ["Float not in class Logic"]-> TVAbstract{} -> evalPanic "logicBinary" ["Abstract type not in `Logic`"]---Ring Arithmetic------------------Ring primitives may be applied to any type that is made up of-finite bitvectors or one of the numeric base types.-On type `[n]`, arithmetic operators are strict in-all input bits, as indicated by the definition of `fromVWord`. For-example, `[error "foo", True] * 2` does not evaluate to `[True,-False]`, but to `[error "foo", error "foo"]`.--> ringNullary ::-> Either EvalError Integer ->-> Either EvalError Rational ->-> (Integer -> Integer -> Either EvalError BigFloat) ->-> TValue -> Value-> ringNullary i q fl = go-> where-> go :: TValue -> Value-> go ty =-> case ty of-> TVBit ->-> evalPanic "arithNullary" ["Bit not in class Ring"]-> TVInteger ->-> VInteger i-> TVIntMod n ->-> VInteger (flip mod n <$> i)-> TVRational ->-> VRational q-> TVFloat e p ->-> VFloat (fpToBF e p <$> fl e p)-> TVArray{} ->-> evalPanic "arithNullary" ["Array not in class Ring"]-> TVSeq w a-> | isTBit a -> vWord w i-> | otherwise -> VList (Nat w) (genericReplicate w (go a))-> TVStream a ->-> VList Inf (repeat (go a))-> TVFun _ ety ->-> VFun (const (go ety))-> TVTuple tys ->-> VTuple (map go tys)-> TVRec fs ->-> VRecord [ (f, go fty) | (f, fty) <- canonicalFields fs ]-> TVAbstract {} ->-> evalPanic "arithNullary" ["Abstract type not in `Ring`"]--> ringUnary ::-> (Integer -> Either EvalError Integer) ->-> (Rational -> Either EvalError Rational) ->-> (Integer -> Integer -> BigFloat -> Either EvalError BigFloat) ->-> TValue -> Value -> Value-> ringUnary iop qop flop = go-> where-> go :: TValue -> Value -> Value-> go ty val =-> case ty of-> TVBit ->-> evalPanic "arithUnary" ["Bit not in class Ring"]-> TVInteger ->-> VInteger $ appOp1 iop (fromVInteger val)-> TVArray{} ->-> evalPanic "arithUnary" ["Array not in class Ring"]-> TVIntMod n ->-> VInteger $ appOp1 (\i -> flip mod n <$> iop i) (fromVInteger val)-> TVRational ->-> VRational $ appOp1 qop (fromVRational val)-> TVFloat e p ->-> VFloat (fpToBF e p <$> appOp1 (flop e p) (fromVFloat val))-> TVSeq w a-> | isTBit a -> vWord w (iop =<< fromVWord val)-> | otherwise -> VList (Nat w) (map (go a) (fromVList val))-> TVStream a ->-> VList Inf (map (go a) (fromVList val))-> TVFun _ ety ->-> VFun (\x -> go ety (fromVFun val x))-> TVTuple tys ->-> VTuple (zipWith go tys (fromVTuple val))-> TVRec fs ->-> VRecord [ (f, go fty (lookupRecord f val)) | (f, fty) <- canonicalFields fs ]-> TVAbstract {} ->-> evalPanic "arithUnary" ["Abstract type not in `Ring`"]--> ringBinary ::-> (Integer -> Integer -> Either EvalError Integer) ->-> (Rational -> Rational -> Either EvalError Rational) ->-> (Integer -> Integer -> BigFloat -> BigFloat -> Either EvalError BigFloat) ->-> TValue -> Value -> Value -> Value-> ringBinary iop qop flop = go-> where-> go :: TValue -> Value -> Value -> Value-> go ty l r =-> case ty of-> TVBit ->-> evalPanic "arithBinary" ["Bit not in class Ring"]-> TVInteger ->-> VInteger $ appOp2 iop (fromVInteger l) (fromVInteger r)-> TVIntMod n ->-> VInteger $ appOp2 (\i j -> flip mod n <$> iop i j) (fromVInteger l) (fromVInteger r)-> TVRational ->-> VRational $ appOp2 qop (fromVRational l) (fromVRational r)-> TVFloat e p ->-> VFloat $ fpToBF e p <$> appOp2 (flop e p) (fromVFloat l) (fromVFloat r)-> TVArray{} ->-> evalPanic "arithBinary" ["Array not in class Ring"]-> TVSeq w a-> | isTBit a -> vWord w $ appOp2 iop (fromVWord l) (fromVWord r)-> | otherwise -> VList (Nat w) (zipWith (go a) (fromVList l) (fromVList r))-> TVStream a ->-> VList Inf (zipWith (go a) (fromVList l) (fromVList r))-> TVFun _ ety ->-> VFun (\x -> go ety (fromVFun l x) (fromVFun r x))-> TVTuple tys ->-> VTuple (zipWith3 go tys (fromVTuple l) (fromVTuple r))-> TVRec fs ->-> VRecord [ (f, go fty (lookupRecord f l) (lookupRecord f r)) | (f, fty) <- canonicalFields fs ]-> TVAbstract {} ->-> evalPanic "arithBinary" ["Abstract type not in class `Ring`"]---Integral------------> cryToInteger :: TValue -> Value -> Either EvalError Integer-> cryToInteger ty v = case ty of-> TVInteger -> fromVInteger v-> TVSeq _ a | isTBit a -> fromVWord v-> _ -> evalPanic "toInteger" [show ty ++ " is not an integral type"]->-> integralBinary ::-> (Integer -> Integer -> Either EvalError Integer) ->-> TValue -> Value -> Value -> Value-> integralBinary op ty x y = case ty of-> TVInteger ->-> VInteger $ appOp2 op (fromVInteger x) (fromVInteger y)-> TVSeq w a | isTBit a ->-> vWord w $ appOp2 op (fromVWord x) (fromVWord y)->-> _ -> evalPanic "integralBinary" [show ty ++ " is not an integral type"]->-> ringExp :: TValue -> Value -> Either EvalError Integer -> Value-> ringExp a _ (Left e) = cryError e a-> ringExp a v (Right i) = foldl (ringMul a) (literal 1 a) (genericReplicate i v)->-> ringMul :: TValue -> Value -> Value -> Value-> ringMul = ringBinary (\x y -> Right (x * y))-> (\x y -> Right (x * y))-> (fpBin FP.bfMul fpImplicitRound)---Signed bitvector division (`/$`) and remainder (`%$`) are defined so-that division rounds toward zero, and the remainder `x %$ y` has the-same sign as `x`. Accordingly, they are implemented with Haskell's-`quot` and `rem` operations.--> divWrap :: Integer -> Integer -> Either EvalError Integer-> divWrap _ 0 = Left DivideByZero-> divWrap x y = Right (x `quot` y)->-> modWrap :: Integer -> Integer -> Either EvalError Integer-> modWrap _ 0 = Left DivideByZero-> modWrap x y = Right (x `rem` y)->-> lg2Wrap :: Integer -> Either EvalError Integer-> lg2Wrap x = if x < 0 then Left LogNegative else Right (lg2 x)---Field--------Types that represent fields are have, in addition to the ring operations-a recipricol operator and a field division operator (not to be-confused with integral division).--> fieldUnary :: (Rational -> Either EvalError Rational) ->-> (Integer -> Integer -> BigFloat -> Either EvalError BigFloat) ->-> TValue -> Value -> Value-> fieldUnary qop flop ty v = case ty of-> TVRational -> VRational $ appOp1 qop (fromVRational v)-> TVFloat e p -> VFloat $ fpToBF e p <$> appOp1 (flop e p) (fromVFloat v)-> _ -> evalPanic "fieldUnary" [show ty ++ " is not a Field type"]->-> fieldBinary ::-> (Rational -> Rational -> Either EvalError Rational) ->-> (Integer -> Integer -> BigFloat -> BigFloat -> Either EvalError BigFloat) ->-> TValue -> Value -> Value -> Value-> fieldBinary qop flop ty l r = case ty of-> TVRational -> VRational $ appOp2 qop (fromVRational l) (fromVRational r)-> TVFloat e p -> VFloat $ fpToBF e p <$> appOp2 (flop e p)-> (fromVFloat l) (fromVFloat r)-> _ -> evalPanic "fieldBinary" [show ty ++ " is not a Field type"]->-> ratDiv :: Rational -> Rational -> Either EvalError Rational-> ratDiv _ 0 = Left DivideByZero-> ratDiv x y = Right (x / y)->-> ratRecip :: Rational -> Either EvalError Rational-> ratRecip 0 = Left DivideByZero-> ratRecip x = Right (recip x)---Round--------> roundUnary :: (Rational -> Integer) ->-> (BF -> Either EvalError Integer) ->-> TValue -> Value -> Value-> roundUnary op flop ty v = case ty of-> TVRational -> VInteger (op <$> fromVRational v)-> TVFloat {} -> VInteger (flop =<< fromVFloat' v)-> _ -> evalPanic "roundUnary" [show ty ++ " is not a Round type"]->--Haskell's definition of "round" is slightly different, as it does-"round to even" on ties.--> roundAwayRat :: Rational -> Integer-> roundAwayRat x-> | x >= 0 = floor (x + 0.5)-> | otherwise = ceiling (x - 0.5)---Rational-------------> ratioOp :: Integer -> Integer -> Either EvalError Rational-> ratioOp _ 0 = Left DivideByZero-> ratioOp x y = Right (fromInteger x / fromInteger y)---Comparison-------------Comparison primitives may be applied to any type that contains a-finite number of bits. All such types are compared using a-lexicographic ordering on bits, where `False` < `True`. Lists and-tuples are compared left-to-right, and record fields are compared in-alphabetical order.--Comparisons on type `Bit` are strict in both arguments. Comparisons on-larger types have short-circuiting behavior: A comparison involving an-error/undefined element will only yield an error if all corresponding-bits to the *left* of that position are equal.--> -- | Process two elements based on their lexicographic ordering.-> cmpOrder :: (Ordering -> Bool) -> TValue -> Value -> Value -> Value-> cmpOrder p ty l r = VBit (fmap p (lexCompare ty l r))->-> -- | Lexicographic ordering on two values.-> lexCompare :: TValue -> Value -> Value -> Either EvalError Ordering-> lexCompare ty l r =-> case ty of-> TVBit ->-> compare <$> fromVBit l <*> fromVBit r-> TVInteger ->-> compare <$> fromVInteger l <*> fromVInteger r-> TVIntMod _ ->-> compare <$> fromVInteger l <*> fromVInteger r-> TVRational ->-> compare <$> fromVRational l <*> fromVRational r-> TVFloat{} ->-> compare <$> fromVFloat l <*> fromVFloat r-> TVArray{} ->-> evalPanic "lexCompare" ["invalid type"]-> TVSeq _w ety ->-> lexList (zipWith (lexCompare ety) (fromVList l) (fromVList r))-> TVStream _ ->-> evalPanic "lexCompare" ["invalid type"]-> TVFun _ _ ->-> evalPanic "lexCompare" ["invalid type"]-> TVTuple etys ->-> lexList (zipWith3 lexCompare etys (fromVTuple l) (fromVTuple r))-> TVRec fields ->-> let tys = map snd (canonicalFields fields)-> ls = map snd (sortBy (comparing fst) (fromVRecord l))-> rs = map snd (sortBy (comparing fst) (fromVRecord r))-> in lexList (zipWith3 lexCompare tys ls rs)-> TVAbstract {} ->-> evalPanic "lexCompare" ["Abstract type not in `Cmp`"]->-> lexList :: [Either EvalError Ordering] -> Either EvalError Ordering-> lexList [] = Right EQ-> lexList (e : es) =-> case e of-> Left err -> Left err-> Right LT -> Right LT-> Right EQ -> lexList es-> Right GT -> Right GT--Signed comparisons may be applied to any type made up of non-empty-bitvectors. All such types are compared using a lexicographic-ordering: Lists and tuples are compared left-to-right, and record-fields are compared in alphabetical order.--> signedLessThan :: TValue -> Value -> Value -> Value-> signedLessThan ty l r = VBit (fmap (== LT) (lexSignedCompare ty l r))->-> -- | Lexicographic ordering on two signed values.-> lexSignedCompare :: TValue -> Value -> Value -> Either EvalError Ordering-> lexSignedCompare ty l r =-> case ty of-> TVBit ->-> evalPanic "lexSignedCompare" ["invalid type"]-> TVInteger ->-> evalPanic "lexSignedCompare" ["invalid type"]-> TVIntMod _ ->-> evalPanic "lexSignedCompare" ["invalid type"]-> TVRational ->-> evalPanic "lexSignedCompare" ["invalid type"]-> TVFloat{} ->-> evalPanic "lexSignedCompare" ["invalid type"]-> TVArray{} ->-> evalPanic "lexSignedCompare" ["invalid type"]-> TVSeq _w ety-> | isTBit ety -> compare <$> fromSignedVWord l <*> fromSignedVWord r-> | otherwise ->-> lexList (zipWith (lexSignedCompare ety) (fromVList l) (fromVList r))-> TVStream _ ->-> evalPanic "lexSignedCompare" ["invalid type"]-> TVFun _ _ ->-> evalPanic "lexSignedCompare" ["invalid type"]-> TVTuple etys ->-> lexList (zipWith3 lexSignedCompare etys (fromVTuple l) (fromVTuple r))-> TVRec fields ->-> let tys = map snd (canonicalFields fields)-> ls = map snd (sortBy (comparing fst) (fromVRecord l))-> rs = map snd (sortBy (comparing fst) (fromVRecord r))-> in lexList (zipWith3 lexSignedCompare tys ls rs)-> TVAbstract {} ->-> evalPanic "lexSignedCompare" ["Abstract type not in `Cmp`"]---Sequences------------> -- | Split a list into 'w' pieces, each of length 'k'.-> splitV :: Nat' -> Integer -> [Value] -> [Value]-> splitV w k xs =-> case w of-> Nat 0 -> []-> Nat n -> VList (Nat k) ys : splitV (Nat (n - 1)) k zs-> Inf -> VList (Nat k) ys : splitV Inf k zs-> where-> (ys, zs) = genericSplitAt k xs->-> -- | Transpose a list of length-'w' lists into 'w' lists.-> transposeV :: Nat' -> [[Value]] -> [[Value]]-> transposeV w xss =-> case w of-> Nat 0 -> []-> Nat n -> heads : transposeV (Nat (n - 1)) tails-> Inf -> heads : transposeV Inf tails-> where-> (heads, tails) = dest xss->-> -- Split a list of non-empty lists into-> -- a list of heads and a list of tails-> dest :: [[Value]] -> ([Value], [[Value]])-> dest [] = ([], [])-> dest ([] : _) = evalPanic "transposeV" ["Expected non-empty list"]-> dest ((y : ys) : yss) = (y : zs, ys : zss)-> where (zs, zss) = dest yss---Shifting-----------Shift and rotate operations are strict in all bits of the shift/rotate-amount, but as lazy as possible in the list values.--> shiftV :: (Nat' -> Value -> [Value] -> Integer -> [Value]) -> Value-> shiftV op =-> VNumPoly $ \n ->-> VPoly $ \ix ->-> VPoly $ \a ->-> VFun $ \v ->-> VFun $ \x ->-> copyByTValue (tvSeq n a) $-> case cryToInteger ix x of-> Left e -> cryError e (tvSeq n a)-> Right i -> VList n (op n (zero a) (fromVList v) i)->-> shiftLV :: Nat' -> Value -> [Value] -> Integer -> [Value]-> shiftLV w z vs i =-> case w of-> Nat n -> genericDrop (min n i) vs ++ genericReplicate (min n i) z-> Inf -> genericDrop i vs->-> shiftRV :: Nat' -> Value -> [Value] -> Integer -> [Value]-> shiftRV w z vs i =-> case w of-> Nat n -> genericReplicate (min n i) z ++ genericTake (n - min n i) vs-> Inf -> genericReplicate i z ++ vs->-> rotateV :: (Integer -> [Value] -> Integer -> [Value]) -> Value-> rotateV op =-> vFinPoly $ \n ->-> VPoly $ \ix ->-> VPoly $ \a ->-> VFun $ \v ->-> VFun $ \x ->-> copyByTValue (TVSeq n a) $-> case cryToInteger ix x of-> Left e -> cryError e (tvSeq (Nat n) a)-> Right i -> VList (Nat n) (op n (fromVList v) i)->-> rotateLV :: Integer -> [Value] -> Integer -> [Value]-> rotateLV 0 vs _ = vs-> rotateLV w vs i = ys ++ xs-> where (xs, ys) = genericSplitAt (i `mod` w) vs->-> rotateRV :: Integer -> [Value] -> Integer -> [Value]-> rotateRV 0 vs _ = vs-> rotateRV w vs i = ys ++ xs-> where (xs, ys) = genericSplitAt ((w - i) `mod` w) vs->-> signedShiftRV :: Value-> signedShiftRV =-> VNumPoly $ \(Nat n) ->-> VPoly $ \ix ->-> VFun $ \v ->-> VFun $ \x ->-> copyByTValue (tvSeq (Nat n) TVBit) $-> case cryToInteger ix x of-> Left e -> cryError e (tvSeq (Nat n) TVBit)-> Right i -> VList (Nat n) $-> let vs = fromVList v-> z = head vs in-> genericReplicate (min n i) z ++ genericTake (n - min n i) vs--Indexing-----------Indexing operations are strict in all index bits, but as lazy as-possible in the list values. An index greater than or equal to the-length of the list produces a run-time error.--> -- | Indexing operations that return one element.-> indexPrimOne :: (Nat' -> TValue -> [Value] -> Integer -> Value) -> Value-> indexPrimOne op =-> VNumPoly $ \n ->-> VPoly $ \a ->-> VPoly $ \ix ->-> VFun $ \l ->-> VFun $ \r ->-> copyByTValue a $-> case cryToInteger ix r of-> Left e -> cryError e a-> Right i -> op n a (fromVList l) i->-> indexFront :: Nat' -> TValue -> [Value] -> Integer -> Value-> indexFront w a vs ix =-> case w of-> Nat n | n <= ix -> cryError (InvalidIndex (Just ix)) a-> _ -> genericIndex vs ix->-> indexBack :: Nat' -> TValue -> [Value] -> Integer -> Value-> indexBack w a vs ix =-> case w of-> Nat n | n > ix -> genericIndex vs (n - ix - 1)-> | otherwise -> cryError (InvalidIndex (Just ix)) a-> Inf -> evalPanic "indexBack" ["unexpected infinite sequence"]->-> updatePrim :: (Nat' -> [Value] -> Integer -> Value -> [Value]) -> Value-> updatePrim op =-> VNumPoly $ \len ->-> VPoly $ \eltTy ->-> VPoly $ \ix ->-> VFun $ \xs ->-> VFun $ \idx ->-> VFun $ \val ->-> copyByTValue (tvSeq len eltTy) $-> case cryToInteger ix idx of-> Left e -> cryError e (tvSeq len eltTy)-> Right i-> | Nat i < len -> VList len (op len (fromVList xs) i val)-> | otherwise -> cryError (InvalidIndex (Just i)) (tvSeq len eltTy)->-> updateFront :: Nat' -> [Value] -> Integer -> Value -> [Value]-> updateFront _ vs i x = updateAt vs i x->-> updateBack :: Nat' -> [Value] -> Integer -> Value -> [Value]-> updateBack Inf _vs _i _x = evalPanic "Unexpected infinite sequence in updateEnd" []-> updateBack (Nat n) vs i x = updateAt vs (n - i - 1) x->-> updateAt :: [a] -> Integer -> a -> [a]-> updateAt [] _ _ = []-> updateAt (_ : xs) 0 y = y : xs-> updateAt (x : xs) i y = x : updateAt xs (i - 1) y---Floating Point Numbers-------------------------Whenever we do operations that do not have an explicit rounding mode,-we round towards the closest number, with ties resolved to the even one.--> fpImplicitRound :: FP.RoundMode-> fpImplicitRound = FP.NearEven--We annotate floating point values with their precision. This is only used-when pretty printing values.--> fpToBF :: Integer -> Integer -> BigFloat -> BF-> fpToBF e p x = BF { bfValue = x, bfExpWidth = e, bfPrecWidth = p }---The following two functions convert between floaitng point numbers-and integers.--> fpFromInteger :: Integer -> Integer -> Integer -> BigFloat-> fpFromInteger e p = FP.fpCheckStatus . FP.bfRoundFloat opts . FP.bfFromInteger-> where opts = FP.fpOpts e p fpImplicitRound--These functions capture the interactions with rationals.---This just captures a common pattern for binary floating point primitives.--> fpBin :: (FP.BFOpts -> BigFloat -> BigFloat -> (BigFloat,FP.Status)) ->-> FP.RoundMode -> Integer -> Integer ->-> BigFloat -> BigFloat -> Either EvalError BigFloat-> fpBin f r e p x y = Right (FP.fpCheckStatus (f (FP.fpOpts e p r) x y))---Computes the reciprocal of a floating point number via division.-This assumes that 1 can be represented exactly, which should be-true for all supported precisions.--> fpRecip :: Integer -> Integer -> BigFloat -> Either EvalError BigFloat-> fpRecip e p x = pure (FP.fpCheckStatus (FP.bfDiv opts (FP.bfFromInteger 1) x))-> where opts = FP.fpOpts e p fpImplicitRound---> floatPrimTable :: Map PrimIdent Value-> floatPrimTable = Map.fromList $ map (\(n, v) -> (floatPrim (T.pack n), v))-> [ "fpNaN" ~> vFinPoly \e -> vFinPoly \p ->-> VFloat $ Right $ fpToBF e p FP.bfNaN->-> , "fpPosInf" ~> vFinPoly \e -> vFinPoly \p ->-> VFloat $ Right $ fpToBF e p FP.bfPosInf->-> , "fpFromBits" ~> vFinPoly \e -> vFinPoly \p -> VFun \bvv ->-> VFloat (FP.floatFromBits e p <$> fromVWord bvv)->-> , "fpToBits" ~> vFinPoly \e -> vFinPoly \p -> VFun \fpv ->-> vWord (e + p) (FP.floatToBits e p <$> fromVFloat fpv)->-> , "=.=" ~> vFinPoly \_ -> vFinPoly \_ -> VFun \xv -> VFun \yv ->-> VBit do x <- fromVFloat xv-> y <- fromVFloat yv-> pure (FP.bfCompare x y == EQ)->-> , "fpIsFinite" ~> vFinPoly \_ -> vFinPoly \_ -> VFun \xv ->-> VBit do x <- fromVFloat xv-> pure (FP.bfIsFinite x)->-> , "fpAdd" ~> fpArith FP.bfAdd-> , "fpSub" ~> fpArith FP.bfSub-> , "fpMul" ~> fpArith FP.bfMul-> , "fpDiv" ~> fpArith FP.bfDiv->-> , "fpToRational" ~>-> vFinPoly \_ -> vFinPoly \_ -> VFun \fpv ->-> VRational do fp <- fromVFloat' fpv-> FP.floatToRational "fpToRational" fp-> , "fpFromRational" ~>-> vFinPoly \e -> vFinPoly \p -> VFun \rmv -> VFun \rv ->-> VFloat do rm <- FP.fpRound =<< fromVWord rmv-> rat <- fromVRational rv-> pure (FP.floatFromRational e p rm rat)-> ]-> where-> (~>) = (,)-> fpArith f = vFinPoly \e -> vFinPoly \p ->-> VFun \vr -> VFun \xv -> VFun \yv ->-> VFloat do r <- fromVWord vr-> rnd <- FP.fpRound r-> x <- fromVFloat xv-> y <- fromVFloat yv-> fpToBF e p <$> fpBin f rnd e p x y---Error Handling-----------------The `evalPanic` function is only called if an internal data invariant-is violated, such as an expression that is not well-typed. Panics-should (hopefully) never occur in practice; a panic message indicates-a bug in Cryptol.--> evalPanic :: String -> [String] -> a-> evalPanic cxt = panic ("[Reference Evaluator]" ++ cxt)--Pretty Printing------------------> ppValue :: PPOpts -> Value -> Doc-> ppValue opts val =-> case val of-> VBit b -> text (either show show b)-> VInteger i -> text (either show show i)-> VRational q -> text (either show show q)-> VFloat fl -> text (either show (show . FP.fpPP opts) fl)-> VList l vs ->-> case l of-> Inf -> ppList (map (ppValue opts) (take (useInfLength opts) vs) ++ [text "..."])-> Nat n ->-> -- For lists of defined bits, print the value as a numeral.-> case traverse isBit vs of-> Just bs -> ppBV opts (mkBv n (bitsToInteger bs))-> Nothing -> ppList (map (ppValue opts) vs)-> where ppList docs = brackets (fsep (punctuate comma docs))-> isBit v = case v of VBit (Right b) -> Just b-> _ -> Nothing-> VTuple vs -> parens (sep (punctuate comma (map (ppValue opts) vs)))-> VRecord fs -> braces (sep (punctuate comma (map ppField fs)))-> where ppField (f,r) = pp f <+> char '=' <+> ppValue opts r-> VFun _ -> text "<function>"-> VPoly _ -> text "<polymorphic value>"-> VNumPoly _ -> text "<polymorphic value>"--Module Command-----------------This module implements the core functionality of the `:eval-<expression>` command for the Cryptol REPL, which prints the result of-running the reference evaluator on an expression.--> evaluate :: Expr -> M.ModuleCmd Value+> -- Copyright : (c) 2013-2020 Galois, Inc.+> -- License : BSD3+> -- Maintainer : cryptol@galois.com+> -- Stability : provisional+> -- Portability : portable+>+> {-# LANGUAGE BlockArguments #-}+> {-# LANGUAGE PatternGuards #-}+> {-# LANGUAGE LambdaCase #-}+>+> module Cryptol.Eval.Reference+> ( Value(..)+> , E(..)+> , evaluate+> , evalExpr+> , evalDeclGroup+> , ppValue+> , ppEValue+> ) where+>+> import Data.Bits+> import Data.Ratio((%))+> import Data.List+> (genericIndex, genericLength, genericReplicate, genericTake, sortBy)+> import Data.Ord (comparing)+> import Data.Map (Map)+> import qualified Data.Map as Map+> import qualified Data.IntMap as IntMap+> import qualified Data.Text as T (pack)+> import LibBF (BigFloat)+> import qualified LibBF as FP+> import qualified GHC.Integer.GMP.Internals as Integer+>+> import Cryptol.ModuleSystem.Name (asPrim)+> import Cryptol.TypeCheck.Solver.InfNat (Nat'(..), nAdd, nMin, nMul)+> import Cryptol.TypeCheck.AST+> import Cryptol.Backend.FloatHelpers (BF(..))+> import qualified Cryptol.Backend.FloatHelpers as FP+> import Cryptol.Backend.Monad (EvalError(..), PPOpts(..))+> import Cryptol.Eval.Type (TValue(..), isTBit, evalValType, evalNumType, TypeEnv)+> import Cryptol.Eval.Concrete (mkBv, ppBV, lg2)+> import Cryptol.Utils.Ident (Ident,PrimIdent, prelPrim, floatPrim)+> import Cryptol.Utils.Panic (panic)+> import Cryptol.Utils.PP+> import Cryptol.Utils.RecordMap+>+> import qualified Cryptol.ModuleSystem as M+> import qualified Cryptol.ModuleSystem.Env as M (loadedModules)++Overview+========++This file describes the semantics of the explicitly-typed Cryptol+language (i.e., terms after type checking). Issues related to type+inference, type functions, and type constraints are beyond the scope+of this document.++Cryptol Types+-------------++Cryptol types come in two kinds: numeric types (kind `#`) and value+types (kind `*`). While value types are inhabited by well-typed+Cryptol expressions, numeric types are only used as parameters to+other types; they have no inhabitants. In this implementation we+represent numeric types as values of the Haskell type `Nat'` of+natural numbers with infinity; value types are represented as values+of type `TValue`.++The value types of Cryptol, along with their Haskell representations,+are as follows:++| Cryptol type | Description | `TValue` representation |+|:------------------|:------------------|:----------------------------|+| `Bit` | booleans | `TVBit` |+| `Integer` | integers | `TVInteger` |+| `Z n` | integers modulo n | `TVIntMod n` |+| `Rational` | rationals | `TVRational` |+| `Float e p` | floating point | `TVFloat` |+| `Array` | arrays | `TVArray` |+| `[n]a` | finite lists | `TVSeq n a` |+| `[inf]a` | infinite lists | `TVStream a` |+| `(a, b, c)` | tuples | `TVTuple [a,b,c]` |+| `{x:a, y:b, z:c}` | records | `TVRec [(x,a),(y,b),(z,c)]` |+| `a -> b` | functions | `TVFun a b` |++We model each (closed) Cryptol value type `t` as a complete partial order (cpo)+*M*(`t`). The values of *M*(`t`) represent the _values_ present in the+type `t`; we distinguish these from the _computations_ at type `t`.+Operationally, the difference is that computations may raise errors or cause+nontermination when evaluated; however, values are already evaluated, and will+not cause errors or nontermination. Denotationally, we represent this+difference via a monad (in the style of Moggi) called *E*. As an+operation on CPOs, *E* adds a new bottom element representing+nontermination, and a collection of erroneous values representing+various runtime error conditions.++To each Cryptol expression `e : t` we assign a meaning+*M*(`e`) in *E*(*M*(`t`)); in particular, recursive Cryptol programs of+type `t` are modeled as least fixed points in *E*(*M*(`t`)). In other words,+this is a domain-theoretic denotational semantics. Note, we do not requre+CPOs defined via *M*(`t`) to have bottom elements, which is why we must take+fixpoints in *E*. We cannot directly represent values without bottom in Haskell,+so instead we are careful in this document only to write clearly-terminating+functions, unless they represent computations under *E*.++*M*(`Bit`) is a discrete cpo with values for `True`, `False`, which+we simply represent in Haskell as `Bool`.+Similarly, *M*(`Integer`) is a discrete cpo with values for integers,+which we model as Haskell's `Integer`. Likewise with the other+base types.++The value cpos for lists, tuples, and records are cartesian products+of _computations_. For example *M*(`(a,b)`) = *E*(*M*(`a`)) × *E*(*M*(`b`)).+The cpo ordering is pointwise. The trivial types `[0]t`,+`()` and `{}` denote single-element cpos. *M*(`a -> b`) is the+continuous function space *E*(*M*(`a`)) $\to$ *E*(*M*(`b`)).++Type schemas of the form `{a1 ... an} (p1 ... pk) => t` classify+polymorphic values in Cryptol. These are represented with the Haskell+type `Schema`. The meaning of a schema is cpo whose elements are+functions: For each valid instantiation `t1 ... tn` of the type+parameters `a1 ... an` that satisfies the constraints `p1 ... pk`, the+function returns a value in *E*(*M*(`t[t1/a1 ... tn/an]`)).++Computation Monad+------------------++This monad represents either an evaluated thing of type `a`+or an evaluation error. In the reference interpreter, only+things under this monad should potentially result in errors+or fail to terminate.++> -- | Computation monad for the reference evaluator.+> data E a = Value !a | Err EvalError+>+> instance Functor E where+> fmap f (Value x) = Value (f x)+> fmap _ (Err e) = Err e++> instance Applicative E where+> pure x = Value x+> Err e <*> _ = Err e+> Value _ <*> Err e = Err e+> Value f <*> Value x = Value (f x)++> instance Monad E where+> m >>= f =+> case m of+> Value x -> f x+> Err r -> Err r+>+> eitherToE :: Either EvalError a -> E a+> eitherToE (Left e) = Err e+> eitherToE (Right x) = pure x++Values+------++The Haskell code in this module defines the semantics of typed Cryptol+terms by providing an evaluator to an appropriate `Value` type.++> -- | Value type for the reference evaluator.+> data Value+> = VBit !Bool -- ^ @ Bit @ booleans+> | VInteger !Integer -- ^ @ Integer @ or @Z n@ integers+> | VRational !Rational -- ^ @ Rational @ rationals+> | VFloat !BF -- ^ Floating point numbers+> | VList Nat' [E Value] -- ^ @ [n]a @ finite or infinite lists+> | VTuple [E Value] -- ^ @ ( .. ) @ tuples+> | VRecord [(Ident, E Value)] -- ^ @ { .. } @ records+> | VFun (E Value -> E Value) -- ^ functions+> | VPoly (TValue -> E Value) -- ^ polymorphic values (kind *)+> | VNumPoly (Nat' -> E Value) -- ^ polymorphic values (kind #)++Operations on Values+--------------------++> -- | Destructor for @VBit@.+> fromVBit :: Value -> Bool+> fromVBit (VBit b) = b+> fromVBit _ = evalPanic "fromVBit" ["Expected a bit"]+>+> -- | Destructor for @VInteger@.+> fromVInteger :: Value -> Integer+> fromVInteger (VInteger i) = i+> fromVInteger _ = evalPanic "fromVInteger" ["Expected an integer"]+>+> -- | Destructor for @VRational@.+> fromVRational :: Value -> Rational+> fromVRational (VRational i) = i+> fromVRational _ = evalPanic "fromVRational" ["Expected a rational"]+>+> fromVFloat :: Value -> BigFloat+> fromVFloat = bfValue . fromVFloat'+>+> fromVFloat' :: Value -> BF+> fromVFloat' v =+> case v of+> VFloat f -> f+> _ -> evalPanic "fromVFloat" [ "Expected a floating point value." ]+>+> -- | Destructor for @VList@.+> fromVList :: Value -> [E Value]+> fromVList (VList _ vs) = vs+> fromVList _ = evalPanic "fromVList" ["Expected a list"]+>+> -- | Destructor for @VTuple@.+> fromVTuple :: Value -> [E Value]+> fromVTuple (VTuple vs) = vs+> fromVTuple _ = evalPanic "fromVTuple" ["Expected a tuple"]+>+> -- | Destructor for @VRecord@.+> fromVRecord :: Value -> [(Ident, E Value)]+> fromVRecord (VRecord fs) = fs+> fromVRecord _ = evalPanic "fromVRecord" ["Expected a record"]+>+> -- | Destructor for @VFun@.+> fromVFun :: Value -> (E Value -> E Value)+> fromVFun (VFun f) = f+> fromVFun _ = evalPanic "fromVFun" ["Expected a function"]+>+> -- | Look up a field in a record.+> lookupRecord :: Ident -> Value -> E Value+> lookupRecord f v =+> case lookup f (fromVRecord v) of+> Just val -> val+> Nothing -> evalPanic "lookupRecord" ["Malformed record"]+>+> -- | Polymorphic function values that expect a finite numeric type.+> vFinPoly :: (Integer -> E Value) -> Value+> vFinPoly f = VNumPoly g+> where+> g (Nat n) = f n+> g Inf = evalPanic "vFinPoly" ["Expected finite numeric type"]+++Environments+------------++An evaluation environment keeps track of the values of term variables+and type variables that are in scope at any point.++> data Env = Env+> { envVars :: !(Map Name (E Value))+> , envTypes :: !TypeEnv+> }+>+> instance Semigroup Env where+> l <> r = Env+> { envVars = Map.union (envVars l) (envVars r)+> , envTypes = IntMap.union (envTypes l) (envTypes r)+> }+>+> instance Monoid Env where+> mempty = Env+> { envVars = Map.empty+> , envTypes = IntMap.empty+> }+> mappend l r = l <> r+>+> -- | Bind a variable in the evaluation environment.+> bindVar :: (Name, E Value) -> Env -> Env+> bindVar (n, val) env = env { envVars = Map.insert n val (envVars env) }+>+> -- | Bind a type variable of kind # or *.+> bindType :: TVar -> Either Nat' TValue -> Env -> Env+> bindType p ty env = env { envTypes = IntMap.insert (tvUnique p) ty (envTypes env) }+++Evaluation+==========++The meaning *M*(`expr`) of a Cryptol expression `expr` is defined by+recursion over its structure. For an expression that contains free+variables, the meaning also depends on the environment `env`, which+assigns values to those variables.++> evalExpr :: Env -- ^ Evaluation environment+> -> Expr -- ^ Expression to evaluate+> -> E Value+> evalExpr env expr =+> case expr of+>+> EList es _ty ->+> pure $ VList (Nat (genericLength es)) [ evalExpr env e | e <- es ]+>+> ETuple es ->+> pure $ VTuple [ evalExpr env e | e <- es ]+>+> ERec fields ->+> pure $ VRecord [ (f, evalExpr env e) | (f, e) <- canonicalFields fields ]+>+> ESel e sel ->+> evalSel sel =<< evalExpr env e+>+> ESet ty e sel v ->+> evalSet (evalValType (envTypes env) ty)+> (evalExpr env e) sel (evalExpr env v)+>+> EIf c t f ->+> condValue (fromVBit <$> evalExpr env c) (evalExpr env t) (evalExpr env f)+>+> EComp _n _ty e branches -> evalComp env e branches+>+> EVar n ->+> case Map.lookup n (envVars env) of+> Just val -> val+> Nothing ->+> evalPanic "evalExpr" ["var `" ++ show (pp n) ++ "` is not defined" ]+>+> ETAbs tv b ->+> case tpKind tv of+> KType -> pure $ VPoly $ \ty ->+> evalExpr (bindType (tpVar tv) (Right ty) env) b+> KNum -> pure $ VNumPoly $ \n ->+> evalExpr (bindType (tpVar tv) (Left n) env) b+> k -> evalPanic "evalExpr" ["Invalid kind on type abstraction", show k]+>+> ETApp e ty ->+> evalExpr env e >>= \case+> VPoly f -> f $! (evalValType (envTypes env) ty)+> VNumPoly f -> f $! (evalNumType (envTypes env) ty)+> _ -> evalPanic "evalExpr" ["Expected a polymorphic value"]+>+> EApp e1 e2 -> appFun (evalExpr env e1) (evalExpr env e2)+> EAbs n _ty b -> pure $ VFun (\v -> evalExpr (bindVar (n, v) env) b)+> EProofAbs _ e -> evalExpr env e+> EProofApp e -> evalExpr env e+> EWhere e dgs -> evalExpr (foldl evalDeclGroup env dgs) e+++> appFun :: E Value -> E Value -> E Value+> appFun f v = f >>= \f' -> fromVFun f' v+++Selectors+---------++Apply the the given selector form to the given value.++> evalSel :: Selector -> Value -> E Value+> evalSel sel val =+> case sel of+> TupleSel n _ -> tupleSel n val+> RecordSel n _ -> recordSel n val+> ListSel n _ -> listSel n val+> where+> tupleSel n v =+> case v of+> VTuple vs -> vs !! n+> _ -> evalPanic "evalSel"+> ["Unexpected value in tuple selection."]+> recordSel n v =+> case v of+> VRecord _ -> lookupRecord n v+> _ -> evalPanic "evalSel"+> ["Unexpected value in record selection."]+> listSel n v =+> case v of+> VList _ vs -> vs !! n+> _ -> evalPanic "evalSel"+> ["Unexpected value in list selection."]+++Update the given value using the given selector and new value.++> evalSet :: TValue -> E Value -> Selector -> E Value -> E Value+> evalSet tyv val sel fval =+> case (tyv, sel) of+> (TVTuple ts, TupleSel n _) -> updTupleAt ts n+> (TVRec fs, RecordSel n _) -> updRecAt fs n+> (TVSeq len _, ListSel n _) -> updSeqAt len n+> (_, _) -> evalPanic "evalSet" ["type/selector mismatch", show tyv, show sel]+> where+> updTupleAt ts n =+> pure $ VTuple+> [ if i == n then fval else+> do vs <- fromVTuple <$> val+> genericIndex vs i+> | (i,_t) <- zip [0 ..] ts+> ]+>+> updRecAt fs n =+> pure $ VRecord+> [ (f, if f == n then fval else lookupRecord f =<< val)+> | (f, _t) <- canonicalFields fs+> ]+>+> updSeqAt len n =+> pure $ generateV (Nat len) $ \i ->+> if i == toInteger n then fval else+> do vs <- fromVList <$> val+> indexFront (Nat len) vs i++Conditionals+------------++Conditionals are explicitly lazy: Run-time errors in an untaken branch+are ignored.++> condValue :: E Bool -> E Value -> E Value -> E Value+> condValue c l r = c >>= \b -> if b then l else r++List Comprehensions+-------------------++Cryptol list comprehensions consist of one or more parallel branches;+each branch has one or more matches that bind values to variables.++The result of evaluating a match in an initial environment is a list+of extended environments. Each new environment binds the same single+variable to a different element of the match's list.++> evalMatch :: Env -> Match -> [Env]+> evalMatch env m =+> case m of+> Let d -> [ bindVar (evalDecl env d) env ]+> From nm len _ty expr -> [ bindVar (nm, get i) env | i <- idxs ]+> where+> get i =+> do v <- evalExpr env expr+> genericIndex (fromVList v) i+>+> idxs :: [Integer]+> idxs =+> case evalNumType (envTypes env) len of+> Inf -> [0 ..]+> Nat n -> [0 .. n-1]++> lenMatch :: Env -> Match -> Nat'+> lenMatch env m =+> case m of+> Let _ -> Nat 1+> From _ len _ _ -> evalNumType (envTypes env) len++The result of of evaluating a branch in an initial environment is a+list of extended environments, each of which extends the initial+environment with the same set of new variables. The length of the list+is equal to the product of the lengths of the lists in the matches.++> evalBranch :: Env -> [Match] -> [Env]+> evalBranch env [] = [env]+> evalBranch env (match : matches) =+> [ env'' | env' <- evalMatch env match+> , env'' <- evalBranch env' matches ]++> lenBranch :: Env -> [Match] -> Nat'+> lenBranch _env [] = Nat 1+> lenBranch env (match : matches) =+> nMul (lenMatch env match) (lenBranch env matches)++The head expression of the comprehension can refer to any variable+bound in any of the parallel branches. So to evaluate the+comprehension, we zip and merge together the lists of extended+environments from each branch. The head expression is then evaluated+separately in each merged environment. The length of the resulting+list is equal to the minimum length over all parallel branches.++> evalComp :: Env -- ^ Starting evaluation environment+> -> Expr -- ^ Head expression of the comprehension+> -> [[Match]] -- ^ List of parallel comprehension branches+> -> E Value+> evalComp env expr branches = pure $ VList len [ evalExpr e expr | e <- envs ]+> where+> -- Generate a new environment for each iteration of each+> -- parallel branch.+> benvs :: [[Env]]+> benvs = map (evalBranch env) branches+>+> -- Zip together the lists of environments from each branch,+> -- producing a list of merged environments. Longer branches get+> -- truncated to the length of the shortest branch.+> envs :: [Env]+> envs = foldr1 (zipWith mappend) benvs+>+> len :: Nat'+> len = foldr1 nMin (map (lenBranch env) branches)+++Declarations+------------++Function `evalDeclGroup` extends the given evaluation environment with+the result of evaluating the given declaration group. In the case of a+recursive declaration group, we tie the recursive knot by evaluating+each declaration in the extended environment `env'` that includes all+the new bindings.++> evalDeclGroup :: Env -> DeclGroup -> Env+> evalDeclGroup env dg = do+> case dg of+> NonRecursive d ->+> bindVar (evalDecl env d) env+> Recursive ds ->+> let env' = foldr bindVar env bindings+> bindings = map (evalDecl env') ds+> in env'+>+> evalDecl :: Env -> Decl -> (Name, E Value)+> evalDecl env d =+> case dDefinition d of+> DPrim -> (dName d, pure (evalPrim (dName d)))+> DExpr e -> (dName d, evalExpr env e)+++Primitives+==========++To evaluate a primitive, we look up its implementation by name in a table.++> evalPrim :: Name -> Value+> evalPrim n+> | Just i <- asPrim n, Just v <- Map.lookup i primTable = v+> | otherwise = evalPanic "evalPrim" ["Unimplemented primitive", show n]++Cryptol primitives fall into several groups, mostly delineated+by corresponding type classes:++* Literals: `True`, `False`, `number`, `ratio`++* Zero: zero++* Logic: `&&`, `||`, `^`, `complement`++* Ring: `+`, `-`, `*`, `negate`, `fromInteger`++* Integral: `/`, `%`, `^^`, `toInteger`++* Bitvector: `/$` `%$`, `lg2`, `<=$`++* Comparison: `<`, `>`, `<=`, `>=`, `==`, `!=`++* Sequences: `#`, `join`, `split`, `splitAt`, `reverse`, `transpose`++* Shifting: `<<`, `>>`, `<<<`, `>>>`++* Indexing: `@`, `@@`, `!`, `!!`, `update`, `updateEnd`++* Enumerations: `fromTo`, `fromThenTo`, `infFrom`, `infFromThen`++* Polynomials: `pmult`, `pdiv`, `pmod`++* Miscellaneous: `error`, `random`, `trace`++> primTable :: Map PrimIdent Value+> primTable = Map.unions+> [ cryptolPrimTable+> , floatPrimTable+> ]++> infixr 0 ~>+> (~>) :: String -> a -> (String,a)+> nm ~> v = (nm,v)+++> cryptolPrimTable :: Map PrimIdent Value+> cryptolPrimTable = Map.fromList $ map (\(n, v) -> (prelPrim (T.pack n), v))+>+> -- Literals+> [ "True" ~> VBit True+> , "False" ~> VBit False+> , "number" ~> vFinPoly $ \val -> pure $+> VPoly $ \a ->+> literal val a+> , "fraction" ~> vFinPoly \top -> pure $+> vFinPoly \bot -> pure $+> vFinPoly \rnd -> pure $+> VPoly \a -> fraction top bot rnd a+> -- Zero+> , "zero" ~> VPoly (pure . zero)+>+> -- Logic (bitwise)+> , "&&" ~> binary (logicBinary (&&))+> , "||" ~> binary (logicBinary (||))+> , "^" ~> binary (logicBinary (/=))+> , "complement" ~> unary (logicUnary not)+>+> -- Ring+> , "+" ~> binary (ringBinary+> (\x y -> pure (x + y))+> (\x y -> pure (x + y))+> (fpBin FP.bfAdd fpImplicitRound)+> )+> , "-" ~> binary (ringBinary+> (\x y -> pure (x - y))+> (\x y -> pure (x - y))+> (fpBin FP.bfSub fpImplicitRound)+> )+> , "*" ~> binary ringMul+> , "negate" ~> unary (ringUnary (\x -> pure (- x))+> (\x -> pure (- x))+> (\_ _ x -> pure (FP.bfNeg x)))+> , "fromInteger"~> VPoly $ \a -> pure $+> VFun $ \x ->+> ringNullary (fromVInteger <$> x)+> (fromInteger . fromVInteger <$> x)+> (\e p -> fpFromInteger e p . fromVInteger <$> x)+> a+>+> -- Integral+> , "toInteger" ~> VPoly $ \a -> pure $+> VFun $ \x ->+> VInteger <$> cryToInteger a x+> , "/" ~> binary (integralBinary divWrap)+> , "%" ~> binary (integralBinary modWrap)+> , "^^" ~> VPoly $ \aty -> pure $+> VPoly $ \ety -> pure $+> VFun $ \a -> pure $+> VFun $ \e ->+> ringExp aty a =<< cryToInteger ety e+>+> -- Field+> , "/." ~> binary (fieldBinary ratDiv zDiv+> (fpBin FP.bfDiv fpImplicitRound)+> )+>+> , "recip" ~> unary (fieldUnary ratRecip zRecip fpRecip)+>+> -- Round+> , "floor" ~> unary (roundUnary floor+> (eitherToE . FP.floatToInteger "floor" FP.ToNegInf))+>+> , "ceiling" ~> unary (roundUnary ceiling+> (eitherToE . FP.floatToInteger "ceiling" FP.ToPosInf))+>+> , "trunc" ~> unary (roundUnary truncate+> (eitherToE . FP.floatToInteger "trunc" FP.ToZero))+>+> , "roundAway" ~> unary (roundUnary roundAwayRat+> (eitherToE . FP.floatToInteger "roundAway" FP.Away))+>+> , "roundToEven"~> unary (roundUnary round+> (eitherToE . FP.floatToInteger "roundToEven" FP.NearEven))+>+>+> -- Comparison+> , "<" ~> binary (cmpOrder (\o -> o == LT))+> , ">" ~> binary (cmpOrder (\o -> o == GT))+> , "<=" ~> binary (cmpOrder (\o -> o /= GT))+> , ">=" ~> binary (cmpOrder (\o -> o /= LT))+> , "==" ~> binary (cmpOrder (\o -> o == EQ))+> , "!=" ~> binary (cmpOrder (\o -> o /= EQ))+> , "<$" ~> binary signedLessThan+>+> -- Bitvector+> , "/$" ~> vFinPoly $ \n -> pure $+> VFun $ \l -> pure $+> VFun $ \r ->+> vWord n <$> appOp2 divWrap+> (fromSignedVWord =<< l)+> (fromSignedVWord =<< r)+> , "%$" ~> vFinPoly $ \n -> pure $+> VFun $ \l -> pure $+> VFun $ \r ->+> vWord n <$> appOp2 modWrap+> (fromSignedVWord =<< l)+> (fromSignedVWord =<< r)+> , ">>$" ~> signedShiftRV+> , "lg2" ~> vFinPoly $ \n -> pure $+> VFun $ \v ->+> vWord n <$> appOp1 lg2Wrap (fromVWord =<< v)+> -- Rational+> , "ratio" ~> VFun $ \l -> pure $+> VFun $ \r ->+> VRational <$> appOp2 ratioOp+> (fromVInteger <$> l)+> (fromVInteger <$> r)+>+> -- Z n+> , "fromZ" ~> vFinPoly $ \n -> pure $+> VFun $ \x ->+> VInteger . flip mod n . fromVInteger <$> x+>+> -- Sequences+> , "#" ~> vFinPoly $ \front -> pure $+> VNumPoly $ \back -> pure $+> VPoly $ \_elty -> pure $+> VFun $ \l -> pure $+> VFun $ \r ->+> pure $ generateV (nAdd (Nat front) back) $ \i ->+> if i < front then+> do l' <- fromVList <$> l+> indexFront (Nat front) l' i+> else+> do r' <- fromVList <$> r+> indexFront back r' (i - front)+>+> , "join" ~> VNumPoly $ \parts -> pure $+> vFinPoly $ \each -> pure $+> VPoly $ \_a -> pure $+> VFun $ \v ->+> pure $ generateV (nMul parts (Nat each)) $ \i ->+> do let (q,r) = divMod i each+> xss <- fromVList <$> v+> xs <- fromVList <$> indexFront parts xss q+> indexFront (Nat each) xs r+>+> , "split" ~> VNumPoly $ \parts -> pure $+> vFinPoly $ \each -> pure $+> VPoly $ \_a -> pure $+> VFun $ \val ->+> pure $ generateV parts $ \i ->+> pure $ generateV (Nat each) $ \j ->+> do vs <- fromVList <$> val+> indexFront (nMul parts (Nat each)) vs (i * each + j)+>+> , "splitAt" ~> vFinPoly $ \front -> pure $+> VNumPoly $ \back -> pure $+> VPoly $ \_a -> pure $+> VFun $ \v ->+> let xs = pure $ generateV (Nat front) $ \i ->+> do vs <- fromVList <$> v+> indexFront (nAdd (Nat front) back) vs i+> ys = pure $ generateV back $ \i ->+> do vs <- fromVList <$> v+> indexFront (nAdd (Nat front) back) vs (front+i)+> in pure (VTuple [ xs, ys ])+>+> , "reverse" ~> vFinPoly $ \n -> pure $+> VPoly $ \_a -> pure $+> VFun $ \v ->+> pure $ generateV (Nat n) $ \i ->+> do vs <- fromVList <$> v+> indexBack (Nat n) vs i+>+> , "transpose" ~> VNumPoly $ \rows -> pure $+> VNumPoly $ \cols -> pure $+> VPoly $ \_a -> pure $+> VFun $ \val ->+> pure $ generateV cols $ \c ->+> pure $ generateV rows $ \r ->+> do xss <- fromVList <$> val+> xs <- fromVList <$> indexFront rows xss r+> indexFront cols xs c+>+> -- Shifting:+> , "<<" ~> shiftV shiftLV+> , ">>" ~> shiftV shiftRV+> , "<<<" ~> rotateV rotateLV+> , ">>>" ~> rotateV rotateRV+>+> -- Indexing:+> , "@" ~> indexPrimOne indexFront+> , "!" ~> indexPrimOne indexBack+> , "update" ~> updatePrim updateFront+> , "updateEnd" ~> updatePrim updateBack+>+> -- Enumerations+> , "fromTo" ~> vFinPoly $ \first -> pure $+> vFinPoly $ \lst -> pure $+> VPoly $ \ty ->+> let f i = literal i ty+> in pure (VList (Nat (1 + lst - first)) (map f [first .. lst]))+>+> , "fromThenTo" ~> vFinPoly $ \first -> pure $+> vFinPoly $ \next -> pure $+> vFinPoly $ \_lst -> pure $+> VPoly $ \ty -> pure $+> vFinPoly $ \len ->+> let f i = literal i ty+> in pure (VList (Nat len)+> (map f (genericTake len [first, next ..])))+>+> , "infFrom" ~> VPoly $ \ty -> pure $+> VFun $ \first ->+> do x <- cryToInteger ty first+> let f i = literal (x + i) ty+> pure $ VList Inf (map f [0 ..])+>+> , "infFromThen"~> VPoly $ \ty -> pure $+> VFun $ \first -> pure $+> VFun $ \next ->+> do x <- cryToInteger ty first+> y <- cryToInteger ty next+> let diff = y - x+> f i = literal (x + diff * i) ty+> pure $ VList Inf (map f [0 ..])+>+> -- Miscellaneous:+> , "parmap" ~> VPoly $ \_a -> pure $+> VPoly $ \_b -> pure $+> VNumPoly $ \n -> pure $+> VFun $ \f -> pure $+> VFun $ \xs ->+> do f' <- fromVFun <$> f+> xs' <- fromVList <$> xs+> -- Note: the reference implementation simply+> -- executes parmap sequentially+> pure $ VList n (map f' xs')+>+> , "error" ~> VPoly $ \_a -> pure $+> VNumPoly $ \_ -> pure $+> VFun $ \s ->+> do msg <- evalString s+> cryError (UserError msg)+>+> , "random" ~> VPoly $ \_a -> pure $+> VFun $ \_seed -> cryError (UserError "random: unimplemented")+>+> , "trace" ~> VNumPoly $ \_n -> pure $+> VPoly $ \_a -> pure $+> VPoly $ \_b -> pure $+> VFun $ \s -> pure $+> VFun $ \x -> pure $+> VFun $ \y ->+> do _ <- evalString s -- evaluate and ignore s+> _ <- x -- evaluate and ignore x+> y+> ]+>+>+> evalString :: E Value -> E String+> evalString v =+> do cs <- fromVList <$> v+> ws <- mapM (fromVWord =<<) cs+> pure (map (toEnum . fromInteger) ws)+>+> unary :: (TValue -> E Value -> E Value) -> Value+> unary f = VPoly $ \ty -> pure $+> VFun $ \x -> f ty x+>+> binary :: (TValue -> E Value -> E Value -> E Value) -> Value+> binary f = VPoly $ \ty -> pure $+> VFun $ \x -> pure $+> VFun $ \y -> f ty x y+>+> appOp1 :: (a -> E b) -> E a -> E b+> appOp1 f x =+> do x' <- x+> f x'+>+> appOp2 :: (a -> b -> E c) -> E a -> E b -> E c+> appOp2 f x y =+> do x' <- x+> y' <- y+> f x' y'++Word operations+---------------++Many Cryptol primitives take numeric arguments in the form of+bitvectors. For such operations, any output bit that depends on the+numeric value is strict in *all* bits of the numeric argument. This is+implemented in function `fromVWord`, which converts a value from a+big-endian binary format to an integer. The result is an evaluation+error if any of the input bits contain an evaluation error.++> fromVWord :: Value -> E Integer+> fromVWord v = bitsToInteger <$> traverse (fmap fromVBit) (fromVList v)+>+> -- | Convert a list of booleans in big-endian format to an integer.+> bitsToInteger :: [Bool] -> Integer+> bitsToInteger bs = foldl f 0 bs+> where f x b = if b then 2 * x + 1 else 2 * x++> fromSignedVWord :: Value -> E Integer+> fromSignedVWord v = signedBitsToInteger <$> traverse (fmap fromVBit) (fromVList v)+>+> -- | Convert a list of booleans in signed big-endian format to an integer.+> signedBitsToInteger :: [Bool] -> Integer+> signedBitsToInteger [] =+> evalPanic "signedBitsToInteger" ["Bitvector has zero length"]+> signedBitsToInteger (b0 : bs) = foldl f (if b0 then -1 else 0) bs+> where f x b = if b then 2 * x + 1 else 2 * x++Function `vWord` converts an integer back to the big-endian bitvector+representation.++> vWord :: Integer -> Integer -> Value+> vWord w e+> | w > toInteger (maxBound :: Int) =+> evalPanic "vWord" ["Word length too large", show w]+> | otherwise =+> VList (Nat w) [ mkBit i | i <- [w-1, w-2 .. 0 ] ]+> where+> mkBit i = pure (VBit (testBit e (fromInteger i)))++Errors+------++> cryError :: EvalError -> E a+> cryError e = Err e++Zero+----++The `Zero` class has a single method `zero` which computes+a zero value for all the built-in types for Cryptol.+For bits, bitvectors and the base numeric types, this+returns the obvious 0 representation. For sequences, records,+and tuples, the zero method operates pointwise the underlying types.+For functions, `zero` returns the constant function that returns+`zero` in the codomain.++> zero :: TValue -> Value+> zero TVBit = VBit False+> zero TVInteger = VInteger 0+> zero TVIntMod{} = VInteger 0+> zero TVRational = VRational 0+> zero (TVFloat e p) = VFloat (fpToBF e p FP.bfPosZero)+> zero TVArray{} = evalPanic "zero" ["Array type not in `Zero`"]+> zero (TVSeq n ety) = VList (Nat n) (genericReplicate n (pure (zero ety)))+> zero (TVStream ety) = VList Inf (repeat (pure (zero ety)))+> zero (TVTuple tys) = VTuple (map (pure . zero) tys)+> zero (TVRec fields) = VRecord [ (f, pure (zero fty))+> | (f, fty) <- canonicalFields fields ]+> zero (TVFun _ bty) = VFun (\_ -> pure (zero bty))+> zero (TVAbstract{}) = evalPanic "zero" ["Abstract type not in `Zero`"]+++Literals+--------++Given a literal integer, construct a value of a type that can represent that literal.++> literal :: Integer -> TValue -> E Value+> literal i = go+> where+> go TVInteger = pure (VInteger i)+> go TVRational = pure (VRational (fromInteger i))+> go (TVIntMod n)+> | i < n = pure (VInteger i)+> | otherwise = evalPanic "literal"+> ["Literal out of range for type Z " ++ show n]+> go (TVSeq w a)+> | isTBit a = pure (vWord w i)+> go ty = evalPanic "literal" [show ty ++ " cannot represent literals"]+++Given a fraction, construct a value of a type that can represent that literal.+The rounding flag determines the behavior if the literal cannot be represented+exactly: 0 means report and error, other numbers round to the nearest+representable value.++> -- TODO: we should probably be using the rounding mode here...+> fraction :: Integer -> Integer -> Integer -> TValue -> E Value+> fraction top btm _rnd ty =+> case ty of+> TVRational -> pure (VRational (top % btm))+> TVFloat e p -> pure $ VFloat $ fpToBF e p $ FP.fpCheckStatus val+> where val = FP.bfDiv opts (FP.bfFromInteger top) (FP.bfFromInteger btm)+> opts = FP.fpOpts e p fpImplicitRound+> _ -> evalPanic "fraction" [show ty ++ " cannot represent " +++> show top ++ "/" ++ show btm]+++Logic+-----++Bitwise logic primitives are defined by recursion over the type+structure. On type `Bit`, the operations are strict in all+arguments. For example, `True || error "foo"`+does not evaluate to `True`, but yields a run-time exception. On other+types, run-time exceptions on input bits only affect the output bits+at the same positions.++> logicUnary :: (Bool -> Bool) -> TValue -> E Value -> E Value+> logicUnary op = go+> where+> go :: TValue -> E Value -> E Value+> go ty val =+> case ty of+> TVBit -> VBit . op . fromVBit <$> val+> TVSeq w ety -> VList (Nat w) . map (go ety) . fromVList <$> val+> TVStream ety -> VList Inf . map (go ety) . fromVList <$> val+> TVTuple etys -> VTuple . zipWith go etys . fromVTuple <$> val+> TVRec fields ->+> do val' <- val+> pure $ VRecord [ (f, go fty (lookupRecord f val'))+> | (f, fty) <- canonicalFields fields ]+> TVFun _ bty -> pure $ VFun (\v -> go bty (appFun val v))+> TVInteger -> evalPanic "logicUnary" ["Integer not in class Logic"]+> TVIntMod _ -> evalPanic "logicUnary" ["Z not in class Logic"]+> TVArray{} -> evalPanic "logicUnary" ["Array not in class Logic"]+> TVRational -> evalPanic "logicUnary" ["Rational not in class Logic"]+> TVFloat{} -> evalPanic "logicUnary" ["Float not in class Logic"]+> TVAbstract{} -> evalPanic "logicUnary" ["Abstract type not in `Logic`"]++> logicBinary :: (Bool -> Bool -> Bool) -> TValue -> E Value -> E Value -> E Value+> logicBinary op = go+> where+> go :: TValue -> E Value -> E Value -> E Value+> go ty l r =+> case ty of+> TVBit ->+> VBit <$> (op <$> (fromVBit <$> l) <*> (fromVBit <$> r))+> TVSeq w ety ->+> VList (Nat w) <$> (zipWith (go ety) <$>+> (fromVList <$> l) <*>+> (fromVList <$> r))+> TVStream ety ->+> VList Inf <$> (zipWith (go ety) <$>+> (fromVList <$> l) <*>+> (fromVList <$> r))+> TVTuple etys ->+> VTuple <$> (zipWith3 go etys <$>+> (fromVTuple <$> l) <*>+> (fromVTuple <$> r))+> TVRec fields ->+> do l' <- l+> r' <- r+> pure $ VRecord+> [ (f, go fty (lookupRecord f l') (lookupRecord f r'))+> | (f, fty) <- canonicalFields fields+> ]+> TVFun _ bty -> pure $ VFun $ \v ->+> do l' <- l+> r' <- r+> go bty (fromVFun l' v) (fromVFun r' v)+> TVInteger -> evalPanic "logicBinary" ["Integer not in class Logic"]+> TVIntMod _ -> evalPanic "logicBinary" ["Z not in class Logic"]+> TVArray{} -> evalPanic "logicBinary" ["Array not in class Logic"]+> TVRational -> evalPanic "logicBinary" ["Rational not in class Logic"]+> TVFloat{} -> evalPanic "logicBinary" ["Float not in class Logic"]+> TVAbstract{} -> evalPanic "logicBinary" ["Abstract type not in `Logic`"]+++Ring Arithmetic+---------------++Ring primitives may be applied to any type that is made up of+finite bitvectors or one of the numeric base types.+On type `[n]`, arithmetic operators are strict in+all input bits, as indicated by the definition of `fromVWord`. For+example, `[error "foo", True] * 2` does not evaluate to `[True,+False]`, but to `error "foo"`.++> ringNullary ::+> E Integer ->+> E Rational ->+> (Integer -> Integer -> E BigFloat) ->+> TValue -> E Value+> ringNullary i q fl = go+> where+> go :: TValue -> E Value+> go ty =+> case ty of+> TVBit ->+> evalPanic "arithNullary" ["Bit not in class Ring"]+> TVInteger ->+> VInteger <$> i+> TVIntMod n ->+> VInteger . flip mod n <$> i+> TVRational ->+> VRational <$> q+> TVFloat e p ->+> VFloat . fpToBF e p <$> fl e p+> TVArray{} ->+> evalPanic "arithNullary" ["Array not in class Ring"]+> TVSeq w a+> | isTBit a -> vWord w <$> i+> | otherwise -> pure $ VList (Nat w) (genericReplicate w (go a))+> TVStream a ->+> pure $ VList Inf (repeat (go a))+> TVFun _ ety ->+> pure $ VFun (const (go ety))+> TVTuple tys ->+> pure $ VTuple (map go tys)+> TVRec fs ->+> pure $ VRecord [ (f, go fty) | (f, fty) <- canonicalFields fs ]+> TVAbstract {} ->+> evalPanic "arithNullary" ["Abstract type not in `Ring`"]++> ringUnary ::+> (Integer -> E Integer) ->+> (Rational -> E Rational) ->+> (Integer -> Integer -> BigFloat -> E BigFloat) ->+> TValue -> E Value -> E Value+> ringUnary iop qop flop = go+> where+> go :: TValue -> E Value -> E Value+> go ty val =+> case ty of+> TVBit ->+> evalPanic "arithUnary" ["Bit not in class Ring"]+> TVInteger ->+> VInteger <$> appOp1 iop (fromVInteger <$> val)+> TVArray{} ->+> evalPanic "arithUnary" ["Array not in class Ring"]+> TVIntMod n ->+> VInteger <$> appOp1 (\i -> flip mod n <$> iop i) (fromVInteger <$> val)+> TVRational ->+> VRational <$> appOp1 qop (fromVRational <$> val)+> TVFloat e p ->+> VFloat . fpToBF e p <$> appOp1 (flop e p) (fromVFloat <$> val)+> TVSeq w a+> | isTBit a -> vWord w <$> (iop =<< (fromVWord =<< val))+> | otherwise -> VList (Nat w) . map (go a) . fromVList <$> val+> TVStream a ->+> VList Inf . map (go a) . fromVList <$> val+> TVFun _ ety ->+> pure $ VFun (\x -> go ety (appFun val x))+> TVTuple tys ->+> VTuple . zipWith go tys . fromVTuple <$> val+> TVRec fs ->+> do val' <- val+> pure $ VRecord [ (f, go fty (lookupRecord f val'))+> | (f, fty) <- canonicalFields fs ]+> TVAbstract {} ->+> evalPanic "arithUnary" ["Abstract type not in `Ring`"]++> ringBinary ::+> (Integer -> Integer -> E Integer) ->+> (Rational -> Rational -> E Rational) ->+> (Integer -> Integer -> BigFloat -> BigFloat -> E BigFloat) ->+> TValue -> E Value -> E Value -> E Value+> ringBinary iop qop flop = go+> where+> go :: TValue -> E Value -> E Value -> E Value+> go ty l r =+> case ty of+> TVBit ->+> evalPanic "arithBinary" ["Bit not in class Ring"]+> TVInteger ->+> VInteger <$> appOp2 iop (fromVInteger <$> l) (fromVInteger <$> r)+> TVIntMod n ->+> VInteger <$> appOp2 (\i j -> flip mod n <$> iop i j) (fromVInteger <$> l) (fromVInteger <$> r)+> TVRational ->+> VRational <$> appOp2 qop (fromVRational <$> l) (fromVRational <$> r)+> TVFloat e p ->+> VFloat . fpToBF e p <$>+> appOp2 (flop e p) (fromVFloat <$> l) (fromVFloat <$> r)+> TVArray{} ->+> evalPanic "arithBinary" ["Array not in class Ring"]+> TVSeq w a+> | isTBit a -> vWord w <$> appOp2 iop (fromVWord =<< l) (fromVWord =<< r)+> | otherwise ->+> VList (Nat w) <$> (zipWith (go a) <$>+> (fromVList <$> l) <*>+> (fromVList <$> r))+> TVStream a ->+> VList Inf <$> (zipWith (go a) <$>+> (fromVList <$> l) <*>+> (fromVList <$> r))+> TVFun _ ety ->+> pure $ VFun (\x -> go ety (appFun l x) (appFun r x))+> TVTuple tys ->+> VTuple <$> (zipWith3 go tys <$>+> (fromVTuple <$> l) <*>+> (fromVTuple <$> r))+> TVRec fs ->+> do l' <- l+> r' <- r+> pure $ VRecord+> [ (f, go fty (lookupRecord f l') (lookupRecord f r'))+> | (f, fty) <- canonicalFields fs ]+> TVAbstract {} ->+> evalPanic "arithBinary" ["Abstract type not in class `Ring`"]+++Integral+---------++> cryToInteger :: TValue -> E Value -> E Integer+> cryToInteger ty v = case ty of+> TVInteger -> fromVInteger <$> v+> TVSeq _ a | isTBit a -> fromVWord =<< v+> _ -> evalPanic "toInteger" [show ty ++ " is not an integral type"]+>+> integralBinary ::+> (Integer -> Integer -> E Integer) ->+> TValue -> E Value -> E Value -> E Value+> integralBinary op ty x y = case ty of+> TVInteger ->+> VInteger <$> appOp2 op (fromVInteger <$> x) (fromVInteger <$> y)+> TVSeq w a | isTBit a ->+> vWord w <$> appOp2 op (fromVWord =<< x) (fromVWord =<< y)+>+> _ -> evalPanic "integralBinary" [show ty ++ " is not an integral type"]+>+> ringExp :: TValue -> E Value -> Integer -> E Value+> ringExp a v i = foldl (ringMul a) (literal 1 a) (genericReplicate i v)+>+> ringMul :: TValue -> E Value -> E Value -> E Value+> ringMul = ringBinary (\x y -> pure (x * y))+> (\x y -> pure (x * y))+> (fpBin FP.bfMul fpImplicitRound)+++Signed bitvector division (`/$`) and remainder (`%$`) are defined so+that division rounds toward zero, and the remainder `x %$ y` has the+same sign as `x`. Accordingly, they are implemented with Haskell's+`quot` and `rem` operations.++> divWrap :: Integer -> Integer -> E Integer+> divWrap _ 0 = cryError DivideByZero+> divWrap x y = pure (x `quot` y)+>+> modWrap :: Integer -> Integer -> E Integer+> modWrap _ 0 = cryError DivideByZero+> modWrap x y = pure (x `rem` y)+>+> lg2Wrap :: Integer -> E Integer+> lg2Wrap x = if x < 0 then cryError LogNegative else pure (lg2 x)+++Field+-----++Types that represent fields have, in addition to the ring operations,+a reciprocal operator and a field division operator (not to be+confused with integral division).++> fieldUnary :: (Rational -> E Rational) ->+> (Integer -> Integer -> E Integer) ->+> (Integer -> Integer -> BigFloat -> E BigFloat) ->+> TValue -> E Value -> E Value+> fieldUnary qop zop flop ty v = case ty of+> TVRational -> VRational <$> appOp1 qop (fromVRational <$> v)+> TVIntMod m -> VInteger <$> appOp1 (zop m) (fromVInteger <$> v)+> TVFloat e p -> VFloat . fpToBF e p <$> appOp1 (flop e p) (fromVFloat <$> v)+> _ -> evalPanic "fieldUnary" [show ty ++ " is not a Field type"]+>+> fieldBinary ::+> (Rational -> Rational -> E Rational) ->+> (Integer -> Integer -> Integer -> E Integer) ->+> (Integer -> Integer -> BigFloat -> BigFloat -> E BigFloat) ->+> TValue -> E Value -> E Value -> E Value+> fieldBinary qop zop flop ty l r = case ty of+> TVRational -> VRational <$>+> appOp2 qop (fromVRational <$> l) (fromVRational <$> r)+> TVIntMod m -> VInteger <$>+> appOp2 (zop m) (fromVInteger <$> l) (fromVInteger <$> r)+> TVFloat e p -> VFloat . fpToBF e p <$>+> appOp2 (flop e p) (fromVFloat <$> l) (fromVFloat <$> r)+> _ -> evalPanic "fieldBinary" [show ty ++ " is not a Field type"]+>+> ratDiv :: Rational -> Rational -> E Rational+> ratDiv _ 0 = cryError DivideByZero+> ratDiv x y = pure (x / y)+>+> ratRecip :: Rational -> E Rational+> ratRecip 0 = cryError DivideByZero+> ratRecip x = pure (recip x)+>+> zRecip :: Integer -> Integer -> E Integer+> zRecip m x = if r == 0 then cryError DivideByZero else pure r+> where r = Integer.recipModInteger x m+>+> zDiv :: Integer -> Integer -> Integer -> E Integer+> zDiv m x y = f <$> zRecip m y+> where f yinv = (x * yinv) `mod` m++Round+-----++> roundUnary :: (Rational -> Integer) ->+> (BF -> E Integer) ->+> TValue -> E Value -> E Value+> roundUnary op flop ty v = case ty of+> TVRational -> VInteger . op . fromVRational <$> v+> TVFloat {} -> VInteger <$> (flop . fromVFloat' =<< v)+> _ -> evalPanic "roundUnary" [show ty ++ " is not a Round type"]+>++Haskell's definition of "round" is slightly different, as it does+"round to even" on ties.++> roundAwayRat :: Rational -> Integer+> roundAwayRat x+> | x >= 0 = floor (x + 0.5)+> | otherwise = ceiling (x - 0.5)+++Rational+----------++> ratioOp :: Integer -> Integer -> E Rational+> ratioOp _ 0 = cryError DivideByZero+> ratioOp x y = pure (fromInteger x / fromInteger y)+++Comparison+----------++Comparison primitives may be applied to any type that is constructed of+out of base types and tuples, records and finite sequences.+All such types are compared using a lexicographic ordering of components.+On bits, we have `False` < `True`. Sequences and+tuples are compared left-to-right, and record fields are compared in+alphabetical order.++Comparisons on base types are strict in both arguments. Comparisons on+larger types have short-circuiting behavior: A comparison involving an+error/undefined element will only yield an error if all corresponding+bits to the *left* of that position are equal.++> -- | Process two elements based on their lexicographic ordering.+> cmpOrder :: (Ordering -> Bool) -> TValue -> E Value -> E Value -> E Value+> cmpOrder p ty l r = VBit . p <$> lexCompare ty l r+>+> -- | Lexicographic ordering on two values.+> lexCompare :: TValue -> E Value -> E Value -> E Ordering+> lexCompare ty l r =+> case ty of+> TVBit ->+> compare <$> (fromVBit <$> l) <*> (fromVBit <$> r)+> TVInteger ->+> compare <$> (fromVInteger <$> l) <*> (fromVInteger <$> r)+> TVIntMod _ ->+> compare <$> (fromVInteger <$> l) <*> (fromVInteger <$> r)+> TVRational ->+> compare <$> (fromVRational <$> l) <*> (fromVRational <$> r)+> TVFloat{} ->+> compare <$> (fromVFloat <$> l) <*> (fromVFloat <$> r)+> TVArray{} ->+> evalPanic "lexCompare" ["invalid type"]+> TVSeq _w ety ->+> lexList =<< (zipWith (lexCompare ety) <$>+> (fromVList <$> l) <*> (fromVList <$> r))+> TVStream _ ->+> evalPanic "lexCompare" ["invalid type"]+> TVFun _ _ ->+> evalPanic "lexCompare" ["invalid type"]+> TVTuple etys ->+> lexList =<< (zipWith3 lexCompare etys <$>+> (fromVTuple <$> l) <*> (fromVTuple <$> r))+> TVRec fields ->+> do let tys = map snd (canonicalFields fields)+> ls <- map snd . sortBy (comparing fst) . fromVRecord <$> l+> rs <- map snd . sortBy (comparing fst) . fromVRecord <$> r+> lexList (zipWith3 lexCompare tys ls rs)+> TVAbstract {} ->+> evalPanic "lexCompare" ["Abstract type not in `Cmp`"]+>+> lexList :: [E Ordering] -> E Ordering+> lexList [] = pure EQ+> lexList (e : es) =+> e >>= \case+> LT -> pure LT+> EQ -> lexList es+> GT -> pure GT++Signed comparisons may be applied to any type made up of non-empty+bitvectors using finite sequences, tuples and records.+All such types are compared using a lexicographic+ordering: Lists and tuples are compared left-to-right, and record+fields are compared in alphabetical order.++> signedLessThan :: TValue -> E Value -> E Value -> E Value+> signedLessThan ty l r = VBit . (== LT) <$> (lexSignedCompare ty l r)+>+> -- | Lexicographic ordering on two signed values.+> lexSignedCompare :: TValue -> E Value -> E Value -> E Ordering+> lexSignedCompare ty l r =+> case ty of+> TVBit ->+> evalPanic "lexSignedCompare" ["invalid type"]+> TVInteger ->+> evalPanic "lexSignedCompare" ["invalid type"]+> TVIntMod _ ->+> evalPanic "lexSignedCompare" ["invalid type"]+> TVRational ->+> evalPanic "lexSignedCompare" ["invalid type"]+> TVFloat{} ->+> evalPanic "lexSignedCompare" ["invalid type"]+> TVArray{} ->+> evalPanic "lexSignedCompare" ["invalid type"]+> TVSeq _w ety+> | isTBit ety ->+> compare <$> (fromSignedVWord =<< l) <*> (fromSignedVWord =<< r)+> | otherwise ->+> lexList =<< (zipWith (lexSignedCompare ety) <$>+> (fromVList <$> l) <*> (fromVList <$> r))+> TVStream _ ->+> evalPanic "lexSignedCompare" ["invalid type"]+> TVFun _ _ ->+> evalPanic "lexSignedCompare" ["invalid type"]+> TVTuple etys ->+> lexList =<< (zipWith3 lexSignedCompare etys <$>+> (fromVTuple <$> l) <*> (fromVTuple <$> r))+> TVRec fields ->+> do let tys = map snd (canonicalFields fields)+> ls <- map snd . sortBy (comparing fst) . fromVRecord <$> l+> rs <- map snd . sortBy (comparing fst) . fromVRecord <$> r+> lexList (zipWith3 lexSignedCompare tys ls rs)+> TVAbstract {} ->+> evalPanic "lexSignedCompare" ["Abstract type not in `Cmp`"]+++Sequences+---------++> generateV :: Nat' -> (Integer -> E Value) -> Value+> generateV len f = VList len [ f i | i <- idxs ]+> where+> idxs = case len of+> Inf -> [ 0 .. ]+> Nat n -> [ 0 .. n-1 ]+++Shifting+--------++Shift and rotate operations are strict in all bits of the shift/rotate+amount, but as lazy as possible in the list values.++> shiftV :: (Nat' -> TValue -> E Value -> Integer -> Value) -> Value+> shiftV op =+> VNumPoly $ \n -> pure $+> VPoly $ \ix -> pure $+> VPoly $ \a -> pure $+> VFun $ \v -> pure $+> VFun $ \x ->+> do i <- cryToInteger ix x+> pure $ op n a v i+>+> shiftLV :: Nat' -> TValue -> E Value -> Integer -> Value+> shiftLV w a v amt =+> case w of+> Inf -> generateV Inf $ \i ->+> do vs <- fromVList <$> v+> indexFront Inf vs (i + amt)+> Nat n -> generateV (Nat n) $ \i ->+> if i + amt < n then+> do vs <- fromVList <$> v+> indexFront (Nat n) vs (i + amt)+> else+> pure (zero a)+>+> shiftRV :: Nat' -> TValue -> E Value -> Integer -> Value+> shiftRV w a v amt =+> generateV w $ \i ->+> if i < amt then+> pure (zero a)+> else+> do vs <- fromVList <$> v+> indexFront w vs (i - amt)+>+> rotateV :: (Integer -> E Value -> Integer -> E Value) -> Value+> rotateV op =+> vFinPoly $ \n -> pure $+> VPoly $ \ix -> pure $+> VPoly $ \_a -> pure $+> VFun $ \v -> pure $+> VFun $ \x ->+> do i <- cryToInteger ix x+> op n v i+>+> rotateLV :: Integer -> E Value -> Integer -> E Value+> rotateLV 0 v _ = v+> rotateLV w v amt =+> pure $ generateV (Nat w) $ \i ->+> do vs <- fromVList <$> v+> indexFront (Nat w) vs ((i + amt) `mod` w)+>+> rotateRV :: Integer -> E Value -> Integer -> E Value+> rotateRV 0 v _ = v+> rotateRV w v amt =+> pure $ generateV (Nat w) $ \i ->+> do vs <- fromVList <$> v+> indexFront (Nat w) vs ((i - amt) `mod` w)+>+> signedShiftRV :: Value+> signedShiftRV =+> VNumPoly $ \(Nat n) -> pure $+> VPoly $ \ix -> pure $+> VFun $ \v -> pure $+> VFun $ \x ->+> do amt <- cryToInteger ix x+> pure $ generateV (Nat n) $ \i ->+> do vs <- fromVList <$> v+> if i < amt then+> indexFront (Nat n) vs 0+> else+> indexFront (Nat n) vs (i - amt)++Indexing+--------++Indexing and update operations are strict in all index bits, but as lazy as+possible in the list values. An index greater than or equal to the+length of the list produces a run-time error.++> -- | Indexing operations that return one element.+> indexPrimOne :: (Nat' -> [E Value] -> Integer -> E Value) -> Value+> indexPrimOne op =+> VNumPoly $ \n -> pure $+> VPoly $ \_a -> pure $+> VPoly $ \ix -> pure $+> VFun $ \l -> pure $+> VFun $ \r ->+> do vs <- fromVList <$> l+> i <- cryToInteger ix r+> op n vs i+>+> indexFront :: Nat' -> [E Value] -> Integer -> E Value+> indexFront w vs ix =+> case w of+> Nat n | 0 <= ix && ix < n -> genericIndex vs ix+> Inf | 0 <= ix -> genericIndex vs ix+> _ -> cryError (InvalidIndex (Just ix))+>+> indexBack :: Nat' -> [E Value] -> Integer -> E Value+> indexBack w vs ix =+> case w of+> Nat n | 0 <= ix && ix < n -> genericIndex vs (n - ix - 1)+> | otherwise -> cryError (InvalidIndex (Just ix))+> Inf -> evalPanic "indexBack" ["unexpected infinite sequence"]+>+> updatePrim :: (Nat' -> Integer -> Integer) -> Value+> updatePrim op =+> VNumPoly $ \len -> pure $+> VPoly $ \_eltTy -> pure $+> VPoly $ \ix -> pure $+> VFun $ \xs -> pure $+> VFun $ \idx -> pure $+> VFun $ \val ->+> do j <- cryToInteger ix idx+> if Nat j < len then+> pure $ generateV len $ \i ->+> if i == op len j then+> val+> else+> do xs' <- fromVList <$> xs+> indexFront len xs' i+> else+> cryError (InvalidIndex (Just j))+>+> updateFront :: Nat' -> Integer -> Integer+> updateFront _ j = j+>+> updateBack :: Nat' -> Integer -> Integer+> updateBack Inf _j = evalPanic "Unexpected infinite sequence in updateEnd" []+> updateBack (Nat n) j = n - j - 1++Floating Point Numbers+----------------------++Whenever we do operations that do not have an explicit rounding mode,+we round towards the closest number, with ties resolved to the even one.++> fpImplicitRound :: FP.RoundMode+> fpImplicitRound = FP.NearEven++We annotate floating point values with their precision. This is only used+when pretty printing values.++> fpToBF :: Integer -> Integer -> BigFloat -> BF+> fpToBF e p x = BF { bfValue = x, bfExpWidth = e, bfPrecWidth = p }+++The following two functions convert between floaitng point numbers+and integers.++> fpFromInteger :: Integer -> Integer -> Integer -> BigFloat+> fpFromInteger e p = FP.fpCheckStatus . FP.bfRoundFloat opts . FP.bfFromInteger+> where opts = FP.fpOpts e p fpImplicitRound++These functions capture the interactions with rationals.+++This just captures a common pattern for binary floating point primitives.++> fpBin :: (FP.BFOpts -> BigFloat -> BigFloat -> (BigFloat,FP.Status)) ->+> FP.RoundMode -> Integer -> Integer ->+> BigFloat -> BigFloat -> E BigFloat+> fpBin f r e p x y = pure (FP.fpCheckStatus (f (FP.fpOpts e p r) x y))+++Computes the reciprocal of a floating point number via division.+This assumes that 1 can be represented exactly, which should be+true for all supported precisions.++> fpRecip :: Integer -> Integer -> BigFloat -> E BigFloat+> fpRecip e p x = pure (FP.fpCheckStatus (FP.bfDiv opts (FP.bfFromInteger 1) x))+> where opts = FP.fpOpts e p fpImplicitRound+++> floatPrimTable :: Map PrimIdent Value+> floatPrimTable = Map.fromList $ map (\(n, v) -> (floatPrim (T.pack n), v))+> [ "fpNaN" ~> vFinPoly \e -> pure $+> vFinPoly \p ->+> pure $ VFloat $ fpToBF e p FP.bfNaN+>+> , "fpPosInf" ~> vFinPoly \e -> pure $+> vFinPoly \p ->+> pure $ VFloat $ fpToBF e p FP.bfPosInf+>+> , "fpFromBits" ~> vFinPoly \e -> pure $+> vFinPoly \p -> pure $+> VFun \bvv ->+> VFloat . FP.floatFromBits e p <$> (fromVWord =<< bvv)+>+> , "fpToBits" ~> vFinPoly \e -> pure $+> vFinPoly \p -> pure $+> VFun \fpv ->+> vWord (e + p) . FP.floatToBits e p . fromVFloat <$> fpv+>+> , "=.=" ~> vFinPoly \_ -> pure $+> vFinPoly \_ -> pure $+> VFun \xv -> pure $+> VFun \yv ->+> do x <- fromVFloat <$> xv+> y <- fromVFloat <$> yv+> pure (VBit (FP.bfCompare x y == EQ))+>+> , "fpIsFinite" ~> vFinPoly \_ -> pure $+> vFinPoly \_ -> pure $+> VFun \xv ->+> do x <- fromVFloat <$> xv+> pure (VBit (FP.bfIsFinite x))+>+> , "fpAdd" ~> fpArith FP.bfAdd+> , "fpSub" ~> fpArith FP.bfSub+> , "fpMul" ~> fpArith FP.bfMul+> , "fpDiv" ~> fpArith FP.bfDiv+>+> , "fpToRational" ~>+> vFinPoly \_ -> pure $+> vFinPoly \_ -> pure $+> VFun \fpv ->+> do fp <- fromVFloat' <$> fpv+> VRational <$> (eitherToE (FP.floatToRational "fpToRational" fp))+> , "fpFromRational" ~>+> vFinPoly \e -> pure $+> vFinPoly \p -> pure $+> VFun \rmv -> pure $+> VFun \rv ->+> do rm <- fromVWord =<< rmv+> rm' <- eitherToE (FP.fpRound rm)+> rat <- fromVRational <$> rv+> pure (VFloat (FP.floatFromRational e p rm' rat))+> ]+> where+> fpArith f = vFinPoly \e -> pure $+> vFinPoly \p -> pure $+> VFun \vr -> pure $+> VFun \xv -> pure $+> VFun \yv ->+> do r <- fromVWord =<< vr+> rnd <- eitherToE (FP.fpRound r)+> x <- fromVFloat <$> xv+> y <- fromVFloat <$> yv+> VFloat . fpToBF e p <$> fpBin f rnd e p x y+++Error Handling+--------------++The `evalPanic` function is only called if an internal data invariant+is violated, such as an expression that is not well-typed. Panics+should (hopefully) never occur in practice; a panic message indicates+a bug in Cryptol.++> evalPanic :: String -> [String] -> a+> evalPanic cxt = panic ("[Reference Evaluator]" ++ cxt)++Pretty Printing+---------------++> ppEValue :: PPOpts -> E Value -> Doc+> ppEValue _opts (Err e) = text (show e)+> ppEValue opts (Value v) = ppValue opts v+>+> ppValue :: PPOpts -> Value -> Doc+> ppValue opts val =+> case val of+> VBit b -> text (show b)+> VInteger i -> text (show i)+> VRational q -> text (show q)+> VFloat fl -> text (show (FP.fpPP opts fl))+> VList l vs ->+> case l of+> Inf -> ppList (map (ppEValue opts)+> (take (useInfLength opts) vs) ++ [text "..."])+> Nat n ->+> -- For lists of defined bits, print the value as a numeral.+> case traverse isBit vs of+> Just bs -> ppBV opts (mkBv n (bitsToInteger bs))+> Nothing -> ppList (map (ppEValue opts) vs)+> where ppList docs = brackets (fsep (punctuate comma docs))+> isBit v = case v of Value (VBit b) -> Just b+> _ -> Nothing+> VTuple vs -> parens (sep (punctuate comma (map (ppEValue opts) vs)))+> VRecord fs -> braces (sep (punctuate comma (map ppField fs)))+> where ppField (f,r) = pp f <+> char '=' <+> ppEValue opts r+> VFun _ -> text "<function>"+> VPoly _ -> text "<polymorphic value>"+> VNumPoly _ -> text "<polymorphic value>"++Module Command+--------------++This module implements the core functionality of the `:eval+<expression>` command for the Cryptol REPL, which prints the result of+running the reference evaluator on an expression.++> evaluate :: Expr -> M.ModuleCmd (E Value) > evaluate expr (_, _, modEnv) = return (Right (evalExpr env expr, modEnv), []) > where > extDgs = concatMap mDecls (M.loadedModules modEnv)
src/Cryptol/Eval/SBV.hs view
@@ -11,357 +11,43 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE MultiWayIf #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE ViewPatterns #-} module Cryptol.Eval.SBV- ( SBV(..), Value- , SBVEval(..), SBVResult(..)- , evalPrim- , forallBV_, existsBV_- , forallSBool_, existsSBool_- , forallSInteger_, existsSInteger_+ ( primTable ) where import qualified Control.Exception as X import Control.Monad (join) import Control.Monad.IO.Class (MonadIO(..))-import Data.Bits (bit, complement, shiftL)-import Data.List (foldl')+import Data.Bits (bit, shiftL) import qualified Data.Map as Map import qualified Data.Text as T -import Data.SBV (symbolicEnv) import Data.SBV.Dynamic as SBV +import Cryptol.Backend+import Cryptol.Backend.Monad ( EvalError(..), Unsupported(..) )+import Cryptol.Backend.SBV+ import Cryptol.Eval.Type (TValue(..), finNat')-import Cryptol.Eval.Backend import Cryptol.Eval.Generic-import Cryptol.Eval.Monad- ( Eval(..), blackhole, delayFill, evalSpark- , EvalError(..), Unsupported(..)- ) import Cryptol.Eval.Value-import Cryptol.Eval.Concrete ( integerToChar, ppBV, BV(..) )-import Cryptol.Testing.Random( randomV ) import Cryptol.TypeCheck.Solver.InfNat (Nat'(..), widthInteger) import Cryptol.Utils.Ident-import Cryptol.Utils.Panic (panic)-import Cryptol.Utils.PP -data SBV = SBV---- Utility operations ---------------------------------------------------------------fromBitsLE :: [SBit SBV] -> SWord SBV-fromBitsLE bs = foldl' f (literalSWord 0 0) bs- where f w b = svJoin (svToWord1 b) w--packSBV :: [SBit SBV] -> SWord SBV-packSBV bs = fromBitsLE (reverse bs)--unpackSBV :: SWord SBV -> [SBit SBV]-unpackSBV x = [ svTestBit x i | i <- reverse [0 .. intSizeOf x - 1] ]--literalSWord :: Int -> Integer -> SWord SBV-literalSWord w i = svInteger (KBounded False w) i--forallBV_ :: Int -> Symbolic (SWord SBV)-forallBV_ w = symbolicEnv >>= liftIO . svMkSymVar (Just ALL) (KBounded False w) Nothing--existsBV_ :: Int -> Symbolic (SWord SBV)-existsBV_ w = symbolicEnv >>= liftIO . svMkSymVar (Just EX) (KBounded False w) Nothing--forallSBool_ :: Symbolic (SBit SBV)-forallSBool_ = symbolicEnv >>= liftIO . svMkSymVar (Just ALL) KBool Nothing--existsSBool_ :: Symbolic (SBit SBV)-existsSBool_ = symbolicEnv >>= liftIO . svMkSymVar (Just EX) KBool Nothing--forallSInteger_ :: Symbolic (SBit SBV)-forallSInteger_ = symbolicEnv >>= liftIO . svMkSymVar (Just ALL) KUnbounded Nothing--existsSInteger_ :: Symbolic (SBit SBV)-existsSInteger_ = symbolicEnv >>= liftIO . svMkSymVar (Just EX) KUnbounded Nothing- -- Values ---------------------------------------------------------------------- type Value = GenValue SBV --- SBV Evaluation monad ---------------------------------------------------------data SBVResult a- = SBVError !EvalError- | SBVResult !SVal !a -- safety predicate and result--instance Functor SBVResult where- fmap _ (SBVError err) = SBVError err- fmap f (SBVResult p x) = SBVResult p (f x)--instance Applicative SBVResult where- pure = SBVResult svTrue- SBVError err <*> _ = SBVError err- _ <*> SBVError err = SBVError err- SBVResult p1 f <*> SBVResult p2 x = SBVResult (svAnd p1 p2) (f x)--instance Monad SBVResult where- return = pure- SBVError err >>= _ = SBVError err- SBVResult px x >>= m =- case m x of- SBVError err -> SBVError err- SBVResult pm z -> SBVResult (svAnd px pm) z--newtype SBVEval a = SBVEval{ sbvEval :: Eval (SBVResult a) }- deriving (Functor)--instance Applicative SBVEval where- pure = SBVEval . pure . pure- f <*> x = SBVEval $- do f' <- sbvEval f- x' <- sbvEval x- pure (f' <*> x')--instance Monad SBVEval where- return = pure- x >>= f = SBVEval $- sbvEval x >>= \case- SBVError err -> pure (SBVError err)- SBVResult px x' ->- sbvEval (f x') >>= \case- SBVError err -> pure (SBVError err)- SBVResult pz z -> pure (SBVResult (svAnd px pz) z)--instance MonadIO SBVEval where- liftIO m = SBVEval $ fmap pure (liftIO m)----- Symbolic Big-endian Words ---------------------------------------------------------instance Backend SBV where- type SBit SBV = SVal- type SWord SBV = SVal- type SInteger SBV = SVal- type SFloat SBV = () -- XXX: not implemented- type SEval SBV = SBVEval-- raiseError _ err = SBVEval (pure (SBVError err))-- assertSideCondition _ cond err- | Just False <- svAsBool cond = SBVEval (pure (SBVError err))- | otherwise = SBVEval (pure (SBVResult cond ()))-- isReady _ (SBVEval (Ready _)) = True- isReady _ _ = False-- sDelayFill _ m retry = SBVEval $- do m' <- delayFill (sbvEval m) (sbvEval retry)- pure (pure (SBVEval m'))-- sSpark _ m = SBVEval $- do m' <- evalSpark (sbvEval m)- pure (pure (SBVEval m'))-- sDeclareHole _ msg = SBVEval $- do (hole, fill) <- blackhole msg- pure (pure (SBVEval hole, \m -> SBVEval (fmap pure $ fill (sbvEval m))))-- mergeEval _sym f c mx my = SBVEval $- do rx <- sbvEval mx- ry <- sbvEval my- case (rx, ry) of- (SBVError err, SBVError _) ->- pure $ SBVError err -- arbitrarily choose left error to report- (SBVError _, SBVResult p y) ->- pure $ SBVResult (svAnd (svNot c) p) y- (SBVResult p x, SBVError _) ->- pure $ SBVResult (svAnd c p) x- (SBVResult px x, SBVResult py y) ->- do zr <- sbvEval (f c x y)- case zr of- SBVError err -> pure $ SBVError err- SBVResult pz z ->- pure $ SBVResult (svAnd (svIte c px py) pz) z-- wordLen _ v = toInteger (intSizeOf v)- wordAsChar _ v = integerToChar <$> svAsInteger v-- ppBit _ v- | Just b <- svAsBool v = text $! if b then "True" else "False"- | otherwise = text "?"- ppWord _ opts v- | Just x <- svAsInteger v = ppBV opts (BV (wordLen SBV v) x)- | otherwise = text "[?]"- ppInteger _ _opts v- | Just x <- svAsInteger v = integer x- | otherwise = text "[?]"-- iteBit _ b x y = pure $! svSymbolicMerge KBool True b x y- iteWord _ b x y = pure $! svSymbolicMerge (kindOf x) True b x y- iteInteger _ b x y = pure $! svSymbolicMerge KUnbounded True b x y-- bitAsLit _ b = svAsBool b- wordAsLit _ w =- case svAsInteger w of- Just x -> Just (toInteger (intSizeOf w), x)- Nothing -> Nothing- integerAsLit _ v = svAsInteger v-- bitLit _ b = svBool b- wordLit _ n x = pure $! literalSWord (fromInteger n) x- integerLit _ x = pure $! svInteger KUnbounded x-- bitEq _ x y = pure $! svEqual x y- bitOr _ x y = pure $! svOr x y- bitAnd _ x y = pure $! svAnd x y- bitXor _ x y = pure $! svXOr x y- bitComplement _ x = pure $! svNot x-- wordBit _ x idx = pure $! svTestBit x (intSizeOf x - 1 - fromInteger idx)-- wordUpdate _ x idx b = pure $! svSymbolicMerge (kindOf x) False b wtrue wfalse- where- i' = intSizeOf x - 1 - fromInteger idx- wtrue = x `svOr` svInteger (kindOf x) (bit i' :: Integer)- wfalse = x `svAnd` svInteger (kindOf x) (complement (bit i' :: Integer))-- packWord _ bs = pure $! packSBV bs- unpackWord _ x = pure $! unpackSBV x-- wordEq _ x y = pure $! svEqual x y- wordLessThan _ x y = pure $! svLessThan x y- wordGreaterThan _ x y = pure $! svGreaterThan x y-- wordSignedLessThan _ x y = pure $! svLessThan sx sy- where sx = svSign x- sy = svSign y-- joinWord _ x y = pure $! svJoin x y-- splitWord _ _leftW rightW w = pure- ( svExtract (intSizeOf w - 1) (fromInteger rightW) w- , svExtract (fromInteger rightW - 1) 0 w- )-- extractWord _ len start w =- pure $! svExtract (fromInteger start + fromInteger len - 1) (fromInteger start) w-- wordAnd _ a b = pure $! svAnd a b- wordOr _ a b = pure $! svOr a b- wordXor _ a b = pure $! svXOr a b- wordComplement _ a = pure $! svNot a-- wordPlus _ a b = pure $! svPlus a b- wordMinus _ a b = pure $! svMinus a b- wordMult _ a b = pure $! svTimes a b- wordNegate _ a = pure $! svUNeg a-- wordDiv sym a b =- do let z = literalSWord (intSizeOf b) 0- assertSideCondition sym (svNot (svEqual b z)) DivideByZero- pure $! svQuot a b-- wordMod sym a b =- do let z = literalSWord (intSizeOf b) 0- assertSideCondition sym (svNot (svEqual b z)) DivideByZero- pure $! svRem a b-- wordSignedDiv sym a b =- do let z = literalSWord (intSizeOf b) 0- assertSideCondition sym (svNot (svEqual b z)) DivideByZero- pure $! signedQuot a b-- wordSignedMod sym a b =- do let z = literalSWord (intSizeOf b) 0- assertSideCondition sym (svNot (svEqual b z)) DivideByZero- pure $! signedRem a b-- wordLg2 _ a = sLg2 a-- wordToInt _ x = pure $! svToInteger x- wordFromInt _ w i = pure $! svFromInteger w i-- intEq _ a b = pure $! svEqual a b- intLessThan _ a b = pure $! svLessThan a b- intGreaterThan _ a b = pure $! svGreaterThan a b-- intPlus _ a b = pure $! svPlus a b- intMinus _ a b = pure $! svMinus a b- intMult _ a b = pure $! svTimes a b- intNegate _ a = pure $! SBV.svUNeg a-- intDiv sym a b =- do let z = svInteger KUnbounded 0- assertSideCondition sym (svNot (svEqual b z)) DivideByZero- let p = svLessThan z b- pure $! svSymbolicMerge KUnbounded True p (svQuot a b) (svQuot (svUNeg a) (svUNeg b))- intMod sym a b =- do let z = svInteger KUnbounded 0- assertSideCondition sym (svNot (svEqual b z)) DivideByZero- let p = svLessThan z b- pure $! svSymbolicMerge KUnbounded True p (svRem a b) (svUNeg (svRem (svUNeg a) (svUNeg b)))-- -- NB, we don't do reduction here- intToZn _ _m a = pure a-- znToInt _ 0 _ = evalPanic "znToInt" ["0 modulus not allowed"]- znToInt _ m a =- do let m' = svInteger KUnbounded m- pure $! svRem a m'-- znEq _ 0 _ _ = evalPanic "znEq" ["0 modulus not allowed"]- znEq _ m a b = svDivisible m (SBV.svMinus a b)-- znPlus _ m a b = sModAdd m a b- znMinus _ m a b = sModSub m a b- znMult _ m a b = sModMult m a b- znNegate _ m a = sModNegate m a-- ppFloat _ _ _ = text "[?]"- fpLit _ _ _ _ = unsupported "fpLit"- fpEq _ _ _ = unsupported "fpEq"- fpLessThan _ _ _ = unsupported "fpLessThan"- fpGreaterThan _ _ _ = unsupported "fpGreaterThan"- fpPlus _ _ _ _ = unsupported "fpPlus"- fpMinus _ _ _ _ = unsupported "fpMinus"- fpMult _ _ _ _ = unsupported "fpMult"- fpDiv _ _ _ _ = unsupported "fpDiv"- fpNeg _ _ = unsupported "fpNeg"- fpFromInteger _ _ _ _ _ = unsupported "fpFromInteger"- fpToInteger _ _ _ _ = unsupported "fpToInteger"--unsupported :: String -> SEval SBV a-unsupported x = liftIO (X.throw (UnsupportedSymbolicOp x))---svToInteger :: SWord SBV -> SInteger SBV-svToInteger w =- case svAsInteger w of- Nothing -> svFromIntegral KUnbounded w- Just x -> svInteger KUnbounded x--svFromInteger :: Integer -> SInteger SBV -> SWord SBV-svFromInteger 0 _ = literalSWord 0 0-svFromInteger n i =- case svAsInteger i of- Nothing -> svFromIntegral (KBounded False (fromInteger n)) i- Just x -> literalSWord (fromInteger n) x---- Errors ------------------------------------------------------------------------evalPanic :: String -> [String] -> a-evalPanic cxt = panic ("[Symbolic]" ++ cxt)-- -- Primitives ------------------------------------------------------------------ -evalPrim :: PrimIdent -> Maybe Value-evalPrim prim = Map.lookup prim primTable- -- See also Cryptol.Eval.Concrete.primTable-primTable :: Map.Map PrimIdent Value-primTable = let sym = SBV in+primTable :: SBV -> Map.Map PrimIdent Value+primTable sym = Map.fromList $ map (\(n, v) -> (prelPrim (T.pack n), v)) [ -- Literals@@ -411,7 +97,7 @@ , ("/$" , sdivV sym) , ("%$" , smodV sym) , ("lg2" , lg2V sym)- , (">>$" , sshrV)+ , (">>$" , sshrV sym) -- Cmp , ("<" , binary (lessThanV sym))@@ -487,16 +173,27 @@ rotateRightReindex rotateLeftReindex) -- Indexing and updates- , ("@" , indexPrim sym indexFront indexFront_bits indexFront)- , ("!" , indexPrim sym indexBack indexBack_bits indexBack)+ , ("@" , indexPrim sym (indexFront sym) (indexFront_bits sym) (indexFront sym))+ , ("!" , indexPrim sym (indexBack sym) (indexBack_bits sym) (indexBack sym)) - , ("update" , updatePrim sym updateFrontSym_word updateFrontSym)- , ("updateEnd" , updatePrim sym updateBackSym_word updateBackSym)+ , ("update" , updatePrim sym (updateFrontSym_word sym) (updateFrontSym sym))+ , ("updateEnd" , updatePrim sym (updateBackSym_word sym) (updateBackSym sym)) -- Misc , ("fromZ" , fromZV sym) + , ("foldl" , foldlV sym)+ , ("foldl'" , foldl'V sym)++ , ("deepseq" ,+ tlam $ \_a ->+ tlam $ \_b ->+ lam $ \x -> pure $+ lam $ \y ->+ do _ <- forceValue =<< x+ y)+ , ("parmap" , parmapV sym) -- {at,len} (fin len) => [len][8] -> at@@ -529,13 +226,14 @@ indexFront ::+ SBV -> Nat' -> TValue -> SeqMap SBV -> TValue -> SVal -> SEval SBV Value-indexFront mblen a xs _ix idx+indexFront sym mblen a xs _ix idx | Just i <- SBV.svAsInteger idx = lookupSeqMap xs i @@ -544,7 +242,7 @@ = do wvs <- traverse (fromWordVal "indexFront" =<<) (enumerateSeqMap n xs) case asWordList wvs of Just ws ->- do z <- wordLit SBV wlen 0+ do z <- wordLit sym wlen 0 return $ VWord wlen $ pure $ WordVal $ SBV.svSelect ws z idx Nothing -> folded @@ -553,8 +251,8 @@ where k = SBV.kindOf idx- def = zeroV SBV a- f n y = iteValue SBV (SBV.svEqual idx (SBV.svInteger k n)) (lookupSeqMap xs n) y+ def = zeroV sym a+ f n y = iteValue sym (SBV.svEqual idx (SBV.svInteger k n)) (lookupSeqMap xs n) y folded = case k of KBounded _ w ->@@ -567,30 +265,32 @@ Inf -> liftIO (X.throw (UnsupportedSymbolicOp "unbounded integer indexing")) indexBack ::+ SBV -> Nat' -> TValue -> SeqMap SBV -> TValue -> SWord SBV -> SEval SBV Value-indexBack (Nat n) a xs ix idx = indexFront (Nat n) a (reverseSeqMap n xs) ix idx-indexBack Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack"]+indexBack sym (Nat n) a xs ix idx = indexFront sym (Nat n) a (reverseSeqMap n xs) ix idx+indexBack _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack"] indexFront_bits ::+ SBV -> Nat' -> TValue -> SeqMap SBV -> TValue -> [SBit SBV] -> SEval SBV Value-indexFront_bits mblen _a xs _ix bits0 = go 0 (length bits0) bits0+indexFront_bits sym mblen _a xs _ix bits0 = go 0 (length bits0) bits0 where go :: Integer -> Int -> [SBit SBV] -> SEval SBV Value go i _k [] -- For indices out of range, fail | Nat n <- mblen , i >= n- = raiseError SBV (InvalidIndex (Just i))+ = raiseError sym (InvalidIndex (Just i)) | otherwise = lookupSeqMap xs i@@ -600,33 +300,34 @@ -- are out of bounds | Nat n <- mblen , (i `shiftL` k) >= n- = raiseError SBV (InvalidIndex Nothing)+ = raiseError sym (InvalidIndex Nothing) | otherwise- = iteValue SBV b+ = iteValue sym b (go ((i `shiftL` 1) + 1) (k-1) bs) (go (i `shiftL` 1) (k-1) bs) indexBack_bits ::+ SBV -> Nat' -> TValue -> SeqMap SBV -> TValue -> [SBit SBV] -> SEval SBV Value-indexBack_bits (Nat n) a xs ix idx = indexFront_bits (Nat n) a (reverseSeqMap n xs) ix idx-indexBack_bits Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack_bits"]+indexBack_bits sym (Nat n) a xs ix idx = indexFront_bits sym (Nat n) a (reverseSeqMap n xs) ix idx+indexBack_bits _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack_bits"] -- | Compare a symbolic word value with a concrete integer.-wordValueEqualsInteger :: WordValue SBV -> Integer -> SEval SBV (SBit SBV)-wordValueEqualsInteger wv i- | wordValueSize SBV wv < widthInteger i = return SBV.svFalse+wordValueEqualsInteger :: SBV -> WordValue SBV -> Integer -> SEval SBV (SBit SBV)+wordValueEqualsInteger sym wv i+ | wordValueSize sym wv < widthInteger i = return SBV.svFalse | otherwise = case wv of WordVal w -> return $ SBV.svEqual w (literalSWord (SBV.intSizeOf w) i)- _ -> bitsAre i <$> enumerateWordValueRev SBV wv -- little-endian+ _ -> bitsAre i <$> enumerateWordValueRev sym wv -- little-endian where bitsAre :: Integer -> [SBit SBV] -> SBit SBV bitsAre n [] = SBV.svBool (n == 0)@@ -637,49 +338,51 @@ updateFrontSym ::+ SBV -> Nat' -> TValue -> SeqMap SBV -> Either (SInteger SBV) (WordValue SBV) -> SEval SBV (GenValue SBV) -> SEval SBV (SeqMap SBV)-updateFrontSym _len _eltTy vs (Left idx) val =+updateFrontSym sym _len _eltTy vs (Left idx) val = case SBV.svAsInteger idx of Just i -> return $ updateSeqMap vs i val Nothing -> return $ IndexSeqMap $ \i ->- do b <- intEq SBV idx =<< integerLit SBV i- iteValue SBV b val (lookupSeqMap vs i)+ do b <- intEq sym idx =<< integerLit sym i+ iteValue sym b val (lookupSeqMap vs i) -updateFrontSym _len _eltTy vs (Right wv) val =+updateFrontSym sym _len _eltTy vs (Right wv) val = case wv of WordVal w | Just j <- SBV.svAsInteger w -> return $ updateSeqMap vs j val _ -> return $ IndexSeqMap $ \i ->- do b <- wordValueEqualsInteger wv i- iteValue SBV b val (lookupSeqMap vs i)+ do b <- wordValueEqualsInteger sym wv i+ iteValue sym b val (lookupSeqMap vs i) updateFrontSym_word ::+ SBV -> Nat' -> TValue -> WordValue SBV -> Either (SInteger SBV) (WordValue SBV) -> SEval SBV (GenValue SBV) -> SEval SBV (WordValue SBV)-updateFrontSym_word Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateFrontSym_bits"]+updateFrontSym_word _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateFrontSym_bits"] -updateFrontSym_word (Nat _) eltTy (LargeBitsVal n bv) idx val =- LargeBitsVal n <$> updateFrontSym (Nat n) eltTy bv idx val+updateFrontSym_word sym (Nat _) eltTy (LargeBitsVal n bv) idx val =+ LargeBitsVal n <$> updateFrontSym sym (Nat n) eltTy bv idx val -updateFrontSym_word (Nat n) eltTy (WordVal bv) (Left idx) val =- do idx' <- wordFromInt SBV n idx- updateFrontSym_word (Nat n) eltTy (WordVal bv) (Right (WordVal idx')) val+updateFrontSym_word sym (Nat n) eltTy (WordVal bv) (Left idx) val =+ do idx' <- wordFromInt sym n idx+ updateFrontSym_word sym (Nat n) eltTy (WordVal bv) (Right (WordVal idx')) val -updateFrontSym_word (Nat n) eltTy bv (Right wv) val =+updateFrontSym_word sym (Nat n) eltTy bv (Right wv) val = case wv of WordVal idx | Just j <- SBV.svAsInteger idx ->- updateWordValue SBV bv j (fromVBit <$> val)+ updateWordValue sym bv j (fromVBit <$> val) | WordVal bw <- bv -> WordVal <$>@@ -692,55 +395,57 @@ let bw' = SBV.svAnd bw (SBV.svNot msk) return $! SBV.svXOr bw' (SBV.svAnd q msk) - _ -> LargeBitsVal n <$> updateFrontSym (Nat n) eltTy (asBitsMap SBV bv) (Right wv) val+ _ -> LargeBitsVal n <$> updateFrontSym sym (Nat n) eltTy (asBitsMap sym bv) (Right wv) val updateBackSym ::+ SBV -> Nat' -> TValue -> SeqMap SBV -> Either (SInteger SBV) (WordValue SBV) -> SEval SBV (GenValue SBV) -> SEval SBV (SeqMap SBV)-updateBackSym Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateBackSym"]+updateBackSym _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateBackSym"] -updateBackSym (Nat n) _eltTy vs (Left idx) val =+updateBackSym sym (Nat n) _eltTy vs (Left idx) val = case SBV.svAsInteger idx of Just i -> return $ updateSeqMap vs (n - 1 - i) val Nothing -> return $ IndexSeqMap $ \i ->- do b <- intEq SBV idx =<< integerLit SBV (n - 1 - i)- iteValue SBV b val (lookupSeqMap vs i)+ do b <- intEq sym idx =<< integerLit sym (n - 1 - i)+ iteValue sym b val (lookupSeqMap vs i) -updateBackSym (Nat n) _eltTy vs (Right wv) val =+updateBackSym sym (Nat n) _eltTy vs (Right wv) val = case wv of WordVal w | Just j <- SBV.svAsInteger w -> return $ updateSeqMap vs (n - 1 - j) val _ -> return $ IndexSeqMap $ \i ->- do b <- wordValueEqualsInteger wv (n - 1 - i)- iteValue SBV b val (lookupSeqMap vs i)+ do b <- wordValueEqualsInteger sym wv (n - 1 - i)+ iteValue sym b val (lookupSeqMap vs i) updateBackSym_word ::+ SBV -> Nat' -> TValue -> WordValue SBV -> Either (SInteger SBV) (WordValue SBV) -> SEval SBV (GenValue SBV) -> SEval SBV (WordValue SBV)-updateBackSym_word Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateBackSym_bits"]+updateBackSym_word _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateBackSym_bits"] -updateBackSym_word (Nat _) eltTy (LargeBitsVal n bv) idx val =- LargeBitsVal n <$> updateBackSym (Nat n) eltTy bv idx val+updateBackSym_word sym (Nat _) eltTy (LargeBitsVal n bv) idx val =+ LargeBitsVal n <$> updateBackSym sym (Nat n) eltTy bv idx val -updateBackSym_word (Nat n) eltTy (WordVal bv) (Left idx) val =- do idx' <- wordFromInt SBV n idx- updateBackSym_word (Nat n) eltTy (WordVal bv) (Right (WordVal idx')) val+updateBackSym_word sym (Nat n) eltTy (WordVal bv) (Left idx) val =+ do idx' <- wordFromInt sym n idx+ updateBackSym_word sym (Nat n) eltTy (WordVal bv) (Right (WordVal idx')) val -updateBackSym_word (Nat n) eltTy bv (Right wv) val = do+updateBackSym_word sym (Nat n) eltTy bv (Right wv) val = do case wv of WordVal idx | Just j <- SBV.svAsInteger idx ->- updateWordValue SBV bv (n - 1 - j) (fromVBit <$> val)+ updateWordValue sym bv (n - 1 - j) (fromVBit <$> val) | WordVal bw <- bv -> WordVal <$>@@ -753,7 +458,7 @@ let bw' = SBV.svAnd bw (SBV.svNot msk) return $! SBV.svXOr bw' (SBV.svAnd q msk) - _ -> LargeBitsVal n <$> updateBackSym (Nat n) eltTy (asBitsMap SBV bv) (Right wv) val+ _ -> LargeBitsVal n <$> updateBackSym sym (Nat n) eltTy (asBitsMap sym bv) (Right wv) val asWordList :: [WordValue SBV] -> Maybe [SWord SBV]@@ -763,88 +468,21 @@ go f (WordVal x :vs) = go (f . (x:)) vs go _f (LargeBitsVal _ _ : _) = Nothing --sModAdd :: Integer -> SInteger SBV -> SInteger SBV -> SEval SBV (SInteger SBV)-sModAdd 0 _ _ = evalPanic "sModAdd" ["0 modulus not allowed"]-sModAdd modulus x y =- case (SBV.svAsInteger x, SBV.svAsInteger y) of- (Just i, Just j) -> integerLit SBV ((i + j) `mod` modulus)- _ -> pure $ SBV.svPlus x y--sModSub :: Integer -> SInteger SBV -> SInteger SBV -> SEval SBV (SInteger SBV)-sModSub 0 _ _ = evalPanic "sModSub" ["0 modulus not allowed"]-sModSub modulus x y =- case (SBV.svAsInteger x, SBV.svAsInteger y) of- (Just i, Just j) -> integerLit SBV ((i - j) `mod` modulus)- _ -> pure $ SBV.svMinus x y--sModNegate :: Integer -> SInteger SBV -> SEval SBV (SInteger SBV)-sModNegate 0 _ = evalPanic "sModNegate" ["0 modulus not allowed"]-sModNegate modulus x =- case SBV.svAsInteger x of- Just i -> integerLit SBV ((negate i) `mod` modulus)- _ -> pure $ SBV.svUNeg x--sModMult :: Integer -> SInteger SBV -> SInteger SBV -> SEval SBV (SInteger SBV)-sModMult 0 _ _ = evalPanic "sModMult" ["0 modulus not allowed"]-sModMult modulus x y =- case (SBV.svAsInteger x, SBV.svAsInteger y) of- (Just i, Just j) -> integerLit SBV ((i * j) `mod` modulus)- _ -> pure $ SBV.svTimes x y---- | Ceiling (log_2 x)-sLg2 :: SWord SBV -> SEval SBV (SWord SBV)-sLg2 x = pure $ go 0- where- lit n = literalSWord (SBV.intSizeOf x) n- go i | i < SBV.intSizeOf x = SBV.svIte (SBV.svLessEq x (lit (2^i))) (lit (toInteger i)) (go (i + 1))- | otherwise = lit (toInteger i)--svDivisible :: Integer -> SInteger SBV -> SEval SBV (SBit SBV)-svDivisible m x =- do m' <- integerLit SBV m- z <- integerLit SBV 0- pure $ SBV.svEqual (SBV.svRem x m') z--signedQuot :: SWord SBV -> SWord SBV -> SWord SBV-signedQuot x y = SBV.svUnsign (SBV.svQuot (SBV.svSign x) (SBV.svSign y))--signedRem :: SWord SBV -> SWord SBV -> SWord SBV-signedRem x y = SBV.svUnsign (SBV.svRem (SBV.svSign x) (SBV.svSign y))--ashr :: SVal -> SVal -> SVal-ashr x idx =- case SBV.svAsInteger idx of- Just i -> SBV.svUnsign (SBV.svShr (SBV.svSign x) (fromInteger i))- Nothing -> SBV.svUnsign (SBV.svShiftRight (SBV.svSign x) idx)--lshr :: SVal -> SVal -> SVal-lshr x idx =- case SBV.svAsInteger idx of- Just i -> SBV.svShr x (fromInteger i)- Nothing -> SBV.svShiftRight x idx--shl :: SVal -> SVal -> SVal-shl x idx =- case SBV.svAsInteger idx of- Just i -> SBV.svShl x (fromInteger i)- Nothing -> SBV.svShiftLeft x idx--sshrV :: Value-sshrV =+sshrV :: SBV -> Value+sshrV sym = nlam $ \n -> tlam $ \ix ->- wlam SBV $ \x -> return $+ wlam sym $ \x -> return $ lam $ \y ->- y >>= asIndex SBV ">>$" ix >>= \case+ y >>= asIndex sym ">>$" ix >>= \case Left idx -> do let w = toInteger (SBV.intSizeOf x) let pneg = svLessThan idx (svInteger KUnbounded 0)- zneg <- shl x . svFromInteger w <$> shiftShrink SBV n ix (SBV.svUNeg idx)- zpos <- ashr x . svFromInteger w <$> shiftShrink SBV n ix idx+ zneg <- shl x . svFromInteger w <$> shiftShrink sym n ix (SBV.svUNeg idx)+ zpos <- ashr x . svFromInteger w <$> shiftShrink sym n ix idx let z = svSymbolicMerge (kindOf x) True pneg zneg zpos return . VWord w . pure . WordVal $ z Right wv ->- do z <- ashr x <$> asWordVal SBV wv+ do z <- ashr x <$> asWordVal sym wv return . VWord (toInteger (SBV.intSizeOf x)) . pure . WordVal $ z
src/Cryptol/Eval/Type.hs view
@@ -11,7 +11,7 @@ {-# LANGUAGE DeriveGeneric #-} module Cryptol.Eval.Type where -import Cryptol.Eval.Monad+import Cryptol.Backend.Monad (evalPanic, typeCannotBeDemoted) import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.PP(pp) import Cryptol.TypeCheck.Solver.InfNat@@ -20,9 +20,8 @@ import Cryptol.Utils.RecordMap import Data.Maybe(fromMaybe)-import qualified Data.Map.Strict as Map+import qualified Data.IntMap.Strict as IntMap import GHC.Generics (Generic)-import GHC.Stack(HasCallStack) import Control.DeepSeq -- | An evaluated type of kind *.@@ -91,15 +90,15 @@ -- Type Evaluation ------------------------------------------------------------- -type TypeEnv = Map.Map TVar (Either Nat' TValue)+type TypeEnv = IntMap.IntMap (Either Nat' TValue) -- | Evaluation for types (kind * or #).-evalType :: HasCallStack => TypeEnv -> Type -> Either Nat' TValue+evalType :: TypeEnv -> Type -> Either Nat' TValue evalType env ty = case ty of TVar tv ->- case Map.lookup tv env of+ case IntMap.lookup (tvUnique tv) env of Just v -> v Nothing -> evalPanic "evalType" ["type variable not bound", show tv] @@ -133,8 +132,8 @@ _ -> evalPanic "evalType" ["not a value type", show ty] TCon (TF f) ts -> Left $ evalTF f (map num ts) TCon (PC p) _ -> evalPanic "evalType" ["invalid predicate symbol", show p]- TCon (TError _ x) _ -> evalPanic "evalType"- ["Lingering typer error", show (pp x)]+ TCon (TError _) ts -> evalPanic "evalType"+ $ "Lingering invalid type" : map (show . pp) ts where val = evalValType env num = evalNumType env@@ -144,14 +143,14 @@ ["Expecting a finite size, but got `inf`"] -- | Evaluation for value types (kind *).-evalValType :: HasCallStack => TypeEnv -> Type -> TValue+evalValType :: TypeEnv -> Type -> TValue evalValType env ty = case evalType env ty of Left _ -> evalPanic "evalValType" ["expected value type, found numeric type"] Right t -> t -- | Evaluation for number types (kind #).-evalNumType :: HasCallStack => TypeEnv -> Type -> Nat'+evalNumType :: TypeEnv -> Type -> Nat' evalNumType env ty = case evalType env ty of Left n -> n@@ -159,7 +158,7 @@ -- | Reduce type functions, raising an exception for undefined values.-evalTF :: HasCallStack => TFun -> [Nat'] -> Nat'+evalTF :: TFun -> [Nat'] -> Nat' evalTF f vs | TCAdd <- f, [x,y] <- vs = nAdd x y | TCSub <- f, [x,y] <- vs = mb $ nSub x y
src/Cryptol/Eval/Value.hs view
@@ -98,9 +98,9 @@ import qualified Data.Map.Strict as Map import MonadLib -import qualified Cryptol.Eval.Arch as Arch-import Cryptol.Eval.Backend-import Cryptol.Eval.Monad+import Cryptol.Backend+import qualified Cryptol.Backend.Arch as Arch+import Cryptol.Backend.Monad ( PPOpts(..), evalPanic, wordTooWide, defaultPPOpts, asciiMode ) import Cryptol.Eval.Type import Cryptol.TypeCheck.Solver.InfNat(Nat'(..))@@ -132,7 +132,7 @@ -- | An arbitrarily-chosen number of elements where we switch from a dense -- sequence representation of bit-level words to 'SeqMap' representation. largeBitSize :: Integer-largeBitSize = 1 `shiftL` 16+largeBitSize = 1 `shiftL` 48 -- | Generate a finite sequence map from a list of values finiteSeqMap :: Backend sym => sym -> [SEval sym (GenValue sym)] -> SeqMap sym@@ -205,13 +205,13 @@ doEval cache i = do v <- lookupSeqMap x i- liftIO $ modifyIORef' cache (Map.insert i v)+ liftIO $ atomicModifyIORef' cache (\m -> (Map.insert i v m, ())) return v -- | Apply the given evaluation function pointwise to the two given -- sequence maps. zipSeqMap ::- Backend sym => + Backend sym => (GenValue sym -> GenValue sym -> SEval sym (GenValue sym)) -> SeqMap sym -> SeqMap sym ->@@ -221,7 +221,7 @@ -- | Apply the given function to each value in the given sequence map mapSeqMap ::- Backend sym => + Backend sym => (GenValue sym -> SEval sym (GenValue sym)) -> SeqMap sym -> SEval sym (SeqMap sym) mapSeqMap f x =@@ -281,7 +281,7 @@ -- | Produce a new 'WordValue' from the one given by updating the @i@th bit with the -- given bit value. updateWordValue :: Backend sym => sym -> WordValue sym -> Integer -> SEval sym (SBit sym) -> SEval sym (WordValue sym)-updateWordValue sym (WordVal w) idx b +updateWordValue sym (WordVal w) idx b | idx < 0 || idx >= wordLen sym w = invalidIndex sym idx | isReady sym b = WordVal <$> (wordUpdate sym w idx =<< b) @@ -336,6 +336,7 @@ VNumPoly _ -> return () + instance Backend sym => Show (GenValue sym) where show v = case v of VRecord fs -> "record:" ++ show (displayOrder fs)@@ -401,9 +402,6 @@ _ -> return $ brackets (fsep (punctuate comma $ map (ppWord x opts) vs)) _ -> do ws' <- traverse loop ws return $ brackets (fsep (punctuate comma ws'))--asciiMode :: PPOpts -> Integer -> Bool-asciiMode opts width = useAscii opts && (width == 7 || width == 8) -- Value Constructors ----------------------------------------------------------
src/Cryptol/Eval/What4.hs view
@@ -4,41 +4,69 @@ -- License : BSD3 -- Maintainer : cryptol@galois.com +{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE OverloadedStrings #-} module Cryptol.Eval.What4- ( What4(..)- , W4Result(..)- , W4Defs(..)- , W4Eval- , w4Eval- , Value- , evalPrim+ ( Value+ , primTable+ , floatPrims ) where --import Control.Monad (join)+import qualified Control.Exception as X+import Control.Concurrent.MVar+import Control.Monad (join,foldM)+import Control.Monad.IO.Class+import Data.Bits import qualified Data.Map as Map+import Data.Map (Map)+import qualified Data.Set as Set+import Data.Text (Text)+import qualified Data.Text as Text+import Data.Parameterized.Context+import Data.Parameterized.Some+import Data.Parameterized.TraversableFC+import qualified Data.BitVector.Sized as BV import qualified What4.Interface as W4+import qualified What4.SWord as SW+import qualified What4.Utils.AbstractDomains as W4 -import Cryptol.Eval.Backend+import Cryptol.Backend+import Cryptol.Backend.Monad ( EvalError(..), Unsupported(..) )+import Cryptol.Backend.What4+import qualified Cryptol.Backend.What4.SFloat as W4+ import Cryptol.Eval.Generic-import Cryptol.Eval.Type (finNat')+import Cryptol.Eval.Type (finNat', TValue(..)) import Cryptol.Eval.Value-import Cryptol.Eval.What4.Value-import Cryptol.Eval.What4.Float(floatPrims)-import Cryptol.Testing.Random( randomV )-import Cryptol.Utils.Ident +import qualified Cryptol.SHA as SHA -evalPrim :: W4.IsSymExprBuilder sym => sym -> PrimIdent -> Maybe (Value sym)-evalPrim sym prim = Map.lookup prim (primTable sym)+import Cryptol.TypeCheck.Solver.InfNat( Nat'(..), widthInteger ) +import Cryptol.Utils.Ident+import Cryptol.Utils.Panic+import Cryptol.Utils.RecordMap++type Value sym = GenValue (What4 sym)+ -- See also Cryptol.Prims.Eval.primTable-primTable :: W4.IsSymExprBuilder sym => sym -> Map.Map PrimIdent (Value sym)-primTable w4sym = let sym = What4 w4sym in+primTable :: W4.IsSymExprBuilder sym => What4 sym -> Map.Map PrimIdent (Value sym)+primTable sym =+ let w4sym = w4 sym in Map.union (floatPrims sym) $+ Map.union (suiteBPrims sym) $+ Map.union (primeECPrims sym) $+ Map.fromList $ map (\(n, v) -> (prelPrim n, v)) [ -- Literals@@ -88,7 +116,7 @@ , ("/$" , sdivV sym) , ("%$" , smodV sym) , ("lg2" , lg2V sym)- , (">>$" , sshrV w4sym)+ , (">>$" , sshrV sym) -- Cmp , ("<" , binary (lessThanV sym))@@ -153,14 +181,25 @@ rotateRightReindex rotateLeftReindex) -- Indexing and updates- , ("@" , indexPrim sym (indexFront_int w4sym) (indexFront_bits w4sym) (indexFront_word w4sym))- , ("!" , indexPrim sym (indexBack_int w4sym) (indexBack_bits w4sym) (indexBack_word w4sym))+ , ("@" , indexPrim sym (indexFront_int sym) (indexFront_bits sym) (indexFront_word sym))+ , ("!" , indexPrim sym (indexBack_int sym) (indexBack_bits sym) (indexBack_word sym)) - , ("update" , updatePrim sym (updateFrontSym_word w4sym) (updateFrontSym w4sym))- , ("updateEnd" , updatePrim sym (updateBackSym_word w4sym) (updateBackSym w4sym))+ , ("update" , updatePrim sym (updateFrontSym_word sym) (updateFrontSym sym))+ , ("updateEnd" , updatePrim sym (updateBackSym_word sym) (updateBackSym sym)) -- Misc + , ("foldl" , foldlV sym)+ , ("foldl'" , foldl'V sym)++ , ("deepseq" ,+ tlam $ \_a ->+ tlam $ \_b ->+ lam $ \x -> pure $+ lam $ \y ->+ do _ <- forceValue =<< x+ y)+ , ("parmap" , parmapV sym) , ("fromZ" , fromZV sym)@@ -193,5 +232,805 @@ y) ] +primeECPrims :: W4.IsSymExprBuilder sym => What4 sym -> Map.Map PrimIdent (Value sym)+primeECPrims sym = Map.fromList $ [ (primeECPrim n, v) | (n,v) <- prims ]+ where+ (~>) = (,) + prims =+ [ -- {p} (prime p, p > 3) => ProjectivePoint p -> ProjectivePoint p+ "ec_double" ~>+ ilam \p ->+ lam \s ->+ do p' <- integerLit sym p+ s' <- toProjectivePoint sym =<< s+ addUninterpWarning sym "Prime ECC"+ fn <- liftIO $ getUninterpFn sym "ec_double"+ (Empty :> W4.BaseIntegerRepr :> projectivePointRepr) projectivePointRepr+ z <- liftIO $ W4.applySymFn (w4 sym) fn (Empty :> p' :> s')+ fromProjectivePoint sym z + -- {p} (prime p, p > 3) => ProjectivePoint p -> ProjectivePoint p -> ProjectivePoint p+ , "ec_add_nonzero" ~>+ ilam \p ->+ lam \s -> pure $+ lam \t ->+ do p' <- integerLit sym p+ s' <- toProjectivePoint sym =<< s+ t' <- toProjectivePoint sym =<< t+ addUninterpWarning sym "Prime ECC"+ fn <- liftIO $ getUninterpFn sym "ec_add_nonzero"+ (Empty :> W4.BaseIntegerRepr :> projectivePointRepr :> projectivePointRepr) projectivePointRepr+ z <- liftIO $ W4.applySymFn (w4 sym) fn (Empty :> p' :> s' :> t')+ fromProjectivePoint sym z++ -- {p} (prime p, p > 3) => Z p -> ProjectivePoint p -> ProjectivePoint p+ , "ec_mult" ~>+ ilam \p ->+ lam \k -> pure $+ lam \s ->+ do p' <- integerLit sym p+ k' <- fromVInteger <$> k+ s' <- toProjectivePoint sym =<< s+ addUninterpWarning sym "Prime ECC"+ fn <- liftIO $ getUninterpFn sym "ec_mult"+ (Empty :> W4.BaseIntegerRepr :> W4.BaseIntegerRepr :> projectivePointRepr) projectivePointRepr+ z <- liftIO $ W4.applySymFn (w4 sym) fn (Empty :> p' :> k' :> s')+ fromProjectivePoint sym z++ -- {p} (prime p, p > 3) => Z p -> ProjectivePoint p -> Z p -> ProjectivePoint p -> ProjectivePoint p+ , "ec_twin_mult" ~>+ ilam \p ->+ lam \j -> pure $+ lam \s -> pure $+ lam \k -> pure $+ lam \t ->+ do p' <- integerLit sym p+ j' <- fromVInteger <$> j+ s' <- toProjectivePoint sym =<< s+ k' <- fromVInteger <$> k+ t' <- toProjectivePoint sym =<< t+ addUninterpWarning sym "Prime ECC"+ fn <- liftIO $ getUninterpFn sym "ec_twin_mult"+ (Empty :> W4.BaseIntegerRepr :> W4.BaseIntegerRepr :> projectivePointRepr :>+ W4.BaseIntegerRepr :> projectivePointRepr)+ projectivePointRepr+ z <- liftIO $ W4.applySymFn (w4 sym) fn (Empty :> p' :> j' :> s' :> k' :> t')+ fromProjectivePoint sym z+ ]+++type ProjectivePoint = W4.BaseStructType (EmptyCtx ::> W4.BaseIntegerType ::> W4.BaseIntegerType ::> W4.BaseIntegerType)++projectivePointRepr :: W4.BaseTypeRepr ProjectivePoint+projectivePointRepr = W4.knownRepr++toProjectivePoint :: W4.IsSymExprBuilder sym =>+ What4 sym -> Value sym -> SEval (What4 sym) (W4.SymExpr sym ProjectivePoint)+toProjectivePoint sym v =+ do x <- fromVInteger <$> lookupRecord "x" v+ y <- fromVInteger <$> lookupRecord "y" v+ z <- fromVInteger <$> lookupRecord "z" v+ liftIO $ W4.mkStruct (w4 sym) (Empty :> x :> y :> z)++fromProjectivePoint :: W4.IsSymExprBuilder sym =>+ What4 sym -> W4.SymExpr sym ProjectivePoint -> SEval (What4 sym) (Value sym)+fromProjectivePoint sym p = liftIO $+ do x <- VInteger <$> W4.structField (w4 sym) p (natIndex @0)+ y <- VInteger <$> W4.structField (w4 sym) p (natIndex @1)+ z <- VInteger <$> W4.structField (w4 sym) p (natIndex @2)+ pure $ VRecord $ recordFromFields [ (packIdent "x",pure x), (packIdent "y",pure y),(packIdent "z",pure z) ]++suiteBPrims :: W4.IsSymExprBuilder sym => What4 sym -> Map.Map PrimIdent (Value sym)+suiteBPrims sym = Map.fromList $ [ (suiteBPrim n, v) | (n,v) <- prims ]+ where+ (~>) = (,)++ prims =+ [ "AESEncRound" ~>+ lam \st ->+ do addUninterpWarning sym "AES encryption"+ applyAESStateFunc sym "AESEncRound" =<< st+ , "AESEncFinalRound" ~>+ lam \st ->+ do addUninterpWarning sym "AES encryption"+ applyAESStateFunc sym "AESEncFinalRound" =<< st+ , "AESDecRound" ~>+ lam \st ->+ do addUninterpWarning sym "AES decryption"+ applyAESStateFunc sym "AESDecRound" =<< st+ , "AESDecFinalRound" ~>+ lam \st ->+ do addUninterpWarning sym "AES decryption"+ applyAESStateFunc sym "AESDecFinalRound" =<< st+ , "AESInvMixColumns" ~>+ lam \st ->+ do addUninterpWarning sym "AES key expansion"+ applyAESStateFunc sym "AESInvMixColumns" =<< st++ -- {k} (fin k, k >= 4, 8 >= k) => [k][32] -> [4*(k+7)][32]+ , "AESKeyExpand" ~>+ ilam \k ->+ lam \st ->+ do ss <- fromVSeq <$> st+ -- pack the arguments into a k-tuple of 32-bit values+ Some ws <- generateSomeM (fromInteger k) (\i -> Some <$> toWord32 sym "AESKeyExpand" ss (toInteger i))+ -- get the types of the arguments+ let args = fmapFC W4.exprType ws+ -- compute the return type which is a tuple of @4*(k+7)@ 32-bit values+ Some ret <- pure $ generateSome (4*(fromInteger k + 7)) (\_ -> Some (W4.BaseBVRepr (W4.knownNat @32)))+ -- retrieve the relevant uninterpreted function and apply it to the arguments+ addUninterpWarning sym "AES key expansion"+ fn <- liftIO $ getUninterpFn sym ("AESKeyExpand" <> Text.pack (show k)) args (W4.BaseStructRepr ret)+ z <- liftIO $ W4.applySymFn (w4 sym) fn ws+ -- compute a sequence that projects the relevant fields from the outout tuple+ pure $ VSeq (4*(k+7)) $ IndexSeqMap $ \i ->+ case intIndex (fromInteger i) (size ret) of+ Just (Some idx) | Just W4.Refl <- W4.testEquality (ret!idx) (W4.BaseBVRepr (W4.knownNat @32)) ->+ fromWord32 =<< liftIO (W4.structField (w4 sym) z idx)+ _ -> invalidIndex sym i++ -- {n} (fin n) => [n][16][32] -> [7][32]+ , "processSHA2_224" ~>+ ilam \n ->+ lam \xs ->+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ addUninterpWarning sym "SHA-224"+ initSt <- liftIO (mkSHA256InitialState sym SHA.initialSHA224State)+ finalSt <- foldM (\st blk -> processSHA256Block sym st =<< blk) initSt blks+ pure $ VSeq 7 $ IndexSeqMap \i ->+ case intIndex (fromInteger i) (knownSize :: Size SHA256State) of+ Just (Some idx) ->+ do z <- liftIO $ W4.structField (w4 sym) finalSt idx+ case W4.testEquality (W4.exprType z) (W4.BaseBVRepr (W4.knownNat @32)) of+ Just W4.Refl -> fromWord32 z+ Nothing -> invalidIndex sym i+ Nothing -> invalidIndex sym i++ -- {n} (fin n) => [n][16][32] -> [8][32]+ , "processSHA2_256" ~>+ ilam \n ->+ lam \xs ->+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ addUninterpWarning sym "SHA-256"+ initSt <- liftIO (mkSHA256InitialState sym SHA.initialSHA256State)+ finalSt <- foldM (\st blk -> processSHA256Block sym st =<< blk) initSt blks+ pure $ VSeq 8 $ IndexSeqMap \i ->+ case intIndex (fromInteger i) (knownSize :: Size SHA256State) of+ Just (Some idx) ->+ do z <- liftIO $ W4.structField (w4 sym) finalSt idx+ case W4.testEquality (W4.exprType z) (W4.BaseBVRepr (W4.knownNat @32)) of+ Just W4.Refl -> fromWord32 z+ Nothing -> invalidIndex sym i+ Nothing -> invalidIndex sym i++ -- {n} (fin n) => [n][16][64] -> [6][64]+ , "processSHA2_384" ~>+ ilam \n ->+ lam \xs ->+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ addUninterpWarning sym "SHA-384"+ initSt <- liftIO (mkSHA512InitialState sym SHA.initialSHA384State)+ finalSt <- foldM (\st blk -> processSHA512Block sym st =<< blk) initSt blks+ pure $ VSeq 6 $ IndexSeqMap \i ->+ case intIndex (fromInteger i) (knownSize :: Size SHA512State) of+ Just (Some idx) ->+ do z <- liftIO $ W4.structField (w4 sym) finalSt idx+ case W4.testEquality (W4.exprType z) (W4.BaseBVRepr (W4.knownNat @64)) of+ Just W4.Refl -> fromWord64 z+ Nothing -> invalidIndex sym i+ Nothing -> invalidIndex sym i++ -- {n} (fin n) => [n][16][64] -> [8][64]+ , "processSHA2_512" ~>+ ilam \n ->+ lam \xs ->+ do blks <- enumerateSeqMap n . fromVSeq <$> xs+ addUninterpWarning sym "SHA-512"+ initSt <- liftIO (mkSHA512InitialState sym SHA.initialSHA512State)+ finalSt <- foldM (\st blk -> processSHA512Block sym st =<< blk) initSt blks+ pure $ VSeq 8 $ IndexSeqMap \i ->+ case intIndex (fromInteger i) (knownSize :: Size SHA512State) of+ Just (Some idx) ->+ do z <- liftIO $ W4.structField (w4 sym) finalSt idx+ case W4.testEquality (W4.exprType z) (W4.BaseBVRepr (W4.knownNat @64)) of+ Just W4.Refl -> fromWord64 z+ Nothing -> invalidIndex sym i+ Nothing -> invalidIndex sym i+ ]+++type SHA256State =+ EmptyCtx ::>+ W4.BaseBVType 32 ::> W4.BaseBVType 32 ::> W4.BaseBVType 32 ::> W4.BaseBVType 32 ::>+ W4.BaseBVType 32 ::> W4.BaseBVType 32 ::> W4.BaseBVType 32 ::> W4.BaseBVType 32++type SHA512State =+ EmptyCtx ::>+ W4.BaseBVType 64 ::> W4.BaseBVType 64 ::> W4.BaseBVType 64 ::> W4.BaseBVType 64 ::>+ W4.BaseBVType 64 ::> W4.BaseBVType 64 ::> W4.BaseBVType 64 ::> W4.BaseBVType 64+++mkSHA256InitialState :: W4.IsSymExprBuilder sym =>+ What4 sym ->+ SHA.SHA256State ->+ IO (W4.SymExpr sym (W4.BaseStructType SHA256State))+mkSHA256InitialState sym (SHA.SHA256S s0 s1 s2 s3 s4 s5 s6 s7) =+ do z0 <- lit s0+ z1 <- lit s1+ z2 <- lit s2+ z3 <- lit s3+ z4 <- lit s4+ z5 <- lit s5+ z6 <- lit s6+ z7 <- lit s7+ W4.mkStruct (w4 sym) (Empty :> z0 :> z1 :> z2 :> z3 :> z4 :> z5 :> z6 :> z7)+ where lit w = W4.bvLit (w4 sym) (W4.knownNat @32) (BV.word32 w)++mkSHA512InitialState :: W4.IsSymExprBuilder sym =>+ What4 sym ->+ SHA.SHA512State ->+ IO (W4.SymExpr sym (W4.BaseStructType SHA512State))+mkSHA512InitialState sym (SHA.SHA512S s0 s1 s2 s3 s4 s5 s6 s7) =+ do z0 <- lit s0+ z1 <- lit s1+ z2 <- lit s2+ z3 <- lit s3+ z4 <- lit s4+ z5 <- lit s5+ z6 <- lit s6+ z7 <- lit s7+ W4.mkStruct (w4 sym) (Empty :> z0 :> z1 :> z2 :> z3 :> z4 :> z5 :> z6 :> z7)+ where lit w = W4.bvLit (w4 sym) (W4.knownNat @64) (BV.word64 w)++processSHA256Block :: W4.IsSymExprBuilder sym =>+ What4 sym ->+ W4.SymExpr sym (W4.BaseStructType SHA256State) ->+ Value sym ->+ SEval (What4 sym) (W4.SymExpr sym (W4.BaseStructType SHA256State))+processSHA256Block sym st blk =+ do let ss = fromVSeq blk+ b0 <- toWord32 sym "processSHA256Block" ss 0+ b1 <- toWord32 sym "processSHA256Block" ss 1+ b2 <- toWord32 sym "processSHA256Block" ss 2+ b3 <- toWord32 sym "processSHA256Block" ss 3+ b4 <- toWord32 sym "processSHA256Block" ss 4+ b5 <- toWord32 sym "processSHA256Block" ss 5+ b6 <- toWord32 sym "processSHA256Block" ss 6+ b7 <- toWord32 sym "processSHA256Block" ss 7+ b8 <- toWord32 sym "processSHA256Block" ss 8+ b9 <- toWord32 sym "processSHA256Block" ss 9+ b10 <- toWord32 sym "processSHA256Block" ss 10+ b11 <- toWord32 sym "processSHA256Block" ss 11+ b12 <- toWord32 sym "processSHA256Block" ss 12+ b13 <- toWord32 sym "processSHA256Block" ss 13+ b14 <- toWord32 sym "processSHA256Block" ss 14+ b15 <- toWord32 sym "processSHA256Block" ss 15+ let args = Empty :> st :>+ b0 :> b1 :> b2 :> b3 :>+ b4 :> b5 :> b6 :> b7 :>+ b8 :> b9 :> b10 :> b11 :>+ b12 :> b13 :> b14 :> b15+ let ret = W4.exprType st+ fn <- liftIO $ getUninterpFn sym "processSHA256Block" (fmapFC W4.exprType args) ret+ liftIO $ W4.applySymFn (w4 sym) fn args+++processSHA512Block :: W4.IsSymExprBuilder sym =>+ What4 sym ->+ W4.SymExpr sym (W4.BaseStructType SHA512State) ->+ Value sym ->+ SEval (What4 sym) (W4.SymExpr sym (W4.BaseStructType SHA512State))+processSHA512Block sym st blk =+ do let ss = fromVSeq blk+ b0 <- toWord64 sym "processSHA512Block" ss 0+ b1 <- toWord64 sym "processSHA512Block" ss 1+ b2 <- toWord64 sym "processSHA512Block" ss 2+ b3 <- toWord64 sym "processSHA512Block" ss 3+ b4 <- toWord64 sym "processSHA512Block" ss 4+ b5 <- toWord64 sym "processSHA512Block" ss 5+ b6 <- toWord64 sym "processSHA512Block" ss 6+ b7 <- toWord64 sym "processSHA512Block" ss 7+ b8 <- toWord64 sym "processSHA512Block" ss 8+ b9 <- toWord64 sym "processSHA512Block" ss 9+ b10 <- toWord64 sym "processSHA512Block" ss 10+ b11 <- toWord64 sym "processSHA512Block" ss 11+ b12 <- toWord64 sym "processSHA512Block" ss 12+ b13 <- toWord64 sym "processSHA512Block" ss 13+ b14 <- toWord64 sym "processSHA512Block" ss 14+ b15 <- toWord64 sym "processSHA512Block" ss 15+ let args = Empty :> st :>+ b0 :> b1 :> b2 :> b3 :>+ b4 :> b5 :> b6 :> b7 :>+ b8 :> b9 :> b10 :> b11 :>+ b12 :> b13 :> b14 :> b15+ let ret = W4.exprType st+ fn <- liftIO $ getUninterpFn sym "processSHA512Block" (fmapFC W4.exprType args) ret+ liftIO $ W4.applySymFn (w4 sym) fn args+++addUninterpWarning :: MonadIO m => What4 sym -> Text -> m ()+addUninterpWarning sym nm = liftIO (modifyMVar_ (w4uninterpWarns sym) (pure . Set.insert nm))++-- | Retrieve the named uninterpreted function, with the given argument types and+-- return type, from a cache. Create a fresh function if it has not previously+-- been requested. A particular named function is required to be used with+-- consistent types every time it is requested; otherwise this function will panic.+getUninterpFn :: W4.IsSymExprBuilder sym =>+ What4 sym ->+ Text {- ^ Function name -} ->+ Assignment W4.BaseTypeRepr args {- ^ function argument types -} ->+ W4.BaseTypeRepr ret {- ^ function return type -} ->+ IO (W4.SymFn sym args ret)+getUninterpFn sym funNm args ret =+ modifyMVar (w4funs sym) $ \m ->+ case Map.lookup funNm m of+ Nothing ->+ do fn <- W4.freshTotalUninterpFn (w4 sym) (W4.safeSymbol (Text.unpack funNm)) args ret+ let m' = Map.insert funNm (SomeSymFn fn) m+ return (m', fn)++ Just (SomeSymFn fn)+ | Just W4.Refl <- W4.testEquality args (W4.fnArgTypes fn)+ , Just W4.Refl <- W4.testEquality ret (W4.fnReturnType fn)+ -> return (m, fn)++ | otherwise -> panic "getUninterpFn"+ [ "Function" ++ show funNm ++ "used at incompatible types"+ , "Created with types:"+ , show (W4.fnArgTypes fn) ++ " -> " ++ show (W4.fnReturnType fn)+ , "Requested at types:"+ , show args ++ " -> " ++ show ret+ ]++toWord32 :: W4.IsSymExprBuilder sym =>+ What4 sym -> String -> SeqMap (What4 sym) -> Integer -> SEval (What4 sym) (W4.SymBV sym 32)+toWord32 sym nm ss i =+ do x <- fromVWord sym nm =<< lookupSeqMap ss i+ case x of+ SW.DBV x' | Just W4.Refl <- W4.testEquality (W4.bvWidth x') (W4.knownNat @32) -> pure x'+ _ -> panic nm ["Unexpected word size", show (SW.bvWidth x)]++fromWord32 :: W4.IsSymExprBuilder sym => W4.SymBV sym 32 -> SEval (What4 sym) (Value sym)+fromWord32 = pure . VWord 32 . pure . WordVal . SW.DBV+++toWord64 :: W4.IsSymExprBuilder sym =>+ What4 sym -> String -> SeqMap (What4 sym) -> Integer -> SEval (What4 sym) (W4.SymBV sym 64)+toWord64 sym nm ss i =+ do x <- fromVWord sym nm =<< lookupSeqMap ss i+ case x of+ SW.DBV x' | Just W4.Refl <- W4.testEquality (W4.bvWidth x') (W4.knownNat @64) -> pure x'+ _ -> panic nm ["Unexpected word size", show (SW.bvWidth x)]++fromWord64 :: W4.IsSymExprBuilder sym => W4.SymBV sym 64 -> SEval (What4 sym) (Value sym)+fromWord64 = pure . VWord 64 . pure . WordVal . SW.DBV++++-- | Apply the named uninterpreted function to a sequence of @[4][32]@ values,+-- and return a sequence of @[4][32]@ values. This shape of function is used+-- for most of the SuiteB AES primitives.+applyAESStateFunc :: forall sym. W4.IsSymExprBuilder sym =>+ What4 sym -> Text -> Value sym -> SEval (What4 sym) (Value sym)+applyAESStateFunc sym funNm x =+ do let ss = fromVSeq x+ w0 <- toWord32 sym nm ss 0+ w1 <- toWord32 sym nm ss 1+ w2 <- toWord32 sym nm ss 2+ w3 <- toWord32 sym nm ss 3+ fn <- liftIO $ getUninterpFn sym funNm argCtx (W4.BaseStructRepr argCtx)+ z <- liftIO $ W4.applySymFn (w4 sym) fn (Empty :> w0 :> w1 :> w2 :> w3)+ pure $ VSeq 4 $ IndexSeqMap \i ->+ if | i == 0 -> fromWord32 =<< liftIO (W4.structField (w4 sym) z (natIndex @0))+ | i == 1 -> fromWord32 =<< liftIO (W4.structField (w4 sym) z (natIndex @1))+ | i == 2 -> fromWord32 =<< liftIO (W4.structField (w4 sym) z (natIndex @2))+ | i == 3 -> fromWord32 =<< liftIO (W4.structField (w4 sym) z (natIndex @3))+ | otherwise -> invalidIndex sym i++ where+ nm = Text.unpack funNm++ argCtx :: Assignment W4.BaseTypeRepr+ (EmptyCtx ::> W4.BaseBVType 32 ::> W4.BaseBVType 32 ::> W4.BaseBVType 32 ::> W4.BaseBVType 32)+ argCtx = W4.knownRepr+++sshrV :: W4.IsSymExprBuilder sym => What4 sym -> Value sym+sshrV sym =+ nlam $ \(Nat n) ->+ tlam $ \ix ->+ wlam sym $ \x -> return $+ lam $ \y ->+ y >>= asIndex sym ">>$" ix >>= \case+ Left i ->+ do pneg <- intLessThan sym i =<< integerLit sym 0+ zneg <- do i' <- shiftShrink sym (Nat n) ix =<< intNegate sym i+ amt <- wordFromInt sym n i'+ w4bvShl (w4 sym) x amt+ zpos <- do i' <- shiftShrink sym (Nat n) ix i+ amt <- wordFromInt sym n i'+ w4bvAshr (w4 sym) x amt+ return (VWord (SW.bvWidth x) (WordVal <$> iteWord sym pneg zneg zpos))++ Right wv ->+ do amt <- asWordVal sym wv+ return (VWord (SW.bvWidth x) (WordVal <$> w4bvAshr (w4 sym) x amt))++indexFront_int ::+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Nat' ->+ TValue ->+ SeqMap (What4 sym) ->+ TValue ->+ SInteger (What4 sym) ->+ SEval (What4 sym) (Value sym)+indexFront_int sym mblen _a xs ix idx+ | Just i <- W4.asInteger idx+ = lookupSeqMap xs i++ | (lo, Just hi) <- bounds+ = foldr f def [lo .. hi]++ | otherwise+ = liftIO (X.throw (UnsupportedSymbolicOp "unbounded integer indexing"))++ where+ w4sym = w4 sym++ def = raiseError sym (InvalidIndex Nothing)++ f n y =+ do p <- liftIO (W4.intEq w4sym idx =<< W4.intLit w4sym n)+ iteValue sym p (lookupSeqMap xs n) y++ bounds =+ (case W4.rangeLowBound (W4.integerBounds idx) of+ W4.Inclusive l -> max l 0+ _ -> 0+ , case (maxIdx, W4.rangeHiBound (W4.integerBounds idx)) of+ (Just n, W4.Inclusive h) -> Just (min n h)+ (Just n, _) -> Just n+ _ -> Nothing+ )++ -- Maximum possible in-bounds index given `Z m`+ -- type information and the length+ -- of the sequence. If the sequences is infinite and the+ -- integer is unbounded, there isn't much we can do.+ maxIdx =+ case (mblen, ix) of+ (Nat n, TVIntMod m) -> Just (min (toInteger n) (toInteger m))+ (Nat n, _) -> Just n+ (_ , TVIntMod m) -> Just m+ _ -> Nothing++indexBack_int ::+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Nat' ->+ TValue ->+ SeqMap (What4 sym) ->+ TValue ->+ SInteger (What4 sym) ->+ SEval (What4 sym) (Value sym)+indexBack_int sym (Nat n) a xs ix idx = indexFront_int sym (Nat n) a (reverseSeqMap n xs) ix idx+indexBack_int _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack_int"]++indexFront_word ::+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Nat' ->+ TValue ->+ SeqMap (What4 sym) ->+ TValue ->+ SWord (What4 sym) ->+ SEval (What4 sym) (Value sym)+indexFront_word sym mblen _a xs _ix idx+ | Just i <- SW.bvAsUnsignedInteger idx+ = lookupSeqMap xs i++ | otherwise+ = foldr f def idxs++ where+ w4sym = w4 sym++ w = SW.bvWidth idx+ def = raiseError sym (InvalidIndex Nothing)++ f n y =+ do p <- liftIO (SW.bvEq w4sym idx =<< SW.bvLit w4sym w n)+ iteValue sym p (lookupSeqMap xs n) y++ -- maximum possible in-bounds index given the bitwidth+ -- of the index value and the length of the sequence+ maxIdx =+ case mblen of+ Nat n | n < 2^w -> n-1+ _ -> 2^w - 1++ -- concrete indices to consider, intersection of the+ -- range of values the index value might take with+ -- the legal values+ idxs =+ case SW.unsignedBVBounds idx of+ Just (lo, hi) -> [lo .. min hi maxIdx]+ _ -> [0 .. maxIdx]++indexBack_word ::+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Nat' ->+ TValue ->+ SeqMap (What4 sym) ->+ TValue ->+ SWord (What4 sym) ->+ SEval (What4 sym) (Value sym)+indexBack_word sym (Nat n) a xs ix idx = indexFront_word sym (Nat n) a (reverseSeqMap n xs) ix idx+indexBack_word _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack_word"]++indexFront_bits :: forall sym.+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Nat' ->+ TValue ->+ SeqMap (What4 sym) ->+ TValue ->+ [SBit (What4 sym)] ->+ SEval (What4 sym) (Value sym)+indexFront_bits sym mblen _a xs _ix bits0 = go 0 (length bits0) bits0+ where+ go :: Integer -> Int -> [W4.Pred sym] -> W4Eval sym (Value sym)+ go i _k []+ -- For indices out of range, fail+ | Nat n <- mblen+ , i >= n+ = raiseError sym (InvalidIndex (Just i))++ | otherwise+ = lookupSeqMap xs i++ go i k (b:bs)+ -- Fail early when all possible indices we could compute from here+ -- are out of bounds+ | Nat n <- mblen+ , (i `shiftL` k) >= n+ = raiseError sym (InvalidIndex Nothing)++ | otherwise+ = iteValue sym b+ (go ((i `shiftL` 1) + 1) (k-1) bs)+ (go (i `shiftL` 1) (k-1) bs)++indexBack_bits ::+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Nat' ->+ TValue ->+ SeqMap (What4 sym) ->+ TValue ->+ [SBit (What4 sym)] ->+ SEval (What4 sym) (Value sym)+indexBack_bits sym (Nat n) a xs ix idx = indexFront_bits sym (Nat n) a (reverseSeqMap n xs) ix idx+indexBack_bits _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack_bits"]+++-- | Compare a symbolic word value with a concrete integer.+wordValueEqualsInteger :: forall sym.+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ WordValue (What4 sym) ->+ Integer ->+ W4Eval sym (W4.Pred sym)+wordValueEqualsInteger sym wv i+ | wordValueSize sym wv < widthInteger i = return (W4.falsePred w4sym)+ | otherwise =+ case wv of+ WordVal w -> liftIO (SW.bvEq w4sym w =<< SW.bvLit w4sym (SW.bvWidth w) i)+ _ -> liftIO . bitsAre i =<< enumerateWordValueRev sym wv -- little-endian+ where+ w4sym = w4 sym++ bitsAre :: Integer -> [W4.Pred sym] -> IO (W4.Pred sym)+ bitsAre n [] = pure (W4.backendPred w4sym (n == 0))+ bitsAre n (b : bs) =+ do pb <- bitIs (testBit n 0) b+ pbs <- bitsAre (n `shiftR` 1) bs+ W4.andPred w4sym pb pbs++ bitIs :: Bool -> W4.Pred sym -> IO (W4.Pred sym)+ bitIs b x = if b then pure x else W4.notPred w4sym x++updateFrontSym ::+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Nat' ->+ TValue ->+ SeqMap (What4 sym) ->+ Either (SInteger (What4 sym)) (WordValue (What4 sym)) ->+ SEval (What4 sym) (Value sym) ->+ SEval (What4 sym) (SeqMap (What4 sym))+updateFrontSym sym _len _eltTy vs (Left idx) val =+ case W4.asInteger idx of+ Just i -> return $ updateSeqMap vs i val+ Nothing -> return $ IndexSeqMap $ \i ->+ do b <- intEq sym idx =<< integerLit sym i+ iteValue sym b val (lookupSeqMap vs i)++updateFrontSym sym _len _eltTy vs (Right wv) val =+ case wv of+ WordVal w | Just j <- SW.bvAsUnsignedInteger w ->+ return $ updateSeqMap vs j val+ _ ->+ memoMap $ IndexSeqMap $ \i ->+ do b <- wordValueEqualsInteger sym wv i+ iteValue sym b val (lookupSeqMap vs i)++updateBackSym ::+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Nat' ->+ TValue ->+ SeqMap (What4 sym) ->+ Either (SInteger (What4 sym)) (WordValue (What4 sym)) ->+ SEval (What4 sym) (Value sym) ->+ SEval (What4 sym) (SeqMap (What4 sym))+updateBackSym _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateBackSym"]++updateBackSym sym (Nat n) _eltTy vs (Left idx) val =+ case W4.asInteger idx of+ Just i -> return $ updateSeqMap vs (n - 1 - i) val+ Nothing -> return $ IndexSeqMap $ \i ->+ do b <- intEq sym idx =<< integerLit sym (n - 1 - i)+ iteValue sym b val (lookupSeqMap vs i)++updateBackSym sym (Nat n) _eltTy vs (Right wv) val =+ case wv of+ WordVal w | Just j <- SW.bvAsUnsignedInteger w ->+ return $ updateSeqMap vs (n - 1 - j) val+ _ ->+ memoMap $ IndexSeqMap $ \i ->+ do b <- wordValueEqualsInteger sym wv (n - 1 - i)+ iteValue sym b val (lookupSeqMap vs i)+++updateFrontSym_word ::+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Nat' ->+ TValue ->+ WordValue (What4 sym) ->+ Either (SInteger (What4 sym)) (WordValue (What4 sym)) ->+ SEval (What4 sym) (GenValue (What4 sym)) ->+ SEval (What4 sym) (WordValue (What4 sym))+updateFrontSym_word _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateFrontSym_word"]++updateFrontSym_word sym (Nat _) eltTy (LargeBitsVal n bv) idx val =+ LargeBitsVal n <$> updateFrontSym sym (Nat n) eltTy bv idx val++updateFrontSym_word sym (Nat n) eltTy (WordVal bv) (Left idx) val =+ do idx' <- wordFromInt sym n idx+ updateFrontSym_word sym (Nat n) eltTy (WordVal bv) (Right (WordVal idx')) val++updateFrontSym_word sym (Nat n) eltTy bv (Right wv) val =+ case wv of+ WordVal idx+ | Just j <- SW.bvAsUnsignedInteger idx ->+ updateWordValue sym bv j (fromVBit <$> val)++ | WordVal bw <- bv ->+ WordVal <$>+ do b <- fromVBit <$> val+ let sz = SW.bvWidth bw+ highbit <- liftIO (SW.bvLit (w4 sym) sz (bit (fromInteger (sz-1))))+ msk <- w4bvLshr (w4 sym) highbit idx+ liftIO $+ case W4.asConstantPred b of+ Just True -> SW.bvOr (w4 sym) bw msk+ Just False -> SW.bvAnd (w4 sym) bw =<< SW.bvNot (w4 sym) msk+ Nothing ->+ do q <- SW.bvFill (w4 sym) sz b+ bw' <- SW.bvAnd (w4 sym) bw =<< SW.bvNot (w4 sym) msk+ SW.bvXor (w4 sym) bw' =<< SW.bvAnd (w4 sym) q msk++ _ -> LargeBitsVal (wordValueSize sym wv) <$>+ updateFrontSym sym (Nat n) eltTy (asBitsMap sym bv) (Right wv) val+++updateBackSym_word ::+ W4.IsSymExprBuilder sym =>+ What4 sym ->+ Nat' ->+ TValue ->+ WordValue (What4 sym) ->+ Either (SInteger (What4 sym)) (WordValue (What4 sym)) ->+ SEval (What4 sym) (GenValue (What4 sym)) ->+ SEval (What4 sym) (WordValue (What4 sym))+updateBackSym_word _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateBackSym_word"]++updateBackSym_word sym (Nat _) eltTy (LargeBitsVal n bv) idx val =+ LargeBitsVal n <$> updateBackSym sym (Nat n) eltTy bv idx val++updateBackSym_word sym (Nat n) eltTy (WordVal bv) (Left idx) val =+ do idx' <- wordFromInt sym n idx+ updateBackSym_word sym (Nat n) eltTy (WordVal bv) (Right (WordVal idx')) val++updateBackSym_word sym (Nat n) eltTy bv (Right wv) val =+ case wv of+ WordVal idx+ | Just j <- SW.bvAsUnsignedInteger idx ->+ updateWordValue sym bv (n - 1 - j) (fromVBit <$> val)++ | WordVal bw <- bv ->+ WordVal <$>+ do b <- fromVBit <$> val+ let sz = SW.bvWidth bw+ lowbit <- liftIO (SW.bvLit (w4 sym) sz 1)+ msk <- w4bvShl (w4 sym) lowbit idx+ liftIO $+ case W4.asConstantPred b of+ Just True -> SW.bvOr (w4 sym) bw msk+ Just False -> SW.bvAnd (w4 sym) bw =<< SW.bvNot (w4 sym) msk+ Nothing ->+ do q <- SW.bvFill (w4 sym) sz b+ bw' <- SW.bvAnd (w4 sym) bw =<< SW.bvNot (w4 sym) msk+ SW.bvXor (w4 sym) bw' =<< SW.bvAnd (w4 sym) q msk++ _ -> LargeBitsVal (wordValueSize sym wv) <$>+ updateBackSym sym (Nat n) eltTy (asBitsMap sym bv) (Right wv) val+++++-- | Table of floating point primitives+floatPrims :: W4.IsSymExprBuilder sym => What4 sym -> Map PrimIdent (Value sym)+floatPrims sym =+ Map.fromList [ (floatPrim i,v) | (i,v) <- nonInfixTable ]+ where+ w4sym = w4 sym+ (~>) = (,)++ nonInfixTable =+ [ "fpNaN" ~> fpConst (W4.fpNaN w4sym)+ , "fpPosInf" ~> fpConst (W4.fpPosInf w4sym)+ , "fpFromBits" ~> ilam \e -> ilam \p -> wlam sym \w ->+ VFloat <$> liftIO (W4.fpFromBinary w4sym e p w)+ , "fpToBits" ~> ilam \e -> ilam \p -> flam \x ->+ pure $ VWord (e+p)+ $ WordVal <$> liftIO (W4.fpToBinary w4sym x)+ , "=.=" ~> ilam \_ -> ilam \_ -> flam \x -> pure $ flam \y ->+ VBit <$> liftIO (W4.fpEq w4sym x y)+ , "fpIsFinite" ~> ilam \_ -> ilam \_ -> flam \x ->+ VBit <$> liftIO do inf <- W4.fpIsInf w4sym x+ nan <- W4.fpIsNaN w4sym x+ weird <- W4.orPred w4sym inf nan+ W4.notPred w4sym weird++ , "fpAdd" ~> fpBinArithV sym fpPlus+ , "fpSub" ~> fpBinArithV sym fpMinus+ , "fpMul" ~> fpBinArithV sym fpMult+ , "fpDiv" ~> fpBinArithV sym fpDiv++ , "fpFromRational" ~>+ ilam \e -> ilam \p -> wlam sym \r -> pure $ lam \x ->+ do rat <- fromVRational <$> x+ VFloat <$> fpCvtFromRational sym e p r rat++ , "fpToRational" ~>+ ilam \_e -> ilam \_p -> flam \fp ->+ VRational <$> fpCvtToRational sym fp+ ]++++-- | A helper for definitng floating point constants.+fpConst ::+ W4.IsSymExprBuilder sym =>+ (Integer -> Integer -> IO (W4.SFloat sym)) ->+ Value sym+fpConst mk =+ ilam \ e ->+ VNumPoly \ ~(Nat p) ->+ VFloat <$> liftIO (mk e p)
− src/Cryptol/Eval/What4/Float.hs
@@ -1,68 +0,0 @@-{-# Language BlockArguments #-}-{-# Language OverloadedStrings #-}--- | Floating point primitives for the What4 backend.-module Cryptol.Eval.What4.Float (floatPrims) where--import Data.Map(Map)-import qualified Data.Map as Map-import qualified What4.Interface as W4-import Control.Monad.IO.Class--import Cryptol.TypeCheck.Solver.InfNat(Nat'(..))-import Cryptol.Eval.Value-import Cryptol.Eval.Generic-import Cryptol.Eval.What4.Value-import qualified Cryptol.Eval.What4.SFloat as W4-import Cryptol.Utils.Ident(PrimIdent, floatPrim)---- | Table of floating point primitives-floatPrims :: W4.IsSymExprBuilder sym => What4 sym -> Map PrimIdent (Value sym)-floatPrims sym4@(What4 sym) =- Map.fromList [ (floatPrim i,v) | (i,v) <- nonInfixTable ]- where- (~>) = (,)-- nonInfixTable =- [ "fpNaN" ~> fpConst (W4.fpNaN sym)- , "fpPosInf" ~> fpConst (W4.fpPosInf sym)- , "fpFromBits" ~> ilam \e -> ilam \p -> wlam sym4 \w ->- VFloat <$> liftIO (W4.fpFromBinary sym e p w)- , "fpToBits" ~> ilam \e -> ilam \p -> flam \x ->- pure $ VWord (e+p)- $ WordVal <$> liftIO (W4.fpToBinary sym x)- , "=.=" ~> ilam \_ -> ilam \_ -> flam \x -> pure $ flam \y ->- VBit <$> liftIO (W4.fpEq sym x y)- , "fpIsFinite" ~> ilam \_ -> ilam \_ -> flam \x ->- VBit <$> liftIO do inf <- W4.fpIsInf sym x- nan <- W4.fpIsNaN sym x- weird <- W4.orPred sym inf nan- W4.notPred sym weird-- , "fpAdd" ~> fpBinArithV sym4 fpPlus- , "fpSub" ~> fpBinArithV sym4 fpMinus- , "fpMul" ~> fpBinArithV sym4 fpMult- , "fpDiv" ~> fpBinArithV sym4 fpDiv-- , "fpFromRational" ~>- ilam \e -> ilam \p -> wlam sym4 \r -> pure $ lam \x ->- do rat <- fromVRational <$> x- VFloat <$> fpCvtFromRational sym4 e p r rat-- , "fpToRational" ~>- ilam \_e -> ilam \_p -> flam \fp ->- VRational <$> fpCvtToRational sym4 fp- ]------ | A helper for definitng floating point constants.-fpConst ::- W4.IsExprBuilder sym =>- (Integer -> Integer -> IO (W4.SFloat sym)) ->- Value sym-fpConst mk =- ilam \ e ->- VNumPoly \ ~(Nat p) ->- VFloat <$> liftIO (mk e p)--
− src/Cryptol/Eval/What4/SFloat.hs
@@ -1,361 +0,0 @@-{-# Language DataKinds #-}-{-# Language FlexibleContexts #-}-{-# Language GADTs #-}-{-# Language RankNTypes #-}-{-# Language TypeApplications #-}-{-# Language TypeOperators #-}--- | Working with floats of dynamic sizes.--- This should probably be moved to What4 one day.-module Cryptol.Eval.What4.SFloat- ( -- * Interface- SFloat(..)- , fpReprOf- , fpSize-- -- * Constants- , fpFresh- , fpNaN- , fpPosInf- , fpFromRationalLit-- -- * Interchange formats- , fpFromBinary- , fpToBinary-- -- * Relations- , SFloatRel- , fpEq- , fpEqIEEE- , fpLtIEEE- , fpGtIEEE-- -- * Arithmetic- , SFloatBinArith- , fpNeg- , fpAdd- , fpSub- , fpMul- , fpDiv-- -- * Conversions- , fpRound- , fpToReal- , fpFromReal- , fpFromRational- , fpToRational- , fpFromInteger-- -- * Queries- , fpIsInf, fpIsNaN-- -- * Exceptions- , UnsupportedFloat(..)- , FPTypeError(..)- ) where--import Control.Exception--import Data.Parameterized.Some-import Data.Parameterized.NatRepr--import What4.BaseTypes-import What4.Panic(panic)-import What4.SWord-import What4.Interface---- | Symbolic floating point numbers.-data SFloat sym where- SFloat :: IsExpr (SymExpr sym) => SymFloat sym fpp -> SFloat sym---------------------------------------------------------------------------------------- | This exception is thrown if the operations try to create a--- floating point value we do not support-data UnsupportedFloat =- UnsupportedFloat { fpWho :: String, exponentBits, precisionBits :: Integer }- deriving Show----- | Throw 'UnsupportedFloat' exception-unsupported ::- String {- ^ Label -} ->- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- IO a-unsupported l e p =- throwIO UnsupportedFloat { fpWho = l- , exponentBits = e- , precisionBits = p }--instance Exception UnsupportedFloat---- | This exceptoin is throws if the types don't match.-data FPTypeError =- FPTypeError { fpExpected :: Some BaseTypeRepr- , fpActual :: Some BaseTypeRepr- }- deriving Show--instance Exception FPTypeError--fpTypeMismatch :: BaseTypeRepr t1 -> BaseTypeRepr t2 -> IO a-fpTypeMismatch expect actual =- throwIO FPTypeError { fpExpected = Some expect- , fpActual = Some actual- }-fpTypeError :: FloatPrecisionRepr t1 -> FloatPrecisionRepr t2 -> IO a-fpTypeError t1 t2 =- fpTypeMismatch (BaseFloatRepr t1) (BaseFloatRepr t2)-------------------------------------------------------------------------------------- | Construct the 'FloatPrecisionRepr' with the given parameters.-fpRepr ::- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- Maybe (Some FloatPrecisionRepr)-fpRepr iE iP =- do Some e <- someNat iE- LeqProof <- testLeq (knownNat @2) e- Some p <- someNat iP- LeqProof <- testLeq (knownNat @2) p- pure (Some (FloatingPointPrecisionRepr e p))--fpReprOf ::- IsExpr (SymExpr sym) => sym -> SymFloat sym fpp -> FloatPrecisionRepr fpp-fpReprOf _ e =- case exprType e of- BaseFloatRepr r -> r--fpSize :: SFloat sym -> (Integer,Integer)-fpSize (SFloat f) =- case exprType f of- BaseFloatRepr (FloatingPointPrecisionRepr e p) -> (intValue e, intValue p)-------------------------------------------------------------------------------------- Constants---- | A fresh variable of the given type.-fpFresh ::- IsSymExprBuilder sym =>- sym ->- Integer ->- Integer ->- IO (SFloat sym)-fpFresh sym e p- | Just (Some fpp) <- fpRepr e p =- SFloat <$> freshConstant sym emptySymbol (BaseFloatRepr fpp)- | otherwise = unsupported "fpFresh" e p---- | Not a number-fpNaN ::- IsExprBuilder sym =>- sym ->- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- IO (SFloat sym)-fpNaN sym e p- | Just (Some fpp) <- fpRepr e p = SFloat <$> floatNaN sym fpp- | otherwise = unsupported "fpNaN" e p----- | Positive infinity-fpPosInf ::- IsExprBuilder sym =>- sym ->- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- IO (SFloat sym)-fpPosInf sym e p- | Just (Some fpp) <- fpRepr e p = SFloat <$> floatPInf sym fpp- | otherwise = unsupported "fpPosInf" e p---- | A floating point number corresponding to the given rations.-fpFromRationalLit ::- IsExprBuilder sym =>- sym ->- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- Rational ->- IO (SFloat sym)-fpFromRationalLit sym e p r- | Just (Some fpp) <- fpRepr e p = SFloat <$> floatLit sym fpp r- | otherwise = unsupported "fpFromRational" e p----- | Make a floating point number with the given bit representation.-fpFromBinary ::- IsExprBuilder sym =>- sym ->- Integer {- ^ Exponent width -} ->- Integer {- ^ Precision width -} ->- SWord sym ->- IO (SFloat sym)-fpFromBinary sym e p swe- | DBV sw <- swe- , Just (Some fpp) <- fpRepr e p- , FloatingPointPrecisionRepr ew pw <- fpp- , let expectW = addNat ew pw- , actual@(BaseBVRepr actualW) <- exprType sw =- case testEquality expectW actualW of- Just Refl -> SFloat <$> floatFromBinary sym fpp sw- Nothing -- we want to report type correct type errors! :-)- | Just LeqProof <- testLeq (knownNat @1) expectW ->- fpTypeMismatch (BaseBVRepr expectW) actual- | otherwise -> panic "fpFromBits" [ "1 >= 2" ]- | otherwise = unsupported "fpFromBits" e p--fpToBinary :: IsExprBuilder sym => sym -> SFloat sym -> IO (SWord sym)-fpToBinary sym (SFloat f)- | FloatingPointPrecisionRepr e p <- fpReprOf sym f- , Just LeqProof <- testLeq (knownNat @1) (addNat e p)- = DBV <$> floatToBinary sym f- | otherwise = panic "fpToBinary" [ "we messed up the types" ]-------------------------------------------------------------------------------------- Arithmetic--fpNeg :: IsExprBuilder sym => sym -> SFloat sym -> IO (SFloat sym)-fpNeg sym (SFloat fl) = SFloat <$> floatNeg sym fl--fpBinArith ::- IsExprBuilder sym =>- (forall t.- sym ->- RoundingMode ->- SymFloat sym t ->- SymFloat sym t ->- IO (SymFloat sym t)- ) ->- sym -> RoundingMode -> SFloat sym -> SFloat sym -> IO (SFloat sym)-fpBinArith fun sym r (SFloat x) (SFloat y) =- let t1 = sym `fpReprOf` x- t2 = sym `fpReprOf` y- in- case testEquality t1 t2 of- Just Refl -> SFloat <$> fun sym r x y- _ -> fpTypeError t1 t2--type SFloatBinArith sym =- sym -> RoundingMode -> SFloat sym -> SFloat sym -> IO (SFloat sym)--fpAdd :: IsExprBuilder sym => SFloatBinArith sym-fpAdd = fpBinArith floatAdd--fpSub :: IsExprBuilder sym => SFloatBinArith sym-fpSub = fpBinArith floatSub--fpMul :: IsExprBuilder sym => SFloatBinArith sym-fpMul = fpBinArith floatMul--fpDiv :: IsExprBuilder sym => SFloatBinArith sym-fpDiv = fpBinArith floatDiv---------------------------------------------------------------------------------------fpRel ::- IsExprBuilder sym =>- (forall t.- sym ->- SymFloat sym t ->- SymFloat sym t ->- IO (Pred sym)- ) ->- sym -> SFloat sym -> SFloat sym -> IO (Pred sym)-fpRel fun sym (SFloat x) (SFloat y) =- let t1 = sym `fpReprOf` x- t2 = sym `fpReprOf` y- in- case testEquality t1 t2 of- Just Refl -> fun sym x y- _ -> fpTypeError t1 t2-----type SFloatRel sym =- sym -> SFloat sym -> SFloat sym -> IO (Pred sym)--fpEq :: IsExprBuilder sym => SFloatRel sym-fpEq = fpRel floatEq--fpEqIEEE :: IsExprBuilder sym => SFloatRel sym-fpEqIEEE = fpRel floatFpEq--fpLtIEEE :: IsExprBuilder sym => SFloatRel sym-fpLtIEEE = fpRel floatLt--fpGtIEEE :: IsExprBuilder sym => SFloatRel sym-fpGtIEEE = fpRel floatGt------------------------------------------------------------------------------------fpRound ::- IsExprBuilder sym => sym -> RoundingMode -> SFloat sym -> IO (SFloat sym)-fpRound sym r (SFloat x) = SFloat <$> floatRound sym r x---- | This is undefined on "special" values (NaN,infinity)-fpToReal :: IsExprBuilder sym => sym -> SFloat sym -> IO (SymReal sym)-fpToReal sym (SFloat x) = floatToReal sym x--fpFromReal ::- IsExprBuilder sym =>- sym -> Integer -> Integer -> RoundingMode -> SymReal sym -> IO (SFloat sym)-fpFromReal sym e p r x- | Just (Some repr) <- fpRepr e p = SFloat <$> realToFloat sym repr r x- | otherwise = unsupported "fpFromReal" e p---fpFromInteger ::- IsExprBuilder sym =>- sym -> Integer -> Integer -> RoundingMode -> SymInteger sym -> IO (SFloat sym)-fpFromInteger sym e p r x = fpFromReal sym e p r =<< integerToReal sym x---fpFromRational ::- IsExprBuilder sym =>- sym -> Integer -> Integer -> RoundingMode ->- SymInteger sym -> SymInteger sym -> IO (SFloat sym)-fpFromRational sym e p r x y =- do num <- integerToReal sym x- den <- integerToReal sym y- res <- realDiv sym num den- fpFromReal sym e p r res--{- | Returns a predicate and two integers, @x@ and @y@.-If the the predicate holds, then @x / y@ is a rational representing-the floating point number. Assumes the FP number is not one of the-special ones that has no real representation. -}-fpToRational ::- IsSymExprBuilder sym =>- sym ->- SFloat sym ->- IO (Pred sym, SymInteger sym, SymInteger sym)-fpToRational sym fp =- do r <- fpToReal sym fp- x <- freshConstant sym emptySymbol BaseIntegerRepr- y <- freshConstant sym emptySymbol BaseIntegerRepr- num <- integerToReal sym x- den <- integerToReal sym y- res <- realDiv sym num den- same <- realEq sym r res- pure (same, x, y)-------------------------------------------------------------------------------------fpIsInf :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)-fpIsInf sym (SFloat x) = floatIsInf sym x--fpIsNaN :: IsExprBuilder sym => sym -> SFloat sym -> IO (Pred sym)-fpIsNaN sym (SFloat x) = floatIsNaN sym x---
− src/Cryptol/Eval/What4/Value.hs
@@ -1,975 +0,0 @@--- |--- Module : Cryptol.Eval.What4--- Copyright : (c) 2020 Galois, Inc.--- License : BSD3--- Maintainer : cryptol@galois.com--{-# LANGUAGE BlockArguments #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ViewPatterns #-}-module Cryptol.Eval.What4.Value where---import qualified Control.Exception as X-import Control.Monad (foldM,ap,liftM)-import Control.Monad.IO.Class-import Data.Bits (bit, shiftR, shiftL, testBit)-import qualified Data.BitVector.Sized as BV-import Data.List-import Data.Parameterized.NatRepr-import Data.Parameterized.Some--import qualified What4.Interface as W4-import qualified What4.SWord as SW-import qualified Cryptol.Eval.What4.SFloat as FP-import qualified What4.Utils.AbstractDomains as W4--import Cryptol.Eval.Backend-import Cryptol.Eval.Concrete.Value( BV(..), ppBV )-import Cryptol.Eval.Generic-import Cryptol.Eval.Monad- ( Eval(..), EvalError(..), Unsupported(..)- , delayFill, blackhole, evalSpark- )-import Cryptol.Eval.Type (TValue(..))-import Cryptol.Eval.Value-import Cryptol.TypeCheck.Solver.InfNat (Nat'(..), widthInteger)-import Cryptol.Utils.Panic-import Cryptol.Utils.PP---data What4 sym = What4 sym--type Value sym = GenValue (What4 sym)--{- | This is the monad used for symbolic evaluation. It adds to-aspects to 'Eval'---'WConn' keeps track of the backend and collects-definitional predicates, and 'W4Eval` adds support for partially-defined values -}-newtype W4Eval sym a = W4Eval { evalPartial :: W4Conn sym (W4Result sym a) }--{- | This layer has the symbolic back-end, and can keep track of definitional-predicates used when working with uninterpreted constants defined-via a property. -}-newtype W4Conn sym a = W4Conn { evalConn :: sym -> Eval (W4Defs sym a) }---- | Keep track of a value and a context defining uninterpeted vairables.-data W4Defs sym a = W4Defs- { w4Defs :: !(W4.Pred sym)- , w4Result :: !a- }---- | The symbolic value we computed.-data W4Result sym a- = W4Error !EvalError- -- ^ A malformed value-- | W4Result !(W4.Pred sym) !a- -- ^ safety predicate and result: the result only makes sense when- -- the predicate holds.-------------------------------------------------------------------------------------- Moving between the layers--w4Eval :: W4Eval sym a -> sym -> Eval (W4Defs sym (W4Result sym a))-w4Eval (W4Eval (W4Conn m)) = m--w4Thunk :: Eval (W4Defs sym (W4Result sym a)) -> W4Eval sym a-w4Thunk m = W4Eval (W4Conn \_ -> m)---- | A value with no context.-doEval :: W4.IsExprBuilder sym => Eval a -> W4Conn sym a-doEval m = W4Conn \sym ->- do a <- m- pure W4Defs { w4Defs = W4.backendPred sym True- , w4Result = a- }---- | A total value.-total :: W4.IsExprBuilder sym => W4Conn sym a -> W4Eval sym a-total m = W4Eval- do sym <- getSym- W4Result (W4.backendPred sym True) <$> m--------------------------------------------------------------------------------------- Operations in WConn--instance W4.IsExprBuilder sym => Functor (W4Conn sym) where- fmap = liftM--instance W4.IsExprBuilder sym => Applicative (W4Conn sym) where- pure = doEval . pure- (<*>) = ap--instance W4.IsExprBuilder sym => Monad (W4Conn sym) where- m1 >>= f = W4Conn \sym ->- do res1 <- evalConn m1 sym- res2 <- evalConn (f (w4Result res1)) sym- defs <- liftIO (W4.andPred sym (w4Defs res1) (w4Defs res2))- pure res2 { w4Defs = defs }--instance W4.IsExprBuilder sym => MonadIO (W4Conn sym) where- liftIO = doEval . liftIO---- | Access the symbolic back-end-getSym :: W4.IsExprBuilder sym => W4Conn sym sym-getSym = W4Conn \sym -> pure W4Defs { w4Defs = W4.backendPred sym True- , w4Result = sym }---- | Record a definition.-addDef :: W4.Pred sym -> W4Conn sym ()-addDef p = W4Conn \_ -> pure W4Defs { w4Defs = p, w4Result = () }---- | Compute conjunction.-w4And :: W4.IsExprBuilder sym =>- W4.Pred sym -> W4.Pred sym -> W4Conn sym (W4.Pred sym)-w4And p q =- do sym <- getSym- liftIO (W4.andPred sym p q)---- | Compute negation.-w4Not :: W4.IsExprBuilder sym => W4.Pred sym -> W4Conn sym (W4.Pred sym)-w4Not p =- do sym <- getSym- liftIO (W4.notPred sym p)---- | Compute if-then-else.-w4ITE :: W4.IsExprBuilder sym =>- W4.Pred sym -> W4.Pred sym -> W4.Pred sym -> W4Conn sym (W4.Pred sym)-w4ITE ifP ifThen ifElse =- do sym <- getSym- liftIO (W4.itePred sym ifP ifThen ifElse)--------------------------------------------------------------------------------------- Operations in W4Eval--instance W4.IsExprBuilder sym => Functor (W4Eval sym) where- fmap = liftM--instance W4.IsExprBuilder sym => Applicative (W4Eval sym) where- pure = total . pure- (<*>) = ap--instance W4.IsExprBuilder sym => Monad (W4Eval sym) where- m1 >>= f = W4Eval- do res1 <- evalPartial m1- case res1 of- W4Error err -> pure (W4Error err)- W4Result px x' ->- do res2 <- evalPartial (f x')- case res2 of- W4Result py y ->- do pz <- w4And px py- pure (W4Result pz y)- W4Error _ -> pure res2--instance W4.IsExprBuilder sym => MonadIO (W4Eval sym) where- liftIO = total . liftIO----- | Add a definitional equation.--- This will always be asserted when we make queries to the solver.-addDefEqn :: W4.IsExprBuilder sym => W4.Pred sym -> W4Eval sym ()-addDefEqn p = total (addDef p)---- | Add s safety condition.-addSafety :: W4.IsExprBuilder sym => W4.Pred sym -> W4Eval sym ()-addSafety p = W4Eval (pure (W4Result p ()))---- | A fully undefined symbolic value-evalError :: W4.IsExprBuilder sym => EvalError -> W4Eval sym a-evalError err = W4Eval (pure (W4Error err))------------------------------------------------------------------------------------assertBVDivisor :: W4.IsExprBuilder sym => sym -> SW.SWord sym -> W4Eval sym ()-assertBVDivisor sym x =- do p <- liftIO (SW.bvIsNonzero sym x)- assertSideCondition (What4 sym) p DivideByZero--assertIntDivisor ::- W4.IsExprBuilder sym => sym -> W4.SymInteger sym -> W4Eval sym ()-assertIntDivisor sym x =- do p <- liftIO (W4.notPred sym =<< W4.intEq sym x =<< W4.intLit sym 0)- assertSideCondition (What4 sym) p DivideByZero----instance W4.IsExprBuilder sym => Backend (What4 sym) where- type SBit (What4 sym) = W4.Pred sym- type SWord (What4 sym) = SW.SWord sym- type SInteger (What4 sym) = W4.SymInteger sym- type SFloat (What4 sym) = FP.SFloat sym- type SEval (What4 sym) = W4Eval sym-- raiseError _ = evalError-- assertSideCondition _ cond err- | Just False <- W4.asConstantPred cond = evalError err- | otherwise = addSafety cond-- isReady (What4 sym) m =- case w4Eval m sym of- Ready _ -> True- _ -> False-- sDelayFill _ m retry =- total- do sym <- getSym- doEval (w4Thunk <$> delayFill (w4Eval m sym) (w4Eval retry sym))-- sSpark _ m =- total- do sym <- getSym- doEval (w4Thunk <$> evalSpark (w4Eval m sym))--- sDeclareHole _ msg =- total- do (hole, fill) <- doEval (blackhole msg)- pure ( w4Thunk hole- , \m -> total- do sym <- getSym- doEval (fill (w4Eval m sym))- )-- mergeEval _sym f c mx my = W4Eval- do rx <- evalPartial mx- ry <- evalPartial my- case (rx, ry) of-- (W4Error err, W4Error _) ->- pure (W4Error err) -- arbitrarily choose left error to report-- (W4Error _, W4Result p y) ->- do p' <- w4And p =<< w4Not c- pure (W4Result p' y)-- (W4Result p x, W4Error _) ->- do p' <- w4And p c- pure (W4Result p' x)-- (W4Result px x, W4Result py y) ->- do zr <- evalPartial (f c x y)- case zr of- W4Error err -> pure $ W4Error err- W4Result pz z ->- do p' <- w4And pz =<< w4ITE c px py- pure (W4Result p' z)-- wordAsChar _ bv- | SW.bvWidth bv == 8 = toEnum . fromInteger <$> SW.bvAsUnsignedInteger bv- | otherwise = Nothing-- wordLen _ bv = SW.bvWidth bv-- bitLit (What4 sym) b = W4.backendPred sym b- bitAsLit _ v = W4.asConstantPred v-- wordLit (What4 sym) intw i- | Just (Some w) <- someNat intw- = case isPosNat w of- Nothing -> pure $ SW.ZBV- Just LeqProof -> SW.DBV <$> liftIO (W4.bvLit sym w (BV.mkBV w i))- | otherwise = panic "what4: wordLit" ["invalid bit width:", show intw ]-- wordAsLit _ v- | Just x <- SW.bvAsUnsignedInteger v = Just (SW.bvWidth v, x)- | otherwise = Nothing-- integerLit (What4 sym) i = liftIO (W4.intLit sym i)-- integerAsLit _ v = W4.asInteger v-- ppBit _ v- | Just b <- W4.asConstantPred v = text $! if b then "True" else "False"- | otherwise = text "?"-- ppWord _ opts v- | Just x <- SW.bvAsUnsignedInteger v- = ppBV opts (BV (SW.bvWidth v) x)-- | otherwise = text "[?]"-- ppInteger _ _opts v- | Just x <- W4.asInteger v = integer x- | otherwise = text "[?]"-- ppFloat _ _opts _ = text "[?]"--- iteBit (What4 sym) c x y = liftIO (W4.itePred sym c x y)- iteWord (What4 sym) c x y = liftIO (SW.bvIte sym c x y)- iteInteger (What4 sym) c x y = liftIO (W4.intIte sym c x y)-- bitEq (What4 sym) x y = liftIO (W4.eqPred sym x y)- bitAnd (What4 sym) x y = liftIO (W4.andPred sym x y)- bitOr (What4 sym) x y = liftIO (W4.orPred sym x y)- bitXor (What4 sym) x y = liftIO (W4.xorPred sym x y)- bitComplement (What4 sym) x = liftIO (W4.notPred sym x)-- wordBit (What4 sym) bv idx = liftIO (SW.bvAtBE sym bv idx)- wordUpdate (What4 sym) bv idx b = liftIO (SW.bvSetBE sym bv idx b)-- packWord sym bs =- do z <- wordLit sym (genericLength bs) 0- let f w (idx,b) = wordUpdate sym w idx b- foldM f z (zip [0..] bs)-- unpackWord (What4 sym) bv = liftIO $- mapM (SW.bvAtBE sym bv) [0 .. SW.bvWidth bv-1]-- joinWord (What4 sym) x y = liftIO $ SW.bvJoin sym x y-- splitWord _sym 0 _ bv = pure (SW.ZBV, bv)- splitWord _sym _ 0 bv = pure (bv, SW.ZBV)- splitWord (What4 sym) lw rw bv = liftIO $- do l <- SW.bvSliceBE sym 0 lw bv- r <- SW.bvSliceBE sym lw rw bv- return (l, r)-- extractWord (What4 sym) bits idx bv =- liftIO $ SW.bvSliceBE sym idx bits bv-- wordEq (What4 sym) x y = liftIO (SW.bvEq sym x y)- wordLessThan (What4 sym) x y = liftIO (SW.bvult sym x y)- wordGreaterThan (What4 sym) x y = liftIO (SW.bvugt sym x y)- wordSignedLessThan (What4 sym) x y = liftIO (SW.bvslt sym x y)-- wordOr (What4 sym) x y = liftIO (SW.bvOr sym x y)- wordAnd (What4 sym) x y = liftIO (SW.bvAnd sym x y)- wordXor (What4 sym) x y = liftIO (SW.bvXor sym x y)- wordComplement (What4 sym) x = liftIO (SW.bvNot sym x)-- wordPlus (What4 sym) x y = liftIO (SW.bvAdd sym x y)- wordMinus (What4 sym) x y = liftIO (SW.bvSub sym x y)- wordMult (What4 sym) x y = liftIO (SW.bvMul sym x y)- wordNegate (What4 sym) x = liftIO (SW.bvNeg sym x)- wordLg2 (What4 sym) x = sLg2 sym x-- wordDiv (What4 sym) x y =- do assertBVDivisor sym y- liftIO (SW.bvUDiv sym x y)- wordMod (What4 sym) x y =- do assertBVDivisor sym y- liftIO (SW.bvURem sym x y)- wordSignedDiv (What4 sym) x y =- do assertBVDivisor sym y- liftIO (SW.bvSDiv sym x y)- wordSignedMod (What4 sym) x y =- do assertBVDivisor sym y- liftIO (SW.bvSRem sym x y)-- wordToInt (What4 sym) x = liftIO (SW.bvToInteger sym x)- wordFromInt (What4 sym) width i = liftIO (SW.integerToBV sym i width)-- intPlus (What4 sym) x y = liftIO $ W4.intAdd sym x y- intMinus (What4 sym) x y = liftIO $ W4.intSub sym x y- intMult (What4 sym) x y = liftIO $ W4.intMul sym x y- intNegate (What4 sym) x = liftIO $ W4.intNeg sym x-- -- NB: What4's division operation provides SMTLib's euclidean division,- -- which doesn't match the round-to-neg-infinity semantics of Cryptol,- -- so we have to do some work to get the desired semantics.- intDiv (What4 sym) x y =- do assertIntDivisor sym y- liftIO $ do- neg <- liftIO (W4.intLt sym y =<< W4.intLit sym 0)- case W4.asConstantPred neg of- Just False -> W4.intDiv sym x y- Just True ->- do xneg <- W4.intNeg sym x- yneg <- W4.intNeg sym y- W4.intDiv sym xneg yneg- Nothing ->- do xneg <- W4.intNeg sym x- yneg <- W4.intNeg sym y- zneg <- W4.intDiv sym xneg yneg- z <- W4.intDiv sym x y- W4.intIte sym neg zneg z-- -- NB: What4's division operation provides SMTLib's euclidean division,- -- which doesn't match the round-to-neg-infinity semantics of Cryptol,- -- so we have to do some work to get the desired semantics.- intMod (What4 sym) x y =- do assertIntDivisor sym y- liftIO $ do- neg <- liftIO (W4.intLt sym y =<< W4.intLit sym 0)- case W4.asConstantPred neg of- Just False -> W4.intMod sym x y- Just True ->- do xneg <- W4.intNeg sym x- yneg <- W4.intNeg sym y- W4.intNeg sym =<< W4.intMod sym xneg yneg- Nothing ->- do xneg <- W4.intNeg sym x- yneg <- W4.intNeg sym y- z <- W4.intMod sym x y- zneg <- W4.intNeg sym =<< W4.intMod sym xneg yneg- W4.intIte sym neg zneg z-- intEq (What4 sym) x y = liftIO $ W4.intEq sym x y- intLessThan (What4 sym) x y = liftIO $ W4.intLt sym x y- intGreaterThan (What4 sym) x y = liftIO $ W4.intLt sym y x-- -- NB, we don't do reduction here on symbolic values- intToZn (What4 sym) m x- | Just xi <- W4.asInteger x- = liftIO $ W4.intLit sym (xi `mod` m)-- | otherwise- = pure x-- znToInt _ 0 _ = evalPanic "znToInt" ["0 modulus not allowed"]- znToInt (What4 sym) m x = liftIO (W4.intMod sym x =<< W4.intLit sym m)-- znEq _ 0 _ _ = evalPanic "znEq" ["0 modulus not allowed"]- znEq (What4 sym) m x y = liftIO $- do diff <- W4.intSub sym x y- W4.intDivisible sym diff (fromInteger m)-- znPlus (What4 sym) m x y = liftIO $ sModAdd sym m x y- znMinus (What4 sym) m x y = liftIO $ sModSub sym m x y- znMult (What4 sym) m x y = liftIO $ sModMult sym m x y- znNegate (What4 sym) m x = liftIO $ sModNegate sym m x-- ---------------------------------------------------------------- fpLit (What4 sym) e p r = liftIO $ FP.fpFromRationalLit sym e p r- fpEq (What4 sym) x y = liftIO $ FP.fpEqIEEE sym x y- fpLessThan (What4 sym) x y = liftIO $ FP.fpLtIEEE sym x y- fpGreaterThan (What4 sym) x y = liftIO $ FP.fpGtIEEE sym x y-- fpPlus = fpBinArith FP.fpAdd- fpMinus = fpBinArith FP.fpSub- fpMult = fpBinArith FP.fpMul- fpDiv = fpBinArith FP.fpDiv-- fpNeg (What4 sym) x = liftIO $ FP.fpNeg sym x-- fpFromInteger sym@(What4 sy) e p r x =- do rm <- fpRoundingMode sym r- liftIO $ FP.fpFromInteger sy e p rm x-- fpToInteger = fpCvtToInteger--sModAdd :: W4.IsExprBuilder sym =>- sym -> Integer -> W4.SymInteger sym -> W4.SymInteger sym -> IO (W4.SymInteger sym)-sModAdd _sym 0 _ _ = evalPanic "sModAdd" ["0 modulus not allowed"]-sModAdd sym m x y- | Just xi <- W4.asInteger x- , Just yi <- W4.asInteger y- = W4.intLit sym ((xi+yi) `mod` m)-- | otherwise- = W4.intAdd sym x y--sModSub :: W4.IsExprBuilder sym =>- sym -> Integer -> W4.SymInteger sym -> W4.SymInteger sym -> IO (W4.SymInteger sym)-sModSub _sym 0 _ _ = evalPanic "sModSub" ["0 modulus not allowed"]-sModSub sym m x y- | Just xi <- W4.asInteger x- , Just yi <- W4.asInteger y- = W4.intLit sym ((xi-yi) `mod` m)-- | otherwise- = W4.intSub sym x y---sModMult :: W4.IsExprBuilder sym =>- sym -> Integer -> W4.SymInteger sym -> W4.SymInteger sym -> IO (W4.SymInteger sym)-sModMult _sym 0 _ _ = evalPanic "sModMult" ["0 modulus not allowed"]-sModMult sym m x y- | Just xi <- W4.asInteger x- , Just yi <- W4.asInteger y- = W4.intLit sym ((xi*yi) `mod` m)-- | otherwise- = W4.intMul sym x y--sModNegate :: W4.IsExprBuilder sym =>- sym -> Integer -> W4.SymInteger sym -> IO (W4.SymInteger sym)-sModNegate _sym 0 _ = evalPanic "sModMult" ["0 modulus not allowed"]-sModNegate sym m x- | Just xi <- W4.asInteger x- = W4.intLit sym ((negate xi) `mod` m)-- | otherwise- = W4.intNeg sym x----- | Try successive powers of 2 to find the first that dominates the input.--- We could perhaps reduce to using CLZ instead...-sLg2 :: W4.IsExprBuilder sym => sym -> SW.SWord sym -> SEval (What4 sym) (SW.SWord sym)-sLg2 sym x = liftIO $ go 0- where- w = SW.bvWidth x- lit n = SW.bvLit sym w (toInteger n)-- go i | toInteger i < w =- do p <- SW.bvule sym x =<< lit (bit i)- lazyIte (SW.bvIte sym) p (lit i) (go (i+1))-- -- base case, should only happen when i = w- go i = lit i------ Errors ------------------------------------------------------------------------evalPanic :: String -> [String] -> a-evalPanic cxt = panic ("[What4 Symbolic]" ++ cxt)---lazyIte ::- (W4.IsExpr p, Monad m) =>- (p W4.BaseBoolType -> a -> a -> m a) ->- p W4.BaseBoolType ->- m a ->- m a ->- m a-lazyIte f c mx my- | Just b <- W4.asConstantPred c = if b then mx else my- | otherwise =- do x <- mx- y <- my- f c x y--indexFront_int ::- W4.IsExprBuilder sym =>- sym ->- Nat' ->- TValue ->- SeqMap (What4 sym) ->- TValue ->- SInteger (What4 sym) ->- SEval (What4 sym) (Value sym)-indexFront_int sym mblen _a xs ix idx- | Just i <- W4.asInteger idx- = lookupSeqMap xs i-- | (lo, Just hi) <- bounds- = foldr f def [lo .. hi]-- | otherwise- = liftIO (X.throw (UnsupportedSymbolicOp "unbounded integer indexing"))-- where- def = raiseError (What4 sym) (InvalidIndex Nothing)-- f n y =- do p <- liftIO (W4.intEq sym idx =<< W4.intLit sym n)- iteValue (What4 sym) p (lookupSeqMap xs n) y-- bounds =- (case W4.rangeLowBound (W4.integerBounds idx) of- W4.Inclusive l -> max l 0- _ -> 0- , case (maxIdx, W4.rangeHiBound (W4.integerBounds idx)) of- (Just n, W4.Inclusive h) -> Just (min n h)- (Just n, _) -> Just n- _ -> Nothing- )-- -- Maximum possible in-bounds index given `Z m`- -- type information and the length- -- of the sequence. If the sequences is infinite and the- -- integer is unbounded, there isn't much we can do.- maxIdx =- case (mblen, ix) of- (Nat n, TVIntMod m) -> Just (min (toInteger n) (toInteger m))- (Nat n, _) -> Just n- (_ , TVIntMod m) -> Just m- _ -> Nothing--indexBack_int ::- W4.IsExprBuilder sym =>- sym ->- Nat' ->- TValue ->- SeqMap (What4 sym) ->- TValue ->- SInteger (What4 sym) ->- SEval (What4 sym) (Value sym)-indexBack_int sym (Nat n) a xs ix idx = indexFront_int sym (Nat n) a (reverseSeqMap n xs) ix idx-indexBack_int _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack_int"]--indexFront_word ::- W4.IsExprBuilder sym =>- sym ->- Nat' ->- TValue ->- SeqMap (What4 sym) ->- TValue ->- SWord (What4 sym) ->- SEval (What4 sym) (Value sym)-indexFront_word sym mblen _a xs _ix idx- | Just i <- SW.bvAsUnsignedInteger idx- = lookupSeqMap xs i-- | otherwise- = foldr f def idxs-- where- w = SW.bvWidth idx- def = raiseError (What4 sym) (InvalidIndex Nothing)-- f n y =- do p <- liftIO (SW.bvEq sym idx =<< SW.bvLit sym w n)- iteValue (What4 sym) p (lookupSeqMap xs n) y-- -- maximum possible in-bounds index given the bitwidth- -- of the index value and the length of the sequence- maxIdx =- case mblen of- Nat n | n < 2^w -> n-1- _ -> 2^w - 1-- -- concrete indices to consider, intersection of the- -- range of values the index value might take with- -- the legal values- idxs =- case SW.unsignedBVBounds idx of- Just (lo, hi) -> [lo .. min hi maxIdx]- _ -> [0 .. maxIdx]--indexBack_word ::- W4.IsExprBuilder sym =>- sym ->- Nat' ->- TValue ->- SeqMap (What4 sym) ->- TValue ->- SWord (What4 sym) ->- SEval (What4 sym) (Value sym)-indexBack_word sym (Nat n) a xs ix idx = indexFront_word sym (Nat n) a (reverseSeqMap n xs) ix idx-indexBack_word _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack_word"]--indexFront_bits :: forall sym.- W4.IsExprBuilder sym =>- sym ->- Nat' ->- TValue ->- SeqMap (What4 sym) ->- TValue ->- [SBit (What4 sym)] ->- SEval (What4 sym) (Value sym)-indexFront_bits sym mblen _a xs _ix bits0 = go 0 (length bits0) bits0- where- go :: Integer -> Int -> [W4.Pred sym] -> W4Eval sym (Value sym)- go i _k []- -- For indices out of range, fail- | Nat n <- mblen- , i >= n- = raiseError (What4 sym) (InvalidIndex (Just i))-- | otherwise- = lookupSeqMap xs i-- go i k (b:bs)- -- Fail early when all possible indices we could compute from here- -- are out of bounds- | Nat n <- mblen- , (i `shiftL` k) >= n- = raiseError (What4 sym) (InvalidIndex Nothing)-- | otherwise- = iteValue (What4 sym) b- (go ((i `shiftL` 1) + 1) (k-1) bs)- (go (i `shiftL` 1) (k-1) bs)--indexBack_bits ::- W4.IsExprBuilder sym =>- sym ->- Nat' ->- TValue ->- SeqMap (What4 sym) ->- TValue ->- [SBit (What4 sym)] ->- SEval (What4 sym) (Value sym)-indexBack_bits sym (Nat n) a xs ix idx = indexFront_bits sym (Nat n) a (reverseSeqMap n xs) ix idx-indexBack_bits _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["indexBack_bits"]----- | Compare a symbolic word value with a concrete integer.-wordValueEqualsInteger :: forall sym.- W4.IsExprBuilder sym =>- sym ->- WordValue (What4 sym) ->- Integer ->- W4Eval sym (W4.Pred sym)-wordValueEqualsInteger sym wv i- | wordValueSize (What4 sym) wv < widthInteger i = return (W4.falsePred sym)- | otherwise =- case wv of- WordVal w -> liftIO (SW.bvEq sym w =<< SW.bvLit sym (SW.bvWidth w) i)- _ -> liftIO . bitsAre i =<< enumerateWordValueRev (What4 sym) wv -- little-endian- where- bitsAre :: Integer -> [W4.Pred sym] -> IO (W4.Pred sym)- bitsAre n [] = pure (W4.backendPred sym (n == 0))- bitsAre n (b : bs) =- do pb <- bitIs (testBit n 0) b- pbs <- bitsAre (n `shiftR` 1) bs- W4.andPred sym pb pbs-- bitIs :: Bool -> W4.Pred sym -> IO (W4.Pred sym)- bitIs b x = if b then pure x else W4.notPred sym x--updateFrontSym ::- W4.IsExprBuilder sym =>- sym ->- Nat' ->- TValue ->- SeqMap (What4 sym) ->- Either (SInteger (What4 sym)) (WordValue (What4 sym)) ->- SEval (What4 sym) (Value sym) ->- SEval (What4 sym) (SeqMap (What4 sym))-updateFrontSym sym _len _eltTy vs (Left idx) val =- case W4.asInteger idx of- Just i -> return $ updateSeqMap vs i val- Nothing -> return $ IndexSeqMap $ \i ->- do b <- intEq (What4 sym) idx =<< integerLit (What4 sym) i- iteValue (What4 sym) b val (lookupSeqMap vs i)--updateFrontSym sym _len _eltTy vs (Right wv) val =- case wv of- WordVal w | Just j <- SW.bvAsUnsignedInteger w ->- return $ updateSeqMap vs j val- _ ->- memoMap $ IndexSeqMap $ \i ->- do b <- wordValueEqualsInteger sym wv i- iteValue (What4 sym) b val (lookupSeqMap vs i)--updateBackSym ::- W4.IsExprBuilder sym =>- sym ->- Nat' ->- TValue ->- SeqMap (What4 sym) ->- Either (SInteger (What4 sym)) (WordValue (What4 sym)) ->- SEval (What4 sym) (Value sym) ->- SEval (What4 sym) (SeqMap (What4 sym))-updateBackSym _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateBackSym"]--updateBackSym sym (Nat n) _eltTy vs (Left idx) val =- case W4.asInteger idx of- Just i -> return $ updateSeqMap vs (n - 1 - i) val- Nothing -> return $ IndexSeqMap $ \i ->- do b <- intEq (What4 sym) idx =<< integerLit (What4 sym) (n - 1 - i)- iteValue (What4 sym) b val (lookupSeqMap vs i)--updateBackSym sym (Nat n) _eltTy vs (Right wv) val =- case wv of- WordVal w | Just j <- SW.bvAsUnsignedInteger w ->- return $ updateSeqMap vs (n - 1 - j) val- _ ->- memoMap $ IndexSeqMap $ \i ->- do b <- wordValueEqualsInteger sym wv (n - 1 - i)- iteValue (What4 sym) b val (lookupSeqMap vs i)---updateFrontSym_word ::- W4.IsExprBuilder sym =>- sym ->- Nat' ->- TValue ->- WordValue (What4 sym) ->- Either (SInteger (What4 sym)) (WordValue (What4 sym)) ->- SEval (What4 sym) (GenValue (What4 sym)) ->- SEval (What4 sym) (WordValue (What4 sym))-updateFrontSym_word _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateFrontSym_word"]--updateFrontSym_word sym (Nat _) eltTy (LargeBitsVal n bv) idx val =- LargeBitsVal n <$> updateFrontSym sym (Nat n) eltTy bv idx val--updateFrontSym_word sym (Nat n) eltTy (WordVal bv) (Left idx) val =- do idx' <- wordFromInt (What4 sym) n idx- updateFrontSym_word sym (Nat n) eltTy (WordVal bv) (Right (WordVal idx')) val--updateFrontSym_word sym (Nat n) eltTy bv (Right wv) val =- case wv of- WordVal idx- | Just j <- SW.bvAsUnsignedInteger idx ->- updateWordValue (What4 sym) bv j (fromVBit <$> val)-- | WordVal bw <- bv ->- WordVal <$>- do b <- fromVBit <$> val- let sz = SW.bvWidth bw- highbit <- liftIO (SW.bvLit sym sz (bit (fromInteger (sz-1))))- msk <- w4bvLshr sym highbit idx- liftIO $- case W4.asConstantPred b of- Just True -> SW.bvOr sym bw msk- Just False -> SW.bvAnd sym bw =<< SW.bvNot sym msk- Nothing ->- do q <- SW.bvFill sym sz b- bw' <- SW.bvAnd sym bw =<< SW.bvNot sym msk- SW.bvXor sym bw' =<< SW.bvAnd sym q msk-- _ -> LargeBitsVal (wordValueSize (What4 sym) wv) <$>- updateFrontSym sym (Nat n) eltTy (asBitsMap (What4 sym) bv) (Right wv) val---updateBackSym_word ::- W4.IsExprBuilder sym =>- sym ->- Nat' ->- TValue ->- WordValue (What4 sym) ->- Either (SInteger (What4 sym)) (WordValue (What4 sym)) ->- SEval (What4 sym) (GenValue (What4 sym)) ->- SEval (What4 sym) (WordValue (What4 sym))-updateBackSym_word _ Inf _ _ _ _ = evalPanic "Expected finite sequence" ["updateBackSym_word"]--updateBackSym_word sym (Nat _) eltTy (LargeBitsVal n bv) idx val =- LargeBitsVal n <$> updateBackSym sym (Nat n) eltTy bv idx val--updateBackSym_word sym (Nat n) eltTy (WordVal bv) (Left idx) val =- do idx' <- wordFromInt (What4 sym) n idx- updateBackSym_word sym (Nat n) eltTy (WordVal bv) (Right (WordVal idx')) val--updateBackSym_word sym (Nat n) eltTy bv (Right wv) val =- case wv of- WordVal idx- | Just j <- SW.bvAsUnsignedInteger idx ->- updateWordValue (What4 sym) bv (n - 1 - j) (fromVBit <$> val)-- | WordVal bw <- bv ->- WordVal <$>- do b <- fromVBit <$> val- let sz = SW.bvWidth bw- lowbit <- liftIO (SW.bvLit sym sz 1)- msk <- w4bvShl sym lowbit idx- liftIO $- case W4.asConstantPred b of- Just True -> SW.bvOr sym bw msk- Just False -> SW.bvAnd sym bw =<< SW.bvNot sym msk- Nothing ->- do q <- SW.bvFill sym sz b- bw' <- SW.bvAnd sym bw =<< SW.bvNot sym msk- SW.bvXor sym bw' =<< SW.bvAnd sym q msk-- _ -> LargeBitsVal (wordValueSize (What4 sym) wv) <$>- updateBackSym sym (Nat n) eltTy (asBitsMap (What4 sym) bv) (Right wv) val---sshrV :: W4.IsExprBuilder sym => sym -> Value sym-sshrV sym =- nlam $ \(Nat n) ->- tlam $ \ix ->- wlam (What4 sym) $ \x -> return $- lam $ \y ->- y >>= asIndex (What4 sym) ">>$" ix >>= \case- Left i ->- do pneg <- intLessThan (What4 sym) i =<< integerLit (What4 sym) 0- zneg <- do i' <- shiftShrink (What4 sym) (Nat n) ix =<< intNegate (What4 sym) i- amt <- wordFromInt (What4 sym) n i'- w4bvShl sym x amt- zpos <- do i' <- shiftShrink (What4 sym) (Nat n) ix i- amt <- wordFromInt (What4 sym) n i'- w4bvAshr sym x amt- return (VWord (SW.bvWidth x) (WordVal <$> iteWord (What4 sym) pneg zneg zpos))-- Right wv ->- do amt <- asWordVal (What4 sym) wv- return (VWord (SW.bvWidth x) (WordVal <$> w4bvAshr sym x amt))---w4bvShl :: W4.IsExprBuilder sym => sym -> SW.SWord sym -> SW.SWord sym -> W4Eval sym (SW.SWord sym)-w4bvShl sym x y = liftIO $ SW.bvShl sym x y--w4bvLshr :: W4.IsExprBuilder sym => sym -> SW.SWord sym -> SW.SWord sym -> W4Eval sym (SW.SWord sym)-w4bvLshr sym x y = liftIO $ SW.bvLshr sym x y--w4bvAshr :: W4.IsExprBuilder sym => sym -> SW.SWord sym -> SW.SWord sym -> W4Eval sym (SW.SWord sym)-w4bvAshr sym x y = liftIO $ SW.bvAshr sym x y--w4bvRol :: W4.IsExprBuilder sym => sym -> SW.SWord sym -> SW.SWord sym -> W4Eval sym (SW.SWord sym)-w4bvRol sym x y = liftIO $ SW.bvRol sym x y--w4bvRor :: W4.IsExprBuilder sym => sym -> SW.SWord sym -> SW.SWord sym -> W4Eval sym (SW.SWord sym)-w4bvRor sym x y = liftIO $ SW.bvRor sym x y----fpRoundingMode ::- W4.IsExprBuilder sym =>- What4 sym -> SWord (What4 sym) -> SEval (What4 sym) W4.RoundingMode-fpRoundingMode sym@(What4 sy) v =- case wordAsLit sym v of- Just (_w,i) ->- case i of- 0 -> pure W4.RNE- 1 -> pure W4.RNA- 2 -> pure W4.RTP- 3 -> pure W4.RTN- 4 -> pure W4.RTZ- x -> do let err = BadRoundingMode x- assertSideCondition sym (W4.falsePred sy) err- raiseError sym err- _ -> liftIO $ X.throwIO $ UnsupportedSymbolicOp "rounding mode"--fpBinArith ::- W4.IsExprBuilder sym =>- FP.SFloatBinArith sym ->- What4 sym ->- SWord (What4 sym) ->- SFloat (What4 sym) ->- SFloat (What4 sym) ->- SEval (What4 sym) (SFloat (What4 sym))-fpBinArith fun = \sym@(What4 s) r x y ->- do m <- fpRoundingMode sym r- liftIO (fun s m x y)---fpCvtToInteger ::- (W4.IsExprBuilder sy, sym ~ What4 sy) =>- sym -> String -> SWord sym -> SFloat sym -> SEval sym (SInteger sym)-fpCvtToInteger sym@(What4 sy) fun r x =- do grd <- liftIO- do bad1 <- FP.fpIsInf sy x- bad2 <- FP.fpIsNaN sy x- W4.notPred sy =<< W4.orPred sy bad1 bad2- assertSideCondition sym grd (BadValue fun)- rnd <- fpRoundingMode sym r- liftIO- do y <- FP.fpToReal sy x- case rnd of- W4.RNE -> W4.realRoundEven sy y- W4.RNA -> W4.realRound sy y- W4.RTP -> W4.realCeil sy y- W4.RTN -> W4.realFloor sy y- W4.RTZ -> W4.realTrunc sy y---fpCvtToRational ::- (W4.IsSymExprBuilder sy, sym ~ What4 sy) =>- sym -> SFloat sym -> SEval sym (SRational sym)-fpCvtToRational sym@(What4 sy) fp =- do grd <- liftIO- do bad1 <- FP.fpIsInf sy fp- bad2 <- FP.fpIsNaN sy fp- W4.notPred sy =<< W4.orPred sy bad1 bad2- assertSideCondition sym grd (BadValue "fpToRational")- (rel,x,y) <- liftIO (FP.fpToRational sy fp)- addDefEqn rel- ratio sym x y--fpCvtFromRational ::- (W4.IsExprBuilder sy, sym ~ What4 sy) =>- sym -> Integer -> Integer -> SWord sym ->- SRational sym -> SEval sym (SFloat sym)-fpCvtFromRational sym@(What4 sy) e p r rat =- do rnd <- fpRoundingMode sym r- liftIO (FP.fpFromRational sy e p rnd (sNum rat) (sDenom rat))--
+ src/Cryptol/F2.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MagicHash #-}+module Cryptol.F2 where++import Data.Bits+import Cryptol.TypeCheck.Solver.InfNat (widthInteger)++pmult :: Int -> Integer -> Integer -> Integer+pmult w x y = go (w-1) 0+ where+ go !i !z+ | i >= 0 = go (i-1) (if testBit x i then (z `shiftL` 1) `xor` y else (z `shiftL` 1))+ | otherwise = z++pdiv :: Int -> Integer -> Integer -> Integer+pdiv w x m = go (w-1) 0 0+ where+ degree :: Int+ degree = fromInteger (widthInteger m - 1)++ reduce :: Integer -> Integer+ reduce u = if testBit u degree then u `xor` m else u+ {-# INLINE reduce #-}++ go !i !z !r+ | i >= 0 = go (i-1) z' r'+ | otherwise = r+ where+ zred = reduce z+ z' = if testBit x i then (zred `shiftL` 1) .|. 1 else zred `shiftL` 1+ r' = if testBit z' degree then (r `shiftL` 1) .|. 1 else r `shiftL` 1+++pmod :: Int -> Integer -> Integer -> Integer+pmod w x m = mask .&. go 0 0 (reduce 1)+ where+ degree :: Int+ degree = fromInteger (widthInteger m - 1)++ reduce :: Integer -> Integer+ reduce u = if testBit u degree then u `xor` m else u+ {-# INLINE reduce #-}++ mask = bit degree - 1++ go !i !z !p+ | i < w = go (i+1) (if testBit x i then z `xor` p else z) (reduce (p `shiftL` 1))+ | otherwise = z
src/Cryptol/IR/FreeVars.hs view
@@ -103,7 +103,7 @@ ETuple es -> freeVars es ERec fs -> freeVars (recordElements fs) ESel e _ -> freeVars e- ESet e _ v -> freeVars [e,v]+ ESet ty e _ v -> freeVars ty <> freeVars [e,v] EIf e1 e2 e3 -> freeVars [e1,e2,e3] EComp t1 t2 e mss -> freeVars [t1,t2] <> rmVals (defs mss) (freeVars e) <> mconcat (map foldFree mss)
src/Cryptol/ModuleSystem.hs view
@@ -75,7 +75,7 @@ loadModuleByName n (evo, byteReader, env) = runModuleM (evo, byteReader, resetModuleEnv env) $ do unloadModule ((n ==) . lmName)- (path,m') <- Base.loadModuleFrom (FromModule n)+ (path,m') <- Base.loadModuleFrom False (FromModule n) setFocusedModule (T.mName m') return (path,m')
src/Cryptol/ModuleSystem/Base.hs view
@@ -42,15 +42,15 @@ import qualified Cryptol.TypeCheck.PP as T import qualified Cryptol.TypeCheck.Sanity as TcSanity import Cryptol.Transform.AddModParams (addModParams)-import Cryptol.Utils.Ident (preludeName, floatName, arrayName, interactiveName- , modNameChunks, notParamInstModName- , isParamInstModName )+import Cryptol.Utils.Ident ( preludeName, floatName, arrayName, suiteBName, primeECName+ , preludeReferenceName, interactiveName, modNameChunks+ , notParamInstModName, isParamInstModName ) import Cryptol.Utils.PP (pretty) import Cryptol.Utils.Panic (panic) import Cryptol.Utils.Logger(logPutStrLn, logPrint) -import Cryptol.Prelude (preludeContents, floatContents, arrayContents)-+import Cryptol.Prelude ( preludeContents, floatContents, arrayContents+ , suiteBContents, primeECContents, preludeReferenceContents ) import Cryptol.Transform.MonoValues (rewModule) import qualified Control.Exception as X@@ -164,7 +164,7 @@ case lookupModule n env of -- loadModule will calculate the canonical path again- Nothing -> doLoadModule (FromModule n) (InFile foundPath) fp pm+ Nothing -> doLoadModule False (FromModule n) (InFile foundPath) fp pm Just lm | path' == loaded -> return (lmModule lm) | otherwise -> duplicateModuleName n path' loaded@@ -172,8 +172,8 @@ -- | Load a module, unless it was previously loaded.-loadModuleFrom :: ImportSource -> ModuleM (ModulePath,T.Module)-loadModuleFrom isrc =+loadModuleFrom :: Bool {- ^ quiet mode -} -> ImportSource -> ModuleM (ModulePath,T.Module)+loadModuleFrom quiet isrc = do let n = importedModule isrc mb <- getLoadedMaybe n case mb of@@ -182,27 +182,29 @@ do path <- findModule n errorInFile path $ do (fp, pm) <- parseModule path- m <- doLoadModule isrc path fp pm+ m <- doLoadModule quiet isrc path fp pm return (path,m) -- | Load dependencies, typecheck, and add to the eval environment. doLoadModule ::+ Bool {- ^ quiet mode: true suppresses the "loading module" message -} -> ImportSource -> ModulePath -> Fingerprint -> P.Module PName -> ModuleM T.Module-doLoadModule isrc path fp pm0 =+doLoadModule quiet isrc path fp pm0 = loading isrc $ do let pm = addPrelude pm0 loadDeps pm - withLogger logPutStrLn+ unless quiet $ withLogger logPutStrLn ("Loading module " ++ pretty (P.thing (P.mName pm))) tcm <- optionalInstantiate =<< checkModule isrc path pm -- extend the eval env, unless a functor.- let ?evalPrim = Concrete.evalPrim+ tbl <- Concrete.primTable <$> getEvalOpts+ let ?evalPrim = \i -> Right <$> Map.lookup i tbl unless (T.isParametrizedModule tcm) $ modifyEvalEnv (E.moduleEnv Concrete tcm) loadedModule path fp tcm @@ -260,7 +262,10 @@ case n of m | m == preludeName -> pure (InMem "Cryptol" preludeContents) | m == floatName -> pure (InMem "Float" floatContents)- | m == arrayName -> pure (InMem "Array" arrayContents)+ | m == arrayName -> pure (InMem "Array" arrayContents)+ | m == suiteBName -> pure (InMem "SuiteB" suiteBContents)+ | m == primeECName -> pure (InMem "PrimeEC" primeECContents)+ | m == preludeReferenceName -> pure (InMem "Cryptol::Reference" preludeReferenceContents) _ -> moduleNotFound n =<< getSearchPath -- generate all possible search paths@@ -310,9 +315,9 @@ do mapM_ loadI (P.mImports m) mapM_ loadF (P.mInstance m) where- loadI i = do (_,m1) <- loadModuleFrom (FromImport i)+ loadI i = do (_,m1) <- loadModuleFrom False (FromImport i) when (T.isParametrizedModule m1) $ importParamModule $ T.mName m1- loadF f = do _ <- loadModuleFrom (FromModuleInstance f)+ loadF f = do _ <- loadModuleFrom False (FromModuleInstance f) return () @@ -500,10 +505,10 @@ case out of - T.InferOK warns seeds supply' o ->+ T.InferOK nameMap warns seeds supply' o -> do setNameSeeds seeds setSupply supply'- typeCheckWarnings warns+ typeCheckWarnings nameMap warns menv <- getModuleEnv case meCoreLint menv of NoCoreLint -> return ()@@ -514,9 +519,9 @@ Left err -> panic "Core lint failed:" [show err] return o - T.InferFailed warns errs ->- do typeCheckWarnings warns- typeCheckingFailed errs+ T.InferFailed nameMap warns errs ->+ do typeCheckWarnings nameMap warns+ typeCheckingFailed nameMap errs -- | Generate input for the typechecker. genInferInput :: Range -> PrimMap ->@@ -555,8 +560,9 @@ env <- getEvalEnv denv <- getDynEnv evopts <- getEvalOpts- let ?evalPrim = Concrete.evalPrim- io $ E.runEval evopts $ (E.evalExpr Concrete (env <> deEnv denv) e)+ let tbl = Concrete.primTable evopts+ let ?evalPrim = \i -> Right <$> Map.lookup i tbl+ io $ E.runEval $ (E.evalExpr Concrete (env <> deEnv denv) e) evalDecls :: [T.DeclGroup] -> ModuleM () evalDecls dgs = do@@ -564,8 +570,9 @@ denv <- getDynEnv evOpts <- getEvalOpts let env' = env <> deEnv denv- let ?evalPrim = Concrete.evalPrim- deEnv' <- io $ E.runEval evOpts $ E.evalDecls Concrete dgs env'+ let tbl = Concrete.primTable evOpts+ let ?evalPrim = \i -> Right <$> Map.lookup i tbl+ deEnv' <- io $ E.runEval $ E.evalDecls Concrete dgs env' let denv' = denv { deDecls = deDecls denv ++ dgs , deEnv = deEnv' }
src/Cryptol/ModuleSystem/InstantiateModule.hs view
@@ -14,6 +14,7 @@ import Cryptol.ModuleSystem.Name import Cryptol.TypeCheck.AST import Cryptol.TypeCheck.Subst(listParamSubst, apSubst)+import Cryptol.TypeCheck.SimpType(tRebuild) import Cryptol.Utils.Ident(ModName,modParamIdent) {-@@ -186,7 +187,7 @@ ETuple es -> ETuple (inst env es) ERec xs -> ERec (fmap go xs) ESel e s -> ESel (go e) s- ESet e x v -> ESet (go e) x (go v)+ ESet ty e x v -> ESet (inst env ty) (go e) x (go v) EIf e1 e2 e3 -> EIf (go e1) (go e2) (go e3) EComp t1 t2 e mss -> EComp (inst env t1) (inst env t2) (go e)@@ -232,6 +233,7 @@ instance Inst Type where inst env ty =+ tRebuild $ case ty of TCon tc ts -> TCon (inst env tc) (inst env ts) TVar tv ->
src/Cryptol/ModuleSystem/Interface.hs view
@@ -32,6 +32,7 @@ import qualified Data.Map as Map import Data.Semigroup+import Data.Text (Text) import GHC.Generics (Generic) import Control.DeepSeq@@ -100,7 +101,7 @@ , ifDeclPragmas :: [Pragma] -- ^ Pragmas , ifDeclInfix :: Bool -- ^ Is this an infix thing , ifDeclFixity :: Maybe Fixity -- ^ Fixity information- , ifDeclDoc :: Maybe String -- ^ Documentation+ , ifDeclDoc :: Maybe Text -- ^ Documentation } deriving (Show, Generic, NFData) mkIfaceDecl :: Decl -> IfaceDecl
src/Cryptol/ModuleSystem/Monad.hs view
@@ -14,7 +14,8 @@ import Cryptol.Eval (EvalEnv,EvalOpts(..)) -import qualified Cryptol.Eval.Monad as E+import qualified Cryptol.Backend.Monad as E+ import Cryptol.ModuleSystem.Env import Cryptol.ModuleSystem.Fingerprint import Cryptol.ModuleSystem.Interface@@ -95,7 +96,7 @@ -- ^ Problems during the NoPat phase | NoIncludeErrors ImportSource [NoInc.IncludeError] -- ^ Problems during the NoInclude phase- | TypeCheckingFailed ImportSource [(Range,T.Error)]+ | TypeCheckingFailed ImportSource T.NameMap [(Range,T.Error)] -- ^ Problems during type checking | OtherFailure String -- ^ Problems after type checking, eg. specialization@@ -127,7 +128,7 @@ RenamerErrors src errs -> src `deepseq` errs `deepseq` () NoPatErrors src errs -> src `deepseq` errs `deepseq` () NoIncludeErrors src errs -> src `deepseq` errs `deepseq` ()- TypeCheckingFailed src errs -> src `deepseq` errs `deepseq` ()+ TypeCheckingFailed nm src errs -> nm `deepseq` src `deepseq` errs `deepseq` () ModuleNameMismatch expected found -> expected `deepseq` found `deepseq` () DuplicateModuleName name path1 path2 ->@@ -175,7 +176,7 @@ NoIncludeErrors _src errs -> vcat (map NoInc.ppIncludeError errs) - TypeCheckingFailed _src errs -> vcat (map T.ppError errs)+ TypeCheckingFailed _src nm errs -> vcat (map (T.ppNamedError nm) errs) ModuleNameMismatch expected found -> hang (text "[error]" <+> pp (P.srcRange found) <.> char ':')@@ -238,10 +239,10 @@ src <- getImportSource ModuleT (raise (NoIncludeErrors src errs)) -typeCheckingFailed :: [(Range,T.Error)] -> ModuleM a-typeCheckingFailed errs = do+typeCheckingFailed :: T.NameMap -> [(Range,T.Error)] -> ModuleM a+typeCheckingFailed nameMap errs = do src <- getImportSource- ModuleT (raise (TypeCheckingFailed src errs))+ ModuleT (raise (TypeCheckingFailed src nameMap errs)) moduleNameMismatch :: P.ModName -> Located P.ModName -> ModuleM a moduleNameMismatch expected found =@@ -272,22 +273,22 @@ -- Warnings -------------------------------------------------------------------- data ModuleWarning- = TypeCheckWarnings [(Range,T.Warning)]+ = TypeCheckWarnings T.NameMap [(Range,T.Warning)] | RenamerWarnings [RenamerWarning] deriving (Show, Generic, NFData) instance PP ModuleWarning where ppPrec _ w = case w of- TypeCheckWarnings ws -> vcat (map T.ppWarning ws)+ TypeCheckWarnings nm ws -> vcat (map (T.ppNamedWarning nm) ws) RenamerWarnings ws -> vcat (map pp ws) warn :: [ModuleWarning] -> ModuleM () warn = ModuleT . put -typeCheckWarnings :: [(Range,T.Warning)] -> ModuleM ()-typeCheckWarnings ws+typeCheckWarnings :: T.NameMap -> [(Range,T.Warning)] -> ModuleM ()+typeCheckWarnings nameMap ws | null ws = return ()- | otherwise = warn [TypeCheckWarnings ws]+ | otherwise = warn [TypeCheckWarnings nameMap ws] renamerWarnings :: [RenamerWarning] -> ModuleM () renamerWarnings ws@@ -488,8 +489,7 @@ modifyEvalEnv f = ModuleT $ do env <- get let evalEnv = meEvalEnv env- evOpts <- unModuleT getEvalOpts- evalEnv' <- inBase $ E.runEval evOpts (f evalEnv)+ evalEnv' <- inBase $ E.runEval (f evalEnv) set $! env { meEvalEnv = evalEnv' } getEvalEnv :: ModuleM EvalEnv
src/Cryptol/ModuleSystem/Name.hs view
@@ -172,7 +172,7 @@ -- | Figure out how the name should be displayed, by referencing the display -- function in the environment. NOTE: this function doesn't take into account--- the need for parenthesis.+-- the need for parentheses. ppName :: Name -> Doc ppName Name { .. } = case nInfo of
src/Cryptol/Parser.y view
@@ -59,6 +59,8 @@ IDENT { $$@(Located _ (Token (Ident [] _) _))} QIDENT { $$@(Located _ (Token Ident{} _))} + SELECTOR { $$@(Located _ (Token (Selector _) _))}+ 'include' { Located $$ (Token (KW KW_include) _)} 'import' { Located $$ (Token (KW KW_import) _)} 'as' { Located $$ (Token (KW KW_as) _)}@@ -95,7 +97,7 @@ ')' { Located $$ (Token (Sym ParenR ) _)} ',' { Located $$ (Token (Sym Comma ) _)} ';' { Located $$ (Token (Sym Semi ) _)}- '.' { Located $$ (Token (Sym Dot ) _)}+ -- '.' { Located $$ (Token (Sym Dot ) _)} '{' { Located $$ (Token (Sym CurlyL ) _)} '}' { Located $$ (Token (Sym CurlyR ) _)} '<|' { Located $$ (Token (Sym TriL ) _)}@@ -271,10 +273,10 @@ (mkProp $4) } -doc :: { Located String }+doc :: { Located Text } : DOC { mkDoc (fmap tokenText $1) } -mbDoc :: { Maybe (Located String) }+mbDoc :: { Maybe (Located Text) } : doc { Just $1 } | {- empty -} { Nothing } @@ -355,6 +357,10 @@ : apats indices { ($1, $2) } | '@' indices1 { ([], $2) } +opt_apats_indices :: { ([Pattern PName], [Pattern PName]) }+ : {- empty -} { ([],[]) }+ | apats_indices { $1 }+ decls :: { [Decl PName] } : decl ';' { [$1] } | decls decl ';' { $2 : $1 }@@ -371,6 +377,7 @@ repl :: { ReplInput PName } : expr { ExprInput $1 } | let_decl { LetInput $1 }+ | {- empty -} { EmptyInput } --------------------------------------------------------------------------------@@ -483,8 +490,8 @@ no_sel_aexpr :: { Expr PName } : qname { at $1 $ EVar (thing $1) } - | NUM { at $1 $ numLit (tokenType (thing $1)) }- | FRAC { at $1 $ fracLit (tokenType (thing $1)) }+ | NUM { at $1 $ numLit (thing $1) }+ | FRAC { at $1 $ fracLit (thing $1) } | STRLIT { at $1 $ ELit $ ECString $ getStr $1 } | CHARLIT { at $1 $ ELit $ ECChar $ getChr $1 } | '_' { at $1 $ EVar $ mkUnqual $ mkIdent "_" }@@ -506,9 +513,11 @@ | '<|' poly_terms '|>' {% mkPoly (rComb $1 $3) $2 } sel_expr :: { Expr PName }- : no_sel_aexpr '.' selector { at ($1,$3) $ ESel $1 (thing $3) }- | sel_expr '.' selector { at ($1,$3) $ ESel $1 (thing $3) }+ : no_sel_aexpr selector { at ($1,$2) $ ESel $1 (thing $2) }+ | sel_expr selector { at ($1,$2) $ ESel $1 (thing $2) } +selector :: { Located Selector }+ : SELECTOR { mkSelector `fmap` $1 } poly_terms :: { [(Bool, Integer)] } : poly_term { [$1] }@@ -519,11 +528,6 @@ | 'x' {% polyTerm $1 1 1 } | 'x' '^^' NUM {% polyTerm (rComb $1 (srcRange $3)) 1 (getNum $3) }--selector :: { Located Selector }- : ident { fmap (`RecordSel` Nothing) $1 }- | NUM {% mkTupleSel (srcRange $1) (getNum $1) }- tuple_exprs :: { [Expr PName] } : expr ',' expr { [ $3, $1] } | tuple_exprs ',' expr { $3 : $1 }@@ -534,24 +538,21 @@ | '_' '|' field_exprs { Left (EUpd Nothing (reverse $3)) } | field_exprs {% Right `fmap` mapM ufToNamed $1 } -field_expr :: { UpdField PName }- : selector field_how expr { UpdField $2 [$1] $3 }- | sels field_how expr { UpdField $2 $1 $3 }- | sels apats_indices field_how expr- { UpdField $3 $1 (mkIndexedExpr $2 $4) }- | selector apats_indices field_how expr- { UpdField $3 [$1] (mkIndexedExpr $2 $4) }--field_how :: { UpdHow }- : '=' { UpdSet }- | '->' { UpdFun }--sels :: { [ Located Selector ] }- : sel_expr {% selExprToSels $1 }- field_exprs :: { [UpdField PName] } : field_expr { [$1] } | field_exprs ',' field_expr { $3 : $1 }++field_expr :: { UpdField PName }+ : field_path opt_apats_indices+ field_how expr { UpdField $3 $1 (mkIndexedExpr $2 $4) }++field_path :: { [Located Selector] }+ : aexpr {% exprToFieldPath $1 }++field_how :: { UpdHow }+ : '=' { UpdSet }+ | '->' { UpdFun }+ list_expr :: { Expr PName } : expr '|' list_alts { EComp $1 (reverse $3) }
src/Cryptol/Parser/AST.hs view
@@ -90,6 +90,7 @@ import Data.Bits(shiftR) import Data.Maybe (catMaybes) import Data.Ratio(numerator,denominator)+import Data.Text (Text) import Numeric(showIntAtBase,showFloat,showHFloat) import GHC.Generics (Generic)@@ -160,7 +161,7 @@ data ParameterType name = ParameterType { ptName :: Located name -- ^ name of type parameter , ptKind :: Kind -- ^ kind of parameter- , ptDoc :: Maybe String -- ^ optional documentation+ , ptDoc :: Maybe Text -- ^ optional documentation , ptFixity :: Maybe Fixity -- ^ info for infix use , ptNumber :: !Int -- ^ number of the parameter } deriving (Eq,Show,Generic,NFData)@@ -169,7 +170,7 @@ data ParameterFun name = ParameterFun { pfName :: Located name -- ^ name of value parameter , pfSchema :: Schema name -- ^ schema for parameter- , pfDoc :: Maybe String -- ^ optional documentation+ , pfDoc :: Maybe Text -- ^ optional documentation , pfFixity :: Maybe Fixity -- ^ info for infix use } deriving (Eq,Show,Generic,NFData) @@ -230,7 +231,7 @@ , bFixity :: Maybe Fixity -- ^ Optional fixity info , bPragmas :: [Pragma] -- ^ Optional pragmas , bMono :: Bool -- ^ Is this a monomorphic binding- , bDoc :: Maybe String -- ^ Optional doc string+ , bDoc :: Maybe Text -- ^ Optional doc string } deriving (Eq, Generic, NFData, Functor, Show) type LBindDef = Located (BindDef PName)@@ -257,10 +258,11 @@ , primTFixity :: Maybe Fixity } deriving (Show,Generic,NFData) --- | Input at the REPL, which can either be an expression or a @let@--- statement.+-- | Input at the REPL, which can be an expression, a @let@+-- statement, or empty (possibly a comment). data ReplInput name = ExprInput (Expr name) | LetInput (Decl name)+ | EmptyInput deriving (Eq, Show) -- | Export information for a declaration.@@ -270,25 +272,25 @@ -- | A top-level module declaration. data TopLevel a = TopLevel { tlExport :: ExportType- , tlDoc :: Maybe (Located String)+ , tlDoc :: Maybe (Located Text) , tlValue :: a } deriving (Show, Generic, NFData, Functor, Foldable, Traversable) -- | Infromation about the representation of a numeric constant.-data NumInfo = BinLit Int -- ^ n-digit binary literal- | OctLit Int -- ^ n-digit octal literal- | DecLit -- ^ overloaded decimal literal- | HexLit Int -- ^ n-digit hex literal+data NumInfo = BinLit Text Int -- ^ n-digit binary literal+ | OctLit Text Int -- ^ n-digit octal literal+ | DecLit Text -- ^ overloaded decimal literal+ | HexLit Text Int -- ^ n-digit hex literal | PolyLit Int -- ^ polynomial literal deriving (Eq, Show, Generic, NFData) -- | Information about fractional literals.-data FracInfo = BinFrac- | OctFrac- | DecFrac- | HexFrac+data FracInfo = BinFrac Text+ | OctFrac Text+ | DecFrac Text+ | HexFrac Text deriving (Eq,Show,Generic,NFData) -- | Literals.@@ -646,10 +648,10 @@ ppFracLit x i | toRational dbl == x = case i of- BinFrac -> frac- OctFrac -> frac- DecFrac -> text (showFloat dbl "")- HexFrac -> text (showHFloat dbl "")+ BinFrac _ -> frac+ OctFrac _ -> frac+ DecFrac _ -> text (showFloat dbl "")+ HexFrac _ -> text (showHFloat dbl "") | otherwise = frac where dbl = fromRational x :: Double@@ -660,11 +662,11 @@ ppNumLit :: Integer -> NumInfo -> Doc ppNumLit n info = case info of- DecLit -> integer n- BinLit w -> pad 2 "0b" w- OctLit w -> pad 8 "0o" w- HexLit w -> pad 16 "0x" w- PolyLit w -> text "<|" <+> poly w <+> text "|>"+ DecLit _ -> integer n+ BinLit _ w -> pad 2 "0b" w+ OctLit _ w -> pad 8 "0o" w+ HexLit _ w -> pad 16 "0x" w+ PolyLit w -> text "<|" <+> poly w <+> text "|>" where pad base pref w = let txt = showIntAtBase base ("0123456789abcdef" !!) n ""
src/Cryptol/Parser/Lexer.x view
@@ -45,18 +45,11 @@ @qual_id = @qual @id @qual_op = @qual @op -@digits2 = (_*[0-1])+-@digits8 = (_*[0-7])+-@digits16 = (_*[0-9A-Fa-f])+-@num2 = "0b" @digits2-@num8 = "0o" @digits8-@num10 = [0-9](_*[0-9])*-@num16 = "0x" @digits16-@fnum2 = @num2 "." @digits2 ([pP] [\+\-]? @num10)?-@fnum8 = @num8 "." @digits8 ([pP] [\+\-]? @num10)?-@fnum10 = @num10 "." @num10 ([eE] [\+\-]? @num10)?-@fnum16 = @num16 "." @digits16 ([pP] [\+\-]? @num10)?+@num = [0-9] @id_next*+@fnum = [0-9] @id_next* "." (@id_next | [pPeE][\+\-])+ +@selector = "." @id_next++ @strPart = [^\\\"]+ @chrPart = [^\\\']+ @@ -130,19 +123,12 @@ "Prop" { emit $ KW KW_Prop } -@num2 { emitS (numToken 2 . Text.drop 2) }-@num8 { emitS (numToken 8 . Text.drop 2) }-@num10 { emitS (numToken 10 . Text.drop 0) }-@num16 { emitS (numToken 16 . Text.drop 2) }-@fnum2 { emitS (fnumToken 2 . Text.drop 2) }-@fnum8 { emitS (fnumToken 8 . Text.drop 2) }-@fnum10 { emitS (fnumToken 10 . Text.drop 0) }-@fnum16 { emitS (fnumToken 16 . Text.drop 2) }--+@num { emitS numToken }+@fnum { emitFancy fnumTokens } "_" { emit $ Sym Underscore } @id { mkIdent }+@selector { emitS selectorToken } "\" { emit $ Sym Lambda } "->" { emit $ Sym ArrR }@@ -152,7 +138,6 @@ "=" { emit $ Sym EqDef } "," { emit $ Sym Comma } ";" { emit $ Sym Semi }-"." { emit $ Sym Dot } ":" { emit $ Sym Colon } "`" { emit $ Sym BackTick } ".." { emit $ Sym DotDot }@@ -261,9 +246,7 @@ let txt = Text.take l (input i) (mtok,s') = act cfg (alexPos i) txt s (rest,pos) = run i' $! s'- in case mtok of- Nothing -> (rest, pos)- Just t -> (t : rest, pos)+ in (mtok ++ rest, pos) -- vim: ft=haskell }
src/Cryptol/Parser/LexerUtils.hs view
@@ -10,6 +10,7 @@ {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternGuards #-}+{-# LANGUAGE BlockArguments #-} module Cryptol.Parser.LexerUtils where import Cryptol.Parser.Position@@ -17,10 +18,13 @@ import Cryptol.Utils.PP import Cryptol.Utils.Panic -import Data.Char(toLower,generalCategory,isAscii,ord,isSpace)+import Control.Monad(guard)+import Data.Char(toLower,generalCategory,isAscii,ord,isSpace,+ isAlphaNum,isAlpha) import qualified Data.Char as Char import Data.Text(Text) import qualified Data.Text as T+import qualified Data.Text.Read as T import Data.Word(Word8) import GHC.Generics (Generic)@@ -47,7 +51,7 @@ type Action = Config -> Position -> Text -> LexS- -> (Maybe (Located Token), LexS)+ -> ([Located Token], LexS) data LexS = Normal | InComment Bool Position ![Position] [Text]@@ -56,7 +60,7 @@ startComment :: Bool -> Action-startComment isDoc _ p txt s = (Nothing, InComment d p stack chunks)+startComment isDoc _ p txt s = ([], InComment d p stack chunks) where (d,stack,chunks) = case s of Normal -> (isDoc, [], [txt]) InComment doc q qs cs -> (doc, q : qs, txt : cs)@@ -65,8 +69,8 @@ endComment :: Action endComment cfg p txt s = case s of- InComment d f [] cs -> (Just (mkToken d f cs), Normal)- InComment d _ (q:qs) cs -> (Nothing, InComment d q qs (txt : cs))+ InComment d f [] cs -> ([mkToken d f cs], Normal)+ InComment d _ (q:qs) cs -> ([], InComment d q qs (txt : cs)) _ -> panic "[Lexer] endComment" ["outside comment"] where mkToken isDoc f cs =@@ -77,7 +81,7 @@ in Located { srcRange = r, thing = Token (White tok) str } addToComment :: Action-addToComment _ _ txt s = (Nothing, InComment doc p stack (txt : chunks))+addToComment _ _ txt s = ([], InComment doc p stack (txt : chunks)) where (doc, p, stack, chunks) = case s of@@ -87,7 +91,7 @@ startEndComment :: Action startEndComment cfg p txt s = case s of- Normal -> (Just tok, Normal)+ Normal -> ([tok], Normal) where tok = Located { srcRange = Range { from = p , to = moves p txt@@ -95,15 +99,15 @@ } , thing = Token (White BlockComment) txt }- InComment d p1 ps cs -> (Nothing, InComment d p1 ps (txt : cs))+ InComment d p1 ps cs -> ([], InComment d p1 ps (txt : cs)) _ -> panic "[Lexer] startEndComment" ["in string or char?"] startString :: Action-startString _ p txt _ = (Nothing,InString p txt)+startString _ p txt _ = ([],InString p txt) endString :: Action endString cfg pe txt s = case s of- InString ps str -> (Just (mkToken ps str), Normal)+ InString ps str -> ([mkToken ps str], Normal) _ -> panic "[Lexer] endString" ["outside string"] where parseStr s1 = case reads s1 of@@ -126,17 +130,17 @@ addToString :: Action addToString _ _ txt s = case s of- InString p str -> (Nothing,InString p (str `T.append` txt))+ InString p str -> ([],InString p (str `T.append` txt)) _ -> panic "[Lexer] addToString" ["outside string"] startChar :: Action-startChar _ p txt _ = (Nothing,InChar p txt)+startChar _ p txt _ = ([],InChar p txt) endChar :: Action endChar cfg pe txt s = case s of- InChar ps str -> (Just (mkToken ps str), Normal)+ InChar ps str -> ([mkToken ps str], Normal) _ -> panic "[Lexer] endString" ["outside character"] where@@ -161,39 +165,41 @@ addToChar :: Action addToChar _ _ txt s = case s of- InChar p str -> (Nothing,InChar p (str `T.append` txt))+ InChar p str -> ([],InChar p (str `T.append` txt)) _ -> panic "[Lexer] addToChar" ["outside character"] mkIdent :: Action-mkIdent cfg p s z = (Just Located { srcRange = r, thing = Token t s }, z)+mkIdent cfg p s z = ([Located { srcRange = r, thing = Token t s }], z) where r = Range { from = p, to = moves p s, source = cfgSource cfg } t = Ident [] s mkQualIdent :: Action-mkQualIdent cfg p s z = (Just Located { srcRange = r, thing = Token t s}, z)+mkQualIdent cfg p s z = ([Located { srcRange = r, thing = Token t s}], z) where r = Range { from = p, to = moves p s, source = cfgSource cfg } t = Ident ns i (ns,i) = splitQual s mkQualOp :: Action-mkQualOp cfg p s z = (Just Located { srcRange = r, thing = Token t s}, z)+mkQualOp cfg p s z = ([Located { srcRange = r, thing = Token t s}], z) where r = Range { from = p, to = moves p s, source = cfgSource cfg } t = Op (Other ns i) (ns,i) = splitQual s emit :: TokenT -> Action-emit t cfg p s z = (Just Located { srcRange = r, thing = Token t s }, z)+emit t cfg p s z = ([Located { srcRange = r, thing = Token t s }], z) where r = Range { from = p, to = moves p s, source = cfgSource cfg } - emitS :: (Text -> TokenT) -> Action emitS t cfg p s z = emit (t s) cfg p s z +emitFancy :: (FilePath -> Position -> Text -> [Located Token]) -> Action+emitFancy f = \cfg p s z -> (f (cfgSource cfg) p s, z) + -- | Split out the prefix and name part of an identifier/operator. splitQual :: T.Text -> ([T.Text], T.Text) splitQual t =@@ -213,52 +219,121 @@ ---------------------------------------------------------------------------------numToken :: Int {- ^ base -} -> Text -> TokenT-numToken rad ds = Num (toVal ds') rad (T.length ds')+numToken :: Text -> TokenT+numToken ds = case toVal of+ Just v -> Num v rad (T.length ds')+ Nothing -> Err MalformedLiteral where- ds' = T.filter (/= '_') ds- toVal = T.foldl' (\x c -> toInteger rad * x + fromDigit c) 0+ rad+ | "0b" `T.isPrefixOf` ds = 2+ | "0o" `T.isPrefixOf` ds = 8+ | "0x" `T.isPrefixOf` ds = 16+ | otherwise = 10 -fromDigit :: Char -> Integer-fromDigit x'- | 'a' <= x && x <= 'z' = toInteger (10 + fromEnum x - fromEnum 'a')- | otherwise = toInteger (fromEnum x - fromEnum '0')- where x = toLower x'+ ds1 = if rad == 10 then ds else T.drop 2 ds + ds' = T.filter (/= '_') ds1+ toVal = T.foldl' step (Just 0) ds'+ irad = toInteger rad+ step mb x = do soFar <- mb+ d <- fromDigit irad x+ pure $! (irad * soFar + d) --- XXX: For now we just keep the number as a rational.--- It might be better to keep the exponent representation,--- to avoid making huge numbers, and using up all the memory though...-fnumToken :: Int -> Text -> TokenT-fnumToken rad ds = Frac ((wholenNum + fracNum) * (eBase ^^ expNum)) rad+fromDigit :: Integer -> Char -> Maybe Integer+fromDigit r x' =+ do d <- v+ guard (d < r)+ pure d where+ x = toLower x'+ v | '0' <= x && x <= '9' = Just $ toInteger $ fromEnum x - fromEnum '0'+ | 'a' <= x && x <= 'z' = Just $ toInteger $ 10 + fromEnum x - fromEnum 'a'+ | otherwise = Nothing+++-- | Interpret something either as a fractional token,+-- a number followed by a selector, or an error.+fnumTokens :: FilePath -> Position -> Text -> [Located Token]+fnumTokens file pos ds =+ case wholeNum of+ Nothing -> [ tokFrom pos ds (Err MalformedLiteral) ]+ Just i+ | Just f <- fracNum, Just e <- expNum ->+ [ tokFrom pos ds (Frac ((fromInteger i + f) * (eBase ^^ e)) rad) ]+ | otherwise ->+ [ tokFrom pos whole (Num i rad (T.length whole))+ , tokFrom afterWhole rest (selectorToken rest)+ ]++ where+ tokFrom tpos txt t =+ Located { srcRange =+ Range { from = tpos, to = moves tpos txt, source = file }+ , thing = Token { tokenText = txt, tokenType = t }+ }++ afterWhole = moves pos whole++ rad+ | "0b" `T.isPrefixOf` ds = 2+ | "0o" `T.isPrefixOf` ds = 8+ | "0x" `T.isPrefixOf` ds = 16+ | otherwise = 10+ radI = fromIntegral rad :: Integer radR = fromIntegral rad :: Rational - (whole,rest) = T.break (== '.') ds+ (whole,rest) = T.break (== '.') (if rad == 10 then ds else T.drop 2 ds) digits = T.filter (/= '_') expSym e = if rad == 10 then toLower e == 'e' else toLower e == 'p' (frac,mbExp) = T.break expSym (T.drop 1 rest) + wholeStep mb c = do soFar <- mb+ d <- fromDigit radI c+ pure $! (radI * soFar + d) - wholenNum = fromInteger- $ T.foldl' (\x c -> radI * x + fromDigit c) 0- $ digits whole+ wholeNum = T.foldl' wholeStep (Just 0) (digits whole) - fracNum = T.foldl' (\x c -> (x + fromInteger (fromDigit c)) / radR) 0- $ T.reverse $ digits frac+ fracStep mb c = do soFar <- mb+ d <- fromInteger <$> fromDigit radI c+ pure $! ((soFar + d) / radR) + fracNum = do let fds = T.reverse (digits frac)+ guard (T.length fds > 0)+ T.foldl' fracStep (Just 0) fds+ expNum = case T.uncons mbExp of- Nothing -> 0 :: Integer+ Nothing -> Just (0 :: Integer) Just (_,es) -> case T.uncons es of- Just ('+', more) -> read $ T.unpack more- _ -> read $ T.unpack es+ Just ('+', more) -> readDecimal more+ Just ('-', more) -> negate <$> readDecimal more+ _ -> readDecimal es eBase = if rad == 10 then 10 else 2 :: Rational +-- assumes we start with a dot+selectorToken :: Text -> TokenT+selectorToken txt+ | Just n <- readDecimal body, n >= 0 = Selector (TupleSelectorTok n)+ | Just (x,xs) <- T.uncons body+ , id_first x+ , T.all id_next xs = Selector (RecordSelectorTok body)+ | otherwise = Err MalformedSelector + where+ body = T.drop 1 txt+ id_first x = isAlpha x || x == '_'+ id_next x = isAlphaNum x || x == '_' || x == '\''+++readDecimal :: Integral a => Text -> Maybe a+readDecimal txt = case T.decimal txt of+ Right (a,more) | T.null more -> Just a+ _ -> Nothing++ ------------------------------------------------------------------------------- data AlexInput = Inp { alexPos :: !Position@@ -462,13 +537,19 @@ | InvalidString | InvalidChar | LexicalError+ | MalformedLiteral+ | MalformedSelector deriving (Eq, Show, Generic, NFData) +data SelectorType = RecordSelectorTok Text | TupleSelectorTok Int+ deriving (Eq, Show, Generic, NFData)+ data TokenT = Num !Integer !Int !Int -- ^ value, base, number of digits | Frac !Rational !Int -- ^ value, base. | ChrLit !Char -- ^ character literal | Ident ![T.Text] !T.Text -- ^ (qualified) identifier | StrLit !String -- ^ string literal+ | Selector !SelectorType -- ^ .hello or .123 | KW !TokenKW -- ^ keyword | Op !TokenOp -- ^ operator | Sym !TokenSym -- ^ symbol
src/Cryptol/Parser/NoPat.hs view
@@ -29,6 +29,7 @@ import MonadLib hiding (mapM) import Data.Maybe(maybeToList) import qualified Data.Map as Map+import Data.Text (Text) import GHC.Generics (Generic) import Control.DeepSeq@@ -323,7 +324,7 @@ , annSigs :: Map.Map PName [Located (Schema PName)] , annValueFs :: Map.Map PName [Located Fixity ] , annTypeFs :: Map.Map PName [Located Fixity ]- , annDocs :: Map.Map PName [Located String ]+ , annDocs :: Map.Map PName [Located Text ] } type Annotates a = a -> StateT AnnotMap NoPatM a@@ -477,7 +478,7 @@ return (Just (thing x)) -checkDocs :: PName -> [Located String] -> NoPatM (Maybe String)+checkDocs :: PName -> [Located Text] -> NoPatM (Maybe Text) checkDocs _ [] = return Nothing checkDocs _ [d] = return (Just (thing d)) checkDocs f ds@(d:_) = do recordError $ MultipleDocs f (map srcRange ds)@@ -502,7 +503,7 @@ toFixity _ = [] -- | Does this top-level declaration provide a documentation string?-toDocs :: TopLevel (Decl PName) -> [(PName, [Located String])]+toDocs :: TopLevel (Decl PName) -> [(PName, [Located Text])] toDocs TopLevel { .. } | Just txt <- tlDoc = go txt tlValue | otherwise = []
src/Cryptol/Parser/ParserUtils.hs view
@@ -22,6 +22,7 @@ import Data.Text(Text) import qualified Data.Text as T import qualified Data.Map as Map+import Text.Read(readMaybe) import GHC.Generics (Generic) import Control.DeepSeq@@ -32,6 +33,7 @@ import Cryptol.Parser.AST import Cryptol.Parser.Lexer+import Cryptol.Parser.LexerUtils(SelectorType(..)) import Cryptol.Parser.Position import Cryptol.Parser.Utils (translateExprToNumT,widthIdent) import Cryptol.Utils.Ident(packModName)@@ -67,12 +69,16 @@ UnterminatedComment -> "unterminated comment" UnterminatedString -> "unterminated string" UnterminatedChar -> "unterminated character"- InvalidString -> "invalid string literal:" +++ InvalidString -> "invalid string literal: " ++ T.unpack (tokenText it)- InvalidChar -> "invalid character literal:" +++ InvalidChar -> "invalid character literal: " ++ T.unpack (tokenText it)- LexicalError -> "unrecognized character:" +++ LexicalError -> "unrecognized character: " ++ T.unpack (tokenText it)+ MalformedLiteral -> "malformed literal: " +++ T.unpack (tokenText it)+ MalformedSelector -> "malformed selector: " +++ T.unpack (tokenText it) where it = thing t t : more -> unP (k t) cfg p s { sPrevTok = Just t, sTokens = more }@@ -201,23 +207,23 @@ Token (StrLit x) _ -> x _ -> panic "[Parser] getStr" ["not a string:", show l] -numLit :: TokenT -> Expr PName-numLit (Num x base digs)- | base == 2 = ELit $ ECNum x (BinLit digs)- | base == 8 = ELit $ ECNum x (OctLit digs)- | base == 10 = ELit $ ECNum x DecLit- | base == 16 = ELit $ ECNum x (HexLit digs)+numLit :: Token -> Expr PName+numLit Token { tokenText = txt, tokenType = Num x base digs }+ | base == 2 = ELit $ ECNum x (BinLit txt digs)+ | base == 8 = ELit $ ECNum x (OctLit txt digs)+ | base == 10 = ELit $ ECNum x (DecLit txt)+ | base == 16 = ELit $ ECNum x (HexLit txt digs) numLit x = panic "[Parser] numLit" ["invalid numeric literal", show x] -fracLit :: TokenT -> Expr PName+fracLit :: Token -> Expr PName fracLit tok =- case tok of+ case tokenType tok of Frac x base- | base == 2 -> ELit $ ECFrac x BinFrac- | base == 8 -> ELit $ ECFrac x OctFrac- | base == 10 -> ELit $ ECFrac x DecFrac- | base == 16 -> ELit $ ECFrac x HexFrac+ | base == 2 -> ELit $ ECFrac x $ BinFrac $ tokenText tok+ | base == 8 -> ELit $ ECFrac x $ OctFrac $ tokenText tok+ | base == 10 -> ELit $ ECFrac x $ DecFrac $ tokenText tok+ | base == 16 -> ELit $ ECFrac x $ HexFrac $ tokenText tok _ -> panic "[Parser] fracLit" [ "Invalid fraction", show tok ] @@ -234,14 +240,6 @@ (errorMessage (srcRange tok) "Fixity levels must be between 1 and 100") return (DFixity (Fixity assoc (fromInteger l)) qns) -mkTupleSel :: Range -> Integer -> ParseM (Located Selector)-mkTupleSel pos n- | n < 0 = errorMessage pos- (show n ++ " is not a valid tuple selector (they start from 0).")- | toInteger asInt /= n = errorMessage pos "Tuple selector is too large."- | otherwise = return $ Located pos $ TupleSel asInt Nothing- where asInt = fromInteger n- fromStrLit :: Located Token -> ParseM (Located String) fromStrLit loc = case tokenType (thing loc) of StrLit str -> return loc { thing = str }@@ -360,18 +358,18 @@ where noName = Located { srcRange = r, thing = mkIdent (T.pack "") } toField t = Named { name = noName, value = t } -exportDecl :: Maybe (Located String) -> ExportType -> Decl PName -> TopDecl PName+exportDecl :: Maybe (Located Text) -> ExportType -> Decl PName -> TopDecl PName exportDecl mbDoc e d = Decl TopLevel { tlExport = e , tlDoc = mbDoc , tlValue = d } -exportNewtype :: ExportType -> Maybe (Located String) -> Newtype PName ->+exportNewtype :: ExportType -> Maybe (Located Text) -> Newtype PName -> TopDecl PName exportNewtype e d n = TDNewtype TopLevel { tlExport = e , tlDoc = d , tlValue = n } -mkParFun :: Maybe (Located String) ->+mkParFun :: Maybe (Located Text) -> Located PName -> Schema PName -> TopDecl PName@@ -381,7 +379,7 @@ , pfFixity = Nothing } -mkParType :: Maybe (Located String) ->+mkParType :: Maybe (Located Text) -> Located PName -> Located Kind -> ParseM (TopDecl PName)@@ -515,7 +513,7 @@ -- instead of just place it on the binding directly. A better solution might be -- to just have a different constructor for primitives. mkPrimDecl ::- Maybe (Located String) -> LPName -> Schema PName -> [TopDecl PName]+ Maybe (Located Text) -> LPName -> Schema PName -> [TopDecl PName] mkPrimDecl mbDoc ln sig = [ exportDecl mbDoc Public $ DBind Bind { bName = ln@@ -533,7 +531,7 @@ ] mkPrimTypeDecl ::- Maybe (Located String) ->+ Maybe (Located Text) -> Schema PName -> Located Kind -> ParseM [TopDecl PName]@@ -601,12 +599,11 @@ -- | Fix-up the documentation strings by removing the comment delimiters on each -- end, and stripping out common prefixes on all the remaining lines.-mkDoc :: Located Text -> Located String+mkDoc :: Located Text -> Located Text mkDoc ltxt = ltxt { thing = docStr } where - docStr = unlines- $ map T.unpack+ docStr = T.unlines $ dropPrefix $ trimFront $ T.lines@@ -713,8 +710,8 @@ _ -> errorMessage (srcRange (head ls)) "Invalid record field. Perhaps you meant to update a record?" -selExprToSels :: Expr PName -> ParseM [Located Selector]-selExprToSels e0 = reverse <$> go noLoc e0+exprToFieldPath :: Expr PName -> ParseM [Located Selector]+exprToFieldPath e0 = reverse <$> go noLoc e0 where noLoc = panic "selExprToSels" ["Missing location?"] go loc expr =@@ -726,10 +723,35 @@ pure (Located { thing = s, srcRange = rng } : ls) EVar (UnQual l) -> pure [ Located { thing = RecordSel l Nothing, srcRange = loc } ]- ELit (ECNum n _) ->- do ts <- mkTupleSel loc n- pure [ ts ]++ ELit (ECNum n (DecLit {})) ->+ pure [ Located { thing = TupleSel (fromInteger n) Nothing+ , srcRange = loc } ]++ ELit (ECFrac _ (DecFrac txt))+ | (as,bs') <- T.break (== '.') txt+ , Just a <- readMaybe (T.unpack as)+ , Just (_,bs) <- T.uncons bs'+ , Just b <- readMaybe (T.unpack bs)+ , let fromP = from loc+ , let midP = fromP { col = col fromP + T.length as + 1 } ->+ -- these are backward because we reverse above+ pure [ Located { thing = TupleSel b Nothing+ , srcRange = loc { from = midP }+ }+ , Located { thing = TupleSel a Nothing+ , srcRange = loc { to = midP }+ }+ ]+ _ -> errorMessage loc "Invalid label in record update." +mkSelector :: Token -> Selector+mkSelector tok =+ case tokenType tok of+ Selector (TupleSelectorTok n) -> TupleSel n Nothing+ Selector (RecordSelectorTok t) -> RecordSel (mkIdent t) Nothing+ _ -> panic "mkSelector"+ [ "Unexpected selector token", show tok ]
src/Cryptol/Prelude.hs view
@@ -15,8 +15,11 @@ module Cryptol.Prelude ( preludeContents+ , preludeReferenceContents , floatContents , arrayContents+ , suiteBContents+ , primeECContents , cryptolTcContents ) where @@ -28,11 +31,20 @@ preludeContents :: ByteString preludeContents = B.pack [there|lib/Cryptol.cry|] +preludeReferenceContents :: ByteString+preludeReferenceContents = B.pack [there|lib/Cryptol/Reference.cry|]+ floatContents :: ByteString floatContents = B.pack [there|lib/Float.cry|] arrayContents :: ByteString arrayContents = B.pack [there|lib/Array.cry|]++suiteBContents :: ByteString+suiteBContents = B.pack [there|lib/SuiteB.cry|]++primeECContents :: ByteString+primeECContents = B.pack [there|lib/PrimeEC.cry|] cryptolTcContents :: String cryptolTcContents = [there|lib/CryptolTC.z3|]
+ src/Cryptol/PrimeEC.hs view
@@ -0,0 +1,574 @@+-----------------------------------------------------------------------------+-- |+-- Module : Cryptol.PrimeEC+-- Copyright : (c) Galois, Inc.+-- License : BSD3+-- Maintainer: rdockins@galois.com+-- Stability : experimental+--+-- This module provides fast primitives for elliptic curve cryptography+-- defined on @Z p@ for prime @p > 3@. These are exposed in cryptol+-- by importing the built-in module "PrimeEC". The primary primitives+-- exposed here are the doubling and addition primitives in the ECC group+-- as well as scalar multiplication and the "twin" multiplication primitive,+-- which simultaneously computes the addition of two scalar multiplies.+--+-- This module makes heavy use of some GHC internals regarding the+-- representation of the Integer type, and the underlying GMP primitives+-- in order to speed up the basic modular arithmetic operations.+-----------------------------------------------------------------------------+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ViewPatterns #-}++module Cryptol.PrimeEC+ ( PrimeModulus+ , primeModulus+ , ProjectivePoint(..)+ , integerToBigNat+ , Integer.bigNatToInteger++ , ec_double+ , ec_add_nonzero+ , ec_mult+ , ec_twin_mult+ ) where+++import GHC.Integer.GMP.Internals (BigNat)+import qualified GHC.Integer.GMP.Internals as Integer+import GHC.Prim+import Data.Bits++import Cryptol.TypeCheck.Solver.InfNat (widthInteger)+import Cryptol.Utils.Panic++-- | Points in the projective plane represented in+-- homogenous coordinates.+data ProjectivePoint =+ ProjectivePoint+ { px :: !BigNat+ , py :: !BigNat+ , pz :: !BigNat+ }++-- | The projective "point at infinity", which represents the zero element+-- of the ECC group.+zro :: ProjectivePoint+zro = ProjectivePoint Integer.oneBigNat Integer.oneBigNat Integer.zeroBigNat++-- | Coerce an integer value to a @BigNat@. This operation only really makes+-- sense for nonnegative values, but this condition is not checked.+integerToBigNat :: Integer -> BigNat+integerToBigNat (Integer.S# i) = Integer.wordToBigNat (int2Word# i)+integerToBigNat (Integer.Jp# b) = b+integerToBigNat (Integer.Jn# b) = b++-- | Simple newtype wrapping the @BigNat@ value of the+-- modulus of the underlying field Z p. This modulus+-- is required to be prime.+newtype PrimeModulus = PrimeModulus { primeMod :: BigNat }+++-- | Inject an integer value into the @PrimeModulus@ type.+-- This modulus is required to be prime.+primeModulus :: Integer -> PrimeModulus+primeModulus = PrimeModulus . integerToBigNat+{-# INLINE primeModulus #-}+++-- Barrett reduction replaces a division by the modulus with+-- two multiplications and some shifting, masking, and additions+-- (and some fairly negligible pre-processing). For the size of+-- moduli we are working with for ECC, this does not appear to be+-- a performance win. Even for largest NIST curve (P-521) Barrett+-- reduction is about 20% slower than naive modular reduction.+-- Smaller curves are worse WRT the baseline.++-- {-# INLINE primeModulus #-}+-- primeModulus :: Integer -> PrimeModulus+-- primeModulus = untrie modulusParameters++-- data PrimeModulus = PrimeModulus+-- { primeMod :: !Integer+-- , barrettInverse :: !Integer+-- , barrettK :: !Int+-- , barrettMask :: !Integer+-- }+-- deriving (Show, Eq)++-- {-# NOINLINE modulusParameters #-}+-- modulusParameters :: Integer :->: PrimeModulus+-- modulusParameters = trie computeModulusParameters++-- computeModulusParameters :: Integer -> PrimeModulus+-- computeModulusParameters p = PrimeModulus p inv k mask+-- where+-- k = fromInteger w++-- b :: Integer+-- b = 2 ^ (64::Int)++-- -- w is the number of 64-bit words required to express p+-- w = (widthInteger p + 63) `div` 64++-- mask = b^(k+1) - 1++-- -- inv = floor ( b^(2*k) / p )+-- inv = b^(2*k) `div` p++-- barrettReduction :: PrimeModulus -> Integer -> Integer+-- barrettReduction p x = go r3+-- where+-- m = primeMod p+-- k = barrettK p+-- inv = barrettInverse p+-- mask = barrettMask p++-- -- q1 <- floor (x / b^(k-1))+-- q1 = x `shiftR` (64 * (k-1))++-- -- q2 <- q1 * floor ( b^(2*k) / m )+-- q2 = q1 * inv++-- -- q3 <- floor (q2 / b^(k+1))+-- q3 = q2 `shiftR` (64 * (k+1))++-- -- r1 <- x mod b^(k+1)+-- r1 = x .&. mask++-- -- r2 <- (q3 * m) mod b^(k+1)+-- r2 = (q3 * m) .&. mask++-- -- r3 <- r1 - r2+-- r3 = r1 - r2++-- -- up to 2 multiples of m must be removed+-- go z = if z > m then go (z - m) else z++-- | Modular addition of two values. The inputs are+-- required to be in reduced form, and will output+-- a value in reduced form.+mod_add :: PrimeModulus -> BigNat -> BigNat -> BigNat+mod_add p !x !y =+ case Integer.isNullBigNat# rmp of+ 0# -> rmp+ _ -> r+ where r = Integer.plusBigNat x y+ rmp = Integer.minusBigNat r (primeMod p)++-- | Compute the "half" value of a modular integer. For a given input @x@+-- this is a value @y@ such that @y+y == x@. Such values must exist+-- in @Z p@ when @p > 2@. The input @x@ is required to be in reduced form,+-- and will output a value in reduced form.+mod_half :: PrimeModulus -> BigNat -> BigNat+mod_half p !x = if Integer.testBitBigNat x 0# then qodd else qeven+ where+ qodd = (Integer.plusBigNat x (primeMod p)) `Integer.shiftRBigNat` 1#+ qeven = x `Integer.shiftRBigNat` 1#++-- | Compute the modular multiplication of two input values. Currently, this+-- uses naive modular reduction, and does not require the inputs to be in+-- reduced form. The output is in reduced form.+mod_mul :: PrimeModulus -> BigNat -> BigNat -> BigNat+mod_mul p !x !y = (Integer.timesBigNat x y) `Integer.remBigNat` (primeMod p)++-- | Compute the modular difference of two input values. The inputs are+-- required to be in reduced form, and will output a value in reduced form.+mod_sub :: PrimeModulus -> BigNat -> BigNat -> BigNat+mod_sub p !x !y = mod_add p x (Integer.minusBigNat (primeMod p) y)++-- | Compute the modular square of an input value @x@; that is, @x*x@.+-- The input is not required to be in reduced form, and the output+-- will be in reduced form.+mod_square :: PrimeModulus -> BigNat -> BigNat+mod_square p !x = Integer.sqrBigNat x `Integer.remBigNat` primeMod p++-- | Compute the modular scalar multiplication @2x = x+x@.+-- The input is required to be in reduced form and the output+-- will be in reduced form.+mul2 :: PrimeModulus -> BigNat -> BigNat+mul2 p !x =+ case Integer.isNullBigNat# rmp of+ 0# -> rmp+ _ -> r+ where+ r = x `Integer.shiftLBigNat` 1#+ rmp = Integer.minusBigNat r (primeMod p)++-- | Compute the modular scalar multiplication @3x = x+x+x@.+-- The input is required to be in reduced form and the output+-- will be in reduced form.+mul3 :: PrimeModulus -> BigNat -> BigNat+mul3 p x = mod_add p x $! mul2 p x++-- | Compute the modular scalar multiplication @4x = x+x+x+x@.+-- The input is required to be in reduced form and the output+-- will be in reduced form.+mul4 :: PrimeModulus -> BigNat -> BigNat+mul4 p x = mul2 p $! mul2 p x++-- | Compute the modular scalar multiplication @8x = x+x+x+x+x+x+x+x@.+-- The input is required to be in reduced form and the output+-- will be in reduced form.+mul8 :: PrimeModulus -> BigNat -> BigNat+mul8 p x = mul2 p $! mul4 p x++-- | Compute the elliptic curve group doubling operation.+-- In other words, if @S@ is a projective point on a curve,+-- this operation computes @S+S@ in the ECC group.+--+-- In geometric terms, this operation computes a tangent line+-- to the curve at @S@ and finds the (unique) intersection point of this+-- line with the curve, @R@; then returns the point @R'@, which is @R@+-- reflected across the x axis.+ec_double :: PrimeModulus -> ProjectivePoint -> ProjectivePoint+ec_double p (ProjectivePoint sx sy sz) =+ if Integer.isZeroBigNat sz then zro else ProjectivePoint r18 r23 r13++ where+ r7 = mod_square p sz {- 7: t4 <- (t3)^2 -}+ r8 = mod_sub p sx r7 {- 8: t5 <- t1 - t4 -}+ r9 = mod_add p sx r7 {- 9: t4 <- t1 + t4 -}+ r10 = mod_mul p r9 r8 {- 10: t5 <- t4 * t5 -}+ r11 = mul3 p r10 {- 11: t4 <- 3 * t5 -}+ r12 = mod_mul p sz sy {- 12: t3 <- t3 * t2 -}+ r13 = mul2 p r12 {- 13: t3 <- 2 * t3 -}+ r14 = mod_square p sy {- 14: t2 <- (t2)^2 -}+ r15 = mod_mul p sx r14 {- 15: t5 <- t1 * t2 -}+ r16 = mul4 p r15 {- 16: t5 <- 4 * t5 -}+ r17 = mod_square p r11 {- 17: t1 <- (t4)^2 -}+ r18 = mod_sub p r17 (mul2 p r16) {- 18: t1 <- t1 - 2 * t5 -}+ r19 = mod_square p r14 {- 19: t2 <- (t2)^2 -}+ r20 = mul8 p r19 {- 20: t2 <- 8 * t2 -}+ r21 = mod_sub p r16 r18 {- 21: t5 <- t5 - t1 -}+ r22 = mod_mul p r11 r21 {- 22: t5 <- t4 * t5 -}+ r23 = mod_sub p r22 r20 {- 23: t2 <- t5 - t2 -}++-- | Compute the elliptic curve group addition operation, including the special+-- case for adding points which might be the identity.+ec_add :: PrimeModulus -> ProjectivePoint -> ProjectivePoint -> ProjectivePoint+ec_add p s t+ | Integer.isZeroBigNat (pz s) = t+ | Integer.isZeroBigNat (pz t) = s+ | otherwise = ec_add_nonzero p s t+{-# INLINE ec_add #-}+++-- | Compute the elliptic curve group subtraction operation, including the special+-- cases for subtracting points which might be the identity.+ec_sub :: PrimeModulus -> ProjectivePoint -> ProjectivePoint -> ProjectivePoint+ec_sub p s t = ec_add p s u+ where u = t{ py = Integer.minusBigNat (primeMod p) (py t) }+{-# INLINE ec_sub #-}+++ec_negate :: PrimeModulus -> ProjectivePoint -> ProjectivePoint+ec_negate p s = s{ py = Integer.minusBigNat (primeMod p) (py s) }+{-# INLINE ec_negate #-}++-- | Compute the elliptic curve group addition operation+-- for values known not to be the identity.+-- In other words, if @S@ and @T@ are projective points on a curve,+-- with nonzero @z@ coordinate this operation computes @S+T@ in the ECC group.+--+-- In geometric terms, this operation computes a line that passes through+-- @S@ and @T@, and finds the (unique) other point @R@ where the line intersects+-- the curve; then returns the point @R'@, which is @R@ reflected across the x axis.+-- In the special case where @S == T@, we instead call the @ec_double@ operation,+-- which instead computes a tangent line to @S@ .+ec_add_nonzero :: PrimeModulus -> ProjectivePoint -> ProjectivePoint -> ProjectivePoint+ec_add_nonzero p s@(ProjectivePoint sx sy sz) (ProjectivePoint tx ty tz) =+ if Integer.isZeroBigNat r13 then+ if Integer.isZeroBigNat r14 then+ ec_double p s+ else+ zro+ else+ ProjectivePoint r32 r37 r27++ where+ tNormalized = Integer.eqBigNat tz Integer.oneBigNat++ tz2 = mod_square p tz+ tz3 = mod_mul p tz tz2++ r5 = if tNormalized then sx else mod_mul p sx tz2+ r7 = if tNormalized then sy else mod_mul p sy tz3++ r9 = mod_square p sz {- 9: t7 <- (t3)^2 -}+ r10 = mod_mul p tx r9 {- 10: t4 <- t4 * t7 -}+ r11 = mod_mul p sz r9 {- 11: t7 <- t3 * t7 -}+ r12 = mod_mul p ty r11 {- 12: t5 <- t5 * t7 -}+ r13 = mod_sub p r5 r10 {- 13: t4 <- t1 - t4 -}+ r14 = mod_sub p r7 r12 {- 14: t5 <- t2 - t5 -}++ r22 = mod_sub p (mul2 p r5) r13 {- 22: t1 <- 2*t1 - t4 -}+ r23 = mod_sub p (mul2 p r7) r14 {- 23: t2 <- 2*t2 - t5 -}++ r25 = if tNormalized then sz else mod_mul p sz tz++ r27 = mod_mul p r25 r13 {- 27: t3 <- t3 * t4 -}+ r28 = mod_square p r13 {- 28: t7 <- (t4)^2 -}+ r29 = mod_mul p r13 r28 {- 29: t4 <- t4 * t7 -}+ r30 = mod_mul p r22 r28 {- 30: t7 <- t1 * t7 -}+ r31 = mod_square p r14 {- 31: t1 <- (t5)^2 -}+ r32 = mod_sub p r31 r30 {- 32: t1 <- t1 - t7 -}+ r33 = mod_sub p r30 (mul2 p r32) {- 33: t7 <- t7 - 2*t1 -}+ r34 = mod_mul p r14 r33 {- 34: t5 <- t5 * t7 -}+ r35 = mod_mul p r23 r29 {- 35: t4 <- t2 * t4 -}+ r36 = mod_sub p r34 r35 {- 36: t2 <- t5 - t4 -}+ r37 = mod_half p r36 {- 37: t2 <- t2/2 -}+++-- | Given a nonidentity projective point, normalize it so that+-- its z component is 1. This helps to avoid some modular+-- multiplies in @ec_add@, and may be a win if the point will+-- be added many times.+ec_normalize :: PrimeModulus -> ProjectivePoint -> ProjectivePoint+ec_normalize p s@(ProjectivePoint x y z)+ | Integer.eqBigNat z Integer.oneBigNat = s+ | otherwise = ProjectivePoint x' y' Integer.oneBigNat+ where+ m = primeMod p++ l = Integer.recipModBigNat z m+ l2 = Integer.sqrBigNat l+ l3 = Integer.timesBigNat l l2++ x' = (Integer.timesBigNat x l2) `Integer.remBigNat` m+ y' = (Integer.timesBigNat y l3) `Integer.remBigNat` m+++-- | Given an integer @k@ and a projective point @S@, compute+-- the scalar multiplication @kS@, which is @S@ added to itself+-- @k@ times.+ec_mult :: PrimeModulus -> Integer -> ProjectivePoint -> ProjectivePoint+ec_mult p d s+ | d == 0 = zro+ | d == 1 = s+ | Integer.isZeroBigNat (pz s) = zro+ | otherwise =+ case m of+ 0# -> panic "ec_mult" ["modulus too large", show (Integer.bigNatToInteger (primeMod p))]+ _ -> go m zro++ where+ s' = ec_normalize p s+ h = 3*d++ d' = integerToBigNat d+ h' = integerToBigNat h++ m = case widthInteger h of+ Integer.S# mint -> mint+ _ -> 0#++ go i !r+ | tagToEnum# (i ==# 0#) = r+ | otherwise = go (i -# 1#) r'++ where+ h_i = Integer.testBitBigNat h' i+ d_i = Integer.testBitBigNat d' i++ r' = if h_i then+ if d_i then r2 else ec_add p r2 s'+ else+ if d_i then ec_sub p r2 s' else r2++ r2 = ec_double p r++{-# INLINE normalizeForTwinMult #-}++-- | Compute the sum and difference of the given points,+-- and normalize all four values. This can be done jointly+-- in a more efficient way than computing the necessary+-- field inverses separately.+-- When given points S and T, the returned tuple contains+-- normalized representations for (S, T, S+T, S-T).+--+-- Note there are some special cases that must be handled separately.+normalizeForTwinMult ::+ PrimeModulus -> ProjectivePoint -> ProjectivePoint ->+ (ProjectivePoint, ProjectivePoint, ProjectivePoint, ProjectivePoint)+normalizeForTwinMult p s t+ -- S == 0 && T == 0+ | Integer.isZeroBigNat a && Integer.isZeroBigNat b =+ (zro, zro, zro, zro)++ -- S == 0 && T != 0+ | Integer.isZeroBigNat a =+ let tnorm = ec_normalize p t+ in (zro, tnorm, tnorm, ec_negate p tnorm)++ -- T == 0 && S != 0+ | Integer.isZeroBigNat b =+ let snorm = ec_normalize p s+ in (snorm, zro, snorm, snorm)++ -- S+T == 0, both != 0+ | Integer.isZeroBigNat c =+ let snorm = ec_normalize p s+ in (snorm, ec_negate p snorm, zro, ec_double p snorm)++ -- S-T == 0, both != 0+ | Integer.isZeroBigNat d =+ let snorm = ec_normalize p s+ in (snorm, snorm, ec_double p snorm, zro)++ -- S, T, S+T and S-T all != 0+ | otherwise = (s',t',spt',smt')++ where+ spt = ec_add p s t+ smt = ec_sub p s t++ m = primeMod p++ a = pz s+ b = pz t+ c = pz spt+ d = pz smt++ ab = mod_mul p a b+ cd = mod_mul p c d+ abc = mod_mul p ab c+ abd = mod_mul p ab d+ acd = mod_mul p a cd+ bcd = mod_mul p b cd++ abcd = mod_mul p a bcd++ e = Integer.recipModBigNat abcd m++ a_inv = mod_mul p e bcd+ b_inv = mod_mul p e acd+ c_inv = mod_mul p e abd+ d_inv = mod_mul p e abc++ a_inv2 = mod_square p a_inv+ a_inv3 = mod_mul p a_inv a_inv2++ b_inv2 = mod_square p b_inv+ b_inv3 = mod_mul p b_inv b_inv2++ c_inv2 = mod_square p c_inv+ c_inv3 = mod_mul p c_inv c_inv2++ d_inv2 = mod_square p d_inv+ d_inv3 = mod_mul p d_inv d_inv2++ s' = ProjectivePoint (mod_mul p (px s) a_inv2) (mod_mul p (py s) a_inv3) Integer.oneBigNat+ t' = ProjectivePoint (mod_mul p (px t) b_inv2) (mod_mul p (py t) b_inv3) Integer.oneBigNat++ spt' = ProjectivePoint (mod_mul p (px spt) c_inv2) (mod_mul p (py spt) c_inv3) Integer.oneBigNat+ smt' = ProjectivePoint (mod_mul p (px smt) d_inv2) (mod_mul p (py smt) d_inv3) Integer.oneBigNat+++-- | Given an integer @j@ and a projective point @S@, together with+-- another integer @k@ and point @T@ compute the "twin" scalar+-- the scalar multiplication @jS + kT@. This computation can be done+-- essentially the same number of modular arithmetic operations+-- as a single scalar multiplication by doing some additional bookkeeping+-- and setup.+ec_twin_mult :: PrimeModulus ->+ Integer -> ProjectivePoint ->+ Integer -> ProjectivePoint ->+ ProjectivePoint+ec_twin_mult p (integerToBigNat -> d0) s (integerToBigNat -> d1) t =+ case m of+ 0# -> panic "ec_twin_mult" ["modulus too large", show (Integer.bigNatToInteger (primeMod p))]+ _ -> go m init_c0 init_c1 zro++ where+ (s',t',spt',smt') = normalizeForTwinMult p s t++ m = case max 4 (widthInteger (Integer.bigNatToInteger (primeMod p))) of+ Integer.S# mint -> mint+ _ -> 0# -- if `m` doesn't fit into an Int, should be impossible++ init_c0 = C False False (tst d0 (m -# 1#)) (tst d0 (m -# 2#)) (tst d0 (m -# 3#)) (tst d0 (m -# 4#))+ init_c1 = C False False (tst d1 (m -# 1#)) (tst d1 (m -# 2#)) (tst d1 (m -# 3#)) (tst d1 (m -# 4#))++ tst x i+ | tagToEnum# (i >=# 0#) = Integer.testBitBigNat x i+ | otherwise = False++ f i =+ if tagToEnum# (i <# 18#) then+ if tagToEnum# (i <# 12#) then+ if tagToEnum# (i <# 4#) then+ 12#+ else+ 14#+ else+ if tagToEnum# (i <# 14#) then+ 12#+ else+ 10#+ else+ if tagToEnum# (i <# 22#) then+ 9#+ else+ if tagToEnum# (i <# 24#) then+ 11#+ else+ 12#++ go !k !c0 !c1 !r = if tagToEnum# (k <# 0#) then r else go (k -# 1#) c0' c1' r'+ where+ h0 = cStateToH c0+ h1 = cStateToH c1+ u0 = if tagToEnum# (h0 <# f h1) then 0# else (if cHead c0 then -1# else 1#)+ u1 = if tagToEnum# (h1 <# f h0) then 0# else (if cHead c1 then -1# else 1#)+ c0' = cStateUpdate u0 c0 (tst d0 (k -# 5#))+ c1' = cStateUpdate u1 c1 (tst d1 (k -# 5#))++ r2 = ec_double p r++ r' =+ case u0 of+ -1# ->+ case u1 of+ -1# -> ec_sub p r2 spt'+ 1# -> ec_sub p r2 smt'+ _ -> ec_sub p r2 s'+ 1# ->+ case u1 of+ -1# -> ec_add p r2 smt'+ 1# -> ec_add p r2 spt'+ _ -> ec_add p r2 s'+ _ ->+ case u1 of+ -1# -> ec_sub p r2 t'+ 1# -> ec_add p r2 t'+ _ -> r2++data CState = C !Bool !Bool !Bool !Bool !Bool !Bool++{-# INLINE cHead #-}+cHead :: CState -> Bool+cHead (C c0 _ _ _ _ _) = c0++{-# INLINE cStateToH #-}+cStateToH :: CState -> Int#+cStateToH c@(C c0 _ _ _ _ _) =+ if c0 then 31# -# cStateToInt c else cStateToInt c++{-# INLINE cStateToInt #-}+cStateToInt :: CState -> Int#+cStateToInt (C _ c1 c2 c3 c4 c5) =+ (dataToTag# c1 `uncheckedIShiftL#` 4#) +#+ (dataToTag# c2 `uncheckedIShiftL#` 3#) +#+ (dataToTag# c3 `uncheckedIShiftL#` 2#) +#+ (dataToTag# c4 `uncheckedIShiftL#` 1#) +#+ (dataToTag# c5)++{-# INLINE cStateUpdate #-}+cStateUpdate :: Int# -> CState -> Bool -> CState+cStateUpdate u (C _ c1 c2 c3 c4 c5) e =+ case u of+ 0# -> C c1 c2 c3 c4 c5 e+ _ -> C (complement c1) c2 c3 c4 c5 e
src/Cryptol/REPL/Command.hs view
@@ -60,9 +60,11 @@ import qualified Cryptol.Utils.Ident as M import qualified Cryptol.ModuleSystem.Env as M +import qualified Cryptol.Backend.Monad as E import Cryptol.Eval.Concrete( Concrete(..) ) import qualified Cryptol.Eval.Concrete as Concrete-import qualified Cryptol.Eval.Monad as E+import qualified Cryptol.Eval.Env as E+import qualified Cryptol.Eval.Type as E import qualified Cryptol.Eval.Value as E import qualified Cryptol.Eval.Reference as R import Cryptol.Testing.Random@@ -92,6 +94,7 @@ import qualified Control.Exception as X import Control.Monad hiding (mapM, mapM)+import qualified Control.Monad.Catch as Ex import Control.Monad.IO.Class(liftIO) import Data.ByteString (ByteString) import qualified Data.ByteString as BS@@ -119,7 +122,7 @@ import System.Random.TF(newTFGen) import Numeric (showFFloat) import qualified Data.Text as T-import Data.IORef(newIORef,readIORef)+import Data.IORef(newIORef,readIORef,writeIORef) import GHC.Float (log1p, expm1) @@ -337,10 +340,7 @@ evalCmd :: String -> REPL () evalCmd str = do- letEnabled <- getLetEnabled- ri <- if letEnabled- then replParseInput str- else P.ExprInput <$> replParseExpr str+ ri <- replParseInput str case ri of P.ExprInput expr -> do (val,_ty) <- replEvalExpr expr@@ -359,6 +359,9 @@ -- explicitly make this a top-level declaration, so that it will -- be generalized if mono-binds is enabled replEvalDecl decl+ P.EmptyInput ->+ -- comment or empty input does nothing+ pure () printCounterexample :: CounterExampleType -> P.Expr P.PName -> [Concrete.Value] -> REPL () printCounterexample cexTy pexpr vs =@@ -382,15 +385,16 @@ dumpTestsCmd outFile str = do expr <- replParseExpr str (val, ty) <- replEvalExpr expr- evo <- getEvalOpts ppopts <- getPPValOpts testNum <- getKnownUser "tests" :: REPL Int g <- io newTFGen+ tenv <- E.envTypes . M.deEnv <$> getDynEnv+ let tyv = E.evalValType tenv ty gens <-- case TestR.dumpableType ty of+ case TestR.dumpableType tyv of Nothing -> raise (TypeNotTestable ty) Just gens -> return gens- tests <- io $ TestR.returnTests g evo gens val testNum+ tests <- io $ TestR.returnTests g gens val testNum out <- forM tests $ \(args, x) -> do argOut <- mapM (rEval . E.ppValue Concrete ppopts) args@@ -422,76 +426,81 @@ qcCmd qcMode str = do expr <- replParseExpr str (val,ty) <- replEvalExpr expr- testNum <- getKnownUser "tests"- case testableType ty of- Just (Just sz,tys,vss) | qcMode == QCExhaust || sz <= toInteger testNum -> do+ testNum <- (toInteger :: Int -> Integer) <$> getKnownUser "tests"+ tenv <- E.envTypes . M.deEnv <$> getDynEnv+ let tyv = E.evalValType tenv ty+ percentRef <- io $ newIORef Nothing+ testsRef <- io $ newIORef 0+ case testableType tyv of+ Just (Just sz,tys,vss,_gens) | qcMode == QCExhaust || sz <= testNum -> do rPutStrLn "Using exhaustive testing."- let f _ [] = panic "Cryptol.REPL.Command"- ["Exhaustive testing ran out of test cases"]- f _ (vs : vss1) = do- evo <- getEvalOpts- result <- io $ evalTest evo val vs- return (result, vss1)- testSpec = TestSpec {- testFn = f- , testProp = str- , testTotal = sz- , testPossible = Just sz- , testRptProgress = ppProgress- , testClrProgress = delProgress- , testRptFailure = ppFailure tys expr- , testRptSuccess = do- delTesting- prtLn $ "Passed " ++ show sz ++ " tests."- rPutStrLn "Q.E.D."- } prt testingMsg- report <- runTests testSpec vss+ (res,num) <-+ Ex.catch (exhaustiveTests (\n -> ppProgress percentRef testsRef n sz)+ val vss)+ (\ex -> do rPutStrLn "\nTest interrupted..."+ num <- io $ readIORef testsRef+ let report = TestReport Pass str num (Just sz)+ ppReport (map E.tValTy tys) expr False report+ rPutStrLn $ interruptedExhaust num sz+ Ex.throwM (ex :: Ex.SomeException))+ let report = TestReport res str num (Just sz)+ delProgress+ delTesting+ ppReport (map E.tValTy tys) expr True report return [report] - Just (sz,tys,_) | qcMode == QCRandom ->- case TestR.testableTypeGenerators ty of- Nothing -> raise (TypeNotTestable ty)- Just gens -> do- rPutStrLn "Using random testing."- evo <- getEvalOpts- let testSpec = TestSpec {- testFn = \sz' g ->- io $ TestR.runOneTest evo val gens sz' g- , testProp = str- , testTotal = toInteger testNum- , testPossible = sz- , testRptProgress = ppProgress- , testClrProgress = delProgress- , testRptFailure = ppFailure tys expr- , testRptSuccess = do- delTesting- prtLn $ "Passed " ++ show testNum ++ " tests."- }- prt testingMsg- g <- io newTFGen- report <- runTests testSpec g- when (isPass (reportResult report)) $- case sz of- Nothing -> return ()- Just n -> rPutStrLn $ coverageString testNum n- return [report]+ Just (sz,tys,_,gens) | qcMode == QCRandom -> do+ rPutStrLn "Using random testing."+ prt testingMsg+ g <- io newTFGen+ (res,num) <-+ Ex.catch (randomTests (\n -> ppProgress percentRef testsRef n testNum)+ testNum val gens g)+ (\ex -> do rPutStrLn "\nTest interrupted..."+ num <- io $ readIORef testsRef+ let report = TestReport Pass str num sz+ ppReport (map E.tValTy tys) expr False report+ case sz of+ Just n -> rPutStrLn $ coverageString num n+ _ -> return ()+ Ex.throwM (ex :: Ex.SomeException))+ let report = TestReport res str num sz+ delProgress+ delTesting+ ppReport (map E.tValTy tys) expr False report+ case sz of+ Just n | isPass res -> rPutStrLn $ coverageString testNum n+ _ -> return ()+ return [report] _ -> raise (TypeNotTestable ty) where testingMsg = "Testing... " + interruptedExhaust testNum sz =+ let percent = (100.0 :: Double) * (fromInteger testNum) / fromInteger sz+ showValNum+ | sz > 2 ^ (20::Integer) =+ "2^^" ++ show (lg2 sz)+ | otherwise = show sz+ in "Test coverage: "+ ++ showFFloat (Just 2) percent "% ("+ ++ show testNum ++ " of "+ ++ showValNum+ ++ " values)"+ coverageString testNum sz =- let (percent, expectedUnique) = expectedCoverage testNum sz- showValNum- | sz > 2 ^ (20::Integer) =- "2^^" ++ show (lg2 sz)- | otherwise = show sz- in "Expected test coverage: "- ++ showFFloat (Just 2) percent "% ("- ++ showFFloat (Just 0) expectedUnique " of "- ++ showValNum- ++ " values)"+ let (percent, expectedUnique) = expectedCoverage testNum sz+ showValNum+ | sz > 2 ^ (20::Integer) =+ "2^^" ++ show (lg2 sz)+ | otherwise = show sz+ in "Expected test coverage: "+ ++ showFFloat (Just 2) percent "% ("+ ++ showFFloat (Just 0) expectedUnique " of "+ ++ showValNum+ ++ " values)" totProgressWidth = 4 -- 100%@@ -505,19 +514,35 @@ prt msg = rPutStr msg >> io (hFlush stdout) prtLn msg = rPutStrLn msg >> io (hFlush stdout) - ppProgress this tot = unlessBatch $- let percent = show (div (100 * this) tot) ++ "%"- width = length percent- pad = replicate (totProgressWidth - width) ' '- in prt (pad ++ percent)+ ppProgress percentRef testsRef this tot =+ do io $ writeIORef testsRef this+ let percent = show (div (100 * this) tot) ++ "%"+ width = length percent+ pad = replicate (totProgressWidth - width) ' '+ unlessBatch $+ do oldPercent <- io $ readIORef percentRef+ case oldPercent of+ Nothing ->+ do io $ writeIORef percentRef (Just percent)+ prt (pad ++ percent)+ Just p | p /= percent ->+ do io $ writeIORef percentRef (Just percent)+ delProgress+ prt (pad ++ percent)+ _ -> return () del n = unlessBatch $ prt (replicate n '\BS' ++ replicate n ' ' ++ replicate n '\BS') delTesting = del (length testingMsg) delProgress = del totProgressWidth + ppReport _tys _expr isExhaustive (TestReport Pass _str testNum _testPossible) =+ do prtLn $ "Passed " ++ show testNum ++ " tests."+ when isExhaustive (rPutStrLn "Q.E.D.")+ ppReport tys expr _ (TestReport failure _str _testNum _testPossible) =+ ppFailure tys expr failure+ ppFailure tys pexpr failure = do- delTesting opts <- getPPValOpts case failure of FailFalse vs -> do@@ -561,7 +586,7 @@ -- situations, we expect the naive approximation @k/n@ to be very -- close to accurate and the expected number of unique values is -- essentially equal to the number of tests.-expectedCoverage :: Int -> Integer -> (Double, Double)+expectedCoverage :: Integer -> Integer -> (Double, Double) expectedCoverage testNum sz = -- If the Double computation has enough precision, use the -- "with replacement" formula.@@ -632,7 +657,7 @@ ~(EnvBool yes) <- getUser "show-examples" when yes $ printCounterexample cexType pexpr vs - bindItVariable t e+ void $ bindItVariable t e AllSatResult _ -> do panic "REPL.Command" ["Unexpected AllSAtResult for ':safe' call"]@@ -678,7 +703,7 @@ ThmResult ts -> do rPutStrLn (if isSat then "Unsatisfiable" else "Q.E.D.") (t, e) <- mkSolverResult cexStr (not isSat) (Left ts)- bindItVariable t e+ void $ bindItVariable t e CounterExample cexType tevs -> do rPutStrLn "Counterexample"@@ -691,7 +716,7 @@ ~(EnvBool yes) <- getUser "show-examples" when yes $ printCounterexample cexType pexpr vs - bindItVariable t e+ void $ bindItVariable t e AllSatResult tevss -> do rPutStrLn "Satisfiable"@@ -717,7 +742,7 @@ when yes $ forM_ vss (printSatisfyingModel pexpr) case (ty, exprs) of- (t, [e]) -> bindItVariable t e+ (t, [e]) -> void $ bindItVariable t e (t, es ) -> bindItVariables t es seeStats <- getUserShowProverStats@@ -753,7 +778,8 @@ Left sbvCfg -> liftModuleCmd $ SBV.satProve sbvCfg cmd Right w4Cfg -> do ~(EnvBool hashConsing) <- getUser "hash-consing"- liftModuleCmd $ W4.satProve w4Cfg hashConsing cmd+ ~(EnvBool warnUninterp) <- getUser "warnUninterp"+ liftModuleCmd $ W4.satProve w4Cfg hashConsing warnUninterp cmd stas <- io (readIORef timing) return (firstProver,res,stas)@@ -807,7 +833,8 @@ Right w4Cfg -> do ~(EnvBool hashConsing) <- getUser "hash-consing"- result <- liftModuleCmd $ W4.satProveOffline w4Cfg hashConsing cmd $ \f ->+ ~(EnvBool warnUninterp) <- getUser "warnUninterp"+ result <- liftModuleCmd $ W4.satProveOffline w4Cfg hashConsing warnUninterp cmd $ \f -> do displayMsg case mfile of Just path ->@@ -875,7 +902,7 @@ validEvalContext schema val <- liftModuleCmd (rethrowEvalError . R.evaluate expr) opts <- getPPValOpts- rPrint $ R.ppValue opts val+ rPrint $ R.ppEValue opts val astOfCmd :: String -> REPL () astOfCmd str = do@@ -915,7 +942,7 @@ let t = T.tWord (T.tNum (toInteger len * 8)) let x = T.EProofApp (T.ETApp (T.ETApp number (T.tNum val)) t) let expr = T.EApp f x- bindItVariable (T.tString len) expr+ void $ bindItVariable (T.tString len) expr -- | Convert a 'ByteString' (big-endian) of length @n@ to an 'Integer' -- with @8*n@ bits. This function uses a balanced binary fold to@@ -963,12 +990,10 @@ rEval :: E.Eval a -> REPL a-rEval m = do ev <- getEvalOpts- io (E.runEval ev m)+rEval m = io (E.runEval m) rEvalRethrow :: E.Eval a -> REPL a-rEvalRethrow m = do ev <- getEvalOpts- io $ rethrowEvalError $ E.runEval ev m+rEvalRethrow m = io $ rethrowEvalError $ E.runEval m reloadCmd :: REPL () reloadCmd = do@@ -1391,11 +1416,7 @@ "requires:" $$ nest 2 (vcat rs) doShowFix (T.atFixitiy a)-- case T.atDoc a of- Nothing -> pure ()- Just d -> do rPutStrLn ""- rPutStrLn d+ doShowDocString (T.atDoc a) fromTyParam = do p <- Map.lookup name (M.ifParamTypes params)@@ -1413,9 +1434,7 @@ doShowTyHelp nameEnv decl doc = do rPutStrLn "" rPrint (runDoc nameEnv (nest 4 decl))- case doc of- Nothing -> return ()- Just d -> rPutStrLn "" >> rPutStrLn d+ doShowDocString doc doShowFix fx = case fx of@@ -1452,9 +1471,7 @@ doShowFix $ ifDeclFixity `mplus` (guard ifDeclInfix >> return P.defaultFixity) - case ifDeclDoc of- Just str -> rPutStrLn ('\n' : str)- Nothing -> return ()+ doShowDocString ifDeclDoc fromNewtype = do _ <- Map.lookup name (M.ifNewtypes env)@@ -1471,10 +1488,12 @@ <+> pp (T.mvpType p) doShowFix (T.mvpFixity p)+ doShowDocString (T.mvpDoc p) - case T.mvpDoc p of- Just str -> rPutStrLn ('\n' : str)- Nothing -> return ()+ doShowDocString doc =+ case doc of+ Nothing -> pure ()+ Just d -> rPutStrLn ('\n' : T.unpack d) showCmdHelp c [arg] | ":set" `elem` cNames c = showOptionHelp arg showCmdHelp c _args =@@ -1565,10 +1584,10 @@ isDefaultWarn _ = False filterDefaults w | warnDefaulting = Just w- filterDefaults (M.TypeCheckWarnings xs) =+ filterDefaults (M.TypeCheckWarnings nameMap xs) = case filter (not . isDefaultWarn . snd) xs of [] -> Nothing- ys -> Just (M.TypeCheckWarnings ys)+ ys -> Just (M.TypeCheckWarnings nameMap ys) filterDefaults w = Just w isShadowWarn (M.SymbolShadowed {}) = True@@ -1639,10 +1658,12 @@ let su = T.listParamSubst tys return (def1, T.apSubst su (T.sType sig)) - val <- liftModuleCmd (rethrowEvalError . M.evalExpr def1)+ -- add "it" to the namespace via a new declaration+ itVar <- bindItVariable ty def1++ -- evaluate the it variable+ val <- liftModuleCmd (rethrowEvalError . M.evalExpr (T.EVar itVar)) whenDebug (rPutStrLn (dump def1))- -- add "it" to the namespace- bindItVariable ty def1 return (val,ty) where warnDefaults ts =@@ -1669,8 +1690,9 @@ either handler (return . Just) x -- | Creates a fresh binding of "it" to the expression given, and adds--- it to the current dynamic environment-bindItVariable :: T.Type -> T.Expr -> REPL ()+-- it to the current dynamic environment. The fresh name generated+-- is returned.+bindItVariable :: T.Type -> T.Expr -> REPL T.Name bindItVariable ty expr = do freshIt <- freshName itIdent M.UserName let schema = T.Forall { T.sVars = []@@ -1690,6 +1712,7 @@ let nenv' = M.singletonE (P.UnQual itIdent) freshIt `M.shadowing` M.deNames denv setDynEnv $ denv { M.deNames = nenv' }+ return freshIt -- | Extend the dynamic environment with a fresh binding for "it",@@ -1701,16 +1724,14 @@ mb <- rEval (Concrete.toExpr prims ty val) case mb of Nothing -> return ()- Just expr -> bindItVariable ty expr--+ Just expr -> void $ bindItVariable ty expr -- | Creates a fresh binding of "it" to a finite sequence of -- expressions of the same type, and adds that sequence to the current -- dynamic environment bindItVariables :: T.Type -> [T.Expr] -> REPL ()-bindItVariables ty exprs = bindItVariable seqTy seqExpr+bindItVariables ty exprs = void $ bindItVariable seqTy seqExpr where len = length exprs seqTy = T.tSeq (T.tNum len) ty
src/Cryptol/REPL/Monad.hs view
@@ -48,9 +48,6 @@ , shouldContinue , unlessBatch , asBatch- , disableLet- , enableLet- , getLetEnabled , validEvalContext , updateREPLTitle , setUpdateREPLTitle@@ -99,7 +96,7 @@ import Cryptol.Symbolic (SatNum(..)) import Cryptol.Symbolic.SBV (SBVPortfolioException) import Cryptol.Symbolic.What4 (W4Exception)-import Cryptol.Eval.Monad(PPFloatFormat(..),PPFloatExp(..))+import Cryptol.Backend.Monad(PPFloatFormat(..),PPFloatExp(..)) import qualified Cryptol.Symbolic.SBV as SBV (proverNames, setupProver, defaultProver, SBVProverConfig) import qualified Cryptol.Symbolic.What4 as W4 (proverNames, setupProver, W4ProverConfig) @@ -158,9 +155,6 @@ , eLogger :: Logger -- ^ Use this to send messages to the user - , eLetEnabled :: Bool- -- ^ Should we allow `let` on the command line- , eUpdateTitle :: REPL () -- ^ Execute this every time we load a module. -- This is used to change the title of terminal when loading a module.@@ -180,7 +174,6 @@ , eModuleEnv = env , eUserEnv = mkUserEnv userOptions , eLogger = l- , eLetEnabled = True , eUpdateTitle = return () , eProverConfig = Left SBV.defaultProver }@@ -444,16 +437,6 @@ modifyRW_ $ (\ rw -> rw { eIsBatch = wasBatch }) return a -disableLet :: REPL ()-disableLet = modifyRW_ (\ rw -> rw { eLetEnabled = False })--enableLet :: REPL ()-enableLet = modifyRW_ (\ rw -> rw { eLetEnabled = True })---- | Are let-bindings enabled in this REPL?-getLetEnabled :: REPL Bool-getLetEnabled = fmap eLetEnabled getRW- -- | Is evaluation enabled. If the currently focused module is -- parameterized, then we cannot evalute. validEvalContext :: T.FreeVars a => a -> REPL ()@@ -769,6 +752,8 @@ "Choose whether to display warnings when defaulting." , simpleOpt "warnShadowing" (EnvBool True) noCheck "Choose whether to display warnings when shadowing symbols."+ , simpleOpt "warnUninterp" (EnvBool True) noCheck+ "Choose whether to issue a warning when uninterpreted functions are used to implement primitives in the symbolic simulator." , simpleOpt "smtfile" (EnvString "-") noCheck "The file to use for SMT-Lib scripts (for debugging or offline proving).\nUse \"-\" for stdout." , OptionDescr "mono-binds" (EnvBool True) noCheck
+ src/Cryptol/SHA.hs view
@@ -0,0 +1,564 @@+{-# LANGUAGE BangPatterns, CPP, FlexibleInstances #-}+-- |Pure implementations of the SHA suite of hash functions. The implementation+-- is basically an unoptimized translation of FIPS 180-2 into Haskell. If you're+-- looking for performance, you probably won't find it here.+module Cryptol.SHA+ ( SHA256State(..), SHA512State(..)+ , SHA256Block(..), SHA512Block(..)++ -- * Raw SHA block functions+ , processSHA512Block+ , processSHA256Block++ , initialSHA224State+ , initialSHA256State+ , initialSHA384State+ , initialSHA512State++ -- * Internal routines included for testing+ , toBigEndianSBS, fromBigEndianSBS+ , calc_k+ , padSHA1, padSHA512+ , padSHA1Chunks, padSHA512Chunks+ )+ where+ +import Data.Bits+import Data.ByteString.Lazy(ByteString)+import Data.Word (Word32, Word64)+import qualified Data.ByteString.Lazy as BS+import qualified Data.ByteString as SBS++-- --------------------------------------------------------------------------+--+-- State Definitions and Initial States+--+-- --------------------------------------------------------------------------++data SHA256State = SHA256S !Word32 !Word32 !Word32 !Word32+ !Word32 !Word32 !Word32 !Word32++initialSHA224State :: SHA256State+initialSHA224State = SHA256S 0xc1059ed8 0x367cd507 0x3070dd17 0xf70e5939+ 0xffc00b31 0x68581511 0x64f98fa7 0xbefa4fa4++initialSHA256State :: SHA256State+initialSHA256State = SHA256S 0x6a09e667 0xbb67ae85 0x3c6ef372 0xa54ff53a+ 0x510e527f 0x9b05688c 0x1f83d9ab 0x5be0cd19++data SHA512State = SHA512S !Word64 !Word64 !Word64 !Word64+ !Word64 !Word64 !Word64 !Word64++initialSHA384State :: SHA512State+initialSHA384State = SHA512S 0xcbbb9d5dc1059ed8 0x629a292a367cd507+ 0x9159015a3070dd17 0x152fecd8f70e5939+ 0x67332667ffc00b31 0x8eb44a8768581511+ 0xdb0c2e0d64f98fa7 0x47b5481dbefa4fa4++initialSHA512State :: SHA512State+initialSHA512State = SHA512S 0x6a09e667f3bcc908 0xbb67ae8584caa73b+ 0x3c6ef372fe94f82b 0xa54ff53a5f1d36f1+ 0x510e527fade682d1 0x9b05688c2b3e6c1f+ 0x1f83d9abfb41bd6b 0x5be0cd19137e2179+++-- --------------------------------------------------------------------------+--+-- Padding+--+-- --------------------------------------------------------------------------++padSHA1 :: ByteString -> ByteString+padSHA1 = generic_pad 448 512 64++padSHA1Chunks :: Int -> [SBS.ByteString]+padSHA1Chunks = generic_pad_chunks 448 512 64++padSHA512 :: ByteString -> ByteString+padSHA512 = generic_pad 896 1024 128++padSHA512Chunks :: Int -> [SBS.ByteString]+padSHA512Chunks = generic_pad_chunks 896 1024 128++generic_pad :: Word64 -> Word64 -> Int -> ByteString -> ByteString+generic_pad a b lSize bs =+ BS.fromChunks $! go 0 chunks+ where+ chunks = BS.toChunks bs++ -- Generates the padded ByteString at the same time it computes the length+ -- of input. If the length is computed before the computation of the hash, it+ -- will break the lazy evaluation of the input and no longer run in constant+ -- memory space.+ go !len [] = generic_pad_chunks a b lSize len+ go !len (c:cs) = c : go (len + SBS.length c) cs++generic_pad_chunks :: Word64 -> Word64 -> Int -> Int -> [SBS.ByteString]+generic_pad_chunks a b lSize len =+ let lenBits = fromIntegral $ len * 8+ k = calc_k a b lenBits+ -- INVARIANT: k is necessarily > 0, and (k + 1) is a multiple of 8.+ kBytes = (k + 1) `div` 8+ nZeroBytes = fromIntegral $! kBytes - 1+ padLength = toBigEndianSBS lSize lenBits+ in [SBS.singleton 0x80, SBS.replicate nZeroBytes 0, padLength]++-- Given a, b, and l, calculate the smallest k such that (l + 1 + k) mod b = a.+calc_k :: Word64 -> Word64 -> Word64 -> Word64+calc_k a b l =+ if r <= -1+ then fromIntegral r + b+ else fromIntegral r+ where+ r = toInteger a - toInteger l `mod` toInteger b - 1++toBigEndianSBS :: (Integral a, Bits a) => Int -> a -> SBS.ByteString+toBigEndianSBS s val = SBS.pack $ map getBits [s - 8, s - 16 .. 0]+ where+ getBits x = fromIntegral $ (val `shiftR` x) .&. 0xFF++fromBigEndianSBS :: (Integral a, Bits a) => SBS.ByteString -> a+fromBigEndianSBS =+ SBS.foldl (\ acc x -> (acc `shiftL` 8) + fromIntegral x) 0++-- --------------------------------------------------------------------------+--+-- SHA Functions+--+-- --------------------------------------------------------------------------++{-# SPECIALIZE ch :: Word32 -> Word32 -> Word32 -> Word32 #-}+{-# SPECIALIZE ch :: Word64 -> Word64 -> Word64 -> Word64 #-}+ch :: Bits a => a -> a -> a -> a+ch x y z = (x .&. y) `xor` (complement x .&. z)++{-# SPECIALIZE maj :: Word32 -> Word32 -> Word32 -> Word32 #-}+{-# SPECIALIZE maj :: Word64 -> Word64 -> Word64 -> Word64 #-}+maj :: Bits a => a -> a -> a -> a+maj x y z = (x .&. (y .|. z)) .|. (y .&. z)+-- note:+-- the original functions is (x & y) ^ (x & z) ^ (y & z)+-- if you fire off truth tables, this is equivalent to +-- (x & y) | (x & z) | (y & z)+-- which you can the use distribution on:+-- (x & (y | z)) | (y & z)+-- which saves us one operation.++bsig256_0 :: Word32 -> Word32+bsig256_0 x = rotateR x 2 `xor` rotateR x 13 `xor` rotateR x 22++bsig256_1 :: Word32 -> Word32+bsig256_1 x = rotateR x 6 `xor` rotateR x 11 `xor` rotateR x 25++lsig256_0 :: Word32 -> Word32+lsig256_0 x = rotateR x 7 `xor` rotateR x 18 `xor` shiftR x 3++lsig256_1 :: Word32 -> Word32+lsig256_1 x = rotateR x 17 `xor` rotateR x 19 `xor` shiftR x 10++bsig512_0 :: Word64 -> Word64+bsig512_0 x = rotateR x 28 `xor` rotateR x 34 `xor` rotateR x 39++bsig512_1 :: Word64 -> Word64+bsig512_1 x = rotateR x 14 `xor` rotateR x 18 `xor` rotateR x 41++lsig512_0 :: Word64 -> Word64+lsig512_0 x = rotateR x 1 `xor` rotateR x 8 `xor` shiftR x 7++lsig512_1 :: Word64 -> Word64+lsig512_1 x = rotateR x 19 `xor` rotateR x 61 `xor` shiftR x 6++-- --------------------------------------------------------------------------+--+-- Message Schedules+--+-- --------------------------------------------------------------------------+++data SHA256Block = SHA256Block !Word32 !Word32 !Word32 !Word32 !Word32 -- 00-04+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 05-09+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 10-14+ !Word32++data SHA256Sched = SHA256Sched !Word32 !Word32 !Word32 !Word32 !Word32 -- 00-04+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 05-09+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 10-14+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 15-19+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 20-24+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 25-29+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 30-34+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 35-39+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 40-44+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 45-49+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 50-54+ !Word32 !Word32 !Word32 !Word32 !Word32 -- 55-59+ !Word32 !Word32 !Word32 !Word32 -- 60-63++getSHA256Sched :: SHA256Block -> SHA256Sched+getSHA256Sched (SHA256Block w00 w01 w02 w03+ w04 w05 w06 w07+ w08 w09 w10 w11+ w12 w13 w14 w15) =+ let w16 = lsig256_1 w14 + w09 + lsig256_0 w01 + w00+ w17 = lsig256_1 w15 + w10 + lsig256_0 w02 + w01+ w18 = lsig256_1 w16 + w11 + lsig256_0 w03 + w02+ w19 = lsig256_1 w17 + w12 + lsig256_0 w04 + w03+ w20 = lsig256_1 w18 + w13 + lsig256_0 w05 + w04+ w21 = lsig256_1 w19 + w14 + lsig256_0 w06 + w05+ w22 = lsig256_1 w20 + w15 + lsig256_0 w07 + w06+ w23 = lsig256_1 w21 + w16 + lsig256_0 w08 + w07+ w24 = lsig256_1 w22 + w17 + lsig256_0 w09 + w08+ w25 = lsig256_1 w23 + w18 + lsig256_0 w10 + w09+ w26 = lsig256_1 w24 + w19 + lsig256_0 w11 + w10+ w27 = lsig256_1 w25 + w20 + lsig256_0 w12 + w11+ w28 = lsig256_1 w26 + w21 + lsig256_0 w13 + w12+ w29 = lsig256_1 w27 + w22 + lsig256_0 w14 + w13+ w30 = lsig256_1 w28 + w23 + lsig256_0 w15 + w14+ w31 = lsig256_1 w29 + w24 + lsig256_0 w16 + w15+ w32 = lsig256_1 w30 + w25 + lsig256_0 w17 + w16+ w33 = lsig256_1 w31 + w26 + lsig256_0 w18 + w17+ w34 = lsig256_1 w32 + w27 + lsig256_0 w19 + w18+ w35 = lsig256_1 w33 + w28 + lsig256_0 w20 + w19+ w36 = lsig256_1 w34 + w29 + lsig256_0 w21 + w20+ w37 = lsig256_1 w35 + w30 + lsig256_0 w22 + w21+ w38 = lsig256_1 w36 + w31 + lsig256_0 w23 + w22+ w39 = lsig256_1 w37 + w32 + lsig256_0 w24 + w23+ w40 = lsig256_1 w38 + w33 + lsig256_0 w25 + w24+ w41 = lsig256_1 w39 + w34 + lsig256_0 w26 + w25+ w42 = lsig256_1 w40 + w35 + lsig256_0 w27 + w26+ w43 = lsig256_1 w41 + w36 + lsig256_0 w28 + w27+ w44 = lsig256_1 w42 + w37 + lsig256_0 w29 + w28+ w45 = lsig256_1 w43 + w38 + lsig256_0 w30 + w29+ w46 = lsig256_1 w44 + w39 + lsig256_0 w31 + w30+ w47 = lsig256_1 w45 + w40 + lsig256_0 w32 + w31+ w48 = lsig256_1 w46 + w41 + lsig256_0 w33 + w32+ w49 = lsig256_1 w47 + w42 + lsig256_0 w34 + w33+ w50 = lsig256_1 w48 + w43 + lsig256_0 w35 + w34+ w51 = lsig256_1 w49 + w44 + lsig256_0 w36 + w35+ w52 = lsig256_1 w50 + w45 + lsig256_0 w37 + w36+ w53 = lsig256_1 w51 + w46 + lsig256_0 w38 + w37+ w54 = lsig256_1 w52 + w47 + lsig256_0 w39 + w38+ w55 = lsig256_1 w53 + w48 + lsig256_0 w40 + w39+ w56 = lsig256_1 w54 + w49 + lsig256_0 w41 + w40+ w57 = lsig256_1 w55 + w50 + lsig256_0 w42 + w41+ w58 = lsig256_1 w56 + w51 + lsig256_0 w43 + w42+ w59 = lsig256_1 w57 + w52 + lsig256_0 w44 + w43+ w60 = lsig256_1 w58 + w53 + lsig256_0 w45 + w44+ w61 = lsig256_1 w59 + w54 + lsig256_0 w46 + w45+ w62 = lsig256_1 w60 + w55 + lsig256_0 w47 + w46+ w63 = lsig256_1 w61 + w56 + lsig256_0 w48 + w47+ in SHA256Sched w00 w01 w02 w03 w04 w05 w06 w07 w08 w09+ w10 w11 w12 w13 w14 w15 w16 w17 w18 w19+ w20 w21 w22 w23 w24 w25 w26 w27 w28 w29+ w30 w31 w32 w33 w34 w35 w36 w37 w38 w39+ w40 w41 w42 w43 w44 w45 w46 w47 w48 w49+ w50 w51 w52 w53 w54 w55 w56 w57 w58 w59+ w60 w61 w62 w63++data SHA512Block = SHA512Block !Word64 !Word64 !Word64 !Word64 !Word64 -- 0- 4+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 5- 9+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 10-14+ !Word64 -- 15++data SHA512Sched = SHA512Sched !Word64 !Word64 !Word64 !Word64 !Word64 -- 0- 4+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 5- 9+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 10-14+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 15-19+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 20-24+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 25-29+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 30-34+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 35-39+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 40-44+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 45-49+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 50-54+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 55-59+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 60-64+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 65-69+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 70-74+ !Word64 !Word64 !Word64 !Word64 !Word64 -- 75-79++getSHA512Sched :: SHA512Block -> SHA512Sched+getSHA512Sched (SHA512Block w00 w01 w02 w03+ w04 w05 w06 w07+ w08 w09 w10 w11+ w12 w13 w14 w15) =+ let w16 = lsig512_1 w14 + w09 + lsig512_0 w01 + w00+ w17 = lsig512_1 w15 + w10 + lsig512_0 w02 + w01+ w18 = lsig512_1 w16 + w11 + lsig512_0 w03 + w02+ w19 = lsig512_1 w17 + w12 + lsig512_0 w04 + w03+ w20 = lsig512_1 w18 + w13 + lsig512_0 w05 + w04+ w21 = lsig512_1 w19 + w14 + lsig512_0 w06 + w05+ w22 = lsig512_1 w20 + w15 + lsig512_0 w07 + w06+ w23 = lsig512_1 w21 + w16 + lsig512_0 w08 + w07+ w24 = lsig512_1 w22 + w17 + lsig512_0 w09 + w08+ w25 = lsig512_1 w23 + w18 + lsig512_0 w10 + w09+ w26 = lsig512_1 w24 + w19 + lsig512_0 w11 + w10+ w27 = lsig512_1 w25 + w20 + lsig512_0 w12 + w11+ w28 = lsig512_1 w26 + w21 + lsig512_0 w13 + w12+ w29 = lsig512_1 w27 + w22 + lsig512_0 w14 + w13+ w30 = lsig512_1 w28 + w23 + lsig512_0 w15 + w14+ w31 = lsig512_1 w29 + w24 + lsig512_0 w16 + w15+ w32 = lsig512_1 w30 + w25 + lsig512_0 w17 + w16+ w33 = lsig512_1 w31 + w26 + lsig512_0 w18 + w17+ w34 = lsig512_1 w32 + w27 + lsig512_0 w19 + w18+ w35 = lsig512_1 w33 + w28 + lsig512_0 w20 + w19+ w36 = lsig512_1 w34 + w29 + lsig512_0 w21 + w20+ w37 = lsig512_1 w35 + w30 + lsig512_0 w22 + w21+ w38 = lsig512_1 w36 + w31 + lsig512_0 w23 + w22+ w39 = lsig512_1 w37 + w32 + lsig512_0 w24 + w23+ w40 = lsig512_1 w38 + w33 + lsig512_0 w25 + w24+ w41 = lsig512_1 w39 + w34 + lsig512_0 w26 + w25+ w42 = lsig512_1 w40 + w35 + lsig512_0 w27 + w26+ w43 = lsig512_1 w41 + w36 + lsig512_0 w28 + w27+ w44 = lsig512_1 w42 + w37 + lsig512_0 w29 + w28+ w45 = lsig512_1 w43 + w38 + lsig512_0 w30 + w29+ w46 = lsig512_1 w44 + w39 + lsig512_0 w31 + w30+ w47 = lsig512_1 w45 + w40 + lsig512_0 w32 + w31+ w48 = lsig512_1 w46 + w41 + lsig512_0 w33 + w32+ w49 = lsig512_1 w47 + w42 + lsig512_0 w34 + w33+ w50 = lsig512_1 w48 + w43 + lsig512_0 w35 + w34+ w51 = lsig512_1 w49 + w44 + lsig512_0 w36 + w35+ w52 = lsig512_1 w50 + w45 + lsig512_0 w37 + w36+ w53 = lsig512_1 w51 + w46 + lsig512_0 w38 + w37+ w54 = lsig512_1 w52 + w47 + lsig512_0 w39 + w38+ w55 = lsig512_1 w53 + w48 + lsig512_0 w40 + w39+ w56 = lsig512_1 w54 + w49 + lsig512_0 w41 + w40+ w57 = lsig512_1 w55 + w50 + lsig512_0 w42 + w41+ w58 = lsig512_1 w56 + w51 + lsig512_0 w43 + w42+ w59 = lsig512_1 w57 + w52 + lsig512_0 w44 + w43+ w60 = lsig512_1 w58 + w53 + lsig512_0 w45 + w44+ w61 = lsig512_1 w59 + w54 + lsig512_0 w46 + w45+ w62 = lsig512_1 w60 + w55 + lsig512_0 w47 + w46+ w63 = lsig512_1 w61 + w56 + lsig512_0 w48 + w47+ w64 = lsig512_1 w62 + w57 + lsig512_0 w49 + w48+ w65 = lsig512_1 w63 + w58 + lsig512_0 w50 + w49+ w66 = lsig512_1 w64 + w59 + lsig512_0 w51 + w50+ w67 = lsig512_1 w65 + w60 + lsig512_0 w52 + w51+ w68 = lsig512_1 w66 + w61 + lsig512_0 w53 + w52+ w69 = lsig512_1 w67 + w62 + lsig512_0 w54 + w53+ w70 = lsig512_1 w68 + w63 + lsig512_0 w55 + w54+ w71 = lsig512_1 w69 + w64 + lsig512_0 w56 + w55+ w72 = lsig512_1 w70 + w65 + lsig512_0 w57 + w56+ w73 = lsig512_1 w71 + w66 + lsig512_0 w58 + w57+ w74 = lsig512_1 w72 + w67 + lsig512_0 w59 + w58+ w75 = lsig512_1 w73 + w68 + lsig512_0 w60 + w59+ w76 = lsig512_1 w74 + w69 + lsig512_0 w61 + w60+ w77 = lsig512_1 w75 + w70 + lsig512_0 w62 + w61+ w78 = lsig512_1 w76 + w71 + lsig512_0 w63 + w62+ w79 = lsig512_1 w77 + w72 + lsig512_0 w64 + w63+ in SHA512Sched w00 w01 w02 w03 w04 w05 w06 w07 w08 w09+ w10 w11 w12 w13 w14 w15 w16 w17 w18 w19+ w20 w21 w22 w23 w24 w25 w26 w27 w28 w29+ w30 w31 w32 w33 w34 w35 w36 w37 w38 w39+ w40 w41 w42 w43 w44 w45 w46 w47 w48 w49+ w50 w51 w52 w53 w54 w55 w56 w57 w58 w59+ w60 w61 w62 w63 w64 w65 w66 w67 w68 w69+ w70 w71 w72 w73 w74 w75 w76 w77 w78 w79++-- --------------------------------------------------------------------------+--+-- SHA Block Processors+--+-- --------------------------------------------------------------------------+++processSHA256Block :: SHA256State -> SHA256Block -> SHA256State+processSHA256Block !s00@(SHA256S a00 b00 c00 d00 e00 f00 g00 h00) !blk = do+ let (SHA256Sched w00 w01 w02 w03 w04 w05 w06 w07 w08 w09+ w10 w11 w12 w13 w14 w15 w16 w17 w18 w19+ w20 w21 w22 w23 w24 w25 w26 w27 w28 w29+ w30 w31 w32 w33 w34 w35 w36 w37 w38 w39+ w40 w41 w42 w43 w44 w45 w46 w47 w48 w49+ w50 w51 w52 w53 w54 w55 w56 w57 w58 w59+ w60 w61 w62 w63) = getSHA256Sched blk+ s01 = step256 s00 0x428a2f98 w00+ s02 = step256 s01 0x71374491 w01+ s03 = step256 s02 0xb5c0fbcf w02+ s04 = step256 s03 0xe9b5dba5 w03+ s05 = step256 s04 0x3956c25b w04+ s06 = step256 s05 0x59f111f1 w05+ s07 = step256 s06 0x923f82a4 w06+ s08 = step256 s07 0xab1c5ed5 w07+ s09 = step256 s08 0xd807aa98 w08+ s10 = step256 s09 0x12835b01 w09+ s11 = step256 s10 0x243185be w10+ s12 = step256 s11 0x550c7dc3 w11+ s13 = step256 s12 0x72be5d74 w12+ s14 = step256 s13 0x80deb1fe w13+ s15 = step256 s14 0x9bdc06a7 w14+ s16 = step256 s15 0xc19bf174 w15+ s17 = step256 s16 0xe49b69c1 w16+ s18 = step256 s17 0xefbe4786 w17+ s19 = step256 s18 0x0fc19dc6 w18+ s20 = step256 s19 0x240ca1cc w19+ s21 = step256 s20 0x2de92c6f w20+ s22 = step256 s21 0x4a7484aa w21+ s23 = step256 s22 0x5cb0a9dc w22+ s24 = step256 s23 0x76f988da w23+ s25 = step256 s24 0x983e5152 w24+ s26 = step256 s25 0xa831c66d w25+ s27 = step256 s26 0xb00327c8 w26+ s28 = step256 s27 0xbf597fc7 w27+ s29 = step256 s28 0xc6e00bf3 w28+ s30 = step256 s29 0xd5a79147 w29+ s31 = step256 s30 0x06ca6351 w30+ s32 = step256 s31 0x14292967 w31+ s33 = step256 s32 0x27b70a85 w32+ s34 = step256 s33 0x2e1b2138 w33+ s35 = step256 s34 0x4d2c6dfc w34+ s36 = step256 s35 0x53380d13 w35+ s37 = step256 s36 0x650a7354 w36+ s38 = step256 s37 0x766a0abb w37+ s39 = step256 s38 0x81c2c92e w38+ s40 = step256 s39 0x92722c85 w39+ s41 = step256 s40 0xa2bfe8a1 w40+ s42 = step256 s41 0xa81a664b w41+ s43 = step256 s42 0xc24b8b70 w42+ s44 = step256 s43 0xc76c51a3 w43+ s45 = step256 s44 0xd192e819 w44+ s46 = step256 s45 0xd6990624 w45+ s47 = step256 s46 0xf40e3585 w46+ s48 = step256 s47 0x106aa070 w47+ s49 = step256 s48 0x19a4c116 w48+ s50 = step256 s49 0x1e376c08 w49+ s51 = step256 s50 0x2748774c w50+ s52 = step256 s51 0x34b0bcb5 w51+ s53 = step256 s52 0x391c0cb3 w52+ s54 = step256 s53 0x4ed8aa4a w53+ s55 = step256 s54 0x5b9cca4f w54+ s56 = step256 s55 0x682e6ff3 w55+ s57 = step256 s56 0x748f82ee w56+ s58 = step256 s57 0x78a5636f w57+ s59 = step256 s58 0x84c87814 w58+ s60 = step256 s59 0x8cc70208 w59+ s61 = step256 s60 0x90befffa w60+ s62 = step256 s61 0xa4506ceb w61+ s63 = step256 s62 0xbef9a3f7 w62+ s64 = step256 s63 0xc67178f2 w63+ SHA256S a64 b64 c64 d64 e64 f64 g64 h64 = s64+ in SHA256S (a00 + a64) (b00 + b64) (c00 + c64) (d00 + d64)+ (e00 + e64) (f00 + f64) (g00 + g64) (h00 + h64)++{-# INLINE step256 #-}+step256 :: SHA256State -> Word32 -> Word32 -> SHA256State+step256 !(SHA256S a b c d e f g h) k w = SHA256S a' b' c' d' e' f' g' h'+ where+ t1 = h + bsig256_1 e + ch e f g + k + w+ t2 = bsig256_0 a + maj a b c+ h' = g+ g' = f+ f' = e+ e' = d + t1+ d' = c+ c' = b+ b' = a+ a' = t1 + t2++processSHA512Block :: SHA512State -> SHA512Block -> SHA512State+processSHA512Block !s00@(SHA512S a00 b00 c00 d00 e00 f00 g00 h00) !blk =+ let (SHA512Sched w00 w01 w02 w03 w04 w05 w06 w07 w08 w09+ w10 w11 w12 w13 w14 w15 w16 w17 w18 w19+ w20 w21 w22 w23 w24 w25 w26 w27 w28 w29+ w30 w31 w32 w33 w34 w35 w36 w37 w38 w39+ w40 w41 w42 w43 w44 w45 w46 w47 w48 w49+ w50 w51 w52 w53 w54 w55 w56 w57 w58 w59+ w60 w61 w62 w63 w64 w65 w66 w67 w68 w69+ w70 w71 w72 w73 w74 w75 w76 w77 w78 w79) = getSHA512Sched blk+ s01 = step512 s00 0x428a2f98d728ae22 w00+ s02 = step512 s01 0x7137449123ef65cd w01+ s03 = step512 s02 0xb5c0fbcfec4d3b2f w02+ s04 = step512 s03 0xe9b5dba58189dbbc w03+ s05 = step512 s04 0x3956c25bf348b538 w04+ s06 = step512 s05 0x59f111f1b605d019 w05+ s07 = step512 s06 0x923f82a4af194f9b w06+ s08 = step512 s07 0xab1c5ed5da6d8118 w07+ s09 = step512 s08 0xd807aa98a3030242 w08+ s10 = step512 s09 0x12835b0145706fbe w09+ s11 = step512 s10 0x243185be4ee4b28c w10+ s12 = step512 s11 0x550c7dc3d5ffb4e2 w11+ s13 = step512 s12 0x72be5d74f27b896f w12+ s14 = step512 s13 0x80deb1fe3b1696b1 w13+ s15 = step512 s14 0x9bdc06a725c71235 w14+ s16 = step512 s15 0xc19bf174cf692694 w15+ s17 = step512 s16 0xe49b69c19ef14ad2 w16+ s18 = step512 s17 0xefbe4786384f25e3 w17+ s19 = step512 s18 0x0fc19dc68b8cd5b5 w18+ s20 = step512 s19 0x240ca1cc77ac9c65 w19+ s21 = step512 s20 0x2de92c6f592b0275 w20+ s22 = step512 s21 0x4a7484aa6ea6e483 w21+ s23 = step512 s22 0x5cb0a9dcbd41fbd4 w22+ s24 = step512 s23 0x76f988da831153b5 w23+ s25 = step512 s24 0x983e5152ee66dfab w24+ s26 = step512 s25 0xa831c66d2db43210 w25+ s27 = step512 s26 0xb00327c898fb213f w26+ s28 = step512 s27 0xbf597fc7beef0ee4 w27+ s29 = step512 s28 0xc6e00bf33da88fc2 w28+ s30 = step512 s29 0xd5a79147930aa725 w29+ s31 = step512 s30 0x06ca6351e003826f w30+ s32 = step512 s31 0x142929670a0e6e70 w31+ s33 = step512 s32 0x27b70a8546d22ffc w32+ s34 = step512 s33 0x2e1b21385c26c926 w33+ s35 = step512 s34 0x4d2c6dfc5ac42aed w34+ s36 = step512 s35 0x53380d139d95b3df w35+ s37 = step512 s36 0x650a73548baf63de w36+ s38 = step512 s37 0x766a0abb3c77b2a8 w37+ s39 = step512 s38 0x81c2c92e47edaee6 w38+ s40 = step512 s39 0x92722c851482353b w39+ s41 = step512 s40 0xa2bfe8a14cf10364 w40+ s42 = step512 s41 0xa81a664bbc423001 w41+ s43 = step512 s42 0xc24b8b70d0f89791 w42+ s44 = step512 s43 0xc76c51a30654be30 w43+ s45 = step512 s44 0xd192e819d6ef5218 w44+ s46 = step512 s45 0xd69906245565a910 w45+ s47 = step512 s46 0xf40e35855771202a w46+ s48 = step512 s47 0x106aa07032bbd1b8 w47+ s49 = step512 s48 0x19a4c116b8d2d0c8 w48+ s50 = step512 s49 0x1e376c085141ab53 w49+ s51 = step512 s50 0x2748774cdf8eeb99 w50+ s52 = step512 s51 0x34b0bcb5e19b48a8 w51+ s53 = step512 s52 0x391c0cb3c5c95a63 w52+ s54 = step512 s53 0x4ed8aa4ae3418acb w53+ s55 = step512 s54 0x5b9cca4f7763e373 w54+ s56 = step512 s55 0x682e6ff3d6b2b8a3 w55+ s57 = step512 s56 0x748f82ee5defb2fc w56+ s58 = step512 s57 0x78a5636f43172f60 w57+ s59 = step512 s58 0x84c87814a1f0ab72 w58+ s60 = step512 s59 0x8cc702081a6439ec w59+ s61 = step512 s60 0x90befffa23631e28 w60+ s62 = step512 s61 0xa4506cebde82bde9 w61+ s63 = step512 s62 0xbef9a3f7b2c67915 w62+ s64 = step512 s63 0xc67178f2e372532b w63+ s65 = step512 s64 0xca273eceea26619c w64+ s66 = step512 s65 0xd186b8c721c0c207 w65+ s67 = step512 s66 0xeada7dd6cde0eb1e w66+ s68 = step512 s67 0xf57d4f7fee6ed178 w67+ s69 = step512 s68 0x06f067aa72176fba w68+ s70 = step512 s69 0x0a637dc5a2c898a6 w69+ s71 = step512 s70 0x113f9804bef90dae w70+ s72 = step512 s71 0x1b710b35131c471b w71+ s73 = step512 s72 0x28db77f523047d84 w72+ s74 = step512 s73 0x32caab7b40c72493 w73+ s75 = step512 s74 0x3c9ebe0a15c9bebc w74+ s76 = step512 s75 0x431d67c49c100d4c w75+ s77 = step512 s76 0x4cc5d4becb3e42b6 w76+ s78 = step512 s77 0x597f299cfc657e2a w77+ s79 = step512 s78 0x5fcb6fab3ad6faec w78+ s80 = step512 s79 0x6c44198c4a475817 w79+ SHA512S a80 b80 c80 d80 e80 f80 g80 h80 = s80+ in SHA512S (a00 + a80) (b00 + b80) (c00 + c80) (d00 + d80)+ (e00 + e80) (f00 + f80) (g00 + g80) (h00 + h80)++{-# INLINE step512 #-}+step512 :: SHA512State -> Word64 -> Word64 -> SHA512State+step512 !(SHA512S a b c d e f g h) k w = SHA512S a' b' c' d' e' f' g' h'+ where+ t1 = h + bsig512_1 e + ch e f g + k + w+ t2 = bsig512_0 a + maj a b c+ h' = g+ g' = f+ f' = e+ e' = d + t1+ d' = c+ c' = b+ b' = a+ a' = t1 + t2
src/Cryptol/Symbolic.hs view
@@ -9,6 +9,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ImplicitParams #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -28,19 +29,38 @@ , finType , unFinType , predArgTypes+ -- * VarShape+ , VarShape(..)+ , varShapeToValue+ , freshVar+ , computeModel+ , FreshVarFns(..)+ , modelPred+ , varModelPred+ , varToExpr ) where +import Control.Monad (foldM) import Data.IORef(IORef)+import Data.List (genericReplicate)+import Data.Ratio+import qualified LibBF as FP +import Cryptol.Backend+import Cryptol.Backend.FloatHelpers(bfValue)+ import qualified Cryptol.Eval.Concrete as Concrete+import Cryptol.Eval.Value import Cryptol.TypeCheck.AST import Cryptol.Eval.Type (TValue(..), evalType)-import Cryptol.Utils.Ident (Ident)+import Cryptol.Utils.Ident (Ident,prelPrim,floatPrim) import Cryptol.Utils.RecordMap+import Cryptol.Utils.Panic import Cryptol.Utils.PP + import Prelude () import Prelude.Compat import Data.Time (NominalDiffTime)@@ -155,3 +175,193 @@ FTSeq l ety -> tSeq (tNum l) (unFinType ety) FTTuple ftys -> tTuple (unFinType <$> ftys) FTRecord fs -> tRec (unFinType <$> fs)+++data VarShape sym+ = VarBit (SBit sym)+ | VarInteger (SInteger sym)+ | VarRational (SInteger sym) (SInteger sym)+ | VarFloat (SFloat sym)+ | VarWord (SWord sym)+ | VarFinSeq Integer [VarShape sym]+ | VarTuple [VarShape sym]+ | VarRecord (RecordMap Ident (VarShape sym))++ppVarShape :: Backend sym => sym -> VarShape sym -> Doc+ppVarShape sym (VarBit b) = ppBit sym b+ppVarShape sym (VarInteger i) = ppInteger sym defaultPPOpts i+ppVarShape sym (VarFloat f) = ppFloat sym defaultPPOpts f+ppVarShape sym (VarRational n d) =+ text "(ratio" <+> ppInteger sym defaultPPOpts n <+> ppInteger sym defaultPPOpts d <+> text ")"+ppVarShape sym (VarWord w) = ppWord sym defaultPPOpts w+ppVarShape sym (VarFinSeq _ xs) =+ brackets (fsep (punctuate comma (map (ppVarShape sym) xs)))+ppVarShape sym (VarTuple xs) =+ parens (sep (punctuate comma (map (ppVarShape sym) xs)))+ppVarShape sym (VarRecord fs) =+ braces (sep (punctuate comma (map ppField (displayFields fs))))+ where+ ppField (f,v) = pp f <+> char '=' <+> ppVarShape sym v+++varShapeToValue :: Backend sym => sym -> VarShape sym -> GenValue sym+varShapeToValue sym var =+ case var of+ VarBit b -> VBit b+ VarInteger i -> VInteger i+ VarRational n d -> VRational (SRational n d)+ VarWord w -> VWord (wordLen sym w) (return (WordVal w))+ VarFloat f -> VFloat f+ VarFinSeq n vs -> VSeq n (finiteSeqMap sym (map (pure . varShapeToValue sym) vs))+ VarTuple vs -> VTuple (map (pure . varShapeToValue sym) vs)+ VarRecord fs -> VRecord (fmap (pure . varShapeToValue sym) fs)++data FreshVarFns sym =+ FreshVarFns+ { freshBitVar :: IO (SBit sym)+ , freshWordVar :: Integer -> IO (SWord sym)+ , freshIntegerVar :: Maybe Integer -> Maybe Integer -> IO (SInteger sym)+ , freshFloatVar :: Integer -> Integer -> IO (SFloat sym)+ }++freshVar :: Backend sym => FreshVarFns sym -> FinType -> IO (VarShape sym)+freshVar fns tp = case tp of+ FTBit -> VarBit <$> freshBitVar fns+ FTInteger -> VarInteger <$> freshIntegerVar fns Nothing Nothing+ FTRational -> VarRational+ <$> freshIntegerVar fns Nothing Nothing+ <*> freshIntegerVar fns (Just 1) Nothing+ FTIntMod 0 -> panic "freshVariable" ["0 modulus not allowed"]+ FTIntMod m -> VarInteger <$> freshIntegerVar fns (Just 0) (Just (m-1))+ FTFloat e p -> VarFloat <$> freshFloatVar fns e p+ FTSeq n FTBit | n > 0 -> VarWord <$> freshWordVar fns (toInteger n)+ FTSeq n t -> VarFinSeq (toInteger n) <$> sequence (genericReplicate n (freshVar fns t))+ FTTuple ts -> VarTuple <$> mapM (freshVar fns) ts+ FTRecord fs -> VarRecord <$> traverse (freshVar fns) fs++computeModel ::+ PrimMap ->+ [FinType] ->+ [VarShape Concrete.Concrete] ->+ [(Type, Expr, Concrete.Value)]+computeModel _ [] [] = []+computeModel primMap (t:ts) (v:vs) =+ do let v' = varShapeToValue Concrete.Concrete v+ let t' = unFinType t+ let e = varToExpr primMap t v+ let zs = computeModel primMap ts vs+ in ((t',e,v'):zs)+computeModel _ _ _ = panic "computeModel" ["type/value list mismatch"]++++modelPred ::+ Backend sym =>+ sym ->+ [VarShape sym] ->+ [VarShape Concrete.Concrete] ->+ SEval sym (SBit sym)+modelPred sym vs xs =+ do ps <- mapM (varModelPred sym) (zip vs xs)+ foldM (bitAnd sym) (bitLit sym True) ps++varModelPred ::+ Backend sym =>+ sym ->+ (VarShape sym, VarShape Concrete.Concrete) ->+ SEval sym (SBit sym)+varModelPred sym vx =+ case vx of+ (VarBit b, VarBit blit) ->+ bitEq sym b (bitLit sym blit)++ (VarInteger i, VarInteger ilit) ->+ intEq sym i =<< integerLit sym ilit++ (VarRational n d, VarRational nlit dlit) ->+ do n' <- integerLit sym nlit+ d' <- integerLit sym dlit+ rationalEq sym (SRational n d) (SRational n' d')++ (VarWord w, VarWord (Concrete.BV len wlit)) ->+ wordEq sym w =<< wordLit sym len wlit++ (VarFloat f, VarFloat flit) ->+ fpLogicalEq sym f =<< fpExactLit sym flit++ (VarFinSeq _n vs, VarFinSeq _ xs) -> modelPred sym vs xs+ (VarTuple vs, VarTuple xs) -> modelPred sym vs xs+ (VarRecord vs, VarRecord xs) -> modelPred sym (recordElements vs) (recordElements xs)+ _ -> panic "varModelPred" ["variable shape mismatch!"]+++varToExpr :: PrimMap -> FinType -> VarShape Concrete.Concrete -> Expr+varToExpr prims = go+ where++ prim n = ePrim prims (prelPrim n)++ go :: FinType -> VarShape Concrete.Concrete -> Expr+ go ty val =+ case (ty,val) of+ (FTRecord tfs, VarRecord vfs) ->+ let res = zipRecords (\_lbl v t -> go t v) vfs tfs+ in case res of+ Left _ -> mismatch -- different fields+ Right efs -> ERec efs+ (FTTuple ts, VarTuple tvs) ->+ ETuple (zipWith go ts tvs)++ (FTBit, VarBit b) ->+ prim (if b then "True" else "False")++ (FTInteger, VarInteger i) ->+ -- This works uniformly for values of type Integer or Z n+ ETApp (ETApp (prim "number") (tNum i)) (unFinType ty)++ (FTIntMod _, VarInteger i) ->+ -- This works uniformly for values of type Integer or Z n+ ETApp (ETApp (prim "number") (tNum i)) (unFinType ty)++ (FTRational, VarRational n d) ->+ let n' = ETApp (ETApp (prim "number") (tNum n)) tInteger+ d' = ETApp (ETApp (prim "number") (tNum d)) tInteger+ in EApp (EApp (prim "ratio") n') d'++ (FTFloat e p, VarFloat f) ->+ floatToExpr prims e p (bfValue f)++ (FTSeq _ FTBit, VarWord (Concrete.BV _ v)) ->+ ETApp (ETApp (prim "number") (tNum v)) (unFinType ty)++ (FTSeq _ t, VarFinSeq _ svs) ->+ EList (map (go t) svs) (unFinType t)++ _ -> mismatch+ where+ mismatch =+ panic "Cryptol.Symbolic.varToExpr"+ ["type mismatch:"+ , show (pp (unFinType ty))+ , show (ppVarShape Concrete.Concrete val)+ ]++floatToExpr :: PrimMap -> Integer -> Integer -> FP.BigFloat -> Expr+floatToExpr prims e p f =+ case FP.bfToRep f of+ FP.BFNaN -> mkP "fpNaN"+ FP.BFRep sign num ->+ case (sign,num) of+ (FP.Pos, FP.Zero) -> mkP "fpPosZero"+ (FP.Neg, FP.Zero) -> mkP "fpNegZero"+ (FP.Pos, FP.Inf) -> mkP "fpPosInf"+ (FP.Neg, FP.Inf) -> mkP "fpNegInf"+ (_, FP.Num m ex) ->+ let r = toRational m * (2 ^^ ex)+ in EProofApp $ ePrim prims (prelPrim "fraction")+ `ETApp` tNum (numerator r)+ `ETApp` tNum (denominator r)+ `ETApp` tNum (0 :: Int)+ `ETApp` tFloat (tNum e) (tNum p)+ where+ mkP n = EProofApp $ ePrim prims (floatPrim n) `ETApp` (tNum e) `ETApp` (tNum p)
src/Cryptol/Symbolic/SBV.hs view
@@ -27,18 +27,19 @@ ) where +import Control.Applicative import Control.Concurrent.Async+import Control.Concurrent.MVar import Control.Monad.IO.Class-import Control.Monad (replicateM, when, zipWithM, foldM, forM_)-import Control.Monad.Writer (WriterT, runWriterT, tell, lift)-import Data.List (genericLength)+import Control.Monad (when, foldM, forM_) import Data.Maybe (fromMaybe)+import qualified Data.Map as Map import qualified Control.Exception as X import System.Exit (ExitCode(ExitSuccess)) import LibBF(bfNaN) -import qualified Data.SBV as SBV (sObserve)+import qualified Data.SBV as SBV (sObserve, symbolicEnv) import qualified Data.SBV.Internals as SBV (SBV(..)) import qualified Data.SBV.Dynamic as SBV import Data.SBV (Timing(SaveTiming))@@ -47,29 +48,29 @@ import qualified Cryptol.ModuleSystem.Env as M import qualified Cryptol.ModuleSystem.Base as M import qualified Cryptol.ModuleSystem.Monad as M+import qualified Cryptol.ModuleSystem.Name as M -import qualified Cryptol.Eval.Backend as Eval+import Cryptol.Backend.SBV+import qualified Cryptol.Backend.FloatHelpers as FH+ import qualified Cryptol.Eval as Eval import qualified Cryptol.Eval.Concrete as Concrete-import Cryptol.Eval.Concrete (Concrete(..))-import qualified Cryptol.Eval.Concrete.FloatHelpers as Concrete-import qualified Cryptol.Eval.Monad as Eval import qualified Cryptol.Eval.Value as Eval import Cryptol.Eval.SBV import Cryptol.Symbolic+import Cryptol.TypeCheck.AST+import Cryptol.Utils.Ident (preludeReferenceName, prelPrim, identText) import Cryptol.Utils.Panic(panic) import Cryptol.Utils.Logger(logPutStrLn) import Cryptol.Utils.RecordMap + import Prelude () import Prelude.Compat -doEval :: MonadIO m => Eval.EvalOpts -> Eval.Eval a -> m a-doEval evo m = liftIO $ Eval.runEval evo m--doSBVEval :: MonadIO m => Eval.EvalOpts -> SBVEval a -> m (SBV.SVal, a)-doSBVEval evo m =- (liftIO $ Eval.runEval evo (sbvEval m)) >>= \case+doSBVEval :: MonadIO m => SBVEval a -> m (SBV.SVal, a)+doSBVEval m =+ (liftIO $ Eval.runEval (sbvEval m)) >>= \case SBVError err -> liftIO (X.throwIO err) SBVResult p x -> pure (p, x) @@ -222,7 +223,12 @@ -- | Select the appropriate solver or solvers from the given prover command, -- and invoke those solvers on the given symbolic value.-runProver :: SBVProverConfig -> ProverCommand -> (String -> IO ()) -> SBV.Symbolic SBV.SVal -> IO (Maybe String, [SBV.SMTResult])+runProver ::+ SBVProverConfig ->+ ProverCommand ->+ (String -> IO ()) ->+ SBV.Symbolic SBV.SVal ->+ IO (Maybe String, [SBV.SMTResult]) runProver proverConfig pc@ProverCommand{..} lPutStrLn x = do let mSatNum = case pcQueryType of SatQuery (SomeSat n) -> Just n@@ -231,7 +237,7 @@ SafetyQuery -> Nothing case proverConfig of- SBVPortfolio ps -> + SBVPortfolio ps -> let ps' = [ p { SBV.transcript = pcSmtFile , SBV.timing = SaveTiming pcProverStats , SBV.verbose = pcVerbose@@ -279,18 +285,17 @@ -- the main goal via a conjunction. prepareQuery :: Eval.EvalOpts ->- M.ModuleEnv -> ProverCommand ->- IO (Either String ([FinType], SBV.Symbolic SBV.SVal))-prepareQuery evo modEnv ProverCommand{..} =- do let extDgs = M.allDeclGroups modEnv ++ pcExtraDecls+ M.ModuleT IO (Either String ([FinType], SBV.Symbolic SBV.SVal))+prepareQuery evo ProverCommand{..} =+ do ds <- do (_mp, m) <- M.loadModuleFrom True (M.FromModule preludeReferenceName)+ let decls = mDecls m+ let nms = fst <$> Map.toList (M.ifDecls (M.ifPublic (M.genIface m)))+ let ds = Map.fromList [ (prelPrim (identText (M.nameIdent nm)), EWhere (EVar nm) decls) | nm <- nms ]+ pure ds - -- The `tyFn` creates variables that are treated as 'forall'- -- or 'exists' bound, depending on the sort of query we are doing.- let tyFn = case pcQueryType of- SatQuery _ -> existsFinType- ProveQuery -> forallFinType- SafetyQuery -> forallFinType+ modEnv <- M.getModuleEnv+ let extDgs = M.allDeclGroups modEnv ++ pcExtraDecls -- The `addAsm` function is used to combine assumptions that -- arise from the types of symbolic variables (e.g. Z n values@@ -302,22 +307,29 @@ SafetyQuery -> \x y -> SBV.svOr (SBV.svNot x) y SatQuery _ -> \x y -> SBV.svAnd x y - let ?evalPrim = evalPrim case predArgTypes pcQueryType pcSchema of Left msg -> return (Left msg)- Right ts ->+ Right ts -> M.io $ do when pcVerbose $ logPutStrLn (Eval.evalLogger evo) "Simulating..." pure $ Right $ (ts,- do -- Compute the symbolic inputs, and any domain constraints needed+ do sbvState <- SBV.symbolicEnv+ stateMVar <- liftIO (newMVar sbvState)+ defRelsVar <- liftIO (newMVar SBV.svTrue)+ let sym = SBV stateMVar defRelsVar+ let tbl = primTable sym+ let ?evalPrim = \i -> (Right <$> Map.lookup i tbl) <|>+ (Left <$> Map.lookup i ds)+ -- Compute the symbolic inputs, and any domain constraints needed -- according to their types.- (args, asms) <- runWriterT (mapM tyFn ts)+ args <- map (pure . varShapeToValue sym) <$>+ liftIO (mapM (freshVar (sbvFreshFns sym)) ts) -- Run the main symbolic computation. First we populate the -- evaluation environment, then we compute the value, finally -- we apply it to the symbolic inputs.- (safety,b) <- doSBVEval evo $- do env <- Eval.evalDecls SBV extDgs mempty- v <- Eval.evalExpr SBV env pcExpr- appliedVal <- foldM Eval.fromVFun v (map pure args)+ (safety,b) <- doSBVEval $+ do env <- Eval.evalDecls sym extDgs mempty+ v <- Eval.evalExpr sym env pcExpr+ appliedVal <- foldM Eval.fromVFun v args case pcQueryType of SafetyQuery -> do Eval.forceValue appliedVal@@ -335,18 +347,19 @@ -- avaliable in the resulting model. SBV.sObserve "safety" (SBV.SBV safety' :: SBV.SBV Bool) - return (foldr addAsm (SBV.svAnd safety' b) asms))+ -- read any definitional relations that were asserted+ defRels <- liftIO (readMVar defRelsVar) + return (addAsm defRels (SBV.svAnd safety' b))) -- | Turn the SMT results from SBV into a @ProverResult@ that is ready for the Cryptol REPL. -- There may be more than one result if we made a multi-sat query. processResults ::- Eval.EvalOpts -> ProverCommand -> [FinType] {- ^ Types of the symbolic inputs -} -> [SBV.SMTResult] {- ^ Results from the solver -} -> M.ModuleT IO ProverResult-processResults evo ProverCommand{..} ts results =+processResults ProverCommand{..} ts results = do let isSat = case pcQueryType of ProveQuery -> False SafetyQuery -> False@@ -385,15 +398,9 @@ -- to always be the first value in the model assignment list. let Right (_, (safetyCV : cvs)) = SBV.getModelAssignment result safety = SBV.cvToBool safetyCV- (vs, _) = parseValues ts cvs- sattys = unFinType <$> ts- satexprs <-- doEval evo (zipWithM (Concrete.toExpr prims) sattys vs)- case zip3 sattys <$> (sequence satexprs) <*> pure vs of- Nothing ->- panic "Cryptol.Symbolic.sat"- [ "unable to make assignment into expression" ]- Just tevs -> return $ (safety, tevs)+ (vs, []) = parseValues ts cvs+ mdl = computeModel prims ts vs+ return (safety, mdl) -- | Execute a symbolic ':prove' or ':sat' command.@@ -409,11 +416,11 @@ let lPutStrLn = logPutStrLn (Eval.evalLogger evo) - M.io (prepareQuery evo modEnv pc) >>= \case+ prepareQuery evo pc >>= \case Left msg -> return (Nothing, ProverError msg) Right (ts, q) -> do (firstProver, results) <- M.io (runProver proverCfg pc lPutStrLn q)- esatexprs <- processResults evo pc ts results+ esatexprs <- processResults pc ts results return (firstProver, esatexprs) -- | Execute a symbolic ':prove' or ':sat' command when the prover is@@ -425,18 +432,15 @@ satProveOffline :: SBVProverConfig -> ProverCommand -> M.ModuleCmd (Either String String) satProveOffline _proverCfg pc@ProverCommand {..} = protectStack (\msg (_,_,modEnv) -> return (Right (Left msg, modEnv), [])) $- \(evOpts, _, modEnv) -> do- let isSat = case pcQueryType of- ProveQuery -> False- SafetyQuery -> False- SatQuery _ -> True-- prepareQuery evOpts modEnv pc >>= \case- Left msg -> return (Right (Left msg, modEnv), [])- Right (_ts, q) ->- do smtlib <- SBV.generateSMTBenchmark isSat q- return (Right (Right smtlib, modEnv), [])+ \(evo, byteReader, modEnv) -> M.runModuleM (evo,byteReader,modEnv) $+ do let isSat = case pcQueryType of+ ProveQuery -> False+ SafetyQuery -> False+ SatQuery _ -> True + prepareQuery evo pc >>= \case+ Left msg -> return (Left msg)+ Right (_ts, q) -> Right <$> M.io (SBV.generateSMTBenchmark isSat q) protectStack :: (String -> M.ModuleCmd a) -> M.ModuleCmd a@@ -451,7 +455,7 @@ -- | Given concrete values from the solver and a collection of finite types, -- reconstruct Cryptol concrete values, and return any unused solver -- values.-parseValues :: [FinType] -> [SBV.CV] -> ([Concrete.Value], [SBV.CV])+parseValues :: [FinType] -> [SBV.CV] -> ([VarShape Concrete.Concrete], [SBV.CV]) parseValues [] cvs = ([], cvs) parseValues (t : ts) cvs = (v : vs, cvs'') where (v, cvs') = parseValue t cvs@@ -460,94 +464,60 @@ -- | Parse a single value of a finite type by consuming some number of -- solver values. The parsed Cryptol values is returned along with -- any solver values not consumed.-parseValue :: FinType -> [SBV.CV] -> (Concrete.Value, [SBV.CV])+parseValue :: FinType -> [SBV.CV] -> (VarShape Concrete.Concrete, [SBV.CV]) parseValue FTBit [] = panic "Cryptol.Symbolic.parseValue" [ "empty FTBit" ]-parseValue FTBit (cv : cvs) = (Eval.VBit (SBV.cvToBool cv), cvs)+parseValue FTBit (cv : cvs) = (VarBit (SBV.cvToBool cv), cvs) parseValue FTInteger cvs = case SBV.genParse SBV.KUnbounded cvs of- Just (x, cvs') -> (Eval.VInteger x, cvs')+ Just (x, cvs') -> (VarInteger x, cvs') Nothing -> panic "Cryptol.Symbolic.parseValue" [ "no integer" ] parseValue (FTIntMod _) cvs = parseValue FTInteger cvs parseValue FTRational cvs = fromMaybe (panic "Cryptol.Symbolic.parseValue" ["no rational"]) $ do (n,cvs') <- SBV.genParse SBV.KUnbounded cvs (d,cvs'') <- SBV.genParse SBV.KUnbounded cvs'- return (Eval.VRational (Eval.SRational n d), cvs'')-parseValue (FTSeq 0 FTBit) cvs = (Eval.word Concrete 0 0, cvs)+ return (VarRational n d, cvs'')+parseValue (FTSeq 0 FTBit) cvs = (VarWord (Concrete.mkBv 0 0), cvs) parseValue (FTSeq n FTBit) cvs = case SBV.genParse (SBV.KBounded False n) cvs of- Just (x, cvs') -> (Eval.word Concrete (toInteger n) x, cvs')- Nothing -> (Eval.VWord (genericLength vs) (Eval.WordVal <$>- (Eval.packWord Concrete (map Eval.fromVBit vs))), cvs')- where (vs, cvs') = parseValues (replicate n FTBit) cvs-parseValue (FTSeq n t) cvs =- (Eval.VSeq (toInteger n) $ Eval.finiteSeqMap Concrete (map Eval.ready vs)- , cvs'- )+ Just (x, cvs') -> (VarWord (Concrete.mkBv (toInteger n) x), cvs')+ Nothing -> panic "Cryptol.Symbolic.parseValue" ["no bitvector"]+parseValue (FTSeq n t) cvs = (VarFinSeq (toInteger n) vs, cvs') where (vs, cvs') = parseValues (replicate n t) cvs-parseValue (FTTuple ts) cvs = (Eval.VTuple (map Eval.ready vs), cvs')+parseValue (FTTuple ts) cvs = (VarTuple vs, cvs') where (vs, cvs') = parseValues ts cvs-parseValue (FTRecord r) cvs = (Eval.VRecord r', cvs')+parseValue (FTRecord r) cvs = (VarRecord r', cvs') where (ns, ts) = unzip $ canonicalFields r (vs, cvs') = parseValues ts cvs- fs = zip ns (map Eval.ready vs)+ fs = zip ns vs r' = recordFromFieldsWithDisplay (displayOrder r) fs parseValue (FTFloat e p) cvs =- (Eval.VFloat Concrete.BF { Concrete.bfValue = bfNaN- , Concrete.bfExpWidth = e- , Concrete.bfPrecWidth = p- }+ (VarFloat FH.BF { FH.bfValue = bfNaN+ , FH.bfExpWidth = e+ , FH.bfPrecWidth = p+ } , cvs ) -- XXX: NOT IMPLEMENTED -inBoundsIntMod :: Integer -> Eval.SInteger SBV -> Eval.SBit SBV-inBoundsIntMod n x =- let z = SBV.svInteger SBV.KUnbounded 0- n' = SBV.svInteger SBV.KUnbounded n- in SBV.svAnd (SBV.svLessEq z x) (SBV.svLessThan x n') -forallFinType :: FinType -> WriterT [Eval.SBit SBV] SBV.Symbolic Value-forallFinType ty =- case ty of- FTBit -> Eval.VBit <$> lift forallSBool_- FTInteger -> Eval.VInteger <$> lift forallSInteger_- FTRational ->- do n <- lift forallSInteger_- d <- lift forallSInteger_- let z = SBV.svInteger SBV.KUnbounded 0- tell [SBV.svLessThan z d]- return (Eval.VRational (Eval.SRational n d))- FTFloat {} -> pure (Eval.VFloat ()) -- XXX: NOT IMPLEMENTED- FTIntMod n -> do x <- lift forallSInteger_- tell [inBoundsIntMod n x]- return (Eval.VInteger x)- FTSeq 0 FTBit -> return $ Eval.word SBV 0 0- FTSeq n FTBit -> Eval.VWord (toInteger n) . return . Eval.WordVal <$> lift (forallBV_ n)- FTSeq n t -> do vs <- replicateM n (forallFinType t)- return $ Eval.VSeq (toInteger n) $ Eval.finiteSeqMap SBV (map pure vs)- FTTuple ts -> Eval.VTuple <$> mapM (fmap pure . forallFinType) ts- FTRecord fs -> Eval.VRecord <$> traverse (fmap pure . forallFinType) fs+freshBoundedInt :: SBV -> Maybe Integer -> Maybe Integer -> IO SBV.SVal+freshBoundedInt sym lo hi =+ do x <- freshSInteger_ sym+ case lo of+ Just l -> addDefEqn sym (SBV.svLessEq (SBV.svInteger SBV.KUnbounded l) x)+ Nothing -> pure ()+ case hi of+ Just h -> addDefEqn sym (SBV.svLessEq x (SBV.svInteger SBV.KUnbounded h))+ Nothing -> pure ()+ return x -existsFinType :: FinType -> WriterT [Eval.SBit SBV] SBV.Symbolic Value-existsFinType ty =- case ty of- FTBit -> Eval.VBit <$> lift existsSBool_- FTInteger -> Eval.VInteger <$> lift existsSInteger_- FTRational ->- do n <- lift existsSInteger_- d <- lift existsSInteger_- let z = SBV.svInteger SBV.KUnbounded 0- tell [SBV.svLessThan z d]- return (Eval.VRational (Eval.SRational n d))- FTFloat {} -> pure $ Eval.VFloat () -- XXX: NOT IMPLEMENTED- FTIntMod n -> do x <- lift existsSInteger_- tell [inBoundsIntMod n x]- return (Eval.VInteger x)- FTSeq 0 FTBit -> return $ Eval.word SBV 0 0- FTSeq n FTBit -> Eval.VWord (toInteger n) . return . Eval.WordVal <$> lift (existsBV_ n)- FTSeq n t -> do vs <- replicateM n (existsFinType t)- return $ Eval.VSeq (toInteger n) $ Eval.finiteSeqMap SBV (map pure vs)- FTTuple ts -> Eval.VTuple <$> mapM (fmap pure . existsFinType) ts- FTRecord fs -> Eval.VRecord <$> traverse (fmap pure . existsFinType) fs+sbvFreshFns :: SBV -> FreshVarFns SBV+sbvFreshFns sym =+ FreshVarFns+ { freshBitVar = freshSBool_ sym+ , freshWordVar = freshBV_ sym . fromInteger+ , freshIntegerVar = freshBoundedInt sym+ , freshFloatVar = \_ _ -> return () -- TODO+ }
src/Cryptol/Symbolic/What4.hs view
@@ -29,14 +29,22 @@ , W4Exception(..) ) where +import Control.Applicative import Control.Concurrent.Async+import Control.Concurrent.MVar import Control.Monad.IO.Class import Control.Monad (when, foldM, forM_) import qualified Control.Exception as X import System.IO (Handle) import Data.Time import Data.IORef+import Data.List (intercalate) import Data.List.NonEmpty (NonEmpty(..))+import qualified Data.Map as Map+import Data.Set (Set)+import qualified Data.Set as Set+import Data.Text (Text)+import qualified Data.Text as Text import qualified Data.List.NonEmpty as NE import System.Exit @@ -44,21 +52,20 @@ import qualified Cryptol.ModuleSystem.Env as M import qualified Cryptol.ModuleSystem.Base as M import qualified Cryptol.ModuleSystem.Monad as M+import qualified Cryptol.ModuleSystem.Name as M +import qualified Cryptol.Backend.FloatHelpers as FH+import Cryptol.Backend.What4+import qualified Cryptol.Backend.What4.SFloat as W4+ import qualified Cryptol.Eval as Eval import qualified Cryptol.Eval.Concrete as Concrete-import qualified Cryptol.Eval.Concrete.FloatHelpers as Concrete--import qualified Cryptol.Eval.Backend as Eval import qualified Cryptol.Eval.Value as Eval import Cryptol.Eval.What4-import qualified Cryptol.Eval.What4.SFloat as W4 import Cryptol.Symbolic import Cryptol.TypeCheck.AST-import Cryptol.Utils.Ident (Ident)-import Cryptol.Utils.Logger(logPutStrLn)-import Cryptol.Utils.Panic (panic)-import Cryptol.Utils.RecordMap+import Cryptol.Utils.Logger(logPutStrLn,logPutStr,Logger)+import Cryptol.Utils.Ident (preludeReferenceName, prelPrim, identText) import qualified What4.Config as W4 import qualified What4.Interface as W4@@ -111,18 +118,15 @@ handler () = mkErr msg modEnv -doEval :: MonadIO m => Eval.EvalOpts -> Eval.Eval a -> m a-doEval evo m = liftIO $ Eval.runEval evo m- -- | Returns definitions, together with the value and it safety predicate. doW4Eval :: (W4.IsExprBuilder sym, MonadIO m) =>- sym -> Eval.EvalOpts -> W4Eval sym a -> m (W4Defs sym (W4.Pred sym, a))-doW4Eval sym evo m =- do res <- liftIO $ Eval.runEval evo (w4Eval m sym)- case w4Result res of+ sym -> W4Eval sym a -> m (W4.Pred sym, a)+doW4Eval sym m =+ do res <- liftIO $ Eval.runEval (w4Eval m sym)+ case res of W4Error err -> liftIO (X.throwIO err)- W4Result p x -> pure res { w4Result = (p,x) }+ W4Result p x -> pure (p,x) data AnAdapter = AnAdapter (forall st. SolverAdapter st)@@ -201,11 +205,6 @@ data CryptolState t = CryptolState ---- TODO? move this?-allDeclGroups :: M.ModuleEnv -> [DeclGroup]-allDeclGroups = concatMap mDecls . M.loadedNonParamModules- setupAdapterOptions :: W4ProverConfig -> W4.ExprBuilder t CryptolState fs -> IO () setupAdapterOptions cfg sym = case cfg of@@ -217,94 +216,118 @@ W4.extendConfig (W4.solver_adapter_config_options adpt) (W4.getConfiguration sym) +what4FreshFns :: W4.IsSymExprBuilder sym => sym -> FreshVarFns (What4 sym)+what4FreshFns sym =+ FreshVarFns+ { freshBitVar = W4.freshConstant sym W4.emptySymbol W4.BaseBoolRepr+ , freshWordVar = SW.freshBV sym W4.emptySymbol+ , freshIntegerVar = W4.freshBoundedInt sym W4.emptySymbol+ , freshFloatVar = W4.fpFresh sym+ }+ -- | Simulate and manipulate query into a form suitable to be sent -- to a solver. prepareQuery :: W4.IsSymExprBuilder sym =>- sym ->+ What4 sym -> ProverCommand -> M.ModuleT IO (Either String- ([FinType],[VarShape sym],W4.Pred sym, W4.Pred sym)+ ([FinType],[VarShape (What4 sym)],W4.Pred sym, W4.Pred sym) ) prepareQuery sym ProverCommand { .. } = case predArgTypes pcQueryType pcSchema of Left msg -> pure (Left msg) Right ts ->- do args <- liftIO (mapM (freshVariable sym) ts)- res <- simulate args+ do args <- liftIO (mapM (freshVar (what4FreshFns (w4 sym))) ts)+ (safety,b) <- simulate args liftIO- do -- add the collected definitions to the goal- let (safety,prop') = w4Result res- b <- W4.andPred sym (w4Defs res) prop'+ do -- Ignore the safety condition if the flag is set+ let safety' = if pcIgnoreSafety then W4.truePred (w4 sym) else safety - -- Ignore the safety condition if the flag is set- let safety' = if pcIgnoreSafety then W4.truePred sym else safety+ defs <- readMVar (w4defs sym) Right <$> case pcQueryType of ProveQuery ->- do q <- W4.notPred sym =<< W4.andPred sym safety' b- pure (ts,args,safety',q)+ do q <- W4.notPred (w4 sym) =<< W4.andPred (w4 sym) safety' b+ q' <- W4.andPred (w4 sym) defs q+ pure (ts,args,safety',q') SafetyQuery ->- do q <- W4.notPred sym safety- pure (ts,args,safety,q)+ do q <- W4.notPred (w4 sym) safety+ q' <- W4.andPred (w4 sym) defs q+ pure (ts,args,safety,q') SatQuery _ ->- do q <- W4.andPred sym safety' b- pure (ts,args,safety',q)+ do q <- W4.andPred (w4 sym) safety' b+ q' <- W4.andPred (w4 sym) defs q+ pure (ts,args,safety',q') where simulate args = do let lPutStrLn = M.withLogger logPutStrLn when pcVerbose (lPutStrLn "Simulating...")- evo <- M.getEvalOpts++ ds <- do (_mp, m) <- M.loadModuleFrom True (M.FromModule preludeReferenceName)+ let decls = mDecls m+ let nms = fst <$> Map.toList (M.ifDecls (M.ifPublic (M.genIface m)))+ let ds = Map.fromList [ (prelPrim (identText (M.nameIdent nm)), EWhere (EVar nm) decls) | nm <- nms ]+ pure ds++ let tbl = primTable sym+ let ?evalPrim = \i -> (Right <$> Map.lookup i tbl) <|>+ (Left <$> Map.lookup i ds)+ modEnv <- M.getModuleEnv- doW4Eval sym evo- do let ?evalPrim = evalPrim sym- let extDgs = allDeclGroups modEnv ++ pcExtraDecls- env <- Eval.evalDecls (What4 sym) extDgs mempty- v <- Eval.evalExpr (What4 sym) env pcExpr+ let extDgs = M.allDeclGroups modEnv ++ pcExtraDecls++ doW4Eval (w4 sym)+ do env <- Eval.evalDecls sym extDgs mempty+ v <- Eval.evalExpr sym env pcExpr appliedVal <-- foldM Eval.fromVFun v (map (pure . varToSymValue sym) args)+ foldM Eval.fromVFun v (map (pure . varShapeToValue sym) args) case pcQueryType of SafetyQuery -> do Eval.forceValue appliedVal- pure (W4.truePred sym)+ pure (W4.truePred (w4 sym)) _ -> pure (Eval.fromVBit appliedVal) --- satProve :: W4ProverConfig ->- Bool ->+ Bool {- ^ hash consing -} ->+ Bool {- ^ warn on uninterpreted functions -} -> ProverCommand -> M.ModuleCmd (Maybe String, ProverResult) -satProve solverCfg hashConsing ProverCommand {..} =+satProve solverCfg hashConsing warnUninterp ProverCommand {..} = protectStack proverError \(evo, byteReader, modEnv) -> M.runModuleM (evo, byteReader, modEnv)- do sym <- liftIO makeSym+ do w4sym <- liftIO makeSym+ defVar <- liftIO (newMVar (W4.truePred w4sym))+ funVar <- liftIO (newMVar mempty)+ uninterpWarnVar <- liftIO (newMVar mempty)+ let sym = What4 w4sym defVar funVar uninterpWarnVar logData <- M.withLogger doLog () start <- liftIO getCurrentTime query <- prepareQuery sym ProverCommand { .. } primMap <- M.getPrimMap+ when warnUninterp+ (M.withLogger printUninterpWarn =<< liftIO (readMVar uninterpWarnVar)) liftIO- do result <- runProver sym evo logData primMap query+ do result <- runProver sym logData primMap query end <- getCurrentTime writeIORef pcProverStats (diffUTCTime end start) return result where makeSym =- do sym <- W4.newExprBuilder W4.FloatIEEERepr- CryptolState- globalNonceGenerator- setupAdapterOptions solverCfg sym- when hashConsing (W4.startCaching sym)- pure sym+ do w4sym <- W4.newExprBuilder W4.FloatIEEERepr+ CryptolState+ globalNonceGenerator+ setupAdapterOptions solverCfg w4sym+ when hashConsing (W4.startCaching w4sym)+ pure w4sym doLog lg () = pure@@ -313,46 +336,60 @@ , logReason = "solver query" } - runProver sym evo logData primMap q =+ runProver sym logData primMap q = case q of Left msg -> pure (Nothing, ProverError msg) Right (ts,args,safety,query) -> case pcQueryType of ProveQuery ->- singleQuery sym solverCfg evo primMap logData ts args+ singleQuery sym solverCfg primMap logData ts args (Just safety) query SafetyQuery ->- singleQuery sym solverCfg evo primMap logData ts args+ singleQuery sym solverCfg primMap logData ts args (Just safety) query SatQuery num ->- multiSATQuery sym solverCfg evo primMap logData ts args+ multiSATQuery sym solverCfg primMap logData ts args query num -+printUninterpWarn :: Logger -> Set Text -> IO ()+printUninterpWarn lg uninterpWarns =+ case Set.toList uninterpWarns of+ [] -> pure ()+ [x] -> logPutStrLn lg ("[Warning] Uninterpreted functions used to represent " ++ Text.unpack x ++ " operations.")+ xs -> logPutStr lg $ unlines+ [ "[Warning] Uninterpreted functions used to represent the following operations:"+ , " " ++ intercalate ", " (map Text.unpack xs) ] satProveOffline :: W4ProverConfig ->- Bool ->+ Bool {- ^ hash consing -} ->+ Bool {- ^ warn on uninterpreted functions -} -> ProverCommand -> ((Handle -> IO ()) -> IO ()) -> M.ModuleCmd (Maybe String) -satProveOffline (W4Portfolio (p:|_)) hashConsing cmd outputContinuation =- satProveOffline (W4ProverConfig p) hashConsing cmd outputContinuation+satProveOffline (W4Portfolio (p:|_)) hashConsing warnUninterp cmd outputContinuation =+ satProveOffline (W4ProverConfig p) hashConsing warnUninterp cmd outputContinuation -satProveOffline (W4ProverConfig (AnAdapter adpt)) hashConsing ProverCommand {..} outputContinuation =+satProveOffline (W4ProverConfig (AnAdapter adpt)) hashConsing warnUninterp ProverCommand {..} outputContinuation = protectStack onError \(evo,byteReader,modEnv) -> M.runModuleM (evo,byteReader,modEnv)- do sym <- liftIO makeSym+ do w4sym <- liftIO makeSym+ defVar <- liftIO (newMVar (W4.truePred w4sym))+ funVar <- liftIO (newMVar mempty)+ uninterpWarnVar <- liftIO (newMVar mempty)+ let sym = What4 w4sym defVar funVar uninterpWarnVar ok <- prepareQuery sym ProverCommand { .. }+ when warnUninterp+ (M.withLogger printUninterpWarn =<< liftIO (readMVar uninterpWarnVar)) liftIO case ok of Left msg -> return (Just msg) Right (_ts,_args,_safety,query) -> do outputContinuation- (\hdl -> solver_adapter_write_smt2 adpt sym hdl [query])+ (\hdl -> solver_adapter_write_smt2 adpt w4sym hdl [query]) return Nothing where makeSym =@@ -373,30 +410,30 @@ multiSATQuery :: sym ~ W4.ExprBuilder t CryptolState fm =>- sym ->+ What4 sym -> W4ProverConfig ->- Eval.EvalOpts -> PrimMap -> W4.LogData -> [FinType] ->- [VarShape sym] ->+ [VarShape (What4 sym)] -> W4.Pred sym -> SatNum -> IO (Maybe String, ProverResult)-multiSATQuery sym solverCfg evo primMap logData ts args query (SomeSat n) | n <= 1 =- singleQuery sym solverCfg evo primMap logData ts args Nothing query+multiSATQuery sym solverCfg primMap logData ts args query (SomeSat n) | n <= 1 =+ singleQuery sym solverCfg primMap logData ts args Nothing query -multiSATQuery _sym (W4Portfolio _) _evo _primMap _logData _ts _args _query _satNum =+multiSATQuery _sym (W4Portfolio _) _primMap _logData _ts _args _query _satNum = fail "What4 portfolio solver cannot be used for multi SAT queries" -multiSATQuery sym (W4ProverConfig (AnAdapter adpt)) evo primMap logData ts args query satNum0 =- do pres <- W4.solver_adapter_check_sat adpt sym logData [query] $ \res ->+multiSATQuery sym (W4ProverConfig (AnAdapter adpt)) primMap logData ts args query satNum0 =+ do pres <- W4.solver_adapter_check_sat adpt (w4 sym) logData [query] $ \res -> case res of W4.Unknown -> return (Left (ProverError "Solver returned UNKNOWN")) W4.Unsat _ -> return (Left (ThmResult (map unFinType ts))) W4.Sat (evalFn,_) ->- do model <- computeModel evo primMap evalFn ts args- blockingPred <- computeBlockingPred sym evalFn args+ do xs <- mapM (varShapeToConcrete evalFn) args+ let model = computeModel primMap ts xs+ blockingPred <- computeBlockingPred sym args xs return (Right (model, blockingPred)) case pres of@@ -409,22 +446,24 @@ computeMoreModels _qs (SomeSat n) | n <= 0 = return [] -- should never happen... computeMoreModels qs (SomeSat n) | n <= 1 = -- final model- W4.solver_adapter_check_sat adpt sym logData qs $ \res ->+ W4.solver_adapter_check_sat adpt (w4 sym) logData qs $ \res -> case res of W4.Unknown -> return [] W4.Unsat _ -> return [] W4.Sat (evalFn,_) ->- do model <- computeModel evo primMap evalFn ts args+ do xs <- mapM (varShapeToConcrete evalFn) args+ let model = computeModel primMap ts xs return [model] computeMoreModels qs satNum =- do pres <- W4.solver_adapter_check_sat adpt sym logData qs $ \res ->+ do pres <- W4.solver_adapter_check_sat adpt (w4 sym) logData qs $ \res -> case res of W4.Unknown -> return Nothing W4.Unsat _ -> return Nothing W4.Sat (evalFn,_) ->- do model <- computeModel evo primMap evalFn ts args- blockingPred <- computeBlockingPred sym evalFn args+ do xs <- mapM (varShapeToConcrete evalFn) args+ let model = computeModel primMap ts xs+ blockingPred <- computeBlockingPred sym args xs return (Just (model, blockingPred)) case pres of@@ -434,19 +473,18 @@ singleQuery :: sym ~ W4.ExprBuilder t CryptolState fm =>- sym ->+ What4 sym -> W4ProverConfig ->- Eval.EvalOpts -> PrimMap -> W4.LogData -> [FinType] ->- [VarShape sym] ->+ [VarShape (What4 sym)] -> Maybe (W4.Pred sym) {- ^ optional safety predicate. Nothing = SAT query -} -> W4.Pred sym -> IO (Maybe String, ProverResult) -singleQuery sym (W4Portfolio ps) evo primMap logData ts args msafe query =- do as <- mapM async [ singleQuery sym (W4ProverConfig p) evo primMap logData ts args msafe query+singleQuery sym (W4Portfolio ps) primMap logData ts args msafe query =+ do as <- mapM async [ singleQuery sym (W4ProverConfig p) primMap logData ts args msafe query | p <- NE.toList ps ] waitForResults [] as@@ -465,13 +503,14 @@ do forM_ others (\a -> X.throwTo (asyncThreadId a) ExitSuccess) return r -singleQuery sym (W4ProverConfig (AnAdapter adpt)) evo primMap logData ts args msafe query =- do pres <- W4.solver_adapter_check_sat adpt sym logData [query] $ \res ->+singleQuery sym (W4ProverConfig (AnAdapter adpt)) primMap logData ts args msafe query =+ do pres <- W4.solver_adapter_check_sat adpt (w4 sym) logData [query] $ \res -> case res of W4.Unknown -> return (ProverError "Solver returned UNKNOWN") W4.Unsat _ -> return (ThmResult (map unFinType ts)) W4.Sat (evalFn,_) ->- do model <- computeModel evo primMap evalFn ts args+ do xs <- mapM (varShapeToConcrete evalFn) args+ let model = computeModel primMap ts xs case msafe of Just s -> do s' <- W4.groundEval evalFn s@@ -484,138 +523,33 @@ computeBlockingPred :: sym ~ W4.ExprBuilder t CryptolState fm =>- sym ->- W4.GroundEvalFn t ->- [VarShape sym] ->- IO (W4.Pred sym)-computeBlockingPred sym evalFn vs =- do ps <- mapM (varBlockingPred sym evalFn) vs- foldM (W4.orPred sym) (W4.falsePred sym) ps--varBlockingPred ::- sym ~ W4.ExprBuilder t CryptolState fm =>- sym ->- W4.GroundEvalFn t ->- VarShape sym ->+ What4 sym ->+ [VarShape (What4 sym)] ->+ [VarShape Concrete.Concrete] -> IO (W4.Pred sym)-varBlockingPred sym evalFn v =- case v of- VarBit b ->- do blit <- W4.groundEval evalFn b- W4.notPred sym =<< W4.eqPred sym b (W4.backendPred sym blit)- VarInteger i ->- do ilit <- W4.groundEval evalFn i- W4.notPred sym =<< W4.intEq sym i =<< W4.intLit sym ilit- VarRational n d ->- do n' <- W4.intLit sym =<< W4.groundEval evalFn n- d' <- W4.intLit sym =<< W4.groundEval evalFn d- x <- W4.intMul sym n d'- y <- W4.intMul sym n' d- W4.notPred sym =<< W4.intEq sym x y- VarWord SW.ZBV -> return (W4.falsePred sym)- VarWord (SW.DBV w) ->- do wlit <- W4.groundEval evalFn w- W4.notPred sym =<< W4.bvEq sym w =<< W4.bvLit sym (W4.bvWidth w) wlit-- VarFloat (W4.SFloat f)- | fr@(W4.FloatingPointPrecisionRepr e p) <- sym `W4.fpReprOf` f- , let wid = W4.addNat e p- , Just W4.LeqProof <- W4.isPosNat wid ->- do bits <- W4.groundEval evalFn f- bv <- W4.bvLit sym wid bits- constF <- W4.floatFromBinary sym fr bv- -- NOTE: we are using logical equality here- W4.notPred sym =<< W4.floatEq sym f constF- | otherwise -> panic "varBlockingPred" [ "1 >= 2 ???" ]-- VarFinSeq _n vs -> computeBlockingPred sym evalFn vs- VarTuple vs -> computeBlockingPred sym evalFn vs- VarRecord fs -> computeBlockingPred sym evalFn (recordElements fs)--computeModel ::- Eval.EvalOpts ->- PrimMap ->- W4.GroundEvalFn t ->- [FinType] ->- [VarShape (W4.ExprBuilder t CryptolState fm)] ->- IO [(Type, Expr, Concrete.Value)]-computeModel _ _ _ [] [] = return []-computeModel evo primMap evalFn (t:ts) (v:vs) =- do v' <- varToConcreteValue evalFn v- let t' = unFinType t- e <- doEval evo (Concrete.toExpr primMap t' v') >>= \case- Nothing -> panic "computeModel" ["could not compute counterexample expression"]- Just e -> pure e- zs <- computeModel evo primMap evalFn ts vs- return ((t',e,v'):zs)-computeModel _ _ _ _ _ = panic "computeModel" ["type/value list mismatch"]---data VarShape sym- = VarBit (W4.Pred sym)- | VarInteger (W4.SymInteger sym)- | VarRational (W4.SymInteger sym) (W4.SymInteger sym)- | VarFloat (W4.SFloat sym)- | VarWord (SW.SWord sym)- | VarFinSeq Int [VarShape sym]- | VarTuple [VarShape sym]- | VarRecord (RecordMap Ident (VarShape sym))--freshVariable :: W4.IsSymExprBuilder sym => sym -> FinType -> IO (VarShape sym)-freshVariable sym ty =- case ty of- FTBit -> VarBit <$> W4.freshConstant sym W4.emptySymbol W4.BaseBoolRepr- FTInteger -> VarInteger <$> W4.freshConstant sym W4.emptySymbol W4.BaseIntegerRepr- FTRational -> VarRational- <$> W4.freshConstant sym W4.emptySymbol W4.BaseIntegerRepr- <*> W4.freshBoundedInt sym W4.emptySymbol (Just 1) Nothing- FTIntMod 0 -> panic "freshVariable" ["0 modulus not allowed"]- FTIntMod n -> VarInteger <$> W4.freshBoundedInt sym W4.emptySymbol (Just 0) (Just (n-1))- FTFloat e p -> VarFloat <$> W4.fpFresh sym e p- FTSeq n FTBit -> VarWord <$> SW.freshBV sym W4.emptySymbol (toInteger n)- FTSeq n t -> VarFinSeq n <$> sequence (replicate n (freshVariable sym t))- FTTuple ts -> VarTuple <$> mapM (freshVariable sym) ts- FTRecord fs -> VarRecord <$> traverse (freshVariable sym) fs--varToSymValue :: W4.IsExprBuilder sym => sym -> VarShape sym -> Value sym-varToSymValue sym var =- case var of- VarBit b -> Eval.VBit b- VarInteger i -> Eval.VInteger i- VarRational n d -> Eval.VRational (Eval.SRational n d)- VarWord w -> Eval.VWord (SW.bvWidth w) (return (Eval.WordVal w))- VarFloat f -> Eval.VFloat f- VarFinSeq n vs -> Eval.VSeq (toInteger n) (Eval.finiteSeqMap (What4 sym) (map (pure . varToSymValue sym) vs))- VarTuple vs -> Eval.VTuple (map (pure . varToSymValue sym) vs)- VarRecord fs -> Eval.VRecord (fmap (pure . varToSymValue sym) fs)+computeBlockingPred sym vs xs =+ do res <- doW4Eval (w4 sym) (modelPred sym vs xs)+ W4.notPred (w4 sym) (snd res) -varToConcreteValue ::+varShapeToConcrete :: W4.GroundEvalFn t ->- VarShape (W4.ExprBuilder t CryptolState fm) ->- IO Concrete.Value-varToConcreteValue evalFn v =+ VarShape (What4 (W4.ExprBuilder t CryptolState fm)) ->+ IO (VarShape Concrete.Concrete)+varShapeToConcrete evalFn v = case v of- VarBit b -> Eval.VBit <$> W4.groundEval evalFn b- VarInteger i -> Eval.VInteger <$> W4.groundEval evalFn i- VarRational n d ->- Eval.VRational <$> (Eval.SRational <$> W4.groundEval evalFn n <*> W4.groundEval evalFn d)- VarWord SW.ZBV ->- pure (Eval.VWord 0 (pure (Eval.WordVal (Concrete.mkBv 0 0))))+ VarBit b -> VarBit <$> W4.groundEval evalFn b+ VarInteger i -> VarInteger <$> W4.groundEval evalFn i+ VarRational n d -> VarRational <$> W4.groundEval evalFn n <*> W4.groundEval evalFn d+ VarWord SW.ZBV -> pure (VarWord (Concrete.mkBv 0 0)) VarWord (SW.DBV x) ->- do let w = W4.intValue (W4.bvWidth x)- Eval.VWord w . pure . Eval.WordVal . Concrete.mkBv w . BV.asUnsigned <$> W4.groundEval evalFn x+ let w = W4.intValue (W4.bvWidth x)+ in VarWord . Concrete.mkBv w . BV.asUnsigned <$> W4.groundEval evalFn x VarFloat fv@(W4.SFloat f) -> do let (e,p) = W4.fpSize fv- bits <- W4.groundEval evalFn f- pure $ Eval.VFloat $ Concrete.floatFromBits e p $ BV.asUnsigned bits-+ VarFloat . FH.floatFromBits e p . BV.asUnsigned <$> W4.groundEval evalFn f VarFinSeq n vs ->- do vs' <- mapM (varToConcreteValue evalFn) vs- pure (Eval.VSeq (toInteger n) (Eval.finiteSeqMap Concrete.Concrete (map pure vs')))+ VarFinSeq n <$> mapM (varShapeToConcrete evalFn) vs VarTuple vs ->- do vs' <- mapM (varToConcreteValue evalFn) vs- pure (Eval.VTuple (map pure vs'))+ VarTuple <$> mapM (varShapeToConcrete evalFn) vs VarRecord fs ->- do fs' <- traverse (varToConcreteValue evalFn) fs- pure (Eval.VRecord (fmap pure fs'))-+ VarRecord <$> traverse (varShapeToConcrete evalFn) fs
src/Cryptol/Testing/Random.hs view
@@ -9,33 +9,40 @@ -- This module generates random values for Cryptol types. {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE TypeFamilies #-}-module Cryptol.Testing.Random where+module Cryptol.Testing.Random+( Gen+, randomValue+, dumpableType+, testableType+, TestReport(..)+, TestResult(..)+, isPass+, returnTests+, exhaustiveTests+, randomTests+) where import qualified Control.Exception as X import Control.Monad (join, liftM2)+import Control.Monad.IO.Class (MonadIO(..)) import Data.Ratio ((%))-import Data.Bits ( (.&.), shiftR ) import Data.List (unfoldr, genericTake, genericIndex, genericReplicate) import qualified Data.Sequence as Seq import System.Random (RandomGen, split, random, randomR)-import System.Random.TF.Gen (seedTFGen) -import Cryptol.Eval.Backend (Backend(..), SRational(..))-import Cryptol.Eval.Concrete.Value-import Cryptol.Eval.Monad (ready,runEval,EvalOpts,Eval,EvalError(..))-import Cryptol.Eval.Type (TValue(..), tValTy)+import Cryptol.Backend (Backend(..), SRational(..))+import Cryptol.Backend.Monad (runEval,Eval,EvalError(..))+import Cryptol.Backend.Concrete++import Cryptol.Eval.Type (TValue(..)) import Cryptol.Eval.Value (GenValue(..),SeqMap(..), WordValue(..), ppValue, defaultPPOpts, finiteSeqMap)-import Cryptol.Eval.Generic (zeroV)-import Cryptol.TypeCheck.AST (Type(..), TCon(..), TC(..), tNoUser, tIsFun- , tIsNum )-import Cryptol.TypeCheck.SimpType(tRebuild')- import Cryptol.Utils.Ident (Ident) import Cryptol.Utils.Panic (panic) import Cryptol.Utils.RecordMap@@ -43,6 +50,8 @@ type Gen g x = Integer -> g -> (SEval x (GenValue x), g) +type Value = GenValue Concrete+ {- | Apply a testable value to some randomly-generated arguments. Returns @Nothing@ if the function returned @True@, or @Just counterexample@ if it returned @False@.@@ -51,34 +60,32 @@ the supplied value, otherwise we'll panic. -} runOneTest :: RandomGen g- => EvalOpts -- ^ how to evaluate things- -> Value -- ^ Function under test+ => Value -- ^ Function under test -> [Gen g Concrete] -- ^ Argument generators -> Integer -- ^ Size -> g -> IO (TestResult, g)-runOneTest evOpts fun argGens sz g0 = do+runOneTest fun argGens sz g0 = do let (args, g1) = foldr mkArg ([], g0) argGens mkArg argGen (as, g) = let (a, g') = argGen sz g in (a:as, g')- args' <- runEval evOpts (sequence args)- result <- evalTest evOpts fun args'+ args' <- runEval (sequence args)+ result <- evalTest fun args' return (result, g1) returnOneTest :: RandomGen g- => EvalOpts -- ^ How to evaluate things- -> Value -- ^ Function to be used to calculate tests+ => Value -- ^ Function to be used to calculate tests -> [Gen g Concrete] -- ^ Argument generators -> Integer -- ^ Size -> g -- ^ Initial random state -> IO ([Value], Value, g) -- ^ Arguments, result, and new random state-returnOneTest evOpts fun argGens sz g0 =+returnOneTest fun argGens sz g0 = do let (args, g1) = foldr mkArg ([], g0) argGens mkArg argGen (as, g) = let (a, g') = argGen sz g in (a:as, g')- args' <- runEval evOpts (sequence args)- result <- runEval evOpts (go fun args')+ args' <- runEval (sequence args)+ result <- runEval (go fun args') return (args', result, g1) where- go (VFun f) (v : vs) = join (go <$> (f (ready v)) <*> pure vs)+ go (VFun f) (v : vs) = join (go <$> (f (pure v)) <*> pure vs) go (VFun _) [] = panic "Cryptol.Testing.Random" ["Not enough arguments to function while generating tests"] go _ (_ : _) = panic "Cryptol.Testing.Random" ["Too many arguments to function while generating tests"] go v [] = return v@@ -87,93 +94,63 @@ -- | Return a collection of random tests. returnTests :: RandomGen g => g -- ^ The random generator state- -> EvalOpts -- ^ How to evaluate things -> [Gen g Concrete] -- ^ Generators for the function arguments -> Value -- ^ The function itself -> Int -- ^ How many tests? -> IO [([Value], Value)] -- ^ A list of pairs of random arguments and computed outputs-returnTests g evo gens fun num = go gens g 0+returnTests g gens fun num = go gens g 0 where go args g0 n | n >= num = return [] | otherwise = do let sz = toInteger (div (100 * (1 + n)) num)- (inputs, output, g1) <- returnOneTest evo fun args sz g0+ (inputs, output, g1) <- returnOneTest fun args sz g0 more <- go args g1 (n + 1) return ((inputs, output) : more) {- | Given a (function) type, compute generators for the function's-arguments. This is like 'testableTypeGenerators', but allows the result to be-any finite type instead of just @Bit@. -}-dumpableType :: forall g. RandomGen g => Type -> Maybe [Gen g Concrete]+arguments. -}+dumpableType :: forall g. RandomGen g => TValue -> Maybe [Gen g Concrete]+dumpableType (TVFun t1 t2) =+ do g <- randomValue Concrete t1+ as <- dumpableType t2+ return (g : as) dumpableType ty =- case tIsFun ty of- Just (t1, t2) ->- do g <- randomValue Concrete t1- as <- testableTypeGenerators t2- return (g : as)- Nothing ->- do (_ :: Gen g Concrete) <- randomValue Concrete ty- return []--{- | Given a (function) type, compute generators for-the function's arguments. Currently we do not support polymorphic functions.-In principle, we could apply these to random types, and test the results. -}-testableTypeGenerators :: RandomGen g => Type -> Maybe [Gen g Concrete]-testableTypeGenerators ty =- case tNoUser ty of- TCon (TC TCFun) [t1,t2] ->- do g <- randomValue Concrete t1- as <- testableTypeGenerators t2- return (g : as)- TCon (TC TCBit) [] -> return []- _ -> Nothing+ do (_ :: Gen g Concrete) <- randomValue Concrete ty+ return [] {-# SPECIALIZE randomValue ::- RandomGen g => Concrete -> Type -> Maybe (Gen g Concrete)+ RandomGen g => Concrete -> TValue -> Maybe (Gen g Concrete) #-} {- | A generator for values of the given type. This fails if we are given a type that lacks a suitable random value generator. -}-randomValue :: (Backend sym, RandomGen g) => sym -> Type -> Maybe (Gen g sym)+randomValue :: (Backend sym, RandomGen g) => sym -> TValue -> Maybe (Gen g sym) randomValue sym ty = case ty of- TCon tc ts ->- case (tc, map (tRebuild' False) ts) of- (TC TCBit, []) -> Just (randomBit sym)-- (TC TCInteger, []) -> Just (randomInteger sym)-- (TC TCRational, []) -> Just (randomRational sym)-- (TC TCIntMod, [TCon (TC (TCNum n)) []]) ->- do return (randomIntMod sym n)-- (TC TCFloat, [e',p']) | Just e <- tIsNum e', Just p <- tIsNum p' ->- return (randomFloat sym e p)-- (TC TCSeq, [TCon (TC TCInf) [], el]) ->- do mk <- randomValue sym el- return (randomStream mk)-- (TC TCSeq, [TCon (TC (TCNum n)) [], TCon (TC TCBit) []]) ->- return (randomWord sym n)-- (TC TCSeq, [TCon (TC (TCNum n)) [], el]) ->- do mk <- randomValue sym el- return (randomSequence n mk)-- (TC (TCTuple _), els) ->- do mks <- mapM (randomValue sym) els- return (randomTuple mks)-- _ -> Nothing+ TVBit -> Just (randomBit sym)+ TVInteger -> Just (randomInteger sym)+ TVRational -> Just (randomRational sym)+ TVIntMod m -> Just (randomIntMod sym m)+ TVFloat e p -> Just (randomFloat sym e p)+ TVSeq n TVBit -> Just (randomWord sym n)+ TVSeq n el ->+ do mk <- randomValue sym el+ return (randomSequence n mk)+ TVStream el ->+ do mk <- randomValue sym el+ return (randomStream mk)+ TVTuple els ->+ do mks <- mapM (randomValue sym) els+ return (randomTuple mks)+ TVRec fs ->+ do gs <- traverse (randomValue sym) fs+ return (randomRecord gs) - TVar _ -> Nothing- TUser _ _ t -> randomValue sym t- TRec fs -> do gs <- traverse (randomValue sym) fs- return (randomRecord gs)+ TVArray{} -> Nothing+ TVFun{} -> Nothing+ TVAbstract{} -> Nothing {-# INLINE randomBit #-} @@ -294,27 +271,7 @@ --- Random Values --------------------------------------------------------------- -{-# SPECIALIZE randomV ::- Concrete -> TValue -> Integer -> SEval Concrete (GenValue Concrete)- #-}---- | Produce a random value with the given seed. If we do not support--- making values of the given type, return zero of that type.--- TODO: do better than returning zero-randomV :: Backend sym => sym -> TValue -> Integer -> SEval sym (GenValue sym)-randomV sym ty seed =- case randomValue sym (tValTy ty) of- Nothing -> zeroV sym ty- Just gen ->- -- unpack the seed into four Word64s- let mask64 = 0xFFFFFFFFFFFFFFFF- unpack s = fromInteger (s .&. mask64) : unpack (s `shiftR` 64)- [a, b, c, d] = take 4 (unpack seed)- in fst $ gen 100 $ seedTFGen (a, b, c, d)-- -- | A test result is either a pass, a failure due to evaluating to -- @False@, or a failure due to an exception raised during evaluation data TestResult@@ -330,18 +287,18 @@ -- Note that this function assumes that the values come from a call to -- `testableType` (i.e., things are type-correct). We run in the IO -- monad in order to catch any @EvalError@s.-evalTest :: EvalOpts -> Value -> [Value] -> IO TestResult-evalTest evOpts v0 vs0 = run `X.catch` handle+evalTest :: Value -> [Value] -> IO TestResult+evalTest v0 vs0 = run `X.catch` handle where run = do- result <- runEval evOpts (go v0 vs0)+ result <- runEval (go v0 vs0) if result then return Pass else return (FailFalse vs0) handle e = return (FailError e vs0) go :: Value -> [Value] -> Eval Bool- go (VFun f) (v : vs) = join (go <$> (f (ready v)) <*> return vs)+ go (VFun f) (v : vs) = join (go <$> (f (pure v)) <*> return vs) go (VFun _) [] = panic "Not enough arguments while applying function" [] go (VBit b) [] = return b@@ -353,113 +310,87 @@ , "Arguments:" ] ++ map show vsdocs -{- | Given a (function) type, compute all possible inputs for it.-We also return the types of the arguments and-the total number of test (i.e., the length of the outer list. -}-testableType :: Type -> Maybe (Maybe Integer, [Type], [[Value]])-testableType ty =- case tNoUser ty of- TCon (TC TCFun) [t1,t2] ->- do let sz = typeSize t1- (tot,ts,vss) <- testableType t2- return (liftM2 (*) sz tot, t1:ts, [ v : vs | v <- typeValues t1, vs <- vss ])- TCon (TC TCBit) [] -> return (Just 1, [], [[]])- _ -> Nothing+{- | Given a (function) type, compute data necessary for+ random or exhaustive testing. + The first returned component is a count of the number of+ possible input test vectors, if the input types are finite.+ The second component is a list of all the types of the function+ inputs. The third component is a list of all input test vectors+ for exhaustive testing. This will be empty unless the+ input types are finite. The final argument is a list of generators+ for the inputs of the function.++ This function will return @Nothing@ if the input type does not+ eventually return @Bit@, or if we cannot compute a generator+ for one of the inputs.+-}+testableType :: RandomGen g =>+ TValue ->+ Maybe (Maybe Integer, [TValue], [[Value]], [Gen g Concrete])+testableType (TVFun t1 t2) =+ do let sz = typeSize t1+ g <- randomValue Concrete t1+ (tot,ts,vss,gs) <- testableType t2+ let tot' = liftM2 (*) sz tot+ let vss' = [ v : vs | v <- typeValues t1, vs <- vss ]+ return (tot', t1:ts, vss', g:gs)+testableType TVBit = return (Just 1, [], [[]], [])+testableType _ = Nothing+ {- | Given a fully-evaluated type, try to compute the number of values in it. Returns `Nothing` for infinite types, user-defined types, polymorphic types, and, currently, function spaces. Of course, we can easily compute the sizes of function spaces, but we can't easily enumerate their inhabitants. -}-typeSize :: Type -> Maybe Integer-typeSize ty =- case ty of- TVar _ -> Nothing- TUser _ _ t -> typeSize t- TRec fs -> product <$> traverse typeSize fs- TCon (TC tc) ts ->- case (tc, ts) of- (TCNum _, _) -> Nothing- (TCInf, _) -> Nothing- (TCBit, _) -> Just 2- (TCInteger, _) -> Nothing- (TCRational, _) -> Nothing- (TCIntMod, [sz]) -> case tNoUser sz of- TCon (TC (TCNum n)) _ -> Just n- _ -> Nothing- (TCIntMod, _) -> Nothing- (TCFloat {}, _) -> Nothing- (TCArray, _) -> Nothing- (TCSeq, [sz,el]) -> case tNoUser sz of- TCon (TC (TCNum n)) _ -> (^ n) <$> typeSize el- _ -> Nothing- (TCSeq, _) -> Nothing- (TCFun, _) -> Nothing- (TCTuple _, els) -> product <$> mapM typeSize els- (TCAbstract _, _) -> Nothing- (TCNewtype _, _) -> Nothing-- TCon _ _ -> Nothing-+typeSize :: TValue -> Maybe Integer+typeSize ty = case ty of+ TVBit -> Just 2+ TVInteger -> Nothing+ TVRational -> Nothing+ TVIntMod n -> Just n+ TVFloat{} -> Nothing -- TODO?+ TVArray{} -> Nothing+ TVStream{} -> Nothing+ TVSeq n el -> (^ n) <$> typeSize el+ TVTuple els -> product <$> mapM typeSize els+ TVRec fs -> product <$> traverse typeSize fs+ TVFun{} -> Nothing+ TVAbstract{} -> Nothing {- | Returns all the values in a type. Returns an empty list of values, for types where 'typeSize' returned 'Nothing'. -}-typeValues :: Type -> [Value]+typeValues :: TValue -> [Value] typeValues ty = case ty of- TVar _ -> []- TUser _ _ t -> typeValues t- TRec fs -> [ VRecord (fmap ready xs)- | xs <- traverse typeValues fs- ]- TCon (TC tc) ts ->- case tc of- TCNum _ -> []- TCInf -> []- TCBit -> [ VBit False, VBit True ]- TCInteger -> []- TCRational -> []- TCIntMod ->- case map tNoUser ts of- [ TCon (TC (TCNum n)) _ ] | 0 < n ->- [ VInteger x | x <- [ 0 .. n - 1 ] ]- _ -> []- TCFloat {} -> []- TCArray -> []- TCSeq ->- case map tNoUser ts of- [ TCon (TC (TCNum n)) _, TCon (TC TCBit) [] ] ->- [ VWord n (ready (WordVal (BV n x))) | x <- [ 0 .. 2^n - 1 ] ]-- [ TCon (TC (TCNum n)) _, t ] ->- [ VSeq n (finiteSeqMap Concrete (map ready xs))- | xs <- sequence $ genericReplicate n- $ typeValues t ]- _ -> []--- TCFun -> [] -- We don't generate function values.- TCTuple _ -> [ VTuple (map ready xs)- | xs <- sequence (map typeValues ts)- ]- TCAbstract _ -> []- TCNewtype _ -> []-- TCon _ _ -> []+ TVBit -> [ VBit False, VBit True ]+ TVInteger -> []+ TVRational -> []+ TVIntMod n -> [ VInteger x | x <- [ 0 .. (n-1) ] ]+ TVFloat{} -> [] -- TODO?+ TVArray{} -> []+ TVStream{} -> []+ TVSeq n TVBit ->+ [ VWord n (pure (WordVal (BV n x)))+ | x <- [ 0 .. 2^n - 1 ]+ ]+ TVSeq n el ->+ [ VSeq n (finiteSeqMap Concrete (map pure xs))+ | xs <- sequence (genericReplicate n (typeValues el))+ ]+ TVTuple ts ->+ [ VTuple (map pure xs)+ | xs <- sequence (map typeValues ts)+ ]+ TVRec fs ->+ [ VRecord (fmap pure xs)+ | xs <- traverse typeValues fs+ ]+ TVFun{} -> []+ TVAbstract{} -> [] -------------------------------------------------------------------------------- -- Driver function -data TestSpec m s = TestSpec {- testFn :: Integer -> s -> m (TestResult, s)- , testProp :: String -- ^ The property as entered by the user- , testTotal :: Integer- , testPossible :: Maybe Integer -- ^ Nothing indicates infinity- , testRptProgress :: Integer -> Integer -> m ()- , testClrProgress :: m ()- , testRptFailure :: TestResult -> m ()- , testRptSuccess :: m ()- }- data TestReport = TestReport { reportResult :: TestResult , reportProp :: String -- ^ The property as entered by the user@@ -467,19 +398,36 @@ , reportTestsPossible :: Maybe Integer } -runTests :: Monad m => TestSpec m s -> s -> m TestReport-runTests TestSpec {..} st0 = go 0 st0+exhaustiveTests :: MonadIO m =>+ (Integer -> m ()) {- ^ progress callback -} ->+ Value {- ^ function under test -} ->+ [[Value]] {- ^ exhaustive set of test values -} ->+ m (TestResult, Integer)+exhaustiveTests ppProgress val = go 0 where- go testNum _ | testNum >= testTotal = do- testRptSuccess- return $ TestReport Pass testProp testNum testPossible- go testNum st =- do testRptProgress testNum testTotal- res <- testFn (div (100 * (1 + testNum)) testTotal) st- testClrProgress- case res of- (Pass, st') -> do -- delProgress -- unnecessary?- go (testNum + 1) st'- (failure, _st') -> do- testRptFailure failure- return $ TestReport failure testProp testNum testPossible+ go !testNum [] = return (Pass, testNum)+ go !testNum (vs:vss) =+ do ppProgress testNum+ res <- liftIO (evalTest val vs)+ case res of+ Pass -> go (testNum+1) vss+ failure -> return (failure, testNum)++randomTests :: (MonadIO m, RandomGen g) =>+ (Integer -> m ()) {- ^ progress callback -} ->+ Integer {- ^ Maximum number of tests to run -} ->+ Value {- ^ function under test -} ->+ [Gen g Concrete] {- ^ input value generators -} ->+ g {- ^ Inital random generator -} ->+ m (TestResult, Integer)+randomTests ppProgress maxTests val gens = go 0+ where+ go !testNum g+ | testNum >= maxTests = return (Pass, testNum)+ | otherwise =+ do ppProgress testNum+ let sz' = div (100 * (1 + testNum)) maxTests+ (res, g') <- liftIO (runOneTest val gens sz' g)+ case res of+ Pass -> go (testNum+1) g'+ failure -> return (failure, testNum)
src/Cryptol/Transform/AddModParams.hs view
@@ -234,7 +234,7 @@ ETuple es -> ETuple (inst ps es) ERec fs -> ERec (fmap (inst ps) fs) ESel e s -> ESel (inst ps e) s- ESet e s v -> ESet (inst ps e) s (inst ps v)+ ESet ty e s v -> ESet (inst ps ty) (inst ps e) s (inst ps v) EIf e1 e2 e3 -> EIf (inst ps e1) (inst ps e2) (inst ps e3) EComp t1 t2 e ms -> EComp (inst ps t1) (inst ps t2)
src/Cryptol/Transform/MonoValues.hs view
@@ -183,7 +183,7 @@ ETuple es -> ETuple <$> mapM go es ERec fs -> ERec <$> traverse go fs ESel e s -> ESel <$> go e <*> return s- ESet e s v -> ESet <$> go e <*> return s <*> go v+ ESet ty e s v -> ESet ty <$> go e <*> return s <*> go v EIf e1 e2 e3 -> EIf <$> go e1 <*> go e2 <*> go e3 EComp len t e mss -> EComp len t <$> go e <*> mapM (mapM (rewM rews)) mss
src/Cryptol/Transform/Specialize.hs view
@@ -74,7 +74,7 @@ ETuple es -> ETuple <$> traverse specializeExpr es ERec fs -> ERec <$> traverse specializeExpr fs ESel e s -> ESel <$> specializeExpr e <*> pure s- ESet e s v -> ESet <$> specializeExpr e <*> pure s <*> specializeExpr v+ ESet ty e s v -> ESet ty <$> specializeExpr e <*> pure s <*> specializeExpr v EIf e1 e2 e3 -> EIf <$> specializeExpr e1 <*> specializeExpr e2 <*> specializeExpr e3 EComp len t e mss -> EComp len t <$> specializeExpr e <*> traverse (traverse specializeMatch) mss -- Bindings within list comprehensions always have monomorphic types.
src/Cryptol/TypeCheck.hs view
@@ -21,6 +21,10 @@ , Warning(..) , ppWarning , ppError+ , WithNames(..)+ , NameMap+ , ppNamedWarning+ , ppNamedError ) where import Cryptol.ModuleSystem.Name@@ -43,6 +47,7 @@ import Cryptol.TypeCheck.Solve(proveModuleTopLevel) import Cryptol.TypeCheck.CheckModuleInstance(checkModuleInstance) import Cryptol.TypeCheck.Monad(withParamType,withParameterConstraints)+import Cryptol.TypeCheck.PP(WithNames(..),NameMap) import Cryptol.Utils.Ident (exprModName,packIdent) import Cryptol.Utils.PP import Cryptol.Utils.Panic(panic)@@ -58,12 +63,11 @@ IO (InferOutput Module) {- ^ new version of instance -} tcModuleInst func m inp = runInferM inp $ do x <- inferModule m- y <- checkModuleInstance func x flip (foldr withParamType) (mParamTypes x) $ withParameterConstraints (mParamConstraints x) $- proveModuleTopLevel-- return y+ do y <- checkModuleInstance func x+ proveModuleTopLevel+ pure y tcExpr :: P.Expr Name -> InferInput -> IO (InferOutput (Expr,Schema)) tcExpr e0 inp = runInferM inp@@ -121,5 +125,14 @@ ppError :: (Range,Error) -> Doc ppError (r,w) = text "[error] at" <+> pp r <.> colon $$ nest 2 (pp w)+++ppNamedWarning :: NameMap -> (Range,Warning) -> Doc+ppNamedWarning nm (r,w) =+ text "[warning] at" <+> pp r <.> colon $$ nest 2 (pp (WithNames w nm))++ppNamedError :: NameMap -> (Range,Error) -> Doc+ppNamedError nm (r,e) =+ text "[error] at" <+> pp r <.> colon $$ nest 2 (pp (WithNames e nm))
src/Cryptol/TypeCheck/AST.hs view
@@ -25,7 +25,6 @@ , Pragma(..) , Fixity(..) , PrimMap(..)- , TCErrorMessage(..) , module Cryptol.TypeCheck.Type ) where @@ -47,6 +46,7 @@ import Data.Map (Map) import qualified Data.Map as Map import qualified Data.IntMap as IntMap+import Data.Text (Text) -- | A Cryptol module.@@ -80,7 +80,7 @@ -- This is used when we move parameters from the module -- level to individual declarations -- (type synonyms in particular)- , mtpDoc :: Maybe String+ , mtpDoc :: Maybe Text } deriving (Show,Generic,NFData) mtpParam :: ModTParam -> TParam@@ -97,7 +97,7 @@ data ModVParam = ModVParam { mvpName :: Name , mvpType :: Schema- , mvpDoc :: Maybe String+ , mvpDoc :: Maybe Text , mvpFixity :: Maybe Fixity } deriving (Show,Generic,NFData) @@ -106,7 +106,8 @@ | ETuple [Expr] -- ^ Tuple value | ERec (RecordMap Ident Expr) -- ^ Record value | ESel Expr Selector -- ^ Elimination for tuple/record/list- | ESet Expr Selector Expr -- ^ Change the value of a field.+ | ESet Type Expr Selector Expr -- ^ Change the value of a field.+ -- The included type gives the type of the record being updated | EIf Expr Expr Expr -- ^ If-then-else | EComp Type Type Expr [[Match]]@@ -167,7 +168,7 @@ , dPragmas :: [Pragma] , dInfix :: !Bool , dFixity :: Maybe Fixity- , dDoc :: Maybe String+ , dDoc :: Maybe Text } deriving (Generic, NFData, Show) data DeclDef = DPrim@@ -211,7 +212,7 @@ ESel e sel -> ppWP 4 e <+> text "." <.> pp sel - ESet e sel v -> braces (pp e <+> "|" <+> pp sel <+> "=" <+> pp v)+ ESet _ty e sel v -> braces (pp e <+> "|" <+> pp sel <+> "=" <+> pp v) EIf e1 e2 e3 -> optParens (prec > 0) $ sep [ text "if" <+> ppW e1@@ -250,7 +251,7 @@ $ ppWP 3 e <+> text "<>" ETApp e t -> optParens (prec > 3)- $ ppWP 3 e <+> ppWP 4 t+ $ ppWP 3 e <+> ppWP 5 t EWhere e ds -> optParens (prec > 0) ( ppW e $$ text "where"@@ -374,4 +375,3 @@ -- XXX: Print abstarct types/functions vcat (map (ppWithNames (addTNames mps nm)) mDecls) where mps = map mtpParam (Map.elems mParamTypes)-
src/Cryptol/TypeCheck/CheckModuleInstance.hs view
@@ -13,7 +13,6 @@ import Cryptol.TypeCheck.Infer import Cryptol.TypeCheck.Subst import Cryptol.TypeCheck.Error-import Cryptol.Utils.PP import Cryptol.Utils.Panic @@ -61,10 +60,12 @@ tParams = Map.fromList [ (tpId x, x) | x0 <- Map.elems (mParamTypes inst) , let x = mtpParam x0 ] - tpId x = case tpName x of- Just n -> nameIdent n+ tpName' x = case tpName x of+ Just n -> n Nothing -> panic "inferModuleInstance.tpId" ["Missing name"] + tpId = nameIdent . tpName'+ -- Find a definition for a given type parameter checkTParamDefined tp0 = let tp = mtpParam tp0@@ -78,15 +79,16 @@ case Map.lookup x tParams of Just tp1 -> checkTP tp tp1 Nothing ->- do recordError $ ErrorMsg $- text "Missing definition for type parameter:" <+> pp x+ do let x' = Located { thing = x,+ srcRange = nameLoc (tpName' tp) }+ recordError (MissingModTParam x') return (tp, TVar (TVBound tp)) -- hm, maybe just stop! -- Check that a type parameter defined as a type synonym is OK checkTySynDef tp ts = do let k1 = kindOf tp k2 = kindOf ts- unless (k1 == k2) (recordError (KindMismatch k1 k2))+ unless (k1 == k2) (recordError (KindMismatch Nothing k1 k2)) let nm = tsName ts src = CtPartialTypeFun nm@@ -104,7 +106,7 @@ checkNewTyDef tp nt = do let k1 = kindOf tp k2 = kindOf nt- unless (k1 == k2) (recordError (KindMismatch k1 k2))+ unless (k1 == k2) (recordError (KindMismatch Nothing k1 k2)) let nm = ntName nt src = CtPartialTypeFun nm@@ -116,7 +118,7 @@ checkTP tp tp1 = do let k1 = kindOf tp k2 = kindOf tp1- unless (k1 == k2) (recordError (KindMismatch k1 k2))+ unless (k1 == k2) (recordError (KindMismatch Nothing k1 k2)) return (tp, TVar (TVBound tp1)) @@ -148,9 +150,9 @@ case Map.lookup (nameIdent x) valMap of Just (n,sD) -> do e <- makeValParamDef n sD (apSubst su sP) return (x,e)- Nothing -> do recordError $ ErrorMsg- $ text "Mising definition for value parameter"- <+> pp x+ Nothing -> do recordError (MissingModVParam+ Located { thing = nameIdent x+ , srcRange = nameLoc x }) return (x, panic "checkValParams" ["Should not use this"])
src/Cryptol/TypeCheck/Default.hs view
@@ -6,7 +6,6 @@ import Data.Maybe(mapMaybe) import Data.List((\\),nub) import Control.Monad(guard,mzero)-import Control.Applicative((<|>)) import Cryptol.TypeCheck.Type import Cryptol.TypeCheck.SimpType(tMax)@@ -16,7 +15,6 @@ import Cryptol.TypeCheck.Solver.SMT(Solver,tryGetModel,shrinkModel) import Cryptol.Utils.Panic(panic) - -------------------------------------------------------------------------------- -- | We default constraints of the form @Literal t a@ and @FLiteral m n r a@.@@ -35,39 +33,44 @@ where gSet = goalsFromList gs allProps = saturatedPropSet gSet- flitCandidates = flitDefaultCandidates gSet+ has p a = Set.member (p (TVar a)) allProps tryDefVar a =- -- we do this first because if we have both a Literand and an FLiteral- -- constraint we should use Rational- Map.lookup a flitCandidates- <|>- do _gt <- Map.lookup a (literalGoals gSet)- defT <- if Set.member (pLogic (TVar a)) allProps then- mzero- else if Set.member (pField (TVar a)) allProps then- pure tRational- else- pure tInteger- let d = tvInfo a- w = DefaultingTo d defT- guard (not (Set.member a (fvs defT))) -- Currently shouldn't happen- -- but future proofing.- -- XXX: Make sure that `defT` has only variables that `a` is allowed- -- to depend on- return ((a,defT),w)+ -- If there is an `FLiteral` constraint we use that for defaulting.+ case Map.lookup a (flitDefaultCandidates gSet) of+ Just m -> m -flitDefaultCandidates :: Goals -> Map TVar ((TVar,Type),Warning)+ -- Otherwise we try to use a `Literal`+ Nothing ->+ do _gt <- Map.lookup a (literalGoals gSet)+ defT <- if has pLogic a then mzero+ else if has pField a && not (has pIntegral a)+ then pure tRational+ else if not (has pField a) then pure tInteger+ else mzero+ let d = tvInfo a+ w = DefaultingTo d defT+ guard (not (Set.member a (fvs defT))) -- Currently shouldn't happen+ -- but future proofing.+ -- XXX: Make sure that `defT` has only variables that `a` is allowed+ -- to depend on+ return ((a,defT),w)+++flitDefaultCandidates :: Goals -> Map TVar (Maybe ((TVar,Type),Warning)) flitDefaultCandidates gs = Map.fromList (mapMaybe flitCandidate (Set.toList (goalSet gs))) where+ allProps = saturatedPropSet gs+ has p a = Set.member (p (TVar a)) allProps+ flitCandidate g = do (_,_,_,x) <- pIsFLiteral (goal g) a <- tIsVar x- guard (not (Set.member (pLogic (TVar a)) (saturatedPropSet gs)))- let defT = tRational- let w = DefaultingTo (tvInfo a) defT- pure (a, ((a,defT),w))+ pure (a, do guard (not (has pLogic a) && not (has pIntegral a))+ let defT = tRational+ let w = DefaultingTo (tvInfo a) defT+ pure ((a,defT),w)) --------------------------------------------------------------------------------
src/Cryptol/TypeCheck/Depends.hs view
@@ -27,16 +27,17 @@ import Data.Map (Map) import qualified Data.Map as Map import qualified Data.Set as Set+import Data.Text (Text) data TyDecl =- TS (P.TySyn Name) (Maybe String) -- ^ Type synonym- | NT (P.Newtype Name) (Maybe String) -- ^ Newtype- | AT (P.ParameterType Name) (Maybe String) -- ^ Parameter type- | PS (P.PropSyn Name) (Maybe String) -- ^ Property synonym- | PT (P.PrimType Name) (Maybe String) -- ^ A primitive/abstract typee+ TS (P.TySyn Name) (Maybe Text) -- ^ Type synonym+ | NT (P.Newtype Name) (Maybe Text) -- ^ Newtype+ | AT (P.ParameterType Name) (Maybe Text) -- ^ Parameter type+ | PS (P.PropSyn Name) (Maybe Text) -- ^ Property synonym+ | PT (P.PrimType Name) (Maybe Text) -- ^ A primitive/abstract typee deriving Show -setDocString :: Maybe String -> TyDecl -> TyDecl+setDocString :: Maybe Text -> TyDecl -> TyDecl setDocString x d = case d of TS a _ -> TS a x
src/Cryptol/TypeCheck/Error.hs view
@@ -1,13 +1,13 @@ {-# Language FlexibleInstances, DeriveGeneric, DeriveAnyClass #-} {-# Language OverloadedStrings #-}+{-# Language Safe #-} module Cryptol.TypeCheck.Error where - import qualified Data.IntMap as IntMap import qualified Data.Set as Set import Control.DeepSeq(NFData) import GHC.Generics(Generic)-import Data.List((\\),sortBy,groupBy,minimumBy)+import Data.List((\\),sortBy,groupBy,partition) import Data.Function(on) import qualified Cryptol.Parser.AST as P@@ -23,43 +23,49 @@ cleanupErrors :: [(Range,Error)] -> [(Range,Error)] cleanupErrors = dropErrorsFromSameLoc . sortBy (compare `on` (cmpR . fst)) -- order errors- . dropSumbsumed+ . dropSubsumed [] where -- pick shortest error from each location.- dropErrorsFromSameLoc = map chooseBestError+ dropErrorsFromSameLoc = concatMap chooseBestError . groupBy ((==) `on` fst) - addErrorSize (r,e) = (length (show (pp e)), (r,e))- chooseBestError = snd . minimumBy (compare `on` fst) . map addErrorSize+ addErrorRating (r,e) = (errorImportance e, (r,e))+ chooseBestError = map snd+ . head+ . groupBy ((==) `on` fst)+ . sortBy (flip compare `on` fst)+ . map addErrorRating - cmpR r = ( source r -- Frist by file+ cmpR r = ( source r -- First by file , from r -- Then starting position , to r -- Finally end position ) - dropSumbsumed xs =+ dropSubsumed survived xs = case xs of- (r,e) : rest -> (r,e) :- dropSumbsumed (filter (not .subsumes e . snd) rest)- [] -> []+ err : rest ->+ let keep e = not (subsumes err e)+ in dropSubsumed (err : filter keep survived) (filter keep rest)+ [] -> survived -- | Should the first error suppress the next one.-subsumes :: Error -> Error -> Bool-subsumes (NotForAll x _) (NotForAll y _) = x == y+subsumes :: (Range,Error) -> (Range,Error) -> Bool+subsumes (_,NotForAll _ x _) (_,NotForAll _ y _) = x == y+subsumes (r1,KindMismatch {}) (r2,err) =+ case err of+ KindMismatch {} -> r1 == r2+ _ -> True subsumes _ _ = False data Warning = DefaultingKind (P.TParam Name) P.Kind | DefaultingWildType P.Kind- | DefaultingTo TVarInfo Type+ | DefaultingTo !TVarInfo Type deriving (Show, Generic, NFData) -- | Various errors that might happen during type checking/inference-data Error = ErrorMsg Doc- -- ^ Just say this-- | KindMismatch Kind Kind+data Error = KindMismatch (Maybe TypeSource) Kind Kind -- ^ Expected kind, inferred kind | TooManyTypeParams Int Kind@@ -78,17 +84,20 @@ | RecursiveTypeDecls [Name] -- ^ The type synonym declarations are recursive - | TypeMismatch Type Type+ | TypeMismatch TypeSource Type Type -- ^ Expected type, inferred type - | RecursiveType Type Type+ | RecursiveType TypeSource Type Type -- ^ Unification results in a recursive type - | UnsolvedGoals (Maybe TCErrorMessage) [Goal]- -- ^ A constraint that we could not solve- -- If we have `TCErrorMess` than the goal is impossible- -- for the given reason+ | UnsolvedGoals [Goal]+ -- ^ A constraint that we could not solve, usually because+ -- there are some left-over variables that we could not infer. + | UnsolvableGoals [Goal]+ -- ^ A constraint that we could not solve and we know+ -- it is impossible to do it.+ | UnsolvedDelayedCt DelayedCt -- ^ A constraint (with context) that we could not solve @@ -96,11 +105,11 @@ -- ^ Type wild cards are not allowed in this context -- (e.g., definitions of type synonyms). - | TypeVariableEscaped Type [TParam]+ | TypeVariableEscaped TypeSource Type [TParam] -- ^ Unification variable depends on quantified variables -- that are not in scope. - | NotForAll TVar Type+ | NotForAll TypeSource TVar Type -- ^ Quantified type variables (of kind *) need to -- match the given type, so it does not work for all types. @@ -118,14 +127,65 @@ -- ^ Could not determine the value of a numeric type variable, -- but we know it must be at least as large as the given type -- (or unconstrained, if Nothing).++ | UndefinedExistVar Name+ | TypeShadowing String Name String+ | MissingModTParam (Located Ident)+ | MissingModVParam (Located Ident) deriving (Show, Generic, NFData) +-- | When we have multiple errors on the same location, we show only the+-- ones with the has highest rating according to this function.+errorImportance :: Error -> Int+errorImportance err =+ case err of+ KindMismatch {} -> 10+ TyVarWithParams {} -> 9+ TypeMismatch {} -> 8+ RecursiveType {} -> 7+ NotForAll {} -> 6+ TypeVariableEscaped {} -> 5++ UndefinedExistVar {} -> 10+ TypeShadowing {} -> 2+ MissingModTParam {} -> 10+ MissingModVParam {} -> 10+++ CannotMixPositionalAndNamedTypeParams {} -> 8+ TooManyTypeParams {} -> 8+ TooFewTyParams {} -> 8+ TooManyPositionalTypeParams {} -> 8+ UndefinedTypeParameter {} -> 8+ RepeatedTypeParameter {} -> 8++ TooManyTySynParams {} -> 8+ UnexpectedTypeWildCard {} -> 8++ RecursiveTypeDecls {} -> 9++ UnsolvableGoals g+ | any tHasErrors (map goal g) -> 0+ | otherwise -> 4++ UnsolvedGoals g+ | any tHasErrors (map goal g) -> 0+ | otherwise -> 4++ UnsolvedDelayedCt dt+ | any tHasErrors (map goal (dctGoals dt)) -> 0+ | otherwise -> 3++ AmbiguousSize {} -> 2+++ instance TVars Warning where apSubst su warn = case warn of DefaultingKind {} -> warn DefaultingWildType {} -> warn- DefaultingTo d ty -> DefaultingTo d (apSubst su ty)+ DefaultingTo d ty -> DefaultingTo d $! (apSubst su ty) instance FVS Warning where fvs warn =@@ -137,52 +197,63 @@ instance TVars Error where apSubst su err = case err of- ErrorMsg _ -> err KindMismatch {} -> err TooManyTypeParams {} -> err TyVarWithParams -> err TooManyTySynParams {} -> err TooFewTyParams {} -> err RecursiveTypeDecls {} -> err- TypeMismatch t1 t2 -> TypeMismatch (apSubst su t1) (apSubst su t2)- RecursiveType t1 t2 -> RecursiveType (apSubst su t1) (apSubst su t2)- UnsolvedGoals x gs -> UnsolvedGoals x (apSubst su gs)- UnsolvedDelayedCt g -> UnsolvedDelayedCt (apSubst su g)+ TypeMismatch src t1 t2 -> TypeMismatch src !$ (apSubst su t1) !$ (apSubst su t2)+ RecursiveType src t1 t2 -> RecursiveType src !$ (apSubst su t1) !$ (apSubst su t2)+ UnsolvedGoals gs -> UnsolvedGoals !$ apSubst su gs+ UnsolvableGoals gs -> UnsolvableGoals !$ apSubst su gs+ UnsolvedDelayedCt g -> UnsolvedDelayedCt !$ (apSubst su g) UnexpectedTypeWildCard -> err- TypeVariableEscaped t xs -> TypeVariableEscaped (apSubst su t) xs- NotForAll x t -> NotForAll x (apSubst su t)+ TypeVariableEscaped src t xs ->+ TypeVariableEscaped src !$ (apSubst su t) .$ xs+ NotForAll src x t -> NotForAll src x !$ (apSubst su t) TooManyPositionalTypeParams -> err CannotMixPositionalAndNamedTypeParams -> err UndefinedTypeParameter {} -> err RepeatedTypeParameter {} -> err- AmbiguousSize x t -> AmbiguousSize x (apSubst su t)+ AmbiguousSize x t -> AmbiguousSize x !$ (apSubst su t) + UndefinedExistVar {} -> err+ TypeShadowing {} -> err+ MissingModTParam {} -> err+ MissingModVParam {} -> err++ instance FVS Error where fvs err = case err of- ErrorMsg {} -> Set.empty KindMismatch {} -> Set.empty TooManyTypeParams {} -> Set.empty TyVarWithParams -> Set.empty TooManyTySynParams {} -> Set.empty TooFewTyParams {} -> Set.empty RecursiveTypeDecls {} -> Set.empty- TypeMismatch t1 t2 -> fvs (t1,t2)- RecursiveType t1 t2 -> fvs (t1,t2)- UnsolvedGoals _ gs -> fvs gs+ TypeMismatch _ t1 t2 -> fvs (t1,t2)+ RecursiveType _ t1 t2 -> fvs (t1,t2)+ UnsolvedGoals gs -> fvs gs+ UnsolvableGoals gs -> fvs gs UnsolvedDelayedCt g -> fvs g UnexpectedTypeWildCard -> Set.empty- TypeVariableEscaped t xs -> fvs t `Set.union`+ TypeVariableEscaped _ t xs-> fvs t `Set.union` Set.fromList (map TVBound xs)- NotForAll x t -> Set.insert x (fvs t)+ NotForAll _ x t -> Set.insert x (fvs t) TooManyPositionalTypeParams -> Set.empty CannotMixPositionalAndNamedTypeParams -> Set.empty UndefinedTypeParameter {} -> Set.empty RepeatedTypeParameter {} -> Set.empty AmbiguousSize _ t -> fvs t + UndefinedExistVar {} -> Set.empty+ TypeShadowing {} -> Set.empty+ MissingModTParam {} -> Set.empty+ MissingModVParam {} -> Set.empty instance PP Warning where ppPrec = ppWithNamesPrec IntMap.empty@@ -208,26 +279,28 @@ instance PP (WithNames Error) where ppPrec _ (WithNames err names) = case err of- ErrorMsg msg ->- addTVarsDescsAfter names err- msg - RecursiveType t1 t2 ->+ RecursiveType src t1 t2 -> addTVarsDescsAfter names err $- nested "Matching would result in an infinite type."- ("The type: " <+> ppWithNames names t1 $$- "occurs in:" <+> ppWithNames names t2)+ nested "Matching would result in an infinite type." $+ vcat [ "The type: " <+> ppWithNames names t1+ , "occurs in:" <+> ppWithNames names t2+ , "When checking" <+> pp src+ ] UnexpectedTypeWildCard -> addTVarsDescsAfter names err $ nested "Wild card types are not allowed in this context" "(e.g., they cannot be used in type synonyms)." - KindMismatch k1 k2 ->+ KindMismatch mbsrc k1 k2 -> addTVarsDescsAfter names err $- nested "Incorrect type form."- ("Expected:" <+> cppKind k1 $$- "Inferred:" <+> cppKind k2)+ nested "Incorrect type form." $+ vcat [ "Expected:" <+> cppKind k1+ , "Inferred:" <+> cppKind k2+ , kindMismatchHint k1 k2+ , maybe empty (\src -> "When checking" <+> pp src) mbsrc+ ] TooManyTypeParams extra k -> addTVarsDescsAfter names err $@@ -256,24 +329,18 @@ nested "Recursive type declarations:" (fsep $ punctuate comma $ map nm ts) - TypeMismatch t1 t2 ->+ TypeMismatch src t1 t2 -> addTVarsDescsAfter names err $- nested "Type mismatch:"- ("Expected type:" <+> ppWithNames names t1 $$- "Inferred type:" <+> ppWithNames names t2 $$- mismatchHint t1 t2)+ nested "Type mismatch:" $+ vcat [ "Expected type:" <+> ppWithNames names t1+ , "Inferred type:" <+> ppWithNames names t2+ , mismatchHint t1 t2+ , "When checking" <+> pp src+ ] - UnsolvedGoals imp gs- | Just msg <- imp ->- addTVarsDescsAfter names err $- nested "Unsolvable constraints:" $- let reason = ["Reason:" <+> text (tcErrorMessage msg)]- unErr g = case tIsError (goal g) of- Just (_,p) -> g { goal = p }- Nothing -> g- in- bullets (map (ppWithNames names) (map unErr gs) ++ reason)+ UnsolvableGoals gs -> explainUnsolvable names gs + UnsolvedGoals gs | noUni -> addTVarsDescsAfter names err $ nested "Unsolved constraints:" $@@ -294,18 +361,22 @@ nested "while validating user-specified signature" $ ppWithNames names g - TypeVariableEscaped t xs ->+ TypeVariableEscaped src t xs -> addTVarsDescsAfter names err $ nested ("The type" <+> ppWithNames names t <+>- "is not sufficiently polymorphic.")- ("It cannot depend on quantified variables:" <+>- sep (punctuate comma (map (ppWithNames names) xs)))+ "is not sufficiently polymorphic.") $+ vcat [ "It cannot depend on quantified variables:" <+>+ sep (punctuate comma (map (ppWithNames names) xs))+ , "When checking" <+> pp src+ ] - NotForAll x t ->+ NotForAll src x t -> addTVarsDescsAfter names err $- nested "Inferred type is not sufficiently polymorphic."- ("Quantified variable:" <+> ppWithNames names x $$- "cannot match type:" <+> ppWithNames names t)+ nested "Inferred type is not sufficiently polymorphic." $+ vcat [ "Quantified variable:" <+> ppWithNames names x+ , "cannot match type:" <+> ppWithNames names t+ , "When checking" <+> pp src+ ] TooManyPositionalTypeParams -> addTVarsDescsAfter names err $@@ -332,6 +403,18 @@ Nothing -> empty in addTVarsDescsAfter names err ("Ambiguous numeric type:" <+> pp (tvarDesc x) $$ sizeMsg) + UndefinedExistVar x -> "Undefined type" <+> quotes (pp x)+ TypeShadowing this new that ->+ "Type" <+> text this <+> quotes (pp new) <+>+ "shadowing an existing" <+> text that <+> "with the same name."+ MissingModTParam x ->+ "Missing definition for type parameter" <+> quotes (pp (thing x))+ MissingModVParam x ->+ "Missing definition for value parameter" <+> quotes (pp (thing x))++++ where bullets xs = vcat [ "•" <+> d | d <- xs ] @@ -342,6 +425,11 @@ nm x = text "`" <.> pp x <.> text "`" + kindMismatchHint k1 k2 =+ case (k1,k2) of+ (KType,KProp) -> "Possibly due to a missing `=>`"+ _ -> empty+ mismatchHint (TRec fs1) (TRec fs2) = hint "Missing" missing $$ hint "Unexpected" extra where@@ -353,3 +441,133 @@ mismatchHint _ _ = mempty noUni = Set.null (Set.filter isFreeTV (fvs err))++++explainUnsolvable :: NameMap -> [Goal] -> Doc+explainUnsolvable names gs =+ addTVarsDescsAfter names gs (bullets (map explain gs))++ where+ bullets xs = vcat [ "•" <+> d | d <- xs ]++++ explain g =+ let useCtr = "Unsolvable constraint:" $$+ nest 2 (ppWithNames names g)++ in+ case tNoUser (goal g) of+ TCon (PC pc) ts ->+ let tys = [ backticks (ppWithNames names t) | t <- ts ]+ doc1 : _ = tys+ custom msg = msg $$+ nest 2 (text "arising from" $$+ pp (goalSource g) $$+ text "at" <+> pp (goalRange g))+ in+ case pc of+ PEqual -> useCtr+ PNeq -> useCtr+ PGeq -> useCtr+ PFin -> useCtr+ PPrime -> useCtr++ PHas sel ->+ custom ("Type" <+> doc1 <+> "does not have field" <+> f + <+> "of type" <+> (tys !! 1))+ where f = case sel of+ P.TupleSel n _ -> int n+ P.RecordSel fl _ -> backticks (pp fl)+ P.ListSel n _ -> int n++ PZero ->+ custom ("Type" <+> doc1 <+> "does not have `zero`")++ PLogic ->+ custom ("Type" <+> doc1 <+> "does not support logical operations.")++ PRing ->+ custom ("Type" <+> doc1 <+> "does not support ring operations.")++ PIntegral ->+ custom (doc1 <+> "is not an integral type.")++ PField ->+ custom ("Type" <+> doc1 <+> "does not support field operations.")++ PRound ->+ custom ("Type" <+> doc1 <+> "does not support rounding operations.")++ PEq ->+ custom ("Type" <+> doc1 <+> "does not support equality.")++ PCmp ->+ custom ("Type" <+> doc1 <+> "does not support comparisons.")++ PSignedCmp ->+ custom ("Type" <+> doc1 <+> "does not support signed comparisons.")++ PLiteral ->+ let doc2 = tys !! 1+ in custom (doc1 <+> "is not a valid literal of type" <+> doc2)++ PFLiteral ->+ case ts of+ ~[m,n,_r,_a] ->+ let frac = backticks (ppWithNamesPrec names 4 m <> "/" <>+ ppWithNamesPrec names 4 n)+ ty = tys !! 3+ in custom (frac <+> "is not a valid literal of type" <+> ty)++ PValidFloat ->+ case ts of+ ~[e,p] ->+ custom ("Unsupported floating point parameters:" $$+ nest 2 ("exponent =" <+> ppWithNames names e $$+ "precision =" <+> ppWithNames names p))+++ PAnd -> useCtr+ PTrue -> useCtr++ _ -> useCtr+++++-- | This picks the names to use when showing errors and warnings.+computeFreeVarNames :: [(Range,Warning)] -> [(Range,Error)] -> NameMap+computeFreeVarNames warns errs =+ mkMap numRoots numVaras `IntMap.union` mkMap otherRoots otherVars++ {- XXX: Currently we pick the names based on the unique of the variable:+ smaller uniques get an earlier name (e.g., 100 might get `a` and 200 `b`)+ This may still lead to changes in the names if the uniques got reordred+ for some reason. A more stable approach might be to order the variables+ on their location in the error/warning, but that's quite a bit more code+ so for now we just go with the simple approximation. -}++ where+ mkName x v = (tvUnique x, v)+ mkMap roots vs = IntMap.fromList (zipWith mkName vs (variants roots))++ (numVaras,otherVars) = partition ((== KNum) . kindOf)+ $ Set.toList+ $ Set.filter isFreeTV+ $ fvs (map snd warns, map snd errs)++ otherRoots = [ "a", "b", "c", "d" ]+ numRoots = [ "m", "n", "u", "v" ]++ useUnicode = True++ suff n+ | n < 10 && useUnicode = [toEnum (0x2080 + n)]+ | otherwise = show n++ variant n x = if n == 0 then x else x ++ suff n++ variants roots = [ variant n r | n <- [ 0 .. ], r <- roots ]+
src/Cryptol/TypeCheck/Infer.hs view
@@ -45,7 +45,6 @@ import Cryptol.TypeCheck.Subst (listSubst,apSubst,(@@),isEmptySubst) import Cryptol.Utils.Ident import Cryptol.Utils.Panic(panic)-import Cryptol.Utils.PP import Cryptol.Utils.RecordMap import qualified Data.Map as Map@@ -117,19 +116,19 @@ P.ECNum num info -> number $ [ ("val", P.TNum num) ] ++ case info of- P.BinLit n -> [ ("rep", tBits (1 * toInteger n)) ]- P.OctLit n -> [ ("rep", tBits (3 * toInteger n)) ]- P.HexLit n -> [ ("rep", tBits (4 * toInteger n)) ]- P.DecLit -> [ ]+ P.BinLit _ n -> [ ("rep", tBits (1 * toInteger n)) ]+ P.OctLit _ n -> [ ("rep", tBits (3 * toInteger n)) ]+ P.HexLit _ n -> [ ("rep", tBits (4 * toInteger n)) ]+ P.DecLit _ -> [ ] P.PolyLit _n -> [ ("rep", P.TSeq P.TWild P.TBit) ] P.ECFrac fr info -> let arg f = P.PosInst (P.TNum (f fr)) rnd = P.PosInst (P.TNum (case info of- P.DecFrac -> 0- P.BinFrac -> 1- P.OctFrac -> 1- P.HexFrac -> 1))+ P.DecFrac _ -> 0+ P.BinFrac _ -> 1+ P.OctFrac _ -> 1+ P.HexFrac _ -> 1)) in P.EAppT fracPrim [ arg numerator, arg denominator, rnd ] P.ECChar c ->@@ -143,7 +142,7 @@ -- | Infer the type of an expression with an explicit instantiation.-appTys :: P.Expr Name -> [TypeArg] -> Type -> InferM Expr+appTys :: P.Expr Name -> [TypeArg] -> TypeWithSource -> InferM Expr appTys expr ts tGoal = case expr of P.EVar x ->@@ -221,7 +220,7 @@ -- | Infer the type of an expression, and translate it to a fully elaborated -- core term.-checkE :: P.Expr Name -> Type -> InferM Expr+checkE :: P.Expr Name -> TypeWithSource -> InferM Expr checkE expr tGoal = case expr of P.EVar x ->@@ -245,7 +244,7 @@ do prim <- mkPrim "generate" checkE (P.EApp prim e) tGoal - P.ELit l@(P.ECNum _ P.DecLit) ->+ P.ELit l@(P.ECNum _ (P.DecLit _)) -> do e <- desugarLiteral l -- NOTE: When 'l' is a decimal literal, 'desugarLiteral' does -- not generate an instantiation for the 'rep' type argument@@ -254,7 +253,7 @@ -- generating an unnecessary unification variable. loc <- curRange let arg = TypeArg { tyArgName = Just (Located loc (packIdent "rep"))- , tyArgType = Checked tGoal+ , tyArgType = Checked (twsType tGoal) } appTys e [arg] tGoal @@ -262,31 +261,35 @@ P.ETuple es -> do etys <- expectTuple (length es) tGoal- es' <- zipWithM checkE es etys+ let mkTGoal n t = WithSource t (TypeOfTupleField n)+ es' <- zipWithM checkE es (zipWith mkTGoal [1..] etys) return (ETuple es') P.ERecord fs -> do es <- expectRec fs tGoal- es' <- traverse (uncurry checkE) es+ let checkField f (e,t) = checkE e (WithSource t (TypeOfRecordField f))+ es' <- traverseRecordMap checkField es return (ERec es') P.EUpd x fs -> checkRecUpd x fs tGoal P.ESel e l ->- do t <- newType (selSrc l) KType- e' <- checkE e t- f <- newHasGoal l t tGoal+ do let src = selSrc l+ t <- newType src KType+ e' <- checkE e (WithSource t src)+ f <- newHasGoal l t (twsType tGoal) return (hasDoSelect f e') P.EList [] -> do (len,a) <- expectSeq tGoal- expectFin 0 len+ expectFin 0 (WithSource len LenOfSeq) return (EList [] a) P.EList es -> do (len,a) <- expectSeq tGoal- expectFin (length es) len- es' <- mapM (`checkE` a) es+ expectFin (length es) (WithSource len LenOfSeq)+ let checkElem e = checkE e (WithSource a TypeOfSeqElement)+ es' <- mapM checkElem es return (EList es' a) P.EFromTo t1 mbt2 t3 mety ->@@ -322,22 +325,25 @@ do (mss', dss, ts) <- unzip3 `fmap` zipWithM inferCArm [ 1 .. ] mss (len,a) <- expectSeq tGoal - newGoals CtComprehension =<< unify len =<< smallest ts+ inferred <- smallest ts+ ctrs <- unify (WithSource len LenOfSeq) inferred+ newGoals CtComprehension ctrs ds <- combineMaps dss- e' <- withMonoTypes ds (checkE e a)+ e' <- withMonoTypes ds (checkE e (WithSource a TypeOfSeqElement)) return (EComp len a e' mss') P.EAppT e fs -> appTys e (map uncheckedTypeArg fs) tGoal P.EApp e1 e2 ->- do t1 <- newType (TypeOfArg Nothing) KType- e1' <- checkE e1 (tFun t1 tGoal)- e2' <- checkE e2 t1+ do let argSrc = TypeOfArg noArgDescr+ t1 <- newType argSrc KType+ e1' <- checkE e1 (WithSource (tFun t1 (twsType tGoal)) FunApp)+ e2' <- checkE e2 (WithSource t1 argSrc) return (EApp e1' e2') P.EIf e1 e2 e3 ->- do e1' <- checkE e1 tBit+ do e1' <- checkE e1 (WithSource tBit TypeOfIfCondExpr) e2' <- checkE e2 tGoal e3' <- checkE e3 tGoal return (EIf e1' e2' e3')@@ -348,7 +354,7 @@ P.ETyped e t -> do tSig <- checkTypeOfKind t KType- e' <- checkE e tSig+ e' <- checkE e (WithSource tSig TypeFromUserAnnotation) checkHasType tSig tGoal return e' @@ -360,7 +366,7 @@ P.Named { name = Located l (packIdent "val") , value = t }]) tGoal - P.EFun ps e -> checkFun (text "anonymous function") ps e tGoal+ P.EFun ps e -> checkFun Nothing ps e tGoal P.ELocated e r -> inRange r (checkE e tGoal) @@ -373,13 +379,8 @@ P.EParens e -> checkE e tGoal -selSrc :: P.Selector -> TVarSource-selSrc l = case l of- RecordSel la _ -> TypeOfRecordField la- TupleSel n _ -> TypeOfTupleField n- ListSel _ _ -> TypeOfSeqElement--checkRecUpd :: Maybe (P.Expr Name) -> [ P.UpdField Name ] -> Type -> InferM Expr+checkRecUpd ::+ Maybe (P.Expr Name) -> [ P.UpdField Name ] -> TypeWithSource -> InferM Expr checkRecUpd mb fs tGoal = case mb of @@ -400,21 +401,24 @@ [l] -> case how of P.UpdSet ->- do ft <- newType (selSrc s) KType- v1 <- checkE v ft- d <- newHasGoal s tGoal ft+ do let src = selSrc s+ ft <- newType src KType+ v1 <- checkE v (WithSource ft src)+ d <- newHasGoal s (twsType tGoal) ft pure (hasDoSet d e v1) P.UpdFun ->- do ft <- newType (selSrc s) KType- v1 <- checkE v (tFun ft ft)- d <- newHasGoal s tGoal ft+ do let src = selSrc s+ ft <- newType src KType+ v1 <- checkE v (WithSource (tFun ft ft) src)+ -- XXX: ^ may be used a different src?+ d <- newHasGoal s (twsType tGoal) ft tmp <- newParamName (packIdent "rf") let e' = EVar tmp pure $ hasDoSet d e' (EApp v1 (hasDoSelect d e')) `EWhere` [ NonRecursive Decl { dName = tmp- , dSignature = tMono tGoal+ , dSignature = tMono (twsType tGoal) , dDefinition = DExpr e , dPragmas = [] , dInfix = False@@ -428,24 +432,24 @@ ] -expectSeq :: Type -> InferM (Type,Type)-expectSeq ty =+expectSeq :: TypeWithSource -> InferM (Type,Type)+expectSeq tGoal@(WithSource ty src) = case ty of TUser _ _ ty' ->- expectSeq ty'+ expectSeq (WithSource ty' src) TCon (TC TCSeq) [a,b] -> return (a,b) TVar _ -> do tys@(a,b) <- genTys- newGoals CtExactType =<< unify ty (tSeq a b)+ newGoals CtExactType =<< unify tGoal (tSeq a b) return tys _ -> do tys@(a,b) <- genTys- recordError (TypeMismatch ty (tSeq a b))+ recordError (TypeMismatch src ty (tSeq a b)) return tys where genTys =@@ -454,36 +458,39 @@ return (a,b) -expectTuple :: Int -> Type -> InferM [Type]-expectTuple n ty =+expectTuple :: Int -> TypeWithSource -> InferM [Type]+expectTuple n tGoal@(WithSource ty src) = case ty of TUser _ _ ty' ->- expectTuple n ty'+ expectTuple n (WithSource ty' src) TCon (TC (TCTuple n')) tys | n == n' -> return tys TVar _ -> do tys <- genTys- newGoals CtExactType =<< unify ty (tTuple tys)+ newGoals CtExactType =<< unify tGoal (tTuple tys) return tys _ -> do tys <- genTys- recordError (TypeMismatch ty (tTuple tys))+ recordError (TypeMismatch src ty (tTuple tys)) return tys where genTys =forM [ 0 .. n - 1 ] $ \ i -> newType (TypeOfTupleField i) KType -expectRec :: RecordMap Ident (Range, a) -> Type -> InferM (RecordMap Ident (a, Type))-expectRec fs ty =+expectRec ::+ RecordMap Ident (Range, a) ->+ TypeWithSource ->+ InferM (RecordMap Ident (a, Type))+expectRec fs tGoal@(WithSource ty src) = case ty of TUser _ _ ty' ->- expectRec fs ty'+ expectRec fs (WithSource ty' src) TRec ls | Right r <- zipRecords (\_ (_rng,v) t -> (v,t)) fs ls -> pure r@@ -496,27 +503,26 @@ fs let tys = fmap snd res case ty of- TVar TVFree{} -> do ps <- unify ty (TRec tys)+ TVar TVFree{} -> do ps <- unify tGoal (TRec tys) newGoals CtExactType ps- _ -> recordError (TypeMismatch ty (TRec tys))+ _ -> recordError (TypeMismatch src ty (TRec tys)) return res -expectFin :: Int -> Type -> InferM ()-expectFin n ty =+expectFin :: Int -> TypeWithSource -> InferM ()+expectFin n tGoal@(WithSource ty src) = case ty of TUser _ _ ty' ->- expectFin n ty'+ expectFin n (WithSource ty' src) TCon (TC (TCNum n')) [] | toInteger n == n' -> return () - _ ->- do newGoals CtExactType =<< unify ty (tNum n)+ _ -> newGoals CtExactType =<< unify tGoal (tNum n) -expectFun :: Int -> Type -> InferM ([Type],Type)-expectFun = go []+expectFun :: Maybe Name -> Int -> TypeWithSource -> InferM ([Type],Type)+expectFun mbN n (WithSource ty0 src) = go [] n ty0 where go tys arity ty@@ -533,37 +539,38 @@ do args <- genArgs arity res <- newType TypeOfRes KType case ty of- TVar TVFree{} -> do ps <- unify ty (foldr tFun res args)- newGoals CtExactType ps- _ -> recordError (TypeMismatch ty (foldr tFun res args))+ TVar TVFree{} ->+ do ps <- unify (WithSource ty src) (foldr tFun res args)+ newGoals CtExactType ps+ _ -> recordError (TypeMismatch src ty (foldr tFun res args)) return (reverse tys ++ args, res) | otherwise = return (reverse tys, ty) genArgs arity = forM [ 1 .. arity ] $- \ ix -> newType (TypeOfArg (Just ix)) KType+ \ ix -> newType (TypeOfArg (ArgDescr mbN (Just ix))) KType -checkHasType :: Type -> Type -> InferM ()-checkHasType inferredType givenType =- do ps <- unify givenType inferredType+checkHasType :: Type -> TypeWithSource -> InferM ()+checkHasType inferredType tGoal =+ do ps <- unify tGoal inferredType case ps of [] -> return () _ -> newGoals CtExactType ps -checkFun :: Doc -> [P.Pattern Name] -> P.Expr Name -> Type -> InferM Expr+checkFun ::+ Maybe Name -> [P.Pattern Name] -> P.Expr Name -> TypeWithSource -> InferM Expr checkFun _ [] e tGoal = checkE e tGoal-checkFun desc ps e tGoal =+checkFun fun ps e tGoal = inNewScope $- do let descs = [ text "type of" <+> ordinal n <+> text "argument"- <+> text "of" <+> desc | n <- [ 1 :: Int .. ] ]+ do let descs = [ TypeOfArg (ArgDescr fun (Just n)) | n <- [ 1 :: Int .. ] ] - (tys,tRes) <- expectFun (length ps) tGoal- largs <- sequence (zipWith3 checkP descs ps tys)+ (tys,tRes) <- expectFun fun (length ps) tGoal+ largs <- sequence (zipWith checkP ps (zipWith WithSource tys descs)) let ds = Map.fromList [ (thing x, x { thing = t }) | (x,t) <- zip largs tys ]- e1 <- withMonoTypes ds (checkE e tRes)+ e1 <- withMonoTypes ds (checkE e (WithSource tRes TypeOfRes)) let args = [ (thing x, t) | (x,t) <- zip largs tys ] return (foldr (\(x,t) b -> EAbs x t b) e1 args)@@ -577,20 +584,20 @@ newGoals CtComprehension [ a =#= foldr1 tMin ts ] return a -checkP :: Doc -> P.Pattern Name -> Type -> InferM (Located Name)-checkP desc p tGoal =- do (x, t) <- inferP desc p+checkP :: P.Pattern Name -> TypeWithSource -> InferM (Located Name)+checkP p tGoal@(WithSource _ src) =+ do (x, t) <- inferP p ps <- unify tGoal (thing t)- let rng = fromMaybe emptyRange $ getLoc p- let mkErr = recordError . UnsolvedGoals Nothing . (:[])- . Goal (CtPattern desc) rng+ let rng = fromMaybe emptyRange (getLoc p)+ let mkErr = recordError . UnsolvedGoals . (:[])+ . Goal (CtPattern src) rng mapM_ mkErr ps return (Located (srcRange t) x) {-| Infer the type of a pattern. Assumes that the pattern will be just a variable. -}-inferP :: Doc -> P.Pattern Name -> InferM (Name, Located Type)-inferP desc pat =+inferP :: P.Pattern Name -> InferM (Name, Located Type)+inferP pat = case pat of P.PVar x0 ->@@ -599,7 +606,7 @@ P.PTyped p t -> do tSig <- checkTypeOfKind t KType- ln <- checkP desc p tSig+ ln <- checkP p (WithSource tSig TypeFromUserAnnotation) return (thing ln, ln { thing = tSig }) _ -> tcPanic "inferP" [ "Unexpected pattern:", show pat ]@@ -609,9 +616,9 @@ -- | Infer the type of one match in a list comprehension. inferMatch :: P.Match Name -> InferM (Match, Name, Located Type, Type) inferMatch (P.Match p e) =- do (x,t) <- inferP (text "a value bound by a generator in a comprehension") p+ do (x,t) <- inferP p n <- newType LenOfCompGen KNum- e' <- checkE e (tSeq n (thing t))+ e' <- checkE e (WithSource (tSeq n (thing t)) GeneratorOfListComp) return (From x n (thing t) e', x, t, n) inferMatch (P.MatchLet b)@@ -645,7 +652,7 @@ -- | @inferBinds isTopLevel isRec binds@ performs inference for a -- strongly-connected component of 'P.Bind's. -- If any of the members of the recursive group are already marked--- as monomorphic, then we don't do generalzation.+-- as monomorphic, then we don't do generalization. -- If @isTopLevel@ is true, -- any bindings without type signatures will be generalized. If it is -- false, and the mono-binds flag is enabled, no bindings without type@@ -857,7 +864,9 @@ P.DPrim -> panic "checkMonoB" ["Primitive with no signature?"] P.DExpr e ->- do e1 <- checkFun (pp (thing (P.bName b))) (P.bParams b) e t+ do let nm = thing (P.bName b)+ let tGoal = WithSource t (DefinitionOf nm)+ e1 <- checkFun (Just nm) (P.bParams b) e tGoal let f = thing (P.bName b) return Decl { dName = f , dSignature = Forall [] [] t@@ -887,12 +896,16 @@ inRangeMb (getLoc b) $ withTParams as $ do (e1,cs0) <- collectGoals $- do e1 <- checkFun (pp (thing (P.bName b))) (P.bParams b) e0 t0+ do let nm = thing (P.bName b)+ tGoal = WithSource t0 (DefinitionOf nm)+ e1 <- checkFun (Just nm) (P.bParams b) e0 tGoal addGoals validSchema () <- simplifyAllConstraints -- XXX: using `asmps` also? return e1- cs <- applySubstGoals cs0 + asmps1 <- applySubstPreds asmps0+ cs <- applySubstGoals cs0+ let findKeep vs keep todo = let stays (_,cvs) = not $ Set.null $ Set.intersection vs cvs (yes,perhaps) = partition stays todo@@ -901,12 +914,14 @@ [] -> (keep,map fst todo) _ -> findKeep (Set.unions (vs:newVars)) (stayPs ++ keep) perhaps - let (stay,leave) = findKeep (Set.fromList (map tpVar as)) []+ let -- if a goal mentions any of these variables, we'll commit to+ -- solving it now.+ stickyVars = Set.fromList (map tpVar as) `Set.union` fvs asmps1+ (stay,leave) = findKeep stickyVars [] [ (c, fvs c) | c <- cs ] addGoals leave - asmps1 <- applySubstPreds asmps0 su <- proveImplication (Just (thing (P.bName b))) as asmps1 stay extendSubst su
src/Cryptol/TypeCheck/InferTypes.hs view
@@ -176,12 +176,20 @@ | CtDefaulting -- ^ Just defaulting on the command line | CtPartialTypeFun Name -- ^ Use of a partial type function. | CtImprovement- | CtPattern Doc -- ^ Constraints arising from type-checking patterns+ | CtPattern TypeSource -- ^ Constraints arising from type-checking patterns | CtModuleInstance ModName -- ^ Instantiating a parametrized module deriving (Show, Generic, NFData) +selSrc :: Selector -> TypeSource+selSrc l = case l of+ RecordSel la _ -> TypeOfRecordField la+ TupleSel n _ -> TypeOfTupleField n+ ListSel _ _ -> TypeOfSeqElement +++ instance TVars ConstraintSource where apSubst su src = case src of@@ -300,7 +308,7 @@ CtDefaulting -> "defaulting" CtPartialTypeFun f -> "use of partial type function" <+> pp f CtImprovement -> "examination of collected goals"- CtPattern desc -> "checking a pattern:" <+> desc+ CtPattern ad -> "checking a pattern:" <+> pp ad CtModuleInstance n -> "module instantiation" <+> pp n ppUse :: Expr -> Doc@@ -308,6 +316,7 @@ case expr of EVar (isPrelPrim -> Just prim) | prim == "number" -> "literal or demoted expression"+ | prim == "fraction" -> "fractional literal" | prim == "infFrom" -> "infinite enumeration" | prim == "infFromThen" -> "infinite enumeration (with step)" | prim == "fromTo" -> "finite enumeration"
src/Cryptol/TypeCheck/Instantiate.hs view
@@ -50,12 +50,12 @@ -checkTyParam :: TVarSource -> Kind -> MaybeCheckedType -> InferM Type+checkTyParam :: TypeSource -> Kind -> MaybeCheckedType -> InferM Type checkTyParam src k mb = case mb of Checked t | k == k' -> pure t- | otherwise -> do recordError (KindMismatch k k')+ | otherwise -> do recordError (KindMismatch (Just src) k k') newType src k where k' = kindOf t Unchecked t -> checkType t (Just k)@@ -203,5 +203,7 @@ checkInst :: (TParam, Type) -> InferM [Prop] checkInst (tp, ty) | Set.notMember tp bounds = return []- | otherwise = unify (TVar (tpVar tp)) ty+ | otherwise = let a = tpVar tp+ src = tvarDesc (tvInfo a)+ in unify (WithSource (TVar a) src) ty
src/Cryptol/TypeCheck/Kind.hs view
@@ -36,6 +36,7 @@ import Data.List(sortBy,groupBy) import Data.Maybe(fromMaybe) import Data.Function(on)+import Data.Text (Text) import Control.Monad(unless,forM,when) @@ -66,7 +67,7 @@ -- | Check a module parameter declarations. Nothing much to check, -- we just translate from one syntax to another.-checkParameterType :: P.ParameterType Name -> Maybe String -> InferM ModTParam+checkParameterType :: P.ParameterType Name -> Maybe Text -> InferM ModTParam checkParameterType a mbDoc = do let k = cvtK (P.ptKind a) n = thing (P.ptName a)@@ -75,7 +76,7 @@ -- | Check a type-synonym declaration.-checkTySyn :: P.TySyn Name -> Maybe String -> InferM TySyn+checkTySyn :: P.TySyn Name -> Maybe Text -> InferM TySyn checkTySyn (P.TySyn x _ as t) mbD = do ((as1,t1),gs) <- collectGoals $ inRange (srcRange x)@@ -91,7 +92,7 @@ } -- | Check a constraint-synonym declaration.-checkPropSyn :: P.PropSyn Name -> Maybe String -> InferM TySyn+checkPropSyn :: P.PropSyn Name -> Maybe Text -> InferM TySyn checkPropSyn (P.PropSyn x _ as ps) mbD = do ((as1,t1),gs) <- collectGoals $ inRange (srcRange x)@@ -108,7 +109,7 @@ -- | Check a newtype declaration. -- XXX: Do something with constraints.-checkNewtype :: P.Newtype Name -> Maybe String -> InferM Newtype+checkNewtype :: P.Newtype Name -> Maybe Text -> InferM Newtype checkNewtype (P.Newtype x as fs) mbD = do ((as1,fs1),gs) <- collectGoals $ inRange (srcRange x) $@@ -128,7 +129,7 @@ , ntDoc = mbD } -checkPrimType :: P.PrimType Name -> Maybe String -> InferM AbstractType+checkPrimType :: P.PrimType Name -> Maybe Text -> InferM AbstractType checkPrimType p mbD = do let (as,cs) = P.primTCts p (as',cs') <- withTParams NoWildCards (TPOther . Just) as $@@ -302,7 +303,7 @@ do let ty = tpVar (mtpParam a) (ts1,k1) <- appTy ts (kindOf ty) case k of- Just ks | ks /= k1 -> kRecordError $ KindMismatch ks k1+ Just ks | ks /= k1 -> kRecordError $ KindMismatch Nothing ks k1 _ -> return () unless (null ts1) $@@ -405,7 +406,7 @@ -> Kind -- ^ Inferred kind -> KindM Type -- ^ A type consistent with expectations. checkKind _ (Just k1) k2- | k1 /= k2 = do kRecordError (KindMismatch k1 k2)+ | k1 /= k2 = do kRecordError (KindMismatch Nothing k1 k2) kNewType TypeErrorPlaceHolder k1 checkKind t _ _ = return t
src/Cryptol/TypeCheck/Monad.hs view
@@ -6,6 +6,7 @@ -- Stability : provisional -- Portability : portable {-# LANGUAGE Safe #-}+{-# LANGUAGE BangPatterns #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE RecordWildCards #-}@@ -26,11 +27,13 @@ import Cryptol.TypeCheck.Subst import Cryptol.TypeCheck.Unify(mgu, runResult, UnificationError(..)) import Cryptol.TypeCheck.InferTypes-import Cryptol.TypeCheck.Error(Warning(..),Error(..),cleanupErrors)-import Cryptol.TypeCheck.PP (brackets, commaSep)+import Cryptol.TypeCheck.Error( Warning(..),Error(..)+ , cleanupErrors, computeFreeVarNames+ ) import qualified Cryptol.TypeCheck.SimpleSolver as Simple import qualified Cryptol.TypeCheck.Solver.SMT as SMT-import Cryptol.Utils.PP(pp, (<+>), text, quotes)+import Cryptol.TypeCheck.PP(NameMap)+import Cryptol.Utils.PP(pp, (<+>), text,commaSep,brackets) import Cryptol.Utils.Ident(Ident) import Cryptol.Utils.Panic(panic) @@ -48,7 +51,6 @@ import Data.IORef - import GHC.Generics (Generic) import Control.DeepSeq @@ -98,10 +100,10 @@ -- | The results of type inference. data InferOutput a- = InferFailed [(Range,Warning)] [(Range,Error)]+ = InferFailed NameMap [(Range,Warning)] [(Range,Error)] -- ^ We found some errors - | InferOK [(Range,Warning)] NameSeeds Supply a+ | InferOK NameMap [(Range,Warning)] NameSeeds Supply a -- ^ Type inference was successful. @@ -113,7 +115,7 @@ runInferM :: TVars a => InferInput -> InferM a -> IO (InferOutput a) runInferM info (IM m) = SMT.withSolver (inpSolverConfig info) $ \solver ->- do coutner <- newIORef 0+ do counter <- newIORef 0 rec ro <- return RO { iRange = inpRange info , iVars = Map.map ExtVar (inpVars info) , iTVars = []@@ -128,7 +130,7 @@ , iMonoBinds = inpMonoBinds info , iSolver = solver , iPrimNames = inpPrimNames info- , iSolveCounter = coutner+ , iSolveCounter = counter } (result, finalRW) <- runStateT rw@@ -136,27 +138,32 @@ let theSu = iSubst finalRW defSu = defaultingSubst theSu- warns = [(r,apSubst theSu w) | (r,w) <- iWarnings finalRW ]+ warns = fmap' (fmap' (apSubst theSu)) (iWarnings finalRW) case iErrors finalRW of [] -> case (iCts finalRW, iHasCts finalRW) of (cts,[])- | nullGoals cts- -> return $ InferOK warns+ | nullGoals cts -> inferOk warns (iNameSeeds finalRW) (iSupply finalRW) (apSubst defSu result)- (cts,has) -> return $ InferFailed warns- $ cleanupErrors+ (cts,has) ->+ inferFailed warns [ ( goalRange g- , UnsolvedGoals Nothing [apSubst theSu g]+ , UnsolvedGoals [apSubst theSu g] ) | g <- fromGoals cts ++ map hasGoal has ]- errs -> return $ InferFailed warns- $ cleanupErrors [(r,apSubst theSu e) | (r,e) <- errs] + errs -> inferFailed warns [(r,apSubst theSu e) | (r,e) <- errs]+ where+ inferOk ws a b c = pure (InferOK (computeFreeVarNames ws []) ws a b c)+ inferFailed ws es =+ let es1 = cleanupErrors es+ in pure (InferFailed (computeFreeVarNames ws es1) ws es1)++ mkExternal x = (IsExternal, x) rw = RW { iErrors = [] , iWarnings = []@@ -390,8 +397,8 @@ simpGoal :: Goal -> InferM [Goal] simpGoal g = case Simple.simplify mempty (goal g) of- p | Just (e,t) <- tIsError p ->- do recordError $ UnsolvedGoals (Just e) [g { goal = t }]+ p | Just t <- tIsError p ->+ do recordError $ UnsolvableGoals [g { goal = t }] return [] | ps <- pSplitAnd p -> return [ g { goal = pr } | pr <- ps ] @@ -453,12 +460,12 @@ in (x, s { seedGoal = x + 1}) -- | Generate a new free type variable.-newTVar :: TVarSource -> Kind -> InferM TVar+newTVar :: TypeSource -> Kind -> InferM TVar newTVar src k = newTVar' src Set.empty k -- | Generate a new free type variable that depends on these additional -- type parameters.-newTVar' :: TVarSource -> Set TParam -> Kind -> InferM TVar+newTVar' :: TypeSource -> Set TParam -> Kind -> InferM TVar newTVar' src extraBound k = do r <- curRange bound <- getBoundInScope@@ -485,7 +492,7 @@ -- | Generate an unknown type. The doc is a note about what is this type about.-newType :: TVarSource -> Kind -> InferM Type+newType :: TypeSource -> Kind -> InferM Type newType src k = TVar `fmap` newTVar src k @@ -494,8 +501,8 @@ -- | Record that the two types should be syntactically equal.-unify :: Type -> Type -> InferM [Prop]-unify t1 t2 =+unify :: TypeWithSource -> Type -> InferM [Prop]+unify (WithSource t1 src) t2 = do t1' <- applySubst t1 t2' <- applySubst t2 let ((su1, ps), errs) = runResult (mgu t1' t2')@@ -503,12 +510,12 @@ let toError :: UnificationError -> Error toError err = case err of- UniTypeLenMismatch _ _ -> TypeMismatch t1' t2'- UniTypeMismatch s1 s2 -> TypeMismatch s1 s2- UniKindMismatch k1 k2 -> KindMismatch k1 k2- UniRecursive x t -> RecursiveType (TVar x) t- UniNonPolyDepends x vs -> TypeVariableEscaped (TVar x) vs- UniNonPoly x t -> NotForAll x t+ UniTypeLenMismatch _ _ -> TypeMismatch src t1' t2'+ UniTypeMismatch s1 s2 -> TypeMismatch src s1 s2+ UniKindMismatch k1 k2 -> KindMismatch (Just src) k1 k2+ UniRecursive x t -> RecursiveType src (TVar x) t+ UniNonPolyDepends x vs -> TypeVariableEscaped src (TVar x) vs+ UniNonPoly x t -> NotForAll src x t case errs of [] -> return ps _ -> do mapM_ (recordError . toError) errs@@ -636,9 +643,7 @@ Nothing -> case scopes of [] ->- do recordError $ ErrorMsg- $ text "Undefined type" <+> quotes (pp x)- <+> text (show x)+ do recordError (UndefinedExistVar x) newType TypeErrorPlaceHolder k sc : more ->@@ -709,10 +714,7 @@ case shadowed of Nothing -> return () Just that ->- recordError $ ErrorMsg $- text "Type" <+> text this <+> quotes (pp new) <+>- text "shadows an existing" <+>- text that <+> text "with the same name."+ recordError (TypeShadowing this new that) @@ -891,7 +893,7 @@ -- NOTE: We do not simplify these, because we end up with bottom. -- See `Kind.hs` -- XXX: Perhaps we can avoid the recursion?-kNewType :: TVarSource -> Kind -> KindM Type+kNewType :: TypeSource -> Kind -> KindM Type kNewType src k = do tps <- KM $ do vs <- asks lazyTParams return $ Set.fromList (Map.elems vs)
src/Cryptol/TypeCheck/Parseable.hs view
@@ -35,7 +35,7 @@ showParseable (ETuple es) = parens (text "ETuple" <+> showParseable es) showParseable (ERec ides) = parens (text "ERec" <+> showParseable (canonicalFields ides)) showParseable (ESel e s) = parens (text "ESel" <+> showParseable e <+> showParseable s)- showParseable (ESet e s v) = parens (text "ESet" <+>+ showParseable (ESet _ty e s v) = parens (text "ESet" <+> showParseable e <+> showParseable s <+> showParseable v) showParseable (EIf c t f) = parens (text "EIf" <+> showParseable c $$ showParseable t $$ showParseable f)
src/Cryptol/TypeCheck/Sanity.hs view
@@ -159,13 +159,14 @@ do fs1 <- traverse exprType fs return $ tMono $ TRec fs1 - ESet e x v -> do ty <- exprType e- expe <- checkHas ty x- has <- exprType v- unless (same expe has) $- reportError $- TypeMismatch "ESet" (tMono expe) (tMono has)- return (tMono ty)+ ESet _ e x v ->+ do ty <- exprType e+ expe <- checkHas ty x+ has <- exprType v+ unless (same expe has) $+ reportError $+ TypeMismatch "ESet" (tMono expe) (tMono has)+ return (tMono ty) ESel e sel -> do ty <- exprType e ty1 <- checkHas ty sel
src/Cryptol/TypeCheck/SimpType.hs view
@@ -108,7 +108,7 @@ tSub :: Type -> Type -> Type tSub x y | Just t <- tOp TCSub (op2 nSub) [x,y] = t- | tIsInf y = tError (tf2 TCSub x y) "cannot subtract `inf`."+ | tIsInf y = tError (tf2 TCSub x y) | Just 0 <- yNum = x | Just k <- yNum , TCon (TF TCAdd) [a,b] <- tNoUser x@@ -165,34 +165,34 @@ tDiv :: Type -> Type -> Type tDiv x y | Just t <- tOp TCDiv (op2 nDiv) [x,y] = t- | tIsInf x = bad "Cannot divide `inf`"- | Just 0 <- tIsNum y = bad "Cannot divide by 0"+ | tIsInf x = bad+ | Just 0 <- tIsNum y = bad | otherwise = tf2 TCDiv x y where bad = tError (tf2 TCDiv x y) tMod :: Type -> Type -> Type tMod x y | Just t <- tOp TCMod (op2 nMod) [x,y] = t- | tIsInf x = bad "Cannot compute remainder of `inf`"- | Just 0 <- tIsNum y = bad "Cannot divide modulo 0"+ | tIsInf x = bad+ | Just 0 <- tIsNum y = bad | otherwise = tf2 TCMod x y where bad = tError (tf2 TCMod x y) tCeilDiv :: Type -> Type -> Type tCeilDiv x y | Just t <- tOp TCCeilDiv (op2 nCeilDiv) [x,y] = t- | tIsInf x = bad "CeilDiv of `inf`"- | tIsInf y = bad "CeilDiv by `inf`"- | Just 0 <- tIsNum y = bad "CeilDiv by 0"+ | tIsInf x = bad+ | tIsInf y = bad+ | Just 0 <- tIsNum y = bad | otherwise = tf2 TCCeilDiv x y where bad = tError (tf2 TCCeilDiv x y) tCeilMod :: Type -> Type -> Type tCeilMod x y | Just t <- tOp TCCeilMod (op2 nCeilMod) [x,y] = t- | tIsInf x = bad "CeilMod of `inf`"- | tIsInf y = bad "CeilMod by `inf`"- | Just 0 <- tIsNum x = bad "CeilMod to size 0"+ | tIsInf x = bad+ | tIsInf y = bad+ | Just 0 <- tIsNum x = bad | otherwise = tf2 TCCeilMod x y where bad = tError (tf2 TCCeilMod x y) @@ -304,12 +304,15 @@ op3 f ~[x,y,z] = f x y z -- | Common checks: check for error, or simple full evaluation.+-- We assume that input kinds and the result kind are the same (i.e., Nat) tOp :: TFun -> ([Nat'] -> Maybe Nat') -> [Type] -> Maybe Type tOp tf f ts- | Just (TCErrorMessage e,t) <- msum (map tIsError ts) = Just (tError t e)+ | Just t <- msum (map tIsError ts) = Just (tError t)+ -- assumes result kind the same as input kind+ | Just xs <- mapM tIsNat' ts = Just $ case f xs of- Nothing -> tError (TCon (TF tf) (map tNat' xs)) "invalid type"+ Nothing -> tError (TCon (TF tf) (map tNat' xs)) Just n -> tNat' n | otherwise = Nothing
src/Cryptol/TypeCheck/SimpleSolver.hs view
@@ -5,7 +5,7 @@ ( tSub, tMul, tDiv, tMod, tExp, tMin, tLenFromThenTo) import Cryptol.TypeCheck.Solver.Types import Cryptol.TypeCheck.Solver.Numeric.Fin(cryIsFinType)-import Cryptol.TypeCheck.Solver.Numeric(cryIsEqual, cryIsNotEqual, cryIsGeq)+import Cryptol.TypeCheck.Solver.Numeric(cryIsEqual, cryIsNotEqual, cryIsGeq, cryIsPrime) import Cryptol.TypeCheck.Solver.Class ( solveZeroInst, solveLogicInst, solveRingInst , solveIntegralInst, solveFieldInst, solveRoundInst@@ -21,8 +21,10 @@ simplify :: Ctxt -> Prop -> Prop simplify ctxt p = case simplifyStep ctxt p of- Unsolvable (TCErrorMessage e) -> tError p e- Unsolved -> dbg msg p+ Unsolvable -> case tIsError p of+ Nothing -> tError p+ _ -> p+ Unsolved -> dbg msg p where msg = text "unsolved:" <+> pp p SolvedIf ps -> dbg msg $ pAnd (map (simplify ctxt) ps) where msg = case ps of@@ -56,6 +58,7 @@ TCon (PC PFLiteral) [t1,t2,t3,t4] -> solveFLiteralInst t1 t2 t3 t4 TCon (PC PValidFloat) [t1,t2] -> solveValidFloat t1 t2+ TCon (PC PPrime) [ty] -> cryIsPrime ctxt ty TCon (PC PFin) [ty] -> cryIsFinType ctxt ty TCon (PC PEqual) [t1,t2] -> cryIsEqual ctxt t1 t2
src/Cryptol/TypeCheck/Solve.hs view
@@ -37,18 +37,18 @@ import Control.Applicative ((<|>)) import Control.Monad(mzero)+import Data.Map (Map) import qualified Data.Map as Map import Data.Set ( Set ) import qualified Data.Set as Set import Data.List(partition)-import Data.Maybe(listToMaybe)+import Data.Maybe(listToMaybe,fromMaybe) -quickSolverIO :: Ctxt -> [Goal] ->- IO (Either (TCErrorMessage,Goal) (Subst,[Goal]))+quickSolverIO :: Ctxt -> [Goal] -> IO (Either Error (Subst,[Goal])) quickSolverIO _ [] = return (Right (emptySubst, [])) quickSolverIO ctxt gs = case quickSolver ctxt gs of@@ -73,7 +73,7 @@ quickSolver :: Ctxt -- ^ Facts we can know -> [Goal] -- ^ Need to solve these- -> Either (TCErrorMessage,Goal) (Subst,[Goal])+ -> Either Error (Subst,[Goal]) -- ^ Left: contradicting goals, -- Right: inferred types, unsolved goals. quickSolver ctxt gs0 = go emptySubst [] gs0@@ -81,32 +81,70 @@ go su [] [] = Right (su,[]) go su unsolved [] =- case matchMaybe (findImprovement unsolved) of- Nothing -> Right (su,unsolved)- Just (newSu, subs) -> go (newSu @@ su) [] (subs ++ apSubst newSu unsolved)+ case matchMaybe (findImprovement noIncompatible unsolved) of+ Nothing -> Right (su,unsolved)+ Just imp ->+ case imp of+ Right (newSu, subs) ->+ go (newSu @@ su) [] (subs ++ apSubst newSu unsolved)+ Left err -> Left err go su unsolved (g : gs) | Set.member (goal g) (saturatedAsmps ctxt) = go su unsolved gs go su unsolved (g : gs) = case Simplify.simplifyStep ctxt (goal g) of- Unsolvable e -> Left (e,g)+ Unsolvable -> Left (UnsolvableGoals [g]) Unsolved -> go su (g : unsolved) gs SolvedIf subs -> let cvt x = g { goal = x } in go su unsolved (map cvt subs ++ gs) -- Probably better to find more than one.- findImprovement [] = mzero- findImprovement (g : gs) =+ findImprovement inc [] =+ do let bad = Map.intersectionWith (,) (integralTVars inc) (fracTVars inc)+ case Map.minView bad of+ Just ((g1,g2),_) -> pure $ Left $ UnsolvableGoals [g1,g2]+ Nothing -> mzero++ findImprovement inc (g : gs) = do (su,ps) <- improveProp False ctxt (goal g)- return (su, [ g { goal = p } | p <- ps ])- <|> findImprovement gs+ return (Right (su, [ g { goal = p } | p <- ps ]))+ <|>+ findImprovement (addIncompatible g inc) gs +--------------------------------------------------------------------------------+-- Look for type variable with incompatible constraints +data Incompatible = Incompatible+ { integralTVars :: Map TVar Goal -- ^ Integral a+ , fracTVars :: Map TVar Goal -- ^ Field a or FLiteral + } +noIncompatible :: Incompatible+noIncompatible = Incompatible+ { integralTVars = Map.empty+ , fracTVars = Map.empty+ } +addIncompatible :: Goal -> Incompatible -> Incompatible+addIncompatible g i =+ fromMaybe i $+ do tv <- tIsVar =<< pIsIntegral (goal g)+ pure i { integralTVars = Map.insert tv g (integralTVars i) }+ <|>+ do tv <- tIsVar =<< pIsField (goal g)+ pure i { fracTVars = Map.insert tv g (fracTVars i) }+ <|>+ do (_,_,_,t) <- pIsFLiteral (goal g)+ tv <- tIsVar t+ pure i { fracTVars = Map.insert tv g (fracTVars i) }+++++ -------------------------------------------------------------------------------- @@ -118,7 +156,7 @@ case mb of Nothing -> return Nothing Just numBinds -> return $- do optss <- mapM tryDefVar otherVs+ do let optss = map tryDefVar otherVs su <- listToMaybe [ binds | nonSu <- sequence optss , let binds = nonSu ++ numBinds@@ -144,17 +182,23 @@ fLitGoals = flitDefaultCandidates gSet - tryDefVar a =- do ((_,t),_) <- Map.lookup (TVBound a) fLitGoals- pure [(a, t)]- <|>- do let a' = TVBound a- gt <- Map.lookup a' (literalGoals gSet)- let ok p = not (Set.member a' (fvs p))- return [ (a,t) | t <- [ tInteger, tBit, tWord (tWidth (goal gt)) ]- , ok t ]+ tryDefVar :: TParam -> [(TParam, Type)]+ tryDefVar a+ -- REPL defaulting for floating-point literals+ | Just m <- Map.lookup (TVBound a) fLitGoals+ = case m of+ Just ((_,t),_) -> [(a,t)]+ Nothing -> [] + -- REPL defaulting for integer literals+ | Just gt <- Map.lookup (TVBound a) (literalGoals gSet)+ = let ok p = not (Set.member (TVBound a) (fvs p)) in+ [ (a,t) | t <- [ tInteger, tWord (tWidth (goal gt)) ]+ , ok t ] + -- REPL defaulting for variables unconstrained by a literal constraint+ | otherwise = [ (a,t) | t <- [tInteger, tRational, tBit] ]+ appExpr tys = foldl (\e1 _ -> EProofApp e1) (foldl ETApp expr tys) (sProps sch)@@ -185,7 +229,7 @@ [] -> return () _ -> case quickSolver mempty gs of- Left (msg,badG) -> recordError (UnsolvedGoals (Just msg) [badG])+ Left err -> recordError err Right (su,gs1) -> do extendSubst su addGoals gs1@@ -255,7 +299,7 @@ do let ctxt = buildSolverCtxt asmps res <- quickSolverIO ctxt gs case res of- Left (msg,bad) -> return (Left [UnsolvedGoals (Just msg) [bad]], emptySubst)+ Left erro -> return (Left [erro], emptySubst) Right (su,[]) -> return (Right [], su) Right (su,gs1) -> do gs2 <- proveImp s asmps gs1@@ -319,10 +363,12 @@ buildSolverCtxt :: [Prop] -> Ctxt buildSolverCtxt ps0 =- SolverCtxt- { intervals = assumptionIntervals mempty ps0- , saturatedAsmps = saturateProps mempty ps0- }+ let ps = saturateProps mempty ps0+ ivals = assumptionIntervals mempty (Set.toList ps)+ in SolverCtxt+ { intervals = ivals+ , saturatedAsmps = ps+ } where saturateProps gs [] = gs
src/Cryptol/TypeCheck/Solver/Class.hs view
@@ -8,7 +8,7 @@ -- -- Solving class constraints. -{-# LANGUAGE PatternGuards, OverloadedStrings #-}+{-# LANGUAGE PatternGuards #-} module Cryptol.TypeCheck.Solver.Class ( solveZeroInst , solveLogicInst@@ -29,7 +29,6 @@ import Cryptol.TypeCheck.Type import Cryptol.TypeCheck.SimpType (tAdd,tWidth) import Cryptol.TypeCheck.Solver.Types-import Cryptol.TypeCheck.PP import Cryptol.Utils.RecordMap {- | This places constraints on the floating point numbers that@@ -69,7 +68,7 @@ solveZeroInst ty = case tNoUser ty of -- Zero Error -> fails- TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable -- Zero Bit TCon (TC TCBit) [] -> SolvedIf []@@ -107,30 +106,22 @@ solveLogicInst ty = case tNoUser ty of -- Logic Error -> fails- TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable -- Logic Bit TCon (TC TCBit) [] -> SolvedIf [] -- Logic Integer fails- TCon (TC TCInteger) [] ->- Unsolvable $- TCErrorMessage "Type 'Integer' does not support logical operations."+ TCon (TC TCInteger) [] -> Unsolvable -- Logic (Z n) fails- TCon (TC TCIntMod) [_] ->- Unsolvable $- TCErrorMessage "Type 'Z' does not support logical operations."+ TCon (TC TCIntMod) [_] -> Unsolvable -- Logic Rational fails- TCon (TC TCRational) [] ->- Unsolvable $- TCErrorMessage "Type 'Rational' does not support logical operations."+ TCon (TC TCRational) [] -> Unsolvable -- Logic (Float e p) fails- TCon (TC TCFloat) [_, _] ->- Unsolvable $- TCErrorMessage "Type 'Float' does not support logical operations."+ TCon (TC TCFloat) [_, _] -> Unsolvable -- Logic a => Logic [n]a TCon (TC TCSeq) [_, a] -> SolvedIf [ pLogic a ]@@ -146,12 +137,13 @@ _ -> Unsolved + -- | Solve a Ring constraint by instance, if possible. solveRingInst :: Type -> Solved solveRingInst ty = case tNoUser ty of -- Ring Error -> fails- TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable -- Ring [n]e TCon (TC TCSeq) [n, e] -> solveRingSeq n e@@ -163,8 +155,7 @@ TCon (TC (TCTuple _)) es -> SolvedIf [ pRing e | e <- es ] -- Ring Bit fails- TCon (TC TCBit) [] ->- Unsolvable $ TCErrorMessage "Type 'Bit' does not support ring operations."+ TCon (TC TCBit) [] -> Unsolvable -- Ring Integer TCon (TC TCInteger) [] -> SolvedIf []@@ -209,11 +200,10 @@ solveIntegralInst ty = case tNoUser ty of -- Integral Error -> fails- TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable -- Integral Bit fails- TCon (TC TCBit) [] ->- Unsolvable $ TCErrorMessage "Type 'Bit' is not an integral type."+ TCon (TC TCBit) [] -> Unsolvable -- Integral Integer TCon (TC TCInteger) [] -> SolvedIf []@@ -223,13 +213,11 @@ case tNoUser elTy of TCon (TC TCBit) [] -> SolvedIf [ pFin n ] TVar _ -> Unsolved- _ -> Unsolvable $ TCErrorMessage $ show- $ "Type" <+> quotes (pp ty) <+> "is not an integral type."+ _ -> Unsolvable TVar _ -> Unsolved - _ -> Unsolvable $ TCErrorMessage $ show- $ "Type" <+> quotes (pp ty) <+> "is not an integral type."+ _ -> Unsolvable -- | Solve a Field constraint by instance, if possible.@@ -237,17 +225,13 @@ solveFieldInst ty = case tNoUser ty of -- Field Error -> fails- TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable -- Field Bit fails- TCon (TC TCBit) [] ->- Unsolvable $- TCErrorMessage "Type 'Bit' does not support field operations."+ TCon (TC TCBit) [] -> Unsolvable -- Field Integer fails- TCon (TC TCInteger) [] ->- Unsolvable $- TCErrorMessage "Type 'Integer' does not support field operations."+ TCon (TC TCInteger) [] -> Unsolvable -- Field Rational TCon (TC TCRational) [] -> SolvedIf []@@ -257,31 +241,20 @@ -- Field Real - -- Field (Z n) fails for now (to be added later with a 'prime n' requirement)- TCon (TC TCIntMod) [_] ->- Unsolvable $- TCErrorMessage "Type 'Z' does not support field operations."--- TCon (TC TCIntMod) [n] -> SolvedIf [ pFin n, n >== tOne, pPrime n ]+ -- Field (Z n)+ TCon (TC TCIntMod) [n] -> SolvedIf [ pPrime n ] -- Field ([n]a) fails- TCon (TC TCSeq) [_, _] ->- Unsolvable $- TCErrorMessage "Sequence types do not support field operations."+ TCon (TC TCSeq) [_, _] -> Unsolvable -- Field (a -> b) fails- TCon (TC TCFun) [_, _] ->- Unsolvable $- TCErrorMessage "Function types do not support field operations."+ TCon (TC TCFun) [_, _] -> Unsolvable -- Field (a, b, ...) fails- TCon (TC (TCTuple _)) _ ->- Unsolvable $- TCErrorMessage "Tuple types do not support field operations."+ TCon (TC (TCTuple _)) _ -> Unsolvable -- Field {x : a, y : b, ...} fails- TRec _ ->- Unsolvable $- TCErrorMessage "Record types do not support field operations."+ TRec _ -> Unsolvable _ -> Unsolved @@ -291,22 +264,16 @@ solveRoundInst ty = case tNoUser ty of -- Round Error -> fails- TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable -- Round Bit fails- TCon (TC TCBit) [] ->- Unsolvable $- TCErrorMessage "Type 'Bit' does not support rounding operations."+ TCon (TC TCBit) [] -> Unsolvable -- Round Integer fails- TCon (TC TCInteger) [] ->- Unsolvable $- TCErrorMessage "Type 'Integer' does not support rounding operations."+ TCon (TC TCInteger) [] -> Unsolvable -- Round (Z n) fails- TCon (TC TCIntMod) [_] ->- Unsolvable $- TCErrorMessage "Type 'Z' does not support rounding operations."+ TCon (TC TCIntMod) [_] -> Unsolvable -- Round Rational TCon (TC TCRational) [] -> SolvedIf []@@ -317,24 +284,16 @@ -- Round Real -- Round ([n]a) fails- TCon (TC TCSeq) [_, _] ->- Unsolvable $- TCErrorMessage "Sequence types do not support rounding operations."+ TCon (TC TCSeq) [_, _] -> Unsolvable -- Round (a -> b) fails- TCon (TC TCFun) [_, _] ->- Unsolvable $- TCErrorMessage "Function types do not support rounding operations."+ TCon (TC TCFun) [_, _] -> Unsolvable -- Round (a, b, ...) fails- TCon (TC (TCTuple _)) _ ->- Unsolvable $- TCErrorMessage "Tuple types do not support rounding operations."+ TCon (TC (TCTuple _)) _ -> Unsolvable -- Round {x : a, y : b, ...} fails- TRec _ ->- Unsolvable $- TCErrorMessage "Record types do not support rounding operations."+ TRec _ -> Unsolvable _ -> Unsolved @@ -345,7 +304,7 @@ solveEqInst ty = case tNoUser ty of -- Eq Error -> fails- TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable -- eq Bit TCon (TC TCBit) [] -> SolvedIf []@@ -369,8 +328,7 @@ TCon (TC (TCTuple _)) es -> SolvedIf (map pEq es) -- Eq (a -> b) fails- TCon (TC TCFun) [_,_] ->- Unsolvable $ TCErrorMessage "Function types do not support comparisons."+ TCon (TC TCFun) [_,_] -> Unsolvable -- (Eq a, Eq b) => Eq { x:a, y:b } TRec fs -> SolvedIf [ pEq e | e <- recordElements fs ]@@ -383,7 +341,7 @@ solveCmpInst ty = case tNoUser ty of -- Cmp Error -> fails- TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable -- Cmp Bit TCon (TC TCBit) [] -> SolvedIf []@@ -395,8 +353,7 @@ TCon (TC TCRational) [] -> SolvedIf [] -- Cmp (Z n) fails- TCon (TC TCIntMod) [_] ->- Unsolvable $ TCErrorMessage "Type 'Z' does not support order comparisons."+ TCon (TC TCIntMod) [_] -> Unsolvable -- ValidFloat e p => Cmp (Float e p) TCon (TC TCFloat) [e,p] -> SolvedIf [ pValidFloat e p ]@@ -408,8 +365,7 @@ TCon (TC (TCTuple _)) es -> SolvedIf (map pCmp es) -- Cmp (a -> b) fails- TCon (TC TCFun) [_,_] ->- Unsolvable $ TCErrorMessage "Function types do not support order comparisons."+ TCon (TC TCFun) [_,_] -> Unsolvable -- (Cmp a, Cmp b) => Cmp { x:a, y:b } TRec fs -> SolvedIf [ pCmp e | e <- recordElements fs ]@@ -437,32 +393,22 @@ solveSignedCmpInst ty = case tNoUser ty of -- SignedCmp Error -> fails- TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable -- SignedCmp Bit fails- TCon (TC TCBit) [] ->- Unsolvable $- TCErrorMessage "Type 'Bit' does not support signed comparisons."+ TCon (TC TCBit) [] -> Unsolvable -- SignedCmp Integer fails- TCon (TC TCInteger) [] ->- Unsolvable $- TCErrorMessage "Type 'Integer' does not support signed comparisons."+ TCon (TC TCInteger) [] -> Unsolvable -- SignedCmp (Z n) fails- TCon (TC TCIntMod) [_] ->- Unsolvable $- TCErrorMessage "Type 'Z' does not support signed comparisons."+ TCon (TC TCIntMod) [_] -> Unsolvable -- SignedCmp Rational fails- TCon (TC TCRational) [] ->- Unsolvable $- TCErrorMessage "Type 'Rational' does not support signed comparisons."+ TCon (TC TCRational) [] -> Unsolvable -- SignedCmp (Float e p) fails- TCon (TC TCFloat) [_, _] ->- Unsolvable $- TCErrorMessage "Type 'Float' does not support signed comparisons."+ TCon (TC TCFloat) [_, _] -> Unsolvable -- SignedCmp for sequences TCon (TC TCSeq) [n,a] -> solveSignedCmpSeq n a@@ -471,9 +417,7 @@ TCon (TC (TCTuple _)) es -> SolvedIf (map pSignedCmp es) -- SignedCmp (a -> b) fails- TCon (TC TCFun) [_,_] ->- Unsolvable $- TCErrorMessage "Function types do not support signed comparisons."+ TCon (TC TCFun) [_,_] -> Unsolvable -- (SignedCmp a, SignedCmp b) => SignedCmp { x:a, y:b } TRec fs -> SolvedIf [ pSignedCmp e | e <- recordElements fs ]@@ -484,19 +428,16 @@ -- | Solving fractional literal constraints. solveFLiteralInst :: Type -> Type -> Type -> Type -> Solved solveFLiteralInst numT denT rndT ty- | TCon (TError _ e) _ <- tNoUser numT = Unsolvable e- | TCon (TError _ e) _ <- tNoUser denT = Unsolvable e- | tIsInf numT || tIsInf denT || tIsInf rndT =- Unsolvable $ TCErrorMessage $ "Fractions may not use `inf`"- | Just 0 <- tIsNum denT =- Unsolvable $ TCErrorMessage- $ "Fractions may not have 0 as the denominator."+ | TCon (TError {}) _ <- tNoUser numT = Unsolvable+ | TCon (TError {}) _ <- tNoUser denT = Unsolvable+ | tIsInf numT || tIsInf denT || tIsInf rndT = Unsolvable+ | Just 0 <- tIsNum denT = Unsolvable | otherwise = case tNoUser ty of TVar {} -> Unsolved - TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable TCon (TC TCRational) [] -> SolvedIf [ pFin numT, pFin denT, denT >== tOne ]@@ -512,25 +453,25 @@ , Just d <- tIsNum denT -> case FP.bfDiv opts (FP.bfFromInteger n) (FP.bfFromInteger d) of (_, FP.Ok) -> SolvedIf []- _ -> Unsolvable $ TCErrorMessage- $ show n ++ "/" ++ show d ++ " cannot be " ++- "represented in " ++ show (pp ty)+ _ -> Unsolvable | otherwise -> Unsolved - _ -> Unsolvable $ TCErrorMessage $ show- $ "Type" <+> quotes (pp ty) <+> "does not support fractional literals."+ _ -> Unsolvable -- | Solve Literal constraints. solveLiteralInst :: Type -> Type -> Solved solveLiteralInst val ty- | TCon (TError _ e) _ <- tNoUser val = Unsolvable e+ | TCon (TError {}) _ <- tNoUser val = Unsolvable | otherwise = case tNoUser ty of -- Literal n Error -> fails- TCon (TError _ e) _ -> Unsolvable e+ TCon (TError {}) _ -> Unsolvable + -- (1 >= val) => Literal val Bit+ TCon (TC TCBit) [] -> SolvedIf [ tOne >== val ]+ -- (fin val) => Literal val Integer TCon (TC TCInteger) [] -> SolvedIf [ pFin val ] @@ -544,9 +485,7 @@ let bf = FP.bfFromInteger n in case FP.bfRoundFloat opts bf of (bf1,FP.Ok) | bf == bf1 -> SolvedIf []- _ -> Unsolvable $ TCErrorMessage- $ show n ++ " cannot be " ++- "represented in " ++ show (pp ty)+ _ -> Unsolvable | otherwise -> Unsolved @@ -565,7 +504,6 @@ TVar _ -> Unsolved - _ -> Unsolvable $ TCErrorMessage $ show- $ "Type" <+> quotes (pp ty) <+> "does not support integer literals."+ _ -> Unsolvable
src/Cryptol/TypeCheck/Solver/Numeric.hs view
@@ -1,15 +1,18 @@-{-# LANGUAGE Safe, PatternGuards, MultiWayIf #-}+{-# LANGUAGE PatternGuards, MagicHash, MultiWayIf, TypeOperators #-} module Cryptol.TypeCheck.Solver.Numeric- ( cryIsEqual, cryIsNotEqual, cryIsGeq+ ( cryIsEqual, cryIsNotEqual, cryIsGeq, cryIsPrime, primeTable ) where import Control.Applicative(Alternative(..)) import Control.Monad (guard,mzero) import qualified Control.Monad.Fail as Fail import Data.List (sortBy)+import Data.MemoTrie +import qualified GHC.Integer.GMP.Internals as Integer++ import Cryptol.Utils.Patterns-import Cryptol.TypeCheck.PP import Cryptol.TypeCheck.Type hiding (tMul) import Cryptol.TypeCheck.TypePat import Cryptol.TypeCheck.Solver.Types@@ -30,7 +33,7 @@ cryIsEqual :: Ctxt -> Type -> Type -> Solved cryIsEqual ctxt t1 t2 = matchDefault Unsolved $- (pBin PEqual (==) t1 t2)+ (pBin (==) t1 t2) <|> (aNat' t1 >>= tryEqK ctxt t2) <|> (aNat' t2 >>= tryEqK ctxt t1) <|> (aTVar t1 >>= tryEqVar t2)@@ -49,13 +52,13 @@ -- | Try to solve @t1 /= t2@ cryIsNotEqual :: Ctxt -> Type -> Type -> Solved-cryIsNotEqual _i t1 t2 = matchDefault Unsolved (pBin PNeq (/=) t1 t2)+cryIsNotEqual _i t1 t2 = matchDefault Unsolved (pBin (/=) t1 t2) -- | Try to solve @t1 >= t2@ cryIsGeq :: Ctxt -> Type -> Type -> Solved cryIsGeq i t1 t2 = matchDefault Unsolved $- (pBin PGeq (>=) t1 t2)+ (pBin (>=) t1 t2) <|> (aNat' t1 >>= tryGeqKThan i t2) <|> (aNat' t2 >>= tryGeqThanK i t1) <|> (aTVar t2 >>= tryGeqThanVar i t1)@@ -72,18 +75,41 @@ -- XXX: max t 10 >= 2 --> True -- XXX: max t 2 >= 10 --> a >= 10 +{-# NOINLINE primeTable #-}+primeTable :: Integer :->: Bool+primeTable = trie isPrime+ where+ isPrime i =+ case Integer.testPrimeInteger i 25# of+ 0# -> False+ _ -> True++cryIsPrime :: Ctxt -> Type -> Solved+cryIsPrime _varInfo ty =+ case tNoUser ty of++ TCon (TC tc) []+ | TCNum n <- tc ->+ if untrie primeTable n then+ SolvedIf []+ else+ Unsolvable++ | TCInf <- tc -> Unsolvable++ _ -> Unsolved++ -- | Try to solve something by evaluation.-pBin :: PC -> (Nat' -> Nat' -> Bool) -> Type -> Type -> Match Solved-pBin tf p t1 t2 =- Unsolvable <$> anError KNum t1- <|> Unsolvable <$> anError KNum t2- <|> (do x <- aNat' t1- y <- aNat' t2- return $ if p x y- then SolvedIf []- else Unsolvable $ TCErrorMessage- $ "It is not the case that " ++- show (pp (TCon (PC tf) [ tNat' x, tNat' y ])))+pBin :: (Nat' -> Nat' -> Bool) -> Type -> Type -> Match Solved+pBin p t1 t2+ | Just _ <- tIsError t1 = pure Unsolvable+ | Just _ <- tIsError t2 = pure Unsolvable+ | otherwise = do x <- aNat' t1+ y <- aNat' t2+ return $ if p x y+ then SolvedIf []+ else Unsolvable --------------------------------------------------------------------------------@@ -151,8 +177,7 @@ k2 <- aNat t2 return $ if k1 >= k2 then SolvedIf [ b >== t2 ]- else Unsolvable $ TCErrorMessage $- show k1 ++ " can't be greater than " ++ show k2+ else Unsolvable -------------------------------------------------------------------------------- @@ -297,9 +322,6 @@ case nSub lk rk of -- NOTE: (Inf - Inf) shouldn't be possible Nothing -> Unsolvable- $ TCErrorMessage- $ "Adding " ++ showNat' rk ++ " will always exceed "- ++ showNat' lk Just r -> SolvedIf [ b =#= tNat' r ] <|>@@ -322,9 +344,7 @@ (Nat 0, Inf) -> SolvedIf [ b =#= tZero ] -- Inf * t = K ~~~> ERR (K /= 0)- (Nat k, Inf) -> Unsolvable- $ TCErrorMessage- $ show k ++ " != inf * anything"+ (Nat _k, Inf) -> Unsolvable (Nat lk', Nat rk') -- 0 * t = K2 ~~> K2 = 0@@ -333,10 +353,7 @@ -- K1 * t = K2 ~~> t = K2/K1 | (q,0) <- divMod lk' rk' -> SolvedIf [ b =#= tNum q ]- | otherwise ->- Unsolvable- $ TCErrorMessage- $ showNat' lk ++ " != " ++ showNat' rk ++ " * anything"+ | otherwise -> Unsolvable <|> -- K1 == K2 ^^ t ~~> t = logBase K2 K1@@ -344,8 +361,7 @@ return $ case lk of Inf | rk > 1 -> SolvedIf [ b =#= tInf ] Nat n | Just (a,True) <- genLog n rk -> SolvedIf [ b =#= tNum a]- _ -> Unsolvable $ TCErrorMessage- $ show rk ++ " ^^ anything != " ++ showNat' lk+ _ -> Unsolvable -- XXX: Min, Max, etx -- 2 = min (10,y) --> y = 2@@ -471,6 +487,3 @@ -showNat' :: Nat' -> String-showNat' Inf = "inf"-showNat' (Nat n) = show n
src/Cryptol/TypeCheck/Solver/Numeric/Fin.hs view
@@ -35,8 +35,7 @@ TCon (TC tc) [] | TCNum _ <- tc -> SolvedIf []- | TCInf <- tc ->- Unsolvable $ TCErrorMessage "Expected a finite type, but found `inf`."+ | TCInf <- tc -> Unsolvable TCon (TF f) ts -> case (f,ts) of
src/Cryptol/TypeCheck/Solver/SMT.hs view
@@ -381,9 +381,6 @@ instance Mk Type where mk tvs f x = SMT.fun f [toSMT tvs x] -instance Mk TCErrorMessage where- mk _ f _ = SMT.fun f []- instance Mk (Type,Type) where mk tvs f (x,y) = SMT.fun f [ toSMT tvs x, toSMT tvs y]
src/Cryptol/TypeCheck/Solver/Selector.hs view
@@ -50,7 +50,8 @@ where cvt _ Nothing = return False cvt f (Just a) = do ty <- f a- newGoals CtExactType =<< unify ty outerT+ ps <- unify (WithSource outerT (selSrc sel)) ty+ newGoals CtExactType ps newT <- applySubst outerT return (newT /= outerT) @@ -125,7 +126,7 @@ case mbInnerT of Nothing -> return (imped, False) Just innerT ->- do newGoals CtExactType =<< unify innerT ft+ do newGoals CtExactType =<< unify (WithSource innerT (selSrc sel)) ft oT <- applySubst outerT iT <- applySubst innerT sln <- mkSelSln sel oT iT@@ -158,7 +159,7 @@ | RecordSel {} <- s -> liftFun t1 t2 _ -> return HasGoalSln { hasDoSelect = \e -> ESel e s- , hasDoSet = \e v -> ESet e s v }+ , hasDoSet = \e v -> ESet outerT e s v } where -- Has s a t => Has s ([n]a) ([n]t)@@ -185,7 +186,7 @@ _ -> panic "mkSelSln" [ "Unexpected inner seq type.", show innerT ] - -- Has s b t => Has s (a -> b)+ -- Has s b t => Has s (a -> b) (a -> t) -- f.s ~~> \x -> (f x).s -- { f | s = g } ~~> \x -> { f x | s = g x } liftFun t1 t2 =
src/Cryptol/TypeCheck/Solver/Types.hs view
@@ -1,3 +1,4 @@+{-# Language OverloadedStrings, DeriveGeneric, DeriveAnyClass #-} module Cryptol.TypeCheck.Solver.Types where import Data.Map(Map)@@ -22,10 +23,11 @@ data Solved = SolvedIf [Prop] -- ^ Solved, assuming the sub-goals. | Unsolved -- ^ We could not solve the goal.- | Unsolvable TCErrorMessage -- ^ The goal can never be solved.+ | Unsolvable -- ^ The goal can never be solved. deriving (Show) + elseTry :: Solved -> Solved -> Solved Unsolved `elseTry` x = x x `elseTry` _ = x@@ -48,4 +50,5 @@ case res of SolvedIf ps -> text "solved" $$ nest 2 (vcat (map pp ps)) Unsolved -> text "unsolved"- Unsolvable e -> text "unsolvable" <.> colon <+> text (tcErrorMessage e)+ Unsolvable -> text "unsolvable"+
src/Cryptol/TypeCheck/Subst.hs view
@@ -6,6 +6,10 @@ -- Stability : provisional -- Portability : portable +{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE FlexibleInstances #-}@@ -30,6 +34,7 @@ , substBinds , applySubstToVar , substToList+ , fmap', (!$), (.$) ) where import Data.Maybe@@ -45,7 +50,7 @@ import qualified Cryptol.TypeCheck.SimpType as Simp import qualified Cryptol.TypeCheck.SimpleSolver as Simp import Cryptol.Utils.Panic(panic)-import Cryptol.Utils.Misc(anyJust)+import Cryptol.Utils.Misc (anyJust, anyJust2) -- | A 'Subst' value represents a substitution that maps each 'TVar' -- to a 'Type'.@@ -196,8 +201,30 @@ +infixl 0 !$+infixl 0 .$ +-- | Left-associative variant of the strict application operator '$!'.+(!$) :: (a -> b) -> a -> b+(!$) = ($!) +-- | Left-associative variant of the application operator '$'.+(.$) :: (a -> b) -> a -> b+(.$) = ($)++-- Only used internally to define fmap'.+data Done a = Done a+ deriving (Functor, Foldable, Traversable)++instance Applicative Done where+ pure x = Done x+ Done f <*> Done x = Done (f x)++-- | Strict variant of 'fmap'.+fmap' :: Traversable t => (a -> b) -> t a -> t b+fmap' f xs = case traverse f' xs of Done y -> y+ where f' x = Done $! f x+ -- | Apply a substitution. Returns `Nothing` if nothing changed. apSubstMaybe :: Subst -> Type -> Maybe Type apSubstMaybe su ty =@@ -209,8 +236,10 @@ PC _ -> Just $! Simp.simplify mempty (TCon t ss) _ -> Just (TCon t ss) - TUser f ts t -> do t1 <- apSubstMaybe su t- return (TUser f (map (apSubst su) ts) t1)+ TUser f ts t ->+ do (ts1, t1) <- anyJust2 (anyJust (apSubstMaybe su)) (apSubstMaybe su) (ts, t)+ Just (TUser f ts1 t1)+ TRec fs -> TRec `fmap` (anyJust (apSubstMaybe su) fs) TVar x -> applySubstToVar su x @@ -226,22 +255,30 @@ case lookupSubst x su of -- For a defaulting substitution, we must recurse in order to -- replace unmapped free vars with default types.- Just t -> Just (if suDefaulting su then apSubst su t else t)+ Just t+ | suDefaulting su -> Just $! apSubst su t+ | otherwise -> Just t Nothing | suDefaulting su -> Just $! defaultFreeVar x | otherwise -> Nothing class TVars t where- apSubst :: Subst -> t -> t -- ^ replaces free vars+ apSubst :: Subst -> t -> t+ -- ^ Replaces free variables. To prevent space leaks when used with+ -- large 'Subst' values, every instance of 'apSubst' should satisfy+ -- a strictness property: Forcing evaluation of @'apSubst' s x@+ -- should also force the evaluation of all recursive calls to+ -- @'apSubst' s@. This ensures that unevaluated thunks will not+ -- cause 'Subst' values to be retained on the heap. instance TVars t => TVars (Maybe t) where- apSubst s = fmap (apSubst s)+ apSubst s = fmap' (apSubst s) instance TVars t => TVars [t] where- apSubst s = map (apSubst s)+ apSubst s = fmap' (apSubst s) instance (TVars s, TVars t) => TVars (s,t) where- apSubst s (x,y) = (apSubst s x, apSubst s y)+ apSubst s (x, y) = (,) !$ apSubst s x !$ apSubst s y instance TVars Type where apSubst su ty = fromMaybe ty (apSubstMaybe su ty)@@ -258,11 +295,11 @@ , "Source: " ++ show d , "Kind: " ++ show (pp k) ] -instance (Functor m, TVars a) => TVars (List m a) where- apSubst su = fmap (apSubst su)+instance (Traversable m, TVars a) => TVars (List m a) where+ apSubst su = fmap' (apSubst su) instance TVars a => TVars (TypeMap a) where- apSubst su = fmap (apSubst su)+ apSubst su = fmap' (apSubst su) -- | Apply the substitution to the keys of a type map.@@ -303,19 +340,19 @@ that variable scopes will be properly preserved. -} instance TVars Schema where- apSubst su (Forall xs ps t) = Forall xs (concatMap pSplitAnd (apSubst su ps))- (apSubst su t)+ apSubst su (Forall xs ps t) =+ Forall xs !$ (concatMap pSplitAnd (apSubst su ps)) !$ (apSubst su t) instance TVars Expr where apSubst su = go where go expr = case expr of- EApp e1 e2 -> EApp (go e1) (go e2)- EAbs x t e1 -> EAbs x (apSubst su t) (go e1)- ETAbs a e -> ETAbs a (go e)- ETApp e t -> ETApp (go e) (apSubst su t)- EProofAbs p e -> EProofAbs hmm (go e)+ EApp e1 e2 -> EApp !$ (go e1) !$ (go e2)+ EAbs x t e1 -> EAbs x !$ (apSubst su t) !$ (go e1)+ ETAbs a e -> ETAbs a !$ (go e)+ ETApp e t -> ETApp !$ (go e) !$ (apSubst su t)+ EProofAbs p e -> EProofAbs !$ hmm !$ (go e) where hmm = case pSplitAnd (apSubst su p) of [p1] -> p1 res -> panic "apSubst@EProofAbs"@@ -329,36 +366,39 @@ , show (pp su) ] - EProofApp e -> EProofApp (go e)+ EProofApp e -> EProofApp !$ (go e) EVar {} -> expr - ETuple es -> ETuple (map go es)- ERec fs -> ERec (fmap go fs)- ESet e x v -> ESet (go e) x (go v)- EList es t -> EList (map go es) (apSubst su t)- ESel e s -> ESel (go e) s- EComp len t e mss -> EComp (apSubst su len) (apSubst su t) (go e) (apSubst su mss)- EIf e1 e2 e3 -> EIf (go e1) (go e2) (go e3)+ ETuple es -> ETuple !$ (fmap' go es)+ ERec fs -> ERec !$ (fmap' go fs)+ ESet ty e x v -> ESet !$ (apSubst su ty) !$ (go e) .$ x !$ (go v)+ EList es t -> EList !$ (fmap' go es) !$ (apSubst su t)+ ESel e s -> ESel !$ (go e) .$ s+ EComp len t e mss -> EComp !$ (apSubst su len) !$ (apSubst su t) !$ (go e) !$ (apSubst su mss)+ EIf e1 e2 e3 -> EIf !$ (go e1) !$ (go e2) !$ (go e3) - EWhere e ds -> EWhere (go e) (apSubst su ds)+ EWhere e ds -> EWhere !$ (go e) !$ (apSubst su ds) instance TVars Match where- apSubst su (From x len t e) = From x (apSubst su len) (apSubst su t) (apSubst su e)- apSubst su (Let b) = Let (apSubst su b)+ apSubst su (From x len t e) = From x !$ (apSubst su len) !$ (apSubst su t) !$ (apSubst su e)+ apSubst su (Let b) = Let !$ (apSubst su b) instance TVars DeclGroup where- apSubst su (NonRecursive d) = NonRecursive (apSubst su d)- apSubst su (Recursive ds) = Recursive (apSubst su ds)+ apSubst su (NonRecursive d) = NonRecursive !$ (apSubst su d)+ apSubst su (Recursive ds) = Recursive !$ (apSubst su ds) instance TVars Decl where- apSubst su d = d { dSignature = apSubst su (dSignature d)- , dDefinition = apSubst su (dDefinition d)- }+ apSubst su d =+ let !sig' = id $! apSubst su (dSignature d)+ !def' = apSubst su (dDefinition d)+ in d { dSignature = sig', dDefinition = def' } instance TVars DeclDef where- apSubst su (DExpr e) = DExpr (apSubst su e)+ apSubst su (DExpr e) = DExpr !$ (apSubst su e) apSubst _ DPrim = DPrim instance TVars Module where- apSubst su m = m { mDecls = apSubst su (mDecls m) }+ apSubst su m =+ let !decls' = apSubst su (mDecls m)+ in m { mDecls = decls' }
src/Cryptol/TypeCheck/TCon.hs view
@@ -1,4 +1,4 @@-{-# Language DeriveGeneric, DeriveAnyClass #-}+{-# Language OverloadedStrings, DeriveGeneric, DeriveAnyClass, Safe #-} module Cryptol.TypeCheck.TCon where import qualified Data.Map as Map@@ -69,6 +69,7 @@ , "!=" ~> PC PNeq , ">=" ~> PC PGeq , "fin" ~> PC PFin+ , "prime" ~> PC PPrime , "Zero" ~> PC PZero , "Logic" ~> PC PLogic , "Ring" ~> PC PRing@@ -122,7 +123,7 @@ kindOf (TC tc) = kindOf tc kindOf (PC pc) = kindOf pc kindOf (TF tf) = kindOf tf- kindOf (TError k _) = k+ kindOf (TError k) = k instance HasKind UserTC where kindOf (UserTC _ k) = k@@ -151,6 +152,7 @@ PNeq -> KNum :-> KNum :-> KProp PGeq -> KNum :-> KNum :-> KProp PFin -> KNum :-> KProp+ PPrime -> KNum :-> KProp PHas _ -> KType :-> KType :-> KProp PZero -> KType :-> KProp PLogic -> KType :-> KProp@@ -188,7 +190,7 @@ -- | Type constants.-data TCon = TC TC | PC PC | TF TFun | TError Kind TCErrorMessage+data TCon = TC TC | PC PC | TF TFun | TError Kind deriving (Show, Eq, Ord, Generic, NFData) @@ -198,6 +200,7 @@ | PNeq -- ^ @_ /= _@ | PGeq -- ^ @_ >= _@ | PFin -- ^ @fin _@+ | PPrime -- ^ @prime _@ -- classes | PHas Selector -- ^ @Has sel type field@ does not appear in schemas@@ -250,10 +253,6 @@ -data TCErrorMessage = TCErrorMessage- { tcErrorMessage :: !String- -- XXX: Add location?- } deriving (Show, Eq, Ord, Generic, NFData) -- | Built-in type functions.@@ -295,12 +294,9 @@ ppPrec _ (TC tc) = pp tc ppPrec _ (PC tc) = pp tc ppPrec _ (TF tc) = pp tc- ppPrec _ (TError _ msg) = pp msg+ ppPrec _ (TError _) = "Error" -instance PP TCErrorMessage where- ppPrec _ tc = parens (text "error:" <+> text (tcErrorMessage tc))- instance PP PC where ppPrec _ x = case x of@@ -308,6 +304,7 @@ PNeq -> text "(/=)" PGeq -> text "(>=)" PFin -> text "fin"+ PPrime -> text "prime" PHas sel -> parens (ppSelector sel) PZero -> text "Zero" PLogic -> text "Logic"
src/Cryptol/TypeCheck/Type.hs view
@@ -15,6 +15,7 @@ import Data.Maybe (fromMaybe) import Data.Set (Set) import qualified Data.Set as Set+import Data.Text (Text) import Cryptol.Parser.Selector import Cryptol.Parser.Position(Range,emptyRange)@@ -111,8 +112,8 @@ -- | Type variables. data TVar = TVFree !Int Kind (Set TParam) TVarInfo- -- ^ Unique, kind, ids of bound type variables that are in scope- -- The last field gives us some infor for nicer warnings/errors.+ -- ^ Unique, kind, ids of bound type variables that are in scope.+ -- The last field gives us some info for nicer warnings/errors. | TVBound {-# UNPACK #-} !TParam@@ -124,13 +125,18 @@ TVFree _ _ _ d -> d TVBound tp -> tpInfo tp -data TVarInfo = TVarInfo { tvarSource :: Range -- ^ Source code that gave rise- , tvarDesc :: TVarSource -- ^ Description+tvUnique :: TVar -> Int+tvUnique (TVFree u _ _ _) = u+tvUnique (TVBound TParam { tpUnique = u }) = u++data TVarInfo = TVarInfo { tvarSource :: !Range -- ^ Source code that gave rise+ , tvarDesc :: !TypeSource -- ^ Description } deriving (Show, Generic, NFData) -data TVarSource = TVFromModParam Name -- ^ Name of module parameter+-- | Explains how this type came to be, for better error messages.+data TypeSource = TVFromModParam Name -- ^ Name of module parameter | TVFromSignature Name -- ^ A variable in a signature | TypeWildCard | TypeOfRecordField Ident@@ -141,13 +147,26 @@ | TypeParamInstPos {-Fun-}Name {-Pos (from 1)-}Int | DefinitionOf Name | LenOfCompGen- | TypeOfArg (Maybe Int)+ | TypeOfArg ArgDescr | TypeOfRes+ | FunApp+ | TypeOfIfCondExpr+ | TypeFromUserAnnotation+ | GeneratorOfListComp | TypeErrorPlaceHolder deriving (Show, Generic, NFData) +data ArgDescr = ArgDescr+ { argDescrFun :: Maybe Name+ , argDescrNumber :: Maybe Int+ }+ deriving (Show,Generic,NFData)++noArgDescr :: ArgDescr+noArgDescr = ArgDescr { argDescrFun = Nothing, argDescrNumber = Nothing }+ -- | Get the names of something that is related to the tvar.-tvSourceName :: TVarSource -> Maybe Name+tvSourceName :: TypeSource -> Maybe Name tvSourceName tvs = case tvs of TVFromModParam x -> Just x@@ -155,8 +174,17 @@ TypeParamInstNamed x _ -> Just x TypeParamInstPos x _ -> Just x DefinitionOf x -> Just x+ TypeOfArg x -> argDescrFun x _ -> Nothing ++-- | A type annotated with information on how it came about.+data TypeWithSource = WithSource+ { twsType :: Type+ , twsSource :: TypeSource+ }++ -- | The type is supposed to be of kind 'KProp'. type Prop = Type @@ -169,7 +197,7 @@ , tsParams :: [TParam] -- ^ Parameters , tsConstraints :: [Prop] -- ^ Ensure body is OK , tsDef :: Type -- ^ Definition- , tsDoc :: !(Maybe String) -- ^ Documentation+ , tsDoc :: !(Maybe Text) -- ^ Documentation } deriving (Show, Generic, NFData) @@ -182,7 +210,7 @@ , ntParams :: [TParam] , ntConstraints :: [Prop] , ntFields :: [(Ident,Type)]- , ntDoc :: Maybe String+ , ntDoc :: Maybe Text } deriving (Show, Generic, NFData) @@ -192,7 +220,7 @@ , atKind :: Kind , atCtrs :: ([TParam], [Prop]) , atFixitiy :: Maybe Fixity- , atDoc :: Maybe String+ , atDoc :: Maybe Text } deriving (Show, Generic, NFData) @@ -281,6 +309,10 @@ -- | Compute the set of all @Prop@s that are implied by the -- given prop via superclass constraints. superclassSet :: Prop -> Set Prop++superclassSet (TCon (PC PPrime) [n]) =+ Set.fromList [ pFin n, n >== tTwo ]+ superclassSet (TCon (PC p0) [t]) = go p0 where super p = Set.insert (TCon (PC p) [t]) (go p)@@ -343,12 +375,20 @@ isBoundTV _ = False -tIsError :: Type -> Maybe (TCErrorMessage,Type)+tIsError :: Type -> Maybe Type tIsError ty = case tNoUser ty of- TCon (TError _ x) [t] -> Just (x,t)- TCon (TError _ _) _ -> panic "tIsError" ["Malformed error"]- _ -> Nothing+ TCon (TError _) [t] -> Just t+ TCon (TError _) _ -> panic "tIsError" ["Malformed error"]+ _ -> Nothing +tHasErrors :: Type -> Bool+tHasErrors ty =+ case tNoUser ty of+ TCon (TError _) _ -> True+ TCon _ ts -> any tHasErrors ts+ TRec mp -> any tHasErrors mp+ _ -> False+ tIsNat' :: Type -> Maybe Nat' tIsNat' ty = case tNoUser ty of@@ -433,6 +473,11 @@ TCon (PC PFin) [t1] -> Just t1 _ -> Nothing +pIsPrime :: Prop -> Maybe Type+pIsPrime ty = case tNoUser ty of+ TCon (PC PPrime) [t1] -> Just t1+ _ -> Nothing+ pIsGeq :: Prop -> Maybe (Type,Type) pIsGeq ty = case tNoUser ty of TCon (PC PGeq) [t1,t2] -> Just (t1,t2)@@ -595,10 +640,9 @@ -- | Make an error value of the given type to replace -- the given malformed type (the argument to the error function)-tError :: Type -> String -> Type-tError t s = TCon (TError (k :-> k) msg) [t]+tError :: Type -> Type+tError t = TCon (TError (k :-> k)) [t] where k = kindOf t- msg = TCErrorMessage s tf1 :: TFun -> Type -> Type tf1 f x = TCon (TF f) [x]@@ -717,14 +761,23 @@ pFin ty = case tNoUser ty of TCon (TC (TCNum _)) _ -> pTrue- TCon (TC TCInf) _ -> tError (TCon (PC PFin) [ty]) "`inf` is not finite"- -- XXX: should we be doing this here??- _ -> TCon (PC PFin) [ty]+ TCon (TC TCInf) _ -> tError prop -- XXX: should we be doing this here??+ _ -> prop+ where+ prop = TCon (PC PFin) [ty] pValidFloat :: Type -> Type -> Type pValidFloat e p = TCon (PC PValidFloat) [e,p] +pPrime :: Type -> Prop+pPrime ty =+ case tNoUser ty of+ TCon (TC TCInf) _ -> tError prop+ _ -> prop+ where+ prop = TCon (PC PPrime) [ty] + -------------------------------------------------------------------------------- noFreeVariables :: FVS t => t -> Bool@@ -855,7 +908,9 @@ -- -- * 3: @app_type@ ----- * 4: @atype@+-- * 4: @dimensions atype@+--+-- * 5: @atype@ instance PP (WithNames Type) where ppPrec prec ty0@(WithNames ty nmMap) = case ty of@@ -866,8 +921,16 @@ _ | Just tinf <- isTInfix ty0 -> optParens (prec > 2) $ ppInfix 2 isTInfix tinf - TUser c [] _ -> pp c- TUser c ts _ -> optParens (prec > 3) $ pp c <+> fsep (map (go 4) ts)+ TUser c ts t ->+ withNameDisp $ \disp ->+ case nameInfo c of+ Declared m _+ | NotInScope <- getNameFormat m (nameIdent c) disp ->+ go prec t -- unfold type synonym if not in scope+ _ ->+ case ts of+ [] -> pp c+ _ -> optParens (prec > 3) $ pp c <+> fsep (map (go 5) ts) TCon (TC tc) ts -> case (tc,ts) of@@ -877,42 +940,43 @@ (TCInteger, []) -> text "Integer" (TCRational, []) -> text "Rational" - (TCIntMod, [n]) -> optParens (prec > 3) $ text "Z" <+> go 4 n+ (TCIntMod, [n]) -> optParens (prec > 3) $ text "Z" <+> go 5 n (TCSeq, [t1,TCon (TC TCBit) []]) -> brackets (go 0 t1)- (TCSeq, [t1,t2]) -> optParens (prec > 3)- $ brackets (go 0 t1) <.> go 3 t2+ (TCSeq, [t1,t2]) -> optParens (prec > 4)+ $ brackets (go 0 t1) <.> go 4 t2 (TCFun, [t1,t2]) -> optParens (prec > 1) $ go 2 t1 <+> text "->" <+> go 1 t2 (TCTuple _, fs) -> parens $ fsep $ punctuate comma $ map (go 0) fs - (_, _) -> optParens (prec > 3) $ pp tc <+> fsep (map (go 4) ts)+ (_, _) -> optParens (prec > 3) $ pp tc <+> fsep (map (go 5) ts) TCon (PC pc) ts -> case (pc,ts) of (PEqual, [t1,t2]) -> go 0 t1 <+> text "==" <+> go 0 t2 (PNeq , [t1,t2]) -> go 0 t1 <+> text "!=" <+> go 0 t2 (PGeq, [t1,t2]) -> go 0 t1 <+> text ">=" <+> go 0 t2- (PFin, [t1]) -> optParens (prec > 3) $ text "fin" <+> (go 4 t1)+ (PFin, [t1]) -> optParens (prec > 3) $ text "fin" <+> (go 5 t1)+ (PPrime, [t1]) -> optParens (prec > 3) $ text "prime" <+> (go 5 t1) (PHas x, [t1,t2]) -> ppSelector x <+> text "of" <+> go 0 t1 <+> text "is" <+> go 0 t2 (PAnd, [t1,t2]) -> parens (commaSep (map (go 0) (t1 : pSplitAnd t2))) - (PRing, [t1]) -> pp pc <+> go 4 t1- (PField, [t1]) -> pp pc <+> go 4 t1- (PIntegral, [t1]) -> pp pc <+> go 4 t1- (PRound, [t1]) -> pp pc <+> go 4 t1+ (PRing, [t1]) -> pp pc <+> go 5 t1+ (PField, [t1]) -> pp pc <+> go 5 t1+ (PIntegral, [t1]) -> pp pc <+> go 5 t1+ (PRound, [t1]) -> pp pc <+> go 5 t1 - (PCmp, [t1]) -> pp pc <+> go 4 t1- (PSignedCmp, [t1]) -> pp pc <+> go 4 t1- (PLiteral, [t1,t2]) -> pp pc <+> go 4 t1 <+> go 4 t2+ (PCmp, [t1]) -> pp pc <+> go 5 t1+ (PSignedCmp, [t1]) -> pp pc <+> go 5 t1+ (PLiteral, [t1,t2]) -> pp pc <+> go 5 t1 <+> go 5 t2 - (_, _) -> optParens (prec > 3) $ pp pc <+> fsep (map (go 4) ts)+ (_, _) -> optParens (prec > 3) $ pp pc <+> fsep (map (go 5) ts) TCon f ts -> optParens (prec > 3)- $ pp f <+> fsep (map (go 4) ts)+ $ pp f <+> fsep (map (go 5) ts) where go p t = ppWithNamesPrec nmMap p t@@ -937,19 +1001,25 @@ instance PP (WithNames TVar) where - ppPrec _ (WithNames (TVBound x) mp) =- case IntMap.lookup (tpUnique x) mp of- Just a -> text a- Nothing ->- case tpFlav x of- TPModParam n -> ppPrefixName n- TPOther (Just n) -> pp n <.> "`" <.> int (tpUnique x)- _ -> pickTVarName (tpKind x) (tvarDesc (tpInfo x)) (tpUnique x)+ ppPrec _ (WithNames tv mp) =+ case tv of+ TVBound {} -> nmTxt+ TVFree {} -> "?" <.> nmTxt+ where+ nmTxt+ | Just a <- IntMap.lookup (tvUnique tv) mp = text a+ | otherwise =+ case tv of+ TVBound x ->+ case tpFlav x of+ TPModParam n -> ppPrefixName n+ TPOther (Just n) -> pp n <.> "`" <.> int (tpUnique x)+ _ -> pickTVarName (tpKind x) (tvarDesc (tpInfo x)) (tpUnique x) - ppPrec _ (WithNames (TVFree x k _ d) _) =- char '?' <.> pickTVarName k (tvarDesc d) x+ TVFree x k _ d -> pickTVarName k (tvarDesc d) x -pickTVarName :: Kind -> TVarSource -> Int -> Doc++pickTVarName :: Kind -> TypeSource -> Int -> Doc pickTVarName k src uni = text $ case src of@@ -969,10 +1039,14 @@ Declared m SystemName | m == exprModName -> mk "it" _ -> using x LenOfCompGen -> mk "n"- TypeOfArg mb -> mk (case mb of+ GeneratorOfListComp -> "seq"+ TypeOfIfCondExpr -> "b"+ TypeOfArg ad -> mk (case argDescrNumber ad of Nothing -> "arg" Just n -> "arg_" ++ show n) TypeOfRes -> "res"+ FunApp -> "fun"+ TypeFromUserAnnotation -> "user" TypeErrorPlaceHolder -> "err" where sh a = show (pp a)@@ -991,7 +1065,17 @@ loc = if rng == emptyRange then empty else "at" <+> pp rng rng = tvarSource tvinfo -instance PP TVarSource where+instance PP ArgDescr where+ ppPrec _ ad = which <+> "argument" <+> ofFun+ where+ which = maybe "function" ordinal (argDescrNumber ad)+ ofFun = case argDescrFun ad of+ Nothing -> empty+ Just f -> "of" <+> pp f++++instance PP TypeSource where ppPrec _ tvsrc = case tvsrc of TVFromModParam m -> "module parameter" <+> pp m@@ -1007,9 +1091,10 @@ quotes (pp f) DefinitionOf x -> "the type of" <+> quotes (pp x) LenOfCompGen -> "length of comprehension generator"- TypeOfArg mb ->- case mb of- Nothing -> "type of function argument"- Just n -> "type of" <+> ordinal n <+> "function argument"+ TypeOfArg ad -> "type of" <+> pp ad TypeOfRes -> "type of function result"+ TypeOfIfCondExpr -> "type of `if` condition"+ TypeFromUserAnnotation -> "user annotation"+ GeneratorOfListComp -> "generator in a list comprehension"+ FunApp -> "function call" TypeErrorPlaceHolder -> "type error place-holder"
src/Cryptol/TypeCheck/TypeMap.hs view
@@ -10,6 +10,8 @@ {-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-} {-# LANGUAGE UndecidableInstances, FlexibleInstances #-} {-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveTraversable #-} module Cryptol.TypeCheck.TypeMap ( TypeMap(..), TypesMap, TrieMap(..) , insertTM, insertWithTM@@ -64,7 +66,7 @@ data List m a = L { nil :: Maybe a , cons :: m (List m a)- } deriving (Functor)+ } deriving (Functor, Foldable, Traversable) instance TrieMap m a => TrieMap (List m) [a] where emptyTM = L { nil = Nothing, cons = emptyTM }@@ -116,7 +118,7 @@ data TypeMap a = TM { tvar :: Map TVar a , tcon :: Map TCon (List TypeMap a) , trec :: Map [Ident] (List TypeMap a)- } deriving (Functor)+ } deriving (Functor, Foldable, Traversable) instance TrieMap TypeMap Type where emptyTM = TM { tvar = emptyTM, tcon = emptyTM, trec = emptyTM }
src/Cryptol/TypeCheck/TypeOf.hs view
@@ -34,7 +34,7 @@ ETuple es -> tTuple (map (fastTypeOf tyenv) es) ERec fields -> tRec (fmap (fastTypeOf tyenv) fields) ESel e sel -> typeSelect (fastTypeOf tyenv e) sel- ESet e _ _ -> fastTypeOf tyenv e+ ESet ty _ _ _ -> ty EIf _ e _ -> fastTypeOf tyenv e EComp len t _ _ -> tSeq len t EAbs x t e -> tFun t (fastTypeOf (Map.insert x (Forall [] [] t) tyenv) e)
src/Cryptol/TypeCheck/TypePat.hs view
@@ -182,10 +182,10 @@ aLogic = tp PLogic ar1 ---------------------------------------------------------------------------------anError :: Kind -> Pat Type TCErrorMessage+anError :: Kind -> Pat Type () anError k = \a -> case tNoUser a of- TCon (TError k1 err) _ | k == k1 -> return err- _ -> mzero+ TCon (TError (_ :-> k1) ) _ | k == k1 -> return ()+ _ -> mzero
src/Cryptol/Utils/Ident.hs view
@@ -16,8 +16,11 @@ , modNameChunks , packModName , preludeName+ , preludeReferenceName , floatName+ , suiteBName , arrayName+ , primeECName , interactiveName , noModuleName , exprModName@@ -38,12 +41,13 @@ , identText , modParamIdent - -- * Identifiers for primitived+ -- * Identifiers for primitives , PrimIdent(..) , prelPrim , floatPrim , arrayPrim-+ , suiteBPrim+ , primeECPrim ) where import Control.DeepSeq (NFData)@@ -108,12 +112,21 @@ preludeName :: ModName preludeName = packModName ["Cryptol"] +preludeReferenceName :: ModName+preludeReferenceName = packModName ["Cryptol","Reference"]+ floatName :: ModName floatName = packModName ["Float"] arrayName :: ModName arrayName = packModName ["Array"] +suiteBName :: ModName+suiteBName = packModName ["SuiteB"]++primeECName :: ModName+primeECName = packModName ["PrimeEC"]+ interactiveName :: ModName interactiveName = packModName ["<interactive>"] @@ -188,6 +201,12 @@ floatPrim :: T.Text -> PrimIdent floatPrim = PrimIdent floatName++suiteBPrim :: T.Text -> PrimIdent+suiteBPrim = PrimIdent suiteBName++primeECPrim :: T.Text -> PrimIdent+primeECPrim = PrimIdent primeECName arrayPrim :: T.Text -> PrimIdent arrayPrim = PrimIdent arrayName
src/Cryptol/Utils/Misc.hs view
@@ -10,7 +10,6 @@ module Cryptol.Utils.Misc where import MonadLib-import Data.Maybe(fromMaybe) import Prelude () import Prelude.Compat@@ -18,7 +17,7 @@ -- | Apply a function to all elements of a container. -- Returns `Nothing` if nothing changed, and @Just container@ otherwise. anyJust :: Traversable t => (a -> Maybe a) -> t a -> Maybe (t a)-anyJust f m = mk $ runId $ runStateT False $ traverse upd m+anyJust f m = mk $ runLift $ runStateT False $ traverse upd m where mk (a,changes) = if changes then Just a else Nothing @@ -32,4 +31,6 @@ anyJust2 f g (a,b) = case (f a, g b) of (Nothing, Nothing) -> Nothing- (x,y) -> Just (fromMaybe a x, fromMaybe b y)+ (Just x , Nothing) -> Just (x, b)+ (Nothing, Just y ) -> Just (a, y)+ (Just x , Just y ) -> Just (x, y)
src/GitRev.hs view
@@ -24,3 +24,4 @@ dirty :: Bool dirty = $(gitDirty)+-- Last build Fri Sep 11 16:44:33 PDT 2020
utils/CryHtml.hs view
@@ -54,6 +54,7 @@ Num {} -> "number" Frac {} -> "number" Ident {} -> "identifier"+ Selector {} -> "selector" KW {} -> "keyword" Op {} -> "operator" Sym {} -> "symbol"@@ -72,6 +73,7 @@ [ "body { font-family: monospace }" , ".number { color: #cc00cc }" , ".identifier { }"+ , ".selector { color: #33033 }" , ".keyword { color: blue; }" , ".operator { color: #cc00cc }" , ".symbol { color: blue }"