mirror of
https://codeberg.org/anoncontributorxmr/monero.git
synced 2024-11-24 16:32:25 +00:00
PATCH: polyseed
This commit is contained in:
parent
b089f9ee69
commit
e4c4a53e29
25 changed files with 809 additions and 21 deletions
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
|
@ -124,8 +124,8 @@ jobs:
|
|||
- name: build
|
||||
run: |
|
||||
${{env.CCACHE_SETTINGS}}
|
||||
cmake .
|
||||
make wallet_api -j3
|
||||
cmake -S . -B build
|
||||
cmake --build build wallet_api -j3
|
||||
|
||||
test-ubuntu:
|
||||
needs: build-ubuntu
|
||||
|
|
6
.gitmodules
vendored
6
.gitmodules
vendored
|
@ -10,6 +10,12 @@
|
|||
[submodule "external/randomx"]
|
||||
path = external/randomx
|
||||
url = https://github.com/tevador/RandomX
|
||||
[submodule "external/utf8proc"]
|
||||
path = external/utf8proc
|
||||
url = https://github.com/JuliaStrings/utf8proc.git
|
||||
[submodule "external/polyseed"]
|
||||
path = external/polyseed
|
||||
url = https://github.com/tevador/polyseed.git
|
||||
[submodule "external/supercop"]
|
||||
path = external/supercop
|
||||
url = https://github.com/monero-project/supercop
|
||||
|
|
|
@ -369,6 +369,8 @@ if(NOT MANUAL_SUBMODULES)
|
|||
check_submodule(external/trezor-common)
|
||||
check_submodule(external/randomx)
|
||||
check_submodule(external/supercop)
|
||||
check_submodule(external/polyseed)
|
||||
check_submodule(external/utf8proc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -458,7 +460,7 @@ endif()
|
|||
# elseif(CMAKE_SYSTEM_NAME MATCHES ".*BSDI.*")
|
||||
# set(BSDI TRUE)
|
||||
|
||||
include_directories(external/rapidjson/include external/easylogging++ src contrib/epee/include external external/supercop/include)
|
||||
include_directories(external/rapidjson/include external/easylogging++ src contrib/epee/include external external/supercop/include external/polyseed/include external/utf8proc)
|
||||
|
||||
if(APPLE)
|
||||
cmake_policy(SET CMP0042 NEW)
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <string>
|
||||
#include "memwipe.h"
|
||||
#include "fnv1.h"
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
@ -75,6 +76,12 @@ namespace epee
|
|||
bool operator!=(const wipeable_string &other) const noexcept { return buffer != other.buffer; }
|
||||
wipeable_string &operator=(wipeable_string &&other);
|
||||
wipeable_string &operator=(const wipeable_string &other);
|
||||
char& operator[](size_t idx);
|
||||
const char& operator[](size_t idx) const;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(buffer)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
private:
|
||||
void grow(size_t sz, size_t reserved = 0);
|
||||
|
|
|
@ -261,4 +261,14 @@ wipeable_string &wipeable_string::operator=(const wipeable_string &other)
|
|||
return *this;
|
||||
}
|
||||
|
||||
char& wipeable_string::operator[](size_t idx) {
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < buffer.size(), "Index out of bounds");
|
||||
return buffer[idx];
|
||||
}
|
||||
|
||||
const char& wipeable_string::operator[](size_t idx) const {
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < buffer.size(), "Index out of bounds");
|
||||
return buffer[idx];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
2
external/CMakeLists.txt
vendored
2
external/CMakeLists.txt
vendored
|
@ -70,3 +70,5 @@ add_subdirectory(db_drivers)
|
|||
add_subdirectory(easylogging++)
|
||||
add_subdirectory(qrcodegen)
|
||||
add_subdirectory(randomx EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(polyseed EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(utf8proc EXCLUDE_FROM_ALL)
|
1
external/polyseed
vendored
Submodule
1
external/polyseed
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit b7c35bb3c6b91e481ecb04fc235eaff69c507fa1
|
1
external/utf8proc
vendored
Submodule
1
external/utf8proc
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 1cb28a66ca79a0845e99433fd1056257456cef8b
|
|
@ -95,6 +95,7 @@ add_subdirectory(net)
|
|||
add_subdirectory(hardforks)
|
||||
add_subdirectory(blockchain_db)
|
||||
add_subdirectory(mnemonics)
|
||||
add_subdirectory(polyseed)
|
||||
add_subdirectory(rpc)
|
||||
if(NOT IOS)
|
||||
add_subdirectory(serialization)
|
||||
|
|
|
@ -71,6 +71,7 @@ target_link_libraries(cryptonote_basic
|
|||
checkpoints
|
||||
cryptonote_format_utils_basic
|
||||
device
|
||||
polyseed_wrapper
|
||||
${Boost_DATE_TIME_LIBRARY}
|
||||
${Boost_PROGRAM_OPTIONS_LIBRARY}
|
||||
${Boost_SERIALIZATION_LIBRARY}
|
||||
|
|
|
@ -87,12 +87,16 @@ DISABLE_VS_WARNINGS(4244 4345)
|
|||
void account_keys::xor_with_key_stream(const crypto::chacha_key &key)
|
||||
{
|
||||
// encrypt a large enough byte stream with chacha20
|
||||
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (2 + m_multisig_keys.size()));
|
||||
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (3 + m_multisig_keys.size()) + m_passphrase.size());
|
||||
const char *ptr = key_stream.data();
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
m_spend_secret_key.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
m_view_secret_key.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
m_polyseed.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < m_passphrase.size(); ++i)
|
||||
m_passphrase.data()[i] ^= *ptr++;
|
||||
for (crypto::secret_key &k: m_multisig_keys)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
|
@ -150,6 +154,8 @@ DISABLE_VS_WARNINGS(4244 4345)
|
|||
{
|
||||
m_keys.m_spend_secret_key = crypto::secret_key();
|
||||
m_keys.m_multisig_keys.clear();
|
||||
m_keys.m_polyseed = crypto::secret_key();
|
||||
m_keys.m_passphrase.wipe();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
|
||||
|
@ -244,6 +250,21 @@ DISABLE_VS_WARNINGS(4244 4345)
|
|||
create_from_keys(address, fake, viewkey);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::create_from_polyseed(const polyseed::data& seed, const epee::wipeable_string &passphrase)
|
||||
{
|
||||
crypto::secret_key secret_key;
|
||||
seed.keygen(&secret_key, sizeof(secret_key));
|
||||
|
||||
if (!passphrase.empty()) {
|
||||
secret_key = cryptonote::decrypt_key(secret_key, passphrase);
|
||||
}
|
||||
|
||||
generate(secret_key, true, false);
|
||||
|
||||
seed.save(m_keys.m_polyseed.data);
|
||||
m_keys.m_passphrase = passphrase;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys)
|
||||
{
|
||||
m_keys.m_account_address.m_spend_public_key = spend_public_key;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "cryptonote_basic.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include "polyseed/polyseed.hpp"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
@ -45,6 +46,8 @@ namespace cryptonote
|
|||
std::vector<crypto::secret_key> m_multisig_keys;
|
||||
hw::device *m_device = &hw::get_device("default");
|
||||
crypto::chacha_iv m_encryption_iv;
|
||||
crypto::secret_key m_polyseed;
|
||||
epee::wipeable_string m_passphrase; // Only used with polyseed
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_account_address)
|
||||
|
@ -53,6 +56,8 @@ namespace cryptonote
|
|||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys)
|
||||
const crypto::chacha_iv default_iv{{0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(m_encryption_iv, default_iv)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_polyseed)
|
||||
KV_SERIALIZE(m_passphrase)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
void encrypt(const crypto::chacha_key &key);
|
||||
|
@ -79,6 +84,7 @@ namespace cryptonote
|
|||
void create_from_device(hw::device &hwdev);
|
||||
void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey);
|
||||
void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey);
|
||||
void create_from_polyseed(const polyseed::data &polyseed, const epee::wipeable_string &passphrase);
|
||||
bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys);
|
||||
const account_keys& get_keys() const;
|
||||
std::string get_public_address_str(network_type nettype) const;
|
||||
|
|
|
@ -207,6 +207,8 @@
|
|||
|
||||
#define DNS_BLOCKLIST_LIFETIME (86400 * 8)
|
||||
|
||||
#define POLYSEED_COIN POLYSEED_MONERO
|
||||
|
||||
//The limit is enough for the mandatory transaction content with 16 outputs (547 bytes),
|
||||
//a custom tag (1 byte) and up to 32 bytes of custom data for each recipient.
|
||||
// (1+32) + (1+1+16*32) + (1+16*32) = 1060
|
||||
|
|
25
src/polyseed/CMakeLists.txt
Normal file
25
src/polyseed/CMakeLists.txt
Normal file
|
@ -0,0 +1,25 @@
|
|||
set(polyseed_sources
|
||||
pbkdf2.c
|
||||
polyseed.cpp
|
||||
)
|
||||
|
||||
monero_find_all_headers(polyseed_private_headers "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
monero_private_headers(polyseed_wrapper
|
||||
${polyseed_private_headers}
|
||||
)
|
||||
|
||||
monero_add_library(polyseed_wrapper
|
||||
${polyseed_sources}
|
||||
${polyseed_headers}
|
||||
${polyseed_private_headers}
|
||||
)
|
||||
|
||||
target_link_libraries(polyseed_wrapper
|
||||
PUBLIC
|
||||
polyseed
|
||||
utf8proc
|
||||
${SODIUM_LIBRARY}
|
||||
PRIVATE
|
||||
${EXTRA_LIBRARIES}
|
||||
)
|
85
src/polyseed/pbkdf2.c
Normal file
85
src/polyseed/pbkdf2.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) 2023, The Monero Project
|
||||
// Copyright (c) 2021, tevador <tevador@gmail.com>
|
||||
// Copyright (c) 2005,2007,2009 Colin Percival
|
||||
//
|
||||
// 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 (c) 2023, The Monero Project
|
||||
// Copyright (c) 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
|
182
src/polyseed/polyseed.cpp
Normal file
182
src/polyseed/polyseed.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
// Copyright (c) 2023, The Monero Project
|
||||
// Copyright (c) 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.hpp"
|
||||
#include "pbkdf2.h"
|
||||
|
||||
#include <sodium/core.h>
|
||||
#include <sodium/utils.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <utf8proc.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
namespace polyseed {
|
||||
|
||||
inline size_t utf8_norm(const char* str, polyseed_str norm, utf8proc_option_t options) {
|
||||
utf8proc_int32_t buffer[POLYSEED_STR_SIZE];
|
||||
utf8proc_ssize_t result;
|
||||
|
||||
result = utf8proc_decompose(reinterpret_cast<const uint8_t*>(str), 0, buffer, POLYSEED_STR_SIZE, options);
|
||||
if (result < 0) {
|
||||
return POLYSEED_STR_SIZE;
|
||||
}
|
||||
if (result > POLYSEED_STR_SIZE - 1) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = utf8proc_reencode(buffer, result, options);
|
||||
|
||||
strcpy(norm, reinterpret_cast<const char*>(buffer));
|
||||
sodium_memzero(buffer, POLYSEED_STR_SIZE);
|
||||
return result;
|
||||
}
|
||||
|
||||
static size_t utf8_nfc(const char* str, polyseed_str norm) {
|
||||
// Note: UTF8PROC_LUMP is used here to replace the ideographic space with a regular space for Japanese phrases
|
||||
// to allow wallets to split on ' '.
|
||||
return utf8_norm(str, norm, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_COMPOSE | UTF8PROC_STRIPNA | UTF8PROC_LUMP));
|
||||
}
|
||||
|
||||
static size_t utf8_nfkd(const char* str, polyseed_str norm) {
|
||||
return utf8_norm(str, norm, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT | UTF8PROC_STRIPNA));
|
||||
}
|
||||
|
||||
struct dependency {
|
||||
dependency();
|
||||
std::vector<language> languages;
|
||||
};
|
||||
|
||||
static dependency deps;
|
||||
|
||||
dependency::dependency() {
|
||||
if (sodium_init() == -1) {
|
||||
throw std::runtime_error("sodium_init failed");
|
||||
}
|
||||
|
||||
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*, 8> 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",
|
||||
"Unicode normalization failed"
|
||||
};
|
||||
|
||||
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::split(const language& lang, polyseed_phrase& words) {
|
||||
check_init();
|
||||
if (!lang.valid()) {
|
||||
throw std::runtime_error("invalid language");
|
||||
}
|
||||
}
|
||||
|
||||
void data::load(polyseed_storage storage) {
|
||||
check_init();
|
||||
auto status = polyseed_load(storage, &m_data);
|
||||
if (status != POLYSEED_OK) {
|
||||
throw get_error(status);
|
||||
}
|
||||
}
|
||||
|
||||
void data::load(const crypto::secret_key &key) {
|
||||
polyseed_storage d;
|
||||
memcpy(&d, &key.data, 32);
|
||||
auto status = polyseed_load(d, &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);
|
||||
}
|
||||
}
|
167
src/polyseed/polyseed.hpp
Normal file
167
src/polyseed/polyseed.hpp
Normal file
|
@ -0,0 +1,167 @@
|
|||
// Copyright (c) 2023, The Monero Project
|
||||
// Copyright (c) 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 POLYSEED_HPP
|
||||
#define POLYSEED_HPP
|
||||
|
||||
#include <polyseed/include/polyseed.h>
|
||||
#include <polyseed/src/lang.h>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
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);
|
||||
}
|
||||
const char* separator() const {
|
||||
return m_lang->separator;
|
||||
}
|
||||
bool valid() const {
|
||||
return m_lang != nullptr;
|
||||
}
|
||||
|
||||
const polyseed_lang* m_lang;
|
||||
private:
|
||||
|
||||
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);
|
||||
|
||||
void load(const crypto::secret_key &key);
|
||||
|
||||
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 split(const language& lang, polyseed_phrase& words);
|
||||
|
||||
void save(polyseed_storage storage) const {
|
||||
check_valid();
|
||||
polyseed_store(m_data, storage);
|
||||
}
|
||||
|
||||
void save(void *storage) const {
|
||||
check_valid();
|
||||
polyseed_store(m_data, (uint8_t*)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;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //POLYSEED_HPP
|
|
@ -690,6 +690,28 @@ bool WalletImpl::recoverFromDevice(const std::string &path, const std::string &p
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WalletImpl::createFromPolyseed(const std::string &path, const std::string &password, const std::string &seed,
|
||||
const std::string &passphrase, bool newWallet, uint64_t restoreHeight)
|
||||
{
|
||||
clearStatus();
|
||||
m_recoveringFromSeed = !newWallet;
|
||||
m_recoveringFromDevice = false;
|
||||
|
||||
polyseed::data polyseed(POLYSEED_COIN);
|
||||
|
||||
try {
|
||||
auto lang = polyseed.decode(seed.data());
|
||||
m_wallet->set_seed_language(lang.name());
|
||||
m_wallet->generate(path, password, polyseed, passphrase, !newWallet);
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
setStatusError(e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Wallet::Device WalletImpl::getDeviceType() const
|
||||
{
|
||||
return static_cast<Wallet::Device>(m_wallet->get_device_type());
|
||||
|
@ -798,6 +820,55 @@ std::string WalletImpl::seed(const std::string& seed_offset) const
|
|||
return std::string(seed.data(), seed.size()); // TODO
|
||||
}
|
||||
|
||||
bool WalletImpl::getPolyseed(std::string &seed_words, std::string &passphrase) const
|
||||
{
|
||||
epee::wipeable_string seed_words_epee(seed_words.c_str(), seed_words.size());
|
||||
epee::wipeable_string passphrase_epee(passphrase.c_str(), passphrase.size());
|
||||
clearStatus();
|
||||
|
||||
if (!m_wallet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = m_wallet->get_polyseed(seed_words_epee, passphrase_epee);
|
||||
|
||||
seed_words.assign(seed_words_epee.data(), seed_words_epee.size());
|
||||
passphrase.assign(passphrase_epee.data(), passphrase_epee.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> Wallet::getPolyseedLanguages()
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> languages;
|
||||
|
||||
auto langs = polyseed::get_langs();
|
||||
for (const auto &lang : langs) {
|
||||
languages.emplace_back(std::pair<std::string, std::string>(lang.name_en(), lang.name()));
|
||||
}
|
||||
|
||||
return languages;
|
||||
}
|
||||
|
||||
bool Wallet::createPolyseed(std::string &seed_words, std::string &err, const std::string &language)
|
||||
{
|
||||
epee::wipeable_string seed_words_epee(seed_words.c_str(), seed_words.size());
|
||||
|
||||
try {
|
||||
polyseed::data polyseed(POLYSEED_COIN);
|
||||
polyseed.create(0);
|
||||
polyseed.encode(polyseed::get_lang_by_name(language), seed_words_epee);
|
||||
|
||||
seed_words.assign(seed_words_epee.data(), seed_words_epee.size());
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
err = e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WalletImpl::getSeedLanguage() const
|
||||
{
|
||||
return m_wallet->get_seed_language();
|
||||
|
|
|
@ -79,9 +79,19 @@ public:
|
|||
bool recoverFromDevice(const std::string &path,
|
||||
const std::string &password,
|
||||
const std::string &device_name);
|
||||
|
||||
bool createFromPolyseed(const std::string &path,
|
||||
const std::string &password,
|
||||
const std::string &seed,
|
||||
const std::string &passphrase = "",
|
||||
bool newWallet = true,
|
||||
uint64_t restoreHeight = 0);
|
||||
|
||||
Device getDeviceType() const override;
|
||||
bool close(bool store = true);
|
||||
std::string seed(const std::string& seed_offset = "") const override;
|
||||
bool getPolyseed(std::string &seed_words, std::string &passphrase) const override;
|
||||
|
||||
std::string getSeedLanguage() const override;
|
||||
void setSeedLanguage(const std::string &arg) override;
|
||||
// void setListener(Listener *) {}
|
||||
|
|
|
@ -700,6 +700,10 @@ struct Wallet
|
|||
static void warning(const std::string &category, const std::string &str);
|
||||
static void error(const std::string &category, const std::string &str);
|
||||
|
||||
virtual bool getPolyseed(std::string &seed, std::string &passphrase) const = 0;
|
||||
static bool createPolyseed(std::string &seed_words, std::string &err, const std::string &language = "English");
|
||||
static std::vector<std::pair<std::string, std::string>> getPolyseedLanguages();
|
||||
|
||||
/**
|
||||
* @brief StartRefresh - Start/resume refresh thread (refresh every 10 seconds)
|
||||
*/
|
||||
|
@ -1256,6 +1260,27 @@ struct WalletManager
|
|||
uint64_t kdf_rounds = 1,
|
||||
WalletListener * listener = nullptr) = 0;
|
||||
|
||||
/*!
|
||||
* \brief creates a wallet from a polyseed mnemonic phrase
|
||||
* \param path Name of the wallet file to be created
|
||||
* \param password Password of wallet file
|
||||
* \param nettype Network type
|
||||
* \param mnemonic Polyseed mnemonic
|
||||
* \param passphrase Optional seed offset passphrase
|
||||
* \param newWallet Whether it is a new wallet
|
||||
* \param restoreHeight Override the embedded restore height
|
||||
* \param kdf_rounds Number of rounds for key derivation function
|
||||
* @return
|
||||
*/
|
||||
virtual Wallet * createWalletFromPolyseed(const std::string &path,
|
||||
const std::string &password,
|
||||
NetworkType nettype,
|
||||
const std::string &mnemonic,
|
||||
const std::string &passphrase = "",
|
||||
bool newWallet = true,
|
||||
uint64_t restore_height = 0,
|
||||
uint64_t kdf_rounds = 1) = 0;
|
||||
|
||||
/*!
|
||||
* \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted
|
||||
* \param wallet previously opened / created wallet instance
|
||||
|
|
|
@ -156,6 +156,15 @@ Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path,
|
|||
return wallet;
|
||||
}
|
||||
|
||||
Wallet *WalletManagerImpl::createWalletFromPolyseed(const std::string &path, const std::string &password, NetworkType nettype,
|
||||
const std::string &mnemonic, const std::string &passphrase,
|
||||
bool newWallet, uint64_t restoreHeight, uint64_t kdf_rounds)
|
||||
{
|
||||
WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds);
|
||||
wallet->createFromPolyseed(path, password, mnemonic, passphrase, newWallet, restoreHeight);
|
||||
return wallet;
|
||||
}
|
||||
|
||||
bool WalletManagerImpl::closeWallet(Wallet *wallet, bool store)
|
||||
{
|
||||
WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet);
|
||||
|
|
|
@ -75,6 +75,16 @@ public:
|
|||
const std::string &subaddressLookahead = "",
|
||||
uint64_t kdf_rounds = 1,
|
||||
WalletListener * listener = nullptr) override;
|
||||
|
||||
virtual Wallet * createWalletFromPolyseed(const std::string &path,
|
||||
const std::string &password,
|
||||
NetworkType nettype,
|
||||
const std::string &mnemonic,
|
||||
const std::string &passphrase,
|
||||
bool newWallet = true,
|
||||
uint64_t restore_height = 0,
|
||||
uint64_t kdf_rounds = 1) override;
|
||||
|
||||
virtual bool closeWallet(Wallet *wallet, bool store = true) override;
|
||||
bool walletExists(const std::string &path) override;
|
||||
bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const override;
|
||||
|
|
|
@ -92,6 +92,7 @@ using namespace epee;
|
|||
#include "device/device_cold.hpp"
|
||||
#include "device_trezor/device_trezor.hpp"
|
||||
#include "net/socks_connect.h"
|
||||
#include "polyseed/include/polyseed.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
@ -1260,7 +1261,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std
|
|||
m_enable_multisig(false),
|
||||
m_pool_info_query_time(0),
|
||||
m_has_ever_refreshed_from_node(false),
|
||||
m_allow_mismatched_daemon_version(false)
|
||||
m_allow_mismatched_daemon_version(false),
|
||||
m_polyseed(false)
|
||||
{
|
||||
set_rpc_client_secret_key(rct::rct2sk(rct::skGen()));
|
||||
}
|
||||
|
@ -1438,10 +1440,25 @@ bool wallet2::get_seed(epee::wipeable_string& electrum_words, const epee::wipeab
|
|||
key = cryptonote::encrypt_key(key, passphrase);
|
||||
if (!crypto::ElectrumWords::bytes_to_words(key, electrum_words, seed_language))
|
||||
{
|
||||
std::cout << "Failed to create seed from key for language: " << seed_language << std::endl;
|
||||
std::cout << "Failed to create seed from key for language: " << seed_language << ", falling back to English." << std::endl;
|
||||
crypto::ElectrumWords::bytes_to_words(key, electrum_words, "English");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::get_polyseed(epee::wipeable_string& polyseed, epee::wipeable_string& passphrase) const
|
||||
{
|
||||
if (!m_polyseed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
polyseed::data data(POLYSEED_COIN);
|
||||
data.load(get_account().get_keys().m_polyseed);
|
||||
data.encode(polyseed::get_lang_by_name(seed_language), polyseed);
|
||||
|
||||
passphrase = get_account().get_keys().m_passphrase;
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
@ -4630,6 +4647,9 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee:
|
|||
value2.SetInt(m_enable_multisig ? 1 : 0);
|
||||
json.AddMember("enable_multisig", value2, json.GetAllocator());
|
||||
|
||||
value2.SetInt(m_polyseed ? 1 : 0);
|
||||
json.AddMember("polyseed", value2, json.GetAllocator());
|
||||
|
||||
// Serialize the JSON object
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||
|
@ -4777,6 +4797,7 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
|
|||
m_credits_target = 0;
|
||||
m_enable_multisig = false;
|
||||
m_allow_mismatched_daemon_version = false;
|
||||
m_polyseed = false;
|
||||
}
|
||||
else if(json.IsObject())
|
||||
{
|
||||
|
@ -5013,6 +5034,8 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
|
|||
m_credits_target = field_credits_target;
|
||||
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, enable_multisig, int, Int, false, false);
|
||||
m_enable_multisig = field_enable_multisig;
|
||||
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, polyseed, int, Int, false, false);
|
||||
m_polyseed = field_polyseed;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5285,6 +5308,48 @@ void wallet2::init_type(hw::device::device_type device_type)
|
|||
m_key_device_type = device_type;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Generates a polyseed wallet or restores one.
|
||||
* \param wallet_ Name of wallet file
|
||||
* \param password Password of wallet file
|
||||
* \param passphrase Seed offset passphrase
|
||||
* \param recover Whether it is a restore
|
||||
* \param seed_words If it is a restore, the polyseed
|
||||
* \param create_address_file Whether to create an address file
|
||||
* \return The secret key of the generated wallet
|
||||
*/
|
||||
void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
|
||||
const polyseed::data &seed, const epee::wipeable_string& passphrase, bool recover, uint64_t restoreHeight, bool create_address_file)
|
||||
{
|
||||
clear();
|
||||
prepare_file_names(wallet_);
|
||||
|
||||
if (!wallet_.empty()) {
|
||||
boost::system::error_code ignored_ec;
|
||||
THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
|
||||
THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
|
||||
}
|
||||
|
||||
m_account.create_from_polyseed(seed, passphrase);
|
||||
|
||||
init_type(hw::device::device_type::SOFTWARE);
|
||||
m_polyseed = true;
|
||||
setup_keys(password);
|
||||
|
||||
if (recover) {
|
||||
m_refresh_from_block_height = estimate_blockchain_height(restoreHeight > 0 ? restoreHeight : seed.birthday());
|
||||
} else {
|
||||
m_refresh_from_block_height = estimate_blockchain_height();
|
||||
}
|
||||
|
||||
create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
|
||||
|
||||
setup_new_blockchain();
|
||||
|
||||
if (!wallet_.empty())
|
||||
store();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Generates a wallet or restores one. Assumes the multisig setup
|
||||
* has already completed for the provided multisig info.
|
||||
|
@ -5412,7 +5477,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
|
|||
return retval;
|
||||
}
|
||||
|
||||
uint64_t wallet2::estimate_blockchain_height()
|
||||
uint64_t wallet2::estimate_blockchain_height(uint64_t time)
|
||||
{
|
||||
// -1 month for fluctuations in block time and machine date/time setup.
|
||||
// avg seconds per block
|
||||
|
@ -5436,7 +5501,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
|
|||
// the daemon is currently syncing.
|
||||
// If we use the approximate height we subtract one month as
|
||||
// a safety margin.
|
||||
height = get_approximate_blockchain_height();
|
||||
height = get_approximate_blockchain_height(time);
|
||||
uint64_t target_height = get_daemon_blockchain_target_height(err);
|
||||
if (err.empty()) {
|
||||
if (target_height < height)
|
||||
|
@ -13133,7 +13198,7 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err)
|
|||
return target_height;
|
||||
}
|
||||
|
||||
uint64_t wallet2::get_approximate_blockchain_height() const
|
||||
uint64_t wallet2::get_approximate_blockchain_height(uint64_t t) const
|
||||
{
|
||||
// time of v2 fork
|
||||
const time_t fork_time = m_nettype == TESTNET ? 1448285909 : m_nettype == STAGENET ? 1520937818 : 1458748658;
|
||||
|
@ -13142,7 +13207,7 @@ uint64_t wallet2::get_approximate_blockchain_height() const
|
|||
// avg seconds per block
|
||||
const int seconds_per_block = DIFFICULTY_TARGET_V2;
|
||||
// Calculated blockchain height
|
||||
uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block;
|
||||
uint64_t approx_blockchain_height = fork_block + ((t > 0 ? t : time(NULL)) - fork_time)/seconds_per_block;
|
||||
// testnet and stagenet got some huge rollbacks, so the estimation is way off
|
||||
static const uint64_t approximate_rolled_back_blocks = m_nettype == TESTNET ? 342100 : m_nettype == STAGENET ? 60000 : 30000;
|
||||
if ((m_nettype == TESTNET || m_nettype == STAGENET) && approx_blockchain_height > approximate_rolled_back_blocks)
|
||||
|
@ -14860,6 +14925,21 @@ bool wallet2::parse_uri(const std::string &uri, std::string &address, std::strin
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day)
|
||||
{
|
||||
std::tm date = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
date.tm_year = year - 1900;
|
||||
date.tm_mon = month - 1;
|
||||
date.tm_mday = day;
|
||||
if (date.tm_mon < 0 || 11 < date.tm_mon || date.tm_mday < 1 || 31 < date.tm_mday)
|
||||
{
|
||||
throw std::runtime_error("month or day out of range");
|
||||
}
|
||||
|
||||
uint64_t timestamp_target = std::mktime(&date);
|
||||
|
||||
return get_blockchain_height_by_timestamp(timestamp_target);
|
||||
}
|
||||
|
||||
uint64_t wallet2::get_blockchain_height_by_timestamp(uint64_t timestamp_target) {
|
||||
uint32_t version;
|
||||
if (!check_connection(&version))
|
||||
{
|
||||
|
@ -14869,15 +14949,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
|
|||
{
|
||||
throw std::runtime_error("this function requires RPC version 1.6 or higher");
|
||||
}
|
||||
std::tm date = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
date.tm_year = year - 1900;
|
||||
date.tm_mon = month - 1;
|
||||
date.tm_mday = day;
|
||||
if (date.tm_mon < 0 || 11 < date.tm_mon || date.tm_mday < 1 || 31 < date.tm_mday)
|
||||
{
|
||||
throw std::runtime_error("month or day out of range");
|
||||
}
|
||||
uint64_t timestamp_target = std::mktime(&date);
|
||||
|
||||
std::string err;
|
||||
uint64_t height_min = 0;
|
||||
uint64_t height_max = get_daemon_blockchain_height(err) - 1;
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
#include "message_store.h"
|
||||
#include "wallet_light_rpc.h"
|
||||
#include "wallet_rpc_helpers.h"
|
||||
#include "polyseed/polyseed.hpp"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.wallet2"
|
||||
|
@ -854,6 +855,20 @@ private:
|
|||
void generate(const std::string& wallet_, const epee::wipeable_string& password,
|
||||
const epee::wipeable_string& multisig_data, bool create_address_file = false);
|
||||
|
||||
/*!
|
||||
* \brief Generates a wallet from a polyseed.
|
||||
* @param wallet_ Name of wallet file
|
||||
* @param password Password of wallet file
|
||||
* @param seed Polyseed data
|
||||
* @param passphrase Optional seed offset passphrase
|
||||
* @param recover Whether it is a restore
|
||||
* @param restoreHeight Override the embedded restore height
|
||||
* @param create_address_file Whether to create an address file
|
||||
*/
|
||||
void generate(const std::string& wallet_, const epee::wipeable_string& password,
|
||||
const polyseed::data &seed, const epee::wipeable_string& passphrase = "",
|
||||
bool recover = false, uint64_t restoreHeight = 0, bool create_address_file = false);
|
||||
|
||||
/*!
|
||||
* \brief Generates a wallet or restores one.
|
||||
* \param wallet_ Name of wallet file
|
||||
|
@ -1018,6 +1033,15 @@ private:
|
|||
bool is_deterministic() const;
|
||||
bool get_seed(epee::wipeable_string& electrum_words, const epee::wipeable_string &passphrase = epee::wipeable_string()) const;
|
||||
|
||||
/*!
|
||||
* \brief get_polyseed Gets the polyseed (if available) and passphrase (if set) needed to recover the wallet.
|
||||
* @param seed Polyseed mnemonic phrase
|
||||
* @param passphrase Seed offset passphrase that was used to restore the wallet
|
||||
* @return Returns true if the wallet has a polyseed.
|
||||
* Note: both the mnemonic phrase and the passphrase are needed to recover the wallet
|
||||
*/
|
||||
bool get_polyseed(epee::wipeable_string& seed, epee::wipeable_string &passphrase) const;
|
||||
|
||||
/*!
|
||||
* \brief Checks if light wallet. A light wallet sends view key to a server where the blockchain is scanned.
|
||||
*/
|
||||
|
@ -1466,8 +1490,8 @@ private:
|
|||
/*!
|
||||
* \brief Calculates the approximate blockchain height from current date/time.
|
||||
*/
|
||||
uint64_t get_approximate_blockchain_height() const;
|
||||
uint64_t estimate_blockchain_height();
|
||||
uint64_t get_approximate_blockchain_height(uint64_t time = 0) const;
|
||||
uint64_t estimate_blockchain_height(uint64_t time = 0);
|
||||
std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct);
|
||||
std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f);
|
||||
std::vector<size_t> select_available_unmixable_outputs();
|
||||
|
@ -1559,6 +1583,7 @@ private:
|
|||
bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error);
|
||||
|
||||
uint64_t get_blockchain_height_by_date(uint16_t year, uint8_t month, uint8_t day); // 1<=month<=12, 1<=day<=31
|
||||
uint64_t get_blockchain_height_by_timestamp(uint64_t timestamp);
|
||||
|
||||
bool is_synced();
|
||||
|
||||
|
@ -1874,6 +1899,7 @@ private:
|
|||
std::string seed_language; /*!< Language of the mnemonics (seed). */
|
||||
bool is_old_file_format; /*!< Whether the wallet file is of an old file format */
|
||||
bool m_watch_only; /*!< no spend key */
|
||||
bool m_polyseed;
|
||||
bool m_multisig; /*!< if > 1 spend secret key will not match spend public key */
|
||||
uint32_t m_multisig_threshold;
|
||||
std::vector<crypto::public_key> m_multisig_signers;
|
||||
|
|
Loading…
Reference in a new issue