Let's say you're building RNG with ChaCha20 and the fast key erasure technique. There seem to be a few ways to do it.
The reference implementation in the SUPERCOP benchmarking toolkit looks like this:
#define KEYBYTES 32
#define OUTPUTBYTES 736
int crypto_rng_chacha20(
unsigned char *r, /* random output */
unsigned char *n, /* new key */
const unsigned char *g /* old key */
)
{
unsigned char x[KEYBYTES + OUTPUTBYTES];
crypto_stream_chacha20(x,sizeof x,nonce,g);
memcpy(n,x,KEYBYTES);
memcpy(r,x + KEYBYTES,OUTPUTBYTES);
return 0;
}
- How often should I replace the key? The SUPERCOP implementation replaces the 32-byte key every 768 bytes.
- What about the nonce and counter? The SUPERCOP implementation sets the nonce to zero and resets the counter to zero every time the key is replaced. What about treating the nonce/counter similar to the key and periodically replacing them with ChaCha20 output? (Except for a few counter bits that we need to crank to get 768 bytes of output.)
- The SUPERCOP implementation replaces the key with the first 32 byte of the 768-byte sequence. Can I use the last 32 bytes instead? That would allow my implementation to keep less state.
- What about replacing the key incrementally? For example, instead of fully replacing the key with the first 32 bytes of every 768, what if I used the first 4 bytes of every 96 and incrementally replaced the key?
Note: I'm asking this question primarily to get a deeper understanding of how things work. In practice, I'd just copy the SUPERCOP implementation.