Polyseed support

This commit is contained in:
tobtoht 2022-05-23 23:43:33 +02:00
parent 6f19c108ef
commit 08a0d8af62
No known key found for this signature in database
GPG key ID: 1CADD27F41F45C3C
15 changed files with 800 additions and 143 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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
)

View file

@ -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);
}

85
src/polyseed/pbkdf2.c Normal file
View file

@ -0,0 +1,85 @@
/*
* Copyright 2005,2007,2009 Colin Percival
* Copyright 2021 tevador <tevador@gmail.com>
* 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 <string.h>
#include <sodium/crypto_auth_hmacsha256.h>
#include <sodium/utils.h>
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);
}

46
src/polyseed/pbkdf2.h Normal file
View file

@ -0,0 +1,46 @@
/*
* Copyright 2021 tevador <tevador@gmail.com>
* 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 <stddef.h>
#include <stdint.h>
#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

161
src/polyseed/polyseed.cpp Normal file
View file

@ -0,0 +1,161 @@
/*
* Copyright 2021 tevador <tevador@gmail.com>
* 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 <sodium/core.h>
#include <sodium/utils.h>
#include <sodium/randombytes.h>
#include <boost/locale.hpp>
#include <cstdint>
#include <cstring>
#include <algorithm>
#include <array>
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<language> 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<language>& 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<const char*, 7> 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);
}
}

147
src/polyseed/polyseed.h Normal file
View file

@ -0,0 +1,147 @@
/*
* Copyright 2021 tevador <tevador@gmail.com>
* 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 <vector>
#include <stdexcept>
#include <string>
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<language>& 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<class str_type>
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;
};
}

View file

@ -1,13 +1,14 @@
// SPDX-License-Identifier: BSD-3-Clause
// SPDX-FileCopyrightText: 2020-2022 The Monero Project
#include <iomanip>
#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) {

View file

@ -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 <QString>

View file

@ -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));

View file

@ -54,6 +54,7 @@ private:
Ui::PageWalletRestoreSeed *ui;
WizardFields *m_fields;
seedType m_polyseed;
seedType m_tevador;
seedType m_legacy;

View file

@ -25,6 +25,19 @@
<property name="text">
<string>14 word mnemonic seed</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">seedBtnGroup</string>
</attribute>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radio16">
<property name="text">
<string>16 word mnemonic seed (Polyseed)</string>
</property>
<property name="checked">
<bool>true</bool>
</property>

View file

@ -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 {

View file

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>877</width>
<height>625</height>
<width>654</width>
<height>594</height>
</rect>
</property>
<property name="windowTitle">
@ -57,7 +57,7 @@
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Store your 14-word wallet seed in a safe location.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Store your &lt;span style=&quot; font-weight:600;&quot;&gt;16-word&lt;/span&gt; seed in a safe location.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@ -79,6 +79,84 @@
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_18">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_20">
<item>
<widget class="QLabel" name="newSeedWarningIcon">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>icon</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QLabel" name="label_14">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Feather recently switched to a new seed scheme called &lt;span style=&quot; font-weight:600;&quot;&gt;Polyseed&lt;/span&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_16">
<property name="text">
<string>Please take note that mnemonic seeds now consist of 16 words instead of 14.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_12">
<property name="text">
<string>For more information visit: docs.featherwallet.org/guides/seed-scheme</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_invalidSeed">
<property name="frameShape">
@ -225,14 +303,14 @@
</widget>
</item>
<item>
<widget class="QFrame" name="frame_13">
<widget class="QFrame" name="frame_3">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="topMargin">
<number>7</number>
</property>
@ -240,7 +318,7 @@
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_27">
<widget class="QLabel" name="label_7">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -248,12 +326,12 @@
</sizepolicy>
</property>
<property name="text">
<string>4.</string>
<string>5.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord4">
<widget class="QLabel" name="seedWord5">
<property name="text">
<string>TextLabel</string>
</property>
@ -263,14 +341,14 @@
</widget>
</item>
<item>
<widget class="QFrame" name="frame_11">
<widget class="QFrame" name="frame_5">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<layout class="QHBoxLayout" name="horizontalLayout_15">
<property name="topMargin">
<number>7</number>
</property>
@ -278,7 +356,7 @@
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_19">
<widget class="QLabel" name="label_29">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -286,50 +364,12 @@
</sizepolicy>
</property>
<property name="text">
<string>7.</string>
<string>9.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord7">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_8">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="topMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>10.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord10">
<widget class="QLabel" name="seedWord9">
<property name="text">
<string>TextLabel</string>
</property>
@ -409,7 +449,7 @@
</widget>
</item>
<item>
<widget class="HelpLabel" name="seedWord2">
<widget class="QLabel" name="seedWord2">
<property name="text">
<string>TextLabel</string>
</property>
@ -419,14 +459,14 @@
</widget>
</item>
<item>
<widget class="QFrame" name="frame_3">
<widget class="QFrame" name="frame_7">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="topMargin">
<number>7</number>
</property>
@ -434,7 +474,7 @@
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_7">
<widget class="QLabel" name="label_11">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -442,12 +482,12 @@
</sizepolicy>
</property>
<property name="text">
<string>5.</string>
<string>6.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord5">
<widget class="QLabel" name="seedWord6">
<property name="text">
<string>TextLabel</string>
</property>
@ -457,14 +497,14 @@
</widget>
</item>
<item>
<widget class="QFrame" name="frame_14">
<widget class="QFrame" name="frame_8">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<property name="topMargin">
<number>7</number>
</property>
@ -472,7 +512,7 @@
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_25">
<widget class="QLabel" name="label_13">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -480,50 +520,12 @@
</sizepolicy>
</property>
<property name="text">
<string>8.</string>
<string>10.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord8">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_12">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_10">
<property name="topMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_21">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>11.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord11">
<widget class="QLabel" name="seedWord10">
<property name="text">
<string>TextLabel</string>
</property>
@ -613,14 +615,14 @@
</widget>
</item>
<item>
<widget class="QFrame" name="frame_7">
<widget class="QFrame" name="frame_11">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<property name="topMargin">
<number>7</number>
</property>
@ -628,7 +630,7 @@
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_11">
<widget class="QLabel" name="label_19">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -636,12 +638,12 @@
</sizepolicy>
</property>
<property name="text">
<string>6.</string>
<string>7.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord6">
<widget class="QLabel" name="seedWord7">
<property name="text">
<string>TextLabel</string>
</property>
@ -651,14 +653,14 @@
</widget>
</item>
<item>
<widget class="QFrame" name="frame_5">
<widget class="QFrame" name="frame_12">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<property name="topMargin">
<number>7</number>
</property>
@ -666,7 +668,7 @@
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_29">
<widget class="QLabel" name="label_21">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -674,12 +676,130 @@
</sizepolicy>
</property>
<property name="text">
<string>9.</string>
<string>11.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord9">
<widget class="QLabel" name="seedWord11">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_16">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_18">
<property name="topMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>15.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord15">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QFrame" name="frame_13">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_11">
<property name="topMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_27">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>4.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord4">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_14">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<property name="topMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_25">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>8.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord8">
<property name="text">
<string>TextLabel</string>
</property>
@ -727,10 +847,41 @@
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string/>
<widget class="QFrame" name="frame_17">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_19">
<property name="topMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item>
<widget class="QLabel" name="label_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>16.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="seedWord16">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
@ -792,13 +943,6 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>HelpLabel</class>
<extends>QLabel</extends>
<header>components.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>