diff --git a/makefile b/makefile index 023f59c..29c087f 100644 --- a/makefile +++ b/makefile @@ -1,9 +1,11 @@ # wyhash bench makefile +CC = gcc +CFLAGS = -O2 -s -Wall CXX = g++ CXXFLAGS = -std=c++11 -O2 -s -Wall -march=native -TARGETS = test_vector wyhash0 wyhash1 wyhash2 xxh3scalar xxh3sse2 xxh3avx2 +TARGETS = test_vector wyhash0 wyhash1 wyhash2 xxh3scalar xxh3sse2 xxh3avx2 wyhash_secret all: $(TARGETS) @@ -28,6 +30,9 @@ xxh3sse2: benchmark.cpp xxh3avx2: benchmark.cpp $(CXX) benchmark.cpp -o xxh3avx2 $(CXXFLAGS) -DXXH_VECTOR=2 -DXXH3 +wyhash_secret: wyhash_secret.h wyhash.h + $(CC) -xc $(CFLAGS) -DWYHASH_SECRET_TESTX wyhash_secret.h -o wyhash_secret + clean: rm $(TARGETS) diff --git a/wyhash.h b/wyhash.h index f066782..9722bc0 100644 --- a/wyhash.h +++ b/wyhash.h @@ -21,7 +21,7 @@ #ifndef WYHASH_32BIT_MUM //0: normal version, slow on 32 bit systems //1: faster on 32 bit systems but produces different results, incompatible with wy2u0k function -#define WYHASH_32BIT_MUM 0 +#define WYHASH_32BIT_MUM 0 #endif //includes @@ -52,7 +52,7 @@ static inline void _wymum(uint64_t *A, uint64_t *B){ *A=_wyrot(hl)^hh; *B=_wyrot(lh)^ll; #endif #elif defined(__SIZEOF_INT128__) - __uint128_t r=*A; r*=*B; + __uint128_t r=*A; r*=*B; #if(WYHASH_CONDOM>1) *A^=(uint64_t)r; *B^=(uint64_t)(r>>64); #else @@ -116,14 +116,14 @@ static inline uint64_t _wyr4(const uint8_t *p) { static inline uint64_t _wyr3(const uint8_t *p, size_t k) { return (((uint64_t)p[0])<<16)|(((uint64_t)p[k>>1])<<8)|p[k-1];} //wyhash main function static inline uint64_t wyhash(const void *key, size_t len, uint64_t seed, const uint64_t *secret){ - const uint8_t *p=(const uint8_t *)key; seed^=_wymix(seed^secret[0],secret[1]); uint64_t a, b; + const uint8_t *p=(const uint8_t *)key; seed^=_wymix(seed^secret[0],secret[1]); uint64_t a, b; if(_likely_(len<=16)){ if(_likely_(len>=4)){ a=(_wyr4(p)<<32)|_wyr4(p+((len>>3)<<2)); b=(_wyr4(p+len-4)<<32)|_wyr4(p+len-4-((len>>3)<<2)); } else if(_likely_(len>0)){ a=_wyr3(p,len); b=0;} else a=b=0; } else{ - size_t i=len; + size_t i=len; if(_unlikely_(i>=48)){ uint64_t see1=seed, see2=seed; do{ @@ -173,97 +173,6 @@ static inline uint64_t wytrand(uint64_t *seed){ static inline uint64_t wy2u0k(uint64_t r, uint64_t k){ _wymum(&r,&k); return k; } #endif -// modified from https://github.com/going-digital/Prime64 -static inline unsigned long long mul_mod(unsigned long long a, unsigned long long b, unsigned long long m) { - unsigned long long r=0; - while (b) { - if (b & 1) { - unsigned long long r2 = r + a; - if (r2 < r) r2 -= m; - r = r2 % m; - } - b >>= 1; - if (b) { - unsigned long long a2 = a + a; - if (a2 < a) a2 -= m; - a = a2 % m; - } - } - return r; -} -static inline unsigned long long pow_mod(unsigned long long a, unsigned long long b, unsigned long long m) { - unsigned long long r=1; - while (b) { - if (b&1) r=mul_mod(r,a,m); - b>>=1; - if (b) a=mul_mod(a,a,m); - } - return r; -} -unsigned sprp(unsigned long long n, unsigned long long a) { - unsigned long long d=n-1; - unsigned char s=0; - while (!(d & 0xff)) { d>>=8; s+=8; } - if (!(d & 0xf)) { d>>=4; s+=4; } - if (!(d & 0x3)) { d>>=2; s+=2; } - if (!(d & 0x1)) { d>>=1; s+=1; } - unsigned long long b=pow_mod(a,d,n); - if ((b==1) || (b==(n-1))) return 1; - unsigned char r; - for (r=1; r> 1) & 0x5555555555555555; - x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); - x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f; - x = (x * 0x0101010101010101) >> 56; - if(x!=32){ ok=0; break; } -#endif - } - if(ok&&!is_prime(secret[i])) ok=0; - }while(!ok); - } -} - #endif /* The Unlicense diff --git a/wyhash_secret.h b/wyhash_secret.h new file mode 100644 index 0000000..b903963 --- /dev/null +++ b/wyhash_secret.h @@ -0,0 +1,127 @@ +// This is free and unencumbered software released into the public domain under The Unlicense (http://unlicense.org/) +// main repo: https://github.com/wangyi-fudan/wyhash +// This is a helper file for wyhash that can generate whole new secret (set of unique, primal seeds). +// Can be included with `#include wyhash_secret.h`. +// Can be compiled as standalone executable with definition of `WYHASH_SECRET_TESTX` and forcing C-lang form compiler (`cc -cx`). + +#include +#include +#include +#include +#include "wyhash.h" + +#ifndef wyhash_secret_standal1 +#define wyhash_secret_standal1 + +// Miller-Rabin primality test from https://rosettacode.org/wiki/Miller%E2%80%93Rabin_primality_test#C +static uint64_t mul_mod(uint64_t a, uint64_t b, const uint64_t mod) +{ + uint64_t res = 0, c; // return (a * b) % mod, avoiding overflow errors while doing modular multiplication. + for (b %= mod; a; a & 1 ? b >= mod - res ? res -= mod : 0, res += b : 0, a >>= 1, (c = b) >= mod - b ? c -= mod : 0, b += c); + return res % mod; +} + +static uint64_t pow_mod(uint64_t n, uint64_t exp, const uint64_t mod) +{ + uint64_t res = 1; // return (n ^ exp) % mod + for (n %= mod; exp; exp & 1 ? res = mul_mod(res, n, mod) : 0, n = mul_mod(n, n, mod), exp >>= 1); + return res; +} + +static int is_prime_mr(uint64_t N) +{ + // Perform a Miller-Rabin test, it should be a deterministic version. + const uint64_t n_primes = 9, primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23}; + for (uint64_t i = 0; i < n_primes; ++i) + if (N % primes[i] == 0) + return N == primes[i]; + if (N < primes[n_primes - 1]) + return 0; + int res = 1, s = 0; + uint64_t t; + for (t = N - 1; ~t & 1; t >>= 1, ++s); + for (uint64_t i = 0; i < n_primes && res; ++i) + { + uint64_t B = pow_mod(primes[i], t, N); + if (B != 1) { + for (int b = s; b-- && (res = B + 1 != N);) + B = mul_mod(B, B, N); + res = !res; + } + } + return res; +} + +//make your own secret +static inline void make_secret(uint64_t seed, uint64_t *secret){ + uint8_t c[] = {15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 53, 54, 57, 58, 60, 71, 75, 77, 78, 83, 85, 86, 89, 90, 92, 99, 101, 102, 105, 106, 108, 113, 114, 116, 120, 135, 139, 141, 142, 147, 149, 150, 153, 154, 156, 163, 165, 166, 169, 170, 172, 177, 178, 180, 184, 195, 197, 198, 201, 202, 204, 209, 210, 212, 216, 225, 226, 228, 232, 240 }; + for(size_t i=0;i<4;i++) { + uint8_t ok; + do { + ok=1; + secret[i]=0; + for(size_t j=0;j<64;j+=8) + secret[i]|=((uint64_t)c[wyrand(&seed)%sizeof(c)])<> 1) & 0x5555555555555555; + x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); + x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f; + x = (x * 0x0101010101010101) >> 56; + if(x!=32) { + ok=0; + break; + } +#endif + } + if(ok) + if(!is_prime_mr(secret[i])) + ok=0; + } while(!ok); + } +} + +#ifdef WYHASH_SECRET_TESTX +int main(int argc, char* argv[]) +{ + uint64_t secret5[5]; + uint64_t ix, i; + if(argc<2) + { + printf("wyhash make secret with 'seed' (integer)\n" + "usage:\n" + "%s \n", argv[0]); + return 0; + } + else + { + ix = strtoull(argv[1], NULL, 0); + printf("seed=%llu (0x%016llx)\n", ix, ix); + make_secret(ix, secret5); + printf("secret:\n"); + for(i=0; i<5; i++) + { + printf("0x%016llx\n", secret5[i]); + } + } + return 0; +} +#endif /* WYHASH_SECRET_TESTX */ + +#endif /* wyhash_secret_standal1 */