104 lines
2.1 KiB
C
104 lines
2.1 KiB
C
|
|
#include "random.h"
|
||
|
|
|
||
|
|
#include <blue/core/random.h>
|
||
|
|
|
||
|
|
#define GET_ALGORITHM_ID(flags) ((flags) & 0xFF)
|
||
|
|
|
||
|
|
extern struct b_random_algorithm z__b_gen_mt19937;
|
||
|
|
|
||
|
|
static struct b_random_algorithm *generators[] = {
|
||
|
|
[B_RANDOM_MT19937] = &z__b_gen_mt19937,
|
||
|
|
};
|
||
|
|
static size_t nr_generators = sizeof generators / sizeof generators[0];
|
||
|
|
|
||
|
|
static struct b_random_ctx g_global_ctx = {0};
|
||
|
|
|
||
|
|
static void init_global_ctx(void)
|
||
|
|
{
|
||
|
|
b_random_init(&g_global_ctx, B_RANDOM_MT19937);
|
||
|
|
}
|
||
|
|
|
||
|
|
struct b_random_ctx *b_random_global_ctx(void)
|
||
|
|
{
|
||
|
|
if (!g_global_ctx.__f) {
|
||
|
|
init_global_ctx();
|
||
|
|
}
|
||
|
|
|
||
|
|
return &g_global_ctx;
|
||
|
|
}
|
||
|
|
|
||
|
|
b_status b_random_init(struct b_random_ctx *ctx, b_random_flags flags)
|
||
|
|
{
|
||
|
|
unsigned int algorithm_id = GET_ALGORITHM_ID(flags);
|
||
|
|
if (algorithm_id >= nr_generators || !generators[algorithm_id]) {
|
||
|
|
return B_ERR_INVALID_ARGUMENT;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct b_random_algorithm *algorithm = generators[algorithm_id];
|
||
|
|
|
||
|
|
ctx->__f = flags;
|
||
|
|
ctx->__a = algorithm;
|
||
|
|
|
||
|
|
unsigned long long seed;
|
||
|
|
if (flags & B_RANDOM_SECURE) {
|
||
|
|
seed = z__b_platform_random_seed_secure();
|
||
|
|
} else {
|
||
|
|
seed = z__b_platform_random_seed();
|
||
|
|
}
|
||
|
|
|
||
|
|
algorithm->gen_init(ctx, seed);
|
||
|
|
|
||
|
|
return B_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
unsigned long long b_random_next_int64(struct b_random_ctx *ctx)
|
||
|
|
{
|
||
|
|
if (!ctx->__a || !ctx->__a->gen_getrand) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ctx->__a->gen_getrand(ctx);
|
||
|
|
}
|
||
|
|
|
||
|
|
double b_random_next_double(struct b_random_ctx *ctx)
|
||
|
|
{
|
||
|
|
unsigned long long v = b_random_next_int64(ctx);
|
||
|
|
if (!v) {
|
||
|
|
return 0.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return (double)(v >> 11) * (1.0 / 9007199254740991.0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void b_random_next_bytes(struct b_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 = b_random_next_int64(ctx);
|
||
|
|
bytes_written += 8;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (bytes_written == nbytes) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t padding = b_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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|