/* * The UCW Library -- Random numbers * * (c) 2020--2022 Pavel Charvat * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. */ #ifndef _UCW_RANDOM_H #define _UCW_RANDOM_H #ifdef CONFIG_UCW_CLEAN_ABI #define fastrand_new ucw_fastrand_new #define fastrand_delete ucw_fastrand_delete #define fastrand_set_seed ucw_fastrand_set_seed #define fastrand_gen_seed_value ucw_fastrand_gen_seed_value #define fastrand_gen_seed ucw_fastrand_gen_seed #define fastrand_has_seed ucw_fastrand_has_seed #define fastrand_reset ucw_fastrand_reset #define fastrand_u32 ucw_fastrand_u32 #define fastrand_u64 ucw_fastrand_u64 #define fastrand_bits_u64 ucw_fastrand_bits_u64 #define fastrand_max ucw_fastrand_max #define fastrand_max_u64 ucw_fastrand_max_u64 #define fastrand_mem ucw_fastrand_mem #define fastrand_double ucw_fastrand_double #define strongrand_close ucw_strongrand_close #define strongrand_reset ucw_strongrand_reset #define strongrand_mem ucw_strongrand_mem #define strongrand_std_open ucw_strongrand_std_open #define strongrand_getrandom_mem_try ucw_strongrand_getrandom_mem_try #endif /* random-fast.c */ /** * Context structure for a fast pseudo-random generator. * Useful for generating numbers in randomized algorithms, but not in critical things like cryptography. * The library is generally thread-safe, but each context must be used by at most one thread at one time. * Also be careful with fork() if you want to avoid the same numbers in subprocesses. **/ struct fastrand; /** * Type for a seed value. Beware that some generators are only able to use the lowest 32 bits. **/ typedef u64 fastrand_seed_t; /** * Allocate a new context. Should be paired with fastrand_delete(). * Don't forget to supply a seed before started to read randomness. **/ struct fastrand *fastrand_new(void); void fastrand_delete(struct fastrand *c); /** (Re)seed the context with given value. **/ void fastrand_set_seed(struct fastrand *c, fastrand_seed_t seed); /** * Generate a seed for fastrand_set_seed(). * * Since glibc 2.25 and kernel 3.17, we use getrandom() syscall * to read kernel's urandom. * * Otherwise we mix these things: * -- current time * -- process id to deal with frequent fork() or startups * -- counter to deal with multiple contexts, for example in threaded application **/ fastrand_seed_t fastrand_gen_seed_value(void); /** (Re)seed the context with fastrand_gen_seed_value(). **/ fastrand_seed_t fastrand_gen_seed(struct fastrand *c); /** Is the context seeded? **/ bool fastrand_has_seed(struct fastrand *c); /** Reset the context to its initial state. Useful after a fork() to assert forgotten reseed. **/ void fastrand_reset(struct fastrand *c); /** Uniformly generate 32 random bits. **/ u32 fastrand_u32(struct fastrand *c); /** Uniformly generate 64 random bits. **/ u64 fastrand_u64(struct fastrand *c); /** Uniformly generate [0, 64] random bits. **/ u64 fastrand_bits_u64(struct fastrand *c, uint bits); /** Uniformly generate [0, 8*sizeof(uint)] random bits. **/ static inline uint fastrand_bits(struct fastrand *c, uint bits) { return fastrand_bits_u64(c, bits); } /** Uniformly generate a random number from range [0, bound-1], where @bound is [1, UINT_MAX]. **/ uint fastrand_max(struct fastrand *c, uint bound); /** Uniformly generate a random number from range [0, bound-1], where @bound is [1, UINT64_MAX]. **/ u64 fastrand_max_u64(struct fastrand *c, u64 bound); /** Generate @size random bytes. **/ void fastrand_mem(struct fastrand *c, void *ptr, size_t size); /** Uniformly generate a random number from range [0.0, 1.0) + possible inaccuracies from basic floating point operations. **/ double fastrand_double(struct fastrand *c); /* random-strong.c */ /** * Context structure for a strong random generator. * Useful for things like generating random ids or cryptography. * The library is generally thread-safe, but each context must be used by at most one thread at one time. * * Also be careful with fork(). Unless said otherwise, it's forbidden to use the context * in a forked child, we can even assert changes of pid. See strongrand_reset() if you * need that. **/ struct strongrand { const char *name; /* (mandatory) Context name for logging. */ void (*read)(struct strongrand *sr, byte *ptr, int size); /* (mandatory) Generate @size random bytes. */ void (*close)(struct strongrand *sr); /* Called from strongrand_close(). */ void (*reset)(struct strongrand *sr); /* Called from strongrand_reset(). */ }; /** Close a previously opened context. **/ void strongrand_close(struct strongrand *c); /** * If you want to use the same context in multiple forked subprocesses, you must * call this function after the fork() to flush any buffered randomness. * Some future back-ends could use it for even more things, for example * to re-connect somewhere. **/ void strongrand_reset(struct strongrand *sr); /** Generate @size random bytes. **/ void strongrand_mem(struct strongrand *c, void *ptr, size_t size); /** * Open kernel's random generator. * Requires exactly one of these flags, among others: * -- STRONGRAND_STD_URANDOM * -- STRONGRAND_STD_RANDOM * * Since glibc 2.25 and kernel 3.17, we use getrandom() syscall, * otherwise we open and read from "/dev/[u]random" device. * * @buf_size can be 0 for unbuffered reading. * * STRONGRAND_STD_x_RESET flags are only useful for buffered reading. * * If at least one of the following conditions are met, strongrand_reset() * after fork() is not necessary: * -- zero @buf_size * -- STRONGRAND_STD_AUTO_RESET flag * -- no read since open or last reset (empty buffer) **/ struct strongrand *strongrand_std_open(uint flags, uint buf_size); enum strongrand_std_flags { STRONGRAND_STD_URANDOM = 0x1, // Use kernel's "urandom" source. STRONGRAND_STD_RANDOM = 0x2, // Use kernel's "random" source. STRONGRAND_STD_DELAYED = 0x4, // Delay non-trivial initializations like opening file descriptor to first read. STRONGRAND_STD_AUTO_RESET = 0x8, // Automatically do strongrand_reset() after changes of getpid(); adds overhead to each read. STRONGRAND_STD_ASSERT_RESET = 0x10, // Assert correct usage of strongrand_reset() after changes of getpid(); for debugging. }; // Internals bool strongrand_getrandom_mem_try(void *buf, size_t size); #endif