Coverage Report

Created: 2024-07-26 06:04

/builds/xfbs/passgen/src/tests/random.c
Line
Count
Source
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
1.05k
    do {                                                         \
13
1.05k
        size_t coverage_len = ((size_t) max) / (collate) + 1ULL; \
14
1.05k
        uint8_t *coverage = calloc((coverage_len + 7) / 8, 1);   \
15
1.05k
        bool full_coverage = false;                              \
16
21.3k
        while(!full_coverage) {                                  \
17
5.22M
            for(size_t i = 0; i < 256; 
i++5.20M
) { \
18
5.20M
                size_t pos = function / (collate);               \
19
5.20M
                coverage[pos / 8] |= 1 << (pos % 8);             \
20
5.20M
            }                                                    \
21
20.3k
            full_coverage = true;                                \
22
47.2M
            for(size_t i = 0; i <= (max / (collate)); 
i++47.1M
) { \
23
47.2M
                if(!(coverage[i / 8] & (1 << (i % 8)))) {        \
24
19.2k
                    full_coverage = false;                       \
25
19.2k
                    break;                                       \
26
19.2k
                }                                                \
27
47.2M
            }                                                    \
28
20.3k
        }                                                        \
29
1.05k
        free(coverage);                                          \
30
1.05k
    } while(false)
31
32
2
double standard_deviation(size_t count, uint32_t *elements) {
33
2
    (void) count;
34
2
    (void) elements;
35
2
    // TODO: determine deviation
36
2
    return 0;
37
2
}
38
39
/// Tests that a given function has an even distribution
40
#define TEST_DISTRIBUTION(max, bucket_num, target, function)   \
41
2
    uint32_t *buckets = calloc(bucket_num, sizeof(uint32_t));  \
42
1.87M
    while(true) {                                              \
43
1.87M
        size_t bucket = function / ((max) / (bucket_num) + 1); \
44
1.87M
        buckets[bucket] += 1;                                  \
45
1.87M
        if(buckets[bucket] == target) {                        \
46
2
            break;                                             \
47
2
        }                                                      \
48
1.87M
    }                                                          \
49
2
    assert(standard_deviation(bucket_num, buckets) < 10);      \
50
2
    free(buckets)
