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:
commit
f08d849f09
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user