diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c201af..bc36034 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,6 +106,13 @@ message(STATUS "libzbar: libraries at ${ZBAR_LIBRARIES}") # Tevador 14 word Monero seed add_subdirectory(contrib/monero-seed) +# Polyseed 16 word mnemonic seeds +find_path(POLYSEED_INCLUDE_DIR polyseed.h) +message(STATUS "POLYSEED PATH ${POLYSEED_INCLUDE_DIR}") + +find_library(POLYSEED_LIBRARY polyseed) +message(STATUS "POLYSEED LIBARY ${POLYSEED_LIBRARY}") + # libzip find_package(zlib CONFIG) find_path(LIBZIP_INCLUDE_DIRS zip.h) diff --git a/Dockerfile.linux b/Dockerfile.linux index 5faac8b..ceaee7f 100644 --- a/Dockerfile.linux +++ b/Dockerfile.linux @@ -306,4 +306,16 @@ RUN git clone -b stable-0.21 --recursive https://github.com/mchehab/zbar.git && ./configure --enable-static --disable-shared --without-imagemagick --with-gtk=no --with-python=no --enable-doc=no && \ make -j$THREADS && \ make install && \ + rm -rf $(pwd) + +# polyseed: Required for Feather +RUN git clone https://github.com/tevador/polyseed.git && \ + cd polyseed && \ + git reset --hard 4945d8239d6b26dc12723ca2aaa9f8110ceff5af && \ + mkdir build && \ + cd build && \ + cmake .. && \ + make && \ + make install && \ + rm /usr/local/lib/libpolyseed.so* && \ rm -rf $(pwd) \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3311867..d453f93 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,6 +60,9 @@ file(GLOB SOURCE_FILES "qrcode/*.cpp" "dialog/*.h" "dialog/*.cpp" + "polyseed/*.h" + "polyseed/*.cpp" + "polyseed/*.c" "qrcode_scanner/QrCodeUtils.cpp" "qrcode_scanner/QrCodeUtils.h" ) @@ -137,6 +140,7 @@ target_include_directories(feather PUBLIC ${ZLIB_INCLUDE_DIRS} ${LIBZIP_INCLUDE_DIRS} ${ZBAR_INCLUDE_DIR} + ${POLYSEED_INCLUDE_DIR} ) if(WITH_SCANNER) @@ -252,6 +256,7 @@ target_link_libraries(feather ${ZLIB_LIBRARIES} ${LIBZIP_LIBRARIES} ${ZBAR_LIBRARIES} + ${POLYSEED_LIBRARY} SingleApplication::SingleApplication ) diff --git a/src/WindowManager.cpp b/src/WindowManager.cpp index 3cede76..072f54a 100644 --- a/src/WindowManager.cpp +++ b/src/WindowManager.cpp @@ -264,12 +264,12 @@ void WindowManager::tryCreateWallet(Seed seed, const QString &path, const QStrin } Wallet *wallet = nullptr; - if (seed.type == Seed::Type::TEVADOR) { + if (seed.type == Seed::Type::POLYSEED || seed.type == Seed::Type::TEVADOR) { wallet = m_walletManager->createDeterministicWalletFromSpendKey(path, password, seed.language, constants::networkType, seed.spendKey, seed.restoreHeight, constants::kdfRounds, seedOffset); wallet->setCacheAttribute("feather.seed", seed.mnemonic.join(" ")); wallet->setCacheAttribute("feather.seedoffset", seedOffset); } - if (seed.type == Seed::Type::MONERO) { + else if (seed.type == Seed::Type::MONERO) { wallet = m_walletManager->recoveryWallet(path, password, seed.mnemonic.join(" "), seedOffset, constants::networkType, seed.restoreHeight, constants::kdfRounds); } diff --git a/src/polyseed/pbkdf2.c b/src/polyseed/pbkdf2.c new file mode 100644 index 0000000..f212e10 --- /dev/null +++ b/src/polyseed/pbkdf2.c @@ -0,0 +1,85 @@ +/* + * Copyright 2005,2007,2009 Colin Percival + * Copyright 2021 tevador + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +#include + +static inline void +store32_be(uint8_t dst[4], uint32_t w) +{ + dst[3] = (uint8_t) w; w >>= 8; + dst[2] = (uint8_t) w; w >>= 8; + dst[1] = (uint8_t) w; w >>= 8; + dst[0] = (uint8_t) w; +} + +void +crypto_pbkdf2_sha256(const uint8_t* passwd, size_t passwdlen, + const uint8_t* salt, size_t saltlen, uint64_t c, + uint8_t* buf, size_t dkLen) +{ + crypto_auth_hmacsha256_state Phctx, PShctx, hctx; + size_t i; + uint8_t ivec[4]; + uint8_t U[32]; + uint8_t T[32]; + uint64_t j; + int k; + size_t clen; + + crypto_auth_hmacsha256_init(&Phctx, passwd, passwdlen); + PShctx = Phctx; + crypto_auth_hmacsha256_update(&PShctx, salt, saltlen); + + for (i = 0; i * 32 < dkLen; i++) { + store32_be(ivec, (uint32_t)(i + 1)); + hctx = PShctx; + crypto_auth_hmacsha256_update(&hctx, ivec, 4); + crypto_auth_hmacsha256_final(&hctx, U); + + memcpy(T, U, 32); + for (j = 2; j <= c; j++) { + hctx = Phctx; + crypto_auth_hmacsha256_update(&hctx, U, 32); + crypto_auth_hmacsha256_final(&hctx, U); + + for (k = 0; k < 32; k++) { + T[k] ^= U[k]; + } + } + + clen = dkLen - i * 32; + if (clen > 32) { + clen = 32; + } + memcpy(&buf[i * 32], T, clen); + } + sodium_memzero((void*)&Phctx, sizeof Phctx); + sodium_memzero((void*)&PShctx, sizeof PShctx); +} \ No newline at end of file diff --git a/src/polyseed/pbkdf2.h b/src/polyseed/pbkdf2.h new file mode 100644 index 0000000..f007240 --- /dev/null +++ b/src/polyseed/pbkdf2.h @@ -0,0 +1,46 @@ +/* + * Copyright 2021 tevador + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef PBKDF2_H +#define PBKDF2_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void +crypto_pbkdf2_sha256(const uint8_t* passwd, size_t passwdlen, + const uint8_t* salt, size_t saltlen, uint64_t c, + uint8_t* buf, size_t dkLen); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/polyseed/polyseed.cpp b/src/polyseed/polyseed.cpp new file mode 100644 index 0000000..061fb97 --- /dev/null +++ b/src/polyseed/polyseed.cpp @@ -0,0 +1,161 @@ +/* + * Copyright 2021 tevador + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "polyseed.h" +#include "pbkdf2.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace polyseed { + + static std::locale locale; + + static size_t utf8_nfc(const char* str, polyseed_str norm) { + auto s = boost::locale::normalize(str, boost::locale::norm_type::norm_nfc, locale); + size_t size = std::min(s.size(), (size_t)POLYSEED_STR_SIZE - 1); + s.copy(norm, size); + norm[size] = '\0'; + sodium_memzero(&s[0], s.size()); + return size; + } + + static size_t utf8_nfkd(const char* str, polyseed_str norm) { + auto s = boost::locale::normalize(str, boost::locale::norm_type::norm_nfkd, locale); + size_t size = std::min(s.size(), (size_t)POLYSEED_STR_SIZE - 1); + s.copy(norm, size); + norm[size] = '\0'; + sodium_memzero(&s[0], s.size()); + return size; + } + + struct dependency { + dependency(); + std::vector languages; + }; + + static dependency deps; + + dependency::dependency() { + if (sodium_init() == -1) { + throw std::runtime_error("sodium_init failed"); + } + + boost::locale::generator gen; + gen.locale_cache_enabled(true); + locale = gen(""); + + polyseed_dependency pd; + pd.randbytes = &randombytes_buf; + pd.pbkdf2_sha256 = &crypto_pbkdf2_sha256; + pd.memzero = &sodium_memzero; + pd.u8_nfc = &utf8_nfc; + pd.u8_nfkd = &utf8_nfkd; + pd.time = nullptr; + pd.alloc = nullptr; + pd.free = nullptr; + + polyseed_inject(&pd); + + for (int i = 0; i < polyseed_get_num_langs(); ++i) { + languages.push_back(language(polyseed_get_lang(i))); + } + } + + static language invalid_lang; + + const std::vector& get_langs() { + return deps.languages; + } + + const language& get_lang_by_name(const std::string& name) { + for (auto& lang : deps.languages) { + if (name == lang.name_en()) { + return lang; + } + if (name == lang.name()) { + return lang; + } + } + return invalid_lang; + } + + inline void data::check_init() const { + if (valid()) { + throw std::runtime_error("already initialized"); + } + } + + static std::array error_desc = { + "Success", + "Wrong number of words in the phrase", + "Unknown language or unsupported words", + "Checksum mismatch", + "Unsupported seed features", + "Invalid seed format", + "Memory allocation failure", + }; + + static error get_error(polyseed_status status) { + if (status > 0 && status < sizeof(error_desc) / sizeof(const char*)) { + return error(error_desc[(int)status], status); + } + return error("Unknown error", status); + } + + void data::create(feature_type features) { + check_init(); + auto status = polyseed_create(features, &m_data); + if (status != POLYSEED_OK) { + throw get_error(status); + } + } + + void data::load(polyseed_storage storage) { + check_init(); + auto status = polyseed_load(storage, &m_data); + if (status != POLYSEED_OK) { + throw get_error(status); + } + } + + language data::decode(const char* phrase) { + check_init(); + const polyseed_lang* lang; + auto status = polyseed_decode(phrase, m_coin, &lang, &m_data); + if (status != POLYSEED_OK) { + throw get_error(status); + } + return language(lang); + } +} \ No newline at end of file diff --git a/src/polyseed/polyseed.h b/src/polyseed/polyseed.h new file mode 100644 index 0000000..0faca2e --- /dev/null +++ b/src/polyseed/polyseed.h @@ -0,0 +1,147 @@ +/* + * Copyright 2021 tevador + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include + +namespace polyseed { + + class data; + + class language { + public: + language() : m_lang(nullptr) {} + language(const language&) = default; + language(const polyseed_lang* lang) : m_lang(lang) {} + const char* name() const { + return polyseed_get_lang_name(m_lang); + } + const char* name_en() const { + return polyseed_get_lang_name_en(m_lang); + } + bool valid() const { + return m_lang != nullptr; + } + private: + const polyseed_lang* m_lang; + + friend class data; + }; + + const std::vector& get_langs(); + const language& get_lang_by_name(const std::string& name); + + class error : public std::runtime_error { + public: + error(const char* msg, polyseed_status status) + : std::runtime_error(msg), m_status(status) + { + } + polyseed_status status() const { + return m_status; + } + private: + polyseed_status m_status; + }; + + using feature_type = unsigned int; + + inline int enable_features(feature_type features) { + return polyseed_enable_features(features); + } + + class data { + public: + data(const data&) = delete; + data(polyseed_coin coin) : m_data(nullptr), m_coin(coin) {} + ~data() { + polyseed_free(m_data); + } + + void create(feature_type features); + + void load(polyseed_storage storage); + + language decode(const char* phrase); + + template + void encode(const language& lang, str_type& str) const { + check_valid(); + if (!lang.valid()) { + throw std::runtime_error("invalid language"); + } + str.resize(POLYSEED_STR_SIZE); + auto size = polyseed_encode(m_data, lang.m_lang, m_coin, &str[0]); + str.resize(size); + } + + void save(polyseed_storage storage) const { + check_valid(); + polyseed_store(m_data, storage); + } + + void crypt(const char* password) { + check_valid(); + polyseed_crypt(m_data, password); + } + + void keygen(void* ptr, size_t key_size) const { + check_valid(); + polyseed_keygen(m_data, m_coin, key_size, (uint8_t*)ptr); + } + + bool valid() const { + return m_data != nullptr; + } + + bool encrypted() const { + check_valid(); + return polyseed_is_encrypted(m_data); + } + + uint64_t birthday() const { + check_valid(); + return polyseed_get_birthday(m_data); + } + + bool has_feature(feature_type feature) const { + check_valid(); + return polyseed_get_feature(m_data, feature) != 0; + } + private: + void check_valid() const { + if (m_data == nullptr) { + throw std::runtime_error("invalid object"); + } + } + void check_init() const; + + polyseed_data* m_data; + polyseed_coin m_coin; + }; +} \ No newline at end of file diff --git a/src/utils/Seed.cpp b/src/utils/Seed.cpp index 236c419..6013adc 100644 --- a/src/utils/Seed.cpp +++ b/src/utils/Seed.cpp @@ -1,13 +1,14 @@ // SPDX-License-Identifier: BSD-3-Clause // SPDX-FileCopyrightText: 2020-2022 The Monero Project +#include #include "Seed.h" Seed::Seed(Type type, NetworkType::Type networkType, QString language) : type(type), networkType(networkType), language(std::move(language)) { - // We only support the creation of Tevador-style seeds for now. - if (this->type != Type::TEVADOR) { + // We only support the creation of Polyseeds + if (this->type != Type::POLYSEED) { this->errorString = "Unsupported seed type"; return; } @@ -21,15 +22,22 @@ Seed::Seed(Type type, NetworkType::Type networkType, QString language) this->time = std::time(nullptr); try { - monero_seed seed(this->time, constants::coinName); + polyseed::data seed(POLYSEED_MONERO); + seed.create(0); - std::stringstream buffer; - buffer << seed; - this->mnemonic = QString::fromStdString(buffer.str()).split(" "); + uint8_t key[32]; + seed.keygen(&key, sizeof(key)); - buffer.str(std::string()); - buffer << seed.key(); - this->spendKey = QString::fromStdString(buffer.str()); + 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()); } catch (const std::exception &e) { this->errorString = QString::fromStdString(e.what()); @@ -54,8 +62,26 @@ Seed::Seed(Type type, QStringList mnemonic, NetworkType::Type networkType) } if (this->type == Type::POLYSEED) { - this->errorString = "Unsupported seed type"; - return; + 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(); + } + catch (const std::exception &e) { + this->errorString = e.what(); + return; + } } if (this->type == Type::TEVADOR) { diff --git a/src/utils/Seed.h b/src/utils/Seed.h index 5318a66..1989068 100644 --- a/src/utils/Seed.h +++ b/src/utils/Seed.h @@ -7,6 +7,7 @@ #include "constants.h" #include "libwalletqt/Wallet.h" #include "monero_seed/monero_seed.hpp" +#include "polyseed/polyseed.h" #include "utils/AppData.h" #include diff --git a/src/wizard/PageWalletRestoreSeed.cpp b/src/wizard/PageWalletRestoreSeed.cpp index 27fc351..ab9eddf 100644 --- a/src/wizard/PageWalletRestoreSeed.cpp +++ b/src/wizard/PageWalletRestoreSeed.cpp @@ -41,6 +41,9 @@ PageWalletRestoreSeed::PageWalletRestoreSeed(WizardFields *fields, QWidget *pare // (illegible word with a known location). This can be tested by replacing a word with xxxx bip39English << "xxxx"; + m_polyseed.length = 16; + m_polyseed.setWords(bip39English); + m_tevador.length = 14; m_tevador.setWords(bip39English); @@ -58,6 +61,12 @@ PageWalletRestoreSeed::PageWalletRestoreSeed(WizardFields *fields, QWidget *pare } void PageWalletRestoreSeed::onSeedTypeToggled() { + if (ui->radio16->isChecked()) { + m_mode = &m_polyseed; + m_fields->seedType = Seed::Type::POLYSEED; + ui->seedEdit->setPlaceholderText("Enter 16 word seed.."); + ui->group_seedLanguage->hide(); + } if (ui->radio14->isChecked()) { m_mode = &m_tevador; m_fields->seedType = Seed::Type::TEVADOR; @@ -128,7 +137,7 @@ bool PageWalletRestoreSeed::validatePage() { } } - Seed _seed = Seed(m_mode->length == 14 ? Seed::Type::TEVADOR : Seed::Type::MONERO, seedSplit, constants::networkType); + Seed _seed = Seed(m_fields->seedType, seedSplit, constants::networkType); if (!_seed.errorString.isEmpty()) { QMessageBox::warning(this, "Invalid seed", QString("Invalid seed:\n\n%1").arg(_seed.errorString)); diff --git a/src/wizard/PageWalletRestoreSeed.h b/src/wizard/PageWalletRestoreSeed.h index eb909a3..0f448b8 100644 --- a/src/wizard/PageWalletRestoreSeed.h +++ b/src/wizard/PageWalletRestoreSeed.h @@ -54,6 +54,7 @@ private: Ui::PageWalletRestoreSeed *ui; WizardFields *m_fields; + seedType m_polyseed; seedType m_tevador; seedType m_legacy; diff --git a/src/wizard/PageWalletRestoreSeed.ui b/src/wizard/PageWalletRestoreSeed.ui index 3e62d38..2c9b226 100644 --- a/src/wizard/PageWalletRestoreSeed.ui +++ b/src/wizard/PageWalletRestoreSeed.ui @@ -25,6 +25,19 @@ 14 word mnemonic seed + + false + + + seedBtnGroup + + + + + + + 16 word mnemonic seed (Polyseed) + true diff --git a/src/wizard/PageWalletSeed.cpp b/src/wizard/PageWalletSeed.cpp index c718e20..7e238ff 100644 --- a/src/wizard/PageWalletSeed.cpp +++ b/src/wizard/PageWalletSeed.cpp @@ -20,13 +20,12 @@ PageWalletSeed::PageWalletSeed(WizardFields *fields, QWidget *parent) QPixmap warningIcon = QPixmap(":/assets/images/warning.png"); ui->warningIcon->setPixmap(warningIcon.scaledToWidth(32, Qt::SmoothTransformation)); + QPixmap infoIcon = QPixmap(":/assets/images/info2.svg"); + ui->newSeedWarningIcon->setPixmap(infoIcon.scaledToWidth(32, Qt::SmoothTransformation)); + QPixmap pixmap = QPixmap(":/assets/images/seed.png"); ui->seedIcon->setPixmap(pixmap.scaledToWidth(32, Qt::SmoothTransformation)); - ui->seedWord2->setHelpText("In addition to the private spend key, Tevador's 14 word seed scheme also encodes the " - "restore date, cryptocurrency type, and reserves a few bits for future use. " - "The second word is static because the reserved bits remain the same for each seed generation."); - connect(ui->btnRoulette, &QPushButton::clicked, [=]{ this->seedRoulette(0); }); @@ -55,11 +54,10 @@ void PageWalletSeed::seedRoulette(int count) { void PageWalletSeed::generateSeed() { QString mnemonic; - do { - m_seed = Seed(Seed::Type::TEVADOR); - mnemonic = m_seed.mnemonic.join(" "); - m_restoreHeight = m_seed.restoreHeight; - } while (mnemonic.split(" ").length() != 14); // https://github.com/tevador/monero-seed/issues/2 + + m_seed = Seed(Seed::Type::POLYSEED); + mnemonic = m_seed.mnemonic.join(" "); + m_restoreHeight = m_seed.restoreHeight; this->displaySeed(mnemonic); @@ -87,6 +85,8 @@ void PageWalletSeed::displaySeed(const QString &seed){ ui->seedWord12->setText(seedSplit[11]); ui->seedWord13->setText(seedSplit[12]); ui->seedWord14->setText(seedSplit[13]); + ui->seedWord15->setText(seedSplit[14]); + ui->seedWord16->setText(seedSplit[15]); } int PageWalletSeed::nextId() const { diff --git a/src/wizard/PageWalletSeed.ui b/src/wizard/PageWalletSeed.ui index f962d61..af3dff2 100644 --- a/src/wizard/PageWalletSeed.ui +++ b/src/wizard/PageWalletSeed.ui @@ -6,8 +6,8 @@ 0 0 - 877 - 625 + 654 + 594 @@ -57,7 +57,7 @@ - Store your 14-word wallet seed in a safe location. + <html><head/><body><p>Store your <span style=" font-weight:600;">16-word</span> seed in a safe location.</p></body></html> true @@ -79,6 +79,84 @@ + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + 0 + 0 + + + + icon + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + + <html><head/><body><p>Feather recently switched to a new seed scheme called <span style=" font-weight:600;">Polyseed</span>.</p></body></html> + + + true + + + + + + + Please take note that mnemonic seeds now consist of 16 words instead of 14. + + + true + + + + + + + For more information visit: docs.featherwallet.org/guides/seed-scheme + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + @@ -225,14 +303,14 @@ - + QFrame::StyledPanel QFrame::Raised - + 7 @@ -240,7 +318,7 @@ 7 - + 0 @@ -248,12 +326,12 @@ - 4. + 5. - + TextLabel @@ -263,14 +341,14 @@ - + QFrame::StyledPanel QFrame::Raised - + 7 @@ -278,7 +356,7 @@ 7 - + 0 @@ -286,50 +364,12 @@ - 7. + 9. - - - TextLabel - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 7 - - - 7 - - - - - - 0 - 0 - - - - 10. - - - - - + TextLabel @@ -409,7 +449,7 @@ - + TextLabel @@ -419,14 +459,14 @@ - + QFrame::StyledPanel QFrame::Raised - + 7 @@ -434,7 +474,7 @@ 7 - + 0 @@ -442,12 +482,12 @@ - 5. + 6. - + TextLabel @@ -457,14 +497,14 @@ - + QFrame::StyledPanel QFrame::Raised - + 7 @@ -472,7 +512,7 @@ 7 - + 0 @@ -480,50 +520,12 @@ - 8. + 10. - - - TextLabel - - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 7 - - - 7 - - - - - - 0 - 0 - - - - 11. - - - - - + TextLabel @@ -613,14 +615,14 @@ - + QFrame::StyledPanel QFrame::Raised - + 7 @@ -628,7 +630,7 @@ 7 - + 0 @@ -636,12 +638,12 @@ - 6. + 7. - + TextLabel @@ -651,14 +653,14 @@ - + QFrame::StyledPanel QFrame::Raised - + 7 @@ -666,7 +668,7 @@ 7 - + 0 @@ -674,12 +676,130 @@ - 9. + 11. - + + + TextLabel + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 7 + + + 7 + + + + + + 0 + 0 + + + + 15. + + + + + + + TextLabel + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 7 + + + 7 + + + + + + 0 + 0 + + + + 4. + + + + + + + TextLabel + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 7 + + + 7 + + + + + + 0 + 0 + + + + 8. + + + + + TextLabel @@ -727,10 +847,41 @@ - - - + + + QFrame::StyledPanel + + QFrame::Raised + + + + 7 + + + 7 + + + + + + 0 + 0 + + + + 16. + + + + + + + TextLabel + + + + @@ -792,13 +943,6 @@ - - - HelpLabel - QLabel -
components.h
-
-