1-- | 2-- Module : Crypto.Random 3-- License : BSD-style 4-- Maintainer : Vincent Hanquez <vincent@snarc.org> 5-- Stability : stable 6-- Portability : good 7-- 8{-# LANGUAGE GeneralizedNewtypeDeriving #-} 9module Crypto.Random 10 ( 11 -- * Deterministic instances 12 ChaChaDRG 13 , SystemDRG 14 , Seed 15 -- * Seed 16 , seedNew 17 , seedFromInteger 18 , seedToInteger 19 , seedFromBinary 20 -- * Deterministic Random class 21 , getSystemDRG 22 , drgNew 23 , drgNewSeed 24 , drgNewTest 25 , withDRG 26 , withRandomBytes 27 , DRG(..) 28 -- * Random abstraction 29 , MonadRandom(..) 30 , MonadPseudoRandom 31 ) where 32 33import Crypto.Error 34import Crypto.Random.Types 35import Crypto.Random.ChaChaDRG 36import Crypto.Random.SystemDRG 37import Data.ByteArray (ByteArray, ByteArrayAccess, ScrubbedBytes) 38import qualified Data.ByteArray as B 39import Crypto.Internal.Imports 40 41import qualified Crypto.Number.Serialize as Serialize 42 43newtype Seed = Seed ScrubbedBytes 44 deriving (ByteArrayAccess) 45 46-- Length for ChaCha DRG seed 47seedLength :: Int 48seedLength = 40 49 50-- | Create a new Seed from system entropy 51seedNew :: MonadRandom randomly => randomly Seed 52seedNew = Seed `fmap` getRandomBytes seedLength 53 54-- | Convert a Seed to an integer 55seedToInteger :: Seed -> Integer 56seedToInteger (Seed b) = Serialize.os2ip b 57 58-- | Convert an integer to a Seed 59seedFromInteger :: Integer -> Seed 60seedFromInteger i = Seed $ Serialize.i2ospOf_ seedLength (i `mod` 2^(seedLength * 8)) 61 62-- | Convert a binary to a seed 63seedFromBinary :: ByteArrayAccess b => b -> CryptoFailable Seed 64seedFromBinary b 65 | B.length b /= 40 = CryptoFailed (CryptoError_SeedSizeInvalid) 66 | otherwise = CryptoPassed $ Seed $ B.convert b 67 68-- | Create a new DRG from system entropy 69drgNew :: MonadRandom randomly => randomly ChaChaDRG 70drgNew = drgNewSeed `fmap` seedNew 71 72-- | Create a new DRG from a seed 73drgNewSeed :: Seed -> ChaChaDRG 74drgNewSeed (Seed seed) = initialize seed 75 76-- | Create a new DRG from 5 Word64. 77-- 78-- This is a convenient interface to create deterministic interface 79-- for quickcheck style testing. 80-- 81-- It can also be used in other contexts provided the input 82-- has been properly randomly generated. 83drgNewTest :: (Word64, Word64, Word64, Word64, Word64) -> ChaChaDRG 84drgNewTest = initializeWords 85 86-- | Generate @len random bytes and mapped the bytes to the function @f. 87-- 88-- This is equivalent to use Control.Arrow 'first' with 'randomBytesGenerate' 89withRandomBytes :: (ByteArray ba, DRG g) => g -> Int -> (ba -> a) -> (a, g) 90withRandomBytes rng len f = (f bs, rng') 91 where (bs, rng') = randomBytesGenerate len rng 92