diff --git a/Makefile b/Makefile
index 988b6ee..21e83b5 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,7 @@ LIB = base
OBJS =\
hex\
baseN\
+ base58\
base64\
hash/sha256\
@@ -19,6 +20,7 @@ TOOLS =\
TESTS =\
test-hex\
test-baseN\
+ test-base58\
test-base64\
hash/test-sha256\
diff --git a/include/base.hpp b/include/base.hpp
index 279ac37..f35d13a 100644
--- a/include/base.hpp
+++ b/include/base.hpp
@@ -1,4 +1,6 @@
-#include
-#include
+#include
#include
-#include
\ No newline at end of file
+#include
+#include
+#include
+
diff --git a/include/base/base58.hpp b/include/base/base58.hpp
new file mode 100644
index 0000000..ee1e693
--- /dev/null
+++ b/include/base/base58.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace base58
+{
+ extern const char digits[59];
+ extern const int8_t map[256];
+
+ bool isValid(const char *str, uint64_t str_size) noexcept;
+ bool isValid(std::string_view str) noexcept;
+
+ uint64_t sizeEncoded(std::span data) noexcept;
+ uint64_t sizeDecoded(std::string_view str) noexcept;
+
+ void encode(const uint8_t *data, uint64_t data_size, char *str, uint64_t str_size) noexcept;
+ std::string encode(std::span data) noexcept;
+
+ void decode(const char *str, uint64_t str_size, uint8_t *data, uint64_t data_size) noexcept;
+ std::vector decode(std::string_view str) noexcept;
+
+ std::string encodeCheck(std::span data) noexcept;
+ std::vector decodeCheck(std::string_view str);
+}
\ No newline at end of file
diff --git a/src/base58.cpp b/src/base58.cpp
new file mode 100644
index 0000000..a22836a
--- /dev/null
+++ b/src/base58.cpp
@@ -0,0 +1,80 @@
+#include
+
+#include
+#include
+#include
+
+namespace base58
+{
+ const char digits[] =
+ "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
+ const int8_t map[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1,
+ -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1,
+ -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ //
+ };
+ bool isValid(const char *str, uint64_t str_size) noexcept
+ {
+ return baseN::isValid(str, str_size, map);
+ }
+ bool isValid(std::string_view str) noexcept
+ {
+ return baseN::isValid(str, map);
+ }
+ uint64_t sizeEncoded(std::span data) noexcept
+ {
+ return baseN::sizeEncoded(data, 58);
+ }
+ uint64_t sizeDecoded(std::string_view str) noexcept
+ {
+ return baseN::sizeDecoded(str, 58);
+ }
+ void encode(const uint8_t *data, uint64_t data_size, char *str, uint64_t str_size) noexcept
+ {
+ baseN::encode(data, data_size, str, str_size, 58, digits);
+ }
+ std::string encode(std::span data) noexcept
+ {
+ return baseN::encode(data, 58, digits);
+ }
+ void decode(const char *str, uint64_t str_size, uint8_t *data, uint64_t data_size) noexcept
+ {
+ baseN::decode(str, str_size, data, data_size, 58, digits, map);
+ }
+ std::vector decode(std::string_view str) noexcept
+ {
+ return baseN::decode(str, 58, digits, map);
+ }
+ std::string encodeCheck(std::span data) noexcept
+ {
+ std::vector buff(data.begin(), data.end()), dhash;
+ dhash = hash::sha256(hash::sha256(data));
+ buff.insert(buff.end(), &dhash[0], &dhash[4]);
+ return base58::encode(buff);
+ }
+ std::vector decodeCheck(std::string_view str)
+ {
+ std::vector buff(base58::decode(str));
+ std::span data(buff.begin(), buff.end() - 4);
+ std::span dhash(buff.end() - 4, buff.end());
+ if (!std::equal(dhash.begin(), dhash.end(), hash::sha256(hash::sha256(data)).begin()))
+ {
+ throw std::logic_error("base58::decodeCheck: checksum incorrect");
+ }
+ return std::vector(data.begin(), data.end());
+ }
+}
\ No newline at end of file
diff --git a/src/baseN.cpp b/src/baseN.cpp
index 4614b79..02f3e65 100644
--- a/src/baseN.cpp
+++ b/src/baseN.cpp
@@ -11,8 +11,7 @@ namespace baseN
{
bool isValid(const char *str, uint64_t str_size, const int8_t *map) noexcept
{
- std::string_view sv(str, str_size);
- return std::all_of(sv.begin(), sv.end(), [map](char ch)
+ return std::all_of(str, str + str_size, [map](char ch)
{ return map[(int8_t)ch] != -1; });
}
bool isValid(std::string_view str, const int8_t *map) noexcept
diff --git a/test/test-base58.cpp b/test/test-base58.cpp
new file mode 100644
index 0000000..fd45628
--- /dev/null
+++ b/test/test-base58.cpp
@@ -0,0 +1,35 @@
+#include
+
+#include
+#include
+#include
+
+using namespace base58;
+
+std::pair test = {
+ "003812e515df45235c6bcc2233ac9d0c4ebbd781de",
+ "167VUagc755PbQoB7cCTfTPjbQ5Nk6fEuD",
+};
+
+TEST(base58, encodeCheck)
+{
+ EXPECT_EQ(encodeCheck(hex::decode(test.first)), test.second);
+}
+TEST(base58, decodeCheck)
+{
+ EXPECT_EQ(test.first, hex::encode(decodeCheck(test.second)));
+ try
+ {
+ decodeCheck("incorrect");
+ }
+ catch (const std::exception &e)
+ {
+ EXPECT_STREQ(e.what(), "base58::decodeCheck: checksum incorrect");
+ }
+}
+
+int main(int argc, char **argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/test/test-base64.cpp b/test/test-base64.cpp
index 610926f..6ab15ec 100644
--- a/test/test-base64.cpp
+++ b/test/test-base64.cpp
@@ -18,14 +18,14 @@ TEST(base64, isValid)
for (auto it : tests)
EXPECT_EQ(it.first, isValid(it.second));
}
+std::vector> tests = {
+ {"", ""},
+ {"BKUEpQ==", "04a504a5"},
+ {"BKUEpQA=", "04a504a500"},
+ {"BKUEpQAA", "04a504a50000"},
+};
TEST(base64, encode)
{
- std::vector> tests = {
- {"", ""},
- {"BKUEpQ==", "04a504a5"},
- {"BKUEpQA=", "04a504a500"},
- {"BKUEpQAA", "04a504a50000"},
- };
for (auto it : tests)
EXPECT_EQ(it.first, encode(hex::decode(it.second)));
}
@@ -36,12 +36,6 @@ TEST(base64, encode_1e7)
}
TEST(base64, decode)
{
- std::vector> tests = {
- {"", ""},
- {"BKUEpQ==", "04a504a5"},
- {"BKUEpQA=", "04a504a500"},
- {"BKUEpQAA", "04a504a50000"},
- };
for (auto it : tests)
EXPECT_EQ(hex::encode(decode(it.first)), it.second);
}
diff --git a/test/test-baseN.cpp b/test/test-baseN.cpp
index 776d472..abd7638 100644
--- a/test/test-baseN.cpp
+++ b/test/test-baseN.cpp
@@ -1,34 +1,12 @@
#include
+#include
#include
#include
#include
using namespace baseN;
-static const char b58digits[] =
- "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
-
-static const int8_t b58map[] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1,
- -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1,
- 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1,
- -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46,
- 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- //
-};
-
TEST(baseN, isValid)
{
std::vector> tests = {
@@ -36,44 +14,38 @@ TEST(baseN, isValid)
{false, "@#$"},
};
for (auto it : tests)
- EXPECT_EQ(it.first, isValid(it.second, b58map));
+ EXPECT_EQ(it.first, isValid(it.second, base58::map));
}
+std::vector> tests = {
+ {"", ""},
+ {"Ky", "044c"},
+ {"KyK", "f94a"},
+ {"KyKX", "387ae2"},
+ {"KyKXa", "0ccbd755"},
+ {"KyKXaa", "02e62ec963"},
+ {"4uqWDRyJZUpS6KKwLAiitndmv7TPFt2bfxVVfhJhgTn3Rh6aQtGHQY6PhhNDpCwSNU8a",
+ "057902f9cebebb68879911002aae743280140a78c4a077405b057902f9cebebb68879911002aae743280140a78c4a077405b"},
+};
TEST(baseN, encode)
{
- std::vector> tests = {
- {"", ""},
- {"Ky", "044c"},
- {"KyK", "f94a"},
- {"KyKX", "387ae2"},
- {"KyKXa", "0ccbd755"},
- {"KyKXaa", "02e62ec963"},
- };
for (auto it : tests)
- EXPECT_EQ(it.first, encode(hex::decode(it.second), 58, b58digits));
+ EXPECT_EQ(it.first, encode(hex::decode(it.second), 58, base58::digits));
}
TEST(baseN, encode_1e3)
{
std::vector data(1e3);
std::fill(data.begin(), data.end(), 1);
- encode(data, 58, b58digits);
+ encode(data, 58, base58::digits);
}
TEST(baseN, decode)
{
- std::vector> tests = {
- {"", ""},
- {"Ky", "044c"},
- {"KyK", "f94a"},
- {"KyKX", "387ae2"},
- {"KyKXa", "0ccbd755"},
- {"KyKXaa", "02e62ec963"},
- };
for (auto it : tests)
- EXPECT_EQ(hex::encode(decode(it.first, 58, b58digits, b58map)), it.second);
+ EXPECT_EQ(hex::encode(decode(it.first, 58, base58::digits, base58::map)), it.second);
}
TEST(baseN, decode_1e3)
{
std::string str(1e3, '2');
- decode(str, 58, b58digits, b58map);
+ decode(str, 58, base58::digits, base58::map);
}
int main(int argc, char **argv)