aboutsummaryrefslogtreecommitdiff
path: root/src/rnd_well512.c
blob: 89fde9f96cd8efb66acee5b9385947f5b4c5d55f (plain)
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;
}