packages feed

monadcryptorandom 0.5 → 0.5.1

raw patch · 2 files changed

+260/−98 lines, 2 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Control.Monad.CryptoRandom: instance (MonadCRandomR e m, Monoid w) => MonadCRandomR e (RWST r w s m)
+ Control.Monad.CryptoRandom: instance (MonadCRandomR e m, Monoid w) => MonadCRandomR e (WriterT w m)
+ Control.Monad.CryptoRandom: instance (MonadCont m, Error e) => MonadCont (CRandT g e m)
+ Control.Monad.CryptoRandom: instance (MonadReader r m, Error e) => MonadReader r (CRandT g e m)
+ Control.Monad.CryptoRandom: instance (MonadState s m, Error e) => MonadState s (CRandT g e m)
+ Control.Monad.CryptoRandom: instance (MonadWriter w m, Error e) => MonadWriter w (CRandT g e m)
+ Control.Monad.CryptoRandom: instance (Monoid w, MonadCRandom e m) => MonadCRandom e (RWST r w s m)
+ Control.Monad.CryptoRandom: instance (Monoid w, MonadCRandom e m) => MonadCRandom e (WriterT w m)
+ Control.Monad.CryptoRandom: instance MonadCRandom e m => MonadCRandom e (ReaderT r m)
+ Control.Monad.CryptoRandom: instance MonadCRandom e m => MonadCRandom e (StateT s m)
+ Control.Monad.CryptoRandom: instance MonadCRandomR e m => MonadCRandomR e (ReaderT r m)
+ Control.Monad.CryptoRandom: instance MonadCRandomR e m => MonadCRandomR e (StateT s m)

Files