51
52
1
test_result test_random_u8(void) {
53
1
    passgen_random random;
54
1
    assert(passgen_random_open(&random, NULL));
55
1
56
1
    TEST_COVERAGE(UINT8_MAX, 1, passgen_random_u8(&random));
57
1
58
1
    passgen_random_close(&random);
59
1
60
1
    return test_ok;
61
1
}
62
63
1
test_result test_random_u8_max(void) {
64
1
    passgen_random random;
65
1
    assert(passgen_random_open(&random, NULL));
66
1
67
255
    for(size_t max = 1; max < UINT8_MAX; 
max++254
) {
68
254
        TEST_COVERAGE(max - 1, 1, passgen_random_u8_max(&random, max));
69
254
    }
70
1
71
1
    passgen_random_close(&random);
72
1
73
1
    return test_ok;
74
1
}
75
76
1
test_result test_random_u16(void) {
77
1
    passgen_random random;
78
1
    assert(passgen_random_open(&random, NULL));
79
1
80
1
    TEST_COVERAGE(UINT16_MAX, 1, passgen_random_u16(&random));
81
1
82
1
    passgen_random_close(&random);
83
1
84
1
    return test_ok;
85
1
}
86
87
1
test_result test_random_u16_max(void) {
88
1
    passgen_random random;
89
1
    assert(passgen_random_open(&random, NULL));
90
1
91
255
    for(size_t max = 1; max < UINT8_MAX; 
max++254
) {
92
254
        TEST_COVERAGE(max - 1, 1, passgen_random_u16_max(&random, max));
93
254
    }
94
1
95
12
    for(size_t max = 1; max < UINT16_MAX; 
max *= 311
) {
96
11
        TEST_COVERAGE(max - 1, 1, passgen_random_u16_max(&random, max));
97
11
    }
98
1
99
1
    passgen_random_close(&random);
100
1
101
1
    return test_ok;
102
1
}
103
104
1
test_result test_random_u32(void) {
105
1
    passgen_random random;
106
1
    assert(passgen_random_open(&random, NULL));
107
1
108
1
    TEST_COVERAGE(UINT32_MAX, 1 << 16, passgen_random_u32(&random));
109
1
    TEST_DISTRIBUTION(
110
1
        UINT32_MAX,
111
1
        1 << 10,
112
1
        1 << 10,
113
1
        passgen_random_u32(&random));
114
1
115
1
    passgen_random_close(&random);
116
1
117
1
    return test_ok;
118
1
}
119
120
1
test_result test_random_u32_max(void) {
121
1
    passgen_random random;
122
1
    assert(passgen_random_open(&random, NULL));
123
1
124
255
    for(size_t max = 1; max < UINT8_MAX; 
max++254
) {
125
254
        TEST_COVERAGE(max - 1, 1, passgen_random_u32_max(&random, max));
126
254
    }
127
1
128
12
    for(size_t max = 1; max < UINT16_MAX; 
max *= 311
) {
129
11
        TEST_COVERAGE(max - 1, 1, passgen_random_u32_max(&random, max));
130
11
    }
131
1
132
1
    passgen_random_close(&random);
133
1
134
1
    return test_ok;
135
1
}
136
137
1
test_result test_random_u64(void) {
138
1
    passgen_random random;
139
1
    assert(passgen_random_open(&random, NULL));
140
1
141
1
    // FIXME
142
1
    // TEST_COVERAGE(UINT64_MAX, 1ULL << 48, 1024, passgen_random_u32(&random));
143
1
    TEST_DISTRIBUTION(
144
1
        UINT64_MAX,
145
1
        1 << 10,
146
1
        1 << 10,
147
1
        passgen_random_u64(&random));
148
1
149
1
    passgen_random_close(&random);
150
1
151
1
    return test_ok;
152
1
}
153
154
1
test_result test_random_u64_max(void) {
155
1
    passgen_random random;
156
1
    assert(passgen_random_open(&random, NULL));
157
1
158
255
    for(size_t max = 1; max < UINT8_MAX; 
max++254
) {
159
254
        TEST_COVERAGE(max - 1, 1, passgen_random_u64_max(&random, max));
160
254
    }
161
1
162
12
    for(size_t max = 1; max < UINT16_MAX; 
max *= 311
) {
163
11
        TEST_COVERAGE(max - 1, 1, passgen_random_u64_max(&random, max));
164
11
    }
165
1
166
1.00M
    for(size_t i = 1; i < 1000000; 
i++999k
) {
167
999k
        uint32_t max = passgen_random_u64(&random);
168
999k
169
999k
        assert(passgen_random_u64_max(&random, max) < max);
170
999k
    }
171
1
172
1
    passgen_random_close(&random);
173
1
174
1
    return test_ok;
175
1
}
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
1
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
1
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
1
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
1
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
1
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
1
227
1
    return test_ok;
228
1
}
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
1
243
1
    return test_ok;
244
1
}
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
1
257
1
    return test_ok;
