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, void *), void *statep) 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, statep);\ 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 }