]> Nutra Git (v1) - gamesguru/feather.git/commitdiff
Polyseed support
authortobtoht <thotbot@protonmail.com>
Mon, 23 May 2022 21:43:33 +0000 (23:43 +0200)
committertobtoht <thotbot@protonmail.com>
Mon, 23 May 2022 21:43:33 +0000 (23:43 +0200)
15 files changed:
CMakeLists.txt
Dockerfile.linux
src/CMakeLists.txt
src/WindowManager.cpp
src/polyseed/pbkdf2.c [new file with mode: 0644]
src/polyseed/pbkdf2.h [new file with mode: 0644]
src/polyseed/polyseed.cpp [new file with mode: 0644]
src/polyseed/polyseed.h [new file with mode: 0644]
src/utils/Seed.cpp
src/utils/Seed.h
src/wizard/PageWalletRestoreSeed.cpp
src/wizard/PageWalletRestoreSeed.h
src/wizard/PageWalletRestoreSeed.ui
src/wizard/PageWalletSeed.cpp
src/wizard/PageWalletSeed.ui

index 6c201af68df08ff6d0ecd6b7545bc48d81237376..bc360342593f5a4e0edd00a70c864a7d1c074499 100644 (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)
index 5faac8b53a91896a734dbb7d9fe804fec2f83b50..ceaee7fbbcdc85f7a08ff16338b5c50160a8e41e 100644 (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)
\ No newline at end of file
index 33118679a26100c6ed68a2b2568b0897a74a5ed0..d453f930abb38e8470dcd191ab925576b246112d 100644 (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
         )
 
index 3cede7663724b73248218a3fb250be520dd2a2f1..072f54affd0d7243bb6353c2f76cece8601905f6 100644 (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);
     }
 
