Browse Source

Merge pull request #4165

f6b7c64 Move base58.h implementation code to base58.cpp (Pieter Wuille)
0.10
Wladimir J. van der Laan 10 years ago
parent
commit
68d5fb3cb3
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 183
      src/base58.cpp
  2. 259
      src/base58.h
  3. 4
      src/test/base58_tests.cpp

183
src/base58.cpp

@ -2,11 +2,18 @@ @@ -2,11 +2,18 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
#include "hash.h"
#include "uint256.h"
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <vector>
#include <string>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
/* All alphanumeric characters except for "0", "I", "O", and "l" */
static const char* pszBase58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
@ -89,3 +96,179 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) @@ -89,3 +96,179 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
str += pszBase58[*(it++)];
return str;
}
std::string EncodeBase58(const std::vector<unsigned char>& vch) {
return EncodeBase58(&vch[0], &vch[0] + vch.size());
}
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet) {
return DecodeBase58(str.c_str(), vchRet);
}
std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn) {
// add 4-byte hash check to the end
std::vector<unsigned char> vch(vchIn);
uint256 hash = Hash(vch.begin(), vch.end());
vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
return EncodeBase58(vch);
}
bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet) {
if (!DecodeBase58(psz, vchRet))
return false;
if (vchRet.size() < 4)
{
vchRet.clear();
return false;
}
// re-calculate the checksum, insure it matches the included 4-byte checksum
uint256 hash = Hash(vchRet.begin(), vchRet.end()-4);
if (memcmp(&hash, &vchRet.end()[-4], 4) != 0)
{
vchRet.clear();
return false;
}
vchRet.resize(vchRet.size()-4);
return true;
}
bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet) {
return DecodeBase58Check(str.c_str(), vchRet);
}
CBase58Data::CBase58Data() {
vchVersion.clear();
vchData.clear();
}
void CBase58Data::SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize) {
vchVersion = vchVersionIn;
vchData.resize(nSize);
if (!vchData.empty())
memcpy(&vchData[0], pdata, nSize);
}
void CBase58Data::SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend) {
SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
}
bool CBase58Data::SetString(const char* psz, unsigned int nVersionBytes) {
std::vector<unsigned char> vchTemp;
DecodeBase58Check(psz, vchTemp);
if (vchTemp.size() < nVersionBytes) {
vchData.clear();
vchVersion.clear();
return false;
}
vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
vchData.resize(vchTemp.size() - nVersionBytes);
if (!vchData.empty())
memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());
OPENSSL_cleanse(&vchTemp[0], vchData.size());
return true;
}
bool CBase58Data::SetString(const std::string& str) {
return SetString(str.c_str());
}
std::string CBase58Data::ToString() const {
std::vector<unsigned char> vch = vchVersion;
vch.insert(vch.end(), vchData.begin(), vchData.end());
return EncodeBase58Check(vch);
}
int CBase58Data::CompareTo(const CBase58Data& b58) const {
if (vchVersion < b58.vchVersion) return -1;
if (vchVersion > b58.vchVersion) return 1;
if (vchData < b58.vchData) return -1;
if (vchData > b58.vchData) return 1;
return 0;
}
namespace {
class CBitcoinAddressVisitor : public boost::static_visitor<bool> {
private:
CBitcoinAddress *addr;
public:
CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { }
bool operator()(const CKeyID &id) const { return addr->Set(id); }
bool operator()(const CScriptID &id) const { return addr->Set(id); }
bool operator()(const CNoDestination &no) const { return false; }
};
};
bool CBitcoinAddress::Set(const CKeyID &id) {
SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
return true;
}
bool CBitcoinAddress::Set(const CScriptID &id) {
SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
return true;
}
bool CBitcoinAddress::Set(const CTxDestination &dest) {
return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
}
bool CBitcoinAddress::IsValid() const {
bool fCorrectSize = vchData.size() == 20;
bool fKnownVersion = vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
return fCorrectSize && fKnownVersion;
}
CTxDestination CBitcoinAddress::Get() const {
if (!IsValid())
return CNoDestination();
uint160 id;
memcpy(&id, &vchData[0], 20);
if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
return CKeyID(id);
else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
return CScriptID(id);
else
return CNoDestination();
}
bool CBitcoinAddress::GetKeyID(CKeyID &keyID) const {
if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
return false;
uint160 id;
memcpy(&id, &vchData[0], 20);
keyID = CKeyID(id);
return true;
}
bool CBitcoinAddress::IsScript() const {
return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
}
void CBitcoinSecret::SetKey(const CKey& vchSecret) {
assert(vchSecret.IsValid());
SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
if (vchSecret.IsCompressed())
vchData.push_back(1);
}
CKey CBitcoinSecret::GetKey() {
CKey ret;
ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1);
return ret;
}
bool CBitcoinSecret::IsValid() const {
bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
return fExpectedFormat && fCorrectVersion;
}
bool CBitcoinSecret::SetString(const char* pszSecret) {
return CBase58Data::SetString(pszSecret) && IsValid();
}
bool CBitcoinSecret::SetString(const std::string& strSecret) {
return SetString(strSecret.c_str());
}

