#ifndef MLD_POLY_H
#define MLD_POLY_H
#include "cbmc.h"
#include "common.h"
#include "reduce.h"
#include "rounding.h"
#define MLD_FQMUL_BOUND ((5 * MLDSA_Q + 3) / 4)
#define MLD_NTT_BOUND (9 * MLD_FQMUL_BOUND)
#define MLD_INTT_BOUND MLDSA_Q
typedef struct
{
int32_t coeffs[MLDSA_N];
} MLD_ALIGN mld_poly;
#define mld_poly_reduce MLD_NAMESPACE(poly_reduce)
MLD_INTERNAL_API
void mld_poly_reduce(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))
);
#define mld_poly_caddq MLD_NAMESPACE(poly_caddq)
MLD_INTERNAL_API
void mld_poly_caddq(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
);
#if !defined(MLD_CONFIG_NO_KEYPAIR_API) || !defined(MLD_CONFIG_NO_SIGN_API) || \
defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)
#define mld_poly_add MLD_NAMESPACE(poly_add)
MLD_INTERNAL_API
void mld_poly_add(mld_poly *r, const mld_poly *b)
__contract__(
requires(memory_no_alias(b, sizeof(mld_poly)))
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(forall(k0, 0, MLDSA_N, (int64_t) r->coeffs[k0] + b->coeffs[k0] < MLD_REDUCE32_DOMAIN_MAX))
requires(forall(k1, 0, MLDSA_N, (int64_t) r->coeffs[k1] + b->coeffs[k1] >= INT32_MIN))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(forall(k2, 0, MLDSA_N, r->coeffs[k2] == old(*r).coeffs[k2] + b->coeffs[k2]))
ensures(forall(k3, 0, MLDSA_N, r->coeffs[k3] < MLD_REDUCE32_DOMAIN_MAX))
ensures(forall(k4, 0, MLDSA_N, r->coeffs[k4] >= INT32_MIN))
);
#endif
#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)
#define mld_poly_sub MLD_NAMESPACE(poly_sub)
MLD_INTERNAL_API
void mld_poly_sub(mld_poly *r, const mld_poly *b)
__contract__(
requires(memory_no_alias(b, sizeof(mld_poly)))
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(array_abs_bound(r->coeffs, 0, MLDSA_N, MLDSA_Q))
requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(array_bound(r->coeffs, 0, MLDSA_N, INT32_MIN, MLD_REDUCE32_DOMAIN_MAX))
);
#endif
#if !defined(MLD_CONFIG_NO_VERIFY_API)
#define mld_poly_shiftl MLD_NAMESPACE(poly_shiftl)
MLD_INTERNAL_API
void mld_poly_shiftl(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
);
#endif
#define mld_poly_ntt MLD_NAMESPACE(poly_ntt)
MLD_INTERNAL_API
void mld_poly_ntt(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
);
#define mld_poly_invntt_tomont MLD_NAMESPACE(poly_invntt_tomont)
MLD_INTERNAL_API
void mld_poly_invntt_tomont(mld_poly *a)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_INTT_BOUND))
);
#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API) || \
defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)
#define mld_poly_pointwise_montgomery MLD_NAMESPACE(poly_pointwise_montgomery)
MLD_INTERNAL_API
void mld_poly_pointwise_montgomery(mld_poly *a, const mld_poly *b)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(memory_no_alias(b, sizeof(mld_poly)))
requires(array_abs_bound(a->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
requires(array_abs_bound(b->coeffs, 0, MLDSA_N, MLD_NTT_BOUND))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_abs_bound(a->coeffs, 0, MLDSA_N, MLDSA_Q))
);
#endif
#if !defined(MLD_CONFIG_NO_KEYPAIR_API)
#define mld_poly_power2round MLD_NAMESPACE(poly_power2round)
MLD_INTERNAL_API
void mld_poly_power2round(mld_poly *a1, mld_poly *a0, const mld_poly *a)
__contract__(
requires(memory_no_alias(a0, sizeof(mld_poly)))
requires(memory_no_alias(a1, sizeof(mld_poly)))
requires(a0 == a)
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
assigns(memory_slice(a1, sizeof(mld_poly)))
assigns(memory_slice(a0, sizeof(mld_poly)))
ensures(array_bound(a0->coeffs, 0, MLDSA_N, -(MLD_2_POW_D/2)+1, (MLD_2_POW_D/2)+1))
ensures(array_bound(a1->coeffs, 0, MLDSA_N, 0, ((MLDSA_Q - 1) / MLD_2_POW_D) + 1))
);
#endif
#define mld_poly_uniform MLD_NAMESPACE(poly_uniform)
MLD_INTERNAL_API
void mld_poly_uniform(mld_poly *a, const uint8_t seed[MLDSA_SEEDBYTES + 2])
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(memory_no_alias(seed, MLDSA_SEEDBYTES + 2))
assigns(memory_slice(a, sizeof(mld_poly)))
ensures(array_bound(a->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
);
#if !defined(MLD_CONFIG_SERIAL_FIPS202_ONLY) && \
(!defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST))
#define mld_poly_uniform_4x MLD_NAMESPACE(poly_uniform_4x)
MLD_INTERNAL_API
void mld_poly_uniform_4x(mld_poly *vec0, mld_poly *vec1, mld_poly *vec2,
mld_poly *vec3,
uint8_t seed[4][MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)])
__contract__(
requires(memory_no_alias(vec0, sizeof(mld_poly)))
requires(memory_no_alias(vec1, sizeof(mld_poly)))
requires(memory_no_alias(vec2, sizeof(mld_poly)))
requires(memory_no_alias(vec3, sizeof(mld_poly)))
requires(memory_no_alias(seed, 4 * MLD_ALIGN_UP(MLDSA_SEEDBYTES + 2)))
assigns(memory_slice(vec0, sizeof(mld_poly)))
assigns(memory_slice(vec1, sizeof(mld_poly)))
assigns(memory_slice(vec2, sizeof(mld_poly)))
assigns(memory_slice(vec3, sizeof(mld_poly)))
ensures(array_bound(vec0->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
ensures(array_bound(vec1->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
ensures(array_bound(vec2->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
ensures(array_bound(vec3->coeffs, 0, MLDSA_N, 0, MLDSA_Q))
);
#endif
#if !defined(MLD_CONFIG_NO_KEYPAIR_API)
#define mld_polyt1_pack MLD_NAMESPACE(polyt1_pack)
MLD_INTERNAL_API
void mld_polyt1_pack(uint8_t r[MLDSA_POLYT1_PACKEDBYTES], const mld_poly *a)
__contract__(
requires(memory_no_alias(r, MLDSA_POLYT1_PACKEDBYTES))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, 1 << 10))
assigns(memory_slice(r, MLDSA_POLYT1_PACKEDBYTES))
);
#endif
#if !defined(MLD_CONFIG_NO_VERIFY_API)
#define mld_polyt1_unpack MLD_NAMESPACE(polyt1_unpack)
MLD_INTERNAL_API
void mld_polyt1_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT1_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(memory_no_alias(a, MLDSA_POLYT1_PACKEDBYTES))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(array_bound(r->coeffs, 0, MLDSA_N, 0, 1 << 10))
);
#endif
#if !defined(MLD_CONFIG_NO_KEYPAIR_API)
#define mld_polyt0_pack MLD_NAMESPACE(polyt0_pack)
MLD_INTERNAL_API
void mld_polyt0_pack(uint8_t r[MLDSA_POLYT0_PACKEDBYTES], const mld_poly *a)
__contract__(
requires(memory_no_alias(r, MLDSA_POLYT0_PACKEDBYTES))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))
assigns(memory_slice(r, MLDSA_POLYT0_PACKEDBYTES))
);
#endif
#if !defined(MLD_CONFIG_NO_SIGN_API) || defined(MLD_UNIT_TEST)
#define mld_polyt0_unpack MLD_NAMESPACE(polyt0_unpack)
MLD_INTERNAL_API
void mld_polyt0_unpack(mld_poly *r, const uint8_t a[MLDSA_POLYT0_PACKEDBYTES])
__contract__(
requires(memory_no_alias(r, sizeof(mld_poly)))
requires(memory_no_alias(a, MLDSA_POLYT0_PACKEDBYTES))
assigns(memory_slice(r, sizeof(mld_poly)))
ensures(array_bound(r->coeffs, 0, MLDSA_N, -(1<<(MLDSA_D-1)) + 1, (1<<(MLDSA_D-1)) + 1))
);
#endif
#define mld_poly_chknorm MLD_NAMESPACE(poly_chknorm)
MLD_INTERNAL_API
MLD_MUST_CHECK_RETURN_VALUE
uint32_t mld_poly_chknorm(const mld_poly *a, int32_t B)
__contract__(
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX)
requires(array_bound(a->coeffs, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))
ensures(return_value == 0 || return_value == 0xFFFFFFFF)
ensures((return_value == 0) == array_abs_bound(a->coeffs, 0, MLDSA_N, B))
);
#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44
#define mld_polyw1_pack_88 MLD_NAMESPACE(polyw1_pack_88)
MLD_INTERNAL_API
void mld_polyw1_pack_88(uint8_t r[MLDSA_POLYW1_PACKEDBYTES_88],
const mld_poly *a)
__contract__(
requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES_88))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2_88)))
assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES_88))
);
#endif
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \
(MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)
#define mld_polyw1_pack_32 MLD_NAMESPACE(polyw1_pack_32)
MLD_INTERNAL_API
void mld_polyw1_pack_32(uint8_t r[MLDSA_POLYW1_PACKEDBYTES_32],
const mld_poly *a)
__contract__(
requires(memory_no_alias(r, MLDSA_POLYW1_PACKEDBYTES_32))
requires(memory_no_alias(a, sizeof(mld_poly)))
requires(array_bound(a->coeffs, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2_32)))
assigns(memory_slice(r, MLDSA_POLYW1_PACKEDBYTES_32))
);
#endif
#endif
#endif