Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

generate phrase #2370

Merged
merged 6 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/crypto/bip39/bip39_provider.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace kagome::crypto {
public:
virtual ~Bip39Provider() = default;

virtual std::string generatePhrase() const = 0;

/**
* @brief calculates entropy from mnemonic
* @param correct mnemonic word list
Expand Down
14 changes: 14 additions & 0 deletions core/crypto/bip39/const.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Copyright Quadrivium LLC
* All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <cstddef>

namespace kagome::crypto::bip39 {
constexpr size_t kWordBits = 11;
constexpr size_t kDictionaryWords = 1 << kWordBits;
} // namespace kagome::crypto::bip39
35 changes: 35 additions & 0 deletions core/crypto/bip39/impl/bip39_provider_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include "crypto/bip39/entropy_accumulator.hpp"
#include "crypto/bip39/mnemonic.hpp"
#include "crypto/bip39/wordlist/english.hpp"
#include "crypto/sha/sha256.hpp"

namespace kagome::crypto {

Expand All @@ -30,13 +32,46 @@ namespace kagome::crypto {

Bip39ProviderImpl::Bip39ProviderImpl(
std::shared_ptr<Pbkdf2Provider> pbkdf2_provider,
std::shared_ptr<CSPRNG> csprng,
std::shared_ptr<Hasher> hasher)
: pbkdf2_provider_{std::move(pbkdf2_provider)},
csprng_{std::move(csprng)},
hasher_{std::move(hasher)},
logger_{log::createLogger("Bip39Provider", "bip39")} {
dictionary_.initialize();
}

// https://github.com/rust-bitcoin/rust-bip39/blob/b100bf3e22891498cb6e0b1c53fd629dab7b34de/src/lib.rs#L267
// https://github.com/rust-bitcoin/rust-bip39/blob/b100bf3e22891498cb6e0b1c53fd629dab7b34de/src/lib.rs#L204
std::string Bip39ProviderImpl::generatePhrase() const {
size_t n_words = 12;
size_t n_check_bits = 4;
auto n_bytes = (n_words / 3) * 4;
SecureBuffer<> bytes(n_bytes);
csprng_->fillRandomly(bytes);
auto check = sha256(bytes);
std::vector<bool> bits((n_bytes * 8) + n_check_bits);
for (size_t i = 0; i < n_bytes; ++i) {
for (size_t j = 0; j < 8; ++j) {
bits[(i * 8) + j] = (bytes[i] & (1 << (7 - j))) > 0;
}
}
for (size_t i = 0; i < n_bytes / 4; ++i) {
bits[(8 * n_bytes) + i] = (check.at(i / 8) & (1 << (7 - (i % 8)))) > 0;
}
std::vector<std::string> words;
for (size_t i = 0; i < n_words; ++i) {
size_t idx = 0;
for (size_t j = 0; j < 11; ++j) {
if (bits[(i * 11) + j]) {
idx += 1 << (10 - j);
}
}
words.emplace_back(bip39::english::dictionary.at(idx));
}
return fmt::format("{}", fmt::join(words, " "));
}

outcome::result<std::vector<uint8_t>> Bip39ProviderImpl::calculateEntropy(
const std::vector<std::string> &word_list) const {
// make entropy accumulator
Expand Down
5 changes: 5 additions & 0 deletions core/crypto/bip39/impl/bip39_provider_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "crypto/bip39/dictionary.hpp"
#include "crypto/hasher.hpp"
#include "crypto/pbkdf2/pbkdf2_provider.hpp"
#include "crypto/random_generator.hpp"
#include "log/logger.hpp"

namespace kagome::crypto {
Expand All @@ -19,8 +20,11 @@ namespace kagome::crypto {
~Bip39ProviderImpl() override = default;

explicit Bip39ProviderImpl(std::shared_ptr<Pbkdf2Provider> pbkdf2_provider,
std::shared_ptr<CSPRNG> csprng,
std::shared_ptr<Hasher> hasher);

std::string generatePhrase() const override;

outcome::result<std::vector<uint8_t>> calculateEntropy(
const std::vector<std::string> &word_list) const override;

Expand All @@ -32,6 +36,7 @@ namespace kagome::crypto {

private:
std::shared_ptr<Pbkdf2Provider> pbkdf2_provider_;
std::shared_ptr<CSPRNG> csprng_;
std::shared_ptr<Hasher> hasher_;
bip39::Dictionary dictionary_;
log::Logger logger_;
Expand Down
4 changes: 3 additions & 1 deletion core/crypto/bip39/wordlist/english.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
#include <array>
#include <string_view>

#include "crypto/bip39/const.hpp"

namespace kagome::crypto::bip39::english {
/// @brief words are taken from
/// https://github.com/bitcoin/bips/blob/master/bip-0039/bip-0039-wordlists.md
constexpr std::array<std::string_view, 2048> dictionary = {
constexpr std::array<std::string_view, kDictionaryWords> dictionary = {
"abandon", "ability", "able", "about", "above", "absent",
"absorb", "abstract", "absurd", "abuse", "access", "accident",
"account", "accuse", "achieve", "acid", "acoustic", "acquire",
Expand Down
1 change: 0 additions & 1 deletion core/crypto/key_store.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include "crypto/sr25519_provider.hpp"
#include "filesystem/common.hpp"
#include "log/logger.hpp"
#include "utils/json_unquote.hpp"
#include "utils/read_file.hpp"

namespace kagome::crypto {
Expand Down
16 changes: 7 additions & 9 deletions core/crypto/key_store/key_file_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "crypto/key_store/key_file_storage.hpp"

#include "common/hexutil.hpp"
#include "common/visitor.hpp"
#include "crypto/key_store/key_type.hpp"
#include "filesystem/common.hpp"
#include "utils/json_unquote.hpp"
Expand Down Expand Up @@ -66,13 +67,17 @@ namespace kagome::crypto {
outcome::result<void> KeyFileStorage::saveKeyPair(
KeyType type,
common::BufferView public_key,
common::BufferView seed) const {
PhraseOrSeed phrase_or_seed) const {
auto &&path = composeKeyPath(type, public_key);
OUTCOME_TRY(saveKeyHexAtPath(seed, path));
SL_TRACE(logger_,
"Saving keypair (public: {}) to {}",
common::hex_lower(public_key),
path.native());
auto text = visit_in_place(
phrase_or_seed,
[](std::string_view phrase) { return jsonQuote(phrase); },
[](BufferView seed) { return common::hex_lower_0x(seed); });
OUTCOME_TRY(writeFile(path, text));
return outcome::success();
}

Expand All @@ -81,13 +86,6 @@ namespace kagome::crypto {
return outcome::success();
}

outcome::result<void> KeyFileStorage::saveKeyHexAtPath(
common::BufferView private_key, const KeyFileStorage::Path &path) const {
OUTCOME_TRY(writeFile(path, common::hex_lower_0x(private_key)));
SL_TRACE(logger_, "Saving key to {}", path.native());
return outcome::success();
}

outcome::result<bool> KeyFileStorage::searchForKey(
KeyType type, common::BufferView public_key_bytes) const {
auto key_path = composeKeyPath(type, public_key_bytes);
Expand Down
13 changes: 2 additions & 11 deletions core/crypto/key_store/key_file_storage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,14 @@ namespace kagome::crypto {
outcome::result<bool> searchForKey(KeyType type,
common::BufferView public_key) const;

using PhraseOrSeed = std::variant<std::string_view, BufferView>;
/**
* Stores the \param seed that generates the \param public_key to the key
* storage
*/
outcome::result<void> saveKeyPair(KeyType type,
common::BufferView public_key,
common::BufferView seed) const;

/**
* Save key as hex to the specific path.
* Used when --node-key-file flag is specified.
* @param key_bytes - key contents to save
* @param file_path - user-provided path to create the file
* @return an error if any
*/
outcome::result<void> saveKeyHexAtPath(common::BufferView private_key,
const Path &path) const;
PhraseOrSeed phrase_or_seed) const;

