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:
Vinnie Falco
2015-06-18 11:05:18 -07:00
parent 63d438c979
commit 2f485672fa
109 changed files with 1901 additions and 1545 deletions

View File

@@ -0,0 +1,194 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2014 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.
*/
//==============================================================================
#ifndef RIPPLE_PROTOCOL_ACCOUNTID_H_INCLUDED
#define RIPPLE_PROTOCOL_ACCOUNTID_H_INCLUDED
#include <ripple/protocol/tokens.h>
// VFALCO Uncomment when the header issues are resolved
//#include <ripple/protocol/AnyPublicKey.h>
#include <ripple/basics/base_uint.h>
#include <ripple/basics/UnorderedContainers.h>
#include <ripple/json/json_value.h>
#include <boost/optional.hpp>
#include <cstddef>
#include <mutex>
#include <string>
namespace ripple {
// VFALCO Forward declared due to header issues
class AnyPublicKey;
namespace detail {
class AccountIDTag { };
} // detail
/** A 160-bit unsigned that uniquely identifies an account. */
using AccountID = base_uint<
160, detail::AccountIDTag>;
/** Convert AccountID to base58 checked string */
std::string
toBase58 (AccountID const& v);
/** Parse AccountID from checked, base58 string.
@return boost::none if a parse error occurs
*/
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);
/** Parse AccountID from hexadecimal string
If the string is not exactly 40
hex digits, boost::none is returned.
@return boost::none if a parse error occurs
*/
template<>
boost::optional<AccountID>
parseHex (std::string const& s);
/** Parse AccountID from hex or checked base58 string.
@return boost::none if a parse error occurs
*/
template<>
boost::optional<AccountID>
parseHexOrBase58 (std::string const& s);
// VFALCO NOTE These help transition away from RippleAddress
/** Compute AccountID from public key.
The account ID is computed as the 160-bit hash of the
public key data. This excludes the version byte and
guard bytes included in the base58 representation.
*/
AccountID
calcAccountID (AnyPublicKey const& pk);
/** A special account that's used as the "issuer" for XRP. */
AccountID const&
xrpAccount();
/** A placeholder for empty accounts. */
AccountID const&
noAccount();
/** Convert hex or base58 string to AccountID.
@return `true` if the parsing was successful.
*/
// DEPRECATED
bool
to_issuer (AccountID&, std::string const&);
// DEPRECATED Should be checking the currency or native flag
inline
bool
isXRP(AccountID const& c)
{
return c == zero;
}
// DEPRECATED
inline
std::string
to_string (AccountID const& account)
{
return toBase58(account);
}
// DEPRECATED
inline std::ostream& operator<< (std::ostream& os, AccountID const& x)
{
os << to_string (x);
return os;
}
//------------------------------------------------------------------------------
/** Caches the base58 representations of AccountIDs
This operation occurs with sufficient frequency to
justify having a cache. In the future, rippled should
require clients to receive "binary" results, where
AccountIDs are hex-encoded.
*/
class AccountIDCache
{
private:
std::mutex mutable mutex_;
std::size_t capacity_;
hash_map<AccountID,
std::string> mutable m0_;
hash_map<AccountID,
std::string> mutable m1_;
public:
AccountIDCache(AccountIDCache const&) = delete;
AccountIDCache& operator= (AccountIDCache const&) = delete;
explicit
AccountIDCache (std::size_t capacity);
/** Return ripple::toBase58 for the AccountID
Thread Safety:
Safe to call from any thread concurrently
@note This function intentionally returns a
copy for correctness.
*/
std::string
toBase58 (AccountID const&) const;
};
} // ripple
//------------------------------------------------------------------------------
namespace std {
// DEPRECATED
// VFALCO Use beast::uhash or a hardened container
template <>
struct hash <ripple::AccountID> : ripple::AccountID::hasher
{
};
} // std
#endif

View File

