diff --git a/src/primitives/base58.h b/src/primitives/base58.h index f6e3bc96..73ee9306 100644 --- a/src/primitives/base58.h +++ b/src/primitives/base58.h @@ -18,32 +18,27 @@ #include #include +#include +#include #include "bignum.h" #include "key.h" #include "script.h" static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; -// Encode a byte sequence as a base58-encoded string inline 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 vchTmp(pend-pbegin+1, 0); - reverse_copy(pbegin, pend, vchTmp.begin()); + std::vector vchTmp(pend - pbegin + 1, 0); + std::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; @@ -56,23 +51,18 @@ inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char 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()); + std::reverse(str.begin(), str.end()); return str; } -// Encode a byte vector as a base58-encoded string inline std::string EncodeBase58(const std::vector& vch) { return EncodeBase58(&vch[0], &vch[0] + vch.size()); } -// Decode a base58-encoded string psz into byte vector vchRet -// returns true if decoding is successful inline bool DecodeBase58(const char* psz, std::vector& vchRet) { CAutoBN_CTX pctx; @@ -80,16 +70,15 @@ inline bool DecodeBase58(const char* psz, std::vector& vchRet) CBigNum bn58 = 58; CBigNum bn = 0; CBigNum bnChar; - while (isspace(*psz)) + while (std::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) + const char* p1 = std::strchr(pszBase58, *p); + if (p1 == nullptr) { - while (isspace(*p)) + while (std::isspace(*p)) p++; if (*p != '\0') return false; @@ -101,110 +90,48 @@ inline bool DecodeBase58(const char* psz, std::vector& vchRet) bn += bnChar; } - // Get bignum as little endian data std::vector 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); + if (vchTmp.size() >= 2 && vchTmp.back() == 0 && vchTmp[vchTmp.size() - 2] >= 0x80) + vchTmp.pop_back(); - // 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()); + std::copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size()); return true; } -// Decode a base58-encoded string str into byte vector vchRet -// returns true if decoding is successful inline bool DecodeBase58(const std::string& str, std::vector& vchRet) { return DecodeBase58(str.c_str(), vchRet); } - - - -// Encode a byte vector to a base58-encoded string, including checksum -inline std::string EncodeBase58Check(const std::vector& vchIn) -{ - // add 4-byte hash check to the end - std::vector vch(vchIn); - uint256 hash = Hash(vch.begin(), vch.end()); - vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4); - return EncodeBase58(vch); -} - -// Decode a base58-encoded string psz that includes a checksum, into byte vector vchRet -// returns true if decoding is successful -inline bool DecodeBase58Check(const char* psz, std::vector& vchRet) -{ - if (!DecodeBase58(psz, vchRet)) - return false; - if (vchRet.size() < 4) - { - vchRet.clear(); - return false; - } - uint256 hash = Hash(vchRet.begin(), vchRet.end()-4); - if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) - { - vchRet.clear(); - return false; - } - vchRet.resize(vchRet.size()-4); - return true; -} - -// Decode a base58-encoded string str that includes a checksum, into byte vector vchRet -// returns true if decoding is successful -inline bool DecodeBase58Check(const std::string& str, std::vector& vchRet) -{ - return DecodeBase58Check(str.c_str(), vchRet); -} - - - - - -/** Base class for all base58-encoded data */ class CBase58Data { protected: - // the version byte unsigned char nVersion; - - // the actually encoded data std::vector vchData; - CBase58Data() - { - nVersion = 0; - vchData.clear(); - } + CBase58Data() : nVersion(0), vchData() {} ~CBase58Data() { - // zero the memory, as it may contain sensitive data if (!vchData.empty()) - memset(&vchData[0], 0, vchData.size()); + std::memset(&vchData[0], 0, vchData.size()); } void SetData(int nVersionIn, const void* pdata, size_t nSize) { nVersion = nVersionIn; - vchData.resize(nSize); - if (!vchData.empty()) - memcpy(&vchData[0], pdata, nSize); + vchData.assign(static_cast(pdata), static_cast(pdata) + nSize); } - void SetData(int nVersionIn, const unsigned char *pbegin, const unsigned char *pend) + void SetData(int nVersionIn, const unsigned char* pbegin, const unsigned char* pend) { - SetData(nVersionIn, (void*)pbegin, pend - pbegin); + SetData(nVersionIn, pbegin, pend - pbegin); } public: @@ -219,10 +146,7 @@ class CBase58Data return false; } nVersion = vchTemp[0]; - vchData.resize(vchTemp.size() - 1); - if (!vchData.empty()) - memcpy(&vchData[0], &vchTemp[1], vchData.size()); - memset(&vchTemp[0], 0, vchTemp.size()); + vchData.assign(vchTemp.begin() + 1, vchTemp.end()); return true; } @@ -250,224 +174,5 @@ class CBase58Data bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; } bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; } bool operator>=(const CBase58Data& b58) const { return CompareTo(b58) >= 0; } - bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < 0; } - bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; } -}; - -/** base58-encoded Bitcoin addresses. - * Public-key-hash-addresses have version 0 (or 111 testnet). - * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. - * Script-hash-addresses have version 5 (or 196 testnet). - * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. - */ -class CBitcoinAddress; -class CBitcoinAddressVisitor : public boost::static_visitor -{ -private: - CBitcoinAddress *addr; -public: - CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { } - bool operator()(const CKeyID &id) const; - bool operator()(const CScriptID &id) const; - bool operator()(const CNoDestination &no) const; - bool operator()(const CStealthAddress &stxAddr) const; -}; - -class CBitcoinAddress : public CBase58Data -{ -public: - enum - { - PUBKEY_ADDRESS = 62, // XST addresses begin with 'S' - SCRIPT_ADDRESS = 85, - PUBKEY_ADDRESS_TEST = 111, - SCRIPT_ADDRESS_TEST = 196, - }; - - bool Set(const CKeyID &id) { - SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &id, 20); - return true; - } - - bool Set(const CKeyID &id, int nNetByte) - { - if ((nNetByte < 0) || (nNetByte > 255)) - { - return false; - } - SetData(nNetByte, &id, 20); - return true; - } - - bool Set(const CScriptID &id) { - SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &id, 20); - return true; - } - - bool Set(const CTxDestination &dest) - { - return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); - } - - bool IsValid() const - { - unsigned int nExpectedSize = 20; - bool fExpectTestNet = false; - switch(nVersion) - { - case PUBKEY_ADDRESS: - nExpectedSize = 20; // Hash of public key - fExpectTestNet = false; - break; - case SCRIPT_ADDRESS: - nExpectedSize = 20; // Hash of CScript - fExpectTestNet = false; - break; - - case PUBKEY_ADDRESS_TEST: - nExpectedSize = 20; - fExpectTestNet = true; - break; - case SCRIPT_ADDRESS_TEST: - nExpectedSize = 20; - fExpectTestNet = true; - break; - - default: - return false; - } - return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize; - } - - CBitcoinAddress() - { - } - - CBitcoinAddress(const CTxDestination &dest) - { - Set(dest); - } - - CBitcoinAddress(const std::string& strAddress) - { - SetString(strAddress); - } - - CBitcoinAddress(const char* pszAddress) - { - SetString(pszAddress); - } - - CTxDestination Get() const { - if (!IsValid()) - return CNoDestination(); - switch (nVersion) { - case PUBKEY_ADDRESS: - case PUBKEY_ADDRESS_TEST: { - uint160 id; - memcpy(&id, &vchData[0], 20); - return CKeyID(id); - } - case SCRIPT_ADDRESS: - case SCRIPT_ADDRESS_TEST: { - uint160 id; - memcpy(&id, &vchData[0], 20); - return CScriptID(id); - } - } - return CNoDestination(); - } - - bool GetKeyID(CKeyID &keyID) const { - if (!IsValid()) - return false; - switch (nVersion) { - case PUBKEY_ADDRESS: - case PUBKEY_ADDRESS_TEST: { - uint160 id; - memcpy(&id, &vchData[0], 20); - keyID = CKeyID(id); - return true; - } - default: return false; - } - } - - bool IsScript() const { - if (!IsValid()) - return false; - switch (nVersion) { - case SCRIPT_ADDRESS: - case SCRIPT_ADDRESS_TEST: { - return true; - } - default: return false; - } - } -}; - -bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); } -bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); } -bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; } -bool inline CBitcoinAddressVisitor::operator()(const CStealthAddress &stxAddr) const { return false; } - -/** A base58-encoded secret key */ -class CBitcoinSecret : public CBase58Data -{ -public: - void SetSecret(const CSecret& vchSecret, bool fCompressed) - { - assert(vchSecret.size() == 32); - SetData(128 + (fTestNet ? CBitcoinAddress::PUBKEY_ADDRESS_TEST : CBitcoinAddress::PUBKEY_ADDRESS), &vchSecret[0], vchSecret.size()); - if (fCompressed) - vchData.push_back(1); - } - - CSecret GetSecret(bool &fCompressedOut) - { - CSecret vchSecret; - vchSecret.resize(32); - memcpy(&vchSecret[0], &vchData[0], 32); - fCompressedOut = vchData.size() == 33; - return vchSecret; - } - - bool IsValid() const - { - bool fExpectTestNet = false; - switch(nVersion) - { - case (128 + CBitcoinAddress::PUBKEY_ADDRESS): - break; - - case (128 + CBitcoinAddress::PUBKEY_ADDRESS_TEST): - fExpectTestNet = true; - break; - - default: - return false; - } - return fExpectTestNet == fTestNet && (vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1)); - } - - bool SetString(const char* pszSecret) - { - return CBase58Data::SetString(pszSecret) && IsValid(); - } - - bool SetString(const std::string& strSecret) - { - return SetString(strSecret.c_str()); - } - - CBitcoinSecret(const CSecret& vchSecret, bool fCompressed) - { - SetSecret(vchSecret, fCompressed); - } - - CBitcoinSecret() - { - } -}; + bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < -#endif