Skip to content

Commit

Permalink
Separete, also standalone make_secret helper
Browse files Browse the repository at this point in the history
  • Loading branch information
tansy committed Oct 5, 2023
1 parent f58bb2a commit 9f33c02
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 96 deletions.
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 */

0 comments on commit 9f33c02

Please sign in to comment.