Skip to content

Commit 4f9dcb1

Browse files
committed
version 4
1 parent 5016fca commit 4f9dcb1

File tree

5 files changed

+387
-21
lines changed

5 files changed

+387
-21
lines changed

digest.cpp

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "sha1.h"
1010
#include "sha256.h"
1111
#include "keccak.h"
12+
#include "sha3.h"
1213

1314
#include <iostream>
1415
#include <fstream>
@@ -18,7 +19,7 @@ int main(int argc, char** argv)
1819
// syntax check
1920
if (argc < 2 || argc > 3)
2021
{
21-
std::cout << "./digest filename [--md5|--sha1|--sha256|--crc]" << std::endl;
22+
std::cout << "./digest filename [--md5|--sha1|--sha256|--crc|--keccak|--sha3]" << std::endl;
2223
return 1;
2324
}
2425

@@ -28,8 +29,9 @@ int main(int argc, char** argv)
2829
bool computeCrc32 = algorithm.empty() || algorithm == "--crc";
2930
bool computeMd5 = algorithm.empty() || algorithm == "--md5";
3031
bool computeSha1 = algorithm.empty() || algorithm == "--sha1";
31-
bool computeSha256 = algorithm.empty() || algorithm == "--sha256";
32-
bool computeKeccak256 = algorithm.empty() || algorithm == "--keccak256";
32+
bool computeSha2 = algorithm.empty() || algorithm == "--sha2" || algorithm == "--sha256";
33+
bool computeKeccak = algorithm.empty() || algorithm == "--keccak";
34+
bool computeSha3 = algorithm.empty() || algorithm == "--sha3";
3335

3436
// each cycle processes about 1 MByte (divisible by 144 => improves Keccak performance)
3537
const size_t BufferSize = 144*7*1024;
@@ -38,8 +40,9 @@ int main(int argc, char** argv)
3840
CRC32 digestCrc32;
3941
MD5 digestMd5;
4042
SHA1 digestSha1;
41-
SHA256 digestSha256;
42-
Keccak digestKeccak256(Keccak::Keccak256);
43+
SHA256 digestSha2;
44+
Keccak digestKeccak(Keccak::Keccak256);
45+
SHA3 digestSha3 (SHA3 ::Bits256);
4346

4447
// open file
4548
std::ifstream file(filename.c_str(), std::ios::in | std::ios::binary);
@@ -55,29 +58,33 @@ int main(int argc, char** argv)
5558
std::size_t numBytesRead = size_t(file.gcount());
5659

5760
if (computeCrc32)
58-
digestCrc32 .add(buffer, numBytesRead);
61+
digestCrc32 .add(buffer, numBytesRead);
5962
if (computeMd5)
60-
digestMd5 .add(buffer, numBytesRead);
63+
digestMd5 .add(buffer, numBytesRead);
6164
if (computeSha1)
62-
digestSha1 .add(buffer, numBytesRead);
63-
if (computeSha256)
64-
digestSha256 .add(buffer, numBytesRead);
65-
if (computeKeccak256)
66-
digestKeccak256.add(buffer, numBytesRead);
65+
digestSha1 .add(buffer, numBytesRead);
66+
if (computeSha2)
67+
digestSha2 .add(buffer, numBytesRead);
68+
if (computeKeccak)
69+
digestKeccak.add(buffer, numBytesRead);
70+
if (computeSha3)
71+
digestSha3 .add(buffer, numBytesRead);
6772
}
6873
file.close();
6974
delete[] buffer;
7075

