Improve readability of DecodeBase58Check(...)
[bitcoinplatinum.git] / src / base58.cpp
blob56acf392ca3895a29900ca5cd3d59c9d664aae18
1 // Copyright (c) 2014-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 #include "base58.h"
7 #include "hash.h"
8 #include "uint256.h"
10 #include <assert.h>
11 #include <stdint.h>
12 #include <string.h>
13 #include <vector>
14 #include <string>
15 #include <boost/variant/apply_visitor.hpp>
16 #include <boost/variant/static_visitor.hpp>
18 /** All alphanumeric characters except for "0", "I", "O", and "l" */
19 static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
21 bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
23 // Skip leading spaces.
24 while (*psz && isspace(*psz))
25 psz++;
26 // Skip and count leading '1's.
27 int zeroes = 0;
28 int length = 0;
29 while (*psz == '1') {
30 zeroes++;
31 psz++;
33 // Allocate enough space in big-endian base256 representation.
34 int size = strlen(psz) * 733 /1000 + 1; // log(58) / log(256), rounded up.
35 std::vector<unsigned char> b256(size);
36 // Process the characters.
37 while (*psz && !isspace(*psz)) {
38 // Decode base58 character
39 const char* ch = strchr(pszBase58, *psz);
40 if (ch == nullptr)
41 return false;
42 // Apply "b256 = b256 * 58 + ch".
43 int carry = ch - pszBase58;
44 int i = 0;
45 for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); (carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {
46 carry += 58 * (*it);
47 *it = carry % 256;
48 carry /= 256;
50 assert(carry == 0);
51 length = i;
52 psz++;
54 // Skip trailing spaces.
55 while (isspace(*psz))
56 psz++;
57 if (*psz != 0)
58 return false;
59 // Skip leading zeroes in b256.
60 std::vector<unsigned char>::iterator it = b256.begin() + (size - length);
61 while (it != b256.end() && *it == 0)
62 it++;
63 // Copy result into output vector.
64 vch.reserve(zeroes + (b256.end() - it));
65 vch.assign(zeroes, 0x00);
66 while (it != b256.end())
67 vch.push_back(*(it++));
68 return true;
71 std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
73 // Skip & count leading zeroes.
74 int zeroes = 0;
75 int length = 0;
76 while (pbegin != pend && *pbegin == 0) {
77 pbegin++;
78 zeroes++;
80 // Allocate enough space in big-endian base58 representation.
81 int size = (pend - pbegin) * 138 / 100 + 1; // log(256) / log(58), rounded up.
82 std::vector<unsigned char> b58(size);
83 // Process the bytes.
84 while (pbegin != pend) {
85 int carry = *pbegin;
86 int i = 0;
87 // Apply "b58 = b58 * 256 + ch".
88 for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); (carry != 0 || i < length) && (it != b58.rend()); it++, i++) {
89 carry += 256 * (*it);
90 *it = carry % 58;
91 carry /= 58;
94 assert(carry == 0);
95 length = i;
96 pbegin++;
98 // Skip leading zeroes in base58 result.
99 std::vector<unsigned char>::iterator it = b58.begin() + (size - length);
100 while (it != b58.end() && *it == 0)
101 it++;
102 // Translate the result into a string.
103 std::string str;
104 str.reserve(zeroes + (b58.end() - it));
105 str.assign(zeroes, '1');
106 while (it != b58.end())
107 str += pszBase58[*(it++)];
108 return str;
111 std::string EncodeBase58(const std::vector<unsigned char>& vch)
113 return EncodeBase58(vch.data(), vch.data() + vch.size());
116 bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
118 return DecodeBase58(str.c_str(), vchRet);
121 std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
123 // add 4-byte hash check to the end
124 std::vector<unsigned char> vch(vchIn);
125 uint256 hash = Hash(vch.begin(), vch.end());
126 vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
127 return EncodeBase58(vch);
130 bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
132 if (!DecodeBase58(psz, vchRet) ||
133 (vchRet.size() < 4)) {
134 vchRet.clear();
135 return false;
137 // re-calculate the checksum, ensure it matches the included 4-byte checksum
138 uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
139 if (memcmp(&hash, &vchRet[vchRet.size() - 4], 4) != 0) {
140 vchRet.clear();
141 return false;
143 vchRet.resize(vchRet.size() - 4);
144 return true;
147 bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
149 return DecodeBase58Check(str.c_str(), vchRet);
152 CBase58Data::CBase58Data()
154 vchVersion.clear();
155 vchData.clear();
158 void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)
160 vchVersion = vchVersionIn;
161 vchData.resize(nSize);
162 if (!vchData.empty())
163 memcpy(vchData.data(), pdata, nSize);
166 void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
168 SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
171 bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
173 std::vector<unsigned char> vchTemp;
174 bool rc58 = DecodeBase58Check(psz, vchTemp);
175 if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
176 vchData.clear();
177 vchVersion.clear();
178 return false;
180 vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
181 vchData.resize(vchTemp.size() - nVersionBytes);
182 if (!vchData.empty())
183 memcpy(vchData.data(), vchTemp.data() + nVersionBytes, vchData.size());
184 memory_cleanse(vchTemp.data(), vchTemp.size());
185 return true;
188 bool CBase58Data::SetString(const std::string& str)
190 return SetString(str.c_str());
193 std::string CBase58Data::ToString() const
195 std::vector<unsigned char> vch = vchVersion;
196 vch.insert(vch.end(), vchData.begin(), vchData.end());
197 return EncodeBase58Check(vch);
200 int CBase58Data::CompareTo(const CBase58Data& b58) const
202 if (vchVersion < b58.vchVersion)
203 return -1;
204 if (vchVersion > b58.vchVersion)
205 return 1;
206 if (vchData < b58.vchData)
207 return -1;
208 if (vchData > b58.vchData)
209 return 1;
210 return 0;
213 namespace
215 class CBitcoinAddressVisitor : public boost::static_visitor<bool>
217 private:
218 CBitcoinAddress* addr;
220 public:
221 explicit CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}
223 bool operator()(const CKeyID& id) const { return addr->Set(id); }
224 bool operator()(const CScriptID& id) const { return addr->Set(id); }
225 bool operator()(const CNoDestination& no) const { return false; }
228 } // namespace
230 bool CBitcoinAddress::Set(const CKeyID& id)
232 SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
233 return true;
236 bool CBitcoinAddress::Set(const CScriptID& id)
238 SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
239 return true;
242 bool CBitcoinAddress::Set(const CTxDestination& dest)
244 return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
247 bool CBitcoinAddress::IsValid() const
249 return IsValid(Params());
252 bool CBitcoinAddress::IsValid(const CChainParams& params) const
254 bool fCorrectSize = vchData.size() == 20;
255 bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
256 vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
257 return fCorrectSize && fKnownVersion;
260 CTxDestination CBitcoinAddress::Get() const
262 if (!IsValid())
263 return CNoDestination();
264 uint160 id;
265 memcpy(&id, vchData.data(), 20);
266 if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
267 return CKeyID(id);
268 else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
269 return CScriptID(id);
270 else
271 return CNoDestination();
274 bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
276 if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
277 return false;
278 uint160 id;
279 memcpy(&id, vchData.data(), 20);
280 keyID = CKeyID(id);
281 return true;
284 bool CBitcoinAddress::IsScript() const
286 return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
289 void CBitcoinSecret::SetKey(const CKey& vchSecret)
291 assert(vchSecret.IsValid());
292 SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
293 if (vchSecret.IsCompressed())
294 vchData.push_back(1);
297 CKey CBitcoinSecret::GetKey()
299 CKey ret;
300 assert(vchData.size() >= 32);
301 ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1);
302 return ret;
305 bool CBitcoinSecret::IsValid() const
307 bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
308 bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
309 return fExpectedFormat && fCorrectVersion;
312 bool CBitcoinSecret::SetString(const char* pszSecret)
314 return CBase58Data::SetString(pszSecret) && IsValid();
317 bool CBitcoinSecret::SetString(const std::string& strSecret)
319 return SetString(strSecret.c_str());