content: {-|
  Module      : Crypto.Lol.Types.Random
  Description : Types for using crypto-api with MonadCryptoRandom.
  Copyright   : (c) Eric Crockett, 2011-2017
                    Chris Peikert, 2011-2017
  License     : GPL-3
  Maintainer  : ecrockett0@email.com
  Stability   : experimental
  Portability : POSIX
  
  Defines a newtype wrapper 'CryptoRand' for crypto-api's
  'CryptoRandomGen', and a corresponding 'RandomGen' wrapper
  instance.  These are needed because 'CryptoRandomGen' generators
  can only be used to get "Data.ByteString"s; the 'RandomGen' wrapper
  instance allows them to be used to generate any 'Random' type.
  -}
  
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  
  module Crypto.Lol.Types.Random (CryptoRand, evalCryptoRandIO) where
  
  import Control.Arrow
  import Control.Monad.CryptoRandom
  import Control.Monad.IO.Class
  import Control.Monad.Random       (RandT, evalRandT)
  import Crypto.Random
  import System.Random
  
  -- | Turns a 'CryptoRandomGen' @g@ into a standard 'RandomGen'.
  newtype CryptoRand g = CryptoRand g deriving (CryptoRandomGen)
  
  -- | Evaluate a 'RandT' computation using a cryptographic generator
  -- @g@, seeded by system entropy.  Note that the updated generator is
  -- not returned.
  evalCryptoRandIO :: (CryptoRandomGen g, MonadIO io) => RandT g io a -> io a
  evalCryptoRandIO x = do
    gen <- liftIO newGenIO -- uses system entropy
    evalRandT x gen
  
  -- "standard" RNG interface wrapper for a cryptographic RNG
  instance (CryptoRandomGen g) => RandomGen (CryptoRand g) where
    -- use 'CRandom' instance for 'Int'
    next (CryptoRand g) = either (error . show) (second CryptoRand) $ crandom g
  
    split (CryptoRand g) =
      either (error . show) (CryptoRand *** CryptoRand) $ splitGen g
  
    {-# INLINABLE next #-}
    {-# INLINABLE split #-}
  