summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-10-24 01:52:32 +0200
committerDirk Engling <erdgeist@erdgeist.org>2026-10-24 01:52:32 +0200
commit4b736de708fe5e0a0fc8b4d9e1af77d3f4c096c0 (patch)
treeb868f1f93a612ddbfb1395bebca6a966bfd1b11f /tests
parentecb1f1e92ab449023d1427f9db26c5bac09c4901 (diff)
Add the actual test for random ;)
Diffstat (limited to 'tests')
-rw-r--r--tests/t_random.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/tests/t_random.c b/tests/t_random.c
new file mode 100644
index 0000000..67dedf6
--- /dev/null
+++ b/tests/t_random.c
@@ -0,0 +1,114 @@
1/* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
3
4 $id$ */
5
6/* System */
7#include <stdint.h>
8#include <string.h>
9
10/* Opentracker */
11#include "ot_random.h"
12#include "test.h"
13
14/* Nothing here can test that the bytes are unpredictable, which is a property
15 of the generator the build selected. What these cases do pin is that the
16 wrapper hands the whole buffer to it, writes nothing beyond the length it
17 was given, and is actually wired to something that varies. The first of
18 those matters: the fallback this module replaced filled only the first
19 sixteen bytes of the sixty-four byte key buffer in ot_udp.c. */
20
21#define DRAWS 32
22#define BUFLEN 64
23
24static void case_every_byte_varies(void) {
25 unsigned char first[BUFLEN], draw[BUFLEN];
26 unsigned char varied[BUFLEN];
27 size_t i, n;
28
29 test_case("every byte of the buffer comes from the generator");
30 memset(varied, 0, sizeof(varied));
31 random_bytes(first, sizeof(first));
32
33 for (n = 0; n < DRAWS; ++n) {
34 random_bytes(draw, sizeof(draw));
35 for (i = 0; i < BUFLEN; ++i)
36 if (draw[i] != first[i])
37 varied[i] = 1;
38 }
39
40 /* A byte position that never moved across 32 draws is not being written.
41 A false alarm needs all 32 draws to agree by chance, around 256^-31. */
42 for (i = 0; i < BUFLEN; ++i)
43 if (!varied[i]) {
44 test_failf(__FILE__, __LINE__, "byte %zu never changed over %d draws", i, DRAWS);
45 return;
46 }
47 ++test_checks;
48}
49
50static void case_respects_length(void) {
51 unsigned char buf[32];
52 size_t i;
53
54 test_case("nothing is written past the requested length");
55 memset(buf, 0xA5, sizeof(buf));
56 random_bytes(buf, 8);
57 for (i = 8; i < sizeof(buf); ++i)
58 if (buf[i] != 0xA5) {
59 test_failf(__FILE__, __LINE__, "byte %zu past the end was overwritten", i);
60 return;
61 }
62 ++test_checks;
63}
64
65static void case_zero_length(void) {
66 unsigned char buf[4];
67
68 test_case("a zero length request writes nothing");
69 memset(buf, 0x5A, sizeof(buf));
70 random_bytes(buf, 0);
71 CHECK_MEM(buf, "\x5a\x5a\x5a\x5a", 4);
72}
73
74static void case_successive_draws_differ(void) {
75 unsigned char a[32], b[32];
76
77 test_case("two draws differ");
78 random_bytes(a, sizeof(a));
79 random_bytes(b, sizeof(b));
80 CHECK(memcmp(a, b, sizeof(a)) != 0);
81}
82
83static void case_uint32_varies(void) {
84 uint32_t first = random_uint32();
85 int differs = 0;
86 size_t n;
87
88 test_case("random_uint32 does not return a constant");
89 for (n = 0; n < DRAWS; ++n)
90 if (random_uint32() != first)
91 differs = 1;
92 CHECK(differs);
93}
94
95static void case_uint32_uses_the_top_bit(void) {
96 uint32_t seen = 0;
97 size_t n;
98
99 test_case("random_uint32 spans the full 32 bits");
100 /* random() never sets bit 31, so a build that returned it unmixed would
101 fail this. Over 64 draws the chance of a false alarm is 2^-64. */
102 for (n = 0; n < 64; ++n)
103 seen |= random_uint32();
104 CHECK_INT(seen & 0x80000000u, 0x80000000u);
105}
106
107void test_random(void) {
108 case_every_byte_varies();
109 case_respects_length();
110 case_zero_length();
111 case_successive_draws_differ();
112 case_uint32_varies();
113 case_uint32_uses_the_top_bit();
114}