@@ -53,9 +53,6 @@ getLedgerFeeIndex ();
uint256
getAccountRootIndex (AccountID const& account);
uint256
getAccountRootIndex (const RippleAddress & account);
uint256
getGeneratorIndex (AccountID const& uGeneratorID);
@@ -110,9 +107,6 @@ namespace keylet {
struct account_t
{
Keylet operator()(AccountID const& id) const;
// DEPRECATED
Keylet operator()(RippleAddress const& ra) const;
};
static account_t const account {};

View File

@@ -41,7 +41,7 @@ JSS ( ClearFlag ); // field.
JSS ( Destination ); // in: TransactionSign; field.
JSS ( Fee ); // in/out: TransactionSign; field.
JSS ( Flags ); // in/out: TransactionSign; field.
JSS ( Invalid ); // out: app/misc/AccountState
JSS ( Invalid ); //
JSS ( LimitAmount ); // field.
JSS ( OfferSequence ); // field.
JSS ( Paths ); // in/out: TransactionSign
@@ -371,7 +371,7 @@ JSS ( uptime ); // out: GetCounts
JSS ( url ); // in/out: Subscribe, Unsubscribe
JSS ( url_password ); // in: Subscribe
JSS ( url_username ); // in: Subscribe
JSS ( urlgravatar ); // out: AccountState
JSS ( urlgravatar ); //
JSS ( username ); // in: Subscribe
JSS ( validated ); // out: NetworkOPs, LookupLedger, AccountTx*
// Tx

View File

@@ -26,24 +26,13 @@
#include <ripple/crypto/KeyType.h>
#include <ripple/json/json_value.h>
#include <ripple/protocol/RipplePublicKey.h>
#include <ripple/protocol/tokens.h>
#include <ripple/protocol/UInt160.h>
#include <ripple/protocol/UintTypes.h>
#include <beast/utility/noexcept.h>
namespace ripple {
enum VersionEncoding
{
VER_NONE = 1,
VER_NODE_PUBLIC = 28,
VER_NODE_PRIVATE = 32,
VER_ACCOUNT_ID = 0,
VER_ACCOUNT_PUBLIC = 35,
VER_ACCOUNT_PRIVATE = 34,
VER_FAMILY_GENERATOR = 41,
VER_FAMILY_SEED = 33,
};
//
// Used to hold addresses and parse and produce human formats.
//
@@ -78,10 +67,8 @@ public:
void clear ();
bool isSet () const;
static void clearCache ();
/** Returns the public key.
Precondition: version == VER_NODE_PUBLIC
Precondition: version == TOKEN_NODE_PUBLIC
*/
RipplePublicKey
toPublicKey() const;
@@ -120,20 +107,6 @@ public:
static RippleAddress createNodePrivate (RippleAddress const& naSeed);
//
// Accounts IDs
//
AccountID getAccountID () const;
std::string humanAccountID () const;
bool setAccountID (
std::string const& strAccountID,
Base58::Alphabet const& alphabet = Base58::getRippleAlphabet());
void setAccountID (AccountID const& hash160In);
static RippleAddress createAccountID (AccountID const& uiAccountID);
//
// Accounts Public
//
@@ -300,6 +273,10 @@ RippleAddress getSeedFromRPC (Json::Value const& params);
KeyPair generateKeysFromSeed (KeyType keyType, RippleAddress const& seed);
// DEPRECATED
AccountID
calcAccountID (RippleAddress const& publicKey);
} // ripple
#endif

View File

@@ -65,9 +65,6 @@ public:
}
std::string getText () const override;
RippleAddress getValueNCA () const;
void setValueNCA (RippleAddress const& nca);
template <typename Tag>
void setValueH160 (base_uint<160, Tag> const& v)
{
@@ -75,6 +72,10 @@ public:
assert (peekValue ().size () == (160 / 8));
}
// VFALCO This is a clumsy interface, it should return
// the value. And it should not be possible to
// have anything other than a uint160 in here.
// The base_uint tag should always be `AccountIDTag`.
template <typename Tag>
bool getValueH160 (base_uint<160, Tag>& v) const
{

View File

@@ -114,17 +114,7 @@ public:
bool isThreadedType() const; // is this a ledger entry that can be threaded
bool isThreaded () const; // is this ledger entry actually threaded
bool hasOneOwner () const; // This node has one other node that owns it
bool hasTwoOwners () const; // This node has two nodes that own it (like ripple balance)
RippleAddress getOwner () const;
RippleAddress getFirstOwner () const;
RippleAddress getSecondOwner () const;
uint256 getThreadedTransaction () const;
std::uint32_t getThreadedLedger () const;

View File

@@ -215,13 +215,16 @@ public:
// Break the multi-signing hash computation into 2 parts for optimization.
Serializer startMultiSigningData () const;
void finishMultiSigningData (
RippleAddress const& signingForID,
RippleAddress const& signingID, Serializer& s) const;
AccountID const& signingForID,
AccountID const& signingID, Serializer& s) const;
// VFALCO Get functions are usually simple observers but
// this one performs an expensive construction.
//
// Get data to compute a complete multi-signature.
Serializer getMultiSigningData (
RippleAddress const& signingForID,
RippleAddress const& signingID) const;
AccountID const& signingForID,
AccountID const& signingID) const;
const STBase& peekAtIndex (int offset) const
{
@@ -259,8 +262,7 @@ public:
uint160 getFieldH160 (SField const& field) const;
uint256 getFieldH256 (SField const& field) const;
RippleAddress getFieldAccount (SField const& field) const;
AccountID getFieldAccount160 (SField const& field) const;
AccountID getAccountID (SField const& field) const;
Blob getFieldVL (SField const& field) const;
STAmount const& getFieldAmount (SField const& field) const;
@@ -282,11 +284,9 @@ public:
void setFieldH128 (SField const& field, uint128 const&);
void setFieldH256 (SField const& field, uint256 const& );
void setFieldVL (SField const& field, Blob const&);
void setFieldAccount (SField const& field, AccountID const&);
void setFieldAccount (SField const& field, RippleAddress const& addr)
{
setFieldAccount (field, addr.getAccountID ());
}
void setAccountID (SField const& field, AccountID const&);
void setFieldAmount (SField const& field, STAmount const&);
void setFieldPathSet (SField const& field, STPathSet const&);
void setFieldV256 (SField const& field, STVector256 const& v);

View File

@@ -22,6 +22,7 @@
#include <ripple/protocol/STObject.h>
#include <ripple/protocol/TxFormats.h>
#include <boost/container/flat_set.hpp>
#include <boost/logic/tribool.hpp>
namespace ripple {
@@ -94,16 +95,11 @@ public:
setFieldAmount (sfFee, fee);
}
RippleAddress getSourceAccount () const
{
return getFieldAccount (sfAccount);
}
Blob getSigningPubKey () const
{
return getFieldVL (sfSigningPubKey);
}
void setSigningPubKey (const RippleAddress & naSignPubKey);
void setSourceAccount (const RippleAddress & naSource);
std::uint32_t getSequence () const
{
@@ -114,7 +110,8 @@ public:
return setFieldU32 (sfSequence, seq);
}
std::vector<RippleAddress> getMentionedAccounts () const;
boost::container::flat_set<AccountID>
getMentionedAccounts() const;
uint256 getTransactionID () const;

View File

@@ -22,11 +22,11 @@
#include <ripple/basics/UnorderedContainers.h>
#include <ripple/basics/base_uint.h>
#include <ripple/protocol/AccountID.h>
namespace ripple {
namespace detail {
class AccountIDTag {};
class CurrencyTag {};
class DirectoryTag {};
class NodeIDTag {};
@@ -37,33 +37,20 @@ class NodeIDTag {};
The last 64 bits of this are the quality. */
using Directory = base_uint<256, detail::DirectoryTag>;
/** AccountID is a hash representing a specific account. */
using AccountID = base_uint<160, detail::AccountIDTag>;
/** Currency is a hash representing a specific currency. */
using Currency = base_uint<160, detail::CurrencyTag>;
/** NodeID is a 160-bit hash representing one node. */
using NodeID = base_uint<160, detail::NodeIDTag>;
using CurrencySet = hash_set<Currency>;
/** A special account that's used as the "issuer" for XRP. */
AccountID const& xrpAccount();
/** XRP currency. */
Currency const& xrpCurrency();
/** A placeholder for empty accounts. */
AccountID const& noAccount();
/** A placeholder for empty currencies. */
Currency const& noCurrency();
/** We deliberately disallow the currency that looks like "XRP" because too
many people were using it instead of the correct XRP currency. */
Currency const& badCurrency();
inline bool isXRP(Currency const& c)
@@ -71,14 +58,6 @@ inline bool isXRP(Currency const& c)
return c == zero;
}
inline bool isXRP(AccountID const& c)
{
return c == zero;
}
/** Returns a human-readable form of the account. */
std::string to_string(AccountID const&);
/** Returns "", "XRP", or three letter ISO code. */
std::string to_string(Currency const& c);
@@ -88,16 +67,6 @@ bool to_currency(Currency&, std::string const&);
/** Tries to convert a string to a Currency, returns noCurrency() on failure. */
Currency to_currency(std::string const&);
/** Tries to convert a string to an AccountID representing an issuer, returns true
* on success. */
bool to_issuer(AccountID&, std::string const&);
inline std::ostream& operator<< (std::ostream& os, AccountID const& x)
{
os << to_string (x);
return os;
}
inline std::ostream& operator<< (std::ostream& os, Currency const& x)
{
os << to_string (x);
@@ -108,11 +77,6 @@ inline std::ostream& operator<< (std::ostream& os, Currency const& x)
namespace std {
template <>
struct hash <ripple::AccountID> : ripple::AccountID::hasher
{
};
template <>
struct hash <ripple::Currency> : ripple::Currency::hasher
{

View 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

View File

@@ -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);

View File

@@ -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 };

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 (...)
{

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View 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

View File

@@ -489,6 +489,6 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(Issue,types,ripple);
BEAST_DEFINE_TESTSUITE(Issue,protocol,ripple);
}

View File

@@ -23,6 +23,7 @@
#include <ripple/protocol/RippleAddress.h>
#include <ripple/protocol/RipplePublicKey.h>
#include <ripple/protocol/Serializer.h>
#include <ripple/protocol/types.h>
#include <ripple/basics/StringUtilities.h>
namespace ripple {
@@ -72,14 +73,14 @@ public:
RippleAddress naAccountPublic0 = RippleAddress::createAccountPublic (generator, 0);
RippleAddress naAccountPrivate0 = RippleAddress::createAccountPrivate (generator, naSeed, 0);
expect (naAccountPublic0.humanAccountID () == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh", naAccountPublic0.humanAccountID ());
expect (toBase58(calcAccountID(naAccountPublic0)) == "rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
expect (naAccountPublic0.humanAccountPublic () == "aBQG8RQAzjs1eTKFEAQXr2gS4utcDiEC9wmi7pfUPTi27VCahwgw", naAccountPublic0.humanAccountPublic ());
// Create account #1 public/private key pair.
RippleAddress naAccountPublic1 = RippleAddress::createAccountPublic (generator, 1);
RippleAddress naAccountPrivate1 = RippleAddress::createAccountPrivate (generator, naSeed, 1);
expect (naAccountPublic1.humanAccountID () == "r4bYF7SLUMD7QgSLLpgJx38WJSY12ViRjP", naAccountPublic1.humanAccountID ());
expect (toBase58(calcAccountID(naAccountPublic1)) == "r4bYF7SLUMD7QgSLLpgJx38WJSY12ViRjP");
expect (naAccountPublic1.humanAccountPublic () == "aBPXpTfuLy1Bhk3HnGTTAqnovpKWQ23NpFMNkAF6F1Atg5vDyPrw", naAccountPublic1.humanAccountPublic ());
// Check account signing.

View File

@@ -20,6 +20,7 @@
#include <BeastConfig.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/STParsedJSON.h>
#include <ripple/protocol/types.h>
#include <ripple/json/to_string.h>
#include <beast/unit_test/suite.h>
@@ -37,7 +38,7 @@ public:
RippleAddress privateAcct = RippleAddress::createAccountPrivate (generator, seed, 1);
STTx j (ttACCOUNT_SET);
j.setSourceAccount (publicAcct);
j.setAccountID (sfAccount, calcAccountID(publicAcct));
j.setSigningPubKey (publicAcct);
j.setFieldVL (sfMessageKey, publicAcct.getAccountPublic ());
j.sign (privateAcct);
@@ -85,11 +86,13 @@ public:
// Create a transaction
RippleAddress txnSeed;
txnSeed.setSeedRandom ();
// VFALCO Generators are no longer supported
RippleAddress txnGenerator = txnSeed.createGeneratorPublic (txnSeed);
// VFALCO Use AnyPublicKey here
RippleAddress txnPublicAcct = txnSeed.createAccountPublic (txnGenerator, 1);
STTx txn (ttACCOUNT_SET);
txn.setSourceAccount (txnPublicAcct);
txn.setAccountID (sfAccount, calcAccountID(txnPublicAcct));
txn.setSigningPubKey (txnPublicAcct);
txn.setFieldVL (sfMessageKey, txnPublicAcct.getAccountPublic ());
Blob const emptyBlob; // Make empty signature for multi-signing
@@ -101,16 +104,17 @@ public:
RippleAddress const saGenerator = saSeed.createGeneratorPublic (saSeed);
RippleAddress const saPublicAcct =
saSeed.createAccountPublic (saGenerator, 1);
AccountID const saID = saPublicAcct.getAccountID ();
AccountID const saID = calcAccountID(saPublicAcct);
// Create a field for SigningFor
AccountID const signingForID = txnPublicAcct.getAccountID ();
AccountID const signingForID = calcAccountID(txnPublicAcct);
RippleAddress saPrivateAcct =
saSeed.createAccountPrivate(saGenerator, saSeed, 0);
// Get the stream of the transaction for use in multi-signing.
Serializer s = txn.getMultiSigningData (saPublicAcct, saPublicAcct);
Serializer s = txn.getMultiSigningData(
calcAccountID(saPublicAcct), calcAccountID(saPublicAcct));
Blob saMultiSignature =
saPrivateAcct.accountPrivateSign (s.getData());
@@ -137,7 +141,7 @@ public:
// Insert SigningAccounts array into SigningFor object.
STObject signingFor (sfSigningFor);
signingFor.setFieldAccount (sfAccount, signingForID);
signingFor.setAccountID (sfAccount, signingForID);
signingFor.setFieldArray (sfSigningAccounts, signingAccts);
// Insert SigningFor into MultiSigners.
@@ -169,7 +173,7 @@ public:
{
// Test case 1. Make a valid SigningAccount object.
STObject soTest1 (sfSigningAccount);
soTest1.setFieldAccount (sfAccount, saID);
soTest1.setAccountID (sfAccount, saID);
soTest1.setFieldVL (sfSigningPubKey,
txnPublicAcct.getAccountPublic ());
soTest1.setFieldVL (sfMultiSignature, saMultiSignature);
@@ -178,14 +182,14 @@ public:
{
// Test case 2. Omit sfSigningPubKey from SigningAccount.
STObject soTest2 (sfSigningAccount);
soTest2.setFieldAccount (sfAccount, saID);
soTest2.setAccountID (sfAccount, saID);
soTest2.setFieldVL (sfMultiSignature, saMultiSignature);
testMalformedSigningAccount (soTest2, false);
}
{
// Test case 3. Extra sfAmount in SigningAccount.
STObject soTest3 (sfSigningAccount);
soTest3.setFieldAccount (sfAccount, saID);
soTest3.setAccountID (sfAccount, saID);
soTest3.setFieldVL (sfSigningPubKey,
txnPublicAcct.getAccountPublic ());
soTest3.setFieldVL (sfMultiSignature, saMultiSignature);

View File

@@ -0,0 +1,47 @@
//------------------------------------------------------------------------------
/*
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/types.h>
#include <beast/unit_test/suite.h>
namespace ripple {
struct types_test : public beast::unit_test::suite
{
void
testAccountID()
{
auto const s =
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
if (expect(parseBase58<AccountID>(s)))
expect(toBase58(
*parseBase58<AccountID>(s)) == s);
}
void
run() override
{
testAccountID();
}
};
BEAST_DEFINE_TESTSUITE(types,protocol,ripple);
}

View File

@@ -0,0 +1,100 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_PROTOCOL_TOKENS_H_INCLUDED
#define RIPPLE_PROTOCOL_TOKENS_H_INCLUDED
#include <boost/optional.hpp>
#include <cstdint>
#include <string>
namespace ripple {
enum TokenType
{
TOKEN_NONE = 1,
TOKEN_NODE_PUBLIC = 28,
TOKEN_NODE_PRIVATE = 32,
TOKEN_ACCOUNT_ID = 0,
TOKEN_ACCOUNT_PUBLIC = 35,
TOKEN_ACCOUNT_SECRET = 34,
TOKEN_FAMILY_GENERATOR = 41,
TOKEN_FAMILY_SEED = 33
};
template <class T>
boost::optional<T>
parseBase58 (std::string const& s);
template <class T>
boost::optional<T>
parseHex (std::string const& s);
template <class T>
boost::optional<T>
parseHexOrBase58 (std::string const& s);
// Facilities for converting Ripple tokens
// to and from their human readable strings
/* 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);
/** Decode a Base58 token
The type and checksum must match or an
empty string is returned.
*/
std::string
decodeBase58Token(
std::string const& s, int type);
/** Decode a Base58 token using Bitcoin alphabet
The type and checksum must match or an
empty string is returned.
This is used to detect user error. Specifically,
when an AccountID is specified using the wrong
base58 alphabet, so that a better error message
may be returned.
*/
std::string
decodeBase58TokenBitcoin(
std::string const& s, int type);
} // ripple
#endif

View File

@@ -0,0 +1,27 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_PROTOCOL_TYPES_H_INCLUDED
#define RIPPLE_PROTOCOL_TYPES_H_INCLUDED
// DEPRECATED HEADER
#include <ripple/protocol/UintTypes.h>
#endif