]> Git Repo - VerusCoin.git/blame_incremental - src/base58.h
Merge pull request #2336 from petertodd/invalid-opcode-coverage
[VerusCoin.git] / src / base58.h
... / ...
CommitLineData
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2012 The Bitcoin Developers
3// Distributed under the MIT/X11 software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6
7//
8// Why base-58 instead of standard base-64 encoding?
9// - Don't want 0OIl characters that look the same in some fonts and
10// could be used to create visually identical looking account numbers.
11// - A string with non-alphanumeric characters is not as easily accepted as an account number.
12// - E-mail usually won't line-break if there's no punctuation to break at.
13// - Double-clicking selects the whole number as one word if it's all alphanumeric.
14//
15#ifndef BITCOIN_BASE58_H
16#define BITCOIN_BASE58_H
17
18#include <string>
19#include <vector>
20
21#include "bignum.h"
22#include "key.h"
23#include "script.h"
24#include "allocators.h"
25
26static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
27
28// Encode a byte sequence as a base58-encoded string
29inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
30{
31 CAutoBN_CTX pctx;
32 CBigNum bn58 = 58;
33 CBigNum bn0 = 0;
34
35 // Convert big endian data to little endian
36 // Extra zero at the end make sure bignum will interpret as a positive number
37 std::vector<unsigned char> vchTmp(pend-pbegin+1, 0);
38 reverse_copy(pbegin, pend, vchTmp.begin());
39
40 // Convert little endian data to bignum
41 CBigNum bn;
42 bn.setvch(vchTmp);
43
44 // Convert bignum to std::string
45 std::string str;
46 // Expected size increase from base58 conversion is approximately 137%
47 // use 138% to be safe
48 str.reserve((pend - pbegin) * 138 / 100 + 1);
49 CBigNum dv;
50 CBigNum rem;
51 while (bn > bn0)
52 {
53 if (!BN_div(&dv, &rem, &bn, &bn58, pctx))
54 throw bignum_error("EncodeBase58 : BN_div failed");
55 bn = dv;
56 unsigned int c = rem.getulong();
57 str += pszBase58[c];
58 }
59
60 // Leading zeroes encoded as base58 zeros
61 for (const unsigned char* p = pbegin; p < pend && *p == 0; p++)
62 str += pszBase58[0];
63
64 // Convert little endian std::string to big endian
65 reverse(str.begin(), str.end());
66 return str;
67}
68
69// Encode a byte vector as a base58-encoded string
70inline std::string EncodeBase58(const std::vector<unsigned char>& vch)
71{
72 return EncodeBase58(&vch[0], &vch[0] + vch.size());
73}
74
75// Decode a base58-encoded string psz into byte vector vchRet
76// returns true if decoding is successful
77inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet)
78{
79 CAutoBN_CTX pctx;
80 vchRet.clear();
81 CBigNum bn58 = 58;
82 CBigNum bn = 0;
83 CBigNum bnChar;
84 while (isspace(*psz))
85 psz++;
86
87 // Convert big endian string to bignum
88 for (const char* p = psz; *p; p++)
89 {
90 const char* p1 = strchr(pszBase58, *p);
91 if (p1 == NULL)
92 {
93 while (isspace(*p))
94 p++;
95 if (*p != '\0')
96 return false;
97 break;
98 }
99 bnChar.setulong(p1 - pszBase58);
100 if (!BN_mul(&bn, &bn, &bn58, pctx))
101 throw bignum_error("DecodeBase58 : BN_mul failed");
102 bn += bnChar;
103 }
104
105 // Get bignum as little endian data
106 std::vector<unsigned char> vchTmp = bn.getvch();
107
108 // Trim off sign byte if present
109 if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80)
110 vchTmp.erase(vchTmp.end()-1);
111
112 // Restore leading zeros
113 int nLeadingZeros = 0;
114 for (const char* p = psz; *p == pszBase58[0]; p++)
115 nLeadingZeros++;
116 vchRet.assign(nLeadingZeros + vchTmp.size(), 0);
117
118 // Convert little endian data to big endian
119 reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size());
120 return true;
121}
122
123// Decode a base58-encoded string str into byte vector vchRet
124// returns true if decoding is successful
125inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
126{
127 return DecodeBase58(str.c_str(), vchRet);
128}
129
130
131
132
133// Encode a byte vector to a base58-encoded string, including checksum
134inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
135{
136 // add 4-byte hash check to the end
137 std::vector<unsigned char> vch(vchIn);
138 uint256 hash = Hash(vch.begin(), vch.end());
139 vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
140 return EncodeBase58(vch);
141}
142
143// Decode a base58-encoded string psz that includes a checksum, into byte vector vchRet
144// returns true if decoding is successful
145inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
146{
147 if (!DecodeBase58(psz, vchRet))
148 return false;
149 if (vchRet.size() < 4)
150 {
151 vchRet.clear();
152 return false;
153 }
154 uint256 hash = Hash(vchRet.begin(), vchRet.end()-4);
155 if (memcmp(&hash, &vchRet.end()[-4], 4) != 0)
156 {
157 vchRet.clear();
158 return false;
159 }
160 vchRet.resize(vchRet.size()-4);
161 return true;
162}
163
164// Decode a base58-encoded string str that includes a checksum, into byte vector vchRet
165// returns true if decoding is successful
166inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
167{
168 return DecodeBase58Check(str.c_str(), vchRet);
169}
170
171
172
173
174
175/** Base class for all base58-encoded data */
176class CBase58Data
177{
178protected:
179 // the version byte
180 unsigned char nVersion;
181
182 // the actually encoded data
183 typedef std::vector<unsigned char, zero_after_free_allocator<unsigned char> > vector_uchar;
184 vector_uchar vchData;
185
186 CBase58Data()
187 {
188 nVersion = 0;
189 vchData.clear();
190 }
191
192 void SetData(int nVersionIn, const void* pdata, size_t nSize)
193 {
194 nVersion = nVersionIn;
195 vchData.resize(nSize);
196 if (!vchData.empty())
197 memcpy(&vchData[0], pdata, nSize);
198 }
199
200 void SetData(int nVersionIn, const unsigned char *pbegin, const unsigned char *pend)
201 {
202 SetData(nVersionIn, (void*)pbegin, pend - pbegin);
203 }
204
205public:
206 bool SetString(const char* psz)
207 {
208 std::vector<unsigned char> vchTemp;
209 DecodeBase58Check(psz, vchTemp);
210 if (vchTemp.empty())
211 {
212 vchData.clear();
213 nVersion = 0;
214 return false;
215 }
216 nVersion = vchTemp[0];
217 vchData.resize(vchTemp.size() - 1);
218 if (!vchData.empty())
219 memcpy(&vchData[0], &vchTemp[1], vchData.size());
220 OPENSSL_cleanse(&vchTemp[0], vchData.size());
221 return true;
222 }
223
224 bool SetString(const std::string& str)
225 {
226 return SetString(str.c_str());
227 }
228
229 std::string ToString() const
230 {
231 std::vector<unsigned char> vch(1, nVersion);
232 vch.insert(vch.end(), vchData.begin(), vchData.end());
233 return EncodeBase58Check(vch);
234 }
235
236 int CompareTo(const CBase58Data& b58) const
237 {
238 if (nVersion < b58.nVersion) return -1;
239 if (nVersion > b58.nVersion) return 1;
240 if (vchData < b58.vchData) return -1;
241 if (vchData > b58.vchData) return 1;
242 return 0;
243 }
244
245 bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; }
246 bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; }
247 bool operator>=(const CBase58Data& b58) const { return CompareTo(b58) >= 0; }
248 bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < 0; }
249 bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
250};
251
252/** base58-encoded Bitcoin addresses.
253 * Public-key-hash-addresses have version 0 (or 111 testnet).
254 * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
255 * Script-hash-addresses have version 5 (or 196 testnet).
256 * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
257 */
258class CBitcoinAddress;
259class CBitcoinAddressVisitor : public boost::static_visitor<bool>
260{
261private:
262 CBitcoinAddress *addr;
263public:
264 CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { }
265 bool operator()(const CKeyID &id) const;
266 bool operator()(const CScriptID &id) const;
267 bool operator()(const CNoDestination &no) const;
268};
269
270class CBitcoinAddress : public CBase58Data
271{
272public:
273 enum
274 {
275 PUBKEY_ADDRESS = 0,
276 SCRIPT_ADDRESS = 5,
277 PUBKEY_ADDRESS_TEST = 111,
278 SCRIPT_ADDRESS_TEST = 196,
279 };
280
281 bool Set(const CKeyID &id) {
282 SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &id, 20);
283 return true;
284 }
285
286 bool Set(const CScriptID &id) {
287 SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &id, 20);
288 return true;
289 }
290
291 bool Set(const CTxDestination &dest)
292 {
293 return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
294 }
295
296 bool IsValid() const
297 {
298 unsigned int nExpectedSize = 20;
299 bool fExpectTestNet = false;
300 switch(nVersion)
301 {
302 case PUBKEY_ADDRESS:
303 nExpectedSize = 20; // Hash of public key
304 fExpectTestNet = false;
305 break;
306 case SCRIPT_ADDRESS:
307 nExpectedSize = 20; // Hash of CScript
308 fExpectTestNet = false;
309 break;
310
311 case PUBKEY_ADDRESS_TEST:
312 nExpectedSize = 20;
313 fExpectTestNet = true;
314 break;
315 case SCRIPT_ADDRESS_TEST:
316 nExpectedSize = 20;
317 fExpectTestNet = true;
318 break;
319
320 default:
321 return false;
322 }
323 return fExpectTestNet == fTestNet && vchData.size() == nExpectedSize;
324 }
325
326 CBitcoinAddress()
327 {
328 }
329
330 CBitcoinAddress(const CTxDestination &dest)
331 {
332 Set(dest);
333 }
334
335 CBitcoinAddress(const std::string& strAddress)
336 {
337 SetString(strAddress);
338 }
339
340 CBitcoinAddress(const char* pszAddress)
341 {
342 SetString(pszAddress);
343 }
344
345 CTxDestination Get() const {
346 if (!IsValid())
347 return CNoDestination();
348 switch (nVersion) {
349 case PUBKEY_ADDRESS:
350 case PUBKEY_ADDRESS_TEST: {
351 uint160 id;
352 memcpy(&id, &vchData[0], 20);
353 return CKeyID(id);
354 }
355 case SCRIPT_ADDRESS:
356 case SCRIPT_ADDRESS_TEST: {
357 uint160 id;
358 memcpy(&id, &vchData[0], 20);
359 return CScriptID(id);
360 }
361 }
362 return CNoDestination();
363 }
364
365 bool GetKeyID(CKeyID &keyID) const {
366 if (!IsValid())
367 return false;
368 switch (nVersion) {
369 case PUBKEY_ADDRESS:
370 case PUBKEY_ADDRESS_TEST: {
371 uint160 id;
372 memcpy(&id, &vchData[0], 20);
373 keyID = CKeyID(id);
374 return true;
375 }
376 default: return false;
377 }
378 }
379
380 bool IsScript() const {
381 if (!IsValid())
382 return false;
383 switch (nVersion) {
384 case SCRIPT_ADDRESS:
385 case SCRIPT_ADDRESS_TEST: {
386 return true;
387 }
388 default: return false;
389 }
390 }
391};
392
393bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); }
394bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); }
395bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; }
396
397/** A base58-encoded secret key */
398class CBitcoinSecret : public CBase58Data
399{
400public:
401 void SetSecret(const CSecret& vchSecret, bool fCompressed)
402 {
403 assert(vchSecret.size() == 32);
404 SetData(fTestNet ? 239 : 128, &vchSecret[0], vchSecret.size());
405 if (fCompressed)
406 vchData.push_back(1);
407 }
408
409 CSecret GetSecret(bool &fCompressedOut)
410 {
411 CSecret vchSecret;
412 vchSecret.resize(32);
413 memcpy(&vchSecret[0], &vchData[0], 32);
414 fCompressedOut = vchData.size() == 33;
415 return vchSecret;
416 }
417
418 bool IsValid() const
419 {
420 bool fExpectTestNet = false;
421 switch(nVersion)
422 {
423 case 128:
424 break;
425
426 case 239:
427 fExpectTestNet = true;
428 break;
429
430 default:
431 return false;
432 }
433 return fExpectTestNet == fTestNet && (vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1));
434 }
435
436 bool SetString(const char* pszSecret)
437 {
438 return CBase58Data::SetString(pszSecret) && IsValid();
439 }
440
441 bool SetString(const std::string& strSecret)
442 {
443 return SetString(strSecret.c_str());
444 }
445
446 CBitcoinSecret(const CSecret& vchSecret, bool fCompressed)
447 {
448 SetSecret(vchSecret, fCompressed);
449 }
450
451 CBitcoinSecret()
452 {
453 }
454};
455
456#endif // BITCOIN_BASE58_H
This page took 0.026205 seconds and 4 git commands to generate.