]>
Commit | Line | Data |
---|---|---|
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 | |
4f7452a8 | 12 | static void test_genuine_random_bytes_one(RandomFlags flags) { |
2416f73b | 13 | uint8_t buf[16] = {}; |
2416f73b | 14 | |
4f7452a8 | 15 | log_info("/* %s(%d) */", __func__, flags); |
2416f73b | 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 | ||
4f7452a8 | 26 | TEST(genuine_random_bytes) { |
4f7452a8 JJ |
27 | test_genuine_random_bytes_one(0); |
28 | test_genuine_random_bytes_one(RANDOM_BLOCK); | |
29 | test_genuine_random_bytes_one(RANDOM_ALLOW_RDRAND); | |
4f7452a8 | 30 | } |
2416f73b | 31 | |
4f7452a8 JJ |
32 | TEST(pseudo_random_bytes) { |
33 | uint8_t buf[16] = {}; | |
2416f73b | 34 | |
93457c0c | 35 | for (size_t i = 1; i < sizeof buf; i++) { |
3335dc2d | 36 | pseudo_random_bytes(buf, i); |
2416f73b ZJS |
37 | if (i + 1 < sizeof buf) |
38 | assert_se(buf[i] == 0); | |
39 | ||
40 | hexdump(stdout, buf, i); | |
41 | } | |
42 | } | |
43 | ||
4f7452a8 | 44 | TEST(rdrand) { |
93457c0c | 45 | int r; |
97fa202a | 46 | |
93457c0c | 47 | for (unsigned i = 0; i < 10; i++) { |
33dbab6f | 48 | unsigned long x = 0; |
97fa202a | 49 | |
33dbab6f | 50 | r = rdrand(&x); |
97fa202a LP |
51 | if (r < 0) { |
52 | log_error_errno(r, "RDRAND failed: %m"); | |
53 | return; | |
54 | } | |
55 | ||
33dbab6f | 56 | printf("%lx\n", x); |
97fa202a LP |
57 | } |
58 | } | |
59 | ||
f2a8b8de ZJS |
60 | #define TOTAL 100000 |
61 | ||
62 | static void test_random_u64_range_one(unsigned mod) { | |
63 | log_info("/* %s(%u) */", __func__, mod); | |
64 | ||
65 | unsigned max = 0, count[mod]; | |
66 | zero(count); | |
67 | ||
68 | for (unsigned i = 0; i < TOTAL; i++) { | |
69 | uint64_t x; | |
70 | ||
71 | x = random_u64_range(mod); | |
72 | ||
f2a8b8de ZJS |
73 | count[x]++; |
74 | max = MAX(max, count[x]); | |
75 | } | |
76 | ||
77 | /* Print histogram: vertical axis — value, horizontal axis — count. | |
78 | * | |
79 | * The expected value is always TOTAL/mod, because the distribution should be flat. The expected | |
80 | * variance is TOTAL×p×(1-p), where p==1/mod, and standard deviation the root of the variance. | |
81 | * Assert that the deviation from the expected value is less than 6 standard deviations. | |
82 | */ | |
83 | unsigned scale = 2 * max / (columns() < 20 ? 80 : columns() - 20); | |
84 | double exp = (double) TOTAL / mod; | |
85 | ||
86 | for (size_t i = 0; i < mod; i++) { | |
87 | double dev = (count[i] - exp) / sqrt(exp * (mod > 1 ? mod - 1 : 1) / mod); | |
88 | log_debug("%02zu: %5u (%+.3f)%*s", | |
89 | i, count[i], dev, | |
90 | count[i] / scale, "x"); | |
91 | ||
92 | assert_se(fabs(dev) < 6); /* 6 sigma is excessive, but this check should be enough to | |
93 | * identify catastrophic failure while minimizing false | |
94 | * positives. */ | |
95 | } | |
96 | } | |
97 | ||
4f7452a8 | 98 | TEST(random_u64_range) { |
f2a8b8de ZJS |
99 | for (unsigned mod = 1; mod < 29; mod++) |
100 | test_random_u64_range_one(mod); | |
101 | } | |
102 | ||
4f7452a8 | 103 | DEFINE_TEST_MAIN(LOG_DEBUG); |