A (hopefully not horribly unsafe) CSPRNG based on Feistel networks with a nonlinear kernel in GF(256), as seen in the 4th iteration kcrypt.
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#define Fi(n,a...) for (int i = 0; i < n; i++) { a; }
#define Fq(n,a...) for (int q = 0; q < n; q++) { a; }
#define _(a...) { return ({ a; }); }
#define S static
typedef uint8_t gf;
typedef struct { gf k1[32], k2[64]; } bk;
typedef struct { gf k2[64], rk[16][32], p[16][32]; } bc;
S void wipe(void * p, size_t n) { Fi(n, ((volatile gf *) p)[i] = 0) }
S gf mul2(gf x)_( x << 1 ^ (gf) -(x >> 7) & 0x1d)
S gf eq(gf a, gf b)_((uint32_t) (a ^ b) - 1 >> 8)
S gf mul(gf a, gf b)_(gf r = 0; Fi(8,
r ^= a & (gf) -(b & 1), b >>= 1, a = mul2(a)) r)
S gf inv(gf x)_(gf x2 = mul(x, x), x3 = mul(x2, x), x6 = mul(x3, x3),
x12 = mul(x6, x6), y = mul(x12, x3); Fi(4, y = mul(y, y))
mul(mul(y, x12), x2))
S gf mod8(gf x, gf m)_(uint32_t r = 0, t; Fi(8,
t = (r += r + (x >> 7 - i & 1)) - m; r = t + (m & -(t >> 31))) r)
S void shuffle(gf p[32], gf key[64], int round) {
Fi(32, p[i] = i) Fi(31, int n = 31 - i;
gf j = mod8(key[n + round * 21 & 63], n + 1), t;
Fq(32, t = (p[n] ^ p[q]) & eq(q, j);
p[n] ^= t; p[q] ^= t))}
S void permute(gf out[32], gf in[32], gf p[32]) {
Fq(32, gf x = 0; Fi(32, x |= in[i] & eq(i, p[q])) out[q] = x)}
S void diffuse(gf a[32]) { gf b[32], * x = a, * y = b, * t; Fq(4,
Fi(32, y[i] = x[i] ^ mul2(x[i + q * q + q + 1 & 31]))
t = x; x = y; y = t) wipe(b, sizeof b); }
S void setup(bc * c, bk * key) {
gf z[2][32], * s = z[0], * u = z[1];
Fi(64, c->k2[i] = key->k2[i]) Fi(32, s[i] = key->k1[i])
Fq(16, shuffle(c->p[q], c->k2, q); permute(u, s, c->p[q]);
Fi(32,
c->rk[q][i] =
inv(u[i] ^ mul2(u[i + 1 & 31])
^ c->k2[i + q * 17 & 63] ^ ((q + 1) * 0x9d + i))
+ c->k2[i + 32 + q * 29 & 63])
diffuse(c->rk[q]); Fi(32, s[i] = c->rk[q][i]))
wipe(z, sizeof z); }
S void block(gf out[64], gf in[64], bc * c) {
gf z[4][32], * l = z[0], * r = z[1], * n = z[2], * u = z[3], * t;
Fi(32, l[i] = in[i]; r[i] = in[32 + i])
Fq(16, permute(u, r, c->p[q]);
Fi(32,
n[i] =
c->rk[q][i]
+ inv(u[i] ^ mul2(u[i + 1 & 31]) ^ c->k2[i + 32 + q * 11 & 63]))
diffuse(n); Fi(32, n[i] ^= l[i]) t = l; l = r; r = n; n = t)
Fi(32, out[i] = l[i]; out[32 + i] = r[i])
wipe(z, sizeof z); }
S int randomize(void * v, size_t left)_(
gf * p = v; int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) return -1;
while (left) {
ssize_t n = read(fd, p, left);
if (n > 0) p += n, left -= n;
else if (n < 0 && errno == EINTR) continue;
else {
int e = n < 0 ? errno : EIO;
close(fd); errno = e; return -1; }
} close(fd))
S int putall(void * v, size_t left)_(
gf * p = v;
while (left) {
ssize_t n = write(STDOUT_FILENO, p, left);
if (n > 0) p += n, left -= n;
else if (n < 0 && errno == EINTR) continue;
else if (n < 0 && errno == EPIPE) return 1;
else { if (!n) errno = EIO; return -1; } } 0)
int main(void)_(
struct { bk key; gf nonce[16]; } seed = {0};
bc c = {0}; gf in[64] = {0}, out[64] = {0}; int rc = 1, w;
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
{ perror("signal"); goto done; }
if (randomize(&seed, sizeof seed) < 0)
{ perror("/dev/urandom"); goto done; }
setup(&c, &seed.key);
Fi(16, in[i] = seed.nonce[i]) in[63] = 3;
wipe(&seed, sizeof seed);
for (uint64_t counter = 0;; counter++) {
Fi(8, in[16 + i] = counter >> i * 8)
block(out, in, &c);
if ((w = putall(out, 64)) > 0)
{ rc = 0; goto done; }
if (w < 0)
{ perror("stdout"); goto done; }
if (counter == UINT64_MAX)
{ fputs("krng: counter exhausted\n", stderr); goto done; } }
done:
wipe(&seed, sizeof seed); wipe(&c, sizeof c);
wipe(in, sizeof in); wipe(out, sizeof out);
rc)
