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/protocol/AccountID.h>
21 #include <ripple/protocol/PublicKey.h>
22 #include <ripple/protocol/digest.h>
23 #include <ripple/protocol/tokens.h>
24 #include <cstring>
25 
26 namespace ripple {
27 
30 {
32 }
33 
34 template <>
37 {
38  auto const result = decodeBase58Token(s, TokenType::AccountID);
39  if (result.size() != AccountID::bytes)
40  return std::nullopt;
41  return AccountID{result};
42 }
43 
44 //------------------------------------------------------------------------------
45 /*
46  Calculation of the Account ID
47 
48  The AccountID is a 160-bit identifier that uniquely
49  distinguishes an account. The account may or may not
50  exist in the ledger. Even for accounts that are not in
51  the ledger, cryptographic operations may be performed
52  which affect the ledger. For example, designating an
53  account not in the ledger as a regular key for an
54  account that is in the ledger.
55 
56  Why did we use half of SHA512 for most things but then
57  SHA256 followed by RIPEMD160 for account IDs? Why didn't
58  we do SHA512 half then RIPEMD160? Or even SHA512 then RIPEMD160?
59  For that matter why RIPEMD160 at all why not just SHA512 and keep
60  only 160 bits?
61 
62  Answer (David Schwartz):
63 
64  The short answer is that we kept Bitcoin's behavior.
65  The longer answer was that:
66  1) Using a single hash could leave ripple
67  vulnerable to length extension attacks.
68  2) Only RIPEMD160 is generally considered safe at 160 bits.
69 
70  Any of those schemes would have been acceptable. However,
71  the one chosen avoids any need to defend the scheme chosen.
72  (Against any criticism other than unnecessary complexity.)
73 
74  "The historical reason was that in the very early days,
75  we wanted to give people as few ways to argue that we were
76  less secure than Bitcoin. So where there was no good reason
77  to change something, it was not changed."
78 */
81 {
82  static_assert(AccountID::bytes == sizeof(ripesha_hasher::result_type));
83 
84  ripesha_hasher rsh;
85  rsh(pk.data(), pk.size());
86  return AccountID{static_cast<ripesha_hasher::result_type>(rsh)};
87 }
88 
89 AccountID const&
91 {
92  static AccountID const account(beast::zero);
93  return account;
94 }
95 
96 AccountID const&
98 {
99  static AccountID const account(1);
100  return account;
101 }
102 
103 bool
104 to_issuer(AccountID& issuer, std::string const& s)
105 {
106  if (issuer.parseHex(s))
107  return true;
108  auto const account = parseBase58<AccountID>(s);
109  if (!account)
110  return false;
111  issuer = *account;
112  return true;
113 }
114 
115 //------------------------------------------------------------------------------
116 
117 /* VFALCO NOTE
118  An alternate implementation could use a pair of insert-only
119  hash maps that each use a single large memory allocation
120  to store a fixed size hash table and all of the AccountID/string
121  pairs laid out in memory (wouldn't use std::string here just a
122  length prefixed or zero terminated array). Possibly using
123  boost::intrusive as the basis for the unordered container.
124  This would cut down to one allocate/free cycle per swap of
125  the map.
126 */
127 
128 AccountIDCache::AccountIDCache(std::size_t capacity) : capacity_(capacity)
129 {
130  m1_.reserve(capacity_);
131 }
132 
135 {
136  std::lock_guard lock(mutex_);
137  auto iter = m1_.find(id);
138  if (iter != m1_.end())
139  return iter->second;
140  iter = m0_.find(id);
141  std::string result;
142  if (iter != m0_.end())
143  {
144  result = iter->second;
145  // Can use insert-only hash maps if
146  // we didn't erase from here.
147  m0_.erase(iter);
148  }
149  else
150  {
151  result = ripple::toBase58(id);
152  }
153  if (m1_.size() >= capacity_)
154  {
155  m0_ = std::move(m1_);
156  m1_.clear();
157  m1_.reserve(capacity_);
158  }
159  m1_.emplace(id, result);
160  return result;
161 }
162 
163 } // namespace ripple
ripple::PublicKey::data
std::uint8_t const * data() const noexcept
Definition: PublicKey.h:81
std::string
STL class.
cstring
ripple::AccountIDCache::capacity_
std::size_t capacity_
Definition: AccountID.h:122
ripple::AccountIDCache::AccountIDCache
AccountIDCache(AccountIDCache const &)=delete
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
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:115
ripple::TokenType::AccountID
@ AccountID
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:498
ripple::base_uint< 160, detail::AccountIDTag >
ripple::AccountIDCache::m1_
hash_map< AccountID, std::string > m1_
Definition: AccountID.h:124
ripple::AccountIDCache::mutex_
std::mutex mutex_
Definition: AccountID.h:121
ripple::base_uint< 160, detail::AccountIDTag >::bytes
static constexpr std::size_t bytes
Definition: base_uint.h:98
ripple::ripesha_hasher
Returns the RIPEMD-160 digest of the SHA256 hash of the message.
Definition: digest.h:131
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::PublicKey::size
std::size_t size() const noexcept
Definition: PublicKey.h:87
ripple::calcAccountID
AccountID calcAccountID(PublicKey const &pk)
Definition: AccountID.cpp:80
std::array
STL class.
ripple::xrpAccount
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:90
ripple::AccountIDCache::m0_
hash_map< AccountID, std::string > m0_
Definition: AccountID.h:123
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
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
std::optional
std::size_t
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:475
ripple::parseBase58
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
Definition: AccountID.cpp:36
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:97
ripple::AccountID
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition: AccountID.h:47
ripple::AccountIDCache::toBase58
std::string toBase58(AccountID const &) const
Return ripple::toBase58 for the AccountID.
Definition: AccountID.cpp:134
ripple::to_issuer
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
Definition: AccountID.cpp:104