zrand.c - libzahl - big integer library | |
git clone git://git.suckless.org/libzahl | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
zrand.c (3981B) | |
--- | |
1 /* See LICENSE file for copyright and license details. */ | |
2 #include "internals.h" | |
3 | |
4 #include <fcntl.h> | |
5 #include <stdlib.h> | |
6 #include <time.h> | |
7 #include <unistd.h> | |
8 | |
9 #ifndef FAST_RANDOM_PATHNAME | |
10 # define FAST_RANDOM_PATHNAME "/dev/urandom" | |
11 #endif | |
12 | |
13 #ifndef SECURE_RANDOM_PATHNAME | |
14 # define SECURE_RANDOM_PATHNAME "/dev/random" | |
15 #endif | |
16 | |
17 | |
18 static void | |
19 zrand_libc_rand(void *out, size_t n, void *statep) | |
20 { | |
21 static char inited = 0; | |
22 | |
23 unsigned int ri; | |
24 double rd; | |
25 unsigned char *buf = out; | |
26 | |
27 if (!inited) { | |
28 inited = 1; | |
29 srand((unsigned)((intptr_t)out | time(NULL))); | |
30 } | |
31 | |
32 while (n--) { | |
33 ri = (unsigned)rand(); | |
34 rd = (double)ri / ((double)RAND_MAX + 1); | |
35 #ifdef GOOD_RAND | |
36 rd *= 256 * 256; | |
37 ri = (unsigned int)rd; | |
38 buf[n] = (unsigned char)((ri >> 0) & 255); | |
39 if (!n--) break; | |
40 buf[n] = (unsigned char)((ri >> 8) & 255); | |
41 #else | |
42 rd *= 256; | |
43 buf[n] = (unsigned char)rd; | |
44 #endif | |
45 } | |
46 | |
47 (void) statep; | |
48 } | |
49 | |
50 static void | |
51 zrand_libc_rand48(void *out, size_t n, void *statep) | |
52 { | |
53 static char inited = 0; | |
54 | |
55 long int r0, r1; | |
56 unsigned char *buf = out; | |
57 | |
58 if (!inited) { | |
59 inited = 1; | |
60 srand48((intptr_t)out | time(NULL)); | |
61 } | |
62 | |
63 while (n--) { | |
64 r0 = lrand48() & 15; | |
65 r1 = lrand48() & 15; | |
66 buf[n] = (unsigned char)((r0 << 4) | r1); | |
67 } | |
68 | |
69 (void) statep; | |
70 } | |
71 | |
72 static void | |
73 zrand_libc_random(void *out, size_t n, void *statep) | |
74 { | |
75 static char inited = 0; | |
76 | |
77 long int ri; | |
78 unsigned char *buf = out; | |
79 | |
80 if (!inited) { | |
81 inited = 1; | |
82 srandom((unsigned)((intptr_t)out | time(NULL))); | |
83 } | |
84 | |
85 while (n--) { | |
86 ri = random(); | |
87 buf[n] = (unsigned char)((ri >> 0) & 255); | |
88 if (!n--) break; | |
89 buf[n] = (unsigned char)((ri >> 8) & 255); | |
90 if (!n--) break; | |
91 buf[n] = (unsigned char)((ri >> 16) & 255); | |
92 } | |
93 | |
94 (void) statep; | |
95 } | |
96 | |
97 static void | |
98 zrand_fd(void *out, size_t n, void *statep) | |
99 { | |
100 int fd = *(int *)statep; | |
101 ssize_t read_just; | |
102 size_t read_total = 0; | |
103 char *buf = out; | |
104 | |
105 while (n) { | |
106 read_just = read(fd, buf + read_total, n); | |
107 if (check(read_just < 0)) | |
108 libzahl_failure(errno); | |
109 read_total += (size_t)read_just; | |
110 n -= (size_t)read_just; | |
111 } | |
112 } | |
113 | |
114 static void | |
115 zrand_get_random_bits(z_t r, size_t bits, void (*fun)(void *, size_t, vo… | |
116 { | |
117 size_t n, chars = CEILING_BITS_TO_CHARS(bits); | |
118 zahl_char_t mask = 1; | |
119 | |
120 ENSURE_SIZE(r, chars); | |
121 | |
122 fun(r->chars, chars * sizeof(zahl_char_t), statep); | |
123 | |
124 bits = BITS_IN_LAST_CHAR(bits); | |
125 mask <<= bits; | |
126 mask -= 1; | |
127 | |
128 r->chars[chars - 1] &= mask; | |
129 for (n = chars; n--;) { | |
130 if (likely(r->chars[n])) { | |
131 r->used = n + 1; | |
132 SET_SIGNUM(r, 1); | |
133 return; | |
134 } | |
135 } | |
136 SET_SIGNUM(r, 0); | |
137 } | |
138 | |
139 void | |
140 zrand(z_t r, enum zranddev dev, enum zranddist dist, z_t n) | |
141 { | |
142 #define RANDOM_UNIFORM(RETRY)\ | |
143 do {\ | |
144 if (check(znegative(n)))\ | |
145 libzahl_failure(-ZERROR_NEGATIVE);\ | |
146 bits = zbits(n);\ | |
147 do\ | |
148 zrand_get_random_bits(r, bits, random_fun, state… | |
149 while (RETRY && unlikely(zcmpmag(r, n) > 0));\ | |
150 } while (0) | |
151 | |
152 | |
153 const char *pathname = 0; | |
154 size_t bits; | |
155 int fd = -1; | |
156 void *statep = 0; | |
157 void (*random_fun)(void *, size_t, void *) = &zrand_fd; | |
158 | |
159 switch (dev) { | |
160 case FAST_RANDOM: | |
161 pathname = FAST_RANDOM_PATHNAME; | |
162 break; | |
163 case SECURE_RANDOM: | |
164 pathname = SECURE_RANDOM_PATHNAME; | |
165 break; | |
166 case LIBC_RAND_RANDOM: | |
167 random_fun = &zrand_libc_rand; | |
168 break; | |
169 case DEFAULT_RANDOM: | |
170 case FASTEST_RANDOM: | |
171 case LIBC_RANDOM_RANDOM: | |
172 random_fun = &zrand_libc_random; | |
173 break; | |
174 case LIBC_RAND48_RANDOM: | |
175 random_fun = &zrand_libc_rand48; | |
176 break; | |
177 default: | |
178 libzahl_failure(EINVAL); | |
179 } | |
180 | |
181 if (unlikely(zzero(n))) { | |
182 SET_SIGNUM(r, 0); | |
183 return; | |
184 } | |
185 | |
186 if (pathname) { | |
187 fd = open(pathname, O_RDONLY); | |
188 if (check(fd < 0)) | |
189 libzahl_failure(errno); | |
190 statep = &fd; | |
191 } | |
192 | |
193 switch (dist) { | |
194 case QUASIUNIFORM: | |
195 RANDOM_UNIFORM(0); | |
196 zadd(r, r, libzahl_const_1); | |
197 zmul(r, r, n); | |
198 zrsh(r, r, bits); | |
199 break; | |
200 | |
201 case UNIFORM: | |
202 RANDOM_UNIFORM(1); | |
203 break; | |
204 | |
205 case MODUNIFORM: | |
206 RANDOM_UNIFORM(0); | |
207 if (unlikely(zcmpmag(r, n) > 0)) | |
208 zsub(r, r, n); | |
209 break; | |
210 | |
211 default: | |
212 #if !defined(ZAHL_UNSAFE) | |
213 libzahl_failure(EINVAL); | |
214 #endif | |
215 break; | |
216 } | |
217 | |
218 if (fd >= 0) | |
219 close(fd); | |
220 } |