    -- | Usage of this module is very simple.  Here is a sample GHCi run:
    --
    -- @
    -- *Crypto.Nonce> g <- new
    -- *Crypto.Nonce> nonce128 g
    -- \"c\\164\\252\\162f\\207\\245\\ESC`\\180p\\DC4\\234\\223QP\"
    -- *Crypto.Nonce> nonce128 g
    -- \"\\203C\\190\\138aI\\158\\194\\146\\&7\\208\\&7\\ETX0\\f\\229\"
    -- *Crypto.Nonce> nonce128url g
    -- \"3RP-iEFT-6NrpCMsxigondMC\"
    -- *Crypto.Nonce> nonce128url g
    -- \"MVZH3Gi5zSKXJY-_qdtznxla\"
    -- *Crypto.Nonce> nonce128url g
    -- \"3f3cVNfuZT62-uGco1CBThci\"
    -- *Crypto.Nonce> nonce128urlT g
    -- \"iGMJyrRkw2QMp09SRy59s4Jx\"
    -- *Crypto.Nonce> nonce128urlT g
    -- \"WsHs0KwYiex3tsqQZ8b0119_\"
    -- *Crypto.Nonce> nonce128urlT g
    -- \"JWkLSX7qSFGu1Q3PHuExwurF\"
    -- @
    --
    -- The functions that generate nonces are not pure on purpose,
    -- since that makes it a lot harder to reuse the same nonce.
    module Crypto.Nonce
      ( Generator
      , new
      , delete
      , withGenerator
      , nonce128
      , nonce128url
      , nonce128urlT
      ) where

    import Control.Monad (liftM)
    import Control.Monad.IO.Class (MonadIO, liftIO)
    import qualified System.Entropy as Entropy
    import Data.Typeable (Typeable)
    import Control.Monad.IO.Unlift (MonadUnliftIO)
    import UnliftIO.Exception (bracket)

    import qualified Data.ByteString as B
    import qualified Data.ByteString.Base64.URL as B64URL
    import qualified Data.Text as T
    import qualified Data.Text.Encoding as TE

    -- | An encapsulated nonce generator.
    newtype Generator = G Entropy.CryptHandle
      deriving (Typeable)

    instance Show Generator where
      show :: Generator -> String
    show _ = "<NonceGenerator>"

    -- | Create a new nonce generator using the system entropy.
    new :: MonadIO m => m Generator
    new :: m Generator
    new = (CryptHandle -> Generator) -> m CryptHandle -> m Generator
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM CryptHandle -> Generator
    G (m CryptHandle -> m Generator)
    -> (IO CryptHandle -> m CryptHandle)
    -> IO CryptHandle
    -> m Generator
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . IO CryptHandle -> m CryptHandle
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO CryptHandle -> m Generator) -> IO CryptHandle -> m Generator
    forall a b. (a -> b) -> a -> b
    $ IO CryptHandle
    Entropy.openHandle

    -- | Release the given generator's resources. The generator won't be
    -- usable afterwards.
    delete :: MonadIO m => Generator -> m ()
    delete :: Generator -> m ()
    delete (G v :: CryptHandle
    v) = IO () -> m ()
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO () -> m ()) -> IO () -> m ()
    forall a b. (a -> b) -> a -> b
    $ CryptHandle -> IO ()
    Entropy.closeHandle CryptHandle
    v

    -- | An exception-safe convenience function.
    --
    -- @
    -- withGenerator = bracket new delete
    -- @
    --
    withGenerator :: MonadUnliftIO m => (Generator -> m a) -> m a
    withGenerator :: (Generator -> m a) -> m a
    withGenerator = m Generator -> (Generator -> m ()) -> (Generator -> m a) -> m a
    forall (m :: * -> *) a b c.
    MonadUnliftIO m =>
    m a -> (a -> m b) -> (a -> m c) -> m c
    bracket m Generator
    forall (m :: * -> *). MonadIO m => m Generator
    new Generator -> m ()
    forall (m :: * -> *). MonadIO m => Generator -> m ()
    delete

    -- | (Internal) Generate the given number of bytes from the DRG.
    genBytes :: MonadIO m => Int -> Generator -> m B.ByteString
    genBytes :: Int -> Generator -> m ByteString
    genBytes n :: Int
    n (G v :: CryptHandle
    v) = IO ByteString -> m ByteString
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO ByteString -> m ByteString) -> IO ByteString -> m ByteString
    forall a b. (a -> b) -> a -> b
    $ CryptHandle -> Int -> IO ByteString
    Entropy.hGetEntropy CryptHandle
    v Int
    n

    -- | Generate a 128 bit nonce as a 'B.ByteString' of 16 bytes.
    -- Each byte may have any value from @0@ to @255@.
    nonce128 :: MonadIO m => Generator -> m B.ByteString
    nonce128 :: Generator -> m ByteString
    nonce128 = Int -> Generator -> m ByteString
    forall (m :: * -> *). MonadIO m => Int -> Generator -> m ByteString
    genBytes 16

    -- | Generate a 128 bit nonce as a 'B.ByteString' of 24 bytes.
    -- Each byte is either a letter (upper or lowercase), a digit, a
    -- dash (@-@) or an underscore (@_@), which is the set of
    -- characters from the base64url encoding.  In order to avoid any
    -- issues with padding, the generated nonce actually has 144 bits.
    nonce128url :: MonadIO m => Generator -> m B.ByteString
    nonce128url :: Generator -> m ByteString
    nonce128url = (ByteString -> ByteString) -> m ByteString -> m ByteString
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM ByteString -> ByteString
    B64URL.encode (m ByteString -> m ByteString)
    -> (Generator -> m ByteString) -> Generator -> m ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Int -> Generator -> m ByteString
    forall (m :: * -> *). MonadIO m => Int -> Generator -> m ByteString
    genBytes 18

    -- | Same as 'nonce128url', but returns its result as 'T.Text'
    -- instead.
    nonce128urlT :: MonadIO m => Generator -> m T.Text
    nonce128urlT :: Generator -> m Text
    nonce128urlT = (ByteString -> Text) -> m ByteString -> m Text
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM ByteString -> Text
    TE.decodeUtf8 (m ByteString -> m Text)
    -> (Generator -> m ByteString) -> Generator -> m Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Generator -> m ByteString
    forall (m :: * -> *). MonadIO m => Generator -> m ByteString
    nonce128url