]>
Commit | Line | Data |
---|---|---|
f914f1a7 | 1 | // Copyright (c) 2014 The Bitcoin Core developers |
fa94b9d5 | 2 | // Distributed under the MIT software license, see the accompanying |
b58be132 PW |
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | ||
f6b7c644 PW |
5 | #include "base58.h" |
6 | ||
3d31e09c PW |
7 | #include <hash.h> |
8 | #include <uint256.h> | |
e104fcdd | 9 | |
b58be132 | 10 | #include <assert.h> |
b58be132 | 11 | #include <string.h> |
9feb4b9e | 12 | #include <stdint.h> |
b58be132 PW |
13 | #include <vector> |
14 | #include <string> | |
f6b7c644 PW |
15 | #include <boost/variant/apply_visitor.hpp> |
16 | #include <boost/variant/static_visitor.hpp> | |
b58be132 | 17 | |
fa94b9d5 | 18 | /** All alphanumeric characters except for "0", "I", "O", and "l" */ |
b58be132 PW |
19 | static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; |
20 | ||
20e01b1a PW |
21 | bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch) |
22 | { | |
b58be132 PW |
23 | // Skip leading spaces. |
24 | while (*psz && isspace(*psz)) | |
25 | psz++; | |
26 | // Skip and count leading '1's. | |
27 | int zeroes = 0; | |
28 | while (*psz == '1') { | |
29 | zeroes++; | |
30 | psz++; | |
31 | } | |
32 | // Allocate enough space in big-endian base256 representation. | |
33 | std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up. | |
34 | // Process the characters. | |
35 | while (*psz && !isspace(*psz)) { | |
36 | // Decode base58 character | |
20e01b1a | 37 | const char* ch = strchr(pszBase58, *psz); |
b58be132 PW |
38 | if (ch == NULL) |
39 | return false; | |
40 | // Apply "b256 = b256 * 58 + ch". | |
41 | int carry = ch - pszBase58; | |
42 | for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) { | |
43 | carry += 58 * (*it); | |
44 | *it = carry % 256; | |
45 | carry /= 256; | |
46 | } | |
47 | assert(carry == 0); | |
48 | psz++; | |
49 | } | |
50 | // Skip trailing spaces. | |
51 | while (isspace(*psz)) | |
52 | psz++; | |
53 | if (*psz != 0) | |
54 | return false; | |
55 | // Skip leading zeroes in b256. | |
56 | std::vector<unsigned char>::iterator it = b256.begin(); | |
57 | while (it != b256.end() && *it == 0) | |
58 | it++; | |
59 | // Copy result into output vector. | |
60 | vch.reserve(zeroes + (b256.end() - it)); | |
61 | vch.assign(zeroes, 0x00); | |
62 | while (it != b256.end()) | |
20e01b1a | 63 | vch.push_back(*(it++)); |
b58be132 PW |
64 | return true; |
65 | } | |
66 | ||
20e01b1a PW |
67 | std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) |
68 | { | |
b58be132 PW |
69 | // Skip & count leading zeroes. |
70 | int zeroes = 0; | |
71 | while (pbegin != pend && *pbegin == 0) { | |
72 | pbegin++; | |
73 | zeroes++; | |
74 | } | |
75 | // Allocate enough space in big-endian base58 representation. | |
76 | std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up. | |
77 | // Process the bytes. | |
78 | while (pbegin != pend) { | |
79 | int carry = *pbegin; | |
80 | // Apply "b58 = b58 * 256 + ch". | |
81 | for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) { | |
82 | carry += 256 * (*it); | |
83 | *it = carry % 58; | |
84 | carry /= 58; | |
85 | } | |
86 | assert(carry == 0); | |
87 | pbegin++; | |
88 | } | |
89 | // Skip leading zeroes in base58 result. | |
90 | std::vector<unsigned char>::iterator it = b58.begin(); | |
91 | while (it != b58.end() && *it == 0) | |
92 | it++; | |
93 | // Translate the result into a string. | |
94 | std::string str; | |
95 | str.reserve(zeroes + (b58.end() - it)); | |
96 | str.assign(zeroes, '1'); | |
97 | while (it != b58.end()) | |
98 | str += pszBase58[*(it++)]; | |
99 | return str; | |
100 | } | |
f6b7c644 | 101 | |
20e01b1a PW |
102 | std::string EncodeBase58(const std::vector<unsigned char>& vch) |
103 | { | |
1b34996b | 104 | return EncodeBase58(vch.data(), vch.data() + vch.size()); |
f6b7c644 PW |
105 | } |
106 | ||
20e01b1a PW |
107 | bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet) |
108 | { | |
f6b7c644 PW |
109 | return DecodeBase58(str.c_str(), vchRet); |
110 | } | |
111 | ||
20e01b1a PW |
112 | std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) |
113 | { | |
f6b7c644 PW |
114 | // add 4-byte hash check to the end |
115 | std::vector<unsigned char> vch(vchIn); | |
116 | uint256 hash = Hash(vch.begin(), vch.end()); | |
117 | vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4); | |
118 | return EncodeBase58(vch); | |
119 | } | |
120 | ||
20e01b1a PW |
121 | bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) |
122 | { | |
88df548d | 123 | if (!DecodeBase58(psz, vchRet) || |
20e01b1a | 124 | (vchRet.size() < 4)) { |
f6b7c644 PW |
125 | vchRet.clear(); |
126 | return false; | |
127 | } | |
128 | // re-calculate the checksum, insure it matches the included 4-byte checksum | |
20e01b1a PW |
129 | uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4); |
130 | if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) { | |
f6b7c644 PW |
131 | vchRet.clear(); |
132 | return false; | |
133 | } | |
20e01b1a | 134 | vchRet.resize(vchRet.size() - 4); |
f6b7c644 PW |
135 | return true; |
136 | } | |
137 | ||
20e01b1a PW |
138 | bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet) |
139 | { | |
f6b7c644 PW |
140 | return DecodeBase58Check(str.c_str(), vchRet); |
141 | } | |
142 | ||
9feb4b9e | 143 | |
20e01b1a PW |
144 | CBase58Data::CBase58Data() |
145 | { | |
f6b7c644 PW |
146 | vchVersion.clear(); |
147 | vchData.clear(); | |
148 | } | |
149 | ||
20e01b1a PW |
150 | void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize) |
151 | { | |
f6b7c644 PW |
152 | vchVersion = vchVersionIn; |
153 | vchData.resize(nSize); | |
154 | if (!vchData.empty()) | |
155 | memcpy(&vchData[0], pdata, nSize); | |
156 | } | |
157 | ||
20e01b1a PW |
158 | void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend) |
159 | { | |
f6b7c644 PW |
160 | SetData(vchVersionIn, (void*)pbegin, pend - pbegin); |
161 | } | |
162 | ||
20e01b1a PW |
163 | bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes) |
164 | { | |
f6b7c644 | 165 | std::vector<unsigned char> vchTemp; |
88df548d JG |
166 | bool rc58 = DecodeBase58Check(psz, vchTemp); |
167 | if ((!rc58) || (vchTemp.size() < nVersionBytes)) { | |
f6b7c644 PW |
168 | vchData.clear(); |
169 | vchVersion.clear(); | |
170 | return false; | |
171 | } | |
172 | vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes); | |
173 | vchData.resize(vchTemp.size() - nVersionBytes); | |
174 | if (!vchData.empty()) | |
175 | memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size()); | |
1630219d | 176 | memory_cleanse(&vchTemp[0], vchData.size()); |
f6b7c644 PW |
177 | return true; |
178 | } | |
179 | ||
00e56272 | 180 | bool CBase58Data::SetString(const std::string& str, unsigned int nVersionBytes) |
20e01b1a | 181 | { |
00e56272 | 182 | return SetString(str.c_str(), nVersionBytes); |
f6b7c644 PW |
183 | } |
184 | ||
20e01b1a PW |
185 | std::string CBase58Data::ToString() const |
186 | { | |
f6b7c644 PW |
187 | std::vector<unsigned char> vch = vchVersion; |
188 | vch.insert(vch.end(), vchData.begin(), vchData.end()); | |
189 | return EncodeBase58Check(vch); | |
190 | } | |
191 | ||
20e01b1a PW |
192 | int CBase58Data::CompareTo(const CBase58Data& b58) const |
193 | { | |
194 | if (vchVersion < b58.vchVersion) | |
195 | return -1; | |
196 | if (vchVersion > b58.vchVersion) | |
197 | return 1; | |
198 | if (vchData < b58.vchData) | |
199 | return -1; | |
200 | if (vchData > b58.vchData) | |
201 | return 1; | |
f6b7c644 PW |
202 | return 0; |
203 | } | |
204 | ||
20e01b1a PW |
205 | namespace |
206 | { | |
207 | class CBitcoinAddressVisitor : public boost::static_visitor<bool> | |
208 | { | |
209 | private: | |
210 | CBitcoinAddress* addr; | |
e10dcf27 | 211 | |
20e01b1a PW |
212 | public: |
213 | CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {} | |
f6b7c644 | 214 | |
20e01b1a PW |
215 | bool operator()(const CKeyID& id) const { return addr->Set(id); } |
216 | bool operator()(const CScriptID& id) const { return addr->Set(id); } | |
217 | bool operator()(const CNoDestination& no) const { return false; } | |
218 | }; | |
e10dcf27 PK |
219 | |
220 | } // anon namespace | |
f6b7c644 | 221 | |
20e01b1a PW |
222 | bool CBitcoinAddress::Set(const CKeyID& id) |
223 | { | |
f6b7c644 PW |
224 | SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); |
225 | return true; | |
226 | } | |
227 | ||
20e01b1a PW |
228 | bool CBitcoinAddress::Set(const CScriptID& id) |
229 | { | |
f6b7c644 PW |
230 | SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); |
231 | return true; | |
232 | } | |
233 | ||
20e01b1a PW |
234 | bool CBitcoinAddress::Set(const CTxDestination& dest) |
235 | { | |
f6b7c644 PW |
236 | return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); |
237 | } | |
238 | ||
20e01b1a PW |
239 | bool CBitcoinAddress::IsValid() const |
240 | { | |
e84843c0 RN |
241 | return IsValid(Params()); |
242 | } | |
243 | ||
20e01b1a PW |
244 | bool CBitcoinAddress::IsValid(const CChainParams& params) const |
245 | { | |
f6b7c644 | 246 | bool fCorrectSize = vchData.size() == 20; |
e84843c0 RN |
247 | bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) || |
248 | vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); | |
f6b7c644 PW |
249 | return fCorrectSize && fKnownVersion; |
250 | } | |
251 | ||
00e56272 DH |
252 | bool CBitcoinAddress::SetString(const char* pszAddress) |
253 | { | |
a18c8eaa | 254 | return CBase58Data::SetString(pszAddress, 1);//2); |
00e56272 DH |
255 | } |
256 | ||
257 | bool CBitcoinAddress::SetString(const std::string& strAddress) | |
258 | { | |
259 | return SetString(strAddress.c_str()); | |
260 | } | |
261 | ||
20e01b1a PW |
262 | CTxDestination CBitcoinAddress::Get() const |
263 | { | |
f6b7c644 PW |
264 | if (!IsValid()) |
265 | return CNoDestination(); | |
266 | uint160 id; | |
267 | memcpy(&id, &vchData[0], 20); | |
268 | if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) | |
269 | return CKeyID(id); | |
270 | else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) | |
271 | return CScriptID(id); | |
272 | else | |
273 | return CNoDestination(); | |
274 | } | |
275 | ||
8b78a819 T |
276 | bool CBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type) const |
277 | { | |
278 | if (!IsValid()) { | |
279 | return false; | |
280 | } else if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) { | |
281 | memcpy(&hashBytes, &vchData[0], 20); | |
282 | type = 1; | |
283 | return true; | |
284 | } else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) { | |
285 | memcpy(&hashBytes, &vchData[0], 20); | |
286 | type = 2; | |
287 | return true; | |
288 | } | |
289 | ||
290 | return false; | |
291 | } | |
292 | ||
20e01b1a PW |
293 | bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const |
294 | { | |
f6b7c644 PW |
295 | if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) |
296 | return false; | |
297 | uint160 id; | |
298 | memcpy(&id, &vchData[0], 20); | |
299 | keyID = CKeyID(id); | |
300 | return true; | |
301 | } | |
302 | ||
74329e19 MT |
303 | bool CBitcoinAddress::GetKeyID_NoCheck(CKeyID& keyID) const |
304 | { | |
305 | uint160 id; | |
306 | memcpy(&id, &vchData[0], 20); | |
307 | keyID = CKeyID(id); | |
308 | return true; | |
309 | } | |
310 | ||
20e01b1a PW |
311 | bool CBitcoinAddress::IsScript() const |
312 | { | |
f6b7c644 PW |
313 | return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); |
314 | } | |
315 | ||
20e01b1a PW |
316 | void CBitcoinSecret::SetKey(const CKey& vchSecret) |
317 | { | |
f6b7c644 PW |
318 | assert(vchSecret.IsValid()); |
319 | SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size()); | |
320 | if (vchSecret.IsCompressed()) | |
321 | vchData.push_back(1); | |
322 | } | |
323 | ||
20e01b1a PW |
324 | CKey CBitcoinSecret::GetKey() |
325 | { | |
f6b7c644 | 326 | CKey ret; |
6f3ae9b5 E |
327 | assert(vchData.size() >= 32); |
328 | ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1); | |
f6b7c644 PW |
329 | return ret; |
330 | } | |
331 | ||
20e01b1a PW |
332 | bool CBitcoinSecret::IsValid() const |
333 | { | |
f6b7c644 PW |
334 | bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1); |
335 | bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY); | |
336 | return fExpectedFormat && fCorrectVersion; | |
337 | } | |
338 | ||
20e01b1a PW |
339 | bool CBitcoinSecret::SetString(const char* pszSecret) |
340 | { | |
00e56272 | 341 | return CBase58Data::SetString(pszSecret, 1) && IsValid(); |
f6b7c644 PW |
342 | } |
343 | ||
20e01b1a PW |
344 | bool CBitcoinSecret::SetString(const std::string& strSecret) |
345 | { | |
f6b7c644 PW |
346 | return SetString(strSecret.c_str()); |
347 | } | |
e104fcdd | 348 | |
13933e4c JG |
349 | template<class DATA_TYPE, CChainParams::Base58Type PREFIX, size_t SER_SIZE> |
350 | bool CZCEncoding<DATA_TYPE, PREFIX, SER_SIZE>::Set(const DATA_TYPE& addr) | |
e104fcdd SB |
351 | { |
352 | CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); | |
353 | ss << addr; | |
354 | std::vector<unsigned char> addrSerialized(ss.begin(), ss.end()); | |
13933e4c JG |
355 | assert(addrSerialized.size() == SER_SIZE); |
356 | SetData(Params().Base58Prefix(PREFIX), &addrSerialized[0], SER_SIZE); | |
e104fcdd SB |
357 | return true; |
358 | } | |
359 | ||
13933e4c JG |
360 | template<class DATA_TYPE, CChainParams::Base58Type PREFIX, size_t SER_SIZE> |
361 | DATA_TYPE CZCEncoding<DATA_TYPE, PREFIX, SER_SIZE>::Get() const | |
e104fcdd | 362 | { |
13933e4c | 363 | if (vchData.size() != SER_SIZE) { |
e104fcdd | 364 | throw std::runtime_error( |
13933e4c | 365 | PrependName(" is invalid") |
e104fcdd SB |
366 | ); |
367 | } | |
368 | ||
13933e4c | 369 | if (vchVersion != Params().Base58Prefix(PREFIX)) { |
e104fcdd | 370 | throw std::runtime_error( |
13933e4c | 371 | PrependName(" is for wrong network type") |
e104fcdd SB |
372 | ); |
373 | } | |
374 | ||
375 | std::vector<unsigned char> serialized(vchData.begin(), vchData.end()); | |
376 | ||
377 | CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); | |
13933e4c | 378 | DATA_TYPE ret; |
0d6864e4 SB |
379 | ss >> ret; |
380 | return ret; | |
381 | } |