|
2 | 2 | // Distributed under the MIT/X11 software license, see the accompanying
|
3 | 3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
4 | 4 |
|
| 5 | +#include "base58.h" |
| 6 | + |
| 7 | +#include "hash.h" |
| 8 | +#include "uint256.h" |
| 9 | + |
5 | 10 | #include <assert.h>
|
6 | 11 | #include <stdint.h>
|
7 | 12 | #include <string.h>
|
8 | 13 | #include <vector>
|
9 | 14 | #include <string>
|
| 15 | +#include <boost/variant/apply_visitor.hpp> |
| 16 | +#include <boost/variant/static_visitor.hpp> |
10 | 17 |
|
11 | 18 | /* All alphanumeric characters except for "0", "I", "O", and "l" */
|
12 | 19 | static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
@@ -89,3 +96,179 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
|
89 | 96 | str += pszBase58[*(it++)];
|
90 | 97 | return str;
|
91 | 98 | }
|
| 99 | + |
| 100 | +std::string EncodeBase58(const std::vector<unsigned char>& vch) { |
| 101 | + return EncodeBase58(&vch[0], &vch[0] + vch.size()); |
| 102 | +} |
| 103 | + |
| 104 | +bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet) { |
| 105 | + return DecodeBase58(str.c_str(), vchRet); |
| 106 | +} |
| 107 | + |
| 108 | +std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) { |
| 109 | + // add 4-byte hash check to the end |
| 110 | + std::vector<unsigned char> vch(vchIn); |
| 111 | + uint256 hash = Hash(vch.begin(), vch.end()); |
| 112 | + vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4); |
| 113 | + return EncodeBase58(vch); |
| 114 | +} |
| 115 | + |
| 116 | +bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) { |
| 117 | + if (!DecodeBase58(psz, vchRet)) |
| 118 | + return false; |
| 119 | + if (vchRet.size() < 4) |
| 120 | + { |
| 121 | + vchRet.clear(); |
| 122 | + return false; |
| 123 | + } |
| 124 | + // re-calculate the checksum, insure it matches the included 4-byte checksum |
| 125 | + uint256 hash = Hash(vchRet.begin(), vchRet.end()-4); |
| 126 | + if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) |
| 127 | + { |
| 128 | + vchRet.clear(); |
| 129 | + return false; |
| 130 | + } |
| 131 | + vchRet.resize(vchRet.size()-4); |
| 132 | + return true; |
| 133 | +} |
| 134 | + |
| 135 | +bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet) { |
| 136 | + return DecodeBase58Check(str.c_str(), vchRet); |
| 137 | +} |
| 138 | + |
| 139 | +CBase58Data::CBase58Data() { |
| 140 | + vchVersion.clear(); |
| 141 | + vchData.clear(); |
| 142 | +} |
| 143 | + |
| 144 | +void CBase58Data::SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize) { |
| 145 | + vchVersion = vchVersionIn; |
| 146 | + vchData.resize(nSize); |
| 147 | + if (!vchData.empty()) |
| 148 | + memcpy(&vchData[0], pdata, nSize); |
| 149 | +} |
| 150 | + |
| 151 | +void CBase58Data::SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend) { |
| 152 | + SetData(vchVersionIn, (void*)pbegin, pend - pbegin); |
| 153 | +} |
| 154 | + |
| 155 | +bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes) { |
| 156 | + std::vector<unsigned char> vchTemp; |
| 157 | + DecodeBase58Check(psz, vchTemp); |
| 158 | + if (vchTemp.size() < nVersionBytes) { |
| 159 | + vchData.clear(); |
| 160 | + vchVersion.clear(); |
| 161 | + return false; |
| 162 | + } |
| 163 | + vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes); |
| 164 | + vchData.resize(vchTemp.size() - nVersionBytes); |
| 165 | + if (!vchData.empty()) |
| 166 | + memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size()); |
| 167 | + OPENSSL_cleanse(&vchTemp[0], vchData.size()); |
| 168 | + return true; |
| 169 | +} |
| 170 | + |
| 171 | +bool CBase58Data::SetString(const std::string& str) { |
| 172 | + return SetString(str.c_str()); |
| 173 | +} |
| 174 | + |
| 175 | +std::string CBase58Data::ToString() const { |
| 176 | + std::vector<unsigned char> vch = vchVersion; |
| 177 | + vch.insert(vch.end(), vchData.begin(), vchData.end()); |
| 178 | + return EncodeBase58Check(vch); |
| 179 | +} |
| 180 | + |
| 181 | +int CBase58Data::CompareTo(const CBase58Data& b58) const { |
| 182 | + if (vchVersion < b58.vchVersion) return -1; |
| 183 | + if (vchVersion > b58.vchVersion) return 1; |
| 184 | + if (vchData < b58.vchData) return -1; |
| 185 | + if (vchData > b58.vchData) return 1; |
| 186 | + return 0; |
| 187 | +} |
| 188 | + |
| 189 | +namespace { |
| 190 | + class CBitcoinAddressVisitor : public boost::static_visitor<bool> { |
| 191 | + private: |
| 192 | + CBitcoinAddress *addr; |
| 193 | + public: |
| 194 | + CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { } |
| 195 | + |
| 196 | + bool operator()(const CKeyID &id) const { return addr->Set(id); } |
| 197 | + bool operator()(const CScriptID &id) const { return addr->Set(id); } |
| 198 | + bool operator()(const CNoDestination &no) const { return false; } |
| 199 | + }; |
| 200 | +}; |
| 201 | + |
| 202 | +bool CBitcoinAddress::Set(const CKeyID &id) { |
| 203 | + SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); |
| 204 | + return true; |
| 205 | +} |
| 206 | + |
| 207 | +bool CBitcoinAddress::Set(const CScriptID &id) { |
| 208 | + SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); |
| 209 | + return true; |
| 210 | +} |
| 211 | + |
| 212 | +bool CBitcoinAddress::Set(const CTxDestination &dest) { |
| 213 | + return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); |
| 214 | +} |
| 215 | + |
| 216 | +bool CBitcoinAddress::IsValid() const { |
| 217 | + bool fCorrectSize = vchData.size() == 20; |
| 218 | + bool fKnownVersion = vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) || |
| 219 | + vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); |
| 220 | + return fCorrectSize && fKnownVersion; |
| 221 | +} |
| 222 | + |
| 223 | +CTxDestination CBitcoinAddress::Get() const { |
| 224 | + if (!IsValid()) |
| 225 | + return CNoDestination(); |
| 226 | + uint160 id; |
| 227 | + memcpy(&id, &vchData[0], 20); |
| 228 | + if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) |
| 229 | + return CKeyID(id); |
| 230 | + else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) |
| 231 | + return CScriptID(id); |
| 232 | + else |
| 233 | + return CNoDestination(); |
| 234 | +} |
| 235 | + |
| 236 | +bool CBitcoinAddress::GetKeyID(CKeyID &keyID) const { |
| 237 | + if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) |
| 238 | + return false; |
| 239 | + uint160 id; |
| 240 | + memcpy(&id, &vchData[0], 20); |
| 241 | + keyID = CKeyID(id); |
| 242 | + return true; |
| 243 | +} |
| 244 | + |
| 245 | +bool CBitcoinAddress::IsScript() const { |
| 246 | + return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); |
| 247 | +} |
| 248 | + |
| 249 | +void CBitcoinSecret::SetKey(const CKey& vchSecret) { |
| 250 | + assert(vchSecret.IsValid()); |
| 251 | + SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size()); |
| 252 | + if (vchSecret.IsCompressed()) |
| 253 | + vchData.push_back(1); |
| 254 | +} |
| 255 | + |
| 256 | +CKey CBitcoinSecret::GetKey() { |
| 257 | + CKey ret; |
| 258 | + ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1); |
| 259 | + return ret; |
| 260 | +} |
| 261 | + |
| 262 | +bool CBitcoinSecret::IsValid() const { |
| 263 | + bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1); |
| 264 | + bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY); |
| 265 | + return fExpectedFormat && fCorrectVersion; |
| 266 | +} |
| 267 | + |
| 268 | +bool CBitcoinSecret::SetString(const char* pszSecret) { |
| 269 | + return CBase58Data::SetString(pszSecret) && IsValid(); |
| 270 | +} |
| 271 | + |
| 272 | +bool CBitcoinSecret::SetString(const std::string& strSecret) { |
| 273 | + return SetString(strSecret.c_str()); |
| 274 | +} |
0 commit comments