-- |
-- Module      : Crypto.PubKey.MLKEM
-- License     : BSD-style
-- Maintainer  : Kazu Yamamoto <kazu@iij.ad.jp>
-- Stability   : experimental
-- Portability : unknown
--
-- ML-KEM, the Module-Lattice-Based Key-Encapsulation Mechanism of
-- <https://csrc.nist.gov/pubs/fips/203/final FIPS 203>, in all three
-- parameter sets.
--
-- A key encapsulation mechanism is not a Diffie-Hellman: there is no shared
-- secret to be computed from two key pairs.  One side publishes an
-- 'EncapsulationKey'; the other calls 'encapsulate' on it, which draws a
-- fresh secret and returns it along with a 'Ciphertext' that only the holder
-- of the matching 'DecapsulationKey' can turn back into that secret.
--
-- > (ek, dk)  <- generateKeyPair MLKEM768        -- the receiver
-- > (ct, ss)  <- encapsulate ek                  -- the sender
-- > let ss'   =  decapsulate dk ct               -- the receiver, again
-- > ss == ss'
--
-- What 'generateKeyPair' and 'encapsulate' draw their randomness from is
-- the 'Crypto.Random.MonadRandom' instance in use.  Its documentation says
-- what an instance of your own has to be.
--
-- The parameter set is a type, so an ML-KEM-768 key cannot be passed where
-- an ML-KEM-1024 one is expected.  The three are fixed by FIPS 203 and the
-- class has no other instances.
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Crypto.PubKey.MLKEM (
    -- * Parameter sets
    MLKEM512 (..),
    MLKEM768 (..),
    MLKEM1024 (..),
    MLKEM (encapsulationKeySize, decapsulationKeySize, ciphertextSize),

    -- * Keys, ciphertexts and shared secrets
    --
    -- | These are the associated types of 'KEM', re-exported so that a
    -- caller of this module alone has them.
    KEM (..),
    SharedSecret (..),

    -- * Smart constructors
    encapsulationKey,
    decapsulationKey,
    ciphertext,

    -- * What ML-KEM has beyond the class
    generateKeyPairAndSeed,
    keyPairFromSeed,

    -- * Sizes
    seedSize,
    encapsulationCoinsSize,
    sharedSecretSize,
) where

import Data.Proxy (Proxy (..))
import Foreign.C.Types (CInt (..))
import Foreign.Ptr (Ptr)

import Crypto.Debug (DebugShow (..), debugShowBytes)
import Crypto.Error
import Crypto.KEM
import Crypto.Internal.ByteArray (
    ByteArrayAccess,
    Bytes,
    ScrubbedBytes,
    withByteArray,
 )
import qualified Crypto.Internal.ByteArray as B
import Crypto.Internal.Compat (unsafeDoIO)
import Crypto.Internal.Imports
import Crypto.Random (MonadRandom, getRandomBytes)

-- | ML-KEM-512.
data MLKEM512 = MLKEM512 deriving (Int -> MLKEM512 -> ShowS
[MLKEM512] -> ShowS
MLKEM512 -> String
(Int -> MLKEM512 -> ShowS)
-> (MLKEM512 -> String) -> ([MLKEM512] -> ShowS) -> Show MLKEM512
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MLKEM512 -> ShowS
showsPrec :: Int -> MLKEM512 -> ShowS
$cshow :: MLKEM512 -> String
show :: MLKEM512 -> String
$cshowList :: [MLKEM512] -> ShowS
showList :: [MLKEM512] -> ShowS
Show, MLKEM512 -> MLKEM512 -> Bool
(MLKEM512 -> MLKEM512 -> Bool)
-> (MLKEM512 -> MLKEM512 -> Bool) -> Eq MLKEM512
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MLKEM512 -> MLKEM512 -> Bool
== :: MLKEM512 -> MLKEM512 -> Bool
$c/= :: MLKEM512 -> MLKEM512 -> Bool
/= :: MLKEM512 -> MLKEM512 -> Bool
Eq)

-- | ML-KEM-768.  This is the set TLS uses, on its own and as the
-- lattice half of the hybrid groups.
data MLKEM768 = MLKEM768 deriving (Int -> MLKEM768 -> ShowS
[MLKEM768] -> ShowS
MLKEM768 -> String
(Int -> MLKEM768 -> ShowS)
-> (MLKEM768 -> String) -> ([MLKEM768] -> ShowS) -> Show MLKEM768
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MLKEM768 -> ShowS
showsPrec :: Int -> MLKEM768 -> ShowS
$cshow :: MLKEM768 -> String
show :: MLKEM768 -> String
$cshowList :: [MLKEM768] -> ShowS
showList :: [MLKEM768] -> ShowS
Show, MLKEM768 -> MLKEM768 -> Bool
(MLKEM768 -> MLKEM768 -> Bool)
-> (MLKEM768 -> MLKEM768 -> Bool) -> Eq MLKEM768
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MLKEM768 -> MLKEM768 -> Bool
== :: MLKEM768 -> MLKEM768 -> Bool
$c/= :: MLKEM768 -> MLKEM768 -> Bool
/= :: MLKEM768 -> MLKEM768 -> Bool
Eq)

-- | ML-KEM-1024.
data MLKEM1024 = MLKEM1024 deriving (Int -> MLKEM1024 -> ShowS
[MLKEM1024] -> ShowS
MLKEM1024 -> String
(Int -> MLKEM1024 -> ShowS)
-> (MLKEM1024 -> String)
-> ([MLKEM1024] -> ShowS)
-> Show MLKEM1024
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MLKEM1024 -> ShowS
showsPrec :: Int -> MLKEM1024 -> ShowS
$cshow :: MLKEM1024 -> String
show :: MLKEM1024 -> String
$cshowList :: [MLKEM1024] -> ShowS
showList :: [MLKEM1024] -> ShowS
Show, MLKEM1024 -> MLKEM1024 -> Bool
(MLKEM1024 -> MLKEM1024 -> Bool)
-> (MLKEM1024 -> MLKEM1024 -> Bool) -> Eq MLKEM1024
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MLKEM1024 -> MLKEM1024 -> Bool
== :: MLKEM1024 -> MLKEM1024 -> Bool
$c/= :: MLKEM1024 -> MLKEM1024 -> Bool
/= :: MLKEM1024 -> MLKEM1024 -> Bool
Eq)

-- | The three parameter sets of FIPS 203.
--
-- This is not an abstract KEM interface and does not try to be: it is the
-- three sets FIPS 203 defines, closed, carrying their sizes and the calls
-- into the implementation.  Only the sizes are exported.  If crypton grows
-- a second KEM and an interface common to both is wanted, that belongs in
-- a module of its own, with this as one of its instances.
class
    ( KEM p
    , EncapsulationKey p ~ MLKEMEncapsulationKey p
    , DecapsulationKey p ~ MLKEMDecapsulationKey p
    , Ciphertext p ~ MLKEMCiphertext p
    , Coins p ~ ScrubbedBytes
    ) =>
    MLKEM p
    where
    -- | Size in bytes of an 'EncapsulationKey' of this parameter set.
    encapsulationKeySize :: proxy p -> Int

    -- | Size in bytes of a 'DecapsulationKey' of this parameter set.
    decapsulationKeySize :: proxy p -> Int

    -- | Size in bytes of a 'Ciphertext' of this parameter set.
    ciphertextSize :: proxy p -> Int

    c_keypair :: proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
    c_enc :: proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
    c_dec :: proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
    c_checkPk :: proxy p -> Ptr Word8 -> IO CInt
    c_checkSk :: proxy p -> Ptr Word8 -> IO CInt

