PRCYCoin  2.0.0.7rc1
P2P Digital Currency
base58.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014 The Bitcoin developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include "base58.h"
6 
7 #include "hash.h"
8 #include "uint256.h"
9 
10 #include <assert.h>
11 #include <boost/variant/apply_visitor.hpp>
12 #include <boost/variant/static_visitor.hpp>
13 #include <sstream>
14 #include <stdint.h>
15 #include <string.h>
16 #include <string>
17 #include <vector>
18 
20 static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
21 
22 bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch)
23 {
24  // Skip leading spaces.
25  while (*psz && isspace(*psz))
26  psz++;
27  // Skip and count leading '1's.
28  int zeroes = 0;
29  while (*psz == '1') {
30  zeroes++;
31  psz++;
32  }
33  // Allocate enough space in big-endian base256 representation.
34  std::vector<unsigned char> b256(strlen(psz) * 733 / 1000 + 1); // log(58) / log(256), rounded up.
35  // Process the characters.
36  while (*psz && !isspace(*psz)) {
37  // Decode base58 character
38  const char* ch = strchr(pszBase58, *psz);
39  if (ch == NULL)
40  return false;
41  // Apply "b256 = b256 * 58 + ch".
42  int carry = ch - pszBase58;
43  for (std::vector<unsigned char>::reverse_iterator it = b256.rbegin(); it != b256.rend(); it++) {
44  carry += 58 * (*it);
45  *it = carry % 256;
46  carry /= 256;
47  }
48  assert(carry == 0);
49  psz++;
50  }
51  // Skip trailing spaces.
52  while (isspace(*psz))
53  psz++;
54  if (*psz != 0)
55  return false;
56  // Skip leading zeroes in b256.
57  std::vector<unsigned char>::iterator it = b256.begin();
58  while (it != b256.end() && *it == 0)
59  it++;
60  // Copy result into output vector.
61  vch.reserve(zeroes + (b256.end() - it));
62  vch.assign(zeroes, 0x00);
63  while (it != b256.end())
64  vch.push_back(*(it++));
65  return true;
66 }
67 
68 std::string DecodeBase58(const char* psz)
69 {
70  std::vector<unsigned char> vch;
71  DecodeBase58(psz, vch);
72  std::stringstream ss;
73  ss << std::hex;
74 
75  for (unsigned int i = 0; i < vch.size(); i++) {
76  unsigned char* c = &vch[i];
77  ss << std::setw(2) << std::setfill('0') << (int)c[0];
78  }
79 
80  return ss.str();
81 }
82 
83 std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
84 {
85  // Skip & count leading zeroes.
86  int zeroes = 0;
87  while (pbegin != pend && *pbegin == 0) {
88  pbegin++;
89  zeroes++;
90  }
91  // Allocate enough space in big-endian base58 representation.
92  std::vector<unsigned char> b58((pend - pbegin) * 138 / 100 + 1); // log(256) / log(58), rounded up.
93  // Process the bytes.
94  while (pbegin != pend) {
95  int carry = *pbegin;
96  // Apply "b58 = b58 * 256 + ch".
97  for (std::vector<unsigned char>::reverse_iterator it = b58.rbegin(); it != b58.rend(); it++) {
98  carry += 256 * (*it);
99  *it = carry % 58;
100  carry /= 58;
101  }
102  assert(carry == 0);
103  pbegin++;
104  }
105  // Skip leading zeroes in base58 result.
106  std::vector<unsigned char>::iterator it = b58.begin();
107  while (it != b58.end() && *it == 0)
108  it++;
109  // Translate the result into a string.
110  std::string str;
111  str.reserve(zeroes + (b58.end() - it));
112  str.assign(zeroes, '1');
113  while (it != b58.end())
114  str += pszBase58[*(it++)];
115  return str;
116 }
117 
118 std::string EncodeBase58(const std::vector<unsigned char>& vch)
119 {
120  return EncodeBase58(&vch[0], &vch[0] + vch.size());
121 }
122 
123 bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
124 {
125  return DecodeBase58(str.c_str(), vchRet);
126 }
127 
128 std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
129 {
130  // add 4-byte hash check to the end
131  std::vector<unsigned char> vch(vchIn);
132  uint256 hash = Hash(vch.begin(), vch.end());
133  vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
134  return EncodeBase58(vch);
135 }
136 
137 bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
138 {
139  if (!DecodeBase58(psz, vchRet) ||
140  (vchRet.size() < 4)) {
141  vchRet.clear();
142  return false;
143  }
144  // re-calculate the checksum, insure it matches the included 4-byte checksum
145  uint256 hash = Hash(vchRet.begin(), vchRet.end() - 4);
146  if (memcmp(&hash, &vchRet.end()[-4], 4) != 0) {
147  vchRet.clear();
148  return false;
149  }
150  vchRet.resize(vchRet.size() - 4);
151  return true;
152 }
153 
154 bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
155 {
156  return DecodeBase58Check(str.c_str(), vchRet);
157 }
158 
160 {
161  vchVersion.clear();
162  vchData.clear();
163 }
164 
165 void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const void* pdata, size_t nSize)
166 {
167  vchVersion = vchVersionIn;
168  vchData.resize(nSize);
169  if (!vchData.empty())
170  memcpy(&vchData[0], pdata, nSize);
171 }
172 
173 void CBase58Data::SetData(const std::vector<unsigned char>& vchVersionIn, const unsigned char* pbegin, const unsigned char* pend)
174 {
175  SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
176 }
177 
178 bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes)
179 {
180  std::vector<unsigned char> vchTemp;
181  bool rc58 = DecodeBase58Check(psz, vchTemp);
182  if ((!rc58) || (vchTemp.size() < nVersionBytes)) {
183  vchData.clear();
184  vchVersion.clear();
185  return false;
186  }
187  vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
188  vchData.resize(vchTemp.size() - nVersionBytes);
189  if (!vchData.empty())
190  memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());
191  memory_cleanse(&vchTemp[0], vchData.size());
192  return true;
193 }
194 
195 bool CBase58Data::SetString(const std::string& str)
196 {
197  return SetString(str.c_str());
198 }
199 
200 std::string CBase58Data::ToString() const
201 {
202  std::vector<unsigned char> vch = vchVersion;
203  vch.insert(vch.end(), vchData.begin(), vchData.end());
204  return EncodeBase58Check(vch);
205 }
206 
207 int CBase58Data::CompareTo(const CBase58Data& b58) const
208 {
209  if (vchVersion < b58.vchVersion)
210  return -1;
211  if (vchVersion > b58.vchVersion)
212  return 1;
213  if (vchData < b58.vchData)
214  return -1;
215  if (vchData > b58.vchData)
216  return 1;
217  return 0;
218 }
219 
220 namespace
221 {
222 class CBitcoinAddressVisitor : public boost::static_visitor<bool>
223 {
224 private:
225  CBitcoinAddress* addr;
226 
227 public:
228  CBitcoinAddressVisitor(CBitcoinAddress* addrIn) : addr(addrIn) {}
229 
230  bool operator()(const CKeyID& id) const { return addr->Set(id); }
231  bool operator()(const CScriptID& id) const { return addr->Set(id); }
232  bool operator()(const CNoDestination& no) const { return false; }
233 };
234 
235 } // anon namespace
236 
238 {
239  SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
240  return true;
241 }
242 
244 {
245  SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
246  return true;
247 }
248 
250 {
251  return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
252 }
253 
255 {
256  return IsValid(Params());
257 }
258 
259 bool CBitcoinAddress::IsValid(const CChainParams& params) const
260 {
261  bool fCorrectSize = vchData.size() == 20;
262  bool fKnownVersion = vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
264  return fCorrectSize && fKnownVersion;
265 }
266 
268 {
269  if (!IsValid())
270  return CNoDestination();
271  uint160 id;
272  memcpy(&id, &vchData[0], 20);
273  if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
274  return CKeyID(id);
275  else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
276  return CScriptID(id);
277  else
278  return CNoDestination();
279 }
280 
282 {
283  if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
284  return false;
285  uint160 id;
286  memcpy(&id, &vchData[0], 20);
287  keyID = CKeyID(id);
288  return true;
289 }
290 
292 {
294 }
295 
296 void CBitcoinSecret::SetKey(const CKey& vchSecret)
297 {
298  assert(vchSecret.IsValid());
299  SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
300  if (vchSecret.IsCompressed())
301  vchData.push_back(1);
302 }
303 
305 {
306  CKey ret;
307  assert(vchData.size() >= 32);
308  ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1);
309  return ret;
310 }
311 
313 {
314  bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
315  bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
316  return fExpectedFormat && fCorrectVersion;
317 }
318 
319 bool CBitcoinSecret::SetString(const char* pszSecret)
320 {
321  return CBase58Data::SetString(pszSecret) && IsValid();
322 }
323 
324 bool CBitcoinSecret::SetString(const std::string& strSecret)
325 {
326  return SetString(strSecret.c_str());
327 }
CKey::IsCompressed
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
Definition: key.h:107
base_uint::end
unsigned char * end()
Definition: arith_uint256.h:245
CBitcoinSecret::GetKey
CKey GetKey()
Definition: base58.cpp:304
CBitcoinAddress::GetKeyID
bool GetKeyID(CKeyID &keyID) const
Definition: base58.cpp:281
CBase58Data::vchData
vector_uchar vchData
Definition: base58.h:84
CBitcoinAddress
base58-encoded PRCY addresses.
Definition: base58.h:109
uint256.h
CKey::Set
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:83
CChainParams
CChainParams defines various tweakable parameters of a given instance of the PRCY system.
Definition: chainparams.h:41
CBase58Data::SetData
void SetData(const std::vector< unsigned char > &vchVersionIn, const void *pdata, size_t nSize)
Definition: base58.cpp:165
memcpy
void * memcpy(void *a, const void *b, size_t c)
Definition: glibc_compat.cpp:15
CKeyID
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:29
EncodeBase58
std::string EncodeBase58(const unsigned char *pbegin, const unsigned char *pend)
Why base-58 instead of standard base-64 encoding?
Definition: base58.cpp:83
CBitcoinAddress::Set
bool Set(const CKeyID &id)
Definition: base58.cpp:237
CBase58Data::CompareTo
int CompareTo(const CBase58Data &b58) const
Definition: base58.cpp:207
memory_cleanse
void memory_cleanse(void *ptr, size_t len)
Definition: cleanse.cpp:27
DecodeBase58
bool DecodeBase58(const char *psz, std::vector< unsigned char > &vch)
Decode a base58-encoded string (psz) into a byte vector (vchRet).
Definition: base58.cpp:22
CBase58Data::ToString
std::string ToString() const
Definition: base58.cpp:200
CBitcoinAddress::IsScript
bool IsScript() const
Definition: base58.cpp:291
CKey::begin
const unsigned char * begin() const
Definition: key.h:100
CBase58Data::SetString
bool SetString(const char *psz, unsigned int nVersionBytes=1)
Definition: base58.cpp:178
CChainParams::SECRET_KEY
@ SECRET_KEY
Definition: chainparams.h:47
CChainParams::Base58Prefix
const std::vector< unsigned char > & Base58Prefix(Base58Type type) const
Definition: chainparams.h:97
CKey::IsValid
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:104
CBase58Data::CBase58Data
CBase58Data()
Definition: base58.cpp:159
zxcvbn::no
const auto no
Definition: adjacency_graphs.cpp:17
CBitcoinSecret::SetString
bool SetString(const char *pszSecret)
Definition: base58.cpp:319
uint256
256-bit unsigned big integer.
Definition: uint256.h:38
DecodeBase58Check
bool DecodeBase58Check(const char *psz, std::vector< unsigned char > &vchRet)
Decode a base58-encoded string (psz) that includes a checksum into a byte vector (vchRet),...
Definition: base58.cpp:137
EncodeBase58Check
std::string EncodeBase58Check(const std::vector< unsigned char > &vchIn)
Encode a byte vector into a base58-encoded string, including checksum.
Definition: base58.cpp:128
CNoDestination
Definition: standard.h:68
CTxDestination
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:81
uint160
160-bit unsigned big integer.
Definition: uint256.h:27
CKey::size
unsigned int size() const
Simple read-only vector-like interface.
Definition: key.h:99
CKey
An encapsulated private key.
Definition: key.h:39
Params
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:463
CChainParams::PUBKEY_ADDRESS
@ PUBKEY_ADDRESS
Definition: chainparams.h:45
hash.h
CBase58Data::vchVersion
std::vector< unsigned char > vchVersion
the version byte(s)
Definition: base58.h:80
base58.h
CBitcoinSecret::IsValid
bool IsValid() const
Definition: base58.cpp:312
CBase58Data
Base class for all base58-encoded data.
Definition: base58.h:76
Hash
std::string Hash(std::string input)
Compute the 256-bit hash of a std::string.
Definition: hash.h:122
CBitcoinAddress::IsValid
bool IsValid() const
Definition: base58.cpp:254
CScriptID
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:20
CBitcoinSecret::SetKey
void SetKey(const CKey &vchSecret)
Definition: base58.cpp:296
CBitcoinAddress::Get
CTxDestination Get() const
Definition: base58.cpp:267
CChainParams::SCRIPT_ADDRESS
@ SCRIPT_ADDRESS
Definition: chainparams.h:46