]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-random-util.c
test-random-util: add stochastic test for random_u64_range()
[thirdparty/systemd.git] / src / test / test-random-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2416f73b 2
f2a8b8de
ZJS
3#include <math.h>
4
2416f73b 5#include "hexdecoct.h"
2416f73b 6#include "log.h"
f2a8b8de
ZJS
7#include "memory-util.h"
8#include "random-util.h"
9#include "terminal-util.h"
6d7c4033 10#include "tests.h"
2416f73b 11
94d457e8 12static void test_genuine_random_bytes(RandomFlags flags) {
2416f73b 13 uint8_t buf[16] = {};
2416f73b
ZJS
14
15 log_info("/* %s */", __func__);
16
93457c0c 17 for (size_t i = 1; i < sizeof buf; i++) {
94d457e8 18 assert_se(genuine_random_bytes(buf, i, flags) == 0);
2416f73b
ZJS
19 if (i + 1 < sizeof buf)
20 assert_se(buf[i] == 0);
21
22 hexdump(stdout, buf, i);
23 }
24}
25
3335dc2d 26static void test_pseudo_random_bytes(void) {
2416f73b 27 uint8_t buf[16] = {};
2416f73b
ZJS
28
29 log_info("/* %s */", __func__);
30
93457c0c 31 for (size_t i = 1; i < sizeof buf; i++) {
3335dc2d 32 pseudo_random_bytes(buf, i);
2416f73b
ZJS
33 if (i + 1 < sizeof buf)
34 assert_se(buf[i] == 0);
35
36 hexdump(stdout, buf, i);
37 }
38}
39
33dbab6f 40static void test_rdrand(void) {
93457c0c 41 int r;
97fa202a 42
93457c0c
ZJS
43 log_info("/* %s */", __func__);
44
45 for (unsigned i = 0; i < 10; i++) {
33dbab6f 46 unsigned long x = 0;
97fa202a 47
33dbab6f 48 r = rdrand(&x);
97fa202a
LP
49 if (r < 0) {
50 log_error_errno(r, "RDRAND failed: %m");
51 return;
52 }
53
33dbab6f 54 printf("%lx\n", x);
97fa202a
LP
55 }
56}
57
f2a8b8de
ZJS
58#define TOTAL 100000
59
60static void test_random_u64_range_one(unsigned mod) {
61 log_info("/* %s(%u) */", __func__, mod);
62
63 unsigned max = 0, count[mod];
64 zero(count);
65
66 for (unsigned i = 0; i < TOTAL; i++) {
67 uint64_t x;
68
69 x = random_u64_range(mod);
70
71 log_trace("%05u: %"PRIu64, i, x);
72 count[x]++;
73 max = MAX(max, count[x]);
74 }
75
76 /* Print histogram: vertical axis — value, horizontal axis — count.
77 *
78 * The expected value is always TOTAL/mod, because the distribution should be flat. The expected
79 * variance is TOTAL×p×(1-p), where p==1/mod, and standard deviation the root of the variance.
80 * Assert that the deviation from the expected value is less than 6 standard deviations.
81 */
82 unsigned scale = 2 * max / (columns() < 20 ? 80 : columns() - 20);
83 double exp = (double) TOTAL / mod;
84
85 for (size_t i = 0; i < mod; i++) {
86 double dev = (count[i] - exp) / sqrt(exp * (mod > 1 ? mod - 1 : 1) / mod);
87 log_debug("%02zu: %5u (%+.3f)%*s",
88 i, count[i], dev,
89 count[i] / scale, "x");
90
91 assert_se(fabs(dev) < 6); /* 6 sigma is excessive, but this check should be enough to
92 * identify catastrophic failure while minimizing false
93 * positives. */
94 }
95}
96
97static void test_random_u64_range(void) {
98 for (unsigned mod = 1; mod < 29; mod++)
99 test_random_u64_range_one(mod);
100}
101
2416f73b 102int main(int argc, char **argv) {
6d7c4033 103 test_setup_logging(LOG_DEBUG);
2416f73b 104
94d457e8
LP
105 test_genuine_random_bytes(RANDOM_EXTEND_WITH_PSEUDO);
106 test_genuine_random_bytes(0);
68534345 107 test_genuine_random_bytes(RANDOM_BLOCK);
cc83d519 108 test_genuine_random_bytes(RANDOM_ALLOW_RDRAND);
0497c4c2 109 test_genuine_random_bytes(RANDOM_ALLOW_INSECURE);
2416f73b 110
3335dc2d 111 test_pseudo_random_bytes();
33dbab6f 112 test_rdrand();
f2a8b8de 113 test_random_u64_range();
97fa202a 114
2416f73b
ZJS
115 return 0;
116}