{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Crypto.HPKE.Setup (
    setupBaseS,
    setupBaseR,
    setupPSKS,
    setupPSKR,
    setupS,
    setupR,
) where

import qualified Control.Exception as E

import Crypto.HPKE.AEAD
import Crypto.HPKE.Context
import Crypto.HPKE.ID
import Crypto.HPKE.KDF
import Crypto.HPKE.KEM
import Crypto.HPKE.KeySchedule
import Crypto.HPKE.Types

-- | Setting up base/auth mode for a sender.
--   This throws 'HPKEError'.
setupBaseS
    :: KEM_ID
    -> KDF_ID
    -> AEAD_ID
    -> Maybe EncodedSecretKey
    -- ^ My ephemeral secret key. Automatically generated if 'Nothing'
    -> Maybe EncodedSecretKey
    -- ^ My secret key for authentication.
    --   'mode_base' is used if 'Nothing'. 'base_auth' is used, otherwise.
    -> EncodedPublicKey
    -- ^ Peer's public key.
    -> Info
    -> IO (EncodedPublicKey, ContextS)
setupBaseS :: KEM_ID
-> KDF_ID
-> AEAD_ID
-> Maybe EncodedSecretKey
-> Maybe EncodedSecretKey
-> EncodedPublicKey
-> Suite
-> IO (EncodedPublicKey, ContextS)
setupBaseS KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id Maybe EncodedSecretKey
mskEm Maybe EncodedSecretKey
mskSm EncodedPublicKey
pkRm Suite
info =
    HPKEMap
-> Mode
-> KEM_ID
-> KDF_ID
-> AEAD_ID
-> Maybe EncodedSecretKey
-> Maybe EncodedSecretKey
-> EncodedPublicKey
-> Suite
-> Suite
-> Suite
-> IO (EncodedPublicKey, ContextS)
setupS HPKEMap
defaultHPKEMap Mode
mode KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id Maybe EncodedSecretKey
mskEm Maybe EncodedSecretKey
mskSm EncodedPublicKey
pkRm Suite
info Suite
"" Suite
""
  where
    mode :: Mode
mode = case Maybe EncodedSecretKey
mskSm of
        Maybe EncodedSecretKey
Nothing -> Mode
ModeBase
        Maybe EncodedSecretKey
_ -> Mode
ModeAuth

-- | Setting up base/auth mode for a receiver with its key pair.
--   This throws 'HPKEError'.
setupBaseR
    :: KEM_ID
    -> KDF_ID
    -> AEAD_ID
    -> EncodedSecretKey
    -- ^ My secret key
    -> Maybe EncodedSecretKey
    -- ^ My secret key for authentication.
    --   'mode_base' is used if 'Nothing'. 'base_auth' is used, otherwise.
    -> EncodedPublicKey
    -- ^ Peer's public key.
    -> Info
    -> IO ContextR
setupBaseR :: KEM_ID
-> KDF_ID
-> AEAD_ID
-> EncodedSecretKey
-> Maybe EncodedSecretKey
-> EncodedPublicKey
-> Suite
-> IO ContextR
setupBaseR KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id EncodedSecretKey
skRm Maybe EncodedSecretKey
mskSm EncodedPublicKey
enc Suite
info =
    HPKEMap
-> Mode
-> KEM_ID
-> KDF_ID
-> AEAD_ID
-> EncodedSecretKey
-> Maybe EncodedSecretKey
-> EncodedPublicKey
-> Suite
-> Suite
-> Suite
-> IO ContextR
setupR HPKEMap
defaultHPKEMap Mode
mode KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id EncodedSecretKey
skRm Maybe EncodedSecretKey
mskSm EncodedPublicKey
enc Suite
info Suite
"" Suite
""
  where
    mode :: Mode
mode = case Maybe EncodedSecretKey
mskSm of
        Maybe EncodedSecretKey
Nothing -> Mode
ModeBase
        Maybe EncodedSecretKey
_ -> Mode
ModeAuth

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

-- | Setting up psk/auth_psk mode for a sender.
--   This throws 'HPKEError'.
setupPSKS
    :: KEM_ID
    -> KDF_ID
    -> AEAD_ID
    -> Maybe EncodedSecretKey
    -- ^ My ephemeral secret key. Automatically generated if 'Nothing'
    -> Maybe EncodedSecretKey
    -- ^ My secret key for authentication.
    --   'mode_base' is used if 'Nothing'. 'base_auth' is used, otherwise.
    -> EncodedPublicKey
    -- ^ Peer's public key.
    -> Info
    -> PSK
    -> PSK_ID
    -> IO (EncodedPublicKey, ContextS)
setupPSKS :: KEM_ID
-> KDF_ID
-> AEAD_ID
-> Maybe EncodedSecretKey
-> Maybe EncodedSecretKey
-> EncodedPublicKey
-> Suite
-> Suite
-> Suite
-> IO (EncodedPublicKey, ContextS)
setupPSKS KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id Maybe EncodedSecretKey
skRm Maybe EncodedSecretKey
mskSm =
    HPKEMap
-> Mode
-> KEM_ID
-> KDF_ID
-> AEAD_ID
-> Maybe EncodedSecretKey
-> Maybe EncodedSecretKey
-> EncodedPublicKey
-> Suite
-> Suite
-> Suite
-> IO (EncodedPublicKey, ContextS)
setupS HPKEMap
defaultHPKEMap Mode
mode KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id Maybe EncodedSecretKey
skRm Maybe EncodedSecretKey
mskSm
  where
    mode :: Mode
mode = case Maybe EncodedSecretKey
mskSm of
        Maybe EncodedSecretKey
Nothing -> Mode
ModePsk
        Maybe EncodedSecretKey
_ -> Mode
ModeAuthPsk

-- | Setting up psk/auth_psk mode for a receiver with its key pair.
--   This throws 'HPKEError'.
setupPSKR
    :: KEM_ID
    -> KDF_ID
    -> AEAD_ID
    -> EncodedSecretKey
    -- ^ My secret key
    -> Maybe EncodedSecretKey
    -- ^ My secret key for authentication.
    --   'mode_base' is used if 'Nothing'. 'base_auth' is used, otherwise.
    -> EncodedPublicKey
    -- ^ Peer's public key.
    -> Info
    -> PSK
    -> PSK_ID
    -> IO ContextR
setupPSKR :: KEM_ID
-> KDF_ID
-> AEAD_ID
-> EncodedSecretKey
-> Maybe EncodedSecretKey
-> EncodedPublicKey
-> Suite
-> Suite
-> Suite
-> IO ContextR
setupPSKR KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id EncodedSecretKey
skRm Maybe EncodedSecretKey
mskSm =
    HPKEMap
-> Mode
-> KEM_ID
-> KDF_ID
-> AEAD_ID
-> EncodedSecretKey
-> Maybe EncodedSecretKey
-> EncodedPublicKey
-> Suite
-> Suite
-> Suite
-> IO ContextR
setupR HPKEMap
defaultHPKEMap Mode
mode KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id EncodedSecretKey
skRm Maybe EncodedSecretKey
mskSm
  where
    mode :: Mode
mode = case Maybe EncodedSecretKey
mskSm of
        Maybe EncodedSecretKey
Nothing -> Mode
ModePsk
        Maybe EncodedSecretKey
_ -> Mode
ModeAuthPsk

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

setupS
    :: HPKEMap
    -> Mode
    -> KEM_ID
    -> KDF_ID
    -> AEAD_ID
    -> Maybe EncodedSecretKey
    -- ^ My ephemeral secret key. Automatically generated if 'Nothing'
    -> Maybe EncodedSecretKey
    -- ^ My secret key for authentication.
    --   'mode_base' is used if 'Nothing'. 'base_auth' is used, otherwise.
    -> EncodedPublicKey
    -- ^ Peer's public key.
    -> Info
    -> PSK
    -> PSK_ID
    -> IO (EncodedPublicKey, ContextS)
setupS :: HPKEMap
-> Mode
-> KEM_ID
-> KDF_ID
-> AEAD_ID
-> Maybe EncodedSecretKey
-> Maybe EncodedSecretKey
-> EncodedPublicKey
-> Suite
-> Suite
-> Suite
-> IO (EncodedPublicKey, ContextS)
setupS HPKEMap
hpkeMap Mode
mode KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id Maybe EncodedSecretKey
mskEm Maybe EncodedSecretKey
mskSm EncodedPublicKey
pkRm Suite
info Suite
psk Suite
psk_id = do
    Mode -> Suite -> Suite -> IO ()
verifyPSKInput Mode
mode Suite
psk Suite
psk_id
    let r :: Either HPKEError ((KEMGroup, KDFHash), KDFHash, AEADCipher)
r = HPKEMap
-> KEM_ID
-> KDF_ID
-> AEAD_ID
-> Either HPKEError ((KEMGroup, KDFHash), KDFHash, AEADCipher)
look HPKEMap
hpkeMap KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id
    Either HPKEError ((KEMGroup, KDFHash), KDFHash, AEADCipher)
-> (((KEMGroup, KDFHash), KDFHash, AEADCipher)
    -> IO (EncodedPublicKey, ContextS))
-> IO (EncodedPublicKey, ContextS)
forall v a. Either HPKEError v -> (v -> IO a) -> IO a
throwOnError Either HPKEError ((KEMGroup, KDFHash), KDFHash, AEADCipher)
r ((((KEMGroup, KDFHash), KDFHash, AEADCipher)
  -> IO (EncodedPublicKey, ContextS))
 -> IO (EncodedPublicKey, ContextS))
-> (((KEMGroup, KDFHash), KDFHash, AEADCipher)
    -> IO (EncodedPublicKey, ContextS))
-> IO (EncodedPublicKey, ContextS)
forall a b. (a -> b) -> a -> b
$ \((KEMGroup Proxy c
group, KDFHash h
h), KDFHash h
h', AEADCipher Proxy a
c) -> do
        let derive :: KeyDeriveFunction
derive = h -> Suite -> KeyDeriveFunction
forall h.
(HashAlgorithm h, KDF h) =>
h -> Suite -> KeyDeriveFunction
extractAndExpand h
h (Suite -> KeyDeriveFunction) -> Suite -> KeyDeriveFunction
forall a b. (a -> b) -> a -> b
$ KEM_ID -> Suite
suiteKEM KEM_ID
kem_id
        encap <- case Maybe EncodedSecretKey
mskEm of
            Maybe EncodedSecretKey
Nothing -> Proxy c -> KeyDeriveFunction -> Maybe EncodedSecretKey -> IO Encap
forall group.
(EllipticCurve group, EllipticCurveDH group) =>
Proxy group
-> KeyDeriveFunction -> Maybe EncodedSecretKey -> IO Encap
encapGen Proxy c
group KeyDeriveFunction
derive Maybe EncodedSecretKey
mskSm
            Just EncodedSecretKey
skEm -> Encap -> IO Encap
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Encap -> IO Encap) -> Encap -> IO Encap
forall a b. (a -> b) -> a -> b
$ Proxy c
-> KeyDeriveFunction
-> EncodedSecretKey
-> Maybe EncodedSecretKey
-> Encap
forall group.
(EllipticCurve group, EllipticCurveDH group) =>
Proxy group
-> KeyDeriveFunction
-> EncodedSecretKey
-> Maybe EncodedSecretKey
-> Encap
encapEnv Proxy c
group KeyDeriveFunction
derive EncodedSecretKey
skEm Maybe EncodedSecretKey
mskSm
        throwOnError (encap pkRm) $ \(SharedSecret
shared_secret, EncodedPublicKey
enc) -> do
            let (Int
nk, Int
nn, Suite -> Seal
seal', Suite -> Seal
_) = Proxy a -> (Int, Int, Suite -> Seal, Suite -> Seal)
forall a.
Aead a =>
Proxy a -> (Int, Int, Suite -> Seal, Suite -> Seal)
aeadParams Proxy a
c
                suite' :: Suite
