Browse Source

update: fixes and improvements

master
Dnomd343 6 months ago
parent
commit
7d3df6bd91
  1. 9
      benchmark.cc
  2. 37
      src/core.cc
  3. 27
      src/md5.h
  4. 34
      src/md5.inc
  5. 66
      src/wrapper.cc

9
benchmark.cc

@ -20,6 +20,15 @@ static void MD5_Update(benchmark::State &state) {
} }
} }
static void MD5_Digest(benchmark::State &state) {
md5::MD5 kk;
for (auto _ : state) {
auto pp = kk.Digest();
}
}
BENCHMARK(MD5_Update); BENCHMARK(MD5_Update);
BENCHMARK(MD5_Digest);
BENCHMARK_MAIN(); BENCHMARK_MAIN();

37
src/core.cc

@ -58,13 +58,13 @@ consteval uint32_t T(int index) { // index -> [0, 64)
return static_cast<uint32_t>(std::abs(val) * 0x100000000); return static_cast<uint32_t>(std::abs(val) * 0x100000000);
} }
void MD5::md5_update(md5_ctx *ctx, const void *data, uint64_t len) { const void* MD5::UpdateImpl(const void *data, uint64_t len) {
auto *block = reinterpret_cast<const uint32_t *>(data); auto *block = static_cast<const uint32_t *>(data);
auto *limit = block + (len >> 2); auto *limit = block + ((len &= ~0b111111ULL) >> 2);
auto A = ctx->A; auto A = ctx_.A;
auto B = ctx->B; auto B = ctx_.B;
auto C = ctx->C; auto C = ctx_.C;
auto D = ctx->D; auto D = ctx_.D;
while (block < limit) { while (block < limit) {
auto A_ = A; auto A_ = A;
@ -82,33 +82,32 @@ void MD5::md5_update(md5_ctx *ctx, const void *data, uint64_t len) {
block += 16; // move to next block block += 16; // move to next block
} }
ctx->A = A; ctx_.A = A;
ctx->B = B; ctx_.B = B;
ctx->C = C; ctx_.C = C;
ctx->D = D; ctx_.D = D;
ctx->size += len; ctx_.size += len;
return static_cast<const void *>(limit);
} }
void MD5::md5_final(md5_ctx *ctx, const void *data, uint64_t len) { void MD5::FinalImpl(const void *data, uint64_t len) {
if (len >= 120) { // len -> [64 + 56, INF) if (len >= 120) { // len -> [64 + 56, INF)
auto size = len & ~(uint64_t)0b111111; data = UpdateImpl(data, len);
md5_update(ctx, data, size);
data = reinterpret_cast<const char*>(data) + size;
len &= 0b111111; // len -> [0, 64) len &= 0b111111; // len -> [0, 64)
} }
unsigned char buffer[128]; // 2 blocks unsigned char buffer[128]; // 2 blocks
std::memcpy(buffer, data, len); std::memcpy(buffer, data, len);
uint64_t total = (ctx->size + len) << 3; // total number in bit uint64_t total = (ctx_.size + len) << 3; // total number in bit
if (len < 56) { // len -> [0, 56) if (len < 56) { // len -> [0, 56)
std::memcpy(buffer + len, Padding, 56 - len); std::memcpy(buffer + len, Padding, 56 - len);
std::memcpy(buffer + 56, &total, 8); std::memcpy(buffer + 56, &total, 8);
md5_update(ctx, buffer, 64); // update 1 block UpdateImpl(buffer, 64); // update 1 block
} else { // len -> [56, 64 + 56) } else { // len -> [56, 64 + 56)
std::memcpy(buffer + len, Padding, 120 - len); std::memcpy(buffer + len, Padding, 120 - len);
std::memcpy(buffer + 120, &total, 8); std::memcpy(buffer + 120, &total, 8);
md5_update(ctx, buffer, 128); // update 2 blocks UpdateImpl(buffer, 128); // update 2 blocks
} }
} }

27
src/md5.h

@ -15,16 +15,26 @@ class MD5 {
public: public:
MD5() = default; MD5() = default;
MD5& Final(); /// Reset for next round of hashing.
MD5& Reset(); MD5& Reset();
/// Update md5 hash with specified data.
MD5& Update(const std::string_view &data); MD5& Update(const std::string_view &data);
MD5& Update(const void *buffer, uint64_t len);
/// Update md5 hash with specified data.
MD5& Update(const void *data, uint64_t len);
/// Stop streaming updates and calculate result.
MD5& Final();
/// Get the string result of md5.
[[nodiscard]] std::string Digest() const; [[nodiscard]] std::string Digest() const;
public: public:
/// Calculate the md5 hash value of the specified data.
static std::string Hash(const std::string_view &data); static std::string Hash(const std::string_view &data);
/// Calculate the md5 hash value of the specified data.
static std::string Hash(const void *data, uint64_t len); static std::string Hash(const void *data, uint64_t len);
private: private:
@ -44,14 +54,15 @@ private:
private: private:
md5_ctx ctx_; md5_ctx ctx_;
char buffer_[64] {}; char buffer_[64] {};
uint64_t buffer_size_ = 0; uint64_t buffer_size_ = 0; // size < 64
private: /// Update md5 ctx with specified data, and return the pointer of unprocessed data (< 64 bytes).
/// Update md5 ctx with specified data, note that `len` is a multiple of 64. const void* UpdateImpl(const void *data, uint64_t len);
static void md5_update(md5_ctx *ctx, const void *buffer, uint64_t len);
/// Update and end the md5 hash with the specified data, the value of `len` has no limit. /// Update and final the md5 hash with the specified data.
static void md5_final(md5_ctx *ctx, const void *buffer, uint64_t len); void FinalImpl(const void *data, uint64_t len);
}; };
} // namespace md5 } // namespace md5
#include "md5.inc"

