-- |
-- Module      : Crypto.Random.Entropy.Backend
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : stable
-- Portability : good
--
{-# LANGUAGE CPP #-}
{-# LANGUAGE ExistentialQuantification #-}
module Crypto.Random.Entropy.Backend
    ( EntropyBackend
    , supportedBackends
    , gatherBackend
    ) where

import Foreign.Ptr
import Data.Proxy
import Data.Word (Word8)
import Crypto.Random.Entropy.Source
#ifdef SUPPORT_RDRAND
import Crypto.Random.Entropy.RDRand
#endif
#ifdef WINDOWS
import Crypto.Random.Entropy.Windows
#else
import Crypto.Random.Entropy.Unix
#endif

-- | All supported backends 
supportedBackends :: [IO (Maybe EntropyBackend)]
supportedBackends :: [IO (Maybe EntropyBackend)]
supportedBackends =
    [
#ifdef SUPPORT_RDRAND
    Proxy RDRand -> IO (Maybe EntropyBackend)
forall b. EntropySource b => Proxy b -> IO (Maybe EntropyBackend)
openBackend (Proxy RDRand
forall {k} (t :: k). Proxy t
Proxy :: Proxy RDRand),
#endif
#ifdef WINDOWS
    openBackend (Proxy :: Proxy WinCryptoAPI)
#else
    Proxy DevRandom -> IO (Maybe EntropyBackend)
forall b. EntropySource b => Proxy b -> IO (Maybe EntropyBackend)
openBackend (Proxy DevRandom
forall {k} (t :: k). Proxy t
Proxy :: Proxy DevRandom), Proxy DevURandom -> IO (Maybe EntropyBackend)
forall b. EntropySource b => Proxy b -> IO (Maybe EntropyBackend)
openBackend (Proxy DevURandom
forall {k} (t :: k). Proxy t
Proxy :: Proxy DevURandom)
#endif
    ]

-- | Any Entropy Backend
data EntropyBackend = forall b . EntropySource b => EntropyBackend b

-- | Open a backend handle
openBackend :: EntropySource b => Proxy b -> IO (Maybe EntropyBackend)
openBackend :: forall b. EntropySource b => Proxy b -> IO (Maybe EntropyBackend)
openBackend Proxy b
b = (b -> EntropyBackend) -> Maybe b -> Maybe EntropyBackend
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap b -> EntropyBackend
forall b. EntropySource b => b -> EntropyBackend
EntropyBackend (Maybe b -> Maybe EntropyBackend)
-> IO (Maybe b) -> IO (Maybe EntropyBackend)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Proxy b -> IO (Maybe b)
forall b. EntropySource b => Proxy b -> IO (Maybe b)
callOpen Proxy b
b
  where callOpen :: EntropySource b => Proxy b -> IO (Maybe b)
        callOpen :: forall b. EntropySource b => Proxy b -> IO (Maybe b)
callOpen Proxy b
_ = IO (Maybe b)
forall a. EntropySource a => IO (Maybe a)
entropyOpen

-- | Gather randomness from an open handle
gatherBackend :: EntropyBackend -- ^ An open Entropy Backend
              -> Ptr Word8      -- ^ Pointer to a buffer to write to
              -> Int            -- ^ number of bytes to write
              -> IO Int         -- ^ return the number of bytes actually written
gatherBackend :: EntropyBackend -> Ptr Word8 -> Int -> IO Int
gatherBackend (EntropyBackend b
backend) Ptr Word8
ptr Int
n = b -> Ptr Word8 -> Int -> IO Int
forall a. EntropySource a => a -> Ptr Word8 -> Int -> IO Int
entropyGather b
backend Ptr Word8
ptr Int
n