suite' = KEM_ID -> KDF_ID -> AEAD_ID -> Suite
suiteHPKE KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id
                keys :: Either HPKEError (Suite, Suite, Int, PRK h)
keys = h
-> Suite
-> Int
-> Int
-> Mode
-> Suite
-> Suite
-> Suite
-> SharedSecret
-> Either HPKEError (Suite, Suite, Int, PRK h)
forall h.
(HashAlgorithm h, KDF h) =>
h
-> Suite
-> Int
-> Int
-> Mode
-> Suite
-> Suite
-> Suite
-> SharedSecret
-> Either HPKEError (Suite, Suite, Int, PRK h)
keySchedule h
h' Suite
suite' Int
nk Int
nn Mode
mode Suite
info Suite
psk Suite
psk_id SharedSecret
shared_secret
            Either HPKEError (Suite, Suite, Int, PRK h)
-> ((Suite, Suite, Int, PRK h) -> IO (EncodedPublicKey, ContextS))
-> IO (EncodedPublicKey, ContextS)
forall v a. Either HPKEError v -> (v -> IO a) -> IO a
throwOnError Either HPKEError (Suite, Suite, Int, PRK h)
keys (((Suite, Suite, Int, PRK h) -> IO (EncodedPublicKey, ContextS))
 -> IO (EncodedPublicKey, ContextS))
