xrpld
Loading...
Searching...
No Matches
AccountID.cpp
1#include <xrpl/protocol/AccountID.h>
2
3#include <xrpl/basics/hardened_hash.h>
4#include <xrpl/basics/spinlock.h>
5#include <xrpl/beast/utility/Zero.h>
6#include <xrpl/beast/utility/instrumentation.h>
7#include <xrpl/protocol/PublicKey.h>
8#include <xrpl/protocol/digest.h>
9#include <xrpl/protocol/tokens.h>
10
11#include <atomic>
12#include <cstdint>
13#include <cstring>
14#include <memory>
15#include <mutex>
16#include <optional>
17#include <string>
18#include <vector>
19
20namespace xrpl {
21
22namespace detail {
23
26{
27private:
29 {
31 char encoding[40] = {0};
32 };
33
34 // The actual cache
36
37 // We use a hash function designed to resist algorithmic complexity attacks
39
40 // 64 spinlocks, packed into a single 64-bit value
42
43public:
45 {
46 // This is non-binding, but we try to avoid wasting memory that
47 // is caused by overallocation.
48 cache_.shrink_to_fit();
49 }
50
53 {
54 auto const index = hasher_(id) % cache_.size();
55
56 PackedSpinlock sl(locks_, index % 64);
57
58 {
59 std::scoped_lock const lock(sl);
60
61 // The check against the first character of the encoding ensures
62 // that we don't mishandle the case of the all-zero account:
63 if (cache_[index].encoding[0] != 0 && cache_[index].id == id)
64 return cache_[index].encoding;
65 }
66
67 auto ret = encodeBase58Token(TokenType::AccountID, id.data(), id.size());
68
69 XRPL_ASSERT(ret.size() <= 38, "xrpl::detail::AccountIdCache : maximum result size");
70
71 {
72 std::scoped_lock const lock(sl);
73 cache_[index].id = id;
74 std::strcpy(cache_[index].encoding, ret.c_str());
75 }
76
77 return ret;
78 }
79};
80
81} // namespace detail
82
84
85void
91
94{
96 return gAccountIdCache->toBase58(v);
97
99}
100
101template <>
104{
105 auto const result = decodeBase58Token(s, TokenType::AccountID);
106 if (result.size() != AccountID::kBytes)
107 return std::nullopt;
108 return AccountID::fromRaw(result);
109}
110
111//------------------------------------------------------------------------------
112/*
113 Calculation of the Account ID
114
115 The AccountID is a 160-bit identifier that uniquely
116 distinguishes an account. The account may or may not
117 exist in the ledger. Even for accounts that are not in
118 the ledger, cryptographic operations may be performed
119 which affect the ledger. For example, designating an
120 account not in the ledger as a regular key for an
121 account that is in the ledger.
122
123 Why did we use half of SHA512 for most things but then
124 SHA256 followed by RIPEMD160 for account IDs? Why didn't
125 we do SHA512 half then RIPEMD160? Or even SHA512 then RIPEMD160?
126 For that matter why RIPEMD160 at all why not just SHA512 and keep
127 only 160 bits?
128
129 Answer (David Schwartz):
130
131 The short answer is that we kept Bitcoin's behavior.
132 The longer answer was that:
133 1) Using a single hash could leave ripple
134 vulnerable to length extension attacks.
135 2) Only RIPEMD160 is generally considered safe at 160 bits.
136
137 Any of those schemes would have been acceptable. However,
138 the one chosen avoids any need to defend the scheme chosen.
139 (Against any criticism other than unnecessary complexity.)
140
141 "The historical reason was that in the very early days,
142 we wanted to give people as few ways to argue that we were
143 less secure than Bitcoin. So where there was no good reason
144 to change something, it was not changed."
145*/
148{
149 static_assert(AccountID::kBytes == sizeof(RipeshaHasher::result_type));
150
151 RipeshaHasher rsh;
152 rsh(pk.data(), pk.size());
153 return AccountID::fromRaw(static_cast<RipeshaHasher::result_type>(rsh));
154}
155
156AccountID const&
158{
159 static AccountID const kAccount(beast::kZero);
160 return kAccount;
161}
162
163AccountID const&
165{
166 static AccountID const kAccount(1);
167 return kAccount;
168}
169
170bool
172{
173 if (issuer.parseHex(s))
174 return true;
175 auto const account = parseBase58<AccountID>(s);
176 if (!account)
177 return false;
178 issuer = *account;
179 return true;
180}
181
182} // namespace xrpl
static BaseUInt fromRaw(Container const &c)
Definition base_uint.h:294
pointer data()
Definition base_uint.h:106
static constexpr std::size_t kBytes
Definition base_uint.h:89
static constexpr std::size_t size()
Definition base_uint.h:530
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:507
Seed functor once per construction.
Classes to handle arrays of spinlocks packed into a single atomic integer:
Definition spinlock.h:75
A public key.
Definition PublicKey.h:42
std::uint8_t const * data() const noexcept
Definition PublicKey.h:67
static std::size_t size() noexcept
Definition PublicKey.h:73
std::string toBase58(AccountID const &id)
Definition AccountID.cpp:52
AccountIdCache(std::size_t count)
Definition AccountID.cpp:44
std::vector< CachedAccountID > cache_
Definition AccountID.cpp:35
std::atomic< std::uint64_t > locks_
Definition AccountID.cpp:41
T make_unique(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
static std::unique_ptr< detail::AccountIdCache > gAccountIdCache
Definition AccountID.cpp:83
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:93
void initAccountIdCache(std::size_t count)
Initialize the global cache used to map AccountID to base58 conversions.
Definition AccountID.cpp:86
AccountID calcAccountID(PublicKey const &pk)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
AccountID const & noAccount()
A placeholder for empty accounts.
AccountID const & xrpAccount()
Compute AccountID from public key.
std::string encodeBase58Token(TokenType type, void const *token, std::size_t size)
Encode data in Base58Check format using XRPL alphabet.
Definition tokens.cpp:178
std::string decodeBase58Token(std::string const &s, TokenType type)
Definition tokens.cpp:188
bool toIssuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
T strcpy(T... args)
Returns the RIPEMD-160 digest of the SHA256 hash of the message.
Definition digest.h:116
std::array< std::uint8_t, 20 > result_type
Definition digest.h:123