diff --git a/src/polyseed/pbkdf2.c b/src/polyseed/pbkdf2.c
new file mode 100644 (file)
index 0000000..f212e10
--- /dev/null
@@ -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);
+}
\ No newline at end of file
diff --git a/src/polyseed/pbkdf2.h b/src/polyseed/pbkdf2.h
new file mode 100644 (file)
index 0000000..f007240
--- /dev/null
@@ -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
\ No newline at end of file
diff --git a/src/polyseed/polyseed.cpp b/src/polyseed/polyseed.cpp
new file mode 100644 (file)
index 0000000..061fb97
--- /dev/null
@@ -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);
+    }
+}
\ No newline at end of file
diff --git a/src/polyseed/polyseed.h b/src/polyseed/polyseed.h
new file mode 100644 (file)
index 0000000..0faca2e
--- /dev/null
@@ -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;
+    };
+}
\ No newline at end of file
index 236c4190e0a89fc078c925d1557eea1663f06409..6013adcf36c265c6d2a1071b8e9a19327560657b 100644 (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) {
index 5318a66ad6f736152b8621c535d31810a3abb861..19890680f686a78224623866aaa59a7879825b41 100644 (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>
index 27fc35146e3108461de95963055cffafe1e8f851..ab9eddfb533f66e0745048ccf38030ad8489998b 100644 (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));
index eb909a30a02cd09b38e5f21cbef0ddeb0d9af4c0..0f448b8133d9ed6b70287f4f7d9972490e00b17f 100644 (file)
@@ -54,6 +54,7 @@ private:
     Ui::PageWalletRestoreSeed *ui;
     WizardFields *m_fields;
 
+    seedType m_polyseed;
     seedType m_tevador;
     seedType m_legacy;
 
index 3e62d387815372d906aee070ef759ac392144427..2c9b226f7894d0c3e879bfe7823a15f71efb85dd 100644 (file)
         <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>
index c718e20e12046e8db52222ecff090036b17fe0fe..7e238ffc452ed4ff901d46a8cc7a4af9a6e0b82e 100644 (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 {
index f962d61fb7cacc8901ffc036d026e8a9501624d2..af3dff257ac165849210d47fc97d4c2108f81f2b 100644 (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>
      </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">
            </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>
               <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>
                 </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>
            </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>
               <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>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>7.</string>
+                <string>9.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="QLabel" name="seedWord7">
+              <widget class="QLabel" name="seedWord9">
                <property name="text">
                 <string>TextLabel</string>
                </property>
            </widget>
           </item>
           <item>
-           <widget class="QFrame" name="frame_8">
+           <widget class="QFrame" name="frame_4">
             <property name="frameShape">
              <enum>QFrame::StyledPanel</enum>
             </property>
             <property name="frameShadow">
              <enum>QFrame::Raised</enum>
             </property>
-            <layout class="QHBoxLayout" name="horizontalLayout_6">
+            <layout class="QHBoxLayout" name="horizontalLayout_16">
              <property name="topMargin">
               <number>7</number>
              </property>
               <number>7</number>
              </property>
              <item>
-              <widget class="QLabel" name="label_13">
+              <widget class="QLabel" name="label_31">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>10.</string>
+                <string>13.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="QLabel" name="seedWord10">
+              <widget class="QLabel" name="seedWord13">
                <property name="text">
                 <string>TextLabel</string>
                </property>
             </layout>
            </widget>
           </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QVBoxLayout" name="verticalLayout_4">
           <item>
-           <widget class="QFrame" name="frame_4">
+           <widget class="QFrame" name="frame_6">
             <property name="frameShape">
              <enum>QFrame::StyledPanel</enum>
             </property>
             <property name="frameShadow">
              <enum>QFrame::Raised</enum>
             </property>
-            <layout class="QHBoxLayout" name="horizontalLayout_16">
+            <layout class="QHBoxLayout" name="horizontalLayout_4">
              <property name="topMargin">
               <number>7</number>
              </property>
               <number>7</number>
              </property>
              <item>
-              <widget class="QLabel" name="label_31">
+              <widget class="QLabel" name="label_9">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>13.</string>
+                <string>2.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="QLabel" name="seedWord13">
+              <widget class="QLabel" name="seedWord2">
                <property name="text">
                 <string>TextLabel</string>
                </property>
             </layout>
            </widget>
           </item>
-         </layout>
-        </item>
-        <item>
-         <layout class="QVBoxLayout" name="verticalLayout_4">
           <item>
-           <widget class="QFrame" name="frame_6">
+           <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_4">
+            <layout class="QHBoxLayout" name="horizontalLayout_5">
              <property name="topMargin">
               <number>7</number>
              </property>
               <number>7</number>
              </property>
              <item>
-              <widget class="QLabel" name="label_9">
+              <widget class="QLabel" name="label_11">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>2.</string>
+                <string>6.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="HelpLabel" name="seedWord2">
+              <widget class="QLabel" name="seedWord6">
                <property name="text">
                 <string>TextLabel</string>
                </property>
            </widget>
           </item>
           <item>
-           <widget class="QFrame" name="frame_3">
+           <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_2">
+            <layout class="QHBoxLayout" name="horizontalLayout_6">
              <property name="topMargin">
               <number>7</number>
              </property>
               <number>7</number>
              </property>
              <item>
-              <widget class="QLabel" name="label_7">
+              <widget class="QLabel" name="label_13">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>5.</string>
+                <string>10.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="QLabel" name="seedWord5">
+              <widget class="QLabel" name="seedWord10">
                <property name="text">
                 <string>TextLabel</string>
                </property>
            </widget>
           </item>
           <item>
-           <widget class="QFrame" name="frame_14">
+           <widget class="QFrame" name="frame_9">
             <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_7">
              <property name="topMargin">
               <number>7</number>
              </property>
               <number>7</number>
              </property>
              <item>
-              <widget class="QLabel" name="label_25">
+              <widget class="QLabel" name="label_15">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>8.</string>
+                <string>14.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="QLabel" name="seedWord8">
+              <widget class="QLabel" name="seedWord14">
                <property name="text">
                 <string>TextLabel</string>
                </property>
             </layout>
            </widget>
           </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QVBoxLayout" name="verticalLayout_5">
           <item>
-           <widget class="QFrame" name="frame_12">
+           <widget class="QFrame" name="frame_10">
             <property name="frameShape">
              <enum>QFrame::StyledPanel</enum>
             </property>
             <property name="frameShadow">
              <enum>QFrame::Raised</enum>
             </property>
-            <layout class="QHBoxLayout" name="horizontalLayout_10">
+            <layout class="QHBoxLayout" name="horizontalLayout_8">
              <property name="topMargin">
               <number>7</number>
              </property>
               <number>7</number>
              </property>
              <item>
-              <widget class="QLabel" name="label_21">
+              <widget class="QLabel" name="label_17">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>11.</string>
+                <string>3.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="QLabel" name="seedWord11">
+              <widget class="QLabel" name="seedWord3">
                <property name="text">
                 <string>TextLabel</string>
                </property>
            </widget>
           </item>
           <item>
-           <widget class="QFrame" name="frame_9">
+           <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_7">
+            <layout class="QHBoxLayout" name="horizontalLayout_9">
              <property name="topMargin">
               <number>7</number>
              </property>
               <number>7</number>
              </property>
              <item>
-              <widget class="QLabel" name="label_15">
+              <widget class="QLabel" name="label_19">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>14.</string>
+                <string>7.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="QLabel" name="seedWord14">
+              <widget class="QLabel" name="seedWord7">
                <property name="text">
                 <string>TextLabel</string>
                </property>
             </layout>
            </widget>
           </item>
-         </layout>
-        </item>
-        <item>
-         <layout class="QVBoxLayout" name="verticalLayout_5">
           <item>
-           <widget class="QFrame" name="frame_10">
+           <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_8">
+            <layout class="QHBoxLayout" name="horizontalLayout_10">
              <property name="topMargin">
               <number>7</number>
              </property>
               <number>7</number>
              </property>
              <item>
-              <widget class="QLabel" name="label_17">
+              <widget class="QLabel" name="label_21">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>3.</string>
+                <string>11.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="QLabel" name="seedWord3">
+              <widget class="QLabel" name="seedWord11">
                <property name="text">
                 <string>TextLabel</string>
                </property>
            </widget>
           </item>
           <item>
-           <widget class="QFrame" name="frame_7">
+           <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_5">
+            <layout class="QHBoxLayout" name="horizontalLayout_18">
              <property name="topMargin">
               <number>7</number>
              </property>
               <number>7</number>
              </property>
              <item>
-              <widget class="QLabel" name="label_11">
+              <widget class="QLabel" name="label_2">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>6.</string>
+                <string>15.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="QLabel" name="seedWord6">
+              <widget class="QLabel" name="seedWord15">
                <property name="text">
                 <string>TextLabel</string>
                </property>
             </layout>
            </widget>
           </item>
+         </layout>
+        </item>
+        <item>
+         <layout class="QVBoxLayout" name="verticalLayout_8">
           <item>
-           <widget class="QFrame" name="frame_5">
+           <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_15">
+            <layout class="QHBoxLayout" name="horizontalLayout_11">
              <property name="topMargin">
               <number>7</number>
              </property>
               <number>7</number>
              </property>
              <item>
-              <widget class="QLabel" name="label_29">
+              <widget class="QLabel" name="label_27">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                 </sizepolicy>
                </property>
                <property name="text">
-                <string>9.</string>
+                <string>4.</string>
                </property>
               </widget>
              </item>
              <item>
-              <widget class="QLabel" name="seedWord9">
+              <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>
            </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>
    </item>
   </layout>
  </widget>
- <customwidgets>
-  <customwidget>
-   <class>HelpLabel</class>
-   <extends>QLabel</extends>
-   <header>components.h</header>
-  </customwidget>
- </customwidgets>
  <resources/>
  <connections/>
 </ui>