-> ((Suite, Suite, Int, PRK h) -> IO (EncodedPublicKey, ContextS))
-> IO (EncodedPublicKey, ContextS)
forall a b. (a -> b) -> a -> b
$ \(Suite
key, Suite
nonce, Int
_, PRK h
prk) -> do
                let expand' :: Suite -> Int -> Suite
expand' = Suite -> PRK h -> Suite -> Suite -> Int -> Suite
forall h. KDF h => Suite -> PRK h -> Suite -> Suite -> Int -> Suite
labeledExpand Suite
suite' PRK h
prk Suite
"sec"
                ctx <- Suite
-> Suite
-> (Suite -> Seal)
-> (Suite -> Int -> Suite)
-> IO ContextS
newContextS Suite
key Suite
nonce Suite -> Seal
seal' Suite -> Int -> Suite
expand'
                return (enc, ctx)

setupR
    :: HPKEMap
    -> Mode
    -> KEM_ID
    -> KDF_ID
    -> AEAD_ID
    -> EncodedSecretKey
    -- ^ My secret key
    -> Maybe EncodedSecretKey
    -- ^ My secret key for authentication.
    --   'mode_base' is used if 'Nothing'. 'base_auth' is used, otherwise.
    -> EncodedPublicKey
    -- ^ Peer's public key.
    -> Info
    -> PSK
    -> PSK_ID
    -> IO ContextR
