diff options
| author | Mattias Andrée <maandree@kth.se> | 2016-03-03 23:28:05 +0100 |
|---|---|---|
| committer | Mattias Andrée <maandree@kth.se> | 2016-03-03 23:28:05 +0100 |
| commit | 3e4e851bfa30869e48cee9e15edc6723bee684f5 (patch) | |
| tree | 9aed4e3a95dc5ac9075a5e41a0cf3b7836741f4c /src | |
| parent | Cleanup and fix bug in ztrunc (diff) | |
| download | libzahl-3e4e851bfa30869e48cee9e15edc6723bee684f5.tar.gz libzahl-3e4e851bfa30869e48cee9e15edc6723bee684f5.tar.bz2 libzahl-3e4e851bfa30869e48cee9e15edc6723bee684f5.tar.xz | |
Add zrand
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'src')
| -rw-r--r-- | src/internals.h | 3 | ||||
| -rw-r--r-- | src/zrand.c | 95 |
2 files changed, 97 insertions, 1 deletions
diff --git a/src/internals.h b/src/internals.h index 6d05bc2..ba9bd44 100644 --- a/src/internals.h +++ b/src/internals.h @@ -33,7 +33,8 @@ #define LIST_CONSTS\ X(libzahl_const_1e19, zsetu, 10000000000000000000ULL) /* The largest power of 10 < 2⁶⁴. */\ - X(libzahl_const_1e9, zsetu, 1000000000ULL) /* The largest power of 10 < 2³². */ + X(libzahl_const_1e9, zsetu, 1000000000ULL) /* The largest power of 10 < 2³². */\ + X(libzahl_const_1, zsetu, 1) #define X(x) extern z_t x; LIST_TEMPS diff --git a/src/zrand.c b/src/zrand.c new file mode 100644 index 0000000..fa1bdfa --- /dev/null +++ b/src/zrand.c @@ -0,0 +1,95 @@ +/* See LICENSE file for copyright and license details. */ +#include "internals" + +#include <fcntl.h> +#include <unistd.h> + +#ifndef FAST_RANDOM_PATHNAME +# define FAST_RANDOM_PATHNAME "/dev/urandom" +#endif + +#ifndef SECURE_RANDOM_PATHNAME +# define SECURE_RANDOM_PATHNAME "/dev/random" +#endif + + +static void +zrand_get_random_bits(z_t r, size_t bits, int fd) +{ + size_t read_total, n, chars = CEILING_BITS_TO_CHARS(bits); + ssize_t read_just; + uint32_t mask = 1; + + if (r->alloced < chars) + zahl_realloc(r, chars); + + for (n = chars << LB_BITS_PER_CHAR; n;) { + read_just = read(fd, (char *)(r->chars) + read_total, n); + if (read_just < 0) + FAILURE_JUMP(); + read_total += read_just; + n -= read_just; + } + + bit = BITS_IN_LAST_CHAR(bit) + mask <<= bit; + mask -= 1; + + r->chars[chars - 1] &= mask; + for (n = chars; n--;) { + if (r->chars[n]) { + r->used = n + 1; + SET_SIGNUM(r, 1); + return; + } + } + SET_SIGNUM(r, 0); +} + +void +zrand(z_t r, enum zranddev dev, enum zranddist dist, z_t n) +{ + const char *pathname = 0; + size_t bits; + int fd; + + switch (dev) { + case FAST_RANDOM: + pathname = FAST_RANDOM_PATHNAME; + break; + case SECURE_RANDOM: + pathname = SECURE_RANDOM_PATHNAME; + break; + default: + abort(); + } + + if (zzero(n)) { + SET_SIGNUM(r, 0); + return; + } + + fd = open(pathname, O_RDONLY); + + switch (dist) { + case QUASIUNIFORM: + bits = zbits(n); + zrand_get_random_bits(r, bits, fd); + zadd(r, r, libzahl_const_1); + zmul(r, r, n); + zrsh(r, r, bits); + break; + + case UNIFORM: + bits = zbits(n); + do + zrand_get_random_bits(r, bits, fd); + while (zcmp(r, n) > 0); + break; + + default: + abort(); + } + + close(fd); +} |
