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