rippled
Loading...
Searching...
No Matches
AccountID.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpl/basics/hardened_hash.h>
21#include <xrpl/basics/spinlock.h>
22#include <xrpl/beast/utility/Zero.h>
23#include <xrpl/beast/utility/instrumentation.h>
24#include <xrpl/protocol/AccountID.h>
25#include <xrpl/protocol/PublicKey.h>
26#include <xrpl/protocol/digest.h>
27#include <xrpl/protocol/tokens.h>
28
29#include <atomic>
30#include <cstdint>
31#include <cstring>
32#include <memory>
33#include <mutex>
34#include <optional>
35#include <string>
36#include <vector>
37
38namespace ripple {
39
40namespace detail {
41
44{
45private:
47 {
49 char encoding[40] = {0};
50 };
51
52 // The actual cache
54
55 // We use a hash function designed to resist algorithmic complexity attacks
57
58 // 64 spinlocks, packed into a single 64-bit value
60
61public:
63 {
64 // This is non-binding, but we try to avoid wasting memory that
65 // is caused by overallocation.
66 cache_.shrink_to_fit();
67 }
68
71 {
72 auto const index = hasher_(id) % cache_.size();
73
74 packed_spinlock sl(locks_, index % 64);
75
76 {
77 std::lock_guard lock(sl);
78
79 // The check against the first character of the encoding ensures
80 // that we don't mishandle the case of the all-zero account:
81 if (cache_[index].encoding[0] != 0 && cache_[index].id == id)
82 return cache_[index].encoding;
83 }
84
85 auto ret =
86 encodeBase58Token(TokenType::AccountID, id.data(), id.size());
87
88 XRPL_ASSERT(
89 ret.size() <= 38,
90 "ripple::detail::AccountIdCache : maximum result size");
91
92 {
93 std::lock_guard lock(sl);
94 cache_[index].id = id;
95 std::strcpy(cache_[index].encoding, ret.c_str());
96 }
97
98 return ret;
99 }
100};
101
102} // namespace detail
103
105
106void
112
115{
116 if (accountIdCache)
117 return accountIdCache->toBase58(v);
118
120}
121
122template <>
125{
126 auto const result = decodeBase58Token(s, TokenType::AccountID);
127 if (result.size() != AccountID::bytes)
128 return std::nullopt;
129 return AccountID{result};
130}
131
132//------------------------------------------------------------------------------
133/*
134 Calculation of the Account ID
135
136 The AccountID is a 160-bit identifier that uniquely
137 distinguishes an account. The account may or may not
138 exist in the ledger. Even for accounts that are not in
139 the ledger, cryptographic operations may be performed
140 which affect the ledger. For example, designating an
141 account not in the ledger as a regular key for an
142 account that is in the ledger.
143
144 Why did we use half of SHA512 for most things but then
145 SHA256 followed by RIPEMD160 for account IDs? Why didn't
146 we do SHA512 half then RIPEMD160? Or even SHA512 then RIPEMD160?
147 For that matter why RIPEMD160 at all why not just SHA512 and keep
148 only 160 bits?
149
150 Answer (David Schwartz):
151
152 The short answer is that we kept Bitcoin's behavior.
153 The longer answer was that:
154 1) Using a single hash could leave ripple
155 vulnerable to length extension attacks.
156 2) Only RIPEMD160 is generally considered safe at 160 bits.
157
158 Any of those schemes would have been acceptable. However,
159 the one chosen avoids any need to defend the scheme chosen.
160 (Against any criticism other than unnecessary complexity.)
161
162 "The historical reason was that in the very early days,
163 we wanted to give people as few ways to argue that we were
164 less secure than Bitcoin. So where there was no good reason
165 to change something, it was not changed."
166*/
169{
170 static_assert(AccountID::bytes == sizeof(ripesha_hasher::result_type));
171
172 ripesha_hasher rsh;
173 rsh(pk.data(), pk.size());
174 return AccountID{static_cast<ripesha_hasher::result_type>(rsh)};
175}
176
177AccountID const&
179{
180 static AccountID const account(beast::zero);
181 return account;
182}
183
184AccountID const&
186{
187 static AccountID const account(1);
188 return account;
189}
190
191bool
193{
194 if (issuer.parseHex(s))
195 return true;
196 auto const account = parseBase58<AccountID>(s);
197 if (!account)
198 return false;
199 issuer = *account;
200 return true;
201}
202
203} // namespace ripple
A public key.
Definition PublicKey.h:62
std::uint8_t const * data() const noexcept
Definition PublicKey.h:87
std::size_t size() const noexcept
Definition PublicKey.h:93
static constexpr std::size_t size()
Definition base_uint.h:526
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:503
Caches the base58 representations of AccountIDs.
Definition AccountID.cpp:44
std::string toBase58(AccountID const &id)
Definition AccountID.cpp:70
AccountIdCache(std::size_t count)
Definition AccountID.cpp:62
std::vector< CachedAccountID > cache_
Definition AccountID.cpp:53
std::atomic< std::uint64_t > locks_
Definition AccountID.cpp:59
Seed functor once per construction.
Classes to handle arrays of spinlocks packed into a single atomic integer:
Definition spinlock.h:91
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:48
AccountID const & noAccount()
A placeholder for empty accounts.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
AccountID const & xrpAccount()
Compute AccountID from public key.
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
static std::unique_ptr< detail::AccountIdCache > accountIdCache
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
void initAccountIdCache(std::size_t count)
Initialize the global cache used to map AccountID to base58 conversions.
std::string encodeBase58Token(TokenType type, void const *token, std::size_t size)
Encode data in Base58Check format using XRPL alphabet.
Definition tokens.cpp:199
AccountID calcAccountID(PublicKey const &pk)
std::string decodeBase58Token(std::string const &s, TokenType type)
Definition tokens.cpp:209
T strcpy(T... args)
Returns the RIPEMD-160 digest of the SHA256 hash of the message.
Definition digest.h:136
std::array< std::uint8_t, 20 > result_type
Definition digest.h:143