From ec5fb4fbdac12a09d69a508d425422dc18b6c89f Mon Sep 17 00:00:00 2001 From: PeterKietzmann <peter.kietzmann@haw-hamburg.de> Date: Mon, 25 Jun 2018 09:05:54 +0200 Subject: [PATCH] sys/random: fix distribution of random_uint32_range() --- sys/include/random.h | 5 +---- sys/random/random.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/sys/include/random.h b/sys/include/random.h index 48b978782f..252a8379cf 100644 --- a/sys/include/random.h +++ b/sys/include/random.h @@ -92,10 +92,7 @@ void random_bytes(uint8_t *buf, size_t size); * * @return a random number on [a,b)-interval */ -static inline uint32_t random_uint32_range(uint32_t a, uint32_t b) -{ - return (random_uint32() % (b - a)) + a; -} +uint32_t random_uint32_range(uint32_t a, uint32_t b); #if PRNG_FLOAT /* These real versions are due to Isaku Wada, 2002/01/09 added */ diff --git a/sys/random/random.c b/sys/random/random.c index dc5e6cf38d..ad80880167 100644 --- a/sys/random/random.c +++ b/sys/random/random.c @@ -54,3 +54,30 @@ void random_bytes(uint8_t *target, size_t n) *target++ = *random_pos++; } } + +uint32_t random_uint32_range(uint32_t a, uint32_t b) +{ + assert(a < b); + + uint32_t divisor, rand_val, range = b - a; + uint8_t range_msb = bitarithm_msb(range); + + /* check if range is a power of two */ + if (!(range & (range - 1))) { + divisor = (1 << range_msb) - 1; + } + else if (range_msb < 31) { + /* leftshift for next power of two interval */ + divisor = (1 << (range_msb + 1)) -1; + } + else { + /* disable modulo operation in loop below */ + divisor = UINT32_MAX; + } + /* get random numbers until value is smaller than range */ + do { + rand_val = (random_uint32() & divisor); + } while (rand_val >= range); + /* return random in range [a,b] */ + return (rand_val + a); +} -- GitLab