CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
HashTest.cpp
Go to the documentation of this file.
1
5// //////////////////////////////////////////////////////////
6// hash/HashTest.cpp
7// Unit test for the hash library (md5, sha1, sha256, crc32, sha3, keccak).
8// Uses published known-answer test vectors.
9//
10
11#include "hash/HashTest.h"
12
13#include "hash/md5.h"
14#include "hash/sha1.h"
15#include "hash/sha256.h"
16#include "hash/crc32.h"
17#include "hash/sha3.h"
18#include "hash/keccak.h"
19
20#include "PsyTime.h"
21#include "UnitTestFramework.h"
22
23#include <string>
24#include <cctype>
25#include <cstring>
26#include <vector>
27
28namespace cmlabs {
29
30// Lower-case a hex digest so comparisons are case-insensitive.
31static std::string ToLowerHex(const std::string& s) {
32 std::string out(s);
33 for (size_t i = 0; i < out.size(); i++)
34 out[i] = (char)std::tolower((unsigned char)out[i]);
35 return out;
36}
37
38// Compare a produced hex digest against the expected value (case-insensitive).
39// On mismatch sets the failure reason (with algo name + expected/got) and
40// returns false.
41static bool CheckHex(const char* algo, const char* input,
42 const std::string& got, const char* expected) {
43 if (ToLowerHex(got) != ToLowerHex(expected)) {
44 unittest::fail("%s(\"%s\"): expected %s, got %s",
45 algo, input, expected, got.c_str());
46 return false;
47 }
48 unittest::detail("%s(\"%s\") = %s", algo, input, got.c_str());
49 return true;
50}
51
53 unittest::progress(0, "start");
54
55 // ---- MD5 known-answer vectors (RFC 1321) ----
56 unittest::progress(10, "md5");
57 {
58 hash::MD5 md5;
59 if (!CheckHex("MD5", "", md5(""),
60 "d41d8cd98f00b204e9800998ecf8427e")) return false;
61 if (!CheckHex("MD5", "abc", md5("abc"),
62 "900150983cd24fb0d6963f7d28e17f72")) return false;
63 if (!CheckHex("MD5", "message digest", md5("message digest"),
64 "f96b697d7cb7938d525a2f31aaf161d0")) return false;
65
66 // Streaming add() must match the one-shot result.
67 hash::MD5 s;
68 s.add("ab", 2);
69 s.add("c", 1);
70 if (!CheckHex("MD5-stream", "abc", s.getHash(),
71 "900150983cd24fb0d6963f7d28e17f72")) return false;
72 }
73
74 // ---- SHA1 known-answer vectors (FIPS 180-2) ----
75 unittest::progress(25, "sha1");
76 {
77 hash::SHA1 sha1;
78 if (!CheckHex("SHA1", "", sha1(""),
79 "da39a3ee5e6b4b0d3255bfef95601890afd80709")) return false;
80 if (!CheckHex("SHA1", "abc", sha1("abc"),
81 "a9993e364706816aba3e25717850c26c9cd0d89d")) return false;
82 if (!CheckHex("SHA1",
83 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
84 sha1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"),
85 "84983e441c3bd26ebaae4aa1f95129e5e54670f1")) return false;
86
87 // getHashRaw() should be HashBytes raw bytes matching the hex digest.
88 hash::SHA1 r;
89 r.add("abc", 3);
90 std::string raw = r.getHashRaw();
91 if (raw.size() != (size_t)hash::SHA1::HashBytes) {
92 unittest::fail("SHA1 getHashRaw size: expected %d, got %zu",
93 (int)hash::SHA1::HashBytes, raw.size());
94 return false;
95 }
96 }
97
98 // ---- SHA256 known-answer vectors (FIPS 180-2) ----
99 unittest::progress(40, "sha256");
100 {
101 hash::SHA256 sha256;
102 if (!CheckHex("SHA256", "",
103 sha256(""),
104 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"))
105 return false;
106 if (!CheckHex("SHA256", "abc",
107 sha256("abc"),
108 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"))
109 return false;
110 }
111
112 // ---- CRC32 known-answer vector ----
113 // CRC32("123456789") == 0xCBF43926; getHash() returns 8 hex chars.
114 unittest::progress(55, "crc32");
115 {
116 hash::CRC32 crc;
117 if (!CheckHex("CRC32", "123456789", crc("123456789"),
118 "cbf43926")) return false;
119
120 // Verify the raw-byte accessor agrees with the hex digest (big-endian).
121 hash::CRC32 c2;
122 c2.add("123456789", 9);
123 unsigned char buf[hash::CRC32::HashBytes];
124 c2.getHash(buf);
125 uint32 val = ((uint32)buf[0] << 24) | ((uint32)buf[1] << 16) |
126 ((uint32)buf[2] << 8) | (uint32)buf[3];
127 if (val != 0xCBF43926u) {
128 unittest::fail("CRC32 raw bytes: expected 0xCBF43926, got 0x%08X", val);
129 return false;
130 }
131 }
132
133 // ---- SHA3-256 known-answer vector ----
134 unittest::progress(68, "sha3");
135 {
137 if (!CheckHex("SHA3-256", "",
138 sha3(""),
139 "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a"))
140 return false;
142 if (!CheckHex("SHA3-256", "abc",
143 sha3b("abc"),
144 "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"))
145 return false;
146 }
147
148 // ---- Keccak-256 known-answer vector (pre-NIST padding) ----
149 unittest::progress(80, "keccak");
150 {
152 if (!CheckHex("Keccak-256", "",
153 keccak(""),
154 "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"))
155 return false;
157 if (!CheckHex("Keccak-256", "abc",
158 keccakb("abc"),
159 "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45"))
160 return false;
161 }
162
163 // ---- Throughput metric: hash a sizeable buffer with SHA256 ----
164 unittest::progress(90, "throughput");
165 {
166 const size_t bufSize = 64 * 1024; // 64 KB block
167 const int iters = 256; // 16 MB total
168 std::vector<unsigned char> buf(bufSize);
169 for (size_t i = 0; i < bufSize; i++)
170 buf[i] = (unsigned char)(i * 31 + 7);
171
172 uint64 t0 = GetTimeNow();
173 hash::SHA256 sha;
174 for (int i = 0; i < iters; i++)
175 sha.add(&buf[0], bufSize);
176 std::string digest = sha.getHash(); // force completion
177 double us = (double)(GetTimeNow() - t0);
178 if (us <= 0.0) us = 1.0;
179 double totalBytes = (double)bufSize * (double)iters;
180 double mbps = (totalBytes / (1024.0 * 1024.0)) / (us / 1e6);
181 unittest::metric("sha256_throughput", mbps, "MB/s", true);
182 unittest::detail("SHA256 hashed %.0f bytes in %.0f us -> %s",
183 totalBytes, us, digest.c_str());
184 }
185
186 unittest::progress(100, "done");
187 return true;
188}
189
192 "Hash library: MD5/SHA1/SHA256/CRC32/SHA3/Keccak known-answer vectors", "util");
193}
194
195} // namespace cmlabs
CMSDK unit test entry point for the vendored hash library (md5, sha1, sha256, crc32,...
CMSDK time: µs-resolution 64-bit timestamps and the Time Mapping Constant (TMC).
Small, dependency-free unit test harness used by all CMSDK object tests.
static UnitTestRunner & instance()
Access the singleton (created on first use).
void registerTest(const char *name, UnitTestFunc func, const char *description="", const char *category="", bool inDefaultRun=true)
Register a test with the runner.
compute CRC32 hash, based on Intel's Slicing-by-8 algorithm
Definition crc32.h:49
std::string getHash()
return latest hash as 8 hex characters
void add(const void *data, size_t numBytes)
add arbitrary number of bytes
@ HashBytes
Definition crc32.h:52
compute Keccak hash (designated SHA3)
Definition keccak.h:44
compute MD5 hash
Definition md5.h:45
void add(const void *data, size_t numBytes)
add arbitrary number of bytes
std::string getHash()
return latest hash as 32 hex characters
compute SHA1 hash
Definition sha1.h:45
std::string getHashRaw()
return latest hash as raw characters
void add(const void *data, size_t numBytes)
add arbitrary number of bytes
@ HashBytes
Definition sha1.h:48
compute SHA256 hash
Definition sha256.h:45
std::string getHash()
return latest hash as 64 hex characters
void add(const void *data, size_t numBytes)
add arbitrary number of bytes
compute SHA3 hash
Definition sha3.h:44
@ Bits256
Definition sha3.h:47
Third-party (vendored): CRC32 checksum from Stephan Brumme's portable hashing library (create....
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
Definition PsyTime.cpp:69
Third-party (vendored): Keccak (pre-standard SHA-3) hash from Stephan Brumme's portable hashing libra...
Third-party (vendored): MD5 hash from Stephan Brumme's portable hashing library (create....
void fail(const char *fmt,...)
Set an explanatory reason shown on the FAIL line.
void metric(const char *name, double value, const char *unit="", bool higherIsBetter=true)
Record a performance metric.
void detail(const char *fmt,...)
Verbose-only indented diagnostic line (shown only when verbose=1).
void progress(int percent, const char *action)
Report progress with a short description of the current action.
static std::string ToLowerHex(const std::string &s)
Definition HashTest.cpp:31
static bool CheckHex(const char *algo, const char *input, const std::string &got, const char *expected)
Definition HashTest.cpp:41
void Register_Hash_Tests()
Definition HashTest.cpp:190
bool Hash_UnitTest()
Exercise the hash classes against known test vectors.
Definition HashTest.cpp:52
Third-party (vendored): SHA-1 hash from Stephan Brumme's portable hashing library (create....
Third-party (vendored): SHA-256 hash from Stephan Brumme's portable hashing library (create....
Third-party (vendored): SHA-3 hash from Stephan Brumme's portable hashing library (create....