7176
if (computeCrc32)
72-
std::cout << "CRC32: " << digestCrc32 .getHash() << std::endl;
77+
std::cout << "CRC32: " << digestCrc32 .getHash() << std::endl;
7378
if (computeMd5)
74-
std::cout << "MD5: " << digestMd5 .getHash() << std::endl;
79+
std::cout << "MD5: " << digestMd5 .getHash() << std::endl;
7580
if (computeSha1)
76-
std::cout << "SHA1: " << digestSha1 .getHash() << std::endl;
77-
if (computeSha256)
78-
std::cout << "SHA256: " << digestSha256 .getHash() << std::endl;
79-
if (computeKeccak256)
80-
std::cout << "Keccak256: " << digestKeccak256.getHash() << std::endl;
81+
std::cout << "SHA1: " << digestSha1 .getHash() << std::endl;
82+
if (computeSha2)
83+
std::cout << "SHA2/256: " << digestSha2 .getHash() << std::endl;
84+
if (computeKeccak)
85+
std::cout << "Keccak/256: " << digestKeccak.getHash() << std::endl;
86+
if (computeSha3)
87+
std::cout << "SHA3/256: " << digestSha3 .getHash() << std::endl;
8188

8289
return 0;
8390
}

keccak.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ std::string Keccak::getHash()
258258
}
259259

260260

261-
/// compute CRC32 of a memory block
261+
/// compute Keccak hash of a memory block
262262
std::string Keccak::operator()(const void* data, size_t numBytes)
263263
{
264264
reset();
@@ -267,7 +267,7 @@ std::string Keccak::operator()(const void* data, size_t numBytes)
267267
}
268268

269269

270-
/// compute CRC32 of a string, excluding final zero
270+
/// compute Keccak hash of a string, excluding final zero
271271
std::string Keccak::operator()(const std::string& text)
272272
{
273273
reset();

md5.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ namespace
6060
return (a << c) | (a >> (32 - c));
6161
}
6262

63+
#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
6364
inline uint32_t swap(uint32_t x)
6465
{
6566
#if defined(__GNUC__) || defined(__clang__)
@@ -74,6 +75,7 @@ namespace
7475
((x << 8) & 0x00FF0000) |
7576
(x << 24);
7677
}
78+
#endif
7779
}
7880

7981

