Revert "libutil: extract Base32 helpers from Hash"

Revert submission 3850

Reason for revert: caused multiple regressions noticed in https://git.lix.systems/lix-project/lix/issues/975 and https://git.lix.systems/lix-project/lix/issues/966 (suspected).

Root cause analysis has not been done yet and this breaks Lix on Darwin on HEAD.

Reverted changes: /q/submissionid:3850

Change-Id: I2dae7147030c883a57be8a8c205e492e16425a23
This commit is contained in:
Raito Bezarius
2025-08-21 14:37:46 +00:00
parent 28bcc7fb24
commit 7622d28dd4
6 changed files with 50 additions and 117 deletions
+48 -3
View File
@@ -80,6 +80,33 @@ static std::string printHash16(const Hash & hash)
}
// omitted: E O U T
const std::string base32Chars = "0123456789abcdfghijklmnpqrsvwxyz";
static std::string printHash32(const Hash & hash)
{
assert(hash.hashSize);
size_t len = hash.base32Len();
assert(len);
std::string s;
s.reserve(len);
for (int n = (int) len - 1; n >= 0; n--) {
unsigned int b = n * 5;
unsigned int i = b / 8;
unsigned int j = b % 8;
unsigned char c =
(hash.hash[i] >> j)
| (i >= hash.hashSize - 1 ? 0 : hash.hash[i + 1] << (8 - j));
s.push_back(base32Chars[c & 0x1f]);
}
return s;
}
std::string printHash16or32(const Hash & hash)
{
return hash.to_string(hash.type == HashType::MD5 ? Base::Base16 : Base::Base32, false);
@@ -98,7 +125,7 @@ std::string Hash::to_string(Base base, bool includeType) const
s += printHash16(*this);
break;
case Base::Base32:
s += base32Encode(std::string_view(charptr_cast<const char *>(hash), hashSize));
s += printHash32(*this);
break;
case Base::Base64:
case Base::SRI:
@@ -198,8 +225,26 @@ Hash::Hash(std::string_view rest, HashType type, bool isSRI)
}
else if (!isSRI && rest.size() == base32Len()) {
auto d = base32Decode(rest);
memcpy(hash, d.data(), hashSize);
for (unsigned int n = 0; n < rest.size(); ++n) {
char c = rest[rest.size() - n - 1];
size_t digit;
for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
if (base32Chars[digit] == c) break;
if (digit >= 32)
throw BadHash("invalid base-32 hash '%s'", rest);
unsigned int b = n * 5;
unsigned int i = b / 8;
unsigned int j = b % 8;
hash[i] |= digit << j;
if (i < hashSize - 1) {
hash[i + 1] |= digit >> (8 - j);
} else {
if (digit >> (8 - j))
throw BadHash("invalid base-32 hash '%s'", rest);
}
}
}
else if (isSRI || rest.size() == base64Len()) {
+2
View File
@@ -32,6 +32,8 @@ const int sha512HashSize = 64;
extern std::set<std::string> hashTypes;
extern const std::string base32Chars;
enum class Base : int { Base64, Base32, Base16, SRI };
-1
View File
@@ -1,5 +1,4 @@
#include "lix/libutil/references.hh"
#include "lix/libutil/strings.hh"
#include "lix/libutil/hash.hh"
#include "lix/libutil/logging.hh"
-60
View File
@@ -195,66 +195,6 @@ std::string base64Decode(std::string_view s)
return res;
}
// omitted: E O U T
const std::string base32Chars = "0123456789abcdfghijklmnpqrsvwxyz";
std::string base32Encode(std::string_view s)
{
if (s.empty()) {
return "";
}
size_t len = (s.size() * 8 - 1) / 5 + 1;
std::string res;
res.reserve(len);
for (int n = (int) len - 1; n >= 0; n--) {
unsigned int b = n * 5;
unsigned int i = b / 8;
unsigned int j = b % 8;
unsigned char c = (static_cast<unsigned char>(s[i]) >> j) | (i >= s.size() - 1 ? 0 : static_cast<unsigned char>(s[i + 1]) << (8 - j));
res.push_back(base32Chars[c & 0x1f]);
}
return res;
}
std::string base32Decode(std::string_view s)
{
if (s.empty()) {
return "";
}
std::string res(((s.size() - 1) * 5) / 8 + 1, 0);
for (unsigned int n = 0; n < s.size(); ++n) {
char c = s[s.size() - n - 1];
size_t digit;
for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */ {
if (base32Chars[digit] == c) {
break;
}
}
if (digit >= 32) {
throw Error("invalid character in base-32 string '%s'", s);
}
unsigned int b = n * 5;
unsigned int i = b / 8;
unsigned int j = b % 8;
res[i] |= digit << j;
if (i < s.size() - 1) {
res[i + 1] |= digit >> (8 - j);
} else {
if (digit >> (8 - j)) {
throw Error("invalid base-32 string '%s'", s);
}
}
}
return res;
}
std::string stripIndentation(std::string_view s)
{
-6
View File
@@ -197,12 +197,6 @@ std::string shellEscape(const std::string_view s);
std::string base64Encode(std::string_view s);
std::string base64Decode(std::string_view s);
/**
* Base32 encoding/decoding.
*/
extern const std::string base32Chars;
std::string base32Encode(std::string_view s);
std::string base32Decode(std::string_view s);
/**
* Remove common leading whitespace from the lines in the string
-47
View File
@@ -364,53 +364,6 @@ namespace nix {
ASSERT_THROW(base64Decode("cXVvZCBlcm_0IGRlbW9uc3RyYW5kdW0="), Error);
}
/* ----------------------------------------------------------------------------
* base32Encode
* --------------------------------------------------------------------------*/
TEST(base32Encode, emptyString) {
ASSERT_EQ(base32Encode(""), "");
}
TEST(base32Encode, encodesAString) {
ASSERT_EQ(base32Encode("quod erat demonstrandum"), "6sxb4drhp4x3kdrpnsrb441s62wk541j6yxbi");
}
TEST(base32Encode, encodeAndDecode) {
auto s = "quod erat demonstrandum";
auto encoded = base32Encode(s);
auto decoded = base32Decode(encoded);
ASSERT_EQ(decoded, s);
}
TEST(base32Encode, encodeAndDecodeNonPrintable) {
char s[256];
std::iota(std::rbegin(s), std::rend(s), 0);
auto encoded = base32Encode(s);
auto decoded = base32Decode(encoded);
EXPECT_EQ(decoded.length(), 255);
ASSERT_EQ(decoded, s);
}
/* ----------------------------------------------------------------------------
* base32Decode
* --------------------------------------------------------------------------*/
TEST(base32Decode, emptyString) {
ASSERT_EQ(base32Decode(""), "");
}
TEST(base32Decode, decodeAString) {
ASSERT_EQ(base32Decode("6sxb4drhp4x3kdrpnsrb441s62wk541j6yxbi"), "quod erat demonstrandum");
}
TEST(base32Decode, decodeThrowsOnInvalidChar) {
ASSERT_THROW(base32Decode("6sxb4drhp4x3kdrpnsrb441s62wk541j6yxbe"), Error);
}
/* ----------------------------------------------------------------------------
* getLine
* --------------------------------------------------------------------------*/