]>
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 | |
94d457e8 | 12 | static 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 | 26 | static 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 | 40 | static 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 | ||
60 | static 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 | ||
97 | static void test_random_u64_range(void) { | |
98 | for (unsigned mod = 1; mod < 29; mod++) | |
99 | test_random_u64_range_one(mod); | |
100 | } | |
101 | ||
2416f73b | 102 | int 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 | } |