Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separete or also standalone make_secret helper #140

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion makefile
Original file line number Diff line number Diff line change
@@ -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)

Expand All @@ -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)

99 changes: 4 additions & 95 deletions wyhash.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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{
Expand Down Expand Up @@ -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<s; r++) {
b=mul_mod(b,b,n);
if (b<=1) return 0;
if (b==(n-1)) return 1;
}
return 0;
}
unsigned is_prime(unsigned long long n) {
if (n<2||!(n&1)) return 0;
if (n<4) return 1;
if (!sprp(n,2)) return 0;
if (n<2047) return 1;
if (!sprp(n,3)) return 0;
if (!sprp(n,5)) return 0;
if (!sprp(n,7)) return 0;
if (!sprp(n,11)) return 0;
if (!sprp(n,13)) return 0;
if (!sprp(n,17)) return 0;
if (!sprp(n,19)) return 0;
if (!sprp(n,23)) return 0;
if (!sprp(n,29)) return 0;
if (!sprp(n,31)) return 0;
if (!sprp(n,37)) return 0;
return 1;
}
//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)])<<j;
if(secret[i]%2==0){ ok=0; continue; }
for(size_t j=0;j<i;j++) {
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
if(__builtin_popcountll(secret[j]^secret[i])!=32){ ok=0; break; }
#elif defined(_MSC_VER) && defined(_M_X64)
if(_mm_popcnt_u64(secret[j]^secret[i])!=32){ ok=0; break; }
#else
//manual popcount
uint64_t x = secret[j]^secret[i];
x -= (x >> 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
Expand Down
127 changes: 127 additions & 0 deletions wyhash_secret.h
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#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)])<<j;
if(secret[i]%2==0) {
ok=0;
continue;
}
for(size_t j=0;j<i;j++) {
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
if(__builtin_popcountll(secret[j]^secret[i])!=32) {
ok=0;
break;
}
#elif defined(_MSC_VER) && defined(_M_X64)
if(_mm_popcnt_u64(secret[j]^secret[i])!=32){
ok=0;
break;
}
#else
//manual popcount
uint64_t x = secret[j]^secret[i];
x -= (x >> 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 <number>\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 */