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