-- | A public encapsulation key, @ek@ in FIPS 203.
newtype MLKEMEncapsulationKey p = MLKEMEncapsulationKey Bytes
    deriving (Int -> MLKEMEncapsulationKey p -> ShowS
[MLKEMEncapsulationKey p] -> ShowS
MLKEMEncapsulationKey p -> String
(Int -> MLKEMEncapsulationKey p -> ShowS)
-> (MLKEMEncapsulationKey p -> String)
-> ([MLKEMEncapsulationKey p] -> ShowS)
-> Show (MLKEMEncapsulationKey p)
forall p. Int -> MLKEMEncapsulationKey p -> ShowS
forall p. [MLKEMEncapsulationKey p] -> ShowS
forall p. MLKEMEncapsulationKey p -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall p. Int -> MLKEMEncapsulationKey p -> ShowS
showsPrec :: Int -> MLKEMEncapsulationKey p -> ShowS
$cshow :: forall p. MLKEMEncapsulationKey p -> String
show :: MLKEMEncapsulationKey p -> String
$cshowList :: forall p. [MLKEMEncapsulationKey p] -> ShowS
showList :: [MLKEMEncapsulationKey p] -> ShowS
Show, MLKEMEncapsulationKey p -> MLKEMEncapsulationKey p -> Bool
(MLKEMEncapsulationKey p -> MLKEMEncapsulationKey p -> Bool)
-> (MLKEMEncapsulationKey p -> MLKEMEncapsulationKey p -> Bool)
-> Eq (MLKEMEncapsulationKey p)
forall p.
MLKEMEncapsulationKey p -> MLKEMEncapsulationKey p -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall p.
MLKEMEncapsulationKey p -> MLKEMEncapsulationKey p -> Bool
== :: MLKEMEncapsulationKey p -> MLKEMEncapsulationKey p -> Bool
$c/= :: forall p.
MLKEMEncapsulationKey p -> MLKEMEncapsulationKey p -> Bool
/= :: MLKEMEncapsulationKey p -> MLKEMEncapsulationKey p -> Bool
Eq, MLKEMEncapsulationKey p -> Int
(MLKEMEncapsulationKey p -> Int)
-> (forall p a. MLKEMEncapsulationKey p -> (Ptr p -> IO a) -> IO a)
-> (forall p. MLKEMEncapsulationKey p -> Ptr p -> IO ())
-> ByteArrayAccess (MLKEMEncapsulationKey p)
forall p. MLKEMEncapsulationKey p -> Int
forall p. MLKEMEncapsulationKey p -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p p. MLKEMEncapsulationKey p -> Ptr p -> IO ()
forall p a. MLKEMEncapsulationKey p -> (Ptr p -> IO a) -> IO a
forall p p a. MLKEMEncapsulationKey p -> (Ptr p -> IO a) -> IO a
$clength :: forall p. MLKEMEncapsulationKey p -> Int
length :: MLKEMEncapsulationKey p -> Int
$cwithByteArray :: forall p p a. MLKEMEncapsulationKey p -> (Ptr p -> IO a) -> IO a
withByteArray :: forall p a. MLKEMEncapsulationKey p -> (Ptr p -> IO a) -> IO a
$ccopyByteArrayToPtr :: forall p p. MLKEMEncapsulationKey p -> Ptr p -> IO ()
copyByteArrayToPtr :: forall p. MLKEMEncapsulationKey p -> Ptr p -> IO ()
ByteArrayAccess, MLKEMEncapsulationKey p -> ()
(MLKEMEncapsulationKey p -> ()) -> NFData (MLKEMEncapsulationKey p)
forall p. MLKEMEncapsulationKey p -> ()
forall a. (a -> ()) -> NFData a
$crnf :: forall p. MLKEMEncapsulationKey p -> ()
rnf :: MLKEMEncapsulationKey p -> ()
NFData)

-- | A private decapsulation key, @dk@ in FIPS 203.  It embeds the matching
-- encapsulation key, which is why it is the larger of the two.
newtype MLKEMDecapsulationKey p = MLKEMDecapsulationKey ScrubbedBytes
    deriving (MLKEMDecapsulationKey p -> MLKEMDecapsulationKey p -> Bool
(MLKEMDecapsulationKey p -> MLKEMDecapsulationKey p -> Bool)
-> (MLKEMDecapsulationKey p -> MLKEMDecapsulationKey p -> Bool)
-> Eq (MLKEMDecapsulationKey p)
forall p.
MLKEMDecapsulationKey p -> MLKEMDecapsulationKey p -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall p.
MLKEMDecapsulationKey p -> MLKEMDecapsulationKey p -> Bool
== :: MLKEMDecapsulationKey p -> MLKEMDecapsulationKey p -> Bool
$c/= :: forall p.
MLKEMDecapsulationKey p -> MLKEMDecapsulationKey p -> Bool
/= :: MLKEMDecapsulationKey p -> MLKEMDecapsulationKey p -> Bool
Eq, MLKEMDecapsulationKey p -> Int
(MLKEMDecapsulationKey p -> Int)
-> (forall p a. MLKEMDecapsulationKey p -> (Ptr p -> IO a) -> IO a)
-> (forall p. MLKEMDecapsulationKey p -> Ptr p -> IO ())
-> ByteArrayAccess (MLKEMDecapsulationKey p)
forall p. MLKEMDecapsulationKey p -> Int
forall p. MLKEMDecapsulationKey p -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p p. MLKEMDecapsulationKey p -> Ptr p -> IO ()
forall p a. MLKEMDecapsulationKey p -> (Ptr p -> IO a) -> IO a
forall p p a. MLKEMDecapsulationKey p -> (Ptr p -> IO a) -> IO a
$clength :: forall p. MLKEMDecapsulationKey p -> Int
length :: MLKEMDecapsulationKey p -> Int
$cwithByteArray :: forall p p a. MLKEMDecapsulationKey p -> (Ptr p -> IO a) -> IO a
withByteArray :: forall p a. MLKEMDecapsulationKey p -> (Ptr p -> IO a) -> IO a
$ccopyByteArrayToPtr :: forall p p. MLKEMDecapsulationKey p -> Ptr p -> IO ()
copyByteArrayToPtr :: forall p. MLKEMDecapsulationKey p -> Ptr p -> IO ()
ByteArrayAccess, MLKEMDecapsulationKey p -> ()
(MLKEMDecapsulationKey p -> ()) -> NFData (MLKEMDecapsulationKey p)
forall p. MLKEMDecapsulationKey p -> ()
forall a. (a -> ()) -> NFData a
$crnf :: forall p. MLKEMDecapsulationKey p -> ()
rnf :: MLKEMDecapsulationKey p -> ()
NFData)

instance Show (MLKEMDecapsulationKey p) where
    show :: MLKEMDecapsulationKey p -> String
show MLKEMDecapsulationKey p
_ = String
"DecapsulationKey <redacted>"

instance DebugShow (MLKEMDecapsulationKey p) where
    debugShow :: MLKEMDecapsulationKey p -> String
debugShow = String -> MLKEMDecapsulationKey p -> String
forall ba. ByteArrayAccess ba => String -> ba -> String
debugShowBytes String
"DecapsulationKey"

