Added MD5, SHA256, CityHash hash function for MultiLevelHashMap testing
[libcds.git] / tests / hashing / md5.cpp
1 // //////////////////////////////////////////////////////////
2 // md5.cpp
3 // Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
4 // see http://create.stephan-brumme.com/disclaimer.html
5 //
6
7 #include "md5.h"
8
9 #ifndef _MSC_VER
10 #include <endian.h>
11 #endif
12
13
14 /// same as reset()
15 MD5::MD5()
16 {
17   reset();
18 }
19
20
21 /// restart
22 void MD5::reset()
23 {
24   m_numBytes   = 0;
25   m_bufferSize = 0;
26
27   // according to RFC 1321
28   m_hash[0] = 0x67452301;
29   m_hash[1] = 0xefcdab89;
30   m_hash[2] = 0x98badcfe;
31   m_hash[3] = 0x10325476;
32 }
33
34
35 namespace
36 {
37   // mix functions for processBlock()
38   inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d)
39   {
40     return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d);
41   }
42
43   inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d)
44   {
45     return c ^ (d & (b ^ c)); // original: f = (b & d) | (c & (~d));
46   }
47
48   inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d)
49   {
50     return b ^ c ^ d;
51   }
52
53   inline uint32_t f4(uint32_t b, uint32_t c, uint32_t d)
54   {
55     return c ^ (b | ~d);
56   }
57
58   inline uint32_t rotate(uint32_t a, uint32_t c)
59   {
60     return (a << c) | (a >> (32 - c));
61   }
62
63 #if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
64   inline uint32_t swap(uint32_t x)
65   {
66 #if defined(__GNUC__) || defined(__clang__)
67     return __builtin_bswap32(x);
68 #endif
69 #ifdef MSC_VER
70     return _byteswap_ulong(x);
71 #endif
72
73     return (x >> 24) |
74           ((x >>  8) & 0x0000FF00) |
75           ((x <<  8) & 0x00FF0000) |
76            (x << 24);
77   }
78 #endif
79 }
80
81
82 /// process 64 bytes
83 void MD5::processBlock(const void* data)
84 {
85   // get last hash
86   uint32_t a = m_hash[0];
87   uint32_t b = m_hash[1];
88   uint32_t c = m_hash[2];
89   uint32_t d = m_hash[3];
90
91   // data represented as 16x 32-bit words
92   const uint32_t* words = (uint32_t*) data;
93
94   // computations are little endian, swap data if necessary
95 #if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
96 #define LITTLEENDIAN(x) swap(x)
97 #else
98 #define LITTLEENDIAN(x) (x)
99 #endif
100
101   // first round
102   uint32_t word0  = LITTLEENDIAN(words[ 0]);
103   a = rotate(a + f1(b,c,d) + word0  + 0xd76aa478,  7) + b;
104   uint32_t word1  = LITTLEENDIAN(words[ 1]);
105   d = rotate(d + f1(a,b,c) + word1  + 0xe8c7b756, 12) + a;
106   uint32_t word2  = LITTLEENDIAN(words[ 2]);
107   c = rotate(c + f1(d,a,b) + word2  + 0x242070db, 17) + d;
108   uint32_t word3  = LITTLEENDIAN(words[ 3]);
109   b = rotate(b + f1(c,d,a) + word3  + 0xc1bdceee, 22) + c;
110
111   uint32_t word4  = LITTLEENDIAN(words[ 4]);
112   a = rotate(a + f1(b,c,d) + word4  + 0xf57c0faf,  7) + b;
113   uint32_t word5  = LITTLEENDIAN(words[ 5]);
114   d = rotate(d + f1(a,b,c) + word5  + 0x4787c62a, 12) + a;
115   uint32_t word6  = LITTLEENDIAN(words[ 6]);
116   c = rotate(c + f1(d,a,b) + word6  + 0xa8304613, 17) + d;
117   uint32_t word7  = LITTLEENDIAN(words[ 7]);
118   b = rotate(b + f1(c,d,a) + word7  + 0xfd469501, 22) + c;
119
120   uint32_t word8  = LITTLEENDIAN(words[ 8]);
121   a = rotate(a + f1(b,c,d) + word8  + 0x698098d8,  7) + b;
122   uint32_t word9  = LITTLEENDIAN(words[ 9]);
123   d = rotate(d + f1(a,b,c) + word9  + 0x8b44f7af, 12) + a;
124   uint32_t word10 = LITTLEENDIAN(words[10]);
125   c = rotate(c + f1(d,a,b) + word10 + 0xffff5bb1, 17) + d;
126   uint32_t word11 = LITTLEENDIAN(words[11]);
127   b = rotate(b + f1(c,d,a) + word11 + 0x895cd7be, 22) + c;
128
129   uint32_t word12 = LITTLEENDIAN(words[12]);
130   a = rotate(a + f1(b,c,d) + word12 + 0x6b901122,  7) + b;
131   uint32_t word13 = LITTLEENDIAN(words[13]);
132   d = rotate(d + f1(a,b,c) + word13 + 0xfd987193, 12) + a;
133   uint32_t word14 = LITTLEENDIAN(words[14]);
134   c = rotate(c + f1(d,a,b) + word14 + 0xa679438e, 17) + d;
135   uint32_t word15 = LITTLEENDIAN(words[15]);
136   b = rotate(b + f1(c,d,a) + word15 + 0x49b40821, 22) + c;
137
138   // second round
139   a = rotate(a + f2(b,c,d) + word1  + 0xf61e2562,  5) + b;
140   d = rotate(d + f2(a,b,c) + word6  + 0xc040b340,  9) + a;
141   c = rotate(c + f2(d,a,b) + word11 + 0x265e5a51, 14) + d;
142   b = rotate(b + f2(c,d,a) + word0  + 0xe9b6c7aa, 20) + c;
143
144   a = rotate(a + f2(b,c,d) + word5  + 0xd62f105d,  5) + b;
145   d = rotate(d + f2(a,b,c) + word10 + 0x02441453,  9) + a;
146   c = rotate(c + f2(d,a,b) + word15 + 0xd8a1e681, 14) + d;
147   b = rotate(b + f2(c,d,a) + word4  + 0xe7d3fbc8, 20) + c;
148
149   a = rotate(a + f2(b,c,d) + word9  + 0x21e1cde6,  5) + b;
150   d = rotate(d + f2(a,b,c) + word14 + 0xc33707d6,  9) + a;
151   c = rotate(c + f2(d,a,b) + word3  + 0xf4d50d87, 14) + d;
152   b = rotate(b + f2(c,d,a) + word8  + 0x455a14ed, 20) + c;
153
154   a = rotate(a + f2(b,c,d) + word13 + 0xa9e3e905,  5) + b;
155   d = rotate(d + f2(a,b,c) + word2  + 0xfcefa3f8,  9) + a;
156   c = rotate(c + f2(d,a,b) + word7  + 0x676f02d9, 14) + d;
157   b = rotate(b + f2(c,d,a) + word12 + 0x8d2a4c8a, 20) + c;
158
159   // third round
160   a = rotate(a + f3(b,c,d) + word5  + 0xfffa3942,  4) + b;
161   d = rotate(d + f3(a,b,c) + word8  + 0x8771f681, 11) + a;
162   c = rotate(c + f3(d,a,b) + word11 + 0x6d9d6122, 16) + d;
163   b = rotate(b + f3(c,d,a) + word14 + 0xfde5380c, 23) + c;
164
165   a = rotate(a + f3(b,c,d) + word1  + 0xa4beea44,  4) + b;
166   d = rotate(d + f3(a,b,c) + word4  + 0x4bdecfa9, 11) + a;
167   c = rotate(c + f3(d,a,b) + word7  + 0xf6bb4b60, 16) + d;
168   b = rotate(b + f3(c,d,a) + word10 + 0xbebfbc70, 23) + c;
169
170   a = rotate(a + f3(b,c,d) + word13 + 0x289b7ec6,  4) + b;
171   d = rotate(d + f3(a,b,c) + word0  + 0xeaa127fa, 11) + a;
172   c = rotate(c + f3(d,a,b) + word3  + 0xd4ef3085, 16) + d;
173   b = rotate(b + f3(c,d,a) + word6  + 0x04881d05, 23) + c;
174
175   a = rotate(a + f3(b,c,d) + word9  + 0xd9d4d039,  4) + b;
176   d = rotate(d + f3(a,b,c) + word12 + 0xe6db99e5, 11) + a;
177   c = rotate(c + f3(d,a,b) + word15 + 0x1fa27cf8, 16) + d;
178   b = rotate(b + f3(c,d,a) + word2  + 0xc4ac5665, 23) + c;
179
180   // fourth round
181   a = rotate(a + f4(b,c,d) + word0  + 0xf4292244,  6) + b;
182   d = rotate(d + f4(a,b,c) + word7  + 0x432aff97, 10) + a;
183   c = rotate(c + f4(d,a,b) + word14 + 0xab9423a7, 15) + d;
184   b = rotate(b + f4(c,d,a) + word5  + 0xfc93a039, 21) + c;
185
186   a = rotate(a + f4(b,c,d) + word12 + 0x655b59c3,  6) + b;
187   d = rotate(d + f4(a,b,c) + word3  + 0x8f0ccc92, 10) + a;
188   c = rotate(c + f4(d,a,b) + word10 + 0xffeff47d, 15) + d;
189   b = rotate(b + f4(c,d,a) + word1  + 0x85845dd1, 21) + c;
190
191   a = rotate(a + f4(b,c,d) + word8  + 0x6fa87e4f,  6) + b;
192   d = rotate(d + f4(a,b,c) + word15 + 0xfe2ce6e0, 10) + a;
193   c = rotate(c + f4(d,a,b) + word6  + 0xa3014314, 15) + d;
194   b = rotate(b + f4(c,d,a) + word13 + 0x4e0811a1, 21) + c;
195
196   a = rotate(a + f4(b,c,d) + word4  + 0xf7537e82,  6) + b;
197   d = rotate(d + f4(a,b,c) + word11 + 0xbd3af235, 10) + a;
198   c = rotate(c + f4(d,a,b) + word2  + 0x2ad7d2bb, 15) + d;
199   b = rotate(b + f4(c,d,a) + word9  + 0xeb86d391, 21) + c;
200
201   // update hash
202   m_hash[0] += a;
203   m_hash[1] += b;
204   m_hash[2] += c;
205   m_hash[3] += d;
206 }
207
208
209 /// add arbitrary number of bytes
210 void MD5::add(const void* data, size_t numBytes)
211 {
212   const uint8_t* current = (const uint8_t*) data;
213
214   if (m_bufferSize > 0)
215   {
216     while (numBytes > 0 && m_bufferSize < BlockSize)
217     {
218       m_buffer[m_bufferSize++] = *current++;
219       numBytes--;
220     }
221   }
222
223   // full buffer
224   if (m_bufferSize == BlockSize)
225   {
226     processBlock(m_buffer);
227     m_numBytes  += BlockSize;
228     m_bufferSize = 0;
229   }
230
231   // no more data ?
232   if (numBytes == 0)
233     return;
234
235   // process full blocks
236   while (numBytes >= BlockSize)
237   {
238     processBlock(current);
239     current    += BlockSize;
240     m_numBytes += BlockSize;
241     numBytes   -= BlockSize;
242   }
243
244   // keep remaining bytes in buffer
245   while (numBytes > 0)
246   {
247     m_buffer[m_bufferSize++] = *current++;
248     numBytes--;
249   }
250 }
251
252
253 /// process final block, less than 64 bytes
254 void MD5::processBuffer()
255 {
256   // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte
257
258   // - append "1" bit to message
259   // - append "0" bits until message length in bit mod 512 is 448
260   // - append length as 64 bit integer
261
262   // number of bits
263   size_t paddedLength = m_bufferSize * 8;
264
265   // plus one bit set to 1 (always appended)
266   paddedLength++;
267
268   // number of bits must be (numBits % 512) = 448
269   size_t lower11Bits = paddedLength & 511;
270   if (lower11Bits <= 448)
271     paddedLength +=       448 - lower11Bits;
272   else
273     paddedLength += 512 + 448 - lower11Bits;
274   // convert from bits to bytes
275   paddedLength /= 8;
276
277   // only needed if additional data flows over into a second block
278   unsigned char extra[BlockSize];
279
280   // append a "1" bit, 128 => binary 10000000
281   if (m_bufferSize < BlockSize)
282     m_buffer[m_bufferSize] = 128;
283   else
284     extra[0] = 128;
285
286   size_t i;
287   for (i = m_bufferSize + 1; i < BlockSize; i++)
288     m_buffer[i] = 0;
289   for (; i < paddedLength; i++)
290     extra[i - BlockSize] = 0;
291
292   // add message length in bits as 64 bit number
293   uint64_t msgBits = 8 * (m_numBytes + m_bufferSize);
294   // find right position
295   unsigned char* addLength;
296   if (paddedLength < BlockSize)
297     addLength = m_buffer + paddedLength;
298   else
299     addLength = extra + paddedLength - BlockSize;
300
301   // must be little endian
302   *addLength++ = msgBits & 0xFF; msgBits >>= 8;
303   *addLength++ = msgBits & 0xFF; msgBits >>= 8;
304   *addLength++ = msgBits & 0xFF; msgBits >>= 8;
305   *addLength++ = msgBits & 0xFF; msgBits >>= 8;
306   *addLength++ = msgBits & 0xFF; msgBits >>= 8;
307   *addLength++ = msgBits & 0xFF; msgBits >>= 8;
308   *addLength++ = msgBits & 0xFF; msgBits >>= 8;
309   *addLength++ = msgBits & 0xFF;
310
311   // process blocks
312   processBlock(m_buffer);
313   // flowed over into a second block ?
314   if (paddedLength > BlockSize)
315     processBlock(extra);
316 }
317
318
319 /// return latest hash as 32 hex characters
320 std::string MD5::getHash()
321 {
322   // compute hash (as raw bytes)
323   unsigned char rawHash[HashBytes];
324   getHash(rawHash);
325
326   // convert to hex string
327   std::string result;
328   result.reserve(2 * HashBytes);
329   for (int i = 0; i < HashBytes; i++)
330   {
331     static const char dec2hex[16+1] = "0123456789abcdef";
332     result += dec2hex[(rawHash[i] >> 4) & 15];
333     result += dec2hex[ rawHash[i]       & 15];
334   }
335
336   return result;
337 }
338
339
340 /// return latest hash as bytes
341 void MD5::getHash(unsigned char buffer[MD5::HashBytes])
342 {
343   // save old hash if buffer is partially filled
344   uint32_t oldHash[HashValues];
345   for (int i = 0; i < HashValues; i++)
346     oldHash[i] = m_hash[i];
347
348   // process remaining bytes
349   processBuffer();
350
351   unsigned char* current = buffer;
352   for (int i = 0; i < HashValues; i++)
353   {
354     *current++ =  m_hash[i]        & 0xFF;
355     *current++ = (m_hash[i] >>  8) & 0xFF;
356     *current++ = (m_hash[i] >> 16) & 0xFF;
357     *current++ = (m_hash[i] >> 24) & 0xFF;
358
359     // restore old hash
360     m_hash[i] = oldHash[i];
361   }
362 }
363
364
365 /// compute MD5 of a memory block
366 std::string MD5::operator()(const void* data, size_t numBytes)
367 {
368   reset();
369   add(data, numBytes);
370   return getHash();
371 }
372
373
374 /// compute MD5 of a string, excluding final zero
375 std::string MD5::operator()(const std::string& text)
376 {
377   reset();
378   add(text.c_str(), text.size());
379   return getHash();
380 }