private:
explicit KeyFileStorage(Path keystore_path);
Expand Down
1 change: 1 addition & 0 deletions core/crypto/key_store/key_store_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "common/bytestr.hpp"
#include "common/visitor.hpp"
#include "crypto/key_store.hpp"
#include "utils/json_unquote.hpp"
#include "utils/read_file.hpp"

OUTCOME_CPP_DEFINE_CATEGORY(kagome::crypto, KeyStoreError, e) {
Expand Down
10 changes: 3 additions & 7 deletions core/crypto/key_store/key_store_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,9 @@ namespace kagome::crypto {
}

outcome::result<Keypair> generateKeypairOnDisk(KeyType key_type) override {
SecureBuffer<> seed_buf(Seed::size());
csprng_->fillRandomly(seed_buf);
OUTCOME_TRY(seed, Seed::from(std::move(seed_buf)));
OUTCOME_TRY(kp, suite_->generateKeypair(seed, {}));
keys_[key_type].insert(std::pair{kp.public_key, kp});
OUTCOME_TRY(file_storage_->saveKeyPair(
key_type, kp.public_key, seed.unsafeBytes()));
auto phrase = bip39_provider_->generatePhrase();
OUTCOME_TRY(kp, generateKeypair(key_type, phrase));
OUTCOME_TRY(file_storage_->saveKeyPair(key_type, kp.public_key, phrase));
return kp;
}

Expand Down
8 changes: 8 additions & 0 deletions core/utils/json_unquote.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace rapidjson {
} // namespace rapidjson

#include <rapidjson/reader.h>
#include <rapidjson/writer.h>

namespace kagome {

Expand All @@ -44,4 +45,11 @@ namespace kagome {
}
return std::nullopt;
}

inline std::string jsonQuote(std::string_view s) {
rapidjson::StringBuffer stream;
rapidjson::Writer writer{stream};
writer.String(s.data(), s.size());
return std::string{stream.GetString(), stream.GetSize()};
}
} // namespace kagome
2 changes: 1 addition & 1 deletion test/core/crypto/bip39/bip39_integration_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ struct Bip39IntegrationTest : public ::testing::TestWithParam<TestItem> {
auto pbkdf2_provider = std::make_shared<Pbkdf2ProviderImpl>();
auto hasher = std::make_shared<HasherImpl>();
bip39_provider =
std::make_shared<Bip39ProviderImpl>(pbkdf2_provider, hasher);
std::make_shared<Bip39ProviderImpl>(pbkdf2_provider, nullptr, hasher);
}

