a09da39c4e3a112ba602fafdff56ec3ee766aec3
[cvc5.git] / examples / hashsmt / sha1.hpp
1 /********************* */
2 /*! \file sha1.hpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Dejan Jovanovic, Tim King
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
8 ** in the top-level source directory) and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
11 **
12 ** \brief [[ Add one-line brief description here ]]
13 **
14 ** [[ Add lengthier description here ]]
15 ** \todo document this file
16 **/
17
18 // boost/uuid/sha1.hpp header file ----------------------------------------------//
19
20 // Copyright 2007 Andy Tompkins.
21 // Distributed under the Boost Software License, Version 1.0. (See
22 // accompanying file LICENSE_1_0.txt or copy at
23 // http://www.boost.org/LICENSE_1_0.txt)
24
25 // Revision History
26 // 29 May 2007 - Initial Revision
27 // 25 Feb 2008 - moved to namespace boost::uuids::detail
28
29 // This is a byte oriented implementation
30 // Note: this implementation does not handle message longer than
31 // 2^32 bytes.
32
33 #ifndef __CVC4__EXAMPLES__HASHSMT__SHA1_H
34 #define __CVC4__EXAMPLES__HASHSMT__SHA1_H
35
36 #include <cstddef>
37
38 #include "word.h"
39
40 #ifdef BOOST_NO_STDC_NAMESPACE
41 namespace std {
42 using ::size_t;
43 } // namespace std
44 #endif
45
46 namespace hashsmt {
47
48 static_assert(sizeof(unsigned char)*8 == 8,
49 "Unexpected size for unsigned char");
50 static_assert(sizeof(unsigned int)*8 == 32,
51 "Unexpected size for unsigned int");
52
53 inline cvc4_uint32 left_rotate(cvc4_uint32 x, std::size_t n)
54 {
55 return (x<<n) ^ (x>> (32-n));
56 }
57
58 class sha1
59 {
60 public:
61 typedef cvc4_uint32(&digest_type)[5];
62 public:
63 sha1(unsigned rounds = 80);
64
65 void reset();
66
67 void process_byte(cvc4_uchar8 byte);
68 void process_block(void const* bytes_begin, void const* bytes_end);
69 void process_bytes(void const* buffer, std::size_t byte_count);
70
71 void get_digest(digest_type digest);
72
73 private:
74 void process_block();
75
76 private:
77 cvc4_uint32 h_[5];
78
79 cvc4_uchar8 block_[64];
80
81 std::size_t block_byte_index_;
82 std::size_t byte_count_;
83
84 unsigned rounds_;
85 };
86
87 inline sha1::sha1(unsigned rounds)
88 : rounds_(rounds)
89 {
90 reset();
91 }
92
93 inline void sha1::reset()
94 {
95 h_[0] = 0x67452301;
96 h_[1] = 0xEFCDAB89;
97 h_[2] = 0x98BADCFE;
98 h_[3] = 0x10325476;
99 h_[4] = 0xC3D2E1F0;
100
101 block_byte_index_ = 0;
102 byte_count_ = 0;
103 }
104
105 inline void sha1::process_byte(cvc4_uchar8 byte)
106 {
107 block_[block_byte_index_++] = byte;
108 ++byte_count_;
109 if (block_byte_index_ == 64) {
110 block_byte_index_ = 0;
111 process_block();
112 }
113 }
114
115 inline void sha1::process_block(void const* bytes_begin, void const* bytes_end)
116 {
117 cvc4_uchar8 const* begin = static_cast<cvc4_uchar8 const*>(bytes_begin);
118 cvc4_uchar8 const* end = static_cast<cvc4_uchar8 const*>(bytes_end);
119 for(; begin != end; ++begin) {
120 process_byte(*begin);
121 }
122 }
123
124 inline void sha1::process_bytes(void const* buffer, std::size_t byte_count)
125 {
126 cvc4_uchar8 const* b = static_cast<cvc4_uchar8 const*>(buffer);
127 process_block(b, b+byte_count);
128 }
129
130 inline void sha1::process_block()
131 {
132 cvc4_uint32 w[80];
133 for (std::size_t i=0; i<16; ++i) {
134 w[i] = (block_[i*4 + 0] << 24);
135 w[i] |= (block_[i*4 + 1] << 16);
136 w[i] |= (block_[i*4 + 2] << 8);
137 w[i] |= (block_[i*4 + 3]);
138 }
139 for (std::size_t i=16; i<80; ++i) {
140 w[i] = left_rotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1);
141 }
142
143 cvc4_uint32 a = h_[0];
144 cvc4_uint32 b = h_[1];
145 cvc4_uint32 c = h_[2];
146 cvc4_uint32 d = h_[3];
147 cvc4_uint32 e = h_[4];
148
149 for (std::size_t i=0; i<rounds_; ++i) {
150 cvc4_uint32 f;
151 cvc4_uint32 k;
152
153 if (i<20) {
154 f = (b & c) | (~b & d);
155 k = 0x5A827999;
156 } else if (i<40) {
157 f = b ^ c ^ d;
158 k = 0x6ED9EBA1;
159 } else if (i<60) {
160 f = (b & c) | (b & d) | (c & d);
161 k = 0x8F1BBCDC;
162 } else {
163 f = b ^ c ^ d;
164 k = 0xCA62C1D6;
165 }
166
167 cvc4_uint32 temp = left_rotate(a, 5) + f + e + k + w[i];
168 e = d;
169 d = c;
170 c = left_rotate(b, 30);
171 b = a;
172 a = temp;
173 }
174
175 h_[0] += a;
176 h_[1] += b;
177 h_[2] += c;
178 h_[3] += d;
179 h_[4] += e;
180 }
181
182 inline void sha1::get_digest(digest_type digest)
183 {
184 std::size_t bit_count = byte_count_*8;
185
186 // append the bit '1' to the message
187 process_byte(0x80);
188
189 // append k bits '0', where k is the minimum number >= 0
190 // such that the resulting message length is congruent to 56 (mod 64)
191 // check if there is enough space for padding and bit_count
192 if (block_byte_index_ > 56) {
193 // finish this block
194 while (block_byte_index_ != 0) {
195 process_byte(0);
196 }
197
198 // one more block
199 while (block_byte_index_ < 56) {
200 process_byte(0);
201 }
202 } else {
203 while (block_byte_index_ < 56) {
204 process_byte(0);
205 }
206 }
207
208 // append length of message (before pre-processing)
209 // as a 64-bit big-endian integer
210 process_byte(0);
211 process_byte(0);
212 process_byte(0);
213 process_byte(0);
214 process_byte( static_cast<unsigned char>((bit_count>>24) & 0xFF));
215 process_byte( static_cast<unsigned char>((bit_count>>16) & 0xFF));
216 process_byte( static_cast<unsigned char>((bit_count>>8 ) & 0xFF));
217 process_byte( static_cast<unsigned char>((bit_count) & 0xFF));
218
219 // get final digest
220 digest[0] = h_[0];
221 digest[1] = h_[1];
222 digest[2] = h_[2];
223 digest[3] = h_[3];
224 digest[4] = h_[4];
225 }
226
227 } // namespace hashsmt
228
229 #endif /* __CVC4__EXAMPLES__HASHSMT__SHA1_H */