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. | |||||
* 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 : public CBase58Data { | |||||
public: | |||||
bool Set(const CKeyID &id); | |||||
bool Set(const CScriptID &id); | |||||
bool Set(const CTxDestination &dest); | |||||
bool IsValid() const; | |||||
bool IsValid(const CChainParams ¶ms) const; | |||||
CBitcoinAddress() {} | |||||
CBitcoinAddress(const CTxDestination &dest) { Set(dest); } | |||||
CBitcoinAddress(const std::string &strAddress) { SetString(strAddress); } | |||||
CBitcoinAddress(const char *pszAddress) { SetString(pszAddress); } | |||||
CTxDestination Get() const; | const uint8_t CASHADDR_VERSION_PUBKEY = 0; | ||||
}; | const uint8_t CASHADDR_VERISON_SCRIPT = 8; | ||||
class CBitcoinAddressVisitor : public boost::static_visitor<bool> { | class DestinationEncoder : public boost::static_visitor<std::string> { | ||||
private: | private: | ||||
CBitcoinAddress *addr; | const CChainParams &m_params; | ||||
public: | public: | ||||
CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) {} | DestinationEncoder(const CChainParams ¶ms) : m_params(params) {} | ||||
std::string operator()(const CKeyID &id) const { | |||||
std::vector<uint8_t> data = {CASHADDR_VERSION_PUBKEY}; | |||||
ConvertBits<8, 5, true>(data, id.begin(), id.end()); | |||||
return cashaddr::Encode(m_params.CashAddrHRP(), data); | |||||
} | |||||
std::string operator()(const CScriptID &id) const { | |||||
std::vector<uint8_t> data = {CASHADDR_VERISON_SCRIPT}; | |||||
ConvertBits<8, 5, true>(data, id.begin(), id.end()); | |||||
return cashaddr::Encode(m_params.CashAddrHRP(), data); | |||||
} | |||||
bool operator()(const CKeyID &id) const { return addr->Set(id); } | std::string operator()(const CNoDestination &no) const { return ""; } | ||||
bool operator()(const CScriptID &id) const { return addr->Set(id); } | |||||
bool operator()(const CNoDestination &no) const { return false; } | |||||
}; | }; | ||||
} // anon namespace | CTxDestination | ||||
DecodeCashAddr(const std::pair<std::string, std::vector<uint8_t>> &bech, | |||||
const CChainParams ¶ms) { | |||||
bool CBitcoinAddress::Set(const CKeyID &id) { | if (bech.first != params.CashAddrHRP()) { | ||||
SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); | return CNoDestination{}; | ||||
return true; | |||||
} | } | ||||
bool CBitcoinAddress::Set(const CScriptID &id) { | if (bech.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(bech.second) + 1, | ||||
end(bech.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 = bech.second.at(0); | ||||
vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); | if (version == CASHADDR_VERSION_PUBKEY) { | ||||
return fCorrectSize && fKnownVersion; | return CKeyID(hash); | ||||
} | } | ||||
if (version == CASHADDR_VERISON_SCRIPT) { | |||||
CTxDestination CBitcoinAddress::Get() const { | return CScriptID(hash); | ||||
if (!IsValid()) return CNoDestination(); | } | ||||
uint160 id; | |||||
memcpy(&id, &vchData[0], 20); | // unknown version | ||||
if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) { | return CNoDestination{}; | ||||
return CKeyID(id); | } | ||||
} else if (vchVersion == | |||||
Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) { | CTxDestination DecodeDestination(const std::string &str, | ||||
return CScriptID(id); | const CChainParams ¶ms) { | ||||
} else { | std::vector<unsigned char> data; | ||||
return CNoDestination(); | 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); | ||||
} | } | ||||
Show All 17 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); | ||||
if (!addr.IsValid()) return ""; | |||||
return addr.ToString(); | |||||
} | } | ||||
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())); | ||||
} | } |