From 9f33c02920cb6cb7e65e53630684127f576edf8e Mon Sep 17 00:00:00 2001
From: tansy <wrotycz@wir.pl>
Date: Thu, 5 Oct 2023 20:20:37 +0000
Subject: [PATCH] Separete, also standalone make_secret helper

---
 makefile        |   7 ++-
 wyhash.h        |  99 ++-----------------------------------
 wyhash_secret.h | 127 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 137 insertions(+), 96 deletions(-)
 create mode 100644 wyhash_secret.h

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<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
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 <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 */