Browse Source

update: fixes and improvements

master
Dnomd343 8 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_Digest);
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);
}
void MD5::md5_update(md5_ctx *ctx, const void *data, uint64_t len) {
auto *block = reinterpret_cast<const uint32_t *>(data);
auto *limit = block + (len >> 2);
auto A = ctx->A;
auto B = ctx->B;
auto C = ctx->C;
auto D = ctx->D;
const void* MD5::UpdateImpl(const void *data, uint64_t len) {
auto *block = static_cast<const uint32_t *>(data);
auto *limit = block + ((len &= ~0b111111ULL) >> 2);
auto A = ctx_.A;
auto B = ctx_.B;
auto C = ctx_.C;
auto D = ctx_.D;
while (block < limit) {
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
}
ctx->A = A;
ctx->B = B;
ctx->C = C;
ctx->D = D;
ctx->size += len;
ctx_.A = A;
ctx_.B = B;
ctx_.C = C;
ctx_.D = D;
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)
auto size = len & ~(uint64_t)0b111111;
md5_update(ctx, data, size);
data = reinterpret_cast<const char*>(data) + size;
data = UpdateImpl(data, len);
len &= 0b111111; // len -> [0, 64)
}
unsigned char buffer[128]; // 2 blocks
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)
std::memcpy(buffer + len, Padding, 56 - len);
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)
std::memcpy(buffer + len, Padding, 120 - len);
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:
MD5() = default;
MD5& Final();
/// Reset for next round of hashing.
MD5& Reset();
/// Update md5 hash with specified 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;
public:
/// Calculate the md5 hash value of the specified 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);
private:
@ -44,14 +54,15 @@ private:
private:
md5_ctx ctx_;
char buffer_[64] {};
uint64_t buffer_size_ = 0;
uint64_t buffer_size_ = 0; // size < 64
private:
/// Update md5 ctx with specified data, note that `len` is a multiple of 64.
static void md5_update(md5_ctx *ctx, const void *buffer, uint64_t len);
/// Update md5 ctx with specified data, and return the pointer of unprocessed data (< 64 bytes).
const void* UpdateImpl(const void *data, uint64_t len);
/// Update and end the md5 hash with the specified data, the value of `len` has no limit.
static void md5_final(md5_ctx *ctx, const void *buffer, uint64_t len);
/// Update and final the md5 hash with the specified data.
void FinalImpl(const void *data, uint64_t len);
};
} // 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 {
// 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) {
if (buffer_size_ != 0) {
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_;
std::memcpy(buffer_ + buffer_size_, data, size);
md5_update(&ctx_, buffer_, 64); // fill and update with buffer
data = reinterpret_cast<const char*>(data) + size;
UpdateImpl(buffer_, 64); // fill and update with buffer
data = static_cast<const char*>(data) + size;
buffer_size_ = 0;
len -= size;
} // buffer is empty for now
auto size = len & ~(uint64_t)0b111111;
md5_update(&ctx_, data, size);
data = reinterpret_cast<const char*>(data) + size;
data = UpdateImpl(data, len);
len &= 0b111111; // len -> [0, 64)
if (len != 0) {
@ -44,42 +30,20 @@ MD5& MD5::Update(const void *data, uint64_t len) {
return *this;
}
MD5& MD5::Update(const std::string_view &data) {
return Update(data.data(), data.size());
}
MD5& MD5::Final() {
md5_final(&ctx_, buffer_, buffer_size_);
return *this;
}
static constexpr char HexTable[] = {
'0','1','2','3','4','5','6','7',
'8','9','a','b','c','d','e','f',
};
std::string MD5::Digest() const {
// 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 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());
std::string result {};
result.resize(32);
auto *src = reinterpret_cast<const uint8_t *>(&ctx_);
for (int i = 0; i < 32; ++src) {
result[i++] = HexTable[*src >> 4];
result[i++] = HexTable[*src & 0b1111];
}
return result;
}
} // namespace md5

Loading…
Cancel
Save