]>
Commit | Line | Data |
---|---|---|
b58be132 PW |
1 | // Copyright (c) 2014 The Bitcoin developers |
2 | // Distributed under the MIT/X11 software license, see the accompanying | |
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 | ||
b58be132 PW |
10 | #include <assert.h> |
11 | #include <stdint.h> | |
12 | #include <string.h> | |
13 | #include <vector> | |
14 | #include <string> | |
f6b7c644 PW |
15 | #include <boost/variant/apply_visitor.hpp> |
16 | #include <boost/variant/static_visitor.hpp> | |
b58be132 PW |
17 | |
18 | /* All alphanumeric characters except for "0", "I", "O", and "l" */ | |
19 | static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | |
20 | ||
20e01b1a PW |
21 | bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch) |
22 | { | |
b58be132 PW |
23 | // Skip leading spaces. |
24 | while (*psz && isspace(*psz)) | |
25 | psz++; | |
26 | // Skip and count leading '1's. | |
27 | int zeroes = 0; | |
28 | while (*psz == '1') { | |
29 | zeroes++; | |
30 | psz++; | |
31 | } | |
32 | // Allocate enough space in big-endian base256 representation. | |
33 | std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up. | |
34 | // Process the characters. | |
35 | while (*psz && !isspace(*psz)) { | |
36 | // Decode base58 character | |
20e01b1a | 37 | const char* ch = strchr(pszBase58, *psz); |
b58be132 PW |
38 | if (ch == NULL) |
39 | return false; | |
40 | // Apply "b256 = b256 * 58 + ch". | |
41 | int carry = ch - pszBase58; | |
42 | for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) { | |
43 | carry += 58 * (*it); | |
44 | *it = carry % 256; | |
45 | carry /= 256; | |
46 | } | |
47 | assert(carry == 0); | |
48 | psz++; | |
49 | } | |
50 | // Skip trailing spaces. | |
51 | while (isspace(*psz)) | |
52 | psz++; | |
53 | if (*psz != 0) | |
54 | return false; | |
55 | // Skip leading zeroes in b256. | |
56 | std::vector<unsigned char>::iterator it = b256.begin(); | |
57 | while (it != b256.end() && *it == 0) | |
58 | it++; | |
59 | // Copy result into output vector. | |
60 | vch.reserve(zeroes + (b256.end() - it)); | |
61 | vch.assign(zeroes, 0x00); | |
62 | while (it != b256.end()) | |
20e01b1a | 63 | vch.push_back(*(it++)); |
b58be132 PW |
64 | return true; |
65 | } | |
66 | ||
20e01b1a PW |
67 | std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) |
68 | { | |
b58be132 PW |
69 | // Skip & count leading zeroes. |
70 | int zeroes = 0; | |
71 | while (pbegin != pend && *pbegin == 0) { | |
72 | pbegin++; | |
73 | zeroes++; | |
74 | } | |
75 | // Allocate enough space in big-endian base58 representation. | |
76 | std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up. | |
77 | // Process the bytes. | |
78 | while (pbegin != pend) { | |
79 | int carry = *pbegin; | |
80 | // Apply "b58 = b58 * 256 + ch". | |
81 | for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) { | |
82 | carry += 256 * (*it); | |
83 | *it = carry % 58; | |
84 | carry /= 58; | |
85 | } | |
86 | assert(carry == 0); | |
87 | pbegin++; | |
88 | } | |
89 | // Skip leading zeroes in base58 result. | |
90 | std::vector<unsigned char>::iterator it = b58.begin(); | |
91 | while (it != b58.end() && *it == 0) | |
92 | it++; | |
93 | // Translate the result into a string. | |
94 | std::string str; | |
95 | str.reserve(zeroes + (b58.end() - it)); | |
96 | str.assign(zeroes, '1'); | |
97 | while (it != b58.end()) | |
98 | str += pszBase58[*(it++)]; | |
99 | return str; | |
100 | } | |
f6b7c644 | 101 | |
20e01b1a PW |
102 | std::string EncodeBase58(const std::vector<unsigned char>& vch) |
103 | { | |
f6b7c644 PW |
104 | return EncodeBase58(&vch[0], &vch[0] + vch.size()); |
105 | } | |
106 | ||
20e01b1a PW |
107 | bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet) |
108 | { | |
f6b7c644 PW |
109 | return DecodeBase58(str.c_str(), vchRet); |
110 | } | |
111 | ||
20e01b1a PW |
112 | std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) |
113 | { | |
f6b7c644 PW |
114 | // add 4-byte hash check to the end |
115 | std::vector<unsigned char> vch(vchIn); | |
116 | uint256 hash = Hash(vch.begin(), vch.end()); | |
117 | vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4); | |
118 | return EncodeBase58(vch); | |
119 | } | |
120 | ||
20e01b1a PW |
121 | bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) |
122 | { | |
88df548d | 123 | if (!DecodeBase58(psz, vchRet) || |
20e01b1a | 124 | (vchRet.size() < 4)) { |
f6b7c644 PW |
125 | vchRet.clear(); |
126 | return false; | |
127 | } | |
128 | // re-calculate the checksum, insure it matches the included 4-byte checksum | |
20e01b1a PW |
129 | uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4); |
130 | if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) { | |
f6b7c644 PW |
131 | vchRet.clear(); |
132 | return false; | |
133 | } | |
20e01b1a | 134 | vchRet.resize(vchRet.size() - 4); |
f6b7c644 PW |
135 | return true; |
136 | } | |
137 | ||
20e01b1a PW |
138 | bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet) |
139 | { | |
f6b7c644 PW |
140 | return DecodeBase58Check(str.c_str(), vchRet); |
141 | } | |
142 | ||
20e01b1a PW |
143 | CBase58Data::CBase58Data() |
144 | { | |
f6b7c644 PW |
145 | vchVersion.clear(); |
146 | vchData.clear(); | |
147 | } | |
148 | ||
20e01b1a PW |
149 | void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize) |
150 | { | |
f6b7c644 PW |
151 | vchVersion = vchVersionIn; |
152 | vchData.resize(nSize); | |
153 | if (!vchData.empty()) | |
154 | memcpy(&vchData[0], pdata, nSize); | |
155 | } | |
156 | ||
20e01b1a PW |
157 | void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend) |
158 | { | |
f6b7c644 PW |
159 | SetData(vchVersionIn, (void*)pbegin, pend - pbegin); |
160 | } | |
161 | ||
20e01b1a PW |
162 | bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes) |
163 | { | |
f6b7c644 | 164 | std::vector<unsigned char> vchTemp; |
88df548d JG |
165 | bool rc58 = DecodeBase58Check(psz, vchTemp); |
166 | if ((!rc58) || (vchTemp.size() < nVersionBytes)) { | |
f6b7c644 PW |
167 | vchData.clear(); |
168 | vchVersion.clear(); | |
169 | return false; | |
170 | } | |
171 | vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes); | |
172 | vchData.resize(vchTemp.size() - nVersionBytes); | |
173 | if (!vchData.empty()) | |
174 | memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size()); | |
175 | OPENSSL_cleanse(&vchTemp[0], vchData.size()); | |
176 | return true; | |
177 | } | |
178 | ||
20e01b1a PW |
179 | bool CBase58Data::SetString(const std::string& str) |
180 | { | |
f6b7c644 PW |
181 | return SetString(str.c_str()); |
182 | } | |
183 | ||
20e01b1a PW |
184 | std::string CBase58Data::ToString() const |
185 | { | |
f6b7c644 PW |
186 | std::vector<unsigned char> vch = vchVersion; |
187 | vch.insert(vch.end(), vchData.begin(), vchData.end()); | |
188 | return EncodeBase58Check(vch); | |
189 | } | |
190 | ||
20e01b1a PW |
191 | int CBase58Data::CompareTo(const CBase58Data& b58) const |
192 | { | |
193 | if (vchVersion < b58.vchVersion) | |
194 | return -1; | |
195 | if (vchVersion > b58.vchVersion) | |
196 | return 1; | |
197 | if (vchData < b58.vchData) | |
198 | return -1; | |
199 | if (vchData > b58.vchData) | |
200 | return 1; | |
f6b7c644 PW |
201 | return 0; |
202 | } | |
203 | ||
20e01b1a PW |
204 | namespace |
205 | { | |
206 | class CBitcoinAddressVisitor : public boost::static_visitor<bool> | |
207 | { | |
208 | private: | |
209 | CBitcoinAddress* addr; | |
e10dcf27 | 210 | |
20e01b1a PW |
211 | public: |
212 | CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {} | |
f6b7c644 | 213 | |
20e01b1a PW |
214 | bool operator()(const CKeyID& id) const { return addr->Set(id); } |
215 | bool operator()(const CScriptID& id) const { return addr->Set(id); } | |
216 | bool operator()(const CNoDestination& no) const { return false; } | |
217 | }; | |
e10dcf27 PK |
218 | |
219 | } // anon namespace | |
f6b7c644 | 220 | |
20e01b1a PW |
221 | bool CBitcoinAddress::Set(const CKeyID& id) |
222 | { | |
f6b7c644 PW |
223 | SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20); |
224 | return true; | |
225 | } | |
226 | ||
20e01b1a PW |
227 | bool CBitcoinAddress::Set(const CScriptID& id) |
228 | { | |
f6b7c644 PW |
229 | SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20); |
230 | return true; | |
231 | } | |
232 | ||
20e01b1a PW |
233 | bool CBitcoinAddress::Set(const CTxDestination& dest) |
234 | { | |
f6b7c644 PW |
235 | return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); |
236 | } | |
237 | ||
20e01b1a PW |
238 | bool CBitcoinAddress::IsValid() const |
239 | { | |
e84843c0 RN |
240 | return IsValid(Params()); |
241 | } | |
242 | ||
20e01b1a PW |
243 | bool CBitcoinAddress::IsValid(const CChainParams& params) const |
244 | { | |
f6b7c644 | 245 | bool fCorrectSize = vchData.size() == 20; |
e84843c0 RN |
246 | bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) || |
247 | vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS); | |
f6b7c644 PW |
248 | return fCorrectSize && fKnownVersion; |
249 | } | |
250 | ||
20e01b1a PW |
251 | CTxDestination CBitcoinAddress::Get() const |
252 | { | |
f6b7c644 PW |
253 | if (!IsValid()) |
254 | return CNoDestination(); | |
255 | uint160 id; | |
256 | memcpy(&id, &vchData[0], 20); | |
257 | if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) | |
258 | return CKeyID(id); | |
259 | else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS)) | |
260 | return CScriptID(id); | |
261 | else | |
262 | return CNoDestination(); | |
263 | } | |
264 | ||
20e01b1a PW |
265 | bool CBitcoinAddress::GetKeyID(CKeyID& keyID) const |
266 | { | |
f6b7c644 PW |
267 | if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS)) |
268 | return false; | |
269 | uint160 id; | |
270 | memcpy(&id, &vchData[0], 20); | |
271 | keyID = CKeyID(id); | |
272 | return true; | |
273 | } | |
274 | ||
20e01b1a PW |
275 | bool CBitcoinAddress::IsScript() const |
276 | { | |
f6b7c644 PW |
277 | return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS); |
278 | } | |
279 | ||
20e01b1a PW |
280 | void CBitcoinSecret::SetKey(const CKey& vchSecret) |
281 | { | |
f6b7c644 PW |
282 | assert(vchSecret.IsValid()); |
283 | SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size()); | |
284 | if (vchSecret.IsCompressed()) | |
285 | vchData.push_back(1); | |
286 | } | |
287 | ||
20e01b1a PW |
288 | CKey CBitcoinSecret::GetKey() |
289 | { | |
f6b7c644 | 290 | CKey ret; |
6f3ae9b5 E |
291 | assert(vchData.size() >= 32); |
292 | ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1); | |
f6b7c644 PW |
293 | return ret; |
294 | } | |
295 | ||
20e01b1a PW |
296 | bool CBitcoinSecret::IsValid() const |
297 | { | |
f6b7c644 PW |
298 | bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1); |
299 | bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY); | |
300 | return fExpectedFormat && fCorrectVersion; | |
301 | } | |
302 | ||
20e01b1a PW |
303 | bool CBitcoinSecret::SetString(const char* pszSecret) |
304 | { | |
f6b7c644 PW |
305 | return CBase58Data::SetString(pszSecret) && IsValid(); |
306 | } | |
307 | ||
20e01b1a PW |
308 | bool CBitcoinSecret::SetString(const std::string& strSecret) |
309 | { | |
f6b7c644 PW |
310 | return SetString(strSecret.c_str()); |
311 | } |