mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Refactor AccountID (RIPD-953):
All AccountID functionality is removed from RippleAddress and
replaced with free functions. The AccountID to string conversion
cache is factored out as an explicit type with an instance in
the Application object. New base58 conversion functions are used,
with no dependence on OpenSSL.
All types and free functions related to AccountID are consolidated
into one header file. Routines to operate on "tokens" are also
introduced and consolidated into a single header file.
A token one of the cryptographic primitives used in Ripple:
Secret Seed
Server Public Key
Server Secret Key
Account ID
Account Public Key
Account Private Key
and these deprecated primitives:
Account Family Seed
Account Family Generator
This commit is contained in:
239
src/ripple/protocol/impl/AccountID.cpp
Normal file
239
src/ripple/protocol/impl/AccountID.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/protocol/AccountID.h>
|
||||
#include <ripple/protocol/AnyPublicKey.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/protocol/tokens.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::string
|
||||
toBase58 (AccountID const& v)
|
||||
{
|
||||
return base58EncodeToken(
|
||||
TOKEN_ACCOUNT_ID,
|
||||
v.data(), v.size());
|
||||
}
|
||||
|
||||
template<>
|
||||
boost::optional<AccountID>
|
||||
parseBase58 (std::string const& s)
|
||||
{
|
||||
auto const result =
|
||||
decodeBase58Token(
|
||||
s, TOKEN_ACCOUNT_ID);
|
||||
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;
|
||||
}
|
||||
|
||||
boost::optional<AccountID>
|
||||
deprecatedParseBitcoinAccountID (std::string const& s)
|
||||
{
|
||||
auto const result =
|
||||
decodeBase58TokenBitcoin(
|
||||
s, TOKEN_ACCOUNT_ID);
|
||||
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)
|
||||
{
|
||||
if (! jv.isString())
|
||||
return false;
|
||||
auto const result =
|
||||
parseBase58<AccountID>(jv.asString());
|
||||
if (! result)
|
||||
return false;
|
||||
account = *result;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
boost::optional<AccountID>
|
||||
parseHex (std::string const& s)
|
||||
{
|
||||
if (s.size() != 40)
|
||||
return boost::none;
|
||||
AccountID id;
|
||||
if (! id.SetHex(s, true))
|
||||
return boost::none;
|
||||
return id;
|
||||
}
|
||||
|
||||
template<>
|
||||
boost::optional<AccountID>
|
||||
parseHexOrBase58 (std::string const& s)
|
||||
{
|
||||
auto result =
|
||||
parseHex<AccountID>(s);
|
||||
if (! result)
|
||||
result = parseBase58<AccountID>(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
Calculation of the Account ID
|
||||
|
||||
The AccountID is a 160-bit identifier that uniquely
|
||||
distinguishes an account. The account may or may not
|
||||
exist in the ledger. Even for accounts that are not in
|
||||
the ledger, cryptographic operations may be performed
|
||||
which affect the ledger. For example, designating an
|
||||
account not in the ledger as a regular key for an
|
||||
account that is in the ledger.
|
||||
|
||||
Why did we use half of SHA512 for most things but then
|
||||
SHA256 followed by RIPEMD160 for account IDs? Why didn't
|
||||
we do SHA512 half then RIPEMD160? Or even SHA512 then RIPEMD160?
|
||||
For that matter why RIPEMD160 at all why not just SHA512 and keep
|
||||
only 160 bits?
|
||||
|
||||
Answer (David Schwartz):
|
||||
|
||||
The short answer is that we kept Bitcoin's behavior.
|
||||
The longer answer was that:
|
||||
1) Using a single hash could leave ripple
|
||||
vulnerable to length extension attacks.
|
||||
2) Only RIPEMD160 is generally considered safe at 160 bits.
|
||||
|
||||
Any of those schemes would have been acceptable. However,
|
||||
the one chosen avoids any need to defend the scheme chosen.
|
||||
(Against any criticism other than unnecessary complexity.)
|
||||
|
||||
"The historical reason was that in the very early days,
|
||||
we wanted to give people as few ways to argue that we were
|
||||
less secure than Bitcoin. So where there was no good reason
|
||||
to change something, it was not changed."
|
||||
*/
|
||||
|
||||
AccountID
|
||||
calcAccountID (AnyPublicKey const& pk)
|
||||
{
|
||||
ripesha_hasher rsh;
|
||||
rsh(pk.data(), pk.size());
|
||||
auto const d = static_cast<
|
||||
ripesha_hasher::result_type>(rsh);
|
||||
AccountID id;
|
||||
static_assert(sizeof(d) == sizeof(id), "");
|
||||
std::memcpy(id.data(), d.data(), d.size());
|
||||
return id;
|
||||
}
|
||||
|
||||
AccountID const&
|
||||
xrpAccount()
|
||||
{
|
||||
static AccountID const account(0);
|
||||
return account;
|
||||
}
|
||||
|
||||
AccountID const&
|
||||
noAccount()
|
||||
{
|
||||
static AccountID const account(1);
|
||||
return account;
|
||||
}
|
||||
|
||||
bool
|
||||
to_issuer (AccountID& issuer, std::string const& s)
|
||||
{
|
||||
if (s.size () == (160 / 4))
|
||||
{
|
||||
issuer.SetHex (s);
|
||||
return true;
|
||||
}
|
||||
auto const account =
|
||||
parseBase58<AccountID>(s);
|
||||
if (! account)
|
||||
return false;
|
||||
issuer = *account;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* VFALCO NOTE
|
||||
An alternate implementation could use a pair of insert-only
|
||||
hash maps that each use a single large memory allocation
|
||||
to store a fixed size hash table and all of the AccountID/string
|
||||
pairs laid out in memory (wouldn't use std::string here just a
|
||||
length prefixed or zero terminated array). Possibly using
|
||||
boost::intrusive as the basis for the unordered container.
|
||||
This would cut down to one allocate/free cycle per swap of
|
||||
the map.
|
||||
*/
|
||||
|
||||
AccountIDCache::AccountIDCache(
|
||||
std::size_t capacity)
|
||||
: capacity_(capacity)
|
||||
{
|
||||
m1_.reserve(capacity_);
|
||||
}
|
||||
|
||||
std::string
|
||||
AccountIDCache::toBase58(
|
||||
AccountID const& id) const
|
||||
{
|
||||
std::lock_guard<
|
||||
std::mutex> lock(mutex_);
|
||||
auto iter = m1_.find(id);
|
||||
if (iter != m1_.end())
|
||||
return iter->second;
|
||||
iter = m0_.find(id);
|
||||
std::string result;
|
||||
if (iter != m0_.end())
|
||||
{
|
||||
result = iter->second;
|
||||
// Can use insert-only hash maps if
|
||||
// we didn't erase from here.
|
||||
m0_.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
result =
|
||||
ripple::toBase58(id);
|
||||
}
|
||||
if (m1_.size() >= capacity_)
|
||||
{
|
||||
m0_ = std::move(m1_);
|
||||
m1_.clear();
|
||||
m1_.reserve(capacity_);
|
||||
}
|
||||
m1_.emplace(id, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
@@ -95,7 +95,7 @@ toString (AnyPublicKey const& pk)
|
||||
{
|
||||
Blob buffer;
|
||||
buffer.reserve (1 + pk.size ());
|
||||
buffer.push_back (VER_NODE_PUBLIC);
|
||||
buffer.push_back (TOKEN_NODE_PUBLIC);
|
||||
auto const data = pk.data ();
|
||||
buffer.insert (buffer.end (), data, data + pk.size ());
|
||||
return Base58::encodeWithCheck (buffer);
|
||||
|
||||
@@ -64,12 +64,6 @@ getAccountRootIndex (AccountID const& account)
|
||||
account);
|
||||
}
|
||||
|
||||
uint256
|
||||
getAccountRootIndex (const RippleAddress & account)
|
||||
{
|
||||
return getAccountRootIndex (account.getAccountID ());
|
||||
}
|
||||
|
||||
uint256
|
||||
getGeneratorIndex (AccountID const& uGeneratorID)
|
||||
{
|
||||
@@ -203,13 +197,6 @@ Keylet account_t::operator()(
|
||||
getAccountRootIndex(id) };
|
||||
}
|
||||
|
||||
Keylet account_t::operator()(
|
||||
RippleAddress const& ra) const
|
||||
{
|
||||
return { ltACCOUNT_ROOT,
|
||||
getAccountRootIndex(ra.getAccountID()) };
|
||||
}
|
||||
|
||||
Keylet child (uint256 const& key)
|
||||
{
|
||||
return { ltCHILD, key };
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
#include <ripple/crypto/GenerateDeterministicKey.h>
|
||||
#include <ripple/crypto/RandomNumbers.h>
|
||||
#include <ripple/crypto/RFC1751.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <ripple/protocol/RippleAddress.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <ripple/protocol/RipplePublicKey.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <ed25519-donna/ed25519.h>
|
||||
#include <openssl/ripemd.h>
|
||||
@@ -83,19 +85,19 @@ bool verifySignature (Blob const& pubkey, uint256 const& hash, Blob const& sig,
|
||||
RippleAddress::RippleAddress ()
|
||||
: mIsValid (false)
|
||||
{
|
||||
nVersion = VER_NONE;
|
||||
nVersion = TOKEN_NONE;
|
||||
}
|
||||
|
||||
void RippleAddress::clear ()
|
||||
{
|
||||
nVersion = VER_NONE;
|
||||
nVersion = TOKEN_NONE;
|
||||
vchData.clear ();
|
||||
mIsValid = false;
|
||||
}
|
||||
|
||||
bool RippleAddress::isSet () const
|
||||
{
|
||||
return nVersion != VER_NONE;
|
||||
return nVersion != TOKEN_NONE;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -145,7 +147,7 @@ RippleAddress RippleAddress::createNodePublic (std::string const& strPublic)
|
||||
RipplePublicKey
|
||||
RippleAddress::toPublicKey() const
|
||||
{
|
||||
assert (nVersion == VER_NODE_PUBLIC);
|
||||
assert (nVersion == TOKEN_NODE_PUBLIC);
|
||||
return RipplePublicKey (vchData.begin(), vchData.end());
|
||||
}
|
||||
|
||||
@@ -159,10 +161,10 @@ NodeID RippleAddress::getNodeID () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getNodeID");
|
||||
|
||||
case VER_NODE_PUBLIC: {
|
||||
case TOKEN_NODE_PUBLIC: {
|
||||
// Note, we are encoding the left.
|
||||
NodeID node;
|
||||
node.copyFrom(Hash160 (vchData));
|
||||
@@ -178,10 +180,10 @@ Blob const& RippleAddress::getNodePublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getNodePublic");
|
||||
|
||||
case VER_NODE_PUBLIC:
|
||||
case TOKEN_NODE_PUBLIC:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
@@ -193,10 +195,10 @@ std::string RippleAddress::humanNodePublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanNodePublic");
|
||||
|
||||
case VER_NODE_PUBLIC:
|
||||
case TOKEN_NODE_PUBLIC:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
@@ -207,7 +209,7 @@ std::string RippleAddress::humanNodePublic () const
|
||||
bool RippleAddress::setNodePublic (std::string const& strPublic)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPublic, VER_NODE_PUBLIC, Base58::getRippleAlphabet ());
|
||||
strPublic, TOKEN_NODE_PUBLIC, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
@@ -216,7 +218,7 @@ void RippleAddress::setNodePublic (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_NODE_PUBLIC, vPublic);
|
||||
SetData (TOKEN_NODE_PUBLIC, vPublic);
|
||||
}
|
||||
|
||||
bool RippleAddress::verifyNodePublic (
|
||||
@@ -250,10 +252,10 @@ Blob const& RippleAddress::getNodePrivateData () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getNodePrivateData");
|
||||
|
||||
case VER_NODE_PRIVATE:
|
||||
case TOKEN_NODE_PRIVATE:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
@@ -265,10 +267,10 @@ uint256 RippleAddress::getNodePrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source = getNodePrivate");
|
||||
|
||||
case VER_NODE_PRIVATE:
|
||||
case TOKEN_NODE_PRIVATE:
|
||||
return uint256 (vchData);
|
||||
|
||||
default:
|
||||
@@ -280,10 +282,10 @@ std::string RippleAddress::humanNodePrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanNodePrivate");
|
||||
|
||||
case VER_NODE_PRIVATE:
|
||||
case TOKEN_NODE_PRIVATE:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
@@ -294,7 +296,7 @@ std::string RippleAddress::humanNodePrivate () const
|
||||
bool RippleAddress::setNodePrivate (std::string const& strPrivate)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPrivate, VER_NODE_PRIVATE, Base58::getRippleAlphabet ());
|
||||
strPrivate, TOKEN_NODE_PRIVATE, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
@@ -303,14 +305,14 @@ void RippleAddress::setNodePrivate (Blob const& vPrivate)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_NODE_PRIVATE, vPrivate);
|
||||
SetData (TOKEN_NODE_PRIVATE, vPrivate);
|
||||
}
|
||||
|
||||
void RippleAddress::setNodePrivate (uint256 hash256)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_NODE_PRIVATE, hash256);
|
||||
SetData (TOKEN_NODE_PRIVATE, hash256);
|
||||
}
|
||||
|
||||
void RippleAddress::signNodePrivate (uint256 const& hash, Blob& vchSig) const
|
||||
@@ -321,131 +323,6 @@ void RippleAddress::signNodePrivate (uint256 const& hash, Blob& vchSig) const
|
||||
throw std::runtime_error ("Signing failed.");
|
||||
}
|
||||
|
||||
//
|
||||
// AccountID
|
||||
//
|
||||
|
||||
AccountID RippleAddress::getAccountID () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - getAccountID");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
return AccountID(vchData);
|
||||
|
||||
case VER_ACCOUNT_PUBLIC: {
|
||||
// Note, we are encoding the left.
|
||||
// TODO(tom): decipher this comment.
|
||||
AccountID account;
|
||||
account.copyFrom (Hash160 (vchData));
|
||||
return account;
|
||||
}
|
||||
|
||||
default:
|
||||
throw badSourceError (nVersion);
|
||||
}
|
||||
}
|
||||
|
||||
using StaticLockType = std::mutex;
|
||||
using StaticScopedLockType = std::lock_guard <StaticLockType>;
|
||||
|
||||
static StaticLockType s_lock;
|
||||
static hash_map <Blob, std::string> rncMapOld, rncMapNew;
|
||||
|
||||
void RippleAddress::clearCache ()
|
||||
{
|
||||
StaticScopedLockType sl (s_lock);
|
||||
|
||||
rncMapOld.clear ();
|
||||
rncMapNew.clear ();
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanAccountID () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
throw std::runtime_error ("unset source - humanAccountID");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
{
|
||||
StaticScopedLockType sl (s_lock);
|
||||
|
||||
auto it = rncMapNew.find (vchData);
|
||||
|
||||
if (it != rncMapNew.end ())
|
||||
{
|
||||
// Found in new map, nothing to do
|
||||
ret = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
it = rncMapOld.find (vchData);
|
||||
|
||||
if (it != rncMapOld.end ())
|
||||
{
|
||||
ret = it->second;
|
||||
rncMapOld.erase (it);
|
||||
}
|
||||
else
|
||||
ret = ToString ();
|
||||
|
||||
if (rncMapNew.size () >= 128000)
|
||||
{
|
||||
rncMapOld = std::move (rncMapNew);
|
||||
rncMapNew.clear ();
|
||||
rncMapNew.reserve (128000);
|
||||
}
|
||||
|
||||
rncMapNew[vchData] = ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
{
|
||||
RippleAddress accountID;
|
||||
|
||||
(void) accountID.setAccountID (getAccountID ());
|
||||
|
||||
return accountID.ToString ();
|
||||
}
|
||||
|
||||
default:
|
||||
throw badSourceError (nVersion);
|
||||
}
|
||||
}
|
||||
|
||||
bool RippleAddress::setAccountID (
|
||||
std::string const& strAccountID, Base58::Alphabet const& alphabet)
|
||||
{
|
||||
if (strAccountID.empty ())
|
||||
{
|
||||
setAccountID (AccountID ());
|
||||
|
||||
mIsValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mIsValid = SetString (strAccountID, VER_ACCOUNT_ID, alphabet);
|
||||
}
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountID (AccountID const& hash160)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (VER_ACCOUNT_ID, hash160);
|
||||
}
|
||||
|
||||
//
|
||||
// AccountPublic
|
||||
//
|
||||
@@ -464,14 +341,14 @@ Blob const& RippleAddress::getAccountPublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getAccountPublic");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
case TOKEN_ACCOUNT_ID:
|
||||
throw std::runtime_error ("public not available from account id");
|
||||
break;
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
case TOKEN_ACCOUNT_PUBLIC:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
@@ -483,13 +360,13 @@ std::string RippleAddress::humanAccountPublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanAccountPublic");
|
||||
|
||||
case VER_ACCOUNT_ID:
|
||||
case TOKEN_ACCOUNT_ID:
|
||||
throw std::runtime_error ("public not available from account id");
|
||||
|
||||
case VER_ACCOUNT_PUBLIC:
|
||||
case TOKEN_ACCOUNT_PUBLIC:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
@@ -500,7 +377,7 @@ std::string RippleAddress::humanAccountPublic () const
|
||||
bool RippleAddress::setAccountPublic (std::string const& strPublic)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPublic, VER_ACCOUNT_PUBLIC, Base58::getRippleAlphabet ());
|
||||
strPublic, TOKEN_ACCOUNT_PUBLIC, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
@@ -509,7 +386,7 @@ void RippleAddress::setAccountPublic (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_ACCOUNT_PUBLIC, vPublic);
|
||||
SetData (TOKEN_ACCOUNT_PUBLIC, vPublic);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPublic (RippleAddress const& generator, int seq)
|
||||
@@ -541,14 +418,6 @@ bool RippleAddress::accountPublicVerify (
|
||||
fullyCanonical);
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createAccountID (AccountID const& account)
|
||||
{
|
||||
RippleAddress na;
|
||||
na.setAccountID (account);
|
||||
|
||||
return na;
|
||||
}
|
||||
|
||||
//
|
||||
// AccountPrivate
|
||||
//
|
||||
@@ -567,10 +436,10 @@ uint256 RippleAddress::getAccountPrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getAccountPrivate");
|
||||
|
||||
case VER_ACCOUNT_PRIVATE:
|
||||
case TOKEN_ACCOUNT_SECRET:
|
||||
return uint256::fromVoid (vchData.data() + (vchData.size() - 32));
|
||||
|
||||
default:
|
||||
@@ -581,7 +450,7 @@ uint256 RippleAddress::getAccountPrivate () const
|
||||
bool RippleAddress::setAccountPrivate (std::string const& strPrivate)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPrivate, VER_ACCOUNT_PRIVATE, Base58::getRippleAlphabet ());
|
||||
strPrivate, TOKEN_ACCOUNT_SECRET, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
@@ -589,13 +458,13 @@ bool RippleAddress::setAccountPrivate (std::string const& strPrivate)
|
||||
void RippleAddress::setAccountPrivate (Blob const& vPrivate)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (VER_ACCOUNT_PRIVATE, vPrivate);
|
||||
SetData (TOKEN_ACCOUNT_SECRET, vPrivate);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPrivate (uint256 hash256)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (VER_ACCOUNT_PRIVATE, hash256);
|
||||
SetData (TOKEN_ACCOUNT_SECRET, hash256);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPrivate (
|
||||
@@ -689,10 +558,10 @@ Blob const& RippleAddress::getGenerator () const
|
||||
// returns the public generator
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getGenerator");
|
||||
|
||||
case VER_FAMILY_GENERATOR:
|
||||
case TOKEN_FAMILY_GENERATOR:
|
||||
// Do nothing.
|
||||
return vchData;
|
||||
|
||||
@@ -705,10 +574,10 @@ std::string RippleAddress::humanGenerator () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanGenerator");
|
||||
|
||||
case VER_FAMILY_GENERATOR:
|
||||
case TOKEN_FAMILY_GENERATOR:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
@@ -719,7 +588,7 @@ std::string RippleAddress::humanGenerator () const
|
||||
void RippleAddress::setGenerator (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (VER_FAMILY_GENERATOR, vPublic);
|
||||
SetData (TOKEN_FAMILY_GENERATOR, vPublic);
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createGeneratorPublic (RippleAddress const& naSeed)
|
||||
@@ -737,10 +606,10 @@ uint128 RippleAddress::getSeed () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - getSeed");
|
||||
|
||||
case VER_FAMILY_SEED:
|
||||
case TOKEN_FAMILY_SEED:
|
||||
return uint128 (vchData);
|
||||
|
||||
default:
|
||||
@@ -752,10 +621,10 @@ std::string RippleAddress::humanSeed1751 () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanSeed1751");
|
||||
|
||||
case VER_FAMILY_SEED:
|
||||
case TOKEN_FAMILY_SEED:
|
||||
{
|
||||
std::string strHuman;
|
||||
std::string strLittle;
|
||||
@@ -780,10 +649,10 @@ std::string RippleAddress::humanSeed () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case VER_NONE:
|
||||
case TOKEN_NONE:
|
||||
throw std::runtime_error ("unset source - humanSeed");
|
||||
|
||||
case VER_FAMILY_SEED:
|
||||
case TOKEN_FAMILY_SEED:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
@@ -809,7 +678,7 @@ int RippleAddress::setSeed1751 (std::string const& strHuman1751)
|
||||
|
||||
bool RippleAddress::setSeed (std::string const& strSeed)
|
||||
{
|
||||
mIsValid = SetString (strSeed, VER_FAMILY_SEED, Base58::getRippleAlphabet ());
|
||||
mIsValid = SetString (strSeed, TOKEN_FAMILY_SEED, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
@@ -820,8 +689,10 @@ bool RippleAddress::setSeedGeneric (std::string const& strText)
|
||||
bool bResult = true;
|
||||
uint128 uSeed;
|
||||
|
||||
if (parseBase58<AccountID>(strText))
|
||||
return false;
|
||||
|
||||
if (strText.empty ()
|
||||
|| naTemp.setAccountID (strText)
|
||||
|| naTemp.setAccountPublic (strText)
|
||||
|| naTemp.setAccountPrivate (strText)
|
||||
|| naTemp.setNodePublic (strText)
|
||||
@@ -853,7 +724,7 @@ void RippleAddress::setSeed (uint128 hash128)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (VER_FAMILY_SEED, hash128);
|
||||
SetData (TOKEN_FAMILY_SEED, hash128);
|
||||
}
|
||||
|
||||
void RippleAddress::setSeedRandom ()
|
||||
@@ -978,4 +849,20 @@ KeyPair generateKeysFromSeed (KeyType type, RippleAddress const& seed)
|
||||
return result;
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
AccountID
|
||||
calcAccountID (RippleAddress const& publicKey)
|
||||
{
|
||||
auto const& pk =
|
||||
publicKey.getAccountPublic();
|
||||
ripesha_hasher rsh;
|
||||
rsh(pk.data(), pk.size());
|
||||
auto const d = static_cast<
|
||||
ripesha_hasher::result_type>(rsh);
|
||||
AccountID id;
|
||||
static_assert(sizeof(d) == sizeof(id), "");
|
||||
std::memcpy(id.data(), d.data(), d.size());
|
||||
return id;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -31,12 +32,11 @@ std::string STAccount::getText () const
|
||||
{
|
||||
AccountID u;
|
||||
RippleAddress a;
|
||||
|
||||
if (!getValueH160 (u))
|
||||
if (! getValueH160 (u))
|
||||
return STBlob::getText ();
|
||||
|
||||
a.setAccountID (u);
|
||||
return a.humanAccountID ();
|
||||
// VFALCO This should use getApp().accountIDCache()
|
||||
// Maybe pass the cache in?
|
||||
return toBase58(u);
|
||||
}
|
||||
|
||||
STAccount*
|
||||
@@ -55,20 +55,4 @@ bool STAccount::isValueH160 () const
|
||||
return peekValue ().size () == (160 / 8);
|
||||
}
|
||||
|
||||
RippleAddress STAccount::getValueNCA () const
|
||||
{
|
||||
RippleAddress a;
|
||||
AccountID account;
|
||||
|
||||
if (getValueH160 (account))
|
||||
a.setAccountID (account);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void STAccount::setValueNCA (RippleAddress const& nca)
|
||||
{
|
||||
setValueH160 (nca.getAccountID ());
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -123,31 +123,6 @@ bool STLedgerEntry::isThreaded () const
|
||||
return isFieldPresent (sfPreviousTxnID);
|
||||
}
|
||||
|
||||
bool STLedgerEntry::hasOneOwner () const
|
||||
{
|
||||
return (type_ != ltACCOUNT_ROOT) && (getFieldIndex (sfAccount) != -1);
|
||||
}
|
||||
|
||||
bool STLedgerEntry::hasTwoOwners () const
|
||||
{
|
||||
return type_ == ltRIPPLE_STATE;
|
||||
}
|
||||
|
||||
RippleAddress STLedgerEntry::getOwner () const
|
||||
{
|
||||
return getFieldAccount (sfAccount);
|
||||
}
|
||||
|
||||
RippleAddress STLedgerEntry::getFirstOwner () const
|
||||
{
|
||||
return RippleAddress::createAccountID (getFieldAmount (sfLowLimit).getIssuer ());
|
||||
}
|
||||
|
||||
RippleAddress STLedgerEntry::getSecondOwner () const
|
||||
{
|
||||
return RippleAddress::createAccountID (getFieldAmount (sfHighLimit).getIssuer ());
|
||||
}
|
||||
|
||||
uint256 STLedgerEntry::getThreadedTransaction () const
|
||||
{
|
||||
return getFieldH256 (sfPreviousTxnID);
|
||||
|
||||
@@ -347,19 +347,21 @@ STObject::startMultiSigningData () const
|
||||
return s;
|
||||
}
|
||||
|
||||
// VFALCO This should not be a member,
|
||||
// and the function shouldn't even exist
|
||||
void
|
||||
STObject::finishMultiSigningData (
|
||||
RippleAddress const& signingForID,
|
||||
RippleAddress const& signingID,
|
||||
AccountID const& signingForID,
|
||||
AccountID const& signingID,
|
||||
Serializer& s) const
|
||||
{
|
||||
s.add160 (signingForID.getAccountID ());
|
||||
s.add160 (signingID.getAccountID ());
|
||||
s.add160 (signingForID);
|
||||
s.add160 (signingID);
|
||||
}
|
||||
|
||||
Serializer
|
||||
STObject::getMultiSigningData (
|
||||
RippleAddress const& signingForID, RippleAddress const& signingID) const
|
||||
AccountID const& signingForID, AccountID const& signingID) const
|
||||
{
|
||||
Serializer s (startMultiSigningData ());
|
||||
finishMultiSigningData (signingForID, signingID, s);
|
||||
@@ -586,26 +588,7 @@ uint256 STObject::getFieldH256 (SField const& field) const
|
||||
return getFieldByValue <STHash256> (field);
|
||||
}
|
||||
|
||||
RippleAddress STObject::getFieldAccount (SField const& field) const
|
||||
{
|
||||
const STBase* rf = peekAtPField (field);
|
||||
|
||||
if (!rf)
|
||||
throw std::runtime_error ("Field not found");
|
||||
|
||||
SerializedTypeID id = rf->getSType ();
|
||||
|
||||
if (id == STI_NOTPRESENT) return RippleAddress ();
|
||||
|
||||
const STAccount* cf = dynamic_cast<const STAccount*> (rf);
|
||||
|
||||
if (!cf)
|
||||
throw std::runtime_error ("Wrong field type");
|
||||
|
||||
return cf->getValueNCA ();
|
||||
}
|
||||
|
||||
AccountID STObject::getFieldAccount160 (SField const& field) const
|
||||
AccountID STObject::getAccountID (SField const& field) const
|
||||
{
|
||||
auto rf = peekAtPField (field);
|
||||
if (!rf)
|
||||
@@ -715,7 +698,7 @@ void STObject::setFieldV256 (SField const& field, STVector256 const& v)
|
||||
setFieldUsingSetValue <STVector256> (field, v);
|
||||
}
|
||||
|
||||
void STObject::setFieldAccount (SField const& field, AccountID const& v)
|
||||
void STObject::setAccountID (SField const& field, AccountID const& v)
|
||||
{
|
||||
STBase* rf = getPField (field, true);
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <ripple/protocol/STParsedJSON.h>
|
||||
#include <ripple/protocol/STPathSet.h>
|
||||
#include <ripple/protocol/TxFormats.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <ripple/protocol/impl/STVar.h>
|
||||
#include <beast/module/core/text/LexicalCast.h>
|
||||
#include <cassert>
|
||||
@@ -544,13 +545,14 @@ static boost::optional<detail::STVar> parseLeaf (
|
||||
// set it, otherwise, we assume it's an AccountID
|
||||
if (!uAccount.SetHexExact (account.asString ()))
|
||||
{
|
||||
RippleAddress a;
|
||||
if (!a.setAccountID (account.asString ()))
|
||||
auto const a = parseBase58<AccountID>(
|
||||
account.asString());
|
||||
if (! a)
|
||||
{
|
||||
error = invalid_data (element_name, "account");
|
||||
return ret;
|
||||
}
|
||||
uAccount = a.getAccountID ();
|
||||
uAccount = *a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,13 +588,14 @@ static boost::optional<detail::STVar> parseLeaf (
|
||||
|
||||
if (!uIssuer.SetHexExact (issuer.asString ()))
|
||||
{
|
||||
RippleAddress a;
|
||||
if (!a.setAccountID (issuer.asString ()))
|
||||
auto const a = parseBase58<AccountID>(
|
||||
issuer.asString());
|
||||
if (! a)
|
||||
{
|
||||
error = invalid_data (element_name, "issuer");
|
||||
return ret;
|
||||
}
|
||||
uIssuer = a.getAccountID ();
|
||||
uIssuer = *a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,18 +626,17 @@ static boost::optional<detail::STVar> parseLeaf (
|
||||
|
||||
try
|
||||
{
|
||||
AccountID account;
|
||||
if (!account.SetHexExact (strValue))
|
||||
// VFALCO This needs careful auditing
|
||||
auto const account =
|
||||
parseHexOrBase58<AccountID>(
|
||||
strValue);
|
||||
if (! account)
|
||||
{
|
||||
RippleAddress a;
|
||||
if (!a.setAccountID (strValue))
|
||||
{
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
account.copyFrom (a.getAccountID ());
|
||||
error = invalid_data (json_name, fieldName);
|
||||
return ret;
|
||||
}
|
||||
ret = detail::make_stvar <STAccount> (field, account);
|
||||
ret = detail::make_stvar <STAccount>(
|
||||
field, *account);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
#include <ripple/protocol/STArray.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
@@ -120,36 +121,29 @@ STTx::getFullText () const
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<RippleAddress>
|
||||
boost::container::flat_set<AccountID>
|
||||
STTx::getMentionedAccounts () const
|
||||
{
|
||||
std::vector<RippleAddress> accounts;
|
||||
boost::container::flat_set<AccountID> list;
|
||||
|
||||
for (auto const& it : *this)
|
||||
{
|
||||
if (auto sa = dynamic_cast<STAccount const*> (&it))
|
||||
{
|
||||
auto const na = sa->getValueNCA ();
|
||||
|
||||
if (std::find (accounts.cbegin (), accounts.cend (), na) == accounts.cend ())
|
||||
accounts.push_back (na);
|
||||
AccountID id;
|
||||
assert(sa->isValueH160());
|
||||
if (sa->getValueH160(id))
|
||||
list.insert(id);
|
||||
}
|
||||
else if (auto sa = dynamic_cast<STAmount const*> (&it))
|
||||
{
|
||||
auto const& issuer = sa->getIssuer ();
|
||||
|
||||
if (isXRP (issuer))
|
||||
continue;
|
||||
|
||||
RippleAddress na;
|
||||
na.setAccountID (issuer);
|
||||
|
||||
if (std::find (accounts.cbegin (), accounts.cend (), na) == accounts.cend ())
|
||||
accounts.push_back (na);
|
||||
if (! isXRP (issuer))
|
||||
list.insert(issuer);
|
||||
}
|
||||
}
|
||||
|
||||
return accounts;
|
||||
return list;
|
||||
}
|
||||
|
||||
static Blob getSigningData (STTx const& that)
|
||||
@@ -226,11 +220,6 @@ void STTx::setSigningPubKey (RippleAddress const& naSignPubKey)
|
||||
setFieldVL (sfSigningPubKey, naSignPubKey.getAccountPublic ());
|
||||
}
|
||||
|
||||
void STTx::setSourceAccount (RippleAddress const& naSource)
|
||||
{
|
||||
setFieldAccount (sfAccount, naSource);
|
||||
}
|
||||
|
||||
Json::Value STTx::getJson (int) const
|
||||
{
|
||||
Json::Value ret = STObject::getJson (0);
|
||||
@@ -269,6 +258,7 @@ std::string STTx::getMetaSQL (std::uint32_t inLedger,
|
||||
return getMetaSQL (s, inLedger, TXN_SQL_VALIDATED, escapedMetaData);
|
||||
}
|
||||
|
||||
// VFALCO This could be a free function elsewhere
|
||||
std::string
|
||||
STTx::getMetaSQL (Serializer rawTxn,
|
||||
std::uint32_t inLedger, char status, std::string const& escapedMetaData) const
|
||||
@@ -281,7 +271,7 @@ STTx::getMetaSQL (Serializer rawTxn,
|
||||
|
||||
return str (boost::format (bfTrans)
|
||||
% to_string (getTransactionID ()) % format->getName ()
|
||||
% getSourceAccount ().humanAccountID ()
|
||||
% toBase58(getAccountID(sfAccount))
|
||||
% getSequence () % inLedger % status % rTxn % escapedMetaData);
|
||||
}
|
||||
|
||||
@@ -338,7 +328,7 @@ STTx::checkMultiSign () const
|
||||
Serializer const dataStart (startMultiSigningData ());
|
||||
|
||||
// We also use the sfAccount field inside the loop. Get it once.
|
||||
RippleAddress const txnAccountID = getFieldAccount (sfAccount);
|
||||
auto const txnAccountID = getAccountID (sfAccount);
|
||||
|
||||
// Determine whether signatures must be full canonical.
|
||||
ECDSA const fullyCanonical = (getFlags() & tfFullyCanonicalSig)
|
||||
@@ -398,17 +388,16 @@ STTx::checkMultiSign () const
|
||||
*/
|
||||
|
||||
// We use this std::set to detect this form of double-signing.
|
||||
std::set<RippleAddress> firstLevelSigners;
|
||||
std::set<AccountID> firstLevelSigners;
|
||||
|
||||
// SigningFors must be in sorted order by AccountID.
|
||||
RippleAddress lastSigningForID;
|
||||
lastSigningForID.setAccountID ("");
|
||||
AccountID lastSigningForID = zero;
|
||||
|
||||
// Every signature must verify or we reject the transaction.
|
||||
for (auto const& signingFor : multiSigners)
|
||||
{
|
||||
RippleAddress const signingForID =
|
||||
signingFor.getFieldAccount (sfAccount);
|
||||
auto const signingForID =
|
||||
signingFor.getAccountID (sfAccount);
|
||||
|
||||
// SigningFors must be in order by account ID. No duplicates allowed.
|
||||
if (lastSigningForID >= signingForID)
|
||||
@@ -440,13 +429,12 @@ STTx::checkMultiSign () const
|
||||
}
|
||||
|
||||
// SingingAccounts must be in sorted order by AccountID.
|
||||
RippleAddress lastSigningAcctID;
|
||||
lastSigningAcctID.setAccountID ("");
|
||||
AccountID lastSigningAcctID = zero;
|
||||
|
||||
for (auto const& signingAcct : signingAccounts)
|
||||
{
|
||||
RippleAddress const signingAcctID =
|
||||
signingAcct.getFieldAccount (sfAccount);
|
||||
auto const signingAcctID =
|
||||
signingAcct.getAccountID (sfAccount);
|
||||
|
||||
// None of the multi-signers may sign for themselves.
|
||||
if (signingForID == signingAcctID)
|
||||
|
||||
@@ -22,15 +22,11 @@
|
||||
#include <ripple/protocol/SystemParameters.h>
|
||||
#include <ripple/protocol/RippleAddress.h>
|
||||
#include <ripple/protocol/UintTypes.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <beast/utility/static_initializer.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::string to_string(AccountID const& account)
|
||||
{
|
||||
return RippleAddress::createAccountID (account).humanAccountID ();
|
||||
}
|
||||
|
||||
std::string to_string(Currency const& currency)
|
||||
{
|
||||
// Characters we are willing to allow in the ASCII representation of a
|
||||
@@ -111,38 +107,12 @@ Currency to_currency(std::string const& code)
|
||||
return currency;
|
||||
}
|
||||
|
||||
bool to_issuer(AccountID& issuer, std::string const& s)
|
||||
{
|
||||
if (s.size () == (160 / 4))
|
||||
{
|
||||
issuer.SetHex (s);
|
||||
return true;
|
||||
}
|
||||
RippleAddress address;
|
||||
bool success = address.setAccountID (s);
|
||||
if (success)
|
||||
issuer = address.getAccountID ();
|
||||
return success;
|
||||
}
|
||||
|
||||
AccountID const& xrpAccount()
|
||||
{
|
||||
static AccountID const account(0);
|
||||
return account;
|
||||
}
|
||||
|
||||
Currency const& xrpCurrency()
|
||||
{
|
||||
static Currency const currency(0);
|
||||
return currency;
|
||||
}
|
||||
|
||||
AccountID const& noAccount()
|
||||
{
|
||||
static AccountID const account(1);
|
||||
return account;
|
||||
}
|
||||
|
||||
Currency const& noCurrency()
|
||||
{
|
||||
static Currency const currency(1);
|
||||
|
||||
@@ -25,12 +25,11 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
static_assert(sizeof(decltype(
|
||||
openssl_ripemd160_hasher::ctx_)) ==
|
||||
sizeof(RIPEMD160_CTX), "");
|
||||
|
||||
openssl_ripemd160_hasher::openssl_ripemd160_hasher()
|
||||
{
|
||||
static_assert(sizeof(decltype(
|
||||
openssl_ripemd160_hasher::ctx_)) ==
|
||||
sizeof(RIPEMD160_CTX), "");
|
||||
auto const ctx = reinterpret_cast<
|
||||
RIPEMD160_CTX*>(ctx_);
|
||||
RIPEMD160_Init(ctx);
|
||||
@@ -54,12 +53,11 @@ openssl_ripemd160_hasher::operator result_type() noexcept
|
||||
return digest;
|
||||
}
|
||||
|
||||
static_assert(sizeof(decltype(
|
||||
openssl_sha256_hasher::ctx_)) ==
|
||||
sizeof(SHA256_CTX), "");
|
||||
|
||||
openssl_sha256_hasher::openssl_sha256_hasher()
|
||||
{
|
||||
static_assert(sizeof(decltype(
|
||||
openssl_sha256_hasher::ctx_)) ==
|
||||
sizeof(SHA256_CTX), "");
|
||||
auto const ctx = reinterpret_cast<
|
||||
SHA256_CTX*>(ctx_);
|
||||
SHA256_Init(ctx);
|
||||
|
||||
331
src/ripple/protocol/impl/tokens.cpp
Normal file
331
src/ripple/protocol/impl/tokens.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/protocol/tokens.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <beast/cxx14/type_traits.h> // <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
static char rippleAlphabet[] =
|
||||
"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz";
|
||||
|
||||
static char bitcoinAlphabet[] =
|
||||
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Hasher>
|
||||
static
|
||||
typename Hasher::result_type
|
||||
digest (void const* data, std::size_t size) noexcept
|
||||
{
|
||||
Hasher h;
|
||||
h(data, size);
|
||||
return static_cast<
|
||||
typename Hasher::result_type>(h);
|
||||
}
|
||||
|
||||
template <class Hasher, class T, std::size_t N,
|
||||
class = std::enable_if_t<sizeof(T) == 1>>
|
||||
static
|
||||
typename Hasher::result_type
|
||||
digest (std::array<T, N> const& v)
|
||||
{
|
||||
return digest<Hasher>(v.data(), v.size());
|
||||
}
|
||||
|
||||
// Computes a double digest (e.g. digest of the digest)
|
||||
template <class Hasher, class... Args>
|
||||
static
|
||||
typename Hasher::result_type
|
||||
digest2 (Args const&... args)
|
||||
{
|
||||
return digest<Hasher>(
|
||||
digest<Hasher>(args...));
|
||||
}
|
||||
|
||||
/* 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
|
||||
to the base58 encoding of identifiers to detect
|
||||
user error in data entry.
|
||||
|
||||
@note This checksum algorithm is part of the client API
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// 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.
|
||||
static
|
||||
std::string
|
||||
encodeBase58(
|
||||
void const* message, std::size_t size,
|
||||
void *temp, char const* const alphabet)
|
||||
{
|
||||
auto pbegin = reinterpret_cast<
|
||||
unsigned char const*>(message);
|
||||
auto const pend = pbegin + size;
|
||||
// Skip & count leading zeroes.
|
||||
int zeroes = 0;
|
||||
while (pbegin != pend && *pbegin == 0)
|
||||
{
|
||||
pbegin++;
|
||||
zeroes++;
|
||||
}
|
||||
auto const b58begin = reinterpret_cast<
|
||||
unsigned char*>(temp);
|
||||
// log(256) / log(58), rounded up.
|
||||
auto const b58end = b58begin +
|
||||
size * (138 / 100 + 1);
|
||||
std::fill(b58begin, b58end, 0);
|
||||
while (pbegin != pend)
|
||||
{
|
||||
int carry = *pbegin;
|
||||
// Apply "b58 = b58 * 256 + ch".
|
||||
for (auto iter = b58end; iter != b58begin; --iter)
|
||||
{
|
||||
carry += 256 * (iter[-1]);
|
||||
iter[-1] = carry % 58;
|
||||
carry /= 58;
|
||||
}
|
||||
assert(carry == 0);
|
||||
pbegin++;
|
||||
}
|
||||
// Skip leading zeroes in base58 result.
|
||||
auto iter = b58begin;
|
||||
while (iter != b58end && *iter == 0)
|
||||
++iter;
|
||||
// Translate the result into a string.
|
||||
std::string str;
|
||||
str.reserve(zeroes + (b58end - iter));
|
||||
str.assign(zeroes, alphabet[0]);
|
||||
while (iter != b58end)
|
||||
str += alphabet[*(iter++)];
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Base-58 encode a Ripple Token
|
||||
|
||||
Ripple Tokens have a one-byte prefx indicating
|
||||
the type of token, followed by the data for the
|
||||
token, and finally a 4-byte checksum.
|
||||
|
||||
Tokens include the following:
|
||||
|
||||
Wallet Seed
|
||||
Account Public Key
|
||||
Account ID
|
||||
|
||||
@param temp A pointer to storage of not
|
||||
less than 2*(size+6) bytes
|
||||
*/
|
||||
std::string
|
||||
base58EncodeToken (std::uint8_t type,
|
||||
void const* token, std::size_t size)
|
||||
{
|
||||
char buf[1024];
|
||||
// expanded token includes type + checksum
|
||||
auto const expanded = 1 + size + 4;
|
||||
// add scratch, log(256) / log(58), rounded up.
|
||||
auto const needed = expanded +
|
||||
size * (138 / 100 + 1);
|
||||
std::unique_ptr<
|
||||
char[]> pbuf;
|
||||
char* temp;
|
||||
if (needed > sizeof(buf))
|
||||
{
|
||||
pbuf.reset(new char[needed]);
|
||||
temp = pbuf.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = buf;
|
||||
}
|
||||
// Lay the data out as
|
||||
// <type><token><checksum>
|
||||
temp[0] = type;
|
||||
std::memcpy(temp + 1, token, size);
|
||||
checksum(temp + 1 + size, temp, 1 + size);
|
||||
return encodeBase58(temp, expanded,
|
||||
temp + expanded, rippleAlphabet);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// 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)
|
||||
{
|
||||
auto psz = s.c_str();
|
||||
auto remain = s.size();
|
||||
// Skip and count leading zeroes
|
||||
int zeroes = 0;
|
||||
while (remain > 0 && inv[*psz] == 0)
|
||||
{
|
||||
++zeroes;
|
||||
++psz;
|
||||
--remain;
|
||||
}
|
||||
// Allocate enough space in big-endian base256 representation.
|
||||
// log(58) / log(256), rounded up.
|
||||
std::vector<unsigned char> b256(
|
||||
remain * 733 / 1000 + 1);
|
||||
while (remain > 0)
|
||||
{
|
||||
auto carry = inv[*psz];
|
||||
if (carry == -1)
|
||||
return {};
|
||||
// Apply "b256 = b256 * 58 + carry".
|
||||
for (auto iter = b256.rbegin();
|
||||
iter != b256.rend(); ++iter)
|
||||
{
|
||||
carry += 58 * *iter;
|
||||
*iter = carry % 256;
|
||||
carry /= 256;
|
||||
}
|
||||
assert(carry == 0);
|
||||
++psz;
|
||||
--remain;
|
||||
}
|
||||
// Skip leading zeroes in b256.
|
||||
auto iter = std::find_if(
|
||||
b256.begin(), b256.end(),[](unsigned char c)
|
||||
{ return c != 0; });
|
||||
std::string result;
|
||||
result.reserve (zeroes + (b256.end() - iter));
|
||||
result.assign (zeroes, 0x00);
|
||||
while (iter != b256.end())
|
||||
result.push_back(*(iter++));
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Base58 decode a Ripple token
|
||||
|
||||
The type and checksum are are checked
|
||||
and removed from the returned result.
|
||||
*/
|
||||
template <class InverseArray>
|
||||
static
|
||||
std::string
|
||||
decodeBase58Token (std::string const& s,
|
||||
int type, InverseArray const& inv)
|
||||
{
|
||||
auto result = decodeBase58(s, inv);
|
||||
if (result.empty())
|
||||
return result;
|
||||
// Reject zero length tokens
|
||||
if (result.size() < 6)
|
||||
return {};
|
||||
if (result[0] != type)
|
||||
return {};
|
||||
std::array<char, 4> guard;
|
||||
checksum(guard.data(),
|
||||
result.data(), result.size() - 4);
|
||||
if (std::memcmp(guard.data(),
|
||||
result.data() +
|
||||
result.size() - 4, 4) != 0)
|
||||
return {};
|
||||
result.resize(result.size() - 4);
|
||||
// Erase the type byte
|
||||
// VFALCO This might cause problems later
|
||||
result.erase(result.begin());
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// 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, int type)
|
||||
{
|
||||
return decodeBase58Token(
|
||||
s, type, rippleInverse);
|
||||
}
|
||||
|
||||
std::string
|
||||
decodeBase58TokenBitcoin(
|
||||
std::string const& s, int type)
|
||||
{
|
||||
return decodeBase58Token(
|
||||
s, type, bitcoinInverse);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
Reference in New Issue
Block a user