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