This provides a 32-bit block cipher based on four 16-bit pseudorandom functions,
precomputed based on the output of a stream cipher. To compute the F_j(i),
the jth PRF evaluated at i, we take the two bytes starting at the
(j * 2^16 + i) * 2th byte of the output of the stream cipher. (This particular
implementation actually uses four distinct stream cipher output streams, and
uses os.urandom() in place of a stream cipher, but you get the idea.) These
four PRFs F_0, F_1, F_2, F_3 are used as the F-functions of a four-round
Feistel network.
To do some benchmarks, simply run main.py.
main.py also exposes an API. Simply import main (possibly renaming main.py
to something else), and then call main.RandomPRFFeistelCipher.generate().
That will return a RandomPRFFeistelCipher object, which has two methods,
encrypt and decrypt; both take two ints between 0 and 65536, left-
inclusive, and return a tuple of two ints, again between 0 and 65536.
This certainly isn't the fastest possible implementation; I'd imagine an optimized C implementation could do hundreds of millions of encryptions per second, assuming there are no issues with memory bandwidth. However, you're not going to get significantly faster generating the pseudorandom functions; that appears to mostly be bounded by the speed of the CSPRNG.