Line data Source code
1 : /*
2 : * libpoporon - rng.c
3 : *
4 : * This file is part of libpoporon.
5 : *
6 : * Author: Go Kudo <zeriyoshi@gmail.com>
7 : * SPDX-License-Identifier: BSD-3-Clause
8 : */
9 :
10 : #include <stdlib.h>
11 : #include <string.h>
12 :
13 : #include <poporon/rng.h>
14 :
15 : #include "internal/common.h"
16 :
17 : #define SPLITMIX32_CONST_0 0x6C078965U
18 : #define SPLITMIX32_CONST_1 0x9D2C5680U
19 : #define SPLITMIX32_CONST_2 0xEFC60000U
20 : #define SPLITMIX32_CONST_3 0x12345678U
21 :
22 : struct _poporon_rng_t {
23 : poporon_rng_type_t type;
24 : uint32_t s[4];
25 : };
26 :
27 783824 : static inline uint32_t rotl(uint32_t x, int k)
28 : {
29 783824 : return (x << k) | (x >> (32 - k));
30 : }
31 :
32 504 : static inline uint32_t splitmix32(uint32_t z)
33 : {
34 504 : z = (z ^ (z >> 16)) * 0x85EBCA6BU;
35 504 : z = (z ^ (z >> 13)) * 0xC2B2AE35U;
36 504 : return z ^ (z >> 16);
37 : }
38 :
39 126 : static inline void xoshiro128pp_init(poporon_rng_t *rng, const void *seed, size_t seed_size)
40 : {
41 : uint32_t s, z;
42 :
43 126 : s = 0;
44 126 : if (seed && seed_size > 0) {
45 125 : memcpy(&s, seed, seed_size < sizeof(uint32_t) ? seed_size : sizeof(uint32_t));
46 : }
47 :
48 126 : z = s + SPLITMIX32_CONST_0;
49 126 : rng->s[0] = splitmix32(z);
50 :
51 126 : z = rng->s[0] + SPLITMIX32_CONST_1;
52 126 : rng->s[1] = splitmix32(z);
53 :
54 126 : z = rng->s[1] + SPLITMIX32_CONST_2;
55 126 : rng->s[2] = splitmix32(z);
56 :
57 126 : z = rng->s[2] + SPLITMIX32_CONST_3;
58 126 : rng->s[3] = splitmix32(z);
59 126 : }
60 :
61 391912 : static inline uint32_t xoshiro128pp_next(poporon_rng_t *rng)
62 : {
63 : uint32_t result, t;
64 :
65 391912 : result = rotl(rng->s[0] + rng->s[3], 7) + rng->s[0];
66 391912 : t = rng->s[1] << 9;
67 :
68 391912 : rng->s[2] ^= rng->s[0];
69 391912 : rng->s[3] ^= rng->s[1];
70 391912 : rng->s[1] ^= rng->s[2];
71 391912 : rng->s[0] ^= rng->s[3];
72 391912 : rng->s[2] ^= t;
73 391912 : rng->s[3] = rotl(rng->s[3], 11);
74 :
75 391912 : return result;
76 : }
77 :
78 126 : extern poporon_rng_t *poporon_rng_create(poporon_rng_type_t type, void *seed, size_t seed_size)
79 : {
80 : poporon_rng_t *rng;
81 :
82 126 : rng = (poporon_rng_t *)pcalloc(1, sizeof(poporon_rng_t));
83 126 : if (!rng) {
84 0 : return NULL;
85 : }
86 :
87 126 : rng->type = type;
88 :
89 : switch (type) {
90 : case XOSHIRO128PP:
91 : default:
92 126 : xoshiro128pp_init(rng, seed, seed_size);
93 126 : break;
94 : }
95 :
96 126 : return rng;
97 : }
98 :
99 127 : extern void poporon_rng_destroy(poporon_rng_t *rng)
100 : {
101 127 : if (rng) {
102 126 : pfree(rng);
103 : }
104 127 : }
105 :
106 391911 : extern bool poporon_rng_next(poporon_rng_t *rng, void *dest, size_t size)
107 : {
108 : uint8_t *p;
109 : uint32_t val;
110 : size_t i, remaining;
111 :
112 391911 : if (!rng || !dest || size == 0) {
113 3 : return false;
114 : }
115 :
116 391908 : p = (uint8_t *)dest;
117 391908 : i = 0;
118 :
119 783818 : while (i + 4 <= size) {
120 391910 : val = xoshiro128pp_next(rng);
121 391910 : pmemcpy(p + i, &val, 4);
122 391910 : i += 4;
123 : }
124 :
125 391908 : remaining = size - i;
126 391908 : if (remaining > 0) {
127 2 : val = xoshiro128pp_next(rng);
128 2 : pmemcpy(p + i, &val, remaining);
129 : }
130 :
131 391908 : return true;
132 : }
|