Characterizing the Rotate-Multiply Iterated Function Part I

Ender314

Characterizing the Rotate-Multiply Iterated Function Part I

I have been playing with genetic programming for several years, attempting to use it to create pseudo random number generators (RNGs) and hash functions. In the course of doing this, with various parameters, I frequently encountered the pseudorandom number generator given by combining a bitwise rotation and a multiply. Sample C# code below, with rotation constant b and multiplication constant c.

public ulong Next()
{
	_state = c * BitOperations.RotateLeft(_state, b);
	return _state;
}

This is a somewhat random function as is, but it has several shortcomings. First, it’s not quite random enough by itself unless you only use half of the output. Second, the period is not well known. The period of an RNG is the number of values it returns before it starts repeating. For most commercial RNGs, the period is known mathematically, or at least a lower bound on it is known. For the RNG above, The period might be as short as 1 or as long as 2^64-1, which is the range of possible non-zero values of a ulong (Clearly the value zero is unchanged by the rotate-multiply, so this generator would have to be seeded with a non-zero value).

Starting from some initial value of _state (an initial, or seed value), and repeatedly calling the function above, it will obviously eventually repeat. The set of values that it traverses before repeating is called the cycle, which has a length. The ideal case that we are searching for is a “full cycle”, where the function traverses every possible value before repeating. We will see that constants b and c which have full cycle are rare. Most have a number of cycles of varying length. Some have multiple cycles of length 1, and some sets of constants b and c have thousands of cycles all length 4 or less. Obviously that doesn’t make for a very good random generator if it keeps returning the same four values in a row, which is why we are trying to find those “full cycle” constants.

Recall that bitwise rotation is a common low-level operation in computers, and is quite simple. For comparison, if we were discussing 5 digit decimal numbers, then RotateLeft(12345,2)=34512 and RotateLeft(100,3)=1. Bitwise rotation is the same thing in base 2 arithmetic. Since computers represent everything in base 2 with zeroes and ones, bitwise rotation is natural, and a well-known way of mixing portions of a number in many cryptographic hash functions or ciphers.

Also, recall that computers use modular arithmetic for integers. That sounds fancier than it is, it really means that the result of any operation is considered as the remainder with the modulus. For instance, among the integers modulo 256 (which would be 8-bit integers), 255+5=4 (260 % 256), and 21*61=1 (1281 % 256). Modular arithmetic isn’t very well known by all developers, so I’ll highlight some results as needed. If you want to learn more you can read about it over on wikipedia. Modular arithmetic is the way integers work by default on computers. If you multiply two unsigned 32-bit integers, the results is given modulo 2^32.

So we are searching for a pair of integers (b,c) for which the function has a full cycle. It is important that the function f(x) is invertible, otherwise it might be possible for two different x’s to have the same result, in which case we couldn’t have a full cycle. Bitwise rotation is clearly invertible, and the multiplication by c will be invertible as long as c is odd. This is a result from modular arithmetic, in the integers modulo 2^n, every odd number has a unique inverse. So we immediately know that we need only consider odd values for c.

I brute forced integers of bit size 3-23, and came up with a list of rotate-multiply constants that have a full cycle. Fortunately, there are definitely such constants for every bit size, suggesting that such constants exist, which I call my first hypothesis.

Hypothesis 1: There are rotate, multiply constants b and c for any given integer size n such that there is a full cycle that contains every non-zero integer.

The basis for this is purely empirical. The table below shows the number of rotate-multiply pairs that exists at each bit length with a full cycle.

Bit LengthCount
31
41
52
64
74
81
94
103
116
123
137
147
1511
169
1713
1810
198
209
2110
2210
2311
Number of full length rotate-multiply pairs at a given bit length

As can be seen, it looks like there are more such pairs as the bit size increases. I didn’t see any a priori reason why such pairs even have to exist, so this is nice to see.

Now we can get to the first theorem, albeit a trivial one. The number I listed in the table above is actually half the number of rotate-multiply pairs that exist, because every such pair (b,c) has a twin pair (n-b, k), where k is the multiplicative inverse of c. You can see this by just inverting the function f(x)=c*RotateLeft(x,b) for a given bit size n. Let k be the multiplicative inverse of c. Then