setupR :: HPKEMap
-> Mode
-> KEM_ID
-> KDF_ID
-> AEAD_ID
-> EncodedSecretKey
-> Maybe EncodedSecretKey
-> EncodedPublicKey
-> Suite
-> Suite
-> Suite
-> IO ContextR
setupR HPKEMap
hpkeMap Mode
mode KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id EncodedSecretKey
skRm Maybe EncodedSecretKey
mskSm EncodedPublicKey
enc Suite
info Suite
psk Suite
psk_id = do
    Mode -> Suite -> Suite -> IO ()
verifyPSKInput Mode
mode Suite
psk Suite
psk_id
    let r :: Either HPKEError ((KEMGroup, KDFHash), KDFHash, AEADCipher)
r = HPKEMap
-> KEM_ID
-> KDF_ID
-> AEAD_ID
-> Either HPKEError ((KEMGroup, KDFHash), KDFHash, AEADCipher)
look HPKEMap
hpkeMap KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id
    Either HPKEError ((KEMGroup, KDFHash), KDFHash, AEADCipher)
-> (((KEMGroup, KDFHash), KDFHash, AEADCipher) -> IO ContextR)
-> IO ContextR
forall v a. Either HPKEError v -> (v -> IO a) -> IO a
throwOnError Either HPKEError ((KEMGroup, KDFHash), KDFHash, AEADCipher)
r ((((KEMGroup, KDFHash), KDFHash, AEADCipher) -> IO ContextR)
 -> IO ContextR)
