#include "base/rebase.hpp"
static bool s_trace = false;
+const int ReRandomizer::m_primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
+ 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109,
+ 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
+ 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277,
+ 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373,
+ 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461,
+ 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569,
+ 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653,
+ 659, 661, 673, 677, 683, 691 };
+const int ReRandomizer::m_countPrimes = sizeof ReRandomizer::m_primes
+ / sizeof(int);
+
/**
* @brief Constructor.
+ *
+ * @param name the name of the generator
*/
-ReRandomizer::ReRandomizer() {
+ReRandomizer::ReRandomizer(const char* name) :
+ m_name(name) {
}
/**
* @brief Destructor.
return x < 0 ? -x : x;
}
#endif
+
/**
- * @brief Returns the next random character.
- *
- * The character is in the range ' ' .. chr(127) (inclusive).
+ * Returns the name of the generator.
*
- * @return The next random character.
+ * @return the name
*/
-char ReRandomizer::nextChar() {
- char rc = nextInt(' ', ' ' + CHARRANGE - 1);
- return rc;
+const QByteArray& ReRandomizer::name() const {
+ return m_name;
}
/**
#endif
return rc;
}
+
+/**
+ * @brief Returns the next random character.
+ *
+ * The character is in the range ' ' .. chr(127) (inclusive).
+ *
+ * @return The next random character.
+ */
+char ReRandomizer::nextChar() {
+ char rc = nextInt(' ', ' ' + CHARRANGE - 1);
+ return rc;
+}
+
/**
* @brief Returns the next random integer.
*
}
}
/**
- * @brief Constructor.
+ * Builds a number from a text by hasing.
+ *
+ * Conditions:
+ * <ul><li>It should be difficult to restore the text from the hash.</li>
+ * <li>Same text must return the same hash value.</li>
+ * <li>All bits should be set from any text (except the empty text)</li>
+ * </ul>
+ *
+ * @param text the text to hash
+ * @return a number
*/
-ReCongruentialGenerator::ReCongruentialGenerator() :
- m_seed(0x4711),
- m_factor(214013),
- m_increment(2531011),
- m_lastSetSeed(0x4711) {
+ReRandomizer::seed_t ReRandomizer::hash(const QByteArray& text) {
+ seed_t rc = 0x200a110b190c580dLL;
+ int ixPrimes = m_countPrimes / 2;
+ for (int ix = text.length() - 1; ix >= 0; ix--) {
+ rc = rc * m_primes[ixPrimes] + text.at(ix) * m_primes[ixPrimes - 1];
+ if ((ixPrimes -= 2) <= 0)
+ ixPrimes = m_countPrimes;
+ }
+ return rc;
}
+
/**
- * @brief Destructor.
+ * Converts a text into a seed
+ * @param text
+ * @param seed
*/
-ReCongruentialGenerator::~ReCongruentialGenerator() {
+void ReRandomizer::hash(const QByteArray& text, QByteArray& seed) {
+ int ixSrc = text.length() / sizeof(seed_t) - 1;
+ int maxSrc = text.length() / sizeof(seed_t) - 1;
+ const seed_t* src = reinterpret_cast<const seed_t*>(text.constData());
+ seed_t srcSeed = 0x44112200773355LL;
+ if (text.length() < (int) sizeof(seed_t)) {
+ for (int ix = text.length() - 1; ix >= 0; ix--)
+ srcSeed = (srcSeed << 8) | text.at(ix);
+ src = &srcSeed;
+ maxSrc = 1;
+ }
+ seed_t last = 0x112012041919891LL;
+ seed_t* trg = reinterpret_cast<seed_t*>(seed.data());
+ int ixTrg;
+ int ixPrime = m_countPrimes;
+ int maxTrg = seed.length() / sizeof(seed_t) - 1;
+ for (ixTrg = 0; ixTrg < maxTrg; ixTrg++) {
+ last = trg[ixTrg] = last * m_primes[ixPrime]
+ + src[ixSrc] * m_primes[ixPrime - 1];
+ if ((ixPrime -= 2) <= 0)
+ ixPrime = m_countPrimes;
+ if (--ixSrc <= 0)
+ ixSrc = maxSrc;
+ }
+ ixSrc = text.length() - 1;
+ char* trgPtr = reinterpret_cast<char*>(seed.data());
+ for (ixTrg = seed.length() % sizeof(seed_t); ixTrg < seed.length();
+ ixTrg++) {
+ last = last + text.at(ixSrc) * m_primes[ixPrime];
+ trgPtr[ixTrg] = (char) last;
+ if (--ixPrime < 0)
+ ixPrime = m_countPrimes;
+ if (--ixSrc < 0)
+ ixSrc = text.length() - 1;
+ }
+ ixTrg = 0;
+ for (int ix = seed.length(); ix < text.length(); ix++) {
+ trg[ixTrg] ^= text.at(ixSrc);
+ if (--ixSrc < 0)
+ ixSrc = text.length() - 1;
+ if (ixTrg++ >= seed.length())
+ ixTrg = 0;
+ }
}
/**
- * @brief Returns the current factor.
+ * @brief Sets the seed to the value given by the last <code>setSeed()</code>.
*
- * @return The current factor.
+ * Note: The constructor does the first <code>setSeed()</code>.
*/
-ReRandomizer::seed_t ReCongruentialGenerator::factor() const {
- return m_factor;
+/**
+ * Constructor.
+ *
+ * @param name the name of the generator
+ */
+ReSingleSeedRandomizer::ReSingleSeedRandomizer(const char* name) :
+ ReRandomizer(name),
+ m_seed(0x1120120419198991ull),
+ m_lastSetSeed(0x1120120419198991ull) {
+}
+/**
+ * Sets the seed to the start point (defined with setSeed()).
+ */
+void ReSingleSeedRandomizer::reset() {
+ m_seed = m_lastSetSeed;
}
/**
- * @brief Returns the current increment.
+ * Sets the current point of pseudo random.
*
- * @return The current increment.
+ * @param seed the current point of pseudo random
*/
-ReRandomizer::seed_t ReCongruentialGenerator::increment() const {
- return m_increment;
+void ReSingleSeedRandomizer::restoreSeed(const QByteArray& seed) {
+ if (seed.size() >= (int) sizeof(seed_t)) {
+ memcpy(&m_seed, seed.constData(), sizeof m_seed);
+ } else {
+ QByteArray buffer = seed;
+ buffer.resize(sizeof m_seed);
+ memset(buffer.data() + seed.size(), 0, sizeof(m_seed) - seed.size());
+ memcpy(&m_seed, buffer.constData(), sizeof m_seed);
+ }
+ m_lastSetSeed = m_seed;
+}
+
+/** @brief Sets the current seed.
+ *
+ * @param seed The seed to set.
+ */
+void ReSingleSeedRandomizer::setSeed(seed_t seed) {
+ m_seed = m_lastSetSeed = seed;
+ if (s_trace)
+ printf(" Seed: %llx ", (long long) seed);
+}
+
+/**
+ * Gets the current point of pseudo random.
+ *
+ * @param seed the current point of pseudo random
+ */
+void ReSingleSeedRandomizer::saveSeed(QByteArray& seed) const {
+ seed.resize(sizeof m_seed);
+ memcpy(seed.data(), &m_seed, sizeof m_seed);
}
/**
*
* @return The current seed.
*/
-ReRandomizer::seed_t ReCongruentialGenerator::seed() const {
+ReRandomizer::seed_t ReSingleSeedRandomizer::seed() const {
return m_seed;
}
/**
- * @brief Sets the seed to the value given by the last <code>setSeed()</code>.
+ * Converts a text (e.g. password) into the generator specific seed.
*
- * Note: The constructor does the first <code>setSeed()</code>.
+ * @param text the text to convert
*/
-void ReCongruentialGenerator::reset() {
- m_seed = m_lastSetSeed;
+void ReSingleSeedRandomizer::textToSeed(const QByteArray& text) {
+ setSeed(hash(text));
+}
+
+/**
+ * @brief Constructor.
+ */
+ReCongruentialGeneratorBase::ReCongruentialGeneratorBase() :
+ m_factor(214013),
+ m_increment(2531011) {
+}
+
+/**
+ * @brief Returns the current factor.
+ *
+ * @return The current factor.
+ */
+ReRandomizer::seed_t ReCongruentialGeneratorBase::factor() const {
+ return m_factor;
+}
+
+/**
+ * @brief Returns the current increment.
+ *
+ * @return The current increment.
+ */
+ReRandomizer::seed_t ReCongruentialGeneratorBase::increment() const {
+ return m_increment;
}
/**
*
* @param factor The new factor.
*/
-void ReCongruentialGenerator::setFactor(seed_t factor) {
+void ReCongruentialGeneratorBase::setFactor(ReRandomizer::seed_t factor) {
this->m_factor = factor;
}
*
* @param increment The new increment.
*/
-void ReCongruentialGenerator::setIncrement(seed_t increment) {
+void ReCongruentialGeneratorBase::setIncrement(ReRandomizer::seed_t increment) {
this->m_increment = increment;
}
-/** @brief Sets the current seed.
+/**
+ * @brief Constructor.
+ */
+ReCongruentialGenerator::ReCongruentialGenerator() :
+ ReSingleSeedRandomizer("Linear Congruential Generator"),
+ ReCongruentialGeneratorBase() {
+}
+
+/** @brief Returns the next 64 bit pseudo random number.
*
- * @param seed The seed to set.
+ * A congruential generator produces good random in the most significant
+ * bits. Therefore we exchange the bits of the result.
+ * Then x % m returns better results.
+ *
+ * @return a pseudo random number
*/
-void ReCongruentialGenerator::setSeed(seed_t seed) {
- m_seed = m_lastSetSeed = seed;
- if (s_trace)
- printf(" Seed: %llx ", (long long) seed);
+ReRandomizer::seed_t ReRotateRandomizer::nextSeed() {
+ seed_t rc = ReCongruentialGenerator::nextSeed();
+ rc = ((rc & 0x7fffffff) << 33) | ((rc >> 31) & 0x1ffffffffll);
+ return rc;
}
/**
- * Gets the current point of pseudo random.
+ * Constructor.
+ */
+
+ReMultiSeedRandomizer::ReMultiSeedRandomizer(int countSeeds, const char* name) :
+ ReRandomizer(name),
+ m_countSeeds(min(256, max(countSeeds, 2))),
+ m_seedBuffer(),
+ m_startSeed(),
+ m_seeds() {
+ m_seedBuffer.fill(0x38, m_countSeeds * sizeof m_seeds[0]);
+ m_seeds = reinterpret_cast<seed_t*>(m_seedBuffer.data());
+ m_startSeed = m_seedBuffer;
+}
+
+/** @brief Sets the instance to a defined start state.
+ */
+void ReMultiSeedRandomizer::reset() {
+ m_seedBuffer = m_startSeed;
+}
+
+/**
+ * Sets the current point of pseudo random with a seed saved by <code>saveSeed()</code>.
*
* @param seed the current point of pseudo random
*/
-void ReCongruentialGenerator::seed(QByteArray& seed) {
- seed.resize(sizeof m_seed);
- memcpy(seed.data(), &m_seed, sizeof m_seed);
+void ReMultiSeedRandomizer::restoreSeed(const QByteArray& seed) {
+ size_t length = min(seed.length(), m_seedBuffer.length());
+ memcpy(m_seedBuffer.data(), seed.constData(), length);
}
/**
- * Sets the current point of pseudo random.
+ * Stores the the current point of pseudo random in a buffer.
+ *
+ * Restoring is done by <code>restoreSeed()</code>
*
* @param seed the current point of pseudo random
*/
-void ReCongruentialGenerator::setSeed(const QByteArray& seed) {
- if (seed.size() >= sizeof(seed_t)) {
- memcpy(&m_seed, seed.constData(), sizeof m_seed);
- } else {
- QByteArray buffer = seed;
- buffer.resize(sizeof m_seed);
- memset(buffer.data() + seed.size(), 0, sizeof(m_seed) - seed.size());
- memcpy(&m_seed, buffer.constData(), sizeof m_seed);
- }
- m_lastSetSeed = m_seed;
+void ReMultiSeedRandomizer::saveSeed(QByteArray& seed) const {
+ size_t size = m_seedBuffer.length();
+ seed.resize(size);
+ memcpy(seed.data(), m_seedBuffer.constData(), size);
+}
+/**
+ * Converts a text (e.g. password) into the generator specific seed.
+ *
+ * @param text the text to convert
+ */
+void ReMultiSeedRandomizer::textToSeed(const QByteArray& text) {
+ hash(text, m_seedBuffer);
+ m_startSeed = m_seedBuffer;
}
-/** @brief Returns the next 64 bit pseudo random number.
+/**
+ * Constructor.
*
- * A congruential generator produces good random in the most significant
- * bits. Therefore we exchange the bits of the result.
- * Then x % m returns better results.
+ * @param countSeeds number of seeds
+ */
+ReMultiCongruentialGenerator::ReMultiCongruentialGenerator(int countSeeds) :
+ ReMultiSeedRandomizer(countSeeds, "Multi LCG"),
+ ReCongruentialGeneratorBase(),
+ m_currentSeed(-1) {
+}
+
+/** @brief Returns the next 64 bit pseudo random number.
*
* @return a pseudo random number
*/
-ReRandomizer::seed_t ReShiftRandom::nextSeed() {
- seed_t rc = ReCongruentialGenerator::nextSeed();
- rc = ((rc & 0x7fffffff) << 33) | ((rc >> 31) & 0x1ffffffffll);
+ReRandomizer::seed_t ReMultiCongruentialGenerator::nextSeed() {
+ m_currentSeed = (m_currentSeed + 1) % m_countSeeds;
+ seed_t rc = m_seeds[m_currentSeed] * m_factor + m_increment;
+ m_seeds[m_currentSeed] = rc;
+ rc = ((rc & 0x7fffffff) << 33) | ((rc >> 31) & 0x1ffffffffLL);
return rc;
}
+
+/**
+ * Constructor.
+ *
+ * @return
+ */
+ReXorShift64Randomizer::ReXorShift64Randomizer() :
+ ReSingleSeedRandomizer("ShiftXor64") {
+}
+
+/**
+ * Calculates the next pseudo random value.
+ *
+ * @return the next pseudo random value
+ */
+ReRandomizer::seed_t ReXorShift64Randomizer::nextSeed() {
+ m_seed ^= m_seed << 13;
+ m_seed ^= m_seed >> 7;
+ m_seed ^= m_seed << 17;
+ return m_seed;
+}
+
+/**
+ * Constructor.
+ */
+ReKISSRandomizer::ReKISSRandomizer() :
+ ReMultiSeedRandomizer(6, "KISS") {
+ m_seeds[0] = 1234567890987654321ULL;
+ m_seeds[1] = 362436362436362436ULL;
+ m_seeds[2] = 1066149217761810ULL;
+ m_seeds[3] = 123456123456123456ULL;
+ m_seeds[4] = 0x20ab110c19d058ULL;
+ m_seeds[5] = 0x20ab040c19d091ULL;
+}
+
+/**
+ * Calculates the next pseudo random value.
+ * @return
+ */
+ReRandomizer::seed_t ReKISSRandomizer::nextSeed() {
+ static const int x = 0;
+ static const int y = 1;
+ static const int z = 2;
+ static const int c = 3;
+ static const int fac = 4;
+ static const int inc = 5;
+
+ seed_t t;
+
+ // Linear congruence generator
+ m_seeds[z] = m_seeds[fac] * m_seeds[z] + m_seeds[inc];
+
+ // Xorshift
+ m_seeds[y] ^= (m_seeds[y] << 13);
+ m_seeds[y] ^= (m_seeds[y] >> 17);
+ m_seeds[y] ^= (m_seeds[y] << 43);
+
+ // Multiply-with-carry
+ t = (m_seeds[x] << 58) + m_seeds[c];
+ m_seeds[c] = (m_seeds[x] >> 6);
+ m_seeds[x] += t;
+ m_seeds[c] += (m_seeds[x] < t);
+
+ return m_seeds[x] + m_seeds[y] + m_seeds[z];
+}
};
typedef uint64_t seed_t;
public:
- ReRandomizer();
+ ReRandomizer(const char* name);
virtual ~ReRandomizer();
public:
- virtual int nextInt(int maxValue = INT_MAX, int minValue = 0);
- virtual int64_t nextInt64(int64_t maxValue = LLONG_MAX,
- int64_t minValue = 0);
+ const QByteArray& name() const;
+ seed_t nearTrueRandom();
char nextChar();
+ int nextInt(int maxValue = INT_MAX, int minValue = 0);
+ int64_t nextInt64(int64_t maxValue = LLONG_MAX, int64_t minValue = 0);
const char* nextString(int minLength, int maxLength, QByteArray& buffer);
void shuffle(void* array, size_t length, size_t elemSize);
+public:
/** @brief Sets the instance to a defined start state.
*/
virtual void reset() = 0;
/**
- * Gets the current point of pseudo random.
+ * Sets the current point of pseudo random with a seed saved by <code>saveSeed()</code>.
*
* @param seed the current point of pseudo random
*/
- virtual void seed(QByteArray& seed) = 0;
+ virtual void restoreSeed(const QByteArray& seed) = 0;
/**
- * Sets the current point of pseudo random.
+ * Stores the the current point of pseudo random in a buffer.
+ *
+ * Restoring is done by <code>restoreSeed()</code>
*
* @param seed the current point of pseudo random
*/
- virtual void setSeed(QByteArray& seed) = 0;
+ virtual void saveSeed(QByteArray& seed) const = 0;
+ /**
+ * Converts a text (e.g. password) into the generator specific seed.
+ * @param text the text to convert
+ */
+ virtual void textToSeed(const QByteArray& text) = 0;
+public:
+ static seed_t hash(const QByteArray& text);
+ static void hash(const QByteArray& text, QByteArray& seed);
+
protected:
/** @brief Returns the next pseudo random number.
* @return the next pseudo random number
* */
virtual seed_t nextSeed() = 0;
+protected:
+ QByteArray m_name;
public:
- seed_t nearTrueRandom();
+ // the first 125 prime numbers
+ static const int m_primes[];
+ static const int m_countPrimes;
};
/**
- * Implements a simple random generator.
- * A linear congruential generator produces the next value using this formula:
- * seed = (seed * factor + increment) % modulus
- * In this implementation modulus is 2**64.
+ * Base class for pseudo random generators with a state variable (seed) of 64 bit.
*/
-class ReCongruentialGenerator: public ReRandomizer {
+class ReSingleSeedRandomizer: public ReRandomizer {
public:
- ReCongruentialGenerator();
- virtual ~ReCongruentialGenerator();
+ ReSingleSeedRandomizer(const char* name);
public:
- seed_t factor() const;
- seed_t increment() const;
virtual void reset();
seed_t seed() const;
- virtual void seed(QByteArray& seed);
- void setFactor(seed_t factor);
- void setIncrement(seed_t increment);
void setSeed(seed_t m_seed);
- virtual void setSeed(const QByteArray& seed);
+ virtual void restoreSeed(const QByteArray& seed);
+ virtual void saveSeed(QByteArray& seed) const;
+ virtual void textToSeed(const QByteArray& text);
protected:
- friend class ReShiftRandom;
- virtual seed_t nextSeed();
-private:
seed_t m_seed;
- seed_t m_factor;
- seed_t m_increment;
seed_t m_lastSetSeed;
};
-class ReShiftRandom: public ReCongruentialGenerator {
+class ReCongruentialGeneratorBase {
+public:
+ ReCongruentialGeneratorBase();
+public:
+ ReRandomizer::seed_t factor() const;
+ ReRandomizer::seed_t increment() const;
+ void setFactor(ReRandomizer::seed_t factor);
+ void setIncrement(ReRandomizer::seed_t increment);
+protected:
+ ReRandomizer::seed_t m_factor;
+ ReRandomizer::seed_t m_increment;
+};
+
+/**
+ * Implements a simple pseudo random generator.
+ * A linear congruential generator produces the next value using this formula:
+ * seed = (seed * factor + increment) % modulus
+ * In this implementation modulus is 2**64.
+ */
+class ReCongruentialGenerator: public ReSingleSeedRandomizer,
+ public ReCongruentialGeneratorBase {
+public:
+ ReCongruentialGenerator();
+protected:
+ friend class ReShiftRandom;
+ virtual seed_t nextSeed();
+};
+
+/**
+ * A simple pseudo random generator simular to <code>ReCongruentialGenerator</code>.
+ *
+ * A congruential generator produces good random in the most significant
+ * bits. Therefore we exchange the bits of the result.
+ * Then x % m returns better results.
+ */
+class ReRotateRandomizer: public ReCongruentialGenerator {
+protected:
+ virtual seed_t nextSeed();
+};
+
+/**
+ * Abstract base class for pseudo random generators with a state variable larger than 64 bit.
+ */
+class ReMultiSeedRandomizer: public ReRandomizer {
+public:
+ ReMultiSeedRandomizer(int countSeeds, const char* name);
+public:
+ virtual void reset();
+ virtual void restoreSeed(const QByteArray& seed);
+ virtual void saveSeed(QByteArray& seed) const;
+ virtual void textToSeed(const QByteArray& text);
protected:
+ int m_countSeeds;
+ QByteArray m_seedBuffer;
+ QByteArray m_startSeed;
+ seed_t* m_seeds;
+};
+
+/**
+ * A simple pseudo random generator simular to <code>ReCongruentialGenerator</code>.
+ *
+ * Difference: An array of seeds is used (round robin)</code>.
+ */
+class ReMultiCongruentialGenerator: public ReMultiSeedRandomizer,
+ public ReCongruentialGeneratorBase {
+public:
+ ReMultiCongruentialGenerator(int countSeeds);
+public:
+ virtual seed_t nextSeed();
+protected:
+ int m_currentSeed;
+};
+
+class ReXorShift64Randomizer: public ReSingleSeedRandomizer {
+public:
+ ReXorShift64Randomizer();
+public:
+ virtual seed_t nextSeed();
+};
+
+/**
+ * A simple pseudo random generator but it fulfills some statistically tests.
+ *
+ * Combines a congruent generator, a xor-shift generator and the multiply
+ * with carry method.
+ */
+class ReKISSRandomizer: public ReMultiSeedRandomizer {
+public:
+ ReKISSRandomizer();
+public:
virtual seed_t nextSeed();
};
+
#endif /* RANDOMIZER_H_ */