How many reversible integer operations do you know?
lemire.me
lemire.me
Incidentally, multiplying by an odd integer works because when working in mod N space, multiplying by any number that is coprime with N yields a permutation, and since for 32-bit integers N = 2^32, the only prime factor of N is 2, which means that N is coprime with all odd integers. (I'm assuming unsigned integers and wrap-around behavior on over/underflow.)
O(lg((2^32)!))
which I think is rougly 32*2^32.
In other words, you'd need about 16GB just to store the program to compute the permutation! Of course, that is not the case for the operations shown here.
So maybe implicitly the real question is, "How many reversible integer operations do you know with small Kolmogorov complexity?" Or in more practical terms, "How many reversible integer operations do you know which don't require too many lines of code?"
Given that we have a finite domain, and 1:1 functions, we should be able to specify f^-1 with some constant overhead and embedding f.
Something along the lines of:
//embed the definition of f.
f^-1(x) = for a in Domain:
if f(a) = x
return a
Formalizing this would involve specifying what description language you are using and how you encode functions.Another way to reach this number is simply to consider that most reversible operations are going to be implementable by non-compressible LUTs, and such a LUT for 32-bits number will be 2^32 * 4 Bytes == 16GB.
LUT's would be vastly faster though.
In this sense the AES provides a much larger number of reversible operations than all those listed :)
For 32 bit permutations my go-to is skipfish. It's not a great cipher but it produces permutations (for e.g. producing a random permutation of all IPv4 addresses) perfectly well.
The Classification of Reversible Bit Operations https://www.scottaaronson.com/papers/gates.pdf
Grier's ITCS presentation on it https://www.youtube.com/watch?v=egU5JLbpmkA
BTW see Lehmer codes for permutation sequences https://en.wikipedia.org/wiki/Lehmer_code (no relation to Lemire ;)
You can start with a reversible gate (such as https://en.wikipedia.org/wiki/Toffoli_gate or https://en.wikipedia.org/wiki/Fredkin_gate) and combine these.
And missing from the list—the identity function! Very fast to compute and universally (not)implemented on all CPUs.
x -> x + 1
and
x -> (x==0) ? 1 : (x == 1) ? 0 : x
generate all possible operations.
See https://en.wikipedia.org/wiki/Reversible_computing
One of the main points is that it would permit significantly lower waste heat generation.
With a block of >1 integer, there are some additional fun ones:
- XOR an even number of integers together, then XOR the resulting value, or any function of it, into all of them. (It's its own inverse, since the XOR of an even number integers isn't changed by XORing the same value into all of them.)
- Bitslicing S-boxes, a potentially nonlinear operation. You can represent S-boxes (esp. small ones) as a network of gates, and you can turn those into AND/OR/XOR/NOT instructions and have your CPU do them on registers at a time. This was core to the AES candidate Serpent using 32-bit registers; now you have larger regs to do it with.
- Some matrix multiplications (including in fields). Thinking of AES's use of MDS matrices.
- Generalized Feistel-like operations: run some function--not necessarily reversible--on part of the input, and use the result to munge another part of the input. a ^= f(b) or (some of the generalizations) a += f(b) or a ^= f(b, c, d). Used tons of places, of course. Then you can easily build an invertible function (on the larger block) from a non-invertible round function, and repeat for a zillion rounds (a ^= f(b, k1); b ^= f(a, k2); a ^= f(b, k3)...). With a loose enough definition of "Feistel-like", even lots of ARX ciphers could qualify.
(You could, of course, do some of these things within a single integer by thinking of it as two, four, etc. narrower ints, or you could call a whole block a very large int. Mostly thinking of register-sized integers when I say integers, FWIW.)
Keccak (SHA-3) has some steps where, like with the XOR-three-rotatations thing, an inverse exists but looks a bit different from the original operation, which is neat! There's a reference (https://keccak.team/files/Keccak-reference-3.0.pdf) describing the operations using math notation, and lots of C implementations (https://github.com/rhash/RHash/blob/master/librhash/sha3.c). It looks like the team published code for the inverses too; see https://github.com/gvanas/KeccakTools/blob/master/Sources/Ke...