3 ms·
Imma just leave this here... https://github.com/dragontamer/AESRand/blob/master/AESRand_Linux/AESRand.cpp https://github.com/dragontamer/AESRand/blob/master/AES
by dragontamer 4y ago
Imma just leave this here... https://github.com/dragontamer/AESRand/blob/master/AESRand_Linux/AESRand.cpp https://github.com/dragontamer/AESRand/blob/master/AESRand_L...
Algorithm:
void AESRand_increment(__m128i& state){
state += increment;
}
std::array<__m128i, 2> AESRand_rand(const __m128i state){
__m128i penultimate = _mm_aesenc_si128(state, increment);
return {_mm_aesenc_si128(penultimate, increment), _mm_aesdec_si128(penultimate, increment)};
}
TL;DR: with respect to the original article. The AESenc instruction generates significant entropy so long as all four uint32 changes. Instead of adding +1 to the 128-bit "pre-AES encryption", add "
__m128i increment = _mm_set_epi8(0x2f, 0x2b, 0x29, 0x25, 0x1f, 0x1d, 0x17, 0x13,
0x11, 0x0D, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01); "
Because this is a 64-bit add of an odd number, it will repeat after 2^64 iterations, which should be good enough for most people's purposes.
Once you have that kind of add happening, you end up with more than sufficient entropy from AESenc. For those unaware, AESenc is approximately 10% of a proper AES, its the hardware AES instruction on x86. Repeating AESenc over the expanded-key 10 times results in a proper AES encryption (or decryption).
---------
Because modern CPUs have 2x parallel AES pipelines (2 AES instructions per clock tick), my RNG supports a 256-bit output every 4 clock cycles. I accomplish this by having AESenc on the first argument, and then AESenc / AESdec on the results of that (encode being the first 128-bit result, and decode being the 2nd 128-bit result).
--------
If you took my RNG output (which can be generated deterministically every 4 clock cycles), and then just AES encrypted that random number generator, you probably would get your cryptographically random numbers that are guaranteed not to repeat.