-- | The value 'encapsulate' produces and 'decapsulate' consumes.
newtype MLKEMCiphertext p = MLKEMCiphertext Bytes
    deriving (Int -> MLKEMCiphertext p -> ShowS
[MLKEMCiphertext p] -> ShowS
MLKEMCiphertext p -> String
(Int -> MLKEMCiphertext p -> ShowS)
-> (MLKEMCiphertext p -> String)
-> ([MLKEMCiphertext p] -> ShowS)
-> Show (MLKEMCiphertext p)
forall p. Int -> MLKEMCiphertext p -> ShowS
forall p. [MLKEMCiphertext p] -> ShowS
forall p. MLKEMCiphertext p -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall p. Int -> MLKEMCiphertext p -> ShowS
showsPrec :: Int -> MLKEMCiphertext p -> ShowS
$cshow :: forall p. MLKEMCiphertext p -> String
show :: MLKEMCiphertext p -> String
$cshowList :: forall p. [MLKEMCiphertext p] -> ShowS
showList :: [MLKEMCiphertext p] -> ShowS
Show, MLKEMCiphertext p -> MLKEMCiphertext p -> Bool
(MLKEMCiphertext p -> MLKEMCiphertext p -> Bool)
-> (MLKEMCiphertext p -> MLKEMCiphertext p -> Bool)
-> Eq (MLKEMCiphertext p)
forall p. MLKEMCiphertext p -> MLKEMCiphertext p -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall p. MLKEMCiphertext p -> MLKEMCiphertext p -> Bool
== :: MLKEMCiphertext p -> MLKEMCiphertext p -> Bool
$c/= :: forall p. MLKEMCiphertext p -> MLKEMCiphertext p -> Bool
/= :: MLKEMCiphertext p -> MLKEMCiphertext p -> Bool
Eq, MLKEMCiphertext p -> Int
(MLKEMCiphertext p -> Int)
-> (forall p a. MLKEMCiphertext p -> (Ptr p -> IO a) -> IO a)
-> (forall p. MLKEMCiphertext p -> Ptr p -> IO ())
-> ByteArrayAccess (MLKEMCiphertext p)
forall p. MLKEMCiphertext p -> Int
forall p. MLKEMCiphertext p -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p p. MLKEMCiphertext p -> Ptr p -> IO ()
forall p a. MLKEMCiphertext p -> (Ptr p -> IO a) -> IO a
forall p p a. MLKEMCiphertext p -> (Ptr p -> IO a) -> IO a
$clength :: forall p. MLKEMCiphertext p -> Int
length :: MLKEMCiphertext p -> Int
$cwithByteArray :: forall p p a. MLKEMCiphertext p -> (Ptr p -> IO a) -> IO a
withByteArray :: forall p a. MLKEMCiphertext p -> (Ptr p -> IO a) -> IO a
$ccopyByteArrayToPtr :: forall p p. MLKEMCiphertext p -> Ptr p -> IO ()
copyByteArrayToPtr :: forall p. MLKEMCiphertext p -> Ptr p -> IO ()
ByteArrayAccess, MLKEMCiphertext p -> ()
(MLKEMCiphertext p -> ()) -> NFData (MLKEMCiphertext p)
forall p. MLKEMCiphertext p -> ()
forall a. (a -> ()) -> NFData a
$crnf :: forall p. MLKEMCiphertext p -> ()
rnf :: MLKEMCiphertext p -> ()
NFData)

-- | Size in bytes of the seed 'keyPairFromSeed' takes, which is @d@ and @z@
-- of FIPS 203 one after the other.
seedSize :: Int
seedSize :: Int
seedSize = Int
64

-- | Size in bytes of the randomness 'encapsulateWith' takes, @m@ in
-- FIPS 203.
encapsulationCoinsSize :: Int
encapsulationCoinsSize :: Int
encapsulationCoinsSize = Int
32

-- | Size in bytes of a 'SharedSecret'.
sharedSecretSize :: Int
sharedSecretSize :: Int
sharedSecretSize = Int
32

-- | Try to read an encapsulation key.
--
-- Beyond the length this runs the check of FIPS 203 section 7.2: the key
-- must be the encoding of coefficients that are all in range, which is to
-- say it must survive a decode and re-encode unchanged.  A key that fails
-- it is not one any honest party produced.
encapsulationKey
    :: forall p ba
     . (MLKEM p, ByteArrayAccess ba)
    => ba -> CryptoFailable (EncapsulationKey p)
encapsulationKey :: forall p ba.
(MLKEM p, ByteArrayAccess ba) =>
ba -> CryptoFailable (EncapsulationKey p)
encapsulationKey ba
bs
    | ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Proxy p -> Int
forall p (proxy :: * -> *). MLKEM p => proxy p -> Int
forall (proxy :: * -> *). proxy p -> Int
encapsulationKeySize Proxy p
p = CryptoError -> CryptoFailable (MLKEMEncapsulationKey p)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_PublicKeySizeInvalid
    | Bool
otherwise = IO (CryptoFailable (EncapsulationKey p))
-> CryptoFailable (EncapsulationKey p)
forall a. IO a -> a
unsafeDoIO (IO (CryptoFailable (EncapsulationKey p))
 -> CryptoFailable (EncapsulationKey p))
-> IO (CryptoFailable (EncapsulationKey p))
-> CryptoFailable (EncapsulationKey p)
forall a b. (a -> b) -> a -> b
$ ba
-> (Ptr Word8 -> IO (CryptoFailable (EncapsulationKey p)))
-> IO (CryptoFailable (EncapsulationKey p))
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
bs ((Ptr Word8 -> IO (CryptoFailable (EncapsulationKey p)))
 -> IO (CryptoFailable (EncapsulationKey p)))
-> (Ptr Word8 -> IO (CryptoFailable (EncapsulationKey p)))
-> IO (CryptoFailable (EncapsulationKey p))
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
inp -> do
        CInt
r <- Proxy p -> Ptr Word8 -> IO CInt
forall p (proxy :: * -> *).
MLKEM p =>
proxy p -> Ptr Word8 -> IO CInt
forall (proxy :: * -> *). proxy p -> Ptr Word8 -> IO CInt
c_checkPk Proxy p
p Ptr Word8
inp
        CryptoFailable (MLKEMEncapsulationKey p)
-> IO (CryptoFailable (MLKEMEncapsulationKey p))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CryptoFailable (MLKEMEncapsulationKey p)
 -> IO (CryptoFailable (MLKEMEncapsulationKey p)))
-> CryptoFailable (MLKEMEncapsulationKey p)
-> IO (CryptoFailable (MLKEMEncapsulationKey p))
forall a b. (a -> b) -> a -> b
$
            if CInt
r CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
0
                then MLKEMEncapsulationKey p -> CryptoFailable (MLKEMEncapsulationKey p)
forall a. a -> CryptoFailable a
CryptoPassed (MLKEMEncapsulationKey p
 -> CryptoFailable (MLKEMEncapsulationKey p))