258
1
}
259
260
1
test_result test_random_new_path(void) {
261
1
    passgen_random *random;
262
1
    random = passgen_random_path_open(NULL, "/dev/nonexistent");
263
1
    assert(!random);
264
1
265
1
    // 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
1
275
1
    return test_ok;
276
1
}
277
278
1
test_result test_random_open(void) {
279
1
    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
1
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
1
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
1
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
1
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
1
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
1
311
1
    return test_ok;
312
1
}
313
314
1
test_result test_random_path_open(void) {
315
1
    passgen_random random;
316
1
    assert(!passgen_random_path_open(&random, "/dev/nonexistent"));
317
1
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
1
327
1
    return test_ok;
328
1
}
329
330
#define XORSHIFT_SEED 234720984723
331
332
1
test_result test_random_read(void) {
333
1
    passgen_random random;
334
1
    assert(passgen_random_xorshift_open(&random, XORSHIFT_SEED));
335
1
336
1
    uint8_t data[2000] = {0};
337
1
338
1
    // 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
1
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
1
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
1
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
1
370
1
    // test wraparound.
371
1.00k
    while(random.pos != (sizeof(random.buffer) - 1)) {
372
1.00k
        passgen_random_read(&random, &data[0], 1);
373
1.00k
    }
374
1
    passgen_random_read(&random, &data[0], 1);
375
1
    assert(random.pos == 0);
376
1
377
1.02k
    while(random.pos != (sizeof(random.buffer) - 1)) {
378
1.02k
        passgen_random_read(&random, &data[0], 1);
379
1.02k
    }
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
1
385
1
    // test reading larger.
386
1
    passgen_random_read(&random, &data[0], sizeof(random.buffer) + 1);
387
1
    assert(random.pos == 2);
388
1
389
1
    passgen_random_close(&random);
390
1
391
1
    return test_ok;
392
1
}
393
394
#undef XORSHIFT_SEED
395
396
1
test_result test_random_xorshift(void) {
397
1
    passgen_random random;
398
1
399
1
    // 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
1
407
1
    // 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
1
415
1
    return test_ok;
416
1
}
417
418
#define CHECK_BEGINNING(random)                  \
419
2
    assert(passgen_random_u8(random) == 180);    \
420
2
    assert(passgen_random_u16(random) == 43073); \
421
2
    assert(passgen_random_u32(random) == 1604870485)
422
423
#define CHECK_REST(random)                                         \
424
3
    assert(passgen_random_u64(random) == 5567227278517054982ULL);  \
425
3
    assert(passgen_random_u64(random) == 10120912194545613486ULL); \
426
3
    assert(passgen_random_u64(random) == 14168488844181147231ULL); \
427
3
    assert(passgen_random_u64(random) == 17990605897407475310ULL); \
428
3
    assert(passgen_random_u64(random) == 14488897527995456554ULL); \
429
3
    assert(passgen_random_u64(random) == 16603445463307625220ULL); \
430
3
    assert(passgen_random_u64(random) == 17826730983279974707ULL); \
431
3
    assert(passgen_random_u64(random) == 7745812445609307379ULL);  \
432
3
    assert(passgen_random_u64(random) == 6756294678665739130ULL)
433
434
#ifdef PASSGEN_MONOCYPHER
435
1
test_result test_random_chacha20_seek(void) {
436
1
    passgen_random random;
437
1
438
1
    assert(
439
1
        passgen_random_chacha20_open(
440
1
            &random,
441
1
            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
442
1
            "passgen") != NULL);
443
2
    
CHECK_BEGINNING1
(&random);
444
8
    
CHECK_REST1
(&random);
445
1
446
1
    // seek back to beginning, same values
447
1
    passgen_random_chacha20_seek(&random, 0);
448
2
    
CHECK_BEGINNING1
(&random);
449
8
    
CHECK_REST1
(&random);
450
1
451
1
    // seek to middle of stream, only latter values
452
1
    passgen_random_chacha20_seek(&random, 7);
453
8
    
CHECK_REST1
(&random);
454
1
455
1
    passgen_random_close(&random);
456
1
457
1
    return test_ok;
458
8
}
459
460
#undef CHECK_BEGINNING
461
#undef CHECK_REST
462
463
1
test_result test_random_chacha20(void) {
464
1
    passgen_random random;
465
1
466
1
    assert(
467
1
        passgen_random_chacha20_open(
468
1
            &random,
469
1
            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
470
1
            "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
1
477
1
    assert(
478
1
        passgen_random_chacha20_open(
479
1
            &random,
480
1
            "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
481
1
            "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
1
488
1
    return test_ok;
489
1
}
490
491
1
test_result test_random_chacha20_argon2(void) {
492
1
    passgen_random random;
493
1
494
1
    assert(
495
1
        passgen_random_chacha20_argon2_open(
496
1
            &random,
497
1
            "mypassword",
498
1
            "google.com",
499
1
            "",
500
1
            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
1
507
1
    return test_ok;
508
1
}
509
510
#endif