1 #include "Platform.h" 2 #include "Hashes.h" 3 #include "KeysetTest.h" 4 #include "SpeedTest.h" 5 #include "AvalancheTest.h" 6 #include "DifferentialTest.h" 7 #include "PMurHash.h" 8 9 #include <stdio.h> 10 #include <time.h> 11 12 //----------------------------------------------------------------------------- 13 // Configuration. TODO - move these to command-line flags 14 15 bool g_testAll = false; 16 17 bool g_testSanity = false; 18 bool g_testSpeed = false; 19 bool g_testDiff = false; 20 bool g_testDiffDist = false; 21 bool g_testAvalanche = false; 22 bool g_testBIC = false; 23 bool g_testCyclic = false; 24 bool g_testTwoBytes = false; 25 bool g_testSparse = false; 26 bool g_testPermutation = false; 27 bool g_testWindow = false; 28 bool g_testText = false; 29 bool g_testZeroes = false; 30 bool g_testSeed = false; 31 32 //----------------------------------------------------------------------------- 33 // This is the list of all hashes that SMHasher can test. 34 35 struct HashInfo 36 { 37 pfHash hash; 38 int hashbits; 39 uint32_t verification; 40 const char * name; 41 const char * desc; 42 }; 43 44 HashInfo g_hashes[] = 45 { 46 { DoNothingHash, 32, 0x00000000, "donothing32", "Do-Nothing function (only valid for measuring call overhead)" }, 47 { DoNothingHash, 64, 0x00000000, "donothing64", "Do-Nothing function (only valid for measuring call overhead)" }, 48 { DoNothingHash, 128, 0x00000000, "donothing128", "Do-Nothing function (only valid for measuring call overhead)" }, 49 50 { crc32, 32, 0x3719DB20, "crc32", "CRC-32" }, 51 52 { md5_32, 32, 0xC10C356B, "md5_32a", "MD5, first 32 bits of result" }, 53 { sha1_32a, 32, 0xF9376EA7, "sha1_32a", "SHA1, first 32 bits of result" }, 54 55 { FNV, 32, 0xE3CBBE91, "FNV", "Fowler-Noll-Vo hash, 32-bit" }, 56 { Bernstein, 32, 0xBDB4B640, "bernstein", "Bernstein, 32-bit" }, 57 { lookup3_test, 32, 0x3D83917A, "lookup3", "Bob Jenkins' lookup3" }, 58 { SuperFastHash, 32, 0x980ACD1D, "superfast", "Paul Hsieh's SuperFastHash" }, 59 { MurmurOAAT_test, 32, 0x5363BD98, "MurmurOAAT", "Murmur one-at-a-time" }, 60 { Crap8_test, 32, 0x743E97A1, "Crap8", "Crap8" }, 61 62 { CityHash64_test, 64, 0x25A20825, "City64", "Google CityHash64WithSeed" }, 63 { CityHash128_test, 128, 0x6531F54E, "City128", "Google CityHash128WithSeed" }, 64 65 { SpookyHash32_test, 32, 0x3F798BBB, "Spooky32", "Bob Jenkins' SpookyHash, 32-bit result" }, 66 { SpookyHash64_test, 64, 0xA7F955F1, "Spooky64", "Bob Jenkins' SpookyHash, 64-bit result" }, 67 { SpookyHash128_test, 128, 0x8D263080, "Spooky128", "Bob Jenkins' SpookyHash, 128-bit result" }, 68 69 // MurmurHash2 70 71 { MurmurHash2_test, 32, 0x27864C1E, "Murmur2", "MurmurHash2 for x86, 32-bit" }, 72 { MurmurHash2A_test, 32, 0x7FBD4396, "Murmur2A", "MurmurHash2A for x86, 32-bit" }, 73 { MurmurHash64A_test, 64, 0x1F0D3804, "Murmur2B", "MurmurHash2 for x64, 64-bit" }, 74 { MurmurHash64B_test, 64, 0xDD537C05, "Murmur2C", "MurmurHash2 for x86, 64-bit" }, 75 76 // MurmurHash3 77 78 { MurmurHash3_x86_32, 32, 0xB0F57EE3, "Murmur3A", "MurmurHash3 for x86, 32-bit" }, 79 { MurmurHash3_x86_128, 128, 0xB3ECE62A, "Murmur3C", "MurmurHash3 for x86, 128-bit" }, 80 { MurmurHash3_x64_128, 128, 0x6384BA69, "Murmur3F", "MurmurHash3 for x64, 128-bit" }, 81 82 { PMurHash32_test, 32, 0xB0F57EE3, "PMurHash32", "Shane Day's portable-ized MurmurHash3 for x86, 32-bit." }, 83 }; 84 85 HashInfo * findHash ( const char * name ) 86 { 87 for(size_t i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++) 88 { 89 if(_stricmp(name,g_hashes[i].name) == 0) return &g_hashes[i]; 90 } 91 92 return NULL; 93 } 94 95 //----------------------------------------------------------------------------- 96 // Self-test on startup - verify that all installed hashes work correctly. 97 98 void SelfTest ( void ) 99 { 100 bool pass = true; 101 102 for(size_t i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++) 103 { 104 HashInfo * info = & g_hashes[i]; 105 106 pass &= VerificationTest(info->hash,info->hashbits,info->verification,false); 107 } 108 109 if(!pass) 110 { 111 printf("Self-test FAILED!\n"); 112 113 for(size_t i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++) 114 { 115 HashInfo * info = & g_hashes[i]; 116 117 printf("%16s - ",info->name); 118 pass &= VerificationTest(info->hash,info->hashbits,info->verification,true); 119 } 120 121 exit(1); 122 } 123 } 124 125 //---------------------------------------------------------------------------- 126 127 template < typename hashtype > 128 void test ( hashfunc<hashtype> hash, HashInfo * info ) 129 { 130 const int hashbits = sizeof(hashtype) * 8; 131 132 printf("-------------------------------------------------------------------------------\n"); 133 printf("--- Testing %s (%s)\n\n",info->name,info->desc); 134 135 //----------------------------------------------------------------------------- 136 // Sanity tests 137 138 if(g_testSanity || g_testAll) 139 { 140 printf("[[[ Sanity Tests ]]]\n\n"); 141 142 VerificationTest(hash,hashbits,info->verification,true); 143 SanityTest(hash,hashbits); 144 AppendedZeroesTest(hash,hashbits); 145 printf("\n"); 146 } 147 148 //----------------------------------------------------------------------------- 149 // Speed tests 150 151 if(g_testSpeed || g_testAll) 152 { 153 printf("[[[ Speed Tests ]]]\n\n"); 154 155 BulkSpeedTest(info->hash,info->verification); 156 printf("\n"); 157 158 for(int i = 1; i < 32; i++) 159 { 160 double cycles; 161 162 TinySpeedTest(hashfunc<hashtype>(info->hash),sizeof(hashtype),i,info->verification,true,cycles); 163 } 164 165 printf("\n"); 166 } 167 168 //----------------------------------------------------------------------------- 169 // Differential tests 170 171 if(g_testDiff || g_testAll) 172 { 173 printf("[[[ Differential Tests ]]]\n\n"); 174 175 bool result = true; 176 bool dumpCollisions = false; 177 178 result &= DiffTest< Blob<64>, hashtype >(hash,5,1000,dumpCollisions); 179 result &= DiffTest< Blob<128>, hashtype >(hash,4,1000,dumpCollisions); 180 result &= DiffTest< Blob<256>, hashtype >(hash,3,1000,dumpCollisions); 181 182 if(!result) printf("*********FAIL*********\n"); 183 printf("\n"); 184 } 185 186 //----------------------------------------------------------------------------- 187 // Differential-distribution tests 188 189 if(g_testDiffDist /*|| g_testAll*/) 190 { 191 printf("[[[ Differential Distribution Tests ]]]\n\n"); 192 193 bool result = true; 194 195 result &= DiffDistTest2<uint64_t,hashtype>(hash); 196 197 printf("\n"); 198 } 199 200 //----------------------------------------------------------------------------- 201 // Avalanche tests 202 203 if(g_testAvalanche || g_testAll) 204 { 205 printf("[[[ Avalanche Tests ]]]\n\n"); 206 207 bool result = true; 208 209 result &= AvalancheTest< Blob< 32>, hashtype > (hash,300000); 210 result &= AvalancheTest< Blob< 40>, hashtype > (hash,300000); 211 result &= AvalancheTest< Blob< 48>, hashtype > (hash,300000); 212 result &= AvalancheTest< Blob< 56>, hashtype > (hash,300000); 213 214 result &= AvalancheTest< Blob< 64>, hashtype > (hash,300000); 215 result &= AvalancheTest< Blob< 72>, hashtype > (hash,300000); 216 result &= AvalancheTest< Blob< 80>, hashtype > (hash,300000); 217 result &= AvalancheTest< Blob< 88>, hashtype > (hash,300000); 218 219 result &= AvalancheTest< Blob< 96>, hashtype > (hash,300000); 220 result &= AvalancheTest< Blob<104>, hashtype > (hash,300000); 221 result &= AvalancheTest< Blob<112>, hashtype > (hash,300000); 222 result &= AvalancheTest< Blob<120>, hashtype > (hash,300000); 223 224 result &= AvalancheTest< Blob<128>, hashtype > (hash,300000); 225 result &= AvalancheTest< Blob<136>, hashtype > (hash,300000); 226 result &= AvalancheTest< Blob<144>, hashtype > (hash,300000); 227 result &= AvalancheTest< Blob<152>, hashtype > (hash,300000); 228 229 if(!result) printf("*********FAIL*********\n"); 230 printf("\n"); 231 } 232 233 //----------------------------------------------------------------------------- 234 // Bit Independence Criteria. Interesting, but doesn't tell us much about 235 // collision or distribution. 236 237 if(g_testBIC) 238 { 239 printf("[[[ Bit Independence Criteria ]]]\n\n"); 240 241 bool result = true; 242 243 //result &= BicTest<uint64_t,hashtype>(hash,2000000); 244 BicTest3<Blob<88>,hashtype>(hash,2000000); 245 246 if(!result) printf("*********FAIL*********\n"); 247 printf("\n"); 248 } 249 250 //----------------------------------------------------------------------------- 251 // Keyset 'Cyclic' - keys of the form "abcdabcdabcd..." 252 253 if(g_testCyclic || g_testAll) 254 { 255 printf("[[[ Keyset 'Cyclic' Tests ]]]\n\n"); 256 257 bool result = true; 258 bool drawDiagram = false; 259 260 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+0,8,10000000,drawDiagram); 261 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+1,8,10000000,drawDiagram); 262 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+2,8,10000000,drawDiagram); 263 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+3,8,10000000,drawDiagram); 264 result &= CyclicKeyTest<hashtype>(hash,sizeof(hashtype)+4,8,10000000,drawDiagram); 265 266 if(!result) printf("*********FAIL*********\n"); 267 printf("\n"); 268 } 269 270 //----------------------------------------------------------------------------- 271 // Keyset 'TwoBytes' - all keys up to N bytes containing two non-zero bytes 272 273 // This generates some huge keysets, 128-bit tests will take ~1.3 gigs of RAM. 274 275 if(g_testTwoBytes || g_testAll) 276 { 277 printf("[[[ Keyset 'TwoBytes' Tests ]]]\n\n"); 278 279 bool result = true; 280 bool drawDiagram = false; 281 282 for(int i = 4; i <= 20; i += 4) 283 { 284 result &= TwoBytesTest2<hashtype>(hash,i,drawDiagram); 285 } 286 287 if(!result) printf("*********FAIL*********\n"); 288 printf("\n"); 289 } 290 291 //----------------------------------------------------------------------------- 292 // Keyset 'Sparse' - keys with all bits 0 except a few 293 294 if(g_testSparse || g_testAll) 295 { 296 printf("[[[ Keyset 'Sparse' Tests ]]]\n\n"); 297 298 bool result = true; 299 bool drawDiagram = false; 300 301 result &= SparseKeyTest< 32,hashtype>(hash,6,true,true,true,drawDiagram); 302 result &= SparseKeyTest< 40,hashtype>(hash,6,true,true,true,drawDiagram); 303 result &= SparseKeyTest< 48,hashtype>(hash,5,true,true,true,drawDiagram); 304 result &= SparseKeyTest< 56,hashtype>(hash,5,true,true,true,drawDiagram); 305 result &= SparseKeyTest< 64,hashtype>(hash,5,true,true,true,drawDiagram); 306 result &= SparseKeyTest< 96,hashtype>(hash,4,true,true,true,drawDiagram); 307 result &= SparseKeyTest< 256,hashtype>(hash,3,true,true,true,drawDiagram); 308 result &= SparseKeyTest<2048,hashtype>(hash,2,true,true,true,drawDiagram); 309 310 if(!result) printf("*********FAIL*********\n"); 311 printf("\n"); 312 } 313 314 //----------------------------------------------------------------------------- 315 // Keyset 'Permutation' - all possible combinations of a set of blocks 316 317 if(g_testPermutation || g_testAll) 318 { 319 { 320 // This one breaks lookup3, surprisingly 321 322 printf("[[[ Keyset 'Combination Lowbits' Tests ]]]\n\n"); 323 324 bool result = true; 325 bool drawDiagram = false; 326 327 uint32_t blocks[] = 328 { 329 0x00000000, 330 331 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 332 }; 333 334 result &= CombinationKeyTest<hashtype>(hash,8,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram); 335 336 if(!result) printf("*********FAIL*********\n"); 337 printf("\n"); 338 } 339 340 { 341 printf("[[[ Keyset 'Combination Highbits' Tests ]]]\n\n"); 342 343 bool result = true; 344 bool drawDiagram = false; 345 346 uint32_t blocks[] = 347 { 348 0x00000000, 349 350 0x20000000, 0x40000000, 0x60000000, 0x80000000, 0xA0000000, 0xC0000000, 0xE0000000 351 }; 352 353 result &= CombinationKeyTest<hashtype>(hash,8,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram); 354 355 if(!result) printf("*********FAIL*********\n"); 356 printf("\n"); 357 } 358 359 { 360 printf("[[[ Keyset 'Combination 0x8000000' Tests ]]]\n\n"); 361 362 bool result = true; 363 bool drawDiagram = false; 364 365 uint32_t blocks[] = 366 { 367 0x00000000, 368 369 0x80000000, 370 }; 371 372 result &= CombinationKeyTest<hashtype>(hash,20,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram); 373 374 if(!result) printf("*********FAIL*********\n"); 375 printf("\n"); 376 } 377 378 { 379 printf("[[[ Keyset 'Combination 0x0000001' Tests ]]]\n\n"); 380 381 bool result = true; 382 bool drawDiagram = false; 383 384 uint32_t blocks[] = 385 { 386 0x00000000, 387 388 0x00000001, 389 }; 390 391 result &= CombinationKeyTest<hashtype>(hash,20,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram); 392 393 if(!result) printf("*********FAIL*********\n"); 394 printf("\n"); 395 } 396 397 { 398 printf("[[[ Keyset 'Combination Hi-Lo' Tests ]]]\n\n"); 399 400 bool result = true; 401 bool drawDiagram = false; 402 403 uint32_t blocks[] = 404 { 405 0x00000000, 406 407 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 408 409 0x80000000, 0x40000000, 0xC0000000, 0x20000000, 0xA0000000, 0x60000000, 0xE0000000 410 }; 411 412 result &= CombinationKeyTest<hashtype>(hash,6,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram); 413 414 if(!result) printf("*********FAIL*********\n"); 415 printf("\n"); 416 } 417 } 418 419 //----------------------------------------------------------------------------- 420 // Keyset 'Window' 421 422 // Skip distribution test for these - they're too easy to distribute well, 423 // and it generates a _lot_ of testing 424 425 if(g_testWindow || g_testAll) 426 { 427 printf("[[[ Keyset 'Window' Tests ]]]\n\n"); 428 429 bool result = true; 430 bool testCollision = true; 431 bool testDistribution = false; 432 bool drawDiagram = false; 433 434 result &= WindowedKeyTest< Blob<hashbits*2>, hashtype > ( hash, 20, testCollision, testDistribution, drawDiagram ); 435 436 if(!result) printf("*********FAIL*********\n"); 437 printf("\n"); 438 } 439 440 //----------------------------------------------------------------------------- 441 // Keyset 'Text' 442 443 if(g_testText || g_testAll) 444 { 445 printf("[[[ Keyset 'Text' Tests ]]]\n\n"); 446 447 bool result = true; 448 bool drawDiagram = false; 449 450 const char * alnum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 451 452 result &= TextKeyTest( hash, "Foo", alnum,4, "Bar", drawDiagram ); 453 result &= TextKeyTest( hash, "FooBar", alnum,4, "", drawDiagram ); 454 result &= TextKeyTest( hash, "", alnum,4, "FooBar", drawDiagram ); 455 456 if(!result) printf("*********FAIL*********\n"); 457 printf("\n"); 458 } 459 460 //----------------------------------------------------------------------------- 461 // Keyset 'Zeroes' 462 463 if(g_testZeroes || g_testAll) 464 { 465 printf("[[[ Keyset 'Zeroes' Tests ]]]\n\n"); 466 467 bool result = true; 468 bool drawDiagram = false; 469 470 result &= ZeroKeyTest<hashtype>( hash, drawDiagram ); 471 472 if(!result) printf("*********FAIL*********\n"); 473 printf("\n"); 474 } 475 476 //----------------------------------------------------------------------------- 477 // Keyset 'Seed' 478 479 if(g_testSeed || g_testAll) 480 { 481 printf("[[[ Keyset 'Seed' Tests ]]]\n\n"); 482 483 bool result = true; 484 bool drawDiagram = false; 485 486 result &= SeedTest<hashtype>( hash, 1000000, drawDiagram ); 487 488 if(!result) printf("*********FAIL*********\n"); 489 printf("\n"); 490 } 491 } 492 493 //----------------------------------------------------------------------------- 494 495 uint32_t g_inputVCode = 1; 496 uint32_t g_outputVCode = 1; 497 uint32_t g_resultVCode = 1; 498 499 HashInfo * g_hashUnderTest = NULL; 500 501 void VerifyHash ( const void * key, int len, uint32_t seed, void * out ) 502 { 503 g_inputVCode = MurmurOAAT(key,len,g_inputVCode); 504 g_inputVCode = MurmurOAAT(&seed,sizeof(uint32_t),g_inputVCode); 505 506 g_hashUnderTest->hash(key,len,seed,out); 507 508 g_outputVCode = MurmurOAAT(out,g_hashUnderTest->hashbits/8,g_outputVCode); 509 } 510 511 //----------------------------------------------------------------------------- 512 513 void testHash ( const char * name ) 514 { 515 HashInfo * pInfo = findHash(name); 516 517 if(pInfo == NULL) 518 { 519 printf("Invalid hash '%s' specified\n",name); 520 return; 521 } 522 else 523 { 524 g_hashUnderTest = pInfo; 525 526 if(pInfo->hashbits == 32) 527 { 528 test<uint32_t>( VerifyHash, pInfo ); 529 } 530 else if(pInfo->hashbits == 64) 531 { 532 test<uint64_t>( pInfo->hash, pInfo ); 533 } 534 else if(pInfo->hashbits == 128) 535 { 536 test<uint128_t>( pInfo->hash, pInfo ); 537 } 538 else if(pInfo->hashbits == 256) 539 { 540 test<uint256_t>( pInfo->hash, pInfo ); 541 } 542 else 543 { 544 printf("Invalid hash bit width %d for hash '%s'",pInfo->hashbits,pInfo->name); 545 } 546 } 547 } 548 //----------------------------------------------------------------------------- 549 550 int main ( int argc, char ** argv ) 551 { 552 const char * hashToTest = "murmur3a"; 553 554 if(argc < 2) 555 { 556 printf("(No test hash given on command line, testing Murmur3_x86_32.)\n"); 557 } 558 else 559 { 560 hashToTest = argv[1]; 561 } 562 563 // Code runs on the 3rd CPU by default 564 565 SetAffinity((1 << 2)); 566 567 SelfTest(); 568 569 int timeBegin = clock(); 570 571 g_testAll = true; 572 573 //g_testSanity = true; 574 //g_testSpeed = true; 575 //g_testAvalanche = true; 576 //g_testBIC = true; 577 //g_testCyclic = true; 578 //g_testTwoBytes = true; 579 //g_testDiff = true; 580 //g_testDiffDist = true; 581 //g_testSparse = true; 582 //g_testPermutation = true; 583 //g_testWindow = true; 584 //g_testZeroes = true; 585 586 testHash(hashToTest); 587 588 //---------- 589 590 int timeEnd = clock(); 591 592 printf("\n"); 593 printf("Input vcode 0x%08x, Output vcode 0x%08x, Result vcode 0x%08x\n",g_inputVCode,g_outputVCode,g_resultVCode); 594 printf("Verification value is 0x%08x - Testing took %f seconds\n",g_verify,double(timeEnd-timeBegin)/double(CLOCKS_PER_SEC)); 595 printf("-------------------------------------------------------------------------------\n"); 596 return 0; 597 } 598