summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/hashing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/hashing.cpp')
-rw-r--r--src/lib/util/hashing.cpp336
1 files changed, 276 insertions, 60 deletions
diff --git a/src/lib/util/hashing.cpp b/src/lib/util/hashing.cpp
index 448cdc5d6ec..3410389fdc8 100644
--- a/src/lib/util/hashing.cpp
+++ b/src/lib/util/hashing.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
+// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************
hashing.c
@@ -9,44 +9,115 @@
***************************************************************************/
#include "hashing.h"
+
+#include "strformat.h"
+
+#include "eminline.h"
+
#include <zlib.h>
+
+#include <algorithm>
#include <iomanip>
#include <sstream>
namespace util {
-//**************************************************************************
-// CONSTANTS
-//**************************************************************************
-
-const crc16_t crc16_t::null = { 0 };
-const crc32_t crc32_t::null = { 0 };
-const md5_t md5_t::null = { { 0 } };
-const sha1_t sha1_t::null = { { 0 } };
-
-
//**************************************************************************
// INLINE FUNCTIONS
//**************************************************************************
+namespace {
+
//-------------------------------------------------
// char_to_hex - return the hex value of a
// character
//-------------------------------------------------
-inline int char_to_hex(char c)
+constexpr int char_to_hex(char c)
{
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return 10 + c - 'a';
- if (c >= 'A' && c <= 'F')
- return 10 + c - 'A';
- return -1;
+ return
+ (c >= '0' && c <= '9') ? (c - '0') :
+ (c >= 'a' && c <= 'f') ? (10 + c - 'a') :
+ (c >= 'A' && c <= 'F') ? (10 + c - 'A') :
+ -1;
}
+inline uint32_t sha1_b(uint32_t *data, unsigned i) noexcept
+{
+ uint32_t r = data[(i + 13) & 15U];
+ r ^= data[(i + 8) & 15U];
+ r ^= data[(i + 2) & 15U];
+ r ^= data[i & 15U];
+ r = rotl_32(r, 1);
+ data[i & 15U] = r;
+ return r;
+}
+
+inline void sha1_r0(const uint32_t *data, std::array<uint32_t, 5> &d, unsigned i) noexcept
+{
+ d[i % 5] = d[i % 5] + ((d[(i + 3) % 5] & (d[(i + 2) % 5] ^ d[(i + 1) % 5])) ^ d[(i + 1) % 5]) + data[i] + 0x5a827999U + rotl_32(d[(i + 4) % 5], 5);
+ d[(i + 3) % 5] = rotl_32(d[(i + 3) % 5], 30);
+}
+
+inline void sha1_r1(uint32_t *data, std::array<uint32_t, 5> &d, unsigned i) noexcept
+{
+ d[i % 5] = d[i % 5] + ((d[(i + 3) % 5] & (d[(i + 2) % 5] ^ d[(i + 1) % 5])) ^ d[(i + 1) % 5])+ sha1_b(data, i) + 0x5a827999U + rotl_32(d[(i + 4) % 5], 5);
+ d[(i + 3) % 5] = rotl_32(d[(i + 3) % 5], 30);
+}
+
+inline void sha1_r2(uint32_t *data, std::array<uint32_t, 5> &d, unsigned i) noexcept
+{
+ d[i % 5] = d[i % 5] + (d[(i + 3) % 5] ^ d[(i + 2) % 5] ^ d[(i + 1) % 5]) + sha1_b(data, i) + 0x6ed9eba1U + rotl_32(d[(i + 4) % 5], 5);
+ d[(i + 3) % 5] = rotl_32(d[(i + 3) % 5], 30);
+}
+
+inline void sha1_r3(uint32_t *data, std::array<uint32_t, 5> &d, unsigned i) noexcept
+{
+ d[i % 5] = d[i % 5] + (((d[(i + 3) % 5] | d[(i + 2) % 5]) & d[(i + 1) % 5]) | (d[(i + 3) % 5] & d[(i + 2) % 5])) + sha1_b(data, i) + 0x8f1bbcdcU + rotl_32(d[(i + 4) % 5], 5);
+ d[(i + 3) % 5] = rotl_32(d[(i + 3) % 5], 30);
+}
+
+inline void sha1_r4(uint32_t *data, std::array<uint32_t, 5> &d, unsigned i) noexcept
+{
+ d[i % 5] = d[i % 5] + (d[(i + 3) % 5] ^ d[(i + 2) % 5] ^ d[(i + 1) % 5]) + sha1_b(data, i) + 0xca62c1d6U + rotl_32(d[(i + 4) % 5], 5);
+ d[(i + 3) % 5] = rotl_32(d[(i + 3) % 5], 30);
+}
+
+inline void sha1_process(std::array<uint32_t, 5> &st, uint32_t *data) noexcept
+{
+ std::array<uint32_t, 5> d = st;
+ unsigned i = 0U;
+ while (i < 16U)
+ sha1_r0(data, d, i++);
+ while (i < 20U)
+ sha1_r1(data, d, i++);
+ while (i < 40U)
+ sha1_r2(data, d, i++);
+ while (i < 60U)
+ sha1_r3(data, d, i++);
+ while (i < 80U)
+ sha1_r4(data, d, i++);
+ for (i = 0U; i < 5U; i++)
+ st[i] += d[i];
+}
+
+} // anonymous namespace
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+const crc16_t crc16_t::null = { 0 };
+const crc32_t crc32_t::null = { 0 };
+const md5_t md5_t::null = { { 0 } };
+const sha1_t sha1_t::null = { { 0 } };
+const sum16_t sum16_t::null = { 0 };
+
+
//**************************************************************************
// SHA-1 HELPERS
@@ -56,23 +127,22 @@ inline int char_to_hex(char c)
// from_string - convert from a string
//-------------------------------------------------
-bool sha1_t::from_string(const char *string, int length)
+bool sha1_t::from_string(std::string_view string) noexcept
{
// must be at least long enough to hold everything
- memset(m_raw, 0, sizeof(m_raw));
- if (length == -1)
- length = strlen(string);
- if (length < 2 * sizeof(m_raw))
+ std::fill(std::begin(m_raw), std::end(m_raw), 0);
+ if (string.length() < 2 * sizeof(m_raw))
return false;
// iterate through our raw buffer
- for (auto & elem : m_raw)
+ for (auto &elem : m_raw)
{
- int upper = char_to_hex(*string++);
- int lower = char_to_hex(*string++);
+ int const upper = char_to_hex(string[0]);
+ int const lower = char_to_hex(string[1]);
if (upper == -1 || lower == -1)
return false;
elem = (upper << 4) | lower;
+ string.remove_prefix(2);
}
return true;
}
@@ -84,15 +154,93 @@ bool sha1_t::from_string(const char *string, int length)
std::string sha1_t::as_string() const
{
- std::ostringstream buffer;
- buffer.fill('0');
- buffer << std::hex;
- for (auto & elem : m_raw)
- buffer << std::setw(2) << unsigned(elem);
- return buffer.str();
+ std::string result(2 * std::size(m_raw), ' ');
+ auto it = result.begin();
+ for (auto const &elem : m_raw)
+ {
+ auto const upper = elem >> 4;
+ auto const lower = elem & 0x0f;
+ *it++ = ((10 > upper) ? '0' : ('a' - 10)) + upper;
+ *it++ = ((10 > lower) ? '0' : ('a' - 10)) + lower;
+ }
+ return result;
+}
+
+
+//-------------------------------------------------
+// reset - prepare to digest a block of data
+//-------------------------------------------------
+
+void sha1_creator::reset() noexcept
+{
+ m_cnt = 0U;
+ m_st[0] = 0xc3d2e1f0U;
+ m_st[1] = 0x10325476U;
+ m_st[2] = 0x98badcfeU;
+ m_st[3] = 0xefcdab89U;
+ m_st[4] = 0x67452301U;
+}
+
+
+//-------------------------------------------------
+// append - digest a block of data
+//-------------------------------------------------
+
+void sha1_creator::append(const void *data, uint32_t length) noexcept
+{
+#ifdef LSB_FIRST
+ constexpr unsigned swizzle = 3U;
+#else
+ constexpr unsigned swizzle = 0U;
+#endif
+ uint32_t residual = (uint32_t(m_cnt) >> 3) & 63U;
+ m_cnt += uint64_t(length) << 3;
+ uint32_t offset = 0U;
+ if (length >= (64U - residual))
+ {
+ if (residual)
+ {
+ for (offset = 0U; (offset + residual) < 64U; offset++)
+ reinterpret_cast<uint8_t *>(m_buf)[(offset + residual) ^ swizzle] = reinterpret_cast<const uint8_t *>(data)[offset];
+ sha1_process(m_st, m_buf);
+ }
+ while ((length - offset) >= 64U)
+ {
+ for (residual = 0U; residual < 64U; residual++, offset++)
+ reinterpret_cast<uint8_t *>(m_buf)[residual ^ swizzle] = reinterpret_cast<const uint8_t *>(data)[offset];
+ sha1_process(m_st, m_buf);
+ }
+ residual = 0U;
+ }
+ for ( ; offset < length; residual++, offset++)
+ reinterpret_cast<uint8_t *>(m_buf)[residual ^ swizzle] = reinterpret_cast<const uint8_t *>(data)[offset];
+}
+
+
+//-------------------------------------------------
+// finish - compute final hash
+//-------------------------------------------------
+
+sha1_t sha1_creator::finish() noexcept
+{
+ const unsigned padlen = 64U - (63U & ((unsigned(m_cnt) >> 3) + 8U));
+ uint8_t padbuf[64];
+ padbuf[0] = 0x80;
+ for (unsigned i = 1U; i < padlen; i++)
+ padbuf[i] = 0x00;
+ uint8_t lenbuf[8];
+ for (unsigned i = 0U; i < 8U; i++)
+ lenbuf[i] = uint8_t(m_cnt >> ((7U - i) << 3));
+ append(padbuf, padlen);
+ append(lenbuf, sizeof(lenbuf));
+ sha1_t result;
+ for (unsigned i = 0U; i < 20U; i++)
+ result.m_raw[i] = uint8_t(m_st[4U - (i >> 2)] >> ((3U - (i & 3)) << 3));
+ return result;
}
+
//**************************************************************************
// MD-5 HELPERS
//**************************************************************************
@@ -101,23 +249,22 @@ std::string sha1_t::as_string() const
// from_string - convert from a string
//-------------------------------------------------
-bool md5_t::from_string(const char *string, int length)
+bool md5_t::from_string(std::string_view string) noexcept
{
// must be at least long enough to hold everything
- memset(m_raw, 0, sizeof(m_raw));
- if (length == -1)
- length = strlen(string);
- if (length < 2 * sizeof(m_raw))
+ std::fill(std::begin(m_raw), std::end(m_raw), 0);
+ if (string.length() < 2 * sizeof(m_raw))
return false;
// iterate through our raw buffer
- for (auto & elem : m_raw)
+ for (auto &elem : m_raw)
{
- int upper = char_to_hex(*string++);
- int lower = char_to_hex(*string++);
+ int const upper = char_to_hex(string[0]);
+ int const lower = char_to_hex(string[1]);
if (upper == -1 || lower == -1)
return false;
elem = (upper << 4) | lower;
+ string.remove_prefix(2);
}
return true;
}
@@ -129,12 +276,16 @@ bool md5_t::from_string(const char *string, int length)
std::string md5_t::as_string() const
{
- std::ostringstream buffer;
- buffer.fill('0');
- buffer << std::hex;
- for (auto & elem : m_raw)
- buffer << std::setw(2) << unsigned(elem);
- return buffer.str();
+ std::string result(2 * std::size(m_raw), ' ');
+ auto it = result.begin();
+ for (auto const &elem : m_raw)
+ {
+ auto const upper = elem >> 4;
+ auto const lower = elem & 0x0f;
+ *it++ = ((10 > upper) ? '0' : ('a' - 10)) + upper;
+ *it++ = ((10 > lower) ? '0' : ('a' - 10)) + lower;
+ }
+ return result;
}
@@ -147,23 +298,22 @@ std::string md5_t::as_string() const
// from_string - convert from a string
//-------------------------------------------------
-bool crc32_t::from_string(const char *string, int length)
+bool crc32_t::from_string(std::string_view string) noexcept
{
// must be at least long enough to hold everything
m_raw = 0;
- if (length == -1)
- length = strlen(string);
- if (length < 2 * sizeof(m_raw))
+ if (string.length() < (2 * sizeof(m_raw)))
return false;
// iterate through our raw buffer
m_raw = 0;
for (int bytenum = 0; bytenum < sizeof(m_raw) * 2; bytenum++)
{
- int nibble = char_to_hex(*string++);
+ int const nibble = char_to_hex(string[0]);
if (nibble == -1)
return false;
m_raw = (m_raw << 4) | nibble;
+ string.remove_prefix(1);
}
return true;
}
@@ -184,7 +334,7 @@ std::string crc32_t::as_string() const
// the currently-accumulated value
//-------------------------------------------------
-void crc32_creator::append(const void *data, uint32_t length)
+void crc32_creator::append(const void *data, uint32_t length) noexcept
{
m_accum.m_raw = crc32(m_accum, reinterpret_cast<const Bytef *>(data), length);
}
@@ -199,23 +349,22 @@ void crc32_creator::append(const void *data, uint32_t length)
// from_string - convert from a string
//-------------------------------------------------
-bool crc16_t::from_string(const char *string, int length)
+bool crc16_t::from_string(std::string_view string) noexcept
{
// must be at least long enough to hold everything
m_raw = 0;
- if (length == -1)
- length = strlen(string);
- if (length < 2 * sizeof(m_raw))
+ if (string.length() < (2 * sizeof(m_raw)))
return false;
// iterate through our raw buffer
m_raw = 0;
for (int bytenum = 0; bytenum < sizeof(m_raw) * 2; bytenum++)
{
- int nibble = char_to_hex(*string++);
+ int const nibble = char_to_hex(string[0]);
if (nibble == -1)
return false;
m_raw = (m_raw << 4) | nibble;
+ string.remove_prefix(1);
}
return true;
}
@@ -246,7 +395,7 @@ std::string crc16_t::as_string() const
* @param length The length.
*/
-void crc16_creator::append(const void *data, uint32_t length)
+void crc16_creator::append(const void *data, uint32_t length) noexcept
{
static const uint16_t s_table[256] =
{
@@ -284,7 +433,7 @@ void crc16_creator::append(const void *data, uint32_t length)
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
- const uint8_t *src = reinterpret_cast<const uint8_t *>(data);
+ const auto *src = reinterpret_cast<const uint8_t *>(data);
// fetch the current value into a local and rip through the source data
uint16_t crc = m_accum.m_raw;
@@ -293,4 +442,71 @@ void crc16_creator::append(const void *data, uint32_t length)
m_accum.m_raw = crc;
}
+
+
+//**************************************************************************
+// SUM-16 HELPERS
+//**************************************************************************
+
+//-------------------------------------------------
+// from_string - convert from a string
+//-------------------------------------------------
+
+bool sum16_t::from_string(std::string_view string) noexcept
+{
+ // must be at least long enough to hold everything
+ m_raw = 0;
+ if (string.length() < (2 * sizeof(m_raw)))
+ return false;
+
+ // iterate through our raw buffer
+ m_raw = 0;
+ for (int bytenum = 0; bytenum < sizeof(m_raw) * 2; bytenum++)
+ {
+ int const nibble = char_to_hex(string[0]);
+ if (nibble == -1)
+ return false;
+ m_raw = (m_raw << 4) | nibble;
+ string.remove_prefix(1);
+ }
+ return true;
+}
+
+/**
+ * @fn std::string sum16_t::as_string() const
+ *
+ * @brief -------------------------------------------------
+ * as_string - convert to a string
+ * -------------------------------------------------.
+ *
+ * @return a std::string.
+ */
+
+std::string sum16_t::as_string() const
+{
+ return string_format("%04x", m_raw);
+}
+
+/**
+ * @fn void sum16_creator::append(const void *data, uint32_t length)
+ *
+ * @brief -------------------------------------------------
+ * append - sum a block of data, appending to the currently-accumulated value
+ * -------------------------------------------------.
+ *
+ * @param data The data.
+ * @param length The length.
+ */
+
+void sum16_creator::append(const void *data, uint32_t length) noexcept
+{
+ const auto *src = reinterpret_cast<const uint8_t *>(data);
+
+ // fetch the current value into a local and rip through the source data
+ uint16_t sum = m_accum.m_raw;
+ while (length-- != 0)
+ sum += *src++;
+ m_accum.m_raw = sum;
+}
+
} // namespace util