std::shared_ptr<Bip39Provider> bip39_provider;
Expand Down
2 changes: 1 addition & 1 deletion test/core/crypto/bip39/entropy_calculation_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ struct Bip39EntropyTest : public ::testing::Test {
auto pbkdf2_provider = std::make_shared<Pbkdf2ProviderImpl>();
auto hasher = std::make_shared<HasherImpl>();
bip39_provider =
std::make_shared<Bip39ProviderImpl>(pbkdf2_provider, hasher);
std::make_shared<Bip39ProviderImpl>(pbkdf2_provider, nullptr, hasher);
phrase =
"legal winner thank year wave sausage worth useful legal winner "
"thank yellow";
Expand Down
1 change: 1 addition & 0 deletions test/core/crypto/ecdsa/ecdsa_provider_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ TEST_F(EcdsaProviderTest, VerifyWrongKeyFail) {
TEST_F(EcdsaProviderTest, Junctions) {
Bip39ProviderImpl bip_provider{
std::make_shared<Pbkdf2ProviderImpl>(),
nullptr,
hasher,
};
auto f = [&](std::string_view phrase, std::string_view pub_str) {
Expand Down
1 change: 1 addition & 0 deletions test/core/crypto/ed25519/ed25519_provider_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ TEST_F(Ed25519ProviderTest, GenerateBySeedSuccess) {
TEST_F(Ed25519ProviderTest, Junctions) {
Bip39ProviderImpl bip_provider{
std::make_shared<Pbkdf2ProviderImpl>(),
nullptr,
hasher,
};
auto f = [&](std::string_view phrase, std::string_view pub_str) {
Expand Down
4 changes: 2 additions & 2 deletions test/core/crypto/key_store/key_store_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ struct KeyStoreTest : public test::BaseFS_Test {
std::make_shared<BandersnatchProviderImpl>(hasher);

auto pbkdf2_provider = std::make_shared<Pbkdf2ProviderImpl>();
bip39_provider =
std::make_shared<Bip39ProviderImpl>(std::move(pbkdf2_provider), hasher);
bip39_provider = std::make_shared<Bip39ProviderImpl>(
std::move(pbkdf2_provider), csprng, hasher);

std::shared_ptr key_file_storage =
kagome::crypto::KeyFileStorage::createAt(crypto_store_test_directory)
Expand Down
1 change: 1 addition & 0 deletions test/core/crypto/sr25519/sr25519_provider_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ TEST_F(Sr25519ProviderTest, GenerateBySeedSuccess) {
TEST_F(Sr25519ProviderTest, Junctions) {
Bip39ProviderImpl bip_provider{
std::make_shared<Pbkdf2ProviderImpl>(),
nullptr,
std::make_shared<HasherImpl>(),
};
auto f = [&](std::string_view phrase, std::string_view pub_str) {
Expand Down
4 changes: 2 additions & 2 deletions test/core/parachain/assignments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ struct AssignmentsTest : public test::BaseFS_Test {
std::make_shared<BandersnatchProviderImpl>(hasher);

auto pbkdf2_provider = std::make_shared<Pbkdf2ProviderImpl>();
auto bip39_provider =
std::make_shared<Bip39ProviderImpl>(std::move(pbkdf2_provider), hasher);
auto bip39_provider = std::make_shared<Bip39ProviderImpl>(
std::move(pbkdf2_provider), nullptr, hasher);

auto keystore_path = kagome::filesystem::path(__FILE__).parent_path()
/ "subkey_keys" / "keystore";
Expand Down
4 changes: 2 additions & 2 deletions test/core/runtime/runtime_test_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ class RuntimeTestBaseImpl {
auto secp256k1_provider = std::make_shared<crypto::Secp256k1ProviderImpl>();
auto elliptic_curves = std::make_shared<crypto::EllipticCurvesImpl>();
auto pbkdf2_provider = std::make_shared<crypto::Pbkdf2ProviderImpl>();
auto bip39_provider =
std::make_shared<crypto::Bip39ProviderImpl>(pbkdf2_provider, hasher_);
auto bip39_provider = std::make_shared<crypto::Bip39ProviderImpl>(
pbkdf2_provider, nullptr, hasher_);
auto keystore_path =
filesystem::temp_directory_path() / filesystem::unique_path();
std::shared_ptr key_file_storage =
Expand Down
Loading