#include "lib/crypt_ops/crypto_rand.h"
#include "lib/log/util_bug.h"
#define IMPLEMENT_RAND_UNSIGNED(type, maxval, limit, fill_stmt) \
do { \
type val; \
type cutoff; \
tor_assert((limit) > 0); \
\
\
\
\
cutoff = (maxval) - ((maxval)%(limit)); \
while (1) { \
fill_stmt; \
if (val < cutoff) \
return val % (limit); \
} \
} while (0)
unsigned
crypto_rand_uint(unsigned limit)
{
tor_assert(limit < UINT_MAX);
IMPLEMENT_RAND_UNSIGNED(unsigned, UINT_MAX, limit,
crypto_rand((char*)&val, sizeof(val)));
}
int
crypto_rand_int(unsigned int max)
{
tor_assert(max <= ((unsigned int)INT_MAX)+1);
return (int)crypto_rand_uint(max);
}
int
crypto_rand_int_range(unsigned int min, unsigned int max)
{
tor_assert(min < max);
tor_assert(max <= INT_MAX);
return min + crypto_rand_int(max - min);
}
uint64_t
crypto_rand_uint64_range(uint64_t min, uint64_t max)
{
tor_assert(min < max);
return min + crypto_rand_uint64(max - min);
}
time_t
crypto_rand_time_range(time_t min, time_t max)
{
tor_assert(min < max);
return min + (time_t)crypto_rand_uint64(max - min);
}
uint64_t
crypto_rand_uint64(uint64_t max)
{
tor_assert(max < UINT64_MAX);
IMPLEMENT_RAND_UNSIGNED(uint64_t, UINT64_MAX, max,
crypto_rand((char*)&val, sizeof(val)));
}
#if SIZEOF_INT == 4
#define UINT_MAX_AS_DOUBLE 4294967296.0
#elif SIZEOF_INT == 8
#define UINT_MAX_AS_DOUBLE 1.8446744073709552e+19
#else
#error SIZEOF_INT is neither 4 nor 8
#endif
double
crypto_rand_double(void)
{
unsigned int u;
crypto_rand((char*)&u, sizeof(u));
return ((double)u) / UINT_MAX_AS_DOUBLE;
}
unsigned
crypto_fast_rng_get_uint(crypto_fast_rng_t *rng, unsigned limit)
{
tor_assert(limit < UINT_MAX);
IMPLEMENT_RAND_UNSIGNED(unsigned, UINT_MAX, limit,
crypto_fast_rng_getbytes(rng, (void*)&val, sizeof(val)));
}
uint64_t
crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit)
{
tor_assert(limit < UINT64_MAX);
IMPLEMENT_RAND_UNSIGNED(uint64_t, UINT64_MAX, limit,
crypto_fast_rng_getbytes(rng, (void*)&val, sizeof(val)));
}
uint32_t
crypto_fast_rng_get_u32(crypto_fast_rng_t *rng)
{
uint32_t val;
crypto_fast_rng_getbytes(rng, (void*)&val, sizeof(val));
return val;
}
uint64_t
crypto_fast_rng_uint64_range(crypto_fast_rng_t *rng,
uint64_t min, uint64_t max)
{
if (BUG(min >= max)) {
return min;
}
return min + crypto_fast_rng_get_uint64(rng, max - min);
}
double
crypto_fast_rng_get_double(crypto_fast_rng_t *rng)
{
unsigned int u;
crypto_fast_rng_getbytes(rng, (void*)&u, sizeof(u));
return ((double)u) / UINT_MAX_AS_DOUBLE;
}