123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- // Copyright (c) 2014 The Bitcoin Core developers
- // Distributed under the MIT software license, see the accompanying
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
- #include "base58.h"
- #include "hash.h"
- #include "uint256.h"
- #include "version.h"
- #include "streams.h"
- #include <assert.h>
- #include <stdint.h>
- #include <string.h>
- #include <vector>
- #include <string>
- #include <boost/variant/apply_visitor.hpp>
- #include <boost/variant/static_visitor.hpp>
- /** All alphanumeric characters except for "0", "I", "O", and "l" */
- static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
- bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
- {
- // Skip leading spaces.
- while (*psz && isspace(*psz))
- psz++;
- // Skip and count leading '1's.
- int zeroes = 0;
- while (*psz == '1') {
- zeroes++;
- psz++;
- }
- // 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.
- 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;
- while (pbegin != pend && *pbegin == 0) {
- pbegin++;
- zeroes++;
- }
- // Allocate enough space in big-endian base58 representation.
- std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up.
- // Process the bytes.
- while (pbegin != pend) {
- int carry = *pbegin;
- // Apply "b58 = b58 * 256 + ch".
- for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) {
- carry += 256 * (*it);
- *it = carry % 58;
- carry /= 58;
- }
- assert(carry == 0);
- pbegin++;
- }
- // Skip leading zeroes in base58 result.
- std::vector<unsigned char>::iterator it = b58.begin();
- 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;
- }
- std::string EncodeBase58(const std::vector<unsigned char>& vch)
- {
- return EncodeBase58(&vch[0], &vch[0] + vch.size());
- }
- bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
- {
- return DecodeBase58(str.c_str(), vchRet);
- }
- std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
- {
- // add 4-byte hash check to the end
- std::vector<unsigned char> vch(vchIn);
- uint256 hash = Hash(vch.begin(), vch.end());
- vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
- return EncodeBase58(vch);
- }
- bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
- {
- if (!DecodeBase58(psz, vchRet) ||
- (vchRet.size() < 4)) {
- vchRet.clear();
- return false;
- }
- // re-calculate the checksum, insure it matches the included 4-byte checksum
- 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;
- }
- bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
- {
- return DecodeBase58Check(str.c_str(), vchRet);
- }
- CBase58Data::CBase58Data()
- {
- vchVersion.clear();
- vchData.clear();
- }
- void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)
- {
- vchVersion = vchVersionIn;
- vchData.resize(nSize);
- if (!vchData.empty())
- memcpy(&vchData[0], pdata, nSize);
- }
- void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
- {
- SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
- }
- bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
- {
- std::vector<unsigned char> vchTemp;
- bool rc58 = DecodeBase58Check(psz, vchTemp);
- if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
- vchData.clear();
- vchVersion.clear();
- return false;
- }
- vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
- vchData.resize(vchTemp.size() - nVersionBytes);
- if (!vchData.empty())
- memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());
- memory_cleanse(&vchTemp[0], vchData.size());
- return true;
- }
- bool CBase58Data::SetString(const std::string& str, unsigned int nVersionBytes)
- {
- return SetString(str.c_str(), nVersionBytes);
- }
- std::string CBase58Data::ToString() const
- {
- std::vector<unsigned char> vch = vchVersion;
- vch.insert(vch.end(), vchData.begin(), vchData.end());
- return EncodeBase58Check(vch);
- }
- int CBase58Data::CompareTo(const CBase58Data& b58) const
- {
- if (vchVersion < b58.vchVersion)
- return -1;
- if (vchVersion > b58.vchVersion)
- return 1;
- if (vchData < b58.vchData)
- return -1;
- if (vchData > b58.vchData)
- return 1;
- return 0;
- }
- namespace
- {
- class CBitcoinAddressVisitor : public boost::static_visitor<bool>
- {
- private:
- CBitcoinAddress* addr;
- public:
- CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}
- bool operator()(const CKeyID& id) const { return addr->Set(id); }
- bool operator()(const CScriptID& id) const { return addr->Set(id); }
- bool operator()(const CNoDestination& no) const { return false; }
- };
- } // anon namespace
- bool CBitcoinAddress::Set(const CKeyID& id)
- {
- SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
- return true;
- }
- bool CBitcoinAddress::Set(const CScriptID& id)
- {
- SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
- return true;
- }
- bool CBitcoinAddress::Set(const CTxDestination& dest)
- {
- return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
- }
- bool CBitcoinAddress::IsValid() const
- {
- return IsValid(Params());
- }
- bool CBitcoinAddress::IsValid(const CChainParams& params) const
- {
- bool fCorrectSize = vchData.size() == 20;
- bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
- vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
- return fCorrectSize && fKnownVersion;
- }
- bool CBitcoinAddress::SetString(const char* pszAddress)
- {
- return CBase58Data::SetString(pszAddress, 2);
- }
- bool CBitcoinAddress::SetString(const std::string& strAddress)
- {
- return SetString(strAddress.c_str());
- }
- CTxDestination CBitcoinAddress::Get() const
- {
- if (!IsValid())
- return CNoDestination();
- uint160 id;
- memcpy(&id, &vchData[0], 20);
- if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
- return CKeyID(id);
- else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
- return CScriptID(id);
- else
- return CNoDestination();
- }
- bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
- {
- if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
- return false;
- uint160 id;
- memcpy(&id, &vchData[0], 20);
- keyID = CKeyID(id);
- return true;
- }
- bool CBitcoinAddress::IsScript() const
- {
- return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
- }
- void CBitcoinSecret::SetKey(const CKey& vchSecret)
- {
- assert(vchSecret.IsValid());
- SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
- if (vchSecret.IsCompressed())
- vchData.push_back(1);
- }
- CKey CBitcoinSecret::GetKey()
- {
- CKey ret;
- assert(vchData.size() >= 32);
- ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1);
- return ret;
- }
- bool CBitcoinSecret::IsValid() const
- {
- bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
- bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
- return fExpectedFormat && fCorrectVersion;
- }
- bool CBitcoinSecret::SetString(const char* pszSecret)
- {
- return CBase58Data::SetString(pszSecret, 1) && IsValid();
- }
- bool CBitcoinSecret::SetString(const std::string& strSecret)
- {
- return SetString(strSecret.c_str());
- }
- bool CZCPaymentAddress::Set(const libzcash::PaymentAddress& addr)
- {
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
- ss << addr;
- std::vector<unsigned char> addrSerialized(ss.begin(), ss.end());
- assert(addrSerialized.size() == libzcash::SerializedPaymentAddressSize);
- SetData(Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS), &addrSerialized[0], libzcash::SerializedPaymentAddressSize);
- return true;
- }
- libzcash::PaymentAddress CZCPaymentAddress::Get() const
- {
- if (vchData.size() != libzcash::SerializedPaymentAddressSize) {
- throw std::runtime_error(
- "payment address is invalid"
- );
- }
- if (vchVersion != Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS)) {
- throw std::runtime_error(
- "payment address is for wrong network type"
- );
- }
- std::vector<unsigned char> serialized(vchData.begin(), vchData.end());
- CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
- libzcash::PaymentAddress ret;
- ss >> ret;
- return ret;
- }
- bool CZCSpendingKey::Set(const libzcash::SpendingKey& addr)
- {
- CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
- ss << addr;
- std::vector<unsigned char> addrSerialized(ss.begin(), ss.end());
- assert(addrSerialized.size() == libzcash::SerializedSpendingKeySize);
- SetData(Params().Base58Prefix(CChainParams::ZCSPENDING_KEY), &addrSerialized[0], libzcash::SerializedSpendingKeySize);
- return true;
- }
- libzcash::SpendingKey CZCSpendingKey::Get() const
- {
- if (vchData.size() != libzcash::SerializedSpendingKeySize) {
- throw std::runtime_error(
- "spending key is invalid"
- );
- }
- if (vchVersion != Params().Base58Prefix(CChainParams::ZCSPENDING_KEY)) {
- throw std::runtime_error(
- "spending key is for wrong network type"
- );
- }
- std::vector<unsigned char> serialized(vchData.begin(), vchData.end());
- CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
- libzcash::SpendingKey ret;
- ss >> ret;
- return ret;
- }
|