Kagome
Polkadot Runtime Engine in C++17
crypto_store_impl.cpp
Go to the documentation of this file.
1 
7 
8 #include <fstream>
9 
10 #include <gsl/span>
11 
12 #include "common/visitor.hpp"
13 
16  switch (e) {
17  case E::UNSUPPORTED_KEY_TYPE:
18  return "key type is not supported";
19  case E::UNSUPPORTED_CRYPTO_TYPE:
20  return "cryptographic type is not supported";
21  case E::WRONG_SEED_SIZE:
22  return "wrong seed size";
23  case E::KEY_NOT_FOUND:
24  return "key not found";
25  case E::BABE_ALREADY_EXIST:
26  return "BABE key already exists";
27  case E::GRAN_ALREADY_EXIST:
28  return "GRAN key already exists";
29  case E::AUDI_ALREADY_EXIST:
30  return "AUDI key already exists";
31  case E::WRONG_PUBLIC_KEY:
32  return "Public key doesn't match seed";
33  }
34  return "Unknown CryptoStoreError code";
35 }
36 
37 namespace kagome::crypto {
38 
40  std::shared_ptr<EcdsaSuite> ecdsa_suite,
41  std::shared_ptr<Ed25519Suite> ed_suite,
42  std::shared_ptr<Sr25519Suite> sr_suite,
43  std::shared_ptr<Bip39Provider> bip39_provider,
44  std::shared_ptr<KeyFileStorage> key_fs)
45  : file_storage_{std::move(key_fs)},
46  ecdsa_suite_{std::move(ecdsa_suite)},
47  ed_suite_{std::move(ed_suite)},
48  sr_suite_{std::move(sr_suite)},
49  bip39_provider_{std::move(bip39_provider)},
50  logger_{log::createLogger("CryptoStore", "crypto_store")} {
51  BOOST_ASSERT(ecdsa_suite_ != nullptr);
52  BOOST_ASSERT(ed_suite_ != nullptr);
53  BOOST_ASSERT(sr_suite_ != nullptr);
54  BOOST_ASSERT(bip39_provider_ != nullptr);
55  BOOST_ASSERT(file_storage_ != nullptr);
56  }
57 
58  outcome::result<EcdsaKeypair> CryptoStoreImpl::generateEcdsaKeypair(
59  KeyTypeId key_type, std::string_view mnemonic_phrase) {
60  OUTCOME_TRY(kp, generateKeypair(mnemonic_phrase, *ecdsa_suite_));
62  .insert(kp.public_key, kp.secret_key);
63  return std::move(kp);
64  }
65 
66  outcome::result<Ed25519Keypair> CryptoStoreImpl::generateEd25519Keypair(
67  KeyTypeId key_type, std::string_view mnemonic_phrase) {
68  OUTCOME_TRY(kp, generateKeypair(mnemonic_phrase, *ed_suite_));
69  getCache(ed_suite_, ed_caches_, key_type)
70  .insert(kp.public_key, kp.secret_key);
71  return std::move(kp);
72  }
73 
74  outcome::result<Sr25519Keypair> CryptoStoreImpl::generateSr25519Keypair(
75  KeyTypeId key_type, std::string_view mnemonic_phrase) {
76  OUTCOME_TRY(kp, generateKeypair(mnemonic_phrase, *sr_suite_));
77  getCache(sr_suite_, sr_caches_, key_type)
78  .insert(kp.public_key, kp.secret_key);
79  return std::move(kp);
80  }
81 
82  outcome::result<EcdsaKeypair> CryptoStoreImpl::generateEcdsaKeypair(
83  KeyTypeId key_type, const EcdsaSeed &seed) {
84  OUTCOME_TRY(kp, ecdsa_suite_->generateKeypair(seed));
86  .insert(kp.public_key, kp.secret_key);
87  return std::move(kp);
88  }
89 
90  outcome::result<Ed25519Keypair> CryptoStoreImpl::generateEd25519Keypair(
91  KeyTypeId key_type, const Ed25519Seed &seed) {
92  OUTCOME_TRY(kp, ed_suite_->generateKeypair(seed));
93  getCache(ed_suite_, ed_caches_, key_type)
94  .insert(kp.public_key, kp.secret_key);
95  return std::move(kp);
96  }
97 
98  outcome::result<Sr25519Keypair> CryptoStoreImpl::generateSr25519Keypair(
99  KeyTypeId key_type, const Sr25519Seed &seed) {
100  OUTCOME_TRY(kp, sr_suite_->generateKeypair(seed));
101  getCache(sr_suite_, sr_caches_, key_type)
102  .insert(kp.public_key, kp.secret_key);
103  return std::move(kp);
104  }
105 
106  outcome::result<EcdsaKeypair> CryptoStoreImpl::generateEcdsaKeypairOnDisk(
107  KeyTypeId key_type) {
109  }
110 
111  outcome::result<Ed25519Keypair> CryptoStoreImpl::generateEd25519KeypairOnDisk(
112  KeyTypeId key_type) {
113  return generateKeypairOnDisk(key_type, ed_suite_, ed_caches_);
114  }
115 
116  outcome::result<Sr25519Keypair> CryptoStoreImpl::generateSr25519KeypairOnDisk(
117  KeyTypeId key_type) {
118  return generateKeypairOnDisk(key_type, sr_suite_, sr_caches_);
119  }
120 
121  outcome::result<EcdsaKeypair> CryptoStoreImpl::findEcdsaKeypair(
122  KeyTypeId key_type, const EcdsaPublicKey &pk) const {
123  auto kp_opt =
124  getCache(ecdsa_suite_, ecdsa_caches_, key_type).searchKeypair(pk);
125  if (kp_opt) {
126  return kp_opt.value();
127  }
128  OUTCOME_TRY(seed_bytes,
129  file_storage_->searchForSeed(key_type, gsl::make_span(pk)));
130  if (not seed_bytes) {
132  }
133  EcdsaSeed seed;
134  auto bytes = seed_bytes.value();
135  if (seed.size() != bytes.size()) {
137  }
138  std::copy(bytes.begin(), bytes.end(), seed.begin());
139  return ecdsa_suite_->generateKeypair(seed);
140  }
141 
142  outcome::result<Ed25519Keypair> CryptoStoreImpl::findEd25519Keypair(
143  KeyTypeId key_type, const Ed25519PublicKey &pk) const {
144  auto kp_opt = getCache(ed_suite_, ed_caches_, key_type).searchKeypair(pk);
145  if (kp_opt) {
146  return kp_opt.value();
147  }
148  OUTCOME_TRY(seed_bytes,
149  file_storage_->searchForSeed(key_type, gsl::make_span(pk)));
150  if (not seed_bytes) {
152  }
153  OUTCOME_TRY(seed, Ed25519Seed::fromSpan(seed_bytes.value()));
154  return ed_suite_->generateKeypair(seed);
155  }
156 
157  outcome::result<Sr25519Keypair> CryptoStoreImpl::findSr25519Keypair(
158  KeyTypeId key_type, const Sr25519PublicKey &pk) const {
159  auto kp_opt = getCache(sr_suite_, sr_caches_, key_type).searchKeypair(pk);
160  if (kp_opt) {
161  return kp_opt.value();
162  }
163  OUTCOME_TRY(seed_bytes,
164  file_storage_->searchForSeed(key_type, gsl::make_span(pk)));
165  if (not seed_bytes) {
167  }
168  OUTCOME_TRY(seed, Sr25519Seed::fromSpan(seed_bytes.value()));
169  return sr_suite_->generateKeypair(seed);
170  }
171 
172  outcome::result<CryptoStoreImpl::EcdsaKeys>
174  return getPublicKeys(key_type,
175  getCache(ecdsa_suite_, ecdsa_caches_, key_type),
176  *ecdsa_suite_);
177  }
178 
179  outcome::result<CryptoStoreImpl::Ed25519Keys>
181  return getPublicKeys(
182  key_type, getCache(ed_suite_, ed_caches_, key_type), *ed_suite_);
183  }
184 
185  outcome::result<CryptoStoreImpl::Sr25519Keys>
187  return getPublicKeys(
188  key_type, getCache(sr_suite_, sr_caches_, key_type), *sr_suite_);
189  }
190 
191  std::optional<libp2p::crypto::KeyPair> CryptoStoreImpl::getLibp2pKeypair()
192  const {
193  auto keys = getEd25519PublicKeys(KEY_TYPE_LP2P);
194  if (not keys or keys.value().empty()) {
195  return std::nullopt;
196  }
197  auto kp = findEd25519Keypair(KEY_TYPE_LP2P, keys.value().at(0));
198  if (kp) {
199  return ed25519KeyToLibp2pKeypair(kp.value());
200  }
201  return std::nullopt;
202  }
203 
204  outcome::result<libp2p::crypto::KeyPair> CryptoStoreImpl::loadLibp2pKeypair(
205  const CryptoStore::Path &key_path) const {
206  auto lookup_res = file_storage_->loadFileContent(key_path);
207  if (lookup_res.has_error()
208  and lookup_res.error() == KeyFileStorage::Error::FILE_DOESNT_EXIST) {
209  OUTCOME_TRY(kp, ed_suite_->generateRandomKeypair());
211  .insert(kp.public_key, kp.secret_key);
212  OUTCOME_TRY(file_storage_->saveKeyHexAtPath(kp.secret_key, key_path));
213  return ed25519KeyToLibp2pKeypair(kp);
214  }
215  // propagate any other error
216  if (lookup_res.has_error()) {
217  return lookup_res.error();
218  }
219  const auto &contents = lookup_res.value();
220  BOOST_ASSERT(ED25519_SEED_LENGTH == contents.size()
221  or 2 * ED25519_SEED_LENGTH == contents.size()); // hex
222  Ed25519Seed seed;
223  if (ED25519_SEED_LENGTH == contents.size()) {
224  OUTCOME_TRY(
225  _seed,
226  Ed25519Seed::fromSpan(gsl::span(
227  reinterpret_cast<const uint8_t *>(contents.data()), // NOLINT
228  ED25519_SEED_LENGTH)));
229  seed = _seed;
230  } else if (2 * ED25519_SEED_LENGTH == contents.size()) { // hex-encoded
231  OUTCOME_TRY(_seed, Ed25519Seed::fromHexWithPrefix(contents));
232  seed = _seed;
233  } else {
235  }
236  OUTCOME_TRY(kp, ed_suite_->generateKeypair(seed));
237 
239  .insert(kp.public_key, kp.secret_key);
240  return ed25519KeyToLibp2pKeypair(kp);
241  }
242 
243  libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(const Ed25519Keypair &kp) {
244  const auto &secret_key = kp.secret_key;
245  const auto &public_key = kp.public_key;
246  libp2p::crypto::PublicKey lp2p_public{
247  {libp2p::crypto::Key::Type::Ed25519,
248  std::vector<uint8_t>{public_key.cbegin(), public_key.cend()}}};
249  libp2p::crypto::PrivateKey lp2p_private{
250  {libp2p::crypto::Key::Type::Ed25519,
251  std::vector<uint8_t>{secret_key.cbegin(), secret_key.cend()}}};
252  return libp2p::crypto::KeyPair{
253  .publicKey = lp2p_public,
254  .privateKey = lp2p_private,
255  };
256  }
257 } // namespace kagome::crypto
outcome::result< Ed25519Keypair > findEd25519Keypair(KeyTypeId key_type, const Ed25519PublicKey &pk) const override
searches for key pair
outcome::result< EcdsaKeypair > generateEcdsaKeypair(KeyTypeId key_type, std::string_view mnemonic_phrase) override
generates ecdsa keypair and stores it in memory
outcome::result< Ed25519Keypair > generateEd25519KeypairOnDisk(KeyTypeId key_type) override
generates Ed25519 keypair and stores it on disk
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::optional< libp2p::crypto::KeyPair > getLibp2pKeypair() const override
outcome::result< Sr25519Keys > getSr25519PublicKeys(KeyTypeId key_type) const override
searches for SR25519 keys of specified type
OUTCOME_CPP_DEFINE_CATEGORY(kagome::crypto, CryptoStoreError, e)
std::shared_ptr< KeyFileStorage > file_storage_
outcome::result< EcdsaKeypair > generateEcdsaKeypairOnDisk(KeyTypeId key_type) override
generates ecdsa keypair and stores it on disk
std::shared_ptr< Ed25519Suite > ed_suite_
std::unordered_map< KeyTypeId, KeyCache< Ed25519Suite > > ed_caches_
std::shared_ptr< EcdsaSuite > ecdsa_suite_
outcome::result< EcdsaKeypair > findEcdsaKeypair(KeyTypeId key_type, const EcdsaPublicKey &pk) const override
searches for key pair
outcome::result< Sr25519Keypair > findSr25519Keypair(KeyTypeId key_type, const Sr25519PublicKey &pk) const override
searches for key pair
outcome::result< Ed25519Keys > getEd25519PublicKeys(KeyTypeId key_type) const override
searches for Ed25519 keys of specified type
libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(const Ed25519Keypair &kp)
uint32_t KeyTypeId
Key type identifier.
Definition: key_type.hpp:21
common::Blob< constants::kGeneralPublicKeySize > PublicKey
gsl::span< const uint8_t > make_span(const rocksdb::Slice &s)
CryptoStoreImpl(std::shared_ptr< EcdsaSuite > ecdsa_suite, std::shared_ptr< Ed25519Suite > ed_suite, std::shared_ptr< Sr25519Suite > sr_suite, std::shared_ptr< Bip39Provider > bip39_provider, std::shared_ptr< KeyFileStorage > key_fs)
KeyCache< Suite > & getCache(std::shared_ptr< Suite > suite, std::unordered_map< KeyTypeId, KeyCache< Suite >> &caches, KeyTypeId type) const
std::shared_ptr< Sr25519Suite > sr_suite_
outcome::result< Sr25519Keypair > generateSr25519KeypairOnDisk(KeyTypeId key_type) override
generates SR25519 keypair and stores it on disk
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
std::unordered_map< KeyTypeId, KeyCache< EcdsaSuite > > ecdsa_caches_
outcome::result< EcdsaKeys > getEcdsaPublicKeys(KeyTypeId key_type) const override
searches for ecdsa keys of specified type
outcome::result< Sr25519Keypair > generateSr25519Keypair(KeyTypeId key_type, std::string_view mnemonic_phrase) override
generates SR25519 keypair and stores it in memory
outcome::result< Ed25519Keypair > generateEd25519Keypair(KeyTypeId key_type, std::string_view mnemonic_phrase) override
generates Ed25519 keypair and stores it in memory
outcome::result< libp2p::crypto::KeyPair > loadLibp2pKeypair(const Path &key_path) const override
static constexpr size_t size()
Definition: blob.hpp:146
std::shared_ptr< Bip39Provider > bip39_provider_
Logger createLogger(const std::string &tag)
Definition: logger.cpp:112