Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13115036
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
17 KB
Subscribers
None
View Options
diff --git a/src/base58.cpp b/src/base58.cpp
index 189f9a7dc..899bbd29d 100644
--- a/src/base58.cpp
+++ b/src/base58.cpp
@@ -1,337 +1,309 @@
// Copyright (c) 2014-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
#include "hash.h"
+#include "script/script.h"
#include "uint256.h"
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
/** All alphanumeric characters except for "0", "I", "O", and "l" */
static const char *pszBase58 =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
bool DecodeBase58(const char *psz, std::vector<uint8_t> &vch) {
// Skip leading spaces.
while (*psz && isspace(*psz)) {
psz++;
}
// Skip and count leading '1's.
int zeroes = 0;
int length = 0;
while (*psz == '1') {
zeroes++;
psz++;
}
// Allocate enough space in big-endian base256 representation.
// log(58) / log(256), rounded up.
int size = strlen(psz) * 733 / 1000 + 1;
std::vector<uint8_t> b256(size);
// Process the characters.
while (*psz && !isspace(*psz)) {
// Decode base58 character
const char *ch = strchr(pszBase58, *psz);
if (ch == nullptr) {
return false;
}
// Apply "b256 = b256 * 58 + ch".
int carry = ch - pszBase58;
int i = 0;
for (std::vector<uint8_t>::reverse_iterator it = b256.rbegin();
(carry != 0 || i < length) && (it != b256.rend()); ++it, ++i) {
carry += 58 * (*it);
*it = carry % 256;
carry /= 256;
}
assert(carry == 0);
length = i;
psz++;
}
// Skip trailing spaces.
while (isspace(*psz)) {
psz++;
}
if (*psz != 0) {
return false;
}
// Skip leading zeroes in b256.
std::vector<uint8_t>::iterator it = b256.begin() + (size - length);
while (it != b256.end() && *it == 0)
it++;
// Copy result into output vector.
vch.reserve(zeroes + (b256.end() - it));
vch.assign(zeroes, 0x00);
while (it != b256.end()) {
vch.push_back(*(it++));
}
return true;
}
std::string EncodeBase58(const uint8_t *pbegin, const uint8_t *pend) {
// Skip & count leading zeroes.
int zeroes = 0;
int length = 0;
while (pbegin != pend && *pbegin == 0) {
pbegin++;
zeroes++;
}
// Allocate enough space in big-endian base58 representation.
// log(256) / log(58), rounded up.
int size = (pend - pbegin) * 138 / 100 + 1;
std::vector<uint8_t> b58(size);
// Process the bytes.
while (pbegin != pend) {
int carry = *pbegin;
int i = 0;
// Apply "b58 = b58 * 256 + ch".
for (std::vector<uint8_t>::reverse_iterator it = b58.rbegin();
(carry != 0 || i < length) && (it != b58.rend()); it++, i++) {
carry += 256 * (*it);
*it = carry % 58;
carry /= 58;
}
assert(carry == 0);
length = i;
pbegin++;
}
// Skip leading zeroes in base58 result.
std::vector<uint8_t>::iterator it = b58.begin() + (size - length);
while (it != b58.end() && *it == 0) {
it++;
}
// Translate the result into a string.
std::string str;
str.reserve(zeroes + (b58.end() - it));
str.assign(zeroes, '1');
while (it != b58.end()) {
str += pszBase58[*(it++)];
}
return str;
}
std::string EncodeBase58(const std::vector<uint8_t> &vch) {
return EncodeBase58(&vch[0], &vch[0] + vch.size());
}
bool DecodeBase58(const std::string &str, std::vector<uint8_t> &vchRet) {
return DecodeBase58(str.c_str(), vchRet);
}
std::string EncodeBase58Check(const std::vector<uint8_t> &vchIn) {
// add 4-byte hash check to the end
std::vector<uint8_t> vch(vchIn);
uint256 hash = Hash(vch.begin(), vch.end());
vch.insert(vch.end(), (uint8_t *)&hash, (uint8_t *)&hash + 4);
return EncodeBase58(vch);
}
bool DecodeBase58Check(const char *psz, std::vector<uint8_t> &vchRet) {
if (!DecodeBase58(psz, vchRet) || (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<uint8_t> &vchRet) {
return DecodeBase58Check(str.c_str(), vchRet);
}
CBase58Data::CBase58Data() {
vchVersion.clear();
vchData.clear();
}
void CBase58Data::SetData(const std::vector<uint8_t> &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<uint8_t> &vchVersionIn,
const uint8_t *pbegin, const uint8_t *pend) {
SetData(vchVersionIn, (void *)pbegin, pend - pbegin);
}
bool CBase58Data::SetString(const char *psz, unsigned int nVersionBytes) {
std::vector<uint8_t> vchTemp;
bool rc58 = DecodeBase58Check(psz, vchTemp);
if ((!rc58) || (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());
}
memory_cleanse(&vchTemp[0], vchTemp.size());
return true;
}
bool CBase58Data::SetString(const std::string &str) {
return SetString(str.c_str());
}
std::string CBase58Data::ToString() const {
std::vector<uint8_t> 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 {
-/**
- * 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 : public CBase58Data {
-public:
- bool Set(const CKeyID &id);
- bool Set(const CScriptID &id);
- bool Set(const CTxDestination &dest);
- bool IsValid() const;
- bool IsValid(const CChainParams ¶ms) const;
-
- CBitcoinAddress() {}
- CBitcoinAddress(const CTxDestination &dest) { Set(dest); }
- CBitcoinAddress(const std::string &strAddress) { SetString(strAddress); }
- CBitcoinAddress(const char *pszAddress) { SetString(pszAddress); }
-
- CTxDestination Get() const;
-};
-
-class CBitcoinAddressVisitor : public boost::static_visitor<bool> {
+class DestinationEncoder : public boost::static_visitor<std::string> {
private:
- CBitcoinAddress *addr;
+ const CChainParams &m_params;
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; }
-};
-
-} // anon namespace
+ DestinationEncoder(const CChainParams ¶ms) : m_params(params) {}
-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);
-}
+ std::string operator()(const CKeyID &id) const {
+ std::vector<uint8_t> data =
+ m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
+ data.insert(data.end(), id.begin(), id.end());
+ return EncodeBase58Check(data);
+ }
-bool CBitcoinAddress::IsValid() const {
- return IsValid(Params());
-}
+ std::string operator()(const CScriptID &id) const {
+ std::vector<uint8_t> data =
+ m_params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
+ data.insert(data.end(), id.begin(), id.end());
+ return EncodeBase58Check(data);
+ }
-bool CBitcoinAddress::IsValid(const CChainParams ¶ms) const {
- bool fCorrectSize = vchData.size() == 20;
- bool fKnownVersion =
- vchVersion == params.Base58Prefix(CChainParams::PUBKEY_ADDRESS) ||
- vchVersion == params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
- return fCorrectSize && fKnownVersion;
-}
+ std::string operator()(const CNoDestination &no) const { return ""; }
+};
-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 {
+CTxDestination DecodeDestination(const std::string &str,
+ const CChainParams ¶ms) {
+ std::vector<uint8_t> data;
+ uint160 hash;
+ if (!DecodeBase58Check(str, data)) {
return CNoDestination();
}
+ // Base58Check decoding
+ const std::vector<uint8_t> &pubkey_prefix =
+ params.Base58Prefix(CChainParams::PUBKEY_ADDRESS);
+ if (data.size() == 20 + pubkey_prefix.size() &&
+ std::equal(pubkey_prefix.begin(), pubkey_prefix.end(), data.begin())) {
+ memcpy(hash.begin(), &data[pubkey_prefix.size()], 20);
+ return CKeyID(hash);
+ }
+ const std::vector<uint8_t> &script_prefix =
+ params.Base58Prefix(CChainParams::SCRIPT_ADDRESS);
+ if (data.size() == 20 + script_prefix.size() &&
+ std::equal(script_prefix.begin(), script_prefix.end(), data.begin())) {
+ memcpy(hash.begin(), &data[script_prefix.size()], 20);
+ return CScriptID(hash);
+ }
+ return CNoDestination();
}
+} // namespace
+
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;
assert(vchData.size() >= 32);
ret.Set(vchData.begin(), vchData.begin() + 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());
}
std::string EncodeDestination(const CTxDestination &dest) {
- CBitcoinAddress addr(dest);
- return addr.IsValid() ? addr.ToString() : "";
+ return boost::apply_visitor(DestinationEncoder(Params()), dest);
}
CTxDestination DecodeDestination(const std::string &str) {
- return CBitcoinAddress(str).Get();
+ return DecodeDestination(str, Params());
}
bool IsValidDestinationString(const std::string &str,
const CChainParams ¶ms) {
- return CBitcoinAddress(str).IsValid(params);
+ return IsValidDestination(DecodeDestination(str, params));
}
bool IsValidDestinationString(const std::string &str) {
- return CBitcoinAddress(str).IsValid();
+ return IsValidDestination(DecodeDestination(str, Params()));
}
diff --git a/src/base58.h b/src/base58.h
index e24804aa7..24dea0d21 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -1,165 +1,164 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
/**
* Why base-58 instead of standard base-64 encoding?
* - Don't want 0OIl characters that look the same in some fonts and
* could be used to create visually identical looking data.
* - A string with non-alphanumeric characters is not as easily accepted as
* input.
* - E-mail usually won't line-break if there's no punctuation to break at.
* - Double-clicking selects the whole string as one word if it's all
* alphanumeric.
*/
#ifndef BITCOIN_BASE58_H
#define BITCOIN_BASE58_H
#include "chainparams.h"
#include "key.h"
#include "pubkey.h"
-#include "script/script.h"
#include "script/standard.h"
#include "support/allocators/zeroafterfree.h"
#include <string>
#include <vector>
/**
* Encode a byte sequence as a base58-encoded string.
* pbegin and pend cannot be nullptr, unless both are.
*/
std::string EncodeBase58(const uint8_t *pbegin, const uint8_t *pend);
/**
* Encode a byte vector as a base58-encoded string
*/
std::string EncodeBase58(const std::vector<uint8_t> &vch);
/**
* Decode a base58-encoded string (psz) into a byte vector (vchRet).
* return true if decoding is successful.
* psz cannot be nullptr.
*/
bool DecodeBase58(const char *psz, std::vector<uint8_t> &vchRet);
/**
* Decode a base58-encoded string (str) into a byte vector (vchRet).
* return true if decoding is successful.
*/
bool DecodeBase58(const std::string &str, std::vector<uint8_t> &vchRet);
/**
* Encode a byte vector into a base58-encoded string, including checksum
*/
std::string EncodeBase58Check(const std::vector<uint8_t> &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<uint8_t> &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<uint8_t> &vchRet);
/**
* Base class for all base58-encoded data
*/
class CBase58Data {
protected:
//! the version byte(s)
std::vector<uint8_t> vchVersion;
//! the actually encoded data
typedef std::vector<uint8_t, zero_after_free_allocator<uint8_t>>
vector_uchar;
vector_uchar vchData;
CBase58Data();
void SetData(const std::vector<uint8_t> &vchVersionIn, const void *pdata,
size_t nSize);
void SetData(const std::vector<uint8_t> &vchVersionIn,
const uint8_t *pbegin, const uint8_t *pend);
public:
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;
}
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; }
};
/**
* A base58-encoded secret key
*/
class CBitcoinSecret : public CBase58Data {
public:
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 {
public:
void SetKey(const K &key) {
uint8_t vch[Size];
key.Encode(vch);
SetData(Params().Base58Prefix(Type), vch, vch + Size);
}
K GetKey() {
K ret;
if (vchData.size() == Size) {
// If base58 encoded data does not hold an ext key, return a
// !IsValid() key
ret.Decode(&vchData[0]);
}
return ret;
}
CBitcoinExtKeyBase(const K &key) { SetKey(key); }
CBitcoinExtKeyBase(const std::string &strBase58c) {
SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size());
}
CBitcoinExtKeyBase() {}
};
typedef CBitcoinExtKeyBase<CExtKey, BIP32_EXTKEY_SIZE,
CChainParams::EXT_SECRET_KEY>
CBitcoinExtKey;
typedef CBitcoinExtKeyBase<CExtPubKey, BIP32_EXTKEY_SIZE,
CChainParams::EXT_PUBLIC_KEY>
CBitcoinExtPubKey;
std::string EncodeDestination(const CTxDestination &dest);
CTxDestination DecodeDestination(const std::string &str);
bool IsValidDestinationString(const std::string &str);
bool IsValidDestinationString(const std::string &str,
const CChainParams ¶ms);
#endif // BITCOIN_BASE58_H
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Mar 2, 09:24 (1 d, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187193
Default Alt Text
(17 KB)
Attached To
rABC Bitcoin ABC
Event Timeline
Log In to Comment