summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortanjent@gmail.com <tanjent@gmail.com@77a7d1d3-4c08-bdc2-d393-d5859734b01a>2010-11-02 00:50:04 +0000
committertanjent@gmail.com <tanjent@gmail.com@77a7d1d3-4c08-bdc2-d393-d5859734b01a>2010-11-02 00:50:04 +0000
commit7e5c363a6f2ae202b928097bd3a1936db46df1b9 (patch)
treef780f37fae2211ec8edefe7b3bbdfa04424751ff
parentb5082b0d1cb91eabc73e91d6db5b5c5035bdbad6 (diff)
downloadsrc-7e5c363a6f2ae202b928097bd3a1936db46df1b9.tar.gz
Initial source checkin
git-svn-id: http://smhasher.googlecode.com/svn/trunk@2 77a7d1d3-4c08-bdc2-d393-d5859734b01a
-rw-r--r--AvalancheTest.cpp273
-rw-r--r--AvalancheTest.h8
-rw-r--r--Bitvec.cpp741
-rw-r--r--Bitvec.h185
-rw-r--r--BlockCipher.cpp294
-rw-r--r--BlockCipher.h90
-rw-r--r--Cipher.cpp1
-rw-r--r--Cipher.h16
-rw-r--r--Core.cpp186
-rw-r--r--Core.h15
-rw-r--r--CycleTest.cpp1
-rw-r--r--CycleTest.h45
-rw-r--r--DictionaryTest.cpp61
-rw-r--r--DictionaryTest.h119
-rw-r--r--DifferentialTest.cpp3
-rw-r--r--DifferentialTest.h202
-rw-r--r--Diffusion.cpp204
-rw-r--r--Diffusion.h1
-rw-r--r--FWTransform.cpp443
-rw-r--r--FWTransform.h12
-rw-r--r--Hamming.cpp133
-rw-r--r--Hamming.h5
-rw-r--r--Hashes.cpp114
-rw-r--r--Hashes.h35
-rw-r--r--Junk.cpp38
-rw-r--r--Junk.h46
-rw-r--r--MurmurHash1.cpp171
-rw-r--r--MurmurHash1.h8
-rw-r--r--MurmurHash2.cpp502
-rw-r--r--MurmurHash2.h13
-rw-r--r--MurmurHash2_test.cpp0
-rw-r--r--MurmurHash3.cpp288
-rw-r--r--MurmurHash3.h11
-rw-r--r--MurmurHash64.cpp0
-rw-r--r--MurmurHashAligned.cpp2
-rw-r--r--MurmurHashAligned2.cpp4
-rw-r--r--MurmurHashNeutral2.cpp2
-rw-r--r--MurmurHashTest.cpp26
-rw-r--r--Random.cpp61
-rw-r--r--Random.h144
-rw-r--r--SimAnneal.cpp97
-rw-r--r--SimAnneal.h6
-rw-r--r--SparseKeyTest.cpp111
-rw-r--r--SparseKeyTest.h89
-rw-r--r--Stats.cpp338
-rw-r--r--Stats.h559
-rw-r--r--StreamCipher.cpp13
-rw-r--r--StreamCipher.h17
-rw-r--r--SuperFastHash.cpp68
-rw-r--r--TEA.cpp52
-rw-r--r--TEA.h23
-rw-r--r--Tests.cpp542
-rw-r--r--Tests.h195
-rw-r--r--Types.cpp17
-rw-r--r--Types.h449
-rw-r--r--XTEA.cpp119
-rw-r--r--XTEA.h23
-rw-r--r--crc.cpp101
-rw-r--r--crc.h77
-rw-r--r--lookup3.cpp72
-rw-r--r--main.cpp104
-rw-r--r--md5.cpp382
-rw-r--r--pstdint.h799
-rw-r--r--scratch.cpp823
-rw-r--r--sha1.cpp603
-rw-r--r--sha1.h89
-rw-r--r--simplex.cpp171
67 files changed, 10442 insertions, 0 deletions
diff --git a/AvalancheTest.cpp b/AvalancheTest.cpp
new file mode 100644
index 0000000..25ee86c
--- /dev/null
+++ b/AvalancheTest.cpp
@@ -0,0 +1,273 @@
+//-----------------------------------------------------------------------------
+// Flipping a single bit of a key should cause an "avalanche" of changes in
+// the hash function's output. Ideally, each output bits should flip 50% of
+// the time - if the probability of an output bit flipping is not 50%, that bit
+// is "biased". Too much bias means that patterns applied to the input will
+// cause "echoes" of the patterns in the output, which in turn can cause the
+// hash function to fail to create an even, random distribution of hash values.
+
+#include "AvalancheTest.h"
+
+#include "Bitvec.h"
+#include "Random.h"
+
+#include <math.h>
+
+// Avalanche fails if a bit is biased by more than 1%
+
+double gc_avalancheFail = 0.01;
+
+//-----------------------------------------------------------------------------
+
+void PrintAvalancheDiagram ( int x, int y, int reps, double scale, int * bins )
+{
+ const char * symbols = ".123456789X";
+
+ for(int i = 0; i < y; i++)
+ {
+ printf("[");
+ for(int j = 0; j < x; j++)
+ {
+ int k = (y - i) -1;
+
+ int bin = bins[k + (j*y)];
+
+ double b = double(bin) / double(reps);
+ b = fabs(b*2 - 1);
+
+ b *= scale;
+
+ int s = (int)floor(b*10);
+
+ if(s > 10) s = 10;
+ if(s < 0) s = 0;
+
+ printf("%c",symbols[s]);
+ }
+
+ printf("]\n");
+ }
+}
+
+//----------------------------------------------------------------------------
+
+double maxBias ( std::vector<int> & counts, int reps )
+{
+ double worst = 0;
+
+ for(int i = 0; i < (int)counts.size(); i++)
+ {
+ double c = double(counts[i]) / double(reps);
+
+ double d = fabs(c * 2 - 1);
+
+ if(d > worst)
+ {
+ worst = d;
+ }
+ }
+
+ return worst;
+}
+
+double rmsBias ( std::vector<int> & counts, int reps )
+{
+ double rms = 0;
+
+ for(int i = 0; i < (int)counts.size(); i++)
+ {
+ double d = double(counts[i]) / reps;
+
+ d = fabs(d * 2 - 1);
+
+ rms += d*d;
+ }
+
+ rms /= counts.size();
+ rms = sqrt(rms);
+
+ return rms;
+}
+
+//-----------------------------------------------------------------------------
+
+void calcBias ( pfHash hash, const int nbitsIn, const int nbitsOut, std::vector<int> & counts, int reps )
+{
+ const int nbytesIn = nbitsIn / 8;
+ const int nbytesOut = nbitsOut / 8;
+
+ uint8_t * K = new uint8_t[nbytesIn];
+ uint8_t * A = new uint8_t[nbytesIn];
+ uint8_t * B = new uint8_t[nbytesIn];
+
+ Rand r(378473);
+
+ for(int irep = 0; irep < reps; irep++)
+ {
+ r.rand_p(K,nbytesIn);
+
+ hash(K,nbytesIn,0,A);
+
+ int * cursor = &counts[0];
+
+ for(int iBit = 0; iBit < nbitsIn; iBit++)
+ {
+ flipbit(K,nbytesIn,iBit);
+ hash(K,nbytesIn,0,B);
+ flipbit(K,nbytesIn,iBit);
+
+ for(int iOut = 0; iOut < nbitsOut; iOut++)
+ {
+ int bitA = getbit(A,nbytesOut,iOut);
+ int bitB = getbit(B,nbytesOut,iOut);
+
+ (*cursor++) += (bitA ^ bitB);
+ }
+ }
+ }
+
+ delete [] K;
+ delete [] A;
+ delete [] B;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AvalancheTest ( pfHash hash, const int keybits, const int hashbits, const int reps )
+{
+ printf("Avalanche for %3d-bit keys -> %3d-bit hashes, %8d reps - ",keybits,hashbits,reps);
+
+ std::vector<int> bins(keybits*hashbits,0);
+
+ calcBias(hash,keybits,hashbits,bins,reps);
+
+ double b = maxBias(bins,reps);
+
+ printf("Max avalanche bias is %f\n",b);
+
+ if(b > gc_avalancheFail)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+//----------------------------------------------------------------------------
+// Computing whether a given mix function produces a low bias can take many
+// millions of tests when the bias is low. This code tries to speed up the
+// process by early-outing if the probability that the bias will fall outside
+// the given range is over 99%
+
+/*
+bool testMixAvalanche32_Fast ( pfMix32 mix, double cutmin, double cutmax, bool winlose )
+{
+ int counts[32*32];
+
+ memset(counts,0,sizeof(counts));
+
+ double pmin = 0;
+ double pmax = 0;
+ double n = 0;
+ double s = 4.75;
+ int w = 0;
+
+ int batchsize = 512;
+
+ for(int iBatch = 0; iBatch < 1024 * 1024; iBatch++)
+ {
+ calcMixBias<uint32_t>(mix,counts,batchsize);
+
+ n = (iBatch+1) * batchsize;
+ w = maxIntBias(32,32,counts,(int)n);
+
+ // compute p such that w is at the bottom of the confidence interval
+
+ double a = s*s*n + n*n;
+ double b = -2.0*double(w)*n - s*s*n;
+ double c = double(w)*double(w);
+
+ SolveQuadratic(a,b,c,pmin,pmax);
+
+ double win = 0;
+ double tie = 0;
+ double lose = 0;
+
+ if(winlose)
+ {
+ if(pmax < cutmax)
+ {
+ printf("\n+!!! %f - %f : %f - %d\n",double(w)/n,pmin,pmax,int(n));
+ return true;
+ }
+
+ if(pmin > cutmax)
+ {
+ //printf("\n-!!! %f - %f : %f - %d\n",double(w)/n,pmin,pmax,int(n));
+ return false;
+ }
+
+ // doesn't fail or win outright. does it have a chance of winning?
+
+ if(pmin < cutmin)
+ {
+ // pmin:pmax contains cutmin:cutmax
+
+ assert(cutmin > pmin);
+ assert(cutmax < pmax);
+
+ win = (cutmin-pmin) / (pmax-pmin);
+ tie = (cutmax-cutmin) / (pmax-pmin);
+ lose = (pmax-cutmax) / (pmax-pmin);
+ }
+ else
+ {
+ // pmin:pmax overlaps above cutmin:cutmax
+
+ assert(cutmin < pmin);
+
+ win = 0;
+ tie = ((cutmax - pmin) / (pmax-pmin)) * ((cutmax-pmin) / (cutmax-cutmin));
+ lose = (pmax-cutmax) / (pmax-pmin);
+
+ return false;
+ }
+
+ double frac = win + tie*0.5;
+
+ if((pmax-pmin)/(cutmax-cutmin) < 5)
+ {
+ if(frac < 0.20)
+ {
+ // 99% chance of loss
+ //printf("\n--- %f - %f : %f - %d\n",double(w)/n,pmin,pmax,int(n));
+ return false;
+ }
+
+ if(frac > 0.80)
+ {
+ // 99% chance of win
+ printf("\n+++ %f - %f : %f - %d\n",double(w)/n,pmin,pmax,int(n));
+ return true;
+ }
+ }
+ }
+
+ if(!winlose && (n > 0) && ((int)n % (128 * 1024) == 0))
+ {
+ printf("%f - %f : %f - %d - %f : %f : %f\n",double(w)/n,pmin,pmax,int(n),win,tie,lose);
+ }
+
+ }
+
+ // We failed to determine whether this mix function passes or fails
+
+ printf("\n??? %f - %f : %f",double(w)/n,pmin,pmax);
+
+ return true;
+}
+*/
+
+//-----------------------------------------------------------------------------
diff --git a/AvalancheTest.h b/AvalancheTest.h
new file mode 100644
index 0000000..88a0bc1
--- /dev/null
+++ b/AvalancheTest.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "Types.h"
+
+double maxBias ( std::vector<int> & counts, int reps );
+double rmsBias ( std::vector<int> & counts, int reps );
+
+bool AvalancheTest ( pfHash hash, const int keybits, const int hashbits, const int reps );
diff --git a/Bitvec.cpp b/Bitvec.cpp
new file mode 100644
index 0000000..07ac815
--- /dev/null
+++ b/Bitvec.cpp
@@ -0,0 +1,741 @@
+#include "Bitvec.h"
+
+#include "Random.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#ifndef DEBUG
+#undef assert
+void assert ( bool )
+{
+}
+#endif
+
+//----------------------------------------------------------------------------
+
+void printbits ( void * blob, int len )
+{
+ uint8_t * data = (uint8_t*)blob;
+
+ printf("[");
+ for(int i = 0; i < len; i++)
+ {
+ unsigned char byte = data[i];
+
+ int hi = (byte >> 4);
+ int lo = (byte & 0xF);
+
+ if(hi) printf("%01x",hi);
+ else printf(".");
+
+ if(lo) printf("%01x",lo);
+ else printf(".");
+
+ if(i != len-1) printf(" ");
+ }
+ printf("]");
+}
+
+void printbits2 ( uint8_t * k, int nbytes )
+{
+ printf("[");
+
+ for(int i = nbytes-1; i >= 0; i--)
+ {
+ uint8_t b = k[i];
+
+ for(int j = 7; j >= 0; j--)
+ {
+ uint8_t c = (b & (1 << j)) ? '#' : ' ';
+
+ putc(c,stdout);
+ }
+ }
+ printf("]");
+}
+
+void printhex32 ( void * blob, int len )
+{
+ assert((len & 3) == 0);
+
+ uint32_t * d = (uint32_t*)blob;
+
+ printf("{ ");
+
+ for(int i = 0; i < len/4; i++)
+ {
+ printf("0x%08x, ",d[i]);
+ }
+
+ printf("}");
+}
+
+
+//-----------------------------------------------------------------------------
+// Bit-level manipulation
+
+// These are from the "Bit Twiddling Hacks" webpage
+
+uint32_t popcount ( uint32_t v )
+{
+ v = v - ((v >> 1) & 0x55555555); // reuse input as temporary
+ v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp
+ uint32_t c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
+
+ return c;
+}
+
+uint32_t popcount128 ( uint32_t * v )
+{
+ uint32_t c = popcount(v[0]);
+
+ c += popcount(v[1]);
+ c += popcount(v[2]);
+ c += popcount(v[3]);
+
+ return c;
+}
+
+uint32_t parity ( uint32_t v )
+{
+ v ^= v >> 16;
+ v ^= v >> 8;
+ v ^= v >> 4;
+ v &= 0xf;
+
+ return (0x6996 >> v) & 1;
+}
+
+uint64_t parity ( uint64_t v )
+{
+ v ^= v >> 32;
+ v ^= v >> 16;
+ v ^= v >> 8;
+ v ^= v >> 4;
+ v &= 0xf;
+
+ return (0x6996 >> v) & 1;
+}
+
+//-----------------------------------------------------------------------------
+
+uint32_t getbit ( void * block, int len, uint32_t bit )
+{
+ uint8_t * b = (uint8_t*)block;
+
+ int byte = bit >> 3;
+ bit = bit & 0x7;
+
+ if(byte < len) return (b[byte] >> bit) & 1;
+
+ return 0;
+}
+
+uint32_t getbit_wrap ( void * block, int len, uint32_t bit )
+{
+ uint8_t * b = (uint8_t*)block;
+
+ int byte = bit >> 3;
+ bit = bit & 0x7;
+
+ byte %= len;
+
+ return (b[byte] >> bit) & 1;
+}
+
+void setbit ( void * block, int len, uint32_t bit )
+{
+ uint8_t * b = (uint8_t*)block;
+
+ int byte = bit >> 3;
+ bit = bit & 0x7;
+
+ if(byte < len) b[byte] |= (1 << bit);
+}
+
+void setbit ( void * block, int len, uint32_t bit, uint32_t val )
+{
+ val ? setbit(block,len,bit) : clearbit(block,len,bit);
+}
+
+void clearbit ( void * block, int len, uint32_t bit )
+{
+ uint8_t * b = (uint8_t*)block;
+
+ int byte = bit >> 3;
+ bit = bit & 0x7;
+
+ if(byte < len) b[byte] &= ~(1 << bit);
+}
+
+void flipbit ( void * block, int len, uint32_t bit )
+{
+ uint8_t * b = (uint8_t*)block;
+
+ int byte = bit >> 3;
+ bit = bit & 0x7;
+
+ if(byte < len) b[byte] ^= (1 << bit);
+}
+
+//-----------------------------------------------------------------------------
+
+void lshift1 ( void * blob, int len, int c )
+{
+ int nbits = len*8;
+
+ for(int i = nbits-1; i >= 0; i--)
+ {
+ setbit(blob,len,i,getbit(blob,len,i-c));
+ }
+}
+
+
+void lshift8 ( void * blob, int nbytes, int c )
+{
+ uint8_t * k = (uint8_t*)blob;
+
+ if(c == 0) return;
+
+ int b = c >> 3;
+ c &= 7;
+
+ for(int i = nbytes-1; i >= b; i--)
+ {
+ k[i] = k[i-b];
+ }
+
+ for(int i = b-1; i >= 0; i--)
+ {
+ k[i] = 0;
+ }
+
+ if(c == 0) return;
+
+ for(int i = nbytes-1; i >= 0; i--)
+ {
+ uint8_t a = k[i];
+ uint8_t b = (i == 0) ? 0 : k[i-1];
+
+ k[i] = (a << c) | (b >> (8-c));
+ }
+}
+
+void lshift32 ( void * blob, int len, int c )
+{
+ assert((len & 3) == 0);
+
+ int nbytes = len;
+ int ndwords = nbytes / 4;
+
+ uint32_t * k = (uint32_t*)blob;
+
+ if(c == 0) return;
+
+ //----------
+
+ int b = c / 32;
+ c &= (32-1);
+
+ for(int i = ndwords-1; i >= b; i--)
+ {
+ k[i] = k[i-b];
+ }
+
+ for(int i = b-1; i >= 0; i--)
+ {
+ k[i] = 0;
+ }
+
+ if(c == 0) return;
+
+ for(int i = ndwords-1; i >= 0; i--)
+ {
+ uint32_t a = k[i];
+ uint32_t b = (i == 0) ? 0 : k[i-1];
+
+ k[i] = (a << c) | (b >> (32-c));
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void rshift1 ( void * blob, int len, int c )
+{
+ int nbits = len*8;
+
+ for(int i = 0; i < nbits; i++)
+ {
+ setbit(blob,len,i,getbit(blob,len,i+c));
+ }
+}
+
+void rshift8 ( void * blob, int nbytes, int c )
+{
+ uint8_t * k = (uint8_t*)blob;
+
+ if(c == 0) return;
+
+ int b = c >> 3;
+ c &= 7;
+
+ for(int i = 0; i < nbytes-b; i++)
+ {
+ k[i] = k[i+b];
+ }
+
+ for(int i = nbytes-b; i < nbytes; i++)
+ {
+ k[i] = 0;
+ }
+
+ if(c == 0) return;
+
+ for(int i = 0; i < nbytes; i++)
+ {
+ uint8_t a = (i == nbytes-1) ? 0 : k[i+1];
+ uint8_t b = k[i];
+
+ k[i] = (a << (8-c) ) | (b >> c);
+ }
+}
+
+void rshift32 ( void * blob, int len, int c )
+{
+ assert((len & 3) == 0);
+
+ int nbytes = len;
+ int ndwords = nbytes / 4;
+
+ uint32_t * k = (uint32_t*)blob;
+
+ //----------
+
+ if(c == 0) return;
+
+ int b = c / 32;
+ c &= (32-1);
+
+ for(int i = 0; i < ndwords-b; i++)
+ {
+ k[i] = k[i+b];
+ }
+
+ for(int i = ndwords-b; i < ndwords; i++)
+ {
+ k[i] = 0;
+ }
+
+ if(c == 0) return;
+
+ for(int i = 0; i < ndwords; i++)
+ {
+ uint32_t a = (i == ndwords-1) ? 0 : k[i+1];
+ uint32_t b = k[i];
+
+ k[i] = (a << (32-c) ) | (b >> c);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void lrot1 ( void * blob, int len, int c )
+{
+ int nbits = len * 8;
+
+ for(int i = 0; i < c; i++)
+ {
+ uint32_t bit = getbit(blob,len,nbits-1);
+
+ lshift1(blob,len,1);
+
+ setbit(blob,len,0,bit);
+ }
+}
+
+void lrot8 ( void * blob, int len, int c )
+{
+ int nbytes = len;
+
+ uint8_t * k = (uint8_t*)blob;
+
+ if(c == 0) return;
+
+ //----------
+
+ int b = c / 8;
+ c &= (8-1);
+
+ for(int j = 0; j < b; j++)
+ {
+ uint8_t t = k[nbytes-1];
+
+ for(int i = nbytes-1; i > 0; i--)
+ {
+ k[i] = k[i-1];
+ }
+
+ k[0] = t;
+ }
+
+ uint8_t t = k[nbytes-1];
+
+ if(c == 0) return;
+
+ for(int i = nbytes-1; i >= 0; i--)
+ {
+ uint8_t a = k[i];
+ uint8_t b = (i == 0) ? t : k[i-1];
+
+ k[i] = (a << c) | (b >> (8-c));
+ }
+}
+
+void lrot32 ( void * blob, int len, int c )
+{
+ assert((len & 3) == 0);
+
+ int nbytes = len;
+ int ndwords = nbytes/4;
+
+ uint32_t * k = (uint32_t*)blob;
+
+ if(c == 0) return;
+
+ //----------
+
+ int b = c / 32;
+ c &= (32-1);
+
+ for(int j = 0; j < b; j++)
+ {
+ uint32_t t = k[ndwords-1];
+
+ for(int i = ndwords-1; i > 0; i--)
+ {
+ k[i] = k[i-1];
+ }
+
+ k[0] = t;
+ }
+
+ uint32_t t = k[ndwords-1];
+
+ if(c == 0) return;
+
+ for(int i = ndwords-1; i >= 0; i--)
+ {
+ uint32_t a = k[i];
+ uint32_t b = (i == 0) ? t : k[i-1];
+
+ k[i] = (a << c) | (b >> (32-c));
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void rrot1 ( void * blob, int len, int c )
+{
+ int nbits = len * 8;
+
+ for(int i = 0; i < c; i++)
+ {
+ uint32_t bit = getbit(blob,len,0);
+
+ rshift1(blob,len,1);
+
+ setbit(blob,len,nbits-1,bit);
+ }
+}
+
+void rrot8 ( void * blob, int len, int c )
+{
+ int nbytes = len;
+
+ uint8_t * k = (uint8_t*)blob;
+
+ if(c == 0) return;
+
+ //----------
+
+ int b = c / 8;
+ c &= (8-1);
+
+ for(int j = 0; j < b; j++)
+ {
+ uint8_t t = k[0];
+
+ for(int i = 0; i < nbytes-1; i++)
+ {
+ k[i] = k[i+1];
+ }
+
+ k[nbytes-1] = t;
+ }
+
+ if(c == 0) return;
+
+ //----------
+
+ uint8_t t = k[0];
+
+ for(int i = 0; i < nbytes; i++)
+ {
+ uint8_t a = (i == nbytes-1) ? t : k[i+1];
+ uint8_t b = k[i];
+
+ k[i] = (a << (8-c)) | (b >> c);
+ }
+}
+
+void rrot32 ( void * blob, int len, int c )
+{
+ assert((len & 3) == 0);
+
+ int nbytes = len;
+ int ndwords = nbytes/4;
+
+ uint32_t * k = (uint32_t*)blob;
+
+ if(c == 0) return;
+
+ //----------
+
+ int b = c / 32;
+ c &= (32-1);
+
+ for(int j = 0; j < b; j++)
+ {
+ uint32_t t = k[0];
+
+ for(int i = 0; i < ndwords-1; i++)
+ {
+ k[i] = k[i+1];
+ }
+
+ k[ndwords-1] = t;
+ }
+
+ if(c == 0) return;
+
+ //----------
+
+ uint32_t t = k[0];
+
+ for(int i = 0; i < ndwords; i++)
+ {
+ uint32_t a = (i == ndwords-1) ? t : k[i+1];
+ uint32_t b = k[i];
+
+ k[i] = (a << (32-c)) | (b >> c);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+uint32_t window1 ( void * blob, int len, int start, int count )
+{
+ int nbits = len*8;
+ start %= nbits;
+
+ uint32_t t = 0;
+
+ for(int i = 0; i < count; i++)
+ {
+ setbit(&t,sizeof(t),i, getbit_wrap(blob,len,start+i));
+ }
+
+ return t;
+}
+
+uint32_t window8 ( void * blob, int len, int start, int count )
+{
+ int nbits = len*8;
+ start %= nbits;
+
+ uint32_t t = 0;
+ uint8_t * k = (uint8_t*)blob;
+
+ if(count == 0) return 0;
+
+ int c = start & (8-1);
+ int d = start / 8;
+
+ for(int i = 0; i < 4; i++)
+ {
+ int ia = (i + d + 1) % len;
+ int ib = (i + d + 0) % len;
+
+ uint32_t a = k[ia];
+ uint32_t b = k[ib];
+
+ uint32_t m = (a << (8-c)) | (b >> c);
+
+ t |= (m << (8*i));
+
+ }
+
+ t &= ((1 << count)-1);
+
+ return t;
+}
+
+uint32_t window32 ( void * blob, int len, int start, int count )
+{
+ int nbits = len*8;
+ start %= nbits;
+
+ assert((len & 3) == 0);
+
+ int ndwords = len / 4;
+
+ uint32_t * k = (uint32_t*)blob;
+
+ if(count == 0) return 0;
+
+ int c = start & (32-1);
+ int d = start / 32;
+
+ if(c == 0) return (k[d] & ((1 << count) - 1));
+
+ int ia = (d + 1) % ndwords;
+ int ib = (d + 0) % ndwords;
+
+ uint32_t a = k[ia];
+ uint32_t b = k[ib];
+
+ uint32_t t = (a << (32-c)) | (b >> c);
+
+ t &= ((1 << count)-1);
+
+ return t;
+}
+
+//-----------------------------------------------------------------------------
+
+bool test_shift ( void )
+{
+ int nbits = 64;
+ int nbytes = nbits / 8;
+ int reps = 10000;
+
+ for(int j = 0; j < reps; j++)
+ {
+ if(j % (reps/10) == 0) printf(".");
+
+ uint64_t a = rand_u64();
+ uint64_t b;
+
+ for(int i = 0; i < nbits; i++)
+ {
+ b = a; lshift1 (&b,nbytes,i); assert(b == (a << i));
+ b = a; lshift8 (&b,nbytes,i); assert(b == (a << i));
+ b = a; lshift32 (&b,nbytes,i); assert(b == (a << i));
+
+ b = a; rshift1 (&b,nbytes,i); assert(b == (a >> i));
+ b = a; rshift8 (&b,nbytes,i); assert(b == (a >> i));
+ b = a; rshift32 (&b,nbytes,i); assert(b == (a >> i));
+
+ b = a; lrot1 (&b,nbytes,i); assert(b == _rotl64(a,i));
+ b = a; lrot8 (&b,nbytes,i); assert(b == _rotl64(a,i));
+ b = a; lrot32 (&b,nbytes,i); assert(b == _rotl64(a,i));
+
+ b = a; rrot1 (&b,nbytes,i); assert(b == _rotr64(a,i));
+ b = a; rrot8 (&b,nbytes,i); assert(b == _rotr64(a,i));
+ b = a; rrot32 (&b,nbytes,i); assert(b == _rotr64(a,i));
+ }
+ }
+
+ printf("PASS\n");
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+
+template < int nbits >
+bool test_window2 ( void )
+{
+ struct keytype
+ {
+ uint8_t bytes[nbits/8];
+ };
+
+ int nbytes = nbits / 8;
+ int reps = 10000;
+
+ for(int j = 0; j < reps; j++)
+ {
+ if(j % (reps/10) == 0) printf(".");
+
+ keytype k;
+
+ rand_p(&k,nbytes);
+
+ for(int start = 0; start < nbits; start++)
+ {
+ for(int count = 0; count < 32; count++)
+ {
+ uint32_t a = window1(&k,nbytes,start,count);
+ uint32_t b = window8(&k,nbytes,start,count);
+ uint32_t c = window(&k,nbytes,start,count);
+
+ assert(a == b);
+ assert(a == c);
+ }
+ }
+ }
+
+ printf("PASS %d\n",nbits);
+
+ return true;
+}
+
+bool test_window ( void )
+{
+ int reps = 10000;
+
+ for(int j = 0; j < reps; j++)
+ {
+ if(j % (reps/10) == 0) printf(".");
+
+ int nbits = 64;
+ int nbytes = nbits / 8;
+
+ uint64_t x = rand_u64();
+
+ for(int start = 0; start < nbits; start++)
+ {
+ for(int count = 0; count < 32; count++)
+ {
+ uint32_t a = (uint32_t)_rotr64(x,start);
+ a &= ((1 << count)-1);
+
+ uint32_t b = window1 (&x,nbytes,start,count);
+ uint32_t c = window8 (&x,nbytes,start,count);
+ uint32_t d = window32(&x,nbytes,start,count);
+ uint32_t e = window (x,start,count);
+
+ assert(a == b);
+ assert(a == c);
+ assert(a == d);
+ assert(a == e);
+ }
+ }
+ }
+
+ printf("PASS 64\n");
+
+ test_window2<8>();
+ test_window2<16>();
+ test_window2<24>();
+ test_window2<32>();
+ test_window2<40>();
+ test_window2<48>();
+ test_window2<56>();
+ test_window2<64>();
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
diff --git a/Bitvec.h b/Bitvec.h
new file mode 100644
index 0000000..b3988de
--- /dev/null
+++ b/Bitvec.h
@@ -0,0 +1,185 @@
+#pragma once
+
+#include "pstdint.h"
+
+#include <stdlib.h> // for _rotl, _rotr, etc.
+
+//-----------------------------------------------------------------------------
+
+uint32_t parity ( uint32_t v );
+uint64_t parity ( uint64_t v );
+
+uint32_t popcount ( uint32_t v );
+uint32_t popcount128 ( uint32_t * v );
+
+void printbits ( void * blob, int len );
+void printhex32 ( void * blob, int len );
+
+uint32_t getbit ( void * blob, int len, uint32_t bit );
+uint32_t getbit_wrap ( void * blob, int len, uint32_t bit );
+
+void setbit ( void * blob, int len, uint32_t bit );
+void setbit ( void * blob, int len, uint32_t bit, uint32_t val );
+
+void clearbit ( void * blob, int len, uint32_t bit );
+
+void flipbit ( void * blob, int len, uint32_t bit );
+
+
+//-----------------------------------------------------------------------------
+// Left and right shift of blobs. The shift(N) versions work on chunks of N
+// bits at a time (faster)
+
+void lshift1 ( void * blob, int len, int c );
+void lshift8 ( void * blob, int len, int c );
+void lshift32 ( void * blob, int len, int c );
+
+void rshift1 ( void * blob, int len, int c );
+void rshift8 ( void * blob, int len, int c );
+void rshift32 ( void * blob, int len, int c );
+
+inline void lshift ( void * blob, int len, int c )
+{
+ if((len & 3) == 0)
+ {
+ lshift32(&blob,len,c);
+ }
+ else
+ {
+ lshift8(&blob,len,c);
+ }
+}
+
+inline void rshift ( void * blob, int len, int c )
+{
+ if((len & 3) == 0)
+ {
+ rshift32(&blob,len,c);
+ }
+ else
+ {
+ rshift8(&blob,len,c);
+ }
+}
+
+template < typename T >
+inline void lshift ( T & blob, int c )
+{
+ if((sizeof(T) & 3) == 0)
+ {
+ lshift32(&blob,sizeof(T),c);
+ }
+ else
+ {
+ lshift8(&blob,sizeof(T),c);
+ }
+}
+
+template < typename T >
+inline void rshift ( T & blob, int c )
+{
+ if((sizeof(T) & 3) == 0)
+ {
+ lshift32(&blob,sizeof(T),c);
+ }
+ else
+ {
+ lshift8(&blob,sizeof(T),c);
+ }
+}
+
+template<> inline void lshift ( uint32_t & blob, int c ) { blob <<= c; }
+template<> inline void lshift ( uint64_t & blob, int c ) { blob <<= c; }
+template<> inline void rshift ( uint32_t & blob, int c ) { blob >>= c; }
+template<> inline void rshift ( uint64_t & blob, int c ) { blob >>= c; }
+
+//-----------------------------------------------------------------------------
+// Left and right rotate of blobs. The rot(N) versions work on chunks of N
+// bits at a time (faster)
+
+void lrot1 ( void * blob, int len, int c );
+void lrot8 ( void * blob, int len, int c );
+void lrot32 ( void * blob, int len, int c );
+
+void rrot1 ( void * blob, int len, int c );
+void rrot8 ( void * blob, int len, int c );
+void rrot32 ( void * blob, int len, int c );
+
+template < typename T >
+inline void lrot ( T & blob, int c )
+{
+ if((sizeof(T) & 3) == 0)
+ {
+ return lrot32(&blob,sizeof(T),c);
+ }
+ else
+ {
+ return lrot8(&blob,sizeof(T),c);
+ }
+}
+
+template < typename T >
+inline void rrot ( T & blob, int c )
+{
+ if((sizeof(T) & 3) == 0)
+ {
+ return rrot32(&blob,sizeof(T),c);
+ }
+ else
+ {
+ return rrot8(&blob,sizeof(T),c);
+ }
+}
+
+template<> inline void lrot ( uint32_t & blob, int c ) { blob = _rotl(blob,c); }
+template<> inline void lrot ( uint64_t & blob, int c ) { blob = _rotl64(blob,c); }
+template<> inline void rrot ( uint32_t & blob, int c ) { blob = _rotr(blob,c); }
+template<> inline void rrot ( uint64_t & blob, int c ) { blob = _rotr64(blob,c); }
+
+//-----------------------------------------------------------------------------
+// Bit-windowing functions - select some N-bit subset of the input blob
+
+uint32_t window1 ( void * blob, int len, int start, int count );
+uint32_t window8 ( void * blob, int len, int start, int count );
+uint32_t window32 ( void * blob, int len, int start, int count );
+
+inline uint32_t window ( void * blob, int len, int start, int count )
+{
+ if(len & 3)
+ {
+ return window8(blob,len,start,count);
+ }
+ else
+ {
+ return window32(blob,len,start,count);
+ }
+}
+
+/*
+template < typename T >
+inline uint32_t window ( T & blob, int start, int count )
+{
+ if((sizeof(T) & 3) == 0)
+ {
+ return window32(&blob,sizeof(T),start,count);
+ }
+ else
+ {
+ return window8(&blob,sizeof(T),start,count);
+ }
+}
+*/
+
+// template<>
+inline uint32_t window ( uint32_t & blob, int start, int count )
+{
+ return _rotr(blob,start) & ((1<<count)-1);
+}
+
+// template<>
+inline uint32_t window ( uint64_t & blob, int start, int count )
+{
+ return (uint32_t)_rotr64(blob,start) & ((1<<count)-1);
+}
+
+//-----------------------------------------------------------------------------
diff --git a/BlockCipher.cpp b/BlockCipher.cpp
new file mode 100644
index 0000000..414cf92
--- /dev/null
+++ b/BlockCipher.cpp
@@ -0,0 +1,294 @@
+#include "BlockCipher.h"
+
+#include <assert.h>
+#include <memory.h>
+
+//----------------------------------------------------------------------------
+
+BlockCipher::BlockCipher ( void )
+{
+ clear();
+
+ setMode(ECB);
+}
+
+BlockCipher::BlockCipher ( CipherMode mode )
+{
+ clear();
+
+ setMode(mode);
+}
+
+BlockCipher::~BlockCipher ( void )
+{
+}
+
+void BlockCipher::clear ( void )
+{
+ memset(m_plain, 0, 64);
+ memset(m_input, 0, 64);
+ memset(m_temp, 0, 64);
+ memset(m_output, 0, 64);
+ memset(m_crypt, 0, 64);
+}
+
+//----------------------------------------------------------------------------
+
+void BlockCipher::setMode ( CipherMode m )
+{
+ switch(m)
+ {
+ case ECB: m_pEncrypt = &BlockCipher::encrypt_ECB; m_pDecrypt = &BlockCipher::decrypt_ECB; break;
+ case ECBN: m_pEncrypt = &BlockCipher::encrypt_ECBN; m_pDecrypt = &BlockCipher::decrypt_ECBN; break;
+ case CBC: m_pEncrypt = &BlockCipher::encrypt_CBC; m_pDecrypt = &BlockCipher::decrypt_CBC; break;
+ case CFB: m_pEncrypt = &BlockCipher::encrypt_CFB; m_pDecrypt = &BlockCipher::decrypt_CFB; break;
+ case OFB: m_pEncrypt = &BlockCipher::encrypt_OFB; m_pDecrypt = &BlockCipher::decrypt_OFB; break;
+ case PCBC: m_pEncrypt = &BlockCipher::encrypt_PCBC; m_pDecrypt = &BlockCipher::decrypt_PCBC; break;
+ case CTR: m_pEncrypt = &BlockCipher::encrypt_CTR; m_pDecrypt = &BlockCipher::decrypt_CTR; break;
+
+ default: assert(false); setMode(PCBC); break;
+ };
+}
+
+//----------------------------------------------------------------------------
+
+void BlockCipher::encrypt ( void * key, int keySize, void * plain, void * crypt, int size )
+{
+ clear();
+
+ uint8_t * in = (uint8_t*)plain;
+ uint8_t * out = (uint8_t*)crypt;
+
+ int blockSize = getBlockSize();
+ int blockCount = size / blockSize;
+
+ setKey(key,keySize);
+
+ for(m_blockIndex = 0; m_blockIndex < blockCount; m_blockIndex++)
+ {
+ copy(m_plain,in);
+
+ (this->*m_pEncrypt)();
+
+ copy(out,m_crypt);
+
+ in += blockSize;
+ out += blockSize;
+ }
+}
+
+void BlockCipher::decrypt ( void * key, int keySize, void * crypt, void * plain, int size )
+{
+ clear();
+
+ uint8_t * in = (uint8_t*)crypt;
+ uint8_t * out = (uint8_t*)plain;
+
+ int blockSize = getBlockSize();
+ int blockCount = size / blockSize;
+
+ setKey(key,keySize);
+
+ for(m_blockIndex = 0; m_blockIndex < blockCount; m_blockIndex++)
+ {
+ copy(m_crypt,in);
+
+ (this->*m_pDecrypt)();
+
+ copy(out,m_plain);
+
+ in += blockSize;
+ out += blockSize;
+ }
+}
+
+//----------------------------------------------------------------------------
+// Electronic Codebook
+
+void BlockCipher::encrypt_ECB ( void )
+{
+ copy(m_crypt,m_plain);
+
+ encrypt(m_crypt,0);
+}
+
+//----------
+
+void BlockCipher::decrypt_ECB ( void )
+{
+ copy(m_plain,m_crypt);
+
+ decrypt(m_plain,0);
+}
+
+//----------------------------------------------------------------------------
+// Electronic Codebook + Nonce
+
+void BlockCipher::encrypt_ECBN ( void )
+{
+ copy(m_crypt,m_plain);
+
+ encrypt(m_crypt,m_blockIndex);
+}
+
+//----------
+
+void BlockCipher::decrypt_ECBN ( void )
+{
+ copy(m_plain,m_crypt);
+
+ decrypt(m_plain,m_blockIndex);
+}
+
+//----------------------------------------------------------------------------
+// Cipher Block Chaining
+
+void BlockCipher::encrypt_CBC ( void )
+{
+ xor(m_temp,m_plain,m_input);
+
+ encrypt(m_temp,0);
+
+ copy(m_input,m_temp);
+ copy(m_crypt,m_temp);
+}
+
+//----------
+
+void BlockCipher::decrypt_CBC ( void )
+{
+ copy(m_temp,m_crypt);
+
+ decrypt(m_temp,0);
+
+ xor(m_plain,m_temp,m_output);
+ copy(m_output,m_crypt);
+}
+
+//----------------------------------------------------------------------------
+// Cipher Feedback
+
+void BlockCipher::encrypt_CFB ( void )
+{
+ copy(m_temp,m_input);
+
+ encrypt(m_temp,0);
+
+ xor(m_crypt,m_temp,m_plain);
+ copy(m_input,m_crypt);
+}
+
+//----------
+
+void BlockCipher::decrypt_CFB ( void )
+{
+ copy(m_temp,m_input);
+
+ encrypt(m_temp,0);
+
+ xor(m_plain,m_temp,m_crypt);
+ copy(m_input,m_crypt);
+}
+
+//----------------------------------------------------------------------------
+// Output Feedback
+
+void BlockCipher::encrypt_OFB ( void )
+{
+ copy(m_temp,m_input);
+
+ encrypt(m_temp,0);
+
+ xor(m_crypt,m_temp,m_plain);
+ copy(m_input,m_temp);
+}
+
+//----------
+
+void BlockCipher::decrypt_OFB( void )
+{
+ copy(m_temp,m_input);
+
+ encrypt(m_temp,0);
+
+ xor(m_plain,m_temp,m_crypt);
+ copy(m_input,m_temp);
+}
+
+//----------------------------------------------------------------------------
+// Propagating Cipher Block Chaining
+
+// P = M(i)
+// I = M(i-1)
+// C = C(i-1)
+
+void BlockCipher::encrypt_PCBC ( void )
+{
+ xor(m_temp,m_input,m_crypt);
+ xor(m_temp,m_temp,m_plain);
+ copy(m_input,m_plain);
+
+ encrypt(m_temp,0);
+
+ copy(m_crypt,m_temp);
+}
+
+//----------
+
+// P = M(i-1)
+// I = C(i-1)
+// C = C(i)
+
+void BlockCipher::decrypt_PCBC ( void )
+{
+ copy(m_temp,m_crypt);
+
+ decrypt(m_temp,0);
+
+ xor(m_plain,m_plain,m_temp);
+ xor(m_plain,m_plain,m_input);
+
+ copy(m_input,m_crypt);
+}
+
+//----------------------------------------------------------------------------
+// Counter mode
+
+void BlockCipher::encrypt_CTR ( void )
+{
+ *(int*)m_temp = m_blockIndex;
+
+ encrypt(m_temp,0);
+
+ xor(m_crypt,m_temp,m_plain);
+}
+
+//----------
+
+void BlockCipher::decrypt_CTR ( void )
+{
+ *(int*)m_temp = m_blockIndex;
+
+ encrypt(m_temp,0);
+
+ xor(m_plain,m_temp,m_crypt);
+}
+
+//----------------------------------------------------------------------------
+
+void BlockCipher::copy ( uint8_t * dst, const uint8_t * src )
+{
+ memcpy(dst,src,getBlockSize());
+}
+
+void BlockCipher::xor ( uint8_t * dst, const uint8_t * a, const uint8_t * b )
+{
+ int blockSize = getBlockSize();
+
+ for(int i = 0; i < blockSize; i++)
+ {
+ dst[i] = a[i] ^ b[i];
+ }
+}
+
+//----------------------------------------------------------------------------
diff --git a/BlockCipher.h b/BlockCipher.h
new file mode 100644
index 0000000..c5c63ad
--- /dev/null
+++ b/BlockCipher.h
@@ -0,0 +1,90 @@
+#pragma once
+#include "Cipher.h"
+#include "pstdint.h"
+
+//----------------------------------------------------------------------------
+
+class BlockCipher : public Cipher
+{
+public:
+
+ enum CipherMode
+ {
+ ECB, // Electronic Codebook
+ ECBN, // Electronic Codebook + Nonce
+ CBC, // Cipher block chaining
+ CFB, // Cipher feedback
+ OFB, // Output feedback
+ PCBC, // Propagating CBC
+ CTR, // Counter
+ MAX = CTR,
+ };
+
+ //----------
+
+ BlockCipher ( void );
+ BlockCipher ( CipherMode mode );
+ virtual ~BlockCipher ( void );
+
+ virtual void clear ( void );
+
+ //----------
+ // Subclass interface
+
+ virtual int getBlockSize ( void ) = 0;
+
+ virtual void setKey ( void * k, int keySize ) = 0;
+
+ virtual void encrypt ( void * block, unsigned int nonce ) const = 0;
+ virtual void decrypt ( void * block, unsigned int nonce ) const = 0;
+
+ //----------
+ // Client interface
+
+ void setMode ( CipherMode m );
+
+ virtual void encrypt ( void * key, int keySize, void * plain, void * crypt, int size );
+ virtual void decrypt ( void * key, int keySize, void * crypt, void * plain, int size );
+
+ //----------
+
+private:
+
+ void encrypt_ECB ( void );
+ void encrypt_ECBN ( void );
+ void encrypt_CBC ( void );
+ void encrypt_CFB ( void );
+ void encrypt_OFB ( void );
+ void encrypt_PCBC ( void );
+ void encrypt_CTR ( void );
+
+ void decrypt_ECB ( void );
+ void decrypt_ECBN ( void );
+ void decrypt_CBC ( void );
+ void decrypt_CFB ( void );
+ void decrypt_OFB ( void );
+ void decrypt_PCBC ( void );
+ void decrypt_CTR ( void );
+
+ //----------
+
+ virtual void copy ( uint8_t * dst, const uint8_t * src );
+ virtual void xor ( uint8_t * dst, const uint8_t * a, const uint8_t * b );
+
+ //----------
+
+ uint8_t m_plain[64];
+ uint8_t m_input[64];
+ uint8_t m_temp[64];
+ uint8_t m_output[64];
+ uint8_t m_crypt[64];
+
+ int m_blockIndex;
+
+ typedef void (BlockCipher::*pFunc)(void);
+
+ pFunc m_pEncrypt;
+ pFunc m_pDecrypt;
+};
+
+//----------------------------------------------------------------------------
diff --git a/Cipher.cpp b/Cipher.cpp
new file mode 100644
index 0000000..a1de5e6
--- /dev/null
+++ b/Cipher.cpp
@@ -0,0 +1 @@
+#include "Cipher.h" \ No newline at end of file
diff --git a/Cipher.h b/Cipher.h
new file mode 100644
index 0000000..5aa4155
--- /dev/null
+++ b/Cipher.h
@@ -0,0 +1,16 @@
+#pragma once
+
+//----------------------------------------------------------------------------
+
+class Cipher
+{
+public:
+
+ Cipher ( void ) {}
+ virtual ~Cipher ( void ) {}
+
+ virtual void encrypt ( void * key, int keySize, void * plain, void * crypt, int size ) = 0;
+ virtual void decrypt ( void * key, int keySize, void * crypt, void * plain, int size ) = 0;
+};
+
+//----------------------------------------------------------------------------
diff --git a/Core.cpp b/Core.cpp
new file mode 100644
index 0000000..f42541e
--- /dev/null
+++ b/Core.cpp
@@ -0,0 +1,186 @@
+#include "Core.h"
+
+#include <math.h>
+
+//-----------------------------------------------------------------------------
+
+int SolveLinear ( double a, double b, double & r )
+{
+ if(a == 0)
+ {
+ return 0;
+ }
+
+ r = -b/a;
+
+ return 1;
+}
+
+//----------
+
+int SolveQuadratic ( double a, double b, double c, double & r1, double & r2 )
+{
+ if(a == 0)
+ {
+ return SolveLinear(b,c,r1);
+ }
+
+ double d = (b*b) - (4*a*c);
+
+ if(d < 0) return 0;
+
+ double d2 = sqrt(d);
+
+ r1 = (-b - d2) / (2.0 * a);
+ r2 = (-b + d2) / (2.0 * a);
+
+ return (r1 == r2) ? 1 : 2;
+}
+
+//----------
+
+uint32_t multinv ( uint32_t x )
+{
+ uint32_t y = 1;
+ uint32_t t = x;
+
+ for(int i = 1; i < 32; i++)
+ {
+ uint32_t b = (1 << i);
+
+ if(t & b)
+ {
+ y |= b;
+ t += (x << i);
+ }
+ }
+
+ return y;
+};
+
+//-----------------------------------------------------------------------------
+// this is random stuff that needs to go somewhere else
+
+uint32_t modmul ( uint32_t k, uint32_t m )
+{
+ uint64_t k2 = k;
+
+ k2 *= m;
+ k2 -= k2 >> 32;
+
+ return (uint32_t)k2;
+}
+
+uint32_t splitmul ( uint32_t k, uint32_t m )
+{
+ k *= m;
+ k -= k >> 16;
+
+ return k;
+}
+
+uint32_t expand16 ( uint32_t k, uint32_t m )
+{
+ return modmul(k+1,m);
+}
+
+bool compare_ham16 ( uint32_t mulA, uint32_t mulB,
+ int cutoffA, int cutoffXA, int cutoffAB,
+ int & minA, int & minB, int & minXA, int & minXB, int & minAB )
+{
+ const int count = 65536;
+
+ uint32_t fA[count];
+ uint32_t fB[count];
+
+ for(int i = 0; i < count; i++)
+ {
+ fA[i] = expand16(i,mulA);
+ fB[i] = expand16(i,mulB);
+ }
+
+ minA = 100000;
+ minB = 100000;
+
+ minXA = 100000;
+ minXB = 100000;
+ minAB = 100000;
+
+ for(int j = 0; j < count-1; j++)
+ for(int k = j+1; k < count; k++)
+ {
+ int X = popcount(j^k);
+ int A = popcount(fA[j]^fA[k]);
+ int B = popcount(fB[j]^fB[k]);
+
+ int XA = X+A;
+ int XB = X+B;
+ int AB = A+B;
+
+ if(A < minA) minA = A;
+ if(B < minB) minB = B;
+ if(XA < minXA) minXA = XA;
+ if(XB < minXB) minXB = XB;
+ if(AB < minAB) minAB = AB;
+
+ if(A < cutoffA)
+ goto dead;
+
+ if(B < cutoffA)
+ goto dead;
+
+ if(XA < cutoffXA)
+ goto dead;
+
+ if(XB < cutoffXA)
+ goto dead;
+
+ if(AB < cutoffAB)
+ goto dead;
+ }
+
+ return true;
+
+ dead:
+
+ return false;
+}
+
+bool test_ham16 ( uint32_t mulA, int cutoffA, int cutoffXA, int & minA, int & minXA )
+{
+ int minB,minXB,minAB;
+
+ return compare_ham16(mulA,mulA, cutoffA,cutoffXA,0, minA,minB,minXA,minXB,minAB);
+}
+
+inline uint32_t foldmul ( uint32_t k, uint32_t m )
+{
+ uint64_t k2 = k;
+
+ k2 *= m;
+ k2 ^= k2 >> 32;
+
+ return (uint32_t)k2;
+}
+
+inline uint32_t revmul ( const uint32_t v, const uint32_t m )
+{
+ uint32_t k1 = (uint32_t)(uint64_t(v) * m);
+ uint32_t k2 = (uint32_t)((uint64_t(v) * m) >> 32);
+
+ uint32_t k = k1-k2;
+
+ if(k2 > k1) k++;
+
+ return k;
+}
+
+inline uint32_t idmul ( const uint32_t v, const uint32_t m )
+{
+ uint32_t k1 = (uint32_t)(uint64_t(v) * m);
+ uint32_t k2 = (uint32_t)((uint64_t(v) * m) >> 32);
+
+ return k1 - k2;
+}
+
+//-----------------------------------------------------------------------------
diff --git a/Core.h b/Core.h
new file mode 100644
index 0000000..0f0f32a
--- /dev/null
+++ b/Core.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "Types.h"
+#include "Bitvec.h"
+#include "Random.h"
+
+//-----------------------------------------------------------------------------
+
+int SolveQuadratic ( double a, double b, double c, double & r1, double & r2 );
+
+void AccumDiffCounts ( void * a, void * b, double * counts, int len, double inc );
+
+unsigned int multinv ( unsigned int x );
+
+//-----------------------------------------------------------------------------
diff --git a/CycleTest.cpp b/CycleTest.cpp
new file mode 100644
index 0000000..125e60e
--- /dev/null
+++ b/CycleTest.cpp
@@ -0,0 +1 @@
+#include "CycleTest.h"
diff --git a/CycleTest.h b/CycleTest.h
new file mode 100644
index 0000000..f221674
--- /dev/null
+++ b/CycleTest.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "Types.h"
+
+template < typename hashtype >
+bool CycleTest ( pfHash hash, int cycleLen, int cycleReps, const int reps )
+{
+ printf("Keyset 'Cycles' (%dk keys, %d cycles, %d bytes)",reps / 1000,cycleReps,cycleLen);
+
+ bool result = true;
+
+ std::vector<hashtype> hashes;
+ hashes.resize(reps);
+
+ int keyLen = cycleLen * cycleReps;
+
+ uint8_t * cycle = new uint8_t[cycleLen + 16];
+ uint8_t * key = new uint8_t[keyLen];
+
+ for(int i = 0; i < reps; i++)
+ {
+ if(i % (reps/10) == 0) printf(".");
+
+ oracle(i,0,cycle,cycleLen);
+
+ *(uint32_t*)cycle = f3mix(i ^ 0x746a94f1);
+
+ for(int j = 0; j < keyLen; j++)
+ {
+ key[j] = cycle[j % cycleLen];
+ }
+
+ hash(key,keyLen,0,&hashes[i]);
+ }
+ printf("\n");
+
+ testhashlist(hashes,true,false);
+
+ delete [] cycle;
+ delete [] key;
+
+ return result;
+}
+
+
diff --git a/DictionaryTest.cpp b/DictionaryTest.cpp
new file mode 100644
index 0000000..56ed6df
--- /dev/null
+++ b/DictionaryTest.cpp
@@ -0,0 +1,61 @@
+#include "DictionaryTest.h"
+
+#include <intrin.h>
+
+#pragma warning(disable:4996) // fopen is unsafe
+
+
+wordlist g_words;
+int g_wordcount = 0;
+
+const char ** g_pwords = NULL;
+int * g_plengths = NULL;
+
+double g_dictoverhead = 0;
+
+//----------------------------------------------------------------------------
+
+void LoadWords ( void )
+{
+ FILE * f = fopen("allwords.txt","r");
+
+ char buffer[1024];
+
+ while(fgets(buffer,1024,f))
+ {
+ char * cursor = buffer + strlen(buffer);
+
+ while((*cursor == 0x0a) || (*cursor == 0))
+ {
+ *cursor = 0;
+ cursor--;
+ }
+
+ g_words.push_back(buffer);
+ }
+
+ fclose(f);
+
+ g_wordcount = (int)g_words.size();
+
+ printf("Loaded %d words\n",g_wordcount);
+
+ g_pwords = new const char*[g_wordcount];
+ g_plengths = new int[g_wordcount];
+
+ for(int i = 0; i < g_wordcount; i++)
+ {
+ g_pwords[i] = g_words[i].c_str();
+ g_plengths[i] = (int)g_words[i].size();
+ }
+}
+
+void DeleteWords ( void )
+{
+ delete [] g_pwords;
+ delete [] g_plengths;
+
+ g_words.clear();
+}
+
+//----------------------------------------------------------------------------
diff --git a/DictionaryTest.h b/DictionaryTest.h
new file mode 100644
index 0000000..2b82047
--- /dev/null
+++ b/DictionaryTest.h
@@ -0,0 +1,119 @@
+#pragma once
+
+#include "Types.h"
+#include "Stats.h" // for testkeylist_string
+
+#include <map>
+
+void LoadWords ( void );
+void DeleteWords ( void );
+
+typedef std::vector<std::string> wordlist;
+
+extern wordlist g_words;
+extern int g_wordcount;
+extern const char ** g_pwords;
+extern int * g_plengths;
+
+//-----------------------------------------------------------------------------
+
+
+template< typename hashtype >
+double DictHashTest ( hashfunc<hashtype> hash )
+{
+ __int64 begin,end;
+
+ const int reps = 999;
+
+ double best = 1.0e90;
+
+ for(int i = 0; i < reps; i++)
+ {
+ begin = __rdtsc();
+
+ for(int i = 0; i < g_wordcount; i++)
+ {
+ const char * buffer = g_pwords[i];
+ const int len = g_plengths[i];
+
+ hash(buffer,len,0);
+ }
+
+ end = __rdtsc();
+
+ double clocks = double(end-begin) / double(g_wordcount);
+
+ if(clocks < best) best = clocks;
+ }
+
+ return best;
+}
+
+//-----------------------------------------------------------------------------
+
+template< typename hashtype >
+void DumpCollisions ( hashfunc<hashtype> hash )
+{
+ printf("\nDumping collisions for seed 0 - \n\n");
+
+ typedef std::map<hashtype,std::vector<std::string>> hashmap;
+ hashmap hashes;
+
+ for(int i = 0; i < g_wordcount; i++)
+ {
+ hashtype h = hash(g_pwords[i],g_plengths[i],0);
+
+ hashes[h].push_back(g_pwords[i]);
+ }
+
+ int collcount = 0;
+
+ for(hashmap::iterator it = hashes.begin(); it != hashes.end(); it++)
+ {
+ hashtype hash = (*it).first;
+
+ std::vector<std::string> & strings = (*it).second;
+
+ if(strings.size() > 1)
+ {
+ collcount += (int)strings.size() - 1;
+
+ printf("0x%08x - ",hash);
+
+ for(int i = 0; i < (int)strings.size(); i++)
+ {
+ printf("%20s,",strings[i].c_str());
+ }
+
+ printf("\n");
+ }
+ }
+
+ printf("%d collisions\n",collcount);
+}
+
+//----------------------------------------------------------------------------
+
+template< typename hashtype >
+void DictionaryTest ( hashfunc<hashtype> hash )
+{
+ printf("Dictionary-based tests -\n");
+ printf("\n");
+
+ LoadWords();
+
+ double clocks = DictHashTest<hashtype>(hash);
+
+ printf("All words hashed in min %f clocks/word\n",clocks);
+ printf("\n");
+
+ printf("Testing dictionary stats\n");
+ testkeylist_string<hashtype>(hash,g_words,true,true);
+ printf("\n");
+
+ DumpCollisions(hash);
+
+ DeleteWords();
+}
+
+//-----------------------------------------------------------------------------
diff --git a/DifferentialTest.cpp b/DifferentialTest.cpp
new file mode 100644
index 0000000..b356085
--- /dev/null
+++ b/DifferentialTest.cpp
@@ -0,0 +1,3 @@
+#include "DifferentialTest.h"
+
+//----------------------------------------------------------------------------
diff --git a/DifferentialTest.h b/DifferentialTest.h
new file mode 100644
index 0000000..d5b17db
--- /dev/null
+++ b/DifferentialTest.h
@@ -0,0 +1,202 @@
+//-----------------------------------------------------------------------------
+// Differential collision & distribution tests - generate a bunch of random keys,
+// see what happens to the hash value when we flip a few bits of the key.
+
+#pragma once
+#include "Types.h"
+
+//-----------------------------------------------------------------------------
+// Check all possible keybits-choose-N differentials for collisions, report
+// ones that occur significantly more often than expected.
+
+// Random collisions can happen with probability 1 in 2^32 - if we do more than
+// 2^32 tests, we'll probably see some spurious random collisions, so don't report
+// them.
+
+template < typename keytype, typename hashtype >
+void DiffTest ( pfHash hash, int diffbits, int reps )
+{
+ const int keybits = sizeof(keytype) * 8;
+ const int hashbits = sizeof(hashtype) * 8;
+
+ double diffcount = chooseUpToK(keybits,diffbits);
+ double testcount = (diffcount * double(reps));
+ double expected = testcount / 4294967296.0;
+
+ std::vector<keytype> diffs;
+
+ keytype k1,k2;
+ hashtype h1,h2;
+
+ printf("Testing %0.f up-to-%d-bit differentials in %d-bit keys -> %d bit hashes.\n",diffcount,diffbits,keybits,hashbits);
+ printf("%d reps, %0.f total tests, expecting %2.2f random collisions",reps,testcount,expected);
+
+ for(int i = 0; i < reps; i++)
+ {
+ if(i % (reps/10) == 0) printf(".");
+
+ rand_p(&k1,sizeof(k1));
+ k2 = k1;
+
+ hash(&k1,sizeof(k1),0,(uint32_t*)&h1);
+
+ DiffTestRecurse<keytype,hashtype>(hash,k1,k2,h1,h2,0,diffbits,diffs);
+ }
+ printf("\n");
+
+ printdiffs(diffs,reps);
+ printf("\n");
+}
+
+//----------
+
+template < typename keytype, typename hashtype >
+void DiffTestRecurse ( pfHash hash, keytype & k1, keytype & k2, hashtype & h1, hashtype & h2, int start, int bitsleft, std::vector<keytype> & diffs )
+{
+ const int bits = sizeof(keytype)*8;
+
+ for(int i = start; i < bits; i++)
+ {
+ flipbit(&k2,sizeof(k2),i);
+ bitsleft--;
+
+ hash(&k2,sizeof(k2),0,&h2);
+
+ if(h1 == h2)
+ {
+ diffs.push_back(k1 ^ k2);
+ }
+
+ if(bitsleft)
+ {
+ DiffTestRecurse(hash,k1,k2,h1,h2,i+1,bitsleft,diffs);
+ }
+
+ flipbit(&k2,sizeof(k2),i);
+ bitsleft++;
+ }
+}
+
+//----------
+
+template < class keytype >
+void printdiffs ( std::vector<keytype> & diffs, int reps )
+{
+ std::sort(diffs.begin(), diffs.end());
+
+ int count = 1;
+ int ignore = 0;
+
+ if(diffs.size())
+ {
+ keytype kp = diffs[0];
+
+ for(int i = 1; i < (int)diffs.size(); i++)
+ {
+ if(diffs[i] == kp)
+ {
+ count++;
+ continue;
+ }
+ else
+ {
+ if(count > 1)
+ {
+ double pct = 100 * (double(count) / double(reps));
+ printbits((unsigned char*)&kp,sizeof(kp));
+ printf(" - %4.2f%%\n", pct );
+ }
+ else
+ {
+ ignore++;
+ }
+
+ kp = diffs[i];
+ count = 1;
+ }
+ }
+
+ if(count > 1)
+ {
+ double pct = 100 * (double(count) / double(reps));
+ printbits((unsigned char*)&kp,sizeof(kp));
+ printf(" - %4.2f%%\n", pct );
+ }
+ else
+ {
+ ignore++;
+ }
+ }
+
+ printf("%d total collisions, of which %d single collisions were ignored\n",(int)diffs.size(),ignore);
+}
+
+//-----------------------------------------------------------------------------
+// Differential distribution test - for each N-bit input differential, generate
+// a large set of differential key pairs, hash them, and test the output
+// differentials using our distribution test code.
+
+// This is a very hard test to pass - even if the hash values are well-distributed,
+// the differences between hash values may not be. It's also not entirely relevant
+// for testing hash functions, but it's still interesting.
+
+// This test is a _lot_ of work, as it's essentially a full keyset test for
+// each of a potentially huge number of input differentials. To speed things
+// along, we do only a few distribution tests per keyset instead of the full
+// grid.
+
+// #TODO - put diagram drawing back on
+
+template < typename keytype, typename hashtype >
+void DiffDistTest ( pfHash hash, const int diffbits, int trials, double & worst, double & avg )
+{
+ std::vector<keytype> keys(trials);
+ std::vector<hashtype> A(trials),B(trials);
+
+ for(int i = 0; i < trials; i++)
+ {
+ rand_t(keys[i]);
+
+ hash(&keys[i],sizeof(keys[i]),0,(uint32_t*)&A[i]);
+ }
+
+ //----------
+
+ std::vector<keytype> diffs;
+
+ keytype temp(0);
+
+ SparseKeygenRecurse<keytype>(0,diffbits,true,temp,diffs);
+
+ //----------
+
+ worst = 0;
+ avg = 0;
+
+ hashtype h2;
+
+ for(size_t j = 0; j < diffs.size(); j++)
+ {
+ keytype & d = diffs[j];
+
+ for(int i = 0; i < trials; i++)
+ {
+ keytype k2 = keys[i] ^ d;
+
+ hash(&k2,sizeof(k2),0,&h2);
+
+ B[i] = A[i] ^ h2;
+ }
+
+ double dworst,davg;
+
+ TestDistributionFast(B,dworst,davg);
+
+ avg += davg;
+ worst = (dworst > worst) ? dworst : worst;
+ }
+
+ avg /= double(diffs.size());
+}
+
+//----------------------------------------------------------------------------
diff --git a/Diffusion.cpp b/Diffusion.cpp
new file mode 100644
index 0000000..6927daa
--- /dev/null
+++ b/Diffusion.cpp
@@ -0,0 +1,204 @@
+#include "Diffusion.h"
+
+#include "Types.h"
+
+#include <memory.h>
+
+//-----------------------------------------------------------------------------
+// check invertibility of diffusion matrix
+
+void TestDiffusionMatrix ( void )
+{
+ //int m[4] = { 3, 1, 1, 3 };
+
+ int tab[65536];
+
+ memset(tab,0,sizeof(tab));
+
+ for(int i = 0; i < 65536; i++)
+ {
+ uint8_t a1 = (uint8_t)i;
+ uint8_t a2 = (uint8_t)(i >> 8);
+
+ //uint8_t b1 = uint8_t(a1 * m[0]) + uint8_t(a2*m[1]);
+ //uint8_t b2 = uint8_t(a1 * m[2]) + uint8_t(a2*m[3]);
+
+ uint8_t b1 = a1;
+ uint8_t b2 = a2;
+
+ b1 += b2;
+ b2 += b1;
+
+ int index = (int(b1) << 8) + b2;
+
+ tab[index]++;
+ }
+
+ int missing = 0;
+
+ for(int i = 0; i < 65536; i++)
+ {
+ if(tab[i] == 0) missing++;
+ }
+
+ printf("missing - %d\n",missing);
+}
+
+//-----------------------------------------------------------------------------
+
+void add_row ( int m[16], int a, int b )
+{
+ for(int i = 0; i < 4; i++)
+ {
+ m[4*a+i] += m[4*b+i];
+ }
+}
+
+void sub_row ( int m[16], int a, int b )
+{
+ for(int i = 0; i < 4; i++)
+ {
+ m[4*a+i] -= m[4*b+i];
+ }
+}
+
+//-----------------------------------------------------------------------------
+// search through diffusion matrices computable in N operations, find ones
+// with a maximal number of odd terms
+
+bool check ( const int m[16], std::vector<int> & dst, std::vector<int> & src )
+{
+ static int best = 0;
+
+ int c = 0;
+ int s = 0;
+
+ if(abs(m[0]+m[4]+m[8]+m[12]) > 2) return false;
+ if(abs(m[1]+m[5]+m[9]+m[13]) > 2) return false;
+ if(abs(m[2]+m[6]+m[10]+m[14]) > 2) return false;
+ if(abs(m[3]+m[7]+m[11]+m[15]) > 2) return false;
+
+ for(int i = 0; i < 16; i++)
+ {
+ if(m[i] == 0) return false;
+
+ int d = abs(m[i]);
+
+ c += (d & 1);
+
+ if(m[i] < 0) s++;
+ }
+
+ if((c == 13) && (s == 8))
+ {
+ std::string g[4];
+
+ g[0] = "A";
+ g[1] = "B";
+ g[2] = "C";
+ g[3] = "D";
+
+ printf("----------\n");
+
+ for(int i = 0; i < (int)dst.size(); i++)
+ {
+ int d = dst[i];
+ int s = src[i];
+
+ std::string tmp;
+
+ tmp += g[d-1];
+
+ tmp += (s < 0) ? "-" : "+";
+
+ tmp += "(";
+ tmp += g[abs(s)-1];
+ tmp += ")";
+
+ g[d-1] = tmp;
+ }
+
+ printf("A : %s\n",g[0].c_str());
+ printf("B : %s\n",g[1].c_str());
+ printf("C : %s\n",g[2].c_str());
+ printf("D : %s\n",g[3].c_str());
+
+ for(int i = 0; i < (int)dst.size(); i++)
+ {
+ int d = dst[i];
+ int s = src[i];
+
+ if(s < 0)
+ {
+ printf("h[%1d] -= h[%1d];\n",d,-s);
+ }
+ else
+ {
+ printf("h[%1d] += h[%1d];\n",d,s);
+ }
+ }
+ printf("----------\n");
+ }
+
+ return c == 16;
+}
+
+bool difrecurse ( const int m[16], int depth, int maxdepth, int last, std::vector<int> & dst, std::vector<int> & src )
+{
+ if(depth == maxdepth)
+ {
+ return check(m,dst,src);
+ }
+
+ for(int i = 0; i < 4; i++)
+ {
+ dst.push_back(i+1);
+
+ for(int j = 0; j < 4; j++)
+ {
+ if(i == j) continue;
+
+ if(i == last) continue;
+ if(j == last) continue;
+
+ int n[16];
+
+ memcpy(n,m,sizeof(n));
+
+ src.push_back(j+1);
+ add_row(n,i,j);
+ difrecurse(n,depth+1,maxdepth,i,dst,src);
+ sub_row(n,i,j);
+ src.pop_back();
+
+ src.push_back(-(j+1));
+ sub_row(n,i,j);
+ difrecurse(n,depth+1,maxdepth,i,dst,src);
+ add_row(n,i,j);
+ src.pop_back();
+ }
+
+ dst.pop_back();
+ }
+
+ return false;
+}
+
+void findDiffuse ( void )
+{
+ int m[16];
+
+ memset(m,0,sizeof(m));
+
+ m[4*0 + 0] = 1;
+ m[4*1 + 1] = 1;
+ m[4*2 + 2] = 1;
+ m[4*3 + 3] = 1;
+
+ std::vector<int> dst;
+ std::vector<int> src;
+
+ difrecurse(m,0,7,-1,dst,src);
+ printf("\n");
+}
+
diff --git a/Diffusion.h b/Diffusion.h
new file mode 100644
index 0000000..7b9637e
--- /dev/null
+++ b/Diffusion.h
@@ -0,0 +1 @@
+#pragma once \ No newline at end of file
diff --git a/FWTransform.cpp b/FWTransform.cpp
new file mode 100644
index 0000000..cf9ed80
--- /dev/null
+++ b/FWTransform.cpp
@@ -0,0 +1,443 @@
+#include "FWTransform.h"
+
+#include "Random.h"
+
+// FWT1/2/3/4 are tested up to 2^16 against a brute-force implementation.
+
+//----------------------------------------------------------------------------
+
+double test_linear_approximation ( mixfunc<uint32_t> f, uint32_t l, uint32_t mask, int64_t size )
+{
+ int64_t d = 0;
+
+ for(int64_t i = 0; i < size; i++)
+ {
+ uint32_t x = (uint32_t)i;
+ uint32_t b1 = parity( f(x) & mask );
+ uint32_t b2 = parity( x & l );
+
+ d += (b1 ^ b2);
+ }
+
+ return double(d) / double(size);
+}
+
+//----------------------------------------------------------------------------
+// In-place, non-recursive FWT transform. Reference implementation.
+
+void FWT1 ( int * v, int64_t count )
+{
+ for(int64_t width = 2; width <= count; width *= 2)
+ {
+ int64_t blocks = count / width;
+
+ for(int64_t i = 0; i < blocks; i++)
+ {
+ int64_t ia = i * width;
+ int64_t ib = ia + (width/2);
+
+ for(int64_t j = 0; j < (width/2); j++)
+ {
+ int a = v[ia];
+ int b = v[ib];
+
+ v[ia++] = a + b;
+ v[ib++] = a - b;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// recursive, but fall back to non-recursive for tables of 4k or smaler
+
+// (this proved to be fastest)
+
+void FWT2 ( int * v, int64_t count )
+{
+ if(count <= 4*1024) return FWT1(v,(int32_t)count);
+
+ int64_t c = count/2;
+
+ for(int64_t i = 0; i < c; i++)
+ {
+ int a = v[i];
+ int b = v[i+c];
+
+ v[i] = a + b;
+ v[i+c] = a - b;
+ }
+
+ if(count > 2)
+ {
+ FWT2(v,c);
+ FWT2(v+c,c);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// fully recursive (slow)
+
+void FWT3 ( int * v, int64_t count )
+{
+ int64_t c = count/2;
+
+ for(int64_t i = 0; i < c; i++)
+ {
+ int a = v[i];
+ int b = v[i+c];
+
+ v[i] = a + b;
+ v[i+c] = a - b;
+ }
+
+ if(count > 2)
+ {
+ FWT3(v,c);
+ FWT3(v+c,c);
+ }
+}
+
+//----------------------------------------------------------------------------
+// some other method
+
+void FWT4 ( int * data, const int64_t count )
+{
+ int nbits = 0;
+
+ for(int64_t c = count; c; c >>= 1) nbits++;
+
+ for (int i = 0; i < nbits; i++)
+ {
+ int64_t block = (int64_t(1) << i);
+ int64_t half = (int64_t(1) << (i-1));
+
+ for (int64_t j = 0; j < count; j += block)
+ {
+ for (int k = 0; k < half; ++k)
+ {
+ int64_t ia = j+k;
+ int64_t ib = j+k+half;
+
+ int a = data[ia];
+ int b = data[ib];
+
+ data[ia] = a+b;
+ data[ib] = a-b;
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+// Evaluate a single point in the FWT hierarchy
+
+/*
+int FWTPoint ( mixfunc<uint32_t> f, int level, int nbits, uint32_t y )
+{
+ if(level == 0)
+ {
+ return f(y);
+ }
+ else
+ {
+ uint32_t mask = 1 << (nbits - level);
+
+ if(y & mask)
+ {
+ return
+ }
+ }
+}
+*/
+
+
+//----------------------------------------------------------------------------
+// compute 2 tiers down into FWT, so we can break a table up into 4 chunks
+
+int computeWalsh2 ( mixfunc<uint32_t> f, int64_t y, int bits, uint32_t mask )
+{
+ uint32_t size1 = 1 << (bits-1);
+ uint32_t size2 = 1 << (bits-2);
+
+ int a = parity(f((uint32_t)y ) & mask) ? 1 : -1;
+ int b = parity(f((uint32_t)y ^ size2) & mask) ? 1 : -1;
+
+ int ab = (y & size2) ? b-a : a+b;
+
+ int c = parity(f((uint32_t)y ^ size1 ) & mask) ? 1 : -1;
+ int d = parity(f((uint32_t)y ^ size1 ^ size2) & mask) ? 1 : -1;
+
+ int cd = (y & size2) ? d-c : c+d;
+
+ int e = (y & size1) ? cd-ab : ab+cd;
+
+ return e;
+}
+
+int computeWalsh2 ( int * func, int64_t y, int bits )
+{
+ uint32_t size1 = 1 << (bits-1);
+ uint32_t size2 = 1 << (bits-2);
+
+ int a = parity((uint32_t)func[(uint32_t)y ]) ? 1 : -1;
+ int b = parity((uint32_t)func[(uint32_t)y ^ size2]) ? 1 : -1;
+
+ int ab = (y & size2) ? b-a : a+b;
+
+ int c = parity((uint32_t)func[(uint32_t)y ^ size1 ]) ? 1 : -1;
+ int d = parity((uint32_t)func[(uint32_t)y ^ size1 ^ size2]) ? 1 : -1;
+
+ int cd = (y & size2) ? d-c : c+d;
+
+ int e = (y & size1) ? cd-ab : ab+cd;
+
+ return e;
+}
+
+//----------------------------------------------------------------------------
+// this version computes the entire table at once - needs 16 gigs of RAM for
+// 32-bit FWT (!!!)
+
+void find_linear_approximation_walsh ( mixfunc<uint32_t> f, uint32_t mask, int inbits, uint32_t & outL, int64_t & outBias )
+{
+ // create table
+
+ const int64_t count = int64_t(1) << inbits;
+
+ int * table = new int[(int)count];
+
+ // fill table
+
+ for(int64_t i = 0; i < count; i++)
+ {
+ table[i] = parity(f((uint32_t)i) & mask) ? 1 : -1;
+ }
+
+ // apply walsh transform
+
+ FWT1(table,count);
+
+ // find maximum value in transformed table, which corresponds
+ // to closest linear approximation to F
+
+ outL = 0;
+ outBias = 0;
+
+ for(unsigned int l = 0; l < count; l++)
+ {
+ if(abs(table[l]) > outBias)
+ {
+ outBias = abs(table[l]);
+ outL = l;
+ }
+ }
+
+ delete [] table;
+}
+
+//-----------------------------------------------------------------------------
+// this version breaks the task into 4 pieces, or 4 gigs of RAM for 32-bit FWT
+
+void find_linear_approximation_walsh2 ( mixfunc<uint32_t> f, uint32_t mask, int inbits, uint32_t & outL, int64_t & outBias )
+{
+ const int64_t count = int64_t(1) << inbits;
+ const int64_t stride = count/4;
+
+ int * table2 = new int[(int)stride];
+
+ uint32_t worstL = 0;
+ int64_t worstBias = 0;
+
+ for(int64_t j = 0; j < count; j += stride)
+ {
+ printf(".");
+
+ for(int i = 0; i < stride; i++)
+ {
+ table2[i] = computeWalsh2(f,i+j,inbits,mask);
+ }
+
+ FWT2(table2,stride);
+
+ for(int64_t l = 0; l < stride; l++)
+ {
+ if(abs(table2[l]) > worstBias)
+ {
+ worstBias = abs(table2[l]);
+ worstL = uint32_t(l)+uint32_t(j);
+ }
+ }
+ }
+
+ outBias = worstBias/2;
+ outL = worstL;
+
+ delete [] table2;
+}
+
+
+//----------------------------------------------------------------------------
+
+void printtab ( int * tab, int size )
+{
+ for(int j = 0; j < 16; j++)
+ {
+ printf("[");
+ for(int i = 0; i < (size/16); i++)
+ {
+ printf("%3d ",tab[j*16+i]);
+ }
+ printf("]\n");
+ }
+}
+
+void comparetab ( int * tabA, int * tabB, int size )
+{
+ bool fail = false;
+
+ for(int i = 0; i < size; i++)
+ {
+ if(tabA[i] != tabB[i])
+ {
+ fail = true;
+ break;
+ }
+ }
+
+ printf(fail ? "X" : "-");
+}
+
+void testFWT ( void )
+{
+ const int bits = 12;
+ const int size = (1 << bits);
+
+ int * func = new int[size];
+ int * resultA = new int[size];
+ int * resultB = new int[size];
+
+ for(int rep = 0; rep < 1; rep++)
+ {
+ // Generate a random boolean function
+
+ for(int i = 0; i < size; i++)
+ {
+ func[i] = rand_u32() & 1;
+
+ //func[i] = (i ^ (i >> 2)) & 1;
+ }
+
+ //printf("Input boolean function -\n");
+ //printtab(func);
+ //printf("\n");
+
+ // Test against all 256 linear functions
+
+
+ memset(resultA,0,size * sizeof(int));
+
+ //printf("Result - \n");
+ for(uint32_t linfunc = 0; linfunc < size; linfunc++)
+ {
+ resultA[linfunc] = 0;
+
+ for(uint32_t k = 0; k < size; k++)
+ {
+ int b1 = func[k];
+ int b2 = parity( k & linfunc );
+
+ if(b1 == b2) resultA[linfunc]++;
+ }
+
+ resultA[linfunc] -= (size/2);
+ }
+
+ //printtab(resultA);
+ //printf("\n");
+
+
+ // Test with FWTs
+
+ for(int i = 0; i < size; i++) resultB[i] = (func[i] == 0) ? -1 : 1;
+ FWT1(resultB,size);
+ for(int i = 0; i < size; i++) resultB[i] = -resultB[i]/2;
+ comparetab(resultA,resultB,size);
+
+ for(int i = 0; i < size; i++) resultB[i] = (func[i] == 0) ? -1 : 1;
+ FWT2(resultB,size);
+ for(int i = 0; i < size; i++) resultB[i] = -resultB[i]/2;
+ comparetab(resultA,resultB,size);
+
+ for(int i = 0; i < size; i++) resultB[i] = (func[i] == 0) ? -1 : 1;
+ FWT3(resultB,size);
+ for(int i = 0; i < size; i++) resultB[i] = -resultB[i]/2;
+ comparetab(resultA,resultB,size);
+
+ // Test with subdiv-by-4
+
+ {
+ for(int i = 0; i < size; i++) resultB[i] = (func[i] == 0) ? -1 : 1;
+
+ const int64_t count = int64_t(1) << bits;
+ const int64_t stride = count/4;
+
+ for(int64_t j = 0; j < count; j += stride)
+ {
+ for(int i = 0; i < stride; i++)
+ {
+ resultB[i+j] = computeWalsh2(func,i+j,bits);
+ }
+
+ FWT2(&resultB[j],stride);
+ }
+
+ for(int i = 0; i < size; i++) resultB[i] = -resultB[i]/2;
+ comparetab(resultA,resultB,size);
+ }
+
+ printf(" ");
+ }
+
+ delete [] func;
+ delete [] resultA;
+ delete [] resultB;
+}
+
+//-----------------------------------------------------------------------------
+// Compare known-good implementation against optimized implementation
+
+void testFWT2 ( void )
+{
+ const int bits = 24;
+ const int size = (1 << bits);
+
+ int * func = new int[size];
+ int * resultA = new int[size];
+ int * resultB = new int[size];
+
+ for(int rep = 0; rep < 4; rep++)
+ {
+ // Generate a random boolean function
+
+ for(int i = 0; i < size; i++)
+ {
+ func[i] = rand_u32() & 1;
+ }
+
+ // Test with FWTs
+
+ for(int i = 0; i < size; i++) resultA[i] = resultB[i] = (func[i] == 0) ? -1 : 1;
+
+ FWT1(resultA,size);
+ FWT4(resultB,size);
+
+ comparetab(resultA,resultB,size);
+
+ printf(" ");
+ }
+
+ delete [] func;
+ delete [] resultA;
+ delete [] resultB;
+} \ No newline at end of file
diff --git a/FWTransform.h b/FWTransform.h
new file mode 100644
index 0000000..6979cbd
--- /dev/null
+++ b/FWTransform.h
@@ -0,0 +1,12 @@
+#include "Types.h"
+#include "Bitvec.h"
+
+// Fast Walsh transform stuff. Used for determining how close an arbitrary
+// boolean function is to the set of all possible linear functions.
+
+// Given an arbitrary N-bit mixing function mix(x), we can generate a boolean
+// function out of it by choosing a N-bit mask and computing
+// parity(mix(x) & mask).
+
+// If the mask has 1 bit set, this is equivalent to selecting a column of
+// output bits from the mixing function to test.
diff --git a/Hamming.cpp b/Hamming.cpp
new file mode 100644
index 0000000..e00e5b7
--- /dev/null
+++ b/Hamming.cpp
@@ -0,0 +1,133 @@
+#include "Hamming.h"
+
+#include "Types.h"
+#include "Random.h"
+
+// Code to measure the hamming weight of mix functions, etc.
+
+// (documentation needed)
+
+// If I change N bits of the input, how many bits of the output change on average?
+
+
+//-----------------------------------------------------------------------------
+// compute table of differential hamming weight for input differentials
+// up to 5 bits
+
+void hamtest ( uint32_t (*mix)(uint32_t), uint32_t d, const int reps, double out[33] )
+{
+ double temp[33];
+
+ memset(temp,0,sizeof(temp));
+
+ for(int i = 0; i < reps; i++)
+ {
+ uint32_t a = rand_u32();
+ uint32_t b = a ^ d;
+
+ uint32_t ma = mix(a);
+ uint32_t mb = mix(b);
+
+ uint32_t md = ma ^ mb;
+
+ temp[popcount(md)] += 1.0 / double(reps);
+ }
+
+ for(int i = 0; i < 33; i++)
+ {
+ if(temp[i] > out[i]) out[i] = temp[i];
+ }
+}
+
+void SparseDiffHamming32 ( uint32_t (*mix)(uint32_t), double accum[33] )
+{
+ uint32_t d = 0;
+
+ memset(accum,0,sizeof(accum));
+
+ //const double c32_1 = 32;
+ //const double c32_2 = 496;
+ //const double c32_3 = 4960;
+ //const double c32_4 = 35960;
+ //const double c32_5 = 201376;
+ //const double c32[5] = { c32_1, c32_2, c32_3, c32_4, c32_5 };
+
+ const int reps = 1000;
+
+ double temp[6][33];
+
+ for(int i = 0; i < 6; i++)
+ {
+ memset(temp[i],0,33 * sizeof(double));
+ }
+
+ for(int i = 0; i < 32; i++)
+ {
+ d ^= (1 << i);
+ hamtest(mix,d,reps,temp[1]);
+
+ for(int j = i+1; j < 32; j++)
+ {
+ d ^= (1 << j);
+ hamtest(mix,d,reps,temp[2]);
+
+ for(int k = j+1; k < 32; k++)
+ {
+ d ^= (1 << k);
+ hamtest(mix,d,reps,temp[3]);
+
+ for(int l = k+1; l < 32; l++)
+ {
+ d ^= (1 << l);
+ hamtest(mix,d,reps,temp[4]);
+
+ //for(int m = l+1; m < 32; m++)
+ //{
+ // d ^= (1 << m);
+ // hamtest(mix,d,reps,temp[5]);
+ //
+ // d ^= (1 << m);
+ //}
+
+ d ^= (1 << l);
+ }
+ d ^= (1 << k);
+ }
+ d ^= (1 << j);
+ }
+ d ^= (1 << i);
+ }
+
+ for(int i = 0; i < 33; i++)
+ {
+ accum[i] = 0;
+ }
+
+ for(int j = 0; j < 33; j++)
+ {
+ for(int i = 0; i < 6; i++)
+ {
+ if((i+j) >= 33) continue;
+
+ double t = temp[i][j];
+
+ if(t > accum[i+j]) accum[i+j] = t;
+ }
+ }
+
+ for(int i = 0; i < 33; i++)
+ {
+ accum[i] *= 100;
+ }
+}
+
+bool hamless ( int count, double * a, double * b )
+{
+ for(int i = 0; i < count; i++)
+ {
+ if(a[i] < b[i]) return true;
+ if(a[i] > b[i]) return false;
+ }
+
+ return false;
+}
diff --git a/Hamming.h b/Hamming.h
new file mode 100644
index 0000000..a372925
--- /dev/null
+++ b/Hamming.h
@@ -0,0 +1,5 @@
+#pragma once
+#include "Types.h"
+
+void SparseDiffHamming32 ( uint32_t (*mix)(uint32_t), double accum[33] );
+bool hamless ( int count, double * a, double * b ); \ No newline at end of file
diff --git a/Hashes.cpp b/Hashes.cpp
new file mode 100644
index 0000000..b27a2f0
--- /dev/null
+++ b/Hashes.cpp
@@ -0,0 +1,114 @@
+#include "Hashes.h"
+
+#include "Random.h"
+
+//----------------------------------------------------------------------------
+// fake / bad hashes
+
+void randhash ( const void *, int, uint32_t, void * out )
+{
+ *(uint32_t*)out = rand_u32();
+}
+
+void BadHash ( const void * key, int len, uint32_t seed, void * out )
+{
+ uint32_t h = seed;
+
+ const uint8_t * data = (const uint8_t*)key;
+
+ for(int i = 0; i < len; i++)
+ {
+ h ^= h >> 3;
+ h ^= h << 5;
+ h ^= data[i];
+ }
+
+ *(uint32_t*)out = h;
+}
+
+void sumhash ( const void * key, int len, uint32_t seed, void * out )
+{
+ uint32_t h = seed;
+
+ const uint8_t * data = (const uint8_t*)key;
+
+ for(int i = 0; i < len; i++)
+ {
+ h += data[i];
+ }
+
+ *(uint32_t*)out = h;
+}
+
+void DoNothingHash ( const void *, int, uint32_t, void * )
+{
+ return;
+}
+
+//-----------------------------------------------------------------------------
+// One-byte-at-a-time hash based on Murmur's mix
+
+uint32_t MurmurOAAT ( const void * key, int len, uint32_t h )
+{
+ const uint8_t * data = (const uint8_t*)key;
+
+ h ^= len;
+
+ for(int i = 0; i < len; i++)
+ {
+ h ^= data[i];
+ h *= 0x5bd1e995;
+ h ^= h >> 16;
+ }
+
+ return h;
+}
+
+//----------------------------------------------------------------------------
+
+void FNV ( const void * key, int len, uint32_t seed, void * out )
+{
+ unsigned int h = seed;
+
+ const uint8_t * data = (const uint8_t*)key;
+
+ h ^= 2166136261;
+
+ for(int i = 0; i < len; i++)
+ {
+ h ^= data[i];
+ h *= 16777619;
+ }
+
+ *(uint32_t*)out = h;
+}
+
+//-----------------------------------------------------------------------------
+
+uint32_t x17 ( const void * key, int len, uint32_t h )
+{
+ const uint8_t * data = (const uint8_t*)key;
+
+ for(int i = 0; i < len; ++i)
+ {
+ h = 17 * h + (data[i] - ' ');
+ }
+
+ return h ^ (h >> 16);
+}
+
+//-----------------------------------------------------------------------------
+
+uint32_t Bernstein ( const void * key, int len, uint32_t h )
+{
+ const uint8_t * data = (const uint8_t*)key;
+
+ for(int i = 0; i < len; ++i)
+ {
+ h = 33 * h + data[i];
+ }
+
+ return h;
+}
+
+//-----------------------------------------------------------------------------
diff --git a/Hashes.h b/Hashes.h
new file mode 100644
index 0000000..8bf998e
--- /dev/null
+++ b/Hashes.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "Types.h"
+
+#include "MurmurHash1.h"
+#include "MurmurHash2.h"
+#include "MurmurHash3.h"
+
+void DoNothingHash ( const void * key, int len, uint32_t seed, void * out );
+void FNV ( const void * key, int len, uint32_t seed, void * out );
+void SuperFastHash ( const void * key, int len, uint32_t seed, void * out );
+void lookup3_test ( const void * key, int len, uint32_t seed, void * out );
+void md5_32 ( const void * key, int len, uint32_t seed, void * out );
+void crc32 ( const void * key, int len, uint32_t seed, void * out );
+
+void MurmurHash2_test ( const void * key, int len, uint32_t seed, void * out );
+void MurmurHash2A_test ( const void * key, int len, uint32_t seed, void * out );
+
+//-----------------------------------------------------------------------------
+
+inline void MurmurHash1_test ( const void * key, int len, uint32_t seed, void * out )
+{
+ *(uint32_t*)out = MurmurHash1(key,len,seed);
+}
+
+inline void MurmurHash2_test ( const void * key, int len, uint32_t seed, void * out )
+{
+ *(uint32_t*)out = MurmurHash2(key,len,seed);
+}
+
+inline void MurmurHash2A_test ( const void * key, int len, uint32_t seed, void * out )
+{
+ *(uint32_t*)out = MurmurHash2A(key,len,seed);
+}
+
diff --git a/Junk.cpp b/Junk.cpp
new file mode 100644
index 0000000..62e700c
--- /dev/null
+++ b/Junk.cpp
@@ -0,0 +1,38 @@
+#include "Junk.h"
+
+#include "Random.h"
+
+//-----------------------------------------------------------------------------
+// Given a 64->32 bit compression function and a set of differentials, compute
+// the number of collisions
+
+typedef uint32_t (*pfCompress32) ( uint64_t x );
+
+int TestCompress ( pfCompress32 comp, std::vector<uint64_t> & diffs, const int reps )
+{
+ int total = 0;
+
+ for(int j = 0; j < (int)diffs.size(); j++)
+ {
+ uint64_t d = diffs[j];
+
+ int collisions = 0;
+
+ for(int i = 0; i < reps; i++)
+ {
+ uint64_t a = rand_u64();
+ uint64_t b = a ^ d;
+
+ uint32_t ca = comp(a);
+ uint32_t cb = comp(b);
+
+ if(ca == cb) collisions++;
+ }
+
+ if(collisions > 1) total += collisions;
+ }
+
+ return total;
+}
+
+//-----------------------------------------------------------------------------
diff --git a/Junk.h b/Junk.h
new file mode 100644
index 0000000..a4fc5fd
--- /dev/null
+++ b/Junk.h
@@ -0,0 +1,46 @@
+#include "Types.h"
+
+//-----------------------------------------------------------------------------
+
+template < typename mixtype >
+void calcMixBias ( mixtype (*mix)(mixtype), std::vector<int>& bins, int reps )
+{
+ const int inbits = sizeof(mixtype) * 8;
+ const int outbits = sizeof(mixtype) * 8;
+
+ mixtype K,A,B,C;
+
+ for(int irep = 0; irep < reps; irep++)
+ {
+ rand_t(K);
+
+ A = mix(K);
+
+ for(int iBit = 0; iBit < inbits; iBit++)
+ {
+ B = mix(K ^ (mixtype(1) << iBit));
+
+ C = A ^ B;
+
+ for(int iOut = 0; iOut < outbits; iOut++)
+ {
+ bins[(iBit*outbits) + iOut] += (C >> iOut) & 1;
+ }
+ }
+ }
+}
+
+//----------
+
+template < typename mixtype >
+double calcMixBias ( mixtype (*mix)(mixtype), int reps )
+{
+ const int bits = sizeof(mixtype) * 8;
+ std::vector<int> bins(bits*bits);
+
+ calcMixBias<mixtype>(mix,bins,reps);
+
+ return maxBias(bins,reps);
+}
+
+//-----------------------------------------------------------------------------
diff --git a/MurmurHash1.cpp b/MurmurHash1.cpp
new file mode 100644
index 0000000..4322bb8
--- /dev/null
+++ b/MurmurHash1.cpp
@@ -0,0 +1,171 @@
+#include "MurmurHash1.h"
+
+//-----------------------------------------------------------------------------
+// MurmurHash1, by Austin Appleby
+
+// Note - This code makes a few assumptions about how your machine behaves -
+
+// 1. We can read a 4-byte value from any address without crashing
+// 2. sizeof(int) == 4
+
+// And it has a few limitations -
+
+// 1. It will not work incrementally.
+// 2. It will not produce the same results on little-endian and big-endian
+// machines.
+
+uint32_t MurmurHash1 ( const void * key, int len, uint32_t seed )
+{
+ const unsigned int m = 0xc6a4a793;
+
+ const int r = 16;
+
+ unsigned int h = seed ^ (len * m);
+
+ //----------
+
+ const unsigned char * data = (const unsigned char *)key;
+
+ while(len >= 4)
+ {
+ unsigned int k = *(unsigned int *)data;
+
+ h += k;
+ h *= m;
+ h ^= h >> 16;
+
+ data += 4;
+ len -= 4;
+ }
+
+ //----------
+
+ switch(len)
+ {
+ case 3:
+ h += data[2] << 16;
+ case 2:
+ h += data[1] << 8;
+ case 1:
+ h += data[0];
+ h *= m;
+ h ^= h >> r;
+ };
+
+ //----------
+
+ h *= m;
+ h ^= h >> 10;
+ h *= m;
+ h ^= h >> 17;
+
+ return h;
+}
+
+//-----------------------------------------------------------------------------
+// MurmurHash1Aligned, by Austin Appleby
+
+// Same algorithm as MurmurHash1, but only does aligned reads - should be safer
+// on certain platforms.
+
+// Performance should be equal to or better than the simple version.
+
+unsigned int MurmurHash1Aligned ( const void * key, int len, unsigned int seed )
+{
+ const unsigned int m = 0xc6a4a793;
+ const int r = 16;
+
+ const unsigned char * data = (const unsigned char *)key;
+
+ unsigned int h = seed ^ (len * m);
+
+ int align = (int)data & 3;
+
+ if(align && (len >= 4))
+ {
+ // Pre-load the temp registers
+
+ unsigned int t = 0, d = 0;
+
+ switch(align)
+ {
+ case 1: t |= data[2] << 16;
+ case 2: t |= data[1] << 8;
+ case 3: t |= data[0];
+ }
+
+ t <<= (8 * align);
+
+ data += 4-align;
+ len -= 4-align;
+
+ int sl = 8 * (4-align);
+ int sr = 8 * align;
+
+ // Mix
+
+ while(len >= 4)
+ {
+ d = *(unsigned int *)data;
+ t = (t >> sr) | (d << sl);
+ h += t;
+ h *= m;
+ h ^= h >> r;
+ t = d;
+
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle leftover data in temp registers
+
+ int pack = len < align ? len : align;
+
+ d = 0;
+
+ switch(pack)
+ {
+ case 3: d |= data[2] << 16;
+ case 2: d |= data[1] << 8;
+ case 1: d |= data[0];
+ case 0: h += (t >> sr) | (d << sl);
+ h *= m;
+ h ^= h >> r;
+ }
+
+ data += pack;
+ len -= pack;
+ }
+ else
+ {
+ while(len >= 4)
+ {
+ h += *(unsigned int *)data;
+ h *= m;
+ h ^= h >> r;
+
+ data += 4;
+ len -= 4;
+ }
+ }
+
+ //----------
+ // Handle tail bytes
+
+ switch(len)
+ {
+ case 3: h += data[2] << 16;
+ case 2: h += data[1] << 8;
+ case 1: h += data[0];
+ h *= m;
+ h ^= h >> r;
+ };
+
+ h *= m;
+ h ^= h >> 10;
+ h *= m;
+ h ^= h >> 17;
+
+ return h;
+}
+
diff --git a/MurmurHash1.h b/MurmurHash1.h
new file mode 100644
index 0000000..e297035
--- /dev/null
+++ b/MurmurHash1.h
@@ -0,0 +1,8 @@
+#include "pstdint.h"
+
+//-----------------------------------------------------------------------------
+
+uint32_t MurmurHash1 ( const void * key, int len, uint32_t seed );
+uint32_t MurmurHash1Aligned ( const void * key, int len, uint32_t seed );
+
+//-----------------------------------------------------------------------------
diff --git a/MurmurHash2.cpp b/MurmurHash2.cpp
new file mode 100644
index 0000000..349ed8e
--- /dev/null
+++ b/MurmurHash2.cpp
@@ -0,0 +1,502 @@
+#include "MurmurHash2.h"
+
+//-----------------------------------------------------------------------------
+// MurmurHash2, by Austin Appleby
+
+// Note - This code makes a few assumptions about how your machine behaves -
+
+// 1. We can read a 4-byte value from any address without crashing
+// 2. sizeof(int) == 4
+
+// And it has a few limitations -
+
+// 1. It will not work incrementally.
+// 2. It will not produce the same results on little-endian and big-endian
+// machines.
+
+uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed )
+{
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+
+ const uint32_t m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+
+ uint32_t h = seed ^ len;
+
+ // Mix 4 bytes at a time into the hash
+
+ const unsigned char * data = (const unsigned char *)key;
+
+ while(len >= 4)
+ {
+ uint32_t k = *(uint32_t*)data;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+
+ switch(len)
+ {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+//-----------------------------------------------------------------------------
+// MurmurHash2, 64-bit versions, by Austin Appleby
+
+// The same caveats as 32-bit MurmurHash2 apply here - beware of alignment
+// and endian-ness issues if used across multiple platforms.
+
+// 64-bit hash for 64-bit platforms
+
+uint64_t MurmurHash64A ( const void * key, int len, uint64_t seed )
+{
+ const uint64_t m = 0xc6a4a7935bd1e995;
+ const int r = 47;
+
+ uint64_t h = seed ^ (len * m);
+
+ const uint64_t * data = (const uint64_t *)key;
+ const uint64_t * end = data + (len/8);
+
+ while(data != end)
+ {
+ uint64_t k = *data++;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h ^= k;
+ h *= m;
+ }
+
+ const unsigned char * data2 = (const unsigned char*)data;
+
+ switch(len & 7)
+ {
+ case 7: h ^= uint64_t(data2[6]) << 48;
+ case 6: h ^= uint64_t(data2[5]) << 40;
+ case 5: h ^= uint64_t(data2[4]) << 32;
+ case 4: h ^= uint64_t(data2[3]) << 24;
+ case 3: h ^= uint64_t(data2[2]) << 16;
+ case 2: h ^= uint64_t(data2[1]) << 8;
+ case 1: h ^= uint64_t(data2[0]);
+ h *= m;
+ };
+
+ h ^= h >> r;
+ h *= m;
+ h ^= h >> r;
+
+ return h;
+}
+
+
+// 64-bit hash for 32-bit platforms
+
+uint64_t MurmurHash64B ( const void * key, int len, uint64_t seed )
+{
+ const uint32_t m = 0x5bd1e995;
+ const int r = 24;
+
+ uint32_t h1 = uint32_t(seed) ^ len;
+ uint32_t h2 = uint32_t(seed >> 32);
+
+ const uint32_t * data = (const uint32_t *)key;
+
+ while(len >= 8)
+ {
+ uint32_t k1 = *data++;
+ k1 *= m; k1 ^= k1 >> r; k1 *= m;
+ h1 *= m; h1 ^= k1;
+ len -= 4;
+
+ uint32_t k2 = *data++;
+ k2 *= m; k2 ^= k2 >> r; k2 *= m;
+ h2 *= m; h2 ^= k2;
+ len -= 4;
+ }
+
+ if(len >= 4)
+ {
+ uint32_t k1 = *data++;
+ k1 *= m; k1 ^= k1 >> r; k1 *= m;
+ h1 *= m; h1 ^= k1;
+ len -= 4;
+ }
+
+ switch(len)
+ {
+ case 3: h2 ^= ((unsigned char*)data)[2] << 16;
+ case 2: h2 ^= ((unsigned char*)data)[1] << 8;
+ case 1: h2 ^= ((unsigned char*)data)[0];
+ h2 *= m;
+ };
+
+ h1 ^= h2 >> 18; h1 *= m;
+ h2 ^= h1 >> 22; h2 *= m;
+ h1 ^= h2 >> 17; h1 *= m;
+ h2 ^= h1 >> 19; h2 *= m;
+
+ uint64_t h = h1;
+
+ h = (h << 32) | h2;
+
+ return h;
+}
+
+//-----------------------------------------------------------------------------
+// MurmurHash2A, by Austin Appleby
+
+// This is a variant of MurmurHash2 modified to use the Merkle-Damgard
+// construction. Bulk speed should be identical to Murmur2, small-key speed
+// will be 10%-20% slower due to the added overhead at the end of the hash.
+
+// This variant fixes a minor issue where null keys were more likely to
+// collide with each other than expected, and also makes the function
+// more amenable to incremental implementations.
+
+#define mmix(h,k) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
+
+uint32_t MurmurHash2A ( const void * key, int len, uint32_t seed )
+{
+ const uint32_t m = 0x5bd1e995;
+ const int r = 24;
+ uint32_t l = len;
+
+ const unsigned char * data = (const unsigned char *)key;
+
+ uint32_t h = seed;
+
+ while(len >= 4)
+ {
+ uint32_t k = *(uint32_t*)data;
+
+ mmix(h,k);
+
+ data += 4;
+ len -= 4;
+ }
+
+ uint32_t t = 0;
+
+ switch(len)
+ {
+ case 3: t ^= data[2] << 16;
+ case 2: t ^= data[1] << 8;
+ case 1: t ^= data[0];
+ };
+
+ mmix(h,t);
+ mmix(h,l);
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+//-----------------------------------------------------------------------------
+// CMurmurHash2A, by Austin Appleby
+
+// This is a sample implementation of MurmurHash2A designed to work
+// incrementally.
+
+// Usage -
+
+// CMurmurHash2A hasher
+// hasher.Begin(seed);
+// hasher.Add(data1,size1);
+// hasher.Add(data2,size2);
+// ...
+// hasher.Add(dataN,sizeN);
+// uint32_t hash = hasher.End()
+
+class CMurmurHash2A
+{
+public:
+
+ void Begin ( uint32_t seed = 0 )
+ {
+ m_hash = seed;
+ m_tail = 0;
+ m_count = 0;
+ m_size = 0;
+ }
+
+ void Add ( const unsigned char * data, int len )
+ {
+ m_size += len;
+
+ MixTail(data,len);
+
+ while(len >= 4)
+ {
+ uint32_t k = *(uint32_t*)data;
+
+ mmix(m_hash,k);
+
+ data += 4;
+ len -= 4;
+ }
+
+ MixTail(data,len);
+ }
+
+ uint32_t End ( void )
+ {
+ mmix(m_hash,m_tail);
+ mmix(m_hash,m_size);
+
+ m_hash ^= m_hash >> 13;
+ m_hash *= m;
+ m_hash ^= m_hash >> 15;
+
+ return m_hash;
+ }
+
+private:
+
+ static const uint32_t m = 0x5bd1e995;
+ static const int r = 24;
+
+ void MixTail ( const unsigned char * & data, int & len )
+ {
+ while( len && ((len<4) || m_count) )
+ {
+ m_tail |= (*data++) << (m_count * 8);
+
+ m_count++;
+ len--;
+
+ if(m_count == 4)
+ {
+ mmix(m_hash,m_tail);
+ m_tail = 0;
+ m_count = 0;
+ }
+ }
+ }
+
+ uint32_t m_hash;
+ uint32_t m_tail;
+ uint32_t m_count;
+ uint32_t m_size;
+};
+
+//-----------------------------------------------------------------------------
+// MurmurHashNeutral2, by Austin Appleby
+
+// Same as MurmurHash2, but endian- and alignment-neutral.
+// Half the speed though, alas.
+
+uint32_t MurmurHashNeutral2 ( const void * key, int len, uint32_t seed )
+{
+ const uint32_t m = 0x5bd1e995;
+ const int r = 24;
+
+ uint32_t h = seed ^ len;
+
+ const unsigned char * data = (const unsigned char *)key;
+
+ while(len >= 4)
+ {
+ uint32_t k;
+
+ k = data[0];
+ k |= data[1] << 8;
+ k |= data[2] << 16;
+ k |= data[3] << 24;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ switch(len)
+ {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+//-----------------------------------------------------------------------------
+// MurmurHashAligned2, by Austin Appleby
+
+// Same algorithm as MurmurHash2, but only does aligned reads - should be safer
+// on certain platforms.
+
+// Performance will be lower than MurmurHash2
+
+#define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; }
+
+uint32_t MurmurHashAligned2 ( const void * key, int len, uint32_t seed )
+{
+ const uint32_t m = 0x5bd1e995;
+ const int r = 24;
+
+ const unsigned char * data = (const unsigned char *)key;
+
+ uint32_t h = seed ^ len;
+
+ int align = (int)data & 3;
+
+ if(align && (len >= 4))
+ {
+ // Pre-load the temp registers
+
+ uint32_t t = 0, d = 0;
+
+ switch(align)
+ {
+ case 1: t |= data[2] << 16;
+ case 2: t |= data[1] << 8;
+ case 3: t |= data[0];
+ }
+
+ t <<= (8 * align);
+
+ data += 4-align;
+ len -= 4-align;
+
+ int sl = 8 * (4-align);
+ int sr = 8 * align;
+
+ // Mix
+
+ while(len >= 4)
+ {
+ d = *(uint32_t *)data;
+ t = (t >> sr) | (d << sl);
+
+ uint32_t k = t;
+
+ MIX(h,k,m);
+
+ t = d;
+
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle leftover data in temp registers
+
+ d = 0;
+
+ if(len >= align)
+ {
+ switch(align)
+ {
+ case 3: d |= data[2] << 16;
+ case 2: d |= data[1] << 8;
+ case 1: d |= data[0];
+ }
+
+ uint32_t k = (t >> sr) | (d << sl);
+ MIX(h,k,m);
+
+ data += align;
+ len -= align;
+
+ //----------
+ // Handle tail bytes
+
+ switch(len)
+ {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+ }
+ else
+ {
+ switch(len)
+ {
+ case 3: d |= data[2] << 16;
+ case 2: d |= data[1] << 8;
+ case 1: d |= data[0];
+ case 0: h ^= (t >> sr) | (d << sl);
+ h *= m;
+ }
+ }
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+ }
+ else
+ {
+ while(len >= 4)
+ {
+ uint32_t k = *(uint32_t *)data;
+
+ MIX(h,k,m);
+
+ data += 4;
+ len -= 4;
+ }
+
+ //----------
+ // Handle tail bytes
+
+ switch(len)
+ {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
diff --git a/MurmurHash2.h b/MurmurHash2.h
new file mode 100644
index 0000000..e3b00da
--- /dev/null
+++ b/MurmurHash2.h
@@ -0,0 +1,13 @@
+#include "pstdint.h"
+
+//-----------------------------------------------------------------------------
+
+uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed );
+uint64_t MurmurHash64A ( const void * key, int len, uint64_t seed );
+uint64_t MurmurHash64B ( const void * key, int len, uint64_t seed );
+uint32_t MurmurHash2A ( const void * key, int len, uint32_t seed );
+uint32_t MurmurHashNeutral2 ( const void * key, int len, uint32_t seed );
+uint32_t MurmurHashAligned2 ( const void * key, int len, uint32_t seed );
+
+//-----------------------------------------------------------------------------
+
diff --git a/MurmurHash2_test.cpp b/MurmurHash2_test.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MurmurHash2_test.cpp
diff --git a/MurmurHash3.cpp b/MurmurHash3.cpp
new file mode 100644
index 0000000..581d1d3
--- /dev/null
+++ b/MurmurHash3.cpp
@@ -0,0 +1,288 @@
+#include "MurmurHash3.h"
+
+#include <stdlib.h> // for _rotl
+
+#pragma warning(disable:4100)
+
+//-----------------------------------------------------------------------------
+// need to replace this
+
+inline uint32_t kmix ( uint32_t k, uint32_t c1, uint32_t c2 )
+{
+ k *= c1;
+ k = _rotl(k,11);
+ k *= c2;
+
+ return k;
+}
+
+// block mix
+
+inline void bmix1 ( uint32_t & h, uint32_t k, uint32_t c1, uint32_t c2 )
+{
+ k = kmix(k,c1,c2);
+
+ h = h*5+0xa6b84e31;
+ h ^= k;
+}
+
+// xor before mul is faster on x64
+
+inline void bmix2 ( uint32_t & h, uint32_t k, uint32_t c1, uint32_t c2 )
+{
+ k = kmix(k,c1,c2);
+
+ h ^= k;
+ h = h*3+0xa6b84e31;
+}
+
+// block constant mix
+
+inline void cmix ( uint32_t & c1, uint32_t & c2 )
+{
+ c1 = c1*9+0x273581d8;
+ c2 = c2*5+0xee700bac;
+}
+
+// finalizer mix - avalanches all bits to within 0.25% bias
+
+inline uint32_t fmix32 ( uint32_t h )
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+
+ return h;
+}
+
+// 64-bit finalizer mix - avalanches all bits to within 0.05% bias
+
+inline uint64_t fmix64 ( uint64_t k )
+{
+ k ^= k >> 33;
+ k *= 0xff51afd7ed558ccd;
+ k ^= k >> 33;
+ k *= 0xc4ceb9fe1a85ec53;
+ k ^= k >> 33;
+
+ return k;
+}
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out )
+{
+ uint32_t h = 0x971e137b ^ seed;
+
+ const uint8_t * tail = (const uint8_t*)(key) + (len & ~3);
+
+ //----------
+ // body
+
+ const uint32_t * block = (const uint32_t *)tail;
+
+ uint32_t c1 = 0x95543787;
+ uint32_t c2 = 0x2ad7eb25;
+
+ for(int l = -(len/4); l; l++)
+ {
+ bmix1(h,block[l],c1,c2);
+ cmix(c1,c2);
+ }
+
+ //----------
+ // tail
+
+ uint32_t k = 0;
+
+ switch(len & 3)
+ {
+ case 3: k ^= tail[2] << 16;
+ case 2: k ^= tail[1] << 8;
+ case 1: k ^= tail[0];
+ bmix1(h,k,c1,c2);
+ };
+
+ //----------
+ // finalization
+
+ h ^= len;
+
+ h = fmix32(h);
+
+ *(uint32_t*)out = h;
+}
+
+//-----------------------------------------------------------------------------
+
+void merge64 ( uint32_t h[2], const uint32_t * blocks, uint32_t c1, uint32_t c2 )
+{
+ h[0] = _rotl(h[0],9);
+ h[1] = _rotl(h[1],24);
+
+ h[0] += h[1];
+ h[1] += h[0];
+
+ bmix1(h[0],blocks[0],c1,c2);
+ bmix1(h[1],blocks[1],c1,c2);
+}
+
+//----------
+
+void MurmurHash3_x86_64 ( const void * data, int len, uint32_t seed, void * out )
+{
+ uint32_t h[2];
+
+ h[0] = 0x8de1c3ac ^ seed;
+ h[1] = 0xbab98226 ^ seed;
+
+ //----------
+ // body
+
+ const uint32_t * blocks = (const uint32_t *)data;
+
+ uint32_t c1 = 0x95543787;
+ uint32_t c2 = 0x2ad7eb25;
+
+ while(len >= 8)
+ {
+ merge64(h,blocks,c1,c2);
+ cmix(c1,c2);
+
+ blocks += 2;
+ len -= 8;
+ }
+
+ //----------
+ // tail
+
+ uint32_t k[2] = { 0, 0 };
+
+ const uint8_t * tail = (const uint8_t*)blocks;
+
+ switch(len)
+ {
+ case 7: k[1] ^= tail[6] << 16;
+ case 6: k[1] ^= tail[5] << 8;
+ case 5: k[1] ^= tail[4] << 0;
+ case 4: k[0] ^= tail[3] << 24;
+ case 3: k[0] ^= tail[2] << 16;
+ case 2: k[0] ^= tail[1] << 8;
+ case 1: k[0] ^= tail[0] << 0;
+ merge64(h,k,c1,c2);
+ };
+
+ //----------
+ // finalization
+
+ h[1] ^= len;
+
+ h[0] = fmix32(h[0]);
+ h[1] ^= kmix(h[0],c1,c2);
+ h[0] ^= fmix32(h[1]);
+ h[1] ^= kmix(h[0],c1,c2);
+
+ ((uint32_t*)out)[0] = h[0];
+ ((uint32_t*)out)[1] = h[1];
+}
+
+//-----------------------------------------------------------------------------
+
+void merge128 ( uint32_t h[4], const uint32_t * blocks, uint32_t c1, uint32_t c2 )
+{
+ h[0] = _rotl(h[0],3);
+ h[1] = _rotl(h[1],10);
+ h[2] = _rotl(h[2],19);
+ h[3] = _rotl(h[3],26);
+
+ h[0] += h[1];
+ h[0] += h[2];
+ h[0] += h[3];
+
+ h[1] += h[0];
+ h[2] += h[0];
+ h[3] += h[0];
+
+ bmix1(h[0],blocks[0],c1,c2);
+ bmix1(h[1],blocks[1],c1,c2);
+ bmix1(h[2],blocks[2],c1,c2);
+ bmix1(h[3],blocks[3],c1,c2);
+}
+
+//----------
+
+void MurmurHash3_x86_128 ( const void * data, int len, uint32_t seed, uint32_t * out )
+{
+ uint32_t h[4] =
+ {
+ 0x8de1c3ac ^ seed,
+ 0xbab98226 ^ seed,
+ 0xfcba5b2d ^ seed,
+ 0x32452e3e ^ seed
+ };
+
+ //----------
+ // body
+
+ const uint32_t * blocks = (const uint32_t *)data;
+
+ uint32_t c1 = 0x95543787;
+ uint32_t c2 = 0x2ad7eb25;
+
+ while(len >= 16)
+ {
+ merge128(h,blocks,c1,c2);
+ cmix(c1,c2);
+
+ blocks += 4;
+ len -= 16;
+ }
+
+ //----------
+ // tail
+
+ uint32_t k[4] = { 0, 0, 0, 0 };
+
+ const uint8_t * tail = (const uint8_t*)blocks;
+
+ switch(len)
+ {
+ case 15: k[3] ^= tail[14] << 16;
+ case 14: k[3] ^= tail[13] << 8;
+ case 13: k[3] ^= tail[12] << 0;
+ case 12: k[2] ^= tail[11] << 24;
+ case 11: k[2] ^= tail[10] << 16;
+ case 10: k[2] ^= tail[ 9] << 8;
+ case 9: k[2] ^= tail[ 8] << 0;
+ case 8: k[1] ^= tail[ 7] << 24;
+ case 7: k[1] ^= tail[ 6] << 16;
+ case 6: k[1] ^= tail[ 5] << 8;
+ case 5: k[1] ^= tail[ 4] << 0;
+ case 4: k[0] ^= tail[ 3] << 24;
+ case 3: k[0] ^= tail[ 2] << 16;
+ case 2: k[0] ^= tail[ 1] << 8;
+ case 1: k[0] ^= tail[ 0] << 0;
+ merge128(h,k,c1,c2);
+ };
+
+ //----------
+ // finalization
+
+ h[3] ^= len;
+
+ h[0] ^= fmix32(h[1]); h[2] ^= fmix32(h[3]);
+ h[1] ^= kmix(h[0],c1,c2); h[3] ^= kmix(h[2],c1,c2);
+ h[3] ^= fmix32(h[0]); h[1] ^= fmix32(h[2]);
+ h[0] ^= kmix(h[3],c1,c2); h[2] ^= kmix(h[1],c1,c2);
+ h[1] ^= fmix32(h[0]); h[3] ^= fmix32(h[2]);
+
+ out[0] = h[0];
+ out[1] = h[1];
+ out[2] = h[2];
+ out[3] = h[3];
+}
+
+//-----------------------------------------------------------------------------
+
diff --git a/MurmurHash3.h b/MurmurHash3.h
new file mode 100644
index 0000000..5e19064
--- /dev/null
+++ b/MurmurHash3.h
@@ -0,0 +1,11 @@
+#include "pstdint.h"
+
+//-----------------------------------------------------------------------------
+
+void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out );
+void MurmurHash3_x64_32 ( const void * key, int len, uint32_t seed, void * out );
+void MurmurHash3_x86_64 ( const void * key, int len, uint32_t seed, void * out );
+void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out );
+
+//-----------------------------------------------------------------------------
+
diff --git a/MurmurHash64.cpp b/MurmurHash64.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MurmurHash64.cpp
diff --git a/MurmurHashAligned.cpp b/MurmurHashAligned.cpp
new file mode 100644
index 0000000..716dda6
--- /dev/null
+++ b/MurmurHashAligned.cpp
@@ -0,0 +1,2 @@
+#include "stdafx.h"
+
diff --git a/MurmurHashAligned2.cpp b/MurmurHashAligned2.cpp
new file mode 100644
index 0000000..23dced4
--- /dev/null
+++ b/MurmurHashAligned2.cpp
@@ -0,0 +1,4 @@
+#include "stdafx.h"
+
+#pragma warning(disable:4311)
+
diff --git a/MurmurHashNeutral2.cpp b/MurmurHashNeutral2.cpp
new file mode 100644
index 0000000..716dda6
--- /dev/null
+++ b/MurmurHashNeutral2.cpp
@@ -0,0 +1,2 @@
+#include "stdafx.h"
+
diff --git a/MurmurHashTest.cpp b/MurmurHashTest.cpp
new file mode 100644
index 0000000..6b18f53
--- /dev/null
+++ b/MurmurHashTest.cpp
@@ -0,0 +1,26 @@
+#include "pstdint.h"
+
+uint32_t MurmurHash1 ( const void * key, int len, uint32_t seed );
+uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed );
+uint64_t MurmurHash64A ( const void * key, int len, uint64_t seed );
+uint64_t MurmurHash64B ( const void * key, int len, uint64_t seed );
+uint32_t MurmurHash2A ( const void * key, int len, uint32_t seed );
+uint32_t MurmurHashNeutral2 ( const void * key, int len, uint32_t seed );
+uint32_t MurmurHashAligned2 ( const void * key, int len, uint32_t seed );
+
+
+void MurmurHash1_test ( const void * key, int len, uint32_t seed, void * out )
+{
+ *(uint32_t*)out = MurmurHash1(key,len,seed);
+}
+
+void MurmurHash2_test ( const void * key, int len, uint32_t seed, void * out )
+{
+ *(uint32_t*)out = MurmurHash2(key,len,seed);
+}
+
+void MurmurHash2A_test ( const void * key, int len, uint32_t seed, void * out )
+{
+ *(uint32_t*)out = MurmurHash2A(key,len,seed);
+}
+
diff --git a/Random.cpp b/Random.cpp
new file mode 100644
index 0000000..12d7077
--- /dev/null
+++ b/Random.cpp
@@ -0,0 +1,61 @@
+#include "Random.h"
+
+Rand g_rand1(1);
+Rand g_rand2(2);
+Rand g_rand3(3);
+Rand g_rand4(4);
+
+//-----------------------------------------------------------------------------
+// Pseudo-random oracle. Mix avalanches x/y/z to < 0.07% bias.
+
+inline void omix ( uint32_t & x, uint32_t & y, uint32_t & z )
+{
+ uint64_t m = 0x65a3d38b;
+ uint64_t t = 0;
+
+ t = x * m; y ^= t; z ^= (t >> 32);
+ t = z * m; x ^= t; y ^= (t >> 32);
+ t = y * m; z ^= t; x ^= (t >> 32);
+ t = x * m; y ^= t; z ^= (t >> 32);
+ t = z * m; x ^= t; y ^= (t >> 32);
+ t = y * m; z ^= t; x ^= (t >> 32);
+}
+
+void oracle ( uint32_t key, uint32_t nonce, void * blob, int size )
+{
+ uint32_t x = 0x498b3bc5;
+ uint32_t y = 0x9c3ed699;
+ uint32_t z = 0x5a05089a;
+
+ x ^= key;
+ y ^= nonce;
+ z ^= size;
+
+ uint8_t * cursor = (uint8_t*)blob;
+
+ while(size)
+ {
+ omix(x,y,z);
+
+ if(size > 4)
+ {
+ *(uint32_t*)cursor = x;
+
+ cursor += 4;
+ size -= 4;
+ }
+ else
+ {
+ switch(size)
+ {
+ case 3: cursor[2] = (uint8_t)(x >> 16);
+ case 2: cursor[1] = (uint8_t)(x >> 8);
+ case 1: cursor[0] = (uint8_t)(x >> 0);
+ };
+
+ return;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
diff --git a/Random.h b/Random.h
new file mode 100644
index 0000000..87ed656
--- /dev/null
+++ b/Random.h
@@ -0,0 +1,144 @@
+#pragma once
+
+#include "Types.h"
+
+//-----------------------------------------------------------------------------
+// random oracle (stateless)
+
+void oracle ( uint32_t key, uint32_t nonce, void * blob, int size );
+
+//-----------------------------------------------------------------------------
+// Xorshift-based RNG from George Marsaglia, algorithm taken from Wikipedia
+
+struct Rand
+{
+ uint32_t x;
+ uint32_t y;
+ uint32_t z;
+ uint32_t w;
+
+ Rand()
+ {
+ reseed(uint32_t(0));
+ }
+
+ Rand( uint32_t seed )
+ {
+ reseed(seed);
+ }
+
+ uint32_t rand_u32 ( void )
+ {
+ uint32_t t = x ^ (x << 11);
+
+ x = y;
+ y = z;
+ z = w;
+ w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
+
+ return w;
+ }
+
+
+ void reseed ( uint32_t seed )
+ {
+ x = 0x498b3bc5 ^ seed;
+ y = 0x9c3ed699 ^ seed;
+ z = 0x5a05089a ^ seed;
+ w = 0x2c8a5c59 ^ seed;
+
+ for(int i = 0; i < 10; i++) rand_u32();
+ }
+
+ void reseed ( uint64_t seed )
+ {
+ x = 0x498b3bc5 ^ (uint32_t)(seed >> 0);
+ y = 0x9c3ed699 ^ (uint32_t)(seed >> 11);
+ z = 0x5a05089a ^ (uint32_t)(seed >> 22);
+ w = 0x2c8a5c59 ^ (uint32_t)(seed >> 32);
+
+ for(int i = 0; i < 10; i++) rand_u32();
+ }
+
+ //-----------------------------------------------------------------------------
+
+ operator uint32_t ( void )
+ {
+ return rand_u32();
+ }
+
+ operator uint64_t ( void )
+ {
+ uint64_t a = rand_u32();
+
+ a <<= 32;
+ a |= rand_u32();
+
+ return a;
+ }
+
+ void rand_p ( void * blob, int bytes )
+ {
+ uint32_t * blocks = (uint32_t*)blob;
+
+ while(bytes >= 4)
+ {
+ *blocks++ = rand_u32();
+ bytes -= 4;
+ }
+
+ uint8_t * tail = (uint8_t*)blocks;
+
+ for(int i = 0; i < bytes; i++)
+ {
+ tail[i] = (uint8_t)rand_u32();
+ }
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+extern Rand g_rand1;
+
+inline uint32_t rand_u32 ( void ) { return g_rand1; }
+inline uint64_t rand_u64 ( void ) { return g_rand1; }
+
+inline void rand_p ( void * blob, int bytes )
+{
+ uint32_t * blocks = (uint32_t*)blob;
+
+ while(bytes >= 4)
+ {
+ *blocks++ = rand_u32();
+ bytes -= 4;
+ }
+
+ uint8_t * tail = (uint8_t*)blocks;
+
+ for(int i = 0; i < bytes; i++)
+ {
+ tail[i] = (uint8_t)rand_u32();
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+template < typename T >
+inline void rand_t ( T & t )
+{
+ rand_p(&,sizeof(t));
+}
+
+template<> inline void rand_t ( uint32_t & t ) { t = rand_u32(); }
+template<> inline void rand_t ( uint64_t & t ) { t = rand_u64(); }
+
+template<> inline void rand_t ( u128 & t )
+{
+ uint32_t * b = (uint32_t*)&t;
+ b[0] = rand_u32();
+ b[1] = rand_u32();
+ b[2] = rand_u32();
+ b[3] = rand_u32();
+}
+
+//-----------------------------------------------------------------------------
diff --git a/SimAnneal.cpp b/SimAnneal.cpp
new file mode 100644
index 0000000..0096598
--- /dev/null
+++ b/SimAnneal.cpp
@@ -0,0 +1,97 @@
+#include "SimAnneal.h"
+
+#include "Types.h"
+#include "Random.h"
+
+//-----------------------------------------------------------------------------
+// Pseudo-simulated-annealing
+
+double SimAnneal ( void * block, int len, pfFitness fit, pfDump dump, int nFlip, int reps )
+{
+ double baseScore = fit(block,len);
+ double tempScore = 0;
+ double bestScore = 0;
+
+ uint8_t * baseBlock = new uint8_t[len];
+ uint8_t * tempBlock = new uint8_t[len];
+ uint8_t * bestBlock = new uint8_t[len];
+
+ memcpy(baseBlock,block,len);
+ memcpy(tempBlock,block,len);
+ memcpy(bestBlock,block,len);
+
+ while(nFlip)
+ {
+ printf("fit - %f, bits - %2d, dump - ",baseScore,nFlip);
+
+ dump(baseBlock,len);
+
+ bestScore = baseScore;
+
+ if(nFlip == 1)
+ {
+ for(int i = 0; i < len*8; i++)
+ {
+ printf(".");
+
+ memcpy(tempBlock,baseBlock,len);
+ flipbit(tempBlock,len,i);
+
+ tempScore = fit(tempBlock,len);
+
+ if(tempScore > bestScore)
+ {
+ bestScore = tempScore;
+ memcpy(bestBlock,tempBlock,len);
+ break;
+ }
+ }
+ }
+ else
+ {
+ for(int i = 0; i < reps; i++)
+ {
+ //if(i % (reps/10) == 0) printf(".");
+ printf(".");
+
+ memcpy(tempBlock,baseBlock,len);
+
+ for(int i = 0; i < nFlip; i++)
+ {
+ flipbit( tempBlock, len, rand_u32() % (len*8) );
+ }
+
+ tempScore = fit(tempBlock,len);
+
+ if(tempScore > bestScore)
+ {
+ bestScore = tempScore;
+ memcpy(bestBlock,tempBlock,len);
+ break;
+ }
+ }
+ }
+
+ printf("\n");
+
+ // If we found a better solution, expand space starting from that solution
+ // Otherwise, shrink space around previous best
+
+ if(bestScore > baseScore)
+ {
+ memcpy(baseBlock,bestBlock,len);
+ baseScore = bestScore;
+
+ nFlip++;
+ }
+ else
+ {
+ nFlip--;
+ }
+ }
+
+ memcpy(block,baseBlock,len);
+ return baseScore;
+}
+
+
diff --git a/SimAnneal.h b/SimAnneal.h
new file mode 100644
index 0000000..1670bbe
--- /dev/null
+++ b/SimAnneal.h
@@ -0,0 +1,6 @@
+#pragma once
+
+typedef double (*pfFitness) ( void * block, int len );
+typedef void (*pfDump) ( void * block, int len );
+
+double SimAnneal ( void * block, int len, pfFitness fit, pfDump dump, int nFlip, int reps ); \ No newline at end of file
diff --git a/SparseKeyTest.cpp b/SparseKeyTest.cpp
new file mode 100644
index 0000000..234b6bb
--- /dev/null
+++ b/SparseKeyTest.cpp
@@ -0,0 +1,111 @@
+#include "SparseKeyTest.h"
+
+#include "Types.h"
+#include "Stats.h" // for testkeylist
+
+//----------------------------------------------------------------------------
+
+template < int keybits, typename hashtype >
+bool SparseKeyTest3 ( hashfunc<hashtype> hash, const int setbits, bool inclusive, bool testColl, bool testDist, bool drawDiagram )
+{
+ printf("Testing %d-bit keys with %s %d bits set - ",keybits, inclusive ? "up to" : "exactly", setbits);
+
+ typedef Blob<keybits> keytype;
+
+ std::vector<keytype> keys;
+
+ keytype k;
+ memset(&k,0,sizeof(k));
+
+ if(inclusive) keys.push_back(k);
+
+ SparseKeygenRecurse(0,setbits,inclusive,k,keys);
+
+ printf("%d keys, %d bytes\n",(int)keys.size(),(int)keys.size() * sizeof(keytype));
+
+ bool result = testkeylist<keytype,hashtype>(hash,keys,testColl,testDist,drawDiagram);
+
+ printf("\n");
+
+ return result;
+}
+
+//----------------------------------------------------------------------------
+
+template< typename hashtype >
+bool SparsePermuteKeyTest2 ( hashfunc<hashtype> hash, bool testColl, bool testDist, bool drawDiagram )
+{
+ bool result = true;
+
+ typedef Blob<320> keytype;
+
+ std::vector<keytype> keys;
+
+ printf("Testing %d-bit sparse-permute keys - ",sizeof(keytype)*8);
+
+ //----------
+
+ keytype key;
+
+ const int ndwords = sizeof(keytype) / 4;
+ uint32_t * dwords = (uint32_t*)&key;
+
+ for(int i = 0; i < ndwords; i++)
+ {
+ dwords[i] = uint32_t(1) << ((i+2) * 3);
+ }
+
+ SPKeygenRecurse2(key,0,keys);
+
+ printf("%d keys, %d bytes\n",(int)keys.size(),(int)keys.size() * sizeof(keytype));
+
+ //----------
+
+ result &= testkeylist<keytype,hashtype>(hash,keys,testColl,testDist,drawDiagram);
+
+ return result;
+}
+
+//----------------------------------------------------------------------------
+// Inclusive test produces about the same distribution on poor hashes, and
+// tends to create more collisions.
+
+template < typename hashtype >
+bool SparseKeyTest2 ( hashfunc<hashtype> hash, bool drawDiagram )
+{
+ bool result = true;
+
+ result &= SparseKeyTest3<32,hashtype>(hash,6,true,true,true,drawDiagram);
+ result &= SparseKeyTest3<40,hashtype>(hash,6,true,true,true,drawDiagram);
+ result &= SparseKeyTest3<48,hashtype>(hash,5,true,true,true,drawDiagram);
+ result &= SparseKeyTest3<56,hashtype>(hash,5,true,true,true,drawDiagram);
+
+ result &= SparseKeyTest3<64,hashtype>(hash,5,true,true,true,drawDiagram);
+ result &= SparseKeyTest3<96,hashtype>(hash,4,true,true,true,drawDiagram);
+ result &= SparseKeyTest3<256,hashtype>(hash,3,true,true,true,drawDiagram);
+ result &= SparseKeyTest3<1536,hashtype>(hash,2,true,true,true,drawDiagram);
+
+ // 192-bit sparse keys with 4 bits set generates 1.4 gigs of keydata - use
+ // at your own risk
+
+ // SparseKeyTest3<192,4,hashtype>(hash,true,true,true);
+
+ result &= SparsePermuteKeyTest2<hashtype>(hash,true,true,drawDiagram);
+
+ return result;
+}
+
+bool SparseKeyTest ( hashfunc<uint32_t> hash, bool drawDiagram )
+{
+ return SparseKeyTest2<uint32_t>(hash,drawDiagram);
+}
+
+bool SparseKeyTest ( hashfunc<uint64_t> hash, bool drawDiagram )
+{
+ return SparseKeyTest2<uint64_t>(hash,drawDiagram);
+}
+
+bool SparseKeyTest ( hashfunc<u128> hash, bool drawDiagram )
+{
+ return SparseKeyTest2<u128>(hash,drawDiagram);
+}
diff --git a/SparseKeyTest.h b/SparseKeyTest.h
new file mode 100644
index 0000000..bfec8c5
--- /dev/null
+++ b/SparseKeyTest.h
@@ -0,0 +1,89 @@
+#pragma once
+
+#include "Types.h"
+
+#pragma warning(push)
+#pragma warning(disable:4200) // user-defined type contains zero length array
+#pragma warning(disable:4127) // conditional expression is constant
+
+//-----------------------------------------------------------------------------
+
+template < typename keytype >
+void SparseKeygenRecurse ( int start, int bitsleft, bool inclusive, keytype & k, std::vector<keytype> & keys )
+{
+ const int nbytes = sizeof(keytype);
+ const int nbits = nbytes * 8;
+
+ for(int i = start; i < nbits; i++)
+ {
+ flipbit(&k,nbytes,i);
+
+ if(inclusive || (bitsleft == 1))
+ {
+ keys.push_back(k);
+ }
+
+ if(bitsleft > 1)
+ {
+ SparseKeygenRecurse(i+1,bitsleft-1,inclusive,k,keys);
+ }
+
+ flipbit(&k,nbytes,i);
+ }
+}
+
+//----------
+
+template < typename keytype >
+void SparseKeygenRecurse_R ( int start, int bitsleft, bool inclusive, keytype & k, std::vector<keytype> & keys )
+{
+ const int nbytes = sizeof(keytype);
+ const int nbits = nbytes * 8;
+
+ for(int i = start; i < nbits; i++)
+ {
+ flipbit(&k,nbytes,(bits-i-1));
+
+ if(inclusive || (bitsleft == 1))
+ {
+ keys.push_back(k);
+ }
+
+ if(bitsleft > 1)
+ {
+ SparseKeygenRecurse(i+1,bitsleft-1,inclusive,k,keys);
+ }
+
+ flipbit(&k,nbytes,(bits-i-1));
+ }
+}
+
+//----------
+
+template< typename keytype >
+void SPKeygenRecurse2 ( keytype & key, int k, std::vector<keytype> & keys )
+{
+ //assert(keytype::align4);
+
+ const int ndwords = key.nbytes/4;
+ uint32_t * dwords = (uint32_t*)&key;
+
+ if(k == ndwords-1)
+ {
+ keys.push_back(key);
+ return;
+ }
+
+ for(int i = k; i < ndwords; i++)
+ {
+ swap(dwords[k],dwords[i]);
+
+ SPKeygenRecurse2(key,k+1,keys);
+
+ swap(dwords[k],dwords[i]);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+#pragma warning(pop)
diff --git a/Stats.cpp b/Stats.cpp
new file mode 100644
index 0000000..31ca481
--- /dev/null
+++ b/Stats.cpp
@@ -0,0 +1,338 @@
+#include "Stats.h"
+
+//-----------------------------------------------------------------------------
+
+// If you want to compute these two statistics, uncomment the code and link with
+// the GSL library.
+
+/*
+extern "C"
+{
+ double gsl_sf_gamma_inc_P(const double a, const double x);
+ double gsl_sf_gamma_inc_Q(const double a, const double x);
+};
+
+// P-val for a set of binomial distributions
+
+void pval_binomial ( int * buckets, int len, int n, double p, double & sdev, double & pval )
+{
+ double c = 0;
+
+ double u = n*p;
+ double s = sqrt(n*p*(1-p));
+
+ for(int i = 0; i < len; i++)
+ {
+ double x = buckets[i];
+
+ double n = (x-u)/s;
+
+ c += n*n;
+ }
+
+ sdev = sqrt(c / len);
+
+ pval = gsl_sf_gamma_inc_P( len/2, c/2 );
+}
+
+// P-val for a histogram - K keys distributed between N buckets
+// Note the (len-1) due to the degree-of-freedom reduction
+
+void pval_pearson ( int * buckets, int len, int keys, double & sdev, double & pval )
+{
+ double c = 0;
+
+ double n = keys;
+ double p = 1.0 / double(len);
+
+ double u = n*p;
+ double s = sqrt(n*p*(1-p));
+
+ for(int i = 0; i < len; i++)
+ {
+ double x = buckets[i];
+
+ double n = (x-u)/s;
+
+ c += n*n;
+ }
+
+ sdev = sqrt(c / len);
+
+ pval = gsl_sf_gamma_inc_P( (len-1)/2, c/2 );
+}
+*/
+
+//----------------------------------------------------------------------------
+
+double erf2 ( double x )
+{
+ const double a1 = 0.254829592;
+ const double a2 = -0.284496736;
+ const double a3 = 1.421413741;
+ const double a4 = -1.453152027;
+ const double a5 = 1.061405429;
+ const double p = 0.3275911;
+
+ double sign = 1;
+ if(x < 0) sign = -1;
+
+ x = abs(x);
+
+ double t = 1.0/(1.0 + p*x);
+ double y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x);
+
+ return sign*y;
+}
+
+double normal_cdf ( double u, double s2, double x )
+{
+ x = (x - u) / sqrt(2*s2);
+
+ double c = (1 + erf2(x)) / 2;
+
+ return c;
+}
+
+double binom_cdf ( double n, double p, double k )
+{
+ double u = n*p;
+ double s2 = n*p*(1-p);
+
+ return normal_cdf(u,s2,k);
+}
+
+// return the probability that a random variable from distribution A is greater than a random variable from distribution B
+
+double comparenorms ( double uA, double sA, double uB, double sB )
+{
+ double c = 1.0 - normal_cdf(uA-uB,sA*sA+sB*sB,0);
+
+ return c;
+}
+
+// convert beta distribution to normal distribution approximation
+
+void beta2norm ( double a, double b, double & u, double & s )
+{
+ u = a / (a+b);
+
+ double t1 = a*b;
+ double t2 = a+b;
+ double t3 = t2*t2*(t2+1);
+
+ s = sqrt( t1 / t3 );
+}
+
+#pragma warning(disable : 4189)
+
+double comparecoins ( double hA, double tA, double hB, double tB )
+{
+ double uA,sA,uB,sB;
+
+ beta2norm(hA+1,tA+1,uA,sA);
+ beta2norm(hB+1,tB+1,uB,sB);
+
+ // this is not the right way to handle the discontinuity at 0.5, but i don't want to deal with truncated normal distributions...
+
+ if(uA < 0.5) uA = 1.0 - uA;
+ if(uB < 0.5) uB = 1.0 - uB;
+
+ return 1.0 - comparenorms(uA,sA,uB,sB);
+}
+
+// Binomial distribution using the normal approximation
+
+double binom2 ( double n, double p, double k )
+{
+ double u = n*p;
+ double s2 = n*p*(1-p);
+
+ double a = k-u;
+
+ const double pi = 3.14159265358979323846264338327950288419716939937510;
+
+ a = a*a / (-2.0*s2);
+ a = exp(a) / sqrt(s2*2.0*pi);
+
+ return a;
+}
+
+double RandWork ( double bucketcount, double keycount )
+{
+ double avgload = keycount / bucketcount;
+
+ double total = 0;
+
+ if(avgload <= 16)
+ {
+ // if the load is low enough we can compute the expected work directly
+
+ double p = pow((bucketcount-1)/bucketcount,keycount);
+
+ double work = 0;
+
+ for(double i = 0; i < 50; i++)
+ {
+ work += i;
+ total += work * p;
+
+ p *= (keycount-i) / ( (i+1) * (bucketcount-1) );
+ }
+ }
+ else
+ {
+ // otherwise precision errors screw up the calculation, and so we fall back
+ // to the normal approxmation to the binomial distribution
+
+ double min = avgload / 5.0;
+ double max = avgload * 5.0;
+
+ for(double i = min; i <= max; i++)
+ {
+ double p = binom2(keycount,1.0 / bucketcount,i);
+
+ total += double((i*i+i) / 2) * p;
+ }
+ }
+
+ return total / avgload;
+}
+
+// Normalized standard deviation.
+
+double nsdev ( int * buckets, int len, int keys )
+{
+ double n = len;
+ double k = keys;
+ double p = 1.0/n;
+
+ double u = k*p;
+ double s = sqrt(k*p*(1-p));
+
+ double c = 0;
+
+ for(int i = 0; i < len; i++)
+ {
+ double d = buckets[i];
+
+ d = (d-u)/s;
+
+ c += d*d;
+ }
+
+ double nsd = sqrt(c / n);
+
+ return nsd;
+}
+
+
+double chooseK ( int n, int k )
+{
+ if(k > (n - k)) k = n - k;
+
+ double c = 1;
+
+ for(int i = 0; i < k; i++)
+ {
+ double t = double(n-i) / double(i+1);
+
+ c *= t;
+ }
+
+ return c;
+}
+
+double chooseUpToK ( int n, int k )
+{
+ double c = 0;
+
+ for(int i = 1; i <= k; i++)
+ {
+ c += chooseK(n,i);
+ }
+
+ return c;
+}
+
+//-----------------------------------------------------------------------------
+
+uint32_t bitrev ( uint32_t v )
+{
+ v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1);
+ v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2);
+ v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4);
+ v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8);
+ v = ( v >> 16 ) | ( v << 16);
+
+ return v;
+}
+
+//-----------------------------------------------------------------------------
+
+// Distribution "score"
+// TODO - big writeup of what this score means
+
+// Basically, we're computing a constant that says "The test distribution is as
+// uniform, RMS-wise, as a random distribution restricted to (1-X)*100 percent of
+// the bins. This makes for a nice uniform way to rate a distribution that isn't
+// dependent on the number of bins or the number of keys
+
+// (as long as # keys > # bins * 3 or so, otherwise random fluctuations show up
+// as distribution weaknesses)
+
+double calcScore ( std::vector<int> const & bins, int keys )
+{
+ double n = (int)bins.size();
+ double k = keys;
+
+ // compute rms value
+
+ double r = 0;
+
+ for(size_t i = 0; i < bins.size(); i++)
+ {
+ double b = bins[i];
+
+ r += b*b;
+ }
+
+ r = sqrt(r / n);
+
+ // compute fill factor
+
+ double f = (k*k - 1) / (n*r*r - k);
+
+ // rescale to (0,1) with 0 = good, 1 = bad
+
+ return 1 - (f / n);
+}
+
+
+//----------------------------------------------------------------------------
+
+void plot ( double n )
+{
+ double n2 = n * 1;
+
+ if(n2 < 0) n2 = 0;
+
+ n2 *= 100;
+
+ if(n2 > 64) n2 = 64;
+
+ int n3 = (int)floor(n2 + 0.5);
+
+ if(n3 == 0)
+ printf(".");
+ else
+ {
+ char x = '0' + char(n3);
+
+ if(x > '9') x = 'X';
+
+ printf("%c",x);
+ }
+}
+
+//-----------------------------------------------------------------------------
diff --git a/Stats.h b/Stats.h
new file mode 100644
index 0000000..5cae64e
--- /dev/null
+++ b/Stats.h
@@ -0,0 +1,559 @@
+#pragma once
+
+#include "Core.h"
+
+#include <algorithm>
+#include <math.h>
+#include <assert.h>
+#include <float.h>
+
+double calcScore ( std::vector<int> const & bins, int balls );
+
+void plot ( double n );
+
+inline double ExpectedCollisions ( double balls, double bins )
+{
+ return balls - bins + bins * pow(1 - 1/bins,balls);
+}
+
+double comparenorms ( double u1, double s1, double u2, double s2 );
+void beta2norm ( double a, double b, double & u, double & s );
+
+double chooseK ( int b, int k );
+double chooseUpToK ( int n, int k );
+
+inline uint32_t f3mix ( uint32_t k )
+{
+ k ^= k >> 16;
+ k *= 0x85ebca6b;
+ k ^= k >> 13;
+ k *= 0xc2b2ae35;
+ k ^= k >> 16;
+
+ return k;
+}
+
+//-----------------------------------------------------------------------------
+
+template< typename hashtype >
+int CountCollisions ( std::vector<hashtype> const & hashes )
+{
+ int collcount = 0;
+
+ std::vector<hashtype> temp = hashes;
+ std::sort(temp.begin(),temp.end());
+
+ for(size_t i = 1; i < hashes.size(); i++)
+ {
+ if(temp[i] == temp[i-1]) collcount++;
+ }
+
+ return collcount;
+}
+
+//-----------------------------------------------------------------------------
+
+/*
+template < class keytype, typename hashtype >
+int PrintCollisions ( hashfunc<hashtype> hash, std::vector<keytype> & keys )
+{
+ int collcount = 0;
+
+ typedef std::map<hashtype,keytype> htab;
+ htab tab;
+
+ for(size_t i = 1; i < keys.size(); i++)
+ {
+ keytype & k1 = keys[i];
+
+ hashtype h = hash(&k1,sizeof(k),0);
+
+ htab::iterator it = tab.find(h);
+
+ if(it != tab.end())
+ {
+ keytype & k2 = (*it).second;
+
+ printf("A: ");
+ printbits(&k1,sizeof(k1));
+ printf("B: ");
+ printbits(&k2,sizeof(k2));
+ }
+ else
+ {
+ htab.insert( htab::value_type(h,k);
+ }
+ }
+
+ return collcount;
+}
+*/
+
+//----------------------------------------------------------------------------
+
+template < typename hashtype >
+bool testhashlist( std::vector<hashtype> & hashes, bool testColl, bool testDist, bool drawDiagram )
+{
+ bool verbose = true;
+ bool result = true;
+
+ if(testColl)
+ {
+ size_t count = hashes.size();
+
+ double expected = (double(count) * double(count-1)) / pow(2.0,double(sizeof(hashtype) * 8 + 1));
+
+ if(verbose) printf("Testing collisions - Expected %8.2f, ",expected);
+
+ double collcount = 0;
+
+ collcount = CountCollisions(hashes);
+
+ if(verbose)
+ {
+ printf("actual %8.2f (%5.2fx) \n",collcount, collcount / expected);
+ }
+ else
+ {
+ double collscore = collcount / expected;
+
+ printf("Coll score %5.3f, ",collscore);
+ }
+
+ // 2x expected collisions = fail
+
+ if(double(collcount) / double(expected) > 2.0)
+ {
+ result = false;
+ }
+ }
+
+ //----------
+
+ if(testDist)
+ {
+ if(verbose) printf("Testing distribution - ");
+
+ if(drawDiagram) printf("\n");
+
+ TestDistribution(hashes,drawDiagram);
+ }
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+
+template < class keytype, typename hashtype >
+bool testkeylist ( hashfunc<hashtype> hash, std::vector<keytype> & keys, bool testColl, bool testDist, bool drawDiagram )
+{
+ int keycount = (int)keys.size();
+
+ std::vector<hashtype> hashes;
+
+ hashes.resize(keycount);
+
+ //printf("Hashing keyset");
+
+ for(int ikey = 0; ikey < keycount; ikey++)
+ {
+ keytype & k = keys[ikey];
+
+ //if(ikey % (keycount / 10) == 0) printf(".");
+
+ hashes[ikey] = hash(&k,sizeof(k),0);
+ }
+
+ //printf("\n");
+
+ bool result = testhashlist(hashes,testColl,testDist,drawDiagram);
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+
+template < typename hashtype >
+bool testkeylist_string ( hashfunc<hashtype> hash, std::vector<std::string> & keys, bool testColl, bool testDist )
+{
+ int keycount = (int)keys.size();
+
+ std::vector<hashtype> hashes;
+
+ hashes.resize(keycount);
+
+ //printf("Hashing keyset");
+
+ for(int ikey = 0; ikey < keycount; ikey++)
+ {
+ std::string & k = keys[ikey];
+
+ //if(ikey % (keycount / 10) == 0) printf(".");
+
+ hashes[ikey] = hash(&k[0],(int)k.size(),0);
+ }
+
+ //printf("\n");
+
+ bool result = testhashlist(hashes,testColl,testDist);
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// Bytepair test - generate 16-bit indices from all possible non-overlapping
+// 8-bit sections of the hash value, check distribution on all of them.
+
+// This is a very good test for catching weak intercorrelations between bits -
+// much harder to pass than the normal distribution test. However, it doesn't
+// really model the normal usage of hash functions in hash table lookup, so
+// I'm not sure it's that useful (and hash functions that fail this test but
+// pass the normal distribution test still work well in practice)
+
+template < typename hashtype >
+double TestDistributionBytepairs ( std::vector<hashtype> & hashes, bool drawDiagram )
+{
+ const int nbytes = sizeof(hashtype);
+ const int nbits = nbytes * 8;
+
+ const int nbins = 65536;
+
+ std::vector<int> bins(nbins,0);
+
+ double worst = 0;
+
+ for(int a = 0; a < nbits; a++)
+ {
+ if(drawDiagram) if((a % 8 == 0) && (a > 0)) printf("\n");
+
+ if(drawDiagram) printf("[");
+
+ for(int b = 0; b < nbits; b++)
+ {
+ if(drawDiagram) if((b % 8 == 0) && (b > 0)) printf(" ");
+
+ bins.clear();
+ bins.resize(nbins,0);
+
+ for(size_t i = 0; i < hashes.size(); i++)
+ {
+ hashtype & hash = hashes[i];
+
+ uint32_t pa = window(&hash,sizeof(hash),a,8);
+ uint32_t pb = window(&hash,sizeof(hash),b,8);
+
+ bins[pa | (pb << 8)]++;
+ }
+
+ double s = calcScore(bins,hashes.size());
+
+ if(drawDiagram) plot(s);
+
+ if(s > worst)
+ {
+ worst = s;
+ }
+ }
+
+ if(drawDiagram) printf("]\n");
+ }
+
+ return worst;
+}
+
+
+//----------------------------------------------------------------------------
+// Measure the distribution "score" for each possible N-bit span up to 16 bits
+// and draw a nice graph of the output. 'X' in graph = 10% deviation from ideal.
+
+template< typename hashtype >
+double TestDistribution ( std::vector<hashtype> & hashes, bool drawDiagram )
+{
+ bool verbose = false;
+
+ const int nbits = sizeof(hashtype) * 8;
+ const int maxwidth = 20;
+
+ std::vector<int> bins;
+
+ double worst = 0;
+ int worstStart = -1;
+ int worstWidth = -1;
+
+ for(int width = 1; width <= maxwidth; width++)
+ {
+ const int bincount = (1 << width);
+
+ //If we don't have enough keys to get 2 per bin, skip the test
+
+ //if(double(hashes.size()) / double(bincount) < 2.0) continue;
+
+ if(drawDiagram) printf("%2d - [",width);
+
+ for(int start = 0; start < nbits; start++)
+ {
+ bins.clear();
+ bins.resize(bincount, 0);
+
+ for(size_t j = 0; j < hashes.size(); j++)
+ {
+ hashtype & hash = hashes[j];
+
+ uint32_t index = window(&hash,sizeof(hash),start,width);
+
+ bins[index]++;
+ }
+
+ double n = calcScore(bins,(int)hashes.size());
+
+ if(n > worst)
+ {
+ worst = n;
+ worstStart = start;
+ worstWidth = width;
+ }
+
+ if(drawDiagram) plot(n);
+ }
+
+ if(drawDiagram) printf("]\n");
+ }
+
+ if(verbose)
+ {
+ printf("Worst distribution is for (%d:%d) - %f\n",worstStart,(worstStart+worstWidth-1)%32,worst);
+ }
+ else
+ {
+ printf("Dist score %6.3f\n",(1.0 - worst) * 100);
+ }
+
+ return worst;
+}
+
+//-----------------------------------------------------------------------------
+// Simplified test - only check 64k distributions, and only on byte boundaries
+
+template < typename hashtype >
+void TestDistributionFast ( std::vector<hashtype> & hashes, double & dworst, double & davg )
+{
+ const int nbits = sizeof(hashtype) * 8;
+ const int nbins = 65536;
+
+ std::vector<int> bins(nbins,0);
+
+ dworst = -1.0e90;
+ davg = 0;
+
+ for(int start = 0; start < nbits; start += 8)
+ {
+ bins.clear();
+ bins.resize(nbins,0);
+
+ for(size_t j = 0; j < hashes.size(); j++)
+ {
+ hashtype & hash = hashes[j];
+
+ uint32_t index = window(&hash,sizeof(hash),start,16);
+
+ bins[index]++;
+ }
+
+ double n = calcScore(bins,(int)hashes.size());
+
+ davg += n;
+
+ if(n > dworst) dworst = n;
+ }
+
+ davg /= double(nbits/8);
+}
+
+//-----------------------------------------------------------------------------
+
+/*
+struct Stats
+{
+ enum mode
+ {
+ AVALANCHE,
+ HISTOGRAM,
+ };
+
+ Stats ( int mode, std::vector<int> const & bins, int balls )
+ {
+ switch(mode)
+ {
+ case AVALANCHE:
+ calcAvalanche(bins,balls);
+ break;
+
+ case HISTOGRAM:
+ calcHistogram(bins,balls);
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ }
+
+ //----------
+ // Histogram mode
+
+ void calcHistogram ( std::vector<int> const & bins, int balls )
+ {
+ m_nbins = (int)bins.size();
+ m_nballs = balls;
+
+ m_mean = 0;
+ m_rms = 0;
+ m_sigma = 0;
+ m_max = -DBL_MAX;
+ m_min = DBL_MAX;
+
+ for(size_t i = 0; i < bins.size(); i++)
+ {
+ double x = bins[i];
+
+ m_mean += x;
+ m_rms += x*x;
+
+ m_max = x > m_max ? x : m_max;
+ m_min = x < m_min ? x : m_min;
+ }
+
+ m_mean /= m_nbins;
+ m_rms /= m_nbins;
+ m_rms = sqrt(m_rms);
+
+ for(size_t i = 0; i < bins.size(); i++)
+ {
+ double d = bins[i] - m_mean;
+
+ m_sigma += d*d;
+ }
+
+ m_sigma /= m_nbins;
+ m_sigma = sqrt(m_sigma);
+ }
+
+ //----------
+ // Normalized standard deviation
+
+ double calcNSD ( std::vector<int> const & bins, int balls )
+ {
+ double n = (int)bins.size();
+ double k = balls;
+ double p = 1.0/n;
+
+ double u = k*p;
+ double s = sqrt(k*p*(1-p));
+
+ double c = 0;
+
+ for(size_t i = 0; i < bins.size(); i++)
+ {
+ double d = bins[i];
+
+ d = (d-u)/s;
+
+ c += d*d;
+ }
+
+ m_nsd = sqrt(c / m_nbins);
+ }
+
+ double calcScore ( std::vector<int> const & bins, int balls )
+ {
+ double n = (int)bins.size();
+ double k = balls;
+
+ // compute rms value
+
+ double r = 0;
+
+ for(size_t i = 0; i < bins.size(); i++)
+ {
+ double b = bins[i];
+
+ r += b*b;
+ }
+
+ r = sqrt(r / n);
+
+ // compute fill factor
+
+ double f = (k*k - 1) / (n*r*r - k);
+
+ // rescale to (0,1) with 0 = good, 1 = bad
+
+ m_score = 1 - (f / n);
+ }
+
+ //----------
+ // Avalanche statistics - convert each table entry to a bias value
+ // and compute stats based on that.
+
+ void calcAvalanche ( std::vector<int> const & bins, int balls )
+ {
+ m_nbins = (int)bins.size();
+ m_nballs = balls;
+
+ m_mean = 0;
+ m_rms = 0;
+ m_sigma = 0;
+ m_max = -DBL_MAX;
+ m_min = DBL_MAX;
+ m_nbad = 0;
+
+ for(size_t i = 0; i < bins.size(); i++)
+ {
+ double x = (bins[i] / m_nballs) * 2 - 1;
+
+ m_mean += x;
+ m_rms += x*x;
+
+ x = fabs(x);
+
+ if(x > 0.7) m_nbad++;
+
+ m_max = x > m_max ? x : m_max;
+ m_min = x < m_min ? x : m_min;
+ }
+
+ m_mean /= m_nbins;
+ m_rms /= m_nbins;
+ m_rms = sqrt(m_rms);
+
+ for(size_t i = 0; i < bins.size(); i++)
+ {
+ double x = (bins[i] / m_nballs) * 2 - 1;
+
+ double d = x - m_mean;
+
+ m_sigma += d*d;
+ }
+
+ m_sigma /= m_nbins;
+ m_sigma = sqrt(m_sigma);
+ }
+
+ double m_nbins;
+ double m_nballs;
+
+ double m_mean;
+ double m_rms;
+ double m_sigma;
+
+ double m_nsd;
+ double m_score;
+
+ double m_nbad;
+
+ double m_max;
+ double m_min;
+};
+*/
+
+//-----------------------------------------------------------------------------
diff --git a/StreamCipher.cpp b/StreamCipher.cpp
new file mode 100644
index 0000000..bf9f620
--- /dev/null
+++ b/StreamCipher.cpp
@@ -0,0 +1,13 @@
+#include "StreamCipher.h"
+
+//----------------------------------------------------------------------------
+
+StreamCipher::StreamCipher ( void )
+{
+}
+
+StreamCipher::~StreamCipher ( void )
+{
+}
+
+//----------------------------------------------------------------------------
diff --git a/StreamCipher.h b/StreamCipher.h
new file mode 100644
index 0000000..b78e4db
--- /dev/null
+++ b/StreamCipher.h
@@ -0,0 +1,17 @@
+#pragma once
+#include "Cipher.h"
+
+//----------------------------------------------------------------------------
+
+class StreamCipher : public Cipher
+{
+public:
+
+ StreamCipher ( void );
+ virtual ~StreamCipher ( void );
+
+ virtual void encrypt ( void * k, int keySize, void * p, void * c, int size ) = 0;
+ virtual void decrypt ( void * k, int keySize, void * c, void * p, int size ) = 0;
+};
+
+//----------------------------------------------------------------------------
diff --git a/SuperFastHash.cpp b/SuperFastHash.cpp
new file mode 100644
index 0000000..3425634
--- /dev/null
+++ b/SuperFastHash.cpp
@@ -0,0 +1,68 @@
+#include "pstdint.h"
+
+/* By Paul Hsieh (C) 2004, 2005. Covered under the Paul Hsieh derivative
+ license. See:
+ http://www.azillionmonkeys.com/qed/weblicense.html for license details.
+
+ http://www.azillionmonkeys.com/qed/hash.html */
+
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+ || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+ +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+uint32_t SuperFastHash (const char * data, int len) {
+uint32_t hash = 0, tmp;
+int rem;
+
+ if (len <= 0 || data == NULL) return 0;
+
+ rem = len & 3;
+ len >>= 2;
+
+ /* Main loop */
+ for (;len > 0; len--) {
+ hash += get16bits (data);
+ tmp = (get16bits (data+2) << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ data += 2*sizeof (uint16_t);
+ hash += hash >> 11;
+ }
+
+ /* Handle end cases */
+ switch (rem) {
+ case 3: hash += get16bits (data);
+ hash ^= hash << 16;
+ hash ^= data[sizeof (uint16_t)] << 18;
+ hash += hash >> 11;
+ break;
+ case 2: hash += get16bits (data);
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ break;
+ case 1: hash += *data;
+ hash ^= hash << 10;
+ hash += hash >> 1;
+ }
+
+ /* Force "avalanching" of final 127 bits */
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 4;
+ hash += hash >> 17;
+ hash ^= hash << 25;
+ hash += hash >> 6;
+
+ return hash;
+}
+
+void SuperFastHash ( const void * key, int len, uint32_t /*seed*/, void * out )
+{
+ *(uint32_t*)out = SuperFastHash((const char*)key,len);
+} \ No newline at end of file
diff --git a/TEA.cpp b/TEA.cpp
new file mode 100644
index 0000000..a84d688
--- /dev/null
+++ b/TEA.cpp
@@ -0,0 +1,52 @@
+#include "TEA.h"
+
+#include <memory.h>
+#include <algorithm>
+
+// The TEA algorithm is public domain
+
+//-----------------------------------------------------------------------------
+
+void TEACipher::setKey ( void * key, int keySize )
+{
+ memset(m_key,0,16);
+ memcpy(m_key,key,std::min(keySize,16));
+}
+
+//----------------------------------------------------------------------------
+
+void TEACipher::encrypt ( void * block, unsigned int /*nonce*/ ) const
+{
+ unsigned int * v = (unsigned int*)block;
+ unsigned int * k = (unsigned int*)m_key;
+
+ unsigned int sum = 0;
+ unsigned int delta = 0x9E3779B9;
+
+ for( int i = 0; i < 32; i++ )
+ {
+ sum += delta;
+ v[0] += ((v[1]<<4) + k[0]) ^ (v[1] + sum) ^ ((v[1]>>5) + k[1]);
+ v[1] += ((v[0]<<4) + k[2]) ^ (v[0] + sum) ^ ((v[0]>>5) + k[3]);
+ }
+}
+
+//----------
+
+void TEACipher::decrypt ( void * block, unsigned int /*nonce*/ ) const
+{
+ unsigned int * v = (unsigned int*)block;
+ unsigned int * k = (unsigned int*)m_key;
+
+ unsigned int sum = 0xC6EF3720;
+ unsigned int delta = 0x9E3779B9;
+
+ for( int i = 0; i < 32; i++ )
+ {
+ v[1] -= ((v[0]<<4) + k[2]) ^ (v[0] + sum) ^ ((v[0]>>5) + k[3]);
+ v[0] -= ((v[1]<<4) + k[0]) ^ (v[1] + sum) ^ ((v[1]>>5) + k[1]);
+ sum -= delta;
+ }
+}
+
+//----------------------------------------------------------------------------
diff --git a/TEA.h b/TEA.h
new file mode 100644
index 0000000..fff63f1
--- /dev/null
+++ b/TEA.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "BlockCipher.h"
+
+//----------------------------------------------------------------------------
+
+class TEACipher : public BlockCipher
+{
+public:
+
+ int getBlockSize ( void ) { return 8; }
+
+ void setKey ( void * key, int keySize );
+
+ void encrypt ( void * block, unsigned int nonce ) const;
+ void decrypt ( void * block, unsigned int nonce ) const;
+
+protected:
+
+ uint32_t m_key[4];
+};
+
+//----------------------------------------------------------------------------
diff --git a/Tests.cpp b/Tests.cpp
new file mode 100644
index 0000000..22bea53
--- /dev/null
+++ b/Tests.cpp
@@ -0,0 +1,542 @@
+#include "Tests.h"
+
+#include "Stats.h" // for CountCollisions
+#include "Random.h"
+#include "Bitvec.h"
+
+#include <string.h>
+#include <math.h>
+#include <set>
+#include <vector>
+#include <intrin.h>
+
+#pragma warning(disable:4127)
+
+#pragma warning(disable:4127) // warning C4985: 'ceil': attributes not present on previous declaration.
+
+//-----------------------------------------------------------------------------
+// 256k blocks seem to give the best results.
+
+void BulkSpeedTest ( pfHash hash )
+{
+ const int trials = 9999;
+ const int blocksize = 256 * 1024;
+
+ printf("Bulk speed test - %d-byte keys\n",blocksize);
+
+ char * block = new char[blocksize + 16];
+
+ rand_p(block,blocksize+16);
+
+ uint32_t temp[16];
+
+ for(int align = 0; align < 4; align++)
+ {
+ double bestbpc = 0;
+
+ for(int itrial = 0; itrial < trials; itrial++)
+ {
+ __int64 begin,end;
+
+ begin = __rdtsc();
+
+ hash(block + align,blocksize,itrial,temp);
+
+ end = __rdtsc();
+
+ blackhole(temp[0]);
+
+ double cycles = double(end-begin);
+ double bpc = double(blocksize) / cycles;
+ if(bpc > bestbpc) bestbpc = bpc;
+ }
+
+ double bestbps = (bestbpc * 3000000000.0 / 1048576.0);
+ printf("Alignment %2d - %8.4f bytes/cycle, (%.2f MiB/sec @ 3 ghz)\n",align,bestbpc,bestbps);
+ }
+ printf("\n");
+
+ delete [] block;
+}
+
+//----------------------------------------------------------------------------
+// Tests the Bit Independence Criteron. Not sure if this still works.
+
+template< int _bits, int _reps, class hashtype >
+void BicTest ( hashfunc<uint32_t> hash )
+{
+ const int bits = _bits;
+ const int reps = _reps;
+ const int bytes = bits / 8;
+ const int hashbytes = sizeof(hashtype);
+ const int hashbits = hashbytes * 8;
+
+ int counts[bits][hashbits][hashbits];
+
+ memset(counts,0,sizeof(counts));
+
+ unsigned char k[bytes];
+
+ for(int irep = 0; irep < reps; irep++)
+ {
+ if(irep % 1000 == 0) printf(".");
+
+ rand_p(k,bytes);
+ unsigned int h1 = hash(k,bytes,0);
+
+ for(int in = 0; in < bits; in++)
+ {
+ flipbit(k,in);
+ unsigned int h2 = hash(k,bytes,0);
+ flipbit(k,in);
+
+ unsigned int h = h1 ^ h2;
+
+ for(int out1 = 0; out1 < hashbits; out1++)
+ for(int out2 = out1; out2 < hashbits; out2++)
+ {
+ int b1 = (h >> out1) & 1;
+ int b2 = (h >> out2) & 1;
+
+ int b = b1 ^ b2;
+
+ if(b1 ^ b2)
+ {
+ counts[in][out1][out2]++;
+ }
+ }
+ }
+ }
+
+ printf("\n");
+
+ int biases[4] = {0,0,0,0};
+
+ for(int i = 0; i < hashbits; i++)
+ {
+ for(int j = 0; j < hashbits; j++)
+ {
+ if(i == j)
+ {
+ printf("\\");
+ }
+ else if(i > j)
+ {
+ printf(" ");
+ }
+ else
+ {
+ double d = double(counts[16][i][j]) / double(reps);
+
+ int b = (int)(fabs(d * 2 - 1) * 100);
+
+ if(b == 0) printf(".");
+ else if(b < 5) printf("o");
+ else if(b < 33) printf("O");
+ else printf("X");
+
+ if(b == 0) biases[0]++;
+ else if(b < 5) biases[1]++;
+ else if(b < 33) biases[2]++;
+ else biases[3]++;
+ }
+ }
+
+ printf("\n");
+ }
+
+
+ printf("Bias distribution - %3d : %3d : %3d : %3d\n",biases[0],biases[1],biases[2],biases[3]);
+
+ printf("\n");
+}
+
+//----------------------------------------------------------------------------
+// Bijection test = hash all possible 32-bit keys, see how many 32-bit values
+// are missing. Each missing value indicates a collision.
+
+void BijectionTest ( hashfunc<uint32_t> hash )
+{
+ const int nbytes = 512 * 1024 * 1024;
+
+ unsigned char * block = new unsigned char[nbytes];
+
+ memset(block,0,nbytes);
+
+ printf("Testing bijection for 32-bit keys");
+
+ unsigned int k = 0;
+
+ do
+ {
+ unsigned int h = hash(&k,4,0);
+ setbit(block,nbytes,h);
+
+ if(k % 100000000 == 0) printf(".");
+
+ k++;
+ }
+ while(k != 0);
+
+ int missing = 0;
+
+ do
+ {
+ if(!getbit(block,nbytes,k)) missing++;
+
+ k++;
+ }
+ while(k != 0);
+
+ printf("\nMissing values - %d\n",missing);
+
+ delete [] block;
+}
+
+//----------------------------------------------------------------------------
+// Loop counting
+
+// Repeatedly hash the same 4-byte value over and over, and track how many
+// loops are in the output.
+
+void LoopTest ( hashfunc<uint32_t> hash )
+{
+ const int nbytes = 512 * 1024 * 1024;
+
+ unsigned char * block = new unsigned char[nbytes];
+
+ memset(block,0,nbytes);
+
+ int loops = 0;
+ unsigned int start = 0;
+
+ while(1)
+ {
+ if(!getbit(block,nbytes,start))
+ {
+ loops++;
+
+ unsigned int r = 0;
+ unsigned int h = start;
+
+ printf("Testing loop starting at %u",start);
+
+ while(1)
+ {
+ setbit(block,nbytes,h);
+ r++;
+ h = hash(&h,4,0);
+
+ if(h == start) break;
+
+ if(r % 100000000 == 0) printf(".");
+ }
+
+ printf("\nStart point %u looped after %u\n",start,r);
+ }
+
+ start++;
+ if(start == 0) break;
+ }
+
+ printf("Total loops - %d\n",loops);
+
+ delete [] block;
+}
+
+//-----------------------------------------------------------------------------
+// Trickle test, not really usable by itself. Used for testing the diffusion
+// properties of a sequence of adds, xors, rotates, etc - replace the adds and
+// xors with ors, compute how many iterations it takes to convert an input with
+// a single 1 bit into all 1s.
+
+// I was using it to find optimal rotation constants for various types of
+// diffusion functions, but didn't end up using them
+
+int trickle ( int r[4], int reps )
+{
+ int worst = 1000;
+
+ for(int i = 0; i < 128; i++)
+ {
+ uint32_t t[4] = { 0, 0, 0, 0 };
+
+ setbit(t,4,i);
+
+ for(int j = 0; j < reps; j++)
+ {
+ t[0] |= t[1];
+ t[2] |= t[3];
+ t[1] |= t[0];
+ t[0] |= t[2];
+
+ t[2] |= t[1];
+ t[1] |= t[0];
+ t[3] |= t[0];
+
+ t[0] = _rotl(t[0],r[0]);
+ t[1] = _rotl(t[1],r[1]);
+ t[2] = _rotl(t[2],r[2]);
+ t[3] = _rotl(t[3],r[3]);
+ }
+
+ int p = popcount(t[0]) + popcount(t[1]) + popcount(t[2]) + popcount(t[3]);
+
+ if(p < worst) worst = p;
+ }
+
+ return worst;
+}
+
+void TrickleTest ( void )
+{
+ int best = 0;
+
+ int r[4];
+
+ for(int i = 0; i < 1024*1024; i++)
+ {
+ r[0] = (i >> 0) & 31;
+ r[1] = (i >> 5) & 31;
+ r[2] = (i >> 10) & 31;
+ r[3] = (i >> 15) & 31;
+
+ //if(trickle(r,2) < 16) continue;
+ //if(trickle(r,3) < 40) continue;
+ //if(trickle(r,4) < 80) continue;
+
+ int worst = trickle(r,6);
+
+ if(worst >= best)
+ //if(i % 10000 == 0)
+ {
+ best = worst;
+
+ printf("\t{");
+ for(int i = 0; i < 4; i++)
+ {
+ printf("%2d, ",r[i]);
+ }
+ printf("}, // %3d\n",worst);
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+// Alignment of the keys should not affect the hash value - if it does,
+// something is broken.
+
+void AlignmentTest ( pfHash hash, const int hashbits )
+{
+ const int hashbytes = hashbits / 8;
+
+ printf("Testing alignment handling on small keys..........");
+
+ char bufs[16][64];
+
+ char * strings[16];
+
+ for(int i = 0; i < 16; i++)
+ {
+ uint32_t b = uint32_t(&bufs[i][0]);
+
+ b = (b+15)&(~15);
+
+ strings[i] = (char*)(b + i);
+
+ strcpy_s(strings[i],32,"DeadBeefDeadBeef");
+ }
+
+ uint32_t hash1[64];
+ uint32_t hash2[64];
+
+ for(int k = 1; k <= 16; k++)
+ for(int j = 0; j < 15; j++)
+ for(int i = j+1; i < 16; i++)
+ {
+ const char * s1 = strings[i];
+ const char * s2 = strings[j];
+
+ hash(s1,k,0,hash1);
+ hash(s2,k,0,hash2);
+
+ if(memcmp(hash1,hash2,hashbytes) != 0)
+ {
+ printf("*********FAIL*********\n");
+ return;
+ }
+ }
+
+ printf("PASS\n");
+}
+
+//----------------------------------------------------------------------------
+// Appending zero bytes to a key should always cause it to produce a different
+// hash value
+
+void AppendedZeroesTest ( pfHash hash, const int hashbits )
+{
+ const int hashbytes = hashbits/8;
+
+ printf("Testing zero-appending..........");
+
+ for(int rep = 0; rep < 100; rep++)
+ {
+ if(rep % 10 == 0) printf(".");
+
+ unsigned char key[256];
+
+ memset(key,0,sizeof(key));
+
+ rand_p(key,32);
+
+ uint32_t h1[16];
+ uint32_t h2[16];
+
+ memset(h1,0,hashbytes);
+ memset(h2,0,hashbytes);
+
+ for(int i = 0; i < 32; i++)
+ {
+ hash(key,32+i,0,h1);
+
+ if(memcmp(h1,h2,hashbytes) == 0)
+ {
+ printf("\n*********FAIL*********\n");
+ return;
+ }
+
+ memcpy(h2,h1,hashbytes);
+ }
+ }
+
+ printf("\nPASS\n");
+}
+
+//----------------------------------------------------------------------------
+// Flipping a bit of a key should, with very high probability, result in a
+// different hash.
+
+bool TwiddleTest ( pfHash hash, const int hashbits )
+{
+ bool result = true;
+
+ const int hashbytes = hashbits/8;
+
+ printf("Testing bit twiddling..........");
+
+ uint8_t key[256];
+ uint32_t h1[16];
+ uint32_t h2[16];
+
+ for(int len = 1; len < 16; len++)
+ {
+ for(int bit = 0; bit < (len * 8); bit++)
+ {
+ rand_p(key,len);
+
+ hash(key,len,0,h1);
+ flipbit(key,len,bit);
+ hash(key,len,0,h2);
+
+ if(memcmp(h1,h2,hashbytes) == 0)
+ {
+ //printf("X");
+ result = false;
+ }
+ else
+ {
+ //printf(".");
+ }
+ }
+
+ //printf("\n");
+ }
+
+ if(result == false)
+ printf("*********FAIL*********\n");
+ else
+ printf("PASS\n");
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// Create a bunch of zero-byte keys of different lengths and check distribution.
+
+// We reuse one block of empty bytes, otherwise the RAM cost is enormous.
+// The distribution table will have some random 1s in the bottom rows due to
+// there not being enough keys for a good test.
+
+void NullKeysetTest ( hashfunc<uint32_t> hash, bool drawDiagram )
+{
+ int keycount = 64*1024;
+
+ unsigned char * nullblock = new unsigned char[keycount];
+ memset(nullblock,0,keycount);
+
+ //----------
+
+ std::vector<uint32_t> hashes;
+
+ hashes.resize(keycount);
+
+ //----------
+
+ printf("Collision test - Hash keyset 100 times, count collisions");
+
+ for(int i = 0; i < keycount; i++)
+ {
+ if(i % (keycount/10) == 0) printf(".");
+
+ uint32_t h = hash(nullblock,i,0);
+ hashes[i] = h;
+ }
+
+ testhashlist(hashes,true,true,drawDiagram);
+
+ delete [] nullblock;
+}
+
+//-----------------------------------------------------------------------------
+// Simple collections of alphanumeric strings
+
+template < typename hashtype >
+void TextKeyTest2 ( hashfunc<hashtype> hash, bool drawDiagram )
+{
+ const char * s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456790123456789";
+
+ const int nbytes = 7;
+ const int nbits = 56;
+ const int nkeys = 1024*1024;
+
+ printf("Testing %d 7-character text keys - \n",nkeys,nbits);
+
+ //----------
+ // generate keyset
+
+ typedef Blob<nbits> keytype;
+
+ std::vector<keytype> keys;
+ keys.reserve(nkeys);
+
+ keytype key;
+
+ uint8_t * bytes = (uint8_t*)&key;
+
+ for(int i = 0; i < nkeys; i++)
+ {
+ for(int j = 0; j < nbytes; j++)
+ {
+ int d = i >> (j * 3);
+
+ bytes[j] = s[d % 64];
+ }
+
+ keys.push_back(key);
+ }
+
+ //----------
+
+ testkeylist<keytype,hashtype>(hash,keys,true,true,drawDiagram);
+}
diff --git a/Tests.h b/Tests.h
new file mode 100644
index 0000000..975b454
--- /dev/null
+++ b/Tests.h
@@ -0,0 +1,195 @@
+#pragma once
+
+#include "Types.h"
+#include "Random.h"
+//#include "Stats.h"
+
+//#include <intrin.h>
+
+#include "AvalancheTest.h"
+#include "CycleTest.h"
+#include "DifferentialTest.h"
+#include "DictionaryTest.h"
+
+//-----------------------------------------------------------------------------
+
+template< typename hashtype >
+void QuickBrownFox ( hashfunc<hashtype> hash )
+{
+ const char * text1 = "The quick brown fox jumps over the lazy dog";
+ const char * text2 = "The quick brown fox jumps over the lazy cog";
+
+ hashtype h1, h2;
+
+ hash(text1,(int)strlen(text1),0,&h1);
+ hash(text2,(int)strlen(text2),0,&h2);
+
+ printf("Quick Brown Fox -\n");
+ printhex32(&h1,sizeof(hashtype)); printf("\n");
+ printhex32(&h2,sizeof(hashtype)); printf("\n");
+ printf("\n");
+}
+
+//-----------------------------------------------------------------------------
+
+void BulkSpeedTest ( pfHash hash );
+
+/*
+template < typename hashtype >
+void BulkSpeedTest ( hashfunc<hashtype> hash )
+{
+ BulkSpeedTest(hash,sizeof(hashtype) * 8);
+}
+*/
+
+//----------------------------------------------------------------------------
+
+template < typename hashtype, int keysize >
+void TinySpeedTest ( pfHash hash )
+{
+ const int trials = 100000;
+
+ printf("Small key speed test - %4d-byte keys - ",keysize);
+
+ uint8_t k[keysize];
+ hashtype h;
+
+ double bestcycles = 1e9;
+
+ for(int itrial = 0; itrial < trials; itrial++)
+ {
+ __int64 begin,end;
+
+ rand_p(k,keysize);
+
+ begin = __rdtsc();
+
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+ hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h); hash(k,keysize,itrial,&h);
+
+ end = __rdtsc();
+
+ blackhole(*(uint32_t*)(&h));
+
+ double cycles = double(end-begin) / 64;
+ if(cycles < bestcycles) bestcycles = cycles;
+ }
+
+ double bestbpc = double(keysize) / bestcycles;
+ printf("%8.2f cycles/hash, %8.4f bytes/cycle\n",bestcycles,bestbpc);
+}
+
+//-----------------------------------------------------------------------------
+
+void AlignmentTest ( pfHash hash, const int hashbits );
+
+template < typename hashtype >
+void AlignmentTest ( hashfunc<hashtype> hash )
+{
+ AlignmentTest(hash,sizeof(hashtype) * 8);
+}
+
+//-----------------------------------------------------------------------------
+
+void AppendedZeroesTest ( pfHash hash, const int hashbits );
+
+template < typename hashtype >
+void AppendedZeroesTest ( hashfunc<hashtype> hash )
+{
+ AppendedZeroesTest(hash,sizeof(hashtype) * 8);
+}
+
+//-----------------------------------------------------------------------------
+
+bool TwiddleTest ( pfHash hash, const int hashbits );
+
+template < typename hashtype >
+bool TwiddleTest ( hashfunc<hashtype> hash )
+{
+ return TwiddleTest(hash,sizeof(hashtype) * 8);
+}
+
+//-----------------------------------------------------------------------------
+
+template < typename hashtype >
+bool AvalancheTest ( hashfunc<hashtype> hash )
+{
+ bool result = true;
+
+ const int nbytes = sizeof(hashtype);
+ const int nbits = nbytes * 8;
+
+ for(int i = 4; i <= 10; i++)
+ {
+ result &= AvalancheTest(hash,8*i,nbits,2000000);
+ }
+
+ if(!result) printf("*********FAIL*********\n");
+
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+
+template < typename hashtype >
+bool SparseKeyTest2 ( hashfunc<hashtype> hash, bool drawDiagram );
+
+template < typename hashtype >
+bool SparseKeyTest ( hashfunc<hashtype> hash, bool drawDiagram )
+{
+ return SparseKeyTest2<hashtype>(hash,drawDiagram);
+}
+
+//-----------------------------------------------------------------------------
+// For a given 20-bit window of a 64-bit key, generate all possible keys with
+// bits set in that window
+
+template < typename hashtype >
+void BitrangeKeysetTest ( hashfunc<hashtype> hash, bool drawDiagram )
+{
+ const int keybits = 64;
+
+ for(int j = 0; j <= (keybits-20); j++)
+ {
+ int minbit = j;
+ int maxbit = j+20-1;
+
+ int keycount = 1 << (maxbit - minbit + 1);
+
+ printf("Bitrange keyset (%2d,%2d) - %d keys - ",minbit,maxbit,keycount);
+
+ std::vector<uint64_t> keys;
+ keys.reserve(keycount);
+
+ for(int i = 0; i < keycount; i++)
+ {
+ uint64_t k = i;
+
+ k = k << minbit;
+
+ keys.push_back(k);
+ }
+
+ testkeylist<uint64_t,hashtype>(hash,keys,true,true,drawDiagram);
+ }
+}
+
+//-----------------------------------------------------------------------------
diff --git a/Types.cpp b/Types.cpp
new file mode 100644
index 0000000..8ae5185
--- /dev/null
+++ b/Types.cpp
@@ -0,0 +1,17 @@
+#include "Types.h"
+
+// Throw a value in the oubliette to prevent the compiler from optimizing away
+// the code that calculated it
+
+#pragma optimize( "", off )
+
+void blackhole ( uint32_t )
+{
+}
+
+uint32_t whitehole ( void )
+{
+ return 0;
+}
+
+#pragma optimize( "", on )
diff --git a/Types.h b/Types.h
new file mode 100644
index 0000000..7dd7cda
--- /dev/null
+++ b/Types.h
@@ -0,0 +1,449 @@
+#pragma once
+
+#include "pstdint.h"
+#include "Bitvec.h"
+#include <vector>
+#include <assert.h>
+
+void blackhole ( uint32_t x );
+uint32_t whitehole ( void );
+
+typedef void (*pfHash) ( const void * blob, int len, uint32_t seed, void * out );
+
+template < typename T >
+void swap ( T & a, T & b )
+{
+ T t = a;
+ a = b;
+ b = t;
+}
+
+//-----------------------------------------------------------------------------
+
+template < class T >
+class hashfunc
+{
+public:
+
+ hashfunc ( pfHash h ) : m_hash(h)
+ {
+ }
+
+ inline void operator () ( const void * key, int len, uint32_t seed, uint32_t * out )
+ {
+ m_hash(key,len,seed,out);
+ }
+
+ inline operator pfHash ( void ) const
+ {
+ return m_hash;
+ }
+
+ inline T operator () ( const void * key, int len, uint32_t seed )
+ {
+ T result;
+
+ m_hash(key,len,seed,(uint32_t*)&result);
+
+ return result;
+ }
+
+ /*
+ T operator () ( T const & key )
+ {
+ T result;
+
+ m_hash(&key,sizeof(T),0,&result);
+
+ return result;
+ }
+ */
+
+ pfHash m_hash;
+};
+
+//-----------------------------------------------------------------------------
+
+template < class T >
+class mixfunc
+{
+public:
+
+ typedef T (*pfMix) ( T key );
+
+ mixfunc ( pfMix m ) : m_mix(m)
+ {
+ }
+
+ T operator () ( T key )
+ {
+ return m_mix(key);
+ }
+
+ pfMix m_mix;
+};
+
+//-----------------------------------------------------------------------------
+
+template < int _bits >
+class Blob
+{
+public:
+
+ Blob()
+ {
+ }
+
+ Blob ( int x )
+ {
+ for(int i = 0; i < nbytes; i++)
+ {
+ bytes[i] = 0;
+ }
+
+ *(int*)bytes = x;
+ }
+
+ Blob ( const Blob & k )
+ {
+ for(int i = 0; i < nbytes; i++)
+ {
+ bytes[i] = k.bytes[i];
+ }
+ }
+
+ Blob & operator = ( const Blob & k )
+ {
+ for(int i = 0; i < nbytes; i++)
+ {
+ bytes[i] = k.bytes[i];
+ }
+
+ return *this;
+ }
+
+ void set ( const void * blob, int len )
+ {
+ const uint8_t * k = (const uint8_t*)blob;
+
+ len = len > nbytes ? nbytes : len;
+
+ for(int i = 0; i < len; i++)
+ {
+ bytes[i] = k[i];
+ }
+
+ for(int i = len; i < nbytes; i++)
+ {
+ bytes[i] = 0;
+ }
+ }
+
+ uint8_t & operator [] ( int i )
+ {
+ return bytes[i];
+ }
+
+ const uint8_t & operator [] ( int i ) const
+ {
+ return bytes[i];
+ }
+
+ //----------
+ // boolean operations
+
+ bool operator < ( const Blob & k ) const
+ {
+ for(int i = 0; i < nbytes; i++)
+ {
+ if(bytes[i] < k.bytes[i]) return true;
+ if(bytes[i] > k.bytes[i]) return false;
+ }
+
+ return false;
+ }
+
+ bool operator == ( const Blob & k ) const
+ {
+ for(int i = 0; i < nbytes; i++)
+ {
+ if(bytes[i] != k.bytes[i]) return false;
+ }
+
+ return true;
+ }
+
+ bool operator != ( const Blob & k ) const
+ {
+ return !(*this == k);
+ }
+
+ //----------
+ // bitwise operations
+
+ Blob operator ^ ( const Blob & k ) const
+ {
+ Blob t;
+
+ for(int i = 0; i < nbytes; i++)
+ {
+ t.bytes[i] = bytes[i] ^ k.bytes[i];
+ }
+
+ return t;
+ }
+
+ Blob & operator ^= ( const Blob & k )
+ {
+ for(int i = 0; i < nbytes; i++)
+ {
+ bytes[i] ^= k.bytes[i];
+ }
+
+ return *this;
+ }
+
+ int operator & ( int x )
+ {
+ return (*(int*)bytes) & x;
+ }
+
+ Blob & operator &= ( const Blob & k )
+ {
+ for(int i = 0; i < nbytes; i++)
+ {
+ bytes[i] &= k.bytes[i];
+ }
+ }
+
+ Blob operator << ( int c )
+ {
+ Blob t = *this;
+
+ lshift(t.bytes,nbytes,c);
+
+ return t;
+ }
+
+ Blob operator >> ( int c )
+ {
+ Blob t = *this;
+
+ rshift(t.bytes,nbytes,c);
+
+ return t;
+ }
+
+ Blob & operator <<= ( int c )
+ {
+ lshift(bytes,nbytes,c);
+
+ return *this;
+ }
+
+ Blob & operator >>= ( int c )
+ {
+ rshift(bytes,nbytes,c);
+
+ return *this;
+ }
+
+ //----------
+
+ enum
+ {
+ nbits = _bits,
+ nbytes = (_bits+7)/8,
+
+ align4 = (nbytes & 2) ? 0 : 1,
+ align8 = (nbytes & 3) ? 0 : 1,
+ align16 = (nbytes & 4) ? 0 : 1,
+ };
+
+private:
+
+ uint8_t bytes[nbytes];
+};
+
+typedef Blob<128> u128;
+
+//-----------------------------------------------------------------------------
+
+class VBlob : public std::vector<uint8_t>
+{
+public:
+
+ VBlob( int len ) : std::vector<uint8_t>(len,0)
+ {
+ }
+
+ /*
+ VBlob ( const VBlob & k )
+ {
+ for(size_t i = 0; i < size(); i++)
+ {
+ at(i) = k.at(i);
+ }
+ }
+ */
+
+ /*
+ VBlob & operator = ( const VBlob & k )
+ {
+ for(size_t i = 0; i < size(); i++)
+ {
+ at(i) = k.at(i);
+ }
+
+ return *this;
+ }
+ */
+
+ void set ( const void * VBlob, int len )
+ {
+ assert(size() == (size_t)len);
+
+ const uint8_t * k = (const uint8_t*)VBlob;
+
+ len = len > (int)size() ? (int)size() : len;
+
+ for(int i = 0; i < len; i++)
+ {
+ at(i) = k[i];
+ }
+
+ for(size_t i = len; i < size(); i++)
+ {
+ at(i) = 0;
+ }
+ }
+
+ //----------
+ // boolean operations
+
+ bool operator < ( const VBlob & k ) const
+ {
+ assert(size() == k.size());
+
+ for(size_t i = 0; i < size(); i++)
+ {
+ if(at(i) < k.at(i)) return true;
+ if(at(i) > k.at(i)) return false;
+ }
+
+ return false;
+ }
+
+ bool operator == ( const VBlob & k ) const
+ {
+ assert(size() == k.size());
+
+ for(size_t i = 0; i < size(); i++)
+ {
+ if(at(i) != k.at(i)) return false;
+ }
+
+ return true;
+ }
+
+ bool operator != ( const VBlob & k ) const
+ {
+ assert(size() == k.size());
+
+ return !(*this == k);
+ }
+
+ //----------
+ // bitwise operations
+
+ VBlob operator ^ ( const VBlob & k ) const
+ {
+ assert(size() == k.size());
+
+ VBlob t((int)k.size());
+
+ for(size_t i = 0; i < size(); i++)
+ {
+ t.at(i) = at(i) ^ k.at(i);
+ }
+
+ return t;
+ }
+
+ VBlob & operator ^= ( const VBlob & k )
+ {
+ assert(size() == k.size());
+
+ for(size_t i = 0; i < size(); i++)
+ {
+ at(i) ^= k.at(i);
+ }
+
+ return *this;
+ }
+
+ VBlob & operator &= ( const VBlob & k )
+ {
+ assert(size() == k.size());
+
+ for(size_t i = 0; i < size(); i++)
+ {
+ at(i) &= k.at(i);
+ }
+ }
+
+ VBlob & operator <<= ( int c )
+ {
+ lshift(&at(0),(int)size(),c);
+
+ return *this;
+ }
+
+ VBlob & operator >>= ( int c )
+ {
+ rshift(&at(0),(int)size(),c);
+
+ return *this;
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+/*
+class Blobvec
+{
+public:
+
+ Blobvec ( int stride, int size )
+ {
+ m_data = new uint8_t[stride*size];
+ }
+
+ ~Blobvec ( void )
+ {
+ delete [] m_data;
+ }
+
+ int size ( void ) const
+ {
+ return m_size;
+ }
+
+ const void * operator [] ( const int index ) const
+ {
+ return &m_data[index * m_stride];
+ }
+
+ void * operator [] ( const int index )
+ {
+ return &m_data[index * m_stride];
+ }
+
+ int m_stride;
+ int m_size;
+
+ uint8_t * m_data;
+};
+*/
+
+//-----------------------------------------------------------------------------
diff --git a/XTEA.cpp b/XTEA.cpp
new file mode 100644
index 0000000..3ec3591
--- /dev/null
+++ b/XTEA.cpp
@@ -0,0 +1,119 @@
+#include "XTEA.h"
+
+#include <algorithm>
+
+static const int g_rounds = 64;
+
+// The XTEA and BTEA algorithms are public domain
+
+//----------------------------------------------------------------------------
+
+void XTEACipher::setKey ( void * key, int keySize )
+{
+ memset(m_key,0,16);
+ memcpy(m_key,key,std::min(keySize,16));
+}
+
+//----------------------------------------------------------------------------
+
+void XTEACipher::encrypt ( void * block, unsigned int nonce ) const
+{
+ uint32_t * v = (uint32_t*)block;
+ uint32_t * k = (uint32_t*)m_key;
+
+ uint32_t delta = 0x9E3779B9;
+ uint32_t sum = 0;
+
+ v[0] ^= nonce;
+
+ for(int i = 0; i < g_rounds; i++)
+ {
+ v[0] += (((v[1] << 4) ^ (v[1] >> 5)) + v[1]) ^ (sum + k[sum & 3]);
+
+ sum += delta;
+
+ v[1] += (((v[0] << 4) ^ (v[0] >> 5)) + v[0]) ^ (sum + k[(sum>>11) & 3]);
+ }
+}
+
+//----------
+
+void XTEACipher::decrypt ( void * block, unsigned int nonce ) const
+{
+ uint32_t * v = (uint32_t*)block;
+ uint32_t * k = (uint32_t*)m_key;
+
+ uint32_t delta = 0x9E3779B9;
+ uint32_t sum = delta * g_rounds;
+
+ for(int i = 0; i < g_rounds; i++)
+ {
+ v[1] -= (((v[0] << 4) ^ (v[0] >> 5)) + v[0]) ^ (sum + k[(sum>>11) & 3]);
+
+ sum -= delta;
+
+ v[0] -= (((v[1] << 4) ^ (v[1] >> 5)) + v[1]) ^ (sum + k[sum & 3]);
+ }
+
+ v[0] ^= nonce;
+}
+
+//----------------------------------------------------------------------------
+
+#define DELTA 0x9e3779b9
+#define MX ((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (k[(p&3)^e] ^ z));
+
+void btea ( unsigned int *v, int n, unsigned int const k[4])
+{
+ const int rounds = 6 + (52/n);
+ unsigned int sum = 0;
+
+ unsigned int y = 0;
+ unsigned int z = v[n-1];
+
+ for(int round = 0; round < rounds; round++)
+ {
+ sum += DELTA;
+ unsigned int e = (sum >> 2) & 3;
+
+ int p;
+
+ for( p=0; p < n-1; p++ )
+ {
+ y = v[p+1];
+ z = v[p] += MX;
+ }
+
+ y = v[0];
+ z = v[n-1] += MX;
+ }
+}
+
+void btea_decrypt ( unsigned int *v, int n, unsigned int const k[4])
+{
+ const int rounds = 6 + (52/n);
+ unsigned int sum = rounds*DELTA;
+
+ unsigned int y = v[0];
+ unsigned int z = 0;
+
+ for(int round = 0; round < rounds; round++)
+ {
+ unsigned int e = (sum >> 2) & 3;
+
+ int p;
+
+ for( p = n-1; p > 0; p-- )
+ {
+ z = v[p-1];
+ y = v[p] -= MX;
+ }
+
+ z = v[n-1];
+ y = v[0] -= MX;
+
+ sum -= DELTA;
+ }
+}
+
+//----------------------------------------------------------------------------
diff --git a/XTEA.h b/XTEA.h
new file mode 100644
index 0000000..770248f
--- /dev/null
+++ b/XTEA.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "BlockCipher.h"
+
+//----------------------------------------------------------------------------
+
+class XTEACipher : public BlockCipher
+{
+public:
+
+ int getBlockSize ( void ) { return 8; }
+
+ void setKey ( void * key, int keySize );
+
+ void encrypt ( void * block, unsigned int nonce ) const;
+ void decrypt ( void * block, unsigned int nonce ) const;
+
+protected:
+
+ uint32_t m_key[4];
+};
+
+//----------------------------------------------------------------------------
diff --git a/crc.cpp b/crc.cpp
new file mode 100644
index 0000000..7e65d3a
--- /dev/null
+++ b/crc.cpp
@@ -0,0 +1,101 @@
+/*
+ * This file is derived from crc32.c from the zlib-1.1.3 distribution
+ * by Jean-loup Gailly and Mark Adler.
+ */
+
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+typedef unsigned long uint32_t;
+typedef unsigned char uint8_t;
+
+
+/* ========================================================================
+ * Table of CRC-32's of all single-byte values (made by make_crc_table)
+ */
+static const uint32_t crc_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+
+/* ========================================================================= */
+
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+
+/* ========================================================================= */
+
+void crc32 ( const void * key, int len, uint32_t seed, void * out )
+{
+ uint8_t * buf = (uint8_t*)key;
+ uint32_t crc = seed ^ 0xffffffffL;
+
+ while (len >= 8)
+ {
+ DO8(buf);
+ len -= 8;
+ }
+
+ while(len--)
+ {
+ DO1(buf);
+ }
+
+ crc ^= 0xffffffffL;
+
+ *(uint32_t*)out = crc;
+}
diff --git a/crc.h b/crc.h
new file mode 100644
index 0000000..893fa61
--- /dev/null
+++ b/crc.h
@@ -0,0 +1,77 @@
+/**********************************************************************
+ *
+ * Filename: crc.h
+ *
+ * Description: A header file describing the various CRC standards.
+ *
+ * Notes:
+ *
+ *
+ * Copyright (c) 2000 by Michael Barr. This software is placed into
+ * the public domain and may be used for any purpose. However, this
+ * notice must not be changed or removed and no warranty is either
+ * expressed or implied by its publication or distribution.
+ **********************************************************************/
+
+#ifndef _crc_h
+#define _crc_h
+
+
+#define FALSE 0
+#define TRUE !FALSE
+
+/*
+ * Select the CRC standard from the list that follows.
+ */
+#define CRC32
+
+
+#if defined(CRC_CCITT)
+
+typedef unsigned short crc;
+
+#define CRC_NAME "CRC-CCITT"
+#define POLYNOMIAL 0x1021
+#define INITIAL_REMAINDER 0xFFFF
+#define FINAL_XOR_VALUE 0x0000
+#define REFLECT_DATA FALSE
+#define REFLECT_REMAINDER FALSE
+#define CHECK_VALUE 0x29B1
+
+#elif defined(CRC16)
+
+typedef unsigned short crc;
+
+#define CRC_NAME "CRC-16"
+#define POLYNOMIAL 0x8005
+#define INITIAL_REMAINDER 0x0000
+#define FINAL_XOR_VALUE 0x0000
+#define REFLECT_DATA TRUE
+#define REFLECT_REMAINDER TRUE
+#define CHECK_VALUE 0xBB3D
+
+#elif defined(CRC32)
+
+typedef unsigned long crc;
+
+#define CRC_NAME "CRC-32"
+#define POLYNOMIAL 0x04C11DB7
+#define INITIAL_REMAINDER 0xFFFFFFFF
+#define FINAL_XOR_VALUE 0xFFFFFFFF
+#define REFLECT_DATA TRUE
+#define REFLECT_REMAINDER TRUE
+#define CHECK_VALUE 0xCBF43926
+
+#else
+
+#error "One of CRC_CCITT, CRC16, or CRC32 must be #define'd."
+
+#endif
+
+
+void crcInit(void);
+crc crcSlow(unsigned char const message[], int nBytes);
+crc crcFast(unsigned char const message[], int nBytes);
+
+
+#endif /* _crc_h */ \ No newline at end of file
diff --git a/lookup3.cpp b/lookup3.cpp
new file mode 100644
index 0000000..5dd3a42
--- /dev/null
+++ b/lookup3.cpp
@@ -0,0 +1,72 @@
+// lookup3 by Bob Jekins, code is public domain.
+
+#include "pstdint.h"
+
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+uint32_t lookup3 ( const void * key, int length, uint32_t initval )
+{
+ uint32_t a,b,c; /* internal state */
+
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : { return c; } /* zero length strings require no mixing */
+ }
+
+ final(a,b,c);
+
+ return c;
+}
+
+void lookup3_test ( const void * key, int len, uint32_t seed, void * out )
+{
+ *(uint32_t*)out = lookup3(key,len,seed);
+}
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..658f668
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,104 @@
+#include <stdio.h>
+
+#include <time.h>
+#include "hashes.h"
+#include "tests.h"
+
+#include <windows.h>
+
+#pragma warning(disable:4702)
+
+//----------------------------------------------------------------------------
+
+template < typename hashtype >
+void test ( hashfunc<hashtype> hash, const char * hashname )
+{
+ printf("Testing %s\n",hashname);
+
+ //const int hbytes = sizeof(hashtype);
+ //const int hbits = hbytes * 8;
+
+ TwiddleTest(hash);
+ AlignmentTest(hash);
+ AppendedZeroesTest(hash);
+ QuickBrownFox(hash);
+ printf("\n");
+
+ BulkSpeedTest(hash);
+
+ TinySpeedTest<hashtype,4>(hash);
+ TinySpeedTest<hashtype,5>(hash);
+ TinySpeedTest<hashtype,6>(hash);
+ TinySpeedTest<hashtype,7>(hash);
+ TinySpeedTest<hashtype,8>(hash);
+ TinySpeedTest<hashtype,256>(hash);
+ printf("\n");
+
+ // # of bytes in the cycle must be at least # of bytes in the hash output
+
+ //CycleTest<hashtype>(hash,sizeof(hashtype)+0,8,10000000);
+ //CycleTest<hashtype>(hash,sizeof(hashtype)+1,8,10000000);
+ //CycleTest<hashtype>(hash,sizeof(hashtype)+2,8,10000000);
+ //CycleTest<hashtype>(hash,sizeof(hashtype)+3,8,10000000);
+ //CycleTest<hashtype>(hash,sizeof(hashtype)+4,8,10000000);
+
+ printf("\n");
+
+ /*
+ DiffTest< Blob<64>, hashtype >(hash,5,1000);
+ DiffTest< Blob<128>, hashtype >(hash,4,1000);
+ DiffTest< Blob<256>, hashtype >(hash,3,1000);
+
+ printf("\n");
+
+ AvalancheTest(hash);
+ */
+
+ SparseKeyTest(hash,false);
+
+ //DictionaryTest(hash);
+ //BitrangeKeysetTest(hash,false);
+ //TextKeyTest(hash.m_hash);
+}
+
+//-----------------------------------------------------------------------------
+
+void optimize_fmix64 ( void );
+
+void main ( void )
+{
+ SetProcessAffinityMask(GetCurrentProcess(),2);
+
+ int a = clock();
+
+#if 0
+
+ optimize_fmix64();
+
+ //scratchmain();
+
+#else
+
+ //----------
+
+ //test<uint32_t> ( md5_32, "MD5, first 32 bits" );
+ //test<uint32_t> ( lookup3_test, "Jenkins lookup3" );
+ //test<uint32_t> ( SuperFastHash, "SuperFastHash" );
+ //test<uint32_t> ( MurmurHash2_test, "MurmurHash2 32-bit" );
+ //test<uint32_t> ( MurmurHash2A_test, "MurmurHash2 32-bit" );
+ //test<uint32_t> ( FNV, "FNV 32-bit" );
+ //test<uint32_t> ( crc32, "CRC-32" );
+ //test<uint32_t> ( DoNothingHash, "MurmurHash3 32-bit" );
+
+ //test<uint32_t> ( MurmurHash3_x86_32, "MurmurHash3 32-bit" );
+ test<uint64_t> ( MurmurHash3_x86_64, "MurmurHash3 64-bit" );
+ //test<k128> ( MurmurHash3_128, "MurmurHash3 128-bit" );
+
+ //test<uint32_t> ( MurmurHash3x64_32, "MurmurHash3 32-bit" );
+
+#endif
+
+ int b = clock();
+
+ printf("time %d\n",b-a);
+} \ No newline at end of file
diff --git a/md5.cpp b/md5.cpp
new file mode 100644
index 0000000..57bcbf3
--- /dev/null
+++ b/md5.cpp
@@ -0,0 +1,382 @@
+#include <memory.h>
+#include "Types.h"
+
+// "Derived from the RSA Data Security, Inc. MD5 Message Digest Algorithm"
+
+/**
+ * \brief MD5 context structure
+ */
+typedef struct
+{
+ unsigned long total[2]; /*!< number of bytes processed */
+ unsigned long state[4]; /*!< intermediate digest state */
+ unsigned char buffer[64]; /*!< data block being processed */
+
+ unsigned char ipad[64]; /*!< HMAC: inner padding */
+ unsigned char opad[64]; /*!< HMAC: outer padding */
+}
+md5_context;
+
+/**
+ * \brief MD5 context setup
+ *
+ * \param ctx context to be initialized
+ */
+void md5_starts( md5_context *ctx );
+
+/**
+ * \brief MD5 process buffer
+ *
+ * \param ctx MD5 context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ */
+void md5_update( md5_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief MD5 final digest
+ *
+ * \param ctx MD5 context
+ * \param output MD5 checksum result
+ */
+void md5_finish( md5_context *ctx, unsigned char output[16] );
+
+/**
+ * \brief Output = MD5( input buffer )
+ *
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output MD5 checksum result
+ */
+void md5( unsigned char *input, int ilen, unsigned char output[16] );
+
+/**
+ * \brief Output = MD5( file contents )
+ *
+ * \param path input file name
+ * \param output MD5 checksum result
+ *
+ * \return 0 if successful, 1 if fopen failed,
+ * or 2 if fread failed
+ */
+int md5_file( char *path, unsigned char output[16] );
+
+/**
+ * \brief MD5 HMAC context setup
+ *
+ * \param ctx HMAC context to be initialized
+ * \param key HMAC secret key
+ * \param keylen length of the HMAC key
+ */
+void md5_hmac_starts( md5_context *ctx, unsigned char *key, int keylen );
+
+/**
+ * \brief MD5 HMAC process buffer
+ *
+ * \param ctx HMAC context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ */
+void md5_hmac_update( md5_context *ctx, unsigned char *input, int ilen );
+
+/**
+ * \brief MD5 HMAC final digest
+ *
+ * \param ctx HMAC context
+ * \param output MD5 HMAC checksum result
+ */
+void md5_hmac_finish( md5_context *ctx, unsigned char output[16] );
+
+/**
+ * \brief Output = HMAC-MD5( hmac key, input buffer )
+ *
+ * \param key HMAC secret key
+ * \param keylen length of the HMAC key
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output HMAC-MD5 result
+ */
+void md5_hmac( unsigned char *key, int keylen,
+ unsigned char *input, int ilen,
+ unsigned char output[16] );
+
+/**
+ * \brief Checkup routine
+ *
+ * \return 0 if successful, or 1 if the test failed
+ */
+int md5_self_test( int verbose );
+
+/*
+ * 32-bit integer manipulation macros (little endian)
+ */
+#ifndef GET_ULONG_LE
+#define GET_ULONG_LE(n,b,i) \
+{ \
+ (n) = ( (unsigned long) (b)[(i) ] ) \
+ | ( (unsigned long) (b)[(i) + 1] << 8 ) \
+ | ( (unsigned long) (b)[(i) + 2] << 16 ) \
+ | ( (unsigned long) (b)[(i) + 3] << 24 ); \
+}
+#endif
+
+#ifndef PUT_ULONG_LE
+#define PUT_ULONG_LE(n,b,i) \
+{ \
+ (b)[(i) ] = (unsigned char) ( (n) ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) >> 24 ); \
+}
+#endif
+
+/*
+ * MD5 context setup
+ */
+void md5_starts( md5_context *ctx )
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+}
+
+static void md5_process( md5_context *ctx, unsigned char data[64] )
+{
+ unsigned long X[16], A, B, C, D;
+
+ GET_ULONG_LE( X[ 0], data, 0 );
+ GET_ULONG_LE( X[ 1], data, 4 );
+ GET_ULONG_LE( X[ 2], data, 8 );
+ GET_ULONG_LE( X[ 3], data, 12 );
+ GET_ULONG_LE( X[ 4], data, 16 );
+ GET_ULONG_LE( X[ 5], data, 20 );
+ GET_ULONG_LE( X[ 6], data, 24 );
+ GET_ULONG_LE( X[ 7], data, 28 );
+ GET_ULONG_LE( X[ 8], data, 32 );
+ GET_ULONG_LE( X[ 9], data, 36 );
+ GET_ULONG_LE( X[10], data, 40 );
+ GET_ULONG_LE( X[11], data, 44 );
+ GET_ULONG_LE( X[12], data, 48 );
+ GET_ULONG_LE( X[13], data, 52 );
+ GET_ULONG_LE( X[14], data, 56 );
+ GET_ULONG_LE( X[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define P(a,b,c,d,k,s,t) \
+{ \
+ a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+
+ P( A, B, C, D, 0, 7, 0xD76AA478 );
+ P( D, A, B, C, 1, 12, 0xE8C7B756 );
+ P( C, D, A, B, 2, 17, 0x242070DB );
+ P( B, C, D, A, 3, 22, 0xC1BDCEEE );
+ P( A, B, C, D, 4, 7, 0xF57C0FAF );
+ P( D, A, B, C, 5, 12, 0x4787C62A );
+ P( C, D, A, B, 6, 17, 0xA8304613 );
+ P( B, C, D, A, 7, 22, 0xFD469501 );
+ P( A, B, C, D, 8, 7, 0x698098D8 );
+ P( D, A, B, C, 9, 12, 0x8B44F7AF );
+ P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
+ P( B, C, D, A, 11, 22, 0x895CD7BE );
+ P( A, B, C, D, 12, 7, 0x6B901122 );
+ P( D, A, B, C, 13, 12, 0xFD987193 );
+ P( C, D, A, B, 14, 17, 0xA679438E );
+ P( B, C, D, A, 15, 22, 0x49B40821 );
+
+#undef F
+
+#define F(x,y,z) (y ^ (z & (x ^ y)))
+
+ P( A, B, C, D, 1, 5, 0xF61E2562 );
+ P( D, A, B, C, 6, 9, 0xC040B340 );
+ P( C, D, A, B, 11, 14, 0x265E5A51 );
+ P( B, C, D, A, 0, 20, 0xE9B6C7AA );
+ P( A, B, C, D, 5, 5, 0xD62F105D );
+ P( D, A, B, C, 10, 9, 0x02441453 );
+ P( C, D, A, B, 15, 14, 0xD8A1E681 );
+ P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
+ P( A, B, C, D, 9, 5, 0x21E1CDE6 );
+ P( D, A, B, C, 14, 9, 0xC33707D6 );
+ P( C, D, A, B, 3, 14, 0xF4D50D87 );
+ P( B, C, D, A, 8, 20, 0x455A14ED );
+ P( A, B, C, D, 13, 5, 0xA9E3E905 );
+ P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
+ P( C, D, A, B, 7, 14, 0x676F02D9 );
+ P( B, C, D, A, 12, 20, 0x8D2A4C8A );
+
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+
+ P( A, B, C, D, 5, 4, 0xFFFA3942 );
+ P( D, A, B, C, 8, 11, 0x8771F681 );
+ P( C, D, A, B, 11, 16, 0x6D9D6122 );
+ P( B, C, D, A, 14, 23, 0xFDE5380C );
+ P( A, B, C, D, 1, 4, 0xA4BEEA44 );
+ P( D, A, B, C, 4, 11, 0x4BDECFA9 );
+ P( C, D, A, B, 7, 16, 0xF6BB4B60 );
+ P( B, C, D, A, 10, 23, 0xBEBFBC70 );
+ P( A, B, C, D, 13, 4, 0x289B7EC6 );
+ P( D, A, B, C, 0, 11, 0xEAA127FA );
+ P( C, D, A, B, 3, 16, 0xD4EF3085 );
+ P( B, C, D, A, 6, 23, 0x04881D05 );
+ P( A, B, C, D, 9, 4, 0xD9D4D039 );
+ P( D, A, B, C, 12, 11, 0xE6DB99E5 );
+ P( C, D, A, B, 15, 16, 0x1FA27CF8 );
+ P( B, C, D, A, 2, 23, 0xC4AC5665 );
+
+#undef F
+
+#define F(x,y,z) (y ^ (x | ~z))
+
+ P( A, B, C, D, 0, 6, 0xF4292244 );
+ P( D, A, B, C, 7, 10, 0x432AFF97 );
+ P( C, D, A, B, 14, 15, 0xAB9423A7 );
+ P( B, C, D, A, 5, 21, 0xFC93A039 );
+ P( A, B, C, D, 12, 6, 0x655B59C3 );
+ P( D, A, B, C, 3, 10, 0x8F0CCC92 );
+ P( C, D, A, B, 10, 15, 0xFFEFF47D );
+ P( B, C, D, A, 1, 21, 0x85845DD1 );
+ P( A, B, C, D, 8, 6, 0x6FA87E4F );
+ P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
+ P( C, D, A, B, 6, 15, 0xA3014314 );
+ P( B, C, D, A, 13, 21, 0x4E0811A1 );
+ P( A, B, C, D, 4, 6, 0xF7537E82 );
+ P( D, A, B, C, 11, 10, 0xBD3AF235 );
+ P( C, D, A, B, 2, 15, 0x2AD7D2BB );
+ P( B, C, D, A, 9, 21, 0xEB86D391 );
+
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+}
+
+/*
+ * MD5 process buffer
+ */
+void md5_update( md5_context *ctx, unsigned char *input, int ilen )
+{
+ int fill;
+ unsigned long left;
+
+ if( ilen <= 0 )
+ return;
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < (unsigned long) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left),
+ (void *) input, fill );
+ md5_process( ctx, ctx->buffer );
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 64 )
+ {
+ md5_process( ctx, input );
+ input += 64;
+ ilen -= 64;
+ }
+
+ if( ilen > 0 )
+ {
+ memcpy( (void *) (ctx->buffer + left),
+ (void *) input, ilen );
+ }
+}
+
+static const unsigned char md5_padding[64] =
+{
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * MD5 final digest
+ */
+void md5_finish( md5_context *ctx, unsigned char output[16] )
+{
+ unsigned long last, padn;
+ unsigned long high, low;
+ unsigned char msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_ULONG_LE( low, msglen, 0 );
+ PUT_ULONG_LE( high, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ md5_update( ctx, (unsigned char *) md5_padding, padn );
+ md5_update( ctx, msglen, 8 );
+
+ PUT_ULONG_LE( ctx->state[0], output, 0 );
+ PUT_ULONG_LE( ctx->state[1], output, 4 );
+ PUT_ULONG_LE( ctx->state[2], output, 8 );
+ PUT_ULONG_LE( ctx->state[3], output, 12 );
+}
+
+/*
+ * output = MD5( input buffer )
+ */
+void md5( unsigned char *input, int ilen, unsigned char output[16] )
+{
+ md5_context ctx;
+
+ md5_starts( &ctx );
+ md5_update( &ctx, input, ilen );
+ md5_finish( &ctx, output );
+
+ memset( &ctx, 0, sizeof( md5_context ) );
+}
+
+unsigned int md5hash ( const void * input, int len, unsigned int /*seed*/ )
+{
+ unsigned int hash[4];
+
+ md5((unsigned char *)input,len,(unsigned char *)hash);
+
+ //return hash[0] ^ hash[1] ^ hash[2] ^ hash[3];
+
+ return hash[0];
+}
+
+void md5_32 ( const void * key, int len, uint32_t /*seed*/, void * out )
+{
+ unsigned int hash[4];
+
+ md5((unsigned char*)key,len,(unsigned char*)hash);
+
+ *(uint32_t*)out = hash[0];
+} \ No newline at end of file
diff --git a/pstdint.h b/pstdint.h
new file mode 100644
index 0000000..12c108a
--- /dev/null
+++ b/pstdint.h
@@ -0,0 +1,799 @@
+/* A portable stdint.h
+ ****************************************************************************
+ * BSD License:
+ ****************************************************************************
+ *
+ * Copyright (c) 2005-2007 Paul Hsieh
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************
+ *
+ * Version 0.1.11
+ *
+ * The ANSI C standard committee, for the C99 standard, specified the
+ * inclusion of a new standard include file called stdint.h. This is
+ * a very useful and long desired include file which contains several
+ * very precise definitions for integer scalar types that is
+ * critically important for making portable several classes of
+ * applications including cryptography, hashing, variable length
+ * integer libraries and so on. But for most developers its likely
+ * useful just for programming sanity.
+ *
+ * The problem is that most compiler vendors have decided not to
+ * implement the C99 standard, and the next C++ language standard
+ * (which has a lot more mindshare these days) will be a long time in
+ * coming and its unknown whether or not it will include stdint.h or
+ * how much adoption it will have. Either way, it will be a long time
+ * before all compilers come with a stdint.h and it also does nothing
+ * for the extremely large number of compilers available today which
+ * do not include this file, or anything comparable to it.
+ *
+ * So that's what this file is all about. Its an attempt to build a
+ * single universal include file that works on as many platforms as
+ * possible to deliver what stdint.h is supposed to. A few things
+ * that should be noted about this file:
+ *
+ * 1) It is not guaranteed to be portable and/or present an identical
+ * interface on all platforms. The extreme variability of the
+ * ANSI C standard makes this an impossibility right from the
+ * very get go. Its really only meant to be useful for the vast
+ * majority of platforms that possess the capability of
+ * implementing usefully and precisely defined, standard sized
+ * integer scalars. Systems which are not intrinsically 2s
+ * complement may produce invalid constants.
+ *
+ * 2) There is an unavoidable use of non-reserved symbols.
+ *
+ * 3) Other standard include files are invoked.
+ *
+ * 4) This file may come in conflict with future platforms that do
+ * include stdint.h. The hope is that one or the other can be
+ * used with no real difference.
+ *
+ * 5) In the current verison, if your platform can't represent
+ * int32_t, int16_t and int8_t, it just dumps out with a compiler
+ * error.
+ *
+ * 6) 64 bit integers may or may not be defined. Test for their
+ * presence with the test: #ifdef INT64_MAX or #ifdef UINT64_MAX.
+ * Note that this is different from the C99 specification which
+ * requires the existence of 64 bit support in the compiler. If
+ * this is not defined for your platform, yet it is capable of
+ * dealing with 64 bits then it is because this file has not yet
+ * been extended to cover all of your system's capabilities.
+ *
+ * 7) (u)intptr_t may or may not be defined. Test for its presence
+ * with the test: #ifdef PTRDIFF_MAX. If this is not defined
+ * for your platform, then it is because this file has not yet
+ * been extended to cover all of your system's capabilities, not
+ * because its optional.
+ *
+ * 8) The following might not been defined even if your platform is
+ * capable of defining it:
+ *
+ * WCHAR_MIN
+ * WCHAR_MAX
+ * (u)int64_t
+ * PTRDIFF_MIN
+ * PTRDIFF_MAX
+ * (u)intptr_t
+ *
+ * 9) The following have not been defined:
+ *
+ * WINT_MIN
+ * WINT_MAX
+ *
+ * 10) The criteria for defining (u)int_least(*)_t isn't clear,
+ * except for systems which don't have a type that precisely
+ * defined 8, 16, or 32 bit types (which this include file does
+ * not support anyways). Default definitions have been given.
+ *
+ * 11) The criteria for defining (u)int_fast(*)_t isn't something I
+ * would trust to any particular compiler vendor or the ANSI C
+ * committee. It is well known that "compatible systems" are
+ * commonly created that have very different performance
+ * characteristics from the systems they are compatible with,
+ * especially those whose vendors make both the compiler and the
+ * system. Default definitions have been given, but its strongly
+ * recommended that users never use these definitions for any
+ * reason (they do *NOT* deliver any serious guarantee of
+ * improved performance -- not in this file, nor any vendor's
+ * stdint.h).
+ *
+ * 12) The following macros:
+ *
+ * PRINTF_INTMAX_MODIFIER
+ * PRINTF_INT64_MODIFIER
+ * PRINTF_INT32_MODIFIER
+ * PRINTF_INT16_MODIFIER
+ * PRINTF_LEAST64_MODIFIER
+ * PRINTF_LEAST32_MODIFIER
+ * PRINTF_LEAST16_MODIFIER
+ * PRINTF_INTPTR_MODIFIER
+ *
+ * are strings which have been defined as the modifiers required
+ * for the "d", "u" and "x" printf formats to correctly output
+ * (u)intmax_t, (u)int64_t, (u)int32_t, (u)int16_t, (u)least64_t,
+ * (u)least32_t, (u)least16_t and (u)intptr_t types respectively.
+ * PRINTF_INTPTR_MODIFIER is not defined for some systems which
+ * provide their own stdint.h. PRINTF_INT64_MODIFIER is not
+ * defined if INT64_MAX is not defined. These are an extension
+ * beyond what C99 specifies must be in stdint.h.
+ *
+ * In addition, the following macros are defined:
+ *
+ * PRINTF_INTMAX_HEX_WIDTH
+ * PRINTF_INT64_HEX_WIDTH
+ * PRINTF_INT32_HEX_WIDTH
+ * PRINTF_INT16_HEX_WIDTH
+ * PRINTF_INT8_HEX_WIDTH
+ * PRINTF_INTMAX_DEC_WIDTH
+ * PRINTF_INT64_DEC_WIDTH
+ * PRINTF_INT32_DEC_WIDTH
+ * PRINTF_INT16_DEC_WIDTH
+ * PRINTF_INT8_DEC_WIDTH
+ *
+ * Which specifies the maximum number of characters required to
+ * print the number of that type in either hexadecimal or decimal.
+ * These are an extension beyond what C99 specifies must be in
+ * stdint.h.
+ *
+ * Compilers tested (all with 0 warnings at their highest respective
+ * settings): Borland Turbo C 2.0, WATCOM C/C++ 11.0 (16 bits and 32
+ * bits), Microsoft Visual C++ 6.0 (32 bit), Microsoft Visual Studio
+ * .net (VC7), Intel C++ 4.0, GNU gcc v3.3.3
+ *
+ * This file should be considered a work in progress. Suggestions for
+ * improvements, especially those which increase coverage are strongly
+ * encouraged.
+ *
+ * Acknowledgements
+ *
+ * The following people have made significant contributions to the
+ * development and testing of this file:
+ *
+ * Chris Howie
+ * John Steele Scott
+ * Dave Thorup
+ *
+ */
+
+#include <stddef.h>
+#include <limits.h>
+#include <signal.h>
+
+/*
+ * For gcc with _STDINT_H, fill in the PRINTF_INT*_MODIFIER macros, and
+ * do nothing else. On the Mac OS X version of gcc this is _STDINT_H_.
+ */
+
+#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined (__WATCOMC__) && (defined (_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) )) && !defined (_PSTDINT_H_INCLUDED)
+#include <stdint.h>
+#define _PSTDINT_H_INCLUDED
+# ifndef PRINTF_INT64_MODIFIER
+# define PRINTF_INT64_MODIFIER "ll"
+# endif
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER "l"
+# endif
+# ifndef PRINTF_INT16_MODIFIER
+# define PRINTF_INT16_MODIFIER "h"
+# endif
+# ifndef PRINTF_INTMAX_MODIFIER
+# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
+# endif
+# ifndef PRINTF_INT64_HEX_WIDTH
+# define PRINTF_INT64_HEX_WIDTH "16"
+# endif
+# ifndef PRINTF_INT32_HEX_WIDTH
+# define PRINTF_INT32_HEX_WIDTH "8"
+# endif
+# ifndef PRINTF_INT16_HEX_WIDTH
+# define PRINTF_INT16_HEX_WIDTH "4"
+# endif
+# ifndef PRINTF_INT8_HEX_WIDTH
+# define PRINTF_INT8_HEX_WIDTH "2"
+# endif
+# ifndef PRINTF_INT64_DEC_WIDTH
+# define PRINTF_INT64_DEC_WIDTH "20"
+# endif
+# ifndef PRINTF_INT32_DEC_WIDTH
+# define PRINTF_INT32_DEC_WIDTH "10"
+# endif
+# ifndef PRINTF_INT16_DEC_WIDTH
+# define PRINTF_INT16_DEC_WIDTH "5"
+# endif
+# ifndef PRINTF_INT8_DEC_WIDTH
+# define PRINTF_INT8_DEC_WIDTH "3"
+# endif
+# ifndef PRINTF_INTMAX_HEX_WIDTH
+# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
+# endif
+# ifndef PRINTF_INTMAX_DEC_WIDTH
+# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
+# endif
+
+/*
+ * Something really weird is going on with Open Watcom. Just pull some of
+ * these duplicated definitions from Open Watcom's stdint.h file for now.
+ */
+
+# if defined (__WATCOMC__) && __WATCOMC__ >= 1250
+# if !defined (INT64_C)
+# define INT64_C(x) (x + (INT64_MAX - INT64_MAX))
+# endif
+# if !defined (UINT64_C)
+# define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
+# endif
+# if !defined (INT32_C)
+# define INT32_C(x) (x + (INT32_MAX - INT32_MAX))
+# endif
+# if !defined (UINT32_C)
+# define UINT32_C(x) (x + (UINT32_MAX - UINT32_MAX))
+# endif
+# if !defined (INT16_C)
+# define INT16_C(x) (x)
+# endif
+# if !defined (UINT16_C)
+# define UINT16_C(x) (x)
+# endif
+# if !defined (INT8_C)
+# define INT8_C(x) (x)
+# endif
+# if !defined (UINT8_C)
+# define UINT8_C(x) (x)
+# endif
+# if !defined (UINT64_MAX)
+# define UINT64_MAX 18446744073709551615ULL
+# endif
+# if !defined (INT64_MAX)
+# define INT64_MAX 9223372036854775807LL
+# endif
+# if !defined (UINT32_MAX)
+# define UINT32_MAX 4294967295UL
+# endif
+# if !defined (INT32_MAX)
+# define INT32_MAX 2147483647L
+# endif
+# if !defined (INTMAX_MAX)
+# define INTMAX_MAX INT64_MAX
+# endif
+# if !defined (INTMAX_MIN)
+# define INTMAX_MIN INT64_MIN
+# endif
+# endif
+#endif
+
+#ifndef _PSTDINT_H_INCLUDED
+#define _PSTDINT_H_INCLUDED
+
+#ifndef SIZE_MAX
+# define SIZE_MAX (~(size_t)0)
+#endif
+
+/*
+ * Deduce the type assignments from limits.h under the assumption that
+ * integer sizes in bits are powers of 2, and follow the ANSI
+ * definitions.
+ */
+
+#ifndef UINT8_MAX
+# define UINT8_MAX 0xff
+#endif
+#ifndef uint8_t
+# if (UCHAR_MAX == UINT8_MAX) || defined (S_SPLINT_S)
+ typedef unsigned char uint8_t;
+# define UINT8_C(v) ((uint8_t) v)
+# else
+# error "Platform not supported"
+# endif
+#endif
+
+#ifndef INT8_MAX
+# define INT8_MAX 0x7f
+#endif
+#ifndef INT8_MIN
+# define INT8_MIN INT8_C(0x80)
+#endif
+#ifndef int8_t
+# if (SCHAR_MAX == INT8_MAX) || defined (S_SPLINT_S)
+ typedef signed char int8_t;
+# define INT8_C(v) ((int8_t) v)
+# else
+# error "Platform not supported"
+# endif
+#endif
+
+#ifndef UINT16_MAX
+# define UINT16_MAX 0xffff
+#endif
+#ifndef uint16_t
+#if (UINT_MAX == UINT16_MAX) || defined (S_SPLINT_S)
+ typedef unsigned int uint16_t;
+# ifndef PRINTF_INT16_MODIFIER
+# define PRINTF_INT16_MODIFIER ""
+# endif
+# define UINT16_C(v) ((uint16_t) (v))
+#elif (USHRT_MAX == UINT16_MAX)
+ typedef unsigned short uint16_t;
+# define UINT16_C(v) ((uint16_t) (v))
+# ifndef PRINTF_INT16_MODIFIER
+# define PRINTF_INT16_MODIFIER "h"
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+#ifndef INT16_MAX
+# define INT16_MAX 0x7fff
+#endif
+#ifndef INT16_MIN
+# define INT16_MIN INT16_C(0x8000)
+#endif
+#ifndef int16_t
+#if (INT_MAX == INT16_MAX) || defined (S_SPLINT_S)
+ typedef signed int int16_t;
+# define INT16_C(v) ((int16_t) (v))
+# ifndef PRINTF_INT16_MODIFIER
+# define PRINTF_INT16_MODIFIER ""
+# endif
+#elif (SHRT_MAX == INT16_MAX)
+ typedef signed short int16_t;
+# define INT16_C(v) ((int16_t) (v))
+# ifndef PRINTF_INT16_MODIFIER
+# define PRINTF_INT16_MODIFIER "h"
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+#ifndef UINT32_MAX
+# define UINT32_MAX (0xffffffffUL)
+#endif
+#ifndef uint32_t
+#if (ULONG_MAX == UINT32_MAX) || defined (S_SPLINT_S)
+ typedef unsigned long uint32_t;
+# define UINT32_C(v) v ## UL
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER "l"
+# endif
+#elif (UINT_MAX == UINT32_MAX)
+ typedef unsigned int uint32_t;
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER ""
+# endif
+# define UINT32_C(v) v ## U
+#elif (USHRT_MAX == UINT32_MAX)
+ typedef unsigned short uint32_t;
+# define UINT32_C(v) ((unsigned short) (v))
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER ""
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+#ifndef INT32_MAX
+# define INT32_MAX (0x7fffffffL)
+#endif
+#ifndef INT32_MIN
+# define INT32_MIN INT32_C(0x80000000)
+#endif
+#ifndef int32_t
+#if (LONG_MAX == INT32_MAX) || defined (S_SPLINT_S)
+ typedef signed long int32_t;
+# define INT32_C(v) v ## L
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER "l"
+# endif
+#elif (INT_MAX == INT32_MAX)
+ typedef signed int int32_t;
+# define INT32_C(v) v
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER ""
+# endif
+#elif (SHRT_MAX == INT32_MAX)
+ typedef signed short int32_t;
+# define INT32_C(v) ((short) (v))
+# ifndef PRINTF_INT32_MODIFIER
+# define PRINTF_INT32_MODIFIER ""
+# endif
+#else
+#error "Platform not supported"
+#endif
+#endif
+
+/*
+ * The macro stdint_int64_defined is temporarily used to record
+ * whether or not 64 integer support is available. It must be
+ * defined for any 64 integer extensions for new platforms that are
+ * added.
+ */
+
+#undef stdint_int64_defined
+#if (defined(__STDC__) && defined(__STDC_VERSION__)) || defined (S_SPLINT_S)
+# if (__STDC__ && __STDC_VERSION >= 199901L) || defined (S_SPLINT_S)
+# define stdint_int64_defined
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+# define UINT64_C(v) v ## ULL
+# define INT64_C(v) v ## LL
+# ifndef PRINTF_INT64_MODIFIER
+# define PRINTF_INT64_MODIFIER "ll"
+# endif
+# endif
+#endif
+
+#if !defined (stdint_int64_defined)
+# if defined(__GNUC__)
+# define stdint_int64_defined
+ __extension__ typedef long long int64_t;
+ __extension__ typedef unsigned long long uint64_t;
+# define UINT64_C(v) v ## ULL
+# define INT64_C(v) v ## LL
+# ifndef PRINTF_INT64_MODIFIER
+# define PRINTF_INT64_MODIFIER "ll"
+# endif
+# elif defined(__MWERKS__) || defined (__SUNPRO_C) || defined (__SUNPRO_CC) || defined (__APPLE_CC__) || defined (_LONG_LONG) || defined (_CRAYC) || defined (S_SPLINT_S)
+# define stdint_int64_defined
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+# define UINT64_C(v) v ## ULL
+# define INT64_C(v) v ## LL
+# ifndef PRINTF_INT64_MODIFIER
+# define PRINTF_INT64_MODIFIER "ll"
+# endif
+# elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined (__BORLANDC__) && __BORLANDC__ > 0x460) || defined (__alpha) || defined (__DECC)
+# define stdint_int64_defined
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+# define UINT64_C(v) v ## UI64
+# define INT64_C(v) v ## I64
+# ifndef PRINTF_INT64_MODIFIER
+# define PRINTF_INT64_MODIFIER "I64"
+# endif
+# endif
+#endif
+
+#if !defined (LONG_LONG_MAX) && defined (INT64_C)
+# define LONG_LONG_MAX INT64_C (9223372036854775807)
+#endif
+#ifndef ULONG_LONG_MAX
+# define ULONG_LONG_MAX UINT64_C (18446744073709551615)
+#endif
+
+#if !defined (INT64_MAX) && defined (INT64_C)
+# define INT64_MAX INT64_C (9223372036854775807)
+#endif
+#if !defined (INT64_MIN) && defined (INT64_C)
+# define INT64_MIN INT64_C (-9223372036854775808)
+#endif
+#if !defined (UINT64_MAX) && defined (INT64_C)
+# define UINT64_MAX UINT64_C (18446744073709551615)
+#endif
+
+/*
+ * Width of hexadecimal for number field.
+ */
+
+#ifndef PRINTF_INT64_HEX_WIDTH
+# define PRINTF_INT64_HEX_WIDTH "16"
+#endif
+#ifndef PRINTF_INT32_HEX_WIDTH
+# define PRINTF_INT32_HEX_WIDTH "8"
+#endif
+#ifndef PRINTF_INT16_HEX_WIDTH
+# define PRINTF_INT16_HEX_WIDTH "4"
+#endif
+#ifndef PRINTF_INT8_HEX_WIDTH
+# define PRINTF_INT8_HEX_WIDTH "2"
+#endif
+
+#ifndef PRINTF_INT64_DEC_WIDTH
+# define PRINTF_INT64_DEC_WIDTH "20"
+#endif
+#ifndef PRINTF_INT32_DEC_WIDTH
+# define PRINTF_INT32_DEC_WIDTH "10"
+#endif
+#ifndef PRINTF_INT16_DEC_WIDTH
+# define PRINTF_INT16_DEC_WIDTH "5"
+#endif
+#ifndef PRINTF_INT8_DEC_WIDTH
+# define PRINTF_INT8_DEC_WIDTH "3"
+#endif
+
+/*
+ * Ok, lets not worry about 128 bit integers for now. Moore's law says
+ * we don't need to worry about that until about 2040 at which point
+ * we'll have bigger things to worry about.
+ */
+
+#ifdef stdint_int64_defined
+ typedef int64_t intmax_t;
+ typedef uint64_t uintmax_t;
+# define INTMAX_MAX INT64_MAX
+# define INTMAX_MIN INT64_MIN
+# define UINTMAX_MAX UINT64_MAX
+# define UINTMAX_C(v) UINT64_C(v)
+# define INTMAX_C(v) INT64_C(v)
+# ifndef PRINTF_INTMAX_MODIFIER
+# define PRINTF_INTMAX_MODIFIER PRINTF_INT64_MODIFIER
+# endif
+# ifndef PRINTF_INTMAX_HEX_WIDTH
+# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT64_HEX_WIDTH
+# endif
+# ifndef PRINTF_INTMAX_DEC_WIDTH
+# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT64_DEC_WIDTH
+# endif
+#else
+ typedef int32_t intmax_t;
+ typedef uint32_t uintmax_t;
+# define INTMAX_MAX INT32_MAX
+# define UINTMAX_MAX UINT32_MAX
+# define UINTMAX_C(v) UINT32_C(v)
+# define INTMAX_C(v) INT32_C(v)
+# ifndef PRINTF_INTMAX_MODIFIER
+# define PRINTF_INTMAX_MODIFIER PRINTF_INT32_MODIFIER
+# endif
+# ifndef PRINTF_INTMAX_HEX_WIDTH
+# define PRINTF_INTMAX_HEX_WIDTH PRINTF_INT32_HEX_WIDTH
+# endif
+# ifndef PRINTF_INTMAX_DEC_WIDTH
+# define PRINTF_INTMAX_DEC_WIDTH PRINTF_INT32_DEC_WIDTH
+# endif
+#endif
+
+/*
+ * Because this file currently only supports platforms which have
+ * precise powers of 2 as bit sizes for the default integers, the
+ * least definitions are all trivial. Its possible that a future
+ * version of this file could have different definitions.
+ */
+
+#ifndef stdint_least_defined
+ typedef int8_t int_least8_t;
+ typedef uint8_t uint_least8_t;
+ typedef int16_t int_least16_t;
+ typedef uint16_t uint_least16_t;
+ typedef int32_t int_least32_t;
+ typedef uint32_t uint_least32_t;
+# define PRINTF_LEAST32_MODIFIER PRINTF_INT32_MODIFIER
+# define PRINTF_LEAST16_MODIFIER PRINTF_INT16_MODIFIER
+# define UINT_LEAST8_MAX UINT8_MAX
+# define INT_LEAST8_MAX INT8_MAX
+# define UINT_LEAST16_MAX UINT16_MAX
+# define INT_LEAST16_MAX INT16_MAX
+# define UINT_LEAST32_MAX UINT32_MAX
+# define INT_LEAST32_MAX INT32_MAX
+# define INT_LEAST8_MIN INT8_MIN
+# define INT_LEAST16_MIN INT16_MIN
+# define INT_LEAST32_MIN INT32_MIN
+# ifdef stdint_int64_defined
+ typedef int64_t int_least64_t;
+ typedef uint64_t uint_least64_t;
+# define PRINTF_LEAST64_MODIFIER PRINTF_INT64_MODIFIER
+# define UINT_LEAST64_MAX UINT64_MAX
+# define INT_LEAST64_MAX INT64_MAX
+# define INT_LEAST64_MIN INT64_MIN
+# endif
+#endif
+#undef stdint_least_defined
+
+/*
+ * The ANSI C committee pretending to know or specify anything about
+ * performance is the epitome of misguided arrogance. The mandate of
+ * this file is to *ONLY* ever support that absolute minimum
+ * definition of the fast integer types, for compatibility purposes.
+ * No extensions, and no attempt to suggest what may or may not be a
+ * faster integer type will ever be made in this file. Developers are
+ * warned to stay away from these types when using this or any other
+ * stdint.h.
+ */
+
+typedef int_least8_t int_fast8_t;
+typedef uint_least8_t uint_fast8_t;
+typedef int_least16_t int_fast16_t;
+typedef uint_least16_t uint_fast16_t;
+typedef int_least32_t int_fast32_t;
+typedef uint_least32_t uint_fast32_t;
+#define UINT_FAST8_MAX UINT_LEAST8_MAX
+#define INT_FAST8_MAX INT_LEAST8_MAX
+#define UINT_FAST16_MAX UINT_LEAST16_MAX
+#define INT_FAST16_MAX INT_LEAST16_MAX
+#define UINT_FAST32_MAX UINT_LEAST32_MAX
+#define INT_FAST32_MAX INT_LEAST32_MAX
+#define INT_FAST8_MIN INT_LEAST8_MIN
+#define INT_FAST16_MIN INT_LEAST16_MIN
+#define INT_FAST32_MIN INT_LEAST32_MIN
+#ifdef stdint_int64_defined
+ typedef int_least64_t int_fast64_t;
+ typedef uint_least64_t uint_fast64_t;
+# define UINT_FAST64_MAX UINT_LEAST64_MAX
+# define INT_FAST64_MAX INT_LEAST64_MAX
+# define INT_FAST64_MIN INT_LEAST64_MIN
+#endif
+
+#undef stdint_int64_defined
+
+/*
+ * Whatever piecemeal, per compiler thing we can do about the wchar_t
+ * type limits.
+ */
+
+#if defined(__WATCOMC__) || defined(_MSC_VER) || defined (__GNUC__)
+# include <wchar.h>
+# ifndef WCHAR_MIN
+# define WCHAR_MIN 0
+# endif
+# ifndef WCHAR_MAX
+# define WCHAR_MAX ((wchar_t)-1)
+# endif
+#endif
+
+/*
+ * Whatever piecemeal, per compiler/platform thing we can do about the
+ * (u)intptr_t types and limits.
+ */
+
+#if defined (_MSC_VER) && defined (_UINTPTR_T_DEFINED)
+# define STDINT_H_UINTPTR_T_DEFINED
+#endif
+
+#ifndef STDINT_H_UINTPTR_T_DEFINED
+# if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (_WIN64)
+# define stdint_intptr_bits 64
+# elif defined (__WATCOMC__) || defined (__TURBOC__)
+# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
+# define stdint_intptr_bits 16
+# else
+# define stdint_intptr_bits 32
+# endif
+# elif defined (__i386__) || defined (_WIN32) || defined (WIN32)
+# define stdint_intptr_bits 32
+# elif defined (__INTEL_COMPILER)
+/* TODO -- what will Intel do about x86-64? */
+# endif
+
+# ifdef stdint_intptr_bits
+# define stdint_intptr_glue3_i(a,b,c) a##b##c
+# define stdint_intptr_glue3(a,b,c) stdint_intptr_glue3_i(a,b,c)
+# ifndef PRINTF_INTPTR_MODIFIER
+# define PRINTF_INTPTR_MODIFIER stdint_intptr_glue3(PRINTF_INT,stdint_intptr_bits,_MODIFIER)
+# endif
+# ifndef PTRDIFF_MAX
+# define PTRDIFF_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
+# endif
+# ifndef PTRDIFF_MIN
+# define PTRDIFF_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
+# endif
+# ifndef UINTPTR_MAX
+# define UINTPTR_MAX stdint_intptr_glue3(UINT,stdint_intptr_bits,_MAX)
+# endif
+# ifndef INTPTR_MAX
+# define INTPTR_MAX stdint_intptr_glue3(INT,stdint_intptr_bits,_MAX)
+# endif
+# ifndef INTPTR_MIN
+# define INTPTR_MIN stdint_intptr_glue3(INT,stdint_intptr_bits,_MIN)
+# endif
+# ifndef INTPTR_C
+# define INTPTR_C(x) stdint_intptr_glue3(INT,stdint_intptr_bits,_C)(x)
+# endif
+# ifndef UINTPTR_C
+# define UINTPTR_C(x) stdint_intptr_glue3(UINT,stdint_intptr_bits,_C)(x)
+# endif
+ typedef stdint_intptr_glue3(uint,stdint_intptr_bits,_t) uintptr_t;
+ typedef stdint_intptr_glue3( int,stdint_intptr_bits,_t) intptr_t;
+# else
+/* TODO -- This following is likely wrong for some platforms, and does
+ nothing for the definition of uintptr_t. */
+ typedef ptrdiff_t intptr_t;
+# endif
+# define STDINT_H_UINTPTR_T_DEFINED
+#endif
+
+/*
+ * Assumes sig_atomic_t is signed and we have a 2s complement machine.
+ */
+
+#ifndef SIG_ATOMIC_MAX
+# define SIG_ATOMIC_MAX ((((sig_atomic_t) 1) << (sizeof (sig_atomic_t)*CHAR_BIT-1)) - 1)
+#endif
+
+#endif
+
+#if defined (__TEST_PSTDINT_FOR_CORRECTNESS)
+
+/*
+ * Please compile with the maximum warning settings to make sure macros are not
+ * defined more than once.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define glue3_aux(x,y,z) x ## y ## z
+#define glue3(x,y,z) glue3_aux(x,y,z)
+
+#define DECLU(bits) glue3(uint,bits,_t) glue3(u,bits,=) glue3(UINT,bits,_C) (0);
+#define DECLI(bits) glue3(int,bits,_t) glue3(i,bits,=) glue3(INT,bits,_C) (0);
+
+#define DECL(us,bits) glue3(DECL,us,) (bits)
+
+#define TESTUMAX(bits) glue3(u,bits,=) glue3(~,u,bits); if (glue3(UINT,bits,_MAX) glue3(!=,u,bits)) printf ("Something wrong with UINT%d_MAX\n", bits)
+
+int main () {
+ DECL(I,8)
+ DECL(U,8)
+ DECL(I,16)
+ DECL(U,16)
+ DECL(I,32)
+ DECL(U,32)
+#ifdef INT64_MAX
+ DECL(I,64)
+ DECL(U,64)
+#endif
+ intmax_t imax = INTMAX_C(0);
+ uintmax_t umax = UINTMAX_C(0);
+ char str0[256], str1[256];
+
+ sprintf (str0, "%d %x\n", 0, ~0);
+
+ sprintf (str1, "%d %x\n", i8, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with i8 : %s\n", str1);
+ sprintf (str1, "%u %x\n", u8, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with u8 : %s\n", str1);
+ sprintf (str1, "%d %x\n", i16, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with i16 : %s\n", str1);
+ sprintf (str1, "%u %x\n", u16, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with u16 : %s\n", str1);
+ sprintf (str1, "%" PRINTF_INT32_MODIFIER "d %x\n", i32, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with i32 : %s\n", str1);
+ sprintf (str1, "%" PRINTF_INT32_MODIFIER "u %x\n", u32, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with u32 : %s\n", str1);
+#ifdef INT64_MAX
+ sprintf (str1, "%" PRINTF_INT64_MODIFIER "d %x\n", i64, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with i64 : %s\n", str1);
+#endif
+ sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "d %x\n", imax, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with imax : %s\n", str1);
+ sprintf (str1, "%" PRINTF_INTMAX_MODIFIER "u %x\n", umax, ~0);
+ if (0 != strcmp (str0, str1)) printf ("Something wrong with umax : %s\n", str1);
+
+ TESTUMAX(8);
+ TESTUMAX(16);
+ TESTUMAX(32);
+#ifdef INT64_MAX
+ TESTUMAX(64);
+#endif
+
+ return EXIT_SUCCESS;
+}
+
+#endif
diff --git a/scratch.cpp b/scratch.cpp
new file mode 100644
index 0000000..0043966
--- /dev/null
+++ b/scratch.cpp
@@ -0,0 +1,823 @@
+#include <stdio.h>
+#include <tchar.h>
+
+#include "Types.h"
+#include "Stats.h"
+#include "Tests.h"
+#include "Hamming.h"
+#include "Junk.h"
+#include "SimAnneal.h"
+
+#include <vector>
+#include <set>
+#include <map>
+#include <math.h>
+#include <intrin.h>
+
+#pragma warning(disable : 4702)
+
+//-----------------------------------------------------------------------------
+
+template < int nbits >
+void printkey ( Blob<nbits> & k )
+{
+ int nbytes = nbits/8;
+
+ printf("{");
+
+ uint8_t * d = (uint8_t*)&k;
+
+ for(int i = 0; i < nbytes; i++)
+ {
+ printf("0x%02x,",d[i]);
+ }
+ printf("};\n");
+}
+
+
+//-----------------------------------------------------------------------------
+// Test code for Murmur3's mix function
+
+/*
+uint32_t i1 = 0x95543787;
+uint32_t i2 = 0x2ad7eb25;
+
+uint32_t m1 = 9;
+uint32_t a1 = 0x273581d8;
+
+uint32_t m2 = 5;
+uint32_t a2 = 0xee700bac;
+
+uint32_t m3 = 3;
+uint32_t a3 = 0xa6b84e31;
+
+uint32_t r1 = 5;
+
+int stage = 0;
+
+uint32_t m3mix ( uint32_t k )
+{
+ //return rand_u32();
+
+ uint32_t h = 0x971e137b;
+ uint32_t c1 = i1;
+ uint32_t c2 = i2;
+
+ for(int i = 0; i < stage; i++)
+ {
+ h = h*m3+a3;
+ c1 = c1*m1+a1;
+ c2 = c2*m2+a2;
+ }
+
+ k *= c1;
+ k = _rotl(k,r1);
+ h = h*m3+a3;
+ k *= c2;
+ c1 = c1*m1+a1;
+ c2 = c2*m2+a2;
+ h ^= k;
+
+ return h;
+}
+*/
+
+/*
+uint32_t m1 = 0x85ebca6b;
+uint32_t m2 = 0xc2b2ae35;
+uint32_t m3 = 0x893ed583;
+
+int s1 = 16;
+int s2 = 13;
+int s3 = 16;
+
+uint32_t fmix ( uint32_t k )
+{
+ return rand_u32();
+
+ k ^= k >> 16;
+ k *= 0x85ebca6b;
+ k ^= k >> 13;
+ k *= 0xc2b2ae35;
+ k ^= k >> 16;
+
+ return k;
+}
+*/
+
+//-----------------------------------------------------------------------------
+
+/*
+struct mixconfig
+{
+ uint32_t m1;
+ uint32_t m2;
+};
+
+mixconfig mc =
+{
+ 0x010d5a2d,
+ 0xd3636b39,
+};
+
+uint32_t fmix32 ( uint32_t k )
+{
+ //return rand_u32();
+
+ k ^= k >> 16;
+ k *= mc.m1;
+ k ^= k >> 16;
+ k *= mc.m2;
+ k ^= k >> 16;
+
+ return k;
+}
+
+double mixfit ( void * block, int )
+{
+ mixconfig * pc = (mixconfig*)block;
+
+ mc.m1 = pc->m1 | 1;
+ mc.m2 = pc->m2 | 1;
+
+ Stats s = testMixAvalanche<uint32_t>(mixfunc<uint32_t>(blahmix),2000000);
+
+ return 1.0 - s.m_max;
+}
+
+void mixdump ( void * block, int )
+{
+ mixconfig * pc = (mixconfig*)block;
+
+ printf("0x%08x 0x%08x",pc->m1, pc->m2 );
+}
+*/
+
+//-----------------------------------------------------------------------------
+// SimAnneal optimize of fmix64
+
+struct mixconfig
+{
+ //uint8_t s1;
+ uint64_t m1;
+ //uint8_t s2;
+ uint64_t m2;
+ //uint8_t s3;
+};
+
+mixconfig mc = { 0xff51afd7ed558ccd, 0xc4ceb9fe1a85ec53 };
+
+uint64_t fmix64_test ( uint64_t k )
+{
+ k ^= k >> 33;
+ //k ^= k >> mc.s1;
+
+ k *= mc.m1;
+
+ k ^= k >> 33;
+ //k ^= k >> mc.s2;
+
+ k *= mc.m2;
+
+ k ^= k >> 33;
+ //k ^= k >> mc.s3;
+
+ return k;
+}
+
+double fmix64_fit ( void * block, int )
+{
+ mixconfig * pc = (mixconfig*)block;
+
+ mc.m1 = pc->m1 | 1;
+ mc.m2 = pc->m2 | 1;
+
+ //mc.s1 = pc->s1 & 63;
+ //mc.s2 = pc->s1 & 63;
+ //mc.s3 = pc->s1 & 63;
+
+ double bias = calcMixBias<uint64_t>(fmix64_test,50000000);
+
+ return 1.0 - bias;
+}
+
+void fmix64_dump ( void * block, int )
+{
+ mixconfig * pc = (mixconfig*)block;
+
+ //pc->s1 &= 63;
+ //pc->s2 &= 63;
+ //pc->s3 &= 63;
+
+ //printf("{ %2d, 0x%016I64x, %2d, 0x%016I64x, %2d }; ",pc->s1, pc->m1, pc->s2, pc->m2, pc->s3 );
+ printf("{ 0x%016I64x, 0x%016I64x }; ", pc->m1, pc->m2 );
+}
+
+uint32_t fmix32_test ( uint32_t h )
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+
+ return h;
+}
+
+void optimize_fmix64 ( void )
+{
+ printf("lskdflksj\n");
+ double bias = calcMixBias<uint32_t>(fmix32_test,500000000);
+
+ printf("%f\n",bias);
+
+ //SimAnneal(&mc,sizeof(mc),fmix64_fit,fmix64_dump,4,100);
+}
+
+
+//-----------------------------------------------------------------------------
+// Fitness == distribution of Hamming weights.
+// Optimize mix by minmaxing Hamming weights
+
+// (we want the smallest differential hamming weight to be as large as possible)
+
+void HammingOptimize ( uint32_t (*mix)(uint32_t) )
+{
+ double best[33];
+ best[0] = 2000000000;
+
+ double c[33];
+
+ printf("0x%08x\n",rand_u32());
+
+ //for(m3 = 0; m3 < 32; m3++)
+
+ for(int i = 0; i < 100000; i++)
+ {
+ //for(r1 = 12; r1 < 18; r1++)
+ {
+ memset(c,0,sizeof(c));
+ SparseDiffHamming32(mix,c);
+
+ if(hamless(33,c,best))
+ {
+ memcpy(best,c,sizeof(c));
+
+ //printf("{%6.3f, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f, %6.3f } - ",c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7],c[8]);
+
+ printf("{");
+
+ for(int i = 0; i < 33; i++) printf("%6.3f ",c[i]);
+ printf("} - ");
+
+ //printf("0x%08x, %2d, 0x%08x %2d\n",m1,r1,m2,m3);
+ //printf("0x%08x, 0x%08x\n",m1,m2);
+ printf("\n");
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+u128 mix128 ( u128 h2 )
+{
+ uint32_t * h = (uint32_t*)&h2;
+
+ for(int i = 0; i < 30; i++)
+ {
+ h[0] = _rotl(h[0],3);
+ h[1] = _rotl(h[1],10);
+ h[2] = _rotl(h[2],19);
+ h[3] = _rotl(h[3],26);
+
+ h[0] += h[1];
+ h[0] += h[2];
+ h[0] += h[3];
+
+ h[1] += h[0];
+ h[2] += h[0];
+ h[3] += h[0];
+ }
+
+ return h2;
+}
+
+//-----------------------------------------------------------------------------
+
+void scratchmain ( void )
+{
+ /*
+ double worst = 1000;
+
+ double worstStage = 0;
+
+ for(stage = 0; stage < 16; stage++)
+ {
+ Stats s = testMixAvalanche<uint32_t>(mixfunc<uint32_t>(m3mix),300);
+
+ if(s.m_nbad > worstStage) worstStage = s.m_nbad;
+ }
+
+ if(worstStage < worst)
+ {
+ worst = worstStage;
+
+ printf("%3.4f : 0x%08x 0x%08x %2d 0x%08x %2d 0x%08x %2d 0x%08x %2d\n",worst,i1,i2,m1,a1,m2,a2,m3,a3,r1);
+ }
+
+ //----------
+
+ for(int i = 0; i < 1000000; i++)
+ {
+ for(m1 = 3; m1 < 10; m1 += 2)
+ for(m2 = 3; m2 < 10; m2 += 2)
+ for(m3 = 3; m3 < 10; m3 += 2)
+ for(r1 = 0; r1 < 32; r1++)
+ //for(int bit = 0; bit < 32; bit++)
+ {
+ //i2 ^= (1 << bit);
+
+ if(m1 == 7) continue;
+ if(m2 == 7) continue;
+ if(m3 == 7) continue;
+
+ double worstStage = 0;
+
+ for(stage = 0; stage < 16; stage++)
+ {
+ Stats s = testMixAvalanche<uint32_t>(mixfunc<uint32_t>(m3mix),300);
+
+ if(s.m_nbad > worstStage) worstStage = s.m_nbad;
+ }
+
+ if(worstStage < worst)
+ {
+ worst = worstStage;
+
+ printf("%3.4f : 0x%08x 0x%08x %2d 0x%08x %2d 0x%08x %2d 0x%08x %2d\n",worst,i1,i2,m1,a1,m2,a2,m3,a3,r1);
+ }
+ else
+ {
+ //i2 ^= (1 << bit);
+ }
+ }
+
+ //i1 = rand_u32();
+ //i2 = rand_u32();
+
+ //a1 = rand_u32();
+ //a2 = rand_u32();
+ //a3 = rand_u32();
+ }
+ */
+}
+
+//-----------------------------------------------------------------------------
+
+/*
+void Pathological ( void )
+{
+ std::set<uint32_t> s;
+
+ uint32_t c = 0;
+ uint32_t seed = 0xdeadbeef * 16;
+
+ for(int j = 0; j < 5000; j++)
+ {
+ for(uint32_t i = 0; i < 10000; i++)
+ {
+ uint32_t key[4] = {c,c,c,c};
+
+ uint32_t hash = MurmurHash2(key,16,seed);
+
+ //v.push_back(hash);
+ s.insert(hash);
+ c++;
+ }
+
+ printf("%8d %8f\n",s.size(),double(s.size()) / double(c));
+ }
+}
+*/
+
+/*
+void Pathological ( void )
+{
+ const int nbytes = 512 * 1024 * 1024;
+
+ unsigned char * block = new unsigned char[nbytes];
+
+ memset(block,0,nbytes);
+
+ unsigned int k = 0;
+ unsigned int key[256];
+ unsigned int collisions = 0;
+
+ do
+ {
+ for(int i = 0; i < 256; i++) key[i] = k;
+
+ unsigned int h;
+ h = MurmurHash2(&key[0],256*4,(0xdeadbeef * 16));
+ //MurmurHash3_x86_32(&key[0],32,(0xdeadbeef * 16),&h);
+
+ //printf("0x%08x\n",h);
+
+ if(getbit(block,nbytes,h))
+ {
+ collisions++;
+ }
+
+ setbit(block,nbytes,h);
+
+ if(k % 10000000 == 0)
+ {
+ printf("%12d : %9d : %f\n",k,collisions,double(collisions) / double(k));
+ }
+
+ k++;
+ }
+ while(k != 0);
+
+ printf("%d total collisions",collisions);
+
+ delete [] block;
+}
+*/
+
+/*
+void Pathological ( void )
+{
+ const int nbytes = 512 * 1024 * 1024;
+
+ unsigned char * block = new unsigned char[nbytes];
+
+ memset(block,0,nbytes);
+
+ unsigned int k = 0;
+ unsigned int unique = 0;
+
+ do
+ {
+ const uint32_t m = 0xdeadbeef;
+ const int r = 24;
+
+ uint32_t x = 0;
+ uint32_t h = 0;
+
+ x = k;
+ x *= m;
+ x ^= x >> r;
+ x *= m;
+
+ h *= m;
+ h ^= x;
+
+ x = k;
+ x *= m;
+ x ^= x >> r;
+ x *= m;
+
+ h *= m;
+ h ^= x;
+
+ if(!getbit(block,nbytes,h))
+ {
+ unique++;
+ }
+
+ setbit(block,nbytes,h);
+
+ if(k % 10000000 == 0)
+ {
+ printf("%12d : %9d :%f\n",k,unique,double(unique) / double(k));
+ }
+
+ k++;
+ }
+ while(k);
+
+ printf("%d unique",unique);
+
+ delete [] block;
+}
+*/
+
+/*
+void Pathological ( void )
+{
+ typedef std::map<uint32_t,uint32_t> cmap;
+
+ cmap collisionmap;
+
+ const int nbytes = 512 * 1024 * 1024;
+
+ unsigned char * block = new unsigned char[nbytes];
+
+ memset(block,0,nbytes);
+
+ unsigned int k = 0;
+ unsigned int key[4];
+ unsigned int collisions = 0;
+
+ do
+ {
+ for(int i = 0; i < 4; i++) key[i] = k;
+
+ unsigned int h;
+ h = MurmurHash2(&key[0],4*sizeof(uint32_t),16);
+ //MurmurHash3_x86_32(&key[0],32,(0xdeadbeef * 16),&h);
+
+ //printf("0x%08x\n",h);
+
+ if(getbit(block,nbytes,h))
+ {
+ collisions++;
+ collisionmap[h]++;
+ }
+
+ setbit(block,nbytes,h);
+
+ if(k % 10000000 == 0)
+ {
+ printf("%12d : %9d : %9d :%f\n",k,collisionmap.size(),collisions,double(collisions) / double(k));
+ }
+
+ k++;
+ }
+ //while(k);
+ while(k <= 200000000);
+
+ uint32_t most = 0;
+ for(cmap::iterator i = collisionmap.begin(); i != collisionmap.end(); ++i)
+ {
+ uint32_t h = (*i).first;
+ uint32_t c = (*i).second;
+
+ if(c > most)
+ {
+ most = c;
+ printf("0x%08x : %d\n",h,c);
+ }
+ }
+
+ printf("%d total collisions",collisions);
+
+ delete [] block;
+}
+*/
+
+/*
+void Pathological ( void )
+{
+ unsigned int k = 0;
+ unsigned int key[4];
+
+ std::vector<uint32_t> v;
+
+ do
+ {
+ for(int i = 0; i < 4; i++) key[i] = k;
+
+ unsigned int h;
+ h = MurmurHash2(&key[0],4*sizeof(uint32_t),16);
+
+ if(h == 0xb5abf828)
+ {
+ v.push_back(k);
+ }
+
+ if(k % 100000000 == 0)
+ {
+ printf("%12u : %12d\n",k,v.size());
+ }
+
+
+ k++;
+ }
+ while(k);
+
+ for(size_t i = 0; i < v.size(); i++)
+ {
+ printf("0x%08x,",v[i]);
+ if(i%8==7) printf("\n");
+ }
+ printf("\n");
+}
+*/
+
+/*
+uint32_t bad[] =
+{
+0x0017f1a9,0x00f8c102,0x01685768,0x01c6d69e,0x02109e20,0x02ea2120,0x03615606,0x03bab745,
+0x03eb73e9,0x03f7db48,0x04391e64,0x04747fa7,0x04b81cf5,0x04fbcab0,0x054bf06a,0x05d33abc,
+0x05d8eb48,0x06560ce6,0x0697bcfa,0x06a40faa,0x071977fb,0x073a4306,0x073eb088,0x0751c777,
+0x07534cb4,0x079d2fbe,0x07a0ba13,0x07cff5fc,0x082b2d13,0x08457c35,0x093de81e,0x09711b75,
+0x097fdb48,0x09ba9060,0x0a06228a,0x0a5f8691,0x0a63881c,0x0a70bcd7,0x0aed67dd,0x0b0ed19a,
+0x0bc68125,0x0c29fe48,0x0ca1eb57,0x0cbfc528,0x0d4017e2,0x0d6d91c2,0x0d7388de,0x0f0133e9,
+0x0f8d17e7,0x0f90e980,0x0fe6be43,0x1033d71d,0x1087872c,0x10b52186,0x12005768,0x12c817e2,
+0x12ed3caf,0x1343eae2,0x137b2949,0x1407d537,0x1462906a,0x156742a0,0x15f44042,0x17204969,
+0x18c86d6a,0x192c6777,0x1950b0f3,0x19548454,0x1961fb59,0x19e92685,0x1a24be52,0x1a72ccfa,
+0x1a7caf9b,0x1a9d7aa6,0x1b9407c9,0x1b9d472c,0x1bdc3c3f,0x1c2a955f,0x1c44f065,0x1c75fda6,
+0x1c934985,0x1cd45315,0x1d1dce3e,0x1d695a2a,0x1e88f490,0x203a3985,0x2050669c,0x20a34f82,
+0x221b4985,0x222718dc,0x2240aa13,0x22a67680,0x24bdf477,0x250ead99,0x255d00e9,0x2652bb8e,
+0x26823b4d,0x27298fd2,0x27bf3042,0x27e2e537,0x282dbcdc,0x295777e2,0x2ab449ff,0x2d347ad3,
+0x2d3c176d,0x2d4c5e25,0x2d72b111,0x2d9f768f,0x2ddfe73b,0x2e00b246,0x2f9f1523,0x2fdbdba7,
+0x30831cfa,0x30cc91ca,0x3129f75c,0x313f9486,0x315255e3,0x31e70a31,0x33490a31,0x33622c30,
+0x33863468,0x3441b8a7,0x349f03ad,0x3715eda6,0x374df66c,0x3766e2fc,0x3848010c,0x385325bb,
+0x38a843f3,0x398e8722,0x39cc0d5b,0x39e572ed,0x3ace4477,0x3afb8c19,0x3b98b8d4,0x3ce6212a,
+0x3cec46c6,0x3d43761a,0x3de45e25,0x3e1e5a2c,0x3f612a36,0x4008f490,0x41431edb,0x4163e9e6,
+0x41742120,0x41854564,0x41ca60f3,0x41fa37f6,0x421e16a3,0x4263b66c,0x42bc7a4a,0x434286ad,
+0x435858a7,0x43bbf5f2,0x43e43d7e,0x442fc96a,0x443e6342,0x44b58d83,0x45378356,0x45df4db0,
+0x46b09971,0x47337cff,0x47f46fc3,0x48023b4d,0x4823a50a,0x49691a36,0x497767dd,0x4a50eadd,
+0x4ad26a3b,0x4b8463b7,0x4bc34e34,0x4bcd5cc3,0x4bf245e3,0x4c62946d,0x4d18b7f9,0x4da4d029,
+0x4dcac8e3,0x4df83139,0x4e2514b8,0x4e859f82,0x4ea95477,0x4ef42c1c,0x4f68a832,0x4f7acba7,
+0x4fa478d9,0x4ffe8c21,0x50ee3486,0x514795c5,0x51948107,0x51c5fce4,0x51e3eaec,0x52015e27,
+0x526260f3,0x5288a930,0x5360193c,0x53e7ac58,0x54a6567b,0x54c72186,0x54cb8f08,0x54dea5f7,
+0x552d9893,0x555d6f96,0x55b80b93,0x56cac69e,0x56fdf9f5,0x5793010a,0x57d7b747,0x57ec6511,
+0x57f0669c,0x57fd9b57,0x5818c523,0x58fe6cff,0x5a011a36,0x5a4ca3a8,0x5b00675e,0x5c50bfbc,
+0x5c6a50f3,0x5d19f667,0x5d2504a9,0x5ddbc685,0x5e85812a,0x5ed4c61f,0x5f4d0056,0x5fd14dba,
+0x5fd77356,0x608b5837,0x60d6c07e,0x610807c9,0x610986bc,0x6194b3b7,0x62f42120,0x62f774b3,
+0x63233736,0x6361c3c1,0x63811ec2,0x64ad27e9,0x650011e5,0x66b945f7,0x66dd8f73,0x67361999,
+0x67471347,0x67760505,0x6789c685,0x68098e1b,0x683ac4a9,0x68ca7a40,0x69b773df,0x69d5acdc,
+0x6a1ec7e7,0x6a202805,0x6a613195,0x6a6a70f8,0x6a74f315,0x6a838109,0x6aaaacbe,0x6af638aa,
+0x6b4727f6,0x6b7bfcc3,0x6d4eb4ac,0x6dc71805,0x6ef55b70,0x6fa82805,0x6fb3f75c,0x6fcd8893,
+0x7014bf91,0x70fc7fc8,0x724ad2f7,0x729b8c19,0x72b8b523,0x735e4f12,0x7378556e,0x73ac5dba,
+0x74b66e52,0x74e8531f,0x754c0ec2,0x7564261f,0x7567c4bd,0x756fc3b7,0x75af8e66,0x75ba9b5c,
+0x7841287f,0x7973ca45,0x7aaa7fc8,0x7ac8f5ed,0x7aec261f,0x7b2c550f,0x7b6cc5bb,0x7d2bf3a3,
+0x7d68ba27,0x7d8f1e39,0x7d98de70,0x7edf3463,0x80626b7a,0x80b1ec4c,0x81ce9727,0x827aca36,
+0x82944f12,0x86352273,0x8831268f,0x885b22f7,0x887d51bd,0x889f261a,0x89259754,0x89bcadba,
+0x8a323fd7,0x8a72ffaa,0x8a792546,0x8ad0549a,0x8b209af1,0x8bbe27e7,0x8c066fc3,0x8c4464b3,
+0x8cd4d306,0x8cee08b6,0x8d4ab321,0x8ecffd5b,0x8f1223e4,0x8f573f73,0x8f871676,0x904958ca,
+0x904f7e66,0x90e53727,0x91711bfe,0x91859d88,0x919dfef4,0x91cb41c2,0x92426c03,0x92c461d6,
+0x92fffef4,0x936c2c30,0x93dd8269,0x94351cd9,0x94c05b7f,0x94e87d04,0x954e3aba,0x95814e43,
+0x95bbcab0,0x96f5f8b6,0x985f48bb,0x99502cb4,0x995a3b43,0x997f2463,0x99ef72ed,0x9a4e3c2b,
+0x9b57a763,0x9b850fb9,0x9bb1f338,0x9bc723cb,0x9be0895d,0x9c3632f7,0x9c7c176d,0x9c810a9c,
+0x9cf586b2,0x9d07aa27,0x9d315759,0x9d8b6aa1,0x9e99eeef,0x9f215f87,0x9f70c96c,0x9fc195cf,
+0x9fef3f73,0xa06af1b8,0xa06d0dbf,0xa0840b00,0xa12e0083,0xa14df1d4,0xa1748ad8,0xa1884c58,
+0xa2ea4e16,0xa307c528,0xa3f0607e,0xa40bfafb,0xa4558d79,0xa547228c,0xa56495c7,0xa5a5a3a3,
+0xa68b4b7f,0xa728daba,0xa78df8b6,0xa8de0999,0xa90e5479,0xa9dd9e3c,0xa9f72f73,0xa9fd51bd,
+0xaab1e329,0xab3aeee7,0xab68a505,0xab9c9eea,0xabfd18dc,0xac125faa,0xac61a49f,0xac9edbac,
+0xacd9ded6,0xad5e2c3a,0xad6451d6,0xae1836b7,0xae639efe,0xae96653c,0xaee4ad99,0xaef795cf,
+0xaf11f9ff,0xaf43c0fd,0xb0845333,0xb0b015b6,0xb0eea241,0xb1114807,0xb28cf065,0xb3db78e8,
+0xb439f81e,0xb483bfa0,0xb4c2f819,0xb4d3f1c7,0xb516a505,0xb55d42a0,0xb5c7a329,0xb65758c0,
+0xb65e9569,0xb66afcc8,0xb72b3e75,0xb7628b5c,0xb7aba667,0xb7bf11ea,0xb7f74f78,0xb801d195,
+0xb8105f89,0xb84c0cc8,0xb8c92e66,0xb8d40676,0xb908db43,0xb90ade7a,0xb917312a,0xb9c66e34,
+0xba10513e,0xba43177c,0xbab89db5,0xbadb932c,0xbbf2fcc8,0xbc2db1e0,0xbc8239f0,0xbd60895d,
+0xbd81f31a,0xbda19e11,0xbe39a2a5,0xbe895e48,0xbe9d1fc8,0xbf150cd7,0xbfb33962,0xbfe0b342,
+0xc04593a3,0xc0eb2d92,0xc10533ee,0xc1393c3a,0xc1745569,0xc2040b00,0xc259dfc3,0xc275319f,
+0xc2a6f89d,0xc2f1049f,0xc2f4a33d,0xc2faa8ac,0xc3284306,0xc33c6ce6,0xc47378e8,0xc53b3962,
+0xc5605e2f,0xc5b70c62,0xc6d5b1ea,0xc700a8c5,0xc8375e48,0xc879049f,0xcb1bfcb9,0xcb25bcf0,
+0xcb3b8eea,0xcbc7a5d4,0xcbd51cd9,0xcc97dfd2,0xcce5ee7a,0xcd109c26,0xcdef49fa,0xce072949,
+0xce1068ac,0xce3ecacc,0xce4f5dbf,0xceb811e5,0xcee91f26,0xd007a8b6,0xd0212d92,0xd0fc1610,
+0xd2c3881c,0xd3167102,0xd5199800,0xd5be050f,0xd60a303d,0xd62c049a,0xd7498c3a,0xd7bf1e57,
+0xd7d02269,0xd8ad7971,0xd8c5dd0e,0xd8f55ccd,0xd94b0667,0xd9934e43,0xd9d14333,0xda61b186,
+0xdad791a1,0xdbca9962,0xdddc5ce6,0xdf127c08,0xdf2add74,0xdfa79c53,0xdfbf7fa5,0xdfe5d291,
+0xe073d3c6,0xe08cdd74,0xe16a60e9,0xe1c1fb59,0xe2755b84,0xe2db193a,0xe2f63e7a,0xe33fb34a,
+0xe348a930,0xe39d18dc,0xe3b2b606,0xe45a2bb1,0xe5bc2bb1,0xe5d54db0,0xe5f955e8,0xe712252d,
+0xe7db1aab,0xe954024b,0xe96d67dd,0xe9890f26,0xe9c117ec,0xe9da047c,0xea08f5ed,0xeabb228c,
+0xeac6473b,0xec01a8a2,0xec26cd6f,0xec3f2edb,0xec58946d,0xed4e744f,0xed6ead99,0xedf7d038,
+0xedf9ec3f,0xee10e980,0xeebadf03,0xeedad054,0xef152ad8,0xf0577fa5,0xf0917bac,0xf094a3a8,
+0xf17d3efe,0xf198d97b,0xf1e26bf9,0xf27c1610,0xf2d4010c,0xf3d70b66,0xf3e742a0,0xf4913823,
+0xf4b5b93a,0xf4d6d7ec,0xf5b5a82d,0xf62f1772,0xf66ae819,0xf69b32f9,0xf6a2eaea,0xf78a303d,
+0xf8c7cd67,0xf923baf1,0xf9297d6a,0xf989f75c,0xfa2bba2c,0xfa755ccd,0xfa96c68a,0xfbea895d,
+0xfc718c19,0xfc84744f,0xfc9ed87f,0xfcc40c5d,0xfcd09f7d,0xfdf78537,0xfe9e2687,0xff8bd979,
+};
+
+void Pathological ( void )
+{
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+
+ const uint32_t m = 0x5bd1e995;
+ const int r = 24;
+
+ for(int i = 0; i < 100; i++)
+ {
+ uint32_t h = 0;
+ uint32_t k = bad[i];
+
+ printf("0x%08x : ",k);
+ k *= m;
+ printf("0x%08x : ",k);
+ k ^= k >> r;
+ printf("0x%08x : ",k);
+ k *= m;
+ printf("0x%08x : ",k);
+
+ printf(" - ");
+
+ h = k;
+ printf("0x%08x : ",h);
+ h *= m;
+ printf("0x%08x : ",h);
+ h ^= k;
+ printf("0x%08x : ",h);
+ h *= m;
+ printf("0x%08x : ",h);
+ h ^= k;
+ printf("0x%08x : ",h);
+ h *= m;
+ printf("0x%08x : ",h);
+ h ^= k;
+ printf("0x%08x\n",h);
+
+ }
+}
+*/
+
+/*
+void Pathological ( void )
+{
+ const int nbytes = 512 * 1024 * 1024;
+
+ unsigned char * block = new unsigned char[nbytes];
+
+ memset(block,0,nbytes);
+
+ unsigned int k = 0;
+ unsigned int collisions = 0;
+
+ do
+ {
+ //const uint32_t m = 0x5bd1e995;
+ unsigned int h = 0;
+
+ uint32_t m1 = 0x5bd1e995;
+ uint32_t m2 = 0x5bd1e995;
+ uint32_t m3 = 0x5bd1e995;
+ uint32_t x;
+
+ x = k; x *= m1; x ^= x >> 25; x *= m2; h ^= x; h *= m3;
+ m2 = m2*9+0x273581d8;
+ x = k; x *= m1; x ^= x >> 25; x *= m2; h ^= x; h *= m3;
+ m2 = m2*9+0x273581d8;
+
+ //printf("0x%08x : 0x%08x\n",k,h);
+ //h *= 3;
+
+ if(getbit(block,nbytes,h))
+ {
+ collisions++;
+ }
+
+ setbit(block,nbytes,h);
+
+ if(k % 10000000 == 0)
+ {
+ printf("%12u : %9u : %f\n",k,collisions,double(collisions) / double(k));
+ }
+
+ k++;
+ }
+ while(k != 0);
+
+ printf("%u total collisions, %f",collisions,double(collisions) / 4294967296.0);
+
+ delete [] block;
+}
+*/
+
+/*
+// Applying FWT to fmix32 to look for linearities (it found some bias, but nothing above a fraction of a percent)
+
+void find_linear_approximation_walsh2 ( mixfunc<uint32_t> f, uint32_t mask, int inbits, uint32_t & outL, int64_t & outBias );
+void find_linear_approximation_walsh ( mixfunc<uint32_t> f, uint32_t mask, int inbits, uint32_t & outL, int64_t & outBias );
+uint32_t test_linear_approximation ( mixfunc<uint32_t> f, uint32_t l, uint32_t mask, int inbits );
+
+uint32_t bitrev ( uint32_t v );
+
+uint32_t FWTMix ( uint32_t x )
+{
+ x ^= x >> 16;
+ x *= 0x85ebca6b;
+ x ^= x >> 13;
+ x *= 0xc2b2ae35;
+ x ^= x >> 16;
+
+ return x;
+}
+
+double test_linear_approximation ( mixfunc<uint32_t> f, uint32_t l, uint32_t mask, int64_t size );
+
+void WalshStuff(void )
+{
+ const int64_t nbits = 32;
+ const int64_t size = int64_t(1) << nbits;
+
+ mixfunc<uint32_t> f(FWTMix);
+
+ for(int i = 0; i < nbits; i++)
+ {
+ uint32_t mask = (1 << i);
+ uint32_t outL = 0;
+ int64_t bias = 0;
+ find_linear_approximation_walsh2(f,mask,nbits,outL,bias);
+
+ double b = test_linear_approximation ( f, outL, mask, size);
+
+ printf("0x%08x, 0x%08x, %8I64d, %f\n",mask,outL,bias,b);
+ }
+}
+*/ \ No newline at end of file
diff --git a/sha1.cpp b/sha1.cpp
new file mode 100644
index 0000000..c4b79b8
--- /dev/null
+++ b/sha1.cpp
@@ -0,0 +1,603 @@
+/*
+ * sha1.cpp
+ *
+ * Copyright (C) 1998, 2009
+ * Paul E. Jones <paulej@packetizer.com>
+ * All Rights Reserved.
+ *
+ *****************************************************************************
+ * $Id: sha1.cpp 12 2009-06-22 19:34:25Z paulej $
+ *****************************************************************************
+ *
+ * Description:
+ * This class implements the Secure Hashing Standard as defined
+ * in FIPS PUB 180-1 published April 17, 1995.
+ *
+ * The Secure Hashing Standard, which uses the Secure Hashing
+ * Algorithm (SHA), produces a 160-bit message digest for a
+ * given data stream. In theory, it is highly improbable that
+ * two messages will produce the same message digest. Therefore,
+ * this algorithm can serve as a means of providing a "fingerprint"
+ * for a message.
+ *
+ * Portability Issues:
+ * SHA-1 is defined in terms of 32-bit "words". This code was
+ * written with the expectation that the processor has at least
+ * a 32-bit machine word size. If the machine word size is larger,
+ * the code should still function properly. One caveat to that
+ * is that the input functions taking characters and character arrays
+ * assume that only 8 bits of information are stored in each character.
+ *
+ * Caveats:
+ * SHA-1 is designed to work with messages less than 2^64 bits long.
+ * Although SHA-1 allows a message digest to be generated for
+ * messages of any number of bits less than 2^64, this implementation
+ * only works with messages with a length that is a multiple of 8
+ * bits.
+ *
+ */
+
+
+#include "sha1.h"
+
+/*
+ * SHA1
+ *
+ * Description:
+ * This is the constructor for the sha1 class.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ *
+ */
+SHA1::SHA1()
+{
+ Reset();
+}
+
+/*
+ * ~SHA1
+ *
+ * Description:
+ * This is the destructor for the sha1 class
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ *
+ */
+SHA1::~SHA1()
+{
+ // The destructor does nothing
+}
+
+/*
+ * Reset
+ *
+ * Description:
+ * This function will initialize the sha1 class member variables
+ * in preparation for computing a new message digest.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ *
+ */
+void SHA1::Reset()
+{
+ Length_Low = 0;
+ Length_High = 0;
+ Message_Block_Index = 0;
+
+ H[0] = 0x67452301;
+ H[1] = 0xEFCDAB89;
+ H[2] = 0x98BADCFE;
+ H[3] = 0x10325476;
+ H[4] = 0xC3D2E1F0;
+
+ Computed = false;
+ Corrupted = false;
+}
+
+/*
+ * Result
+ *
+ * Description:
+ * This function will return the 160-bit message digest into the
+ * array provided.
+ *
+ * Parameters:
+ * message_digest_array: [out]
+ * This is an array of five unsigned integers which will be filled
+ * with the message digest that has been computed.
+ *
+ * Returns:
+ * True if successful, false if it failed.
+ *
+ * Comments:
+ *
+ */
+bool SHA1::Result(unsigned *message_digest_array)
+{
+ int i; // Counter
+
+ if (Corrupted)
+ {
+ return false;
+ }
+
+ if (!Computed)
+ {
+ PadMessage();
+ Computed = true;
+ }
+
+ for(i = 0; i < 5; i++)
+ {
+ message_digest_array[i] = H[i];
+ }
+
+ return true;
+}
+
+/*
+ * Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion of
+ * the message.
+ *
+ * Parameters:
+ * message_array: [in]
+ * An array of characters representing the next portion of the
+ * message.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ *
+ */
+void SHA1::Input( const unsigned char *message_array,
+ unsigned length)
+{
+ if (!length)
+ {
+ return;
+ }
+
+ if (Computed || Corrupted)
+ {
+ Corrupted = true;
+ return;
+ }
+
+ while(length-- && !Corrupted)
+ {
+ Message_Block[Message_Block_Index++] = (*message_array & 0xFF);
+
+ Length_Low += 8;
+ Length_Low &= 0xFFFFFFFF; // Force it to 32 bits
+ if (Length_Low == 0)
+ {
+ Length_High++;
+ Length_High &= 0xFFFFFFFF; // Force it to 32 bits
+ if (Length_High == 0)
+ {
+ Corrupted = true; // Message is too long
+ }
+ }
+
+ if (Message_Block_Index == 64)
+ {
+ ProcessMessageBlock();
+ }
+
+ message_array++;
+ }
+}
+
+/*
+ * Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion of
+ * the message.
+ *
+ * Parameters:
+ * message_array: [in]
+ * An array of characters representing the next portion of the
+ * message.
+ * length: [in]
+ * The length of the message_array
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ *
+ */
+void SHA1::Input( const char *message_array,
+ unsigned length)
+{
+ Input((unsigned char *) message_array, length);
+}
+
+/*
+ * Input
+ *
+ * Description:
+ * This function accepts a single octets as the next message element.
+ *
+ * Parameters:
+ * message_element: [in]
+ * The next octet in the message.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ *
+ */
+void SHA1::Input(unsigned char message_element)
+{
+ Input(&message_element, 1);
+}
+
+/*
+ * Input
+ *
+ * Description:
+ * This function accepts a single octet as the next message element.
+ *
+ * Parameters:
+ * message_element: [in]
+ * The next octet in the message.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ *
+ */
+void SHA1::Input(char message_element)
+{
+ Input((unsigned char *) &message_element, 1);
+}
+
+/*
+ * operator<<
+ *
+ * Description:
+ * This operator makes it convenient to provide character strings to
+ * the SHA1 object for processing.
+ *
+ * Parameters:
+ * message_array: [in]
+ * The character array to take as input.
+ *
+ * Returns:
+ * A reference to the SHA1 object.
+ *
+ * Comments:
+ * Each character is assumed to hold 8 bits of information.
+ *
+ */
+SHA1& SHA1::operator<<(const char *message_array)
+{
+ const char *p = message_array;
+
+ while(*p)
+ {
+ Input(*p);
+ p++;
+ }
+
+ return *this;
+}
+
+/*
+ * operator<<
+ *
+ * Description:
+ * This operator makes it convenient to provide character strings to
+ * the SHA1 object for processing.
+ *
+ * Parameters:
+ * message_array: [in]
+ * The character array to take as input.
+ *
+ * Returns:
+ * A reference to the SHA1 object.
+ *
+ * Comments:
+ * Each character is assumed to hold 8 bits of information.
+ *
+ */
+SHA1& SHA1::operator<<(const unsigned char *message_array)
+{
+ const unsigned char *p = message_array;
+
+ while(*p)
+ {
+ Input(*p);
+ p++;
+ }
+
+ return *this;
+}
+
+/*
+ * operator<<
+ *
+ * Description:
+ * This function provides the next octet in the message.
+ *
+ * Parameters:
+ * message_element: [in]
+ * The next octet in the message
+ *
+ * Returns:
+ * A reference to the SHA1 object.
+ *
+ * Comments:
+ * The character is assumed to hold 8 bits of information.
+ *
+ */
+SHA1& SHA1::operator<<(const char message_element)
+{
+ Input((unsigned char *) &message_element, 1);
+
+ return *this;
+}
+
+/*
+ * operator<<
+ *
+ * Description:
+ * This function provides the next octet in the message.
+ *
+ * Parameters:
+ * message_element: [in]
+ * The next octet in the message
+ *
+ * Returns:
+ * A reference to the SHA1 object.
+ *
+ * Comments:
+ * The character is assumed to hold 8 bits of information.
+ *
+ */
+SHA1& SHA1::operator<<(const unsigned char message_element)
+{
+ Input(&message_element, 1);
+
+ return *this;
+}
+
+/*
+ * ProcessMessageBlock
+ *
+ * Description:
+ * This function will process the next 512 bits of the message
+ * stored in the Message_Block array.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ * Many of the variable names in this function, especially the single
+ * character names, were used because those were the names used
+ * in the publication.
+ *
+ */
+void SHA1::ProcessMessageBlock()
+{
+ const unsigned K[] = { // Constants defined for SHA-1
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+ };
+ int t; // Loop counter
+ unsigned temp; // Temporary word value
+ unsigned W[80]; // Word sequence
+ unsigned A, B, C, D, E; // Word buffers
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for(t = 0; t < 16; t++)
+ {
+ W[t] = ((unsigned) Message_Block[t * 4]) << 24;
+ W[t] |= ((unsigned) Message_Block[t * 4 + 1]) << 16;
+ W[t] |= ((unsigned) Message_Block[t * 4 + 2]) << 8;
+ W[t] |= ((unsigned) Message_Block[t * 4 + 3]);
+ }
+
+ for(t = 16; t < 80; t++)
+ {
+ W[t] = CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+ }
+
+ A = H[0];
+ B = H[1];
+ C = H[2];
+ D = H[3];
+ E = H[4];
+
+ for(t = 0; t < 20; t++)
+ {
+ temp = CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0];
+ temp &= 0xFFFFFFFF;
+ E = D;
+ D = C;
+ C = CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 20; t < 40; t++)
+ {
+ temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
+ temp &= 0xFFFFFFFF;
+ E = D;
+ D = C;
+ C = CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 40; t < 60; t++)
+ {
+ temp = CircularShift(5,A) +
+ ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
+ temp &= 0xFFFFFFFF;
+ E = D;
+ D = C;
+ C = CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ for(t = 60; t < 80; t++)
+ {
+ temp = CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
+ temp &= 0xFFFFFFFF;
+ E = D;
+ D = C;
+ C = CircularShift(30,B);
+ B = A;
+ A = temp;
+ }
+
+ H[0] = (H[0] + A) & 0xFFFFFFFF;
+ H[1] = (H[1] + B) & 0xFFFFFFFF;
+ H[2] = (H[2] + C) & 0xFFFFFFFF;
+ H[3] = (H[3] + D) & 0xFFFFFFFF;
+ H[4] = (H[4] + E) & 0xFFFFFFFF;
+
+ Message_Block_Index = 0;
+}
+
+/*
+ * PadMessage
+ *
+ * Description:
+ * According to the standard, the message must be padded to an even
+ * 512 bits. The first padding bit must be a '1'. The last 64 bits
+ * represent the length of the original message. All bits in between
+ * should be 0. This function will pad the message according to those
+ * rules by filling the message_block array accordingly. It will also
+ * call ProcessMessageBlock() appropriately. When it returns, it
+ * can be assumed that the message digest has been computed.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+ *
+ */
+void SHA1::PadMessage()
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second block.
+ */
+ if (Message_Block_Index > 55)
+ {
+ Message_Block[Message_Block_Index++] = 0x80;
+ while(Message_Block_Index < 64)
+ {
+ Message_Block[Message_Block_Index++] = 0;
+ }
+
+ ProcessMessageBlock();
+
+ while(Message_Block_Index < 56)
+ {
+ Message_Block[Message_Block_Index++] = 0;
+ }
+ }
+ else
+ {
+ Message_Block[Message_Block_Index++] = 0x80;
+ while(Message_Block_Index < 56)
+ {
+ Message_Block[Message_Block_Index++] = 0;
+ }
+
+ }
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ Message_Block[56] = (Length_High >> 24) & 0xFF;
+ Message_Block[57] = (Length_High >> 16) & 0xFF;
+ Message_Block[58] = (Length_High >> 8) & 0xFF;
+ Message_Block[59] = (Length_High) & 0xFF;
+ Message_Block[60] = (Length_Low >> 24) & 0xFF;
+ Message_Block[61] = (Length_Low >> 16) & 0xFF;
+ Message_Block[62] = (Length_Low >> 8) & 0xFF;
+ Message_Block[63] = (Length_Low) & 0xFF;
+
+ ProcessMessageBlock();
+}
+
+
+/*
+ * CircularShift
+ *
+ * Description:
+ * This member function will perform a circular shifting operation.
+ *
+ * Parameters:
+ * bits: [in]
+ * The number of bits to shift (1-31)
+ * word: [in]
+ * The value to shift (assumes a 32-bit integer)
+ *
+ * Returns:
+ * The shifted value.
+ *
+ * Comments:
+ *
+ */
+unsigned SHA1::CircularShift(int bits, unsigned word)
+{
+ return ((word << bits) & 0xFFFFFFFF) | ((word & 0xFFFFFFFF) >> (32-bits));
+}
+
+
+//-----------------------------------------------------------------------------
+// Adapter for HashTest
+
+void sha1hash ( const void * key, int len, unsigned int seed, unsigned int * result )
+{
+ SHA1 s;
+
+ s.Input((const unsigned char*)&seed,4);
+ s.Input((const unsigned char*)key,len);
+
+ s.Result(result);
+} \ No newline at end of file
diff --git a/sha1.h b/sha1.h
new file mode 100644
index 0000000..c0efa1c
--- /dev/null
+++ b/sha1.h
@@ -0,0 +1,89 @@
+/*
+ * sha1.h
+ *
+ * Copyright (C) 1998, 2009
+ * Paul E. Jones <paulej@packetizer.com>
+ * All Rights Reserved.
+ *
+ *****************************************************************************
+ * $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $
+ *****************************************************************************
+ *
+ * Description:
+ * This class implements the Secure Hashing Standard as defined
+ * in FIPS PUB 180-1 published April 17, 1995.
+ *
+ * Many of the variable names in this class, especially the single
+ * character names, were used because those were the names used
+ * in the publication.
+ *
+ * Please read the file sha1.cpp for more information.
+ *
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+class SHA1
+{
+
+ public:
+
+ SHA1();
+ virtual ~SHA1();
+
+ /*
+ * Re-initialize the class
+ */
+ void Reset();
+
+ /*
+ * Returns the message digest
+ */
+ bool Result(unsigned *message_digest_array);
+
+ /*
+ * Provide input to SHA1
+ */
+ void Input( const unsigned char *message_array,
+ unsigned length);
+ void Input( const char *message_array,
+ unsigned length);
+ void Input(unsigned char message_element);
+ void Input(char message_element);
+ SHA1& operator<<(const char *message_array);
+ SHA1& operator<<(const unsigned char *message_array);
+ SHA1& operator<<(const char message_element);
+ SHA1& operator<<(const unsigned char message_element);
+
+ private:
+
+ /*
+ * Process the next 512 bits of the message
+ */
+ void ProcessMessageBlock();
+
+ /*
+ * Pads the current message block to 512 bits
+ */
+ void PadMessage();
+
+ /*
+ * Performs a circular left shift operation
+ */
+ inline unsigned CircularShift(int bits, unsigned word);
+
+ unsigned H[5]; // Message digest buffers
+
+ unsigned Length_Low; // Message length in bits
+ unsigned Length_High; // Message length in bits
+
+ unsigned char Message_Block[64]; // 512-bit message blocks
+ int Message_Block_Index; // Index into message block array
+
+ bool Computed; // Is the digest computed?
+ bool Corrupted; // Is the message digest corruped?
+
+};
+
+#endif
diff --git a/simplex.cpp b/simplex.cpp
new file mode 100644
index 0000000..3f08f1d
--- /dev/null
+++ b/simplex.cpp
@@ -0,0 +1,171 @@
+#include <stdio.h>
+#include <set>
+#include <map>
+#include "pstdint.h"
+
+#pragma warning(disable:4996)
+
+struct node;
+
+typedef std::set<node*> nodeset;
+
+struct node
+{
+ node ( void )
+ {
+ name = 0;
+ mark = 0;
+ used = 0;
+ next = 0;
+ }
+
+ uint32_t name;
+ uint32_t mark;
+ uint32_t used;
+
+ node * next;
+
+ nodeset edges;
+};
+
+typedef std::map<uint32_t,node> nodegraph;
+
+nodegraph graph;
+
+bool can_link ( node * A, node * B )
+{
+ if(A->edges.find(B) == A->edges.end()) return false;
+ if(B->edges.find(A) == B->edges.end()) return false;
+
+ return true;
+}
+
+bool can_link_all ( node * A, node * B )
+{
+ node * cursor = A;
+
+ while(cursor)
+ {
+ if(!can_link(cursor,B)) return false;
+
+ cursor = cursor->next;
+ }
+
+ return true;
+}
+
+void print_simplex( node * head )
+{
+ node * cursor = head;
+
+ while(cursor)
+ {
+ printf("0x%08x,",cursor->name);
+ cursor = cursor->next;
+ }
+ printf("\n");
+}
+
+void find_simplex ( node * head )
+{
+ bool found = false;
+
+ for(nodeset::iterator it = head->edges.begin(); it != head->edges.end(); it++)
+ {
+ node * next = (*it);
+
+ if(next->mark) continue;
+ if(next->name > head->name) continue;
+
+ if(can_link_all(head,next))
+ {
+ found = true;
+ next->mark = head->mark + 1;
+ next->next = head;
+
+ find_simplex(next);
+
+ next->mark = 0;
+ next->next = 0;
+ }
+ }
+
+ if(!found && (head->mark > 3))
+ {
+ bool used = false;
+
+ node * cursor = head;
+
+ while(cursor)
+ {
+ if(cursor->used) used = true;
+
+ cursor = cursor->next;
+ }
+
+ if(!used)
+ {
+ print_simplex(head);
+
+ node * cursor = head;
+
+ while(cursor)
+ {
+ cursor->used = 1;
+ cursor = cursor->next;
+ }
+ }
+ }
+}
+
+int simplex_main ( int argc, char * argv[] )
+{
+ if(argc < 2)
+ {
+ printf("blah\n");
+ return 1;
+ }
+
+ FILE * file = fopen(argv[1],"r");
+
+ if(!file)
+ {
+ printf("Couldn't open file\n");
+ return 1;
+ }
+
+ char buffer[512];
+
+ while(fgets(buffer,512,file))
+ {
+ uint32_t nameA;
+ uint32_t nameB;
+
+ int found = sscanf(buffer,"0x%08x,0x%08x",&nameA,&nameB);
+
+ if(found != 2) continue;
+
+ node * nodeA = &graph[nameA];
+ node * nodeB = &graph[nameB];
+
+ nodeA->name = nameA;
+ nodeB->name = nameB;
+
+ nodeA->edges.insert(nodeB);
+ nodeB->edges.insert(nodeA);
+ }
+
+ for(std::map<uint32_t,node>::iterator it = graph.begin(); it != graph.end(); it++)
+ {
+ node & n = (*it).second;
+
+ n.mark = 1;
+
+ find_simplex(&n);
+
+ n.mark = 0;
+ }
+
+ return 0;
+}
+