-- | Generation of random numbers via "Crypto.RNG".
module Effectful.Crypto.RNG
  ( -- * Effect
    RNG(..)
  , CryptoRNG(..)

    -- ** Handlers
  , runCryptoRNG

    -- * Instantiation of the initial RNG state
  , CryptoRNGState
  , newCryptoRNGState
  , newCryptoRNGStateSized
  ) where

import Control.Monad.IO.Class
import Crypto.RNG
import Effectful
import Effectful.Dispatch.Dynamic
import qualified System.Random.Stateful as R

import Effectful.Crypto.RNG.Effect

-- | Generate cryptographically secure random numbers.
runCryptoRNG :: IOE :> es => CryptoRNGState -> Eff (RNG : es) a -> Eff es a
runCryptoRNG :: CryptoRNGState -> Eff (RNG : es) a -> Eff es a
runCryptoRNG CryptoRNGState
rng = EffectHandler RNG es -> Eff (RNG : es) a -> Eff es a
forall (e :: (Type -> Type) -> Type -> Type)
       (es :: [(Type -> Type) -> Type -> Type]) a.
(DispatchOf e ~ 'Dynamic) =>
EffectHandler e es -> Eff (e : es) a -> Eff es a
interpret (EffectHandler RNG es -> Eff (RNG : es) a -> Eff es a)
-> EffectHandler RNG es -> Eff (RNG : es) a -> Eff es a
forall a b. (a -> b) -> a -> b
$ \LocalEnv localEs es
_ -> \case
  RandomBytes n  -> IO ByteString -> Eff es ByteString
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO ByteString -> Eff es ByteString)
-> IO ByteString -> Eff es ByteString
forall a b. (a -> b) -> a -> b
$ Int -> CryptoRNGState -> IO ByteString
randomBytesIO Int
n CryptoRNGState
rng
  RNG (Eff localEs) a
Random         -> IO a -> Eff es a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO a -> Eff es a) -> IO a -> Eff es a
forall a b. (a -> b) -> a -> b
$ CryptoRNGState -> IO a
forall a g (m :: Type -> Type).
(Uniform a, StatefulGen g m) =>
g -> m a
R.uniformM CryptoRNGState
rng
  RandomR bounds -> IO a -> Eff es a
forall (m :: Type -> Type) a. MonadIO m => IO a -> m a
liftIO (IO a -> Eff es a) -> IO a -> Eff es a
forall a b. (a -> b) -> a -> b
$ (a, a) -> CryptoRNGState -> IO a
forall a g (m :: Type -> Type).
(UniformRange a, StatefulGen g m) =>
(a, a) -> g -> m a
R.uniformRM (a, a)
bounds CryptoRNGState
rng