A (hopefully not horribly unsafe) CSPRNG based on 3-round Feistel networks, as seen in the 4th iteration kcrypt.
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define Fi(n,a...) for (int i = 0; i < n; i++) { a; }
typedef uint8_t gf; typedef struct { gf k1[32], k2[64]; } bk;
static gf LOG[256], EXP[510];
static void gentab(void) {
int b = 1; Fi(255, LOG[EXP[i] = EXP[i + 255] = b] = i,
b = b * 2 ^ b / 128 * 285)
}
static gf mul2(gf x) { return x * 2 ^ x / 128 * 285; }
static gf inv(gf x) { return x ? EXP[255 - LOG[x]] : 0; }
static void shuffle(gf p[32], gf key[64], int round) {
int j, t; Fi(32, p[i] = i)
for (int i = 32; --i;)
t = p[i], p[i] = p[j = key[i + round * 21 & 63] % -~i], p[j] = t;
}
static void diffuse(gf a[32]) {
static const int offset[] = { 1, 3, 7, 13 }; gf b[32];
for (int q = 0; q < 4; q++) {
Fi(32, b[i] = a[i] ^ mul2(a[i + offset[q] & 31]))
memcpy(a, b, 32);
}
}
static void block(gf out[64], gf in[64], bk * key) {
gf rk[16][32], s[32], next[32], p[32]; memcpy(s, key->k1, 32);
for (int q = 0; q < 16; q++) {
shuffle(p, key->k2, q);
Fi(32, next[i] = (gf) (inv(s[p[i]] ^ mul2(s[p[i + 1 & 31]])
^ key->k2[i + q * 17 & 63] ^ (gf) ((q + 1) * 0x9d + i))
+ key->k2[i + 32 + q * 29 & 63]))
diffuse(next); memcpy(rk[q], next, 32); memcpy(s, next, 32);
}
memcpy(out, in, 64);
for (int q = 0; q < 16; q++) {
gf r[32]; memcpy(r, out + 32, 32); shuffle(p, key->k2, q);
Fi(32, out[32 + i] = (gf) (rk[q][i] + inv(r[p[i]]
^ mul2(r[p[i + 1 & 31]]) ^ key->k2[i + 32 + q * 11 & 63])))
diffuse(out + 32); Fi(32, out[32 + i] ^= out[i])
memcpy(out, r, 32);
}
}
int main(void) {
gentab(); struct { bk key; gf nonce[16]; } seed;
int random = open("/dev/urandom", O_RDONLY);
if (random < 0) goto err;
gf * p = (gf *) &seed;
for (size_t left = sizeof seed; left;) {
ssize_t n = read(random, p, left);
if (n > 0) p += n, left -= (size_t)n;
else if (n < 0 && errno == EINTR) continue;
else goto err;
}
if (close(random) < 0)
{ err: perror("/dev/urandom"); return 1; }
gf in[64] = {0}, out[64]; memcpy(in, seed.nonce, 16); in[63] = 3;
for (uint64_t counter = 0;; counter++) {
Fi(8, in[16 + i] = counter >> i * 8)
block(p = out, in, &seed.key);
for (size_t left = 64; left;) {
ssize_t n = write(STDOUT_FILENO, p, left);
if (n > 0) p += n, left -= (size_t)n;
else if (n < 0 && errno == EINTR) continue;
else {
if (errno == EPIPE) return 0;
perror("stdout"); return 1;
}
}
if (counter == UINT64_MAX)
{ fputs("krng: counter exhausted\n", stderr); return 1; }
}
}

