    module Network.TLS.Extra.Cipher (
        -- * Cipher suite
        ciphersuite_default,
        ciphersuite_default_det,
        ciphersuite_all,
        ciphersuite_all_det,
        ciphersuite_strong,
        ciphersuite_strong_det,
        ciphersuite_dhe_rsa,

        -- * Individual ciphers

        -- ** RFC 5288
        cipher_DHE_RSA_WITH_AES_128_GCM_SHA256,
        cipher_DHE_RSA_WITH_AES_256_GCM_SHA384,

        -- ** RFC 8446
        cipher13_AES_128_GCM_SHA256,
        cipher13_AES_256_GCM_SHA384,
        cipher13_CHACHA20_POLY1305_SHA256,
        cipher13_AES_128_CCM_SHA256,
        cipher13_AES_128_CCM_8_SHA256,

        -- ** RFC 5289
        cipher_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
        cipher_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
        cipher_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
        cipher_ECDHE_RSA_WITH_AES_256_GCM_SHA384,

        -- ** RFC 7251
        cipher_ECDHE_ECDSA_WITH_AES_128_CCM,
        cipher_ECDHE_ECDSA_WITH_AES_256_CCM,
        cipher_ECDHE_ECDSA_WITH_AES_128_CCM_8,
        cipher_ECDHE_ECDSA_WITH_AES_256_CCM_8,

        -- ** RFC 7905
        cipher_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
        cipher_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
        cipher_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,

        -- * Deprecated names

        -- ** RFC 5288
        cipher_DHE_RSA_AES128GCM_SHA256,
        cipher_DHE_RSA_AES256GCM_SHA384,

        -- ** RFC 8446
        cipher_TLS13_AES128GCM_SHA256,
        cipher_TLS13_AES256GCM_SHA384,
        cipher_TLS13_CHACHA20POLY1305_SHA256,
        cipher_TLS13_AES128CCM_SHA256,
        cipher_TLS13_AES128CCM8_SHA256,

        -- ** RFC 5289
        cipher_ECDHE_ECDSA_AES128GCM_SHA256,
        cipher_ECDHE_ECDSA_AES256GCM_SHA384,
        cipher_ECDHE_RSA_AES128GCM_SHA256,
        cipher_ECDHE_RSA_AES256GCM_SHA384,

        -- ** RFC 7251
        cipher_ECDHE_ECDSA_AES128CCM_SHA256,
        cipher_ECDHE_ECDSA_AES256CCM_SHA256,
        cipher_ECDHE_ECDSA_AES128CCM8_SHA256,
        cipher_ECDHE_ECDSA_AES256CCM8_SHA256,

        -- ** RFC 7905
        cipher_ECDHE_RSA_CHACHA20POLY1305_SHA256,
        cipher_ECDHE_ECDSA_CHACHA20POLY1305_SHA256,
        cipher_DHE_RSA_CHACHA20POLY1305_SHA256,
    ) where

    import qualified Data.ByteString as B

    import Data.Tuple (swap)
    import Network.TLS.Cipher
    import Network.TLS.Types

    import Crypto.Cipher.AES
    import qualified Crypto.Cipher.ChaChaPoly1305 as ChaChaPoly1305
    import Crypto.Cipher.Types hiding (Cipher, cipherName)
    import Crypto.Error
    import qualified Crypto.MAC.Poly1305 as Poly1305
    import Crypto.System.CPU

    ----------------------------------------------------------------

    -- | All AES and ChaCha20-Poly1305 ciphers supported ordered from strong to
    -- weak.  This choice of ciphersuites should satisfy most normal needs.  For
    -- otherwise strong ciphers we make little distinction between AES128 and
    -- AES256, and list each but the weakest of the AES128 ciphers ahead of the
    -- corresponding AES256 ciphers.
    --
    -- AEAD ciphers with equivalent security properties are ordered based on CPU
    -- hardware-acceleration support.  If this dynamic runtime behavior is not
    -- desired, use 'ciphersuite_default_det' instead.
    ciphersuite_default :: [Cipher]
    ciphersuite_default :: [Cipher]
    ciphersuite_default = [Cipher]
    ciphersuite_strong

    -- | Same as 'ciphersuite_default', but using deterministic preference not
    -- influenced by the CPU.
    ciphersuite_default_det :: [Cipher]
    ciphersuite_default_det :: [Cipher]
    ciphersuite_default_det = [Cipher]
    ciphersuite_strong_det

    ----------------------------------------------------------------

    -- | The default ciphersuites + some not recommended last resort ciphers.
    --
    -- AEAD ciphers with equivalent security properties are ordered based on CPU
    -- hardware-acceleration support.  If this dynamic runtime behavior is not
    -- desired, use 'ciphersuite_all_det' instead.
    ciphersuite_all :: [Cipher]
    ciphersuite_all :: [Cipher]
    ciphersuite_all = [Cipher]
    ciphersuite_default [Cipher] -> [Cipher] -> [Cipher]
    forall a. [a] -> [a] -> [a]
    ++ [Cipher]
    complement_all

    -- | Same as 'ciphersuite_all', but using deterministic preference not
    -- influenced by the CPU.
    ciphersuite_all_det :: [Cipher]
    ciphersuite_all_det :: [Cipher]
    ciphersuite_all_det = [Cipher]
    ciphersuite_default_det [Cipher] -> [Cipher] -> [Cipher]
    forall a. [a] -> [a] -> [a]
    ++ [Cipher]
    complement_all

    complement_all :: [Cipher]
    complement_all :: [Cipher]
    complement_all =
        [ Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_CCM_8
        , Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_CCM_8
        , Cipher
    cipher13_AES_128_CCM_8_SHA256
        ]

    -- | The strongest ciphers supported.  For ciphers with PFS, AEAD and SHA2, we
    -- list each AES128 variant after the corresponding AES256 and ChaCha20-Poly1305
    -- variants.  For weaker constructs, we use just the AES256 form.
    --
    -- AEAD ciphers with equivalent security properties are ordered based on CPU
    -- hardware-acceleration support.  If this dynamic runtime behavior is not
    -- desired, use 'ciphersuite_strong_det' instead.
    ciphersuite_strong :: [Cipher]
    ciphersuite_strong :: [Cipher]
    ciphersuite_strong = [CipherSet] -> [Cipher]
    sortOptimized [CipherSet]
    sets_strong

    -- | Same as 'ciphersuite_strong', but using deterministic preference not
    -- influenced by the CPU.
    ciphersuite_strong_det :: [Cipher]
    ciphersuite_strong_det :: [Cipher]
    ciphersuite_strong_det = [CipherSet] -> [Cipher]
    sortDeterministic [CipherSet]
    sets_strong

    sets_strong :: [CipherSet]
    sets_strong :: [CipherSet]
    sets_strong =
        [ -- If we have PFS + AEAD + SHA2, then allow AES128, else just 256
          [Cipher] -> [Cipher] -> [Cipher] -> CipherSet
    SetAead
            [Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384]
            [Cipher
    cipher_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256]
            [Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_CCM]
        , [Cipher] -> [Cipher] -> [Cipher] -> CipherSet
    SetAead
            [Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256]
            []
            [Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_CCM]
        , [Cipher] -> [Cipher] -> [Cipher] -> CipherSet
    SetAead
            [Cipher
    cipher_ECDHE_RSA_WITH_AES_256_GCM_SHA384]
            [Cipher
    cipher_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256]
            []
        , [Cipher] -> [Cipher] -> [Cipher] -> CipherSet
    SetAead
            [Cipher
    cipher_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
            []
            []
        , -- TLS13 (listed at the end but version is negotiated first)
          [Cipher] -> [Cipher] -> [Cipher] -> CipherSet
    SetAead
            [Cipher
    cipher13_AES_256_GCM_SHA384]
            [Cipher
    cipher13_CHACHA20_POLY1305_SHA256]
            []
        , [Cipher] -> [Cipher] -> [Cipher] -> CipherSet
    SetAead
            [Cipher
    cipher13_AES_128_GCM_SHA256]
            []
            [Cipher
    cipher13_AES_128_CCM_SHA256]
        ]

    -- | DHE-RSA cipher suite.  This only includes ciphers bound specifically to
    -- DHE-RSA so TLS 1.3 ciphers must be added separately.
    --
    -- @since 2.1.5
    ciphersuite_dhe_rsa :: [Cipher]
    ciphersuite_dhe_rsa :: [Cipher]
    ciphersuite_dhe_rsa =
        [ Cipher
    cipher_DHE_RSA_WITH_AES_256_GCM_SHA384
        , Cipher
    cipher_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
        , Cipher
    cipher_DHE_RSA_WITH_AES_128_GCM_SHA256
        ]

    ----------------------------------------------------------------
    ----------------------------------------------------------------

    -- A list of cipher suite is found from:
    -- https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4

    ----------------------------------------------------------------
    -- RFC 5288

    -- TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
    cipher_DHE_RSA_WITH_AES_128_GCM_SHA256 :: Cipher
    cipher_DHE_RSA_WITH_AES_128_GCM_SHA256 :: Cipher
    cipher_DHE_RSA_WITH_AES_128_GCM_SHA256 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0x009E
            , cipherName :: String
    cipherName = String
    "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes128gcm
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA256
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_DHE_RSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12 -- RFC 5288 Sec 4
            }

    {-# DEPRECATED
        cipher_DHE_RSA_AES128GCM_SHA256
        "Use cipher_DHE_RSA_WITH_AES_128_GCM_SHA256 instead"
        #-}
    cipher_DHE_RSA_AES128GCM_SHA256 :: Cipher
    cipher_DHE_RSA_AES128GCM_SHA256 :: Cipher
    cipher_DHE_RSA_AES128GCM_SHA256 = Cipher
    cipher_DHE_RSA_WITH_AES_128_GCM_SHA256

    -- TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
    cipher_DHE_RSA_WITH_AES_256_GCM_SHA384 :: Cipher
    cipher_DHE_RSA_WITH_AES_256_GCM_SHA384 :: Cipher
    cipher_DHE_RSA_WITH_AES_256_GCM_SHA384 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0x009F
            , cipherName :: String
    cipherName = String
    "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes256gcm
            , cipherHash :: Hash
    cipherHash = Hash
    SHA384
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA384
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_DHE_RSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12
            }

    {-# DEPRECATED
        cipher_DHE_RSA_AES256GCM_SHA384
        "Use cipher_DHE_RSA_WITH_AES_256_GCM_SHA384 instead"
        #-}
    cipher_DHE_RSA_AES256GCM_SHA384 :: Cipher
    cipher_DHE_RSA_AES256GCM_SHA384 :: Cipher
    cipher_DHE_RSA_AES256GCM_SHA384 = Cipher
    cipher_DHE_RSA_WITH_AES_256_GCM_SHA384

    ----------------------------------------------------------------
    -- RFC 8446

    -- TLS_AES_128_GCM_SHA256
    cipher13_AES_128_GCM_SHA256 :: Cipher
    cipher13_AES_128_GCM_SHA256 :: Cipher
    cipher13_AES_128_GCM_SHA256 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0x1301
            , cipherName :: String
    cipherName = String
    "TLS_AES_128_GCM_SHA256"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes128gcm_13
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Maybe Hash
    forall a. Maybe a
    Nothing
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_TLS13
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS13
            }

    cipher_TLS13_AES128GCM_SHA256 :: Cipher
    cipher_TLS13_AES128GCM_SHA256 :: Cipher
    cipher_TLS13_AES128GCM_SHA256 = Cipher
    cipher13_AES_128_GCM_SHA256
    {-# DEPRECATED
        cipher_TLS13_AES128GCM_SHA256
        "Use cipher13_AES_128_GCM_SHA256 instead"
        #-}

    -- TLS_AES_256_GCM_SHA384
    cipher13_AES_256_GCM_SHA384 :: Cipher
    cipher13_AES_256_GCM_SHA384 :: Cipher
    cipher13_AES_256_GCM_SHA384 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0x1302
            , cipherName :: String
    cipherName = String
    "TLS_AES_256_GCM_SHA384"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes256gcm_13
            , cipherHash :: Hash
    cipherHash = Hash
    SHA384
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Maybe Hash
    forall a. Maybe a
    Nothing
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_TLS13
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS13
            }

    cipher_TLS13_AES256GCM_SHA384 :: Cipher
    cipher_TLS13_AES256GCM_SHA384 :: Cipher
    cipher_TLS13_AES256GCM_SHA384 = Cipher
    cipher13_AES_256_GCM_SHA384
    {-# DEPRECATED
        cipher_TLS13_AES256GCM_SHA384
        "Use cipher13_AES_256_GCM_SHA384 instead"
        #-}

    -- TLS_CHACHA20_POLY1305_SHA256
    cipher13_CHACHA20_POLY1305_SHA256 :: Cipher
    cipher13_CHACHA20_POLY1305_SHA256 :: Cipher
    cipher13_CHACHA20_POLY1305_SHA256 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0x1303
            , cipherName :: String
    cipherName = String
    "TLS_CHACHA20_POLY1305_SHA256"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_chacha20poly1305
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Maybe Hash
    forall a. Maybe a
    Nothing
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_TLS13
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS13
            }

    cipher_TLS13_CHACHA20POLY1305_SHA256 :: Cipher
    cipher_TLS13_CHACHA20POLY1305_SHA256 :: Cipher
    cipher_TLS13_CHACHA20POLY1305_SHA256 = Cipher
    cipher13_CHACHA20_POLY1305_SHA256
    {-# DEPRECATED
        cipher_TLS13_CHACHA20POLY1305_SHA256
        "Use cipher13_CHACHA20_POLY1305_SHA256 instead"
        #-}

    -- TLS_AES_128_CCM_SHA256
    cipher13_AES_128_CCM_SHA256 :: Cipher
    cipher13_AES_128_CCM_SHA256 :: Cipher
    cipher13_AES_128_CCM_SHA256 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0x1304
            , cipherName :: String
    cipherName = String
    "TLS_AES_128_CCM_SHA256"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes128ccm_13
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Maybe Hash
    forall a. Maybe a
    Nothing
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_TLS13
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS13
            }

    cipher_TLS13_AES128CCM_SHA256 :: Cipher
    cipher_TLS13_AES128CCM_SHA256 :: Cipher
    cipher_TLS13_AES128CCM_SHA256 = Cipher
    cipher13_AES_128_CCM_SHA256
    {-# DEPRECATED
        cipher_TLS13_AES128CCM_SHA256
        "Use cipher13_AES_128_CCM_SHA256 instead"
        #-}

    -- TLS_AES_128_CCM_8_SHA256
    cipher13_AES_128_CCM_8_SHA256 :: Cipher
    cipher13_AES_128_CCM_8_SHA256 :: Cipher
    cipher13_AES_128_CCM_8_SHA256 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0x1305
            , cipherName :: String
    cipherName = String
    "TLS_AES_128_CCM_8_SHA256"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes128ccm8_13
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Maybe Hash
    forall a. Maybe a
    Nothing
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_TLS13
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS13
            }

    cipher_TLS13_AES128CCM8_SHA256 :: Cipher
    cipher_TLS13_AES128CCM8_SHA256 :: Cipher
    cipher_TLS13_AES128CCM8_SHA256 = Cipher
    cipher13_AES_128_CCM_8_SHA256
    {-# DEPRECATED
        cipher_TLS13_AES128CCM8_SHA256
        "Use cipher13_AES_128_CCM_8_SHA256 instead"
        #-}

    ----------------------------------------------------------------
    -- GCM: RFC 5289

    -- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    cipher_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xC02B
            , cipherName :: String
    cipherName = String
    "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes128gcm
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA256
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_ECDHE_ECDSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12 -- RFC 5289
            }

    cipher_ECDHE_ECDSA_AES128GCM_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_AES128GCM_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_AES128GCM_SHA256 = Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    {-# DEPRECATED
        cipher_ECDHE_ECDSA_AES128GCM_SHA256
        "Use cipher_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 instead"
        #-}

    -- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    cipher_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xC02C
            , cipherName :: String
    cipherName = String
    "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes256gcm
            , cipherHash :: Hash
    cipherHash = Hash
    SHA384
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA384
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_ECDHE_ECDSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12 -- RFC 5289
            }

    cipher_ECDHE_ECDSA_AES256GCM_SHA384 :: Cipher
    cipher_ECDHE_ECDSA_AES256GCM_SHA384 :: Cipher
    cipher_ECDHE_ECDSA_AES256GCM_SHA384 = Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    {-# DEPRECATED
        cipher_ECDHE_ECDSA_AES256GCM_SHA384
        "Use cipher_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 instead"
        #-}

    -- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    cipher_ECDHE_RSA_WITH_AES_128_GCM_SHA256 :: Cipher
    cipher_ECDHE_RSA_WITH_AES_128_GCM_SHA256 :: Cipher
    cipher_ECDHE_RSA_WITH_AES_128_GCM_SHA256 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xC02F
            , cipherName :: String
    cipherName = String
    "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes128gcm
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA256
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_ECDHE_RSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12 -- RFC 5288 Sec 4
            }

    cipher_ECDHE_RSA_AES128GCM_SHA256 :: Cipher
    cipher_ECDHE_RSA_AES128GCM_SHA256 :: Cipher
    cipher_ECDHE_RSA_AES128GCM_SHA256 = Cipher
    cipher_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    {-# DEPRECATED
        cipher_ECDHE_RSA_AES128GCM_SHA256
        "Use cipher_ECDHE_RSA_WITH_AES_128_GCM_SHA256 instead"
        #-}

    -- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    cipher_ECDHE_RSA_WITH_AES_256_GCM_SHA384 :: Cipher
    cipher_ECDHE_RSA_WITH_AES_256_GCM_SHA384 :: Cipher
    cipher_ECDHE_RSA_WITH_AES_256_GCM_SHA384 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xC030
            , cipherName :: String
    cipherName = String
    "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes256gcm
            , cipherHash :: Hash
    cipherHash = Hash
    SHA384
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA384
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_ECDHE_RSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12 -- RFC 5289
            }

    cipher_ECDHE_RSA_AES256GCM_SHA384 :: Cipher
    cipher_ECDHE_RSA_AES256GCM_SHA384 :: Cipher
    cipher_ECDHE_RSA_AES256GCM_SHA384 = Cipher
    cipher_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    {-# DEPRECATED
        cipher_ECDHE_RSA_AES256GCM_SHA384
        "Use cipher_ECDHE_RSA_WITH_AES_256_GCM_SHA384 instead"
        #-}

    ----------------------------------------------------------------
    -- CCM/ECC: RFC 7251

    -- TLS_ECDHE_ECDSA_WITH_AES_128_CCM
    cipher_ECDHE_ECDSA_WITH_AES_128_CCM :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_CCM :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_CCM =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xC0AC
            , cipherName :: String
    cipherName = String
    "TLS_ECDHE_ECDSA_WITH_AES_128_CCM"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes128ccm
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA256
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_ECDHE_ECDSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12 -- RFC 7251
            }

    cipher_ECDHE_ECDSA_AES128CCM_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_AES128CCM_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_AES128CCM_SHA256 = Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_CCM
    {-# DEPRECATED
        cipher_ECDHE_ECDSA_AES128CCM_SHA256
        "User cipher_ECDHE_ECDSA_WITH_AES_128_CCM instead"
        #-}

    -- TLS_ECDHE_ECDSA_WITH_AES_256_CCM
    cipher_ECDHE_ECDSA_WITH_AES_256_CCM :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_CCM :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_CCM =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xC0AD
            , cipherName :: String
    cipherName = String
    "TLS_ECDHE_ECDSA_WITH_AES_256_CCM"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes256ccm
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA256
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_ECDHE_ECDSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12 -- RFC 7251
            }

    cipher_ECDHE_ECDSA_AES256CCM_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_AES256CCM_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_AES256CCM_SHA256 = Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_CCM
    {-# DEPRECATED
        cipher_ECDHE_ECDSA_AES256CCM_SHA256
        "Use cipher_ECDHE_ECDSA_WITH_AES_256_CCM instead"
        #-}

    -- TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
    cipher_ECDHE_ECDSA_WITH_AES_128_CCM_8 :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_CCM_8 :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_CCM_8 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xC0AE
            , cipherName :: String
    cipherName = String
    "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes128ccm8
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA256
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_ECDHE_ECDSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12 -- RFC 7251
            }

    cipher_ECDHE_ECDSA_AES128CCM8_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_AES128CCM8_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_AES128CCM8_SHA256 = Cipher
    cipher_ECDHE_ECDSA_WITH_AES_128_CCM_8
    {-# DEPRECATED
        cipher_ECDHE_ECDSA_AES128CCM8_SHA256
        "Use cipher_ECDHE_ECDSA_WITH_AES_128_CCM_8 instead"
        #-}

    -- TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
    cipher_ECDHE_ECDSA_WITH_AES_256_CCM_8 :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_CCM_8 :: Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_CCM_8 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xC0AF
            , cipherName :: String
    cipherName = String
    "TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_aes256ccm8
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA256
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_ECDHE_ECDSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12 -- RFC 7251
            }

    cipher_ECDHE_ECDSA_AES256CCM8_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_AES256CCM8_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_AES256CCM8_SHA256 = Cipher
    cipher_ECDHE_ECDSA_WITH_AES_256_CCM_8
    {-# DEPRECATED
        cipher_ECDHE_ECDSA_AES256CCM8_SHA256
        "Use cipher_ECDHE_ECDSA_WITH_AES_256_CCM_8 instead"
        #-}

    ----------------------------------------------------------------
    -- RFC 7905

    -- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
    cipher_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :: Cipher
    cipher_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :: Cipher
    cipher_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xCCA8
            , cipherName :: String
    cipherName = String
    "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_chacha20poly1305
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA256
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_ECDHE_RSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12
            }

    cipher_ECDHE_RSA_CHACHA20POLY1305_SHA256 :: Cipher
    cipher_ECDHE_RSA_CHACHA20POLY1305_SHA256 :: Cipher
    cipher_ECDHE_RSA_CHACHA20POLY1305_SHA256 = Cipher
    cipher_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
    {-# DEPRECATED
        cipher_ECDHE_RSA_CHACHA20POLY1305_SHA256
        "Use cipher_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 instead"
        #-}

    -- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
    cipher_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xCCA9
            , cipherName :: String
    cipherName = String
    "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_chacha20poly1305
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA256
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_ECDHE_ECDSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12
            }

    cipher_ECDHE_ECDSA_CHACHA20POLY1305_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_CHACHA20POLY1305_SHA256 :: Cipher
    cipher_ECDHE_ECDSA_CHACHA20POLY1305_SHA256 = Cipher
    cipher_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
    {-# DEPRECATED
        cipher_ECDHE_ECDSA_CHACHA20POLY1305_SHA256
        "Use cipher_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 instead"
        #-}

    -- TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
    cipher_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :: Cipher
    cipher_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 :: Cipher
    cipher_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 =
        Cipher
            { cipherID :: CipherID
    cipherID = CipherID
    0xCCAA
            , cipherName :: String
    cipherName = String
    "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
            , cipherBulk :: Bulk
    cipherBulk = Bulk
    bulk_chacha20poly1305
            , cipherHash :: Hash
    cipherHash = Hash
    SHA256
            , cipherPRFHash :: Maybe Hash
    cipherPRFHash = Hash -> Maybe Hash
    forall a. a -> Maybe a
    Just Hash
    SHA256
            , cipherKeyExchange :: CipherKeyExchangeType
    cipherKeyExchange = CipherKeyExchangeType
    CipherKeyExchange_DHE_RSA
            , cipherMinVer :: Maybe Version
    cipherMinVer = Version -> Maybe Version
    forall a. a -> Maybe a
    Just Version
    TLS12
            }

    cipher_DHE_RSA_CHACHA20POLY1305_SHA256 :: Cipher
    cipher_DHE_RSA_CHACHA20POLY1305_SHA256 :: Cipher
    cipher_DHE_RSA_CHACHA20POLY1305_SHA256 = Cipher
    cipher_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
    {-# DEPRECATED
        cipher_DHE_RSA_CHACHA20POLY1305_SHA256
        "Use cipher_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 instead"
        #-}

    ----------------------------------------------------------------
    ----------------------------------------------------------------

    data CipherSet
        = SetAead [Cipher] [Cipher] [Cipher] -- gcm, chacha, ccm
        | SetOther [Cipher]

    -- Preference between AEAD ciphers having equivalent properties is based on
    -- hardware-acceleration support in the crypton implementation.
    sortOptimized :: [CipherSet] -> [Cipher]
    sortOptimized :: [CipherSet] -> [Cipher]
    sortOptimized = (CipherSet -> [Cipher]) -> [CipherSet] -> [Cipher]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap CipherSet -> [Cipher]
    f
      where
        f :: CipherSet -> [Cipher]
    f (SetAead [Cipher]
    gcm [Cipher]
    chacha [Cipher]
    ccm)
            | ProcessorOption
    AESNI ProcessorOption -> [ProcessorOption] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [ProcessorOption]
    processorOptions = [Cipher]
    chacha [Cipher] -> [Cipher] -> [Cipher]
    forall a. [a] -> [a] -> [a]
    ++ [Cipher]
    gcm [Cipher] -> [Cipher] -> [Cipher]
    forall a. [a] -> [a] -> [a]
    ++ [Cipher]
    ccm
            | ProcessorOption
    PCLMUL ProcessorOption -> [ProcessorOption] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [ProcessorOption]
    processorOptions = [Cipher]
    ccm [Cipher] -> [Cipher] -> [Cipher]
    forall a. [a] -> [a] -> [a]
    ++ [Cipher]
    chacha [Cipher] -> [Cipher] -> [Cipher]
    forall a. [a] -> [a] -> [a]
    ++ [Cipher]
    gcm
            | Bool
    otherwise = [Cipher]
    gcm [Cipher] -> [Cipher] -> [Cipher]
    forall a. [a] -> [a] -> [a]
    ++ [Cipher]
    ccm [Cipher] -> [Cipher] -> [Cipher]
    forall a. [a] -> [a] -> [a]
    ++ [Cipher]
    chacha
        f (SetOther [Cipher]
    ciphers) = [Cipher]
    ciphers

    -- Order which is deterministic but not optimized for the CPU.
    sortDeterministic :: [CipherSet] -> [Cipher]
    sortDeterministic :: [CipherSet] -> [Cipher]
    sortDeterministic = (CipherSet -> [Cipher]) -> [CipherSet] -> [Cipher]
    forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
    concatMap CipherSet -> [Cipher]
    f
      where
        f :: CipherSet -> [Cipher]
    f (SetAead [Cipher]
    gcm [Cipher]
    chacha [Cipher]
    ccm) = [Cipher]
    gcm [Cipher] -> [Cipher] -> [Cipher]
    forall a. [a] -> [a] -> [a]
    ++ [Cipher]
    chacha [Cipher] -> [Cipher] -> [Cipher]
    forall a. [a] -> [a] -> [a]
    ++ [Cipher]
    ccm
        f (SetOther [Cipher]
    ciphers) = [Cipher]
    ciphers

    ----------------------------------------------------------------

    aes128ccm :: BulkDirection -> BulkKey -> BulkAEAD
    aes128ccm :: BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes128ccm BulkDirection
    BulkEncrypt BulkAdditionalData
    key =
        let ctx :: AES128
    ctx = CryptoFailable AES128 -> AES128
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES128
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES128
    cipherInit BulkAdditionalData
    key) :: AES128
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let mode :: AEADMode
    mode = Int -> CCM_M -> CCM_L -> AEADMode
    AEAD_CCM (BulkAdditionalData -> Int
    B.length BulkAdditionalData
    d) CCM_M
    CCM_M16 CCM_L
    CCM_L3
                    aeadIni :: AEAD AES128
    aeadIni = CryptoFailable (AEAD AES128) -> AEAD AES128
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES128 -> BulkAdditionalData -> CryptoFailable (AEAD AES128)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES128 -> iv -> CryptoFailable (AEAD AES128)
    aeadInit AEADMode
    mode AES128
    ctx BulkAdditionalData
    nonce)
                 in (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a, b) -> (b, a)
    swap ((AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag))
    -> (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a -> b) -> a -> b
    $ AEAD AES128
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (AuthTag, BulkAdditionalData)
    forall aad ba a.
    (ByteArrayAccess aad, ByteArray ba) =>
    AEAD a -> aad -> ba -> Int -> (AuthTag, ba)
    aeadSimpleEncrypt AEAD AES128
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    16
            )
    aes128ccm BulkDirection
    BulkDecrypt BulkAdditionalData
    key =
        let ctx :: AES128
    ctx = CryptoFailable AES128 -> AES128
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES128
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES128
    cipherInit BulkAdditionalData
    key) :: AES128
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let mode :: AEADMode
    mode = Int -> CCM_M -> CCM_L -> AEADMode
    AEAD_CCM (BulkAdditionalData -> Int
    B.length BulkAdditionalData
    d) CCM_M
    CCM_M16 CCM_L
    CCM_L3
                    aeadIni :: AEAD AES128
    aeadIni = CryptoFailable (AEAD AES128) -> AEAD AES128
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES128 -> BulkAdditionalData -> CryptoFailable (AEAD AES128)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES128 -> iv -> CryptoFailable (AEAD AES128)
    aeadInit AEADMode
    mode AES128
    ctx BulkAdditionalData
    nonce)
                 in AEAD AES128
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    forall cipher.
    AEAD cipher
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    simpleDecrypt AEAD AES128
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    16
            )

    aes128ccm8 :: BulkDirection -> BulkKey -> BulkAEAD
    aes128ccm8 :: BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes128ccm8 BulkDirection
    BulkEncrypt BulkAdditionalData
    key =
        let ctx :: AES128
    ctx = CryptoFailable AES128 -> AES128
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES128
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES128
    cipherInit BulkAdditionalData
    key) :: AES128
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let mode :: AEADMode
    mode = Int -> CCM_M -> CCM_L -> AEADMode
    AEAD_CCM (BulkAdditionalData -> Int
    B.length BulkAdditionalData
    d) CCM_M
    CCM_M8 CCM_L
    CCM_L3
                    aeadIni :: AEAD AES128
    aeadIni = CryptoFailable (AEAD AES128) -> AEAD AES128
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES128 -> BulkAdditionalData -> CryptoFailable (AEAD AES128)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES128 -> iv -> CryptoFailable (AEAD AES128)
    aeadInit AEADMode
    mode AES128
    ctx BulkAdditionalData
    nonce)
                 in (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a, b) -> (b, a)
    swap ((AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag))
    -> (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a -> b) -> a -> b
    $ AEAD AES128
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (AuthTag, BulkAdditionalData)
    forall aad ba a.
    (ByteArrayAccess aad, ByteArray ba) =>
    AEAD a -> aad -> ba -> Int -> (AuthTag, ba)
    aeadSimpleEncrypt AEAD AES128
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    8
            )
    aes128ccm8 BulkDirection
    BulkDecrypt BulkAdditionalData
    key =
        let ctx :: AES128
    ctx = CryptoFailable AES128 -> AES128
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES128
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES128
    cipherInit BulkAdditionalData
    key) :: AES128
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let mode :: AEADMode
    mode = Int -> CCM_M -> CCM_L -> AEADMode
    AEAD_CCM (BulkAdditionalData -> Int
    B.length BulkAdditionalData
    d) CCM_M
    CCM_M8 CCM_L
    CCM_L3
                    aeadIni :: AEAD AES128
    aeadIni = CryptoFailable (AEAD AES128) -> AEAD AES128
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES128 -> BulkAdditionalData -> CryptoFailable (AEAD AES128)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES128 -> iv -> CryptoFailable (AEAD AES128)
    aeadInit AEADMode
    mode AES128
    ctx BulkAdditionalData
    nonce)
                 in AEAD AES128
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    forall cipher.
    AEAD cipher
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    simpleDecrypt AEAD AES128
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    8
            )

    aes128gcm :: BulkDirection -> BulkKey -> BulkAEAD
    aes128gcm :: BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes128gcm BulkDirection
    BulkEncrypt BulkAdditionalData
    key =
        let ctx :: AES128
    ctx = CryptoFailable AES128 -> AES128
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES128
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES128
    cipherInit BulkAdditionalData
    key) :: AES128
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let aeadIni :: AEAD AES128
    aeadIni = CryptoFailable (AEAD AES128) -> AEAD AES128
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES128 -> BulkAdditionalData -> CryptoFailable (AEAD AES128)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES128 -> iv -> CryptoFailable (AEAD AES128)
    aeadInit AEADMode
    AEAD_GCM AES128
    ctx BulkAdditionalData
    nonce)
                 in (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a, b) -> (b, a)
    swap ((AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag))
    -> (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a -> b) -> a -> b
    $ AEAD AES128
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (AuthTag, BulkAdditionalData)
    forall aad ba a.
    (ByteArrayAccess aad, ByteArray ba) =>
    AEAD a -> aad -> ba -> Int -> (AuthTag, ba)
    aeadSimpleEncrypt AEAD AES128
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    16
            )
    aes128gcm BulkDirection
    BulkDecrypt BulkAdditionalData
    key =
        let ctx :: AES128
    ctx = CryptoFailable AES128 -> AES128
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES128
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES128
    cipherInit BulkAdditionalData
    key) :: AES128
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let aeadIni :: AEAD AES128
    aeadIni = CryptoFailable (AEAD AES128) -> AEAD AES128
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES128 -> BulkAdditionalData -> CryptoFailable (AEAD AES128)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES128 -> iv -> CryptoFailable (AEAD AES128)
    aeadInit AEADMode
    AEAD_GCM AES128
    ctx BulkAdditionalData
    nonce)
                 in AEAD AES128
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    forall cipher.
    AEAD cipher
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    simpleDecrypt AEAD AES128
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    16
            )

    aes256ccm :: BulkDirection -> BulkKey -> BulkAEAD
    aes256ccm :: BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes256ccm BulkDirection
    BulkEncrypt BulkAdditionalData
    key =
        let ctx :: AES256
    ctx = CryptoFailable AES256 -> AES256
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES256
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES256
    cipherInit BulkAdditionalData
    key) :: AES256
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let mode :: AEADMode
    mode = Int -> CCM_M -> CCM_L -> AEADMode
    AEAD_CCM (BulkAdditionalData -> Int
    B.length BulkAdditionalData
    d) CCM_M
    CCM_M16 CCM_L
    CCM_L3
                    aeadIni :: AEAD AES256
    aeadIni = CryptoFailable (AEAD AES256) -> AEAD AES256
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES256 -> BulkAdditionalData -> CryptoFailable (AEAD AES256)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES256 -> iv -> CryptoFailable (AEAD AES256)
    aeadInit AEADMode
    mode AES256
    ctx BulkAdditionalData
    nonce)
                 in (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a, b) -> (b, a)
    swap ((AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag))
    -> (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a -> b) -> a -> b
    $ AEAD AES256
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (AuthTag, BulkAdditionalData)
    forall aad ba a.
    (ByteArrayAccess aad, ByteArray ba) =>
    AEAD a -> aad -> ba -> Int -> (AuthTag, ba)
    aeadSimpleEncrypt AEAD AES256
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    16
            )
    aes256ccm BulkDirection
    BulkDecrypt BulkAdditionalData
    key =
        let ctx :: AES256
    ctx = CryptoFailable AES256 -> AES256
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES256
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES256
    cipherInit BulkAdditionalData
    key) :: AES256
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let mode :: AEADMode
    mode = Int -> CCM_M -> CCM_L -> AEADMode
    AEAD_CCM (BulkAdditionalData -> Int
    B.length BulkAdditionalData
    d) CCM_M
    CCM_M16 CCM_L
    CCM_L3
                    aeadIni :: AEAD AES256
    aeadIni = CryptoFailable (AEAD AES256) -> AEAD AES256
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES256 -> BulkAdditionalData -> CryptoFailable (AEAD AES256)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES256 -> iv -> CryptoFailable (AEAD AES256)
    aeadInit AEADMode
    mode AES256
    ctx BulkAdditionalData
    nonce)
                 in AEAD AES256
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    forall cipher.
    AEAD cipher
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    simpleDecrypt AEAD AES256
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    16
            )

    aes256ccm8 :: BulkDirection -> BulkKey -> BulkAEAD
    aes256ccm8 :: BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes256ccm8 BulkDirection
    BulkEncrypt BulkAdditionalData
    key =
        let ctx :: AES256
    ctx = CryptoFailable AES256 -> AES256
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES256
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES256
    cipherInit BulkAdditionalData
    key) :: AES256
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let mode :: AEADMode
    mode = Int -> CCM_M -> CCM_L -> AEADMode
    AEAD_CCM (BulkAdditionalData -> Int
    B.length BulkAdditionalData
    d) CCM_M
    CCM_M8 CCM_L
    CCM_L3
                    aeadIni :: AEAD AES256
    aeadIni = CryptoFailable (AEAD AES256) -> AEAD AES256
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES256 -> BulkAdditionalData -> CryptoFailable (AEAD AES256)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES256 -> iv -> CryptoFailable (AEAD AES256)
    aeadInit AEADMode
    mode AES256
    ctx BulkAdditionalData
    nonce)
                 in (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a, b) -> (b, a)
    swap ((AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag))
    -> (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a -> b) -> a -> b
    $ AEAD AES256
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (AuthTag, BulkAdditionalData)
    forall aad ba a.
    (ByteArrayAccess aad, ByteArray ba) =>
    AEAD a -> aad -> ba -> Int -> (AuthTag, ba)
    aeadSimpleEncrypt AEAD AES256
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    8
            )
    aes256ccm8 BulkDirection
    BulkDecrypt BulkAdditionalData
    key =
        let ctx :: AES256
    ctx = CryptoFailable AES256 -> AES256
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES256
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES256
    cipherInit BulkAdditionalData
    key) :: AES256
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let mode :: AEADMode
    mode = Int -> CCM_M -> CCM_L -> AEADMode
    AEAD_CCM (BulkAdditionalData -> Int
    B.length BulkAdditionalData
    d) CCM_M
    CCM_M8 CCM_L
    CCM_L3
                    aeadIni :: AEAD AES256
    aeadIni = CryptoFailable (AEAD AES256) -> AEAD AES256
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES256 -> BulkAdditionalData -> CryptoFailable (AEAD AES256)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES256 -> iv -> CryptoFailable (AEAD AES256)
    aeadInit AEADMode
    mode AES256
    ctx BulkAdditionalData
    nonce)
                 in AEAD AES256
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    forall cipher.
    AEAD cipher
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    simpleDecrypt AEAD AES256
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    8
            )

    aes256gcm :: BulkDirection -> BulkKey -> BulkAEAD
    aes256gcm :: BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes256gcm BulkDirection
    BulkEncrypt BulkAdditionalData
    key =
        let ctx :: AES256
    ctx = CryptoFailable AES256 -> AES256
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES256
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES256
    cipherInit BulkAdditionalData
    key) :: AES256
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let aeadIni :: AEAD AES256
    aeadIni = CryptoFailable (AEAD AES256) -> AEAD AES256
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES256 -> BulkAdditionalData -> CryptoFailable (AEAD AES256)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES256 -> iv -> CryptoFailable (AEAD AES256)
    aeadInit AEADMode
    AEAD_GCM AES256
    ctx BulkAdditionalData
    nonce)
                 in (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a, b) -> (b, a)
    swap ((AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag))
    -> (AuthTag, BulkAdditionalData) -> (BulkAdditionalData, AuthTag)
    forall a b. (a -> b) -> a -> b
    $ AEAD AES256
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (AuthTag, BulkAdditionalData)
    forall aad ba a.
    (ByteArrayAccess aad, ByteArray ba) =>
    AEAD a -> aad -> ba -> Int -> (AuthTag, ba)
    aeadSimpleEncrypt AEAD AES256
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    16
            )
    aes256gcm BulkDirection
    BulkDecrypt BulkAdditionalData
    key =
        let ctx :: AES256
    ctx = CryptoFailable AES256 -> AES256
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable AES256
    forall cipher key.
    (Cipher cipher, ByteArray key) =>
    key -> CryptoFailable cipher
    forall key. ByteArray key => key -> CryptoFailable AES256
    cipherInit BulkAdditionalData
    key) :: AES256
         in ( \BulkAdditionalData
    nonce BulkAdditionalData
    d BulkAdditionalData
    ad ->
                let aeadIni :: AEAD AES256
    aeadIni = CryptoFailable (AEAD AES256) -> AEAD AES256
    forall a. CryptoFailable a -> a
    noFail (AEADMode
    -> AES256 -> BulkAdditionalData -> CryptoFailable (AEAD AES256)
    forall cipher iv.
    (BlockCipher cipher, ByteArrayAccess iv) =>
    AEADMode -> cipher -> iv -> CryptoFailable (AEAD cipher)
    forall iv.
    ByteArrayAccess iv =>
    AEADMode -> AES256 -> iv -> CryptoFailable (AEAD AES256)
    aeadInit AEADMode
    AEAD_GCM AES256
    ctx BulkAdditionalData
    nonce)
                 in AEAD AES256
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    forall cipher.
    AEAD cipher
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    simpleDecrypt AEAD AES256
    aeadIni BulkAdditionalData
    ad BulkAdditionalData
    d Int
    16
            )

    simpleDecrypt
        :: AEAD cipher -> B.ByteString -> B.ByteString -> Int -> (B.ByteString, AuthTag)
    simpleDecrypt :: forall cipher.
    AEAD cipher
    -> BulkAdditionalData
    -> BulkAdditionalData
    -> Int
    -> (BulkAdditionalData, AuthTag)
    simpleDecrypt AEAD cipher
    aeadIni BulkAdditionalData
    header BulkAdditionalData
    input Int
    taglen = (BulkAdditionalData
    output, AuthTag
    tag)
      where
        aead :: AEAD cipher
    aead = AEAD cipher -> BulkAdditionalData -> AEAD cipher
    forall aad cipher.
    ByteArrayAccess aad =>
    AEAD cipher -> aad -> AEAD cipher
    aeadAppendHeader AEAD cipher
    aeadIni BulkAdditionalData
    header
        (BulkAdditionalData
    output, AEAD cipher
    aeadFinal) = AEAD cipher
    -> BulkAdditionalData -> (BulkAdditionalData, AEAD cipher)
    forall ba cipher.
    ByteArray ba =>
    AEAD cipher -> ba -> (ba, AEAD cipher)
    aeadDecrypt AEAD cipher
    aead BulkAdditionalData
    input
        tag :: AuthTag
    tag = AEAD cipher -> Int -> AuthTag
    forall cipher. AEAD cipher -> Int -> AuthTag
    aeadFinalize AEAD cipher
    aeadFinal Int
    taglen

    noFail :: CryptoFailable a -> a
    noFail :: forall a. CryptoFailable a -> a
    noFail = CryptoFailable a -> a
    forall a. CryptoFailable a -> a
    throwCryptoError

    chacha20poly1305 :: BulkDirection -> BulkKey -> BulkAEAD
    chacha20poly1305 :: BulkDirection -> BulkAdditionalData -> BulkAEAD
    chacha20poly1305 BulkDirection
    BulkEncrypt BulkAdditionalData
    key BulkAdditionalData
    nonce =
        let st :: State
    st = CryptoFailable State -> State
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable Nonce
    forall iv. ByteArrayAccess iv => iv -> CryptoFailable Nonce
    ChaChaPoly1305.nonce12 BulkAdditionalData
    nonce CryptoFailable Nonce
    -> (Nonce -> CryptoFailable State) -> CryptoFailable State
    forall a b.
    CryptoFailable a -> (a -> CryptoFailable b) -> CryptoFailable b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= BulkAdditionalData -> Nonce -> CryptoFailable State
    forall key.
    ByteArrayAccess key =>
    key -> Nonce -> CryptoFailable State
    ChaChaPoly1305.initialize BulkAdditionalData
    key)
         in ( \BulkAdditionalData
    input BulkAdditionalData
    ad ->
                let st2 :: State
    st2 = State -> State
    ChaChaPoly1305.finalizeAAD (BulkAdditionalData -> State -> State
    forall ba. ByteArrayAccess ba => ba -> State -> State
    ChaChaPoly1305.appendAAD BulkAdditionalData
    ad State
    st)
                    (BulkAdditionalData
    output, State
    st3) = BulkAdditionalData -> State -> (BulkAdditionalData, State)
    forall ba. ByteArray ba => ba -> State -> (ba, State)
    ChaChaPoly1305.encrypt BulkAdditionalData
    input State
    st2
                    Poly1305.Auth Bytes
    tag = State -> Auth
    ChaChaPoly1305.finalize State
    st3
                 in (BulkAdditionalData
    output, Bytes -> AuthTag
    AuthTag Bytes
    tag)
            )
    chacha20poly1305 BulkDirection
    BulkDecrypt BulkAdditionalData
    key BulkAdditionalData
    nonce =
        let st :: State
    st = CryptoFailable State -> State
    forall a. CryptoFailable a -> a
    noFail (BulkAdditionalData -> CryptoFailable Nonce
    forall iv. ByteArrayAccess iv => iv -> CryptoFailable Nonce
    ChaChaPoly1305.nonce12 BulkAdditionalData
    nonce CryptoFailable Nonce
    -> (Nonce -> CryptoFailable State) -> CryptoFailable State
    forall a b.
    CryptoFailable a -> (a -> CryptoFailable b) -> CryptoFailable b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= BulkAdditionalData -> Nonce -> CryptoFailable State
    forall key.
    ByteArrayAccess key =>
    key -> Nonce -> CryptoFailable State
    ChaChaPoly1305.initialize BulkAdditionalData
    key)
         in ( \BulkAdditionalData
    input BulkAdditionalData
    ad ->
                let st2 :: State
    st2 = State -> State
    ChaChaPoly1305.finalizeAAD (BulkAdditionalData -> State -> State
    forall ba. ByteArrayAccess ba => ba -> State -> State
    ChaChaPoly1305.appendAAD BulkAdditionalData
    ad State
    st)
                    (BulkAdditionalData
    output, State
    st3) = BulkAdditionalData -> State -> (BulkAdditionalData, State)
    forall ba. ByteArray ba => ba -> State -> (ba, State)
    ChaChaPoly1305.decrypt BulkAdditionalData
    input State
    st2
                    Poly1305.Auth Bytes
    tag = State -> Auth
    ChaChaPoly1305.finalize State
    st3
                 in (BulkAdditionalData
    output, Bytes -> AuthTag
    AuthTag Bytes
    tag)
            )

    ----------------------------------------------------------------

    bulk_aes128ccm :: Bulk
    bulk_aes128ccm :: Bulk
    bulk_aes128ccm =
        Bulk
            { bulkName :: String
    bulkName = String
    "AES128CCM"
            , bulkKeySize :: Int
    bulkKeySize = Int
    16 -- RFC 5116 Sec 5.1: K_LEN
            , bulkIVSize :: Int
    bulkIVSize = Int
    4 -- RFC 6655 CCMNonce.salt, fixed_iv_length
            , bulkExplicitIV :: Int
    bulkExplicitIV = Int
    8
            , bulkAuthTagLen :: Int
    bulkAuthTagLen = Int
    16
            , bulkBlockSize :: Int
    bulkBlockSize = Int
    0 -- dummy, not used
            , bulkF :: BulkFunctions
    bulkF = (BulkDirection -> BulkAdditionalData -> BulkAEAD) -> BulkFunctions
    BulkAeadF BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes128ccm
            }

    bulk_aes128ccm8 :: Bulk
    bulk_aes128ccm8 :: Bulk
    bulk_aes128ccm8 =
        Bulk
            { bulkName :: String
    bulkName = String
    "AES128CCM8"
            , bulkKeySize :: Int
    bulkKeySize = Int
    16 -- RFC 5116 Sec 5.1: K_LEN
            , bulkIVSize :: Int
    bulkIVSize = Int
    4 -- RFC 6655 CCMNonce.salt, fixed_iv_length
            , bulkExplicitIV :: Int
    bulkExplicitIV = Int
    8
            , bulkAuthTagLen :: Int
    bulkAuthTagLen = Int
    8
            , bulkBlockSize :: Int
    bulkBlockSize = Int
    0 -- dummy, not used
            , bulkF :: BulkFunctions
    bulkF = (BulkDirection -> BulkAdditionalData -> BulkAEAD) -> BulkFunctions
    BulkAeadF BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes128ccm8
            }

    bulk_aes128gcm :: Bulk
    bulk_aes128gcm :: Bulk
    bulk_aes128gcm =
        Bulk
            { bulkName :: String
    bulkName = String
    "AES128GCM"
            , bulkKeySize :: Int
    bulkKeySize = Int
    16 -- RFC 5116 Sec 5.1: K_LEN
            , bulkIVSize :: Int
    bulkIVSize = Int
    4 -- RFC 5288 GCMNonce.salt, fixed_iv_length
            , bulkExplicitIV :: Int
    bulkExplicitIV = Int
    8
            , bulkAuthTagLen :: Int
    bulkAuthTagLen = Int
    16
            , bulkBlockSize :: Int
    bulkBlockSize = Int
    0 -- dummy, not used
            , bulkF :: BulkFunctions
    bulkF = (BulkDirection -> BulkAdditionalData -> BulkAEAD) -> BulkFunctions
    BulkAeadF BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes128gcm
            }

    bulk_aes256ccm :: Bulk
    bulk_aes256ccm :: Bulk
    bulk_aes256ccm =
        Bulk
            { bulkName :: String
    bulkName = String
    "AES256CCM"
            , bulkKeySize :: Int
    bulkKeySize = Int
    32 -- RFC 5116 Sec 5.1: K_LEN
            , bulkIVSize :: Int
    bulkIVSize = Int
    4 -- RFC 6655 CCMNonce.salt, fixed_iv_length
            , bulkExplicitIV :: Int
    bulkExplicitIV = Int
    8
            , bulkAuthTagLen :: Int
    bulkAuthTagLen = Int
    16
            , bulkBlockSize :: Int
    bulkBlockSize = Int
    0 -- dummy, not used
            , bulkF :: BulkFunctions
    bulkF = (BulkDirection -> BulkAdditionalData -> BulkAEAD) -> BulkFunctions
    BulkAeadF BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes256ccm
            }

    bulk_aes256ccm8 :: Bulk
    bulk_aes256ccm8 :: Bulk
    bulk_aes256ccm8 =
        Bulk
            { bulkName :: String
    bulkName = String
    "AES256CCM8"
            , bulkKeySize :: Int
    bulkKeySize = Int
    32 -- RFC 5116 Sec 5.1: K_LEN
            , bulkIVSize :: Int
    bulkIVSize = Int
    4 -- RFC 6655 CCMNonce.salt, fixed_iv_length
            , bulkExplicitIV :: Int
    bulkExplicitIV = Int
    8
            , bulkAuthTagLen :: Int
    bulkAuthTagLen = Int
    8
            , bulkBlockSize :: Int
    bulkBlockSize = Int
    0 -- dummy, not used
            , bulkF :: BulkFunctions
    bulkF = (BulkDirection -> BulkAdditionalData -> BulkAEAD) -> BulkFunctions
    BulkAeadF BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes256ccm8
            }

    bulk_aes256gcm :: Bulk
    bulk_aes256gcm :: Bulk
    bulk_aes256gcm =
        Bulk
            { bulkName :: String
    bulkName = String
    "AES256GCM"
            , bulkKeySize :: Int
    bulkKeySize = Int
    32 -- RFC 5116 Sec 5.1: K_LEN
            , bulkIVSize :: Int
    bulkIVSize = Int
    4 -- RFC 5288 GCMNonce.salt, fixed_iv_length
            , bulkExplicitIV :: Int
    bulkExplicitIV = Int
    8
            , bulkAuthTagLen :: Int
    bulkAuthTagLen = Int
    16
            , bulkBlockSize :: Int
    bulkBlockSize = Int
    0 -- dummy, not used
            , bulkF :: BulkFunctions
    bulkF = (BulkDirection -> BulkAdditionalData -> BulkAEAD) -> BulkFunctions
    BulkAeadF BulkDirection -> BulkAdditionalData -> BulkAEAD
    aes256gcm
            }

    bulk_chacha20poly1305 :: Bulk
    bulk_chacha20poly1305 :: Bulk
    bulk_chacha20poly1305 =
        Bulk
            { bulkName :: String
    bulkName = String
    "CHACHA20POLY1305"
            , bulkKeySize :: Int
    bulkKeySize = Int
    32
            , bulkIVSize :: Int
    bulkIVSize = Int
    12 -- RFC 7905 section 2, fixed_iv_length
            , bulkExplicitIV :: Int
    bulkExplicitIV = Int
    0
            , bulkAuthTagLen :: Int
    bulkAuthTagLen = Int
    16
            , bulkBlockSize :: Int
    bulkBlockSize = Int
    0 -- dummy, not used
            , bulkF :: BulkFunctions
    bulkF = (BulkDirection -> BulkAdditionalData -> BulkAEAD) -> BulkFunctions
    BulkAeadF BulkDirection -> BulkAdditionalData -> BulkAEAD
    chacha20poly1305
            }

    -- TLS13 bulks are same as TLS12 except they never have explicit IV
    bulk_aes128gcm_13 :: Bulk
    bulk_aes128gcm_13 :: Bulk
    bulk_aes128gcm_13 = Bulk
    bulk_aes128gcm{bulkIVSize = 12, bulkExplicitIV = 0}

    bulk_aes256gcm_13 :: Bulk
    bulk_aes256gcm_13 :: Bulk
    bulk_aes256gcm_13 = Bulk
    bulk_aes256gcm{bulkIVSize = 12, bulkExplicitIV = 0}

    bulk_aes128ccm_13 :: Bulk
    bulk_aes128ccm_13 :: Bulk
    bulk_aes128ccm_13 = Bulk
    bulk_aes128ccm{bulkIVSize = 12, bulkExplicitIV = 0}

    bulk_aes128ccm8_13 :: Bulk
    bulk_aes128ccm8_13 :: Bulk
    bulk_aes128ccm8_13 = Bulk
    bulk_aes128ccm8{bulkIVSize = 12, bulkExplicitIV = 0}