crypto/fipsmodule/ml_kem/mlkem/poly_k.h (256 lines of code) (raw):
/*
* Copyright (c) 2024-2025 The mlkem-native project authors
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef MLK_POLY_K_H
#define MLK_POLY_K_H
#include <stdint.h>
#include "common.h"
#include "compress.h"
#include "poly.h"
/* Level namespacing
* This is to facilitate building multiple instances
* of mlkem-native (e.g. with varying security levels)
* within a single compilation unit. */
#define mlk_polyvec MLK_ADD_LEVEL(mlk_polyvec)
#define mlk_polymat MLK_ADD_LEVEL(mlk_polymat)
#define mlk_polyvec_mulcache MLK_ADD_LEVEL(mlk_polyvec_mulcache)
/* End of level namespacing */
typedef mlk_poly mlk_polyvec[MLKEM_K];
typedef mlk_poly mlk_polymat[MLKEM_K * MLKEM_K];
typedef mlk_poly_mulcache mlk_polyvec_mulcache[MLKEM_K];
#define mlk_poly_compress_du MLK_NAMESPACE_K(poly_compress_du)
/*************************************************
* Name: mlk_poly_compress_du
*
* Description: Compression (du bits) and subsequent serialization of a
* polynomial
*
* Arguments: - uint8_t *r: pointer to output byte array
* (of length MLKEM_POLYCOMPRESSEDBYTES_DU bytes)
* - const mlk_poly *a: pointer to input polynomial
* Coefficients must be unsigned canonical,
* i.e. in [0,1,..,MLKEM_Q-1].
*
* Specification: Implements `ByteEncode_{d_u} (Compress_{d_u} (u))`
* in [FIPS 203, Algorithm 14 (K-PKE.Encrypt), L22],
* with level-specific d_u defined in [FIPS 203, Table 2],
* and given by MLKEM_DU here.
*
**************************************************/
static MLK_INLINE void mlk_poly_compress_du(
uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DU], const mlk_poly *a)
__contract__(
requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_DU))
requires(memory_no_alias(a, sizeof(mlk_poly)))
requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))
assigns(memory_slice(r, MLKEM_POLYCOMPRESSEDBYTES_DU)))
{
#if MLKEM_DU == 10
mlk_poly_compress_d10(r, a);
#elif MLKEM_DU == 11
mlk_poly_compress_d11(r, a);
#else
#error "Invalid value of MLKEM_DU"
#endif
}
#define mlk_poly_decompress_du MLK_NAMESPACE_K(poly_decompress_du)
/*************************************************
* Name: mlk_poly_decompress_du
*
* Description: De-serialization and subsequent decompression (du bits) of a
* polynomial; approximate inverse of mlk_poly_compress_du
*
* Arguments: - mlk_poly *r: pointer to output polynomial
* - const uint8_t *a: pointer to input byte array
* (of length MLKEM_POLYCOMPRESSEDBYTES_DU bytes)
*
* Upon return, the coefficients of the output polynomial are unsigned-canonical
* (non-negative and smaller than MLKEM_Q).
*
* Specification: Implements `Decompress_{d_u} (ByteDecode_{d_u} (u))`
* in [FIPS 203, Algorithm 15 (K-PKE.Decrypt), L3].
* with level-specific d_u defined in [FIPS 203, Table 2],
* and given by MLKEM_DU here.
*
**************************************************/
static MLK_INLINE void mlk_poly_decompress_du(
mlk_poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DU])
__contract__(
requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_DU))
requires(memory_no_alias(r, sizeof(mlk_poly)))
assigns(memory_slice(r, sizeof(mlk_poly)))
ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q)))
{
#if MLKEM_DU == 10
mlk_poly_decompress_d10(r, a);
#elif MLKEM_DU == 11
mlk_poly_decompress_d11(r, a);
#else
#error "Invalid value of MLKEM_DU"
#endif
}
#define mlk_poly_compress_dv MLK_NAMESPACE_K(poly_compress_dv)
/*************************************************
* Name: mlk_poly_compress_dv
*
* Description: Compression (dv bits) and subsequent serialization of a
* polynomial
*
* Arguments: - uint8_t *r: pointer to output byte array
* (of length MLKEM_POLYCOMPRESSEDBYTES_DV bytes)
* - const mlk_poly *a: pointer to input polynomial
* Coefficients must be unsigned canonical,
* i.e. in [0,1,..,MLKEM_Q-1].
*
* Specification: Implements `ByteEncode_{d_v} (Compress_{d_v} (v))`
* in [FIPS 203, Algorithm 14 (K-PKE.Encrypt), L23].
* with level-specific d_v defined in [FIPS 203, Table 2],
* and given by MLKEM_DV here.
*
**************************************************/
static MLK_INLINE void mlk_poly_compress_dv(
uint8_t r[MLKEM_POLYCOMPRESSEDBYTES_DV], const mlk_poly *a)
__contract__(
requires(memory_no_alias(r, MLKEM_POLYCOMPRESSEDBYTES_DV))
requires(memory_no_alias(a, sizeof(mlk_poly)))
requires(array_bound(a->coeffs, 0, MLKEM_N, 0, MLKEM_Q))
assigns(object_whole(r)))
{
#if MLKEM_DV == 4
mlk_poly_compress_d4(r, a);
#elif MLKEM_DV == 5
mlk_poly_compress_d5(r, a);
#else
#error "Invalid value of MLKEM_DV"
#endif
}
#define mlk_poly_decompress_dv MLK_NAMESPACE_K(poly_decompress_dv)
/*************************************************
* Name: mlk_poly_decompress_dv
*
* Description: De-serialization and subsequent decompression (dv bits) of a
* polynomial; approximate inverse of poly_compress
*
* Arguments: - mlk_poly *r: pointer to output polynomial
* - const uint8_t *a: pointer to input byte array
* (of length MLKEM_POLYCOMPRESSEDBYTES_DV bytes)
*
* Upon return, the coefficients of the output polynomial are unsigned-canonical
* (non-negative and smaller than MLKEM_Q).
*
* Specification: Implements `Decompress_{d_v} (ByteDecode_{d_v} (v))`
* in [FIPS 203, Algorithm 15 (K-PKE.Decrypt), L4].
* with level-specific d_v defined in [FIPS 203, Table 2],
* and given by MLKEM_DV here.
*
**************************************************/
static MLK_INLINE void mlk_poly_decompress_dv(
mlk_poly *r, const uint8_t a[MLKEM_POLYCOMPRESSEDBYTES_DV])
__contract__(
requires(memory_no_alias(a, MLKEM_POLYCOMPRESSEDBYTES_DV))
requires(memory_no_alias(r, sizeof(mlk_poly)))
assigns(object_whole(r))
ensures(array_bound(r->coeffs, 0, MLKEM_N, 0, MLKEM_Q)))
{
#if MLKEM_DV == 4
mlk_poly_decompress_d4(r, a);
#elif MLKEM_DV == 5
mlk_poly_decompress_d5(r, a);
#else
#error "Invalid value of MLKEM_DV"
#endif
}
#define mlk_polyvec_compress_du MLK_NAMESPACE_K(polyvec_compress_du)
/*************************************************
* Name: mlk_polyvec_compress_du
*
* Description: Compress and serialize vector of polynomials
*
* Arguments: - uint8_t *r: pointer to output byte array
* (needs space for MLKEM_POLYVECCOMPRESSEDBYTES_DU)
* - const mlk_polyvec a: pointer to input vector of polynomials.
* Coefficients must be unsigned canonical,
* i.e. in [0,1,..,MLKEM_Q-1].
*
* Specification: Implements `ByteEncode_{d_u} (Compress_{d_u} (u))`
* in [FIPS 203, Algorithm 14 (K-PKE.Encrypt), L22].
* with level-specific d_u defined in [FIPS 203, Table 2],
* and given by MLKEM_DU here.
*
**************************************************/
MLK_INTERNAL_API
void mlk_polyvec_compress_du(uint8_t r[MLKEM_POLYVECCOMPRESSEDBYTES_DU],
const mlk_polyvec a)
__contract__(
requires(memory_no_alias(r, MLKEM_POLYVECCOMPRESSEDBYTES_DU))
requires(memory_no_alias(a, sizeof(mlk_polyvec)))
requires(forall(k0, 0, MLKEM_K,
array_bound(a[k0].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))
assigns(object_whole(r))
);
#define mlk_polyvec_decompress_du MLK_NAMESPACE_K(polyvec_decompress_du)
/*************************************************
* Name: mlk_polyvec_decompress_du
*
* Description: De-serialize and decompress vector of polynomials;
* approximate inverse of mlk_polyvec_compress_du
*
* Arguments: - mlk_polyvec r: pointer to output vector of polynomials.
* Output will have coefficients normalized to [0,..,q-1].
* - const uint8_t *a: pointer to input byte array
* (of length MLKEM_POLYVECCOMPRESSEDBYTES_DU)
*
* Specification: Implements `Decompress_{d_u} (ByteDecode_{d_u} (u))`
* in [FIPS 203, Algorithm 15 (K-PKE.Decrypt), L3].
* with level-specific d_u defined in [FIPS 203, Table 2],
* and given by MLKEM_DU here.
*
**************************************************/
MLK_INTERNAL_API
void mlk_polyvec_decompress_du(mlk_polyvec r,
const uint8_t a[MLKEM_POLYVECCOMPRESSEDBYTES_DU])
__contract__(
requires(memory_no_alias(a, MLKEM_POLYVECCOMPRESSEDBYTES_DU))
requires(memory_no_alias(r, sizeof(mlk_polyvec)))
assigns(object_whole(r))
ensures(forall(k0, 0, MLKEM_K,
array_bound(r[k0].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))
);
#define mlk_polyvec_tobytes MLK_NAMESPACE_K(polyvec_tobytes)
/*************************************************
* Name: mlk_polyvec_tobytes
*
* Description: Serialize vector of polynomials
*
* Arguments: - uint8_t *r: pointer to output byte array
* (needs space for MLKEM_POLYVECBYTES)
* - const mlk_polyvec a: pointer to input vector of polynomials
* Each polynomial must have coefficients in [0,..,q-1].
*
* Specification: Implements ByteEncode_12 [FIPS 203, Algorithm 5].
* Extended to vectors as per
* [FIPS 203, 2.4.8 Applying Algorithms to Arrays]
* and [FIPS 203, 2.4.6, Matrices and Vectors]
*
**************************************************/
MLK_INTERNAL_API
void mlk_polyvec_tobytes(uint8_t r[MLKEM_POLYVECBYTES], const mlk_polyvec a)
__contract__(
requires(memory_no_alias(a, sizeof(mlk_polyvec)))
requires(memory_no_alias(r, MLKEM_POLYVECBYTES))
requires(forall(k0, 0, MLKEM_K,
array_bound(a[k0].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))
assigns(object_whole(r))
);
#define mlk_polyvec_frombytes MLK_NAMESPACE_K(polyvec_frombytes)
/*************************************************
* Name: mlk_polyvec_frombytes
*
* Description: De-serialize vector of polynomials;
* inverse of mlk_polyvec_tobytes
*
* Arguments: - const mlk_polyvec a: pointer to output vector of polynomials
* (of length MLKEM_POLYVECBYTES). Output will have coefficients
* normalized in [0..4095].
* - uint8_t *r: pointer to input byte array
*
* Specification: Implements ByteDecode_12 [FIPS 203, Algorithm 6].
* Extended to vectors as per
* [FIPS 203, 2.4.8 Applying Algorithms to Arrays]
* and [FIPS 203, 2.4.6, Matrices and Vectors]
*
**************************************************/
MLK_INTERNAL_API
void mlk_polyvec_frombytes(mlk_polyvec r, const uint8_t a[MLKEM_POLYVECBYTES])
__contract__(
requires(memory_no_alias(r, sizeof(mlk_polyvec)))
requires(memory_no_alias(a, MLKEM_POLYVECBYTES))
assigns(object_whole(r))
ensures(forall(k0, 0, MLKEM_K,
array_bound(r[k0].coeffs, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT)))
);
#define mlk_polyvec_ntt MLK_NAMESPACE_K(polyvec_ntt)
/*************************************************
* Name: mlk_polyvec_ntt
*
* Description: Apply forward NTT to all elements of a vector of polynomials.
*
* The input is assumed to be in normal order and
* coefficient-wise bound by MLKEM_Q in absolute value.
*
* The output polynomial is in bitreversed order, and
* coefficient-wise bound by MLK_NTT_BOUND in absolute value.
*
* Arguments: - mlk_polyvec r: pointer to in/output vector of polynomials
*
* Specification:
* - Implements [FIPS 203, Algorithm 9, NTT]
* - Extended to vectors as per [FIPS 203, 2.4.6, Matrices and Vectors]
*
**************************************************/
MLK_INTERNAL_API
void mlk_polyvec_ntt(mlk_polyvec r)
__contract__(
requires(memory_no_alias(r, sizeof(mlk_polyvec)))
requires(forall(j, 0, MLKEM_K,
array_abs_bound(r[j].coeffs, 0, MLKEM_N, MLKEM_Q)))
assigns(object_whole(r))
ensures(forall(j, 0, MLKEM_K,
array_abs_bound(r[j].coeffs, 0, MLKEM_N, MLK_NTT_BOUND)))
);
#define mlk_polyvec_invntt_tomont MLK_NAMESPACE_K(polyvec_invntt_tomont)
/*************************************************
* Name: mlk_polyvec_invntt_tomont
*
* Description: Apply inverse NTT to all elements of a vector of polynomials
* and multiply by Montgomery factor 2^16
*
* The input is assumed to be in bitreversed order, and can
* have arbitrary coefficients in int16_t.
*
* The output polynomial is in normal order, and
* coefficient-wise bound by MLK_INVNTT_BOUND in absolute value.
*
* Arguments: - mlk_polyvec r: pointer to in/output vector of polynomials
*
* Specification:
* - Implements [FIPS 203, Algorithm 10, NTT^{-1}]
* - Extended to vectors as per [FIPS 203, 2.4.6, Matrices and Vectors]
*
**************************************************/
MLK_INTERNAL_API
void mlk_polyvec_invntt_tomont(mlk_polyvec r)
__contract__(
requires(memory_no_alias(r, sizeof(mlk_polyvec)))
assigns(object_whole(r))
ensures(forall(j, 0, MLKEM_K,
array_abs_bound(r[j].coeffs, 0, MLKEM_N, MLK_INVNTT_BOUND)))
);
#define mlk_polyvec_basemul_acc_montgomery_cached \
MLK_NAMESPACE_K(polyvec_basemul_acc_montgomery_cached)
/*************************************************
* Name: mlk_polyvec_basemul_acc_montgomery_cached
*
* Description: Scalar product of two vectors of polynomials in NTT domain,
* using mulcache for second operand.
*
* Bounds:
* - Every coefficient of a is assumed to be in [0..4095]
* - No bounds guarantees for the coefficients in the result.
*
* Arguments: - mlk_poly *r: pointer to output polynomial
* - const mlk_polyvec a: pointer to first input polynomial vector
* - const mlk_polyvec b: pointer to second input polynomial
* vector
* - const mlk_polyvec_mulcache b_cache: pointer to mulcache
* for second input polynomial vector. Can be computed
* via mlk_polyvec_mulcache_compute().
*
* Specification: Implements
* - [FIPS 203, Section 2.4.7, Eq (2.14)]
* - [FIPS 203, Algorithm 11, MultiplyNTTs]
* - [FIPS 203, Algorithm 12, BaseCaseMultiply]
*
**************************************************/
MLK_INTERNAL_API
void mlk_polyvec_basemul_acc_montgomery_cached(
mlk_poly *r, const mlk_polyvec a, const mlk_polyvec b,
const mlk_polyvec_mulcache b_cache)
__contract__(
requires(memory_no_alias(r, sizeof(mlk_poly)))
requires(memory_no_alias(a, sizeof(mlk_polyvec)))
requires(memory_no_alias(b, sizeof(mlk_polyvec)))
requires(memory_no_alias(b_cache, sizeof(mlk_polyvec_mulcache)))
requires(forall(k1, 0, MLKEM_K,
array_bound(a[k1].coeffs, 0, MLKEM_N, 0, MLKEM_UINT12_LIMIT)))
assigns(object_whole(r))
);
#define mlk_polyvec_mulcache_compute MLK_NAMESPACE_K(polyvec_mulcache_compute)
/************************************************************
* Name: mlk_polyvec_mulcache_compute
*
* Description: Computes the mulcache for a vector of polynomials in NTT domain
*
* The mulcache of a degree-2 polynomial b := b0 + b1*X
* in Fq[X]/(X^2-zeta) is the value b1*zeta, needed when
* computing products of b in Fq[X]/(X^2-zeta).
*
* The mulcache of a polynomial in NTT domain -- which is
* a 128-tuple of degree-2 polynomials in Fq[X]/(X^2-zeta),
* for varying zeta, is the 128-tuple of mulcaches of those
* polynomials.
*
* The mulcache of a vector of polynomials is the vector
* of mulcaches of its entries.
*
* Arguments: - x: Pointer to mulcache to be populated
* - a: Pointer to input polynomial vector
*
* Specification:
* - Caches `b_1 * \gamma` in [FIPS 203, Algorithm 12, BaseCaseMultiply, L1]
*
************************************************************/
/*
* NOTE: The default C implementation of this function populates
* the mulcache with values in (-q,q), but this is not needed for the
* higher level safety proofs, and thus not part of the spec.
*/
MLK_INTERNAL_API
void mlk_polyvec_mulcache_compute(mlk_polyvec_mulcache x, const mlk_polyvec a)
__contract__(
requires(memory_no_alias(x, sizeof(mlk_polyvec_mulcache)))
requires(memory_no_alias(a, sizeof(mlk_polyvec)))
assigns(object_whole(x))
);
#define mlk_polyvec_reduce MLK_NAMESPACE_K(polyvec_reduce)
/*************************************************
* Name: mlk_polyvec_reduce
*
* Description: Applies Barrett reduction to each coefficient
* of each element of a vector of polynomials;
* for details of the Barrett reduction see comments in reduce.c
*
* Arguments: - mlk_polyvec r: pointer to input/output polynomial
*
* Specification: Normalizes on unsigned canoncial representatives
* ahead of calling [FIPS 203, Compress_d, Eq (4.7)].
* This is not made explicit in FIPS 203.
*
**************************************************/
/*
* NOTE: The semantics of mlk_polyvec_reduce() is different in
* the reference implementation, which requires
* signed canonical output data. Unsigned canonical
* outputs are better suited to the only remaining
* use of mlk_poly_reduce() in the context of (de)serialization.
*/
MLK_INTERNAL_API
void mlk_polyvec_reduce(mlk_polyvec r)
__contract__(
requires(memory_no_alias(r, sizeof(mlk_polyvec)))
assigns(object_whole(r))
ensures(forall(k0, 0, MLKEM_K,
array_bound(r[k0].coeffs, 0, MLKEM_N, 0, MLKEM_Q)))
);
#define mlk_polyvec_add MLK_NAMESPACE_K(polyvec_add)
/*************************************************
* Name: mlk_polyvec_add
*
* Description: Add vectors of polynomials
*
* Arguments: - mlk_polyvec r: pointer to input-output vector of polynomials to
* be added to
* - const mlk_polyvec b: pointer to second input vector of
* polynomials
*
* The coefficients of r and b must be so that the addition does
* not overflow. Otherwise, the behaviour of this function is undefined.
*
* The coefficients returned in *r are in int16_t which is sufficient
* to prove type-safety of calling units. Therefore, no stronger
* ensures clause is required on this function.
*
* Specification:
* - [FIPS 203, 2.4.5, Arithmetic With Polynomials and NTT Representations]
* - Used in [FIPS 203, Algorithm 14 (K-PKE.Encrypt), L19]
*
**************************************************/
MLK_INTERNAL_API
void mlk_polyvec_add(mlk_polyvec r, const mlk_polyvec b)
__contract__(
requires(memory_no_alias(r, sizeof(mlk_polyvec)))
requires(memory_no_alias(b, sizeof(mlk_polyvec)))
requires(forall(j0, 0, MLKEM_K,
forall(k0, 0, MLKEM_N,
(int32_t)r[j0].coeffs[k0] + b[j0].coeffs[k0] <= INT16_MAX)))
requires(forall(j1, 0, MLKEM_K,
forall(k1, 0, MLKEM_N,
(int32_t)r[j1].coeffs[k1] + b[j1].coeffs[k1] >= INT16_MIN)))
assigns(object_whole(r))
);
#define mlk_polyvec_tomont MLK_NAMESPACE_K(polyvec_tomont)
/*************************************************
* Name: mlk_polyvec_tomont
*
* Description: Inplace conversion of all coefficients of a polynomial
* vector from normal domain to Montgomery domain
*
* Bounds: Output < q in absolute value.
*
*
* Specification: Internal normalization required in `mlk_indcpa_keypair_derand`
* as part of matrix-vector multiplication
* [FIPS 203, Algorithm 13, K-PKE.KeyGen, L18].
*
**************************************************/
MLK_INTERNAL_API
void mlk_polyvec_tomont(mlk_polyvec r)
__contract__(
requires(memory_no_alias(r, sizeof(mlk_polyvec)))
assigns(memory_slice(r, sizeof(mlk_polyvec)))
assigns(object_whole(r))
ensures(forall(j, 0, MLKEM_K,
array_abs_bound(r[j].coeffs, 0, MLKEM_N, MLKEM_Q)))
);
#define mlk_poly_getnoise_eta1_4x MLK_NAMESPACE_K(poly_getnoise_eta1_4x)
/*************************************************
* Name: mlk_poly_getnoise_eta1_4x
*
* Description: Batch sample four polynomials deterministically from a seed
* and nonces, with output polynomials close to centered binomial
* distribution with parameter MLKEM_ETA1.
*
* Arguments: - mlk_poly *r{0,1,2,3}: pointer to output polynomial
* - const uint8_t *seed: pointer to input seed
* (of length MLKEM_SYMBYTES bytes)
* - uint8_t nonce{0,1,2,3}: one-byte input nonce
*
* Specification:
* Implements 4x `SamplePolyCBD_{eta1} (PRF_{eta1} (sigma, N))`:
* - [FIPS 203, Algorithm 8, SamplePolyCBD_eta]
* - [FIPS 203, Eq (4.3), PRF_eta]
* - `SamplePolyCBD_{eta1} (PRF_{eta1} (sigma, N))` appears in
* [FIPS 203, Algorithm 13, K-PKE.KeyGen, L{9, 13}]
* [FIPS 203, Algorithm 14, K-PKE.Encrypt, L10]
*
**************************************************/
MLK_INTERNAL_API
void mlk_poly_getnoise_eta1_4x(mlk_poly *r0, mlk_poly *r1, mlk_poly *r2,
mlk_poly *r3, const uint8_t seed[MLKEM_SYMBYTES],
uint8_t nonce0, uint8_t nonce1, uint8_t nonce2,
uint8_t nonce3)
__contract__(
requires(memory_no_alias(seed, MLKEM_SYMBYTES))
requires(memory_no_alias(r0, sizeof(mlk_poly)))
requires(memory_no_alias(r1, sizeof(mlk_poly)))
requires(memory_no_alias(r2, sizeof(mlk_poly)))
requires(memory_no_alias(r3, sizeof(mlk_poly)))
assigns(memory_slice(r0, sizeof(mlk_poly)))
assigns(memory_slice(r1, sizeof(mlk_poly)))
assigns(memory_slice(r2, sizeof(mlk_poly)))
assigns(memory_slice(r3, sizeof(mlk_poly)))
ensures(
array_abs_bound(r0->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1)
&& array_abs_bound(r1->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1)
&& array_abs_bound(r2->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1)
&& array_abs_bound(r3->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1));
);
#if MLKEM_ETA1 == MLKEM_ETA2
/*
* We only require mlk_poly_getnoise_eta2_4x for ml-kem-768 and ml-kem-1024
* where MLKEM_ETA2 = MLKEM_ETA1 = 2.
* For ml-kem-512, mlk_poly_getnoise_eta1122_4x is used instead.
*/
#define mlk_poly_getnoise_eta2_4x mlk_poly_getnoise_eta1_4x
#endif /* MLKEM_ETA1 == MLKEM_ETA2 */
#if MLKEM_K == 2 || MLKEM_K == 4
#define mlk_poly_getnoise_eta2 MLK_NAMESPACE_K(poly_getnoise_eta2)
/*************************************************
* Name: mlk_poly_getnoise_eta2
*
* Description: Sample a polynomial deterministically from a seed and a nonce,
* with output polynomial close to centered binomial distribution
* with parameter MLKEM_ETA2
*
* Arguments: - mlk_poly *r: pointer to output polynomial
* - const uint8_t *seed: pointer to input seed
* (of length MLKEM_SYMBYTES bytes)
* - uint8_t nonce: one-byte input nonce
*
* Specification:
* Implements `SamplePolyCBD_{eta2} (PRF_{eta2} (sigma, N))`:
* - [FIPS 203, Algorithm 8, SamplePolyCBD_eta]
* - [FIPS 203, Eq (4.3), PRF_eta]
* - `SamplePolyCBD_{eta2} (PRF_{eta2} (sigma, N))` appears in
* [FIPS 203, Algorithm 14, K-PKE.Encrypt, L14]
*
**************************************************/
MLK_INTERNAL_API
void mlk_poly_getnoise_eta2(mlk_poly *r, const uint8_t seed[MLKEM_SYMBYTES],
uint8_t nonce)
__contract__(
requires(memory_no_alias(r, sizeof(mlk_poly)))
requires(memory_no_alias(seed, MLKEM_SYMBYTES))
assigns(object_whole(r))
ensures(array_abs_bound(r->coeffs, 0, MLKEM_N, MLKEM_ETA2 + 1))
);
#endif /* MLKEM_K == 2 || MLKEM_K == 4 */
#if MLKEM_K == 2
#define mlk_poly_getnoise_eta1122_4x MLK_NAMESPACE_K(poly_getnoise_eta1122_4x)
/*************************************************
* Name: mlk_poly_getnoise_eta1122_4x
*
* Description: Batch sample four polynomials deterministically from a seed
* and a nonces, with output polynomials close to centered binomial
* distribution with parameter MLKEM_ETA1 and MLKEM_ETA2
*
* Arguments: - mlk_poly *r{0,1,2,3}: pointer to output polynomial
* - const uint8_t *seed: pointer to input seed
* (of length MLKEM_SYMBYTES bytes)
* - uint8_t nonce{0,1,2,3}: one-byte input nonce
*
* Specification:
* Implements two instances each of
* `SamplePolyCBD_{eta1} (PRF_{eta1} (sigma, N))` and
* `SamplePolyCBD_{eta2} (PRF_{eta2} (sigma, N))`:
* - [FIPS 203, Algorithm 8, SamplePolyCBD_eta]
* - [FIPS 203, Eq (4.3), PRF_eta]
* - `SamplePolyCBD_{eta2} (PRF_{eta2} (sigma, N))` appears in
* [FIPS 203, Algorithm 14, K-PKE.Encrypt, L14]
*
**************************************************/
MLK_INTERNAL_API
void mlk_poly_getnoise_eta1122_4x(mlk_poly *r0, mlk_poly *r1, mlk_poly *r2,
mlk_poly *r3,
const uint8_t seed[MLKEM_SYMBYTES],
uint8_t nonce0, uint8_t nonce1,
uint8_t nonce2, uint8_t nonce3)
__contract__(
requires( /* r0, r1 consecutive, r2, r3 consecutive */
(memory_no_alias(r0, 2 * sizeof(mlk_poly)) && memory_no_alias(r2, 2 * sizeof(mlk_poly)) &&
r1 == r0 + 1 && r3 == r2 + 1 && !same_object(r0, r2)))
requires(memory_no_alias(seed, MLKEM_SYMBYTES))
assigns(object_whole(r0), object_whole(r1), object_whole(r2), object_whole(r3))
ensures(array_abs_bound(r0->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1)
&& array_abs_bound(r1->coeffs,0, MLKEM_N, MLKEM_ETA1 + 1)
&& array_abs_bound(r2->coeffs,0, MLKEM_N, MLKEM_ETA2 + 1)
&& array_abs_bound(r3->coeffs,0, MLKEM_N, MLKEM_ETA2 + 1));
);
#endif /* MLKEM_K == 2 */
#endif /* !MLK_POLY_K_H */