From 4b736de708fe5e0a0fc8b4d9e1af77d3f4c096c0 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Sat, 24 Oct 2026 01:52:32 +0200 Subject: Add the actual test for random ;) --- tests/t_random.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tests/t_random.c (limited to 'tests') 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 @@ +/* This software was written by Dirk Engling + It is considered beerware. Prost. Skol. Cheers or whatever. + + $id$ */ + +/* System */ +#include +#include + +/* Opentracker */ +#include "ot_random.h" +#include "test.h" + +/* Nothing here can test that the bytes are unpredictable, which is a property + of the generator the build selected. What these cases do pin is that the + wrapper hands the whole buffer to it, writes nothing beyond the length it + was given, and is actually wired to something that varies. The first of + those matters: the fallback this module replaced filled only the first + sixteen bytes of the sixty-four byte key buffer in ot_udp.c. */ + +#define DRAWS 32 +#define BUFLEN 64 + +static void case_every_byte_varies(void) { + unsigned char first[BUFLEN], draw[BUFLEN]; + unsigned char varied[BUFLEN]; + size_t i, n; + + test_case("every byte of the buffer comes from the generator"); + memset(varied, 0, sizeof(varied)); + random_bytes(first, sizeof(first)); + + for (n = 0; n < DRAWS; ++n) { + random_bytes(draw, sizeof(draw)); + for (i = 0; i < BUFLEN; ++i) + if (draw[i] != first[i]) + varied[i] = 1; + } + + /* A byte position that never moved across 32 draws is not being written. + A false alarm needs all 32 draws to agree by chance, around 256^-31. */ + for (i = 0; i < BUFLEN; ++i) + if (!varied[i]) { + test_failf(__FILE__, __LINE__, "byte %zu never changed over %d draws", i, DRAWS); + return; + } + ++test_checks; +} + +static void case_respects_length(void) { + unsigned char buf[32]; + size_t i; + + test_case("nothing is written past the requested length"); + memset(buf, 0xA5, sizeof(buf)); + random_bytes(buf, 8); + for (i = 8; i < sizeof(buf); ++i) + if (buf[i] != 0xA5) { + test_failf(__FILE__, __LINE__, "byte %zu past the end was overwritten", i); + return; + } + ++test_checks; +} + +static void case_zero_length(void) { + unsigned char buf[4]; + + test_case("a zero length request writes nothing"); + memset(buf, 0x5A, sizeof(buf)); + random_bytes(buf, 0); + CHECK_MEM(buf, "\x5a\x5a\x5a\x5a", 4); +} + +static void case_successive_draws_differ(void) { + unsigned char a[32], b[32]; + + test_case("two draws differ"); + random_bytes(a, sizeof(a)); + random_bytes(b, sizeof(b)); + CHECK(memcmp(a, b, sizeof(a)) != 0); +} + +static void case_uint32_varies(void) { + uint32_t first = random_uint32(); + int differs = 0; + size_t n; + + test_case("random_uint32 does not return a constant"); + for (n = 0; n < DRAWS; ++n) + if (random_uint32() != first) + differs = 1; + CHECK(differs); +} + +static void case_uint32_uses_the_top_bit(void) { + uint32_t seen = 0; + size_t n; + + test_case("random_uint32 spans the full 32 bits"); + /* random() never sets bit 31, so a build that returned it unmixed would + fail this. Over 64 draws the chance of a false alarm is 2^-64. */ + for (n = 0; n < 64; ++n) + seen |= random_uint32(); + CHECK_INT(seen & 0x80000000u, 0x80000000u); +} + +void test_random(void) { + case_every_byte_varies(); + case_respects_length(); + case_zero_length(); + case_successive_draws_differ(); + case_uint32_varies(); + case_uint32_uses_the_top_bit(); +} -- cgit v1.3