}
#endif
+/**
+ * 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
+ */
+ReRandomizer::seed_t ReRandomizer::hash(const QByteArray& text) {
+ seed_t rc = 0x200a110b190c580dLL;
+ int ixPrimes = m_countPrimes / 2;
+ rc *= text.at(0);
+ 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;
+}
+
+/**
+ * Converts a text into a seed
+ * @param text
+ * @param seed
+ */
+void ReRandomizer::hash(const QByteArray& text, QByteArray& seed) {
+ int maxTrg = seed.length() / sizeof(seed_t) - 1;
+ seed_t* trg = reinterpret_cast<seed_t *>(seed.data());
+ seed_t last = 0x1b20a811cc19f258LL;
+ int textLength = text.length();
+ for (int ix = maxTrg; ix >= 0; ix--) {
+ last = trg[ix] = last * text.at(ix % textLength)
+ + m_primes[ix % m_countPrimes] * text.at((ix + 1) % textLength);
+ }
+ // length password > length seed:
+ for (int ix = maxTrg; ix < textLength; ix++) {
+ last = trg[ix % maxTrg] ^= last * text.at(ix)
+ + m_primes[ix % m_countPrimes];
+ }
+ // length password < length seed:
+ for (int ix = textLength; ix <= maxTrg; ix++) {
+ last = trg[ix] = last * text.at(ix % textLength)
+ + m_primes[ix % m_countPrimes];
+ }
+ // mix of all seed entries:
+ for (int ix = 0; ix <= maxTrg; ix++)
+ last = trg[ix] ^= last * trg[maxTrg - ix];
+}
+
/**
* Returns the name of the generator.
*
return rc;
}
-/**
- * @brief Calculates the next seed for the generator.
- *
- * @return The next seed.
- */
-ReRandomizer::seed_t ReCongruentialGenerator::nextSeed() {
- m_seed = m_seed * m_factor + m_increment;
- return m_seed;
-}
-
/**
* @brief Returns a string with random characters.
*
}
}
}
-/**
- * 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
- */
-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;
-}
-
-/**
- * Converts a text into a seed
- * @param text
- * @param seed
- */
-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 Sets the seed to the value given by the last <code>setSeed()</code>.
*
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.
*
return 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);
+}
+
/**
* Converts a text (e.g. password) into the generator specific seed.
*
return m_increment;
}
+/**
+ * @brief Calculates the next seed for the generator.
+ *
+ * @return The next seed.
+ */
+ReRandomizer::seed_t ReCongruentialGenerator::nextSeed() {
+ m_seed = m_seed * m_factor + m_increment;
+ return m_seed;
+}
+
/**
* Sets the factor.
*
* @brief Constructor.
*/
ReCongruentialGenerator::ReCongruentialGenerator() :
- ReSingleSeedRandomizer("Linear Congruential Generator"),
+ ReSingleSeedRandomizer("LCG"),
+ ReCongruentialGeneratorBase() {
+}
+
+/**
+ * @brief Constructor.
+ */
+ReCongruentialGenerator::ReCongruentialGenerator(const char* name) :
+ ReSingleSeedRandomizer(name),
ReCongruentialGeneratorBase() {
}
+/**
+ * Constructor.
+ */
+ReRotateRandomizer::ReRotateRandomizer() :
+ ReCongruentialGenerator("Rotating LCG") {
+
+}
+
/** @brief Returns the next 64 bit pseudo random number.
*
* A congruential generator produces good random in the most significant
*
* @return a pseudo random number
*/
+
ReRandomizer::seed_t ReRotateRandomizer::nextSeed() {
seed_t rc = ReCongruentialGenerator::nextSeed();
rc = ((rc & 0x7fffffff) << 33) | ((rc >> 31) & 0x1ffffffffll);
m_seedBuffer(),
m_startSeed(),
m_seeds() {
- m_seedBuffer.fill(0x38, m_countSeeds * sizeof m_seeds[0]);
+ m_seedBuffer.resize(m_countSeeds * sizeof m_seeds[0]);
m_seeds = reinterpret_cast<seed_t*>(m_seedBuffer.data());
+ for (int ix = 0; ix < m_countSeeds; ix++) {
+ int ixPrimes = ix % m_countPrimes;
+ m_seeds[ix] = m_primes[ixPrimes] * (2 * ix + 1)
+ + (seed_t(m_primes[m_countPrimes - 1 - ixPrimes]) << 32);
+ }
// assignment does not work: copy on write
m_startSeed.resize(m_seedBuffer.length());
- memcpy(m_seedBuffer.data(), m_startSeed.constData(), m_startSeed.length());
+ memcpy(m_startSeed.data(), m_seedBuffer.constData(), m_startSeed.length());
+}
+
+/** @brief Returns the next 64 bit pseudo random number.
+ *
+ * @return a pseudo random number
+ */
+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;
}
/** @brief Sets the instance to a defined start state.
void ReMultiSeedRandomizer::textToSeed(const QByteArray& text) {
hash(text, m_seedBuffer);
// assignment does not work: copy on write
- memcpy(m_seedBuffer.data(), m_startSeed.constData(), m_seedBuffer.length());
+ memcpy(m_startSeed.data(), m_seedBuffer.constData(), m_seedBuffer.length());
}
/**
m_currentSeed(-1) {
}
-/** @brief Returns the next 64 bit pseudo random number.
- *
- * @return a pseudo random number
+/**
+ * Sets the seed to the start point (defined with setSeed()).
*/
-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;
+void ReMultiCongruentialGenerator::reset() {
+ ReMultiSeedRandomizer::reset();
+ m_currentSeed = -1;
}
/**
return m_params.m_x + m_params.m_y + m_params.m_z;
}
+/**
+ * Sets the seed to the start point (defined with setSeed()).
+ */
void ReKISSRandomizer::reset() {
m_params = m_startParams;
}
+/**
+ * Sets the current point of pseudo random with a seed saved by <code>saveSeed()</code>.
+ *
+ * @param seed the current point of pseudo random
+ */
void ReKISSRandomizer::restoreSeed(const QByteArray& seed) {
restore(seed, m_params);
}
+/**
+ * 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 ReKISSRandomizer::saveSeed(QByteArray& seed) const {
save(m_params, seed);
}
+/**
+ * Converts a text (e.g. password) into the generator specific seed.
+ *
+ * @param text the text to convert
+ */
void ReKISSRandomizer::textToSeed(const QByteArray& text) {
QByteArray seeds;
seeds.resize(sizeof m_params);
rand.saveSeed(seed2);
checkEqu(seed1, seed2);
char cc2 = rand.nextChar();
- checkEqu(cc1, cc2);
+ if (cc1 != cc1) {
+ checkEqu(cc1, cc2);
+ }
rand.reset();
int numbers[16];
for (size_t ix = 0; ix < sizeof numbers / sizeof numbers[0]; ix++)
checkEqu(numbers[ix], rand.nextInt());
clock_t start = clock();
- for (int ix = 0; ix < 1000 * 1000; ix++) {
+ for (int ix = 0; ix < 10 * 1000 * 1000; ix++) {
rand.nextInt64();
}
double duration = double(clock() - start) / CLOCKS_PER_SEC;
ReXorShift64Randomizer rand5;
testOne(rand5);
}
+ void testOnePassw(const char* pw, ReRandomizer& rand) {
+ QByteArray passw(pw);
+ QByteArray seed;
+ rand.textToSeed(passw);
+ rand.saveSeed(seed);
+ passw.append(": ", 8 - passw.length());
+ passw = rand.name() + ": " + passw;
+ passw.append(seed.toHex());
+ log(passw.constData());
+ }
+ void testPasswords(ReRandomizer& rand) {
+ testOnePassw("a", rand);
+ testOnePassw("b", rand);
+ testOnePassw("aa", rand);
+ testOnePassw("ab", rand);
+ testOnePassw("aaa", rand);
+ testOnePassw("aab", rand);
+ }
+
+ void testTextToSeed() {
+ ReCongruentialGenerator rand;
+ testPasswords(rand);
+ ReXorShift64Randomizer rand2;
+ testPasswords(rand2);
+ ReMultiCongruentialGenerator rand3(2);
+ testPasswords(rand3);
+ ReKISSRandomizer rand4;
+ testPasswords(rand4);
+ log("ready");
+ }
+ void write1m(ReRandomizer& rand) {
+ QByteArray fn = ReFileUtils::tempFile(rand.name().constData());
+ fn.append(".data");
+ QByteArray buffer;
+ buffer.reserve(1000 * sizeof(int64_t));
+ FILE* fp = fopen(fn.constData(), "w");
+ checkNN(fp);
+ if (fp != NULL) {
+ for (int block = 0; block < 1000; block++) {
+ buffer.clear();
+ for (int ix = 0; ix < 1000; ix++) {
+ int64_t x = rand.nextInt64();
+ buffer.append((const char*) &x, sizeof x);
+ }
+ fwrite(buffer.constData(), 1, buffer.length(), fp);
+ }
+ fclose(fp);
+ }
+ }
+
void special() {
- ReKISSRandomizer rand;
- int i1 = rand.nextInt();
- rand.reset();
- int i2 = rand.nextInt();
- checkEqu(i1, i2);
+ ReCongruentialGenerator rand;
+ write1m(rand);
+ ReXorShift64Randomizer rand2;
+ write1m(rand2);
+ ReMultiCongruentialGenerator rand3(2);
+ write1m(rand3);
+ ReKISSRandomizer rand4;
+ write1m(rand4);
+ log("ready");
}
virtual void run(void) {
special();
+ testTextToSeed();
testBasics();
+ int ix = 1;
}
};
void testReRandomizer() {