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