259
src/base58.h

@ -15,17 +15,12 @@ @@ -15,17 +15,12 @@
#define BITCOIN_BASE58_H
#include "chainparams.h"
#include "hash.h"
#include "key.h"
#include "script.h"
#include "uint256.h"
#include <string>
#include <vector>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
/**
* Encode a byte sequence as a base58-encoded string.
* pbegin and pend cannot be NULL, unless both are.
@ -35,10 +30,7 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend) @@ -35,10 +30,7 @@ std::string EncodeBase58(const unsigned char* pbegin, const unsigned char* pend)
/**
* Encode a byte vector as a base58-encoded string
*/
inline std::string EncodeBase58(const std::vector<unsigned char>& vch)
{
return EncodeBase58(&vch[0], &vch[0] + vch.size());
}
std::string EncodeBase58(const std::vector<unsigned char>& vch);
/**
* Decode a base58-encoded string (psz) into a byte vector (vchRet).
@ -51,55 +43,24 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet); @@ -51,55 +43,24 @@ bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet);
* Decode a base58-encoded string (str) into a byte vector (vchRet).
* return true if decoding is successful.
*/
inline bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet)
{
return DecodeBase58(str.c_str(), vchRet);
}
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet);
/**
* Encode a byte vector into a base58-encoded string, including checksum
*/
inline std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
{
// add 4-byte hash check to the end
std::vector<unsigned char> vch(vchIn);
uint256 hash = Hash(vch.begin(), vch.end());
vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
return EncodeBase58(vch);
}
std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn);
/**
* Decode a base58-encoded string (psz) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet)
{
if (!DecodeBase58(psz, vchRet))
return false;
if (vchRet.size() < 4)
{
vchRet.clear();
return false;
}
// re-calculate the checksum, insure it matches the included 4-byte checksum
uint256 hash = Hash(vchRet.begin(), vchRet.end()-4);
if (memcmp(&hash, &vchRet.end()[-4], 4) != 0)
{
vchRet.clear();
return false;
}
vchRet.resize(vchRet.size()-4);
return true;
}
inline bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet);
/**
* Decode a base58-encoded string (str) that includes a checksum into a byte
* vector (vchRet), return true if decoding is successful
*/
inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet)
{
return DecodeBase58Check(str.c_str(), vchRet);
}
inline bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet);
/**
* Base class for all base58-encoded data
@ -114,64 +75,15 @@ protected: @@ -114,64 +75,15 @@ protected:
typedef std::vector<unsigned char, zero_after_free_allocator<unsigned char> > vector_uchar;
vector_uchar vchData;
CBase58Data()
{
vchVersion.clear();
vchData.clear();
}
void SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize)
{
vchVersion = vchVersionIn;
vchData.resize(nSize);
if (!vchData.empty())
memcpy(&vchData[0], pdata, nSize);
}
void SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend)
{
SetData(vchVersionIn, (void*)pbegin, pend - pbegin);
}
CBase58Data();
void SetData(const std::vector<unsigned char> &vchVersionIn, const void* pdata, size_t nSize);
void SetData(const std::vector<unsigned char> &vchVersionIn, const unsigned char *pbegin, const unsigned char *pend);
public:
bool SetString(const char* psz, unsigned int nVersionBytes = 1)
{
std::vector<unsigned char> vchTemp;
DecodeBase58Check(psz, vchTemp);
if (vchTemp.size() < nVersionBytes)
{
vchData.clear();
vchVersion.clear();
return false;
}
vchVersion.assign(vchTemp.begin(), vchTemp.begin() + nVersionBytes);
vchData.resize(vchTemp.size() - nVersionBytes);
if (!vchData.empty())
memcpy(&vchData[0], &vchTemp[nVersionBytes], vchData.size());
OPENSSL_cleanse(&vchTemp[0], vchData.size());
return true;
}
bool SetString(const std::string& str)
{
return SetString(str.c_str());
}
std::string ToString() const
{
std::vector<unsigned char> vch = vchVersion;
vch.insert(vch.end(), vchData.begin(), vchData.end());
return EncodeBase58Check(vch);
}
int CompareTo(const CBase58Data& b58) const
{
if (vchVersion < b58.vchVersion) return -1;
if (vchVersion > b58.vchVersion) return 1;
if (vchData < b58.vchData) return -1;
if (vchData > b58.vchData) return 1;
return 0;
}
bool SetString(const char* psz, unsigned int nVersionBytes = 1);
bool SetString(const std::string& str);
std::string ToString() const;
int CompareTo(const CBase58Data& b58) const;
bool operator==(const CBase58Data& b58) const { return CompareTo(b58) == 0; }
bool operator<=(const CBase58Data& b58) const { return CompareTo(b58) <= 0; }
@ -186,140 +98,37 @@ public: @@ -186,140 +98,37 @@ public:
* 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<bool>
{
private:
CBitcoinAddress *addr;
class CBitcoinAddress : public CBase58Data {
public:
CBitcoinAddressVisitor(CBitcoinAddress *addrIn) : addr(addrIn) { }
bool operator()(const CKeyID &id) const;
bool operator()(const CScriptID &id) const;
bool operator()(const CNoDestination &no) const;
bool Set(const CKeyID &id);
bool Set(const CScriptID &id);
bool Set(const CTxDestination &dest);
bool IsValid() const;
CBitcoinAddress() {}
CBitcoinAddress(const CTxDestination &dest) { Set(dest); }
CBitcoinAddress(const std::string& strAddress) { SetString(strAddress); }
CBitcoinAddress(const char* pszAddress) { SetString(pszAddress); }
CTxDestination Get() const;
bool GetKeyID(CKeyID &keyID) const;
bool IsScript() const;
};
class CBitcoinAddress : public CBase58Data
{
public:
bool Set(const CKeyID &id) {
SetData(Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS), &id, 20);
return true;
}
bool Set(const CScriptID &id) {
SetData(Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS), &id, 20);
return true;
}
bool Set(const CTxDestination &dest)
{
return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
}
bool IsValid() const
{
bool fCorrectSize = vchData.size() == 20;
bool fKnownVersion = vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
return fCorrectSize && fKnownVersion;
}
CBitcoinAddress()
{
}
CBitcoinAddress(const CTxDestination &dest)
{
Set(dest);
}
CBitcoinAddress(const std::string& strAddress)
{
SetString(strAddress);
}
CBitcoinAddress(const char* pszAddress)
{
SetString(pszAddress);
}
CTxDestination Get() const {
if (!IsValid())
return CNoDestination();
uint160 id;
memcpy(&id, &vchData[0], 20);
if (vchVersion == Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
return CKeyID(id);
else if (vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS))
return CScriptID(id);
else
return CNoDestination();
}
bool GetKeyID(CKeyID &keyID) const {
if (!IsValid() || vchVersion != Params().Base58Prefix(CChainParams::PUBKEY_ADDRESS))
return false;
uint160 id;
memcpy(&id, &vchData[0], 20);
keyID = CKeyID(id);
return true;
}
bool IsScript() const {
return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
}
};
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 SetKey(const CKey& vchSecret)
{
assert(vchSecret.IsValid());
SetData(Params().Base58Prefix(CChainParams::SECRET_KEY), vchSecret.begin(), vchSecret.size());
if (vchSecret.IsCompressed())
vchData.push_back(1);
}
CKey GetKey()
{
CKey ret;
ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1);
return ret;
}
bool IsValid() const
{
bool fExpectedFormat = vchData.size() == 32 || (vchData.size() == 33 && vchData[32] == 1);
bool fCorrectVersion = vchVersion == Params().Base58Prefix(CChainParams::SECRET_KEY);
return fExpectedFormat && fCorrectVersion;
}
bool SetString(const char* pszSecret)
{
return CBase58Data::SetString(pszSecret) && IsValid();
}
bool SetString(const std::string& strSecret)
{
return SetString(strSecret.c_str());
}
CBitcoinSecret(const CKey& vchSecret)
{
SetKey(vchSecret);
}
CBitcoinSecret()
{
}
void SetKey(const CKey& vchSecret);
CKey GetKey();
bool IsValid() const;
bool SetString(const char* pszSecret);
bool SetString(const std::string& strSecret);
CBitcoinSecret(const CKey& vchSecret) { SetKey(vchSecret); }
CBitcoinSecret() {}
};
template<typename K, int Size, CChainParams::Base58Type Type> class CBitcoinExtKeyBase : public CBase58Data

4
src/test/base58_tests.cpp

@ -233,7 +233,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) @@ -233,7 +233,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
continue;
}
CBitcoinAddress addrOut;
BOOST_CHECK_MESSAGE(boost::apply_visitor(CBitcoinAddressVisitor(&addrOut), dest), "encode dest: " + strTest);
BOOST_CHECK_MESSAGE(addrOut.Set(dest), "encode dest: " + strTest);
BOOST_CHECK_MESSAGE(addrOut.ToString() == exp_base58string, "mismatch: " + strTest);
}
}
@ -241,7 +241,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) @@ -241,7 +241,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
// Visiting a CNoDestination must fail
CBitcoinAddress dummyAddr;
CTxDestination nodest = CNoDestination();
BOOST_CHECK(!boost::apply_visitor(CBitcoinAddressVisitor(&dummyAddr), nodest));
BOOST_CHECK(!dummyAddr.Set(nodest));
SelectParams(CChainParams::MAIN);
}

Loading…
Cancel
Save