I have written a small PRNG using Qt Creator C++. It uses the basic ideas of a linear feedback shift-register as applied to an array of quint32. The array has 32 elements. Normally, a shift would require 31 operations of moving each array element value into an adjacent element. However, this PRNG has a variable, zerodex on the range [0..31], which is indexed after each shift. zerodex is kept in range by zerodex = zerodex % 32. zerodex is an effective zeroth element for the array. The feedback taps, then, require nothing more than an offset for each tap. The actual array index is tapindex = (zerodex + tapoffset) % 32. This approach will allow the array size to be increased to a large number without any loss of performance. The PRNG runs at about 60 percent the speed of qrand().

There are several things which I hope this community can discuss:

1. Are there any obvious coding errors?

2. What is the quality of the output? I understand that there are many tests which can be applied to determine this.

3. Can the code be altered to attain better performance?

4. How secure is this PRNG? It requires 1Kbit to intialize. What kind of attack would be effective against it? Are there modifications which can be done to increase its security?


===================================================================================
Code:
/*
I, Ken Davis, the sole author of Shifter32, waive my copyright to it, placing
it in the public domain.  The library comes with absolutely no warranty.
However, any commercial use of it may require consideration of Digia Oyj.
*/

#ifndef SHIFTER32_H
#define SHIFTER32_H

#include <QtCore>
#include <QtGlobal>
#include <QTime>
#include <QObject>
#include <QDebug>
#include <QDataStream>
#include <QString>


#include <iostream>
#include <cstdio>
#include <cmath>
#include <stdlib.h>


static const quint32 RUNNINGXOR_INIT = 1822237083;   //Just a qrand() value
static const quint32 FBWORD_INIT     = 1822237083;



//==========  class Shifter32  ==========

class Shifter32
{
public:
    Shifter32();
    ~Shifter32();
    quint32 fetchOutput();
    void    initializeTaps();
    bool    seedShifter (quint32 data[32]);

private:
    //Initialized with qrand() generated numbers
    quint32 shifterA[32] = {    2577819336,
                                917694050,
                                951263515,
                                983060851,
                                1917880928,
                                3083531132,
                                4037153175,
                                1014752460,
                                1662080985,
                                1873885915,
                                2389985822,
                                2751043653,
                                1144385890,
                                324096830,
                                3254812018,
                                1119491730,
                                2027535888,
                                2376333583,
                                3177285309,
                                1496918926,
                                3733071073,
                                1883966812,
                                2775744657,
                                2253506365,
                                1024114618,
                                1668120797,
                                2170190823,
                                3076122828,
                                922828395,
                                2508418802,
                                2867381025,
                                405718413 };

    quint32 taps[4495][3]; //Using 3 taps
    quint32 zerodex;
    quint32 fbWord  = FBWORD_INIT;
    quint32 runningXOR = RUNNINGXOR_INIT;
    bool    seedSwitch;
    bool    doIgnore;


};

#endif // SHIFTER32_H






#ifndef  SHIFTER32_H
#include "shifter32.h"
#endif


//Used in debugging and diagnostics:
void DoDebug ( quint32, quint32, quint32, quint32);


//========== Shifter32 ==========

Shifter32 :: Shifter32() {
    initializeTaps();

    //Gotta start somewhere
    zerodex = 15;

    fbWord = FBWORD_INIT;

    seedSwitch = true;
    doIgnore = false;
}//Constructor

//---------- ~Shifter32 ----------

Shifter32 :: ~Shifter32() {

}//Destructor

//---------- Shifter32 :: initializeTaps ----------

void Shifter32 :: initializeTaps() {

    //Create the 3 taps.
    int ndex = 0;
    for (quint32 t0=0; t0<=28; t0++) {
        for (quint32 t1 = (t0+1); t1<=29; t1++) {
            for (quint32 t2 = (t1+1); t2<=30; t2++) {

                taps[ndex][0] = t0;
                taps[ndex][1] = t1;
                taps[ndex][2] = t2;
                ndex++;
            }//for t2
        }//for t1
    }//for t0
}//initializeTaps

//---------- Shifter32 :: seedShifter ----------

bool Shifter32 :: seedShifter (quint32 data[32]){

    //May not seed after fetchOutput has been called
    if (!seedSwitch){
        return false;
    }//if

    for (int i=0; i<32; i++){
        shifterA[i] = shifterA[i] ^ data[i];
    }//for

    //Spool off some output
    quint32 dummy;
    for (int i=0; i<500; i++){
        doIgnore = true;
        dummy = fetchOutput();
    }//for

    return true;
}//seedShifter

//---------- Shifter32 :: fetchOutput ----------

quint32 Shifter32 :: fetchOutput() {

    quint32 output;
    quint32 t0, t1, t2;
    quint32 dex31 = (zerodex + 31) & 0x0000001F;

    if (!doIgnore)
        seedSwitch = false; //Stops further seeding

    //Use runningXOR to gen shifter index to generate index for taps[]
    quint32 tdex = (shifterA[runningXOR & 0x0000001F]) % 4495;

    t0 = taps[tdex][0];
    t1 = taps[tdex][1];
    t2 = taps[tdex][2];

    fbWord = ((shifterA[(zerodex + t0) & 0x0000001F]
                    ^ shifterA[(zerodex + t1) & 0x0000001F])
                        ^ shifterA[(zerodex + t2) & 0x0000001F]);

    //XOR fbWord with 31st shifter word.  31st is feedback target.
    shifterA[dex31] = shifterA[dex31] ^ fbWord;

    //Produce new value for runningXOR
    runningXOR = runningXOR ^ fbWord;

    //Output is 0th word
    output = runningXOR ^ shifterA[zerodex];

    //Index zerodex
    zerodex = ++zerodex;
    zerodex = zerodex & 0x0000001F;

    doIgnore = false;
    return output;
}//fetchOutput

//--------------- DoDebug ---------------

void DoDebug ( quint32 t1, quint32 t2, quint32 t3, quint32 t4){

    qDebug() << "";
    QString str1 = QString("%1").arg(t1, 8, 16, QLatin1Char('0') );
    QString outStr1 = QString("num1  %1   %2   %3").
                                arg(str1.toUpper(), 10, ' ').
                                    arg(QString::number(t1), 10, ' ').
                                        arg(t1, 32, 2, QLatin1Char('0'));
    qDebug()<<outStr1;

    //----------

    QString str2 = QString("%1").arg(t2, 8, 16, QLatin1Char('0') );
    QString outStr2 = QString("num2  %1   %2   %3").
                                arg(str2.toUpper(), 10, ' ').
                                    arg(QString::number(t2), 10, ' ').
                                        arg(t2, 32, 2, QLatin1Char('0'));
    qDebug()<<outStr2;

    //----------

    QString str3 = QString("%1").arg(t3, 8, 16, QLatin1Char('0') );
    QString outStr3 = QString("num3  %1   %2   %3").
                                arg(str3.toUpper(), 10, ' ').
                                    arg(QString::number(t3), 10, ' ').
                                        arg(t3, 32, 2, QLatin1Char('0'));
    qDebug()<<outStr3;


    //----------

    QString str4 = QString("%1").arg(t4, 8, 16, QLatin1Char('0') );
    QString outStr4 = QString("num4  %1   %2   %3").
                                arg(str4.toUpper(), 10, ' ').
                                    arg(QString::number(t4), 10, ' ').
                                        arg(t4, 32, 2, QLatin1Char('0'));
    qDebug()<<outStr4;
}//DoDebug