void HashTest::test_performance() { const int ITERATION_COUNT = 1000000; { Hash hf; clock_t t = clock(); for(int i = 0; i < ITERATION_COUNT; ++i) { Id<16> id(true); hf.AddData(id.ConstData(), id.Size); GUINT32 hash = hf.Final(); GUTIL_UNUSED(hash); } clock_t e = clock(); qDebug("Number of ticks to do %d hashes was: %d", ITERATION_COUNT, (int)(e - t)); } { std::hash<string> hf; clock_t t = clock(); for(int i = 0; i < ITERATION_COUNT; ++i) { Id<16> id(true); string s((char const *)id.ConstData(), id.Size); GUINT32 hash = hf(s); GUTIL_UNUSED(hash); } clock_t e = clock(); qDebug("Number of ticks to do %d standard hashes was: %d", ITERATION_COUNT, (int)(e - t)); } }
void HashTest::test_collisions() { // Do a collision check. It should be practically impossible to get a collision double my_avg = 0; const int ITERATION_COUNT = 25; for(int i = 0; i < ITERATION_COUNT; ++i) { //qDebug("Iteration %d", i); set<GUINT32> hashes; GUINT32 cnt = 0; bool collision = false; Hash hf; forever{ cnt++; Id<16> id(true); hf.AddData(id.ConstData(), id.Size); GUINT32 hash = hf.Final(); collision = hashes.find(hash) != hashes.end(); if(!collision) hashes.insert(hash); else break; } //qDebug(QString("Did %1 hashes before a collision").arg(cnt).toAscii()); //QVERIFY(cnt > 10000); my_avg += cnt; } my_avg /= ITERATION_COUNT; qDebug("My average number of hashes before collision was: %f", my_avg); QVERIFY(my_avg > 50000); // Compare our results with the standard hash double their_avg = 0; for(int i = 0; i < ITERATION_COUNT; ++i) { set<GUINT32> hashes; GUINT32 cnt = 0; bool collision = false; std::hash<string> sh; forever{ cnt++; Id<16> id(true); string s((char const *)id.ConstData(), id.Size); GUINT32 hash = sh(s); collision = hashes.find(hash) != hashes.end(); if(!collision) hashes.insert(hash); else break; } their_avg += cnt; //qDebug(QString("Standard hash did %1 hashes before a collision").arg(cnt).toAscii()); } their_avg /= ITERATION_COUNT; qDebug("The average number of standard hashes before collision was: %f", their_avg); }
ConstBufferPtr Digest<Hash>::computeDigest(const uint8_t* buffer, size_t size) { Hash hash; BufferPtr result = make_shared<Buffer>(hash.DigestSize()); hash.Update(buffer, size); hash.Final(result->get()); return result; }
void HashTest::test_basics() { Hash h; qDebug(QString("The hash object is %1 bytes large").arg(sizeof(h)).toAscii()); QVERIFY(4 == h.Size); QVERIFY(Hash::Size == h.Size); // The null hash is 0 QVERIFY(h.Final() == 0); QVERIFY(Hash::ComputeHash(NULL, 0) == 0); { // Make sure hashes of all single bytes are unique set<GUINT32> hashes; for(int i = 0; i < 0x100; ++i){ byte tmp = i; GUINT32 hash = Hash::ComputeHash(&tmp, 1); QVERIFY(hashes.find(hash) == hashes.end()); hashes.insert(hash); } // Make sure hashing the same input gives us the same output for(int i = 0; i < 0x100; ++i){ byte tmp = i; GUINT32 hash = Hash::ComputeHash(&tmp, 1); QVERIFY(hashes.find(hash) != hashes.end()); } } // Hashes one way are not the same as hashes the other way { set<GUINT32> hashes; for(byte c = 'a'; c <= 'z'; ++c){ for(byte c2 = c + 1; c2 <= 'z'; ++c2){ h.AddData(&c, 1); h.AddData(&c2, 1); GUINT32 hash1 = h.Final(); h.AddData(&c2, 1); h.AddData(&c, 1); GUINT32 hash2 = h.Final(); QVERIFY(hash1 != hash2); QVERIFY(hashes.find(hash1) == hashes.end()); QVERIFY(hashes.find(hash2) == hashes.end()); hashes.insert(hash1); hashes.insert(hash2); } } } // Hashes of repeat characters don't repeat hashes { set<GUINT32> hashes; for(int i = 1; i < 10000; i++){ String s('a', i); GUINT32 hash = Hash::ComputeHash((byte const *)s.ConstData(), i); QVERIFY2(hashes.find(hash) == hashes.end(), QString("%1: %2").arg(i).arg(hash, 8, 16).toAscii()); hashes.insert(hash); } } }