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 +0/−195
- Control/Monad/CryptoRandom.hs +205/−0
- monadcryptorandom.cabal +3/−3
− 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