bool Base58::decode (const char* psz, Blob& vchRet, Alphabet const& alphabet) { CAutoBN_CTX pctx; vchRet.clear (); CBigNum bn58 = 58; CBigNum bn = 0; CBigNum bnChar; while (isspace (*psz)) psz++; // Convert big endian string to bignum for (const char* p = psz; *p; p++) { // VFALCO TODO Make this use the inverse table! // Or better yet ditch this and call raw_decode // const char* p1 = strchr (alphabet.chars(), *p); if (p1 == nullptr) { while (isspace (*p)) p++; if (*p != '\0') return false; break; } bnChar.setuint (p1 - alphabet.chars()); if (!BN_mul (&bn, &bn, &bn58, pctx)) throw bignum_error ("DecodeBase58 : BN_mul failed"); bn += bnChar; } // Get bignum as little endian data Blob vchTmp = bn.getvch (); // Trim off sign byte if present if (vchTmp.size () >= 2 && vchTmp.end ()[-1] == 0 && vchTmp.end ()[-2] >= 0x80) vchTmp.erase (vchTmp.end () - 1); // Restore leading zeros int nLeadingZeros = 0; for (const char* p = psz; *p == alphabet.chars()[0]; p++) nLeadingZeros++; vchRet.assign (nLeadingZeros + vchTmp.size (), 0); // Convert little endian data to big endian std::reverse_copy (vchTmp.begin (), vchTmp.end (), vchRet.end () - vchTmp.size ()); return true; }
// Decode a base58-encoded string psz into byte vector vchRet // returns true if decoding is successful bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet) { CAutoBN_CTX pctx; vchRet.clear(); CBigNum bn58 = 58; CBigNum bn = 0; CBigNum bnChar; while (isspace(*psz)) psz++; // Convert big endian string to bignum for (const char* p = psz; *p; p++) { const char* p1 = strchr(pszBase58, *p); if (p1 == NULL) { while (isspace(*p)) p++; if (*p != '\0') return false; break; } bnChar.setuint32((uint32_t)(p1 - pszBase58)); if (!BN_mul(&bn, &bn, &bn58, pctx)) throw bignum_error("DecodeBase58 : BN_mul failed"); bn += bnChar; } // Get bignum as little endian data std::vector<unsigned char> vchTmp = bn.getvch(); // Trim off sign byte if present if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80) vchTmp.erase(vchTmp.end()-1); // Restore leading zeros int nLeadingZeros = 0; for (const char* p = psz; *p == pszBase58[0]; p++) nLeadingZeros++; vchRet.assign(nLeadingZeros + vchTmp.size(), 0); // Convert little endian data to big endian reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size()); return true; }
// Encode a byte sequence as a base58-encoded string std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) { CAutoBN_CTX pctx; CBigNum bn58 = 58; CBigNum bn0 = 0; // Convert big endian data to little endian // Extra zero at the end make sure bignum will interpret as a positive number std::vector<unsigned char> vchTmp(pend-pbegin+1, 0); reverse_copy(pbegin, pend, vchTmp.begin()); // Convert little endian data to bignum CBigNum bn; bn.setvch(vchTmp); // Convert bignum to std::string std::string str; // Expected size increase from base58 conversion is approximately 137% // use 138% to be safe str.reserve((pend - pbegin) * 138 / 100 + 1); CBigNum dv; CBigNum rem; while (bn > bn0) { if (!BN_div(&dv, &rem, &bn, &bn58, pctx)) throw bignum_error("EncodeBase58 : BN_div failed"); bn = dv; unsigned int c = rem.getuint32(); str += pszBase58[c]; } // Leading zeroes encoded as base58 zeros for (const unsigned char* p = pbegin; p < pend && *p == 0; p++) str += pszBase58[0]; // Convert little endian std::string to big endian reverse(str.begin(), str.end()); return str; }
std::string Base58::raw_encode ( unsigned char const* begin, unsigned char const* end, Alphabet const& alphabet, bool withCheck) { CAutoBN_CTX pctx; CBigNum bn58 = 58; CBigNum bn0 = 0; // Convert little endian data to bignum CBigNum bn (begin, end); std::size_t const size (std::distance (begin, end)); // Convert bignum to std::string std::string str; // Expected size increase from base58 conversion is approximately 137% // use 138% to be safe str.reserve (size * 138 / 100 + 1); CBigNum dv; CBigNum rem; while (bn > bn0) { if (!BN_div (&dv, &rem, &bn, &bn58, pctx)) throw bignum_error ("EncodeBase58 : BN_div failed"); bn = dv; unsigned int c = rem.getuint (); str += alphabet [c]; } for (const unsigned char* p = end-2; p >= begin && *p == 0; p--) str += alphabet [0]; // Convert little endian std::string to big endian reverse (str.begin (), str.end ()); return str; }
bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet) { CAutoBN_CTX pctx; vchRet.clear(); CBigNum bn58 = 58; CBigNum bn = 0; CBigNum bnChar; // Skip leading spaces. while (*psz && isspace(*psz)) psz++; // Skip and count leading '1's. int zeroes = 0; while (*psz == '1') { zeroes++; psz++; } // Convert big endian string to bignum for (const char* p = psz; *p; p++) { const char* p1 = strchr(pszBase58, *p); if (p1 == NULL) { while (isspace(*p)) p++; if (*p != '\0') return false; break; } bnChar.setulong(p1 - pszBase58); if (!BN_mul(&bn, &bn, &bn58, pctx)) throw bignum_error("DecodeBase58 : BN_mul failed"); bn += bnChar; } // Get bignum as little endian data std::vector<unsigned char> vchTmp = bn.getvch(); // Trim off sign byte if present if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80) vchTmp.erase(vchTmp.end()-1); // Restore leading zeros int nLeadingZeros = 0; for (const char* p = psz; *p == pszBase58[0]; p++) nLeadingZeros++; vchRet.assign(nLeadingZeros + vchTmp.size(), 0); // Convert little endian data to big endian reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size()); return true; // Allocate enough space in big-endian base256 representation. std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up. // Process the characters. while (*psz && !isspace(*psz)) { // Decode base58 character const char *ch = strchr(pszBase58, *psz); if (ch == NULL) return false; // Apply "b256 = b256 * 58 + ch". int carry = ch - pszBase58; for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) { carry += 58 * (*it); *it = carry % 256; carry /= 256; } assert(carry == 0); 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(); while (it != b256.end() && *it == 0) it++; // Copy result into output vector. vchRet.reserve(zeroes + (b256.end() - it)); vchRet.assign(zeroes, 0x00); while (it != b256.end()) vchRet.push_back(*(it++)); return true; }