libutil/hash: Simplify some parts
Use a span representing the underlying hash, this allows comparing based on those spans. Other minor tweaks to the header file. Change-Id: Ie05960439e60500109083c06d347d6cdf41bfda8
This commit is contained in:
+37
-78
@@ -16,53 +16,7 @@
|
||||
|
||||
namespace nix {
|
||||
|
||||
static size_t regularHashSize(HashType type) {
|
||||
switch (type) {
|
||||
case HashType::MD5: return md5HashSize;
|
||||
case HashType::SHA1: return sha1HashSize;
|
||||
case HashType::SHA256: return sha256HashSize;
|
||||
case HashType::SHA512: return sha512HashSize;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
std::set<std::string> hashTypes = { "md5", "sha1", "sha256", "sha512" };
|
||||
|
||||
|
||||
Hash::Hash(HashType type) : type(type)
|
||||
{
|
||||
hashSize = regularHashSize(type);
|
||||
assert(hashSize <= maxHashSize);
|
||||
memset(hash, 0, maxHashSize);
|
||||
}
|
||||
|
||||
|
||||
bool Hash::operator == (const Hash & h2) const
|
||||
{
|
||||
if (hashSize != h2.hashSize) return false;
|
||||
for (unsigned int i = 0; i < hashSize; i++)
|
||||
if (hash[i] != h2.hash[i]) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Hash::operator != (const Hash & h2) const
|
||||
{
|
||||
return !(*this == h2);
|
||||
}
|
||||
|
||||
|
||||
bool Hash::operator < (const Hash & h) const
|
||||
{
|
||||
if (hashSize < h.hashSize) return true;
|
||||
if (hashSize > h.hashSize) return false;
|
||||
for (unsigned int i = 0; i < hashSize; i++) {
|
||||
if (hash[i] < h.hash[i]) return true;
|
||||
if (hash[i] > h.hash[i]) return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const std::set<std::string> hashTypes = {"md5", "sha1", "sha256", "sha512"};
|
||||
|
||||
const std::string base16Chars = "0123456789abcdef";
|
||||
|
||||
@@ -247,7 +201,6 @@ static void update(detail::EvpMdCtxPtr & ctx, std::string_view data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void finish(detail::EvpMdCtxPtr & ctx, unsigned char * hash)
|
||||
{
|
||||
if (!EVP_DigestFinal_ex(ctx.get(), hash, NULL)) {
|
||||
@@ -255,7 +208,6 @@ static void finish(detail::EvpMdCtxPtr & ctx, unsigned char * hash)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Hash hashString(HashType ht, std::string_view s)
|
||||
{
|
||||
Hash hash(ht);
|
||||
@@ -265,7 +217,6 @@ Hash hashString(HashType ht, std::string_view s)
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
Hash hashFile(HashType ht, const Path & path)
|
||||
{
|
||||
HashSink sink(ht);
|
||||
@@ -273,11 +224,7 @@ Hash hashFile(HashType ht, const Path & path)
|
||||
return sink.finish().first;
|
||||
}
|
||||
|
||||
|
||||
HashSink::HashSink(HashType ht) : ht(ht), ctx(start(ht))
|
||||
{
|
||||
bytes = 0;
|
||||
}
|
||||
HashSink::HashSink(HashType ht) : ht(ht), ctx(start(ht)), bytes(0) {}
|
||||
|
||||
void HashSink::writeUnbuffered(std::string_view data)
|
||||
{
|
||||
@@ -305,7 +252,6 @@ HashResult HashSink::currentHash()
|
||||
return HashResult(hash, bytes);
|
||||
}
|
||||
|
||||
|
||||
HashResult hashPath(HashType ht, const PreparedDump & path)
|
||||
{
|
||||
HashSink sink(ht);
|
||||
@@ -313,42 +259,55 @@ HashResult hashPath(HashType ht, const PreparedDump & path)
|
||||
return sink.finish();
|
||||
}
|
||||
|
||||
|
||||
Hash compressHash(const Hash & hash, unsigned int newSize)
|
||||
Hash compressHash(const Hash & hash, size_t newSize)
|
||||
{
|
||||
Hash h(hash.type);
|
||||
h.hashSize = newSize;
|
||||
for (unsigned int i = 0; i < hash.hashSize; ++i)
|
||||
h.hash[i % newSize] ^= hash.hash[i];
|
||||
Hash h(newSize, hash.type);
|
||||
|
||||
for (const auto [idx, c] : enumerate(hash.as_span())) {
|
||||
h.hash[idx % newSize] ^= c;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
|
||||
std::optional<HashType> parseHashTypeOpt(std::string_view s)
|
||||
{
|
||||
if (s == "md5") return HashType::MD5;
|
||||
else if (s == "sha1") return HashType::SHA1;
|
||||
else if (s == "sha256") return HashType::SHA256;
|
||||
else if (s == "sha512") return HashType::SHA512;
|
||||
else return std::optional<HashType> {};
|
||||
if (s == "md5") {
|
||||
return HashType::MD5;
|
||||
}
|
||||
if (s == "sha1") {
|
||||
return HashType::SHA1;
|
||||
}
|
||||
if (s == "sha256") {
|
||||
return HashType::SHA256;
|
||||
}
|
||||
if (s == "sha512") {
|
||||
return HashType::SHA512;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
HashType parseHashType(std::string_view s)
|
||||
{
|
||||
auto opt_h = parseHashTypeOpt(s);
|
||||
if (opt_h)
|
||||
if (auto opt_h = parseHashTypeOpt(s)) {
|
||||
return *opt_h;
|
||||
else
|
||||
throw UsageError("unknown hash algorithm '%1%'", s);
|
||||
}
|
||||
|
||||
throw UsageError("unknown hash algorithm '%1%'", s);
|
||||
}
|
||||
|
||||
std::string_view printHashType(HashType ht)
|
||||
std::string_view printHashType(HashType type)
|
||||
{
|
||||
switch (ht) {
|
||||
case HashType::MD5: return "md5";
|
||||
case HashType::SHA1: return "sha1";
|
||||
case HashType::SHA256: return "sha256";
|
||||
case HashType::SHA512: return "sha512";
|
||||
switch (type) {
|
||||
case HashType::MD5:
|
||||
return "md5";
|
||||
case HashType::SHA1:
|
||||
return "sha1";
|
||||
case HashType::SHA256:
|
||||
return "sha256";
|
||||
case HashType::SHA512:
|
||||
return "sha512";
|
||||
default:
|
||||
// illegal hash type enum value internally, as opposed to external input
|
||||
// which should be validated with nice error message.
|
||||
|
||||
+48
-15
@@ -20,13 +20,27 @@ MakeError(BadHash, Error);
|
||||
|
||||
enum class HashType : char { MD5 = 42, SHA1, SHA256, SHA512 };
|
||||
|
||||
const size_t md5HashSize = 16;
|
||||
const size_t sha1HashSize = 20;
|
||||
const size_t sha256HashSize = 32;
|
||||
const size_t sha512HashSize = 64;
|
||||
|
||||
const int md5HashSize = 16;
|
||||
const int sha1HashSize = 20;
|
||||
const int sha256HashSize = 32;
|
||||
const int sha512HashSize = 64;
|
||||
static constexpr size_t regularHashSize(HashType type)
|
||||
{
|
||||
switch (type) {
|
||||
case HashType::MD5:
|
||||
return md5HashSize;
|
||||
case HashType::SHA1:
|
||||
return sha1HashSize;
|
||||
case HashType::SHA256:
|
||||
return sha256HashSize;
|
||||
case HashType::SHA512:
|
||||
return sha512HashSize;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
extern std::set<std::string> hashTypes;
|
||||
extern const std::set<std::string> hashTypes;
|
||||
|
||||
/**
|
||||
* @brief Enumeration representing the hash formats.
|
||||
@@ -55,7 +69,13 @@ struct Hash
|
||||
/**
|
||||
* Create a zero-filled hash object.
|
||||
*/
|
||||
Hash(HashType type);
|
||||
Hash(size_t hashSize, HashType type) : hashSize(hashSize), type(type)
|
||||
{
|
||||
assert(hashSize <= maxHashSize);
|
||||
memset(hash, 0, maxHashSize);
|
||||
}
|
||||
|
||||
Hash(HashType type) : Hash(regularHashSize(type), type) {}
|
||||
|
||||
/**
|
||||
* Parse the hash from a string representation in the format
|
||||
@@ -91,17 +111,22 @@ public:
|
||||
/**
|
||||
* Check whether two hash are equal.
|
||||
*/
|
||||
bool operator == (const Hash & h2) const;
|
||||
|
||||
/**
|
||||
* Check whether two hash are not equal.
|
||||
*/
|
||||
bool operator != (const Hash & h2) const;
|
||||
bool operator==(const Hash & other) const
|
||||
{
|
||||
return std::ranges::equal(as_span(), other.as_span());
|
||||
}
|
||||
|
||||
/**
|
||||
* For sorting.
|
||||
*/
|
||||
bool operator < (const Hash & h) const;
|
||||
std::strong_ordering operator<=>(const Hash & other) const
|
||||
{
|
||||
std::span<const uint8_t> lhs = as_span(), rhs = other.as_span();
|
||||
|
||||
return (lhs.size() == rhs.size())
|
||||
? std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end())
|
||||
: lhs.size() <=> rhs.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of a base-16 representation of this hash.
|
||||
@@ -127,6 +152,14 @@ public:
|
||||
return ((4 * hashSize / 3) + 3) & ~3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a span of the intrinsic hash
|
||||
*/
|
||||
std::span<const uint8_t> as_span() const
|
||||
{
|
||||
return {hash, hashSize};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of the hash, in base-16, base-32
|
||||
* or base-64. By default, this is prefixed by the hash type
|
||||
@@ -141,7 +174,7 @@ public:
|
||||
|
||||
std::string gitShortRev() const
|
||||
{
|
||||
return std::string(to_string(HashFormat::Base16, false), 0, 7);
|
||||
return std::string(gitRev(), 0, 7);
|
||||
}
|
||||
|
||||
static Hash dummy;
|
||||
@@ -177,7 +210,7 @@ inline HashResult hashPath(HashType ht, Path path)
|
||||
* Compress a hash to the specified number of bytes by cyclically
|
||||
* XORing bytes together.
|
||||
*/
|
||||
Hash compressHash(const Hash & hash, unsigned int newSize);
|
||||
Hash compressHash(const Hash & hash, size_t newSize);
|
||||
|
||||
/**
|
||||
* Parse a string representing a hash type.
|
||||
|
||||
Reference in New Issue
Block a user