From 817f6c4fb11edfd108d6464330f622feae9a04be Mon Sep 17 00:00:00 2001 From: SEK1RO Date: Thu, 19 Sep 2024 01:50:32 +0300 Subject: [PATCH] feat(base58): unfixed bug with double \0 and incorrect real str_size --- Makefile | 2 ++ include/base.hpp | 8 +++-- include/base/base58.hpp | 27 ++++++++++++++ src/base58.cpp | 80 +++++++++++++++++++++++++++++++++++++++++ src/baseN.cpp | 3 +- test/test-base58.cpp | 35 ++++++++++++++++++ test/test-base64.cpp | 18 ++++------ test/test-baseN.cpp | 60 +++++++++---------------------- 8 files changed, 172 insertions(+), 61 deletions(-) create mode 100644 include/base/base58.hpp create mode 100644 src/base58.cpp create mode 100644 test/test-base58.cpp 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)