34
src/md5.inc

@ -0,0 +1,34 @@
#pragma once
namespace md5 {
inline MD5& MD5::Reset() {
ctx_.A = MD5_A;
ctx_.B = MD5_B;
ctx_.C = MD5_C;
ctx_.D = MD5_D;
ctx_.size = 0;
buffer_size_ = 0;
return *this;
}
inline MD5& MD5::Final() {
FinalImpl(buffer_, buffer_size_);
return *this;
}
inline MD5& MD5::Update(const std::string_view &data) {
return Update(data.data(), data.size());
}
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) {
MD5 md5;
md5.FinalImpl(data, len);
return md5.Digest();
}
} // namespace md5

66
src/wrapper.cc

@ -4,18 +4,6 @@
namespace md5 { namespace md5 {
// TODO: inline impl
MD5& MD5::Reset() {
ctx_.A = MD5_A;
ctx_.B = MD5_B;
ctx_.C = MD5_C;
ctx_.D = MD5_D;
ctx_.size = 0;
buffer_size_ = 0;
return *this;
}
MD5& MD5::Update(const void *data, uint64_t len) { MD5& MD5::Update(const void *data, uint64_t len) {
if (buffer_size_ != 0) { if (buffer_size_ != 0) {
if (buffer_size_ + len < 64) { // buffer not filled if (buffer_size_ + len < 64) { // buffer not filled
@ -26,15 +14,13 @@ MD5& MD5::Update(const void *data, uint64_t len) {
auto size = 64 - buffer_size_; auto size = 64 - buffer_size_;
std::memcpy(buffer_ + buffer_size_, data, size); std::memcpy(buffer_ + buffer_size_, data, size);
md5_update(&ctx_, buffer_, 64); // fill and update with buffer UpdateImpl(buffer_, 64); // fill and update with buffer
data = reinterpret_cast<const char*>(data) + size; data = static_cast<const char*>(data) + size;
buffer_size_ = 0; buffer_size_ = 0;
len -= size; len -= size;
} // buffer is empty for now } // buffer is empty for now
auto size = len & ~(uint64_t)0b111111; data = UpdateImpl(data, len);
md5_update(&ctx_, data, size);
data = reinterpret_cast<const char*>(data) + size;
len &= 0b111111; // len -> [0, 64) len &= 0b111111; // len -> [0, 64)
if (len != 0) { if (len != 0) {
@ -44,42 +30,20 @@ MD5& MD5::Update(const void *data, uint64_t len) {
return *this; return *this;
} }
MD5& MD5::Update(const std::string_view &data) { static constexpr char HexTable[] = {
return Update(data.data(), data.size()); '0','1','2','3','4','5','6','7',
} '8','9','a','b','c','d','e','f',
};
MD5& MD5::Final() {
md5_final(&ctx_, buffer_, buffer_size_);
return *this;
}
std::string MD5::Digest() const { std::string MD5::Digest() const {
// TODO: perf convert speed std::string result {};
char tmp[33]; result.resize(32);
sprintf(tmp, "%08x%08x%08x%08x", auto *src = reinterpret_cast<const uint8_t *>(&ctx_);
__builtin_bswap32(ctx_.A), for (int i = 0; i < 32; ++src) {
__builtin_bswap32(ctx_.B), result[i++] = HexTable[*src >> 4];
__builtin_bswap32(ctx_.C), result[i++] = HexTable[*src & 0b1111];
__builtin_bswap32(ctx_.D)); }
return {tmp}; return result;
}
std::string MD5::Hash(const void *data, uint64_t len) {
md5_ctx ctx;
md5_final(&ctx, data, len);
// TODO: perf convert speed
char tmp[33];
sprintf(tmp, "%08x%08x%08x%08x",
__builtin_bswap32(ctx.A),
__builtin_bswap32(ctx.B),
__builtin_bswap32(ctx.C),
__builtin_bswap32(ctx.D));
return {tmp};
}
std::string MD5::Hash(const std::string_view &data) {
return Hash(data.data(), data.size());
} }
} // namespace md5 } // namespace md5

Loading…
Cancel
Save