From 5a25f07f8e5c7adc1a18d8f16f29a29ed4125166 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 25 Jan 2017 16:12:12 +1100 Subject: [PATCH] hash/crc: adapt implementation from png appendix --- CMakeLists.txt | 1 + hash/crc.cpp | 91 ++++++++++++++++++++++++++++------------------- hash/crc.hpp | 7 +++- test/hash/crc.cpp | 40 +++++++++++++++++++++ 4 files changed, 101 insertions(+), 38 deletions(-) create mode 100644 test/hash/crc.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dc3ebf3..f37f0ed9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -464,6 +464,7 @@ if (TESTS) geom/aabb geom/ray hash/checksum + hash/crc hash/fasthash hash/hmac hash/hotp diff --git a/hash/crc.cpp b/hash/crc.cpp index 436771d7..8bc7b27b 100644 --- a/hash/crc.cpp +++ b/hash/crc.cpp @@ -18,13 +18,53 @@ #include "../debug.hpp" +#include + using util::hash::crc32; /////////////////////////////////////////////////////////////////////////////// +static +std::array +make_table (void) +{ + std::array value {}; + + for (int i = 0; i < 256; ++i) { + std::uint32_t c = i; + + for (int k = 0; k < 8; ++k) { + if (c & 1) + c = 0xEDB88320L ^ (c >> 1); + else + c >>= 1; + } + + value[i] = c; + } + + return value; +}; + + +//----------------------------------------------------------------------------- +static std::array table = make_table (); + + +/////////////////////////////////////////////////////////////////////////////// +crc32::crc32 () noexcept +{ + reset (); +} + + +//----------------------------------------------------------------------------- void -crc32::reset (void) -{ ; } +crc32::reset (void) noexcept +{ + m_digest = 0; + m_digest = ~m_digest; +} /////////////////////////////////////////////////////////////////////////////// @@ -34,55 +74,32 @@ crc32::update (const uint8_t *restrict first, { CHECK_LE (first, last); - return update (first, last - first); + for (auto cursor = first; cursor != last; ++cursor) { + m_digest = table[*cursor ^ (m_digest & 0xFF)] ^ (m_digest >> 8u); + } } //----------------------------------------------------------------------------- void -crc32::update (const void *restrict, size_t) noexcept +crc32::update (const void *restrict _data, size_t len) noexcept { - not_implemented (); - - /* - const uint8_t *restrict data = static_cast (_data); - static const uint32_t POLYNOMIAL = hton (static_cast(0x04C11DB7)); - - uint64_t bits = 0; - unsigned int i = 0; - - if (size == 0) - return POLYNOMIAL; - - switch (size) { - default: bits |= static_cast(data[3]) << 32U; - case 3: bits |= static_cast(data[2]) << 40U; - case 2: bits |= static_cast(data[1]) << 48U; - case 1: bits |= static_cast(data[0]) << 56U; - } - - for (size_t i = 0; i < size; ++i) { - for (unsigned j = 0; j < 32; ++j) { - bool mix = bits 0x7000000000000000ULL; - bits <<= 1; - - if (mix) - bits ^= POLYNOMIAL << 32; - } - - - } - */ + auto data = reinterpret_cast (_data); + return update(data, data + len); } //----------------------------------------------------------------------------- void crc32::finish (void) -{ not_implemented (); } +{ + ; +} //----------------------------------------------------------------------------- typename crc32::digest_t crc32::digest (void) const -{ not_implemented (); } +{ + return ~m_digest; +} \ No newline at end of file diff --git a/hash/crc.hpp b/hash/crc.hpp index 06106a80..4cf718f5 100644 --- a/hash/crc.hpp +++ b/hash/crc.hpp @@ -27,7 +27,9 @@ namespace util::hash { public: using digest_t = uint32_t; - void reset (void); + crc32 () noexcept; + + void reset (void) noexcept; void update (const void *restrict data, size_t bytes) noexcept; void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept; @@ -35,6 +37,9 @@ namespace util::hash { void finish (void); digest_t digest (void) const; + + private: + digest_t m_digest; }; } diff --git a/test/hash/crc.cpp b/test/hash/crc.cpp new file mode 100644 index 00000000..b6cd8cf6 --- /dev/null +++ b/test/hash/crc.cpp @@ -0,0 +1,40 @@ +#include "tap.hpp" +#include "hash/crc.hpp" +#include "hash/simple.hpp" + +#include +#include +#include + + +/////////////////////////////////////////////////////////////////////////////// +static const +struct { + uint32_t result; + const char *dat; + const char *msg; +} TESTS[] = { + { 0x00000000, "", "empty" }, + { 0xe8b7be43, "a", "single letter" }, + { 0xa684c7c6, "0123456789", "10 digits" }, + { 0x414fa339, "The quick brown fox jumps over the lazy dog", "quick brown fox" }, +}; + + +/////////////////////////////////////////////////////////////////////////////// +int +main (int, char**) +{ + util::TAP::logger tap; + + for (const auto &t: TESTS) { + auto first = t.dat; + auto last = first + strlen (t.dat); + + auto result = util::hash::simple (first, last); + + tap.expect_eq (t.result, result, "%s %xu", t.msg, result); + } + + return tap.status (); +} \ No newline at end of file