-> (((KEMGroup, KDFHash), KDFHash, AEADCipher) -> IO ContextR)
-> IO ContextR
forall a b. (a -> b) -> a -> b
$ \((KEMGroup Proxy c
group, KDFHash h
h), KDFHash h
h', AEADCipher Proxy a
c) -> do
        let derive :: KeyDeriveFunction
derive = h -> Suite -> KeyDeriveFunction
forall h.
(HashAlgorithm h, KDF h) =>
h -> Suite -> KeyDeriveFunction
extractAndExpand h
h (Suite -> KeyDeriveFunction) -> Suite -> KeyDeriveFunction
forall a b. (a -> b) -> a -> b
$ KEM_ID -> Suite
suiteKEM KEM_ID
kem_id
            decap :: Decap
decap = Proxy c
-> KeyDeriveFunction
-> EncodedSecretKey
-> Maybe EncodedSecretKey
-> Decap
forall group.
(EllipticCurve group, EllipticCurveDH group) =>
Proxy group
-> KeyDeriveFunction
-> EncodedSecretKey
-> Maybe EncodedSecretKey
-> Decap
decapEnv Proxy c
group KeyDeriveFunction
derive EncodedSecretKey
skRm Maybe EncodedSecretKey
mskSm
        Either HPKEError SharedSecret
