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