]> Git Repo - VerusCoin.git/blame - src/base58.cpp
Auto merge of #2704 - bitcartel:fix_qa_shieldcoinbase_hang, r=str4d
[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"
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
22static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
23
20e01b1a
PW
24bool 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
70std::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
105std::string EncodeBase58(const std::vector<unsigned char>& vch)
106{
f6b7c644
PW
107 return EncodeBase58(&vch[0], &vch[0] + vch.size());
108}
109
20e01b1a
PW
110bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
111{
f6b7c644
PW
112 return DecodeBase58(str.c_str(), vchRet);
113}
114
20e01b1a
PW
115std::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
124bool 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
141bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
142{
f6b7c644
PW
143 return DecodeBase58Check(str.c_str(), vchRet);
144}
145
20e01b1a
PW
146CBase58Data::CBase58Data()
147{
f6b7c644
PW
148 vchVersion.clear();
149 vchData.clear();
150}
151
20e01b1a
PW
152void 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
160void 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
165bool 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 182bool 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
187std::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
194int 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
207namespace
208{
209class CBitcoinAddressVisitor : public boost::static_visitor<bool>
210{
211private:
212 CBitcoinAddress* addr;
e10dcf27 213
20e01b1a
PW
214public:
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
224bool CBitcoinAddress::Set(const CKeyID& id)
225{
f6b7c644
PW
226 SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
227 return true;
228}
229
20e01b1a
PW
230bool CBitcoinAddress::Set(const CScriptID& id)
231{
f6b7c644
PW
232 SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
233 return true;
234}
235
20e01b1a
PW
236bool CBitcoinAddress::Set(const CTxDestination& dest)
237{
f6b7c644
PW
238 return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
239}
240
20e01b1a
PW
241bool CBitcoinAddress::IsValid() const
242{
e84843c0
RN
243 return IsValid(Params());
244}
245
20e01b1a
PW
246bool 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
254bool CBitcoinAddress::SetString(const char* pszAddress)
255{
256 return CBase58Data::SetString(pszAddress, 2);
257}
258
259bool CBitcoinAddress::SetString(const std::string& strAddress)
260{
261 return SetString(strAddress.c_str());
262}
263
20e01b1a
PW
264CTxDestination 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
278bool 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
288bool CBitcoinAddress::IsScript() const
289{
f6b7c644
PW
290 return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
291}
292
20e01b1a
PW
293void 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
301CKey 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
309bool 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
316bool CBitcoinSecret::SetString(const char* pszSecret)
317{
00e56272 318 return CBase58Data::SetString(pszSecret, 1) && IsValid();
f6b7c644
PW
319}
320
20e01b1a
PW
321bool CBitcoinSecret::SetString(const std::string& strSecret)
322{
f6b7c644
PW
323 return SetString(strSecret.c_str());
324}
e104fcdd 325
e104fcdd
SB
326bool 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
336libzcash::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
358bool 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
368libzcash::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
This page took 0.178161 seconds and 4 git commands to generate.