| /* |
| * xxhsum - Command line interface for xxhash algorithms |
| * Copyright (C) 2013-2021 Yann Collet |
| * |
| * GPL v2 License |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * You can contact the author at: |
| * - xxHash homepage: https://www.xxhash.com |
| * - xxHash source repository: https://github.com/Cyan4973/xxHash |
| */ |
| |
| #include "xsum_sanity_check.h" |
| #include "xsum_output.h" /* XSUM_log */ |
| #ifndef XXH_STATIC_LINKING_ONLY |
| # define XXH_STATIC_LINKING_ONLY |
| #endif |
| #include "../xxhash.h" |
| |
| #include <stdlib.h> /* exit */ |
| #include <assert.h> |
| #include <string.h> /* memcmp */ |
| |
| /* use #define to make them constant, required for initialization */ |
| #define PRIME32 2654435761U |
| #define PRIME64 11400714785074694797ULL |
| |
| /* |
| * Fills a test buffer with pseudorandom data. |
| * |
| * This is used in the sanity check - its values must not be changed. |
| */ |
| XSUM_API void XSUM_fillTestBuffer(XSUM_U8* buffer, size_t len) |
| { |
| XSUM_U64 byteGen = PRIME32; |
| size_t i; |
| |
| assert(buffer != NULL); |
| |
| for (i=0; i<len; i++) { |
| buffer[i] = (XSUM_U8)(byteGen>>56); |
| byteGen *= PRIME64; |
| } |
| } |
| |
| |
| |
| /* ************************************************ |
| * Self-test: |
| * ensure results consistency across platforms |
| *********************************************** */ |
| #if XSUM_NO_TESTS |
| XSUM_API void XSUM_sanityCheck(void) |
| { |
| XSUM_log("This version of xxhsum is not verified.\n"); |
| } |
| #else |
| |
| /* |
| * Test data vectors |
| */ |
| typedef struct { |
| XSUM_U32 len; |
| XSUM_U32 seed; |
| XSUM_U32 Nresult; |
| } XSUM_testdata32_t; |
| |
| typedef struct { |
| XSUM_U32 len; |
| XSUM_U64 seed; |
| XSUM_U64 Nresult; |
| } XSUM_testdata64_t; |
| |
| typedef struct { |
| XSUM_U32 len; |
| XSUM_U64 seed; |
| XXH128_hash_t Nresult; |
| } XSUM_testdata128_t; |
| |
| #define SECRET_SAMPLE_NBBYTES 5 |
| typedef struct { |
| XSUM_U32 seedLen; |
| XSUM_U32 secretLen; |
| XSUM_U8 byte[SECRET_SAMPLE_NBBYTES]; |
| } XSUM_testdata_sample_t; |
| |
| /* XXH32 */ |
| static const XSUM_testdata32_t XSUM_XXH32_testdata[] = { |
| { 0, 0, 0x02CC5D05U }, |
| { 0, PRIME32, 0x36B78AE7U }, |
| { 1, 0, 0xCF65B03EU }, |
| { 1, PRIME32, 0xB4545AA4U }, |
| { 14, 0, 0x1208E7E2U }, |
| { 14, PRIME32, 0x6AF1D1FEU }, |
| { 222, 0, 0x5BD11DBDU }, |
| { 222, PRIME32, 0x58803C5FU } |
| }; |
| |
| /* XXH64 */ |
| static const XSUM_testdata64_t XSUM_XXH64_testdata[] = { |
| { 0, 0, 0xEF46DB3751D8E999ULL }, |
| { 0, PRIME32, 0xAC75FDA2929B17EFULL }, |
| { 1, 0, 0xE934A84ADB052768ULL }, |
| { 1, PRIME32, 0x5014607643A9B4C3ULL }, |
| { 4, 0, 0x9136A0DCA57457EEULL }, |
| { 14, 0, 0x8282DCC4994E35C8ULL }, |
| { 14, PRIME32, 0xC3BD6BF63DEB6DF0ULL }, |
| { 222, 0, 0xB641AE8CB691C174ULL }, |
| { 222, PRIME32, 0x20CB8AB7AE10C14AULL } |
| }; |
| /* |
| * XXH3: |
| * Due to being a more complex hash function with specializations for certain |
| * lengths, a more extensive test is used for XXH3. |
| */ |
| |
| /* XXH3_64bits, seeded */ |
| static const XSUM_testdata64_t XSUM_XXH3_testdata[] = { |
| { 0, 0, 0x2D06800538D394C2ULL }, /* empty string */ |
| { 0, PRIME64, 0xA8A6B918B2F0364AULL }, |
| { 1, 0, 0xC44BDFF4074EECDBULL }, /* 1 - 3 */ |
| { 1, PRIME64, 0x032BE332DD766EF8ULL }, |
| { 6, 0, 0x27B56A84CD2D7325ULL }, /* 4 - 8 */ |
| { 6, PRIME64, 0x84589C116AB59AB9ULL }, |
| { 12, 0, 0xA713DAF0DFBB77E7ULL }, /* 9 - 16 */ |
| { 12, PRIME64, 0xE7303E1B2336DE0EULL }, |
| { 24, 0, 0xA3FE70BF9D3510EBULL }, /* 17 - 32 */ |
| { 24, PRIME64, 0x850E80FC35BDD690ULL }, |
| { 48, 0, 0x397DA259ECBA1F11ULL }, /* 33 - 64 */ |
| { 48, PRIME64, 0xADC2CBAA44ACC616ULL }, |
| { 80, 0, 0xBCDEFBBB2C47C90AULL }, /* 65 - 96 */ |
| { 80, PRIME64, 0xC6DD0CB699532E73ULL }, |
| { 195, 0, 0xCD94217EE362EC3AULL }, /* 129-240 */ |
| { 195, PRIME64, 0xBA68003D370CB3D9ULL }, |
| |
| { 403, 0, 0xCDEB804D65C6DEA4ULL }, /* one block, last stripe is overlapping */ |
| { 403, PRIME64, 0x6259F6ECFD6443FDULL }, |
| { 512, 0, 0x617E49599013CB6BULL }, /* one block, finishing at stripe boundary */ |
| { 512, PRIME64, 0x3CE457DE14C27708ULL }, |
| { 2048, 0, 0xDD59E2C3A5F038E0ULL }, /* 2 blocks, finishing at block boundary */ |
| { 2048, PRIME64, 0x66F81670669ABABCULL }, |
| { 2099, 0, 0xC6B9D9B3FC9AC765ULL }, /* 2 blocks + 1 partial block, to detect off-by-one scrambling issues, like #816 */ |
| { 2099, PRIME64, 0x184F316843663974ULL }, |
| { 2240, 0, 0x6E73A90539CF2948ULL }, /* 3 blocks, finishing at stripe boundary */ |
| { 2240, PRIME64, 0x757BA8487D1B5247ULL }, |
| { 2367, 0, 0xCB37AEB9E5D361EDULL }, /* 3 blocks, last stripe is overlapping */ |
| { 2367, PRIME64, 0xD2DB3415B942B42AULL } |
| }; |
| /* XXH3_64bits, custom secret */ |
| static const XSUM_testdata64_t XSUM_XXH3_withSecret_testdata[] = { |
| { 0, 0, 0x3559D64878C5C66CULL }, /* empty string */ |
| { 1, 0, 0x8A52451418B2DA4DULL }, /* 1 - 3 */ |
| { 6, 0, 0x82C90AB0519369ADULL }, /* 4 - 8 */ |
| { 12, 0, 0x14631E773B78EC57ULL }, /* 9 - 16 */ |
| { 24, 0, 0xCDD5542E4A9D9FE8ULL }, /* 17 - 32 */ |
| { 48, 0, 0x33ABD54D094B2534ULL }, /* 33 - 64 */ |
| { 80, 0, 0xE687BA1684965297ULL }, /* 65 - 96 */ |
| { 195, 0, 0xA057273F5EECFB20ULL }, /* 129-240 */ |
| |
| { 403, 0, 0x14546019124D43B8ULL }, /* one block, last stripe is overlapping */ |
| { 512, 0, 0x7564693DD526E28DULL }, /* one block, finishing at stripe boundary */ |
| { 2048, 0, 0xD32E975821D6519FULL }, /* >= 2 blodcks, at least one scrambling */ |
| { 2367, 0, 0x293FA8E5173BB5E7ULL }, /* >= 2 blocks, at least one scrambling, last stripe unaligned */ |
| |
| { 64*10*3, 0, 0x751D2EC54BC6038BULL } /* exactly 3 full blocks, not a multiple of 256 */ |
| }; |
| /* XXH3_128bits, seeded */ |
| static const XSUM_testdata128_t XSUM_XXH128_testdata[] = { |
| { 0, 0, { 0x6001C324468D497FULL, 0x99AA06D3014798D8ULL } }, /* empty string */ |
| { 0, PRIME32, { 0x5444F7869C671AB0ULL, 0x92220AE55E14AB50ULL } }, |
| { 1, 0, { 0xC44BDFF4074EECDBULL, 0xA6CD5E9392000F6AULL } }, /* 1 - 3 */ |
| { 1, PRIME32, { 0xB53D5557E7F76F8DULL, 0x89B99554BA22467CULL } }, |
| { 6, 0, { 0x3E7039BDDA43CFC6ULL, 0x082AFE0B8162D12AULL } }, /* 4 - 8 */ |
| { 6, PRIME32, { 0x269D8F70BE98856EULL, 0x5A865B5389ABD2B1ULL } }, |
| { 12, 0, { 0x061A192713F69AD9ULL, 0x6E3EFD8FC7802B18ULL } }, /* 9 - 16 */ |
| { 12, PRIME32, { 0x9BE9F9A67F3C7DFBULL, 0xD7E09D518A3405D3ULL } }, |
| { 24, 0, { 0x1E7044D28B1B901DULL, 0x0CE966E4678D3761ULL } }, /* 17 - 32 */ |
| { 24, PRIME32, { 0xD7304C54EBAD40A9ULL, 0x3162026714A6A243ULL } }, |
| { 48, 0, { 0xF942219AED80F67BULL, 0xA002AC4E5478227EULL } }, /* 33 - 64 */ |
| { 48, PRIME32, { 0x7BA3C3E453A1934EULL, 0x163ADDE36C072295ULL } }, |
| { 81, 0, { 0x5E8BAFB9F95FB803ULL, 0x4952F58181AB0042ULL } }, /* 65 - 96 */ |
| { 81, PRIME32, { 0x703FBB3D7A5F755CULL, 0x2724EC7ADC750FB6ULL } }, |
| { 222, 0, { 0xF1AEBD597CEC6B3AULL, 0x337E09641B948717ULL } }, /* 129-240 */ |
| { 222, PRIME32, { 0xAE995BB8AF917A8DULL, 0x91820016621E97F1ULL } }, |
| |
| { 403, 0, { 0xCDEB804D65C6DEA4ULL, 0x1B6DE21E332DD73DULL } }, /* one block, last stripe is overlapping */ |
| { 403, PRIME64, { 0x6259F6ECFD6443FDULL, 0xBED311971E0BE8F2ULL } }, |
| { 512, 0, { 0x617E49599013CB6BULL, 0x18D2D110DCC9BCA1ULL } }, /* one block, finishing at stripe boundary */ |
| { 512, PRIME64, { 0x3CE457DE14C27708ULL, 0x925D06B8EC5B8040ULL } }, |
| { 2048, 0, { 0xDD59E2C3A5F038E0ULL, 0xF736557FD47073A5ULL } }, /* 2 blocks, finishing at block boundary */ |
| { 2048, PRIME32, { 0x230D43F30206260BULL, 0x7FB03F7E7186C3EAULL } }, |
| { 2240, 0, { 0x6E73A90539CF2948ULL, 0xCCB134FBFA7CE49DULL } }, /* 3 blocks, finishing at stripe boundary */ |
| { 2240, PRIME32, { 0xED385111126FBA6FULL, 0x50A1FE17B338995FULL } }, |
| { 2367, 0, { 0xCB37AEB9E5D361EDULL, 0xE89C0F6FF369B427ULL } }, /* 3 blocks, last stripe is overlapping */ |
| { 2367, PRIME32, { 0x6F5360AE69C2F406ULL, 0xD23AAE4B76C31ECBULL } } |
| }; |
| |
| /* XXH128, custom secret */ |
| static const XSUM_testdata128_t XSUM_XXH128_withSecret_testdata[] = { |
| { 0, 0, { 0x005923CCEECBE8AEULL, 0x5F70F4EA232F1D38ULL } }, /* empty string */ |
| { 1, 0, { 0x8A52451418B2DA4DULL, 0x3A66AF5A9819198EULL } }, /* 1 - 3 */ |
| { 6, 0, { 0x0B61C8ACA7D4778FULL, 0x376BD91B6432F36DULL } }, /* 4 - 8 */ |
| { 12, 0, { 0xAF82F6EBA263D7D8ULL, 0x90A3C2D839F57D0FULL } } /* 9 - 16 */ |
| }; |
| |
| #define SECRET_SIZE_MAX 9867 |
| static const XSUM_testdata_sample_t XSUM_XXH3_generateSecret_testdata[] = { |
| { 0, 192, { 0xE7, 0x8C, 0x77, 0x77, 0x00 } }, |
| { 1, 240, { 0x2B, 0x3E, 0xDE, 0xC1, 0x00 } }, |
| { XXH3_SECRET_SIZE_MIN - 1, 277, { 0xE8, 0x39, 0x6C, 0xCC, 0x7B } }, |
| { XXH3_SECRET_DEFAULT_SIZE + 500, SECRET_SIZE_MAX, { 0xD6, 0x1C, 0x41, 0x17, 0xB3 } } |
| }; |
| |
| static void XSUM_checkResult32(XXH32_hash_t r1, XXH32_hash_t r2) |
| { |
| static int nbTests = 1; |
| if (r1!=r2) { |
| XSUM_log("\rError: 32-bit hash test %i: Internal sanity check failed!\n", nbTests); |
| XSUM_log("\rGot 0x%08X, expected 0x%08X.\n", (unsigned)r1, (unsigned)r2); |
| XSUM_log("\rNote: If you modified the hash functions, make sure to either update the values\n" |
| "or temporarily recompile with XSUM_NO_TESTS=1.\n"); |
| exit(1); |
| } |
| nbTests++; |
| } |
| |
| static void XSUM_checkResult64(XXH64_hash_t r1, XXH64_hash_t r2) |
| { |
| static int nbTests = 1; |
| if (r1!=r2) { |
| XSUM_log("\rError: 64-bit hash test %i: Internal sanity check failed!\n", nbTests); |
| XSUM_log("\rGot 0x%08X%08XULL, expected 0x%08X%08XULL.\n", |
| (unsigned)(r1>>32), (unsigned)r1, (unsigned)(r2>>32), (unsigned)r2); |
| XSUM_log("\rNote: If you modified the hash functions, make sure to either update the values\n" |
| "or temporarily recompile with XSUM_NO_TESTS=1.\n"); |
| exit(1); |
| } |
| nbTests++; |
| } |
| |
| static void XSUM_checkResult128(XXH128_hash_t r1, XXH128_hash_t r2) |
| { |
| static int nbTests = 1; |
| if ((r1.low64 != r2.low64) || (r1.high64 != r2.high64)) { |
| XSUM_log("\rError: 128-bit hash test %i: Internal sanity check failed.\n", nbTests); |
| XSUM_log("\rGot { 0x%08X%08XULL, 0x%08X%08XULL }, expected { 0x%08X%08XULL, 0x%08X%08XULL } \n", |
| (unsigned)(r1.low64>>32), (unsigned)r1.low64, (unsigned)(r1.high64>>32), (unsigned)r1.high64, |
| (unsigned)(r2.low64>>32), (unsigned)r2.low64, (unsigned)(r2.high64>>32), (unsigned)r2.high64 ); |
| XSUM_log("\rNote: If you modified the hash functions, make sure to either update the values\n" |
| "or temporarily recompile with XSUM_NO_TESTS=1.\n"); |
| exit(1); |
| } |
| nbTests++; |
| } |
| |
| |
| static void XSUM_testXXH32(const void* data, const XSUM_testdata32_t* testData) |
| { |
| XXH32_state_t *state = XXH32_createState(); |
| size_t pos; |
| |
| size_t len = testData->len; |
| XSUM_U32 seed = testData->seed; |
| XSUM_U32 Nresult = testData->Nresult; |
| |
| if (len == 0) { |
| data = NULL; |
| } else { |
| assert(data != NULL); |
| } |
| |
| assert(state != NULL); |
| |
| XSUM_checkResult32(XXH32(data, len, seed), Nresult); |
| |
| (void)XXH32_reset(state, seed); |
| (void)XXH32_update(state, data, len); |
| XSUM_checkResult32(XXH32_digest(state), Nresult); |
| |
| (void)XXH32_reset(state, seed); |
| for (pos=0; pos<len; pos++) |
| (void)XXH32_update(state, ((const char*)data)+pos, 1); |
| XSUM_checkResult32(XXH32_digest(state), Nresult); |
| XXH32_freeState(state); |
| } |
| |
| static void XSUM_testXXH64(const void* data, const XSUM_testdata64_t* testData) |
| { |
| XXH64_state_t *state = XXH64_createState(); |
| size_t pos; |
| |
| size_t len = (size_t)testData->len; |
| XSUM_U64 seed = testData->seed; |
| XSUM_U64 Nresult = testData->Nresult; |
| |
| if (len == 0) { |
| data = NULL; |
| } else { |
| assert(data != NULL); |
| } |
| |
| assert(state != NULL); |
| |
| XSUM_checkResult64(XXH64(data, len, seed), Nresult); |
| |
| (void)XXH64_reset(state, seed); |
| (void)XXH64_update(state, data, len); |
| XSUM_checkResult64(XXH64_digest(state), Nresult); |
| |
| (void)XXH64_reset(state, seed); |
| for (pos=0; pos<len; pos++) |
| (void)XXH64_update(state, ((const char*)data)+pos, 1); |
| XSUM_checkResult64(XXH64_digest(state), Nresult); |
| XXH64_freeState(state); |
| } |
| |
| /* |
| * Used to get "random" (but actually 100% reproducible) lengths for |
| * XSUM_XXH3_randomUpdate. |
| */ |
| static XSUM_U32 XSUM_rand(void) |
| { |
| static XSUM_U64 seed = PRIME32; |
| seed *= PRIME64; |
| return (XSUM_U32)(seed >> 40); |
| } |
| |
| /* |
| * Technically, XXH3_64bits_update is identical to XXH3_128bits_update as of |
| * v0.8.0, but we treat them as separate. |
| */ |
| typedef XXH_errorcode (*XSUM_XXH3_update_t)(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t length); |
| |
| /* |
| * Runs the passed XXH3_update variant on random lengths. This is to test the |
| * more complex logic of the update function, catching bugs like this one: |
| * https://github.com/Cyan4973/xxHash/issues/378 |
| */ |
| static void XSUM_XXH3_randomUpdate(XXH3_state_t* state, const void* data, |
| size_t len, XSUM_XXH3_update_t update_fn) |
| { |
| size_t p = 0; |
| while (p < len) { |
| size_t const modulo = len > 2 ? len : 2; |
| size_t l = (size_t)(XSUM_rand()) % modulo; |
| if (p + l > len) l = len - p; |
| (void)update_fn(state, (const char*)data+p, l); |
| p += l; |
| } |
| } |
| |
| static void XSUM_testXXH3(const void* data, const XSUM_testdata64_t* testData) |
| { |
| size_t len = testData->len; |
| XSUM_U64 seed = testData->seed; |
| XSUM_U64 Nresult = testData->Nresult; |
| if (len == 0) { |
| data = NULL; |
| } else { |
| assert(data != NULL); |
| } |
| { XSUM_U64 const Dresult = XXH3_64bits_withSeed(data, len, seed); |
| XSUM_checkResult64(Dresult, Nresult); |
| } |
| |
| /* check that the no-seed variant produces same result as seed==0 */ |
| if (seed == 0) { |
| XSUM_U64 const Dresult = XXH3_64bits(data, len); |
| XSUM_checkResult64(Dresult, Nresult); |
| } |
| |
| /* check that the combination of |
| * XXH3_generateSecret_fromSeed() and XXH3_64bits_withSecretandSeed() |
| * results in exactly the same hash generation as XXH3_64bits_withSeed() */ |
| { char secretBuffer[XXH3_SECRET_DEFAULT_SIZE+1]; |
| char* const secret = secretBuffer + 1; /* intentional unalignment */ |
| XXH3_generateSecret_fromSeed(secret, seed); |
| { XSUM_U64 const Dresult = XXH3_64bits_withSecretandSeed(data, len, secret, XXH3_SECRET_DEFAULT_SIZE, seed); |
| XSUM_checkResult64(Dresult, Nresult); |
| } |
| |
| /* check that XXH3_64bits_withSecretandSeed() |
| * results in exactly the same return value as XXH3_64bits_withSeed() |
| * when len <= XXH3_MIDSIZE_MAX, whatever the content of @secret */ |
| memset(secret, 0x99, 9); |
| if (len <= XXH3_MIDSIZE_MAX) { |
| XSUM_U64 const Dresult = XXH3_64bits_withSecretandSeed(data, len, secret, XXH3_SECRET_DEFAULT_SIZE, seed); |
| XSUM_checkResult64(Dresult, Nresult); |
| } |
| } |
| |
| /* streaming API test */ |
| { XXH3_state_t* const state = XXH3_createState(); |
| assert(state != NULL); |
| /* single ingestion */ |
| (void)XXH3_64bits_reset_withSeed(state, seed); |
| (void)XXH3_64bits_update(state, data, len); |
| XSUM_checkResult64(XXH3_64bits_digest(state), Nresult); |
| |
| /* random ingestion */ |
| (void)XXH3_64bits_reset_withSeed(state, seed); |
| XSUM_XXH3_randomUpdate(state, data, len, XXH3_64bits_update); |
| XSUM_checkResult64(XXH3_64bits_digest(state), Nresult); |
| |
| /* byte by byte ingestion */ |
| { size_t pos; |
| (void)XXH3_64bits_reset_withSeed(state, seed); |
| for (pos=0; pos<len; pos++) |
| (void)XXH3_64bits_update(state, ((const char*)data)+pos, 1); |
| XSUM_checkResult64(XXH3_64bits_digest(state), Nresult); |
| } |
| |
| /* check that streaming with a combination of |
| * XXH3_generateSecret_fromSeed() and XXH3_64bits_reset_withSecretandSeed() |
| * results in exactly the same hash generation as XXH3_64bits_reset_withSeed() */ |
| { char secretBuffer[XXH3_SECRET_DEFAULT_SIZE+1]; |
| char* const secret = secretBuffer + 1; /* intentional unalignment */ |
| XXH3_generateSecret_fromSeed(secret, seed); |
| /* single ingestion */ |
| (void)XXH3_64bits_reset_withSecretandSeed(state, secret, XXH3_SECRET_DEFAULT_SIZE, seed); |
| (void)XXH3_64bits_update(state, data, len); |
| XSUM_checkResult64(XXH3_64bits_digest(state), Nresult); |
| |
| /* check that XXH3_64bits_withSecretandSeed() |
| * results in exactly the same return value as XXH3_64bits_withSeed() |
| * when len <= XXH3_MIDSIZE_MAX, whatever the content of @secret */ |
| if (len <= XXH3_MIDSIZE_MAX) { |
| /* single ingestion */ |
| memset(secret, 0x99, 9); |
| (void)XXH3_64bits_reset_withSecretandSeed(state, secret, XXH3_SECRET_DEFAULT_SIZE, seed); |
| (void)XXH3_64bits_update(state, data, len); |
| XSUM_checkResult64(XXH3_64bits_digest(state), Nresult); |
| } |
| } |
| |
| XXH3_freeState(state); |
| } |
| |
| } |
| |
| |
| static void XSUM_testXXH3_withSecret(const void* data, const void* secret, |
| size_t secretSize, const XSUM_testdata64_t* testData) |
| { |
| size_t len = (size_t)testData->len; |
| XSUM_U64 Nresult = testData->Nresult; |
| |
| if (len == 0) { |
| data = NULL; |
| } else { |
| assert(data != NULL); |
| } |
| { XSUM_U64 const Dresult = XXH3_64bits_withSecret(data, len, secret, secretSize); |
| XSUM_checkResult64(Dresult, Nresult); |
| } |
| |
| /* check that XXH3_64bits_withSecretandSeed() |
| * results in exactly the same return value as XXH3_64bits_withSecret() */ |
| if (len > XXH3_MIDSIZE_MAX) |
| { XSUM_U64 const Dresult = XXH3_64bits_withSecretandSeed(data, len, secret, secretSize, 0); |
| XSUM_checkResult64(Dresult, Nresult); |
| } |
| |
| /* streaming API test */ |
| { XXH3_state_t *state = XXH3_createState(); |
| assert(state != NULL); |
| (void)XXH3_64bits_reset_withSecret(state, secret, secretSize); |
| (void)XXH3_64bits_update(state, data, len); |
| XSUM_checkResult64(XXH3_64bits_digest(state), Nresult); |
| |
| /* random ingestion */ |
| (void)XXH3_64bits_reset_withSecret(state, secret, secretSize); |
| XSUM_XXH3_randomUpdate(state, data, len, XXH3_64bits_update); |
| XSUM_checkResult64(XXH3_64bits_digest(state), Nresult); |
| |
| /* byte by byte ingestion */ |
| { size_t pos; |
| (void)XXH3_64bits_reset_withSecret(state, secret, secretSize); |
| for (pos=0; pos<len; pos++) |
| (void)XXH3_64bits_update(state, ((const char*)data)+pos, 1); |
| XSUM_checkResult64(XXH3_64bits_digest(state), Nresult); |
| } |
| |
| /* check that XXH3_64bits_reset_withSecretandSeed() |
| * results in exactly the same return value as XXH3_64bits_reset_withSecret() |
| * when len > XXH3_MIDSIZE_MAX, whatever the value of @seed */ |
| if (len > XXH3_MIDSIZE_MAX) { |
| /* single ingestion */ |
| (void)XXH3_64bits_reset_withSecretandSeed(state, secret, secretSize, 17); |
| (void)XXH3_64bits_update(state, data, len); |
| XSUM_checkResult64(XXH3_64bits_digest(state), Nresult); |
| } |
| |
| XXH3_freeState(state); |
| } |
| } |
| |
| static void XSUM_testXXH128(const void* data, const XSUM_testdata128_t* testData) |
| { |
| size_t len = (size_t)testData->len; |
| XSUM_U64 seed = testData->seed; |
| XXH128_hash_t const Nresult = testData->Nresult; |
| if (len == 0) { |
| data = NULL; |
| } else { |
| assert(data != NULL); |
| } |
| |
| { XXH128_hash_t const Dresult = XXH3_128bits_withSeed(data, len, seed); |
| XSUM_checkResult128(Dresult, Nresult); |
| } |
| |
| /* check that XXH128() is identical to XXH3_128bits_withSeed() */ |
| { XXH128_hash_t const Dresult2 = XXH128(data, len, seed); |
| XSUM_checkResult128(Dresult2, Nresult); |
| } |
| |
| /* check that the no-seed variant produces same result as seed==0 */ |
| if (seed == 0) { |
| XXH128_hash_t const Dresult = XXH3_128bits(data, len); |
| XSUM_checkResult128(Dresult, Nresult); |
| } |
| |
| /* check that the combination of |
| * XXH3_generateSecret_fromSeed() and XXH3_128bits_withSecretandSeed() |
| * results in exactly the same hash generation as XXH3_64bits_withSeed() */ |
| { char secretBuffer[XXH3_SECRET_DEFAULT_SIZE+1]; |
| char* const secret = secretBuffer + 1; /* intentional unalignment */ |
| XXH3_generateSecret_fromSeed(secret, seed); |
| { XXH128_hash_t const Dresult = XXH3_128bits_withSecretandSeed(data, len, secret, XXH3_SECRET_DEFAULT_SIZE, seed); |
| XSUM_checkResult128(Dresult, Nresult); |
| } |
| |
| /* check that XXH3_128bits_withSecretandSeed() |
| * results in exactly the same return value as XXH3_128bits_withSeed() |
| * if len <= XXH3_MIDSIZE_MAX, whatever the content of @secret */ |
| memset(secret, 0x99, 9); |
| if (len <= XXH3_MIDSIZE_MAX) { |
| XXH128_hash_t const Dresult = XXH3_128bits_withSecretandSeed(data, len, secret, XXH3_SECRET_DEFAULT_SIZE, seed); |
| XSUM_checkResult128(Dresult, Nresult); |
| } |
| } |
| |
| /* streaming API test */ |
| { XXH3_state_t *state = XXH3_createState(); |
| assert(state != NULL); |
| |
| /* single ingestion */ |
| (void)XXH3_128bits_reset_withSeed(state, seed); |
| (void)XXH3_128bits_update(state, data, len); |
| XSUM_checkResult128(XXH3_128bits_digest(state), Nresult); |
| |
| /* random ingestion */ |
| (void)XXH3_128bits_reset_withSeed(state, seed); |
| XSUM_XXH3_randomUpdate(state, data, len, XXH3_128bits_update); |
| XSUM_checkResult128(XXH3_128bits_digest(state), Nresult); |
| |
| /* byte by byte ingestion */ |
| { size_t pos; |
| (void)XXH3_128bits_reset_withSeed(state, seed); |
| for (pos=0; pos<len; pos++) |
| (void)XXH3_128bits_update(state, ((const char*)data)+pos, 1); |
| XSUM_checkResult128(XXH3_128bits_digest(state), Nresult); |
| } |
| |
| /* check that streaming with a combination of |
| * XXH3_generateSecret_fromSeed() and XXH3_128bits_reset_withSecretandSeed() |
| * results in exactly the same hash generation as XXH3_128bits_reset_withSeed() */ |
| { char secretBuffer[XXH3_SECRET_DEFAULT_SIZE+1]; |
| char* const secret = secretBuffer + 1; /* intentional unalignment */ |
| XXH3_generateSecret_fromSeed(secret, seed); |
| /* single ingestion */ |
| (void)XXH3_128bits_reset_withSecretandSeed(state, secret, XXH3_SECRET_DEFAULT_SIZE, seed); |
| (void)XXH3_128bits_update(state, data, len); |
| XSUM_checkResult128(XXH3_128bits_digest(state), Nresult); |
| |
| /* check that XXH3_128bits_reset_withSecretandSeed() |
| * results in exactly the same return value as XXH3_128bits_reset_withSeed() |
| * if len <= XXH3_MIDSIZE_MAX, whatever the content of @secret */ |
| if (len <= XXH3_MIDSIZE_MAX) { |
| /* single ingestion */ |
| memset(secret, 0x99, 9); |
| (void)XXH3_128bits_reset_withSecretandSeed(state, secret, XXH3_SECRET_DEFAULT_SIZE, seed); |
| (void)XXH3_128bits_update(state, data, len); |
| XSUM_checkResult128(XXH3_128bits_digest(state), Nresult); |
| } |
| } |
| |
| XXH3_freeState(state); |
| } |
| } |
| |
| static void XSUM_testXXH128_withSecret(const void* data, const void* secret, size_t secretSize, const XSUM_testdata128_t* testData) |
| { |
| size_t len = testData->len; |
| XXH128_hash_t Nresult = testData->Nresult; |
| if (len == 0) { |
| data = NULL; |
| } else { |
| assert(data != NULL); |
| } |
| { XXH128_hash_t const Dresult = XXH3_128bits_withSecret(data, len, secret, secretSize); |
| XSUM_checkResult128(Dresult, Nresult); |
| } |
| |
| /* check that XXH3_128bits_withSecretandSeed() |
| * results in exactly the same return value as XXH3_128bits_withSecret() */ |
| if (len > XXH3_MIDSIZE_MAX) |
| { XXH128_hash_t const Dresult = XXH3_128bits_withSecretandSeed(data, len, secret, secretSize, 0); |
| XSUM_checkResult128(Dresult, Nresult); |
| } |
| |
| /* streaming API test */ |
| { XXH3_state_t* const state = XXH3_createState(); |
| assert(state != NULL); |
| (void)XXH3_128bits_reset_withSecret(state, secret, secretSize); |
| (void)XXH3_128bits_update(state, data, len); |
| XSUM_checkResult128(XXH3_128bits_digest(state), Nresult); |
| |
| /* random ingestion */ |
| (void)XXH3_128bits_reset_withSecret(state, secret, secretSize); |
| XSUM_XXH3_randomUpdate(state, data, len, XXH3_128bits_update); |
| XSUM_checkResult128(XXH3_128bits_digest(state), Nresult); |
| |
| /* byte by byte ingestion */ |
| { size_t pos; |
| (void)XXH3_128bits_reset_withSecret(state, secret, secretSize); |
| for (pos=0; pos<len; pos++) |
| (void)XXH3_128bits_update(state, ((const char*)data)+pos, 1); |
| XSUM_checkResult128(XXH3_128bits_digest(state), Nresult); |
| } |
| |
| /* check that XXH3_128bits_reset_withSecretandSeed() |
| * results in exactly the same return value as XXH3_128bits_reset_withSecret() */ |
| if (len > XXH3_MIDSIZE_MAX) { |
| /* single ingestion */ |
| (void)XXH3_128bits_reset_withSecretandSeed(state, secret, secretSize, 0); |
| (void)XXH3_128bits_update(state, data, len); |
| XSUM_checkResult128(XXH3_128bits_digest(state), Nresult); |
| } |
| |
| XXH3_freeState(state); |
| } |
| } |
| |
| static void XSUM_testSecretGenerator(const void* customSeed, const XSUM_testdata_sample_t* testData) |
| { |
| static int nbTests = 1; |
| const int sampleIndex[SECRET_SAMPLE_NBBYTES] = { 0, 62, 131, 191, 241 }; /* position of sampled bytes */ |
| XSUM_U8 secretBuffer[SECRET_SIZE_MAX] = {0}; |
| XSUM_U8 samples[SECRET_SAMPLE_NBBYTES]; |
| int i; |
| |
| assert(testData->secretLen <= SECRET_SIZE_MAX); |
| XXH3_generateSecret(secretBuffer, testData->secretLen, customSeed, testData->seedLen); |
| for (i=0; i<SECRET_SAMPLE_NBBYTES; i++) { |
| samples[i] = secretBuffer[sampleIndex[i]]; |
| } |
| if (memcmp(samples, testData->byte, sizeof(testData->byte))) { |
| XSUM_log("\rError: Secret generation test %i: Internal sanity check failed. \n", nbTests); |
| XSUM_log("\rGot { 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X }, expected { 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X } \n", |
| samples[0], samples[1], samples[2], samples[3], samples[4], |
| testData->byte[0], testData->byte[1], testData->byte[2], testData->byte[3], testData->byte[4] ); |
| exit(1); |
| } |
| nbTests++; |
| } |
| |
| /*! |
| * XSUM_sanityCheck(): |
| * Runs a sanity check before the benchmark. |
| * |
| * Exits on an incorrect output. |
| */ |
| XSUM_API void XSUM_sanityCheck(void) |
| { |
| size_t i; |
| #define SANITY_BUFFER_SIZE 2367 |
| XSUM_U8 sanityBuffer[SANITY_BUFFER_SIZE]; |
| const void* const secret = sanityBuffer + 7; |
| const size_t secretSize = XXH3_SECRET_SIZE_MIN + 11; |
| assert(sizeof(sanityBuffer) >= 7 + secretSize); |
| |
| XSUM_fillTestBuffer(sanityBuffer, sizeof(sanityBuffer)); |
| |
| /* XXH32 */ |
| for (i = 0; i < (sizeof(XSUM_XXH32_testdata)/sizeof(XSUM_XXH32_testdata[0])); i++) { |
| XSUM_testXXH32(sanityBuffer, &XSUM_XXH32_testdata[i]); |
| } |
| /* XXH64 */ |
| for (i = 0; i < (sizeof(XSUM_XXH64_testdata)/sizeof(XSUM_XXH64_testdata[0])); i++) { |
| XSUM_testXXH64(sanityBuffer, &XSUM_XXH64_testdata[i]); |
| } |
| /* XXH3_64bits, seeded */ |
| for (i = 0; i < (sizeof(XSUM_XXH3_testdata)/sizeof(XSUM_XXH3_testdata[0])); i++) { |
| XSUM_testXXH3(sanityBuffer, &XSUM_XXH3_testdata[i]); |
| } |
| /* XXH3_64bits, custom secret */ |
| for (i = 0; i < (sizeof(XSUM_XXH3_withSecret_testdata)/sizeof(XSUM_XXH3_withSecret_testdata[0])); i++) { |
| XSUM_testXXH3_withSecret(sanityBuffer, secret, secretSize, &XSUM_XXH3_withSecret_testdata[i]); |
| } |
| /* XXH128 */ |
| for (i = 0; i < (sizeof(XSUM_XXH128_testdata)/sizeof(XSUM_XXH128_testdata[0])); i++) { |
| XSUM_testXXH128(sanityBuffer, &XSUM_XXH128_testdata[i]); |
| } |
| /* XXH128 with custom Secret */ |
| for (i = 0; i < (sizeof(XSUM_XXH128_withSecret_testdata)/sizeof(XSUM_XXH128_withSecret_testdata[0])); i++) { |
| XSUM_testXXH128_withSecret(sanityBuffer, secret, secretSize, &XSUM_XXH128_withSecret_testdata[i]); |
| } |
| /* secret generator */ |
| for (i = 0; i < (sizeof(XSUM_XXH3_generateSecret_testdata)/sizeof(XSUM_XXH3_generateSecret_testdata[0])); i++) { |
| assert(XSUM_XXH3_generateSecret_testdata[i].seedLen <= SANITY_BUFFER_SIZE); |
| XSUM_testSecretGenerator(sanityBuffer, &XSUM_XXH3_generateSecret_testdata[i]); |
| } |
| |
| XSUM_logVerbose(3, "\r%70s\r", ""); /* Clean display line */ |
| XSUM_logVerbose(3, "Sanity check -- all tests ok\n"); |
| } |
| |
| #endif /* !XSUM_NO_TESTS */ |