1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
// The Well Equidistributed Long-period Linear PRNG 512a variant
// http://www.iro.umontreal.ca/~panneton/well/WELL512a.c
/* ***************************************************************************** */
/* Copyright: Francois Panneton and Pierre L'Ecuyer, University of Montreal */
/* Makoto Matsumoto, Hiroshima University */
/* Notice: This code can be used freely for personal, academic, */
/* or non-commercial purposes. For commercial purposes, */
/* please contact P. L'Ecuyer at: lecuyer@iro.UMontreal.ca */
/* ***************************************************************************** */
#include "rnd.h"
#include "util_rt.h"
#include <string.h>
#include <errno.h>
typedef struct {
uint32_t state[16];
size_t index;
} rnd_well512_ctx_t;
static uint32_t rnd_well512_pull (rnd_well512_ctx_t *ctx) {
uint32_t a, b, c, d;
a = ctx->state[ctx->index];
c = ctx->state[(ctx->index + 13) & 15];
b = a ^ c ^ (a << 16) ^ (c << 15);
c = ctx->state[(ctx->index + 9) & 15];
c ^= (c >> 11);
a = ctx->state[ctx->index] = b ^ c;
d = a ^ ((a << 5) & 0xDA442D24UL);
ctx->index = (ctx->index + 15) & 15;
a = ctx->state[ctx->index];
ctx->state[ctx->index] = a ^ b ^ d ^ (a << 2) ^ (b << 18) ^ (c << 28);
return ctx->state[ctx->index];
}
static bool rnd_well512_f (void *p, uint8_t *buf, size_t len) {
rnd_well512_ctx_t *ctx = (rnd_well512_ctx_t*)p;
size_t consume;
uint32_t n;
while (len > 0) {
n = rnd_well512_pull(ctx);
consume = prne_op_min(len, sizeof(n));
memcpy(buf, &n, consume);
buf += consume;
len -= consume;
}
return true;
}
static void rnd_free_well512 (void *p) {
prne_free(p);
}
bool prne_rnd_alloc_well512 (
prne_rnd_t *p,
const uint8_t *is)
{
rnd_well512_ctx_t *ctx;
ctx = (rnd_well512_ctx_t*)prne_calloc(sizeof(rnd_well512_ctx_t), 1);
if (ctx == NULL) {
return false;
}
prne_free_rnd(p);
memcpy(ctx->state, is, sizeof(ctx->state));
p->ctx = ctx;
p->free_ctx_f = rnd_free_well512;
p->random = rnd_well512_f;
return true;
}
|