/*
 * Copyright (C) 2022 - 2026, Stephan Mueller <smueller@chronox.de>
 *
 * License: see LICENSE file in root directory
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
 * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */
/*
 * This code is derived in parts from the code distribution provided with
 * https://github.com/pq-crystals/kyber
 *
 * That code is released under Public Domain
 * (https://creativecommons.org/share-your-work/public-domain/cc0/).
 */

#ifndef LC_KYBER_@kyber_header@H
#define LC_KYBER_@kyber_header@H

#ifndef __ASSEMBLER__

#include "ext_headers.h"
#include "lc_rng.h"

#endif /* __ASSEMBLER__ */

#ifdef __cplusplus
extern "C" {
#endif

/// \cond DO_NOT_DOCUMENT
/*
 * Kyber 512:  K == 2 - NIST security category 1
 * Kyber 768:  K == 3 - NIST security category 3
 * Kyber 1024: K == 4 - NIST security category 5
 */
#define LC_KYBER_K @kyber_strength@

#define LC_KYBER_N 256
#define LC_KYBER_Q 3329

#define LC_KYBER_SYMBYTES 32 /* size in bytes of hashes, and seeds */
#define LC_KYBER_SSBYTES 32 /* size in bytes of shared key */

#define LC_KYBER_POLYBYTES 384
#define LC_KYBER_POLYVECBYTES (LC_KYBER_K * LC_KYBER_POLYBYTES)

#if LC_KYBER_K == 2
#define LC_KYBER_ETA1 3
#define LC_KYBER_POLYCOMPRESSEDBYTES 128
#define LC_KYBER_POLYVECCOMPRESSEDBYTES (LC_KYBER_K * 320)
#elif LC_KYBER_K == 3
#define LC_KYBER_ETA1 2
#define LC_KYBER_POLYCOMPRESSEDBYTES 128
#define LC_KYBER_POLYVECCOMPRESSEDBYTES (LC_KYBER_K * 320)
#elif LC_KYBER_K == 4
#define LC_KYBER_ETA1 2
#define LC_KYBER_POLYCOMPRESSEDBYTES 160
#define LC_KYBER_POLYVECCOMPRESSEDBYTES (LC_KYBER_K * 352)
#endif

#define LC_KYBER_ETA2 2

#define LC_KYBER_INDCPA_MSGBYTES (LC_KYBER_SYMBYTES)
#define LC_KYBER_INDCPA_PUBLICKEYBYTES                                         \
	(LC_KYBER_POLYVECBYTES + LC_KYBER_SYMBYTES)
#define LC_KYBER_INDCPA_SECRETKEYBYTES (LC_KYBER_POLYVECBYTES)
#define LC_KYBER_INDCPA_BYTES                                                  \
	(LC_KYBER_POLYVECCOMPRESSEDBYTES + LC_KYBER_POLYCOMPRESSEDBYTES)

/*
 * Sizes of the different Kyber buffer types.
 *
 * WARNING: Do not use these defines in your code. If you need the sizes of
 * the different variable sizes, use sizeof of the different variable structs
 * or use the different *_size functions offered below for the particular sizes
 * of a given parameter.
 */
#define LC_KYBER_PUBLICKEYBYTES (LC_KYBER_INDCPA_PUBLICKEYBYTES)
/* 32 bytes of additional space to save H(pk) */
#define LC_KYBER_SECRETKEYBYTES                                                \
	(LC_KYBER_INDCPA_SECRETKEYBYTES + LC_KYBER_INDCPA_PUBLICKEYBYTES +     \
	 2 * LC_KYBER_SYMBYTES)
#define LC_KYBER_CIPHERTEXTBYTES (LC_KYBER_INDCPA_BYTES)

#define LC_CRYPTO_SECRETKEYBYTES LC_KYBER_SECRETKEYBYTES
#define LC_CRYPTO_PUBLICKEYBYTES LC_KYBER_PUBLICKEYBYTES
#define LC_CRYPTO_CIPHERTEXTBYTES LC_KYBER_CIPHERTEXTBYTES
#define LC_CRYPTO_BYTES LC_KYBER_SSBYTES
/// \endcond

#ifndef __ASSEMBLER__
/**
 * General KEM API considerations:
 *
 * * all APIs starting with lc_kyber_512 / lc_kex_512 use Kyber-512
 * * all APIs starting with lc_kyber_768 / lc_kex_768 use Kyber-768
 * * all APIs starting with lc_kyber_1024 / lc_kex_1024 use Kyber-1024
 */

/************************************* KEM ************************************/
/**
 * @brief Kyber secret key
 */
struct @kyber_name@_sk {
	uint8_t sk[LC_KYBER_SECRETKEYBYTES];
};

/**
 * @brief Kyber public key
 */
struct @kyber_name@_pk {
	uint8_t pk[LC_KYBER_PUBLICKEYBYTES];
};

/**
 * @brief Kyber ciphertext
 */
struct @kyber_name@_ct {
	uint8_t ct[LC_CRYPTO_CIPHERTEXTBYTES];
};

/**
 * @brief Kyber shared secret
 */
struct @kyber_name@_ss {
	uint8_t ss[LC_KYBER_SSBYTES];
};

/**
 * @brief Return the size of the Kyber secret key.
 */
LC_PURE
static inline unsigned int @kyber_name@_sk_size(void)
{
	return lc_member_size(struct @kyber_name@_sk, sk);
}

/**
 * @brief Return the size of the Kyber public key.
 */
LC_PURE
static inline unsigned int @kyber_name@_pk_size(void)
{
	return lc_member_size(struct @kyber_name@_pk, pk);
}

/**
 * @brief Return the size of the Kyber ciphertext.
 */
LC_PURE
static inline unsigned int @kyber_name@_ct_size(void)
{
	return lc_member_size(struct @kyber_name@_ct, ct);
}

/**
 * @brief Return the size of the Kyber shared secret.
 */
LC_PURE
static inline unsigned int @kyber_name@_ss_size(void)
{
	return lc_member_size(struct @kyber_name@_ss, ss);
}

/**
 * @brief lc_kyber_keypair - Generates public and private key for
 *			     IND-CCA2-secure Kyber key encapsulation mechanism
 *
 * @param [out] pk pointer to already allocated output public key
 * @param [out] sk pointer to already allocated output private key
 * @param [in] rng_ctx pointer to seeded random number generator context
 *
 * @return 0 (success) or < 0 on error
 */
int @kyber_name@_keypair(struct @kyber_name@_pk *pk, struct @kyber_name@_sk *sk,
		     struct lc_rng_ctx *rng_ctx);

/**
 * @brief lc_kyber__keypair_from_seed - Generates Kyber public and private key
 *					from a given seed.
 *
 * The idea of the function is the allowance of FIPS 203 to maintain the seed
 * used to generate a key pair in lieu of maintaining a private key or the
 * key pair (which used much more memory). The seed must be treated equally
 * sensitive as a private key.
 *
 * The seed is generated by simply obtaining 64 bytes from a properly seeded
 * DRNG, i.e. the same way as a symmetric key would be generated.
 *
 * Compliant to the notation of FIPS 203 the following definition applies:
 *	seed = d || z
 *
 * @param [out] pk pointer to allocated output public key
 * @param [out] sk pointer to allocated output private key
 * @param [in] seed buffer with the seed data which must be exactly 64 bytes
 *		    in size
 * @param [in] seedlen length of the seed buffer
 *
 * @return 0 (success) or < 0 on error
 */
int @kyber_name@_keypair_from_seed(struct @kyber_name@_pk *pk,
				   struct @kyber_name@_sk *sk,
				   const uint8_t *seed, size_t seedlen);

/**
 * @brief Generates Kyber public from private key.
 *
 * @param [out] pk pointer to allocated output public key
 * @param [in] sk pointer private key
 *
 * @return 0 (success) or < 0 on error
 */
int @kyber_name@_pk_from_sk(struct @kyber_name@_pk *pk,
			    const struct @kyber_name@_sk *sk);

/**
 * @brief lc_kyber_enc - Key encapsulation
 *
 * Generates cipher text and shared secret for given public key.
 *
 * @param [out] ct pointer to output cipher text to used for decapsulation
 * @param [out] ss pointer to output shared secret that will be also produced
 *		   during decapsulation
 * @param [in] pk pointer to input public key
 *
 * Returns 0 (success) or < 0 on error
 */
int @kyber_name@_enc(struct @kyber_name@_ct *ct, struct @kyber_name@_ss *ss,
		 const struct @kyber_name@_pk *pk);

/**
 * @brief @kyber_name@_enc_kdf - Key encapsulation with KDF applied to shared secret
 *
 * Generates cipher text and shared secret for given public key. The shared
 * secret is derived from the Kyber SS using the KDF derived from the round 3
 * definition of Kyber:
 *
 *	SS <- KMAC256(K = Kyber-SS, X = Kyber-CT, L = requested SS length,
 *		      S = "Kyber KEM SS")
 *
 * @param [out] ct pointer to output cipher text to used for decapsulation
 * @param [out] ss pointer to output shared secret that will be also produced
 *		   during decapsulation
 * @param [in] ss_len length of shared secret to be generated
 * @param [in] pk pointer to input public key
 *
 * Returns 0 (success) or < 0 on error
 */
int @kyber_name@_enc_kdf(struct @kyber_name@_ct *ct, uint8_t *ss, size_t ss_len,
		     const struct @kyber_name@_pk *pk);

/**
 * @brief lc_kyber_dec - Key decapsulation
 *
 * Generates shared secret for given cipher text and private key
 *
 * @param [out] ss pointer to output shared secret that is the same as produced
 *		   during encapsulation
 * @param [in] ct pointer to input cipher text generated during encapsulation
 * @param [in] sk pointer to input private key
 *
 * @return 0
 *
 * On failure, ss will contain a pseudo-random value.
 */
int @kyber_name@_dec(struct @kyber_name@_ss *ss, const struct @kyber_name@_ct *ct,
		 const struct @kyber_name@_sk *sk);

/**
 * @brief lc_kyber_dec_kdf - Key decapsulation with KDF applied to shared secret
 *
 * Generates cipher text and shared secret for given private key. The shared
 * secret is derived from the Kyber SS using the KDF derived from the round 3
 * definition of Kyber:
 *
 *	SS <- KMAC256(K = Kyber-SS, X = Kyber-CT, L = requested SS length,
 *		      S = "Kyber KEM SS")
 *
 * @param [out] ss pointer to output shared secret that is the same as produced
 *		   during encapsulation
 * @param [in] ss_len length of shared secret to be generated
 * @param [in] ct pointer to input cipher text generated during encapsulation
 * @param [in] sk pointer to input private key
 *
 * @return 0
 *
 * On failure, ss will contain a pseudo-random value.
 */
int @kyber_name@_dec_kdf(uint8_t *ss, size_t ss_len, const struct @kyber_name@_ct *ct,
		     const struct @kyber_name@_sk *sk);


int @kyber_name@_iv_sk(const struct @kyber_name@_sk *sk);

/************************************* KEX ************************************/

/**
 * Unilaterally authenticated key exchange
 *
 * The key exchange provides a shared secret between two communication parties.
 * Only the initiator authenticates the key exchange with his private key.
 *
 * The idea is that the pk_r/sk_r key pair is a static key pair that is
 * generated and exchanged before the KEX handshake. For the unilaterally
 * authenticated key exchange, only the initiator uses the responder's public
 * key which implies that the initiator authenticates the responder.
 *```
 * 		Alice (initiator)		Bob (responder)
 *
 * Step 1					generate static keypair
 *						Result:
 *							public key pk_r
 *							secret key sk_r
 *
 * Step 2					send public key
 * 		pk_r <-------------------------	pk_r
 *
 * Step 3	initiate key exchange
 *		Result:
 *			Public key pk_e_i
 *			Cipher text ct_e_i
 *			KEM shared secret tk
 *			Secret key sk_e
 *
 * Step 4	send kex data
 *		Public key pk_e_i ------------>	Public key pk_e_i
 *		Cipher text ct_e_i ----------->	Cipher text ct_e_i
 *
 * Step 5					calculate shared secret
 *						Result:
 *							Cipher text ct_e_r
 *							Shared secret SS
 *
 * Step 6					send kex data
 *		Cipher text ct_e_r <-----------	Cipher text ct_e_r
 *
 * Step 7	calculate shared secret
 *		Result:
 * 			Shared secret SS
 *```
 */

/**
 * @brief lc_kex_uake_initiator_init - Initialize unilaterally authenticated
 *				       key exchange
 *
 * @param [out] pk_e_i initiator's ephemeral public key to be sent to the
 *		       responder
 * @param [out] ct_e_i initiator's ephemeral cipher text to be sent to the
 *		       responder
 * @param [out] tk KEM shared secret data to be used for the initiator's shared
 *		   secret generation
 * @param [out] sk_e initiator's ephemeral secret key to be used for the
 *		     initiator's shared secret generation
 * @param [in] pk_r responder's public key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_uake_initiator_init(struct @kyber_name@_pk *pk_e_i,
			       struct @kyber_name@_ct *ct_e_i,
			       struct @kyber_name@_ss *tk, struct @kyber_name@_sk *sk_e,
			       const struct @kyber_name@_pk *pk_r);

/**
 * @brief lc_kex_uake_responder_ss - Initiator's shared secret generation
 *
 * @param [out] ct_e_r responder's ephemeral cipher text to be sent to the
 *		       initiator
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] pk_e_i initiator's ephemeral public key
 * @param [in] ct_e_i initiator's ephemeral cipher text
 * @param [in] sk_r responder's secret key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_uake_responder_ss(struct @kyber_name@_ct *ct_e_r, uint8_t *shared_secret,
			     size_t shared_secret_len, const uint8_t *kdf_nonce,
			     size_t kdf_nonce_len,
			     const struct @kyber_name@_pk *pk_e_i,
			     const struct @kyber_name@_ct *ct_e_i,
			     const struct @kyber_name@_sk *sk_r);

/**
 * @brief lc_kex_uake_initiator_ss - Responder's shared secret generation
 *
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] ct_e_r responder's ephemeral cipher text
 * @param [in] tk KEM shared secret data that was generated during the
 *		  initiator's initialization
 * @param [in] sk_e initiator's ephemeral secret that was generated during the
 *		    initiator's initialization
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_uake_initiator_ss(uint8_t *shared_secret, size_t shared_secret_len,
			     const uint8_t *kdf_nonce, size_t kdf_nonce_len,
			     const struct @kyber_name@_ct *ct_e_r,
			     const struct @kyber_name@_ss *tk,
			     const struct @kyber_name@_sk *sk_e);

/**
 * Authenticated key exchange
 *
 * The key exchange provides a shared secret between two communication parties.
 * The initiator and responder authenticates the key exchange with their private
 * keys.
 *
 * The idea is that the pk_i/sk_i and pk_r/sk_r key pairs are static key pairs
 * that are generated and exchanged before the KEX handshake. For the
 * authenticated key exchange, both sides use the respective peer's public key
 * which implies either side authenticates the other end.
 *```
 * 		Alice (initiator)		Bob (responder)
 *
 * Step 1	generate static keypair		generate static keypair
 *		Result:				Result:
 *			public key pk_i			public key pk_r
 *			secret key sk_i			secret key sk_r
 *
 * Step 2	send public key			send public key
 * 		pk_r <-------------------------	pk_r
 *		pk_i -------------------------> pk_i
 *
 * Step 3	initiate key exchange
 *		Result:
 *			Public key pk_e_i
 *			Cipher text ct_e_i
 *			KEM shared secret tk
 *			Secret key sk_e
 *
 * Step 4	send kex data
 *		Public key pk_e_i ------------>	Public key pk_e_i
 *		Cipher text ct_e_i ----------->	Cipher text ct_e_i
 *
 * Step 5					calculate shared secret
 *						Result:
 *							Cipher text ct_e_r_1
 *							Cipher text ct_e_r_2
 *							Shared secret SS
 *
 * Step 6					send kex data
 *		Cipher text ct_e_r_1 <---------	Cipher text ct_e_r_1
 *		Cipher text ct_e_r_2 <---------	Cipher text ct_e_r_2
 *
 * Step 7	calculate shared secret
 *		Result:
 * 			Shared secret SS
 *```
 */

/**
 * @brief lc_kex_ake_initiator_init - Initialize authenticated key exchange
 *
 * @param [out] pk_e_i initiator's ephemeral public key to be sent to the
 *		       responder
 * @param [out] ct_e_i initiator's ephemeral cipher text to be sent to the
 *		       responder
 * @param [out] tk KEM shared secret data to be used for the initiator's shared
 *		   secret generation
 * @param [out] sk_e initiator's ephemeral secret key to be used for the
 *		     initiator's shared secret generation
 * @param [in] pk_r responder's public key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_ake_initiator_init(struct @kyber_name@_pk *pk_e_i,
			      struct @kyber_name@_ct *ct_e_i,
			      struct @kyber_name@_ss *tk, struct @kyber_name@_sk *sk_e,
			      const struct @kyber_name@_pk *pk_r);

/**
 * @brief lc_kex_ake_responder_ss - Initiator's shared secret generation
 *
 * @param [out] ct_e_r_1 responder's ephemeral cipher text to be sent to the
 *			 initator
 * @param [out] ct_e_r_2 responder's ephemeral cipher text to be sent to the
 *			 initator
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] pk_e_i initator's ephemeral public key
 * @param [in] ct_e_i initator's ephemeral cipher text
 * @param [in] sk_r responder's secret key
 * @param [in] pk_i initator's public key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_ake_responder_ss(struct @kyber_name@_ct *ct_e_r_1,
			    struct @kyber_name@_ct *ct_e_r_2,
			    uint8_t *shared_secret, size_t shared_secret_len,
			    const uint8_t *kdf_nonce, size_t kdf_nonce_len,
			    const struct @kyber_name@_pk *pk_e_i,
			    const struct @kyber_name@_ct *ct_e_i,
			    const struct @kyber_name@_sk *sk_r,
			    const struct @kyber_name@_pk *pk_i);

/**
 * @brief lc_kex_ake_initiator_ss - Responder's shared secret generation
 *
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] ct_e_r_1 responder's ephemeral cipher text
 * @param [in] ct_e_r_2 responder's ephemeral cipher text
 * @param [in] tk KEM shared secret data that was generated during the
 *		  initator's initialization
 * @param [in] sk_e initator's ephemeral secret that was generated during the
 *		    initator's initialization
 * @param [in] sk_i initator's secret key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_ake_initiator_ss(uint8_t *shared_secret, size_t shared_secret_len,
			    const uint8_t *kdf_nonce, size_t kdf_nonce_len,
			    const struct @kyber_name@_ct *ct_e_r_1,
			    const struct @kyber_name@_ct *ct_e_r_2,
			    const struct @kyber_name@_ss *tk,
			    const struct @kyber_name@_sk *sk_e,
			    const struct @kyber_name@_sk *sk_i);

/************************************* IES ************************************/
/* Macro set during leancrypto compile time for target platform */
#mesondefine LC_KYBER_IES
#ifdef LC_KYBER_IES

#include "lc_aead.h"

/**
 * @brief lc_kyber_ies_enc - KyberIES encryption oneshot
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] pk Kyber public key of data owner
 * @param [out] ct Kyber ciphertext to be sent to the decryption operation
 * @param [in] plaintext Plaintext data to be encrypted
 * @param [out] ciphertext Buffer of equal size as plaintext that will be filled
 *			   with the encryption result
 * @param [in] datalen Length of the plaintext buffer
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 * @param [out] tag Buffer that will be filled with the authentication tag
 * @param [in] taglen Length of the tag buffer
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 *
 * @return 0 on success, < 0 on error
 */
int @kyber_name@_ies_enc(const struct @kyber_name@_pk *pk, struct @kyber_name@_ct *ct,
		     const uint8_t *plaintext, uint8_t *ciphertext,
		     size_t datalen, const uint8_t *aad, size_t aadlen,
		     uint8_t *tag, size_t taglen, struct lc_aead_ctx *aead);

/**
 * @brief lc_kyber_ies_enc_init - KyberIES encryption stream operation
 *				  initialization
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * The aead context is initialized such that it can be used with
 * lc_kyber_ies_enc_[update|final].
 *
 * @param [out] aead Allocated AEAD algorithm - the caller only needs to provide
 *		     an allocated but otherwise unused instance of an AEAD
 *		     algorithm. This allows the caller to define the AEAD
 *		     algorithm type. The caller must zeroize and release the
 *		     context after completion.
 * @param [in] pk Kyber public key of data owner
 * @param [out] ct Kyber ciphertext to be sent to the decryption operation
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 *
 * @return 0 on success, < 0 on error
 */
int @kyber_name@_ies_enc_init(struct lc_aead_ctx *aead,
			  const struct @kyber_name@_pk *pk, struct @kyber_name@_ct *ct,
			  const uint8_t *aad, size_t aadlen);

/**
 * @brief lc_kyber_ies_enc_update - KyberIES encryption stream operation
 *				    add more data
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [in] plaintext Plaintext data to be encrypted
 * @param [out] ciphertext Buffer of equal size as plaintext that will be filled
 *			   with the encryption result
 * @param [in] datalen Length of the plaintext buffer
 *
 * @return 0 on success, < 0 on error
 */
static inline int @kyber_name@_ies_enc_update(struct lc_aead_ctx *aead,
					  const uint8_t *plaintext,
					  uint8_t *ciphertext, size_t datalen)
{
	return lc_aead_enc_update(aead, plaintext, ciphertext, datalen);
}

/**
 * @brief lc_kyber_ies_enc_final - KyberIES encryption stream operation
 *				   finalization / integrity test
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [out] tag Buffer that will be filled with the authentication tag
 * @param [in] taglen Length of the tag buffer
 *
 * @return 0 on success, < 0 on error
 */
static inline int @kyber_name@_ies_enc_final(struct lc_aead_ctx *aead,
					 uint8_t *tag, size_t taglen)
{
	return lc_aead_enc_final(aead, tag, taglen);
}

/**
 * @brief lc_kyber_ies_dec - KyberIES decryption oneshot
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] sk Kyber secret key of data owner
 * @param [in] ct Kyber ciphertext received from the encryption operation
 * @param [in] ciphertext Ciphertext data to be encrypted
 * @param [out] plaintext Buffer of equal size as ciphertext that will be
 *			   filled with the decryption result
 * @param [in] datalen Length of the ciphertext buffer
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 * @param [in] tag Buffer with the authentication tag
 * @param [in] taglen Length of the tag buffer
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @return 0 on success, < 0 on error (-EBADMSG on integrity error)
 */
int @kyber_name@_ies_dec(const struct @kyber_name@_sk *sk, const struct @kyber_name@_ct *ct,
		     const uint8_t *ciphertext, uint8_t *plaintext,
		     size_t datalen, const uint8_t *aad, size_t aadlen,
		     const uint8_t *tag, size_t taglen,
		     struct lc_aead_ctx *aead);

/**
 * @brief lc_kyber_ies_dec_init - KyberIES decryption stream operation
 *				  initialization
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * The aead context is initialized such that it can be used with
 * @kyber_name@_ies_dec_[update|final].
 *
 * @param [out] aead Allocated AEAD algorithm - the caller only needs to provide
 *		     an allocated but otherwise unused instance of an AEAD
 *		     algorithm. This allows the caller to define the AEAD
 *		     algorithm type. The caller must zeroize and release the
 *		     context after completion.
 * @param [in] sk Kyber secret key of data owner
 * @param [in] ct Kyber ciphertext received from the encryption operation
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 * @return 0 on success, < 0 on error
 */
int @kyber_name@_ies_dec_init(struct lc_aead_ctx *aead,
			  const struct @kyber_name@_sk *sk,
			  const struct @kyber_name@_ct *ct,
			  const uint8_t *aad, size_t aadlen);

/**
 * @brief lc_kyber_ies_dec_update - KyberIES decryption stream operation
 *				    add more data
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [in] ciphertext Ciphertext data to be encrypted
 * @param [out] plaintext Buffer of equal size as ciphertext that will be
 *			   filled with the decryption result
 * @param [in] datalen Length of the ciphertext buffer
 *
 * @return 0 on success, < 0 on error
 */
static inline int @kyber_name@_ies_dec_update(struct lc_aead_ctx *aead,
					  const uint8_t *ciphertext,
					  uint8_t *plaintext, size_t datalen)
{
	return lc_aead_dec_update(aead, ciphertext, plaintext, datalen);
}

/**
 * @brief lc_kyber_ies_dec_final - KyberIES decryption stream operation
 *				   finalization / integrity test
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [in] tag Buffer with the authentication tag
 * @param [in] taglen Length of the tag buffer
 *
 * @return 0 on success, < 0 on error (-EBADMSG on integrity error)
 */
static inline int @kyber_name@_ies_dec_final(struct lc_aead_ctx *aead,
					 const uint8_t *tag, size_t taglen)
{
	return lc_aead_dec_final(aead, tag, taglen);
}

#endif /* LC_KYBER_IES */

/****************************** Kyber X25519 KEM ******************************/

/*
 * The double KEM implements Kyber KEM together with the X25519 elliptic curve
 * KEX. The use is identical as the Kyber KEM. The only difference is that
 * the transmitted pk and ct has a different content.
 */
/* Macro set during leancrypto compile time for target platform */
#mesondefine LC_KYBER_X25519_KEM
#ifdef LC_KYBER_X25519_KEM

#include "lc_x25519.h"

/**
 * @brief Kyber secret key
 */
struct @kyber_name@_x25519_sk {
	struct @kyber_name@_sk sk;
	struct lc_x25519_sk sk_x25519;
};

/**
 * @brief Kyber public key
 */
struct @kyber_name@_x25519_pk {
	struct @kyber_name@_pk pk;
	struct lc_x25519_pk pk_x25519;
};

/**
 * @brief Kyber ciphertext
 */
struct @kyber_name@_x25519_ct {
	struct @kyber_name@_ct ct;
	struct lc_x25519_pk pk_x25519;
};

/**
 * @brief Kyber shared secret
 */
struct @kyber_name@_x25519_ss {
	struct @kyber_name@_ss ss;
	struct lc_x25519_ss ss_x25519;
};

/**
 * @brief lc_kyber_x25519_keypair - Generates public and private key for
 *			     	    IND-CCA2-secure Kyber key encapsulation
 *				    mechanism
 *
 * @param [out] pk pointer to already allocated output public key
 * @param [out] sk pointer to already allocated output private key
 * @param [in] rng_ctx pointer to seeded random number generator context
 *
 * @return 0 (success) or < 0 on error
 */
int @kyber_name@_x25519_keypair(struct @kyber_name@_x25519_pk *pk,
			    struct @kyber_name@_x25519_sk *sk,
			    struct lc_rng_ctx *rng_ctx);

/**
 * @brief Generates Kyber public from private key.
 *
 * @param [out] pk pointer to allocated output public key
 * @param [in] sk pointer private key
 *
 * @return 0 (success) or < 0 on error
 */
int @kyber_name@_x25519_pk_from_sk(struct @kyber_name@_x25519_pk *pk,
				   const struct @kyber_name@_x25519_sk *sk);

/**
 * @brief lc_kyber_x25519_enc_kdf - Key encapsulation with KDF applied to shared
 *			      	    secret
 *
 * Generates cipher text and shared secret for given public key. The shared
 * secret is derived from the Kyber SS using the KDF derived from the round 3
 * definition of Kyber:
 *
 *	SS <- KMAC256(K = Kyber-SS || X25519-SS, X = Kyber-CT,
 *		      L = requested SS length, S = "Kyber KEM Double SS")
 *
 * NOTE: The concatenatino of Kyber-SS || ECC-SS complies with SP800-56C rev 2
 * chapter 2 defining the hybrid shared secret of the form Z' = Z || T where
 * Z is the "standard shared secret" from Kyber followed by the auxiliary
 * shared secret T that has been generated by some other method.
 *
 * @param [out] ct pointer to output cipher text to used for decapsulation
 * @param [out] ss pointer to output shared secret that will be also produced
 *		   during decapsulation
 * @param [in] ss_len length of shared secret to be generated
 * @param [in] pk pointer to input public key
 *
 * Returns 0 (success) or < 0 on error
 */
int @kyber_name@_x25519_enc_kdf(struct @kyber_name@_x25519_ct *ct, uint8_t *ss,
			    size_t ss_len, const struct @kyber_name@_x25519_pk *pk);

/**
 * @brief lc_kyber_x25519_dec_kdf - Key decapsulation with KDF applied to shared
 *			       	    secret
 *
 * Generates cipher text and shared secret for given private key. The shared
 * secret is derived from the Kyber SS using the KDF derived from the round 3
 * definition of Kyber:
 *
 *	SS <- KMAC256(K = Kyber-SS || X25519-SS, X = Kyber-CT,
 *		      L = requested SS length, S = "Kyber KEM Double SS")
 *
 * @param [out] ss pointer to output shared secret that is the same as produced
 *		   during encapsulation
 * @param [in] ss_len length of shared secret to be generated
 * @param [in] ct pointer to input cipher text generated during encapsulation
 * @param [in] sk pointer to input private key
 *
 * @return 0
 *
 * On failure, ss will contain a pseudo-random value.
 */
int @kyber_name@_x25519_dec_kdf(uint8_t *ss, size_t ss_len,
			    const struct @kyber_name@_x25519_ct *ct,
			    const struct @kyber_name@_x25519_sk *sk);

/****************************** Kyber X25519 KEX ******************************/

/**
 * @brief lc_kex_x25519_uake_initiator_init - Initialize unilaterally
 *					      authenticated key exchange
 *
 * @param [out] pk_e_i initiator's ephemeral public key to be sent to the
 *		       responder
 * @param [out] ct_e_i initiator's ephemeral cipher text to be sent to the
 *		       responder
 * @param [out] tk KEM shared secret data to be used for the initiator's shared
 *		   secret generation
 * @param [out] sk_e initiator's ephemeral secret key to be used for the
 *		     initiator's shared secret generation
 * @param [in] pk_r responder's public key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x25519_uake_initiator_init(struct @kyber_name@_x25519_pk *pk_e_i,
				      struct @kyber_name@_x25519_ct *ct_e_i,
				      struct @kyber_name@_x25519_ss *tk,
				      struct @kyber_name@_x25519_sk *sk_e,
				      const struct @kyber_name@_x25519_pk *pk_r);

/**
 * @brief lc_kex_x25519_uake_responder_ss - Initiator's shared secret generation
 *
 * @param [out] ct_e_r responder's ephemeral cipher text to be sent to the
 *		       initiator
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] pk_e_i initiator's ephemeral public key
 * @param [in] ct_e_i initiator's ephemeral cipher text
 * @param [in] sk_r responder's secret key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x25519_uake_responder_ss(struct @kyber_name@_x25519_ct *ct_e_r,
				    uint8_t *shared_secret,
				    size_t shared_secret_len,
				    const uint8_t *kdf_nonce,
				    size_t kdf_nonce_len,
				    const struct @kyber_name@_x25519_pk *pk_e_i,
				    const struct @kyber_name@_x25519_ct *ct_e_i,
				    const struct @kyber_name@_x25519_sk *sk_r);

/**
 * @brief lc_kex_x25519_uake_initiator_ss - Responder's shared secret generation
 *
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] ct_e_r responder's ephemeral cipher text
 * @param [in] tk KEM shared secret data that was generated during the
 *		  initiator's initialization
 * @param [in] sk_e initiator's ephemeral secret that was generated during the
 *		    initiator's initialization
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x25519_uake_initiator_ss(uint8_t *shared_secret,
				    size_t shared_secret_len,
				    const uint8_t *kdf_nonce,
				    size_t kdf_nonce_len,
				    const struct @kyber_name@_x25519_ct *ct_e_r,
				    const struct @kyber_name@_x25519_ss *tk,
				    const struct @kyber_name@_x25519_sk *sk_e);

/**
 * @brief lc_kex_x25519_ake_initiator_init - Initialize authenticated key
 *					     exchange
 *
 * @param [out] pk_e_i initiator's ephemeral public key to be sent to the
 *		       responder
 * @param [out] ct_e_i initiator's ephemeral cipher text to be sent to the
 *		       responder
 * @param [out] tk KEM shared secret data to be used for the initiator's shared
 *		   secret generation
 * @param [out] sk_e initiator's ephemeral secret key to be used for the
 *		     initiator's shared secret generation
 * @param [in] pk_r responder's public key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x25519_ake_initiator_init(struct @kyber_name@_x25519_pk *pk_e_i,
				     struct @kyber_name@_x25519_ct *ct_e_i,
				     struct @kyber_name@_x25519_ss *tk,
				     struct @kyber_name@_x25519_sk *sk_e,
				     const struct @kyber_name@_x25519_pk *pk_r);

/**
 * @brief lc_kex_x25519_ake_responder_ss - Initiator's shared secret generation
 *
 * @param [out] ct_e_r_1 responder's ephemeral cipher text to be sent to the
 *			 initator
 * @param [out] ct_e_r_2 responder's ephemeral cipher text to be sent to the
 *			 initator
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] pk_e_i initator's ephemeral public key
 * @param [in] ct_e_i initator's ephemeral cipher text
 * @param [in] sk_r responder's secret key
 * @param [in] pk_i initator's public key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x25519_ake_responder_ss(struct @kyber_name@_x25519_ct *ct_e_r_1,
				   struct @kyber_name@_x25519_ct *ct_e_r_2,
				   uint8_t *shared_secret,
				   size_t shared_secret_len,
				   const uint8_t *kdf_nonce,
				   size_t kdf_nonce_len,
				   const struct @kyber_name@_x25519_pk *pk_e_i,
				   const struct @kyber_name@_x25519_ct *ct_e_i,
				   const struct @kyber_name@_x25519_sk *sk_r,
				   const struct @kyber_name@_x25519_pk *pk_i);

/**
 * @brief lc_kex_x25519_ake_initiator_ss - Responder's shared secret generation
 *
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] ct_e_r_1 responder's ephemeral cipher text
 * @param [in] ct_e_r_2 responder's ephemeral cipher text
 * @param [in] tk KEM shared secret data that was generated during the
 *		  initator's initialization
 * @param [in] sk_e initator's ephemeral secret that was generated during the
 *		    initator's initialization
 * @param [in] sk_i initator's secret key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x25519_ake_initiator_ss(uint8_t *shared_secret,
				   size_t shared_secret_len,
				   const uint8_t *kdf_nonce,
				   size_t kdf_nonce_len,
				   const struct @kyber_name@_x25519_ct *ct_e_r_1,
				   const struct @kyber_name@_x25519_ct *ct_e_r_2,
				   const struct @kyber_name@_x25519_ss *tk,
				   const struct @kyber_name@_x25519_sk *sk_e,
				   const struct @kyber_name@_x25519_sk *sk_i);

/****************************** Kyber X25519 IES ******************************/

#ifdef LC_KYBER_IES

/**
 * @brief lc_kyber_x25519_ies_enc - KyberIES encryption oneshot
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] pk Kyber public key of data owner
 * @param [out] ct Kyber ciphertext to be sent to the decryption operation
 * @param [in] plaintext Plaintext data to be encrypted
 * @param [out] ciphertext Buffer of equal size as plaintext that will be filled
 *			   with the encryption result
 * @param [in] datalen Length of the plaintext buffer
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 * @param [out] tag Buffer that will be filled with the authentication tag
 * @param [in] taglen Length of the tag buffer
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 *
 * @return 0 on success, < 0 on error
 */
int @kyber_name@_x25519_ies_enc(const struct @kyber_name@_x25519_pk *pk,
			    struct @kyber_name@_x25519_ct *ct,
			    const uint8_t *plaintext, uint8_t *ciphertext,
			    size_t datalen, const uint8_t *aad, size_t aadlen,
			    uint8_t *tag, size_t taglen,
			    struct lc_aead_ctx *aead);

/**
 * @brief lc_kyber_x25519_ies_enc_init - KyberIES encryption stream operation
 *				 	 initialization
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * The aead context is initialized such that it can be used with
 * lc_kyber_x25519_ies_enc_[update|final].
 *
 * @param [out] aead Allocated AEAD algorithm - the caller only needs to provide
 *		     an allocated but otherwise unused instance of an AEAD
 *		     algorithm. This allows the caller to define the AEAD
 *		     algorithm type. The caller must zeroize and release the
 *		     context after completion.
 * @param [in] pk Kyber public key of data owner
 * @param [out] ct Kyber ciphertext to be sent to the decryption operation
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 *
 * @return 0 on success, < 0 on error
 */
int @kyber_name@_x25519_ies_enc_init(struct lc_aead_ctx *aead,
				 const struct @kyber_name@_x25519_pk *pk,
				 struct @kyber_name@_x25519_ct *ct,
				 const uint8_t *aad, size_t aadlen);

/**
 * @brief lc_kyber_x25519_ies_enc_update - KyberIES encryption stream operation
 *				    	   add more data
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [in] plaintext Plaintext data to be encrypted
 * @param [out] ciphertext Buffer of equal size as plaintext that will be filled
 *			   with the encryption result
 * @param [in] datalen Length of the plaintext buffer
 */
static inline int @kyber_name@_x25519_ies_enc_update(struct lc_aead_ctx *aead,
						 const uint8_t *plaintext,
						 uint8_t *ciphertext,
						 size_t datalen)
{
	return lc_aead_enc_update(aead, plaintext, ciphertext, datalen);
}

/**
 * @brief lc_kyber_x25519_ies_enc_final - KyberIES encryption stream operation
 *				 	  finalization / integrity test
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [out] tag Buffer that will be filled with the authentication tag
 * @param [in] taglen Length of the tag buffer
 *
 * @return 0 on success, < 0 on error
 */
static inline int @kyber_name@_x25519_ies_enc_final(struct lc_aead_ctx *aead,
						uint8_t *tag, size_t taglen)
{
	return lc_aead_enc_final(aead, tag, taglen);
}

/**
 * @brief lc_kyber_x25519_ies_dec - KyberIES decryption oneshot
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] sk Kyber secret key of data owner
 * @param [in] ct Kyber ciphertext received from the encryption operation
 * @param [in] ciphertext Ciphertext data to be encrypted
 * @param [out] plaintext Buffer of equal size as ciphertext that will be
 *			   filled with the decryption result
 * @param [in] datalen Length of the ciphertext buffer
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 * @param [in] tag Buffer with the authentication tag
 * @param [in] taglen Length of the tag buffer
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 *
 * @return 0 on success, < 0 on error (-EBADMSG on integrity error)
 */
int @kyber_name@_x25519_ies_dec(const struct @kyber_name@_x25519_sk *sk,
			    const struct @kyber_name@_x25519_ct *ct,
			    const uint8_t *ciphertext, uint8_t *plaintext,
			    size_t datalen, const uint8_t *aad, size_t aadlen,
			    const uint8_t *tag, size_t taglen,
			    struct lc_aead_ctx *aead);

/**
 * @brief lc_kyber_x25519_ies_dec_init - KyberIES decryption stream operation
 *					 initialization
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * The aead context is initialized such that it can be used with
 * lc_kyber_x25519_ies_dec_[update|final].
 *
 * @param [out] aead Allocated AEAD algorithm - the caller only needs to provide
 *		     an allocated but otherwise unused instance of an AEAD
 *		     algorithm. This allows the caller to define the AEAD
 *		     algorithm type. The caller must zeroize and release the
 *		     context after completion.
 * @param [in] sk Kyber secret key of data owner
 * @param [in] ct Kyber ciphertext received from the encryption operation
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 *
 * @return 0 on success, < 0 on error
 */
int @kyber_name@_x25519_ies_dec_init(struct lc_aead_ctx *aead,
				 const struct @kyber_name@_x25519_sk *sk,
				 const struct @kyber_name@_x25519_ct *ct,
				 const uint8_t *aad, size_t aadlen);

/**
 * @brief lc_kyber_x25519_ies_dec_update - KyberIES decryption stream operation
 *				  	   add more data
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [in] ciphertext Ciphertext data to be encrypted
 * @param [out] plaintext Buffer of equal size as ciphertext that will be
 *			   filled with the decryption result
 * @param [in] datalen Length of the ciphertext buffer
 *
 * @return 0 on success, < 0 on error
 */
static inline int @kyber_name@_x25519_ies_dec_update(struct lc_aead_ctx *aead,
						 const uint8_t *ciphertext,
						 uint8_t *plaintext,
						 size_t datalen)
{
	return lc_aead_dec_update(aead, ciphertext, plaintext, datalen);
}

/**
 * @brief lc_kyber	_x25519_ies_dec_final - KyberIES decryption stream operation
 *				  	  finalization / integrity test
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [in] tag Buffer with the authentication tag
 * @param [in] taglen Length of the tag buffer
 *
 * @return 0 on success, < 0 on error (-EBADMSG on integrity error)
 */
static inline int @kyber_name@_x25519_ies_dec_final(struct lc_aead_ctx *aead,
						const uint8_t *tag,
						size_t taglen)
{
	return lc_aead_dec_final(aead, tag, taglen);
}

#endif /* LC_KYBER_IES */

#endif /* LC_KYBER_X25519_KEM */

/****************************** Kyber X448 KEM ******************************/

/*
 * The double KEM implements Kyber KEM together with the X448 elliptic curve
 * KEX. The use is identical as the Kyber KEM. The only difference is that
 * the transmitted pk and ct has a different content.
 */
/* Macro set during leancrypto compile time for target platform */
#mesondefine LC_KYBER_X448_KEM
#ifdef LC_KYBER_X448_KEM

#include "lc_x448.h"

/**
 * @brief Kyber secret key
 */
struct @kyber_name@_x448_sk {
	struct @kyber_name@_sk sk;
	struct lc_x448_sk sk_x448;
};

/**
 * @brief Kyber public key
 */
struct @kyber_name@_x448_pk {
	struct @kyber_name@_pk pk;
	struct lc_x448_pk pk_x448;
};

/**
 * @brief Kyber ciphertext
 */
struct @kyber_name@_x448_ct {
	struct @kyber_name@_ct ct;
	struct lc_x448_pk pk_x448;
};

/**
 * @brief Kyber shared secret
 */
struct @kyber_name@_x448_ss {
	struct @kyber_name@_ss ss;
	struct lc_x448_ss ss_x448;
};

/**
 * @brief lc_kyber_x448_keypair - Generates public and private key for
 *			     	    IND-CCA2-secure Kyber key encapsulation
 *				    mechanism
 *
 * @param [out] pk pointer to already allocated output public key
 * @param [out] sk pointer to already allocated output private key
 * @param [in] rng_ctx pointer to seeded random number generator context
 *
 * @return 0 (success) or < 0 on error
 */
int @kyber_name@_x448_keypair(struct @kyber_name@_x448_pk *pk,
			    struct @kyber_name@_x448_sk *sk,
			    struct lc_rng_ctx *rng_ctx);

/**
 * @brief Generates Kyber public from private key.
 *
 * @param [out] pk pointer to allocated output public key
 * @param [in] sk pointer private key
 *
 * @return 0 (success) or < 0 on error
 */
int @kyber_name@_x448_pk_from_sk(struct @kyber_name@_x448_pk *pk,
				 const struct @kyber_name@_x448_sk *sk);

/**
 * @brief lc_kyber_x448_enc_kdf - Key encapsulation with KDF applied to shared
 *			      	    secret
 *
 * Generates cipher text and shared secret for given public key. The shared
 * secret is derived from the Kyber SS using the KDF derived from the round 3
 * definition of Kyber:
 *
 *	SS <- KMAC256(K = Kyber-SS || X448-SS, X = Kyber-CT,
 *		      L = requested SS length, S = "Kyber KEM Double SS")
 *
 * NOTE: The concatenatino of Kyber-SS || ECC-SS complies with SP800-56C rev 2
 * chapter 2 defining the hybrid shared secret of the form Z' = Z || T where
 * Z is the "standard shared secret" from Kyber followed by the auxiliary
 * shared secret T that has been generated by some other method.
 *
 * @param [out] ct pointer to output cipher text to used for decapsulation
 * @param [out] ss pointer to output shared secret that will be also produced
 *		   during decapsulation
 * @param [in] ss_len length of shared secret to be generated
 * @param [in] pk pointer to input public key
 *
 * Returns 0 (success) or < 0 on error
 */
int @kyber_name@_x448_enc_kdf(struct @kyber_name@_x448_ct *ct, uint8_t *ss,
			    size_t ss_len, const struct @kyber_name@_x448_pk *pk);

/**
 * @brief lc_kyber_x448_dec_kdf - Key decapsulation with KDF applied to shared
 *			       	    secret
 *
 * Generates cipher text and shared secret for given private key. The shared
 * secret is derived from the Kyber SS using the KDF derived from the round 3
 * definition of Kyber:
 *
 *	SS <- KMAC256(K = Kyber-SS || X448-SS, X = Kyber-CT,
 *		      L = requested SS length, S = "Kyber KEM Double SS")
 *
 * @param [out] ss pointer to output shared secret that is the same as produced
 *		   during encapsulation
 * @param [in] ss_len length of shared secret to be generated
 * @param [in] ct pointer to input cipher text generated during encapsulation
 * @param [in] sk pointer to input private key
 *
 * @return 0
 *
 * On failure, ss will contain a pseudo-random value.
 */
int @kyber_name@_x448_dec_kdf(uint8_t *ss, size_t ss_len,
			    const struct @kyber_name@_x448_ct *ct,
			    const struct @kyber_name@_x448_sk *sk);

/****************************** Kyber X448 KEX ******************************/

/**
 * @brief lc_kex_x448_uake_initiator_init - Initialize unilaterally
 *					      authenticated key exchange
 *
 * @param [out] pk_e_i initiator's ephemeral public key to be sent to the
 *		       responder
 * @param [out] ct_e_i initiator's ephemeral cipher text to be sent to the
 *		       responder
 * @param [out] tk KEM shared secret data to be used for the initiator's shared
 *		   secret generation
 * @param [out] sk_e initiator's ephemeral secret key to be used for the
 *		     initiator's shared secret generation
 * @param [in] pk_r responder's public key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x448_uake_initiator_init(struct @kyber_name@_x448_pk *pk_e_i,
				      struct @kyber_name@_x448_ct *ct_e_i,
				      struct @kyber_name@_x448_ss *tk,
				      struct @kyber_name@_x448_sk *sk_e,
				      const struct @kyber_name@_x448_pk *pk_r);

/**
 * @brief lc_kex_x448_uake_responder_ss - Initiator's shared secret generation
 *
 * @param [out] ct_e_r responder's ephemeral cipher text to be sent to the
 *		       initiator
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] pk_e_i initiator's ephemeral public key
 * @param [in] ct_e_i initiator's ephemeral cipher text
 * @param [in] sk_r responder's secret key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x448_uake_responder_ss(struct @kyber_name@_x448_ct *ct_e_r,
				    uint8_t *shared_secret,
				    size_t shared_secret_len,
				    const uint8_t *kdf_nonce,
				    size_t kdf_nonce_len,
				    const struct @kyber_name@_x448_pk *pk_e_i,
				    const struct @kyber_name@_x448_ct *ct_e_i,
				    const struct @kyber_name@_x448_sk *sk_r);

/**
 * @brief lc_kex_x448_uake_initiator_ss - Responder's shared secret generation
 *
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] ct_e_r responder's ephemeral cipher text
 * @param [in] tk KEM shared secret data that was generated during the
 *		  initiator's initialization
 * @param [in] sk_e initiator's ephemeral secret that was generated during the
 *		    initiator's initialization
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x448_uake_initiator_ss(uint8_t *shared_secret,
				    size_t shared_secret_len,
				    const uint8_t *kdf_nonce,
				    size_t kdf_nonce_len,
				    const struct @kyber_name@_x448_ct *ct_e_r,
				    const struct @kyber_name@_x448_ss *tk,
				    const struct @kyber_name@_x448_sk *sk_e);

/**
 * @brief lc_kex_x448_ake_initiator_init - Initialize authenticated key
 *					     exchange
 *
 * @param [out] pk_e_i initiator's ephemeral public key to be sent to the
 *		       responder
 * @param [out] ct_e_i initiator's ephemeral cipher text to be sent to the
 *		       responder
 * @param [out] tk KEM shared secret data to be used for the initiator's shared
 *		   secret generation
 * @param [out] sk_e initiator's ephemeral secret key to be used for the
 *		     initiator's shared secret generation
 * @param [in] pk_r responder's public key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x448_ake_initiator_init(struct @kyber_name@_x448_pk *pk_e_i,
				     struct @kyber_name@_x448_ct *ct_e_i,
				     struct @kyber_name@_x448_ss *tk,
				     struct @kyber_name@_x448_sk *sk_e,
				     const struct @kyber_name@_x448_pk *pk_r);

/**
 * @brief lc_kex_x448_ake_responder_ss - Initiator's shared secret generation
 *
 * @param [out] ct_e_r_1 responder's ephemeral cipher text to be sent to the
 *			 initator
 * @param [out] ct_e_r_2 responder's ephemeral cipher text to be sent to the
 *			 initator
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] pk_e_i initator's ephemeral public key
 * @param [in] ct_e_i initator's ephemeral cipher text
 * @param [in] sk_r responder's secret key
 * @param [in] pk_i initator's public key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x448_ake_responder_ss(struct @kyber_name@_x448_ct *ct_e_r_1,
				   struct @kyber_name@_x448_ct *ct_e_r_2,
				   uint8_t *shared_secret,
				   size_t shared_secret_len,
				   const uint8_t *kdf_nonce,
				   size_t kdf_nonce_len,
				   const struct @kyber_name@_x448_pk *pk_e_i,
				   const struct @kyber_name@_x448_ct *ct_e_i,
				   const struct @kyber_name@_x448_sk *sk_r,
				   const struct @kyber_name@_x448_pk *pk_i);

/**
 * @brief lc_kex_x448_ake_initiator_ss - Responder's shared secret generation
 *
 * @param [out] shared_secret Shared secret between initiator and responder
 * @param [in] shared_secret_len Requested size of the shared secret
 * @param [in] kdf_nonce An optional nonce that is concatenated at the end of
 *			 the Kyber KEX-generated data to be inserted into
 *			 the KDF. If not required, use NULL.
 * @param [in] kdf_nonce_len Length of the kdf_nonce.
 * @param [in] ct_e_r_1 responder's ephemeral cipher text
 * @param [in] ct_e_r_2 responder's ephemeral cipher text
 * @param [in] tk KEM shared secret data that was generated during the
 *		  initator's initialization
 * @param [in] sk_e initator's ephemeral secret that was generated during the
 *		    initator's initialization
 * @param [in] sk_i initator's secret key
 *
 * @return 0 (success) or < 0 on error
 */
int @kex_name@_x448_ake_initiator_ss(uint8_t *shared_secret,
				   size_t shared_secret_len,
				   const uint8_t *kdf_nonce,
				   size_t kdf_nonce_len,
				   const struct @kyber_name@_x448_ct *ct_e_r_1,
				   const struct @kyber_name@_x448_ct *ct_e_r_2,
				   const struct @kyber_name@_x448_ss *tk,
				   const struct @kyber_name@_x448_sk *sk_e,
				   const struct @kyber_name@_x448_sk *sk_i);

/****************************** Kyber X448 IES ******************************/

#ifdef LC_KYBER_IES

/**
 * @brief lc_kyber_x448_ies_enc - KyberIES encryption oneshot
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] pk Kyber public key of data owner
 * @param [out] ct Kyber ciphertext to be sent to the decryption operation
 * @param [in] plaintext Plaintext data to be encrypted
 * @param [out] ciphertext Buffer of equal size as plaintext that will be filled
 *			   with the encryption result
 * @param [in] datalen Length of the plaintext buffer
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 * @param [out] tag Buffer that will be filled with the authentication tag
 * @param [in] taglen Length of the tag buffer
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 *
 * @return 0 on success, < 0 on error
 */
int @kyber_name@_x448_ies_enc(const struct @kyber_name@_x448_pk *pk,
			    struct @kyber_name@_x448_ct *ct,
			    const uint8_t *plaintext, uint8_t *ciphertext,
			    size_t datalen, const uint8_t *aad, size_t aadlen,
			    uint8_t *tag, size_t taglen,
			    struct lc_aead_ctx *aead);

/**
 * @brief lc_kyber_x448_ies_enc_init - KyberIES encryption stream operation
 *				 	 initialization
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * The aead context is initialized such that it can be used with
 * lc_kyber_x448_ies_enc_[update|final].
 *
 * @param [out] aead Allocated AEAD algorithm - the caller only needs to provide
 *		     an allocated but otherwise unused instance of an AEAD
 *		     algorithm. This allows the caller to define the AEAD
 *		     algorithm type. The caller must zeroize and release the
 *		     context after completion.
 * @param [in] pk Kyber public key of data owner
 * @param [out] ct Kyber ciphertext to be sent to the decryption operation
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 *
 * @return 0 on success, < 0 on error
 */
int @kyber_name@_x448_ies_enc_init(struct lc_aead_ctx *aead,
				 const struct @kyber_name@_x448_pk *pk,
				 struct @kyber_name@_x448_ct *ct,
				 const uint8_t *aad, size_t aadlen);

/**
 * @brief lc_kyber_x448_ies_enc_update - KyberIES encryption stream operation
 *				    	   add more data
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [in] plaintext Plaintext data to be encrypted
 * @param [out] ciphertext Buffer of equal size as plaintext that will be filled
 *			   with the encryption result
 * @param [in] datalen Length of the plaintext buffer
 */
static inline int @kyber_name@_x448_ies_enc_update(struct lc_aead_ctx *aead,
						 const uint8_t *plaintext,
						 uint8_t *ciphertext,
						 size_t datalen)
{
	return lc_aead_enc_update(aead, plaintext, ciphertext, datalen);
}

/**
 * @brief lc_kyber_x448_ies_enc_final - KyberIES encryption stream operation
 *				 	  finalization / integrity test
 *
 * The implementation supports an in-place data encryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [out] tag Buffer that will be filled with the authentication tag
 * @param [in] taglen Length of the tag buffer
 *
 * @return 0 on success, < 0 on error
 */
static inline int @kyber_name@_x448_ies_enc_final(struct lc_aead_ctx *aead,
						uint8_t *tag, size_t taglen)
{
	return lc_aead_enc_final(aead, tag, taglen);
}

/**
 * @brief lc_kyber_x448_ies_dec - KyberIES decryption oneshot
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] sk Kyber secret key of data owner
 * @param [in] ct Kyber ciphertext received from the encryption operation
 * @param [in] ciphertext Ciphertext data to be encrypted
 * @param [out] plaintext Buffer of equal size as ciphertext that will be
 *			   filled with the decryption result
 * @param [in] datalen Length of the ciphertext buffer
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 * @param [in] tag Buffer with the authentication tag
 * @param [in] taglen Length of the tag buffer
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 *
 * @return 0 on success, < 0 on error (-EBADMSG on integrity error)
 */
int @kyber_name@_x448_ies_dec(const struct @kyber_name@_x448_sk *sk,
			    const struct @kyber_name@_x448_ct *ct,
			    const uint8_t *ciphertext, uint8_t *plaintext,
			    size_t datalen, const uint8_t *aad, size_t aadlen,
			    const uint8_t *tag, size_t taglen,
			    struct lc_aead_ctx *aead);

/**
 * @brief lc_kyber_x448_ies_dec_init - KyberIES decryption stream operation
 *					 initialization
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * The aead context is initialized such that it can be used with
 * lc_kyber_x448_ies_dec_[update|final].
 *
 * @param [out] aead Allocated AEAD algorithm - the caller only needs to provide
 *		     an allocated but otherwise unused instance of an AEAD
 *		     algorithm. This allows the caller to define the AEAD
 *		     algorithm type. The caller must zeroize and release the
 *		     context after completion.
 * @param [in] sk Kyber secret key of data owner
 * @param [in] ct Kyber ciphertext received from the encryption operation
 * @param [in] aad Additional authenticate data to be processed - this is data
 *		   which is not encrypted, but considered as part of the
 *		   authentication.
 * @param [in] aadlen Length of the AAD buffer
 *
 * @return 0 on success, < 0 on error
 */
int @kyber_name@_x448_ies_dec_init(struct lc_aead_ctx *aead,
				 const struct @kyber_name@_x448_sk *sk,
				 const struct @kyber_name@_x448_ct *ct,
				 const uint8_t *aad, size_t aadlen);

/**
 * @brief lc_kyber_x448_ies_dec_update - KyberIES decryption stream operation
 *				  	   add more data
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [in] ciphertext Ciphertext data to be encrypted
 * @param [out] plaintext Buffer of equal size as ciphertext that will be
 *			   filled with the decryption result
 * @param [in] datalen Length of the ciphertext buffer
 *
 * @return 0 on success, < 0 on error
 */
static inline int @kyber_name@_x448_ies_dec_update(struct lc_aead_ctx *aead,
						 const uint8_t *ciphertext,
						 uint8_t *plaintext,
						 size_t datalen)
{
	return lc_aead_dec_update(aead, ciphertext, plaintext, datalen);
}

/**
 * @brief lc_kyber	_x448_ies_dec_final - KyberIES decryption stream operation
 *				  	  finalization / integrity test
 *
 * The implementation supports an in-place data decryption where the
 * plaintext and ciphertext buffer pointers refer to the same memory location.
 *
 * The function entirely operates on stack memory.
 *
 * @param [in] aead Allocated AEAD algorithm - the caller only needs to provide
 *		    an allocated but otherwise unused instance of an AEAD
 *		    algorithm. This allows the caller to define the AEAD
 *		    algorithm type. The caller must zeroize and release the
 *		    context after completion.
 * @param [in] tag Buffer with the authentication tag
 * @param [in] taglen Length of the tag buffer
 *
 * @return 0 on success, < 0 on error (-EBADMSG on integrity error)
 */
static inline int @kyber_name@_x448_ies_dec_final(struct lc_aead_ctx *aead,
						const uint8_t *tag,
						size_t taglen)
{
	return lc_aead_dec_final(aead, tag, taglen);
}

#endif /* LC_KYBER_IES */

#endif /* LC_KYBER_X448_KEM */

#endif /* __ASSEMBLER__ */

/*
 * To allow including the different lc_kyber_*.h files, these macros need to be
 * undefined. Only during compilation of leancrypto, these macros remain defined
 * as this header file is not included multiple times.
 */
#ifndef LC_KYBER_INTERNAL
#undef LC_KYBER_K
#undef LC_KYBER_N
#undef LC_KYBER_Q
#undef LC_KYBER_SYMBYTES
#undef LC_KYBER_SSBYTES
#undef LC_KYBER_POLYBYTES
#undef LC_KYBER_POLYVECBYTES
#undef LC_KYBER_ETA1
#undef LC_KYBER_POLYCOMPRESSEDBYTES
#undef LC_KYBER_POLYVECCOMPRESSEDBYTES
#undef LC_KYBER_ETA2
#undef LC_KYBER_INDCPA_MSGBYTES
#undef LC_KYBER_INDCPA_PUBLICKEYBYTES
#undef LC_KYBER_INDCPA_SECRETKEYBYTES
#undef LC_KYBER_INDCPA_BYTES
#undef LC_KYBER_PUBLICKEYBYTES
#undef LC_KYBER_SECRETKEYBYTES
#undef LC_KYBER_CIPHERTEXTBYTES
#undef LC_CRYPTO_SECRETKEYBYTES
#undef LC_CRYPTO_PUBLICKEYBYTES
#undef LC_CRYPTO_CIPHERTEXTBYTES
#undef LC_CRYPTO_BYTES
#endif /* LC_KYBER_INTERNAL */

#ifdef __cplusplus
}
#endif

#endif /* LC_KYBER_@kyber_header@H */
