Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Base58 codec and remove Bitcoin support: #3581

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions src/ripple/protocol/AccountID.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@ template <>
boost::optional<AccountID>
parseBase58(std::string const& s);

// Parses AccountID using Bitcoin's alphabet
// This is to catch user error. Likely not needed
// DEPRECATED
boost::optional<AccountID>
deprecatedParseBitcoinAccountID(std::string const& s);

// Compatibility with legacy code
bool
deprecatedParseBase58(AccountID& account, Json::Value const& jv);
Expand Down
2 changes: 1 addition & 1 deletion src/ripple/protocol/ErrorCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ enum error_code_i {
rpcNO_PF_REQUEST = 33,

// Bad parameter
rpcACT_BITCOIN = 34,
// NOT USED DO NOT USE AGAIN rpcACT_BITCOIN = 34,
rpcACT_MALFORMED = 35,
rpcALREADY_MULTISIG = 36,
rpcALREADY_SINGLE_SIG = 37,
Expand Down
2 changes: 1 addition & 1 deletion src/ripple/protocol/PublicKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ struct STExchange<STBlob, PublicKey>
inline std::string
toBase58(TokenType type, PublicKey const& pk)
{
return base58EncodeToken(type, pk.data(), pk.size());
return encodeBase58Token(type, pk.data(), pk.size());
}

template <>
Expand Down
2 changes: 1 addition & 1 deletion src/ripple/protocol/SecretKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ parseBase58(TokenType type, std::string const& s);
inline std::string
toBase58(TokenType type, SecretKey const& sk)
{
return base58EncodeToken(type, sk.data(), sk.size());
return encodeBase58Token(type, sk.data(), sk.size());
}

/** Create a secret key using secure random numbers. */
Expand Down
2 changes: 1 addition & 1 deletion src/ripple/protocol/Seed.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ seedAs1751(Seed const& seed);
inline std::string
toBase58(Seed const& seed)
{
return base58EncodeToken(TokenType::FamilySeed, seed.data(), seed.size());
return encodeBase58Token(TokenType::FamilySeed, seed.data(), seed.size());
}

} // namespace ripple
Expand Down
15 changes: 1 addition & 14 deletions src/ripple/protocol/impl/AccountID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace ripple {
std::string
toBase58(AccountID const& v)
{
return base58EncodeToken(TokenType::AccountID, v.data(), v.size());
return encodeBase58Token(TokenType::AccountID, v.data(), v.size());
}

template <>
Expand All @@ -45,19 +45,6 @@ parseBase58(std::string const& s)
return id;
}

boost::optional<AccountID>
deprecatedParseBitcoinAccountID(std::string const& s)
{
auto const result = decodeBase58TokenBitcoin(s, TokenType::AccountID);
if (result.empty())
return boost::none;
AccountID id;
if (result.size() != id.size())
return boost::none;
std::memcpy(id.data(), result.data(), result.size());
return id;
}

