A toolkit for working with phylogenetic data.
v0.18.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
sha1.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2017 Lucas Czech
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
32 
33 #include <fstream>
34 #include <iomanip>
35 #include <iostream>
36 #include <sstream>
37 
38 namespace genesis {
39 namespace utils {
40 
41 // ================================================================================================
42 // Constructors and Rule of Five
43 // ================================================================================================
44 
49 {
50  reset_();
51 }
52 
53 // ================================================================================================
54 // Member Functions
55 // ================================================================================================
56 
60 void SHA1::update( std::string const& s )
61 {
62  std::istringstream is(s);
63  update(is);
64 }
65 
69 void SHA1::update(std::istream& is)
70 {
71  while (true) {
72  char sbuf[SHA1::BlockBytes];
73  is.read(sbuf, SHA1::BlockBytes - buffer_.size());
74  buffer_.append(sbuf, is.gcount());
75  if (buffer_.size() != SHA1::BlockBytes) {
76  return;
77  }
78  uint32_t block[SHA1::BlockInts];
79  buffer_to_block_(buffer_, block);
80  transform_( block );
81  buffer_.clear();
82  }
83 }
84 
88 std::string SHA1::final_hex()
89 {
90  // Calculate digest, also reset for next use.
91  auto digest = final_digest();
92 
93  /* Hex std::string */
94  std::ostringstream result;
95  for (size_t i = 0; i < digest.size(); ++i) {
96  result << std::hex << std::setfill('0') << std::setw(8);
97  result << digest[i];
98  }
99 
100  return result.str();
101 }
102 
107 {
108  /* Total number of hashed bits */
109  uint64_t total_bits = (transforms_*SHA1::BlockBytes + buffer_.size()) * 8;
110 
111  /* Padding */
112  buffer_ += static_cast<char>( 0x80 );
113  size_t orig_size = buffer_.size();
114  while (buffer_.size() < SHA1::BlockBytes) {
115  buffer_ += static_cast<char>( 0x00 );
116  }
117 
118  uint32_t block[SHA1::BlockInts];
119  buffer_to_block_(buffer_, block);
120 
121  if (orig_size > SHA1::BlockBytes - 8) {
122  transform_( block );
123  for (size_t i = 0; i < SHA1::BlockInts - 2; i++) {
124  block[i] = 0;
125  }
126  }
127 
128  /* Append total_bits, split this uint64_t into two uint32_t */
129  block[SHA1::BlockInts - 1] = total_bits;
130  block[SHA1::BlockInts - 2] = (total_bits >> 32);
131  transform_( block );
132 
133  auto result = digest_;
134 
135  /* Reset for next run */
136  reset_();
137 
138  return result;
139 }
140 
144 std::string SHA1::from_file_hex( std::string const& filename )
145 {
146  std::ifstream stream( filename.c_str(), std::ios::binary );
147  SHA1 checksum;
148  checksum.update(stream);
149  return checksum.final_hex();
150 }
151 
155 SHA1::DigestType SHA1::from_file_digest( std::string const& filename )
156 {
157  std::ifstream stream( filename.c_str(), std::ios::binary );
158  SHA1 checksum;
159  checksum.update(stream);
160  return checksum.final_digest();
161 }
162 
166 std::string SHA1::from_string_hex( std::string const& input )
167 {
168  SHA1 checksum;
169  checksum.update( input );
170  return checksum.final_hex();
171 }
172 
176 SHA1::DigestType SHA1::from_string_digest( std::string const& input )
177 {
178  SHA1 checksum;
179  checksum.update( input );
180  return checksum.final_digest();
181 }
182 
183 // ================================================================================================
184 // Internal Functions
185 // ================================================================================================
186 
187 void SHA1::reset_()
188 {
189  /* SHA1 initialization constants */
190  digest_[0] = 0x67452301;
191  digest_[1] = 0xefcdab89;
192  digest_[2] = 0x98badcfe;
193  digest_[3] = 0x10325476;
194  digest_[4] = 0xc3d2e1f0;
195 
196  /* Reset counters */
197  buffer_ = "";
198  transforms_ = 0;
199 }
200 
201 uint32_t SHA1::rol_(const uint32_t value, const size_t bits)
202 {
203  return (value << bits) | (value >> (32 - bits));
204 }
205 
206 uint32_t SHA1::blk_(const uint32_t block[SHA1::BlockInts], const size_t i)
207 {
208  return rol_(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i], 1);
209 }
210 
211 void SHA1::R0_(
212  const uint32_t block[SHA1::BlockInts], const uint32_t v, uint32_t& w, const uint32_t x,
213  const uint32_t y, uint32_t& z, const size_t i
214 ) {
215  z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol_(v, 5);
216  w = rol_(w, 30);
217 }
218 
219 void SHA1::R1_(
220  uint32_t block[SHA1::BlockInts], const uint32_t v, uint32_t& w, const uint32_t x,
221  const uint32_t y, uint32_t& z, const size_t i
222 ) {
223  block[i] = blk_(block, i);
224  z += ((w&(x^y))^y) + block[i] + 0x5a827999 + rol_(v, 5);
225  w = rol_(w, 30);
226 }
227 
228 void SHA1::R2_(
229  uint32_t block[SHA1::BlockInts], const uint32_t v, uint32_t& w, const uint32_t x,
230  const uint32_t y, uint32_t& z, const size_t i
231 ) {
232  block[i] = blk_(block, i);
233  z += (w^x^y) + block[i] + 0x6ed9eba1 + rol_(v, 5);
234  w = rol_(w, 30);
235 }
236 
237 void SHA1::R3_(
238  uint32_t block[SHA1::BlockInts], const uint32_t v, uint32_t& w, const uint32_t x,
239  const uint32_t y, uint32_t& z, const size_t i
240 ) {
241  block[i] = blk_(block, i);
242  z += (((w|x)&y)|(w&x)) + block[i] + 0x8f1bbcdc + rol_(v, 5);
243  w = rol_(w, 30);
244 }
245 
246 
247 void SHA1::R4_(
248  uint32_t block[SHA1::BlockInts], const uint32_t v, uint32_t& w, const uint32_t x,
249  const uint32_t y, uint32_t& z, const size_t i
250 ) {
251  block[i] = blk_(block, i);
252  z += (w^x^y) + block[i] + 0xca62c1d6 + rol_(v, 5);
253  w = rol_(w, 30);
254 }
255 
259 void SHA1::transform_( uint32_t block[SHA1::BlockInts] )
260 {
261  // Copy digest[] to working vars
262  uint32_t a = digest_[0];
263  uint32_t b = digest_[1];
264  uint32_t c = digest_[2];
265  uint32_t d = digest_[3];
266  uint32_t e = digest_[4];
267 
268  // 4 rounds of 20 operations each. Loop unrolled.
269  R0_(block, a, b, c, d, e, 0);
270  R0_(block, e, a, b, c, d, 1);
271  R0_(block, d, e, a, b, c, 2);
272  R0_(block, c, d, e, a, b, 3);
273  R0_(block, b, c, d, e, a, 4);
274  R0_(block, a, b, c, d, e, 5);
275  R0_(block, e, a, b, c, d, 6);
276  R0_(block, d, e, a, b, c, 7);
277  R0_(block, c, d, e, a, b, 8);
278  R0_(block, b, c, d, e, a, 9);
279  R0_(block, a, b, c, d, e, 10);
280  R0_(block, e, a, b, c, d, 11);
281  R0_(block, d, e, a, b, c, 12);
282  R0_(block, c, d, e, a, b, 13);
283  R0_(block, b, c, d, e, a, 14);
284  R0_(block, a, b, c, d, e, 15);
285  R1_(block, e, a, b, c, d, 0);
286  R1_(block, d, e, a, b, c, 1);
287  R1_(block, c, d, e, a, b, 2);
288  R1_(block, b, c, d, e, a, 3);
289  R2_(block, a, b, c, d, e, 4);
290  R2_(block, e, a, b, c, d, 5);
291  R2_(block, d, e, a, b, c, 6);
292  R2_(block, c, d, e, a, b, 7);
293  R2_(block, b, c, d, e, a, 8);
294  R2_(block, a, b, c, d, e, 9);
295  R2_(block, e, a, b, c, d, 10);
296  R2_(block, d, e, a, b, c, 11);
297  R2_(block, c, d, e, a, b, 12);
298  R2_(block, b, c, d, e, a, 13);
299  R2_(block, a, b, c, d, e, 14);
300  R2_(block, e, a, b, c, d, 15);
301  R2_(block, d, e, a, b, c, 0);
302  R2_(block, c, d, e, a, b, 1);
303  R2_(block, b, c, d, e, a, 2);
304  R2_(block, a, b, c, d, e, 3);
305  R2_(block, e, a, b, c, d, 4);
306  R2_(block, d, e, a, b, c, 5);
307  R2_(block, c, d, e, a, b, 6);
308  R2_(block, b, c, d, e, a, 7);
309  R3_(block, a, b, c, d, e, 8);
310  R3_(block, e, a, b, c, d, 9);
311  R3_(block, d, e, a, b, c, 10);
312  R3_(block, c, d, e, a, b, 11);
313  R3_(block, b, c, d, e, a, 12);
314  R3_(block, a, b, c, d, e, 13);
315  R3_(block, e, a, b, c, d, 14);
316  R3_(block, d, e, a, b, c, 15);
317  R3_(block, c, d, e, a, b, 0);
318  R3_(block, b, c, d, e, a, 1);
319  R3_(block, a, b, c, d, e, 2);
320  R3_(block, e, a, b, c, d, 3);
321  R3_(block, d, e, a, b, c, 4);
322  R3_(block, c, d, e, a, b, 5);
323  R3_(block, b, c, d, e, a, 6);
324  R3_(block, a, b, c, d, e, 7);
325  R3_(block, e, a, b, c, d, 8);
326  R3_(block, d, e, a, b, c, 9);
327  R3_(block, c, d, e, a, b, 10);
328  R3_(block, b, c, d, e, a, 11);
329  R4_(block, a, b, c, d, e, 12);
330  R4_(block, e, a, b, c, d, 13);
331  R4_(block, d, e, a, b, c, 14);
332  R4_(block, c, d, e, a, b, 15);
333  R4_(block, b, c, d, e, a, 0);
334  R4_(block, a, b, c, d, e, 1);
335  R4_(block, e, a, b, c, d, 2);
336  R4_(block, d, e, a, b, c, 3);
337  R4_(block, c, d, e, a, b, 4);
338  R4_(block, b, c, d, e, a, 5);
339  R4_(block, a, b, c, d, e, 6);
340  R4_(block, e, a, b, c, d, 7);
341  R4_(block, d, e, a, b, c, 8);
342  R4_(block, c, d, e, a, b, 9);
343  R4_(block, b, c, d, e, a, 10);
344  R4_(block, a, b, c, d, e, 11);
345  R4_(block, e, a, b, c, d, 12);
346  R4_(block, d, e, a, b, c, 13);
347  R4_(block, c, d, e, a, b, 14);
348  R4_(block, b, c, d, e, a, 15);
349 
350  /* Add the working vars back into digest[] */
351  digest_[0] += a;
352  digest_[1] += b;
353  digest_[2] += c;
354  digest_[3] += d;
355  digest_[4] += e;
356 
357  /* Count the number of transformations */
358  ++transforms_;
359 }
360 
364 void SHA1::buffer_to_block_(const std::string& buffer, uint32_t block[SHA1::BlockInts])
365 {
366  for (size_t i = 0; i < SHA1::BlockInts; i++) {
367  block[i] = ( buffer[4*i+3] & 0xff )
368  | ( buffer[4*i+2] & 0xff ) << 8
369  | ( buffer[4*i+1] & 0xff ) << 16
370  | ( buffer[4*i+0] & 0xff ) << 24;
371  }
372 }
373 
374 } // namespace utils
375 } // namespace genesis
DigestType final_digest()
Finish the calculation, prepare the object for next use, and return the digest.
Definition: sha1.cpp:106
std::string final_hex()
Finish the calculation, prepare the object for next use, and return the hash.
Definition: sha1.cpp:88
static DigestType from_string_digest(std::string const &input)
Calculate the hash digest for the content of a string.
Definition: sha1.cpp:176
std::array< uint32_t, 5 > DigestType
Store a SHA1 digest.
Definition: sha1.hpp:74
static std::string from_string_hex(std::string const &input)
Calculate the checksum for the content of a string.
Definition: sha1.cpp:166
static const size_t BlockInts
Definition: sha1.hpp:64
static DigestType from_file_digest(std::string const &filename)
Calculate the hash digest for the content of a file, given its path.
Definition: sha1.cpp:155
static const size_t BlockBytes
Definition: sha1.hpp:65
static std::string from_file_hex(std::string const &filename)
Calculate the checksum for the content of a file, given its path.
Definition: sha1.cpp:144
void update(std::string const &s)
Add the contents of a string to the hash digest.
Definition: sha1.cpp:60
Calculate SHA1 hashes for strings and files.
Definition: sha1.hpp:55
SHA1()
Initialize the object for use.
Definition: sha1.cpp:48