104 lines
2.1 KiB
C
104 lines
2.1 KiB
C
#include "random.h"
|
|
|
|
#include <fx/core/random.h>
|
|
|
|
#define GET_ALGORITHM_ID(flags) ((flags) & 0xFF)
|
|
|
|
FX_API struct fx_random_algorithm z__fx_gen_mt19937;
|
|
|
|
static struct fx_random_algorithm *generators[] = {
|
|
[FX_RANDOM_MT19937] = &z__fx_gen_mt19937,
|
|
};
|
|
static size_t nr_generators = sizeof generators / sizeof generators[0];
|
|
|
|
static struct fx_random_ctx g_global_ctx = {0};
|
|
|
|
static void init_global_ctx(void)
|
|
{
|
|
fx_random_init(&g_global_ctx, FX_RANDOM_MT19937);
|
|
}
|
|
|
|
struct fx_random_ctx *fx_random_global_ctx(void)
|
|
{
|
|
if (!g_global_ctx.__f) {
|
|
init_global_ctx();
|
|
}
|
|
|
|
return &g_global_ctx;
|
|
}
|
|
|
|
fx_status fx_random_init(struct fx_random_ctx *ctx, fx_random_flags flags)
|
|
{
|
|
unsigned int algorithm_id = GET_ALGORITHM_ID(flags);
|
|
if (algorithm_id >= nr_generators || !generators[algorithm_id]) {
|
|
return FX_ERR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
struct fx_random_algorithm *algorithm = generators[algorithm_id];
|
|
|
|
ctx->__f = flags;
|
|
ctx->__a = algorithm;
|
|
|
|
unsigned long long seed;
|
|
if (flags & FX_RANDOM_SECURE) {
|
|
seed = z__fx_platform_random_seed_secure();
|
|
} else {
|
|
seed = z__fx_platform_random_seed();
|
|
}
|
|
|
|
algorithm->gen_init(ctx, seed);
|
|
|
|
return FX_SUCCESS;
|
|
}
|
|
|
|
unsigned long long fx_random_next_int64(struct fx_random_ctx *ctx)
|
|
{
|
|
if (!ctx->__a || !ctx->__a->gen_getrand) {
|
|
return 0;
|
|
}
|
|
|
|
return ctx->__a->gen_getrand(ctx);
|
|
}
|
|
|
|
double fx_random_next_double(struct fx_random_ctx *ctx)
|
|
{
|
|
unsigned long long v = fx_random_next_int64(ctx);
|
|
if (!v) {
|
|
return 0.0;
|
|
}
|
|
|
|
return (double)(v >> 11) * (1.0 / 9007199254740991.0);
|
|
}
|
|
|
|
void fx_random_next_bytes(struct fx_random_ctx *ctx, unsigned char *out, size_t nbytes)
|
|
{
|
|
size_t n_qwords = 0;
|
|
n_qwords = nbytes >> 3;
|
|
|
|
if ((n_qwords << 3) < nbytes) {
|
|
n_qwords++;
|
|
}
|
|
|
|
size_t bytes_written = 0;
|
|
for (size_t i = 0; i < n_qwords; i++) {
|
|
uint64_t *dest = (uint64_t *)&out[bytes_written];
|
|
*dest = fx_random_next_int64(ctx);
|
|
bytes_written += 8;
|
|
}
|
|
|
|
if (bytes_written == nbytes) {
|
|
return;
|
|
}
|
|
|
|
uint64_t padding = fx_random_next_int64(ctx);
|
|
unsigned char *padding_bytes = (unsigned char *)&padding;
|
|
|
|
for (size_t i = 0; i < 8; i++) {
|
|
out[bytes_written++] = padding_bytes[i];
|
|
|
|
if (bytes_written == nbytes) {
|
|
break;
|
|
}
|
|
}
|
|
}
|