A fine-tuned implementation of the SHA256 hashing algorithm.
Dependents: EntropySource Wallet_v1
Revision 6:c0ed1bf37651, committed 2011-06-20
- Comitter:
- Remco
- Date:
- Mon Jun 20 13:21:38 2011 +0000
- Parent:
- 5:246096ab9e56
- Commit message:
Changed in this revision
SHA256.cpp | Show annotated file Show diff for this revision Revisions of this file |
SHA256.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 246096ab9e56 -r c0ed1bf37651 SHA256.cpp --- a/SHA256.cpp Mon Jun 20 11:11:10 2011 +0000 +++ b/SHA256.cpp Mon Jun 20 13:21:38 2011 +0000 @@ -1,221 +1,221 @@ -// Author: Remco Bloemen -// Based on: -// http://en.wikipedia.org/wiki/SHA-2 -// http://www.iwar.org.uk/comsec/resources/cipher/sha256-384-512.pdf -// some of the OpenSSL optimizations - -#include "SHA256.h" - -inline unsigned int reverse_bytes(unsigned int x) -{ - return __rev(x); -} - -inline unsigned int rotate_right(unsigned int x, int shift) -{ - // return (x >> shift) | (x << (32 - shift)); - return __ror(x, shift); -} - -void SHA256::reset() -{ - hash[0] = 0x6A09E667; - hash[1] = 0xBB67AE85; - hash[2] = 0x3C6EF372; - hash[3] = 0xA54FF53A; - hash[4] = 0x510E527F; - hash[5] = 0x9B05688C; - hash[6] = 0x1F83D9AB; - hash[7] = 0x5BE0CD19; - length = 0; -} - -void SHA256::append(const char* data, int size) -{ - int index = length % 64; - length += size; - const char* end = data + size; - - // Word align data - char* bytes = reinterpret_cast<char*>(w + (index / 4)); - switch(index % 4) - { - // Remember to reverse! (little endian!) - case 1: bytes[2] = *data++; ++index; - case 2: bytes[1] = *data++; ++index; - case 3: bytes[0] = *data++; ++index; - case 0: break; - } - if(data > end) { - // We have overshot reading data - // but w and length are correct - return; - } - - // Index is now word alligned - index /= 4; - if(index == 16) { - process_chunk(); - index = 0; - } - - // Process whole words - int num_words = (end - data) / 4; - const unsigned int* data_words = reinterpret_cast<const unsigned int*>(data); - const unsigned int* data_words_end = data_words + num_words; - while(data_words != data_words_end) - { - w[index++] = reverse_bytes(*data_words++); - if(index == 16) { - process_chunk(); - index = 0; - } - } - - // Process trailing data bytes - // Again, we won't worry about overshooting data - w[index] = reverse_bytes(*data_words); -} - -void SHA256::finalize() -{ - int trailing = length % 64; - - // Append the bit '1' to the message - int last_block = trailing / 4; - unsigned int bit_in_block = 0x80 << (24 - (trailing % 4) * 8); - w[last_block] |= bit_in_block; - - // Set all other bits to zero - w[last_block] &= ~(bit_in_block - 1); - for(int i = last_block + 1; i < 16; ++i) - w[i] = 0; - - // Make room for the length if necessary - if(trailing >= 56) { - process_chunk(); - for(int i = 0; i <= last_block; ++i) - w[i] = 0; - } - - // Append the length in bits - w[14] = length >> (32 - 3); - w[15] = length << 3; - process_chunk(); - - // Convert the result to big endian - for(int i = 0; i < 8; ++i) - hash[i] = reverse_bytes(hash[i]); -} - -#define s0(x) (rotate_right(x, 7) ^ rotate_right(x, 18) ^ (x >> 3)) -#define s1(x) (rotate_right(x, 17) ^ rotate_right(x, 19) ^ (x >> 10)) -#define s2(x) (rotate_right(x, 2) ^ rotate_right(x, 13) ^ rotate_right(x, 22)) -#define s3(x) (rotate_right(x, 6) ^ rotate_right(x, 11) ^ rotate_right(x, 25)) -#define maj(a,b,c) ((a & b) ^ (a & c) ^ (b & c)) -#define ch(a,b,c) ((a & b) ^ ((~a) & c)) - -const unsigned int k[64] = { - 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, - 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, - 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, - 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, - 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, - 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, - 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, - 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 -}; - -#define ROUND(a,b,c,d,e,f,g,h,i) \ - h += w[i];\ - h += *K++;\ - h += s3(e); \ - h += ch(e, f, g); \ - d += h;\ - h += s2(a);\ - h += maj(a, b, c); - -#define W(n) w[(n) & 0xf] - -#define ROUND2(a,b,c,d,e,f,g,h,i) \ - W(i) += s0(W(i+1)) + W(i+9) + s1(W(i+14));\ - h += W(i); \ - h += *K++;\ - h += s3(e);\ - h += ch(e, f, g); \ - d += h;\ - h += s2(a);\ - h += maj(a, b, c); - -// Process a 512 bit chunk stored in w[1...15] -void SHA256::process_chunk() -{ - // Initialize using current hash - unsigned int a = hash[0]; - unsigned int b = hash[1]; - unsigned int c = hash[2]; - unsigned int d = hash[3]; - unsigned int e = hash[4]; - unsigned int f = hash[5]; - unsigned int g = hash[6]; - unsigned int h = hash[7]; - - // Main loop - const unsigned int* K = k; - const unsigned int* K_end = k + 64; - ROUND(a,b,c,d,e,f,g,h,0); - ROUND(h,a,b,c,d,e,f,g,1); - ROUND(g,h,a,b,c,d,e,f,2); - ROUND(f,g,h,a,b,c,d,e,3); - ROUND(e,f,g,h,a,b,c,d,4); - ROUND(d,e,f,g,h,a,b,c,5); - ROUND(c,d,e,f,g,h,a,b,6); - ROUND(b,c,d,e,f,g,h,a,7); - ROUND(a,b,c,d,e,f,g,h,8); - ROUND(h,a,b,c,d,e,f,g,9); - ROUND(g,h,a,b,c,d,e,f,10); - ROUND(f,g,h,a,b,c,d,e,11); - ROUND(e,f,g,h,a,b,c,d,12); - ROUND(d,e,f,g,h,a,b,c,13); - ROUND(c,d,e,f,g,h,a,b,14); - ROUND(b,c,d,e,f,g,h,a,15); - do { - ROUND2(a,b,c,d,e,f,g,h,0); - ROUND2(h,a,b,c,d,e,f,g,1); - ROUND2(g,h,a,b,c,d,e,f,2); - ROUND2(f,g,h,a,b,c,d,e,3); - ROUND2(e,f,g,h,a,b,c,d,4); - ROUND2(d,e,f,g,h,a,b,c,5); - ROUND2(c,d,e,f,g,h,a,b,6); - ROUND2(b,c,d,e,f,g,h,a,7); - ROUND2(a,b,c,d,e,f,g,h,8); - ROUND2(h,a,b,c,d,e,f,g,9); - ROUND2(g,h,a,b,c,d,e,f,10); - ROUND2(f,g,h,a,b,c,d,e,11); - ROUND2(e,f,g,h,a,b,c,d,12); - ROUND2(d,e,f,g,h,a,b,c,13); - ROUND2(c,d,e,f,g,h,a,b,14); - ROUND2(b,c,d,e,f,g,h,a,15); - } while(K != K_end); - - // Update hash - hash[0] += a; - hash[1] += b; - hash[2] += c; - hash[3] += d; - hash[4] += e; - hash[5] += f; - hash[6] += g; - hash[7] += h; -} - -std::string SHA256::hexString() -{ - const char* hex = "0123456789abcdef"; - std::string hexstr(64, '0'); - for(int i = 0; i < 32; ++i) { - hexstr[2 * i + 0] = hex[digest()[i] >> 4]; - hexstr[2 * i + 1] = hex[digest()[i] & 0xf]; - } - return hexstr; -} +// Author: Remco Bloemen +// Based on: +// http://en.wikipedia.org/wiki/SHA-2 +// http://www.iwar.org.uk/comsec/resources/cipher/sha256-384-512.pdf +// some of the OpenSSL optimizations + +#include "SHA256.h" + +inline unsigned int reverse_bytes(unsigned int x) +{ + return __rev(x); +} + +inline unsigned int rotate_right(unsigned int x, int shift) +{ + // return (x >> shift) | (x << (32 - shift)); + return __ror(x, shift); +} + +void SHA256::reset() +{ + hash[0] = 0x6A09E667; + hash[1] = 0xBB67AE85; + hash[2] = 0x3C6EF372; + hash[3] = 0xA54FF53A; + hash[4] = 0x510E527F; + hash[5] = 0x9B05688C; + hash[6] = 0x1F83D9AB; + hash[7] = 0x5BE0CD19; + length = 0; +} + +void SHA256::append(const char* data, int size) +{ + int index = length % 64; + length += size; + const char* end = data + size; + + // Word align data + char* bytes = reinterpret_cast<char*>(w + (index / 4)); + switch(index % 4) + { + // Remember to reverse! (little endian!) + case 1: bytes[2] = *data++; ++index; + case 2: bytes[1] = *data++; ++index; + case 3: bytes[0] = *data++; ++index; + case 0: break; + } + if(data > end) { + // We have overshot reading data + // but w and length are correct + return; + } + + // Index is now word alligned + index /= 4; + if(index == 16) { + process_chunk(); + index = 0; + } + + // Process whole words + int num_words = (end - data) / 4; + const unsigned int* data_words = reinterpret_cast<const unsigned int*>(data); + const unsigned int* data_words_end = data_words + num_words; + while(data_words != data_words_end) + { + w[index++] = reverse_bytes(*data_words++); + if(index == 16) { + process_chunk(); + index = 0; + } + } + + // Process trailing data bytes + // Again, we won't worry about overshooting data + w[index] = reverse_bytes(*data_words); +} + +void SHA256::finalize() +{ + int trailing = length % 64; + + // Append the bit '1' to the message + int last_block = trailing / 4; + unsigned int bit_in_block = 0x80 << (24 - (trailing % 4) * 8); + w[last_block] |= bit_in_block; + + // Set all other bits to zero + w[last_block] &= ~(bit_in_block - 1); + for(int i = last_block + 1; i < 16; ++i) + w[i] = 0; + + // Make room for the length if necessary + if(trailing >= 56) { + process_chunk(); + for(int i = 0; i <= last_block; ++i) + w[i] = 0; + } + + // Append the length in bits + w[14] = length >> (32 - 3); + w[15] = length << 3; + process_chunk(); + + // Convert the result to big endian + for(int i = 0; i < 8; ++i) + hash[i] = reverse_bytes(hash[i]); +} + +#define s0(x) (rotate_right(x, 7) ^ rotate_right(x, 18) ^ (x >> 3)) +#define s1(x) (rotate_right(x, 17) ^ rotate_right(x, 19) ^ (x >> 10)) +#define s2(x) (rotate_right(x, 2) ^ rotate_right(x, 13) ^ rotate_right(x, 22)) +#define s3(x) (rotate_right(x, 6) ^ rotate_right(x, 11) ^ rotate_right(x, 25)) +#define maj(a,b,c) ((a & b) ^ (a & c) ^ (b & c)) +#define ch(a,b,c) ((a & b) ^ ((~a) & c)) + +const unsigned int k[64] = { + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2 +}; + +#define ROUND(a,b,c,d,e,f,g,h,i) \ + h += w[i];\ + h += *K++;\ + h += s3(e); \ + h += ch(e, f, g); \ + d += h;\ + h += s2(a);\ + h += maj(a, b, c); + +#define W(n) w[(n) & 0xf] + +#define ROUND2(a,b,c,d,e,f,g,h,i) \ + W(i) += s0(W(i+1)) + W(i+9) + s1(W(i+14));\ + h += W(i); \ + h += *K++;\ + h += s3(e);\ + h += ch(e, f, g); \ + d += h;\ + h += s2(a);\ + h += maj(a, b, c); + +// Process a 512 bit chunk stored in w[1...15] +void SHA256::process_chunk() +{ + // Initialize using current hash + unsigned int a = hash[0]; + unsigned int b = hash[1]; + unsigned int c = hash[2]; + unsigned int d = hash[3]; + unsigned int e = hash[4]; + unsigned int f = hash[5]; + unsigned int g = hash[6]; + unsigned int h = hash[7]; + + // Main loop + const unsigned int* K = k; + const unsigned int* K_end = k + 64; + ROUND(a,b,c,d,e,f,g,h,0); + ROUND(h,a,b,c,d,e,f,g,1); + ROUND(g,h,a,b,c,d,e,f,2); + ROUND(f,g,h,a,b,c,d,e,3); + ROUND(e,f,g,h,a,b,c,d,4); + ROUND(d,e,f,g,h,a,b,c,5); + ROUND(c,d,e,f,g,h,a,b,6); + ROUND(b,c,d,e,f,g,h,a,7); + ROUND(a,b,c,d,e,f,g,h,8); + ROUND(h,a,b,c,d,e,f,g,9); + ROUND(g,h,a,b,c,d,e,f,10); + ROUND(f,g,h,a,b,c,d,e,11); + ROUND(e,f,g,h,a,b,c,d,12); + ROUND(d,e,f,g,h,a,b,c,13); + ROUND(c,d,e,f,g,h,a,b,14); + ROUND(b,c,d,e,f,g,h,a,15); + do { + ROUND2(a,b,c,d,e,f,g,h,0); + ROUND2(h,a,b,c,d,e,f,g,1); + ROUND2(g,h,a,b,c,d,e,f,2); + ROUND2(f,g,h,a,b,c,d,e,3); + ROUND2(e,f,g,h,a,b,c,d,4); + ROUND2(d,e,f,g,h,a,b,c,5); + ROUND2(c,d,e,f,g,h,a,b,6); + ROUND2(b,c,d,e,f,g,h,a,7); + ROUND2(a,b,c,d,e,f,g,h,8); + ROUND2(h,a,b,c,d,e,f,g,9); + ROUND2(g,h,a,b,c,d,e,f,10); + ROUND2(f,g,h,a,b,c,d,e,11); + ROUND2(e,f,g,h,a,b,c,d,12); + ROUND2(d,e,f,g,h,a,b,c,13); + ROUND2(c,d,e,f,g,h,a,b,14); + ROUND2(b,c,d,e,f,g,h,a,15); + } while(K != K_end); + + // Update hash + hash[0] += a; + hash[1] += b; + hash[2] += c; + hash[3] += d; + hash[4] += e; + hash[5] += f; + hash[6] += g; + hash[7] += h; +} + +std::string SHA256::hexString() +{ + const char* hex = "0123456789abcdef"; + std::string hexstr(64, '0'); + for(int i = 0; i < 32; ++i) { + hexstr[2 * i + 0] = hex[digest()[i] >> 4]; + hexstr[2 * i + 1] = hex[digest()[i] & 0xf]; + } + return hexstr; +}
diff -r 246096ab9e56 -r c0ed1bf37651 SHA256.h --- a/SHA256.h Mon Jun 20 11:11:10 2011 +0000 +++ b/SHA256.h Mon Jun 20 13:21:38 2011 +0000 @@ -99,11 +99,11 @@ /// /// @returns a std::string containing the digest in hexadecimal ascii. std::string hexString(); - -private: - void process_chunk(); + +protected: int length; unsigned int hash[8]; unsigned int w[16]; + void process_chunk(); };