-> (SharedSecret -> IO ContextR) -> IO ContextR
forall v a. Either HPKEError v -> (v -> IO a) -> IO a
throwOnError (Decap
decap EncodedPublicKey
enc) ((SharedSecret -> IO ContextR) -> IO ContextR)
-> (SharedSecret -> IO ContextR) -> IO ContextR
forall a b. (a -> b) -> a -> b
$ \SharedSecret
shared_secret -> do
            let (Int
nk, Int
nn, Suite -> Seal
_, Suite -> Seal
open') = Proxy a -> (Int, Int, Suite -> Seal, Suite -> Seal)
forall a.
Aead a =>
Proxy a -> (Int, Int, Suite -> Seal, Suite -> Seal)
aeadParams Proxy a
c
                suite' :: Suite
suite' = KEM_ID -> KDF_ID -> AEAD_ID -> Suite
suiteHPKE KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id
                keys :: Either HPKEError (Suite, Suite, Int, PRK h)
keys = h
-> Suite
-> Int
-> Int
-> Mode
-> Suite
-> Suite
-> Suite
-> SharedSecret
-> Either HPKEError (Suite, Suite, Int, PRK h)
forall h.
(HashAlgorithm h, KDF h) =>
h
-> Suite
-> Int
-> Int
-> Mode
-> Suite
-> Suite
-> Suite
-> SharedSecret
-> Either HPKEError (Suite, Suite, Int, PRK h)
keySchedule h
h' Suite
suite' Int
nk Int
nn Mode
mode Suite
info Suite
psk Suite
psk_id SharedSecret
shared_secret
            Either HPKEError (Suite, Suite, Int, PRK h)
-> ((Suite, Suite, Int, PRK h) -> IO ContextR) -> IO ContextR
forall v a. Either HPKEError v -> (v -> IO a) -> IO a
throwOnError Either HPKEError (Suite, Suite, Int, PRK h)
keys (((Suite, Suite, Int, PRK h) -> IO ContextR) -> IO ContextR)
-> ((Suite, Suite, Int, PRK h) -> IO ContextR) -> IO ContextR
forall a b. (a -> b) -> a -> b
$ \(Suite
key, Suite
nonce, Int
_, PRK h
prk) -> do
                let expand' :: Suite -> Int -> Suite
expand' = Suite -> PRK h -> Suite -> Suite -> Int -> Suite
forall h. KDF h => Suite -> PRK h -> Suite -> Suite -> Int -> Suite
labeledExpand Suite
suite' PRK h
prk Suite
"sec"
                Suite
-> Suite
-> (Suite -> Seal)
-> (Suite -> Int -> Suite)
-> IO ContextR
newContextR Suite
key Suite
nonce Suite -> Seal
open' Suite -> Int -> Suite
expand'

aeadParams
    :: Aead a
    => Proxy a -> (Int, Int, Key -> Seal, Key -> Open)
aeadParams :: forall a.
Aead a =>
Proxy a -> (Int, Int, Suite -> Seal, Suite -> Seal)
aeadParams Proxy a
c = (Proxy a -> Int
forall a. Aead a => Proxy a -> Int
nK Proxy a
c, Proxy a -> Int
forall a. Aead a => Proxy a -> Int
nN Proxy a
c, Proxy a -> Suite -> Seal
forall a. Aead a => Proxy a -> Suite -> Seal
sealA Proxy a
c, Proxy a -> Suite -> Seal
forall a. Aead a => Proxy a -> Suite -> Seal
openA Proxy a
c)

throwOnError :: Either HPKEError v -> (v -> IO a) -> IO a
throwOnError :: forall v a. Either HPKEError v -> (v -> IO a) -> IO a
throwOnError (Left HPKEError
err) v -> IO a
_body = HPKEError -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
E.throwIO HPKEError
err
throwOnError (Right v
ss) v -> IO a
body = v -> IO a
body v
ss

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

look
    :: HPKEMap
    -> KEM_ID
    -> KDF_ID
    -> AEAD_ID
    -> Either HPKEError ((KEMGroup, KDFHash), KDFHash, AEADCipher)
look :: HPKEMap
-> KEM_ID
-> KDF_ID
-> AEAD_ID
-> Either HPKEError ((KEMGroup, KDFHash), KDFHash, AEADCipher)
look HPKEMap{[(AEAD_ID, AEADCipher)]
[(KDF_ID, KDFHash)]
[(KEM_ID, (KEMGroup, KDFHash))]
kemMap :: [(KEM_ID, (KEMGroup, KDFHash))]
kdfMap :: [(KDF_ID, KDFHash)]
cipherMap :: [(AEAD_ID, AEADCipher)]
cipherMap :: HPKEMap -> [(AEAD_ID, AEADCipher)]
kdfMap :: HPKEMap -> [(KDF_ID, KDFHash)]
kemMap :: HPKEMap -> [(KEM_ID, (KEMGroup, KDFHash))]
..} KEM_ID
kem_id KDF_ID
kdf_id AEAD_ID
aead_id = do
    k <- KEM_ID
-> [(KEM_ID, (KEMGroup, KDFHash))]
-> Either HPKEError (KEMGroup, KDFHash)
forall k v. (Eq k, Show k) => k -> [(k, v)] -> Either HPKEError v
lookupE KEM_ID
kem_id [(KEM_ID, (KEMGroup, KDFHash))]
kemMap
    h <- lookupE kdf_id kdfMap
    a <- lookupE aead_id cipherMap
    return (k, h, a)

verifyPSKInput :: Mode -> PSK -> PSK_ID -> IO ()
verifyPSKInput :: Mode -> Suite -> Suite -> IO ()
verifyPSKInput Mode
mode Suite
psk Suite
psk_id
    | Bool
got_psk Bool -> Bool -> Bool
forall a. Eq a => a -> a -> Bool
/= Bool
got_psk_id =
        HPKEError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
E.throwIO (HPKEError -> IO ()) -> HPKEError -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> HPKEError
ValidationError String
"mismatch for psk and psk_id"
    | Bool
got_psk Bool -> Bool -> Bool
&& Mode
mode Mode -> [Mode] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Mode
ModeBase, Mode
ModeAuth] =
        HPKEError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
