#ifndef MLD_NATIVE_API_H
#define MLD_NATIVE_API_H
#include "../cbmc.h"
#include "../common.h"
#define MLD_NATIVE_FUNC_SUCCESS (0)
#define MLD_NATIVE_FUNC_FALLBACK (-1)
#define MLD_FQMUL_BOUND ((5 * MLDSA_Q + 3) / 4)
#define MLD_NTT_BOUND (9 * MLD_FQMUL_BOUND)
#define MLD_INTT_BOUND MLDSA_Q
#define MLD_REDUCE32_RANGE_MAX 6283009
#if defined(MLD_USE_NATIVE_NTT)
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_ntt_native(int32_t p[MLDSA_N])
__contract__(
requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N))
requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_NTT_BOUND))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N))
);
#endif
#if defined(MLD_USE_NATIVE_NTT_CUSTOM_ORDER)
#if !defined(MLD_USE_NATIVE_NTT) || !defined(MLD_USE_NATIVE_INTT)
#error \
"Invalid native profile: MLD_USE_NATIVE_NTT_CUSTOM_ORDER can only be \
set if there are native implementations for NTT and INTT."
#endif
static MLD_INLINE void mld_poly_permute_bitrev_to_custom(int32_t p[MLDSA_N])
__contract__(
requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N))
requires(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q))
assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N))
ensures(array_bound(p, 0, MLDSA_N, 0, MLDSA_Q)));
#endif
#if defined(MLD_USE_NATIVE_INTT)
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_intt_native(int32_t p[MLDSA_N])
__contract__(
requires(memory_no_alias(p, sizeof(int32_t) * MLDSA_N))
requires(array_abs_bound(p, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(p, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(p, 0, MLDSA_N, MLD_INTT_BOUND))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(p, 0, MLDSA_N, MLDSA_Q))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(p, MLDSA_N))
);
#endif
#if defined(MLD_USE_NATIVE_REJ_UNIFORM)
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_rej_uniform_native(int32_t *r, unsigned len,
const uint8_t *buf,
unsigned buflen)
__contract__(
requires(len <= MLDSA_N)
requires(buflen <= ( 5 * 168) && buflen % 3 == 0)
requires(memory_no_alias(r, sizeof(int32_t) * len))
requires(memory_no_alias(buf, buflen))
assigns(memory_slice(r, sizeof(int32_t) * len))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len))
ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(r, 0, (unsigned) return_value, 0, MLDSA_Q))
);
#endif
#if !defined(MLD_CONFIG_NO_KEYPAIR_API)
#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA2)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_ETA == 2
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_rej_uniform_eta2_native(int32_t *r, unsigned len,
const uint8_t *buf,
unsigned buflen)
__contract__(
requires(len <= MLDSA_N)
requires(buflen <= (2 * 136))
requires(memory_no_alias(r, sizeof(int32_t) * len))
requires(memory_no_alias(buf, buflen))
assigns(memory_slice(r, sizeof(int32_t) * len))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len))
ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, 3)))
);
#endif
#endif
#if defined(MLD_USE_NATIVE_REJ_UNIFORM_ETA4)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_ETA == 4
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_rej_uniform_eta4_native(int32_t *r, unsigned len,
const uint8_t *buf,
unsigned buflen)
__contract__(
requires(len <= MLDSA_N)
requires(buflen <= (2 * 136))
requires(memory_no_alias(r, sizeof(int32_t) * len))
requires(memory_no_alias(buf, buflen))
assigns(memory_slice(r, sizeof(int32_t) * len))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || (0 <= return_value && return_value <= len))
ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==> (array_abs_bound(r, 0, return_value, 5)))
);
#endif
#endif
#endif
#if !defined(MLD_CONFIG_NO_SIGN_API)
#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_32)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \
(MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_poly_decompose_32_native(int32_t *a1, int32_t *a0)
__contract__(
requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N))
requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N))
requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))
assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N))
assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N))
);
#endif
#endif
#if defined(MLD_USE_NATIVE_POLY_DECOMPOSE_88)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_poly_decompose_88_native(int32_t *a1, int32_t *a0)
__contract__(
requires(memory_no_alias(a1, sizeof(int32_t) * MLDSA_N))
requires(memory_no_alias(a0, sizeof(int32_t) * MLDSA_N))
requires(array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))
assigns(memory_slice(a1, sizeof(int32_t) * MLDSA_N))
assigns(memory_slice(a0, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a1, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a0, 0, MLDSA_N, MLDSA_GAMMA2+1))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_bound(a0, 0, MLDSA_N, 0, MLDSA_Q))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a0, MLDSA_N))
);
#endif
#endif
#endif
#if defined(MLD_USE_NATIVE_POLY_CADDQ)
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_poly_caddq_native(int32_t a[MLDSA_N])
__contract__(
requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))
requires(array_abs_bound(a, 0, MLDSA_N, MLDSA_Q))
assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N))
);
#endif
#if !defined(MLD_CONFIG_NO_VERIFY_API)
#if defined(MLD_USE_NATIVE_POLY_USE_HINT_32)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \
(MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_poly_use_hint_32_native(int32_t *a, const int32_t *h)
__contract__(
requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))
requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N))
requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))
requires(array_bound(h, 0, MLDSA_N, 0, 2))
assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N))
);
#endif
#endif
#if defined(MLD_USE_NATIVE_POLY_USE_HINT_88)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_poly_use_hint_88_native(int32_t *a, const int32_t *h)
__contract__(
requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))
requires(memory_no_alias(h, sizeof(int32_t) * MLDSA_N))
requires(array_bound(a, 0, MLDSA_N, 0, MLDSA_Q))
requires(array_bound(h, 0, MLDSA_N, 0, 2))
assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(a, 0, MLDSA_N, 0, (MLDSA_Q-1)/(2*MLDSA_GAMMA2)))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(a, MLDSA_N))
);
#endif
#endif
#endif
#if defined(MLD_USE_NATIVE_POLY_CHKNORM)
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_poly_chknorm_native(const int32_t *a, int32_t B)
__contract__(
requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))
requires(0 <= B && B <= MLDSA_Q - MLD_REDUCE32_RANGE_MAX)
requires(array_bound(a, 0, MLDSA_N, -MLD_REDUCE32_RANGE_MAX, MLD_REDUCE32_RANGE_MAX))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == 0 ||
return_value == 1)
ensures((return_value != MLD_NATIVE_FUNC_FALLBACK) ==>
((return_value == 0) == array_abs_bound(a, 0, MLDSA_N, B)))
);
#endif
#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API)
#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_17)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLD_CONFIG_PARAMETER_SET == 44
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_polyz_unpack_17_native(int32_t *r, const uint8_t *a)
__contract__(
requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))
requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES))
assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N))
);
#endif
#endif
#if defined(MLD_USE_NATIVE_POLYZ_UNPACK_19)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || \
(MLD_CONFIG_PARAMETER_SET == 65 || MLD_CONFIG_PARAMETER_SET == 87)
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_polyz_unpack_19_native(int32_t *r, const uint8_t *a)
__contract__(
requires(memory_no_alias(r, sizeof(int32_t) * MLDSA_N))
requires(memory_no_alias(a, MLDSA_POLYZ_PACKEDBYTES))
assigns(memory_slice(r, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_bound(r, 0, MLDSA_N, -(MLDSA_GAMMA1 - 1), MLDSA_GAMMA1 + 1))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(r, MLDSA_N))
);
#endif
#endif
#endif
#if !defined(MLD_CONFIG_NO_SIGN_API) || !defined(MLD_CONFIG_NO_VERIFY_API) || \
defined(MLD_CONFIG_REDUCE_RAM) || defined(MLD_UNIT_TEST)
#if defined(MLD_USE_NATIVE_POINTWISE_MONTGOMERY)
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_poly_pointwise_montgomery_native(
int32_t a[MLDSA_N], const int32_t b[MLDSA_N])
__contract__(
requires(memory_no_alias(a, sizeof(int32_t) * MLDSA_N))
requires(memory_no_alias(b, sizeof(int32_t) * MLDSA_N))
requires(array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND))
requires(array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND))
assigns(memory_slice(a, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(a, 0, MLDSA_N, MLDSA_Q))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(a, 0, MLDSA_N, MLD_NTT_BOUND))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_abs_bound(b, 0, MLDSA_N, MLD_NTT_BOUND))
);
#endif
#endif
#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L4)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 4
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l4_native(
int32_t w[MLDSA_N], const int32_t u[4][MLDSA_N],
const int32_t v[4][MLDSA_N])
__contract__(
requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N))
requires(memory_no_alias(u, sizeof(int32_t) * 4 * MLDSA_N))
requires(memory_no_alias(v, sizeof(int32_t) * 4 * MLDSA_N))
requires(forall(l0, 0, 4,
array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q)))
requires(forall(l1, 0, 4,
array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND)))
assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N))
);
#endif
#endif
#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L5)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 5
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l5_native(
int32_t w[MLDSA_N], const int32_t u[5][MLDSA_N],
const int32_t v[5][MLDSA_N])
__contract__(
requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N))
requires(memory_no_alias(u, sizeof(int32_t) * 5 * MLDSA_N))
requires(memory_no_alias(v, sizeof(int32_t) * 5 * MLDSA_N))
requires(forall(l0, 0, 5,
array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q)))
requires(forall(l1, 0, 5,
array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND)))
assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N))
);
#endif
#endif
#if defined(MLD_USE_NATIVE_POLYVECL_POINTWISE_ACC_MONTGOMERY_L7)
#if defined(MLD_CONFIG_MULTILEVEL_WITH_SHARED) || MLDSA_L == 7
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int mld_polyvecl_pointwise_acc_montgomery_l7_native(
int32_t w[MLDSA_N], const int32_t u[7][MLDSA_N],
const int32_t v[7][MLDSA_N])
__contract__(
requires(memory_no_alias(w, sizeof(int32_t) * MLDSA_N))
requires(memory_no_alias(u, sizeof(int32_t) * 7 * MLDSA_N))
requires(memory_no_alias(v, sizeof(int32_t) * 7 * MLDSA_N))
requires(forall(l0, 0, 7,
array_bound(u[l0], 0, MLDSA_N, 0, MLDSA_Q)))
requires(forall(l1, 0, 7,
array_abs_bound(v[l1], 0, MLDSA_N, MLD_NTT_BOUND)))
assigns(memory_slice(w, sizeof(int32_t) * MLDSA_N))
ensures(return_value == MLD_NATIVE_FUNC_FALLBACK || return_value == MLD_NATIVE_FUNC_SUCCESS)
ensures((return_value == MLD_NATIVE_FUNC_SUCCESS) ==> array_abs_bound(w, 0, MLDSA_N, MLDSA_Q))
ensures((return_value == MLD_NATIVE_FUNC_FALLBACK) ==> array_unchanged(w, MLDSA_N))
);
#endif
#endif
#endif