Nice work, just a few minor queries: > -static void extract_crng(u8 out[CHACHA_BLOCK_SIZE]) > +/* > + * The general form here is based on a "fast key erasure RNG" from > + * <https://blog.cr.yp.to/20170723-random.html>. It generates a ChaCha > + * block using the provided key, and then immediately overwites that > + * key with half the block. It returns the resultant ChaCha state to the > + * user, along with the second half of the block containing 32 bytes of > + * random data that may be used; random_data_len may not be greater than > + * 32. > + */ > +static void crng_fast_key_erasure(u8 key[CHACHA_KEY_SIZE], > + u32 chacha_state[CHACHA_STATE_WORDS], > + u8 *random_data, size_t random_data_len) > { > - unsigned long flags, init_time; > + u8 first_block[CHACHA_BLOCK_SIZE]; Do we need a BUG_ON(random_data_len > 32) here? > > - if (crng_ready()) { > - init_time = READ_ONCE(primary_crng.init_time); > - if (time_after(jiffies, init_time + CRNG_RESEED_INTERVAL)) > - crng_reseed(); > - } > - spin_lock_irqsave(&primary_crng.lock, flags); > - chacha20_block(&primary_crng.state[0], out); > - if (primary_crng.state[12] == 0) > - primary_crng.state[13]++; > - spin_unlock_irqrestore(&primary_crng.lock, flags); > + chacha_init_consts(chacha_state); > + memcpy(&chacha_state[4], key, CHACHA_KEY_SIZE); > + memset(&chacha_state[12], 0, sizeof(u32) * 4); No IV, no generation counter here? As you already have a generation counter in use for other purposes, why not use it here as well as some non-zero starting point? Otherwise, it looks really nice. Thanks, Dominik