    //! CSPRNG

    const std = @import("std");
    const Random = std.rand.Random;
    const min = std.math.min;
    const mem = std.mem;
    const Xoodoo = @This();

    const State = std.crypto.core.Xoodoo;

    state: State,

    const rate = 16;
    pub const secret_seed_length = 32;

    /// The seed must be uniform, secret and `secret_seed_length` bytes long.
    pub fn init(secret_seed: [secret_seed_length]u8) Xoodoo {
        var initial_state: [State.block_bytes]u8 = undefined;
        mem.copy(u8, initial_state[0..secret_seed_length], &secret_seed);
        mem.set(u8, initial_state[secret_seed_length..], 0);
        var state = State.init(initial_state);
        state.permute();
        return Xoodoo{ .state = state };
    }

    pub fn random(self: *Xoodoo) Random {
        return Random.init(self, fill);
    }

    pub fn fill(self: *Xoodoo, buf: []u8) void {
        var i: usize = 0;
        while (true) {
            const left = buf.len - i;
            const n = min(left, rate);
            self.state.extract(buf[i..][0..n]);
            if (left == 0) break;
            self.state.permute();
            i += n;
        }
        self.state.clear(0, rate);
        self.state.permute();
    }