E.throwIO (HPKEError -> IO ()) -> HPKEError -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> HPKEError
ValidationError String
"invalid mode (1)"
    | (Bool -> Bool
not Bool
got_psk) Bool -> Bool -> Bool
&& Mode
mode Mode -> [Mode] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Mode
ModePsk, Mode
ModeAuthPsk] =
        HPKEError -> IO ()
forall e a. (HasCallStack, Exception e) => e -> IO a
E.throwIO (HPKEError -> IO ()) -> HPKEError -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> HPKEError
ValidationError String
"invalid mode (2)"
    | Bool
otherwise = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  where
    got_psk :: Bool
got_psk = Suite
psk Suite -> Suite -> Bool
forall a. Eq a => a -> a -> Bool
/= Suite
""
    got_psk_id :: Bool
got_psk_id = Suite
psk_id Suite -> Suite -> Bool
forall a. Eq a => a -> a -> Bool
/= Suite
""

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

suiteKEM :: KEM_ID -> Suite
suiteKEM :: KEM_ID -> Suite
suiteKEM KEM_ID
kem_id = Suite
"KEM" Suite -> Suite -> Suite
forall a. Semigroup a => a -> a -> a
<> Suite
i
  where
    i :: Suite
i = Int -> Integer -> Suite
forall ba. ByteArray ba => Int -> Integer -> ba
i2ospOf_ Int
2 (Integer -> Suite) -> Integer -> Suite
forall a b. (a -> b) -> a -> b
$ Word16 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> Integer) -> Word16 -> Integer
forall a b. (a -> b) -> a -> b
$ KEM_ID -> Word16
fromKEM_ID KEM_ID
kem_id

suiteHPKE :: KEM_ID -> KDF_ID -> AEAD_ID -> Suite
suiteHPKE :: KEM_ID -> KDF_ID -> AEAD_ID -> Suite
suiteHPKE KEM_ID
kem_id KDF_ID
hkdf_id AEAD_ID
aead_id = Suite
"HPKE" Suite -> Suite -> Suite
forall a. Semigroup a => a -> a -> a
<> Suite
i0 Suite -> Suite -> Suite
forall a. Semigroup a => a -> a -> a
<> Suite
i1 Suite -> Suite -> Suite
forall a. Semigroup a => a -> a -> a
<> Suite
i2
  where
    i0 :: Suite
i0 = Int -> Integer -> Suite
forall ba. ByteArray ba => Int -> Integer -> ba
i2ospOf_ Int
2 (Integer -> Suite) -> Integer -> Suite
forall a b. (a -> b) -> a -> b
$ Word16 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> Integer) -> Word16 -> Integer
forall a b. (a -> b) -> a -> b
$ KEM_ID -> Word16
fromKEM_ID KEM_ID
kem_id
    i1 :: Suite
i1 = Int -> Integer -> Suite
forall ba. ByteArray ba => Int -> Integer -> ba
i2ospOf_ Int
2 (Integer -> Suite) -> Integer -> Suite
forall a b. (a -> b) -> a -> b
$ Word16 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> Integer) -> Word16 -> Integer
forall a b. (a -> b) -> a -> b
$ KDF_ID -> Word16
fromKDF_ID KDF_ID
hkdf_id
    i2 :: Suite
i2 = Int -> Integer -> Suite
forall ba. ByteArray ba => Int -> Integer -> ba
i2ospOf_ Int
2 (Integer -> Suite) -> Integer -> Suite
forall a b. (a -> b) -> a -> b
$ Word16 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16 -> Integer) -> Word16 -> Integer
forall a b. (a -> b) -> a -> b
$ AEAD_ID -> Word16
fromAEAD_ID AEAD_ID
aead_id