Workshop o mikrokontrolérech na SKSP 2024.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
6.3 KiB

3 months ago
/*
* The UCW Library -- Random numbers
*
* (c) 2020--2022 Pavel Charvat <pchar@ucw.cz>
*
* 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