Control/Monad/CryptoRandom.hs view
@@ -1,38 +1,46 @@ {-# LANGUAGE FlexibleInstances, TypeSynonymInstances, FlexibleContexts-  , GeneralizedNewtypeDeriving, MultiParamTypeClasses #-}+  , GeneralizedNewtypeDeriving, MultiParamTypeClasses, UndecidableInstances #-} {-|   Maintainer: Thomas.DuBuisson@gmail.com   Stability: beta-  Portability: portable +  Portability: portable  Much like the "MonadRandom" package ("Control.Monad.Random"), this module provides plumbing for the CryptoRandomGen generators.  -}- + module Control.Monad.CryptoRandom-        ( CRandom(..)-        , CRandomR(..)-        , MonadCRandom(..)-        , MonadCRandomR(..)-        , ContainsGenError(..)-        , CRandT-        , CRand-        , runCRandT-        , evalCRandT-        , runCRand-        , evalCRand-        , newGenCRand-        , module Crypto.Random-        ) where+  ( CRandom(..)+  , CRandomR(..)+  , MonadCRandom(..)+  , MonadCRandomR(..)+  , ContainsGenError(..)+  , CRandT+  , CRand+  , runCRandT+  , evalCRandT+  , runCRand+  , evalCRand+  , newGenCRand+  , module Crypto.Random+  ) where  import Control.Applicative import Control.Arrow (right, left) import Control.Monad (liftM)+import Control.Monad.Cont import Control.Monad.Error import Control.Monad.IO.Class import Control.Monad.Identity-import Control.Monad.State+import Control.Monad.Reader+import Control.Monad.RWS.Lazy as Lazy+import Control.Monad.RWS.Strict as Strict+import Control.Monad.State.Lazy as Lazy+import Control.Monad.State.Strict as Strict+import Control.Monad.Writer.Class+import Control.Monad.Writer.Lazy as Lazy+import Control.Monad.Writer.Strict as Strict import Crypto.Random (CryptoRandomGen(..), GenError(..)) import Data.Bits (xor, setBit, shiftR, shiftL, (.&.)) import Data.Int@@ -45,11 +53,81 @@ -- random values (or fail with a 'GenError').  It is suggested -- you use the 'CRandT' transformer in your monad stack. class (ContainsGenError e, MonadError e m) => MonadCRandom e m where-        getCRandom   :: CRandom a => m a-        getBytes     :: Int -> m B.ByteString-        getBytesWithEntropy :: Int -> B.ByteString -> m B.ByteString-        doReseed :: B.ByteString -> m ()+  getCRandom   :: CRandom a => m a+  getBytes     :: Int -> m B.ByteString+  getBytesWithEntropy :: Int -> B.ByteString -> m B.ByteString+  doReseed :: B.ByteString -> m () +instance MonadCRandom e m => MonadCRandom e (Lazy.StateT s m) where+  getCRandom = lift getCRandom+  {-# INLINE getCRandom #-}+  getBytes = lift . getBytes+  {-# INLINE getBytes #-}+  getBytesWithEntropy i = lift . getBytesWithEntropy i+  {-# INLINE getBytesWithEntropy #-}+  doReseed = lift . doReseed+  {-# INLINE doReseed #-}++instance MonadCRandom e m => MonadCRandom e (Strict.StateT s m) where+  getCRandom = lift getCRandom+  {-# INLINE getCRandom #-}+  getBytes = lift . getBytes+  {-# INLINE getBytes #-}+  getBytesWithEntropy i = lift . getBytesWithEntropy i+  {-# INLINE getBytesWithEntropy #-}+  doReseed = lift . doReseed+  {-# INLINE doReseed #-}++instance (Monoid w, MonadCRandom e m) => MonadCRandom e (Strict.WriterT w m) where+  getCRandom = lift getCRandom+  {-# INLINE getCRandom #-}+  getBytes = lift . getBytes+  {-# INLINE getBytes #-}+  getBytesWithEntropy i = lift . getBytesWithEntropy i+  {-# INLINE getBytesWithEntropy #-}+  doReseed = lift . doReseed+  {-# INLINE doReseed #-}++instance (Monoid w, MonadCRandom e m) => MonadCRandom e (Lazy.WriterT w m) where+  getCRandom = lift getCRandom+  {-# INLINE getCRandom #-}+  getBytes = lift . getBytes+  {-# INLINE getBytes #-}+  getBytesWithEntropy i = lift . getBytesWithEntropy i+  {-# INLINE getBytesWithEntropy #-}+  doReseed = lift . doReseed+  {-# INLINE doReseed #-}++instance MonadCRandom e m => MonadCRandom e (ReaderT r m) where+  getCRandom = lift getCRandom+  {-# INLINE getCRandom #-}+  getBytes = lift . getBytes+  {-# INLINE getBytes #-}+  getBytesWithEntropy i = lift . getBytesWithEntropy i+  {-# INLINE getBytesWithEntropy #-}+  doReseed = lift . doReseed+  {-# INLINE doReseed #-}++instance (Monoid w, MonadCRandom e m) => MonadCRandom e (Strict.RWST r w s m) where+  getCRandom = lift getCRandom+  {-# INLINE getCRandom #-}+  getBytes = lift . getBytes+  {-# INLINE getBytes #-}+  getBytesWithEntropy i = lift . getBytesWithEntropy i+  {-# INLINE getBytesWithEntropy #-}+  doReseed = lift . doReseed+  {-# INLINE doReseed #-}++instance (Monoid w, MonadCRandom e m) => MonadCRandom e (Lazy.RWST r w s m) where+  getCRandom = lift getCRandom+  {-# INLINE getCRandom #-}+  getBytes = lift . getBytes+  {-# INLINE getBytes #-}+  getBytesWithEntropy i = lift . getBytesWithEntropy i+  {-# INLINE getBytesWithEntropy #-}+  doReseed = lift . doReseed+  {-# INLINE doReseed #-}+ newGenCRand :: (CryptoRandomGen g, MonadCRandom GenError m, Functor m) => m g newGenCRand = go 0   where@@ -58,21 +136,21 @@                 getTypedGen :: (Functor m, CryptoRandomGen g, MonadCRandom GenError m)                             => Proxy g -> m (Either GenError g)                 getTypedGen pr = fmap newGen (getBytes $ proxy genSeedLength pr)-            res <- getTypedGen p +            res <- getTypedGen p             case res of                 Left _  -> go (i+1)                 Right g -> return (g `asProxyTypeOf` p)  class (ContainsGenError e, MonadError e m) => MonadCRandomR e m where-        getCRandomR  :: CRandomR a => (a,a) -> m a+  getCRandomR  :: CRandomR a => (a,a) -> m a  class ContainsGenError e where-        toGenError :: e -> Maybe GenError-        fromGenError :: GenError -> e+  toGenError :: e -> Maybe GenError+  fromGenError :: GenError -> e  instance ContainsGenError GenError where-        toGenError = Just-        fromGenError = id+  toGenError = Just+  fromGenError = id  -- |@CRandom a@ is much like the 'Random' class from the "System.Random" module in the "random" package. -- The main difference is CRandom builds on "crypto-api"'s 'CryptoRandomGen', so it allows@@ -83,118 +161,166 @@ -- -- Provided instances for @crandom g@ generates randoms between the bounds and between +/- 2^256 -- for Integer.--- +-- -- The 'crandomR' function has degraded (theoretically unbounded, probabilistically decent) performance -- the closer your range size (high - low) is to 2^n (from the top). class CRandom a where-    crandom   :: (CryptoRandomGen g) => g -> Either GenError (a, g)-    crandoms  :: (CryptoRandomGen g) => g -> [a]-    crandoms g =-        case crandom g of-                Left _       -> []-                Right (a,g') -> a : crandoms g'+  crandom   :: (CryptoRandomGen g) => g -> Either GenError (a, g)+  crandoms  :: (CryptoRandomGen g) => g -> [a]+  crandoms g =+    case crandom g of+      Left _       -> []+      Right (a,g') -> a : crandoms g'  class CRandomR a where-    crandomR  :: (CryptoRandomGen g) => (a, a) -> g -> Either GenError (a, g)-    crandomRs :: (CryptoRandomGen g) => (a, a) -> g -> [a]-    crandomRs r g =-        case crandomR r g of-                Left _       -> []-                Right (a,g') -> a : crandomRs r g'+  crandomR  :: (CryptoRandomGen g) => (a, a) -> g -> Either GenError (a, g)+  crandomRs :: (CryptoRandomGen g) => (a, a) -> g -> [a]+  crandomRs r g =+    case crandomR r g of+      Left _       -> []+      Right (a,g') -> a : crandomRs r g'  instance CRandomR Integer where-   crandomR = crandomR_Num+  crandomR = crandomR_Num+  {-# INLINE crandomR #-}  instance CRandom Int where-    crandom = crandomR (minBound, maxBound)+  crandom = crandomR (minBound, maxBound)+  {-# INLINE crandom #-}  instance CRandomR Int where-    crandomR = crandomR_Num+  crandomR = crandomR_Num+  {-# INLINE crandomR #-}  instance CRandom Word8 where-    crandom = crandomR (minBound, maxBound)+  crandom = crandomR (minBound, maxBound)+  {-# INLINE crandom #-}  instance CRandomR Word8 where-    crandomR = crandomR_Num+  crandomR = crandomR_Num+  {-# INLINE crandomR #-}  instance CRandom Word16 where-    crandom = crandomR (minBound, maxBound)+  crandom = crandomR (minBound, maxBound)+  {-# INLINE crandom #-}  instance CRandomR Word16 where-    crandomR = crandomR_Num+  crandomR = crandomR_Num+  {-# INLINE crandomR #-}  instance CRandom Word32 where-    crandom = crandomR (minBound, maxBound)+  crandom = crandomR (minBound, maxBound)+  {-# INLINE crandom #-}  instance CRandomR Word32 where-    crandomR = crandomR_Num+  crandomR = crandomR_Num+  {-# INLINE crandomR #-}  instance CRandom Word64 where-    crandom = crandomR (minBound, maxBound)+  crandom = crandomR (minBound, maxBound)+  {-# INLINE crandom #-}  instance CRandomR Word64 where-    crandomR = crandomR_Num+  crandomR = crandomR_Num+  {-# INLINE crandomR #-}  instance CRandom Int8 where-    crandom = crandomR (minBound, maxBound)+  crandom = crandomR (minBound, maxBound)+  {-# INLINE crandom #-}  instance CRandomR Int8 where-    crandomR = crandomR_Num+  crandomR = crandomR_Num+  {-# INLINE crandomR #-}  instance CRandom Int16 where-    crandom = crandomR (minBound, maxBound)+  crandom = crandomR (minBound, maxBound)+  {-# INLINE crandom #-}  instance CRandomR Int16 where-    crandomR = crandomR_Num+  crandomR = crandomR_Num+  {-# INLINE crandomR #-}  instance CRandom Int32 where-    crandom = crandomR (minBound, maxBound)+  crandom = crandomR (minBound, maxBound)+  {-# INLINE crandom #-}  instance CRandomR Int32 where-    crandomR = crandomR_Num+  crandomR = crandomR_Num+  {-# INLINE crandomR #-}  instance CRandom Int64 where-    crandom = crandomR (minBound, maxBound)+  crandom = crandomR (minBound, maxBound)+  {-# INLINE crandom #-}+ instance CRandomR Int64 where-    crandomR = crandomR_Num+  crandomR = crandomR_Num+  {-# INLINE crandomR #-}  crandomR_Num :: (Integral a, CryptoRandomGen g) => (a,a) -> g -> Either GenError (a,g) crandomR_Num (low, high) g-      | high < low = crandomR_Num  (high,low) g-      | high == low = Right (high, g)-      | otherwise = go g-      where-      mask    = foldl' setBit 0 [0 .. fromIntegral nrBits - 1]-      nrBits  = base2Log range-      range :: Integer-      range   = (fromIntegral high) - (fromIntegral low) + 1-      nrBytes = (nrBits + 7) `div` 8-      go gen =-        let offset = genBytes (fromIntegral nrBytes) gen-        in case offset of-        Left err -> Left err-        Right (bs, g') ->-                let res = fromIntegral low + (bs2i bs .&. mask)-                in if res > fromIntegral high then go g' else Right (fromIntegral res, g')+  | high < low = crandomR_Num  (high,low) g+  | high == low = Right (high, g)+  | otherwise = go g+  where+  mask    = foldl' setBit 0 [0 .. fromIntegral nrBits - 1]+  nrBits  = base2Log range+  range :: Integer+  range   = (fromIntegral high) - (fromIntegral low) + 1+  nrBytes = (nrBits + 7) `div` 8+  go gen =+    let offset = genBytes (fromIntegral nrBytes) gen+    in case offset of+    Left err -> Left err+    Right (bs, g') ->+      let res = fromIntegral low + (bs2i bs .&. mask)+      in if res > fromIntegral high then go g' else Right (fromIntegral res, g') {-# INLINE crandomR_Num #-}  wrap :: (Monad m, ContainsGenError e, Error e) => (g -> Either GenError (a,g)) -> CRandT g e m a wrap f = CRandT $ do-        g <- get-        case f g of-                Right (a,g') -> put g' >> return a-                Left x -> throwError (fromGenError x)+  g <- get+  case f g of+    Right (a,g') -> put g' >> return a+    Left x -> throwError (fromGenError x)+{-# INLINE wrap #-}  -- |CRandT is the transformer suggested for MonadCRandom.-newtype CRandT g e m a = CRandT { unCRandT :: StateT g (ErrorT e m) a } deriving (MonadError e, Monad, MonadIO, Functor, MonadFix)+newtype CRandT g e m a = CRandT { unCRandT :: Lazy.StateT g (ErrorT e m) a } deriving (MonadError e, Monad, MonadIO, Functor, MonadFix)  instance (Functor m,Monad m,Error e) => Applicative (CRandT g e m) where   pure = return+  {-# INLINE pure #-}   (<*>) = ap+  {-# INLINE (<*>) #-}  instance (Error e) => MonadTrans (CRandT g e) where-        lift = CRandT . lift . lift+  lift = CRandT . lift . lift+  {-# INLINE lift #-} +instance (MonadState s m, Error e) => MonadState s (CRandT g e m) where+  get = lift get+  {-# INLINE get #-}+  put = lift . put+  {-# INLINE put #-}++instance (MonadReader r m, Error e) => MonadReader r (CRandT g e m) where+  ask = lift ask+  {-# INLINE ask #-}+  local f = CRandT . local f . unCRandT+  {-# INLINE local #-}++instance (MonadWriter w m, Error e) => MonadWriter w (CRandT g e m) where+  tell = lift . tell+  {-# INLINE tell #-}+  listen = CRandT . listen . unCRandT+  {-# INLINE listen #-}+  pass = CRandT . pass . unCRandT+  {-# INLINE pass #-}++instance (MonadCont m, Error e) => MonadCont (CRandT g e m) where+  callCC f = CRandT $ callCC $ \amb -> unCRandT $ f (CRandT . amb)+  {-# INLINE callCC #-}+ -- |Simple users of generators can use CRand for -- quick and easy generation of randoms.  See -- below for a simple use of 'newGenIO' (from "crypto-api"),@@ -214,44 +340,80 @@ type CRand g e = CRandT g e Identity  runCRandT :: ContainsGenError e => CRandT g e m a -> g -> m (Either e (a,g))-runCRandT m g = runErrorT . flip runStateT g . unCRandT $ m+runCRandT m g = runErrorT . flip Lazy.runStateT g . unCRandT $ m+{-# INLINE runCRandT #-}  evalCRandT :: (ContainsGenError e, Monad m) => CRandT g e m a -> g -> m (Either e a) evalCRandT m g = liftM (right fst) (runCRandT m g)+{-# INLINE evalCRandT #-}  runCRand :: CRand g GenError a -> g -> Either GenError (a, g) runCRand m = runIdentity . runCRandT m+{-# INLINE runCRand #-}  evalCRand :: CRand g GenError a -> g -> Either GenError a evalCRand m = runIdentity . evalCRandT m+{-# INLINE evalCRand #-}  instance (ContainsGenError e, Error e, Monad m, CryptoRandomGen g) => MonadCRandom e (CRandT g e m) where-        getCRandom  = wrap crandom-        getBytes i = wrap (genBytes i)-        getBytesWithEntropy i e = wrap (genBytesWithEntropy i e)-        doReseed bs = CRandT $ do+  getCRandom  = wrap crandom+  {-# INLINE getCRandom #-}+  getBytes i = wrap (genBytes i)+  {-# INLINE getBytes #-}+  getBytesWithEntropy i e = wrap (genBytesWithEntropy i e)+  {-# INLINE getBytesWithEntropy #-}+  doReseed bs = CRandT $ do                         get >>= \g ->                          case reseed bs g of                             Right g' -> put g'                             Left  x  -> throwError (fromGenError x)+  {-# INLINE doReseed #-}  instance (ContainsGenError e, Error e, Monad m, CryptoRandomGen g) => MonadCRandomR e (CRandT g e m) where-        getCRandomR = wrap . crandomR+  getCRandomR = wrap . crandomR+  {-# INLINE getCRandomR #-} +instance MonadCRandomR e m => MonadCRandomR e (Lazy.StateT s m) where+  getCRandomR = lift . getCRandomR+  {-# INLINE getCRandomR #-}++instance MonadCRandomR e m => MonadCRandomR e (Strict.StateT s m) where+  getCRandomR = lift . getCRandomR+  {-# INLINE getCRandomR #-}++instance (MonadCRandomR e m, Monoid w) => MonadCRandomR e (Lazy.WriterT w m) where+  getCRandomR = lift . getCRandomR+  {-# INLINE getCRandomR #-}++instance (MonadCRandomR e m, Monoid w) => MonadCRandomR e (Strict.WriterT w m) where+  getCRandomR = lift . getCRandomR+  {-# INLINE getCRandomR #-}++instance MonadCRandomR e m => MonadCRandomR e (ReaderT r m) where+  getCRandomR = lift . getCRandomR+  {-# INLINE getCRandomR #-}++instance (MonadCRandomR e m, Monoid w) => MonadCRandomR e (Lazy.RWST r w s m) where+  getCRandomR = lift . getCRandomR+  {-# INLINE getCRandomR #-}++instance (MonadCRandomR e m, Monoid w) => MonadCRandomR e (Strict.RWST r w s m) where+  getCRandomR = lift . getCRandomR+  {-# INLINE getCRandomR #-}+ instance Error GenError where-        noMsg = GenErrorOther "noMsg"-        strMsg = GenErrorOther+  noMsg = GenErrorOther "noMsg"+  strMsg = GenErrorOther  base2Log :: Integer -> Integer base2Log i-        | i >= setBit 0 64 = 64 + base2Log (i `shiftR` 64)-        | i >= setBit 0 32 = 32 + base2Log (i `shiftR` 32)-        | i >= setBit 0 16 = 16 + base2Log (i `shiftR` 16)-        | i >= setBit 0 8  = 8  + base2Log (i `shiftR` 8)-        | i >= setBit 0 0  = 1  + base2Log (i `shiftR` 1)-        | otherwise        = 0+  | i >= setBit 0 64 = 64 + base2Log (i `shiftR` 64)+  | i >= setBit 0 32 = 32 + base2Log (i `shiftR` 32)+  | i >= setBit 0 16 = 16 + base2Log (i `shiftR` 16)+  | i >= setBit 0 8  = 8  + base2Log (i `shiftR` 8)+  | i >= setBit 0 0  = 1  + base2Log (i `shiftR` 1)+  | otherwise        = 0  bs2i :: B.ByteString -> Integer bs2i bs = B.foldl' (\i b -> (i `shiftL` 8) + fromIntegral b) 0 bs {-# INLINE bs2i #-}-
monadcryptorandom.cabal view
@@ -1,5 +1,5 @@ name:           monadcryptorandom-version:        0.5+version:        0.5.1 license:        BSD3 license-file:   LICENSE copyright:      Thomas DuBuisson <thomas.dubuisson@gmail.com>