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 <>
35 boost::optional<AccountID>
37 {
38  auto const result = decodeBase58Token(s, TokenType::AccountID);
39  if (result.empty())
40  return boost::none;
41  AccountID id;
42  if (result.size() != id.size())
43  return boost::none;
44  std::memcpy(id.data(), result.data(), result.size());
45  return id;
46 }
47 
48 bool
50 {
51  if (!jv.isString())
52  return false;
53  auto const result = parseBase58<AccountID>(jv.asString());
54  if (!result)
55  return false;
56  account = *result;
57  return true;
58 }
59 
60 template <>
61 boost::optional<AccountID>
63 {
64  if (s.size() != 40)
65  return boost::none;
66  AccountID id;
67  if (!id.SetHex(s, true))
68  return boost::none;
69  return id;
70 }
71 
72 template <>
73 boost::optional<AccountID>
75 {
76  auto result = parseHex<AccountID>(s);
77  if (!result)
78  result = parseBase58<AccountID>(s);
79  return result;
80 }
81 
82 //------------------------------------------------------------------------------
83 /*
84  Calculation of the Account ID
85 
86  The AccountID is a 160-bit identifier that uniquely
87  distinguishes an account. The account may or may not
88  exist in the ledger. Even for accounts that are not in
89  the ledger, cryptographic operations may be performed
90  which affect the ledger. For example, designating an
91  account not in the ledger as a regular key for an
92  account that is in the ledger.
93 
94  Why did we use half of SHA512 for most things but then
95  SHA256 followed by RIPEMD160 for account IDs? Why didn't
96  we do SHA512 half then RIPEMD160? Or even SHA512 then RIPEMD160?
97  For that matter why RIPEMD160 at all why not just SHA512 and keep
98  only 160 bits?
99 
100  Answer (David Schwartz):
101 
102  The short answer is that we kept Bitcoin's behavior.
103  The longer answer was that:
104  1) Using a single hash could leave ripple
105  vulnerable to length extension attacks.
106  2) Only RIPEMD160 is generally considered safe at 160 bits.
107 
108  Any of those schemes would have been acceptable. However,
109  the one chosen avoids any need to defend the scheme chosen.
110  (Against any criticism other than unnecessary complexity.)
111 
112  "The historical reason was that in the very early days,
113  we wanted to give people as few ways to argue that we were
114  less secure than Bitcoin. So where there was no good reason
115  to change something, it was not changed."
116 */
117 AccountID
119 {
120  ripesha_hasher rsh;
121  rsh(pk.data(), pk.size());
122  auto const d = static_cast<ripesha_hasher::result_type>(rsh);
123  AccountID id;
124  static_assert(sizeof(d) == id.size(), "");
125  std::memcpy(id.data(), d.data(), d.size());
126  return id;
127 }
128 
129 AccountID const&
131 {
132  static AccountID const account(beast::zero);
133  return account;
134 }
135 
136 AccountID const&
138 {
139  static AccountID const account(1);
140  return account;
141 }
142 
143 bool
144 to_issuer(AccountID& issuer, std::string const& s)
145 {
146  if (s.size() == (160 / 4))
147  {
148  issuer.SetHex(s);
149  return true;
150  }
151  auto const account = parseBase58<AccountID>(s);
152  if (!account)
153  return false;
154  issuer = *account;
155  return true;
156 }
157 
158 //------------------------------------------------------------------------------
159 
160 /* VFALCO NOTE
161  An alternate implementation could use a pair of insert-only
162  hash maps that each use a single large memory allocation
163  to store a fixed size hash table and all of the AccountID/string
164  pairs laid out in memory (wouldn't use std::string here just a
165  length prefixed or zero terminated array). Possibly using
166  boost::intrusive as the basis for the unordered container.
167  This would cut down to one allocate/free cycle per swap of
168  the map.
169 */
170 
171 AccountIDCache::AccountIDCache(std::size_t capacity) : capacity_(capacity)
172 {
173  m1_.reserve(capacity_);
174 }
175 
178 {
179  std::lock_guard lock(mutex_);
180  auto iter = m1_.find(id);
181  if (iter != m1_.end())
182  return iter->second;
183  iter = m0_.find(id);
184  std::string result;
185  if (iter != m0_.end())
186  {
187  result = iter->second;
188  // Can use insert-only hash maps if
189  // we didn't erase from here.
190  m0_.erase(iter);
191  }
192  else
193  {
194  result = ripple::toBase58(id);
195  }
196  if (m1_.size() >= capacity_)
197  {
198  m0_ = std::move(m1_);
199  m1_.clear();
200  m1_.reserve(capacity_);
201  }
202  m1_.emplace(id, result);
203  return result;
204 }
205 
206 } // namespace ripple
ripple::PublicKey::data
std::uint8_t const * data() const noexcept
Definition: PublicKey.h:81
std::string
STL class.
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
cstring
ripple::AccountIDCache::capacity_
std::size_t capacity_
Definition: AccountID.h:145
ripple::AccountIDCache::AccountIDCache
AccountIDCache(AccountIDCache const &)=delete
std::string::size
T size(T... args)
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
ripple::parseHex
boost::optional< AccountID > parseHex(std::string const &s)
Parse AccountID from hexadecimal string.
Definition: AccountID.cpp:62
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:103
ripple::TokenType::AccountID
@ AccountID
ripple::base_uint::size
constexpr static std::size_t size()
Definition: base_uint.h:462
ripple::base_uint
Definition: base_uint.h:63
ripple::AccountIDCache::m1_
hash_map< AccountID, std::string > m1_
Definition: AccountID.h:147
ripple::AccountIDCache::mutex_
std::mutex mutex_
Definition: AccountID.h:144
ripple::ripesha_hasher
Returns the RIPEMD-160 digest of the SHA256 hash of the message.
Definition: digest.h:140
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:118
std::array
STL class.
ripple::base_uint::SetHex
bool SetHex(const char *psz, bool bStrict=false)
Parse a hex string into a base_uint The input can be:
Definition: base_uint.h:406
ripple::xrpAccount
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:130
ripple::AccountIDCache::m0_
hash_map< AccountID, std::string > m0_
Definition: AccountID.h:146
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
ripple::parseHexOrBase58
boost::optional< AccountID > parseHexOrBase58(std::string const &s)
Parse AccountID from hex or checked base58 string.
Definition: AccountID.cpp:74
std::size_t
std::memcpy
T memcpy(T... args)
ripple::deprecatedParseBase58
bool deprecatedParseBase58(AccountID &account, Json::Value const &jv)
Definition: AccountID.cpp:49
ripple::parseBase58
boost::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:137
ripple::AccountID
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition: AccountID.h:47
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::AccountIDCache::toBase58
std::string toBase58(AccountID const &) const
Return ripple::toBase58 for the AccountID.
Definition: AccountID.cpp:177
ripple::to_issuer
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
Definition: AccountID.cpp:144
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469