blob: f11d5122411b59fff63c25b9a8888cfd2643bfd4 [file] [log] [blame]
tanjent@gmail.comad4b3632010-11-05 01:20:58 +00001#include "KeysetTest.h"
2
tanjent@gmail.com603c8782011-04-01 08:50:06 +00003#include "Platform.h"
tanjent@gmail.comad4b3632010-11-05 01:20:58 +00004#include "Random.h"
5
tanjent@gmail.com603c8782011-04-01 08:50:06 +00006#include <map>
7#include <set>
8
tanjent@gmail.comad4b3632010-11-05 01:20:58 +00009//-----------------------------------------------------------------------------
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000010// This should hopefully be a thorough and uambiguous test of whether a hash
11// is correctly implemented on a given platform
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000012
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000013bool VerificationTest ( pfHash hash, const int hashbits, uint32_t expected, bool verbose )
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000014{
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000015 const int hashbytes = hashbits / 8;
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000016
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000017 uint8_t * key = new uint8_t[256];
18 uint8_t * hashes = new uint8_t[hashbytes * 256];
19 uint8_t * final = new uint8_t[hashbytes];
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000020
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000021 memset(key,0,256);
22 memset(hashes,0,hashbytes*256);
23 memset(final,0,hashbytes);
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000024
tanjent@gmail.com623590d2011-03-28 18:19:31 +000025 // Hash keys of the form {0}, {0,1}, {0,1,2}... up to N=255,using 256-N as
26 // the seed
27
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000028 for(int i = 0; i < 256; i++)
29 {
30 key[i] = (uint8_t)i;
tanjent@gmail.com623590d2011-03-28 18:19:31 +000031
32 hash(key,i,256-i,&hashes[i*hashbytes]);
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000033 }
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000034
tanjent@gmail.com623590d2011-03-28 18:19:31 +000035 // Then hash the result array
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000036
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000037 hash(hashes,hashbytes*256,0,final);
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000038
tanjent@gmail.com623590d2011-03-28 18:19:31 +000039 // The first four bytes of that hash, interpreted as a little-endian integer, is our
40 // verification value
41
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000042 uint32_t verification = (final[0] << 0) | (final[1] << 8) | (final[2] << 16) | (final[3] << 24);
43
44 delete [] key;
45 delete [] hashes;
46 delete [] final;
47
48 //----------
49
50 if(expected != verification)
51 {
52 if(verbose) printf("Verification value 0x%08X : Failed! (Expected 0x%08x)\n",verification,expected);
53 return false;
54 }
55 else
56 {
57 if(verbose) printf("Verification value 0x%08X : Passed!\n",verification);
58 return true;
59 }
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000060}
61
62//----------------------------------------------------------------------------
tanjent@gmail.combabb5532011-02-28 06:03:12 +000063// Basic sanity checks -
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000064
tanjent@gmail.combabb5532011-02-28 06:03:12 +000065// A hash function should not be reading outside the bounds of the key.
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000066
tanjent@gmail.combabb5532011-02-28 06:03:12 +000067// Flipping a bit of a key should, with overwhelmingly high probability,
68// result in a different hash.
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000069
tanjent@gmail.combabb5532011-02-28 06:03:12 +000070// Hashing the same key twice should always produce the same result.
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000071
tanjent@gmail.combabb5532011-02-28 06:03:12 +000072// The memory alignment of the key should not affect the hash result.
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000073
tanjent@gmail.combabb5532011-02-28 06:03:12 +000074bool SanityTest ( pfHash hash, const int hashbits )
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000075{
76 printf("Running sanity check 1");
aappleby@google.com7f20a312011-03-21 20:55:06 +000077
78 Rand r(883741);
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000079
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000080 bool result = true;
tanjent@gmail.com9d17d0b2010-11-17 04:07:51 +000081
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000082 const int hashbytes = hashbits/8;
83 const int reps = 10;
84 const int keymax = 128;
85 const int pad = 16;
86 const int buflen = keymax + pad*3;
87
88 uint8_t * buffer1 = new uint8_t[buflen];
89 uint8_t * buffer2 = new uint8_t[buflen];
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000090
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000091 uint8_t * hash1 = new uint8_t[hashbytes];
92 uint8_t * hash2 = new uint8_t[hashbytes];
tanjent@gmail.combabb5532011-02-28 06:03:12 +000093
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +000094 //----------
95
96 for(int irep = 0; irep < reps; irep++)
97 {
98 if(irep % (reps/10) == 0) printf(".");
tanjent@gmail.comad4b3632010-11-05 01:20:58 +000099
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000100 for(int len = 4; len <= keymax; len++)
101 {
102 for(int offset = pad; offset < pad*2; offset++)
103 {
104 uint8_t * key1 = &buffer1[pad];
105 uint8_t * key2 = &buffer2[pad+offset];
tanjent@gmail.combabb5532011-02-28 06:03:12 +0000106
aappleby@google.com7f20a312011-03-21 20:55:06 +0000107 r.rand_p(buffer1,buflen);
108 r.rand_p(buffer2,buflen);
tanjent@gmail.combabb5532011-02-28 06:03:12 +0000109
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000110 memcpy(key2,key1,len);
tanjent@gmail.combabb5532011-02-28 06:03:12 +0000111
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000112 hash(key1,len,0,hash1);
tanjent@gmail.combabb5532011-02-28 06:03:12 +0000113
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000114 for(int bit = 0; bit < (len * 8); bit++)
115 {
116 // Flip a bit, hash the key -> we should get a different result.
tanjent@gmail.combabb5532011-02-28 06:03:12 +0000117
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000118 flipbit(key2,len,bit);
119 hash(key2,len,0,hash2);
tanjent@gmail.combabb5532011-02-28 06:03:12 +0000120
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000121 if(memcmp(hash1,hash2,hashbytes) == 0)
122 {
123 result = false;
124 }
tanjent@gmail.combabb5532011-02-28 06:03:12 +0000125
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000126 // Flip it back, hash again -> we should get the original result.
tanjent@gmail.combabb5532011-02-28 06:03:12 +0000127
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000128 flipbit(key2,len,bit);
129 hash(key2,len,0,hash2);
tanjent@gmail.combabb5532011-02-28 06:03:12 +0000130
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000131 if(memcmp(hash1,hash2,hashbytes) != 0)
132 {
133 result = false;
134 }
135 }
136 }
137 }
138 }
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000139
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000140 if(result == false)
141 {
142 printf("*********FAIL*********\n");
143 }
144 else
145 {
146 printf("PASS\n");
147 }
tanjent@gmail.com9d17d0b2010-11-17 04:07:51 +0000148
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000149 delete [] hash1;
150 delete [] hash2;
tanjent@gmail.combabb5532011-02-28 06:03:12 +0000151
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000152 return result;
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000153}
154
155//----------------------------------------------------------------------------
156// Appending zero bytes to a key should always cause it to produce a different
157// hash value
158
159void AppendedZeroesTest ( pfHash hash, const int hashbits )
160{
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000161 printf("Running sanity check 2");
aappleby@google.com7f20a312011-03-21 20:55:06 +0000162
163 Rand r(173994);
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000164
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000165 const int hashbytes = hashbits/8;
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000166
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000167 for(int rep = 0; rep < 100; rep++)
168 {
169 if(rep % 10 == 0) printf(".");
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000170
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000171 unsigned char key[256];
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000172
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000173 memset(key,0,sizeof(key));
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000174
aappleby@google.com7f20a312011-03-21 20:55:06 +0000175 r.rand_p(key,32);
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000176
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000177 uint32_t h1[16];
178 uint32_t h2[16];
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000179
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000180 memset(h1,0,hashbytes);
181 memset(h2,0,hashbytes);
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000182
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000183 for(int i = 0; i < 32; i++)
184 {
185 hash(key,32+i,0,h1);
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000186
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000187 if(memcmp(h1,h2,hashbytes) == 0)
188 {
189 printf("\n*********FAIL*********\n");
190 return;
191 }
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000192
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000193 memcpy(h2,h1,hashbytes);
194 }
195 }
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000196
tanjent@gmail.com6ffe0102011-03-19 21:28:26 +0000197 printf("PASS\n");
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000198}
199
tanjent@gmail.comad4b3632010-11-05 01:20:58 +0000200//-----------------------------------------------------------------------------
tanjent@gmail.com603c8782011-04-01 08:50:06 +0000201// Generate all keys of up to N bytes containing two non-zero bytes
202
203void TwoBytesKeygen ( int maxlen, KeyCallback & c )
204{
205 //----------
206 // Compute # of keys
207
208 int keycount = 0;
209
210 for(int i = 2; i <= maxlen; i++) keycount += (int)chooseK(i,2);
211
212 keycount *= 255*255;
213
214 for(int i = 2; i <= maxlen; i++) keycount += i*255;
215
216 printf("Keyset 'TwoBytes' - up-to-%d-byte keys, %d total keys\n",maxlen, keycount);
217
218 c.reserve(keycount);
219
220 //----------
221 // Add all keys with one non-zero byte
222
223 uint8_t key[256];
224
225 memset(key,0,256);
226
227 for(int keylen = 2; keylen <= maxlen; keylen++)
228 for(int byteA = 0; byteA < keylen; byteA++)
229 {
230 for(int valA = 1; valA <= 255; valA++)
231 {
232 key[byteA] = (uint8_t)valA;
233
234 c(key,keylen);
235 }
236
237 key[byteA] = 0;
238 }
239
240 //----------
241 // Add all keys with two non-zero bytes
242
243 for(int keylen = 2; keylen <= maxlen; keylen++)
244 for(int byteA = 0; byteA < keylen-1; byteA++)
245 for(int byteB = byteA+1; byteB < keylen; byteB++)
246 {
247 for(int valA = 1; valA <= 255; valA++)
248 {
249 key[byteA] = (uint8_t)valA;
250
251 for(int valB = 1; valB <= 255; valB++)
252 {
253 key[byteB] = (uint8_t)valB;
254 c(key,keylen);
255 }
256
257 key[byteB] = 0;
258 }
259
260 key[byteA] = 0;
261 }
262}
263
264//-----------------------------------------------------------------------------