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