CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Loading...
Searching...
No Matches
xoroshiro.h
Go to the documentation of this file.
1// Copyright Microsoft and CHERIoT Contributors.
2// SPDX-License-Identifier: MIT
3//
4// Imported from snmalloc 4f9d991449380ed7d881a25ba02cc5668c1ff394.
5
6#pragma once
7
8#include <cstdint>
9#include <cstdlib>
10#include <debug.hh>
11#include <initializer_list>
12
13/**
14 * \file
15 * Pseudo random number generator based on Xoroshiro algorithm. Rather
16 * than using this directly you should probably use an implementation of the
17 * IsEntropySource concept so that different entropy sources may be substituted.
18 */
19
20namespace ds::xoroshiro
21{
22
23 namespace detail
24 {
25 using Debug = ConditionalDebug<false, "xoroshiro">;
26
27 /**
28 * The xoroshiro+ (not ++) generator(s) of Blackman and Vigna's
29 * Scrambled Linear Pseudorandom Number Generators
30 * (https://arxiv.org/abs/1805.01407, Figure 1).
31 *
32 * This spelling is parameterized on the type of the two state
33 * variables used internally (State), the type of each sample (Result),
34 * and the seed state values (A, B, C).
35 */
36 template<typename State,
37 typename Result,
38 State A,
39 State B,
40 State C,
41 State Jump0 = 0,
42 State Jump1 = 0,
43 State LongJump0 = 0,
44 State LongJump1 = 0>
45 class XorOshiro
46 {
47 private:
48 static constexpr unsigned StateBits = 8 * sizeof(State);
49 static constexpr unsigned ResultBits = 8 * sizeof(Result);
50
51 static_assert(StateBits >= ResultBits,
52 "State must have at least as many bits as Result");
53
54 /* Parameters must be valid shifts */
55 static_assert(0 <= A && A <= StateBits);
56 static_assert(0 <= B && B <= StateBits);
57 static_assert(0 <= C && C <= StateBits);
58
59 State x;
60 State y;
61
62 static inline State rotl(State x, State k)
63 {
64 return (x << k) | (x >> (StateBits - k));
65 }
66
67 void jump(State jump0, State jump1)
68 {
69 const State Jump[] = {jump0, jump1};
70 uint64_t s0 = 0;
71 uint64_t s1 = 0;
72 for (int i : {0, 1})
73 {
74 for (int b = 0; b < 64; b++)
75 {
76 if (Jump[i] & static_cast<uint64_t>(1) << b)
77 {
78 s0 ^= x;
79 s1 ^= y;
80 }
81 next();
82 }
83 }
84 x = s0;
85 y = s1;
86 }
87
88 public:
89 XorOshiro(State x = 5489, State y = 0) : x(x), y(y)
90 {
91 // If both zero, then this does not work
92 Debug::Invariant((x != 0) || (y != 0),
93 "Invalid state, both x and y are zero");
94
95 next();
96 }
97
98 void set_state(State nx, State ny = 0)
99 {
100 // If both zero, then this does not work
101 Debug::Invariant((nx != 0) || (ny != 0),
102 "Invalid state, both nx and ny are zero");
103
104 x = nx;
105 y = ny;
106 next();
107 }
108
109 Result next()
110 {
111 State oldX = x;
112 State oldY = y;
113 State r = x + y;
114 y ^= x;
115 x = rotl(x, A) ^ y ^ (y << B);
116 y = rotl(y, C);
117 // If both zero, then this does not work
118 Debug::Invariant((x != 0) || (y != 0),
119 "Invalid state, both x and y are zero after "
120 "next() with x: {}, y: {}",
121 oldX,
122 oldY);
123 return r >> (StateBits - ResultBits);
124 }
125
126 Result operator()()
127 {
128 return next();
129 }
130
131 /**
132 * Jump. If supported, this is equivalent to 2^64 calls to next().
133 */
134 void jump()
135 requires(Jump0 != 0) && (Jump1 != 0)
136 {
137 jump(Jump0, Jump1);
138 }
139
140 /**
141 * Jump a *really* long way. If supported, this is equivalent to
142 * 2^96 calls to next().
143 */
145 requires(LongJump0 != 0) && (LongJump1 != 0)
146 {
147 jump(LongJump0, LongJump1);
148 }
149 };
150 } // namespace detail
151
152 /**
153 * xoroshiro128+ with 64-bit output using the 2018 parameters.
154 *
155 * Parameters (including jump parameters) from:
156 * https://prng.di.unimi.it/xoroshiro128plus.c
157 */
158 using P128R64 = detail::XorOshiro<uint64_t,
159 uint64_t,
160 24,
161 16,
162 37,
163 0xdf900294d8f554a5,
164 0x170865df4b3201fc,
165 0xd2a98b26625eee7b,
166 0xdddf9b1090aa7ac1>;
167
168 /**
169 * xoroshiro128+ with 32-bit output using the 2018 parameters.
170 *
171 * Parameters as per P128R64, above.
172 */
174
175 /**
176 * A "xoroshiro64+" with 32-bit outputs.
177 *
178 * As per Sebastino Vigna himself, writing in
179 * https://groups.google.com/g/prng/c/Ll-KDIbpO8k/m/bfHK4FlUCwAJ, these
180 * parameters are one of may full-period triples.
181 */
183
184 /**
185 * A "xoroshiro64+" with 16-bit outputs.
186 *
187 * Parameters as per P64R32, above.
188 */
190
191 /**
192 * A "xoroshiro32+" with 16-bit outputs.
193 *
194 * Parameters as per the Parallax Propeller 2 PRNG (discarding the "++"
195 * variant's fourth parameter "R"). See
196 * https://forums.parallax.com/discussion/comment/1448894 .
197 */
199
200 /**
201 * A "xoroshiro32+" with 16-bit outputs.
202 *
203 * Parameters as per P32R16, above.
204 */
206
207 /**
208 * A "xoroshiro16+" with 8-bit outputs.
209 *
210 * As per Sebastino Vigna himself, writing in
211 * https://groups.google.com/g/prng/c/MWJjq11zRis/m/7nM_cwRzAQAJ , the
212 * parameters are one of may full-period triples, but "There are no good
213 * 16-bit generators".
214 */
216} // namespace ds::xoroshiro
The xoroshiro+ (not ++) generator(s) of Blackman and Vigna's Scrambled Linear Pseudorandom Number Gen...
Definition xoroshiro.h:46
void long_jump()
Jump a really long way.
Definition xoroshiro.h:144
C++ APIs for assertions, invariants, and writing formatted debug messages to a UART.
detail::XorOshiro< uint32_t, uint16_t, 27, 7, 20 > P64R16
A "xoroshiro64+" with 16-bit outputs.
Definition xoroshiro.h:189
detail::XorOshiro< uint64_t, uint64_t, 24, 16, 37, 0xdf900294d8f554a5, 0x170865df4b3201fc, 0xd2a98b26625eee7b, 0xdddf9b1090aa7ac1 > P128R64
xoroshiro128+ with 64-bit output using the 2018 parameters.
Definition xoroshiro.h:158
detail::XorOshiro< uint8_t, uint8_t, 4, 7, 3 > P16R8
A "xoroshiro16+" with 8-bit outputs.
Definition xoroshiro.h:215
detail::XorOshiro< uint16_t, uint8_t, 13, 5, 10 > P32R8
A "xoroshiro32+" with 16-bit outputs.
Definition xoroshiro.h:205
detail::XorOshiro< uint64_t, uint32_t, 24, 16, 37 > P128R32
xoroshiro128+ with 32-bit output using the 2018 parameters.
Definition xoroshiro.h:173
detail::XorOshiro< uint32_t, uint32_t, 27, 7, 20 > P64R32
A "xoroshiro64+" with 32-bit outputs.
Definition xoroshiro.h:182
detail::XorOshiro< uint16_t, uint16_t, 13, 5, 10 > P32R16
A "xoroshiro32+" with 16-bit outputs.
Definition xoroshiro.h:198