Projects : bitcoin : bitcoin_dumpblock_no_losers
1 | // Copyright (c) 2009-2010 Satoshi Nakamoto |
2 | // Copyright (c) 2011 The Bitcoin Developers |
3 | // Distributed under the MIT/X11 software license, see the accompanying |
4 | // file license.txt 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 | // - Doubleclicking 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 | #include "bignum.h" |
21 | #include "key.h" |
22 | |
23 | static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; |
24 | |
25 | // Encode a byte sequence as a base58-encoded string |
26 | inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) |
27 | { |
28 | CAutoBN_CTX pctx; |
29 | CBigNum bn58 = 58; |
30 | CBigNum bn0 = 0; |
31 | |
32 | // Convert big endian data to little endian |
33 | // Extra zero at the end make sure bignum will interpret as a positive number |
34 | std::vector<unsigned char> vchTmp(pend-pbegin+1, 0); |
35 | reverse_copy(pbegin, pend, vchTmp.begin()); |
36 | |
37 | // Convert little endian data to bignum |
38 | CBigNum bn; |
39 | bn.setvch(vchTmp); |
40 | |
41 | // Convert bignum to std::string |
42 | std::string str; |
43 | // Expected size increase from base58 conversion is approximately 137% |
44 | // use 138% to be safe |
45 | str.reserve((pend - pbegin) * 138 / 100 + 1); |
46 | CBigNum dv; |
47 | CBigNum rem; |
48 | while (bn > bn0) |
49 | { |
50 | if (!BN_div(&dv, &rem, &bn, &bn58, pctx)) |
51 | throw bignum_error("EncodeBase58 : BN_div failed"); |
52 | bn = dv; |
53 | unsigned int c = rem.getulong(); |
54 | str += pszBase58[c]; |
55 | } |
56 | |
57 | // Leading zeroes encoded as base58 zeros |
58 | for (const unsigned char* p = pbegin; p < pend && *p == 0; p++) |
59 | str += pszBase58[0]; |
60 | |
61 | // Convert little endian std::string to big endian |
62 | reverse(str.begin(), str.end()); |
63 | return str; |
64 | } |
65 | |
66 | // Encode a byte vector as a base58-encoded string |
67 | inline std::string EncodeBase58(const std::vector<unsigned char>& vch) |
68 | { |
69 | return EncodeBase58(&vch[0], &vch[0] + vch.size()); |
70 | } |
71 | |
72 | // Decode a base58-encoded string psz into byte vector vchRet |
73 | // returns true if decoding is succesful |
74 | inline bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet) |
75 | { |
76 | CAutoBN_CTX pctx; |
77 | vchRet.clear(); |
78 | CBigNum bn58 = 58; |
79 | CBigNum bn = 0; |
80 | CBigNum bnChar; |
81 | while (isspace(*psz)) |
82 | psz++; |
83 | |
84 | // Convert big endian string to bignum |
85 | for (const char* p = psz; *p; p++) |
86 | { |
87 | const char* p1 = strchr(pszBase58, *p); |
88 | if (p1 == NULL) |
89 | { |
90 | while (isspace(*p)) |
91 | p++; |
92 | if (*p != '\0') |
93 | return false; |
94 | break; |
95 | } |
96 | bnChar.setulong(p1 - pszBase58); |
97 | if (!BN_mul(&bn, &bn, &bn58, pctx)) |
98 | throw bignum_error("DecodeBase58 : BN_mul failed"); |
99 | bn += bnChar; |
100 | } |
101 | |
102 | // Get bignum as little endian data |
103 | std::vector<unsigned char> vchTmp = bn.getvch(); |
104 | |
105 | // Trim off sign byte if present |
106 | if (vchTmp.size() >= 2 && vchTmp.end()[-1] == 0 && vchTmp.end()[-2] >= 0x80) |
107 | vchTmp.erase(vchTmp.end()-1); |
108 | |
109 | // Restore leading zeros |
110 | int nLeadingZeros = 0; |
111 | for (const char* p = psz; *p == pszBase58[0]; p++) |
112 | nLeadingZeros++; |
113 | vchRet.assign(nLeadingZeros + vchTmp.size(), 0); |
114 | |
115 | // Convert little endian data to big endian |
116 | reverse_copy(vchTmp.begin(), vchTmp.end(), vchRet.end() - vchTmp.size()); |
117 | return true; |
118 | } |
119 | |
120 | // Decode a base58-encoded string str into byte vector vchRet |
121 | // returns true if decoding is succesful |
122 | inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet) |
123 | { |
124 | return DecodeBase58(str.c_str(), vchRet); |
125 | } |
126 | |
127 | |
128 | |
129 | |
130 | // Encode a byte vector to a base58-encoded string, including checksum |
131 | inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) |
132 | { |
133 | // add 4-byte hash check to the end |
134 | std::vector<unsigned char> vch(vchIn); |
135 | uint256 hash = Hash(vch.begin(), vch.end()); |
136 | vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4); |
137 | return EncodeBase58(vch); |
138 | } |
139 | |
140 | // Decode a base58-encoded string psz that includes a checksum, into byte vector vchRet |
141 | // returns true if decoding is succesful |
142 | inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) |
143 | { |
144 | if (!DecodeBase58(psz, vchRet)) |
145 | return false; |
146 | if (vchRet.size() < 4) |
147 | { |
148 | vchRet.clear(); |
149 | return false; |
150 | } |
151 | uint256 hash = Hash(vchRet.begin(), vchRet.end()-4); |
152 | if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) |
153 | { |
154 | vchRet.clear(); |
155 | return false; |
156 | } |
157 | vchRet.resize(vchRet.size()-4); |
158 | return true; |
159 | } |
160 | |
161 | // Decode a base58-encoded string str that includes a checksum, into byte vector vchRet |
162 | // returns true if decoding is succesful |
163 | inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet) |
164 | { |
165 | return DecodeBase58Check(str.c_str(), vchRet); |
166 | } |
167 | |
168 | |
169 | |
170 | |
171 | |
172 | // Base class for all base58-encoded data |
173 | class CBase58Data |
174 | { |
175 | protected: |
176 | // the version byte |
177 | unsigned char nVersion; |
178 | |
179 | // the actually encoded data |
180 | std::vector<unsigned char> vchData; |
181 | |
182 | CBase58Data() |
183 | { |
184 | nVersion = 0; |
185 | vchData.clear(); |
186 | } |
187 | |
188 | ~CBase58Data() |
189 | { |
190 | // zero the memory, as it may contain sensitive data |
191 | if (!vchData.empty()) |
192 | memset(&vchData[0], 0, vchData.size()); |
193 | } |
194 | |
195 | void SetData(int nVersionIn, const void* pdata, size_t nSize) |
196 | { |
197 | nVersion = nVersionIn; |
198 | vchData.resize(nSize); |
199 | if (!vchData.empty()) |
200 | memcpy(&vchData[0], pdata, nSize); |
201 | } |
202 | |
203 | void SetData(int nVersionIn, const unsigned char *pbegin, const unsigned char *pend) |
204 | { |
205 | SetData(nVersionIn, (void*)pbegin, pend - pbegin); |
206 | } |
207 | |
208 | public: |
209 | bool SetString(const char* psz) |
210 | { |
211 | std::vector<unsigned char> vchTemp; |
212 | DecodeBase58Check(psz, vchTemp); |
213 | if (vchTemp.empty()) |
214 | { |
215 | vchData.clear(); |
216 | nVersion = 0; |
217 | return false; |
218 | } |
219 | nVersion = vchTemp[0]; |
220 | vchData.resize(vchTemp.size() - 1); |
221 | if (!vchData.empty()) |
222 | memcpy(&vchData[0], &vchTemp[1], vchData.size()); |
223 | memset(&vchTemp[0], 0, vchTemp.size()); |
224 | return true; |
225 | } |
226 | |
227 | bool SetString(const std::string& str) |
228 | { |
229 | return SetString(str.c_str()); |
230 | } |
231 | |
232 | std::string ToString() const |
233 | { |
234 | std::vector<unsigned char> vch(1, nVersion); |
235 | vch.insert(vch.end(), vchData.begin(), vchData.end()); |
236 | return EncodeBase58Check(vch); |
237 | } |
238 | |
239 | int CompareTo(const CBase58Data& b58) const |
240 | { |
241 | if (nVersion < b58.nVersion) return -1; |
242 | if (nVersion > b58.nVersion) return 1; |
243 | if (vchData < b58.vchData) return -1; |
244 | if (vchData > b58.vchData) return 1; |
245 | return 0; |
246 | } |
247 | |
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 | bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < 0; } |
252 | bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; } |
253 | }; |
254 | |
255 | // base58-encoded bitcoin addresses |
256 | // Addresses have version 0 |
257 | // The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key |
258 | class CBitcoinAddress : public CBase58Data |
259 | { |
260 | public: |
261 | bool SetHash160(const uint160& hash160) |
262 | { |
263 | SetData(0, &hash160, 20); |
264 | return true; |
265 | } |
266 | |
267 | bool SetPubKey(const std::vector<unsigned char>& vchPubKey) |
268 | { |
269 | return SetHash160(Hash160(vchPubKey)); |
270 | } |
271 | |
272 | bool IsValid() const |
273 | { |
274 | int nExpectedSize = 20; |
275 | switch(nVersion) |
276 | { |
277 | case 0: |
278 | break; |
279 | |
280 | default: |
281 | return false; |
282 | } |
283 | return vchData.size() == nExpectedSize; |
284 | } |
285 | |
286 | CBitcoinAddress() |
287 | { |
288 | } |
289 | |
290 | CBitcoinAddress(uint160 hash160In) |
291 | { |
292 | SetHash160(hash160In); |
293 | } |
294 | |
295 | CBitcoinAddress(const std::vector<unsigned char>& vchPubKey) |
296 | { |
297 | SetPubKey(vchPubKey); |
298 | } |
299 | |
300 | CBitcoinAddress(const std::string& strAddress) |
301 | { |
302 | SetString(strAddress); |
303 | } |
304 | |
305 | CBitcoinAddress(const char* pszAddress) |
306 | { |
307 | SetString(pszAddress); |
308 | } |
309 | |
310 | uint160 GetHash160() const |
311 | { |
312 | assert(vchData.size() == 20); |
313 | uint160 hash160; |
314 | memcpy(&hash160, &vchData[0], 20); |
315 | return hash160; |
316 | } |
317 | }; |
318 | |
319 | /** A base58-encoded secret key */ |
320 | class CBitcoinSecret : public CBase58Data |
321 | { |
322 | public: |
323 | void SetSecret(const CSecret& vchSecret) |
324 | { |
325 | assert(vchSecret.size() == 32); |
326 | SetData(128, &vchSecret[0], vchSecret.size()); |
327 | } |
328 | |
329 | CSecret GetSecret() |
330 | { |
331 | CSecret vchSecret; |
332 | vchSecret.resize(32); |
333 | memcpy(&vchSecret[0], &vchData[0], 32); |
334 | return vchSecret; |
335 | } |
336 | |
337 | CBitcoinSecret(const CSecret& vchSecret) |
338 | { |
339 | SetSecret(vchSecret); |
340 | } |
341 | |
342 | CBitcoinSecret() |
343 | { |
344 | } |
345 | }; |
346 | |
347 | #endif |