fork download
  1. #include <algorithm>
  2. #include <array>
  3. #include <cstdlib>
  4. #include <iostream>
  5. #include <memory>
  6. #include <string>
  7.  
  8. using namespace std;
  9.  
  10. class BitInputStream;
  11. class StringBitInputStream;
  12.  
  13. extern shared_ptr<array<unsigned long, 5> > computeHashBySHA1(const shared_ptr<BitInputStream>& msg);
  14.  
  15. class BitInputStream {
  16. public:
  17. virtual bool getBit() = 0;
  18. virtual bool isEOF() = 0;
  19. };
  20.  
  21. class StringBitInputStream : public BitInputStream {
  22. public:
  23. StringBitInputStream(const string& str);
  24. virtual bool getBit();
  25. virtual bool isEOF();
  26. protected:
  27. string str;
  28. size_t str_pos;
  29. unsigned int ch_pos;
  30. };
  31.  
  32. #define ASSERT(pred) assert(#pred, pred);
  33.  
  34. extern void assert(const char* pred_str, const bool& pred);
  35.  
  36. typedef unsigned long (*FUNCTION_IN_SHA1)(const unsigned long& x, const unsigned long& y, const unsigned long& z);
  37.  
  38. static unsigned long rotateLeft(const unsigned long& x, const unsigned int& n);
  39. static unsigned long chInSHA1(const unsigned long& x, const unsigned long& y, const unsigned long& z);
  40. static unsigned long parityInSHA1(const unsigned long& x, const unsigned long& y, const unsigned long& z);
  41. static unsigned long majInSHA1(const unsigned long& x, const unsigned long& y, const unsigned long& z);
  42.  
  43. static const FUNCTION_IN_SHA1 FUNCTIONS_IN_SHA1[] = {
  44. chInSHA1,
  45. parityInSHA1,
  46. majInSHA1,
  47. parityInSHA1,
  48. };
  49.  
  50. static const unsigned long K_IN_SHA1[] = {
  51. 0x5a827999,
  52. 0x6ed9eba1,
  53. 0x8f1bbcdc,
  54. 0xca62c1d6,
  55. };
  56.  
  57. static const unsigned long INITIAL_HASH_VALUES_IN_SHA1[] = {
  58. 0x67452301,
  59. 0xefcdab89,
  60. 0x98badcfe,
  61. 0x10325476,
  62. 0xc3d2e1f0,
  63. };
  64.  
  65. shared_ptr<array<unsigned long, 5> > computeHashBySHA1(const shared_ptr<BitInputStream>& msg) {
  66. shared_ptr<array<unsigned long, 5> > hash(new array<unsigned long, 5>);
  67. copy(INITIAL_HASH_VALUES_IN_SHA1, INITIAL_HASH_VALUES_IN_SHA1 + 5, &hash->front());
  68. shared_ptr<array<unsigned long, 16> > block(new array<unsigned long, 16>);
  69. shared_ptr<array<unsigned long, 80> > sche(new array<unsigned long, 80>);
  70. unsigned long long len = 0;
  71. bool put_end = false;
  72. bool put_len = false;
  73. while (!put_len) {
  74. block->fill(0);
  75. unsigned int block_pos = 0;
  76. for (; block_pos < 512 && !msg->isEOF(); block_pos++) {
  77. block->at(block_pos >> 5) |= (msg->getBit() == true ? 1 : 0) << (31 - (block_pos & 0x1F));
  78. len++;
  79. }
  80. if (block_pos < 512) {
  81. if (!put_end) {
  82. block->at(block_pos >> 5) |= 1 << (31 - (block_pos & 0x1F));
  83. block_pos++;
  84. put_end = true;
  85. }
  86. if (block_pos + 64 <= 512) {
  87. block->at(14) = len >> 32;
  88. block->at(15) = len & 0xFFFFFFFF;
  89. put_len = true;
  90. }
  91. }
  92. for (unsigned int i = 0; i < 80; i++) {
  93. if (i < 16) sche->at(i) = block->at(i);
  94. else sche->at(i) = rotateLeft(sche->at(i - 3) ^ sche->at(i - 8) ^ sche->at(i - 14) ^ sche->at(i - 16), 1);
  95. }
  96. unsigned long a = hash->at(0);
  97. unsigned long b = hash->at(1);
  98. unsigned long c = hash->at(2);
  99. unsigned long d = hash->at(3);
  100. unsigned long e = hash->at(4);
  101. for (unsigned int i = 0; i < 80; i++) {
  102. unsigned long t = 0;
  103. t += rotateLeft(a, 5);
  104. t += FUNCTIONS_IN_SHA1[i / 20](b, c, d);
  105. t += e;
  106. t += K_IN_SHA1[i / 20];
  107. t += sche->at(i);
  108. e = d;
  109. d = c;
  110. c = rotateLeft(b, 30);
  111. b = a;
  112. a = t;
  113. }
  114. hash->at(0) += a;
  115. hash->at(1) += b;
  116. hash->at(2) += c;
  117. hash->at(3) += d;
  118. hash->at(4) += e;
  119. }
  120. return hash;
  121. }
  122.  
  123. unsigned long rotateLeft(const unsigned long& x, const unsigned int& n) {
  124. return (x << n) | (x >> (32 - n));
  125. }
  126.  
  127. unsigned long chInSHA1(const unsigned long& x, const unsigned long& y, const unsigned long& z) {
  128. return (x & y) ^ (~x & z);
  129. }
  130.  
  131. unsigned long parityInSHA1(const unsigned long& x, const unsigned long& y, const unsigned long& z) {
  132. return x ^ y ^ z;
  133. }
  134.  
  135. unsigned long majInSHA1(const unsigned long& x, const unsigned long& y, const unsigned long& z) {
  136. return (x & y) ^ (x & z) ^ (y & z);
  137. }
  138.  
  139. StringBitInputStream::StringBitInputStream(const string& str) : str(str), str_pos(0), ch_pos(7) {}
  140.  
  141. bool StringBitInputStream::getBit() {
  142. bool res = ((this->str.at(this->str_pos) >> this->ch_pos) & 1) == 1;
  143. if (this->ch_pos == 0) {
  144. this->str_pos++;
  145. this->ch_pos = 7;
  146. }
  147. else this->ch_pos--;
  148. return res;
  149. }
  150.  
  151. bool StringBitInputStream::isEOF() {
  152. return this->str_pos >= this->str.length();
  153. }
  154.  
  155. void assert(const char* pred_str, const bool& pred) {
  156. if (pred) {
  157. cout << "アサート成功: " << pred_str << endl;
  158. }
  159. else {
  160. cerr << "アサート失敗: " << pred_str << endl;
  161. exit(1);
  162. }
  163. }
  164.  
  165. int main() {
  166. {
  167. shared_ptr<array<unsigned long, 5> > hash = computeHashBySHA1(shared_ptr<BitInputStream>(new StringBitInputStream(
  168. "abc")));
  169. ASSERT(hash->at(0) == 0xa9993e36)
  170. ASSERT(hash->at(1) == 0x4706816a)
  171. ASSERT(hash->at(2) == 0xba3e2571)
  172. ASSERT(hash->at(3) == 0x7850c26c)
  173. ASSERT(hash->at(4) == 0x9cd0d89d)
  174. }
  175. {
  176. shared_ptr<array<unsigned long, 5> > hash = computeHashBySHA1(shared_ptr<BitInputStream>(new StringBitInputStream(
  177. "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq")));
  178. ASSERT(hash->at(0) == 0x84983e44)
  179. ASSERT(hash->at(1) == 0x1c3bd26e)
  180. ASSERT(hash->at(2) == 0xbaae4aa1)
  181. ASSERT(hash->at(3) == 0xf95129e5)
  182. ASSERT(hash->at(4) == 0xe54670f1)
  183. }
  184. return 0;
  185. }
  186.  
Success #stdin #stdout 0s 3480KB
stdin
Standard input is empty
stdout
アサート成功: hash->at(0) == 0xa9993e36
アサート成功: hash->at(1) == 0x4706816a
アサート成功: hash->at(2) == 0xba3e2571
アサート成功: hash->at(3) == 0x7850c26c
アサート成功: hash->at(4) == 0x9cd0d89d
アサート成功: hash->at(0) == 0x84983e44
アサート成功: hash->at(1) == 0x1c3bd26e
アサート成功: hash->at(2) == 0xbaae4aa1
アサート成功: hash->at(3) == 0xf95129e5
アサート成功: hash->at(4) == 0xe54670f1