-> MLKEMEncapsulationKey p
-> CryptoFailable (MLKEMEncapsulationKey p)
forall a b. (a -> b) -> a -> b
$ Bytes -> MLKEMEncapsulationKey p
forall p. Bytes -> MLKEMEncapsulationKey p
MLKEMEncapsulationKey (Bytes -> MLKEMEncapsulationKey p)
-> Bytes -> MLKEMEncapsulationKey p
forall a b. (a -> b) -> a -> b
$ ba -> (Ptr Any -> IO ()) -> Bytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> bs2
B.copyAndFreeze ba
bs (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
                else CryptoError -> CryptoFailable (MLKEMEncapsulationKey p)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_PublicKeyStructureInvalid
  where
    p :: Proxy p
p = Proxy p
forall {k} (t :: k). Proxy t
Proxy :: Proxy p
{-# NOINLINE encapsulationKey #-}

-- | Try to read a decapsulation key.
--
-- Beyond the length this runs the check of FIPS 203 section 7.3: the hash
-- of the encapsulation key the private key embeds must match the copy of
-- that hash it also embeds.  The two disagreeing means the key was not
-- produced as a pair, and decapsulating with it would silently answer with
-- the implicit rejection every time.
decapsulationKey
    :: forall p ba
     . (MLKEM p, ByteArrayAccess ba)
    => ba -> CryptoFailable (DecapsulationKey p)
decapsulationKey :: forall p ba.
(MLKEM p, ByteArrayAccess ba) =>
ba -> CryptoFailable (DecapsulationKey p)
decapsulationKey ba
bs
    | ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Proxy p -> Int
forall p (proxy :: * -> *). MLKEM p => proxy p -> Int
forall (proxy :: * -> *). proxy p -> Int
decapsulationKeySize Proxy p
p = CryptoError -> CryptoFailable (MLKEMDecapsulationKey p)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SecretKeySizeInvalid
    | Bool
otherwise = IO (CryptoFailable (DecapsulationKey p))
-> CryptoFailable (DecapsulationKey p)
forall a. IO a -> a
unsafeDoIO (IO (CryptoFailable (DecapsulationKey p))
 -> CryptoFailable (DecapsulationKey p))
-> IO (CryptoFailable (DecapsulationKey p))
-> CryptoFailable (DecapsulationKey p)
forall a b. (a -> b) -> a -> b
$ ba
-> (Ptr Word8 -> IO (CryptoFailable (DecapsulationKey p)))
-> IO (CryptoFailable (DecapsulationKey p))
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
bs ((Ptr Word8 -> IO (CryptoFailable (DecapsulationKey p)))
 -> IO (CryptoFailable (DecapsulationKey p)))
-> (Ptr Word8 -> IO (CryptoFailable (DecapsulationKey p)))
-> IO (CryptoFailable (DecapsulationKey p))
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
inp -> do
        CInt
r <- Proxy p -> Ptr Word8 -> IO CInt
forall p (proxy :: * -> *).
MLKEM p =>
proxy p -> Ptr Word8 -> IO CInt
forall (proxy :: * -> *). proxy p -> Ptr Word8 -> IO CInt
c_checkSk Proxy p
p Ptr Word8
inp
        CryptoFailable (MLKEMDecapsulationKey p)
-> IO (CryptoFailable (MLKEMDecapsulationKey p))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CryptoFailable (MLKEMDecapsulationKey p)
 -> IO (CryptoFailable (MLKEMDecapsulationKey p)))
-> CryptoFailable (MLKEMDecapsulationKey p)
-> IO (CryptoFailable (MLKEMDecapsulationKey p))
forall a b. (a -> b) -> a -> b
$
            if CInt
r CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
0
                then MLKEMDecapsulationKey p -> CryptoFailable (MLKEMDecapsulationKey p)
forall a. a -> CryptoFailable a
CryptoPassed (MLKEMDecapsulationKey p
 -> CryptoFailable (MLKEMDecapsulationKey p))
-> MLKEMDecapsulationKey p
-> CryptoFailable (MLKEMDecapsulationKey p)
forall a b. (a -> b) -> a -> b
$ ScrubbedBytes -> MLKEMDecapsulationKey p
forall p. ScrubbedBytes -> MLKEMDecapsulationKey p
MLKEMDecapsulationKey (ScrubbedBytes -> MLKEMDecapsulationKey p)
-> ScrubbedBytes -> MLKEMDecapsulationKey p
forall a b. (a -> b) -> a -> b
$ ba -> (Ptr Any -> IO ()) -> ScrubbedBytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> bs2
B.copyAndFreeze ba
bs (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
                else CryptoError -> CryptoFailable (MLKEMDecapsulationKey p)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SecretKeyStructureInvalid
  where
    p :: Proxy p
p = Proxy p
forall {k} (t :: k). Proxy t
Proxy :: Proxy p
{-# NOINLINE decapsulationKey #-}

-- | Try to read a ciphertext.  Only the length is checked; every string of
-- the right length is a ciphertext that 'decapsulate' will answer.
ciphertext
    :: forall p ba
     . (MLKEM p, ByteArrayAccess ba)
    => ba -> CryptoFailable (Ciphertext p)
ciphertext :: forall p ba.
(MLKEM p, ByteArrayAccess ba) =>
ba -> CryptoFailable (Ciphertext p)
ciphertext ba
bs
    | ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
bs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Proxy p -> Int
forall p (proxy :: * -> *). MLKEM p => proxy p -> Int
forall (proxy :: * -> *). proxy p -> Int
ciphertextSize (Proxy p
forall {k} (t :: k). Proxy t
Proxy :: Proxy p) =
        Ciphertext p -> CryptoFailable (Ciphertext p)
forall a. a -> CryptoFailable a
CryptoPassed (Ciphertext p -> CryptoFailable (Ciphertext p))
-> Ciphertext p -> CryptoFailable (Ciphertext p)
forall a b. (a -> b) -> a -> b
$ Bytes -> MLKEMCiphertext p
forall p. Bytes -> MLKEMCiphertext p
MLKEMCiphertext (Bytes -> MLKEMCiphertext p) -> Bytes -> MLKEMCiphertext p
forall a b. (a -> b) -> a -> b
$ ba -> (Ptr Any -> IO ()) -> Bytes
forall bs1 bs2 p.
(ByteArrayAccess bs1, ByteArray bs2) =>
bs1 -> (Ptr p -> IO ()) -> bs2
B.copyAndFreeze ba
bs (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
    | Bool
otherwise = CryptoError -> CryptoFailable (MLKEMCiphertext p)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_PointSizeInvalid

-- | Generate a key pair.
--
-- The seed it is derived from is drawn here and thrown away.  Use
-- 'generateKeyPairAndSeed' where it has to be kept.
mlkemGenerateKeyPair
    :: forall p proxy m
     . (MLKEM p, MonadRandom m)
    => proxy p -> m (MLKEMEncapsulationKey p, DecapsulationKey p)
mlkemGenerateKeyPair :: forall p (proxy :: * -> *) (m :: * -> *).
(MLKEM p, MonadRandom m) =>
proxy p -> m (MLKEMEncapsulationKey p, DecapsulationKey p)
mlkemGenerateKeyPair proxy p
p = do
    (MLKEMEncapsulationKey p
ek, MLKEMDecapsulationKey p
dk, ScrubbedBytes
_) <- proxy p
-> m (MLKEMEncapsulationKey p, DecapsulationKey p, ScrubbedBytes)
forall p (proxy :: * -> *) (m :: * -> *).
(MLKEM p, MonadRandom m) =>
proxy p
-> m (MLKEMEncapsulationKey p, DecapsulationKey p, ScrubbedBytes)
generateKeyPairAndSeed proxy p
p
    (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p)
-> m (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (MLKEMEncapsulationKey p
ek, MLKEMDecapsulationKey p
dk)

-- | Generate a key pair and hand back the seed it was derived from, @d@
-- and @z@ of FIPS 203 one after the other.
--
-- A 'DecapsulationKey' is the expanded key and nothing else, so the seed
-- cannot be recovered from a pair afterwards.  An application that has to
-- write the key out in a form that keeps the seed has to generate it here:
--
-- > (ek, dk, seed) <- generateKeyPairAndSeed MLKEM768
--
-- The seed is as secret as the decapsulation key: 'keyPairFromSeed' turns
-- it back into the same pair.
generateKeyPairAndSeed
    :: forall p proxy m
     . (MLKEM p, MonadRandom m)
    => proxy p
    -> m (MLKEMEncapsulationKey p, DecapsulationKey p, ScrubbedBytes)
generateKeyPairAndSeed :: forall p (proxy :: * -> *) (m :: * -> *).
(MLKEM p, MonadRandom m) =>
proxy p
-> m (MLKEMEncapsulationKey p, DecapsulationKey p, ScrubbedBytes)
generateKeyPairAndSeed proxy p
p = do
    ScrubbedBytes
seed <- Int -> m ScrubbedBytes
forall byteArray. ByteArray byteArray => Int -> m byteArray
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes Int
seedSize :: m ScrubbedBytes
    case proxy p
-> ScrubbedBytes
-> CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p)
forall p (proxy :: * -> *) ba.
(MLKEM p, ByteArrayAccess ba) =>
proxy p
-> ba
-> CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p)
keyPairFromSeed proxy p
p ScrubbedBytes
seed of
        CryptoPassed (MLKEMEncapsulationKey p
ek, DecapsulationKey p
dk) -> (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p, ScrubbedBytes)
-> m (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p,
      ScrubbedBytes)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (MLKEMEncapsulationKey p
ek, DecapsulationKey p
MLKEMDecapsulationKey p
dk, ScrubbedBytes
seed)
        CryptoFailed CryptoError
e ->
            String
-> m (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p,
      ScrubbedBytes)
forall a. HasCallStack => String -> a
error (String
"Crypto.PubKey.MLKEM.generateKeyPairAndSeed: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ CryptoError -> String
forall a. Show a => a -> String
show CryptoError
e)

-- | Derive a key pair from a seed, which is @d@ and @z@ of FIPS 203 one
-- after the other and must be 'seedSize' bytes.
--
-- This is the entry point to use when the seed comes from somewhere
-- particular -- a test vector, or a store that keeps seeds rather than
-- expanded keys.  For an ordinary key, 'generateKeyPair' draws the seed
-- itself.
keyPairFromSeed
    :: forall p proxy ba
     . (MLKEM p, ByteArrayAccess ba)
    => proxy p
    -> ba
    -> CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p)
keyPairFromSeed :: forall p (proxy :: * -> *) ba.
(MLKEM p, ByteArrayAccess ba) =>
proxy p
-> ba
-> CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p)
keyPairFromSeed proxy p
p ba
seed
    | ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ba
seed Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
seedSize = CryptoError
-> CryptoFailable
     (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SeedSizeInvalid
    | Bool
otherwise = IO (CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p))
-> CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p)
forall a. IO a -> a
unsafeDoIO (IO (CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p))
 -> CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p))
