]> Git Repo - VerusCoin.git/blame - src/base58.h
Generalize version bytes
[VerusCoin.git] / src / base58.h
CommitLineData
0a61b0df 1// Copyright (c) 2009-2010 Satoshi Nakamoto
88216419 2// Copyright (c) 2009-2012 The Bitcoin Developers
0a61b0df 3// Distributed under the MIT/X11 software license, see the accompanying
3a25a2b9 4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
0a61b0df 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.
814efd6f 13// - Double-clicking selects the whole number as one word if it's all alphanumeric.
0a61b0df 14//
223b6f1b
WL
15#ifndef BITCOIN_BASE58_H
16#define BITCOIN_BASE58_H
0a61b0df 17
223b6f1b
WL
18#include <string>
19#include <vector>
0f8a6477 20
0e4b3175 21#include "chainparams.h"
223b6f1b 22#include "bignum.h"
15a8590e 23#include "key.h"
10254401 24#include "script.h"
d0b0925b 25#include "allocators.h"
0a61b0df 26
27static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
28
d825e6a3 29// Encode a byte sequence as a base58-encoded string
223b6f1b 30inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
0a61b0df 31{
32 CAutoBN_CTX pctx;
33 CBigNum bn58 = 58;
34 CBigNum bn0 = 0;
35
36 // Convert big endian data to little endian
37 // Extra zero at the end make sure bignum will interpret as a positive number
223b6f1b 38 std::vector<unsigned char> vchTmp(pend-pbegin+1, 0);
0a61b0df 39 reverse_copy(pbegin, pend, vchTmp.begin());
40
41 // Convert little endian data to bignum
42 CBigNum bn;
43 bn.setvch(vchTmp);
44
223b6f1b
WL
45 // Convert bignum to std::string
46 std::string str;
a9d3af88
DH
47 // Expected size increase from base58 conversion is approximately 137%
48 // use 138% to be safe
0a61b0df 49 str.reserve((pend - pbegin) * 138 / 100 + 1);
50 CBigNum dv;
51 CBigNum rem;
52 while (bn > bn0)
53 {
54 if (!BN_div(&dv, &rem, &bn, &bn58, pctx))
55 throw bignum_error("EncodeBase58 : BN_div failed");
56 bn = dv;
57 unsigned int c = rem.getulong();
58 str += pszBase58[c];
59 }
60
61 // Leading zeroes encoded as base58 zeros
62 for (const unsigned char* p = pbegin; p < pend && *p == 0; p++)
63 str += pszBase58[0];
64
223b6f1b 65 // Convert little endian std::string to big endian
0a61b0df 66 reverse(str.begin(), str.end());
67 return str;
68}
69
d825e6a3 70// Encode a byte vector as a base58-encoded string
223b6f1b 71inline std::string EncodeBase58(const std::vector<unsigned char>& vch)
0a61b0df 72{
73 return EncodeBase58(&vch[0], &vch[0] + vch.size());
74}
75
d825e6a3 76// Decode a base58-encoded string psz into byte vector vchRet
7790f391 77// returns true if decoding is successful
223b6f1b 78inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet)
0a61b0df 79{
80 CAutoBN_CTX pctx;
81 vchRet.clear();
82 CBigNum bn58 = 58;
83 CBigNum bn = 0;
84 CBigNum bnChar;
85 while (isspace(*psz))
86 psz++;
87
88 // Convert big endian string to bignum
89 for (const char* p = psz; *p; p++)
90 {
91 const char* p1 = strchr(pszBase58, *p);
92 if (p1 == NULL)
93 {
94 while (isspace(*p))
95 p++;
96 if (*p != '\0')
97 return false;
98 break;
99 }
100 bnChar.setulong(p1 - pszBase58);
101 if (!BN_mul(&bn, &bn, &bn58, pctx))
102 throw bignum_error("DecodeBase58 : BN_mul failed");
103 bn += bnChar;
104 }
105
106 // Get bignum as little endian data
223b6f1b 107 std::vector<unsigned char> vchTmp = bn.getvch();
0a61b0df 108
109 // Trim off sign byte if present
110 if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80)
111 vchTmp.erase(vchTmp.end()-1);
112
113 // Restore leading zeros
114 int nLeadingZeros = 0;
115 for (const char* p = psz; *p == pszBase58[0]; p++)
116 nLeadingZeros++;
117 vchRet.assign(nLeadingZeros + vchTmp.size(), 0);
118
119 // Convert little endian data to big endian
120 reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size());
121 return true;
122}
123
d825e6a3 124// Decode a base58-encoded string str into byte vector vchRet
e7494052 125// returns true if decoding is successful
223b6f1b 126inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
0a61b0df 127{
128 return DecodeBase58(str.c_str(), vchRet);
129}
130
131
132
133
d825e6a3 134// Encode a byte vector to a base58-encoded string, including checksum
223b6f1b 135inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
0a61b0df 136{
137 // add 4-byte hash check to the end
223b6f1b 138 std::vector<unsigned char> vch(vchIn);
0a61b0df 139 uint256 hash = Hash(vch.begin(), vch.end());
140 vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
141 return EncodeBase58(vch);
142}
143
d825e6a3 144// Decode a base58-encoded string psz that includes a checksum, into byte vector vchRet
e7494052 145// returns true if decoding is successful
223b6f1b 146inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
0a61b0df 147{
148 if (!DecodeBase58(psz, vchRet))
149 return false;
150 if (vchRet.size() < 4)
151 {
152 vchRet.clear();
153 return false;
154 }
155 uint256 hash = Hash(vchRet.begin(), vchRet.end()-4);
156 if (memcmp(&hash, &vchRet.end()[-4], 4) != 0)
157 {
158 vchRet.clear();
159 return false;
160 }
161 vchRet.resize(vchRet.size()-4);
162 return true;
163}
164
d825e6a3 165// Decode a base58-encoded string str that includes a checksum, into byte vector vchRet
e7494052 166// returns true if decoding is successful
223b6f1b 167inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
0a61b0df 168{
169 return DecodeBase58Check(str.c_str(), vchRet);
170}
171
172
173
174
175
6b8de05d 176/** Base class for all base58-encoded data */
cb61b8dc 177class CBase58Data
0a61b0df 178{
2ffba736 179protected:
8388289e
PW
180 // the version byte(s)
181 std::vector<unsigned char> vchVersion;
d825e6a3
PW
182
183 // the actually encoded data
d0b0925b
PK
184 typedef std::vector<unsigned char, zero_after_free_allocator<unsigned char> > vector_uchar;
185 vector_uchar vchData;
0a61b0df 186
cb61b8dc 187 CBase58Data()
2ffba736 188 {
8388289e 189 vchVersion.clear();
cb61b8dc
PW
190 vchData.clear();
191 }
192
8388289e 193 void SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize)
cb61b8dc 194 {
8388289e 195 vchVersion = vchVersionIn;
cb61b8dc 196 vchData.resize(nSize);
03f8b545
AJ
197 if (!vchData.empty())
198 memcpy(&vchData[0], pdata, nSize);
cb61b8dc
PW
199 }
200
8388289e 201 void SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend)
cb61b8dc 202 {
8388289e 203 SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
2ffba736 204 }
0a61b0df 205
cb61b8dc 206public:
8388289e 207 bool SetString(const char* psz, unsigned int nVersionBytes = 1)
2ffba736
PW
208 {
209 std::vector<unsigned char> vchTemp;
cb61b8dc 210 DecodeBase58Check(psz, vchTemp);
8388289e 211 if (vchTemp.size() < nVersionBytes)
2ffba736
PW
212 {
213 vchData.clear();
8388289e 214 vchVersion.clear();
2ffba736
PW
215 return false;
216 }
8388289e
PW
217 vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
218 vchData.resize(vchTemp.size() - nVersionBytes);
03f8b545 219 if (!vchData.empty())
8388289e 220 memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());
0f8a6477 221 OPENSSL_cleanse(&vchTemp[0], vchData.size());
2ffba736
PW
222 return true;
223 }
0a61b0df 224
cb61b8dc
PW
225 bool SetString(const std::string& str)
226 {
227 return SetString(str.c_str());
228 }
229
230 std::string ToString() const
2ffba736 231 {
8388289e 232 std::vector<unsigned char> vch = vchVersion;
cb61b8dc
PW
233 vch.insert(vch.end(), vchData.begin(), vchData.end());
234 return EncodeBase58Check(vch);
2ffba736 235 }
0a61b0df 236
cb61b8dc 237 int CompareTo(const CBase58Data& b58) const
2ffba736 238 {
8388289e
PW
239 if (vchVersion < b58.vchVersion) return -1;
240 if (vchVersion > b58.vchVersion) return 1;
cb61b8dc
PW
241 if (vchData < b58.vchData) return -1;
242 if (vchData > b58.vchData) return 1;
243 return 0;
244 }
245
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 bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; }
251};
252
ff0ee876 253/** base58-encoded Bitcoin addresses.
6b8de05d
PW
254 * Public-key-hash-addresses have version 0 (or 111 testnet).
255 * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key.
256 * Script-hash-addresses have version 5 (or 196 testnet).
257 * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script.
258 */
10254401
PW
259class CBitcoinAddress;
260class CBitcoinAddressVisitor : public boost::static_visitor<bool>
261{
262private:
263 CBitcoinAddress *addr;
264public:
265 CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { }
266 bool operator()(const CKeyID &id) const;
267 bool operator()(const CScriptID &id) const;
268 bool operator()(const CNoDestination &no) const;
269};
270
cb61b8dc
PW
271class CBitcoinAddress : public CBase58Data
272{
273public:
10254401 274 bool Set(const CKeyID &id) {
0e4b3175 275 SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
9e470585 276 return true;
cb61b8dc
PW
277 }
278
10254401 279 bool Set(const CScriptID &id) {
0e4b3175 280 SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
10254401 281 return true;
2ffba736
PW
282 }
283
10254401 284 bool Set(const CTxDestination &dest)
e679ec96 285 {
10254401 286 return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
e679ec96
GA
287 }
288
2ffba736
PW
289 bool IsValid() const
290 {
0e4b3175 291 bool fCorrectSize = vchData.size() == 20;
8388289e
PW
292 bool fKnownVersion = vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
293 vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
0e4b3175 294 return fCorrectSize && fKnownVersion;
2ffba736 295 }
0a61b0df 296
2ffba736
PW
297 CBitcoinAddress()
298 {
2ffba736
PW
299 }
300
10254401 301 CBitcoinAddress(const CTxDestination &dest)
2ffba736 302 {
10254401 303 Set(dest);
2ffba736 304 }
0a61b0df 305
2ffba736
PW
306 CBitcoinAddress(const std::string& strAddress)
307 {
cb61b8dc 308 SetString(strAddress);
2ffba736
PW
309 }
310
311 CBitcoinAddress(const char* pszAddress)
312 {
cb61b8dc 313 SetString(pszAddress);
2ffba736
PW
314 }
315
10254401
PW
316 CTxDestination Get() const {
317 if (!IsValid())
318 return CNoDestination();
0e4b3175
MH
319 uint160 id;
320 memcpy(&id, &vchData[0], 20);
8388289e 321 if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
10254401 322 return CKeyID(id);
8388289e 323 else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
10254401 324 return CScriptID(id);
0e4b3175
MH
325 else
326 return CNoDestination();
10254401
PW
327 }
328
329 bool GetKeyID(CKeyID &keyID) const {
8388289e 330 if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
10254401 331 return false;
0e4b3175
MH
332 uint160 id;
333 memcpy(&id, &vchData[0], 20);
334 keyID = CKeyID(id);
335 return true;
10254401
PW
336 }
337
338 bool IsScript() const {
8388289e 339 return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
2ffba736 340 }
2ffba736 341};
223b6f1b 342
10254401
PW
343bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); }
344bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); }
345bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; }
346
6b8de05d 347/** A base58-encoded secret key */
15a8590e
PW
348class CBitcoinSecret : public CBase58Data
349{
350public:
dfa23b94 351 void SetKey(const CKey& vchSecret)
ea0796bd 352 {
dfa23b94 353 assert(vchSecret.IsValid());
0e4b3175 354 SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
dfa23b94 355 if (vchSecret.IsCompressed())
11529c6e 356 vchData.push_back(1);
15a8590e
PW
357 }
358
dfa23b94 359 CKey GetKey()
15a8590e 360 {
dfa23b94
PW
361 CKey ret;
362 ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1);
363 return ret;
15a8590e
PW
364 }
365
366 bool IsValid() const
367 {
0e4b3175 368 bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
8388289e 369 bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
0e4b3175 370 return fExpectedFormat && fCorrectVersion;
15a8590e
PW
371 }
372
b3a6e613
CM
373 bool SetString(const char* pszSecret)
374 {
375 return CBase58Data::SetString(pszSecret) && IsValid();
376 }
377
378 bool SetString(const std::string& strSecret)
379 {
380 return SetString(strSecret.c_str());
381 }
382
dfa23b94 383 CBitcoinSecret(const CKey& vchSecret)
15a8590e 384 {
dfa23b94 385 SetKey(vchSecret);
15a8590e
PW
386 }
387
388 CBitcoinSecret()
389 {
390 }
391};
392
d0b0925b 393#endif // BITCOIN_BASE58_H
This page took 0.130408 seconds and 4 git commands to generate.