1 | // |
2 | // Random.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: Crypt |
6 | // Module: Random |
7 | // |
8 | // Definition of class Random. |
9 | // |
10 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
11 | // and Contributors. |
12 | // |
13 | // SPDX-License-Identifier: BSL-1.0 |
14 | // |
15 | // |
16 | // Based on the FreeBSD random number generator. |
17 | // src/lib/libc/stdlib/random.c,v 1.25 |
18 | // |
19 | // Copyright (c) 1983, 1993 |
20 | // The Regents of the University of California. All rights reserved. |
21 | // Redistribution and use in source and binary forms, with or without |
22 | // modification, are permitted provided that the following conditions |
23 | // are met: |
24 | // 1. Redistributions of source code must retain the above copyright |
25 | // notice, this list of conditions and the following disclaimer. |
26 | // 2. Redistributions in binary form must reproduce the above copyright |
27 | // notice, this list of conditions and the following disclaimer in the |
28 | // documentation and/or other materials provided with the distribution. |
29 | // 4. Neither the name of the University nor the names of its contributors |
30 | // may be used to endorse or promote products derived from this software |
31 | // without specific prior written permission. |
32 | // |
33 | // THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
34 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
35 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
36 | // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
37 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
38 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
39 | // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
40 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
41 | // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
42 | // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
43 | // SUCH DAMAGE. |
44 | // |
45 | |
46 | |
47 | #include "Poco/Random.h" |
48 | #include "Poco/RandomStream.h" |
49 | #include <ctime> |
50 | #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 |
51 | #include "wce_time.h" |
52 | #endif |
53 | |
54 | |
55 | /* |
56 | * random.c: |
57 | * |
58 | * An improved random number generation package. In addition to the standard |
59 | * rand()/srand() like interface, this package also has a special state info |
60 | * interface. The initstate() routine is called with a seed, an array of |
61 | * bytes, and a count of how many bytes are being passed in; this array is |
62 | * then initialized to contain information for random number generation with |
63 | * that much state information. Good sizes for the amount of state |
64 | * information are 32, 64, 128, and 256 bytes. The state can be switched by |
65 | * calling the setstate() routine with the same array as was initiallized |
66 | * with initstate(). By default, the package runs with 128 bytes of state |
67 | * information and generates far better random numbers than a linear |
68 | * congruential generator. If the amount of state information is less than |
69 | * 32 bytes, a simple linear congruential R.N.G. is used. |
70 | * |
71 | * Internally, the state information is treated as an array of uint32_t's; the |
72 | * zeroeth element of the array is the type of R.N.G. being used (small |
73 | * integer); the remainder of the array is the state information for the |
74 | * R.N.G. Thus, 32 bytes of state information will give 7 ints worth of |
75 | * state information, which will allow a degree seven polynomial. (Note: |
76 | * the zeroeth word of state information also has some other information |
77 | * stored in it -- see setstate() for details). |
78 | * |
79 | * The random number generation technique is a linear feedback shift register |
80 | * approach, employing trinomials (since there are fewer terms to sum up that |
81 | * way). In this approach, the least significant bit of all the numbers in |
82 | * the state table will act as a linear feedback shift register, and will |
83 | * have period 2^deg - 1 (where deg is the degree of the polynomial being |
84 | * used, assuming that the polynomial is irreducible and primitive). The |
85 | * higher order bits will have longer periods, since their values are also |
86 | * influenced by pseudo-random carries out of the lower bits. The total |
87 | * period of the generator is approximately deg*(2**deg - 1); thus doubling |
88 | * the amount of state information has a vast influence on the period of the |
89 | * generator. Note: the deg*(2**deg - 1) is an approximation only good for |
90 | * large deg, when the period of the shift is the dominant factor. |
91 | * With deg equal to seven, the period is actually much longer than the |
92 | * 7*(2**7 - 1) predicted by this formula. |
93 | * |
94 | * Modified 28 December 1994 by Jacob S. Rosenberg. |
95 | * The following changes have been made: |
96 | * All references to the type u_int have been changed to unsigned long. |
97 | * All references to type int have been changed to type long. Other |
98 | * cleanups have been made as well. A warning for both initstate and |
99 | * setstate has been inserted to the effect that on Sparc platforms |
100 | * the 'arg_state' variable must be forced to begin on word boundaries. |
101 | * This can be easily done by casting a long integer array to char *. |
102 | * The overall logic has been left STRICTLY alone. This software was |
103 | * tested on both a VAX and Sun SpacsStation with exactly the same |
104 | * results. The new version and the original give IDENTICAL results. |
105 | * The new version is somewhat faster than the original. As the |
106 | * documentation says: "By default, the package runs with 128 bytes of |
107 | * state information and generates far better random numbers than a linear |
108 | * congruential generator. If the amount of state information is less than |
109 | * 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of |
110 | * 128 bytes, this new version runs about 19 percent faster and for a 16 |
111 | * byte buffer it is about 5 percent faster. |
112 | */ |
113 | |
114 | |
115 | /* |
116 | * For each of the currently supported random number generators, we have a |
117 | * break value on the amount of state information (you need at least this |
118 | * many bytes of state info to support this random number generator), a degree |
119 | * for the polynomial (actually a trinomial) that the R.N.G. is based on, and |
120 | * the separation between the two lower order coefficients of the trinomial. |
121 | */ |
122 | #define TYPE_0 0 /* linear congruential */ |
123 | #define BREAK_0 8 |
124 | #define DEG_0 0 |
125 | #define SEP_0 0 |
126 | |
127 | #define TYPE_1 1 /* x**7 + x**3 + 1 */ |
128 | #define BREAK_1 32 |
129 | #define DEG_1 7 |
130 | #define SEP_1 3 |
131 | |
132 | #define TYPE_2 2 /* x**15 + x + 1 */ |
133 | #define BREAK_2 64 |
134 | #define DEG_2 15 |
135 | #define SEP_2 1 |
136 | |
137 | #define TYPE_3 3 /* x**31 + x**3 + 1 */ |
138 | #define BREAK_3 128 |
139 | #define DEG_3 31 |
140 | #define SEP_3 3 |
141 | |
142 | #define TYPE_4 4 /* x**63 + x + 1 */ |
143 | #define BREAK_4 256 |
144 | #define DEG_4 63 |
145 | #define SEP_4 1 |
146 | |
147 | |
148 | namespace Poco { |
149 | |
150 | |
151 | Random::Random(int stateSize) |
152 | { |
153 | poco_assert (BREAK_0 <= stateSize && stateSize <= BREAK_4); |
154 | |
155 | _pBuffer = new char[stateSize]; |
156 | #if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 |
157 | initState((UInt32) wceex_time(NULL), _pBuffer, stateSize); |
158 | #else |
159 | initState((UInt32) std::time(NULL), _pBuffer, stateSize); |
160 | #endif |
161 | } |
162 | |
163 | |
164 | Random::~Random() |
165 | { |
166 | delete [] _pBuffer; |
167 | } |
168 | |
169 | |
170 | /* |
171 | * Compute x = (7^5 * x) mod (2^31 - 1) |
172 | * wihout overflowing 31 bits: |
173 | * (2^31 - 1) = 127773 * (7^5) + 2836 |
174 | * From "Random number generators: good ones are hard to find", |
175 | * Park and Miller, Communications of the ACM, vol. 31, no. 10, |
176 | * October 1988, p. 1195. |
177 | */ |
178 | inline UInt32 Random::goodRand(Int32 x) |
179 | { |
180 | Int32 hi, lo; |
181 | |
182 | if (x == 0) x = 123459876; |
183 | hi = x / 127773; |
184 | lo = x % 127773; |
185 | x = 16807 * lo - 2836 * hi; |
186 | if (x < 0) x += 0x7FFFFFFF; |
187 | |
188 | return x; |
189 | } |
190 | |
191 | |
192 | /* |
193 | * Initialize the random number generator based on the given seed. If the |
194 | * type is the trivial no-state-information type, just remember the seed. |
195 | * Otherwise, initializes state[] based on the given "seed" via a linear |
196 | * congruential generator. Then, the pointers are set to known locations |
197 | * that are exactly rand_sep places apart. Lastly, it cycles the state |
198 | * information a given number of times to get rid of any initial dependencies |
199 | * introduced by the L.C.R.N.G. Note that the initialization of randtbl[] |
200 | * for default usage relies on values produced by this routine. |
201 | */ |
202 | void Random::seed(UInt32 x) |
203 | { |
204 | int i, lim; |
205 | |
206 | _state[0] = x; |
207 | if (_randType == TYPE_0) |
208 | lim = NSHUFF; |
209 | else |
210 | { |
211 | for (i = 1; i < _randDeg; i++) |
212 | _state[i] = goodRand(_state[i - 1]); |
213 | _fptr = &_state[_randSep]; |
214 | _rptr = &_state[0]; |
215 | lim = 10 * _randDeg; |
216 | } |
217 | for (i = 0; i < lim; i++) |
218 | next(); |
219 | } |
220 | |
221 | |
222 | /* |
223 | * Many programs choose the seed value in a totally predictable manner. |
224 | * This often causes problems. We seed the generator using the much more |
225 | * secure random(4) interface. Note that this particular seeding |
226 | * procedure can generate states which are impossible to reproduce by |
227 | * calling srandom() with any value, since the succeeding terms in the |
228 | * state buffer are no longer derived from the LC algorithm applied to |
229 | * a fixed seed. |
230 | */ |
231 | void Random::seed() |
232 | { |
233 | std::streamsize len; |
234 | |
235 | if (_randType == TYPE_0) |
236 | len = sizeof _state[0]; |
237 | else |
238 | len = _randDeg * sizeof _state[0]; |
239 | |
240 | RandomInputStream rstr; |
241 | rstr.read((char*) _state, len); |
242 | } |
243 | |
244 | |
245 | /* |
246 | * Initialize the state information in the given array of n bytes for future |
247 | * random number generation. Based on the number of bytes we are given, and |
248 | * the break values for the different R.N.G.'s, we choose the best (largest) |
249 | * one we can and set things up for it. srandom() is then called to |
250 | * initialize the state information. |
251 | * |
252 | * Note that on return from srandom(), we set state[-1] to be the type |
253 | * multiplexed with the current value of the rear pointer; this is so |
254 | * successive calls to initstate() won't lose this information and will be |
255 | * able to restart with setstate(). |
256 | * |
257 | * Note: the first thing we do is save the current state, if any, just like |
258 | * setstate() so that it doesn't matter when initstate is called. |
259 | * |
260 | * Returns a pointer to the old state. |
261 | * |
262 | * Note: The Sparc platform requires that arg_state begin on an int |
263 | * word boundary; otherwise a bus error will occur. Even so, lint will |
264 | * complain about mis-alignment, but you should disregard these messages. |
265 | */ |
266 | void Random::initState(UInt32 s, char* argState, Int32 n) |
267 | { |
268 | UInt32* intArgState = (UInt32*) argState; |
269 | |
270 | if (n < BREAK_0) |
271 | { |
272 | poco_bugcheck_msg("not enough state" ); |
273 | return; |
274 | } |
275 | if (n < BREAK_1) |
276 | { |
277 | _randType = TYPE_0; |
278 | _randDeg = DEG_0; |
279 | _randSep = SEP_0; |
280 | } |
281 | else if (n < BREAK_2) |
282 | { |
283 | _randType = TYPE_1; |
284 | _randDeg = DEG_1; |
285 | _randSep = SEP_1; |
286 | } |
287 | else if (n < BREAK_3) |
288 | { |
289 | _randType = TYPE_2; |
290 | _randDeg = DEG_2; |
291 | _randSep = SEP_2; |
292 | } |
293 | else if (n < BREAK_4) |
294 | { |
295 | _randType = TYPE_3; |
296 | _randDeg = DEG_3; |
297 | _randSep = SEP_3; |
298 | } |
299 | else |
300 | { |
301 | _randType = TYPE_4; |
302 | _randDeg = DEG_4; |
303 | _randSep = SEP_4; |
304 | } |
305 | _state = intArgState + 1; /* first location */ |
306 | _endPtr = &_state[_randDeg]; /* must set end_ptr before seed */ |
307 | seed(s); |
308 | if (_randType == TYPE_0) |
309 | intArgState[0] = _randType; |
310 | else |
311 | intArgState[0] = MAX_TYPES * (int) (_rptr - _state) + _randType; |
312 | } |
313 | |
314 | |
315 | /* |
316 | * Next: |
317 | * |
318 | * If we are using the trivial TYPE_0 R.N.G., just do the old linear |
319 | * congruential bit. Otherwise, we do our fancy trinomial stuff, which is |
320 | * the same in all the other cases due to all the global variables that have |
321 | * been set up. The basic operation is to add the number at the rear pointer |
322 | * into the one at the front pointer. Then both pointers are advanced to |
323 | * the next location cyclically in the table. The value returned is the sum |
324 | * generated, reduced to 31 bits by throwing away the "least random" low bit. |
325 | * |
326 | * Note: the code takes advantage of the fact that both the front and |
327 | * rear pointers can't wrap on the same call by not testing the rear |
328 | * pointer if the front one has wrapped. |
329 | * |
330 | * Returns a 31-bit random number. |
331 | */ |
332 | UInt32 Random::next() |
333 | { |
334 | UInt32 i; |
335 | UInt32 *f, *r; |
336 | |
337 | if (_randType == TYPE_0) |
338 | { |
339 | i = _state[0]; |
340 | _state[0] = i = goodRand(i) & 0x7FFFFFFF; |
341 | } |
342 | else |
343 | { |
344 | /* |
345 | * Use local variables rather than static variables for speed. |
346 | */ |
347 | f = _fptr; r = _rptr; |
348 | *f += *r; |
349 | i = (*f >> 1) & 0x7FFFFFFF; /* chucking least random bit */ |
350 | if (++f >= _endPtr) { |
351 | f = _state; |
352 | ++r; |
353 | } |
354 | else if (++r >= _endPtr) { |
355 | r = _state; |
356 | } |
357 | |
358 | _fptr = f; _rptr = r; |
359 | } |
360 | return i; |
361 | } |
362 | |
363 | |
364 | } // namespace Poco |
365 | |