aboutsummaryrefslogtreecommitdiff
path: root/src/rnd_well512.c
blob: a6bca13d7734aa1c3146e6aebfadb2b0ec2ad10b (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
#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;
}