    {-# LANGUAGE BangPatterns       #-}
    {-# LANGUAGE DeriveDataTypeable #-}
    {-# LANGUAGE DeriveGeneric      #-}
    {-# LANGUAGE LambdaCase         #-}
    {-# LANGUAGE OverloadedStrings  #-}
    {-# LANGUAGE RecordWildCards    #-}
    {-# LANGUAGE Trustworthy        #-}

    {-|

    Module      : Crypto.Argon2
    License     : BSD3
    Maintainer  : hvr@gnu.org

    "Crypto.Argon2" provides bindings to the
    <https://github.com/P-H-C/phc-winner-argon2 reference implementation> of Argon2,
    the password-hashing function that won the
    <https://password-hashing.net/ Password Hashing Competition (PHC)>.

    The main entry points to this module are 'hashEncoded', which produces a
    crypt-like ASCII output; and 'hash' which produces a 'BS.ByteString' (a stream
    of bytes). Argon2 is a configurable hash function, and can be configured by
    supplying a particular set of 'HashOptions' - 'defaultHashOptions' should provide
    a good starting point. See 'HashOptions' for more documentation on the particular
    parameters that can be adjusted.

    For (unsafe) access directly to the C interface, see "Crypto.Argon2.FFI".

    @since 1.3.0.0
    -}
    module Crypto.Argon2
        ( -- * Hash computation & verification
          -- ** Binary hash representation
          hash
          -- ** ASCII-encoded representation
          --
          -- | These operations use the [PHC string format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md), a [crypt(3)](https://en.wikipedia.org/wiki/Crypt_\(C\))-like serialization format for password hashes.
        , hashEncoded
        , verifyEncoded
          -- * Configuring hashing
        , HashOptions(..)
        , Argon2Variant(..)
        , Argon2Version(..)
        , defaultHashOptions
          -- * Status codes
        , Argon2Status(..)
        ) where

    import           Control.DeepSeq   (NFData (rnf))
    import           Control.Exception
    import qualified Crypto.Argon2.FFI as FFI
    import qualified Data.ByteString   as BS
    import qualified Data.Text.Short   as TS
    import           Data.Typeable
    import           Foreign
    import           Foreign.C
    import           GHC.Generics      (Generic)
    import           System.IO.Unsafe  (unsafePerformIO)

    -- | Which variant of Argon2 to use. You should choose the variant that is most
    -- applicable to your intention to hash inputs.
    data Argon2Variant
      = Argon2i  -- ^ Argon2i uses data-independent memory access, which is preferred
                 -- for password hashing and password-based key derivation. Argon2i
                 -- is slower as it makes more passes over the memory to protect from
                 -- tradeoff attacks.
      | Argon2d  -- ^ Argon2d is faster and uses data-depending memory access, which
                 -- makes it suitable for cryptocurrencies and applications with no
                 -- threats from side-channel timing attacks.
      | Argon2id -- ^ Argon2id works as Argon2i for the first half of the first iteration
                 -- over the memory, and as Argon2d for the rest, thus providing both
                 -- side-channel attack protection and brute-force cost savings due to
                 -- time-memory tradeoffs.
      deriving (Argon2Variant -> Argon2Variant -> Bool
    (Argon2Variant -> Argon2Variant -> Bool)
    -> (Argon2Variant -> Argon2Variant -> Bool) -> Eq Argon2Variant
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Argon2Variant -> Argon2Variant -> Bool
    $c/= :: Argon2Variant -> Argon2Variant -> Bool
    == :: Argon2Variant -> Argon2Variant -> Bool
    $c== :: Argon2Variant -> Argon2Variant -> Bool
    Eq,Eq Argon2Variant
    Eq Argon2Variant =>
    (Argon2Variant -> Argon2Variant -> Ordering)
    -> (Argon2Variant -> Argon2Variant -> Bool)
    -> (Argon2Variant -> Argon2Variant -> Bool)
    -> (Argon2Variant -> Argon2Variant -> Bool)
    -> (Argon2Variant -> Argon2Variant -> Bool)
    -> (Argon2Variant -> Argon2Variant -> Argon2Variant)
    -> (Argon2Variant -> Argon2Variant -> Argon2Variant)
    -> Ord Argon2Variant
    Argon2Variant -> Argon2Variant -> Bool
    Argon2Variant -> Argon2Variant -> Ordering
    Argon2Variant -> Argon2Variant -> Argon2Variant
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    min :: Argon2Variant -> Argon2Variant -> Argon2Variant
    $cmin :: Argon2Variant -> Argon2Variant -> Argon2Variant
    max :: Argon2Variant -> Argon2Variant -> Argon2Variant
    $cmax :: Argon2Variant -> Argon2Variant -> Argon2Variant
    >= :: Argon2Variant -> Argon2Variant -> Bool
    $c>= :: Argon2Variant -> Argon2Variant -> Bool
    > :: Argon2Variant -> Argon2Variant -> Bool
    $c> :: Argon2Variant -> Argon2Variant -> Bool
    <= :: Argon2Variant -> Argon2Variant -> Bool
    $c<= :: Argon2Variant -> Argon2Variant -> Bool
    < :: Argon2Variant -> Argon2Variant -> Bool
    $c< :: Argon2Variant -> Argon2Variant -> Bool
    compare :: Argon2Variant -> Argon2Variant -> Ordering
    $ccompare :: Argon2Variant -> Argon2Variant -> Ordering
    $cp1Ord :: Eq Argon2Variant
    Ord,ReadPrec [Argon2Variant]
    ReadPrec Argon2Variant
    Int -> ReadS Argon2Variant
    ReadS [Argon2Variant]
    (Int -> ReadS Argon2Variant)
    -> ReadS [Argon2Variant]
    -> ReadPrec Argon2Variant
    -> ReadPrec [Argon2Variant]
    -> Read Argon2Variant
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    readListPrec :: ReadPrec [Argon2Variant]
    $creadListPrec :: ReadPrec [Argon2Variant]
    readPrec :: ReadPrec Argon2Variant
    $creadPrec :: ReadPrec Argon2Variant
    readList :: ReadS [Argon2Variant]
    $creadList :: ReadS [Argon2Variant]
    readsPrec :: Int -> ReadS Argon2Variant
    $creadsPrec :: Int -> ReadS Argon2Variant
    Read,Int -> Argon2Variant -> ShowS
    [Argon2Variant] -> ShowS
    Argon2Variant -> String
    (Int -> Argon2Variant -> ShowS)
    -> (Argon2Variant -> String)
    -> ([Argon2Variant] -> ShowS)
    -> Show Argon2Variant
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Argon2Variant] -> ShowS
    $cshowList :: [Argon2Variant] -> ShowS
    show :: Argon2Variant -> String
    $cshow :: Argon2Variant -> String
    showsPrec :: Int -> Argon2Variant -> ShowS
    $cshowsPrec :: Int -> Argon2Variant -> ShowS
    Show,Argon2Variant
    Argon2Variant -> Argon2Variant -> Bounded Argon2Variant
    forall a. a -> a -> Bounded a
    maxBound :: Argon2Variant
    $cmaxBound :: Argon2Variant
    minBound :: Argon2Variant
    $cminBound :: Argon2Variant
    Bounded,(forall x. Argon2Variant -> Rep Argon2Variant x)
    -> (forall x. Rep Argon2Variant x -> Argon2Variant)
    -> Generic Argon2Variant
    forall x. Rep Argon2Variant x -> Argon2Variant
    forall x. Argon2Variant -> Rep Argon2Variant x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cto :: forall x. Rep Argon2Variant x -> Argon2Variant
    $cfrom :: forall x. Argon2Variant -> Rep Argon2Variant x
    Generic,Typeable,Int -> Argon2Variant
    Argon2Variant -> Int
    Argon2Variant -> [Argon2Variant]
    Argon2Variant -> Argon2Variant
    Argon2Variant -> Argon2Variant -> [Argon2Variant]
    Argon2Variant -> Argon2Variant -> Argon2Variant -> [Argon2Variant]
    (Argon2Variant -> Argon2Variant)
    -> (Argon2Variant -> Argon2Variant)
    -> (Int -> Argon2Variant)
    -> (Argon2Variant -> Int)
    -> (Argon2Variant -> [Argon2Variant])
    -> (Argon2Variant -> Argon2Variant -> [Argon2Variant])
    -> (Argon2Variant -> Argon2Variant -> [Argon2Variant])
    -> (Argon2Variant
        -> Argon2Variant -> Argon2Variant -> [Argon2Variant])
    -> Enum Argon2Variant
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    enumFromThenTo :: Argon2Variant -> Argon2Variant -> Argon2Variant -> [Argon2Variant]
    $cenumFromThenTo :: Argon2Variant -> Argon2Variant -> Argon2Variant -> [Argon2Variant]
    enumFromTo :: Argon2Variant -> Argon2Variant -> [Argon2Variant]
    $cenumFromTo :: Argon2Variant -> Argon2Variant -> [Argon2Variant]
    enumFromThen :: Argon2Variant -> Argon2Variant -> [Argon2Variant]
    $cenumFromThen :: Argon2Variant -> Argon2Variant -> [Argon2Variant]
    enumFrom :: Argon2Variant -> [Argon2Variant]
    $cenumFrom :: Argon2Variant -> [Argon2Variant]
    fromEnum :: Argon2Variant -> Int
    $cfromEnum :: Argon2Variant -> Int
    toEnum :: Int -> Argon2Variant
    $ctoEnum :: Int -> Argon2Variant
    pred :: Argon2Variant -> Argon2Variant
    $cpred :: Argon2Variant -> Argon2Variant
    succ :: Argon2Variant -> Argon2Variant
    $csucc :: Argon2Variant -> Argon2Variant
    Enum)

    instance NFData Argon2Variant where rnf :: Argon2Variant -> ()
    rnf !Argon2Variant
    _ = ()

    toArgon2Type :: Argon2Variant -> FFI.Argon2_type
    toArgon2Type :: Argon2Variant -> Argon2_type
    toArgon2Type Argon2i  = Argon2_type
    forall a. (Eq a, Num a) => a
    FFI.Argon2_i
    toArgon2Type Argon2d  = Argon2_type
    forall a. (Eq a, Num a) => a
    FFI.Argon2_d
    toArgon2Type Argon2id = Argon2_type
    forall a. (Eq a, Num a) => a
    FFI.Argon2_id

    -- | Version of the Argon2 algorithm.
    data Argon2Version
      = Argon2Version10 -- ^ Version 1.0 (deprecated)
      | Argon2Version13 -- ^ Version 1.3 (See [this announcment](https://www.ietf.org/mail-archive/web/cfrg/current/msg07948.html) for more details)
      deriving (Argon2Version -> Argon2Version -> Bool
    (Argon2Version -> Argon2Version -> Bool)
    -> (Argon2Version -> Argon2Version -> Bool) -> Eq Argon2Version
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Argon2Version -> Argon2Version -> Bool
    $c/= :: Argon2Version -> Argon2Version -> Bool
    == :: Argon2Version -> Argon2Version -> Bool
    $c== :: Argon2Version -> Argon2Version -> Bool
    Eq,Eq Argon2Version
    Eq Argon2Version =>
    (Argon2Version -> Argon2Version -> Ordering)
    -> (Argon2Version -> Argon2Version -> Bool)
    -> (Argon2Version -> Argon2Version -> Bool)
    -> (Argon2Version -> Argon2Version -> Bool)
    -> (Argon2Version -> Argon2Version -> Bool)
    -> (Argon2Version -> Argon2Version -> Argon2Version)
    -> (Argon2Version -> Argon2Version -> Argon2Version)
    -> Ord Argon2Version
    Argon2Version -> Argon2Version -> Bool
    Argon2Version -> Argon2Version -> Ordering
    Argon2Version -> Argon2Version -> Argon2Version
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    min :: Argon2Version -> Argon2Version -> Argon2Version
    $cmin :: Argon2Version -> Argon2Version -> Argon2Version
    max :: Argon2Version -> Argon2Version -> Argon2Version
    $cmax :: Argon2Version -> Argon2Version -> Argon2Version
    >= :: Argon2Version -> Argon2Version -> Bool
    $c>= :: Argon2Version -> Argon2Version -> Bool
    > :: Argon2Version -> Argon2Version -> Bool
    $c> :: Argon2Version -> Argon2Version -> Bool
    <= :: Argon2Version -> Argon2Version -> Bool
    $c<= :: Argon2Version -> Argon2Version -> Bool
    < :: Argon2Version -> Argon2Version -> Bool
    $c< :: Argon2Version -> Argon2Version -> Bool
    compare :: Argon2Version -> Argon2Version -> Ordering
    $ccompare :: Argon2Version -> Argon2Version -> Ordering
    $cp1Ord :: Eq Argon2Version
    Ord,ReadPrec [Argon2Version]
    ReadPrec Argon2Version
    Int -> ReadS Argon2Version
    ReadS [Argon2Version]
    (Int -> ReadS Argon2Version)
    -> ReadS [Argon2Version]
    -> ReadPrec Argon2Version
    -> ReadPrec [Argon2Version]
    -> Read Argon2Version
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    readListPrec :: ReadPrec [Argon2Version]
    $creadListPrec :: ReadPrec [Argon2Version]
    readPrec :: ReadPrec Argon2Version
    $creadPrec :: ReadPrec Argon2Version
    readList :: ReadS [Argon2Version]
    $creadList :: ReadS [Argon2Version]
    readsPrec :: Int -> ReadS Argon2Version
    $creadsPrec :: Int -> ReadS Argon2Version
    Read,Int -> Argon2Version -> ShowS
    [Argon2Version] -> ShowS
    Argon2Version -> String
    (Int -> Argon2Version -> ShowS)
    -> (Argon2Version -> String)
    -> ([Argon2Version] -> ShowS)
    -> Show Argon2Version
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Argon2Version] -> ShowS
    $cshowList :: [Argon2Version] -> ShowS
    show :: Argon2Version -> String
    $cshow :: Argon2Version -> String
    showsPrec :: Int -> Argon2Version -> ShowS
    $cshowsPrec :: Int -> Argon2Version -> ShowS
    Show,Argon2Version
    Argon2Version -> Argon2Version -> Bounded Argon2Version
    forall a. a -> a -> Bounded a
    maxBound :: Argon2Version
    $cmaxBound :: Argon2Version
    minBound :: Argon2Version
    $cminBound :: Argon2Version
    Bounded,(forall x. Argon2Version -> Rep Argon2Version x)
    -> (forall x. Rep Argon2Version x -> Argon2Version)
    -> Generic Argon2Version
    forall x. Rep Argon2Version x -> Argon2Version
    forall x. Argon2Version -> Rep Argon2Version x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cto :: forall x. Rep Argon2Version x -> Argon2Version
    $cfrom :: forall x. Argon2Version -> Rep Argon2Version x
    Generic,Typeable,Int -> Argon2Version
    Argon2Version -> Int
    Argon2Version -> [Argon2Version]
    Argon2Version -> Argon2Version
    Argon2Version -> Argon2Version -> [Argon2Version]
    Argon2Version -> Argon2Version -> Argon2Version -> [Argon2Version]
    (Argon2Version -> Argon2Version)
    -> (Argon2Version -> Argon2Version)
    -> (Int -> Argon2Version)
    -> (Argon2Version -> Int)
    -> (Argon2Version -> [Argon2Version])
    -> (Argon2Version -> Argon2Version -> [Argon2Version])
    -> (Argon2Version -> Argon2Version -> [Argon2Version])
    -> (Argon2Version
        -> Argon2Version -> Argon2Version -> [Argon2Version])
    -> Enum Argon2Version
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    enumFromThenTo :: Argon2Version -> Argon2Version -> Argon2Version -> [Argon2Version]
    $cenumFromThenTo :: Argon2Version -> Argon2Version -> Argon2Version -> [Argon2Version]
    enumFromTo :: Argon2Version -> Argon2Version -> [Argon2Version]
    $cenumFromTo :: Argon2Version -> Argon2Version -> [Argon2Version]
    enumFromThen :: Argon2Version -> Argon2Version -> [Argon2Version]
    $cenumFromThen :: Argon2Version -> Argon2Version -> [Argon2Version]
    enumFrom :: Argon2Version -> [Argon2Version]
    $cenumFrom :: Argon2Version -> [Argon2Version]
    fromEnum :: Argon2Version -> Int
    $cfromEnum :: Argon2Version -> Int
    toEnum :: Int -> Argon2Version
    $ctoEnum :: Int -> Argon2Version
    pred :: Argon2Version -> Argon2Version
    $cpred :: Argon2Version -> Argon2Version
    succ :: Argon2Version -> Argon2Version
    $csucc :: Argon2Version -> Argon2Version
    Enum)

    instance NFData Argon2Version where rnf :: Argon2Version -> ()
    rnf !Argon2Version
    _ = ()

    toArgon2Ver :: Argon2Version -> FFI.Argon2_version
    toArgon2Ver :: Argon2Version -> Argon2_type
    toArgon2Ver Argon2Version10 = Argon2_type
    forall a. (Eq a, Num a) => a
    FFI.ARGON2_VERSION_10
    toArgon2Ver Argon2Version13 = Argon2_type
    forall a. (Eq a, Num a) => a
    FFI.ARGON2_VERSION_13

    -- | Parameters that can be adjusted to change the runtime performance of the
    -- hashing. See also 'defaultHashOptions'.
    data HashOptions =
      HashOptions { HashOptions -> Argon2_type
    hashIterations  :: !Word32 -- ^ The time cost, which defines the amount of computation realized and therefore the execution time, given in number of iterations.
                                             --
                                             -- 'FFI.ARGON2_MIN_TIME' <= 'hashIterations' <= 'FFI.ARGON2_MAX_TIME'

                  , HashOptions -> Argon2_type
    hashMemory      :: !Word32 -- ^ The memory cost, which defines the memory usage, given in [kibibytes](https://en.wikipedia.org/wiki/Kibibyte).
                                         --
                                         -- max 'FFI.ARGON2_MIN_MEMORY' (8 * 'hashParallelism') <= 'hashMemory' <= 'FFI.ARGON2_MAX_MEMORY'

                  , HashOptions -> Argon2_type
    hashParallelism :: !Word32 -- ^ A parallelism degree, which defines the number of parallel threads.
                                              --
                                              -- 'FFI.ARGON2_MIN_LANES' <= 'hashParallelism' <= 'FFI.ARGON2_MAX_LANES' && 'FFI.ARGON_MIN_THREADS' <= 'hashParallelism' <= 'FFI.ARGON2_MAX_THREADS'

                  , HashOptions -> Argon2Variant
    hashVariant     :: !Argon2Variant -- ^ Which variant of Argon2 to use.

                  , HashOptions -> Argon2Version
    hashVersion     :: !Argon2Version -- ^ Which version of Argon2 to use for generating hashes.

                  , HashOptions -> Argon2_type
    hashLength      :: !Word32        -- ^ Desired length of hash expressed in octets.
                  }
      deriving (HashOptions -> HashOptions -> Bool
    (HashOptions -> HashOptions -> Bool)
    -> (HashOptions -> HashOptions -> Bool) -> Eq HashOptions
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: HashOptions -> HashOptions -> Bool
    $c/= :: HashOptions -> HashOptions -> Bool
    == :: HashOptions -> HashOptions -> Bool
    $c== :: HashOptions -> HashOptions -> Bool
    Eq,Eq HashOptions
    Eq HashOptions =>
    (HashOptions -> HashOptions -> Ordering)
    -> (HashOptions -> HashOptions -> Bool)
    -> (HashOptions -> HashOptions -> Bool)
    -> (HashOptions -> HashOptions -> Bool)
    -> (HashOptions -> HashOptions -> Bool)
    -> (HashOptions -> HashOptions -> HashOptions)
    -> (HashOptions -> HashOptions -> HashOptions)
    -> Ord HashOptions
    HashOptions -> HashOptions -> Bool
    HashOptions -> HashOptions -> Ordering
    HashOptions -> HashOptions -> HashOptions
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    min :: HashOptions -> HashOptions -> HashOptions
    $cmin :: HashOptions -> HashOptions -> HashOptions
    max :: HashOptions -> HashOptions -> HashOptions
    $cmax :: HashOptions -> HashOptions -> HashOptions
    >= :: HashOptions -> HashOptions -> Bool
    $c>= :: HashOptions -> HashOptions -> Bool
    > :: HashOptions -> HashOptions -> Bool
    $c> :: HashOptions -> HashOptions -> Bool
    <= :: HashOptions -> HashOptions -> Bool
    $c<= :: HashOptions -> HashOptions -> Bool
    < :: HashOptions -> HashOptions -> Bool
    $c< :: HashOptions -> HashOptions -> Bool
    compare :: HashOptions -> HashOptions -> Ordering
    $ccompare :: HashOptions -> HashOptions -> Ordering
    $cp1Ord :: Eq HashOptions
    Ord,ReadPrec [HashOptions]
    ReadPrec HashOptions
    Int -> ReadS HashOptions
    ReadS [HashOptions]
    (Int -> ReadS HashOptions)
    -> ReadS [HashOptions]
    -> ReadPrec HashOptions
    -> ReadPrec [HashOptions]
    -> Read HashOptions
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    readListPrec :: ReadPrec [HashOptions]
    $creadListPrec :: ReadPrec [HashOptions]
    readPrec :: ReadPrec HashOptions
    $creadPrec :: ReadPrec HashOptions
    readList :: ReadS [HashOptions]
    $creadList :: ReadS [HashOptions]
    readsPrec :: Int -> ReadS HashOptions
    $creadsPrec :: Int -> ReadS HashOptions
    Read,Int -> HashOptions -> ShowS
    [HashOptions] -> ShowS
    HashOptions -> String
    (Int -> HashOptions -> ShowS)
    -> (HashOptions -> String)
    -> ([HashOptions] -> ShowS)
    -> Show HashOptions
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [HashOptions] -> ShowS
    $cshowList :: [HashOptions] -> ShowS
    show :: HashOptions -> String
    $cshow :: HashOptions -> String
    showsPrec :: Int -> HashOptions -> ShowS
    $cshowsPrec :: Int -> HashOptions -> ShowS
    Show,HashOptions
    HashOptions -> HashOptions -> Bounded HashOptions
    forall a. a -> a -> Bounded a
    maxBound :: HashOptions
    $cmaxBound :: HashOptions
    minBound :: HashOptions
    $cminBound :: HashOptions
    Bounded,(forall x. HashOptions -> Rep HashOptions x)
    -> (forall x. Rep HashOptions x -> HashOptions)
    -> Generic HashOptions
    forall x. Rep HashOptions x -> HashOptions
    forall x. HashOptions -> Rep HashOptions x
    forall a.
    (forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
    $cto :: forall x. Rep HashOptions x -> HashOptions
    $cfrom :: forall x. HashOptions -> Rep HashOptions x
    Generic,Typeable)

    instance NFData HashOptions where rnf :: HashOptions -> ()
    rnf !HashOptions
    _ = ()

    -- | A set of default 'HashOptions', taken from the @argon2@ executable.
    --
    -- @
    -- 'defaultHashOptions' :: 'HashOptions'
    -- 'defaultHashOptions' =
    --   'HashOptions' { 'hashIterations'  = 3
    --               , 'hashMemory'      = 2 ^ 12 -- 4 MiB
    --               , 'hashParallelism' = 1
    --               , 'hashVariant'     = 'Argon2i'
    --               , 'hashVersion'     = 'Argon2Version13'
    --               , 'hashLength'      = 2 ^ 5 -- 32 bytes
    --               }
    -- @
    --
    -- For more information on how to select these parameters for your application, see section 6.4 of the [Argon2 specification](https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf).
    --
    defaultHashOptions :: HashOptions
    defaultHashOptions :: HashOptions
    defaultHashOptions = $WHashOptions :: Argon2_type
    -> Argon2_type
    -> Argon2_type
    -> Argon2Variant
    -> Argon2Version
    -> Argon2_type
    -> HashOptions
    HashOptions
        { hashIterations :: Argon2_type
    hashIterations  = 3
        , hashMemory :: Argon2_type
    hashMemory      = 2 Argon2_type -> Int -> Argon2_type
    forall a b. (Num a, Integral b) => a -> b -> a
    ^ (12 :: Int) -- 4 MiB
        , hashParallelism :: Argon2_type
    hashParallelism = 1
        , hashVariant :: Argon2Variant
    hashVariant     = Argon2Variant
    Argon2i
        , hashVersion :: Argon2Version
    hashVersion     = Argon2Version
    Argon2Version13
        , hashLength :: Argon2_type
    hashLength      = 32
        }

    -- | Encode a password with a given salt and 'HashOptions' and produce a binary stream
    -- of bytes (of size 'hashLength').
    hash :: HashOptions -- ^ Options pertaining to how expensive the hash is to calculate.
         -> BS.ByteString -- ^ The password to hash. Must be less than 4294967295 bytes.
         -> BS.ByteString -- ^ The salt to use when hashing. Must be less than 4294967295 bytes.
         -> Either Argon2Status BS.ByteString -- ^ The un-encoded password hash (or error code in case of failure).
    hash :: HashOptions
    -> ByteString -> ByteString -> Either Argon2Status ByteString
    hash options :: HashOptions
    options password :: ByteString
    password salt :: ByteString
    salt = IO (Either Argon2Status ByteString)
    -> Either Argon2Status ByteString
    forall a. IO a -> a
    unsafePerformIO (IO (Either Argon2Status ByteString)
     -> Either Argon2Status ByteString)
    -> IO (Either Argon2Status ByteString)
    -> Either Argon2Status ByteString
    forall a b. (a -> b) -> a -> b
    $ IO ByteString -> IO (Either Argon2Status ByteString)
    forall e a. Exception e => IO a -> IO (Either e a)
    try (IO ByteString -> IO (Either Argon2Status ByteString))
    -> IO ByteString -> IO (Either Argon2Status ByteString)
    forall a b. (a -> b) -> a -> b
    $ HashOptions -> ByteString -> ByteString -> IO ByteString
    hash' HashOptions
    options ByteString
    password ByteString
    salt

    -- | Encode a password with a given salt and 'HashOptions' and produce a textual
    -- encoding according to the [PHC string format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md) of the result.
    --
    -- Use 'verifyEncoded' to verify.
    hashEncoded :: HashOptions   -- ^ Options pertaining to how expensive the hash is to calculate.
                -> BS.ByteString -- ^ The password to hash. Must be less than 4294967295 bytes.
                -> BS.ByteString -- ^ The salt to use when hashing. Must be less than 4294967295 bytes.
                -> Either Argon2Status TS.ShortText  -- ^ The encoded password hash (or error code in case of failure).
    hashEncoded :: HashOptions
    -> ByteString -> ByteString -> Either Argon2Status ShortText
    hashEncoded options :: HashOptions
    options password :: ByteString
    password salt :: ByteString
    salt = IO (Either Argon2Status ShortText) -> Either Argon2Status ShortText
    forall a. IO a -> a
    unsafePerformIO (IO (Either Argon2Status ShortText)
     -> Either Argon2Status ShortText)
    -> IO (Either Argon2Status ShortText)
    -> Either Argon2Status ShortText
    forall a b. (a -> b) -> a -> b
    $ IO ShortText -> IO (Either Argon2Status ShortText)
    forall e a. Exception e => IO a -> IO (Either e a)
    try (IO ShortText -> IO (Either Argon2Status ShortText))
    -> IO ShortText -> IO (Either Argon2Status ShortText)
    forall a b. (a -> b) -> a -> b
    $ HashOptions -> ByteString -> ByteString -> IO ShortText
    hashEncoded' HashOptions
    options ByteString
    password ByteString
    salt

    -- | Verify that a given password could result in a given hash output.
    -- Automatically determines the correct 'HashOptions' based on the
    -- encoded hash (using the [PHC string format](https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md) as produced by 'hashEncoded').
    --
    -- Returns 'Argon2Ok' on successful verification. If decoding is
    -- successful but the password mismatches, 'Argon2VerifyMismatch' is
    -- returned; if decoding fails, the respective 'Argon2Status' code is
    -- returned.
    verifyEncoded :: TS.ShortText -> BS.ByteString -> Argon2Status
    verifyEncoded :: ShortText -> ByteString -> Argon2Status
    verifyEncoded encoded :: ShortText
    encoded password :: ByteString
    password
      -- c.f. https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md
      | "$argon2id$" ShortText -> ShortText -> Bool
    `TS.isPrefixOf` ShortText
    encoded = IO Argon2Status -> Argon2Status
    forall a. IO a -> a
    unsafePerformIO (IO Argon2Status -> Argon2Status)
    -> IO Argon2Status -> Argon2Status
    forall a b. (a -> b) -> a -> b
    $ Argon2_type -> IO Argon2Status
    go Argon2_type
    forall a. (Eq a, Num a) => a
    FFI.Argon2_id
      | "$argon2i$"  ShortText -> ShortText -> Bool
    `TS.isPrefixOf` ShortText
    encoded = IO Argon2Status -> Argon2Status
    forall a. IO a -> a
    unsafePerformIO (IO Argon2Status -> Argon2Status)
    -> IO Argon2Status -> Argon2Status
    forall a b. (a -> b) -> a -> b
    $ Argon2_type -> IO Argon2Status
    go Argon2_type
    forall a. (Eq a, Num a) => a
    FFI.Argon2_i
      | "$argon2d$"  ShortText -> ShortText -> Bool
    `TS.isPrefixOf` ShortText
    encoded = IO Argon2Status -> Argon2Status
    forall a. IO a -> a
    unsafePerformIO (IO Argon2Status -> Argon2Status)
    -> IO Argon2Status -> Argon2Status
    forall a b. (a -> b) -> a -> b
    $ Argon2_type -> IO Argon2Status
    go Argon2_type
    forall a. (Eq a, Num a) => a
    FFI.Argon2_d
      | Bool
    otherwise                            = Argon2Status
    Argon2DecodingFail
      where
        go :: Argon2_type -> IO Argon2Status
    go v :: Argon2_type
    v = ByteString -> (CString -> IO Argon2Status) -> IO Argon2Status
    forall a. ByteString -> (CString -> IO a) -> IO a
    BS.useAsCString ByteString
    password ((CString -> IO Argon2Status) -> IO Argon2Status)
    -> (CString -> IO Argon2Status) -> IO Argon2Status
    forall a b. (a -> b) -> a -> b
    $ \pwd :: CString
    pwd ->
                 ByteString -> (CString -> IO Argon2Status) -> IO Argon2Status
    forall a. ByteString -> (CString -> IO a) -> IO a
    BS.useAsCString (ShortText -> ByteString
    TS.toByteString ShortText
    encoded) ((CString -> IO Argon2Status) -> IO Argon2Status)
    -> (CString -> IO Argon2Status) -> IO Argon2Status
    forall a b. (a -> b) -> a -> b
    $ \enc :: CString
    enc ->
                   CInt -> Argon2Status
    toArgon2Status (CInt -> Argon2Status) -> IO CInt -> IO Argon2Status
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CString -> CString -> CSize -> Argon2_type -> IO CInt
    forall a. CString -> Ptr a -> CSize -> Argon2_type -> IO CInt
    FFI.argon2_verify CString
    enc CString
    pwd (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (ByteString -> Int
    BS.length ByteString
    password)) Argon2_type
    v

    -- | Returned status code for Argon2 functions.
    --
    -- Not all 'HashOptions' can necessarily be used to compute hashes. If
    -- you supply unsupported or invalid 'HashOptions' (or hashing
    -- otherwise fails) an 'Argon2Status' value will be returned to
    -- describe the failure.
    --
    -- Note that this enumeration contains some status codes which are not
    -- expected to be returned by the operation provided by the Haskell
    -- API.
    data Argon2Status
        = Argon2Ok                            -- ^ OK (operation succeeded)
        | Argon2OutputPtrNull                 -- ^ Output pointer is @NULL@
        | Argon2OutputTooShort                -- ^ Output is too short
        | Argon2OutputTooLong                 -- ^ Output is too long
        | Argon2PwdTooShort                   -- ^ Password is too short
        | Argon2PwdTooLong                    -- ^ Password is too long
        | Argon2SaltTooShort                  -- ^ Salt is too short
        | Argon2SaltTooLong                   -- ^ Salt is too long
        | Argon2AdTooShort                    -- ^ Associated data is too short
        | Argon2AdTooLong                     -- ^ Associated data is too long
        | Argon2SecretTooShort                -- ^ Secret is too short
        | Argon2SecretTooLong                 -- ^ Secret is too long
        | Argon2TimeTooSmall                  -- ^ Time cost is too small
        | Argon2TimeTooLarge                  -- ^ Time cost is too large
        | Argon2MemoryTooLittle               -- ^ Memory cost is too small
        | Argon2MemoryTooMuch                 -- ^ Memory cost is too large
        | Argon2LanesTooFew                   -- ^ Too few lanes
        | Argon2LanesTooMany                  -- ^ Too many lanes
        | Argon2PwdPtrMismatch                -- ^ Password pointer is @NULL@, but password length is not 0
        | Argon2SaltPtrMismatch               -- ^ Salt pointer is @NULL@, but salt length is not 0
        | Argon2SecretPtrMismatch             -- ^ Secret pointer is @NULL@, but secret length is not 0
        | Argon2AdPtrMismatch                 -- ^ Associated data pointer is @NULL@, but ad length is not 0
        | Argon2MemoryAllocationError         -- ^ Memory allocation error
        | Argon2FreeMemoryCbkNull             -- ^ The free memory callback is @NULL@
        | Argon2AllocateMemoryCbkNull         -- ^ The allocate memory callback is @NULL@
        | Argon2IncorrectParameter            -- ^ @Argon2_Context@ context is @NULL@
        | Argon2IncorrectType                 -- ^ There is no such version of Argon2
        | Argon2OutPtrMismatch                -- ^ Output pointer mismatch
        | Argon2ThreadsTooFew                 -- ^ Not enough threads
        | Argon2ThreadsTooMany                -- ^ Too many threads
        | Argon2MissingArgs                   -- ^ Missing arguments
        | Argon2EncodingFail                  -- ^ Encoding failed
        | Argon2DecodingFail                  -- ^ Decoding failed
        | Argon2ThreadFail                    -- ^ Threading failure
        | Argon2DecodingLengthFail            -- ^ Some of encoded parameters are too long or too short
        | Argon2VerifyMismatch                -- ^ The password does not match the supplied hash

        | Argon2InternalError                 -- ^ Internal error or unrecognized status code
        deriving (Typeable,Argon2Status -> Argon2Status -> Bool
    (Argon2Status -> Argon2Status -> Bool)
    -> (Argon2Status -> Argon2Status -> Bool) -> Eq Argon2Status
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    /= :: Argon2Status -> Argon2Status -> Bool
    $c/= :: Argon2Status -> Argon2Status -> Bool
    == :: Argon2Status -> Argon2Status -> Bool
    $c== :: Argon2Status -> Argon2Status -> Bool
    Eq,Eq Argon2Status
    Eq Argon2Status =>
    (Argon2Status -> Argon2Status -> Ordering)
    -> (Argon2Status -> Argon2Status -> Bool)
    -> (Argon2Status -> Argon2Status -> Bool)
    -> (Argon2Status -> Argon2Status -> Bool)
    -> (Argon2Status -> Argon2Status -> Bool)
    -> (Argon2Status -> Argon2Status -> Argon2Status)
    -> (Argon2Status -> Argon2Status -> Argon2Status)
    -> Ord Argon2Status
    Argon2Status -> Argon2Status -> Bool
    Argon2Status -> Argon2Status -> Ordering
    Argon2Status -> Argon2Status -> Argon2Status
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    min :: Argon2Status -> Argon2Status -> Argon2Status
    $cmin :: Argon2Status -> Argon2Status -> Argon2Status
    max :: Argon2Status -> Argon2Status -> Argon2Status
    $cmax :: Argon2Status -> Argon2Status -> Argon2Status
    >= :: Argon2Status -> Argon2Status -> Bool
    $c>= :: Argon2Status -> Argon2Status -> Bool
    > :: Argon2Status -> Argon2Status -> Bool
    $c> :: Argon2Status -> Argon2Status -> Bool
    <= :: Argon2Status -> Argon2Status -> Bool
    $c<= :: Argon2Status -> Argon2Status -> Bool
    < :: Argon2Status -> Argon2Status -> Bool
    $c< :: Argon2Status -> Argon2Status -> Bool
    compare :: Argon2Status -> Argon2Status -> Ordering
    $ccompare :: Argon2Status -> Argon2Status -> Ordering
    $cp1Ord :: Eq Argon2Status
    Ord,ReadPrec [Argon2Status]
    ReadPrec Argon2Status
    Int -> ReadS Argon2Status
    ReadS [Argon2Status]
    (Int -> ReadS Argon2Status)
    -> ReadS [Argon2Status]
    -> ReadPrec Argon2Status
    -> ReadPrec [Argon2Status]
    -> Read Argon2Status
    forall a.
    (Int -> ReadS a)
    -> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
    readListPrec :: ReadPrec [Argon2Status]
    $creadListPrec :: ReadPrec [Argon2Status]
    readPrec :: ReadPrec Argon2Status
    $creadPrec :: ReadPrec Argon2Status
    readList :: ReadS [Argon2Status]
    $creadList :: ReadS [Argon2Status]
    readsPrec :: Int -> ReadS Argon2Status
    $creadsPrec :: Int -> ReadS Argon2Status
    Read,Int -> Argon2Status -> ShowS
    [Argon2Status] -> ShowS
    Argon2Status -> String
    (Int -> Argon2Status -> ShowS)
    -> (Argon2Status -> String)
    -> ([Argon2Status] -> ShowS)
    -> Show Argon2Status
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    showList :: [Argon2Status] -> ShowS
    $cshowList :: [Argon2Status] -> ShowS
    show :: Argon2Status -> String
    $cshow :: Argon2Status -> String
    showsPrec :: Int -> Argon2Status -> ShowS
    $cshowsPrec :: Int -> Argon2Status -> ShowS
    Show,Int -> Argon2Status
    Argon2Status -> Int
    Argon2Status -> [Argon2Status]
    Argon2Status -> Argon2Status
    Argon2Status -> Argon2Status -> [Argon2Status]
    Argon2Status -> Argon2Status -> Argon2Status -> [Argon2Status]
    (Argon2Status -> Argon2Status)
    -> (Argon2Status -> Argon2Status)
    -> (Int -> Argon2Status)
    -> (Argon2Status -> Int)
    -> (Argon2Status -> [Argon2Status])
    -> (Argon2Status -> Argon2Status -> [Argon2Status])
    -> (Argon2Status -> Argon2Status -> [Argon2Status])
    -> (Argon2Status -> Argon2Status -> Argon2Status -> [Argon2Status])
    -> Enum Argon2Status
    forall a.
    (a -> a)
    -> (a -> a)
    -> (Int -> a)
    -> (a -> Int)
    -> (a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> [a])
    -> (a -> a -> a -> [a])
    -> Enum a
    enumFromThenTo :: Argon2Status -> Argon2Status -> Argon2Status -> [Argon2Status]
    $cenumFromThenTo :: Argon2Status -> Argon2Status -> Argon2Status -> [Argon2Status]
    enumFromTo :: Argon2Status -> Argon2Status -> [Argon2Status]
    $cenumFromTo :: Argon2Status -> Argon2Status -> [Argon2Status]
    enumFromThen :: Argon2Status -> Argon2Status -> [Argon2Status]
    $cenumFromThen :: Argon2Status -> Argon2Status -> [Argon2Status]
    enumFrom :: Argon2Status -> [Argon2Status]
    $cenumFrom :: Argon2Status -> [Argon2Status]
    fromEnum :: Argon2Status -> Int
    $cfromEnum :: Argon2Status -> Int
    toEnum :: Int -> Argon2Status
    $ctoEnum :: Int -> Argon2Status
    pred :: Argon2Status -> Argon2Status
    $cpred :: Argon2Status -> Argon2Status
    succ :: Argon2Status -> Argon2Status
    $csucc :: Argon2Status -> Argon2Status
    Enum,Argon2Status
    Argon2Status -> Argon2Status -> Bounded Argon2Status
    forall a. a -> a -> Bounded a
    maxBound :: Argon2Status
    $cmaxBound :: Argon2Status
    minBound :: Argon2Status
    $cminBound :: Argon2Status
    Bounded)

    instance NFData Argon2Status where rnf :: Argon2Status -> ()
    rnf !Argon2Status
    _ = ()

    instance Exception Argon2Status

    toArgon2Status :: CInt -> Argon2Status
    toArgon2Status :: CInt -> Argon2Status
    toArgon2Status = \case
        FFI.ARGON2_OK                         -> Argon2Status
    Argon2Ok
        FFI.ARGON2_OUTPUT_PTR_NULL            -> Argon2Status
    Argon2OutputPtrNull
        FFI.ARGON2_OUTPUT_TOO_SHORT           -> Argon2Status
    Argon2OutputTooShort
        FFI.ARGON2_OUTPUT_TOO_LONG            -> Argon2Status
    Argon2OutputTooLong
        FFI.ARGON2_PWD_TOO_SHORT              -> Argon2Status
    Argon2PwdTooShort
        FFI.ARGON2_PWD_TOO_LONG               -> Argon2Status
    Argon2PwdTooLong
        FFI.ARGON2_SALT_TOO_SHORT             -> Argon2Status
    Argon2SaltTooShort
        FFI.ARGON2_SALT_TOO_LONG              -> Argon2Status
    Argon2SaltTooLong
        FFI.ARGON2_AD_TOO_SHORT               -> Argon2Status
    Argon2AdTooShort
        FFI.ARGON2_AD_TOO_LONG                -> Argon2Status
    Argon2AdTooLong
        FFI.ARGON2_SECRET_TOO_SHORT           -> Argon2Status
    Argon2SecretTooShort
        FFI.ARGON2_SECRET_TOO_LONG            -> Argon2Status
    Argon2SecretTooLong
        FFI.ARGON2_TIME_TOO_SMALL             -> Argon2Status
    Argon2TimeTooSmall
        FFI.ARGON2_TIME_TOO_LARGE             -> Argon2Status
    Argon2TimeTooLarge
        FFI.ARGON2_MEMORY_TOO_LITTLE          -> Argon2Status
    Argon2MemoryTooLittle
        FFI.ARGON2_MEMORY_TOO_MUCH            -> Argon2Status
    Argon2MemoryTooMuch
        FFI.ARGON2_LANES_TOO_FEW              -> Argon2Status
    Argon2LanesTooFew
        FFI.ARGON2_LANES_TOO_MANY             -> Argon2Status
    Argon2LanesTooMany
        FFI.ARGON2_PWD_PTR_MISMATCH           -> Argon2Status
    Argon2PwdPtrMismatch
        FFI.ARGON2_SALT_PTR_MISMATCH          -> Argon2Status
    Argon2SaltPtrMismatch
        FFI.ARGON2_SECRET_PTR_MISMATCH        -> Argon2Status
    Argon2SecretPtrMismatch
        FFI.ARGON2_AD_PTR_MISMATCH            -> Argon2Status
    Argon2AdPtrMismatch
        FFI.ARGON2_MEMORY_ALLOCATION_ERROR    -> Argon2Status
    Argon2MemoryAllocationError
        FFI.ARGON2_FREE_MEMORY_CBK_NULL       -> Argon2Status
    Argon2FreeMemoryCbkNull
        FFI.ARGON2_ALLOCATE_MEMORY_CBK_NULL   -> Argon2Status
    Argon2AllocateMemoryCbkNull
        FFI.ARGON2_INCORRECT_PARAMETER        -> Argon2Status
    Argon2IncorrectParameter
        FFI.ARGON2_INCORRECT_TYPE             -> Argon2Status
    Argon2IncorrectType
        FFI.ARGON2_OUT_PTR_MISMATCH           -> Argon2Status
    Argon2OutPtrMismatch
        FFI.ARGON2_THREADS_TOO_FEW            -> Argon2Status
    Argon2ThreadsTooFew
        FFI.ARGON2_THREADS_TOO_MANY           -> Argon2Status
    Argon2ThreadsTooMany
        FFI.ARGON2_MISSING_ARGS               -> Argon2Status
    Argon2MissingArgs
        FFI.ARGON2_ENCODING_FAIL              -> Argon2Status
    Argon2EncodingFail
        FFI.ARGON2_DECODING_FAIL              -> Argon2Status
    Argon2DecodingFail
        FFI.ARGON2_THREAD_FAIL                -> Argon2Status
    Argon2ThreadFail
        FFI.ARGON2_DECODING_LENGTH_FAIL       -> Argon2Status
    Argon2DecodingLengthFail
        FFI.ARGON2_VERIFY_MISMATCH            -> Argon2Status
    Argon2VerifyMismatch
        _                                     -> Argon2Status
    Argon2InternalError -- should never happen

    hashEncoded' :: HashOptions
                 -> BS.ByteString
                 -> BS.ByteString
                 -> IO TS.ShortText
    hashEncoded' :: HashOptions -> ByteString -> ByteString -> IO ShortText
    hashEncoded' HashOptions{..} password :: ByteString
    password salt :: ByteString
    salt =
        Int -> (CString -> IO ShortText) -> IO ShortText
    forall a b. Int -> (Ptr a -> IO b) -> IO b
    allocaBytes (CSize -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral CSize
    outLen) ((CString -> IO ShortText) -> IO ShortText)
    -> (CString -> IO ShortText) -> IO ShortText
    forall a b. (a -> b) -> a -> b
    $ \out :: CString
    out -> do
            CInt
    res <- ByteString -> (CString -> IO CInt) -> IO CInt
    forall a. ByteString -> (CString -> IO a) -> IO a
    BS.useAsCString ByteString
    password ((CString -> IO CInt) -> IO CInt)
    -> (CString -> IO CInt) -> IO CInt
    forall a b. (a -> b) -> a -> b
    $ \password' :: CString
    password' ->
                   ByteString -> (CString -> IO CInt) -> IO CInt
    forall a. ByteString -> (CString -> IO a) -> IO a
    BS.useAsCString ByteString
    salt ((CString -> IO CInt) -> IO CInt)
    -> (CString -> IO CInt) -> IO CInt
    forall a b. (a -> b) -> a -> b
    $ \salt' :: CString
    salt' ->
                   Argon2_type
    -> Argon2_type
    -> Argon2_type
    -> CString
    -> CSize
    -> CString
    -> CSize
    -> Ptr Any
    -> CSize
    -> CString
    -> CSize
    -> Argon2_type
    -> Argon2_type
    -> IO CInt
    forall a b c.
    Argon2_type
    -> Argon2_type
    -> Argon2_type
    -> Ptr a
    -> CSize
    -> Ptr b
    -> CSize
    -> Ptr c
    -> CSize
    -> CString
    -> CSize
    -> Argon2_type
    -> Argon2_type
    -> IO CInt
    FFI.argon2_hash
                       Argon2_type
    hashIterations
                       Argon2_type
    hashMemory
                       Argon2_type
    hashParallelism
                       CString
    password'
                       CSize
    passwordLen
                       CString
    salt'
                       (Argon2_type -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Argon2_type
    saltLen)
                       Ptr Any
    forall a. Ptr a
    nullPtr
                       (Argon2_type -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Argon2_type
    hashLength)
                       CString
    out
                       CSize
    outLen
                       (Argon2Variant -> Argon2_type
    toArgon2Type Argon2Variant
    hashVariant)
                       (Argon2Version -> Argon2_type
    toArgon2Ver Argon2Version
    hashVersion)

            CInt -> IO ()
    handleSuccessCode CInt
    res
            Maybe ShortText
    res' <- ByteString -> Maybe ShortText
    TS.fromByteString (ByteString -> Maybe ShortText)
    -> IO ByteString -> IO (Maybe ShortText)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> CString -> IO ByteString
    BS.packCString CString
    out
            case Maybe ShortText
    res' of
              Nothing -> Argon2Status -> IO ShortText
    forall e a. Exception e => e -> IO a
    throwIO Argon2Status
    Argon2InternalError
              Just t :: ShortText
    t  -> ShortText -> IO ShortText
    forall a. a -> IO a
    evaluate ShortText
    t

      where
        !outLen :: CSize
    outLen = Argon2_type
    -> Argon2_type
    -> Argon2_type
    -> Argon2_type
    -> Argon2_type
    -> Argon2_type
    -> CSize
    FFI.argon2_encodedlen
                        Argon2_type
    hashIterations
                        Argon2_type
    hashMemory
                        Argon2_type
    hashParallelism
                        Argon2_type
    saltLen
                        Argon2_type
    hashLength
                        (Argon2Variant -> Argon2_type
    toArgon2Type Argon2Variant
    hashVariant)

        saltLen :: Argon2_type
    saltLen     = Int -> Argon2_type
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (ByteString -> Int
    BS.length ByteString
    salt)
        passwordLen :: CSize
    passwordLen = Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (ByteString -> Int
    BS.length ByteString
    password)

    hash' :: HashOptions
          -> BS.ByteString
          -> BS.ByteString
          -> IO BS.ByteString
    hash' :: HashOptions -> ByteString -> ByteString -> IO ByteString
    hash' HashOptions{..} password :: ByteString
    password salt :: ByteString
    salt =
        Int -> (CString -> IO ByteString) -> IO ByteString
    forall a b. Int -> (Ptr a -> IO b) -> IO b
    allocaBytes (Argon2_type -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Argon2_type
    hashLength) ((CString -> IO ByteString) -> IO ByteString)
    -> (CString -> IO ByteString) -> IO ByteString
    forall a b. (a -> b) -> a -> b
    $ \out :: CString
    out -> do
            CInt
    res <- ByteString -> (CString -> IO CInt) -> IO CInt
    forall a. ByteString -> (CString -> IO a) -> IO a
    BS.useAsCString ByteString
    password ((CString -> IO CInt) -> IO CInt)
    -> (CString -> IO CInt) -> IO CInt
    forall a b. (a -> b) -> a -> b
    $ \password' :: CString
    password' ->
                   ByteString -> (CString -> IO CInt) -> IO CInt
    forall a. ByteString -> (CString -> IO a) -> IO a
    BS.useAsCString ByteString
    salt ((CString -> IO CInt) -> IO CInt)
    -> (CString -> IO CInt) -> IO CInt
    forall a b. (a -> b) -> a -> b
    $ \salt' :: CString
    salt' ->
                   Argon2_type
    -> Argon2_type
    -> Argon2_type
    -> CString
    -> CSize
    -> CString
    -> CSize
    -> CString
    -> CSize
    -> CString
    -> CSize
    -> Argon2_type
    -> Argon2_type
    -> IO CInt
    forall a b c.
    Argon2_type
    -> Argon2_type
    -> Argon2_type
    -> Ptr a
    -> CSize
    -> Ptr b
    -> CSize
    -> Ptr c
    -> CSize
    -> CString
    -> CSize
    -> Argon2_type
    -> Argon2_type
    -> IO CInt
    FFI.argon2_hash
                       Argon2_type
    hashIterations
                       Argon2_type
    hashMemory
                       Argon2_type
    hashParallelism
                       CString
    password'
                       CSize
    passwordLen
                       CString
    salt'
                       CSize
    saltLen
                       CString
    out
                       (Argon2_type -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Argon2_type
    hashLength)
                       CString
    forall a. Ptr a
    nullPtr
                       0
                       (Argon2Variant -> Argon2_type
    toArgon2Type Argon2Variant
    hashVariant)
                       (Argon2Version -> Argon2_type
    toArgon2Ver Argon2Version
    hashVersion)

            CInt -> IO ()
    handleSuccessCode CInt
    res
            ByteString -> IO ByteString
    forall a. a -> IO a
    evaluate (ByteString -> IO ByteString) -> IO ByteString -> IO ByteString
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< CStringLen -> IO ByteString
    BS.packCStringLen (CString
    out, Argon2_type -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Argon2_type
    hashLength)
      where
        saltLen :: CSize
    saltLen     = Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (ByteString -> Int
    BS.length ByteString
    salt)
        passwordLen :: CSize
    passwordLen = Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (ByteString -> Int
    BS.length ByteString
    password)

    handleSuccessCode :: CInt -> IO ()
    handleSuccessCode :: CInt -> IO ()
    handleSuccessCode res :: CInt
    res = case CInt -> Argon2Status
    toArgon2Status CInt
    res of
                              Argon2Ok -> () -> IO ()
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
                              nok :: Argon2Status
    nok      -> Argon2Status -> IO ()
    forall e a. Exception e => e -> IO a
    throwIO Argon2Status
    nok