{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE UndecidableInstances #-}
module Crypto.RNG.Class where

import Control.Monad.Trans
import Crypto.Random.DRBG
import Data.ByteString (ByteString)
import System.Random (Uniform, UniformRange)

-- | Monads carrying around the RNG state.
class Monad m => CryptoRNG m where
  -- | Generate a given number of cryptographically secure random bytes.
  randomBytes
    :: ByteLength -- ^ A number of bytes to generate.
    -> m ByteString

  -- | Generate a cryptographically secure value uniformly distributed over all
  -- possible values of that type.
  random :: Uniform a => m a

  -- | Generate a cryptographically secure value in a given, closed range.
  randomR :: UniformRange a => (a, a) -> m a

-- | Generic, overlapping instance.
instance {-# OVERLAPPABLE #-} (
    Monad (t m)
  , MonadTrans t
  , CryptoRNG m
  ) => CryptoRNG (t m) where
    randomBytes :: ByteLength -> t m ByteString
randomBytes = m ByteString -> t m ByteString
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m ByteString -> t m ByteString)
-> (ByteLength -> m ByteString) -> ByteLength -> t m ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteLength -> m ByteString
forall (m :: * -> *). CryptoRNG m => ByteLength -> m ByteString
randomBytes
    random :: t m a
random      = m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m a
forall (m :: * -> *) a. (CryptoRNG m, Uniform a) => m a
random
    randomR :: (a, a) -> t m a
randomR     = m a -> t m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (m a -> t m a) -> ((a, a) -> m a) -> (a, a) -> t m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a, a) -> m a
forall (m :: * -> *) a.
(CryptoRNG m, UniformRange a) =>
(a, a) -> m a
randomR