Kagome
Polkadot Runtime Engine in C++17
crypto_store_impl.hpp
Go to the documentation of this file.
1 
6 #ifndef KAGOME_CRYPTO_STORE_IMPL_HPP
7 #define KAGOME_CRYPTO_STORE_IMPL_HPP
8 
9 #include <unordered_set>
10 
11 #include <boost/filesystem.hpp>
12 #include <boost/variant.hpp>
13 
14 #include "common/blob.hpp"
17 #include "crypto/crypto_store.hpp"
22 #include "log/logger.hpp"
23 
24 namespace kagome::crypto {
25 
26  enum class CryptoStoreError {
35  };
36 
37  libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(const Ed25519Keypair &kp);
38 
44  class CryptoStoreImpl : public CryptoStore {
45  public:
46  CryptoStoreImpl(std::shared_ptr<EcdsaSuite> ecdsa_suite,
47  std::shared_ptr<Ed25519Suite> ed_suite,
48  std::shared_ptr<Sr25519Suite> sr_suite,
49  std::shared_ptr<Bip39Provider> bip39_provider,
50  std::shared_ptr<KeyFileStorage> key_fs);
51 
52  outcome::result<EcdsaKeypair> generateEcdsaKeypair(
53  KeyTypeId key_type, std::string_view mnemonic_phrase) override;
54 
55  outcome::result<Ed25519Keypair> generateEd25519Keypair(
56  KeyTypeId key_type, std::string_view mnemonic_phrase) override;
57 
58  outcome::result<Sr25519Keypair> generateSr25519Keypair(
59  KeyTypeId key_type, std::string_view mnemonic_phrase) override;
60 
61  outcome::result<EcdsaKeypair> generateEcdsaKeypair(
62  KeyTypeId key_type, const EcdsaSeed &seed) override;
63 
64  outcome::result<Ed25519Keypair> generateEd25519Keypair(
65  KeyTypeId key_type, const Ed25519Seed &seed) override;
66 
67  outcome::result<Sr25519Keypair> generateSr25519Keypair(
68  KeyTypeId key_type, const Sr25519Seed &seed) override;
69 
70  outcome::result<EcdsaKeypair> generateEcdsaKeypairOnDisk(
71  KeyTypeId key_type) override;
72 
73  outcome::result<Ed25519Keypair> generateEd25519KeypairOnDisk(
74  KeyTypeId key_type) override;
75 
76  outcome::result<Sr25519Keypair> generateSr25519KeypairOnDisk(
77  KeyTypeId key_type) override;
78 
79  outcome::result<EcdsaKeypair> findEcdsaKeypair(
80  KeyTypeId key_type, const EcdsaPublicKey &pk) const override;
81 
82  outcome::result<Ed25519Keypair> findEd25519Keypair(
83  KeyTypeId key_type, const Ed25519PublicKey &pk) const override;
84 
85  outcome::result<Sr25519Keypair> findSr25519Keypair(
86  KeyTypeId key_type, const Sr25519PublicKey &pk) const override;
87 
88  outcome::result<EcdsaKeys> getEcdsaPublicKeys(
89  KeyTypeId key_type) const override;
90 
91  outcome::result<Ed25519Keys> getEd25519PublicKeys(
92  KeyTypeId key_type) const override;
93 
94  outcome::result<Sr25519Keys> getSr25519PublicKeys(
95  KeyTypeId key_type) const override;
96 
97  std::optional<libp2p::crypto::KeyPair> getLibp2pKeypair() const override;
98 
99  outcome::result<libp2p::crypto::KeyPair> loadLibp2pKeypair(
100  const Path &key_path) const override;
101 
102  private:
103  template <typename CryptoSuite>
104  outcome::result<std::vector<typename CryptoSuite::PublicKey>> getPublicKeys(
105  KeyTypeId key_type,
106  const KeyCache<CryptoSuite> &cache,
107  const CryptoSuite &suite) const {
108  auto cached_keys = cache.getPublicKeys();
109  OUTCOME_TRY(keys, file_storage_->collectPublicKeys(key_type));
110 
111  std::vector<typename CryptoSuite::PublicKey> res;
112  res.reserve(keys.size());
113  for (auto &key : keys) {
114  OUTCOME_TRY(pk, suite.toPublicKey(key));
115  auto erased = cached_keys.erase(pk);
116  // if we erased pk from cache, it means it was there and thus was a
117  // valid cached key, which we can collect to our result
118  if (erased == 1) {
119  res.emplace_back(std::move(pk));
120 
121  // otherwise, pk was not found in cache and has to be loaded and
122  // checked
123  } else {
124  // need to check if the read key's algorithm belongs to the given
125  // CryptoSuite
126  OUTCOME_TRY(seed_bytes, file_storage_->searchForSeed(key_type, key));
127  BOOST_ASSERT_MSG(
128  seed_bytes,
129  "The public key has just been scanned, its file has to exist");
130  if (not seed_bytes) {
131  logger_->error("Error reading key seed from key file storage");
132  continue;
133  }
134  auto seed_res = suite.toSeed(seed_bytes.value());
135  if (not seed_res) {
136  // cannot create a seed from file content; suppose it belongs to a
137  // different algorithm
138  continue;
139  }
140  SL_TRACE(logger_, "Loaded key {}", pk.toHex());
141  OUTCOME_TRY(kp, suite.generateKeypair(seed_res.value()));
142  auto &&[pub, priv] = suite.decomposeKeypair(kp);
143  if (pub == pk) {
144  SL_TRACE(logger_, "Key is correct {}", pk.toHex());
145  res.emplace_back(std::move(pk));
146  }
147  }
148  }
149  std::move(
150  cached_keys.begin(), cached_keys.end(), std::back_inserter(res));
151  return res;
152  }
153 
154  template <typename CryptoSuite>
155  outcome::result<typename CryptoSuite::Keypair> generateKeypair(
156  std::string_view mnemonic_phrase, const CryptoSuite &suite) {
157  using Seed = typename CryptoSuite::Seed;
158  if (auto seed = DevMnemonicPhrase::get().find<Seed>(mnemonic_phrase)) {
159  return suite.generateKeypair(seed.value());
160  }
161  OUTCOME_TRY(bip_seed, bip39_provider_->generateSeed(mnemonic_phrase));
162  if (bip_seed.size() < Seed::size()) {
164  }
165  auto seed_span = gsl::make_span(bip_seed.data(), Seed::size());
166  OUTCOME_TRY(seed, Seed::fromSpan(seed_span));
167  return suite.generateKeypair(seed);
168  }
169 
170  template <typename CryptoSuite>
171  outcome::result<typename CryptoSuite::Keypair> generateKeypairOnDisk(
172  KeyTypeId key_type,
173  const std::shared_ptr<CryptoSuite> &suite,
174  std::unordered_map<KeyTypeId, KeyCache<CryptoSuite>> &caches) {
175  OUTCOME_TRY(kp, suite->generateRandomKeypair());
176  getCache(suite, caches, key_type).insert(kp.public_key, kp.secret_key);
177  OUTCOME_TRY(file_storage_->saveKeyPair(key_type, kp.public_key, kp.seed));
178  return std::move(kp);
179  }
180 
181  template <typename Suite>
183  std::shared_ptr<Suite> suite,
184  std::unordered_map<KeyTypeId, KeyCache<Suite>> &caches,
185  KeyTypeId type) const {
186  auto it = caches.find(type);
187  if (it == caches.end()) {
188  auto &&[new_it, success] = caches.insert({type, KeyCache{type, suite}});
189  BOOST_ASSERT(success);
190  it = new_it;
191  }
192  return it->second;
193  }
194 
195  mutable std::unordered_map<KeyTypeId, KeyCache<EcdsaSuite>> ecdsa_caches_;
196  mutable std::unordered_map<KeyTypeId, KeyCache<Ed25519Suite>> ed_caches_;
197  mutable std::unordered_map<KeyTypeId, KeyCache<Sr25519Suite>> sr_caches_;
198  std::shared_ptr<KeyFileStorage> file_storage_;
199  std::shared_ptr<EcdsaSuite> ecdsa_suite_;
200  std::shared_ptr<Ed25519Suite> ed_suite_;
201  std::shared_ptr<Sr25519Suite> sr_suite_;
202  std::shared_ptr<Bip39Provider> bip39_provider_;
204  };
205 
206 } // namespace kagome::crypto
207 
209 
210 #endif // KAGOME_CRYPTO_STORE_IMPL_HPP
static const DevMnemonicPhrase & get()
boost::filesystem::path Path
std::unordered_map< KeyTypeId, KeyCache< Sr25519Suite > > sr_caches_
outcome::result< typename CryptoSuite::Keypair > generateKeypair(std::string_view mnemonic_phrase, const CryptoSuite &suite)
std::shared_ptr< KeyFileStorage > file_storage_
std::shared_ptr< Ed25519Suite > ed_suite_
std::unordered_map< KeyTypeId, KeyCache< Ed25519Suite > > ed_caches_
std::shared_ptr< EcdsaSuite > ecdsa_suite_
virtual outcome::result< Seed > toSeed(gsl::span< const uint8_t > bytes) const noexcept=0
libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(const Ed25519Keypair &kp)
uint32_t KeyTypeId
Key type identifier.
Definition: key_type.hpp:21
virtual outcome::result< PublicKey > toPublicKey(gsl::span< const uint8_t > bytes) const noexcept=0
gsl::span< const uint8_t > make_span(const rocksdb::Slice &s)
KeyCache< Suite > & getCache(std::shared_ptr< Suite > suite, std::unordered_map< KeyTypeId, KeyCache< Suite >> &caches, KeyTypeId type) const
std::shared_ptr< Sr25519Suite > sr_suite_
std::shared_ptr< soralog::Logger > Logger
Definition: logger.hpp:23
outcome::result< typename CryptoSuite::Keypair > generateKeypairOnDisk(KeyTypeId key_type, const std::shared_ptr< CryptoSuite > &suite, std::unordered_map< KeyTypeId, KeyCache< CryptoSuite >> &caches)
outcome::result< std::vector< typename CryptoSuite::PublicKey > > getPublicKeys(KeyTypeId key_type, const KeyCache< CryptoSuite > &cache, const CryptoSuite &suite) const
OUTCOME_HPP_DECLARE_ERROR(kagome::crypto, CryptoStoreError)
std::unordered_map< KeyTypeId, KeyCache< EcdsaSuite > > ecdsa_caches_
std::shared_ptr< Bip39Provider > bip39_provider_
virtual outcome::result< Keypair > generateKeypair(const Seed &seed) const noexcept=0
virtual std::pair< PublicKey, PrivateKey > decomposeKeypair(const Keypair &kp) const noexcept=0
std::unordered_set< PublicKey > getPublicKeys() const
Definition: key_cache.hpp:54