1273872Smarkm/*-
2284959Smarkm * Copyright (c) 2000-2015 Mark R V Murray
3273872Smarkm * All rights reserved.
4273872Smarkm *
5273872Smarkm * Redistribution and use in source and binary forms, with or without
6273872Smarkm * modification, are permitted provided that the following conditions
7273872Smarkm * are met:
8273872Smarkm * 1. Redistributions of source code must retain the above copyright
9273872Smarkm *    notice, this list of conditions and the following disclaimer
10273872Smarkm *    in this position and unchanged.
11273872Smarkm * 2. Redistributions in binary form must reproduce the above copyright
12273872Smarkm *    notice, this list of conditions and the following disclaimer in the
13273872Smarkm *    documentation and/or other materials provided with the distribution.
14273872Smarkm *
15273872Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16273872Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17273872Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18273872Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19273872Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20273872Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21273872Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22273872Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23273872Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24273872Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25273872Smarkm *
26273872Smarkm * $FreeBSD$
27273872Smarkm */
28273872Smarkm
29273872Smarkm/*
30273872Smarkm Build this by going:
31273872Smarkm
32287023Smarkmcc -g -O0 -pthread -DRANDOM_<alg> -I../.. -lstdthreads -Wall \
33273872Smarkm	unit_test.c \
34273872Smarkm	yarrow.c \
35273872Smarkm	fortuna.c \
36273872Smarkm	hash.c \
37273872Smarkm	../../crypto/rijndael/rijndael-api-fst.c \
38273872Smarkm	../../crypto/rijndael/rijndael-alg-fst.c \
39292782Sallanjude	../../crypto/sha2/sha256c.c \
40284959Smarkm        -lz \
41273872Smarkm	-o unit_test
42273872Smarkm./unit_test
43273872Smarkm
44273872SmarkmWhere <alg> is YARROW or FORTUNA.
45273872Smarkm*/
46273872Smarkm
47273872Smarkm#include <sys/types.h>
48273872Smarkm#include <inttypes.h>
49286839Smarkm#include <stdbool.h>
50273872Smarkm#include <stdio.h>
51273872Smarkm#include <stdlib.h>
52273872Smarkm#include <threads.h>
53273872Smarkm#include <unistd.h>
54284959Smarkm#include <zlib.h>
55273872Smarkm
56285422Smarkm#include "randomdev.h"
57273872Smarkm#include "unit_test.h"
58273872Smarkm
59284959Smarkm#define	NUM_THREADS	  3
60284959Smarkm#define	DEBUG
61273872Smarkm
62273872Smarkmstatic volatile int stopseeding = 0;
63273872Smarkm
64284959Smarkmstatic __inline void
65284959Smarkmcheck_err(int err, const char *func)
66284959Smarkm{
67284959Smarkm	if (err != Z_OK) {
68284959Smarkm		fprintf(stderr, "Compress error in %s: %d\n", func, err);
69284959Smarkm		exit(0);
70284959Smarkm	}
71284959Smarkm}
72284959Smarkm
73284959Smarkmvoid *
74284959Smarkmmyalloc(void *q, unsigned n, unsigned m)
75284959Smarkm{
76284959Smarkm	q = Z_NULL;
77284959Smarkm	return (calloc(n, m));
78284959Smarkm}
79284959Smarkm
80284959Smarkmvoid myfree(void *q, void *p)
81284959Smarkm{
82284959Smarkm	q = Z_NULL;
83284959Smarkm	free(p);
84284959Smarkm}
85284959Smarkm
86284959Smarkmsize_t
87284959Smarkmblock_deflate(uint8_t *uncompr, uint8_t *compr, const size_t len)
88284959Smarkm{
89284959Smarkm	z_stream c_stream;
90284959Smarkm	int err;
91284959Smarkm
92284959Smarkm	if (len == 0)
93284959Smarkm		return (0);
94284959Smarkm
95284959Smarkm	c_stream.zalloc = myalloc;
96284959Smarkm	c_stream.zfree = myfree;
97284959Smarkm	c_stream.opaque = NULL;
98284959Smarkm
99284959Smarkm	err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
100284959Smarkm	check_err(err, "deflateInit");
101284959Smarkm
102284959Smarkm	c_stream.next_in  = uncompr;
103284959Smarkm	c_stream.next_out = compr;
104284959Smarkm	c_stream.avail_in = len;
105284959Smarkm	c_stream.avail_out = len*2u +512u;
106284959Smarkm
107284959Smarkm	while (c_stream.total_in != len && c_stream.total_out < (len*2u + 512u)) {
108284959Smarkm		err = deflate(&c_stream, Z_NO_FLUSH);
109284959Smarkm#ifdef DEBUG
110285422Smarkm		printf("deflate progress: len = %zd  total_in = %lu  total_out = %lu\n", len, c_stream.total_in, c_stream.total_out);
111284959Smarkm#endif
112284959Smarkm		check_err(err, "deflate(..., Z_NO_FLUSH)");
113284959Smarkm	}
114284959Smarkm
115284959Smarkm	for (;;) {
116284959Smarkm		err = deflate(&c_stream, Z_FINISH);
117284959Smarkm#ifdef DEBUG
118285422Smarkm		printf("deflate    final: len = %zd  total_in = %lu  total_out = %lu\n", len, c_stream.total_in, c_stream.total_out);
119284959Smarkm#endif
120284959Smarkm		if (err == Z_STREAM_END) break;
121284959Smarkm		check_err(err, "deflate(..., Z_STREAM_END)");
122284959Smarkm	}
123284959Smarkm
124284959Smarkm	err = deflateEnd(&c_stream);
125284959Smarkm	check_err(err, "deflateEnd");
126284959Smarkm
127284959Smarkm	return ((size_t)c_stream.total_out);
128284959Smarkm}
129284959Smarkm
130273872Smarkmvoid
131285422Smarkmrandomdev_unblock(void)
132273872Smarkm{
133273872Smarkm
134273872Smarkm#if 0
135273872Smarkm	if (mtx_trylock(&random_reseed_mtx) == thrd_busy)
136273872Smarkm		printf("Mutex held. Good.\n");
137273872Smarkm	else {
138273872Smarkm		printf("Mutex not held. PANIC!!\n");
139273872Smarkm		thrd_exit(0);
140273872Smarkm	}
141273872Smarkm#endif
142273872Smarkm	printf("random: unblocking device.\n");
143273872Smarkm}
144273872Smarkm
145273872Smarkmstatic int
146273872SmarkmRunHarvester(void *arg __unused)
147273872Smarkm{
148273872Smarkm	int i, r;
149273872Smarkm	struct harvest_event e;
150273872Smarkm
151273872Smarkm	for (i = 0; ; i++) {
152273872Smarkm		if (stopseeding)
153273872Smarkm			break;
154273872Smarkm		if (i % 1000 == 0)
155273872Smarkm			printf("Harvest: %d\n", i);
156273872Smarkm		r = random()%10;
157273872Smarkm		e.he_somecounter = i;
158273872Smarkm		*((uint64_t *)e.he_entropy) = random();
159273872Smarkm		e.he_size = 8;
160273872Smarkm		e.he_bits = random()%4;
161273872Smarkm		e.he_destination = i;
162273872Smarkm		e.he_source = (i + 3)%7;
163273872Smarkm		e.he_next = NULL;
164285422Smarkm		random_alg_context.ra_event_processor(&e);
165273872Smarkm		usleep(r);
166273872Smarkm	}
167273872Smarkm
168273872Smarkm	printf("Thread #0 ends\n");
169273872Smarkm
170273872Smarkm	thrd_exit(0);
171273872Smarkm
172273872Smarkm	return (0);
173273872Smarkm}
174273872Smarkm
175273872Smarkmstatic int
176273872SmarkmReadCSPRNG(void *threadid)
177273872Smarkm{
178284959Smarkm	size_t tid, zsize;
179285422Smarkm	u_int buffersize;
180284959Smarkm	uint8_t *buf, *zbuf;
181273872Smarkm	int i;
182284959Smarkm#ifdef DEBUG
183284959Smarkm	int j;
184284959Smarkm#endif
185273872Smarkm
186273872Smarkm	tid = (size_t)threadid;
187273872Smarkm	printf("Thread #%zd starts\n", tid);
188273872Smarkm
189285422Smarkm	while (!random_alg_context.ra_seeded())
190273872Smarkm	{
191285422Smarkm		random_alg_context.ra_pre_read();
192273872Smarkm		usleep(100);
193273872Smarkm	}
194273872Smarkm
195273872Smarkm	for (i = 0; i < 100000; i++) {
196285422Smarkm		buffersize = i + RANDOM_BLOCKSIZE;
197285422Smarkm		buffersize -= buffersize%RANDOM_BLOCKSIZE;
198285422Smarkm		buf = malloc(buffersize);
199284959Smarkm		zbuf = malloc(2*i + 1024);
200273872Smarkm		if (i % 1000 == 0)
201284959Smarkm			printf("Thread read %zd - %d\n", tid, i);
202284959Smarkm		if (buf != NULL && zbuf != NULL) {
203285422Smarkm			random_alg_context.ra_pre_read();
204285422Smarkm			random_alg_context.ra_read(buf, buffersize);
205284959Smarkm			zsize = block_deflate(buf, zbuf, i);
206284959Smarkm			if (zsize < i)
207284959Smarkm				printf("ERROR!! Compressible RNG output!\n");
208284959Smarkm#ifdef DEBUG
209284959Smarkm			printf("RNG output:\n");
210273872Smarkm			for (j = 0; j < i; j++) {
211273872Smarkm				printf(" %02X", buf[j]);
212273872Smarkm				if (j % 32 == 31 || j == i - 1)
213273872Smarkm					printf("\n");
214273872Smarkm			}
215284959Smarkm			printf("Compressed output:\n");
216284959Smarkm			for (j = 0; j < zsize; j++) {
217284959Smarkm				printf(" %02X", zbuf[j]);
218284959Smarkm				if (j % 32 == 31 || j == zsize - 1)
219284959Smarkm					printf("\n");
220273872Smarkm			}
221273872Smarkm#endif
222284959Smarkm			free(zbuf);
223273872Smarkm			free(buf);
224273872Smarkm		}
225273872Smarkm		usleep(100);
226273872Smarkm	}
227273872Smarkm
228273872Smarkm	printf("Thread #%zd ends\n", tid);
229273872Smarkm
230273872Smarkm	thrd_exit(0);
231273872Smarkm
232273872Smarkm	return (0);
233273872Smarkm}
234273872Smarkm
235273872Smarkmint
236273872Smarkmmain(int argc, char *argv[])
237273872Smarkm{
238273872Smarkm	thrd_t threads[NUM_THREADS];
239273872Smarkm	int rc;
240273872Smarkm	long t;
241273872Smarkm
242285422Smarkm	random_alg_context.ra_init_alg(NULL);
243273872Smarkm
244273872Smarkm	for (t = 0; t < NUM_THREADS; t++) {
245273872Smarkm		printf("In main: creating thread %ld\n", t);
246286839Smarkm		rc = thrd_create(&threads[t], (t == 0 ? RunHarvester : ReadCSPRNG), NULL);
247273872Smarkm		if (rc != thrd_success) {
248273872Smarkm			printf("ERROR; return code from thrd_create() is %d\n", rc);
249273872Smarkm			exit(-1);
250273872Smarkm		}
251273872Smarkm	}
252273872Smarkm
253273872Smarkm	for (t = 2; t < NUM_THREADS; t++)
254273872Smarkm		thrd_join(threads[t], &rc);
255273872Smarkm
256273872Smarkm	stopseeding = 1;
257273872Smarkm
258273872Smarkm	thrd_join(threads[1], &rc);
259273872Smarkm	thrd_join(threads[0], &rc);
260273872Smarkm
261285422Smarkm	random_alg_context.ra_deinit_alg(NULL);
262273872Smarkm
263273872Smarkm	/* Last thing that main() should do */
264273872Smarkm	thrd_exit(0);
265273872Smarkm
266273872Smarkm	return (0);
267273872Smarkm}
268