packages feed

monadcryptorandom 0.2 → 0.3

raw patch · 3 files changed

+208/−198 lines, 3 filesdep +transformersPVP ok

version bump matches the API change (PVP)

Dependencies added: transformers

API changes (from Hackage documentation)

- Control.Monad.Crypto.Random: class CRandom a
- Control.Monad.Crypto.Random: class MonadError GenError m => MonadCryptoRandom m
- Control.Monad.Crypto.Random: crandom :: (CRandom a, CryptoRandomGen g) => g -> Either GenError (a, g)
- Control.Monad.Crypto.Random: crandomR :: (CRandom a, CryptoRandomGen g) => (a, a) -> g -> Either GenError (a, g)
- Control.Monad.Crypto.Random: crandomRs :: (CRandom a, CryptoRandomGen g) => (a, a) -> g -> [a]
- Control.Monad.Crypto.Random: crandoms :: (CRandom a, CryptoRandomGen g) => g -> [a]
- Control.Monad.Crypto.Random: data CRandT g m a
- Control.Monad.Crypto.Random: doReseed :: MonadCryptoRandom m => ByteString -> m ()
- Control.Monad.Crypto.Random: evalCRand :: CRand g a -> g -> Either GenError a
- Control.Monad.Crypto.Random: evalCRandT :: Monad m => CRandT g m a -> g -> m (Either GenError a)
- Control.Monad.Crypto.Random: getBytes :: MonadCryptoRandom m => Int -> m ByteString
- Control.Monad.Crypto.Random: getBytesWithEntropy :: MonadCryptoRandom m => Int -> ByteString -> m ByteString
- Control.Monad.Crypto.Random: getCRandom :: (MonadCryptoRandom m, CRandom a) => m a
- Control.Monad.Crypto.Random: getCRandomR :: (MonadCryptoRandom m, CRandom a) => (a, a) -> m a
- Control.Monad.Crypto.Random: instance (Monad m, CryptoRandomGen g) => MonadCryptoRandom (CRandT g m)
- Control.Monad.Crypto.Random: instance CRandom Int
- Control.Monad.Crypto.Random: instance CRandom Int16
- Control.Monad.Crypto.Random: instance CRandom Int32
- Control.Monad.Crypto.Random: instance CRandom Int64
- Control.Monad.Crypto.Random: instance CRandom Int8
- Control.Monad.Crypto.Random: instance CRandom Integer
- Control.Monad.Crypto.Random: instance CRandom Word16
- Control.Monad.Crypto.Random: instance CRandom Word32
- Control.Monad.Crypto.Random: instance CRandom Word64
- Control.Monad.Crypto.Random: instance CRandom Word8
- Control.Monad.Crypto.Random: instance Error GenError
- Control.Monad.Crypto.Random: instance Monad m => Monad (CRandT g m)
- Control.Monad.Crypto.Random: instance Monad m => MonadError GenError (CRandT g m)
- Control.Monad.Crypto.Random: instance MonadTrans (CRandT g)
- Control.Monad.Crypto.Random: runCRand :: CRand g a -> g -> Either GenError (a, g)
- Control.Monad.Crypto.Random: runCRandT :: CRandT g m a -> g -> m (Either GenError (a, g))
- Control.Monad.Crypto.Random: type CRand g = CRandT g Identity
+ Control.Monad.CryptoRandom: class CRandom a
+ Control.Monad.CryptoRandom: class ContainsGenError e
+ Control.Monad.CryptoRandom: class (ContainsGenError e, MonadError e m) => MonadCryptoRandom e m
+ Control.Monad.CryptoRandom: crandom :: (CRandom a, CryptoRandomGen g) => g -> Either GenError (a, g)
+ Control.Monad.CryptoRandom: crandomR :: (CRandom a, CryptoRandomGen g) => (a, a) -> g -> Either GenError (a, g)
+ Control.Monad.CryptoRandom: crandomRs :: (CRandom a, CryptoRandomGen g) => (a, a) -> g -> [a]
+ Control.Monad.CryptoRandom: crandoms :: (CRandom a, CryptoRandomGen g) => g -> [a]
+ Control.Monad.CryptoRandom: data CRandT g e m a
+ Control.Monad.CryptoRandom: doReseed :: MonadCryptoRandom e m => ByteString -> m ()
+ Control.Monad.CryptoRandom: evalCRand :: CRand g GenError a -> g -> Either GenError a
+ Control.Monad.CryptoRandom: evalCRandT :: (ContainsGenError e, Monad m) => CRandT g e m a -> g -> m (Either e a)
+ Control.Monad.CryptoRandom: fromGenError :: ContainsGenError e => GenError -> e
+ Control.Monad.CryptoRandom: getBytes :: MonadCryptoRandom e m => Int -> m ByteString
+ Control.Monad.CryptoRandom: getBytesWithEntropy :: MonadCryptoRandom e m => Int -> ByteString -> m ByteString
+ Control.Monad.CryptoRandom: getCRandom :: (MonadCryptoRandom e m, CRandom a) => m a
+ Control.Monad.CryptoRandom: getCRandomR :: (MonadCryptoRandom e m, CRandom a) => (a, a) -> m a
+ Control.Monad.CryptoRandom: instance (ContainsGenError e, Error e, Monad m, CryptoRandomGen g) => MonadCryptoRandom e (CRandT g e m)
+ Control.Monad.CryptoRandom: instance (Monad m, Error e) => Monad (CRandT g e m)
+ Control.Monad.CryptoRandom: instance (Monad m, Error e) => MonadError e (CRandT g e m)
+ Control.Monad.CryptoRandom: instance (MonadIO m, Error e) => MonadIO (CRandT g e m)
+ Control.Monad.CryptoRandom: instance CRandom Int
+ Control.Monad.CryptoRandom: instance CRandom Int16
+ Control.Monad.CryptoRandom: instance CRandom Int32
+ Control.Monad.CryptoRandom: instance CRandom Int64
+ Control.Monad.CryptoRandom: instance CRandom Int8
+ Control.Monad.CryptoRandom: instance CRandom Integer
+ Control.Monad.CryptoRandom: instance CRandom Word16
+ Control.Monad.CryptoRandom: instance CRandom Word32
+ Control.Monad.CryptoRandom: instance CRandom Word64
+ Control.Monad.CryptoRandom: instance CRandom Word8
+ Control.Monad.CryptoRandom: instance ContainsGenError GenError
+ Control.Monad.CryptoRandom: instance Error GenError
+ Control.Monad.CryptoRandom: instance Error e => MonadTrans (CRandT g e)
+ Control.Monad.CryptoRandom: runCRand :: CRand g GenError a -> g -> Either GenError (a, g)
+ Control.Monad.CryptoRandom: runCRandT :: ContainsGenError e => CRandT g e m a -> g -> m (Either e (a, g))
+ Control.Monad.CryptoRandom: toGenError :: ContainsGenError e => e -> Maybe GenError
+ Control.Monad.CryptoRandom: type CRand g e = CRandT g e Identity