bool
deprecatedParseBase58(AccountID& account, Json::Value const& jv)
{
Expand Down
1 change: 0 additions & 1 deletion src/ripple/protocol/impl/ErrorCodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ namespace detail {
// This array will be omitted from the object file; only the sorted version
// will remain in the object file. But the string literals will remain.
constexpr static ErrorInfo unorderedErrorInfos[]{
{rpcACT_BITCOIN, "actBitcoin", "Account is bitcoin address."},
{rpcACT_MALFORMED, "actMalformed", "Account malformed."},
{rpcACT_NOT_FOUND, "actNotFound", "Account not found."},
{rpcALREADY_MULTISIG, "alreadyMultisig", "Already multisigned."},
Expand Down
179 changes: 53 additions & 126 deletions src/ripple/protocol/impl/tokens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,17 @@

namespace ripple {

static char rippleAlphabet[] =
static constexpr char const* alphabetForward =
"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz";

static char bitcoinAlphabet[] =
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";

//------------------------------------------------------------------------------
static constexpr std::array<int, 256> const alphabetReverse = []() {
std::array<int, 256> map{};
for (auto& m : map)
m = -1;
for (int i = 0, j = 0; alphabetForward[i] != 0; ++i)
map[static_cast<unsigned char>(alphabetForward[i])] = j++;
return map;
}();

template <class Hasher>
static typename Hasher::result_type
Expand Down Expand Up @@ -66,7 +70,7 @@ digest2(Args const&... args)
return digest<Hasher>(digest<Hasher>(args...));
}

/* Calculate a 4-byte checksum of the data
/** Calculate a 4-byte checksum of the data

The checksum is calculated as the first 4 bytes
of the SHA256 digest of the message. This is added
Expand All @@ -75,32 +79,28 @@ digest2(Args const&... args)

@note This checksum algorithm is part of the client API
*/
void
static void
checksum(void* out, void const* message, std::size_t size)
{
auto const h = digest2<sha256_hasher>(message, size);
std::memcpy(out, h.data(), 4);
}

//------------------------------------------------------------------------------
namespace detail {

// Code from Bitcoin: https://github.com/bitcoin/bitcoin
// Copyright (c) 2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// Modified from the original
//
// WARNING Do not call this directly, use
// encodeBase58Token instead since it
// calculates the size of buffer needed.
/* The base58 encoding & decoding routines in this namespace are taken from
* Bitcoin but have been modified from the original.
*
* Copyright (c) 2014 The Bitcoin Core developers
* Distributed under the MIT software license, see the accompanying
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
*/
static std::string
encodeBase58(
void const* message,
std::size_t size,
void* temp,
std::size_t temp_size,
char const* const alphabet)
std::size_t temp_size)
{
auto pbegin = reinterpret_cast<unsigned char const*>(message);
auto const pend = pbegin + size;
Expand Down Expand Up @@ -140,73 +140,20 @@ encodeBase58(
// Translate the result into a string.
std::string str;
str.reserve(zeroes + (b58end - iter));
str.assign(zeroes, alphabet[0]);
str.assign(zeroes, alphabetForward[0]);
while (iter != b58end)
str += alphabet[*(iter++)];
str += alphabetForward[*(iter++)];
return str;
}

static std::string
encodeToken(
TokenType type,
void const* token,
std::size_t size,
char const* const alphabet)
{
// expanded token includes type + 4 byte checksum
auto const expanded = 1 + size + 4;

// We need expanded + expanded * (log(256) / log(58)) which is
// bounded by expanded + expanded * (138 / 100 + 1) which works
// out to expanded * 3:
auto const bufsize = expanded * 3;

boost::container::small_vector<std::uint8_t, 1024> buf(bufsize);

// Lay the data out as
// <type><token><checksum>
buf[0] = safe_cast<std::underlying_type_t<TokenType>>(type);
if (size)
std::memcpy(buf.data() + 1, token, size);
checksum(buf.data() + 1 + size, buf.data(), 1 + size);

return encodeBase58(
buf.data(),
expanded,
buf.data() + expanded,
bufsize - expanded,
alphabet);
}

std::string
base58EncodeToken(TokenType type, void const* token, std::size_t size)
{
return encodeToken(type, token, size, rippleAlphabet);
}

std::string
base58EncodeTokenBitcoin(TokenType type, void const* token, std::size_t size)
{
return encodeToken(type, token, size, bitcoinAlphabet);
}

//------------------------------------------------------------------------------

// Code from Bitcoin: https://github.com/bitcoin/bitcoin
// Copyright (c) 2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// Modified from the original
template <class InverseArray>
static std::string
decodeBase58(std::string const& s, InverseArray const& inv)
decodeBase58(std::string const& s)
{
auto psz = s.c_str();
auto remain = s.size();
// Skip and count leading zeroes
int zeroes = 0;
while (remain > 0 && inv[*psz] == 0)
while (remain > 0 && alphabetReverse[*psz] == 0)
{
++zeroes;
++psz;
Expand All @@ -221,7 +168,7 @@ decodeBase58(std::string const& s, InverseArray const& inv)
std::vector<unsigned char> b256(remain * 733 / 1000 + 1);
while (remain > 0)
{
auto carry = inv[*psz];
auto carry = alphabetReverse[*psz];
if (carry == -1)
return {};
// Apply "b256 = b256 * 58 + carry".
Expand All @@ -246,16 +193,36 @@ decodeBase58(std::string const& s, InverseArray const& inv)
return result;
}

/* Base58 decode a Ripple token
} // namespace detail

The type and checksum are are checked
and removed from the returned result.
*/
template <class InverseArray>
static std::string
decodeBase58Token(std::string const& s, TokenType type, InverseArray const& inv)
std::string
encodeBase58Token(TokenType type, void const* token, std::size_t size)
{
std::string const ret = decodeBase58(s, inv);
// expanded token includes type + 4 byte checksum
auto const expanded = 1 + size + 4;

// We need expanded + expanded * (log(256) / log(58)) which is
// bounded by expanded + expanded * (138 / 100 + 1) which works
// out to expanded * 3:
auto const bufsize = expanded * 3;

boost::container::small_vector<std::uint8_t, 1024> buf(bufsize);

// Lay the data out as
// <type><token><checksum>
buf[0] = safe_cast<std::underlying_type_t<TokenType>>(type);
if (size)
std::memcpy(buf.data() + 1, token, size);
checksum(buf.data() + 1 + size, buf.data(), 1 + size);

return detail::encodeBase58(
buf.data(), expanded, buf.data() + expanded, bufsize - expanded);
}

std::string
decodeBase58Token(std::string const& s, TokenType type)
{
std::string const ret = detail::decodeBase58(s);

// Reject zero length tokens
if (ret.size() < 6)
Expand All @@ -275,44 +242,4 @@ decodeBase58Token(std::string const& s, TokenType type, InverseArray const& inv)
return ret.substr(1, ret.size() - 1 - guard.size());
}

//------------------------------------------------------------------------------

// Maps characters to their base58 digit
class InverseAlphabet
{
private:
std::array<int, 256> map_;

public:
explicit InverseAlphabet(std::string const& digits)
{
map_.fill(-1);
int i = 0;
for (auto const c : digits)
map_[static_cast<unsigned char>(c)] = i++;
}

int
operator[](char c) const
{
return map_[static_cast<unsigned char>(c)];
}
};

static InverseAlphabet rippleInverse(rippleAlphabet);

static InverseAlphabet bitcoinInverse(bitcoinAlphabet);

std::string
decodeBase58Token(std::string const& s, TokenType type)
{
return decodeBase58Token(s, type, rippleInverse);
}

std::string
decodeBase58TokenBitcoin(std::string const& s, TokenType type)
{
return decodeBase58Token(s, type, bitcoinInverse);
}

} // namespace ripple
Loading