A fine-tuned implementation of the SHA256 hashing algorithm.

Dependents:   EntropySource Wallet_v1

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SHA256.cpp Source File

SHA256.cpp

00001 // Author: Remco Bloemen
00002 // Based on:
00003 //   http://en.wikipedia.org/wiki/SHA-2
00004 //   http://www.iwar.org.uk/comsec/resources/cipher/sha256-384-512.pdf
00005 //   some of the OpenSSL optimizations
00006 
00007 #include "SHA256.h"
00008 
00009 inline unsigned int reverse_bytes(unsigned int x)
00010 {
00011     return __rev(x);
00012 }
00013 
00014 inline unsigned int rotate_right(unsigned int x, int shift)
00015 {
00016     // return (x >> shift) | (x << (32 - shift));
00017     return __ror(x, shift);
00018 }
00019 
00020 void SHA256::reset()
00021 {
00022     hash[0] = 0x6A09E667;
00023     hash[1] = 0xBB67AE85;
00024     hash[2] = 0x3C6EF372;
00025     hash[3] = 0xA54FF53A;
00026     hash[4] = 0x510E527F;
00027     hash[5] = 0x9B05688C;
00028     hash[6] = 0x1F83D9AB;
00029     hash[7] = 0x5BE0CD19;
00030     length = 0;
00031 }
00032 
00033 void SHA256::append(const char* data, int size)
00034 {
00035     int index = length % 64;
00036     length += size;
00037     const char* end = data + size;
00038     
00039     // Word align data
00040     char* bytes = reinterpret_cast<char*>(w + (index / 4));
00041     switch(index % 4)
00042     {
00043         // Remember to reverse! (little endian!)
00044         case 1: bytes[2] = *data++; ++index;
00045         case 2: bytes[1] = *data++; ++index;
00046         case 3: bytes[0] = *data++; ++index;
00047         case 0: break;
00048     }
00049     if(data > end) {
00050         // We have overshot reading data
00051         // but w and length are correct
00052         return;
00053     }
00054     
00055     // Index is now word alligned
00056     index /= 4;
00057     if(index == 16) {
00058         process_chunk();
00059         index = 0;
00060     }
00061     
00062     // Process whole words
00063     int num_words = (end - data) / 4;
00064     const unsigned int* data_words = reinterpret_cast<const unsigned int*>(data);
00065     const unsigned int* data_words_end = data_words + num_words;
00066     while(data_words != data_words_end)
00067     {
00068         w[index++] = reverse_bytes(*data_words++);
00069         if(index == 16) {
00070             process_chunk();
00071             index = 0;
00072         }
00073     }
00074     
00075     // Process trailing data bytes
00076     // Again, we won't worry about overshooting data
00077     w[index] = reverse_bytes(*data_words);
00078 }
00079 
00080 void SHA256::finalize()
00081 {
00082     int trailing = length % 64;
00083     
00084     // Append the bit '1' to the message
00085     int last_block = trailing / 4;
00086     unsigned int bit_in_block = 0x80 << (24 - (trailing % 4) * 8); 
00087     w[last_block] |= bit_in_block;
00088     
00089     // Set all other bits to zero
00090     w[last_block] &= ~(bit_in_block - 1);
00091     for(int i = last_block + 1; i < 16; ++i)
00092         w[i] = 0;
00093     
00094     // Make room for the length if necessary
00095     if(trailing >= 56) {
00096         process_chunk();
00097         for(int i = 0; i <= last_block; ++i)
00098             w[i] = 0;
00099     }
00100     
00101     // Append the length in bits
00102     w[14] = length >> (32 - 3);
00103     w[15] = length << 3;
00104     process_chunk();
00105     
00106     // Convert the result to big endian
00107     for(int i = 0; i < 8; ++i)
00108        hash[i] = reverse_bytes(hash[i]);
00109 }
00110 
00111 #define s0(x) (rotate_right(x, 7) ^ rotate_right(x, 18) ^ (x >> 3))
00112 #define s1(x) (rotate_right(x, 17) ^ rotate_right(x, 19) ^ (x >> 10))
00113 #define s2(x) (rotate_right(x, 2) ^ rotate_right(x, 13) ^ rotate_right(x, 22))
00114 #define s3(x) (rotate_right(x, 6) ^ rotate_right(x, 11) ^ rotate_right(x, 25))
00115 #define maj(a,b,c) ((a & b) ^ (a & c) ^ (b & c))
00116 #define ch(a,b,c) ((a & b) ^ ((~a) & c))
00117 
00118 const unsigned int k[64] = {
00119     0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
00120     0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
00121     0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
00122     0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
00123     0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
00124     0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
00125     0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
00126     0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
00127 };
00128 
00129 #define ROUND(a,b,c,d,e,f,g,h,i) \
00130     h += w[i];\
00131     h += *K++;\
00132     h += s3(e); \
00133     h += ch(e, f, g); \
00134     d += h;\
00135     h += s2(a);\
00136     h += maj(a, b, c);
00137 
00138 #define W(n) w[(n) & 0xf]
00139 
00140 #define ROUND2(a,b,c,d,e,f,g,h,i) \
00141     W(i) += s0(W(i+1)) + W(i+9) + s1(W(i+14));\
00142     h += W(i); \
00143     h += *K++;\
00144     h += s3(e);\
00145     h += ch(e, f, g); \
00146     d += h;\
00147     h += s2(a);\
00148     h += maj(a, b, c);
00149 
00150 // Process a 512 bit chunk stored in w[1...15]
00151 void SHA256::process_chunk()
00152 {
00153     // Initialize using current hash
00154     unsigned int a = hash[0];
00155     unsigned int b = hash[1];
00156     unsigned int c = hash[2];
00157     unsigned int d = hash[3];
00158     unsigned int e = hash[4];
00159     unsigned int f = hash[5];
00160     unsigned int g = hash[6];
00161     unsigned int h = hash[7];
00162     
00163     // Main loop
00164     const unsigned int* K = k;
00165     const unsigned int* K_end = k + 64;
00166     ROUND(a,b,c,d,e,f,g,h,0);
00167     ROUND(h,a,b,c,d,e,f,g,1);
00168     ROUND(g,h,a,b,c,d,e,f,2);
00169     ROUND(f,g,h,a,b,c,d,e,3);
00170     ROUND(e,f,g,h,a,b,c,d,4);
00171     ROUND(d,e,f,g,h,a,b,c,5);
00172     ROUND(c,d,e,f,g,h,a,b,6);
00173     ROUND(b,c,d,e,f,g,h,a,7);
00174     ROUND(a,b,c,d,e,f,g,h,8);
00175     ROUND(h,a,b,c,d,e,f,g,9);
00176     ROUND(g,h,a,b,c,d,e,f,10);
00177     ROUND(f,g,h,a,b,c,d,e,11);
00178     ROUND(e,f,g,h,a,b,c,d,12);
00179     ROUND(d,e,f,g,h,a,b,c,13);
00180     ROUND(c,d,e,f,g,h,a,b,14);
00181     ROUND(b,c,d,e,f,g,h,a,15);
00182     do {
00183         ROUND2(a,b,c,d,e,f,g,h,0);
00184         ROUND2(h,a,b,c,d,e,f,g,1);
00185         ROUND2(g,h,a,b,c,d,e,f,2);
00186         ROUND2(f,g,h,a,b,c,d,e,3);
00187         ROUND2(e,f,g,h,a,b,c,d,4);
00188         ROUND2(d,e,f,g,h,a,b,c,5);
00189         ROUND2(c,d,e,f,g,h,a,b,6);
00190         ROUND2(b,c,d,e,f,g,h,a,7);
00191         ROUND2(a,b,c,d,e,f,g,h,8);
00192         ROUND2(h,a,b,c,d,e,f,g,9);
00193         ROUND2(g,h,a,b,c,d,e,f,10);
00194         ROUND2(f,g,h,a,b,c,d,e,11);
00195         ROUND2(e,f,g,h,a,b,c,d,12);
00196         ROUND2(d,e,f,g,h,a,b,c,13);
00197         ROUND2(c,d,e,f,g,h,a,b,14);
00198         ROUND2(b,c,d,e,f,g,h,a,15);
00199     } while(K != K_end);
00200     
00201     // Update hash
00202     hash[0] += a;
00203     hash[1] += b;
00204     hash[2] += c;
00205     hash[3] += d;
00206     hash[4] += e;
00207     hash[5] += f;
00208     hash[6] += g;
00209     hash[7] += h; 
00210 }
00211 
00212 std::string SHA256::hexString()
00213 {
00214     const char* hex = "0123456789abcdef";
00215     std::string hexstr(64, '0');
00216     for(int i = 0; i < 32; ++i) {
00217         hexstr[2 * i + 0] = hex[digest()[i] >> 4];
00218         hexstr[2 * i + 1] = hex[digest()[i] & 0xf];
00219     }
00220     return hexstr;
00221 }