-> IO
     (CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p))
-> CryptoFailable (MLKEMEncapsulationKey p, DecapsulationKey p)
forall a b. (a -> b) -> a -> b
$ do
        -- Not zeroed, and does not need to be: the C writes the whole
        -- buffer, and on a non-zero return the result is discarded without
        -- being read.  Anything that is *read* before being written has to
        -- use B.zero instead -- see signInternal in Crypto.PubKey.MLDSA.
        ScrubbedBytes
dk <- Int -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc (proxy p -> Int
forall p (proxy :: * -> *). MLKEM p => proxy p -> Int
forall (proxy :: * -> *). proxy p -> Int
decapsulationKeySize proxy p
p) (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()) :: IO ScrubbedBytes
        (CInt
r, Bytes
ek) <- Int -> (Ptr Word8 -> IO CInt) -> IO (CInt, Bytes)
forall ba p a. ByteArray ba => Int -> (Ptr p -> IO a) -> IO (a, ba)
forall p a. Int -> (Ptr p -> IO a) -> IO (a, Bytes)
B.allocRet (proxy p -> Int
forall p (proxy :: * -> *). MLKEM p => proxy p -> Int
forall (proxy :: * -> *). proxy p -> Int
encapsulationKeySize proxy p
p) ((Ptr Word8 -> IO CInt) -> IO (CInt, Bytes))
-> (Ptr Word8 -> IO CInt) -> IO (CInt, Bytes)
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pek ->
            ScrubbedBytes -> (Ptr Word8 -> IO CInt) -> IO CInt
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
withByteArray ScrubbedBytes
dk ((Ptr Word8 -> IO CInt) -> IO CInt)
-> (Ptr Word8 -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pdk ->
                ba -> (Ptr Word8 -> IO CInt) -> IO CInt
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
seed ((Ptr Word8 -> IO CInt) -> IO CInt)
-> (Ptr Word8 -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pseed ->
                    proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
forall p (proxy :: * -> *).
MLKEM p =>
proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
forall (proxy :: * -> *).
proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_keypair proxy p
p Ptr Word8
pek Ptr Word8
pdk Ptr Word8
pseed
        CryptoFailable (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p)
-> IO
     (CryptoFailable (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CryptoFailable (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p)
 -> IO
      (CryptoFailable
         (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p)))
-> CryptoFailable
     (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p)
-> IO
     (CryptoFailable (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p))
forall a b. (a -> b) -> a -> b
$
            if CInt
r CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
0
                then (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p)
-> CryptoFailable
     (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p)
forall a. a -> CryptoFailable a
CryptoPassed (Bytes -> MLKEMEncapsulationKey p
forall p. Bytes -> MLKEMEncapsulationKey p
MLKEMEncapsulationKey Bytes
ek, ScrubbedBytes -> MLKEMDecapsulationKey p
forall p. ScrubbedBytes -> MLKEMDecapsulationKey p
MLKEMDecapsulationKey ScrubbedBytes
dk)
                else CryptoError
-> CryptoFailable
     (MLKEMEncapsulationKey p, MLKEMDecapsulationKey p)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_ParameterInvalid
{-# NOINLINE keyPairFromSeed #-}

-- | Encapsulate against a public key, drawing the randomness.
mlkemEncapsulate
    :: forall p m
     . (MLKEM p, MonadRandom m)
    => MLKEMEncapsulationKey p
    -> m (CryptoFailable (Ciphertext p, SharedSecret))
mlkemEncapsulate :: forall p (m :: * -> *).
(MLKEM p, MonadRandom m) =>
MLKEMEncapsulationKey p
-> m (CryptoFailable (Ciphertext p, SharedSecret))
mlkemEncapsulate MLKEMEncapsulationKey p
ek = do
    ScrubbedBytes
coins <- Int -> m ScrubbedBytes
forall byteArray. ByteArray byteArray => Int -> m byteArray
forall (m :: * -> *) byteArray.
(MonadRandom m, ByteArray byteArray) =>
Int -> m byteArray
getRandomBytes Int
encapsulationCoinsSize :: m ScrubbedBytes
    CryptoFailable (MLKEMCiphertext p, SharedSecret)
-> m (CryptoFailable (MLKEMCiphertext p, SharedSecret))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (MLKEMEncapsulationKey p
-> ScrubbedBytes -> CryptoFailable (Ciphertext p, SharedSecret)
forall p.
MLKEM p =>
MLKEMEncapsulationKey p
-> ScrubbedBytes -> CryptoFailable (Ciphertext p, SharedSecret)
mlkemEncapsulateWith MLKEMEncapsulationKey p
ek ScrubbedBytes
coins)

-- The class's 'encapsulateWith' for ML-KEM, where the coins are @m@ of
-- FIPS 203 and must be 'encapsulationCoinsSize' bytes.
mlkemEncapsulateWith
    :: forall p
     . MLKEM p
    => MLKEMEncapsulationKey p
    -> ScrubbedBytes
    -> CryptoFailable (Ciphertext p, SharedSecret)
mlkemEncapsulateWith :: forall p.
MLKEM p =>
MLKEMEncapsulationKey p
-> ScrubbedBytes -> CryptoFailable (Ciphertext p, SharedSecret)
mlkemEncapsulateWith MLKEMEncapsulationKey p
ek ScrubbedBytes
coins
    | ScrubbedBytes -> Int
forall ba. ByteArrayAccess ba => ba -> Int
B.length ScrubbedBytes
coins Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
encapsulationCoinsSize = CryptoError -> CryptoFailable (MLKEMCiphertext p, SharedSecret)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SeedSizeInvalid
    | Bool
otherwise = IO (CryptoFailable (Ciphertext p, SharedSecret))
-> CryptoFailable (Ciphertext p, SharedSecret)
forall a. IO a -> a
unsafeDoIO (IO (CryptoFailable (Ciphertext p, SharedSecret))
 -> CryptoFailable (Ciphertext p, SharedSecret))
-> IO (CryptoFailable (Ciphertext p, SharedSecret))
-> CryptoFailable (Ciphertext p, SharedSecret)
forall a b. (a -> b) -> a -> b
$ do
        ScrubbedBytes
ss <- Int -> (Ptr Any -> IO ()) -> IO ScrubbedBytes
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
B.alloc Int
sharedSecretSize (\Ptr Any
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()) :: IO ScrubbedBytes
        (CInt
r, Bytes
ct) <- Int -> (Ptr Word8 -> IO CInt) -> IO (CInt, Bytes)
forall ba p a. ByteArray ba => Int -> (Ptr p -> IO a) -> IO (a, ba)
forall p a. Int -> (Ptr p -> IO a) -> IO (a, Bytes)
B.allocRet (Proxy p -> Int
forall p (proxy :: * -> *). MLKEM p => proxy p -> Int
forall (proxy :: * -> *). proxy p -> Int
ciphertextSize Proxy p
p) ((Ptr Word8 -> IO CInt) -> IO (CInt, Bytes))
-> (Ptr Word8 -> IO CInt) -> IO (CInt, Bytes)
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pct ->
            ScrubbedBytes -> (Ptr Word8 -> IO CInt) -> IO CInt
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
withByteArray ScrubbedBytes
ss ((Ptr Word8 -> IO CInt) -> IO CInt)
-> (Ptr Word8 -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pss ->
                MLKEMEncapsulationKey p -> (Ptr Word8 -> IO CInt) -> IO CInt
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. MLKEMEncapsulationKey p -> (Ptr p -> IO a) -> IO a
withByteArray MLKEMEncapsulationKey p
ek ((Ptr Word8 -> IO CInt) -> IO CInt)
-> (Ptr Word8 -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pek ->
                    ScrubbedBytes -> (Ptr Word8 -> IO CInt) -> IO CInt
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. ScrubbedBytes -> (Ptr p -> IO a) -> IO a
withByteArray ScrubbedBytes
coins ((Ptr Word8 -> IO CInt) -> IO CInt)
-> (Ptr Word8 -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pcoins ->
                        Proxy p
-> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
forall p (proxy :: * -> *).
MLKEM p =>
proxy p
-> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
forall (proxy :: * -> *).
proxy p
-> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_enc Proxy p
p Ptr Word8
pct Ptr Word8
pss Ptr Word8
pek Ptr Word8
pcoins
        CryptoFailable (MLKEMCiphertext p, SharedSecret)
-> IO (CryptoFailable (MLKEMCiphertext p, SharedSecret))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CryptoFailable (MLKEMCiphertext p, SharedSecret)
 -> IO (CryptoFailable (MLKEMCiphertext p, SharedSecret)))
-> CryptoFailable (MLKEMCiphertext p, SharedSecret)
-> IO (CryptoFailable (MLKEMCiphertext p, SharedSecret))
forall a b. (a -> b) -> a -> b
$
            if CInt
r CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
0
                then (MLKEMCiphertext p, SharedSecret)
-> CryptoFailable (MLKEMCiphertext p, SharedSecret)
forall a. a -> CryptoFailable a
CryptoPassed (Bytes -> MLKEMCiphertext p
forall p. Bytes -> MLKEMCiphertext p
MLKEMCiphertext Bytes
ct, ScrubbedBytes -> SharedSecret
SharedSecret ScrubbedBytes
ss)
                else CryptoError -> CryptoFailable (MLKEMCiphertext p, SharedSecret)
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_ParameterInvalid
  where
    p :: Proxy p
p = Proxy p
forall {k} (t :: k). Proxy t
Proxy :: Proxy p
{-# NOINLINE mlkemEncapsulateWith #-}

-- | Recover the shared secret from a ciphertext.
--
-- A ciphertext that was not produced by encapsulating against the matching
-- key is not an error.  ML-KEM rejects implicitly: it yields a secret
-- derived from the private key and the ciphertext, and the caller cannot
-- tell that case from the other one, which is the point -- telling them
-- apart is what a chosen-ciphertext attack needs.  A ciphertext that does
-- not belong here shows up later, as the two sides failing to agree on
-- anything.
--
-- The checks FIPS 203 does require are at the point where bytes become a
-- value of these types, which is where they can be reported:
--
-- * The ciphertext type check of section 7.3 is its length, and
--   'ciphertext' is the only way to build a 'Ciphertext' from bytes.  There
--   is nothing else to check: a ciphertext's coefficients are compressed to
--   fewer than twelve bits, so every bit pattern decodes to a value in
--   range.
-- * The hash check of section 7.3 is on the decapsulation key, and
--   'decapsulationKey' runs it; a key from 'generateKeyPair' or
--   'keyPairFromSeed' satisfies it by construction.
--
-- So the result is 'CryptoPassed' for every key and ciphertext this module
-- can produce.  It is 'CryptoFailable' rather than a bare 'SharedSecret'
-- because the implementation checks the key again on its way through, and
-- what it finds is better reported than turned into an exception.
mlkemDecapsulate
    :: forall p
     . MLKEM p
    => DecapsulationKey p -> Ciphertext p -> CryptoFailable SharedSecret
mlkemDecapsulate :: forall p.
MLKEM p =>
DecapsulationKey p -> Ciphertext p -> CryptoFailable SharedSecret
mlkemDecapsulate DecapsulationKey p
dk Ciphertext p
ct = IO (CryptoFailable SharedSecret) -> CryptoFailable SharedSecret
forall a. IO a -> a
unsafeDoIO (IO (CryptoFailable SharedSecret) -> CryptoFailable SharedSecret)
-> IO (CryptoFailable SharedSecret) -> CryptoFailable SharedSecret
forall a b. (a -> b) -> a -> b
$ do
    (CInt
r, ScrubbedBytes
ss) <- Int -> (Ptr Word8 -> IO CInt) -> IO (CInt, ScrubbedBytes)
forall ba p a. ByteArray ba => Int -> (Ptr p -> IO a) -> IO (a, ba)
forall p a. Int -> (Ptr p -> IO a) -> IO (a, ScrubbedBytes)
B.allocRet Int
sharedSecretSize ((Ptr Word8 -> IO CInt) -> IO (CInt, ScrubbedBytes))
-> (Ptr Word8 -> IO CInt) -> IO (CInt, ScrubbedBytes)
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pss ->
        MLKEMCiphertext p -> (Ptr Word8 -> IO CInt) -> IO CInt
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. MLKEMCiphertext p -> (Ptr p -> IO a) -> IO a
withByteArray Ciphertext p
MLKEMCiphertext p
ct ((Ptr Word8 -> IO CInt) -> IO CInt)
-> (Ptr Word8 -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pct ->
            MLKEMDecapsulationKey p -> (Ptr Word8 -> IO CInt) -> IO CInt
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
forall p a. MLKEMDecapsulationKey p -> (Ptr p -> IO a) -> IO a
withByteArray DecapsulationKey p
MLKEMDecapsulationKey p
dk ((Ptr Word8 -> IO CInt) -> IO CInt)
-> (Ptr Word8 -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pdk ->
                Proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
forall p (proxy :: * -> *).
MLKEM p =>
proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
forall (proxy :: * -> *).
proxy p -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_dec (Proxy p
forall {k} (t :: k). Proxy t
Proxy :: Proxy p) Ptr Word8
pss Ptr Word8
pct Ptr Word8
pdk
    CryptoFailable SharedSecret -> IO (CryptoFailable SharedSecret)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CryptoFailable SharedSecret -> IO (CryptoFailable SharedSecret))
-> CryptoFailable SharedSecret -> IO (CryptoFailable SharedSecret)
forall a b. (a -> b) -> a -> b
$
        if CInt
r CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== (CInt
0 :: CInt)
            then SharedSecret -> CryptoFailable SharedSecret
forall a. a -> CryptoFailable a
CryptoPassed (ScrubbedBytes -> SharedSecret
SharedSecret ScrubbedBytes
ss)
            else CryptoError -> CryptoFailable SharedSecret
forall a. CryptoError -> CryptoFailable a
CryptoFailed CryptoError
CryptoError_SecretKeyStructureInvalid
{-# NOINLINE mlkemDecapsulate #-}

-- The class's view of the three sets.  The operations are the ones above;
-- only the shape of the arguments differs, because the class takes the
-- mechanism as a proxy.
instance KEM MLKEM512 where
    type EncapsulationKey MLKEM512 = MLKEMEncapsulationKey MLKEM512
    type DecapsulationKey MLKEM512 = MLKEMDecapsulationKey MLKEM512
    type Ciphertext MLKEM512 = MLKEMCiphertext MLKEM512
    type Coins MLKEM512 = ScrubbedBytes
    generateKeyPair :: forall (m :: * -> *) (proxy :: * -> *).
MonadRandom m =>
proxy MLKEM512
-> m (EncapsulationKey MLKEM512, DecapsulationKey MLKEM512)
generateKeyPair = proxy MLKEM512
-> m (EncapsulationKey MLKEM512, DecapsulationKey MLKEM512)
proxy MLKEM512
-> m (MLKEMEncapsulationKey MLKEM512, DecapsulationKey MLKEM512)
forall p (proxy :: * -> *) (m :: * -> *).
(MLKEM p, MonadRandom m) =>
proxy p -> m (MLKEMEncapsulationKey p, DecapsulationKey p)
mlkemGenerateKeyPair
    encapsulate :: forall (m :: * -> *) (proxy :: * -> *).
MonadRandom m =>
proxy MLKEM512
-> EncapsulationKey MLKEM512
-> m (CryptoFailable (Ciphertext MLKEM512, SharedSecret))
encapsulate proxy MLKEM512
_ = EncapsulationKey MLKEM512
-> m (CryptoFailable (Ciphertext MLKEM512, SharedSecret))
MLKEMEncapsulationKey MLKEM512
-> m (CryptoFailable (Ciphertext MLKEM512, SharedSecret))
forall p (m :: * -> *).
(MLKEM p, MonadRandom m) =>
MLKEMEncapsulationKey p
-> m (CryptoFailable (Ciphertext p, SharedSecret))
mlkemEncapsulate
    encapsulateWith :: forall (proxy :: * -> *).
proxy MLKEM512
-> EncapsulationKey MLKEM512
-> Coins MLKEM512
-> CryptoFailable (Ciphertext MLKEM512, SharedSecret)
encapsulateWith proxy MLKEM512
_ = EncapsulationKey MLKEM512
-> Coins MLKEM512
-> CryptoFailable (Ciphertext MLKEM512, SharedSecret)
MLKEMEncapsulationKey MLKEM512
-> ScrubbedBytes
-> CryptoFailable (Ciphertext MLKEM512, SharedSecret)
forall p.
MLKEM p =>
MLKEMEncapsulationKey p
-> ScrubbedBytes -> CryptoFailable (Ciphertext p, SharedSecret)
mlkemEncapsulateWith
    decapsulate :: forall (proxy :: * -> *).
proxy MLKEM512
-> DecapsulationKey MLKEM512
-> Ciphertext MLKEM512
-> CryptoFailable SharedSecret
decapsulate proxy MLKEM512
_ = DecapsulationKey MLKEM512
-> Ciphertext MLKEM512 -> CryptoFailable SharedSecret
forall p.
MLKEM p =>
DecapsulationKey p -> Ciphertext p -> CryptoFailable SharedSecret
mlkemDecapsulate

instance KEM MLKEM768 where
    type EncapsulationKey MLKEM768 = MLKEMEncapsulationKey MLKEM768
    type DecapsulationKey MLKEM768 = MLKEMDecapsulationKey MLKEM768
    type Ciphertext MLKEM768 = MLKEMCiphertext MLKEM768
    type Coins MLKEM768 = ScrubbedBytes
    generateKeyPair :: forall (m :: * -> *) (proxy :: * -> *).
MonadRandom m =>
proxy MLKEM768
-> m (EncapsulationKey MLKEM768, DecapsulationKey MLKEM768)
generateKeyPair = proxy MLKEM768
-> m (EncapsulationKey MLKEM768, DecapsulationKey MLKEM768)
proxy MLKEM768
-> m (MLKEMEncapsulationKey MLKEM768, DecapsulationKey MLKEM768)
forall p (proxy :: * -> *) (m :: * -> *).
(MLKEM p, MonadRandom m) =>
proxy p -> m (MLKEMEncapsulationKey p, DecapsulationKey p)
mlkemGenerateKeyPair
    encapsulate :: forall (m :: * -> *) (proxy :: * -> *).
MonadRandom m =>
proxy MLKEM768
-> EncapsulationKey MLKEM768
-> m (CryptoFailable (Ciphertext MLKEM768, SharedSecret))
encapsulate proxy MLKEM768
_ = EncapsulationKey MLKEM768
-> m (CryptoFailable (Ciphertext MLKEM768, SharedSecret))
MLKEMEncapsulationKey MLKEM768
-> m (CryptoFailable (Ciphertext MLKEM768, SharedSecret))
forall p (m :: * -> *).
(MLKEM p, MonadRandom m) =>
MLKEMEncapsulationKey p
-> m (CryptoFailable (Ciphertext p, SharedSecret))
mlkemEncapsulate
    encapsulateWith :: forall (proxy :: * -> *).
proxy MLKEM768
-> EncapsulationKey MLKEM768
-> Coins MLKEM768
-> CryptoFailable (Ciphertext MLKEM768, SharedSecret)
encapsulateWith proxy MLKEM768
_ = EncapsulationKey MLKEM768
-> Coins MLKEM768
-> CryptoFailable (Ciphertext MLKEM768, SharedSecret)
MLKEMEncapsulationKey MLKEM768
-> ScrubbedBytes
-> CryptoFailable (Ciphertext MLKEM768, SharedSecret)
forall p.
MLKEM p =>
MLKEMEncapsulationKey p
-> ScrubbedBytes -> CryptoFailable (Ciphertext p, SharedSecret)
mlkemEncapsulateWith
    decapsulate :: forall (proxy :: * -> *).
proxy MLKEM768
-> DecapsulationKey MLKEM768
-> Ciphertext MLKEM768
-> CryptoFailable SharedSecret
decapsulate proxy MLKEM768
_ = DecapsulationKey MLKEM768
-> Ciphertext MLKEM768 -> CryptoFailable SharedSecret
forall p.
MLKEM p =>
DecapsulationKey p -> Ciphertext p -> CryptoFailable SharedSecret
mlkemDecapsulate

instance KEM MLKEM1024 where
    type EncapsulationKey MLKEM1024 = MLKEMEncapsulationKey MLKEM1024
    type DecapsulationKey MLKEM1024 = MLKEMDecapsulationKey MLKEM1024
    type Ciphertext MLKEM1024 = MLKEMCiphertext MLKEM1024
    type Coins MLKEM1024 = ScrubbedBytes
    generateKeyPair :: forall (m :: * -> *) (proxy :: * -> *).
MonadRandom m =>
proxy MLKEM1024
-> m (EncapsulationKey MLKEM1024, DecapsulationKey MLKEM1024)
generateKeyPair = proxy MLKEM1024
-> m (EncapsulationKey MLKEM1024, DecapsulationKey MLKEM1024)
proxy MLKEM1024
-> m (MLKEMEncapsulationKey MLKEM1024, DecapsulationKey MLKEM1024)
forall p (proxy :: * -> *) (m :: * -> *).
(MLKEM p, MonadRandom m) =>
proxy p -> m (MLKEMEncapsulationKey p, DecapsulationKey p)
mlkemGenerateKeyPair
    encapsulate :: forall (m :: * -> *) (proxy :: * -> *).
MonadRandom m =>
proxy MLKEM1024
-> EncapsulationKey MLKEM1024
-> m (CryptoFailable (Ciphertext MLKEM1024, SharedSecret))
encapsulate proxy MLKEM1024
_ = EncapsulationKey MLKEM1024
-> m (CryptoFailable (Ciphertext MLKEM1024, SharedSecret))
MLKEMEncapsulationKey MLKEM1024
-> m (CryptoFailable (Ciphertext MLKEM1024, SharedSecret))
forall p (m :: * -> *).
(MLKEM p, MonadRandom m) =>
MLKEMEncapsulationKey p
-> m (CryptoFailable (Ciphertext p, SharedSecret))
mlkemEncapsulate
    encapsulateWith :: forall (proxy :: * -> *).
proxy MLKEM1024
-> EncapsulationKey MLKEM1024
-> Coins MLKEM1024
-> CryptoFailable (Ciphertext MLKEM1024, SharedSecret)
encapsulateWith proxy MLKEM1024
_ = EncapsulationKey MLKEM1024
-> Coins MLKEM1024
-> CryptoFailable (Ciphertext MLKEM1024, SharedSecret)
MLKEMEncapsulationKey MLKEM1024
-> ScrubbedBytes
-> CryptoFailable (Ciphertext MLKEM1024, SharedSecret)
forall p.
MLKEM p =>
MLKEMEncapsulationKey p
-> ScrubbedBytes -> CryptoFailable (Ciphertext p, SharedSecret)
mlkemEncapsulateWith
    decapsulate :: forall (proxy :: * -> *).
proxy MLKEM1024
-> DecapsulationKey MLKEM1024
-> Ciphertext MLKEM1024
-> CryptoFailable SharedSecret
decapsulate proxy MLKEM1024
_ = DecapsulationKey MLKEM1024
-> Ciphertext MLKEM1024 -> CryptoFailable SharedSecret
forall p.
MLKEM p =>
DecapsulationKey p -> Ciphertext p -> CryptoFailable SharedSecret
mlkemDecapsulate

instance MLKEM MLKEM512 where
    encapsulationKeySize :: forall (proxy :: * -> *). proxy MLKEM512 -> Int
encapsulationKeySize proxy MLKEM512
_ = Int
800
    decapsulationKeySize :: forall (proxy :: * -> *). proxy MLKEM512 -> Int
decapsulationKeySize proxy MLKEM512
_ = Int
1632
    ciphertextSize :: forall (proxy :: * -> *). proxy MLKEM512 -> Int
ciphertextSize proxy MLKEM512
_ = Int
768
    c_keypair :: forall (proxy :: * -> *).
proxy MLKEM512 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_keypair proxy MLKEM512
_ = Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_mlkem512_keypair
    c_enc :: forall (proxy :: * -> *).
proxy MLKEM512
-> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_enc proxy MLKEM512
_ = Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_mlkem512_enc
    c_dec :: forall (proxy :: * -> *).
proxy MLKEM512 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_dec proxy MLKEM512
_ = Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_mlkem512_dec
    c_checkPk :: forall (proxy :: * -> *). proxy MLKEM512 -> Ptr Word8 -> IO CInt
c_checkPk proxy MLKEM512
_ = Ptr Word8 -> IO CInt
c_mlkem512_check_pk
    c_checkSk :: forall (proxy :: * -> *). proxy MLKEM512 -> Ptr Word8 -> IO CInt
c_checkSk proxy MLKEM512
_ = Ptr Word8 -> IO CInt
c_mlkem512_check_sk

instance MLKEM MLKEM768 where
    encapsulationKeySize :: forall (proxy :: * -> *). proxy MLKEM768 -> Int
encapsulationKeySize proxy MLKEM768
_ = Int
1184
    decapsulationKeySize :: forall (proxy :: * -> *). proxy MLKEM768 -> Int
decapsulationKeySize proxy MLKEM768
_ = Int
2400
    ciphertextSize :: forall (proxy :: * -> *). proxy MLKEM768 -> Int
ciphertextSize proxy MLKEM768
_ = Int
1088
    c_keypair :: forall (proxy :: * -> *).
proxy MLKEM768 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_keypair proxy MLKEM768
_ = Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_mlkem768_keypair
    c_enc :: forall (proxy :: * -> *).
proxy MLKEM768
-> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_enc proxy MLKEM768
_ = Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_mlkem768_enc
    c_dec :: forall (proxy :: * -> *).
proxy MLKEM768 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_dec proxy MLKEM768
_ = Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_mlkem768_dec
    c_checkPk :: forall (proxy :: * -> *). proxy MLKEM768 -> Ptr Word8 -> IO CInt
c_checkPk proxy MLKEM768
_ = Ptr Word8 -> IO CInt
c_mlkem768_check_pk
    c_checkSk :: forall (proxy :: * -> *). proxy MLKEM768 -> Ptr Word8 -> IO CInt
c_checkSk proxy MLKEM768
_ = Ptr Word8 -> IO CInt
c_mlkem768_check_sk

instance MLKEM MLKEM1024 where
    encapsulationKeySize :: forall (proxy :: * -> *). proxy MLKEM1024 -> Int
encapsulationKeySize proxy MLKEM1024
_ = Int
1568
    decapsulationKeySize :: forall (proxy :: * -> *). proxy MLKEM1024 -> Int
decapsulationKeySize proxy MLKEM1024
_ = Int
3168
    ciphertextSize :: forall (proxy :: * -> *). proxy MLKEM1024 -> Int
ciphertextSize proxy MLKEM1024
_ = Int
1568
    c_keypair :: forall (proxy :: * -> *).
proxy MLKEM1024 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_keypair proxy MLKEM1024
_ = Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_mlkem1024_keypair
    c_enc :: forall (proxy :: * -> *).
proxy MLKEM1024
-> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_enc proxy MLKEM1024
_ = Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_mlkem1024_enc
    c_dec :: forall (proxy :: * -> *).
proxy MLKEM1024 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_dec proxy MLKEM1024
_ = Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
c_mlkem1024_dec
    c_checkPk :: forall (proxy :: * -> *). proxy MLKEM1024 -> Ptr Word8 -> IO CInt
c_checkPk proxy MLKEM1024
_ = Ptr Word8 -> IO CInt
c_mlkem1024_check_pk
    c_checkSk :: forall (proxy :: * -> *). proxy MLKEM1024 -> Ptr Word8 -> IO CInt
c_checkSk proxy MLKEM1024
_ = Ptr Word8 -> IO CInt
c_mlkem1024_check_sk

foreign import ccall unsafe "crypton_mlkem512_keypair_derand"
    c_mlkem512_keypair :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem512_enc_derand"
    c_mlkem512_enc :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem512_dec"
    c_mlkem512_dec :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem512_check_pk"
    c_mlkem512_check_pk :: Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem512_check_sk"
    c_mlkem512_check_sk :: Ptr Word8 -> IO CInt

foreign import ccall unsafe "crypton_mlkem768_keypair_derand"
    c_mlkem768_keypair :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem768_enc_derand"
    c_mlkem768_enc :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem768_dec"
    c_mlkem768_dec :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem768_check_pk"
    c_mlkem768_check_pk :: Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem768_check_sk"
    c_mlkem768_check_sk :: Ptr Word8 -> IO CInt

foreign import ccall unsafe "crypton_mlkem1024_keypair_derand"
    c_mlkem1024_keypair :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem1024_enc_derand"
    c_mlkem1024_enc :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem1024_dec"
    c_mlkem1024_dec :: Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem1024_check_pk"
    c_mlkem1024_check_pk :: Ptr Word8 -> IO CInt
foreign import ccall unsafe "crypton_mlkem1024_check_sk"
    c_mlkem1024_check_sk :: Ptr Word8 -> IO CInt