X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fbase58.h;h=5675c049b8d2cae53e755c599dc5ac792be010eb;hb=6f895c2539c4ddefce658bb2ec7083774bbbd5a3;hp=816193eaebc129cf67977ccf7790db6efa7330c6;hpb=2ffba736e9102d016b96c2e5de2ce7757e612667;p=novacoin.git diff --git a/src/base58.h b/src/base58.h index 816193e..5675c04 100644 --- a/src/base58.h +++ b/src/base58.h @@ -1,6 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2012 The Bitcoin Developers // Distributed under the MIT/X11 software license, see the accompanying -// file license.txt or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or http://www.opensource.org/licenses/mit-license.php. // @@ -9,7 +10,7 @@ // could be used to create visually identical looking account numbers. // - A string with non-alphanumeric characters is not as easily accepted as an account number. // - E-mail usually won't line-break if there's no punctuation to break at. -// - Doubleclicking selects the whole number as one word if it's all alphanumeric. +// - Double-clicking selects the whole number as one word if it's all alphanumeric. // #ifndef BITCOIN_BASE58_H #define BITCOIN_BASE58_H @@ -17,10 +18,12 @@ #include #include #include "bignum.h" +#include "key.h" +#include "script.h" static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - +// Encode a byte sequence as a base58-encoded string inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) { CAutoBN_CTX pctx; @@ -48,7 +51,7 @@ inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char if (!BN_div(&dv, &rem, &bn, &bn58, pctx)) throw bignum_error("EncodeBase58 : BN_div failed"); bn = dv; - unsigned int c = rem.getulong(); + unsigned int c = rem.getuint32(); str += pszBase58[c]; } @@ -61,11 +64,14 @@ inline std::string EncodeBase58(const unsigned char* pbegin, const unsigned char return str; } +// Encode a byte vector as a base58-encoded string inline std::string EncodeBase58(const std::vector& vch) { return EncodeBase58(&vch[0], &vch[0] + vch.size()); } +// Decode a base58-encoded string psz into byte vector vchRet +// returns true if decoding is successful inline bool DecodeBase58(const char* psz, std::vector& vchRet) { CAutoBN_CTX pctx; @@ -88,7 +94,7 @@ inline bool DecodeBase58(const char* psz, std::vector& vchRet) return false; break; } - bnChar.setulong(p1 - pszBase58); + bnChar.setuint32(p1 - pszBase58); if (!BN_mul(&bn, &bn, &bn58, pctx)) throw bignum_error("DecodeBase58 : BN_mul failed"); bn += bnChar; @@ -112,6 +118,8 @@ inline bool DecodeBase58(const char* psz, std::vector& vchRet) return true; } +// Decode a base58-encoded string str into byte vector vchRet +// returns true if decoding is successful inline bool DecodeBase58(const std::string& str, std::vector& vchRet) { return DecodeBase58(str.c_str(), vchRet); @@ -120,7 +128,7 @@ inline bool DecodeBase58(const std::string& str, std::vector& vch - +// Encode a byte vector to a base58-encoded string, including checksum inline std::string EncodeBase58Check(const std::vector& vchIn) { // add 4-byte hash check to the end @@ -130,6 +138,8 @@ inline std::string EncodeBase58Check(const std::vector& vchIn) return EncodeBase58(vch); } +// Decode a base58-encoded string psz that includes a checksum, into byte vector vchRet +// returns true if decoding is successful inline bool DecodeBase58Check(const char* psz, std::vector& vchRet) { if (!DecodeBase58(psz, vchRet)) @@ -149,6 +159,8 @@ inline bool DecodeBase58Check(const char* psz, std::vector& vchRe return true; } +// Decode a base58-encoded string str that includes a checksum, into byte vector vchRet +// returns true if decoding is successful inline bool DecodeBase58Check(const std::string& str, std::vector& vchRet) { return DecodeBase58Check(str.c_str(), vchRet); @@ -158,26 +170,47 @@ inline bool DecodeBase58Check(const std::string& str, std::vector - -class CBitcoinAddress +/** Base class for all base58-encoded data */ +class CBase58Data { protected: + // the version byte unsigned char nVersion; + + // the actually encoded data std::vector vchData; -public: - bool SetAddress(const uint160& hash160) + CBase58Data() { - nVersion = fTestNet ? 111 : 0; - vchData.resize(20); - memcpy(&vchData[0], &hash160, 20); - return true; + nVersion = 0; + vchData.clear(); + } + + ~CBase58Data() + { + // zero the memory, as it may contain sensitive data + if (!vchData.empty()) + memset(&vchData[0], 0, vchData.size()); } - bool SetAddress(const char* pszAddress) + void SetData(int nVersionIn, const void* pdata, size_t nSize) + { + nVersion = nVersionIn; + vchData.resize(nSize); + if (!vchData.empty()) + memcpy(&vchData[0], pdata, nSize); + } + + void SetData(int nVersionIn, const unsigned char *pbegin, const unsigned char *pend) + { + SetData(nVersionIn, (void*)pbegin, pend - pbegin); + } + +public: + bool SetString(const char* psz) { std::vector vchTemp; - DecodeBase58Check(pszAddress, vchTemp); + DecodeBase58Check(psz, vchTemp); if (vchTemp.empty()) { vchData.clear(); @@ -186,30 +219,105 @@ public: } nVersion = vchTemp[0]; vchData.resize(vchTemp.size() - 1); - memcpy(&vchData[0], &vchTemp[1], vchData.size()); + if (!vchData.empty()) + memcpy(&vchData[0], &vchTemp[1], vchData.size()); + memset(&vchTemp[0], 0, vchTemp.size()); return true; } - bool SetAddress(const std::string& strAddress) + bool SetString(const std::string& str) { - return SetAddress(strAddress.c_str()); + return SetString(str.c_str()); } - bool SetAddress(const std::vector& vchPubKey) + std::string ToString() const { - return SetAddress(Hash160(vchPubKey)); + std::vector vch(1, nVersion); + vch.insert(vch.end(), vchData.begin(), vchData.end()); + return EncodeBase58Check(vch); + } + + int CompareTo(const CBase58Data& b58) const + { + if (nVersion < b58.nVersion) return -1; + if (nVersion > b58.nVersion) return 1; + if (vchData < b58.vchData) return -1; + if (vchData > b58.vchData) return 1; + return 0; + } + + bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; } + bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; } + bool operator>=(const CBase58Data& b58) const { return CompareTo(b58) >= 0; } + bool operator< (const CBase58Data& b58) const { return CompareTo(b58) < 0; } + bool operator> (const CBase58Data& b58) const { return CompareTo(b58) > 0; } +}; + +/** base58-encoded Bitcoin addresses. + * Public-key-hash-addresses have version 0 (or 111 testnet). + * The data vector contains RIPEMD160(SHA256(pubkey)), where pubkey is the serialized public key. + * Script-hash-addresses have version 5 (or 196 testnet). + * The data vector contains RIPEMD160(SHA256(cscript)), where cscript is the serialized redemption script. + */ +class CBitcoinAddress; +class CBitcoinAddressVisitor : public boost::static_visitor +{ +private: + CBitcoinAddress *addr; +public: + CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { } + bool operator()(const CKeyID &id) const; + bool operator()(const CScriptID &id) const; + bool operator()(const CNoDestination &no) const; +}; + +class CBitcoinAddress : public CBase58Data +{ +public: + enum + { + PUBKEY_ADDRESS = 8, + SCRIPT_ADDRESS = 20, + PUBKEY_ADDRESS_TEST = 111, + SCRIPT_ADDRESS_TEST = 196, + }; + + bool Set(const CKeyID &id) { + SetData(fTestNet ? PUBKEY_ADDRESS_TEST : PUBKEY_ADDRESS, &id, 20); + return true; + } + + bool Set(const CScriptID &id) { + SetData(fTestNet ? SCRIPT_ADDRESS_TEST : SCRIPT_ADDRESS, &id, 20); + return true; + } + + bool Set(const CTxDestination &dest) + { + return boost::apply_visitor(CBitcoinAddressVisitor(this), dest); } bool IsValid() const { - int nExpectedSize = 20; + unsigned int nExpectedSize = 20; bool fExpectTestNet = false; switch(nVersion) { - case 0: + case PUBKEY_ADDRESS: + nExpectedSize = 20; // Hash of public key + fExpectTestNet = false; + break; + case SCRIPT_ADDRESS: + nExpectedSize = 20; // Hash of CScript + fExpectTestNet = false; break; - case 111: + case PUBKEY_ADDRESS_TEST: + nExpectedSize = 20; + fExpectTestNet = true; + break; + case SCRIPT_ADDRESS_TEST: + nExpectedSize = 20; fExpectTestNet = true; break; @@ -221,59 +329,132 @@ public: CBitcoinAddress() { - nVersion = 0; - vchData.clear(); } - CBitcoinAddress(uint160 hash160In) + CBitcoinAddress(const CTxDestination &dest) { - SetAddress(hash160In); + Set(dest); } - CBitcoinAddress(const std::vector& vchPubKey) + CBitcoinAddress(const std::string& strAddress) { - SetAddress(vchPubKey); + SetString(strAddress); } - CBitcoinAddress(const std::string& strAddress) + CBitcoinAddress(const char* pszAddress) { - SetAddress(strAddress); + SetString(pszAddress); } - CBitcoinAddress(const char* pszAddress) + CTxDestination Get() const { + if (!IsValid()) + return CNoDestination(); + switch (nVersion) { + case PUBKEY_ADDRESS: + case PUBKEY_ADDRESS_TEST: { + uint160 id; + memcpy(&id, &vchData[0], 20); + return CKeyID(id); + } + case SCRIPT_ADDRESS: + case SCRIPT_ADDRESS_TEST: { + uint160 id; + memcpy(&id, &vchData[0], 20); + return CScriptID(id); + } + } + return CNoDestination(); + } + + bool GetKeyID(CKeyID &keyID) const { + if (!IsValid()) + return false; + switch (nVersion) { + case PUBKEY_ADDRESS: + case PUBKEY_ADDRESS_TEST: { + uint160 id; + memcpy(&id, &vchData[0], 20); + keyID = CKeyID(id); + return true; + } + default: return false; + } + } + + bool IsScript() const { + if (!IsValid()) + return false; + switch (nVersion) { + case SCRIPT_ADDRESS: + case SCRIPT_ADDRESS_TEST: { + return true; + } + default: return false; + } + } +}; + +bool inline CBitcoinAddressVisitor::operator()(const CKeyID &id) const { return addr->Set(id); } +bool inline CBitcoinAddressVisitor::operator()(const CScriptID &id) const { return addr->Set(id); } +bool inline CBitcoinAddressVisitor::operator()(const CNoDestination &id) const { return false; } + +/** A base58-encoded secret key */ +class CBitcoinSecret : public CBase58Data +{ +public: + void SetSecret(const CSecret& vchSecret, bool fCompressed) { - SetAddress(pszAddress); + assert(vchSecret.size() == 32); + SetData(128 + (fTestNet ? CBitcoinAddress::PUBKEY_ADDRESS_TEST : CBitcoinAddress::PUBKEY_ADDRESS), &vchSecret[0], vchSecret.size()); + if (fCompressed) + vchData.push_back(1); } - std::string ToString() const + CSecret GetSecret(bool &fCompressedOut) { - std::vector vch(1, nVersion); - vch.insert(vch.end(), vchData.begin(), vchData.end()); - return EncodeBase58Check(vch); + CSecret vchSecret; + vchSecret.resize(32); + memcpy(&vchSecret[0], &vchData[0], 32); + fCompressedOut = vchData.size() == 33; + return vchSecret; + } + + bool IsValid() const + { + bool fExpectTestNet = false; + switch(nVersion) + { + case (128 + CBitcoinAddress::PUBKEY_ADDRESS): + break; + + case (128 + CBitcoinAddress::PUBKEY_ADDRESS_TEST): + fExpectTestNet = true; + break; + + default: + return false; + } + return fExpectTestNet == fTestNet && (vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1)); } - uint160 GetHash160() const + bool SetString(const char* pszSecret) { - assert(vchData.size() == 20); - uint160 hash160; - memcpy(&hash160, &vchData[0], 20); - return hash160; + return CBase58Data::SetString(pszSecret) && IsValid(); } - int CompareTo(const CBitcoinAddress& address) const + bool SetString(const std::string& strSecret) { - if (nVersion < address.nVersion) return -1; - if (nVersion < address.nVersion) return 1; - if (vchData < address.vchData) return -1; - if (vchData > address.vchData) return 1; - return 0; + return SetString(strSecret.c_str()); + } + + CBitcoinSecret(const CSecret& vchSecret, bool fCompressed) + { + SetSecret(vchSecret, fCompressed); } - bool operator==(const CBitcoinAddress& address) const { return CompareTo(address) == 0; } - bool operator<=(const CBitcoinAddress& address) const { return CompareTo(address) <= 0; } - bool operator>=(const CBitcoinAddress& address) const { return CompareTo(address) >= 0; } - bool operator< (const CBitcoinAddress& address) const { return CompareTo(address) < 0; } - bool operator> (const CBitcoinAddress& address) const { return CompareTo(address) > 0; } + CBitcoinSecret() + { + } }; #endif