Files

− Control/Monad/Crypto/Random.hs
@@ -1,195 +0,0 @@-{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, FlexibleContexts, GeneralizedNewtypeDeriving #-}-{-|-  Maintainer: Thomas.DuBuisson@gmail.com-  Stability: beta-  Portability: portable --Much like the "MonadRandom" package ("Control.Monad.Random"), this module-provides plumbing for the CryptoRandomGen generators.---}- -module Control.Monad.Crypto.Random-        ( CRandom(..)-        , MonadCryptoRandom(..)-        , CRandT-        , CRand-        , runCRandT-        , evalCRandT-        , runCRand-        , evalCRand-        ) where--import Crypto.Random (CryptoRandomGen(..), GenError(..))-import qualified Data.ByteString as B-import Data.Bits (xor, setBit, shiftR, shiftL, (.&.))-import Data.List (foldl')-import Data.Word-import Data.Int-import Control.Arrow (right)-import Control.Monad (liftM)-import Control.Monad.Identity-import Control.Monad.Error-import Control.Monad.State---- |@MonadCryptoRandom m@ represents a monad that can produce--- random values (or fail with a 'GenError').  It is suggestd--- you use the 'CRandT' transformer in your monad stack.-class (MonadError GenError m) => MonadCryptoRandom m where-        getCRandom   :: CRandom a => m a-        getCRandomR  :: CRandom a => (a,a) -> m a-        getBytes     :: Int -> m B.ByteString-        getBytesWithEntropy :: Int -> B.ByteString -> m B.ByteString-        doReseed :: B.ByteString -> m ()---- |@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--- explicit failure.------ @crandomR (low,high) g@ as typically instantiated will generate a value between--- [low, high] inclusively, swapping the pair if high < low.------ 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)-    crandomR  :: (CryptoRandomGen g) => (a, a) -> g -> Either GenError (a, g)-    crandoms  :: (CryptoRandomGen g) => g -> [a]-    crandoms g =-        case crandom g of-                Left _       -> []-                Right (a,g') -> a : crandoms 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 CRandom Integer where-   crandom = crandomR ((-(2^256)), 2^256)-   crandomR = crandomR_Num--instance CRandom Int where-    crandom = crandomR (minBound, maxBound)-    crandomR = crandomR_Num--instance CRandom Word8 where-    crandom = crandomR (minBound, maxBound)-    crandomR = crandomR_Num-instance CRandom Word16 where-    crandom = crandomR (minBound, maxBound)-    crandomR = crandomR_Num-instance CRandom Word32 where-    crandom = crandomR (minBound, maxBound)-    crandomR = crandomR_Num-instance CRandom Word64 where-    crandom = crandomR (minBound, maxBound)-    crandomR = crandomR_Num--instance CRandom Int8 where-    crandom = crandomR (minBound, maxBound)-    crandomR = crandomR_Num-instance CRandom Int16 where-    crandom = crandomR (minBound, maxBound)-    crandomR = crandomR_Num-instance CRandom Int32 where-    crandom = crandomR (minBound, maxBound)-    crandomR = crandomR_Num-instance CRandom Int64 where-    crandom = crandomR (minBound, maxBound)-    crandomR = crandomR_Num---- FIXME specialize-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 $ fromIntegral low + (bs2i bs .&. mask)-                in if res > high then go g' else Right (res, g')--wrap :: (Monad m) => (g -> Either GenError (a,g)) -> CRandT g m a-wrap f = CRandT $ do-        g <- get-        case f g of-                Right (a,g') -> put g' >> return a-                Left x -> throwError x---- |CRandT is the transformer suggested for MonadCryptoRandom.-newtype CRandT g m a = CRandT { unCRandT :: StateT g (ErrorT GenError m) a } deriving (MonadError GenError, Monad)--instance MonadTrans (CRandT g) where-	lift = CRandT . lift . lift---- |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"),--- 'getCRandom', 'getBytes', and 'runCRandom'.------ @getRandPair = do---   int <- getCRandom---   bytes <- getBytes 100---   return (int, bytes)------  func = do---   g <- newGenIO---   case runCRand getRandPair g of---       Right ((int,bytes), g') -> useRandomVals (int,bytes)---       Left x -> handleGenError x--- @-type CRand g = CRandT g Identity--runCRandT :: CRandT g m a -> g -> m (Either GenError (a,g))-runCRandT m g = runErrorT . flip runStateT g . unCRandT $ m--evalCRandT :: Monad m => CRandT g m a -> g -> m (Either GenError a)-evalCRandT m g = liftM (right fst) (runCRandT m g)--runCRand :: CRand g a -> g -> Either GenError (a, g)-runCRand m = runIdentity . runCRandT m--evalCRand :: CRand g a -> g -> Either GenError a-evalCRand m = runIdentity . evalCRandT m--instance (Monad m, CryptoRandomGen g) => MonadCryptoRandom (CRandT g m) where-        getCRandom  = wrap crandom-        getCRandomR = wrap . crandomR-        getBytes i = wrap (genBytes i)-        getBytesWithEntropy i e = wrap (genBytesWithEntropy i e)-        doReseed bs = CRandT $ do-                        get >>= \g ->-                         case reseed bs g of-                            Right g' -> put g'-                            Left  x  -> throwError x--instance Error GenError where-        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--bs2i :: B.ByteString -> Integer-bs2i bs = B.foldl' (\i b -> (i `shiftL` 8) + fromIntegral b) 0 bs-{-# INLINE bs2i #-}-
+ Control/Monad/CryptoRandom.hs view
@@ -0,0 +1,205 @@+{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, FlexibleContexts, GeneralizedNewtypeDeriving, MultiParamTypeClasses #-}+{-|+  Maintainer: Thomas.DuBuisson@gmail.com+  Stability: beta+  Portability: portable ++Much like the "MonadRandom" package ("Control.Monad.Random"), this module+provides plumbing for the CryptoRandomGen generators.++-}+ +module Control.Monad.CryptoRandom+        ( CRandom(..)+        , MonadCryptoRandom(..)+	, ContainsGenError(..)+        , CRandT+        , CRand+        , runCRandT+        , evalCRandT+        , runCRand+        , evalCRand+        ) where++import Crypto.Random (CryptoRandomGen(..), GenError(..))+import qualified Data.ByteString as B+import Data.Bits (xor, setBit, shiftR, shiftL, (.&.))+import Data.List (foldl')+import Data.Word+import Data.Int+import Control.Arrow (right, left)+import Control.Monad (liftM)+import Control.Monad.Identity+import Control.Monad.Error+import Control.Monad.State+import Control.Monad.IO.Class++-- |@MonadCryptoRandom m@ represents a monad that can produce+-- random values (or fail with a 'GenError').  It is suggestd+-- you use the 'CRandT' transformer in your monad stack.+class (ContainsGenError e, MonadError e m) => MonadCryptoRandom e m where+        getCRandom   :: CRandom a => m a+        getCRandomR  :: CRandom a => (a,a) -> m a+        getBytes     :: Int -> m B.ByteString+        getBytesWithEntropy :: Int -> B.ByteString -> m B.ByteString+        doReseed :: B.ByteString -> m ()++class ContainsGenError e where+	toGenError :: e -> Maybe GenError+	fromGenError :: GenError -> e++instance ContainsGenError GenError where+	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+-- explicit failure.+--+-- @crandomR (low,high) g@ as typically instantiated will generate a value between+-- [low, high] inclusively, swapping the pair if high < low.+--+-- 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)+    crandomR  :: (CryptoRandomGen g) => (a, a) -> g -> Either GenError (a, g)+    crandoms  :: (CryptoRandomGen g) => g -> [a]+    crandoms g =+        case crandom g of+                Left _       -> []+                Right (a,g') -> a : crandoms 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 CRandom Integer where+   crandom = crandomR ((-(2^256)), 2^256)+   crandomR = crandomR_Num++instance CRandom Int where+    crandom = crandomR (minBound, maxBound)+    crandomR = crandomR_Num++instance CRandom Word8 where+    crandom = crandomR (minBound, maxBound)+    crandomR = crandomR_Num+instance CRandom Word16 where+    crandom = crandomR (minBound, maxBound)+    crandomR = crandomR_Num+instance CRandom Word32 where+    crandom = crandomR (minBound, maxBound)+    crandomR = crandomR_Num+instance CRandom Word64 where+    crandom = crandomR (minBound, maxBound)+    crandomR = crandomR_Num++instance CRandom Int8 where+    crandom = crandomR (minBound, maxBound)+    crandomR = crandomR_Num+instance CRandom Int16 where+    crandom = crandomR (minBound, maxBound)+    crandomR = crandomR_Num+instance CRandom Int32 where+    crandom = crandomR (minBound, maxBound)+    crandomR = crandomR_Num+instance CRandom Int64 where+    crandom = crandomR (minBound, maxBound)+    crandomR = crandomR_Num++-- FIXME specialize+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 $ fromIntegral low + (bs2i bs .&. mask)+                in if res > high then go g' else Right (res, g')++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)++-- |CRandT is the transformer suggested for MonadCryptoRandom.+newtype CRandT g e m a = CRandT { unCRandT :: StateT g (ErrorT e m) a } deriving (MonadError e, Monad, MonadIO)++instance (Error e) => MonadTrans (CRandT g e) where+	lift = CRandT . lift . lift++-- |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"),+-- 'getCRandom', 'getBytes', and 'runCRandom'.+--+-- @getRandPair = do+--   int <- getCRandom+--   bytes <- getBytes 100+--   return (int, bytes)+--+--  func = do+--   g <- newGenIO+--   case runCRand getRandPair g of+--       Right ((int,bytes), g') -> useRandomVals (int,bytes)+--       Left x -> handleGenError x+-- @+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++evalCRandT :: (ContainsGenError e, Monad m) => CRandT g e m a -> g -> m (Either e a)+evalCRandT m g = liftM (right fst) (runCRandT m g)++runCRand :: CRand g GenError a -> g -> Either GenError (a, g)+runCRand m = runIdentity . runCRandT m++evalCRand :: CRand g GenError a -> g -> Either GenError a+evalCRand m = runIdentity . evalCRandT m++instance (ContainsGenError e, Error e, Monad m, CryptoRandomGen g) => MonadCryptoRandom e (CRandT g e m) where+        getCRandom  = wrap crandom+        getCRandomR = wrap . crandomR+        getBytes i = wrap (genBytes i)+        getBytesWithEntropy i e = wrap (genBytesWithEntropy i e)+        doReseed bs = CRandT $ do+                        get >>= \g ->+                         case reseed bs g of+                            Right g' -> put g'+                            Left  x  -> throwError (fromGenError x)++instance Error GenError where+        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++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.2+version:        0.3 license:        BSD3 license-file:   LICENSE copyright:      Thomas DuBuisson <thomas.dubuisson@gmail.com>@@ -20,7 +20,7 @@ Library   Build-Depends: base == 4.*,                  bytestring >= 0.9 && < 0.10,-                 mtl >= 2.0, crypto-api >= 0.2+                 mtl >= 2.0, crypto-api >= 0.2, transformers >= 0.2   ghc-options:   hs-source-dirs:-  exposed-modules: Control.Monad.Crypto.Random+  exposed-modules: Control.Monad.CryptoRandom