LCOV - code coverage report
Current view: top level - src/tests - random.c (source / functions) Hit Total Coverage
Test: passgen-test.info Lines: 266 266 100.0 %
Date: 2024-11-29 06:05:05 Functions: 20 20 100.0 %

          Line data    Source code
       1             : #include "passgen/random.h"
       2             : #include "passgen/config.h"
       3             : 
       4             : #include <stdbool.h>
       5             : #include <stdio.h>
       6             : #include <stdlib.h>
       7             : 
       8             : #include "tests.h"
       9             : 
      10             : /// Tests that a given function covers all possible outputs (0..max, inclusive).
      11             : #define TEST_COVERAGE(max, collate, function)                    \
      12             :     do {                                                         \
      13             :         size_t coverage_len = ((size_t) max) / (collate) + 1ULL; \
      14             :         uint8_t *coverage = calloc((coverage_len + 7) / 8, 1);   \
      15             :         bool full_coverage = false;                              \
      16             :         while(!full_coverage) {                                  \
      17             :             for(size_t i = 0; i < 256; i++) {                    \
      18             :                 size_t pos = function / (collate);               \
      19             :                 coverage[pos / 8] |= 1 << (pos % 8);             \
      20             :             }                                                    \
      21             :             full_coverage = true;                                \
      22             :             for(size_t i = 0; i <= (max / (collate)); i++) {     \
      23             :                 if(!(coverage[i / 8] & (1 << (i % 8)))) {        \
      24             :                     full_coverage = false;                       \
      25             :                     break;                                       \
      26             :                 }                                                \
      27             :             }                                                    \
      28             :         }                                                        \
      29             :         free(coverage);                                          \
      30             :     } while(false)
      31             : 
      32           2 : double standard_deviation(size_t count, uint32_t *elements) {
      33             :     (void) count;
      34             :     (void) elements;
      35             :     // TODO: determine deviation
      36           2 :     return 0;
      37             : }
      38             : 
      39             : /// Tests that a given function has an even distribution
      40             : #define TEST_DISTRIBUTION(max, bucket_num, target, function)   \
      41             :     uint32_t *buckets = calloc(bucket_num, sizeof(uint32_t));  \
      42             :     while(true) {                                              \
      43             :         size_t bucket = function / ((max) / (bucket_num) + 1); \
      44             :         buckets[bucket] += 1;                                  \
      45             :         if(buckets[bucket] == target) {                        \
      46             :             break;                                             \
      47             :         }                                                      \
      48             :     }                                                          \
      49             :     assert(standard_deviation(bucket_num, buckets) < 10);      \
      50             :     free(buckets)
      51             : 
      52           1 : test_result test_random_u8(void) {
      53             :     passgen_random random;
      54           1 :     assert(passgen_random_open(&random, NULL));
      55             : 
      56        2745 :     TEST_COVERAGE(UINT8_MAX, 1, passgen_random_u8(&random));
      57             : 
      58           1 :     passgen_random_close(&random);
      59             : 
      60           1 :     return test_ok;
      61             : }
      62             : 
      63           1 : test_result test_random_u8_max(void) {
      64             :     passgen_random random;
      65           1 :     assert(passgen_random_open(&random, NULL));
      66             : 
      67         255 :     for(size_t max = 1; max < UINT8_MAX; max++) {
      68      279071 :         TEST_COVERAGE(max - 1, 1, passgen_random_u8_max(&random, max));
      69             :     }
      70             : 
      71           1 :     passgen_random_close(&random);
      72             : 
      73           1 :     return test_ok;
      74             : }
      75             : 
      76           1 : test_result test_random_u16(void) {
      77             :     passgen_random random;
      78           1 :     assert(passgen_random_open(&random, NULL));
      79             : 
      80    18939245 :     TEST_COVERAGE(UINT16_MAX, 1, passgen_random_u16(&random));
      81             : 
      82           1 :     passgen_random_close(&random);
      83             : 
      84           1 :     return test_ok;
      85             : }
      86             : 
      87           1 : test_result test_random_u16_max(void) {
      88             :     passgen_random random;
      89           1 :     assert(passgen_random_open(&random, NULL));
      90             : 
      91         255 :     for(size_t max = 1; max < UINT8_MAX; max++) {
      92      266879 :         TEST_COVERAGE(max - 1, 1, passgen_random_u16_max(&random, max));
      93             :     }
      94             : 
      95          12 :     for(size_t max = 1; max < UINT16_MAX; max *= 3) {
      96    16899591 :         TEST_COVERAGE(max - 1, 1, passgen_random_u16_max(&random, max));
      97             :     }
      98             : 
      99           1 :     passgen_random_close(&random);
     100             : 
     101           1 :     return test_ok;
     102             : }
     103             : 
     104           1 : test_result test_random_u32(void) {
     105             :     passgen_random random;
     106           1 :     assert(passgen_random_open(&random, NULL));
     107             : 
     108     7650941 :     TEST_COVERAGE(UINT32_MAX, 1 << 16, passgen_random_u32(&random));
     109      943787 :     TEST_DISTRIBUTION(
     110             :         UINT32_MAX,
     111             :         1 << 10,
     112             :         1 << 10,
     113             :         passgen_random_u32(&random));
     114             : 
     115           1 :     passgen_random_close(&random);
     116             : 
     117           1 :     return test_ok;
     118             : }
     119             : 
     120           1 : test_result test_random_u32_max(void) {
     121             :     passgen_random random;
     122           1 :     assert(passgen_random_open(&random, NULL));
     123             : 
     124         255 :     for(size_t max = 1; max < UINT8_MAX; max++) {
     125      273812 :         TEST_COVERAGE(max - 1, 1, passgen_random_u32_max(&random, max));
     126             :     }
     127             : 
     128          12 :     for(size_t max = 1; max < UINT16_MAX; max *= 3) {
     129    23552414 :         TEST_COVERAGE(max - 1, 1, passgen_random_u32_max(&random, max));
     130             :     }
     131             : 
     132           1 :     passgen_random_close(&random);
     133             : 
     134           1 :     return test_ok;
     135             : }
     136             : 
     137           1 : test_result test_random_u64(void) {
     138             :     passgen_random random;
     139           1 :     assert(passgen_random_open(&random, NULL));
     140             : 
     141             :     // FIXME
     142             :     //TEST_COVERAGE(UINT64_MAX, 1ULL << 48, 1024, passgen_random_u32(&random));
     143      956600 :     TEST_DISTRIBUTION(
     144             :         UINT64_MAX,
     145             :         1 << 10,
     146             :         1 << 10,
     147             :         passgen_random_u64(&random));
     148             : 
     149           1 :     passgen_random_close(&random);
     150             : 
     151           1 :     return test_ok;
     152             : }
     153             : 
     154           1 : test_result test_random_u64_max(void) {
     155             :     passgen_random random;
     156           1 :     assert(passgen_random_open(&random, NULL));
     157             : 
     158         255 :     for(size_t max = 1; max < UINT8_MAX; max++) {
     159      274422 :         TEST_COVERAGE(max - 1, 1, passgen_random_u64_max(&random, max));
     160             :     }
     161             : 
     162          12 :     for(size_t max = 1; max < UINT16_MAX; max *= 3) {
     163    30170954 :         TEST_COVERAGE(max - 1, 1, passgen_random_u64_max(&random, max));
     164             :     }
     165             : 
     166     1000000 :     for(size_t i = 1; i < 1000000; i++) {
     167      999999 :         uint32_t max = passgen_random_u64(&random);
     168             : 
     169      999999 :         assert(passgen_random_u64_max(&random, max) < max);
     170             :     }
     171             : 
     172           1 :     passgen_random_close(&random);
     173             : 
     174           1 :     return test_ok;
     175             : }
     176             : 
     177           1 : test_result test_random_new(void) {
     178           1 :     passgen_random *random_default = passgen_random_open(NULL, NULL);
     179           1 :     assert(random_default);
     180           1 :     assert(random_default->read);
     181           1 :     assert(random_default->close);
     182             : 
     183           1 :     passgen_random *random = passgen_random_open(NULL, "system");
     184           1 :     assert(random);
     185           1 :     assert_eq(random->read, random_default->read);
     186           1 :     assert_eq(random->close, random_default->close);
     187           1 :     passgen_random_free(random);
     188           1 :     passgen_random_free(random_default);
     189             : 
     190           1 :     random = passgen_random_open(NULL, "zero");
     191           1 :     assert(random);
     192           1 :     assert(random->read);
     193           1 :     assert(random->close);
     194           1 :     assert_eq(passgen_random_u8(random), 0);
     195           1 :     assert_eq(passgen_random_u16(random), 0);
     196           1 :     assert_eq(passgen_random_u32(random), 0);
     197           1 :     assert_eq(passgen_random_u64(random), 0);
     198           1 :     passgen_random_free(random);
     199             : 
     200           1 :     random = passgen_random_open(NULL, "xorshift:1234");
     201           1 :     assert(random);
     202           1 :     assert(random->read);
     203           1 :     assert(random->close);
     204           1 :     assert_eq(passgen_random_u8(random), 91);
     205           1 :     assert_eq(passgen_random_u16(random), 11632);
     206           1 :     assert_eq(passgen_random_u32(random), 79584);
     207           1 :     assert_eq(passgen_random_u64(random), 3801598356675656448ULL);
     208           1 :     assert_eq(passgen_random_u64_max(random, 999999999), 851051297);
     209           1 :     passgen_random_free(random);
     210             : 
     211           1 :     random = passgen_random_open(NULL, "file:/dev/zero");
     212           1 :     assert(random);
     213           1 :     assert(random->read);
     214           1 :     assert(random->close);
     215           1 :     assert_eq(passgen_random_u8(random), 0);
     216           1 :     assert_eq(passgen_random_u16(random), 0);
     217           1 :     assert_eq(passgen_random_u32(random), 0);
     218           1 :     assert_eq(passgen_random_u64(random), 0);
     219           1 :     passgen_random_free(random);
     220             : 
     221           1 :     assert(!passgen_random_open(NULL, "other"));
     222           1 :     assert(!passgen_random_open(NULL, "xorshift:abc"));
     223           1 :     assert(!passgen_random_open(NULL, "xorshift:"));
     224           1 :     assert(!passgen_random_open(NULL, "file:"));
     225           1 :     assert(!passgen_random_open(NULL, "file:/dev/nonexistant"));
     226             : 
     227           1 :     return test_ok;
     228             : }
     229             : 
     230           1 : test_result test_random_file(void) {
     231           1 :     FILE *file = fopen("/dev/zero", "r");
     232           1 :     assert(file);
     233           1 :     passgen_random *random = passgen_random_file_open(NULL, file);
     234           1 :     assert(random);
     235           1 :     assert(random->read);
     236           1 :     assert(random->close);
     237           1 :     assert_eq(passgen_random_u8(random), 0);
     238           1 :     assert_eq(passgen_random_u16(random), 0);
     239           1 :     assert_eq(passgen_random_u32(random), 0);
     240           1 :     assert_eq(passgen_random_u64(random), 0);
     241           1 :     passgen_random_free(random);
     242             : 
     243           1 :     return test_ok;
     244             : }
     245             : 
     246           1 : test_result test_random_zero(void) {
     247           1 :     passgen_random *random = passgen_random_zero_open(NULL);
     248           1 :     assert(random);
     249           1 :     assert(random->read);
     250           1 :     assert(random->close);
     251           1 :     assert_eq(passgen_random_u8(random), 0);
     252           1 :     assert_eq(passgen_random_u16(random), 0);
     253           1 :     assert_eq(passgen_random_u32(random), 0);
     254           1 :     assert_eq(passgen_random_u64(random), 0);
     255           1 :     passgen_random_free(random);
     256             : 
     257           1 :     return test_ok;
     258             : }
     259             : 
     260           1 : test_result test_random_new_path(void) {
     261             :     passgen_random *random;
     262           1 :     random = passgen_random_path_open(NULL, "/dev/nonexistent");
     263           1 :     assert(!random);
     264             : 
     265             :     // reading from /dev/zero should always yield zero.
     266           1 :     random = passgen_random_path_open(NULL, "/dev/zero");
     267           1 :     assert(random);
     268           1 :     assert(random->context);
     269           1 :     assert(passgen_random_u8(random) == 0);
     270           1 :     assert(passgen_random_u16(random) == 0);
     271           1 :     assert(passgen_random_u32(random) == 0);
     272           1 :     assert(passgen_random_u64(random) == 0);
     273           1 :     passgen_random_free(random);
     274             : 
     275           1 :     return test_ok;
     276             : }
     277             : 
     278           1 : test_result test_random_open(void) {
     279             :     passgen_random random;
     280           1 :     assert(passgen_random_open(&random, NULL));
     281           1 :     assert(random.read);
     282           1 :     assert(random.close);
     283           1 :     passgen_random_close(&random);
     284           1 :     assert(!random.read);
     285             : 
     286           1 :     assert(passgen_random_open(&random, "system"));
     287           1 :     assert(random.read);
     288           1 :     assert(random.close);
     289           1 :     passgen_random_close(&random);
     290             : 
     291           1 :     assert(passgen_random_open(&random, "xorshift:1234"));
     292           1 :     assert(random.read);
     293           1 :     assert(random.close);
     294           1 :     passgen_random_close(&random);
     295             : 
     296           1 :     assert(passgen_random_open(&random, "zero"));
     297           1 :     assert(random.read);
     298           1 :     assert(random.close);
     299           1 :     passgen_random_close(&random);
     300             : 
     301           1 :     assert(passgen_random_open(&random, "file:/dev/random"));
     302           1 :     assert(random.read);
     303           1 :     assert(random.close);
     304           1 :     passgen_random_close(&random);
     305             : 
     306           1 :     assert(!passgen_random_open(&random, "other"));
     307           1 :     assert(!passgen_random_open(&random, "file:/dev/notexists"));
     308           1 :     assert(!passgen_random_open(&random, "xorshift:"));
     309           1 :     assert(!passgen_random_open(&random, "xorshift:abc"));
     310             : 
     311           1 :     return test_ok;
     312             : }
     313             : 
     314           1 : test_result test_random_path_open(void) {
     315             :     passgen_random random;
     316           1 :     assert(!passgen_random_path_open(&random, "/dev/nonexistent"));
     317             : 
     318           1 :     assert(passgen_random_path_open(&random, "/dev/zero"));
     319           1 :     assert(random.context);
     320           1 :     assert(passgen_random_u8(&random) == 0);
     321           1 :     assert(passgen_random_u16(&random) == 0);
     322           1 :     assert(passgen_random_u32(&random) == 0);
     323           1 :     assert(passgen_random_u64(&random) == 0);
     324           1 :     passgen_random_close(&random);
     325           1 :     assert(!random.context);
     326             : 
     327           1 :     return test_ok;
     328             : }
     329             : 
     330             : #define XORSHIFT_SEED 234720984723
     331             : 
     332           1 : test_result test_random_read(void) {
     333             :     passgen_random random;
     334           1 :     assert(passgen_random_xorshift_open(&random, XORSHIFT_SEED));
     335             : 
     336           1 :     uint8_t data[2000] = {0};
     337             : 
     338             :     // fill small.
     339           1 :     passgen_random_read(&random, &data[0], 1);
     340           1 :     assert(random.pos == 1);
     341           1 :     assert(data[0] == random.buffer[0]);
     342           1 :     assert(data[1] == 0);
     343             : 
     344           1 :     passgen_random_read(&random, &data[0], 2);
     345           1 :     assert(random.pos == 3);
     346           1 :     assert(data[0] == random.buffer[1]);
     347           1 :     assert(data[1] == random.buffer[2]);
     348           1 :     assert(data[2] == 0);
     349             : 
     350           1 :     passgen_random_read(&random, &data[0], 4);
     351           1 :     assert(random.pos == 7);
     352           1 :     assert(data[0] == random.buffer[3]);
     353           1 :     assert(data[1] == random.buffer[4]);
     354           1 :     assert(data[2] == random.buffer[5]);
     355           1 :     assert(data[3] == random.buffer[6]);
     356           1 :     assert(data[4] == 0);
     357             : 
     358           1 :     passgen_random_read(&random, &data[0], 8);
     359           1 :     assert(random.pos == 15);
     360           1 :     assert(data[0] == random.buffer[7]);
     361           1 :     assert(data[1] == random.buffer[8]);
     362           1 :     assert(data[2] == random.buffer[9]);
     363           1 :     assert(data[3] == random.buffer[10]);
     364           1 :     assert(data[4] == random.buffer[11]);
     365           1 :     assert(data[5] == random.buffer[12]);
     366           1 :     assert(data[6] == random.buffer[13]);
     367           1 :     assert(data[7] == random.buffer[14]);
     368           1 :     assert(data[8] == 0);
     369             : 
     370             :     // test wraparound.
     371        1009 :     while(random.pos != (sizeof(random.buffer) - 1)) {
     372        1008 :         passgen_random_read(&random, &data[0], 1);
     373             :     }
     374           1 :     passgen_random_read(&random, &data[0], 1);
     375           1 :     assert(random.pos == 0);
     376             : 
     377        1024 :     while(random.pos != (sizeof(random.buffer) - 1)) {
     378        1023 :         passgen_random_read(&random, &data[0], 1);
     379             :     }
     380           1 :     passgen_random_read(&random, &data[0], 3);
     381           1 :     assert(data[1] == random.buffer[0]);
     382           1 :     assert(data[2] == random.buffer[1]);
     383           1 :     assert(random.pos == 2);
     384             : 
     385             :     // test reading larger.
     386           1 :     passgen_random_read(&random, &data[0], sizeof(random.buffer) + 1);
     387           1 :     assert(random.pos == 2);
     388             : 
     389           1 :     passgen_random_close(&random);
     390             : 
     391           1 :     return test_ok;
     392             : }
     393             : 
     394             : #undef XORSHIFT_SEED
     395             : 
     396           1 : test_result test_random_xorshift(void) {
     397             :     passgen_random random;
     398             : 
     399             :     // using a state of zero generates only zeroes.
     400           1 :     assert(passgen_random_xorshift_open(&random, 0) != NULL);
     401           1 :     assert(passgen_random_u8(&random) == 0);
     402           1 :     assert(passgen_random_u16(&random) == 0);
     403           1 :     assert(passgen_random_u32(&random) == 0);
     404           1 :     assert(passgen_random_u64(&random) == 0);
     405           1 :     passgen_random_close(&random);
     406             : 
     407             :     // same seed always yields the same output
     408           1 :     assert(passgen_random_xorshift_open(&random, 123) != NULL);
     409           1 :     assert(passgen_random_u8(&random) == 187);
     410           1 :     assert(passgen_random_u16(&random) == 31102);
     411           1 :     assert(passgen_random_u32(&random) == 7933);
     412           1 :     assert(passgen_random_u64(&random) == 2214108778545186304ULL);
     413           1 :     passgen_random_close(&random);
     414             : 
     415           1 :     return test_ok;
     416             : }
     417             : 
     418             : #define CHECK_BEGINNING(random)                  \
     419             :     assert(passgen_random_u8(random) == 180);    \
     420             :     assert(passgen_random_u16(random) == 43073); \
     421             :     assert(passgen_random_u32(random) == 1604870485)
     422             : 
     423             : #define CHECK_REST(random)                                         \
     424             :     assert(passgen_random_u64(random) == 5567227278517054982ULL);  \
     425             :     assert(passgen_random_u64(random) == 10120912194545613486ULL); \
     426             :     assert(passgen_random_u64(random) == 14168488844181147231ULL); \
     427             :     assert(passgen_random_u64(random) == 17990605897407475310ULL); \
     428             :     assert(passgen_random_u64(random) == 14488897527995456554ULL); \
     429             :     assert(passgen_random_u64(random) == 16603445463307625220ULL); \
     430             :     assert(passgen_random_u64(random) == 17826730983279974707ULL); \
     431             :     assert(passgen_random_u64(random) == 7745812445609307379ULL);  \
     432             :     assert(passgen_random_u64(random) == 6756294678665739130ULL)
     433             : 
     434             : #ifdef PASSGEN_MONOCYPHER
     435           1 : test_result test_random_chacha20_seek(void) {
     436             :     passgen_random random;
     437             : 
     438           1 :     assert(
     439             :         passgen_random_chacha20_open(
     440             :             &random,
     441             :             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
     442             :             "passgen") != NULL);
     443           1 :     CHECK_BEGINNING(&random);
     444           1 :     CHECK_REST(&random);
     445             : 
     446             :     // seek back to beginning, same values
     447           1 :     passgen_random_chacha20_seek(&random, 0);
     448           1 :     CHECK_BEGINNING(&random);
     449           1 :     CHECK_REST(&random);
     450             : 
     451             :     // seek to middle of stream, only latter values
     452           1 :     passgen_random_chacha20_seek(&random, 7);
     453           1 :     CHECK_REST(&random);
     454             : 
     455           1 :     passgen_random_close(&random);
     456             : 
     457           1 :     return test_ok;
     458             : }
     459             : 
     460             : #undef CHECK_BEGINNING
     461             : #undef CHECK_REST
     462             : 
     463           1 : test_result test_random_chacha20(void) {
     464             :     passgen_random random;
     465             : 
     466           1 :     assert(
     467             :         passgen_random_chacha20_open(
     468             :             &random,
     469             :             "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
     470             :             "passgen") != NULL);
     471           1 :     assert(passgen_random_u8(&random) == 180);
     472           1 :     assert(passgen_random_u16(&random) == 43073);
     473           1 :     assert(passgen_random_u32(&random) == 1604870485);
     474           1 :     assert(passgen_random_u64(&random) == 5567227278517054982ULL);
     475           1 :     passgen_random_close(&random);
     476             : 
     477           1 :     assert(
     478             :         passgen_random_chacha20_open(
     479             :             &random,
     480             :             "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
     481             :             "passgen") != NULL);
     482           1 :     assert(passgen_random_u8(&random) == 14);
     483           1 :     assert(passgen_random_u16(&random) == 19281);
     484           1 :     assert(passgen_random_u32(&random) == 2608689089);
     485           1 :     assert(passgen_random_u64(&random) == 12744604773769097796ULL);
     486           1 :     passgen_random_close(&random);
     487             : 
     488           1 :     return test_ok;
     489             : }
     490             : 
     491           1 : test_result test_random_chacha20_argon2(void) {
     492             :     passgen_random random;
     493             : 
     494           1 :     assert(
     495             :         passgen_random_chacha20_argon2_open(
     496             :             &random,
     497             :             "mypassword",
     498             :             "google.com",
     499             :             "",
     500             :             NULL) != NULL);
     501           1 :     assert(passgen_random_u8(&random) == 53);
     502           1 :     assert(passgen_random_u16(&random) == 45909);
     503           1 :     assert(passgen_random_u32(&random) == 1750958599);
     504           1 :     assert(passgen_random_u64(&random) == 13270789079271667756ULL);
     505           1 :     passgen_random_close(&random);
     506             : 
     507           1 :     return test_ok;
     508             : }
     509             : 
     510             : #endif

Generated by: LCOV version 1.14