#ifndef MLD_CT_H
#define MLD_CT_H
#include "cbmc.h"
#include "common.h"
#if defined(MLD_HAVE_INLINE_ASM) && !defined(MLD_CONFIG_NO_ASM_VALUE_BARRIER)
#define MLD_USE_ASM_VALUE_BARRIER
#endif
#if !defined(MLD_USE_ASM_VALUE_BARRIER)
#define mld_ct_opt_blocker_u64 MLD_NAMESPACE(ct_opt_blocker_u64)
extern volatile uint64_t mld_ct_opt_blocker_u64;
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint64_t mld_ct_get_optblocker_u64(void)
__contract__(ensures(return_value == 0)) { return mld_ct_opt_blocker_u64; }
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int64_t mld_ct_get_optblocker_i64(void)
__contract__(ensures(return_value == 0)) { return (int64_t)mld_ct_get_optblocker_u64(); }
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint32_t mld_ct_get_optblocker_u32(void)
__contract__(ensures(return_value == 0)) { return (uint32_t)mld_ct_get_optblocker_u64(); }
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint8_t mld_ct_get_optblocker_u8(void)
__contract__(ensures(return_value == 0)) { return (uint8_t)mld_ct_get_optblocker_u64(); }
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b)
__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_i64()); }
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b)
__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u32()); }
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b)
__contract__(ensures(return_value == b)) { return (b ^ mld_ct_get_optblocker_u8()); }
#else
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int64_t mld_value_barrier_i64(int64_t b)
__contract__(ensures(return_value == b))
{
__asm__ volatile("" : "+r"(b));
return b;
}
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint32_t mld_value_barrier_u32(uint32_t b)
__contract__(ensures(return_value == b))
{
__asm__ volatile("" : "+r"(b));
return b;
}
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint8_t mld_value_barrier_u8(uint8_t b)
__contract__(ensures(return_value == b))
{
__asm__ volatile("" : "+r"(b));
return b;
}
#endif
#ifdef CBMC
#pragma CPROVER check push
#pragma CPROVER check disable "conversion"
#endif
MLD_MUST_CHECK_RETURN_VALUE
static MLD_ALWAYS_INLINE int32_t mld_cast_uint32_to_int32(uint32_t x)
{
return (int32_t)x;
}
#ifdef CBMC
#pragma CPROVER check pop
#endif
MLD_MUST_CHECK_RETURN_VALUE
static MLD_ALWAYS_INLINE uint32_t mld_cast_int64_to_uint32(int64_t x)
{
return (uint32_t)(x & (int64_t)UINT32_MAX);
}
MLD_MUST_CHECK_RETURN_VALUE
static MLD_ALWAYS_INLINE uint32_t mld_cast_int32_to_uint32(int32_t x)
{
return mld_cast_int64_to_uint32((int64_t)x);
}
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int32_t mld_ct_sel_int32(int32_t a, int32_t b, uint32_t cond)
__contract__(
requires(cond == 0x0 || cond == 0xFFFFFFFF)
ensures(return_value == (cond ? a : b))
)
{
uint32_t au = mld_cast_int32_to_uint32(a);
uint32_t bu = mld_cast_int32_to_uint32(b);
uint32_t res = bu ^ (mld_value_barrier_u32(cond) & (au ^ bu));
return mld_cast_uint32_to_int32(res);
}
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint32_t mld_ct_cmask_nonzero_u32(uint32_t x)
__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFFFFFFFF)))
{
int64_t tmp = mld_value_barrier_i64(-((int64_t)x));
tmp >>= 32;
return mld_cast_int64_to_uint32(tmp);
}
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint8_t mld_ct_cmask_nonzero_u8(uint8_t x)
__contract__(ensures(return_value == ((x == 0) ? 0 : 0xFF)))
{
uint32_t mask = mld_ct_cmask_nonzero_u32((uint32_t)x);
return (uint8_t)(mask & 0xFF);
}
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint32_t mld_ct_cmask_neg_i32(int32_t x)
__contract__(
ensures(return_value == ((x < 0) ? 0xFFFFFFFF : 0))
)
{
int64_t tmp = mld_value_barrier_i64((int64_t)x);
tmp >>= 31;
return mld_cast_int64_to_uint32(tmp);
}
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE int32_t mld_ct_abs_i32(int32_t x)
__contract__(
requires(x >= -INT32_MAX)
ensures(return_value == ((x < 0) ? -x : x))
)
{
return mld_ct_sel_int32(-x, x, mld_ct_cmask_neg_i32(x));
}
MLD_MUST_CHECK_RETURN_VALUE
static MLD_INLINE uint8_t mld_ct_memcmp(const uint8_t *a, const uint8_t *b,
const size_t len)
__contract__(
requires(len <= UINT16_MAX)
requires(memory_no_alias(a, len))
requires(memory_no_alias(b, len))
ensures((return_value == 0) || (return_value == 0xFF))
ensures((return_value == 0) == forall(i, 0, len, (a[i] == b[i]))))
{
uint8_t r = 0, s = 0;
unsigned i;
for (i = 0; i < len; i++)
__loop__(
invariant(i <= len)
invariant((r == 0) == (forall(k, 0, i, (a[k] == b[k]))))
decreases(len - i))
{
r |= a[i] ^ b[i];
s ^= a[i] ^ b[i];
}
return (mld_value_barrier_u8(mld_ct_cmask_nonzero_u8(r) ^ s) ^ s);
}
#if !defined(MLD_CONFIG_CUSTOM_ZEROIZE)
#if defined(MLD_SYS_WINDOWS)
#include <windows.h>
static MLD_INLINE void mld_zeroize(void *ptr, size_t len)
__contract__(
requires(memory_no_alias(ptr, len))
assigns(memory_slice(ptr, len))) { SecureZeroMemory(ptr, len); }
#elif defined(MLD_HAVE_INLINE_ASM)
#include <string.h>
static MLD_INLINE void mld_zeroize(void *ptr, size_t len)
__contract__(
requires(memory_no_alias(ptr, len))
assigns(memory_slice(ptr, len)))
{
memset(ptr, 0, len);
__asm__ __volatile__("" : : "r"(ptr) : "memory");
}
#else
#error No plausibly-secure implementation of mld_zeroize available. Please provide your own using MLD_CONFIG_CUSTOM_ZEROIZE.
#endif
#endif
#endif