Implement {Encode,Decode}PaymentAddress etc. without CZCEncoding
[VerusCoin.git] / src / base58.cpp
CommitLineData
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"
c8f9c87b 8#include "script/script.h"
f6b7c644
PW
9#include "uint256.h"
10
e104fcdd
SB
11#include "version.h"
12#include "streams.h"
13
f6b7c644
PW
14#include <boost/variant/apply_visitor.hpp>
15#include <boost/variant/static_visitor.hpp>
b58be132 16
c8f9c87b
PW
17#include <algorithm>
18#include <assert.h>
19#include <string.h>
20
21
fa94b9d5 22/** All alphanumeric characters except for "0", "I", "O", and "l" */
b58be132
PW
23static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
24
20e01b1a
PW
25bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
26{
b58be132
PW
27 // Skip leading spaces.
28 while (*psz && isspace(*psz))
29 psz++;
30 // Skip and count leading '1's.
31 int zeroes = 0;
32 while (*psz == '1') {
33 zeroes++;
34 psz++;
35 }
36 // Allocate enough space in big-endian base256 representation.
37 std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up.
38 // Process the characters.
39 while (*psz && !isspace(*psz)) {
40 // Decode base58 character
20e01b1a 41 const char* ch = strchr(pszBase58, *psz);
b58be132
PW
42 if (ch == NULL)
43 return false;
44 // Apply "b256 = b256 * 58 + ch".
45 int carry = ch - pszBase58;
46 for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) {
47 carry += 58 * (*it);
48 *it = carry % 256;
49 carry /= 256;
50 }
51 assert(carry == 0);
52 psz++;
53 }
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();
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())
20e01b1a 67 vch.push_back(*(it++));
b58be132
PW
68 return true;
69}
70
20e01b1a
PW
71std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
72{
b58be132
PW
73 // Skip & count leading zeroes.
74 int zeroes = 0;
75 while (pbegin != pend && *pbegin == 0) {
76 pbegin++;
77 zeroes++;
78 }
79 // Allocate enough space in big-endian base58 representation.
80 std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up.
81 // Process the bytes.
82 while (pbegin != pend) {
83 int carry = *pbegin;
84 // Apply "b58 = b58 * 256 + ch".
85 for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) {
86 carry += 256 * (*it);
87 *it = carry % 58;
88 carry /= 58;
89 }
90 assert(carry == 0);
91 pbegin++;
92 }
93 // Skip leading zeroes in base58 result.
94 std::vector<unsigned char>::iterator it = b58.begin();
95 while (it != b58.end() && *it == 0)
96 it++;
97 // Translate the result into a string.
98 std::string str;
99 str.reserve(zeroes + (b58.end() - it));
100 str.assign(zeroes, '1');
101 while (it != b58.end())
102 str += pszBase58[*(it++)];
103 return str;
104}
f6b7c644 105
20e01b1a
PW
106std::string EncodeBase58(const std::vector<unsigned char>& vch)
107{
1b34996b 108 return EncodeBase58(vch.data(), vch.data() + vch.size());
f6b7c644
PW
109}
110
20e01b1a
PW
111bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
112{
f6b7c644
PW
113 return DecodeBase58(str.c_str(), vchRet);
114}
115
20e01b1a
PW
116std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
117{
f6b7c644
PW
118 // add 4-byte hash check to the end
119 std::vector<unsigned char> vch(vchIn);
120 uint256 hash = Hash(vch.begin(), vch.end());
121 vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
122 return EncodeBase58(vch);
123}
124
20e01b1a
PW
125bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
126{
88df548d 127 if (!DecodeBase58(psz, vchRet) ||
20e01b1a 128 (vchRet.size() < 4)) {
f6b7c644
PW
129 vchRet.clear();
130 return false;
131 }
132 // re-calculate the checksum, insure it matches the included 4-byte checksum
20e01b1a
PW
133 uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
134 if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) {
f6b7c644
PW
135 vchRet.clear();
136 return false;
137 }
20e01b1a 138 vchRet.resize(vchRet.size() - 4);
f6b7c644
PW
139 return true;
140}
141
20e01b1a
PW
142bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
143{
f6b7c644
PW
144 return DecodeBase58Check(str.c_str(), vchRet);
145}
146
20e01b1a
PW
147CBase58Data::CBase58Data()
148{
f6b7c644
PW
149 vchVersion.clear();
150 vchData.clear();
151}
152
20e01b1a
PW
153void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)
154{
f6b7c644
PW
155 vchVersion = vchVersionIn;
156 vchData.resize(nSize);
157 if (!vchData.empty())
1b34996b 158 memcpy(vchData.data(), pdata, nSize);
f6b7c644
PW
159}
160
20e01b1a
PW
161void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
162{
f6b7c644
PW
163 SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
164}
165
20e01b1a
PW
166bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
167{
f6b7c644 168 std::vector<unsigned char> vchTemp;
88df548d
JG
169 bool rc58 = DecodeBase58Check(psz, vchTemp);
170 if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
f6b7c644
PW
171 vchData.clear();
172 vchVersion.clear();
173 return false;
174 }
175 vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
176 vchData.resize(vchTemp.size() - nVersionBytes);
177 if (!vchData.empty())
1b34996b
JR
178 memcpy(vchData.data(), vchTemp.data() + nVersionBytes, vchData.size());
179 memory_cleanse(vchTemp.data(), vchTemp.size());
f6b7c644
PW
180 return true;
181}
182
00e56272 183bool CBase58Data::SetString(const std::string& str, unsigned int nVersionBytes)
20e01b1a 184{
00e56272 185 return SetString(str.c_str(), nVersionBytes);
f6b7c644
PW
186}
187
20e01b1a
PW
188std::string CBase58Data::ToString() const
189{
f6b7c644
PW
190 std::vector<unsigned char> vch = vchVersion;
191 vch.insert(vch.end(), vchData.begin(), vchData.end());
192 return EncodeBase58Check(vch);
193}
194
20e01b1a
PW
195int CBase58Data::CompareTo(const CBase58Data& b58) const
196{
197 if (vchVersion < b58.vchVersion)
198 return -1;
199 if (vchVersion > b58.vchVersion)
200 return 1;
201 if (vchData < b58.vchData)
202 return -1;
203 if (vchData > b58.vchData)
204 return 1;
f6b7c644
PW
205 return 0;
206}
207
20e01b1a
PW
208namespace
209{
c8f9c87b 210class DestinationEncoder : public boost::static_visitor<std::string>
20e01b1a
PW
211{
212private:
c8f9c87b 213 const CChainParams& m_params;
e10dcf27 214
20e01b1a 215public:
c8f9c87b 216 DestinationEncoder(const CChainParams& params) : m_params(params) {}
f6b7c644 217
c8f9c87b
PW
218 std::string operator()(const CKeyID& id) const
219 {
220 std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
221 data.insert(data.end(), id.begin(), id.end());
222 return EncodeBase58Check(data);
223 }
f6b7c644 224
c8f9c87b
PW
225 std::string operator()(const CScriptID& id) const
226 {
227 std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
228 data.insert(data.end(), id.begin(), id.end());
229 return EncodeBase58Check(data);
230 }
00e56272 231
c8f9c87b
PW
232 std::string operator()(const CNoDestination& no) const { return ""; }
233};
00e56272 234
c8f9c87b
PW
235CTxDestination DecodeDestination(const std::string& str, const CChainParams& params)
236{
237 std::vector<unsigned char> data;
238 uint160 hash;
239 if (DecodeBase58Check(str, data)) {
240 // base58-encoded Bitcoin addresses.
241 // Public-key-hash-addresses have version 0 (or 111 testnet).
242 // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
243 const std::vector<unsigned char>& pubkey_prefix = params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
244 if (data.size() == hash.size() + pubkey_prefix.size() && std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
245 std::copy(data.begin() + pubkey_prefix.size(), data.end(), hash.begin());
246 return CKeyID(hash);
247 }
248 // Script-hash-addresses have version 5 (or 196 testnet).
249 // The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
250 const std::vector<unsigned char>& script_prefix = params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
251 if (data.size() == hash.size() + script_prefix.size() && std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
252 std::copy(data.begin() + script_prefix.size(), data.end(), hash.begin());
253 return CScriptID(hash);
254 }
255 }
256 return CNoDestination();
f6b7c644 257}
c8f9c87b 258} // namespace
f6b7c644 259
f146029b 260CKey DecodeSecret(const std::string& str)
20e01b1a 261{
f146029b
PW
262 CKey key;
263 std::vector<unsigned char> data;
264 if (DecodeBase58Check(str, data)) {
265 const std::vector<unsigned char>& privkey_prefix = Params().Base58Prefix(CChainParams::SECRET_KEY);
266 if ((data.size() == 32 + privkey_prefix.size() || (data.size() == 33 + privkey_prefix.size() && data.back() == 1)) &&
267 std::equal(privkey_prefix.begin(), privkey_prefix.end(), data.begin())) {
268 bool compressed = data.size() == 33 + privkey_prefix.size();
269 key.Set(data.begin() + privkey_prefix.size(), data.begin() + privkey_prefix.size() + 32, compressed);
270 }
271 }
272 memory_cleanse(data.data(), data.size());
273 return key;
f6b7c644
PW
274}
275
f146029b 276std::string EncodeSecret(const CKey& key)
20e01b1a 277{
f146029b
PW
278 assert(key.IsValid());
279 std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::SECRET_KEY);
280 data.insert(data.end(), key.begin(), key.end());
281 if (key.IsCompressed()) {
282 data.push_back(1);
283 }
284 std::string ret = EncodeBase58Check(data);
285 memory_cleanse(data.data(), data.size());
f6b7c644
PW
286 return ret;
287}
288
07444da1
PW
289std::string EncodeDestination(const CTxDestination& dest)
290{
c8f9c87b 291 return boost::apply_visitor(DestinationEncoder(Params()), dest);
07444da1
PW
292}
293
294CTxDestination DecodeDestination(const std::string& str)
295{
c8f9c87b 296 return DecodeDestination(str, Params());
07444da1
PW
297}
298
299bool IsValidDestinationString(const std::string& str, const CChainParams& params)
300{
c8f9c87b 301 return IsValidDestination(DecodeDestination(str, params));
07444da1
PW
302}
303
304bool IsValidDestinationString(const std::string& str)
305{
c8f9c87b 306 return IsValidDestinationString(str, Params());
07444da1
PW
307}
308
80ed13d5
JG
309std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr)
310{
aa333ee8
JG
311 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
312 ss << zaddr;
313 std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
314 data.insert(data.end(), ss.begin(), ss.end());
315 return EncodeBase58Check(data);
80ed13d5
JG
316}
317
318boost::optional<libzcash::PaymentAddress> DecodePaymentAddress(const std::string& str)
319{
aa333ee8
JG
320 std::vector<unsigned char> data;
321 if (DecodeBase58Check(str, data)) {
322 const std::vector<unsigned char>& zaddr_prefix = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS);
323 if ((data.size() == libzcash::SerializedPaymentAddressSize + zaddr_prefix.size()) &&
324 std::equal(zaddr_prefix.begin(), zaddr_prefix.end(), data.begin())) {
325 CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end());
326 CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
327 libzcash::PaymentAddress ret;
328 ss >> ret;
329 return ret;
330 }
80ed13d5 331 }
aa333ee8 332 return boost::none;
80ed13d5 333}
472f75bc 334
8bf3a3d7
JG
335std::string EncodeViewingKey(const libzcash::ViewingKey& vk)
336{
aa333ee8
JG
337 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
338 ss << vk;
339 std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY);
340 data.insert(data.end(), ss.begin(), ss.end());
341 std::string ret = EncodeBase58Check(data);
342 memory_cleanse(data.data(), data.size());
343 return ret;
8bf3a3d7
JG
344}
345
346boost::optional<libzcash::ViewingKey> DecodeViewingKey(const std::string& str)
347{
aa333ee8
JG
348 std::vector<unsigned char> data;
349 if (DecodeBase58Check(str, data)) {
350 const std::vector<unsigned char>& vk_prefix = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY);
351 if ((data.size() == libzcash::SerializedViewingKeySize + vk_prefix.size()) &&
352 std::equal(vk_prefix.begin(), vk_prefix.end(), data.begin())) {
353 CSerializeData serialized(data.begin() + vk_prefix.size(), data.end());
354 CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
355 libzcash::ViewingKey ret;
356 ss >> ret;
357 memory_cleanse(serialized.data(), serialized.size());
358 memory_cleanse(data.data(), data.size());
359 return ret;
360 }
8bf3a3d7 361 }
aa333ee8
JG
362 memory_cleanse(data.data(), data.size());
363 return boost::none;
8bf3a3d7
JG
364}
365
472f75bc
JG
366std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey)
367{
aa333ee8
JG
368 CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
369 ss << zkey;
370 std::vector<unsigned char> data = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY);
371 data.insert(data.end(), ss.begin(), ss.end());
372 std::string ret = EncodeBase58Check(data);
373 memory_cleanse(data.data(), data.size());
374 return ret;
472f75bc
JG
375}
376
377boost::optional<libzcash::SpendingKey> DecodeSpendingKey(const std::string& str)
378{
aa333ee8
JG
379 std::vector<unsigned char> data;
380 if (DecodeBase58Check(str, data)) {
381 const std::vector<unsigned char>& zkey_prefix = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY);
382 if ((data.size() == libzcash::SerializedSpendingKeySize + zkey_prefix.size()) &&
383 std::equal(zkey_prefix.begin(), zkey_prefix.end(), data.begin())) {
384 CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end());
385 CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION);
386 libzcash::SpendingKey ret;
387 ss >> ret;
388 memory_cleanse(serialized.data(), serialized.size());
389 memory_cleanse(data.data(), data.size());
390 return ret;
391 }
472f75bc 392 }
aa333ee8
JG
393 memory_cleanse(data.data(), data.size());
394 return boost::none;
472f75bc 395}
This page took 0.243376 seconds and 4 git commands to generate.