mirror of
https://github.com/feather-wallet/feather.git
synced 2024-12-22 19:49:28 +00:00
Polyseed support
This commit is contained in:
parent
6f19c108ef
commit
08a0d8af62
15 changed files with 800 additions and 143 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -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
85
src/polyseed/pbkdf2.c
Normal 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
46
src/polyseed/pbkdf2.h
Normal 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
161
src/polyseed/polyseed.cpp
Normal 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
147
src/polyseed/polyseed.h
Normal 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;
|
||||
};
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -54,6 +54,7 @@ private:
|
|||
Ui::PageWalletRestoreSeed *ui;
|
||||
WizardFields *m_fields;
|
||||
|
||||
seedType m_polyseed;
|
||||
seedType m_tevador;
|
||||
seedType m_legacy;
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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><html><head/><body><p>Store your <span style=" font-weight:600;">16-word</span> seed in a safe location.</p></body></html></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><html><head/><body><p>Feather recently switched to a new seed scheme called <span style=" font-weight:600;">Polyseed</span>.</p></body></html></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>
|
||||
|
|
Loading…
Reference in a new issue