rand/noise.c (noise_devrandom): Refactor internals.
[catacomb] / rand / grand.c
CommitLineData
aa1082f2 1/* -*-c-*-
2 *
aa1082f2 3 * Generic interface to random number generators
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
45c0fd36 8/*----- Licensing notice --------------------------------------------------*
aa1082f2 9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
45c0fd36 16 *
aa1082f2 17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
45c0fd36 21 *
aa1082f2 22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
aa1082f2 28/*----- Header files ------------------------------------------------------*/
29
30#include <stddef.h>
31
32#include <mLib/bits.h>
33
34#include "grand.h"
35
44ff6c11
MW
36/*----- Default operations ------------------------------------------------*/
37
38/* --- @grand_defaultbyte@ --- *
39 *
40 * Arguments: @grand *r@ = pointet to generic generator
41 *
42 * Returns: A uniformly-distributed pseudorandom integer in the interval
43 * %$[0, 256)$%.
44 *
45 * Use: Default @byte@ output method. This calls the @range@ method
46 * to return a uniform random value between 0 and 255.
47 */
48
49octet grand_defaultbyte(grand *r)
50 { return (r->ops->range(r, 256)); }
51
52/* --- @grand_defaultword@ --- *
53 *
54 * Arguments: @grand *r@ = pointet to generic generator
55 *
56 * Returns: A uniformly-distributed pseudorandom integer in the interval
57 * %$[0, 2^{32})$%.
58 *
59 * Use: Default @word@ output method. This calls the @fill@ method
60 * to fill a 4-octet buffer with uniform random bytes, and then
61 * converts them to an integer.
62 */
63
64uint32 grand_defaultword(grand *r)
65 { octet buf[4]; r->ops->fill(r, buf, sizeof(buf)); return (LOAD32(buf)); }
66
67/* --- @grand_defaultrange@ --- *
68 *
69 * Arguments: @grand *r@ = pointet to generic generator
70 * @uint32 l@ = limit for acceptable results
71 *
72 * Returns: A uniformly-distributed pseudorandom integer in the interval
73 * %$[0, l)$%.
74 *
75 * Use: Default @range@ output method. This falls back to either
76 * @word@ (if the generator's @max@ is zero, or if @max < l@) or
77 * @raw@ (otherwise). This might recurse via @fill@ and @byte@,
78 * but this is safe because of the constraint on the @raw@
79 * method.
80 */
81
82uint32 grand_defaultrange(grand *r, uint32 l)
83{
84 uint32 m, z;
85 uint32 (*w)(grand */*r*/);
86 uint32 x;
87
88 /* --- Decide where to get data from --- *
89 *
90 * The choice of %$2^{32} - 1$% as a limit when using @grand_word@ isn't
91 * wonderful, but working with %$2^{32}$% is awkward and the loss of a few
92 * return values isn't significant. The algorithm below still successfully
93 * returns uniformly distributed results.
94 *
95 * If there's a raw generator, and it can cope with the limit, then use it;
96 * otherwise use the @word@ generator, which may recurse via @fill@ and
97 * @byte@, but by that point it must be able to satisfy us.
98 */
99
100 if (r->ops->max && r->ops->max >= l) {
101 w = r->ops->raw;
102 m = r->ops->max;
103 } else {
104 assert(!r->ops->max || r->ops->max >= 256);
105 w = grand_word;
106 m = 0xffffffff;
107 }
108
109 /* --- Work out maximum acceptable return value --- *
110 *
111 * This will be the highest multiple of @l@ less than @m@.
112 */
113
114 z = m - m%l;
115
116 /* --- Generate numbers until something acceptable is found --- *
117 *
118 * This will require an expected number of attempts less than 2.
119 */
120
121 do x = w(r); while (x >= z);
122 return (x%l);
123}
124
125/* --- @grand_defaultfill@ --- *
126 *
127 * Arguments: @grand *r@ = pointet to generic generator
128 * @void *p@ = pointer to a buffer
129 * @size_t sz@ = size of the buffer
130 *
131 * Returns: ---
132 *
133 * Use: Fills a buffer with uniformly distributed pseudorandom bytes.
134 * This calls the @byte@ method repeatedly to fill in the output
135 * buffer.
136 */
137
138void grand_defaultfill(grand *r, void *p, size_t sz)
139 { octet *q = p; while (sz--) *q++ = r->ops->byte(r); }
140
aa1082f2 141/*----- Main code ---------------------------------------------------------*/
142
143/* --- @grand_byte@ --- *
144 *
145 * Arguments: @grand *r@ = pointet to generic generator
146 *
147 * Returns: A uniformly-distributed pseudorandom integer in the interval
148 * %$[0, 256)$%.
149 */
150
151octet grand_byte(grand *r)
152{
44ff6c11
MW
153 if (r->ops->byte == grand_byte) return (grand_defaultbyte(r));
154 else return (r->ops->byte(r));
aa1082f2 155}
156
157/* --- @grand_word@ --- *
158 *
159 * Arguments: @grand *r@ = pointet to generic generator
160 *
161 * Returns: A uniformly-distributed pseudorandom integer in the interval
162 * %$[0, 2^{32})$%.
163 */
164
165uint32 grand_word(grand *r)
166{
44ff6c11
MW
167 if (r->ops->word == grand_word) return (grand_defaultword(r));
168 else return (r->ops->word(r));
aa1082f2 169}
170
171/* --- @grand_range@ --- *
172 *
173 * Arguments: @grand *r@ = pointet to generic generator
174 * @uint32 l@ = limit for acceptable results
175 *
176 * Returns: A uniformly-distributed pseudorandom integer in the interval
177 * %$[0, l)$%.
178 */
179
180uint32 grand_range(grand *r, uint32 l)
181{
44ff6c11
MW
182 if (r->ops->range == grand_range) return (grand_defaultrange(r, l));
183 else return (r->ops->range(r, l));
aa1082f2 184}
185
186/* --- @grand_fill@ --- *
187 *
188 * Arguments: @grand *r@ = pointet to generic generator
189 * @void *p@ = pointer to a buffer
190 * @size_t sz@ = size of the buffer
191 *
192 * Returns: ---
193 *
194 * Use: Fills a buffer with uniformly distributed pseudorandom bytes
195 * (see @grand_byte@).
196 */
197
198void grand_fill(grand *r, void *p, size_t sz)
199{
44ff6c11
MW
200 if (r->ops->fill == grand_fill) grand_defaultfill(r, p, sz);
201 else r->ops->fill(r, p, sz);
aa1082f2 202}
203
204/*----- That's all, folks -------------------------------------------------*/