xn+1=c*RotateLeft(xn,b)
kxn+1 = RotateLeft(xn,b)
RotateLeft(kxn+1, n-b)=xn

This is just another recurrence relation, although it’s a little different. It’s going backwards, and the multiply happens, then the rotate. This must have the same length as the original, although it’s a slightly different kind of formula. I noticed this empirically before I saw the math, but I’ll call that a theorem. The key is to notice that the relationship alternates rotate and multiply. You could look at the function as multiply first, then rotate, or rotate first, then multiply. You would get a different sequence, but of the same length.

I visualize this by thinking of the sequence obtained by starting from an initial value, rotating it, then multiplying it. For instance, for an 8-bit integer with rotate 3 and multiply 21, starting from 1, we get RotateLeft(1,3)=8, then 8 * 21 = 168, then we repeat the process, obtaining the sequence below.

1,8,168,69,169,77,81,138,82,146,250,215,163,29,97,11,231,…

The first recurrence relationship describes the sequence 1,168,169,81,82,250,163,97,231. The second relationship, going backwards, describes 11,29,215,146,138,77,69,8. So the sequences are related, but they must be of the same length since they are looking at the same chain of operations.

Theorem 1: For a given bit size n, if (b, c) is a rotate-multiply pair with a cycle length m, then (n-b, k), where k is the inverse of c, is another rotate-multiply pair with a cycle length m.

As an example, for 8-bit integers, (3,21) is a full-cycle pair of constants, and so is (5,61), since 3+5=8 and 61 is the multiplicative inverse of 21 modulo 256. The generated sequences are related by the equation above, but are not the same. The first sequence is 1, 168, 169, 81, 82, 250, … The second is 1, 160, 196, 56, 171, 225. This reduces the search space by half. Only the rotates less or equal to than n/2 need to be checked, as the twin pair can be easily deduced. Mark Overton has done some research on this topic, and his appendix C contains a rotate multiplier pair of (18: 3,731,015,275) for 32 bit integers, with period just shy of max. He notes that rotates greater than 16 are less random. Using this theorem, we can construct the twin pair, which would be “more random”, and better suited for his purposes – (14: 583,185,987). With a seed of 1, I have confirmed the period of both of these is 4,294,967,293, as the paper says.

Hypothesis 2: The multiplier c in a full-cycle pair is always congruent to 1 (mod 4)

This is another empirical hypothesis, but I observed it for every full-cycle pair for bit size 3 to 21. This is strong enough evidence for me to use it to reduce my search. Now the code ignores constants c that are congruent to 3 (mod 4). Note that c is congruent to 1 (mod 4) is just a fancy way of saying the constant c divided by 4 has remainder 1, or c % 4 = 1 in c-style syntax.

There will be more articles coming, as I am collecting data and looking through it for patterns that may help me find the constants b and c that work for 64 bit integers. Future articles will discuss cycle statistics, fixed points, roots of unity, and order in cyclic groups. Below is what I have gathered so far. These are full cycle bit length, rotate left, multiply pairs.

Bit LengthRotateMultiplyBit LengthRotateMultiply
31517560669
41917587353
521317659053
521717665537
613317676209
625717765537
632917795205
635317850845
716117882897
7165182225013
729184178077
726518518125
8321185112837
92105185131073
92257185192957
92289186143697
93241187182433
10163718968729
103513189237001
1041009192519821
11122519459753
11123719514177
1111813195128565
1141081195323697
1141165197211525
1151025198409841
1211625199228385
123725201634197
1253561201940945
1317897201958881
1324033202283877
133561203497933
1331965206727193
134637207167493
134905207524289
1345429207950113
141745721278437
1431629212737153
1439901214723317
14313377216321549
14519652161523857
14719572171740677
14720932181933937
15112957219518925
151163852110286961
1512012121101048577
15219292212097153
152163852231458649
154136092232107557
154163852261359401
1554781227547981
15586812272383549
15643052281358145
156311732281690877
16159772282158689
161313732293168081
161542052312502269
161558332351856189
161563732354194305
16213233236716037
162559212367071101
165174972381904041
165232692392413621
171390772394194305
1733871323105903105
1736553723107835097
1748298123116768185
Sets of bitlength, rotate, and multiply pairs that are full cycle