mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 12:52:44 +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
|
* @return a random number on [a,b)-interval
|
||||||
*/
|
*/
|
||||||
static inline uint32_t random_uint32_range(uint32_t a, uint32_t b)
|
uint32_t random_uint32_range(uint32_t a, uint32_t b);
|
||||||
{
|
|
||||||
return (random_uint32() % (b - a)) + a;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if PRNG_FLOAT
|
#if PRNG_FLOAT
|
||||||
/* These real versions are due to Isaku Wada, 2002/01/09 added */
|
/* 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++;
|
*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
|
## Supported commands
|
||||||
* distributions [N] — Take N samples and print a bit distribution graph on the terminal.
|
* 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.
|
* fips — Run the FIPS 140-2 random number tests.
|
||||||
* entropy [N] — Calculate Shannon's entropy from N samples.
|
* entropy [N] — Calculate Shannon's entropy from N samples.
|
||||||
* seed [N] — Set the random seed to use.
|
* seed [N] — Set the random seed to use.
|
||||||
* source [N] — Select the RNG source, or list them all.
|
* 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
|
## Sources
|
||||||
The following sources are supported:
|
The following sources are supported:
|
||||||
|
@ -90,12 +90,26 @@ static int cmd_dump(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
uint32_t samples = 100;
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -220,12 +234,25 @@ static int cmd_speed(int argc, char **argv)
|
|||||||
{
|
{
|
||||||
uint32_t duration = 10;
|
uint32_t duration = 10;
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc < 2) {
|
||||||
duration = strtoul(argv[1], NULL, 0);
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,27 @@ static inline uint32_t test_get_uint32(void)
|
|||||||
return 0;
|
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
|
* @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)
|
void test_fips(void)
|
||||||
{
|
{
|
||||||
uint8_t last_bit = UINT8_MAX;
|
uint8_t last_bit = UINT8_MAX;
|
||||||
@ -378,3 +408,27 @@ void test_speed(uint32_t duration)
|
|||||||
fmt_u64_dec(tmp2, (samples * 4 / 1024) / duration);
|
fmt_u64_dec(tmp2, (samples * 4 / 1024) / duration);
|
||||||
printf("Collected %s samples in %" PRIu32 " seconds (%s KiB/s).\n", tmp1, duration, tmp2);
|
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);
|
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.
|
* @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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user