Line data Source code
1 : // Copyright (c) 2014 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.
4 :
5 : #include "base58.h"
6 :
7 : #include "hash.h"
8 : #include "uint256.h"
9 :
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>
17 :
18 : /** All alphanumeric characters except for "0", "I", "O", and "l" */
19 : static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
20 :
21 1107 : bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
22 : {
23 : // Skip leading spaces.
24 2228 : while (*psz && isspace(*psz))
25 14 : psz++;
26 : // Skip and count leading '1's.
27 : int zeroes = 0;
28 1164 : while (*psz == '1') {
29 57 : zeroes++;
30 57 : psz++;
31 : }
32 : // Allocate enough space in big-endian base256 representation.
33 2214 : std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up.
34 : // Process the characters.
35 50102 : while (*psz && !isspace(*psz)) {
36 : // Decode base58 character
37 95820 : const char* ch = strchr(pszBase58, *psz);
38 47910 : if (ch == NULL)
39 : return false;
40 : // Apply "b256 = b256 * 58 + ch".
41 47888 : int carry = ch - pszBase58;
42 3589282 : for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) {
43 1770697 : carry += 58 * (*it);
44 1770697 : *it = carry % 256;
45 1770697 : carry /= 256;
46 : }
47 47888 : assert(carry == 0);
48 47888 : psz++;
49 : }
50 : // Skip trailing spaces.
51 1099 : while (isspace(*psz))
52 14 : psz++;
53 1085 : if (*psz != 0)
54 : return false;
55 : // Skip leading zeroes in b256.
56 1084 : std::vector<unsigned char>::iterator it = b256.begin();
57 4839 : while (it != b256.end() && *it == 0)
58 529 : it++;
59 : // Copy result into output vector.
60 3252 : vch.reserve(zeroes + (b256.end() - it));
61 : vch.assign(zeroes, 0x00);
62 72264 : while (it != b256.end())
63 70096 : vch.push_back(*(it++));
64 : return true;
65 : }
66 :
67 2297 : std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
68 : {
69 : // Skip & count leading zeroes.
70 2297 : int zeroes = 0;
71 4652 : while (pbegin != pend && *pbegin == 0) {
72 58 : pbegin++;
73 58 : zeroes++;
74 : }
75 : // Allocate enough space in big-endian base58 representation.
76 4594 : std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up.
77 : // Process the bytes.
78 67804 : while (pbegin != pend) {
79 63210 : int carry = *pbegin;
80 : // Apply "b58 = b58 * 256 + ch".
81 5286812 : for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) {
82 2611801 : carry += 256 * (*it);
83 2611801 : *it = carry % 58;
84 2611801 : carry /= 58;
85 : }
86 63210 : assert(carry == 0);
87 63210 : pbegin++;
88 : }
89 : // Skip leading zeroes in base58 result.
90 2297 : std::vector<unsigned char>::iterator it = b58.begin();
91 13767 : while (it != b58.end() && *it == 0)
92 2292 : it++;
93 : // Translate the result into a string.
94 : std::string str;
95 6891 : str.reserve(zeroes + (b58.end() - it));
96 2297 : str.assign(zeroes, '1');
97 176874 : while (it != b58.end())
98 172280 : str += pszBase58[*(it++)];
99 2297 : return str;
100 : }
101 :
102 0 : std::string EncodeBase58(const std::vector<unsigned char>& vch)
103 : {
104 2285 : return EncodeBase58(&vch[0], &vch[0] + vch.size());
105 : }
106 :
107 12 : bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
108 : {
109 12 : return DecodeBase58(str.c_str(), vchRet);
110 : }
111 :
112 2285 : std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
113 : {
114 : // add 4-byte hash check to the end
115 2285 : std::vector<unsigned char> vch(vchIn);
116 2285 : uint256 hash = Hash(vch.begin(), vch.end());
117 : vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
118 2285 : return EncodeBase58(vch);
119 : }
120 :
121 1092 : bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
122 : {
123 2163 : if (!DecodeBase58(psz, vchRet) ||
124 1071 : (vchRet.size() < 4)) {
125 : vchRet.clear();
126 26 : return false;
127 : }
128 : // re-calculate the checksum, insure it matches the included 4-byte checksum
129 2132 : uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
130 2132 : if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) {
131 : vchRet.clear();
132 19 : return false;
133 : }
134 2094 : vchRet.resize(vchRet.size() - 4);
135 : return true;
136 : }
137 :
138 : bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
139 : {
140 : return DecodeBase58Check(str.c_str(), vchRet);
141 : }
142 :
143 6344 : CBase58Data::CBase58Data()
144 : {
145 3172 : vchVersion.clear();
146 3172 : vchData.clear();
147 3172 : }
148 :
149 2275 : void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)
150 : {
151 2275 : vchVersion = vchVersionIn;
152 2275 : vchData.resize(nSize);
153 4550 : if (!vchData.empty())
154 2275 : memcpy(&vchData[0], pdata, nSize);
155 2275 : }
156 :
157 24 : void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
158 : {
159 24 : SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
160 24 : }
161 :
162 1092 : bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
163 : {
164 : std::vector<unsigned char> vchTemp;
165 1092 : bool rc58 = DecodeBase58Check(psz, vchTemp);
166 2139 : if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
167 45 : vchData.clear();
168 45 : vchVersion.clear();
169 45 : return false;
170 : }
171 3141 : vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
172 2094 : vchData.resize(vchTemp.size() - nVersionBytes);
173 2094 : if (!vchData.empty())
174 3141 : memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());
175 2094 : memory_cleanse(&vchTemp[0], vchData.size());
176 : return true;
177 : }
178 :
179 616 : bool CBase58Data::SetString(const std::string& str)
180 : {
181 616 : return SetString(str.c_str());
182 : }
183 :
184 2285 : std::string CBase58Data::ToString() const
185 : {
186 2285 : std::vector<unsigned char> vch = vchVersion;
187 6855 : vch.insert(vch.end(), vchData.begin(), vchData.end());
188 4570 : return EncodeBase58Check(vch);
189 : }
190 :
191 104 : int CBase58Data::CompareTo(const CBase58Data& b58) const
192 : {
193 208 : if (vchVersion < b58.vchVersion)
194 : return -1;
195 208 : if (vchVersion > b58.vchVersion)
196 : return 1;
197 208 : if (vchData < b58.vchData)
198 : return -1;
199 82 : if (vchData > b58.vchData)
200 : return 1;
201 0 : return 0;
202 : }
203 :
204 : namespace
205 : {
206 1891 : class CBitcoinAddressVisitor : public boost::static_visitor<bool>
207 : {
208 : private:
209 : CBitcoinAddress* addr;
210 :
211 : public:
212 1891 : CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}
213 :
214 3654 : bool operator()(const CKeyID& id) const { return addr->Set(id); }
215 126 : bool operator()(const CScriptID& id) const { return addr->Set(id); }
216 0 : bool operator()(const CNoDestination& no) const { return false; }
217 : };
218 :
219 : } // anon namespace
220 :
221 0 : bool CBitcoinAddress::Set(const CKeyID& id)
222 : {
223 3654 : SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
224 0 : return true;
225 : }
226 :
227 0 : bool CBitcoinAddress::Set(const CScriptID& id)
228 : {
229 126 : SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
230 0 : return true;
231 : }
232 :
233 1891 : bool CBitcoinAddress::Set(const CTxDestination& dest)
234 : {
235 3782 : return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
236 : }
237 :
238 354 : bool CBitcoinAddress::IsValid() const
239 : {
240 907 : return IsValid(Params());
241 : }
242 :
243 907 : bool CBitcoinAddress::IsValid(const CChainParams& params) const
244 : {
245 1814 : bool fCorrectSize = vchData.size() == 20;
246 1077 : bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
247 1077 : vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
248 907 : return fCorrectSize && fKnownVersion;
249 : }
250 :
251 518 : CTxDestination CBitcoinAddress::Get() const
252 : {
253 518 : if (!IsValid())
254 : return CNoDestination();
255 : uint160 id;
256 518 : memcpy(&id, &vchData[0], 20);
257 1036 : if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
258 486 : return CKeyID(id);
259 64 : else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
260 32 : return CScriptID(id);
261 : else
262 : return CNoDestination();
263 : }
264 :
265 6 : bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const
266 : {
267 18 : if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
268 : return false;
269 : uint160 id;
270 6 : memcpy(&id, &vchData[0], 20);
271 6 : keyID = CKeyID(id);
272 6 : return true;
273 : }
274 :
275 29 : bool CBitcoinAddress::IsScript() const
276 : {
277 58 : return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
278 : }
279 :
280 361 : void CBitcoinSecret::SetKey(const CKey& vchSecret)
281 : {
282 361 : assert(vchSecret.IsValid());
283 1444 : SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
284 361 : if (vchSecret.IsCompressed())
285 349 : vchData.push_back(1);
286 361 : }
287 :
288 371 : CKey CBitcoinSecret::GetKey()
289 : {
290 : CKey ret;
291 742 : assert(vchData.size() >= 32);
292 1484 : ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1);
293 371 : return ret;
294 : }
295 :
296 538 : bool CBitcoinSecret::IsValid() const
297 : {
298 1076 : bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
299 1076 : bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
300 538 : return fExpectedFormat && fCorrectVersion;
301 : }
302 :
303 448 : bool CBitcoinSecret::SetString(const char* pszSecret)
304 : {
305 448 : return CBase58Data::SetString(pszSecret) && IsValid();
306 : }
307 :
308 448 : bool CBitcoinSecret::SetString(const std::string& strSecret)
309 : {
310 448 : return SetString(strSecret.c_str());
311 330 : }
|