packages feed

botan-bindings-0.2.0.0: src/Botan/Bindings/RNG.hs

{-|
Module      : Botan.Bindings.RNG
Description : Random number generators
Copyright   : (c) 2023-2024, Apotheca Labs
              (c) 2024-2025, Haskell Foundation
License     : BSD-3-Clause
Maintainer  : joris@well-typed.com, leo@apotheca.io
Stability   : experimental
Portability : POSIX
-}

{-# LANGUAGE CApiFFI           #-}
{-# LANGUAGE OverloadedStrings #-}

module Botan.Bindings.RNG (
    BotanRNGStruct
  , BotanRNG (..)
  , botan_rng_destroy
  , pattern BOTAN_RNG_TYPE_SYSTEM
  , pattern BOTAN_RNG_TYPE_USER
  , pattern BOTAN_RNG_TYPE_USER_THREADSAFE
  , pattern BOTAN_RNG_TYPE_RDRAND
  , botan_rng_init
  , BotanRNGGetCallback
  , mallocBotanRNGGetCallbackFunPtr
  , BotanRNGAddEntropyCallback
  , mallocBotanRNGAddEntropyCallbackFunPtr
  , BotanRNGDestroyCallback
  , mallocBotanRNGDestroyCallbackFunPtr
  , botan_rng_init_custom
  , botan_rng_get
  , botan_system_rng_get
  , botan_rng_reseed
  , botan_rng_reseed_from_rng
  , botan_rng_add_entropy
  ) where

import           Botan.Bindings.ConstPtr
import           Data.String
import           Data.Word
import           Foreign.C.Types
import           Foreign.ForeignPtr
import           Foreign.Ptr
import           Foreign.Storable

-- | Opaque RNG struct
data {-# CTYPE "botan/ffi.h" "struct botan_rng_struct" #-} BotanRNGStruct

-- | Botan RNG object
newtype {-# CTYPE "botan/ffi.h" "botan_rng_t" #-} BotanRNG
    = MkBotanRNG { runBotanRNG :: Ptr BotanRNGStruct }
        deriving newtype (Eq, Ord, Storable)

-- | Frees all resources of the random number generator object
foreign import capi safe "botan/ffi.h &botan_rng_destroy"
    botan_rng_destroy
        :: FinalizerPtr BotanRNGStruct

-- WARNING: Not real botan constants, values are taken from documentation / source code.
-- TODO: Maybe move to Botan.Low.RNG
pattern BOTAN_RNG_TYPE_SYSTEM           -- ^ system RNG
    ,   BOTAN_RNG_TYPE_USER             -- ^ userspace RNG
    ,   BOTAN_RNG_TYPE_USER_THREADSAFE  -- ^ userspace RNG, with internal locking
    ,   BOTAN_RNG_TYPE_RDRAND           -- ^ directly read RDRAND
    ::  (Eq a, IsString a) => a
pattern BOTAN_RNG_TYPE_SYSTEM            = "system"
pattern BOTAN_RNG_TYPE_USER              = "user"
pattern BOTAN_RNG_TYPE_USER_THREADSAFE   = "user-threadsafe"
pattern BOTAN_RNG_TYPE_RDRAND            = "rdrand"

{- |
Initialize a random number generator object

rng_type has the possible values:

    - "system": system RNG

    - "user": userspace RNG

    - "user-threadsafe": userspace RNG, with internal locking

    - "rdrand": directly read RDRAND

Set rng_type to null to let the library choose some default.
-}
foreign import capi safe "botan/ffi.h botan_rng_init"
    botan_rng_init
        :: Ptr BotanRNG     -- ^ __rng__
        -> ConstPtr CChar   -- ^ __rng_type__: type of the rng
        -> IO CInt          -- ^ 0 if success, else error code

-- | Callback for getting random bytes from the rng, return 0 for success
type BotanRNGGetCallback ctx
    =  Ptr ctx      -- ^ __context__
    -> Ptr Word8    -- ^ __out__
    -> CSize        -- ^ __out_len__
    -> IO CInt

-- NOTE: "Wrapper stubs can't be used with CApiFFI."
foreign import ccall "wrapper"
    mallocBotanRNGGetCallbackFunPtr
        :: BotanRNGGetCallback ctx
        -> IO (FunPtr (BotanRNGGetCallback ctx))

-- | Callback for adding entropy to the rng, return 0 for success
type BotanRNGAddEntropyCallback ctx
    =  Ptr ctx          -- ^ __context__
    -> ConstPtr Word8   -- ^ __input[]__
    -> CSize            -- ^ __length__
    -> IO CInt

-- NOTE: "Wrapper stubs can't be used with CApiFFI."
foreign import ccall "wrapper"
    mallocBotanRNGAddEntropyCallbackFunPtr
        :: BotanRNGAddEntropyCallback ctx
        -> IO (FunPtr (BotanRNGAddEntropyCallback ctx))

-- | Callback called when rng is destroyed
type BotanRNGDestroyCallback ctx
    =  Ptr ctx  -- ^ __context__
    -> IO ()

-- NOTE: "Wrapper stubs can't be used with CApiFFI."
foreign import ccall "wrapper"
    mallocBotanRNGDestroyCallbackFunPtr
        :: BotanRNGDestroyCallback ctx
        -> IO (FunPtr (BotanRNGDestroyCallback ctx))

-- | Initialize a custom random number generator from a set of callback functions
foreign import capi safe "botan/ffi.h botan_rng_init_custom"
    botan_rng_init_custom
        :: Ptr BotanRNG     -- ^ __rng_out__
        -> ConstPtr CChar   -- ^ __rng_name__: name of the rng
        -> Ptr ctx          -- ^ __context__: an application-specific context passed to the callback functions
        -> FunPtr (BotanRNGGetCallback ctx)         -- ^ __get_cb__
        -> FunPtr (BotanRNGAddEntropyCallback ctx)  -- ^ __add_entropy_cb__: may be NULL
        -> FunPtr (BotanRNGDestroyCallback ctx)     -- ^ __destroy_cb__: may be NULL
        -> IO CInt

-- | Get random bytes from a random number generators
foreign import capi safe "botan/ffi.h botan_rng_get"
    botan_rng_get
        :: BotanRNG     -- ^ __rng__: rng object
        -> Ptr Word8    -- ^ __out__: output buffer of size out_len
        -> CSize        -- ^ __out_len__: number of requested bytes
        -> IO CInt      -- ^ 0 on success, negative on failure

-- | Get random bytes from system random number generator
foreign import capi safe "botan/ffi.h botan_system_rng_get"
    botan_system_rng_get
        :: Ptr Word8    -- ^ __out__: output buffer of size out_len
        -> CSize        -- ^ __out_len__: number of requested bytes
        -> IO CInt      -- ^ 0 on success, negative on failure

{- |
Reseed a random number generator

Uses the System_RNG as a seed generator.
-}
foreign import capi safe "botan/ffi.h botan_rng_reseed"
    botan_rng_reseed
        :: BotanRNG -- ^ __rng__: rng object
        -> CSize    -- ^ __bits__: number of bits to reseed with
        -> IO CInt  -- ^ 0 on success, a negative value on failure

-- | Reseed a random number generator
foreign import capi safe "botan/ffi.h botan_rng_reseed_from_rng"
    botan_rng_reseed_from_rng
        :: BotanRNG -- ^ __rng__: rng object
        -> BotanRNG -- ^ __source_rng__: the rng that will be read from
        -> CSize    -- ^ __bits__: number of bits to reseed with
        -> IO CInt  -- ^ 0 on success, a negative value on failure

-- | Add some seed material to a random number generator
foreign import capi safe "botan/ffi.h botan_rng_add_entropy"
    botan_rng_add_entropy
        :: BotanRNG         -- ^ __rng__: rng object
        -> ConstPtr Word8   -- ^ __entropy__: the data to add
        -> CSize            -- ^ __entropy_len__: length of entropy buffer
        -> IO CInt          -- ^ 0 on success, a negative value on failure