Changeset View
Changeset View
Standalone View
Standalone View
src/base58.cpp
// Copyright (c) 2014-2016 The Bitcoin Core developers | // Copyright (c) 2014-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "base58.h" | #include "base58.h" | ||||
#include "cashaddr.h" | |||||
#include "hash.h" | #include "hash.h" | ||||
#include "script/script.h" | |||||
#include "uint256.h" | #include "uint256.h" | ||||
#include "utilstrencodings.h" | |||||
#include <boost/variant/apply_visitor.hpp> | #include <boost/variant/apply_visitor.hpp> | ||||
#include <boost/variant/static_visitor.hpp> | #include <boost/variant/static_visitor.hpp> | ||||
#include <cassert> | #include <cassert> | ||||
#include <cstdint> | #include <cstdint> | ||||
#include <cstring> | #include <cstring> | ||||
#include <string> | #include <string> | ||||
#include <vector> | #include <vector> | ||||
▲ Show 20 Lines • Show All 186 Lines • ▼ Show 20 Lines | int CBase58Data::CompareTo(const CBase58Data &b58) const { | ||||
if (vchVersion < b58.vchVersion) return -1; | if (vchVersion < b58.vchVersion) return -1; | ||||
if (vchVersion > b58.vchVersion) return 1; | if (vchVersion > b58.vchVersion) return 1; | ||||
if (vchData < b58.vchData) return -1; | if (vchData < b58.vchData) return -1; | ||||
if (vchData > b58.vchData) return 1; | if (vchData > b58.vchData) return 1; | ||||
return 0; | return 0; | ||||
} | } | ||||
namespace { | namespace { | ||||
/** | |||||
* base58-encoded Bitcoin addresses. | const uint8_t CASHADDR_VERSION_PUBKEY = 0; | ||||
* Public-key-hash-addresses have version 0 (or 111 testnet). | const uint8_t CASHADDR_VERISON_SCRIPT = 8; | ||||
* The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the | |||||
* serialized public key. | class DestinationEncoder : public boost::static_visitor<std::string> { | ||||
* Script-hash-addresses have version 5 (or 196 testnet). | private: | ||||
* The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the | const CChainParams &m_params; | ||||
* serialized redemption script. | |||||
*/ | |||||
class CBitcoinAddress : public CBase58Data { | |||||
public: | public: | ||||
bool Set(const CKeyID &id); | DestinationEncoder(const CChainParams ¶ms) : m_params(params) {} | ||||
bool Set(const CScriptID &id); | |||||
bool Set(const CTxDestination &dest); | std::string operator()(const CKeyID &id) const { | ||||
bool IsValid() const; | std::vector<uint8_t> data = {CASHADDR_VERSION_PUBKEY}; | ||||
bool IsValid(const CChainParams ¶ms) const; | ConvertBits<8, 5, true>(data, id.begin(), id.end()); | ||||
return cashaddr::Encode(m_params.CashAddrPrefix(), data); | |||||
CBitcoinAddress() {} | } | ||||
CBitcoinAddress(const CTxDestination &dest) { Set(dest); } | |||||
CBitcoinAddress(const std::string &strAddress) { SetString(strAddress); } | std::string operator()(const CScriptID &id) const { | ||||
CBitcoinAddress(const char *pszAddress) { SetString(pszAddress); } | std::vector<uint8_t> data = {CASHADDR_VERISON_SCRIPT}; | ||||
ConvertBits<8, 5, true>(data, id.begin(), id.end()); | |||||
return cashaddr::Encode(m_params.CashAddrPrefix(), data); | |||||
} | |||||
CTxDestination Get() const; | std::string operator()(const CNoDestination &no) const { return ""; } | ||||
}; | }; | ||||
class CBitcoinAddressVisitor : public boost::static_visitor<bool> { | /// Deprecated: This is the legacy BTC encoding. | ||||
class Base58DestinationEncoder : public boost::static_visitor<std::string> { | |||||
private: | private: | ||||
CBitcoinAddress *addr; | const CChainParams &m_params; | ||||
public: | public: | ||||
CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) {} | Base58DestinationEncoder(const CChainParams ¶ms) : m_params(params) {} | ||||
std::string operator()(const CKeyID &id) const { | |||||
std::vector<unsigned char> data = | |||||
m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); | |||||
data.insert(data.end(), id.begin(), id.end()); | |||||
return EncodeBase58Check(data); | |||||
} | |||||
bool operator()(const CKeyID &id) const { return addr->Set(id); } | std::string operator()(const CScriptID &id) const { | ||||
bool operator()(const CScriptID &id) const { return addr->Set(id); } | std::vector<unsigned char> data = | ||||
bool operator()(const CNoDestination &no) const { return false; } | m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); | ||||
data.insert(data.end(), id.begin(), id.end()); | |||||
return EncodeBase58Check(data); | |||||
} | |||||
std::string operator()(const CNoDestination &no) const { return ""; } | |||||
}; | }; | ||||
} // anon namespace | CTxDestination | ||||
DecodeCashAddr(const std::pair<std::string, std::vector<uint8_t>> &cashaddr, | |||||
const CChainParams ¶ms) { | |||||
bool CBitcoinAddress::Set(const CKeyID &id) { | if (cashaddr.first != params.CashAddrPrefix()) { | ||||
SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); | return CNoDestination{}; | ||||
return true; | |||||
} | } | ||||
bool CBitcoinAddress::Set(const CScriptID &id) { | if (cashaddr.second.empty()) { | ||||
SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); | return CNoDestination{}; | ||||
return true; | |||||
} | } | ||||
bool CBitcoinAddress::Set(const CTxDestination &dest) { | std::vector<unsigned char> data; | ||||
return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); | if (!ConvertBits<5, 8, false>(data, begin(cashaddr.second) + 1, | ||||
end(cashaddr.second))) { | |||||
return CNoDestination(); | |||||
} | } | ||||
bool CBitcoinAddress::IsValid() const { | if (data.size() != 20) { | ||||
return IsValid(Params()); | return CNoDestination{}; | ||||
} | } | ||||
bool CBitcoinAddress::IsValid(const CChainParams ¶ms) const { | uint160 hash; | ||||
bool fCorrectSize = vchData.size() == 20; | memcpy(hash.begin(), &data[0], 20); | ||||
bool fKnownVersion = | |||||
vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) || | int version = cashaddr.second.at(0); | ||||
vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); | if (version == CASHADDR_VERSION_PUBKEY) { | ||||
return fCorrectSize && fKnownVersion; | return CKeyID(hash); | ||||
} | |||||
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(); | |||||
} | } | ||||
if (version == CASHADDR_VERISON_SCRIPT) { | |||||
return CScriptID(hash); | |||||
} | } | ||||
// unknown version | |||||
return CNoDestination{}; | |||||
} | |||||
CTxDestination DecodeDestination(const std::string &str, | |||||
const CChainParams ¶ms) { | |||||
std::vector<unsigned char> data; | |||||
uint160 hash; | |||||
if (DecodeBase58Check(str, data)) { | |||||
// Base58Check decoding | |||||
const std::vector<unsigned char> &pubkey_prefix = | |||||
params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); | |||||
if (data.size() == 20 + pubkey_prefix.size() && | |||||
std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), | |||||
data.begin())) { | |||||
memcpy(hash.begin(), &data[pubkey_prefix.size()], 20); | |||||
return CKeyID(hash); | |||||
} | |||||
const std::vector<unsigned char> &script_prefix = | |||||
params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); | |||||
if (data.size() == 20 + script_prefix.size() && | |||||
std::equal(script_prefix.begin(), script_prefix.end(), | |||||
data.begin())) { | |||||
memcpy(hash.begin(), &data[script_prefix.size()], 20); | |||||
return CScriptID(hash); | |||||
} | |||||
} | |||||
return DecodeCashAddr(cashaddr::Decode(str), params); | |||||
} | |||||
} // namespace | |||||
void CBitcoinSecret::SetKey(const CKey &vchSecret) { | void CBitcoinSecret::SetKey(const CKey &vchSecret) { | ||||
assert(vchSecret.IsValid()); | assert(vchSecret.IsValid()); | ||||
SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), | SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), | ||||
vchSecret.size()); | vchSecret.size()); | ||||
if (vchSecret.IsCompressed()) vchData.push_back(1); | if (vchSecret.IsCompressed()) vchData.push_back(1); | ||||
} | } | ||||
CKey CBitcoinSecret::GetKey() { | CKey CBitcoinSecret::GetKey() { | ||||
Show All 16 Lines | bool CBitcoinSecret::SetString(const char *pszSecret) { | ||||
return CBase58Data::SetString(pszSecret) && IsValid(); | return CBase58Data::SetString(pszSecret) && IsValid(); | ||||
} | } | ||||
bool CBitcoinSecret::SetString(const std::string &strSecret) { | bool CBitcoinSecret::SetString(const std::string &strSecret) { | ||||
return SetString(strSecret.c_str()); | return SetString(strSecret.c_str()); | ||||
} | } | ||||
std::string EncodeDestination(const CTxDestination &dest) { | std::string EncodeDestination(const CTxDestination &dest) { | ||||
CBitcoinAddress addr(dest); | return boost::apply_visitor(DestinationEncoder(Params()), dest); | ||||
return addr.IsValid() ? addr.ToString() : ""; | } | ||||
// deprecated | |||||
std::string EncodeDestinationBase58(const CTxDestination &dest) { | |||||
return boost::apply_visitor(Base58DestinationEncoder(Params()), dest); | |||||
} | } | ||||
CTxDestination DecodeDestination(const std::string &str) { | CTxDestination DecodeDestination(const std::string &str) { | ||||
return CBitcoinAddress(str).Get(); | return DecodeDestination(str, Params()); | ||||
} | } | ||||
bool IsValidDestinationString(const std::string &str, | bool IsValidDestinationString(const std::string &str, | ||||
const CChainParams ¶ms) { | const CChainParams ¶ms) { | ||||
return CBitcoinAddress(str).IsValid(params); | return IsValidDestination(DecodeDestination(str, params)); | ||||
} | } | ||||
bool IsValidDestinationString(const std::string &str) { | bool IsValidDestinationString(const std::string &str) { | ||||
return CBitcoinAddress(str).IsValid(); | return IsValidDestination(DecodeDestination(str, Params())); | ||||
} | } |