#if !defined(OQS_USE_OPENSSL) && !defined(_WIN32) && !defined(OQS_HAVE_EXPLICIT_BZERO) && !defined(OQS_HAVE_EXPLICIT_MEMSET)
#define __STDC_WANT_LIB_EXT1__ 1
#endif
#include <oqs/common.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stddef.h>
#if defined(OQS_DIST_BUILD) && defined(OQS_USE_PTHREADS)
#include <pthread.h>
#endif
#if !defined(OQS_HAVE_POSIX_MEMALIGN) || defined(__MINGW32__) || defined(__MINGW64__) || defined(_MSC_VER)
#include <malloc.h>
#endif
#if defined(_WIN32)
#include <windows.h>
#endif
#if defined(OQS_USE_OPENSSL)
#include "ossl_helpers.h"
#endif
#if defined(OQS_DIST_BUILD)
static unsigned int cpu_ext_data[OQS_CPU_EXT_COUNT] = {0};
#if defined(OQS_USE_PTHREADS)
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
#endif
#endif
#if defined(OQS_DIST_X86_64_BUILD)
#include "x86_64_helpers.h"
static void set_available_cpu_extensions(void) {
cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
cpuid_out leaf_1;
cpuid(&leaf_1, 1);
if (leaf_1.eax == 0) {
return;
}
cpuid_out leaf_7;
cpuid(&leaf_7, 7);
const unsigned int has_xsave = is_bit_set(leaf_1.ecx, 26);
const unsigned int has_osxsave = is_bit_set(leaf_1.ecx, 27);
const uint32_t xcr0_eax = (has_xsave && has_osxsave) ? xgetbv_eax(0) : 0;
cpu_ext_data[OQS_CPU_EXT_AES] = is_bit_set(leaf_1.ecx, 25);
if (has_mask(xcr0_eax, MASK_XMM | MASK_YMM)) {
cpu_ext_data[OQS_CPU_EXT_AVX] = is_bit_set(leaf_1.ecx, 28);
cpu_ext_data[OQS_CPU_EXT_AVX2] = is_bit_set(leaf_7.ebx, 5);
}
cpu_ext_data[OQS_CPU_EXT_PCLMULQDQ] = is_bit_set(leaf_1.ecx, 1);
cpu_ext_data[OQS_CPU_EXT_POPCNT] = is_bit_set(leaf_1.ecx, 23);
cpu_ext_data[OQS_CPU_EXT_BMI1] = is_bit_set(leaf_7.ebx, 3);
cpu_ext_data[OQS_CPU_EXT_BMI2] = is_bit_set(leaf_7.ebx, 8);
cpu_ext_data[OQS_CPU_EXT_ADX] = is_bit_set(leaf_7.ebx, 19);
if (has_mask(xcr0_eax, MASK_XMM)) {
cpu_ext_data[OQS_CPU_EXT_SSE] = is_bit_set(leaf_1.edx, 25);
cpu_ext_data[OQS_CPU_EXT_SSE2] = is_bit_set(leaf_1.edx, 26);
cpu_ext_data[OQS_CPU_EXT_SSE3] = is_bit_set(leaf_1.ecx, 0);
}
if (has_mask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 | MASK_ZMM16_31)) {
unsigned int avx512f = is_bit_set(leaf_7.ebx, 16);
unsigned int avx512bw = is_bit_set(leaf_7.ebx, 30);
unsigned int avx512dq = is_bit_set(leaf_7.ebx, 17);
if (avx512f && avx512bw && avx512dq) {
cpu_ext_data[OQS_CPU_EXT_AVX512] = 1;
}
cpu_ext_data[OQS_CPU_EXT_VPCLMULQDQ] = is_bit_set(leaf_7.ecx, 10);
}
}
#elif defined(OQS_DIST_X86_BUILD)
static void set_available_cpu_extensions(void) {
cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
}
#elif defined(OQS_DIST_ARM64_V8_BUILD)
#if defined(__APPLE__)
#include <sys/sysctl.h>
static unsigned int macos_feature_detection(const char *feature_name) {
int p;
size_t p_len = sizeof(p);
int res = sysctlbyname(feature_name, &p, &p_len, NULL, 0);
if (res != 0) {
return 0;
} else {
return (p != 0) ? 1 : 0;
}
}
static void set_available_cpu_extensions(void) {
cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
cpu_ext_data[OQS_CPU_EXT_ARM_SHA3] = macos_feature_detection("hw.optional.armv8_2_sha3");
cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = macos_feature_detection("hw.optional.neon");
cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
}
#elif defined(__FreeBSD__) || defined(__FreeBSD)
#include <sys/auxv.h>
#include <machine/elf.h>
static void set_available_cpu_extensions(void) {
u_long hwcaps = 0;
cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
if (elf_aux_info(AT_HWCAP, &hwcaps, sizeof(u_long))) {
fprintf(stderr, "Error getting HWCAP for ARM on FreeBSD\n");
return;
}
if (hwcaps & HWCAP_AES) {
cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
}
if (hwcaps & HWCAP_ASIMD) {
cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
}
if (hwcaps & HWCAP_SHA2) {
cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
}
#ifdef HWCAP_SHA3
if (hwcaps & HWCAP_SHA3) {
cpu_ext_data[OQS_CPU_EXT_ARM_SHA3] = 1;
}
#endif
}
#elif defined(_WIN32)
static void set_available_cpu_extensions(void) {
cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
BOOL crypto = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
if (crypto) {
cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
}
BOOL neon = IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
if (neon) {
cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
}
}
#else
#include <sys/auxv.h>
#include <asm/hwcap.h>
static void set_available_cpu_extensions(void) {
cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
unsigned long int hwcaps = getauxval(AT_HWCAP);
if (hwcaps & HWCAP_AES) {
cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
}
if (hwcaps & HWCAP_SHA2) {
cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
}
#ifdef HWCAP_SHA3
if (hwcaps & HWCAP_SHA3) {
cpu_ext_data[OQS_CPU_EXT_ARM_SHA3] = 1;
}
#endif
if (hwcaps & HWCAP_ASIMD) {
cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
}
}
#endif
#elif defined(OQS_DIST_ARM32v7_BUILD)
#include <sys/auxv.h>
#include <asm/hwcap.h>
static void set_available_cpu_extensions(void) {
cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
unsigned long int hwcaps = getauxval(AT_HWCAP);
unsigned long int hwcaps2 = getauxval(AT_HWCAP2);
if (hwcaps2 & HWCAP2_AES) {
cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
}
if (hwcaps2 & HWCAP2_SHA2) {
cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
}
if (hwcaps & HWCAP_NEON) {
cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
}
}
#elif defined(OQS_DIST_PPC64LE_BUILD)
static void set_available_cpu_extensions(void) {
cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
}
#elif defined(OQS_DIST_S390X_BUILD)
static void set_available_cpu_extensions(void) {
cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
}
#elif defined(OQS_DIST_LOONGARCH64_BUILD)
static void set_available_cpu_extensions(void) {
cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
}
#elif defined(OQS_DIST_BUILD)
static void set_available_cpu_extensions(void) {
}
#endif
OQS_API int OQS_CPU_has_extension(OQS_CPU_EXT ext) {
#if defined(OQS_DIST_BUILD)
#if defined(OQS_USE_PTHREADS)
pthread_once(&once_control, &set_available_cpu_extensions);
#else
if (0 == cpu_ext_data[OQS_CPU_EXT_INIT]) {
set_available_cpu_extensions();
}
#endif
if (0 < ext && ext < OQS_CPU_EXT_COUNT) {
return (int)cpu_ext_data[ext];
}
#else
(void)ext;
#endif
return 0;
}
OQS_API void OQS_init(void) {
#if defined(OQS_DIST_BUILD)
OQS_CPU_has_extension(OQS_CPU_EXT_INIT);
#endif
}
OQS_API void OQS_thread_stop(void) {
#if defined(OQS_USE_OPENSSL)
oqs_thread_stop();
#endif
}
OQS_API const char *OQS_version(void) {
return OQS_VERSION_TEXT;
}
OQS_API void OQS_destroy(void) {
#if defined(OQS_USE_OPENSSL)
oqs_ossl_destroy();
#endif
}
OQS_API int OQS_MEM_secure_bcmp(const void *a, const void *b, size_t len) {
uint8_t r = 0;
for (size_t i = 0; i < len; i++) {
r |= ((const uint8_t *)a)[i] ^ ((const uint8_t *)b)[i];
}
return 1 & ((-(unsigned int)r) >> 8);
}
OQS_API void OQS_MEM_cleanse(void *ptr, size_t len) {
if (ptr == NULL) {
return;
}
#if defined(OQS_USE_OPENSSL)
OSSL_FUNC(OPENSSL_cleanse)(ptr, len);
#elif defined(_WIN32)
SecureZeroMemory(ptr, len);
#elif defined(OQS_HAVE_EXPLICIT_BZERO)
explicit_bzero(ptr, len);
#elif defined(OQS_HAVE_EXPLICIT_MEMSET)
explicit_memset(ptr, 0, len);
#elif defined(__STDC_LIB_EXT1__) || defined(OQS_HAVE_MEMSET_S)
if (0U < len && memset_s(ptr, (rsize_t)len, 0, (rsize_t)len) != 0) {
abort();
}
#else
typedef void *(*memset_t)(void *, int, size_t);
static volatile memset_t memset_func = memset;
memset_func(ptr, 0, len);
#endif
}
OQS_API void OQS_MEM_secure_free(void *ptr, size_t len) {
if (ptr != NULL) {
OQS_MEM_cleanse(ptr, len);
OQS_MEM_insecure_free(ptr);
}
}
OQS_API void OQS_MEM_insecure_free(void *ptr) {
#if defined(OQS_USE_OPENSSL) && defined(OPENSSL_VERSION_NUMBER)
OSSL_FUNC(CRYPTO_free)(ptr, OPENSSL_FILE, OPENSSL_LINE);
#else
free(ptr); #endif
}
void *OQS_MEM_aligned_alloc(size_t alignment, size_t size) {
#if defined(OQS_USE_OPENSSL)
if (!size) {
return NULL;
}
const size_t offset = alignment - 1 + sizeof(uint8_t);
uint8_t *buffer = OSSL_FUNC(CRYPTO_malloc)(size + offset, OPENSSL_FILE, OPENSSL_LINE);
if (!buffer) {
return NULL;
}
uint8_t *ptr = (uint8_t *)(((uintptr_t)(buffer) + offset) & ~(alignment - 1));
ptrdiff_t diff = ptr - buffer;
if (diff > UINT8_MAX) {
OSSL_FUNC(CRYPTO_free)(buffer, OPENSSL_FILE, OPENSSL_LINE);
errno = EINVAL;
return NULL;
}
ptr[-1] = (uint8_t)diff;
return ptr;
#elif defined(OQS_HAVE_ALIGNED_ALLOC)
return aligned_alloc(alignment, size);
#else
if (alignment & (alignment - 1) || size & (alignment - 1) || alignment < sizeof(void *)) {
errno = EINVAL;
return NULL;
}
#if defined(OQS_HAVE_POSIX_MEMALIGN)
void *ptr = NULL;
const int err = posix_memalign(&ptr, alignment, size);
if (err) {
errno = err;
ptr = NULL;
}
return ptr;
#elif defined(OQS_HAVE_MEMALIGN)
return memalign(alignment, size);
#elif defined(__MINGW32__) || defined(__MINGW64__)
return __mingw_aligned_malloc(size, alignment);
#elif defined(_MSC_VER)
return _aligned_malloc(size, alignment);
#else
if (!size) {
return NULL;
}
const size_t offset = alignment - 1 + sizeof(uint8_t);
uint8_t *buffer = malloc(size + offset); if (!buffer) {
return NULL;
}
uint8_t *ptr = (uint8_t *)(((uintptr_t)(buffer) + offset) & ~(alignment - 1));
ptrdiff_t diff = ptr - buffer;
if (diff > UINT8_MAX) {
free(buffer); errno = EINVAL;
return NULL;
}
ptr[-1] = diff;
return ptr;
#endif
#endif
}
void OQS_MEM_aligned_free(void *ptr) {
if (ptr == NULL) {
return;
}
#if defined(OQS_USE_OPENSSL)
uint8_t *u8ptr = ptr;
OSSL_FUNC(CRYPTO_free)(u8ptr - u8ptr[-1], OPENSSL_FILE, OPENSSL_LINE);
#elif defined(OQS_HAVE_ALIGNED_ALLOC) || defined(OQS_HAVE_POSIX_MEMALIGN) || defined(OQS_HAVE_MEMALIGN)
free(ptr); #elif defined(__MINGW32__) || defined(__MINGW64__)
__mingw_aligned_free(ptr);
#elif defined(_MSC_VER)
_aligned_free(ptr);
#else
uint8_t *u8ptr = ptr;
free(u8ptr - u8ptr[-1]); #endif
}
OQS_API void *OQS_MEM_malloc(size_t size) {
#if defined(OQS_USE_OPENSSL)
return OSSL_FUNC(CRYPTO_malloc)(size, OPENSSL_FILE, OPENSSL_LINE);
#else
return malloc(size); #endif
}
OQS_API void *OQS_MEM_calloc(size_t num_elements, size_t element_size) {
#if defined(OQS_USE_OPENSSL)
return OSSL_FUNC(CRYPTO_zalloc)(num_elements * element_size,
OPENSSL_FILE, OPENSSL_LINE);
#else
return calloc(num_elements, element_size); #endif
}
OQS_API char *OQS_MEM_strdup(const char *str) {
#if defined(OQS_USE_OPENSSL)
return OSSL_FUNC(CRYPTO_strdup)(str, OPENSSL_FILE, OPENSSL_LINE);
#else
return strdup(str); #endif
}