sha3.cpp

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
// //////////////////////////////////////////////////////////
2+
// sha3.cpp
3+
// Copyright (c) 2014 Stephan Brumme. All rights reserved.
4+
// see http://create.stephan-brumme.com/disclaimer.html
5+
//
6+
7+
#include "sha3.h"
8+
9+
// big endian architectures need #define __BYTE_ORDER __BIG_ENDIAN
10+
#ifndef _MSC_VER
11+
#include <endian.h>
12+
#endif
13+
14+
15+
/// same as reset()
16+
SHA3::SHA3(Bits bits)
17+
: m_blockSize(200 - 2 * (bits / 8)),
18+
m_bits(bits)
19+
{
20+
reset();
21+
}
22+
23+
24+
/// restart
25+
void SHA3::reset()
26+
{
27+
for (size_t i = 0; i < StateSize; i++)
28+
m_hash[i] = 0;
29+
30+
m_numBytes = 0;
31+
m_bufferSize = 0;
32+
}
33+
34+
35+
/// constants and local helper functions
36+
namespace
37+
{
38+
const unsigned int Rounds = 24;
39+
const uint64_t XorMasks[Rounds] =
40+
{
41+
0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL,
42+
0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL,
43+
0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL,
44+
0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL,
45+
0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL,
46+
0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL,
47+
0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL,
48+
0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL
49+
};
50+
51+
/// rotate left and wrap around to the right
52+
inline uint64_t rotateLeft(uint64_t x, uint8_t numBits)
53+
{
54+
return (x << numBits) | (x >> (64 - numBits));
55+
}
56+
57+
/// convert litte vs big endian
58+
inline uint64_t swap(uint64_t x)
59+
{
60+
#if defined(__GNUC__) || defined(__clang__)
61+
return __builtin_bswap64(x);
62+
#endif
63+
#ifdef MSC_VER
64+
return _byteswap_uint64(x);
65+
#endif
66+
67+
return (x >> 56) |
68+
((x >> 40) & 0x000000000000FF00ULL) |
69+
((x >> 24) & 0x0000000000FF0000ULL) |
70+
((x >> 8) & 0x00000000FF000000ULL) |
71+
((x << 8) & 0x000000FF00000000ULL) |
72+
((x << 24) & 0x0000FF0000000000ULL) |
73+
((x << 40) & 0x00FF000000000000ULL) |
74+
(x << 56);
75+
}
76+
77+
78+
/// return x % 5 for 0 <= x <= 9
79+
unsigned int mod5(unsigned int x)
80+
{
81+
if (x < 5)
82+
return x;
83+
84+
return x - 5;
85+
}
86+
}
87+
88+
89+
/// process a full block
90+
void SHA3::processBlock(const void* data)
91+
{
92+
#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
93+
#define LITTLEENDIAN(x) swap(x)
94+
#else
95+
#define LITTLEENDIAN(x) (x)
96+
#endif
97+
98+
const uint64_t* data64 = (const uint64_t*) data;
99+
// mix data into state
100+
for (unsigned int i = 0; i < m_blockSize / 8; i++)
101+
m_hash[i] ^= LITTLEENDIAN(data64[i]);
102+
103+
// re-compute state
104+
for (unsigned int round = 0; round < Rounds; round++)
105+
{
106+
// Theta
107+
uint64_t coefficients[5];
108+
for (unsigned int i = 0; i < 5; i++)
109+
coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20];
110+
111+
for (unsigned int i = 0; i < 5; i++)
112+
{
113+
uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1);
114+
m_hash[i ] ^= one;
115+
m_hash[i + 5] ^= one;
116+
m_hash[i + 10] ^= one;
117+
m_hash[i + 15] ^= one;
118+
m_hash[i + 20] ^= one;
119+
}
120+
121+
// temporary
122+
uint64_t one;
123+
124+
// Rho Pi
125+
uint64_t last = m_hash[1];
126+
one = m_hash[10]; m_hash[10] = rotateLeft(last, 1); last = one;
127+
one = m_hash[ 7]; m_hash[ 7] = rotateLeft(last, 3); last = one;
128+
one = m_hash[11]; m_hash[11] = rotateLeft(last, 6); last = one;
129+
one = m_hash[17]; m_hash[17] = rotateLeft(last, 10); last = one;
130+
one = m_hash[18]; m_hash[18] = rotateLeft(last, 15); last = one;
131+
one = m_hash[ 3]; m_hash[ 3] = rotateLeft(last, 21); last = one;
132+
one = m_hash[ 5]; m_hash[ 5] = rotateLeft(last, 28); last = one;
133+
one = m_hash[16]; m_hash[16] = rotateLeft(last, 36); last = one;
134+
one = m_hash[ 8]; m_hash[ 8] = rotateLeft(last, 45); last = one;
135+
one = m_hash[21]; m_hash[21] = rotateLeft(last, 55); last = one;
136+
one = m_hash[24]; m_hash[24] = rotateLeft(last, 2); last = one;
137+
one = m_hash[ 4]; m_hash[ 4] = rotateLeft(last, 14); last = one;
138+
one = m_hash[15]; m_hash[15] = rotateLeft(last, 27); last = one;
139+
one = m_hash[23]; m_hash[23] = rotateLeft(last, 41); last = one;
140+
one = m_hash[19]; m_hash[19] = rotateLeft(last, 56); last = one;
141+
one = m_hash[13]; m_hash[13] = rotateLeft(last, 8); last = one;
142+
one = m_hash[12]; m_hash[12] = rotateLeft(last, 25); last = one;
143+
one = m_hash[ 2]; m_hash[ 2] = rotateLeft(last, 43); last = one;
144+
one = m_hash[20]; m_hash[20] = rotateLeft(last, 62); last = one;
145+
one = m_hash[14]; m_hash[14] = rotateLeft(last, 18); last = one;
146+
one = m_hash[22]; m_hash[22] = rotateLeft(last, 39); last = one;
147+
one = m_hash[ 9]; m_hash[ 9] = rotateLeft(last, 61); last = one;
148+
one = m_hash[ 6]; m_hash[ 6] = rotateLeft(last, 20); last = one;
149+
m_hash[ 1] = rotateLeft(last, 44);
150+
151+
// Chi
152+
for (unsigned int j = 0; j < 25; j += 5)
153+
{
154+
// temporaries
155+
uint64_t one = m_hash[j];
156+
uint64_t two = m_hash[j + 1];
157+
158+
m_hash[j] ^= m_hash[j + 2] & ~two;
159+
m_hash[j + 1] ^= m_hash[j + 3] & ~m_hash[j + 2];
160+
m_hash[j + 2] ^= m_hash[j + 4] & ~m_hash[j + 3];
161+
m_hash[j + 3] ^= one & ~m_hash[j + 4];
162+
m_hash[j + 4] ^= two & ~one;
163+
}
164+
165+
// Iota
166+
m_hash[0] ^= XorMasks[round];
167+
}
168+
}
169+
170+
171+
/// add arbitrary number of bytes
172+
void SHA3::add(const void* data, size_t numBytes)
173+
{
174+
const uint8_t* current = (const uint8_t*) data;
175+
176+
if (m_bufferSize > 0)
177+
{
178+
while (numBytes > 0 && m_bufferSize < m_blockSize)
179+
{
180+
m_buffer[m_bufferSize++] = *current++;
181+
numBytes--;
182+
}
183+
}
184+
185+
// full buffer
186+
if (m_bufferSize == m_blockSize)
187+
{
188+
processBlock((void*)m_buffer);
189+
m_numBytes += m_blockSize;
190+
m_bufferSize = 0;
191+
}
192+
193+
// no more data ?
194+
if (numBytes == 0)
195+
return;
196+
197+
// process full blocks
198+
while (numBytes >= m_blockSize)
199+
{
200+
processBlock(current);
201+
current += m_blockSize;
202+
m_numBytes += m_blockSize;
203+
numBytes -= m_blockSize;
204+
}
205+
206+
// keep remaining bytes in buffer
207+
while (numBytes > 0)
208+
{
209+
m_buffer[m_bufferSize++] = *current++;
210+
numBytes--;
211+
}
212+
}
213+
214+
215+
/// process everything left in the internal buffer
216+
void SHA3::processBuffer()
217+
{
218+
unsigned int blockSize = 200 - 2 * (m_bits / 8);
219+
220+
// add padding
221+
size_t offset = m_bufferSize;
222+
// add a "1" byte
223+
m_buffer[offset++] = 0x06;
224+
// fill with zeros
225+
while (offset < blockSize - 1)
226+
m_buffer[offset++] = 0;
227+
228+
// and add a single set bit
229+
m_buffer[blockSize - 1] = 0x80;
230+
231+
processBlock(m_buffer);
232+
}
233+
234+
235+
/// return latest hash as 16 hex characters
236+
std::string SHA3::getHash()
237+
{
238+
// process remaining bytes
239+
processBuffer();
240+
241+
// convert hash to string
242+
static const char dec2hex[16 + 1] = "0123456789abcdef";
243+
244+
// number of significant elements in hash (uint64_t)
245+
unsigned int hashLength = m_bits / 64;
246+
247+
std::string result;
248+
for (unsigned int i = 0; i < hashLength; i++)
249+
for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes
250+
{
251+
// convert a byte to hex
252+
unsigned char oneByte = (unsigned char) (m_hash[i] >> (8 * j));
253+
result += dec2hex[oneByte >> 4];
254+
result += dec2hex[oneByte & 15];
255+
}
256+
257+
return result;
258+
}
259+
260+
261+
/// compute SHA3 of a memory block
262+
std::string SHA3::operator()(const void* data, size_t numBytes)
263+
{
264+
reset();
265+
add(data, numBytes);
266+
return getHash();
267+
}
268+
269+
270+
/// compute SHA3 of a string, excluding final zero
271+
std::string SHA3::operator()(const std::string& text)
272+
{
273+
reset();
274+
add(text.c_str(), text.size());
275+
return getHash();
276+
}

0 commit comments

Comments
 (0)