diff --git a/src/impl/algorithm.inc b/src/impl/algorithm.inc index 023f036..c320099 100644 --- a/src/impl/algorithm.inc +++ b/src/impl/algorithm.inc @@ -33,27 +33,15 @@ #define MD5_UPDATE \ MD5_ROUND(MD5_FF) MD5_ROUND(MD5_GG) MD5_ROUND(MD5_HH) MD5_ROUND(MD5_II) -#include "sine.inc" +#include "value.inc" namespace md5::impl { -/// Hexadecimal character mapping table. -constexpr char HexTable[] = { - '0','1','2','3','4','5','6','7', - '8','9','a','b','c','d','e','f', -}; - -/// MD5 fixed constants in little endian. -constexpr uint32_t MD5_A = 0x67452301; -constexpr uint32_t MD5_B = 0xefcdab89; -constexpr uint32_t MD5_C = 0x98badcfe; -constexpr uint32_t MD5_D = 0x10325476; - struct md5_ctx { - uint32_t A = MD5_A; - uint32_t B = MD5_B; - uint32_t C = MD5_C; - uint32_t D = MD5_D; + uint32_t A = value::kA; + uint32_t B = value::kB; + uint32_t C = value::kC; + uint32_t D = value::kD; uint64_t size = 0; // processed size in byte }; @@ -77,8 +65,11 @@ constexpr int S(const int i) { /// MD5 T-table constant, input between 0 and 63. constexpr uint32_t T(const int i) { - const auto val = ::md5::math::sin(i + 1); - return static_cast(::md5::math::abs(val) * 0x100000000); + return value::kT[i]; } +static_assert(K(0) != K(63), "invalid constexpr"); +static_assert(S(0) != S(63), "invalid constexpr"); +static_assert(T(0) != T(63), "invalid constexpr"); + } // namespace md5::impl diff --git a/src/impl/constexpr.inc b/src/impl/constexpr.inc index a04f04c..7ff5f1a 100644 --- a/src/impl/constexpr.inc +++ b/src/impl/constexpr.inc @@ -1,26 +1,24 @@ #pragma once -#include - namespace md5::impl { struct md5_ctx_ce { - uint32_t A = MD5_A; - uint32_t B = MD5_B; - uint32_t C = MD5_C; - uint32_t D = MD5_D; + uint32_t A = value::kA; + uint32_t B = value::kB; + uint32_t C = value::kC; + uint32_t D = value::kD; const char *data; uint64_t data_len, padded_len; - constexpr md5_ctx_ce(const char *data, uint64_t len) + constexpr md5_ctx_ce(const char *data, const uint64_t len) : data(data), data_len(len), padded_len((len + 64 + 8) & ~0b111111ULL) {} }; using Block = std::array; // single md5 block with 64 bytes /// Get the data and padding byte of the specified index. -constexpr uint8_t GetByte(md5_ctx_ce *ctx, const uint64_t index) { +constexpr uint8_t GetByte(const md5_ctx_ce *ctx, const uint64_t index) { if (index < ctx->data_len) // message data return ctx->data[index]; if (index == ctx->data_len) // padding flag @@ -32,10 +30,10 @@ constexpr uint8_t GetByte(md5_ctx_ce *ctx, const uint64_t index) { } /// Get the MD5 block content at the specified index. -constexpr Block GetBlock(md5_ctx_ce *ctx, const uint64_t index) { +constexpr Block GetBlock(const md5_ctx_ce *ctx, const uint64_t index) { Block block {}; for (int i = 0; i < 16; ++i) { - auto offset = index + i * 4; + const auto offset = index + i * 4; (block[i] <<= 8) |= GetByte(ctx, offset + 3); (block[i] <<= 8) |= GetByte(ctx, offset + 2); (block[i] <<= 8) |= GetByte(ctx, offset + 1); @@ -45,13 +43,13 @@ constexpr Block GetBlock(md5_ctx_ce *ctx, const uint64_t index) { } /// Convert origin MD5 integers to hexadecimal character array. -constexpr std::array DigestCE(std::array ctx) { +constexpr std::array DigestCE(const std::array &ctx) { std::array result {}; for (uint32_t i = 0, val = 0; i < 32; val >>= 8) { if (!(i & 0b111)) val = ctx[i >> 3]; - result[i++] = HexTable[(val >> 4) & 0b1111]; - result[i++] = HexTable[val & 0b1111]; + result[i++] = value::HexTable[(val >> 4) & 0b1111]; + result[i++] = value::HexTable[val & 0b1111]; } return result; } @@ -73,4 +71,6 @@ constexpr std::array MD5::HashCE(const char *data, uint64_t len) { return DigestCE({ctx.A, ctx.B, ctx.C, ctx.D}); } +static_assert(MD5::HashCE("")[0] == 'd', "invalid constexpr"); + } // namespace md5::impl diff --git a/src/impl/core.cc b/src/impl/core.cc index 1f2d286..53db601 100644 --- a/src/impl/core.cc +++ b/src/impl/core.cc @@ -33,7 +33,7 @@ const void* MD5::UpdateImpl(const void *data, uint64_t len) { ctx_.C = C; ctx_.D = D; ctx_.size += len; - return static_cast(limit); + return limit; } void MD5::FinalImpl(const void *data, uint64_t len) { @@ -44,7 +44,7 @@ void MD5::FinalImpl(const void *data, uint64_t len) { unsigned char buffer[128]; // 2 blocks ::std::memcpy(buffer, data, len); - uint64_t total = (ctx_.size + len) << 3; // total number in bit + const uint64_t total = (ctx_.size + len) << 3; // total number in bit if (len < 56) { // len -> [0, 56) ::std::memcpy(buffer + len, Padding, 56 - len); diff --git a/src/impl/inline.inc b/src/impl/inline.inc index e1d725f..1329747 100644 --- a/src/impl/inline.inc +++ b/src/impl/inline.inc @@ -3,10 +3,10 @@ namespace md5::impl { inline MD5& MD5::Reset() { - ctx_.A = MD5_A; - ctx_.B = MD5_B; - ctx_.C = MD5_C; - ctx_.D = MD5_D; + ctx_.A = value::kA; + ctx_.B = value::kB; + ctx_.C = value::kC; + ctx_.D = value::kD; ctx_.size = 0; buffer_size_ = 0; return *this; @@ -25,7 +25,7 @@ inline std::string MD5::Hash(const std::string_view &data) { return Hash(data.data(), data.size()); } -inline std::string MD5::Hash(const void *data, uint64_t len) { +inline std::string MD5::Hash(const void *data, const uint64_t len) { MD5 md5; md5.FinalImpl(data, len); return md5.Digest(); diff --git a/src/impl/value.inc b/src/impl/value.inc new file mode 100644 index 0000000..467030d --- /dev/null +++ b/src/impl/value.inc @@ -0,0 +1,48 @@ +#pragma once + +#include "sine.inc" + +namespace md5::value { + +/// Hexadecimal character mapping table. +constexpr char HexTable[] = { + '0','1','2','3','4','5','6','7', + '8','9','a','b','c','d','e','f', +}; + +/// MD5 fixed constants in little endian. +constexpr uint32_t kA = 0x67452301; +constexpr uint32_t kB = 0xefcdab89; +constexpr uint32_t kC = 0x98badcfe; +constexpr uint32_t kD = 0x10325476; + +// In order to be compatible with C++17, the `consteval` keyword cannot be used +// here. The MD5 T-table constants will be macro-expanded and calculated. + +constexpr uint32_t TCal(const int i) { + const auto val = math::sin(i + 1); + return static_cast(math::abs(val) * 0x100000000); +} + +#define MD5_TT \ + MD5_T(00) MD5_T(01) MD5_T(02) MD5_T(03) MD5_T(04) MD5_T(05) MD5_T(06) MD5_T(07) \ + MD5_T(08) MD5_T(09) MD5_T(0a) MD5_T(0b) MD5_T(0c) MD5_T(0d) MD5_T(0e) MD5_T(0f) \ + MD5_T(10) MD5_T(11) MD5_T(12) MD5_T(13) MD5_T(14) MD5_T(15) MD5_T(16) MD5_T(17) \ + MD5_T(18) MD5_T(19) MD5_T(1a) MD5_T(1b) MD5_T(1c) MD5_T(1d) MD5_T(1e) MD5_T(1f) \ + MD5_T(20) MD5_T(21) MD5_T(22) MD5_T(23) MD5_T(24) MD5_T(25) MD5_T(26) MD5_T(27) \ + MD5_T(28) MD5_T(29) MD5_T(2a) MD5_T(2b) MD5_T(2c) MD5_T(2d) MD5_T(2e) MD5_T(2f) \ + MD5_T(30) MD5_T(31) MD5_T(32) MD5_T(33) MD5_T(34) MD5_T(35) MD5_T(36) MD5_T(37) \ + MD5_T(38) MD5_T(39) MD5_T(3a) MD5_T(3b) MD5_T(3c) MD5_T(3d) MD5_T(3e) MD5_T(3f) + +#define MD5_T(x) constexpr auto kT_##x = TCal(0x##x); +MD5_TT +#undef MD5_T + +#define MD5_T(x) kT_##x, +/// MD5 T-table constant array. +constexpr std::array kT = {MD5_TT}; +#undef MD5_T + +#undef MD5_TT + +} // namespace md5::value diff --git a/src/impl/wrapper.cc b/src/impl/wrapper.cc index 6995e4c..33cd814 100644 --- a/src/impl/wrapper.cc +++ b/src/impl/wrapper.cc @@ -8,8 +8,8 @@ std::string MD5::Digest() const { std::string result(32, 0x00); auto *ptr = reinterpret_cast(&ctx_); for (int i = 0; i < 32; ++ptr) { - result[i++] = HexTable[*ptr >> 4]; - result[i++] = HexTable[*ptr & 0b1111]; + result[i++] = value::HexTable[*ptr >> 4]; + result[i++] = value::HexTable[*ptr & 0b1111]; } return result; } @@ -22,7 +22,7 @@ MD5& MD5::Update(const void *data, uint64_t len) { return *this; // save into buffer and return } - auto size = 64 - buffer_size_; + const auto size = 64 - buffer_size_; ::std::memcpy(buffer_ + buffer_size_, data, size); UpdateImpl(buffer_, 64); // fill and update with buffer data = static_cast(data) + size;