-- |
-- Module      : Crypto.Random.Entropy.RDRand
-- License     : BSD-style
-- Maintainer  : Vincent Hanquez <vincent@snarc.org>
-- Stability   : experimental
-- Portability : Good
--
{-# LANGUAGE ForeignFunctionInterface #-}
module Crypto.Random.Entropy.RDRand
    ( RDRand
    ) where

import Foreign.Ptr
import Foreign.C.Types
import Data.Word (Word8)
import Crypto.Random.Entropy.Source

foreign import ccall unsafe "cryptonite_cpu_has_rdrand"
   c_cpu_has_rdrand :: IO CInt

foreign import ccall unsafe "cryptonite_get_rand_bytes"
  c_get_rand_bytes :: Ptr Word8 -> CInt -> IO CInt

-- | Fake handle to Intel RDRand entropy CPU instruction
data RDRand = RDRand

instance EntropySource RDRand where
    entropyOpen :: IO (Maybe RDRand)
entropyOpen     = IO (Maybe RDRand)
rdrandGrab
    entropyGather :: RDRand -> Ptr Word8 -> Int -> IO Int
entropyGather RDRand
_ = Ptr Word8 -> Int -> IO Int
rdrandGetBytes
    entropyClose :: RDRand -> IO ()
entropyClose  RDRand
_ = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

rdrandGrab :: IO (Maybe RDRand)
rdrandGrab :: IO (Maybe RDRand)
rdrandGrab = CInt -> Maybe RDRand
forall a. (Eq a, Num a) => a -> Maybe RDRand
supported (CInt -> Maybe RDRand) -> IO CInt -> IO (Maybe RDRand)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` IO CInt
c_cpu_has_rdrand
  where supported :: a -> Maybe RDRand
supported a
0 = Maybe RDRand
forall a. Maybe a
Nothing
        supported a
_ = RDRand -> Maybe RDRand
forall a. a -> Maybe a
Just RDRand
RDRand

rdrandGetBytes :: Ptr Word8 -> Int -> IO Int
rdrandGetBytes :: Ptr Word8 -> Int -> IO Int
rdrandGetBytes Ptr Word8
ptr Int
sz = CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CInt -> Int) -> IO CInt -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Ptr Word8 -> CInt -> IO CInt
c_get_rand_bytes Ptr Word8
ptr (Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
sz)