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