c++ Base58编码解码
Base58
-
字符集 Base58 使用 58 个字符进行编码,字符集为:123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz。注意:0(零)、O(大写字母O)、I(大写字母I)和 l(小写字母L)等字符被排除,以避免视觉上的混淆。
-
编码长度:Base58 编码和 Base64 类似,但由于字符集更小,编码后的长度比 Base64 稍短。
-
应用场景:
-
主要用于加密货币(如比特币)中,作为钱包地址等信息的编码方式。
-
由于字符集避免了视觉上容易混淆的字符,因此在用户界面中显示时更为友好。
-
示例:
"Hello" -> "JxF12TrwUP45p7r"
#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;/** All alphanumeric characters except for "0", "I", "O", and "l" */
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
static const int8_t mapBase58[256] = {-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-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,
};
constexpr inline bool IsSpace(char c) noexcept {return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v';
}bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len)
{// Skip leading spaces.while (*psz && IsSpace(*psz))psz++;// Skip and count leading '1's.int zeroes = 0;int length = 0;while (*psz == '1') {zeroes++;if (zeroes > max_ret_len) return false;psz++;}// Allocate enough space in big-endian base256 representation.int size = strlen(psz) * 733 / 1000 + 1; // log(58) / log(256), rounded up.std::vector<unsigned char> b256(size);// Process the characters.static_assert(sizeof(mapBase58) / sizeof(mapBase58[0]) == 256, "mapBase58.size() should be 256"); // guarantee not out of rangewhile (*psz && !IsSpace(*psz)) {// Decode base58 characterint carry = mapBase58[(uint8_t)*psz];if (carry == -1) // Invalid b58 characterreturn false;int i = 0;for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {carry += 58 * (*it);*it = carry % 256;carry /= 256;}assert(carry == 0);length = i;if (length + zeroes > max_ret_len) return false;psz++;}// Skip trailing spaces.while (IsSpace(*psz))psz++;if (*psz != 0)return false;// Skip leading zeroes in b256.std::vector<unsigned char>::iterator it = b256.begin() + (size - length);// Copy result into output vector.vch.reserve(zeroes + (b256.end() - it));vch.assign(zeroes, 0x00);while (it != b256.end())vch.push_back(*(it++));return true;
}std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
{// Skip & count leading zeroes.int zeroes = 0;int length = 0;while (pbegin != pend && *pbegin == 0) {pbegin++;zeroes++;}// Allocate enough space in big-endian base58 representation.int size = (pend - pbegin) * 138 / 100 + 1; // log(256) / log(58), rounded up.std::vector<unsigned char> b58(size);// Process the bytes.while (pbegin != pend) {int carry = *pbegin;int i = 0;// Apply "b58 = b58 * 256 + ch".for (auto it = b58.rbegin();(carry != 0 || i < length) && (it != b58.rend());it++, i++) {carry += 256 * (*it);*it = carry % 58;carry /= 58;}assert(carry == 0);length = i;pbegin++;}// Skip leading zeroes in base58 result.std::vector<unsigned char>::iterator it = b58.begin() + (size - length);while (it != b58.end() && *it == 0)it++;// Translate the result into a string.std::string str;str.reserve(zeroes + (b58.end() - it));str.assign(zeroes, '1');while (it != b58.end())str += pszBase58[*(it++)];return str;
}int main(int argc, char argv[])
{unsigned char data[] = "测试base58数据";int len = sizeof(data);cout << data << endl;std::string re = EncodeBase58(data, data + len);cout << re << endl;std::vector<unsigned char> vsh;DecodeBase58(re.data(), vsh, 4096);cout << vsh.data() << endl;return 0;
}