Skip to content

Commit 2f3f1fa

Browse files
committed
Make checksumming more flexible
1 parent 555fb85 commit 2f3f1fa

File tree

3 files changed

+159
-45
lines changed

3 files changed

+159
-45
lines changed

include/dwarfs/checksum.h

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,63 @@
2222
#pragma once
2323

2424
#include <cstddef>
25+
#include <memory>
2526
#include <stdexcept>
2627

28+
#include "dwarfs/error.h"
29+
2730
namespace dwarfs {
2831

29-
enum class checksum_algorithm {
30-
SHA1,
31-
SHA2_512_256,
32-
XXH3_64,
33-
};
32+
class checksum {
33+
public:
34+
enum class algorithm {
35+
SHA1,
36+
SHA2_512_256,
37+
XXH3_64,
38+
};
39+
40+
static constexpr size_t digest_size(algorithm alg) {
41+
switch (alg) {
42+
case algorithm::SHA1:
43+
return 20;
44+
case algorithm::SHA2_512_256:
45+
return 32;
46+
case algorithm::XXH3_64:
47+
return 8;
48+
}
49+
DWARFS_CHECK(false, "unknown algorithm");
50+
}
51+
52+
static bool
53+
compute(algorithm alg, void const* data, size_t size, void* digest);
54+
55+
static bool
56+
verify(algorithm alg, void const* data, size_t size, void const* digest);
57+
58+
checksum(algorithm alg);
3459

35-
constexpr size_t checksum_size(checksum_algorithm alg) {
36-
switch (alg) {
37-
case checksum_algorithm::SHA1:
38-
return 20;
39-
case checksum_algorithm::SHA2_512_256:
40-
return 32;
41-
case checksum_algorithm::XXH3_64:
42-
return 8;
60+
checksum& update(void const* data, size_t size) {
61+
impl_->update(data, size);
62+
return *this;
4363
}
44-
throw std::logic_error("unknown algorithm");
45-
}
4664

47-
bool compute_checksum(checksum_algorithm alg, void const* data, size_t size,
48-
void* result);
49-
bool verify_checksum(checksum_algorithm alg, void const* data, size_t size,
50-
const void* checksum);
65+
bool finalize(void* digest) const { return impl_->finalize(digest); }
66+
67+
bool verify(void const* digest) const;
68+
69+
algorithm type() const { return alg_; }
70+
71+
class impl {
72+
public:
73+
virtual ~impl() = default;
74+
75+
virtual void update(void const* data, size_t size) = 0;
76+
virtual bool finalize(void* digest) = 0;
77+
};
78+
79+
private:
80+
std::unique_ptr<impl> impl_;
81+
algorithm const alg_;
82+
};
5183

5284
} // namespace dwarfs

src/dwarfs/checksum.cpp

Lines changed: 104 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -35,52 +35,134 @@ namespace dwarfs {
3535
namespace {
3636

3737
bool compute_evp(const EVP_MD* algorithm, void const* data, size_t size,
38-
void* result, unsigned int* digest_size) {
39-
return EVP_Digest(data, size, reinterpret_cast<unsigned char*>(result),
38+
void* digest, unsigned int* digest_size) {
39+
return EVP_Digest(data, size, reinterpret_cast<unsigned char*>(digest),
4040
digest_size, algorithm, nullptr);
4141
}
4242

43-
bool compute_xxh3_64(void const* data, size_t size, void* result) {
44-
auto checksum = XXH3_64bits(data, size);
45-
static_assert(checksum_size(checksum_algorithm::XXH3_64) == sizeof(checksum));
46-
::memcpy(result, &checksum, sizeof(checksum));
43+
bool compute_xxh3_64(void const* data, size_t size, void* digest) {
44+
auto hash = XXH3_64bits(data, size);
45+
static_assert(checksum::digest_size(checksum::algorithm::XXH3_64) ==
46+
sizeof(hash));
47+
::memcpy(digest, &hash, sizeof(hash));
4748
return true;
4849
}
4950

51+
class checksum_evp : public checksum::impl {
52+
public:
53+
checksum_evp(EVP_MD const* evp, checksum::algorithm alg)
54+
: context_(EVP_MD_CTX_new())
55+
, dig_size_(checksum::digest_size(alg)) {
56+
EVP_DigestInit_ex(context_, evp, nullptr);
57+
}
58+
59+
~checksum_evp() override { EVP_MD_CTX_destroy(context_); }
60+
61+
void update(void const* data, size_t size) override {
62+
DWARFS_CHECK(EVP_DigestUpdate(context_, data, size),
63+
"EVP_DigestUpdate() failed");
64+
}
65+
66+
bool finalize(void* digest) override {
67+
unsigned int dig_size = 0;
68+
bool rv = EVP_DigestFinal_ex(
69+
context_, reinterpret_cast<unsigned char*>(digest), &dig_size);
70+
71+
if (rv) {
72+
DWARFS_CHECK(
73+
dig_size_ == dig_size,
74+
fmt::format("digest size mismatch: {0} != {1}", dig_size_, dig_size));
75+
}
76+
77+
return rv;
78+
}
79+
80+
private:
81+
EVP_MD_CTX* context_;
82+
size_t const dig_size_;
83+
};
84+
85+
class checksum_xxh3_64 : public checksum::impl {
86+
public:
87+
checksum_xxh3_64()
88+
: state_(XXH3_createState()) {
89+
DWARFS_CHECK(XXH3_64bits_reset(state_) == XXH_OK,
90+
"XXH3_64bits_reset() failed");
91+
}
92+
93+
~checksum_xxh3_64() override { XXH3_freeState(state_); }
94+
95+
void update(void const* data, size_t size) override {
96+
auto err = XXH3_64bits_update(state_, data, size);
97+
DWARFS_CHECK(err == XXH_OK, fmt::format("XXH3_64bits_update() failed: {}",
98+
static_cast<int>(err)));
99+
}
100+
101+
bool finalize(void* digest) override {
102+
auto hash = XXH3_64bits_digest(state_);
103+
::memcpy(digest, &hash, sizeof(hash));
104+
return true;
105+
}
106+
107+
private:
108+
XXH3_state_t* state_;
109+
};
110+
50111
} // namespace
51112

52-
bool compute_checksum(checksum_algorithm alg, void const* data, size_t size,
53-
void* result) {
113+
bool checksum::compute(algorithm alg, void const* data, size_t size,
114+
void* digest) {
54115
bool rv = false;
55-
unsigned int digest_size = 0;
116+
unsigned int dig_size = 0;
56117

57118
switch (alg) {
58-
case checksum_algorithm::SHA1:
59-
rv = compute_evp(EVP_sha1(), data, size, result, &digest_size);
119+
case algorithm::SHA1:
120+
rv = compute_evp(EVP_sha1(), data, size, digest, &dig_size);
60121
break;
61-
case checksum_algorithm::SHA2_512_256:
62-
rv = compute_evp(EVP_sha512_256(), data, size, result, &digest_size);
122+
case algorithm::SHA2_512_256:
123+
rv = compute_evp(EVP_sha512_256(), data, size, digest, &dig_size);
63124
break;
64-
case checksum_algorithm::XXH3_64:
65-
rv = compute_xxh3_64(data, size, result);
125+
case algorithm::XXH3_64:
126+
rv = compute_xxh3_64(data, size, digest);
66127
break;
67128
}
68129

69-
if (rv && digest_size > 0) {
70-
DWARFS_CHECK(checksum_size(alg) == digest_size,
130+
if (rv && dig_size > 0) {
131+
DWARFS_CHECK(digest_size(alg) == dig_size,
71132
fmt::format("digest size mismatch: {0} != {1} [{2}]",
72-
checksum_size(alg), digest_size,
133+
digest_size(alg), dig_size,
73134
static_cast<int>(alg)));
74135
}
75136

76137
return rv;
77138
}
78139

79-
bool verify_checksum(checksum_algorithm alg, void const* data, size_t size,
80-
const void* checksum) {
140+
bool checksum::verify(algorithm alg, void const* data, size_t size,
141+
const void* digest) {
142+
char tmp[EVP_MAX_MD_SIZE];
143+
return compute(alg, data, size, tmp) &&
144+
::memcmp(digest, tmp, digest_size(alg)) == 0;
145+
}
146+
147+
checksum::checksum(algorithm alg)
148+
: alg_(alg) {
149+
switch (alg) {
150+
case algorithm::SHA1:
151+
impl_ = std::make_unique<checksum_evp>(EVP_sha1(), alg);
152+
break;
153+
case algorithm::SHA2_512_256:
154+
impl_ = std::make_unique<checksum_evp>(EVP_sha512_256(), alg);
155+
break;
156+
case algorithm::XXH3_64:
157+
impl_ = std::make_unique<checksum_xxh3_64>();
158+
break;
159+
}
160+
DWARFS_CHECK(false, "unknown algorithm");
161+
}
162+
163+
bool checksum::verify(void const* digest) const {
81164
char tmp[EVP_MAX_MD_SIZE];
82-
return compute_checksum(alg, data, size, tmp) &&
83-
::memcmp(checksum, tmp, checksum_size(alg)) == 0;
165+
return impl_->finalize(tmp) && ::memcmp(digest, tmp, digest_size(alg_)) == 0;
84166
}
85167

86168
} // namespace dwarfs

src/dwarfs/entry.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,16 @@ uint32_t file::inode_num() const { return inode_->num(); }
162162
void file::accept(entry_visitor& v, bool) { v.visit(this); }
163163

164164
void file::scan(os_access& os, progress& prog) {
165-
constexpr auto alg = checksum_algorithm::SHA1;
166-
static_assert(checksum_size(alg) == sizeof(data::hash_type));
165+
constexpr auto alg = checksum::algorithm::SHA1;
166+
static_assert(checksum::digest_size(alg) == sizeof(data::hash_type));
167167

168168
if (size_t s = size(); s > 0) {
169169
prog.original_size += s;
170170
auto mm = os.map_file(path(), s);
171-
DWARFS_CHECK(compute_checksum(alg, mm->as<void>(), s, &data_->hash[0]),
171+
DWARFS_CHECK(checksum::compute(alg, mm->as<void>(), s, &data_->hash[0]),
172172
"checksum computation failed");
173173
} else {
174-
DWARFS_CHECK(compute_checksum(alg, nullptr, 0, &data_->hash[0]),
174+
DWARFS_CHECK(checksum::compute(alg, nullptr, 0, &data_->hash[0]),
175175
"checksum computation failed");
176176
}
177177
}

0 commit comments

Comments
 (0)