]>
Commit | Line | Data |
---|---|---|
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 | |
27 | static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | |
28 | ||
d825e6a3 | 29 | // Encode a byte sequence as a base58-encoded string |
223b6f1b | 30 | inline 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 | 71 | inline 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 | 78 | inline 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 | 126 | inline 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 | 135 | inline 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 | 146 | inline 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 | 167 | inline 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 | 177 | class CBase58Data |
0a61b0df | 178 | { |
2ffba736 | 179 | protected: |
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 | 206 | public: |
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 |
259 | class CBitcoinAddress; |
260 | class CBitcoinAddressVisitor : public boost::static_visitor<bool> | |
261 | { | |
262 | private: | |
263 | CBitcoinAddress *addr; | |
264 | public: | |
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 |
271 | class CBitcoinAddress : public CBase58Data |
272 | { | |
273 | public: | |
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 |
343 | bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); } |
344 | bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); } | |
345 | bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; } | |
346 | ||
6b8de05d | 347 | /** A base58-encoded secret key */ |
15a8590e PW |
348 | class CBitcoinSecret : public CBase58Data |
349 | { | |
350 | public: | |
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 |