1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #9410 from PeterKietzmann/pr_sys_rand_range

sys/random: fix distribution of random_uint32_range()
This commit is contained in:
Cenk Gündoğan 2018-06-26 15:41:45 +02:00 committed by GitHub
commit f08d849f09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 145 additions and 14 deletions

View File

@ -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 */

View File

@ -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);
}

View File

@ -3,12 +3,14 @@ Test application for the RNG sourcs.
## Supported commands
* distributions [N] — Take N samples and print a bit distribution graph on the terminal.
* dump [N] — Take N samples and print them on the terminal.
* dump [N][A B] — Take N samples and print them on the terminal. If A and B are
set, the PRNG returns values in the [A,B)-interval.
* fips — Run the FIPS 140-2 random number tests.
* entropy [N] — Calculate Shannon's entropy from N samples.
* seed [N] — Set the random seed to use.
* source [N] — Select the RNG source, or list them all.
* speed [N] — Run a PRNG for N seconds and print the number of KiB/sec afterwards.
* speed [N][A B] — Run a PRNG for N seconds and print the number of KiB/sec
afterwards. If A and B are set, the PRNG returns values in the [A,B)-interval.
## Sources
The following sources are supported:

View File

@ -90,12 +90,26 @@ static int cmd_dump(int argc, char **argv)
{
uint32_t samples = 100;
if (argc > 1) {
if (argc < 2) {
/* run the test */
test_dump(samples);
}
else if (argc == 2) {
samples = strtoul(argv[1], NULL, 0);
/* run the test */
test_dump(samples);
}
else if (argc == 4) {
samples = strtoul(argv[1], NULL, 0);
uint32_t low_thresh = strtoul(argv[2], NULL, 0);
uint32_t high_thresh = strtoul(argv[3], NULL, 0);
/* run the test */
test_dump_range(samples, low_thresh, high_thresh);
}
else {
printf("usage: %s [samples] [lower-bound upper-bound]\n", argv[0]);
}
/* run the test */
test_dump(samples);
return 0;
}
@ -220,12 +234,25 @@ static int cmd_speed(int argc, char **argv)
{
uint32_t duration = 10;
if (argc > 1) {
duration = strtoul(argv[1], NULL, 0);
if (argc < 2) {
/* run the test */
test_speed(duration);
}
else if (argc == 2) {
duration = strtoul(argv[1], NULL, 0);
/* run the test */
test_speed(duration);
}
else if (argc == 4) {
duration = strtoul(argv[1], NULL, 0);
uint32_t low_thresh = strtoul(argv[2], NULL, 0);
uint32_t high_thresh = strtoul(argv[3], NULL, 0);
/* run the test */
test_speed_range(duration, low_thresh, high_thresh);
}
else {
printf("usage: %s [duration] [lower-bound upper-bound]\n", argv[0]);
}
/* run the test */
test_speed(duration);
return 0;
}

View File

@ -103,6 +103,27 @@ static inline uint32_t test_get_uint32(void)
return 0;
}
/**
* @brief Retrieve a 32-bit number of the source RNG on [a,b)-interval
*/
static inline uint32_t test_get_uint32_range(uint32_t a, uint32_t b)
{
if (source == RNG_PRNG) {
return random_uint32_range(a, b);
}
#ifdef MODULE_PERIPH_HWRNG
else if (source == RNG_HWRNG) {
puts("Range feature not supported by HWRNG");
}
#endif
else if (source == RNG_CONSTANT) {
/* use the seed as the constant value */
return seed;
}
return 0;
}
/**
* @brief Helper for printing `passed` or `failed` depending on condition
*
@ -192,6 +213,15 @@ void test_dump(uint32_t samples)
}
}
void test_dump_range(uint32_t samples, uint32_t low_thresh, uint32_t high_thresh)
{
test_init("dump range");
while (samples--) {
printf("%" PRIu32 "\n", test_get_uint32_range(low_thresh, high_thresh));
}
}
void test_fips(void)
{
uint8_t last_bit = UINT8_MAX;
@ -378,3 +408,27 @@ void test_speed(uint32_t duration)
fmt_u64_dec(tmp2, (samples * 4 / 1024) / duration);
printf("Collected %s samples in %" PRIu32 " seconds (%s KiB/s).\n", tmp1, duration, tmp2);
}
void test_speed_range(uint32_t duration, uint32_t low_thresh, uint32_t high_thresh)
{
char tmp1[16] = { 0 }, tmp2[16] = { 0 };
uint64_t timeout = 0;
uint64_t samples = 0;
/* initialize test */
test_init("speed range");
/* collect samples as long as timer has not expired */
timeout = xtimer_now_usec64() + (duration * US_PER_SEC);
while (xtimer_now_usec64() < timeout) {
test_get_uint32_range(low_thresh, high_thresh);
samples++;
}
/* print results */
fmt_u64_dec(tmp1, samples);
fmt_u64_dec(tmp2, (samples * 4 / 1024) / duration);
printf("Collected %s samples in %" PRIu32 " seconds (%s KiB/s).\n", tmp1, duration, tmp2);
}

View File

@ -73,6 +73,18 @@ void test_distributions(uint32_t samples);
*/
void test_dump(uint32_t samples);
/**
* @brief Test for dumping random number r with a <= r < b. Each number
* is printed on a separate line as an unsigned 32-bit number.
*
* @param[in] samples Number of samples to print.
* @param[in] a Minimum for random number
* @param[in] b Upper bound for random number
*
* @pre a < b
*/
void test_dump_range(uint32_t samples, uint32_t a, uint32_t b);
/**
* @brief Run the FIPS 140-2 battery of test.
*
@ -104,6 +116,18 @@ void test_entropy(uint32_t samples);
*/
void test_speed(uint32_t duration);
/**
* @brief Run the speed test for random numbers r with a <= r < b and a given duration.
* It utillizes xtimer for setting an alarm.
*
* @param[in] duration Test duration (in seconds)
* @param[in] a Minimum for random number
* @param[in] b Upper bound for random number
*
* @pre a < b
*/
void test_speed_range(uint32_t duration, uint32_t a, uint32_t b);
#ifdef __cplusplus
}
#endif