feather/src/utils/Seed.cpp

141 lines
4.4 KiB
C++
Raw Normal View History

2022-02-25 15:29:33 +00:00
// SPDX-License-Identifier: BSD-3-Clause
2023-01-02 19:30:11 +00:00
// SPDX-FileCopyrightText: 2020-2023 The Monero Project
2022-02-25 15:29:33 +00:00
2022-05-23 21:43:33 +00:00
#include <iomanip>
2022-02-25 15:29:33 +00:00
#include "Seed.h"
2023-11-24 23:54:01 +00:00
Seed::Seed(Type type, NetworkType::Type networkType, QString language, const char* secret)
: type(type)
, networkType(networkType)
, language(std::move(language))
2022-02-25 15:29:33 +00:00
{
2022-05-23 21:43:33 +00:00
// We only support the creation of Polyseeds
if (this->type != Type::POLYSEED) {
2022-02-25 15:29:33 +00:00
this->errorString = "Unsupported seed type";
return;
}
// We only support the creation of English language seeds for now.
if (this->language != "English") {
this->errorString = "Unsupported seed language";
return;
}
this->time = std::time(nullptr);
try {
2022-05-23 21:43:33 +00:00
polyseed::data seed(POLYSEED_MONERO);
2023-11-24 23:54:01 +00:00
if (secret) {
seed.create_from_secret(0, secret);
} else {
seed.create(0);
}
2022-02-25 15:29:33 +00:00
2022-05-23 21:43:33 +00:00
uint8_t key[32];
seed.keygen(&key, sizeof(key));
2022-02-25 15:29:33 +00:00
2022-05-23 21:43:33 +00:00
std::stringstream keyStream;
for (unsigned char i : key) {
keyStream << std::hex << std::setfill('0') << std::setw(2) << (int)i;
}
std::string phrase;
seed.encode(polyseed::get_lang_by_name("English"), phrase);
this->mnemonic = QString::fromStdString(phrase).split(" ");
this->spendKey = QString::fromStdString(keyStream.str());
2022-02-25 15:29:33 +00:00
}
catch (const std::exception &e) {
this->errorString = QString::fromStdString(e.what());
return;
}
// Basic check against seed library implementation issues
if (m_insecureSeeds.contains(this->spendKey)) {
this->errorString = "Insecure spendkey";
return;
}
this->setRestoreHeight();
}
Seed::Seed(Type type, QStringList mnemonic, NetworkType::Type networkType)
: type(type), mnemonic(std::move(mnemonic)), networkType(networkType)
{
if (m_seedLength[this->type] != this->mnemonic.length()) {
this->errorString = "Invalid seed length";
return;
}
if (this->type == Type::POLYSEED) {
2022-05-23 21:43:33 +00:00
try {
polyseed::data seed(POLYSEED_MONERO);
auto lang = seed.decode(this->mnemonic.join(" ").toStdString().c_str());
uint8_t key[32];
seed.keygen(&key, sizeof(key));
std::stringstream keyStream;
for (unsigned char i : key) {
keyStream << std::hex << std::setfill('0') << std::setw(2) << (int)i;
}
this->spendKey = QString::fromStdString(keyStream.str());
this->time = seed.birthday();
this->setRestoreHeight();
this->encrypted = seed.encrypted();
2022-05-23 21:43:33 +00:00
}
catch (const std::exception &e) {
this->errorString = e.what();
return;
}
2022-02-25 15:29:33 +00:00
}
if (this->type == Type::TEVADOR) {
try {
monero_seed seed(this->mnemonic.join(" ").toStdString(), constants::coinName);
this->time = seed.date();
this->setRestoreHeight();
std::stringstream buffer;
buffer << seed.key();
this->spendKey = QString::fromStdString(buffer.str());
// Tevador style seeds have built-in error correction
// Any word can be replaced with 'xxxx' to recover the original word
this->correction = QString::fromStdString(seed.correction());
if (!this->correction.isEmpty()) {
buffer.str(std::string());
buffer << seed;
int index = this->mnemonic.indexOf("xxxx");
this->mnemonic.replace(index, this->correction);
}
}
catch (const std::exception &e) {
this->errorString = e.what();
return;
}
}
}
void Seed::setRestoreHeight(int height) {
auto now = std::time(nullptr);
auto nowClearance = 3600 * 24;
auto currentBlockHeight = appData()->restoreHeights[this->networkType]->dateToHeight(now - nowClearance);
if (height >= currentBlockHeight + nowClearance) {
qWarning() << "unrealistic restore height detected, setting to current blockheight instead: " << currentBlockHeight;
this->restoreHeight = currentBlockHeight;
} else {
this->restoreHeight = height;
}
}
void Seed::setRestoreHeight() {
// Ignore the embedded restore date, new wallets should sync from the current block height.
this->restoreHeight = appData()->restoreHeights[networkType]->dateToHeight(this->time);
}
Seed::Seed() = default;