From: boucher@csl.sri.com (Peter K. Boucher) Newsgroups: sci.crypt Subject: Re: Yet Another Secure? RNG
for(i = 0; i < 17; i++)
{ /* ensure all v[i] are changed */
a = prng.rotor.R2[(i + *ndx) % 2] +
prng.rotor.R3[(i + *ndx) % 3] +
prng.rotor.R5[(i + *ndx) % 5] +
prng.rotor.R7[(i + *ndx) % 7];
v[(i + *ndx) % 17] = a + ROTATE(v[(i + *ndx) % 17]);
}
You've got 17*7 = 119 divisions (modulo operators) per byte of output. This will be REALLY SLOW... There's simply no reason to index the rotors or v this way, unless you mean this as pseudo-code.
Here's a version that addresses your concerns and is only a little slow (it's almost as fast as my version of M). I added 2 more rotors, but, still, only 4 of them go into the output. The other two are used to mangle the output, and to update the state.
In this case, making the rotors bigger has two costs: memory and initalization-time. However, making the rotors bigger has to benefits: run-time speed (less wrap-arounds for indexing) and period-length.
Also, I use unsigned longs instead of bytes. You get 4 times the output for the same amount of processor-time. Is it weaker this way?
/* These must be PRIMES !!! */
#define R0_SIZE 313
#define R1_SIZE 761
#define R2_SIZE 127
#define R3_SIZE 541
#define R4_SIZE 257
#define R5_SIZE 691
#define vSIZE (R0_SIZE+R1_SIZE+R2_SIZE+R3_SIZE+R4_SIZE+R5_SIZE)
static union
{
unsigned long v[vSIZE]; /* vector of vSIZE random longs */
struct
{
unsigned long R0[R0_SIZE], /* ..redefined as rotors*/
R1[R1_SIZE],
R2[R2_SIZE],
R3[R3_SIZE],
R4[R4_SIZE],
R5[R5_SIZE];
} rotor;
} prng; /* end union */
static unsigned long *rotor0, *rotor1, *rotor2, *rotor3, *rotor4, *rotor5;
#define SPINDLE_1(X,n) ( ((~(X))<<(n)) ^ ( (X) >>(32-(n))) )
#define SPINDLE_2(X,n) ( ( (X) >>(n)) ^ ((~(X))<<(32-(n))) )
#define SPINDLE_3(X,n) ( ( (X) <<(n)) ^ ((~(X))>>(32-(n))) )
#define SPINDLE_4(X,n) ( ((~(X))>>(n)) ^ ( (X) <<(32-(n))) )
void f2(qty, *dest)
int qty; /* quantity of random longs to return */
unsigned long *dest; /* ->receiving buffer */
{
register unsigned long a, b, c, d, e, f;
while (qty--) {
a = *rotor0, /* read out six values from v */
b = *rotor1,
c = *rotor2,
d = *rotor3,
e = *rotor4,
f = *rotor5;
*rotor0 += f; /* update six values in v */
*rotor1 += a;
*rotor2 += b;
*rotor3 += c;
*rotor4 += d;
*rotor5 += e;
/* index the rotors, without those darn divisions */
if (++rotor0 >= &(prng.rotor.R0[R0_SIZE])) rotor0 = prng.rotor.R0;
if (++rotor1 >= &(prng.rotor.R1[R1_SIZE])) rotor1 = prng.rotor.R1;
if (++rotor2 >= &(prng.rotor.R2[R2_SIZE])) rotor2 = prng.rotor.R2;
if (++rotor3 >= &(prng.rotor.R3[R3_SIZE])) rotor3 = prng.rotor.R3;
if (++rotor4 >= &(prng.rotor.R4[R4_SIZE])) rotor4 = prng.rotor.R4;
if (++rotor5 >= &(prng.rotor.R5[R5_SIZE])) rotor5 = prng.rotor.R5;
/* use the values from rotors 4 and 5 to fold, spindle, and */
/* mutilate the values from rotors 0 thru 3. */
*(dest++) = ( (SPINDLE_1(a,e&31) - SPINDLE_2(b,f>>27))
^ (SPINDLE_3(c,f&31) + SPINDLE_4(d,e>>27)) );
}
}